changeset 14046:1d129c71b628

Merged illumos/illumos-gate into default
author enricop <enricop@computer.org>
date Wed, 29 May 2013 08:31:24 +0200
parents 17d182b692ec (diff) 63225a03be3f (current diff)
children de84c244f325
files
diffstat 299 files changed, 78704 insertions(+), 32616 deletions(-) [+]
line wrap: on
line diff
--- a/exception_lists/copyright	Sun May 19 12:27:58 2013 +0200
+++ b/exception_lists/copyright	Wed May 29 08:31:24 2013 +0200
@@ -28,6 +28,9 @@
 exception_lists/copyright
 exception_lists/cstyle
 exception_lists/hdrchk
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/*/*.[ch]
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/*.[ch]
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/dbus/*.[ch]
 usr/src/cmd/dtrace/test/tst/common/*/*.out
 usr/src/cmd/krb5/kadmin/cli/kadmin_ct.c
 usr/src/cmd/krb5/kadmin/cli/kadmin.h
@@ -332,6 +335,8 @@
 usr/src/lib/krb5/ss/options.c
 usr/src/lib/krb5/ss/std_rqs.c
 usr/src/lib/krb5/ss/utils.c
+usr/src/lib/libdladm/common/wpa_ctrl.c
+usr/src/lib/libdladm/common/wpa_ie.c
 usr/src/lib/librstp/common/*.[ch]
 usr/src/lib/librstp/common/[CRT]*
 usr/src/uts/intel/nsmb/ioc_check.ref
--- a/exception_lists/cstyle	Sun May 19 12:27:58 2013 +0200
+++ b/exception_lists/cstyle	Wed May 29 08:31:24 2013 +0200
@@ -1,3 +1,133 @@
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eapol_supp/eapol_supp_sm.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eapol_supp/eapol_supp_sm.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_server/eap_methods.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/p2p/p2p.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/base64.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/includes.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/uuid.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/wpabuf.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/trace.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/common.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/wpa_debug.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/eloop.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/list.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/os_unix.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/state_machine.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/build_config.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/os.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/base64.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/wpa_debug.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/eloop.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/pcsc_funcs.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/wpabuf.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_methods.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/tncc.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/mschapv2.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_tls.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_config.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_tls_common.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_gtc.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_i.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_mschapv2.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/mschapv2.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_methods.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_tls_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_peap.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_md5.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_ttls.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/pmksa_cache.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/peerkey.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/wpa_ie.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/wpa.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/preauth.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/wpa_i.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/peerkey.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/pmksa_cache.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/preauth.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/wpa.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/wpa_ie.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/drivers/driver.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/drivers/driver_common.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/drivers/drivers.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/wps/wps.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/wps/wps_defs.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/l2_packet/l2_packet.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/random.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/aes.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/ms_funcs.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/sha1.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/md5.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/aes_wrap.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/sha1-tlsprf.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/crypto_openssl.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/aes-unwrap.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/ms_funcs.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/sha1.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/sha256.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/random.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/sha1-pbkdf2.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/tls.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/md5.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/crypto.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/tls_openssl.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/dh_group5.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_wsc_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_common.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/chap.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_peap_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_ttls.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_tlv_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/chap.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_peap_common.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_defs.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/version.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/wpa_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/ieee802_11_defs.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/defs.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/wpa_common.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/wpa_ctrl.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/ieee802_11_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/eapol_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/ap/hostapd.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/notify.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/wpa_supplicant_i.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/driver_i.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/offchannel.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/ctrl_iface.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/wps_supplicant.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/sme.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/p2p_supplicant.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/dbus/dbus_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/dbus/dbus_old.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/dbus/dbus_new.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/scan.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/bgscan.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/wpas_glue.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/bss.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/ap.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/config.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/blacklist.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/interworking.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/wpa_supplicant.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/scan.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/config_ssid.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/ctrl_iface_unix.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/notify.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/ibss_rsn.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/eap_register.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/events.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/ctrl_iface.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/Makefile
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/main.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/config.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/blacklist.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/gas_query.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/bss.c
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/wpas_glue.h
 usr/src/cmd/krb5/kadmin/cli/kadmin_ct.c
 usr/src/cmd/krb5/kadmin/cli/kadmin.c
 usr/src/cmd/krb5/kadmin/cli/kadmin.h
@@ -508,6 +638,8 @@
 usr/src/lib/krb5/ss/ss.h
 usr/src/lib/krb5/ss/std_rqs.c
 usr/src/lib/krb5/ss/utils.c
+usr/src/lib/libdladm/common/wpa_ctrl.c
+usr/src/lib/libdladm/common/wpa_ie.c
 usr/src/lib/libgss/g_glue.c
 usr/src/lib/librstp/common/base.h
 usr/src/lib/librstp/common/choose.h
--- a/exception_lists/hdrchk	Sun May 19 12:27:58 2013 +0200
+++ b/exception_lists/hdrchk	Wed May 29 08:31:24 2013 +0200
@@ -1,3 +1,83 @@
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eapol_supp/eapol_supp_sm.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_server/eap_methods.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/p2p/p2p.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/base64.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/includes.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/uuid.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/wpabuf.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/trace.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/list.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/state_machine.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/build_config.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/os.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/wpa_debug.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/eloop.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/pcsc_funcs.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_methods.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/tncc.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/mschapv2.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_config.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_i.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_tls_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/wpa_ie.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/preauth.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/wpa_i.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/peerkey.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/pmksa_cache.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/wpa.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/drivers/driver.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/wps/wps.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/wps/wps_defs.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/l2_packet/l2_packet.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/random.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/aes.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/sha1.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/md5.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/aes_wrap.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/ms_funcs.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/sha256.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/tls.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/crypto.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/dh_group5.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_wsc_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_peap_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_ttls.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_tlv_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/chap.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_defs.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/version.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/wpa_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/ieee802_11_defs.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/defs.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/wpa_ctrl.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/ieee802_11_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/eapol_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/ap/hostapd.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/notify.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/wpa_supplicant_i.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/driver_i.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/offchannel.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/wps_supplicant.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/sme.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/p2p_supplicant.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/dbus/dbus_common.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/dbus/dbus_old.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/dbus/dbus_new.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/bgscan.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/bss.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/ap.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/config.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/blacklist.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/interworking.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/scan.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/config_ssid.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/ibss_rsn.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/ctrl_iface.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/gas_query.h
+usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/wpas_glue.h
 usr/src/cmd/krb5/kadmin/cli/kadmin.h
 usr/src/cmd/krb5/kadmin/dbutil/import_err.h
 usr/src/cmd/krb5/kadmin/dbutil/kdb5_util.h
--- a/exception_lists/packaging	Sun May 19 12:27:58 2013 +0200
+++ b/exception_lists/packaging	Wed May 29 08:31:24 2013 +0200
@@ -105,6 +105,12 @@
 usr/include/libdlvnic.h
 usr/include/libdlwlan_impl.h
 usr/include/libdlwlan.h
+usr/include/secobj.h
+#
+# Wpa_Supplicant common headers
+#
+usr/include/wpa_defs.h
+usr/include/wpa_ctrl.h
 #
 # Virtual Network Interface Card (VNIC)
 #
@@ -369,8 +375,6 @@
 usr/include/sys/net80211_proto.h
 usr/include/sys/net80211.h
 #
-usr/include/net/wpa.h
-#
 # PPPoE files not delivered to customers.
 #
 usr/include/net/pppoe.h
--- a/usr/src/Makefile	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/Makefile	Wed May 29 08:31:24 2013 +0200
@@ -201,6 +201,7 @@
 cmdheaders: FRC
 	@cd cmd/fm; pwd; $(MAKE) install_h
 	@cd cmd/mdb; pwd; $(MAKE) install_h
+	@cd cmd/cmd-inet/usr.lib/wpa_supplicant; pwd; $(MAKE) install_h
 
 # each xmod target depends on a corresponding MACH-specific pseudotarget
 # before doing common xmod work
--- a/usr/src/Makefile.lint	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/Makefile.lint	Wed May 29 08:31:24 2013 +0200
@@ -80,7 +80,6 @@
 	cmd/cmd-inet/usr.lib/pppoe \
 	cmd/cmd-inet/usr.lib/slpd \
 	cmd/cmd-inet/usr.lib/vrrpd \
-	cmd/cmd-inet/usr.lib/wpad \
 	cmd/cmd-inet/usr.lib/wanboot \
 	cmd/cmd-inet/usr.sadm \
 	cmd/cmd-inet/usr.sbin \
--- a/usr/src/README.license-files	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/README.license-files	Wed May 29 08:31:24 2013 +0200
@@ -41,7 +41,7 @@
       you'll put one in each source directory (i.e. one per library,
       or one per command, or one per kernel module.)
 
-      EXAMPLE: usr/src/uts/common/io/pcan/THIRDPARTYLICENSE
+      EXAMPLE: usr/src/uts/common/io/mwl/THIRDPARTYLICENSE
 
       If this file proves unmanageable, or you're adding licenses
       that really are independent of each other, you may instead
--- a/usr/src/cmd/Makefile.check	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/Makefile.check	Wed May 29 08:31:24 2013 +0200
@@ -92,7 +92,7 @@
 	cmd-inet/usr.lib/mdnsd		\
 	cmd-inet/usr.lib/slpd		\
 	cmd-inet/usr.lib/vrrpd		\
-	cmd-inet/usr.lib/wpad		\
+	cmd-inet/usr.lib/wpa_supplicant	\
 	cmd-inet/usr.sbin		\
 	cmd-inet/usr.sbin/in.ftpd	\
 	cmd-inet/usr.sbin/in.rdisc	\
--- a/usr/src/cmd/cmd-inet/lib/nwamd/Makefile	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/Makefile	Wed May 29 08:31:24 2013 +0200
@@ -20,6 +20,7 @@
 #
 #
 # Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
 #
 # usr/src/cmd/cmd-inet/lib/nwamd/Makefile
 #
@@ -31,7 +32,7 @@
 OBJS=		conditions.o dlpi_events.o door_if.o enm.o\
 		events.o known_wlans.o llp.o loc.o logging.o\
 		main.o ncp.o ncu.o ncu_phys.o ncu_ip.o objects.o\
-		routing_events.o sysevent_events.o util.o
+		routing_events.o sysevent_events.o wpa_s_events.o util.o
 SRCS=		$(OBJS:%.o=%.c)
 HEADERS=	conditions.h events.h known_wlans.h llp.h ncp.h ncu.h\
 		objects.h
@@ -51,15 +52,10 @@
 
 ROOTCMDDIR=	$(ROOTFS_LIBDIR)/inet
 
-LDLIBS +=	-ldhcpagent -ldhcputil -ldladm -ldlpi -lgen \
+LDLIBS +=	-ldhcpagent -ldhcputil -ldladm -ldlpi \
 		-linetutil -lipadm -lkstat -lnsl -lnvpair -lnwam \
 		-lsecdb -lscf -lsocket -lsysevent -lumem -luutil
 
-CERRWARN +=	-_gcc=-Wno-uninitialized
-CERRWARN +=	-_gcc=-Wno-parentheses
-CERRWARN +=	-_gcc=-Wno-switch
-CERRWARN +=	-_gcc=-Wno-unused-label
-
 #
 # Instrument with CTF data to ease debugging.
 #
@@ -96,7 +92,7 @@
 	$(INS.dir)
 
 $(LOCDIRS): $(ROOTLOCDIR)
-	$(INS.dir) 
+	$(INS.dir)
 
 $(ROOTLOCDIR)/%: $(ROOTLOCDIR) %
 	$(INS.file)
--- a/usr/src/cmd/cmd-inet/lib/nwamd/conditions.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/conditions.c	Wed May 29 08:31:24 2013 +0200
@@ -21,15 +21,13 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #include <arpa/inet.h>
 #include <ctype.h>
 #include <errno.h>
 #include <inet/ip.h>
-#include <libdladm.h>
-#include <libdllink.h>
-#include <libdlwlan.h>
 #include <netdb.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -79,12 +77,6 @@
 static boolean_t test_condition_adv_domain(nwam_condition_t condition,
     const char *domainname);
 
-/*  WLAN conditions */
-static boolean_t test_condition_wireless_essid(nwam_condition_t condition,
-    const char *essid);
-static boolean_t test_condition_wireless_bssid(nwam_condition_t condition,
-    const char *essid);
-
 struct nwamd_condition_map {
 	nwam_condition_object_type_t object_type;
 	boolean_t (*condition_func)(nwam_condition_t, const char *);
@@ -96,14 +88,12 @@
 	{ NWAM_CONDITION_OBJECT_TYPE_LOC, test_condition_loc },
 	{ NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS, test_condition_ip_address },
 	{ NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN, test_condition_sys_domain },
-	{ NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN, test_condition_adv_domain },
-	{ NWAM_CONDITION_OBJECT_TYPE_ESSID, test_condition_wireless_essid },
-	{ NWAM_CONDITION_OBJECT_TYPE_BSSID, test_condition_wireless_bssid }
+	{ NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN, test_condition_adv_domain }
 };
 
 /*
  * This function takes which kind of conditions (is or is not) we are testing
- * the object against and an object and applies the conditon to the object.
+ * the object against and an object and applies the condition to the object.
  */
 static boolean_t
 test_condition_object_state(nwam_condition_t condition,
@@ -549,145 +539,9 @@
 
 struct nwamd_wlan_condition_walk_arg {
 	nwam_condition_t condition;
-	const char *exp_essid;
-	const char *exp_bssid;
-	uint_t num_connected;
 	boolean_t res;
 };
 
-static int
-check_wlan(const char *linkname, void *arg)
-{
-	struct nwamd_wlan_condition_walk_arg *wa = arg;
-	datalink_id_t linkid;
-	dladm_wlan_linkattr_t attr;
-	dladm_status_t status;
-	char cur_essid[DLADM_STRSIZE];
-	char cur_bssid[DLADM_STRSIZE];
-	char errmsg[DLADM_STRSIZE];
-
-	if ((status = dladm_name2info(dld_handle, linkname, &linkid, NULL, NULL,
-	    NULL)) != DLADM_STATUS_OK) {
-		nlog(LOG_DEBUG, "check_wlan: dladm_name2info() for %s "
-		    "failed: %s", linkname,
-		    dladm_status2str(status, errmsg));
-		return (DLADM_WALK_CONTINUE);
-	}
-
-	status = dladm_wlan_get_linkattr(dld_handle, linkid, &attr);
-	if (status != DLADM_STATUS_OK) {
-		nlog(LOG_DEBUG, "check_wlan: dladm_wlan_get_linkattr() for %s "
-		    "failed: %s", linkname,
-		    dladm_status2str(status, errmsg));
-		return (DLADM_WALK_CONTINUE);
-	}
-	if (attr.la_status == DLADM_WLAN_LINK_DISCONNECTED)
-		return (DLADM_WALK_TERMINATE);
-
-	wa->num_connected++;
-
-	if (wa->exp_essid != NULL) {
-		/* Is the NIC associated with the expected access point? */
-		(void) dladm_wlan_essid2str(&attr.la_wlan_attr.wa_essid,
-		    cur_essid);
-		switch (wa->condition) {
-		case NWAM_CONDITION_IS:
-			wa->res = strcmp(cur_essid, wa->exp_essid) == 0;
-			if (wa->res)
-				return (DLADM_WALK_TERMINATE);
-			break;
-		case NWAM_CONDITION_IS_NOT:
-			wa->res = strcmp(cur_essid, wa->exp_essid) != 0;
-			if (!wa->res)
-				return (DLADM_WALK_TERMINATE);
-			break;
-		case NWAM_CONDITION_CONTAINS:
-			wa->res = strstr(cur_essid, wa->exp_essid) != NULL;
-			if (wa->res)
-				return (DLADM_WALK_TERMINATE);
-			break;
-		case NWAM_CONDITION_DOES_NOT_CONTAIN:
-			wa->res = strstr(cur_essid, wa->exp_essid) == NULL;
-			if (!wa->res)
-				return (DLADM_WALK_TERMINATE);
-			break;
-		default:
-			return (DLADM_WALK_TERMINATE);
-		}
-		return (DLADM_WALK_CONTINUE);
-	}
-	if (wa->exp_bssid != NULL) {
-		/* Is the NIC associated with the expected access point? */
-		(void) dladm_wlan_bssid2str(&attr.la_wlan_attr.wa_bssid,
-		    cur_bssid);
-		switch (wa->condition) {
-		case NWAM_CONDITION_IS:
-			wa->res = strcmp(cur_bssid, wa->exp_bssid) == 0;
-			if (wa->res)
-				return (DLADM_WALK_TERMINATE);
-			break;
-		case NWAM_CONDITION_IS_NOT:
-			wa->res = strcmp(cur_bssid, wa->exp_bssid) != 0;
-			if (!wa->res)
-				return (DLADM_WALK_TERMINATE);
-			break;
-		default:
-			return (DLADM_WALK_TERMINATE);
-		}
-		return (DLADM_WALK_CONTINUE);
-	}
-	/*
-	 * Neither an ESSID or BSSID match is required - being connected to a
-	 * WLAN is enough.
-	 */
-	switch (wa->condition) {
-	case NWAM_CONDITION_IS:
-		wa->res = B_TRUE;
-		return (DLADM_WALK_TERMINATE);
-	default:
-		wa->res = B_FALSE;
-		return (DLADM_WALK_TERMINATE);
-	}
-	/*NOTREACHED*/
-	return (DLADM_WALK_CONTINUE);
-}
-
-static boolean_t
-test_condition_wireless_essid(nwam_condition_t condition,
-    const char *essid)
-{
-	struct nwamd_wlan_condition_walk_arg wa;
-
-	wa.condition = condition;
-	wa.exp_essid = essid;
-	wa.exp_bssid = NULL;
-	wa.num_connected = 0;
-	wa.res = B_FALSE;
-
-	(void) dladm_walk(check_wlan, dld_handle, &wa, DATALINK_CLASS_PHYS,
-	    DL_WIFI, DLADM_OPT_ACTIVE);
-
-	return (wa.num_connected > 0 && wa.res == B_TRUE);
-}
-
-static boolean_t
-test_condition_wireless_bssid(nwam_condition_t condition,
-    const char *bssid)
-{
-	struct nwamd_wlan_condition_walk_arg wa;
-
-	wa.condition = condition;
-	wa.exp_bssid = bssid;
-	wa.exp_essid = NULL;
-	wa.num_connected = 0;
-	wa.res = B_FALSE;
-
-	(void) dladm_walk(check_wlan, dld_handle, &wa, DATALINK_CLASS_PHYS,
-	    DL_WIFI, DLADM_OPT_ACTIVE);
-
-	return (wa.num_connected > 0 && wa.res == B_TRUE);
-}
-
 /*
  * This function takes an activation mode and a string representation of a
  * condition and evaluates it.
@@ -696,10 +550,10 @@
 nwamd_check_conditions(nwam_activation_mode_t activation_mode,
     char **condition_strings, uint_t num_conditions)
 {
-	boolean_t ret;
+	boolean_t ret = B_FALSE;
 	nwam_condition_t condition;
 	nwam_condition_object_type_t object_type;
-	char *object_name;
+	char *object_name = NULL;
 	int i, j;
 
 	for (i = 0; i < num_conditions; i++) {
--- a/usr/src/cmd/cmd-inet/lib/nwamd/dlpi_events.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/dlpi_events.c	Wed May 29 08:31:24 2013 +0200
@@ -21,12 +21,14 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #include <arpa/inet.h>
 #include <assert.h>
 #include <fcntl.h>
 #include <libdlpi.h>
+#include <libdlwlan.h>
 #include <libnwam.h>
 #include <net/if.h>
 #include <pthread.h>
@@ -121,7 +123,13 @@
 		return;
 	}
 
-	nwamd_set_unset_link_properties(ncu, B_TRUE);
+	/* Wifi links do not support setting/unsetting these properties */
+	if (dladm_wlan_validate(dld_handle, ncu->ncu_link.nwamd_link_id,
+	    NULL, NULL) == DLADM_STATUS_OK) {
+		nlog(LOG_DEBUG, "nwamd_dlpi_add_link(%s): skipping "
+		    "wifi link properties initialization", ncu->ncu_name);
+	} else
+		nwamd_set_unset_link_properties(ncu, B_TRUE);
 
 	rc = dlpi_enabnotify(link->nwamd_link_dhp,
 	    DL_NOTE_LINK_UP | DL_NOTE_LINK_DOWN, nwamd_dlpi_notify,
@@ -161,8 +169,16 @@
 		    ncu->ncu_link.nwamd_link_dlpi_thread);
 		(void) pthread_join(ncu->ncu_link.nwamd_link_dlpi_thread, NULL);
 		ncu->ncu_link.nwamd_link_dlpi_thread = 0;
-		/* Unset properties before closing */
-		nwamd_set_unset_link_properties(ncu, B_FALSE);
+
+		/* Unset properties before closing. Wifi links do not support
+		 * setting/unsetting these properties */
+		if (dladm_wlan_validate(dld_handle, ncu->ncu_link.nwamd_link_id,
+		    NULL, NULL) == DLADM_STATUS_OK) {
+			nlog(LOG_DEBUG, "nwamd_dlpi_delete_link(%s): skipping "
+			    "wifi link properties de-initialization",
+			    ncu->ncu_name);
+		} else
+			nwamd_set_unset_link_properties(ncu, B_FALSE);
 	}
 
 	dlpi_close(ncu->ncu_link.nwamd_link_dhp);
--- a/usr/src/cmd/cmd-inet/lib/nwamd/door_if.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/door_if.c	Wed May 29 08:31:24 2013 +0200
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #include <auth_attr.h>
@@ -30,6 +31,7 @@
 #include <door.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <libdlwlan.h>
 #include <libnwam_priv.h>
 #include <libuutil.h>
 #include <pthread.h>
@@ -84,8 +86,6 @@
 	ucred_t *, struct passwd *);
 static nwam_error_t nwamd_door_req_wlan_select(nwamd_door_arg_t *,
 	ucred_t *, struct passwd *);
-static nwam_error_t nwamd_door_req_wlan_set_key(nwamd_door_arg_t *,
-	ucred_t *, struct passwd *);
 static nwam_error_t nwamd_door_req_action(nwamd_door_arg_t *,
 	ucred_t *, struct passwd *);
 static nwam_error_t nwamd_door_req_state(nwamd_door_arg_t *,
@@ -111,8 +111,6 @@
 	nwamd_door_req_wlan_scan_results },
 	{ NWAM_REQUEST_TYPE_WLAN_SELECT, AUTOCONF_WLAN_AUTH,
 	nwamd_door_req_wlan_select },
-	{ NWAM_REQUEST_TYPE_WLAN_SET_KEY, AUTOCONF_WLAN_AUTH,
-	nwamd_door_req_wlan_set_key },
 	/* Requires WRITE, SELECT or WLAN auth depending on action */
 	{ NWAM_REQUEST_TYPE_ACTION, NULL, nwamd_door_req_action },
 	{ NWAM_REQUEST_TYPE_STATE, AUTOCONF_READ_AUTH,
@@ -188,12 +186,12 @@
 
 	ncu = obj->nwamd_object_data;
 	link = &ncu->ncu_link;
-	num_wlans = link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr_num;
+	num_wlans = link->nwamd_link_wifi_scan.nwamd_wifi_sres_num;
 
 	if (num_wlans > 0) {
 		(void) memcpy
 		    (req->nwda_data.nwdad_wlan_info.nwdad_wlans,
-		    link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr,
+		    link->nwamd_link_wifi_scan.nwamd_wifi_sres,
 		    num_wlans * sizeof (nwam_wlan_t));
 	}
 	req->nwda_data.nwdad_wlan_info.nwdad_num_wlans = num_wlans;
@@ -210,38 +208,22 @@
 nwamd_door_req_wlan_select(nwamd_door_arg_t *req, ucred_t *ucr,
     struct passwd *pwd)
 {
+	char tmpbuf[DLADM_WLAN_BSSID_LEN*3];
+        
 	nlog(LOG_DEBUG,
 	    "nwamd_door_req_wlan_select: processing WLAN selection : "
 	    "link %s ESSID %s , BSSID %s",
 	    req->nwda_data.nwdad_wlan_info.nwdad_name,
-	    req->nwda_data.nwdad_wlan_info.nwdad_essid,
-	    req->nwda_data.nwdad_wlan_info.nwdad_bssid);
+	    req->nwda_data.nwdad_wlan_info.nwdad_wlans[0].nww_essid,
+	    dladm_wlan_bssid2str(
+	    req->nwda_data.nwdad_wlan_info.nwdad_wlans[0].nww_bssid, tmpbuf));
 	return (nwamd_wlan_select
 	    (req->nwda_data.nwdad_wlan_info.nwdad_name,
-	    req->nwda_data.nwdad_wlan_info.nwdad_essid,
-	    req->nwda_data.nwdad_wlan_info.nwdad_bssid,
-	    req->nwda_data.nwdad_wlan_info.nwdad_security_mode,
-	    req->nwda_data.nwdad_wlan_info.nwdad_add_to_known_wlans));
-}
-
-/* ARGSUSED */
-static nwam_error_t
-nwamd_door_req_wlan_set_key(nwamd_door_arg_t *req, ucred_t *ucr,
-    struct passwd *pwd)
-{
-	nlog(LOG_DEBUG,
-	    "nwamd_door_req_wlan_set_key: processing WLAN key input : "
-	    "link %s ESSID %s BSSID %s",
-	    req->nwda_data.nwdad_wlan_info.nwdad_name,
-	    req->nwda_data.nwdad_wlan_info.nwdad_essid,
-	    req->nwda_data.nwdad_wlan_info.nwdad_bssid);
-	return (nwamd_wlan_set_key
-	    (req->nwda_data.nwdad_wlan_info.nwdad_name,
-	    req->nwda_data.nwdad_wlan_info.nwdad_essid,
-	    req->nwda_data.nwdad_wlan_info.nwdad_bssid,
-	    req->nwda_data.nwdad_wlan_info.nwdad_security_mode,
-	    req->nwda_data.nwdad_wlan_info.nwdad_keyslot,
-	    req->nwda_data.nwdad_wlan_info.nwdad_key));
+	    &req->nwda_data.nwdad_wlan_info.nwdad_wlans[0],
+	    req->nwda_data.nwdad_wlan_info.nwdad_key.wk_class ?
+	    &req->nwda_data.nwdad_wlan_info.nwdad_key : NULL,
+	    req->nwda_data.nwdad_wlan_info.nwdad_eap.eap_valid ?
+	    &req->nwda_data.nwdad_wlan_info.nwdad_eap : NULL));
 }
 
 static nwam_error_t
@@ -328,6 +310,9 @@
 		case NWAM_OBJECT_TYPE_LOC:
 			err = nwamd_loc_action(name, action);
 			break;
+		case NWAM_OBJECT_TYPE_KNOWN_WLAN:
+			err = nwamd_known_wlan_action(name, action);
+			break;
 		case NWAM_OBJECT_TYPE_NCU:
 			err = nwamd_ncu_action(name, parent, action);
 			break;
@@ -487,6 +472,7 @@
 	case NWAM_OBJECT_TYPE_LOC:
 	case NWAM_OBJECT_TYPE_NCU:
 	case NWAM_OBJECT_TYPE_ENM:
+	case NWAM_OBJECT_TYPE_KNOWN_WLAN:
 		obj = nwamd_object_find(object_type, name);
 		if (obj == NULL) {
 			nlog(LOG_ERR, "nwamd_door_req_state: %s %s not found",
--- a/usr/src/cmd/cmd-inet/lib/nwamd/enm.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/enm.c	Wed May 29 08:31:24 2013 +0200
@@ -21,14 +21,12 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #include <arpa/inet.h>
 #include <errno.h>
 #include <inet/ip.h>
-#include <libdladm.h>
-#include <libdllink.h>
-#include <libdlwlan.h>
 #include <libscf.h>
 #include <netinet/in.h>
 #include <netdb.h>
--- a/usr/src/cmd/cmd-inet/lib/nwamd/events.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/events.c	Wed May 29 08:31:24 2013 +0200
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #include <atomic.h>
@@ -56,6 +57,8 @@
 	nwamd_routing_events_init, nwamd_routing_events_fini },
 	{ "sysevent_events",
 	nwamd_sysevent_events_init, nwamd_sysevent_events_fini },
+	{ "wpa_s_events",
+	nwamd_wpa_s_events_init, nwamd_wpa_s_events_fini },
 };
 
 /* Counter for event ids */
@@ -89,8 +92,6 @@
 		return ("TIMER");
 	case NWAM_EVENT_TYPE_UPGRADE:
 		return ("UPGRADE");
-	case NWAM_EVENT_TYPE_PERIODIC_SCAN:
-		return ("PERIODIC_SCAN");
 	case NWAM_EVENT_TYPE_QUEUE_QUIET:
 		return ("QUEUE_QUIET");
 	default:
@@ -412,21 +413,20 @@
 }
 
 nwamd_event_t
-nwamd_event_init_wlan(const char *name, int32_t type, boolean_t connected,
-    nwam_wlan_t *wlans, uint_t num_wlans)
+nwamd_event_init_wlan(const char *name, int32_t type, nwam_wlan_t *wlan,
+    uint_t scanned_wl)
 {
-	size_t size = 0;
 	char *object_name;
 	nwamd_event_t event;
 	nwam_error_t err;
 
 	switch (type) {
 	case NWAM_EVENT_TYPE_WLAN_SCAN_REPORT:
-	case NWAM_EVENT_TYPE_WLAN_NEED_CHOICE:
-		size = sizeof (nwam_wlan_t) * (num_wlans - 1);
-		break;
-	case NWAM_EVENT_TYPE_WLAN_NEED_KEY:
+	case NWAM_EVENT_TYPE_WLAN_WRONG_KEY:
+	case NWAM_EVENT_TYPE_WLAN_ASSOCIATION_REPORT:
 	case NWAM_EVENT_TYPE_WLAN_CONNECTION_REPORT:
+	case NWAM_EVENT_TYPE_WLAN_DISASSOCIATION_REPORT:
+		/* one nwam_wlan_t is enough */
 		break;
 	default:
 		nlog(LOG_ERR, "nwamd_event_init_wlan: unexpected "
@@ -441,19 +441,19 @@
 		return (NULL);
 	}
 
-	event = nwamd_event_init(type, NWAM_OBJECT_TYPE_NCU, size, object_name);
+	event = nwamd_event_init(type, NWAM_OBJECT_TYPE_NCU, 0, object_name);
 	free(object_name);
 	if (event == NULL)
 		return (NULL);
 
 	(void) strlcpy(event->event_msg->nwe_data.nwe_wlan_info.nwe_name, name,
 	    sizeof (event->event_msg->nwe_data.nwe_wlan_info.nwe_name));
-	event->event_msg->nwe_data.nwe_wlan_info.nwe_connected = connected;
-	event->event_msg->nwe_data.nwe_wlan_info.nwe_num_wlans = num_wlans;
+	event->event_msg->nwe_data.nwe_wlan_info.nwe_scanres_num = scanned_wl;
 
 	/* copy the wlans */
-	(void) memcpy(event->event_msg->nwe_data.nwe_wlan_info.nwe_wlans, wlans,
-	    num_wlans * sizeof (nwam_wlan_t));
+	if (wlan != NULL)
+		(void) memcpy(&event->event_msg->nwe_data.nwe_wlan_info.
+		    nwe_wlan, wlan, sizeof (nwam_wlan_t));
 
 	return (event);
 }
@@ -706,14 +706,10 @@
 		return;
 	}
 
-	for (i = 0;
-	    event_methods[i].event_type != NWAM_EVENT_TYPE_NOOP;
-	    i++) {
-		if (event_methods[i].event_type ==
-		    event->event_type &&
+	for (i = 0; event_methods[i].event_type != NWAM_EVENT_TYPE_NOOP; i++) {
+		if (event_methods[i].event_type == event->event_type &&
 		    event_methods[i].event_method != NULL) {
-			nlog(LOG_DEBUG,
-			    "(%p) %s: running method for event %s",
+			nlog(LOG_DEBUG, "(%p) %s: running method for event %s",
 			    (void *)event, event->event_object,
 			    nwamd_event_name(event->event_type));
 			/* run method */
--- a/usr/src/cmd/cmd-inet/lib/nwamd/events.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/events.h	Wed May 29 08:31:24 2013 +0200
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #ifndef _EVENTS_H
@@ -48,8 +49,7 @@
 #define	NWAM_EVENT_TYPE_NCU_CHECK		NWAM_EVENT_MAX + 5
 #define	NWAM_EVENT_TYPE_TIMER			NWAM_EVENT_MAX + 6
 #define	NWAM_EVENT_TYPE_UPGRADE			NWAM_EVENT_MAX + 7
-#define	NWAM_EVENT_TYPE_PERIODIC_SCAN		NWAM_EVENT_MAX + 8
-#define	NWAM_EVENT_TYPE_QUEUE_QUIET		NWAM_EVENT_MAX + 9
+#define	NWAM_EVENT_TYPE_QUEUE_QUIET		NWAM_EVENT_MAX + 8
 
 #define	NEXT_FEW_SECONDS			5
 
@@ -84,6 +84,8 @@
 extern void nwamd_routing_events_fini(void);
 extern void nwamd_sysevent_events_init(void);
 extern void nwamd_sysevent_events_fini(void);
+extern void nwamd_wpa_s_events_init(void);
+extern void nwamd_wpa_s_events_fini(void);
 
 /* Event init/enqueueing */
 extern void nwamd_event_queue_init(void);
@@ -102,8 +104,8 @@
 extern nwamd_event_t nwamd_event_init_link_state(const char *, boolean_t);
 extern nwamd_event_t nwamd_event_init_if_state(const char *, uint32_t,
     uint32_t, struct sockaddr *, struct sockaddr *);
-extern nwamd_event_t nwamd_event_init_wlan(const char *, int32_t, boolean_t,
-    nwam_wlan_t *, uint_t);
+extern nwamd_event_t nwamd_event_init_wlan(const char *, int32_t, nwam_wlan_t *,
+    uint_t);
 extern nwamd_event_t nwamd_event_init_ncu_check(void);
 extern nwamd_event_t nwamd_event_init_init(void);
 extern nwamd_event_t nwamd_event_init_shutdown(void);
--- a/usr/src/cmd/cmd-inet/lib/nwamd/known_wlans.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/known_wlans.c	Wed May 29 08:31:24 2013 +0200
@@ -21,19 +21,12 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
 #include <string.h>
-#include <libdladm.h>
-#include <libdllink.h>
 #include <libdlwlan.h>
-#include <libgen.h>
-#include <libnwam.h>
+#include <syslog.h>
 
 #include "events.h"
 #include "known_wlans.h"
@@ -41,441 +34,163 @@
 #include "objects.h"
 #include "util.h"
 
-/*
- * known_wlans.c - contains routines which handle the known WLAN abstraction.
- */
-
-#define	KNOWN_WIFI_NETS_FILE		"/etc/nwam/known_wifi_nets"
-
-/* enum for parsing each line of /etc/nwam/known_wifi_nets */
-typedef enum {
-	ESSID = 0,
-	BSSID,
-	MAX_FIELDS
-} known_wifi_nets_fields_t;
+int
+find_matching_wlan_cb(nwam_known_wlan_handle_t kwh, void *data)
+{
+	nwam_wlan_t *mywlan = data;
+	nwam_error_t err;
 
-/* Structure for one BSSID */
-typedef struct bssid {
-	struct qelem	bssid_links;
-	char		*bssid;
-} bssid_t;
+	nwam_value_t bssidval;
+	char *bssidstr;
+	nwam_value_t ssidval;
+	char *ssidstr;
+	nwam_value_t keynameval;
+	char *keynamestr;
 
-/* Structure for an ESSID and its BSSIDs */
-typedef struct kw {
-	struct qelem	kw_links;
-	char		kw_essid[NWAM_MAX_NAME_LEN];
-	uint32_t	kw_num_bssids;
-	struct qelem	kw_bssids;
-} kw_t;
+	char *currnamestr;
+	int currid = -1;
 
-/* Holds the linked-list of ESSIDs to make Known WLANs out of */
-static struct qelem kw_list;
+	if (mywlan == NULL)
+		return (-1);
+
+	/*
+	 * We return NWAM_SUCCESS if nothing is found or errors are encountered
+	 * to not halt known wlans walk
+	 */
 
-/* Used in walking secobjs looking for an ESSID prefix match. */
-struct nwamd_secobj_arg {
-	char nsa_essid_prefix[DLADM_WLAN_MAX_KEYNAME_LEN];
-	char nsa_keyname[DLADM_WLAN_MAX_KEYNAME_LEN];
-	dladm_wlan_key_t *nsa_key;
-	uint64_t nsa_secmode;
-};
-
-static void
-kw_list_init(void)
-{
-	kw_list.q_forw = kw_list.q_back = &kw_list;
-}
+	/*
+	 * BSSID. Skip this check if the user added manually a known wlan
+	 * without bssid field
+	 */
+	if ((err = nwam_known_wlan_get_prop_value(kwh,
+	    NWAM_KNOWN_WLAN_PROP_BSSID, &bssidval)) == NWAM_SUCCESS) {
+		uint8_t bssid[6];
 
-static void
-kw_list_free(void)
-{
-	kw_t *kw;
-	bssid_t *b;
-
-	while (kw_list.q_forw != &kw_list) {
-		kw = (kw_t *)kw_list.q_forw;
-
-		/* free kw_bssids */
-		while (kw->kw_bssids.q_forw != &kw->kw_bssids) {
-			b = (bssid_t *)kw->kw_bssids.q_forw;
-			remque(&b->bssid_links);
-			free(b->bssid);
-			free(b);
+		err = nwam_value_get_string(bssidval, &bssidstr);
+		if (err != NWAM_SUCCESS) {
+			nwam_value_free(bssidval);
+			return (NWAM_SUCCESS);
 		}
-		remque(&kw->kw_links);
-		free(kw);
+		if (dladm_wlan_str2bssid(bssidstr, bssid)) {
+			nwam_value_free(bssidval);
+			return (NWAM_SUCCESS);
+		}
+		if (memcmp(bssid, mywlan->nww_bssid,
+		    DLADM_WLAN_BSSID_LEN) != 0) {
+			nwam_value_free(bssidval);
+			return (NWAM_SUCCESS);
+		}
+		nwam_value_free(bssidval);
 	}
-}
-
-/* Returns the entry in kw_list for the given ESSID.  NULL if non-existent */
-static kw_t *
-kw_lookup(const char *essid)
-{
-	kw_t *kw;
-
-	if (essid == NULL)
-		return (NULL);
-
-	for (kw = (kw_t *)kw_list.q_forw;
-	    kw != (kw_t *)&kw_list;
-	    kw = (kw_t *)kw->kw_links.q_forw) {
-		if (strcmp(essid, kw->kw_essid) == 0)
-			return (kw);
-	}
-	return (NULL);
-}
-
-/* Adds an ESSID/BSSID combination to kw_list.  Returns B_TRUE on success. */
-static boolean_t
-kw_add(const char *essid, const char *bssid)
-{
-	kw_t *kw;
-	bssid_t *b;
 
-	if ((b = calloc(1, sizeof (bssid_t))) == NULL) {
-		nlog(LOG_ERR, "kw_add: cannot allocate for bssid_t: %m");
-		return (B_FALSE);
-	}
-	if ((kw = calloc(1, sizeof (kw_t))) == NULL) {
-		nlog(LOG_ERR, "kw_add: cannot allocate for kw_t: %m");
-		free(b);
-		return (B_FALSE);
-	}
-	kw->kw_bssids.q_forw = kw->kw_bssids.q_back = &kw->kw_bssids;
-
-	b->bssid = strdup(bssid);
-	(void) strlcpy(kw->kw_essid, essid, sizeof (kw->kw_essid));
-	kw->kw_num_bssids = 1;
-
-	insque(&b->bssid_links, kw->kw_bssids.q_back);
-	insque(&kw->kw_links, kw_list.q_back);
+	/* ssid */
+	if ((err = nwam_known_wlan_get_prop_value(kwh,
+	    NWAM_KNOWN_WLAN_PROP_SSID, &ssidval)) != NWAM_SUCCESS)
+		return (NWAM_SUCCESS);
 
-	nlog(LOG_DEBUG, "kw_add: added Known WLAN %s, BSSID %s", essid, bssid);
-	return (B_TRUE);
-}
-
-/*
- * Add the BSSID to the given kw.  Since /etc/nwam/known_wifi_nets is
- * populated such that the wifi networks visited later are towards the end
- * of the file, remove the give kw from its current position and append it
- * to the end of kw_list.  This ensures that kw_list is in the reverse
- * order of visited wifi networks.  Returns B_TRUE on success.
- */
-static boolean_t
-kw_update(kw_t *kw, const char *bssid)
-{
-	bssid_t *b;
-
-	if ((b = calloc(1, sizeof (bssid_t))) == NULL) {
-		nlog(LOG_ERR, "kw_update: cannot allocate for bssid_t: %m");
-		return (B_FALSE);
+	err = nwam_value_get_string(ssidval, &ssidstr);
+	if (err != NWAM_SUCCESS) {
+		nwam_value_free(ssidval);
+		return (NWAM_SUCCESS);
 	}
 
-	b->bssid = strdup(bssid);
-	insque(&b->bssid_links, kw->kw_bssids.q_back);
-	kw->kw_num_bssids++;
-
-	/* remove kw from current position */
-	remque(&kw->kw_links);
-	/* and insert at end */
-	insque(&kw->kw_links, kw_list.q_back);
-
-	nlog(LOG_DEBUG, "kw_update: appended BSSID %s to Known WLAN %s",
-	    bssid, kw->kw_essid);
-	return (B_TRUE);
-}
+	if (memcmp(ssidstr, mywlan->nww_essid, mywlan->nww_esslen) != 0) {
+		nwam_value_free(ssidval);
+		return (NWAM_SUCCESS);
+	}
+	nwam_value_free(ssidval);
 
-/*
- * Parses /etc/nwam/known_wifi_nets and populates kw_list, with the oldest
- * wifi networks first in the list.  Returns the number of unique entries
- * in kw_list (to use for priority values).
- */
-static int
-parse_known_wifi_nets(void)
-{
-	FILE *fp;
-	char line[LINE_MAX];
-	char *cp, *tok[MAX_FIELDS];
-	int lnum, num_kw = 0;
-	kw_t *kw;
-
-	kw_list_init();
+	/* secmode <> secobjclass */
+	err = nwam_known_wlan_get_prop_value(kwh, NWAM_KNOWN_WLAN_PROP_KEYNAME,
+	    &keynameval);
+	if (mywlan->nww_security_mode == DLADM_WLAN_SECMODE_NONE &&
+	    err != NWAM_SUCCESS) {
+		goto valid;
+	} else if (err != NWAM_SUCCESS) {
+		return (NWAM_SUCCESS);
+	}
+	err = nwam_value_get_string(keynameval, &keynamestr);
+	if (err != NWAM_SUCCESS) {
+		nwam_value_free(keynameval);
+		return (NWAM_SUCCESS);
+	}
 
-	/*
-	 * The file format is:
-	 * essid\tbssid (essid followed by tab followed by bssid)
-	 */
-	fp = fopen(KNOWN_WIFI_NETS_FILE, "r");
-	if (fp == NULL)
-		return (0);
-	for (lnum = 1; fgets(line, sizeof (line), fp) != NULL; lnum++) {
+	{
+		secobj_class_info_t key_if;
 
-		cp = line;
-		while (isspace(*cp))
-			cp++;
-		if (*cp == '#' || *cp == '\0')
-			continue;
-
-		if (bufsplit(cp, MAX_FIELDS, tok) != MAX_FIELDS) {
-			syslog(LOG_ERR, "%s:%d: wrong number of tokens; "
-			    "ignoring entry", KNOWN_WIFI_NETS_FILE, lnum);
-			continue;
+		key_if.sc_name = keynamestr;
+		key_if.sc_dladmclass = 0;
+		if (dladm_walk_secobj(dld_handle, &key_if, find_matching_secobj,
+		    DLADM_OPT_PERSIST)) {
+			nwam_value_free(keynameval);
+			return (NWAM_SUCCESS);
 		}
 
-		if ((kw = kw_lookup(tok[ESSID])) == NULL) {
-			if (!kw_add(tok[ESSID], tok[BSSID])) {
-				nlog(LOG_ERR,
-				    "%s:%d: cannot add entry (%s,%s) to list",
-				    KNOWN_WIFI_NETS_FILE, lnum,
-				    tok[ESSID], tok[BSSID]);
-			} else {
-				num_kw++;
-			}
-		} else {
-			if (!kw_update(kw, tok[BSSID])) {
-				nlog(LOG_ERR,
-				    "%s:%d:cannot update entry (%s,%s) to list",
-				    KNOWN_WIFI_NETS_FILE, lnum,
-				    tok[ESSID], tok[BSSID]);
-			}
+		if (key_if.sc_dladmclass == 0) {
+			nwam_value_free(keynameval);
+			return (NWAM_SUCCESS);
 		}
-		/* next line ... */
+
+		if (!((key_if.sc_dladmclass == DLADM_SECOBJ_CLASS_PSK &&
+		    mywlan->nww_security_mode == DLADM_WLAN_SECMODE_PSK) ||
+		    (key_if.sc_dladmclass == DLADM_SECOBJ_CLASS_WEP &&
+		    mywlan->nww_security_mode == DLADM_WLAN_SECMODE_WEP) ||
+		    (key_if.sc_dladmclass >= DLADM_SECOBJ_CLASS_TLS &&
+		    mywlan->nww_security_mode == DLADM_WLAN_SECMODE_EAP))) {
+			nwam_value_free(keynameval);
+			return (NWAM_SUCCESS);
+		}
+		nwam_value_free(keynameval);
 	}
 
-	(void) fclose(fp);
-	return (num_kw);
+valid:
+	if ((err = nwam_known_wlan_get_name(kwh, &currnamestr)) !=
+	    NWAM_SUCCESS)
+		return (NWAM_SUCCESS);
+
+	currid = atoi(currnamestr);
+	free(currnamestr);
+
+	if (currid <= 0 || currid >= INT_MAX)
+		return (NWAM_SUCCESS);
+
+	mywlan->nww_wlanid = currid;
+
+	/* found known wlan, halt walk */
+	return (currid);
 }
 
-/*
- * Walk security objects looking for one that matches the essid prefix.
- * Store the key and keyname if a match is found - we use the last match
- * as the key for the known WLAN, since it is the most recently updated.
- */
-/* ARGSUSED0 */
-static boolean_t
-find_secobj_matching_prefix(dladm_handle_t dh, void *arg,
-    const char *secobjname)
-{
-	struct nwamd_secobj_arg *nsa = arg;
-
-	if (strncmp(nsa->nsa_essid_prefix, secobjname,
-	    strlen(nsa->nsa_essid_prefix)) == 0) {
-		nlog(LOG_DEBUG, "find_secobj_matching_prefix: "
-		    "found secobj with prefix %s : %s\n",
-		    nsa->nsa_essid_prefix, secobjname);
-		/* Free last key found (if any) */
-		if (nsa->nsa_key != NULL)
-			free(nsa->nsa_key);
-		/* Retrive key so we can get security mode */
-		nsa->nsa_key = nwamd_wlan_get_key_named(secobjname, 0);
-		(void) strlcpy(nsa->nsa_keyname, secobjname,
-		    sizeof (nsa->nsa_keyname));
-		switch (nsa->nsa_key->wk_class) {
-		case DLADM_SECOBJ_CLASS_WEP:
-			nsa->nsa_secmode = DLADM_WLAN_SECMODE_WEP;
-			nlog(LOG_DEBUG, "find_secobj_matching_prefix: "
-			    "got WEP key %s", nsa->nsa_keyname);
-			break;
-		case DLADM_SECOBJ_CLASS_WPA:
-			nsa->nsa_secmode = DLADM_WLAN_SECMODE_WPA;
-			nlog(LOG_DEBUG, "find_secobj_matching_prefix: "
-			    "got WPA key %s", nsa->nsa_keyname);
-			break;
-		default:
-			/* shouldn't happen */
-			nsa->nsa_secmode = DLADM_WLAN_SECMODE_NONE;
-			nlog(LOG_ERR, "find_secobj_matching_prefix: "
-			    "key class for key %s was invalid",
-			    nsa->nsa_keyname);
-			break;
-		}
-	}
-	return (B_TRUE);
-}
-
-
-/* Upgrade /etc/nwam/known_wifi_nets file to new libnwam-based config model */
-void
-upgrade_known_wifi_nets_config(void)
-{
-	kw_t *kw;
-	bssid_t *b;
-	nwam_known_wlan_handle_t kwh;
-	char **bssids;
-	nwam_error_t err;
-	uint64_t priority;
-	int i, num_kw;
-	struct nwamd_secobj_arg nsa;
-
-	nlog(LOG_INFO, "Upgrading %s to Known WLANs", KNOWN_WIFI_NETS_FILE);
-
-	/* Parse /etc/nwam/known_wifi_nets */
-	num_kw = parse_known_wifi_nets();
-
-	/* Create Known WLANs for each unique ESSID */
-	for (kw = (kw_t *)kw_list.q_forw, priority = num_kw-1;
-	    kw != (kw_t *)&kw_list;
-	    kw = (kw_t *)kw->kw_links.q_forw, priority--) {
-		nwam_value_t priorityval = NULL;
-		nwam_value_t bssidsval = NULL;
-		nwam_value_t secmodeval = NULL;
-		nwam_value_t keynameval = NULL;
-
-		nlog(LOG_DEBUG, "Creating Known WLAN %s", kw->kw_essid);
-
-		if ((err = nwam_known_wlan_create(kw->kw_essid, &kwh))
-		    != NWAM_SUCCESS) {
-			nlog(LOG_ERR, "upgrade wlan %s: "
-			    "could not create known wlan: %s", kw->kw_essid,
-			    nwam_strerror(err));
-			continue;
-		}
-
-		/* priority of this ESSID */
-		if ((err = nwam_value_create_uint64(priority, &priorityval))
-		    != NWAM_SUCCESS) {
-			nlog(LOG_ERR, "upgrade wlan %s: "
-			    "could not create priority value: %s", kw->kw_essid,
-			    nwam_strerror(err));
-			nwam_known_wlan_free(kwh);
-			continue;
-		}
-		err = nwam_known_wlan_set_prop_value(kwh,
-		    NWAM_KNOWN_WLAN_PROP_PRIORITY, priorityval);
-		nwam_value_free(priorityval);
-		if (err != NWAM_SUCCESS) {
-			nlog(LOG_ERR, "upgrade wlan %s: "
-			    "could not set priority value: %s", kw->kw_essid,
-			    nwam_strerror(err));
-			nwam_known_wlan_free(kwh);
-			continue;
-		}
-
-		/* loop through kw->kw_bssids and create an array of bssids */
-		bssids = calloc(kw->kw_num_bssids, sizeof (char *));
-		if (bssids == NULL) {
-			nwam_known_wlan_free(kwh);
-			nlog(LOG_ERR, "upgrade wlan %s: "
-			    "could not calloc for bssids: %m", kw->kw_essid);
-			continue;
-		}
-		for (b = (bssid_t *)kw->kw_bssids.q_forw, i = 0;
-		    b != (bssid_t *)&kw->kw_bssids;
-		    b = (bssid_t *)b->bssid_links.q_forw, i++) {
-			bssids[i] = strdup(b->bssid);
-		}
-
-		/* BSSIDs for this ESSID */
-		if ((err = nwam_value_create_string_array(bssids,
-		    kw->kw_num_bssids, &bssidsval)) != NWAM_SUCCESS) {
-			nlog(LOG_ERR, "upgrade wlan %s: "
-			    "could not create bssids value: %s", kw->kw_essid,
-			    nwam_strerror(err));
-			for (i = 0; i < kw->kw_num_bssids; i++)
-				free(bssids[i]);
-			free(bssids);
-			nwam_known_wlan_free(kwh);
-			continue;
-		}
-		err = nwam_known_wlan_set_prop_value(kwh,
-		    NWAM_KNOWN_WLAN_PROP_BSSIDS, bssidsval);
-		nwam_value_free(bssidsval);
-		for (i = 0; i < kw->kw_num_bssids; i++)
-			free(bssids[i]);
-		free(bssids);
-		if (err != NWAM_SUCCESS) {
-			nlog(LOG_ERR, "upgrade wlan %s: "
-			    "could not set bssids: %s", kw->kw_essid,
-			    nwam_strerror(err));
-			nwam_known_wlan_free(kwh);
-			continue;
-		}
-
-		/*
-		 * Retrieve last key matching ESSID prefix if any, and set
-		 * the retrieved key name and security mode.
-		 */
-		nwamd_set_key_name(kw->kw_essid, NULL, nsa.nsa_essid_prefix,
-		    sizeof (nsa.nsa_essid_prefix));
-		nsa.nsa_key = NULL;
-		nsa.nsa_secmode = DLADM_WLAN_SECMODE_NONE;
-		(void) dladm_walk_secobj(dld_handle, &nsa,
-		    find_secobj_matching_prefix, DLADM_OPT_PERSIST);
-		if (nsa.nsa_key != NULL) {
-			if ((err = nwam_value_create_string(nsa.nsa_keyname,
-			    &keynameval)) == NWAM_SUCCESS) {
-				(void) nwam_known_wlan_set_prop_value(kwh,
-				    NWAM_KNOWN_WLAN_PROP_KEYNAME, keynameval);
-			}
-			free(nsa.nsa_key);
-			nwam_value_free(keynameval);
-		}
-
-		if ((err = nwam_value_create_uint64(nsa.nsa_secmode,
-		    &secmodeval)) != NWAM_SUCCESS ||
-		    (err = nwam_known_wlan_set_prop_value(kwh,
-		    NWAM_KNOWN_WLAN_PROP_SECURITY_MODE, secmodeval))
-		    != NWAM_SUCCESS) {
-			nlog(LOG_ERR, "upgrade wlan %s: "
-			    "could not set security mode: %s",
-			    kw->kw_essid, nwam_strerror(err));
-			nwam_value_free(secmodeval);
-			nwam_known_wlan_free(kwh);
-			continue;
-		}
-
-		/* commit, no collision checking by libnwam */
-		err = nwam_known_wlan_commit(kwh,
-		    NWAM_FLAG_KNOWN_WLAN_NO_COLLISION_CHECK);
-		nwam_known_wlan_free(kwh);
-		if (err != NWAM_SUCCESS) {
-			nlog(LOG_ERR, "upgrade wlan %s: "
-			    "could not commit wlan: %s", kw->kw_essid,
-			    nwam_strerror(err));
-		}
-		/* next ... */
-	}
-
-	kw_list_free();
-}
-
-nwam_error_t
-known_wlan_get_keyname(const char *essid, char *name)
-{
-	nwam_known_wlan_handle_t kwh = NULL;
-	nwam_value_t keynameval = NULL;
-	char *keyname;
-	nwam_error_t err;
-
-	if ((err = nwam_known_wlan_read(essid, 0, &kwh)) != NWAM_SUCCESS)
-		return (err);
-	if ((err = nwam_known_wlan_get_prop_value(kwh,
-	    NWAM_KNOWN_WLAN_PROP_KEYNAME, &keynameval)) == NWAM_SUCCESS &&
-	    (err = nwam_value_get_string(keynameval, &keyname))
-	    == NWAM_SUCCESS) {
-		(void) strlcpy(name, keyname, NWAM_MAX_VALUE_LEN);
-	}
-	if (keynameval != NULL)
-		nwam_value_free(keynameval);
-
-	if (kwh != NULL)
-		nwam_known_wlan_free(kwh);
-
-	return (err);
-}
-
-/* Performs a scan on a wifi link NCU */
 /* ARGSUSED */
 static int
 nwamd_ncu_known_wlan_committed(nwamd_object_t object, void *data)
 {
 	nwamd_ncu_t *ncu_data = object->nwamd_object_data;
+	dladm_status_t status;
+	struct wpa_ctrl *ctrl_conn = NULL;
+	char *reconf[] = {"RECONFIGURE"};
 
-	if (ncu_data->ncu_type != NWAM_NCU_TYPE_LINK)
+	if (ncu_data->ncu_type != NWAM_NCU_TYPE_LINK ||
+	    ncu_data->ncu_link.nwamd_link_media != DL_WIFI ||
+	    (object->nwamd_object_state != NWAM_STATE_OFFLINE &&
+	    object->nwamd_object_state != NWAM_STATE_INITIALIZED))
 		return (0);
 
-	/* network selection will be done only if possible */
-	if (ncu_data->ncu_link.nwamd_link_media == DL_WIFI)
-		(void) nwamd_wlan_scan(ncu_data->ncu_name);
+	status = dladm_wlan_validate(dld_handle,
+	    ncu_data->ncu_link.nwamd_link_id, &ctrl_conn, NULL);
+	if (status != DLADM_STATUS_OK) {
+		nlog(LOG_ERR, "nwamd_ncu_known_wlan_committed(%s): wpa_s ctrl "
+		    "interface is down (%d)", ncu_data->ncu_name, status);
+		return (-1);
+	}
+
+	if (wpa_request(ctrl_conn, 1, reconf)) {
+		nlog(LOG_ERR, "nwamd_ncu_known_wlan_committed(%s): failed wpa_s"
+		    "reconfiguration", ncu_data->ncu_name);
+		wpa_ctrl_close(ctrl_conn);
+		return (-1);
+	}
+
+	wpa_ctrl_close(ctrl_conn);
 	return (0);
 }
 
@@ -485,8 +200,10 @@
 nwamd_known_wlan_handle_init_event(nwamd_event_t known_wlan_event)
 {
 	/*
-	 * Since the Known WLAN list has changed, do a rescan so that the
-	 * best network is selected.
+	 * Since the Known WLAN list has changed, do a reconfigure so that the
+	 * best network is selected. If the known wlan is destroyed by nwamd or
+	 * by the user we need to propagate new known wlan list to wpa_s
+	 * configuration as well.
 	 */
 	(void) nwamd_walk_objects(NWAM_OBJECT_TYPE_NCU,
 	    nwamd_ncu_known_wlan_committed, NULL);
@@ -499,14 +216,11 @@
 	    nwe_action) {
 	case NWAM_ACTION_ADD:
 	case NWAM_ACTION_REFRESH:
+	case NWAM_ACTION_DESTROY:
+	case NWAM_ACTION_ENABLE:
+	case NWAM_ACTION_DISABLE:
 		nwamd_known_wlan_handle_init_event(known_wlan_event);
 		break;
-	case NWAM_ACTION_DESTROY:
-		/* Nothing needs to be done for destroy */
-		break;
-	/* all other events are invalid for known WLANs */
-	case NWAM_ACTION_ENABLE:
-	case NWAM_ACTION_DISABLE:
 	default:
 		nlog(LOG_INFO, "nwam_known_wlan_handle_action_event: "
 		    "unexpected action");
@@ -518,7 +232,7 @@
 nwamd_known_wlan_action(const char *known_wlan, nwam_action_t action)
 {
 	nwamd_event_t known_wlan_event = nwamd_event_init_object_action
-	    (NWAM_OBJECT_TYPE_KNOWN_WLAN, known_wlan, NULL, action);
+		(NWAM_OBJECT_TYPE_KNOWN_WLAN, known_wlan, NULL, action);
 	if (known_wlan_event == NULL)
 		return (1);
 	nwamd_event_enqueue(known_wlan_event);
--- a/usr/src/cmd/cmd-inet/lib/nwamd/known_wlans.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/known_wlans.h	Wed May 29 08:31:24 2013 +0200
@@ -22,16 +22,13 @@
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #ifndef _KNOWN_WLANS_H
 #define	_KNOWN_WLANS_H
 
 #include <libnwam.h>
-#include <syslog.h>
 
-void upgrade_known_wifi_nets_config(void);
-nwam_error_t known_wlan_get_keyname(const char *, char *);
-nwam_error_t known_wlan_get_keyslot(const char *, uint_t *);
-
+int find_matching_wlan_cb(nwam_known_wlan_handle_t, void *);
 #endif /* _KNOWN_WLANS_H */
--- a/usr/src/cmd/cmd-inet/lib/nwamd/llp.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/llp.c	Wed May 29 08:31:24 2013 +0200
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 /*
@@ -39,7 +40,6 @@
 #include <strings.h>
 
 #include <libnwam.h>
-#include "known_wlans.h"
 #include "llp.h"
 #include "ncu.h"
 #include "util.h"
@@ -488,9 +488,6 @@
 		(void) pthread_mutex_unlock(&active_ncp_mutex);
 	}
 
-	/* upgrade /etc/nwam/known_wifi_nets */
-	upgrade_known_wifi_nets_config();
-
 	/*
 	 * SMF property nwamd/dhcp_wait_time in Phase 0/0.5 has been
 	 * replaced by nwamd/ncu_wait_time property.  If the dhcp_wait_time
--- a/usr/src/cmd/cmd-inet/lib/nwamd/loc.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/loc.c	Wed May 29 08:31:24 2013 +0200
@@ -21,16 +21,13 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #include <arpa/inet.h>
 #include <errno.h>
 #include <inet/ip.h>
-#include <libdladm.h>
-#include <libdllink.h>
-#include <libdlwlan.h>
 #include <libscf.h>
-#include <limits.h>
 #include <netdb.h>
 #include <netinet/in.h>
 #include <stdio.h>
--- a/usr/src/cmd/cmd-inet/lib/nwamd/main.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/main.c	Wed May 29 08:31:24 2013 +0200
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #include <errno.h>
@@ -181,7 +182,7 @@
 
 	(void) pthread_attr_init(&attr);
 	(void) pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-	if (err = pthread_create(&sighand, &attr, sighandler, NULL)) {
+	if ((err = pthread_create(&sighand, &attr, sighandler, NULL)) != 0) {
 		nlog(LOG_ERR, "pthread_create system: %s", strerror(err));
 		exit(EXIT_FAILURE);
 	} else {
@@ -220,14 +221,9 @@
 lookup_daemon_properties(void)
 {
 	char *active_ncp_tmp;
-	char *scan_level_tmp;
 
 	(void) nwamd_lookup_boolean_property(OUR_FMRI, OUR_PG,
 	    OUR_DEBUG_PROP_NAME, &debug);
-	(void) nwamd_lookup_boolean_property(OUR_FMRI, OUR_PG,
-	    OUR_AUTOCONF_PROP_NAME, &wireless_autoconf);
-	(void) nwamd_lookup_boolean_property(OUR_FMRI, OUR_PG,
-	    OUR_STRICT_BSSID_PROP_NAME, &wireless_strict_bssid);
 
 	(void) pthread_mutex_lock(&active_ncp_mutex);
 	if ((active_ncp_tmp = malloc(NWAM_MAX_NAME_LEN)) == NULL ||
@@ -246,22 +242,6 @@
 	    &condition_check_interval) != 0)
 		condition_check_interval = CONDITION_CHECK_INTERVAL_DEFAULT;
 
-	if ((scan_level_tmp = malloc(NWAM_MAX_NAME_LEN)) == NULL ||
-	    nwamd_lookup_string_property(OUR_FMRI, OUR_PG,
-	    OUR_WIRELESS_SCAN_LEVEL_PROP_NAME, scan_level_tmp,
-	    NWAM_MAX_NAME_LEN) != 0) {
-		wireless_scan_level = WIRELESS_SCAN_LEVEL_DEFAULT;
-	} else {
-		if (dladm_wlan_str2strength(scan_level_tmp,
-		    &wireless_scan_level) != DLADM_STATUS_OK)
-			wireless_scan_level = DLADM_WLAN_STRENGTH_VERY_WEAK;
-	}
-	free(scan_level_tmp);
-
-	if (nwamd_lookup_count_property(OUR_FMRI, OUR_PG,
-	    OUR_WIRELESS_SCAN_INTERVAL_PROP_NAME, &wireless_scan_interval) != 0)
-		wireless_scan_interval = WIRELESS_SCAN_INTERVAL_DEFAULT;
-
 	if (nwamd_lookup_count_property(OUR_FMRI, OUR_PG,
 	    OUR_NCU_WAIT_TIME_PROP_NAME, &ncu_wait_time) != 0)
 		ncu_wait_time = NCU_WAIT_TIME_DEFAULT;
--- a/usr/src/cmd/cmd-inet/lib/nwamd/ncp.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/ncp.h	Wed May 29 08:31:24 2013 +0200
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #ifndef _NCP_H
@@ -28,7 +29,6 @@
 
 #include <libdladm.h>
 #include <libdlpi.h>
-#include <libdlwlan.h>
 #include <libnwam.h>
 #include <libuutil.h>
 #include <pthread.h>
--- a/usr/src/cmd/cmd-inet/lib/nwamd/ncu.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/ncu.c	Wed May 29 08:31:24 2013 +0200
@@ -21,13 +21,15 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #include <arpa/inet.h>
 #include <assert.h>
 #include <libdlaggr.h>
+#include <libdlstat.h>
 #include <libdllink.h>
-#include <libdlstat.h>
+#include <libdlwlan.h>
 #include <libnwam.h>
 #include <libscf.h>
 #include <netinet/in.h>
@@ -137,12 +139,10 @@
 {
 	nwamd_object_t object;
 	nwamd_ncu_t *ncu;
-	link_state_t link_state;
-	nwamd_event_t event;
-	nwam_wlan_t key_wlan, connected_wlan;
 	nwamd_link_t *link;
-	char linkname[NWAM_MAX_NAME_LEN];
+
 	boolean_t up;
+	boolean_t is_wireless;
 
 	if ((object = nwamd_object_find(NWAM_OBJECT_TYPE_NCU, object_name))
 	    == NULL) {
@@ -154,58 +154,34 @@
 	ncu = object->nwamd_object_data;
 	link = &ncu->ncu_link;
 
+	is_wireless = (link->nwamd_link_media == DL_WIFI);
+
 	switch (object->nwamd_object_aux_state) {
 	case NWAM_AUX_STATE_INITIALIZED:
 		if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) {
+			link_state_t link_state;
 			/*
 			 * For wired/wireless links, need to get link
-			 * up/down events and even if these are not supported,
-			 * dlpi_open()ing the link prevents the driver from
-			 * being unloaded.
+			 * up/down events.
 			 */
 			nwamd_dlpi_add_link(object);
 
-			if (link->nwamd_link_media == DL_WIFI) {
-				/*
-				 * First, if we're unexpectedly connected,
-				 * disconnect.
-				 */
-				if (!link->nwamd_link_wifi_connected &&
-				    nwamd_wlan_connected(object)) {
-					nlog(LOG_DEBUG,
-					    "nwamd_ncu_state_machine: "
-					    "WiFi unexpectedly connected, "
-					    "disconnecting...");
-					(void) dladm_wlan_disconnect(dld_handle,
-					    link->nwamd_link_id);
-					nwamd_set_selected_connected(ncu,
-					    B_FALSE, B_FALSE);
-				}
-				/* move to scanning aux state */
+			/*
+			 * If initial link state is unknown, we
+			 * will need to assume the link is up, since
+			 * we will not get DL_NOTE_LINK_UP/DOWN events.
+			 */
+			link_state = nwamd_get_link_state(ncu->ncu_name);
+			if (link_state == LINK_STATE_UP ||
+			    (link_state == LINK_STATE_UNKNOWN &&
+			    !is_wireless)) {
 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
-				    object_name, object->nwamd_object_state,
-				    NWAM_AUX_STATE_LINK_WIFI_SCANNING);
+				    object_name, NWAM_STATE_ONLINE,
+				    NWAM_AUX_STATE_UP);
 			} else {
-				/*
-				 * If initial wired link state is unknown, we
-				 * will need to assume the link is up, since
-				 * we won´t get DL_NOTE_LINK_UP/DOWN events.
-				 */
-				link_state = nwamd_get_link_state
-				    (ncu->ncu_name);
-				if (link_state == LINK_STATE_UP ||
-				    link_state == LINK_STATE_UNKNOWN) {
-					nwamd_object_set_state
-					    (NWAM_OBJECT_TYPE_NCU,
-					    object_name, NWAM_STATE_ONLINE,
-					    NWAM_AUX_STATE_UP);
-				} else {
-					nwamd_object_set_state
-					    (NWAM_OBJECT_TYPE_NCU,
-					    object_name,
-					    NWAM_STATE_ONLINE_TO_OFFLINE,
-					    NWAM_AUX_STATE_DOWN);
-				}
+				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
+				    object_name, NWAM_STATE_ONLINE_TO_OFFLINE,
+				    NWAM_AUX_STATE_DOWN);
 			}
 		} else {
 			/*
@@ -261,117 +237,84 @@
 		 */
 		break;
 
-	case NWAM_AUX_STATE_LINK_WIFI_SCANNING:
-		/* launch scan thread */
-		(void) strlcpy(linkname, ncu->ncu_name, sizeof (linkname));
-		(void) nwamd_wlan_scan(linkname);
-		/* Create periodic scan event */
-		nwamd_ncu_create_periodic_scan_event(object);
-		break;
-
-	case NWAM_AUX_STATE_LINK_WIFI_NEED_SELECTION:
-		/* send "need choice" event */
-		event = nwamd_event_init_wlan
-		    (ncu->ncu_name, NWAM_EVENT_TYPE_WLAN_NEED_CHOICE, B_FALSE,
-		    link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr,
-		    link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr_num);
-		if (event == NULL)
-			break;
-		nwamd_event_enqueue(event);
-		nwamd_set_selected_connected(ncu, B_FALSE, B_FALSE);
+	case NWAM_AUX_STATE_LINK_WIFI_ASSOCIATED:
+		if (ncu->ncu_type == NWAM_NCU_TYPE_LINK && is_wireless &&
+		    ncu->ncu_enabled) {
+			nwamd_event_t assoc_event;
+			assoc_event = nwamd_event_init_wlan(ncu->ncu_name,
+			    NWAM_EVENT_TYPE_WLAN_ASSOCIATION_REPORT,
+			    &link->nwamd_link_wifi_wlan, 1);
+			if (assoc_event == NULL) {
+				nlog(LOG_ERR, "nwamd_ncu_state_machine(%s): "
+				    "failed to init wlan association report",
+				    ncu->ncu_name);
+			} else
+				nwamd_event_enqueue(assoc_event);
+		}
 		break;
 
-	case NWAM_AUX_STATE_LINK_WIFI_NEED_KEY:
-		/*
-		 * Send "need key" event.  Set selected to true, connected
-		 * and have_key to false.  Do not fill in WLAN details as
-		 * multiple WLANs may match the ESSID name, and each may
-		 * have a different speed and channel.
-		 */
-		bzero(&key_wlan, sizeof (key_wlan));
-		(void) strlcpy(key_wlan.nww_essid, link->nwamd_link_wifi_essid,
-		    sizeof (key_wlan.nww_essid));
-		(void) strlcpy(key_wlan.nww_bssid, link->nwamd_link_wifi_bssid,
-		    sizeof (key_wlan.nww_bssid));
-		key_wlan.nww_security_mode =
-		    link->nwamd_link_wifi_security_mode;
-		key_wlan.nww_selected = B_TRUE;
-		key_wlan.nww_connected = B_FALSE;
-		key_wlan.nww_have_key = B_FALSE;
-		event = nwamd_event_init_wlan
-		    (ncu->ncu_name, NWAM_EVENT_TYPE_WLAN_NEED_KEY, B_FALSE,
-		    &key_wlan, 1);
-		if (event == NULL)
-			break;
-		nwamd_event_enqueue(event);
-		break;
-
-	case NWAM_AUX_STATE_LINK_WIFI_CONNECTING:
-		(void) strlcpy(linkname, ncu->ncu_name, sizeof (linkname));
-		nwamd_wlan_connect(linkname);
+	case NWAM_AUX_STATE_LINK_WIFI_CONNECTED:
+		if (ncu->ncu_type == NWAM_NCU_TYPE_LINK && is_wireless &&
+		    ncu->ncu_enabled) {
+			if (nwamd_wlan_connected(object) &&
+			    link->nwamd_link_wifi_wlan.nww_wlanid == 0) {
+				nwam_error_t err;
+				const char *invalid_prop;
+				nlog(LOG_DEBUG, "nwamd_ncu_state_machine: "
+				    "adding '%s' to known WLANs",
+				    link->nwamd_link_wifi_wlan.nww_essid);
+				err = nwam_known_wlan_add_to_known_wlans
+				    (dld_handle, &link->nwamd_link_wifi_wlan,
+				    link->nwamd_link_wifi_key,
+				    link->nwamd_link_wifi_eap, &invalid_prop);
+				if (err != NWAM_SUCCESS) {
+					nlog(LOG_ERR, "nwamd_ncu_state_machine:"
+					    " failed adding to known WLANs(%s)."
+					    " Invalid Prop: %s",
+					    nwam_strerror(err),
+					    invalid_prop ? invalid_prop : "");
+				} else {
+					/* update scan result */
+					link->nwamd_link_wifi_scan.
+					    nwamd_wifi_sres[link->
+					    nwamd_link_wifi_wlan.nww_scanid].
+					    nww_wlanid = link->
+					    nwamd_link_wifi_wlan.nww_wlanid;
+				}
+			}
+			nlog(LOG_DEBUG, "nwamd_ncu_state_machine: connect "
+			    "succeeded, setting link state online");
+			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
+			    object_name, NWAM_STATE_ONLINE, NWAM_AUX_STATE_UP);
+		}
 		break;
 
 	case NWAM_AUX_STATE_UP:
 	case NWAM_AUX_STATE_DOWN:
 		up = (object->nwamd_object_aux_state == NWAM_AUX_STATE_UP);
-		if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) {
-			if (link->nwamd_link_media == DL_WIFI) {
-				/*
-				 * Connected/disconnected - send WLAN
-				 * connection report.
-				 */
-				link->nwamd_link_wifi_connected = up;
-				nwamd_set_selected_connected(ncu, B_TRUE, up);
 
-				(void) strlcpy(connected_wlan.nww_essid,
-				    link->nwamd_link_wifi_essid,
-				    sizeof (connected_wlan.nww_essid));
-				(void) strlcpy(connected_wlan.nww_bssid,
-				    link->nwamd_link_wifi_bssid,
-				    sizeof (connected_wlan.nww_bssid));
-				connected_wlan.nww_security_mode =
-				    link->nwamd_link_wifi_security_mode;
-				event = nwamd_event_init_wlan
-				    (ncu->ncu_name,
-				    NWAM_EVENT_TYPE_WLAN_CONNECTION_REPORT, up,
-				    &connected_wlan, 1);
-				if (event == NULL)
-					break;
-				nwamd_event_enqueue(event);
+		if (ncu->ncu_type == NWAM_NCU_TYPE_LINK && !up && is_wireless &&
+		    (object->nwamd_object_state ==
+		    NWAM_STATE_OFFLINE_TO_ONLINE ||
+		    object->nwamd_object_state ==
+		    NWAM_STATE_ONLINE_TO_OFFLINE)) {
+			dladm_status_t status;
+			struct wpa_ctrl *ctrl_conn = NULL;
+			char *reconf[] = {"RECONFIGURE"};
 
-				/*
-				 * If disconnected, restart the state machine
-				 * for the WiFi link (WiFi is always trying
-				 * to connect).
-				 *
-				 * If connected, start signal strength
-				 * monitoring thread.
-				 */
-				if (!up && ncu->ncu_enabled) {
-					nlog(LOG_DEBUG,
-					    "nwamd_ncu_state_machine: "
-					    "wifi disconnect - start over "
-					    "after %dsec interval",
-					    WIRELESS_RETRY_INTERVAL);
-					link->nwamd_link_wifi_connected =
-					    B_FALSE;
-					/* propogate down event to IP NCU */
-					nwamd_propogate_link_up_down_to_ip
-					    (ncu->ncu_name, B_FALSE);
-					nwamd_object_set_state_timed
-					    (NWAM_OBJECT_TYPE_NCU, object_name,
-					    NWAM_STATE_OFFLINE_TO_ONLINE,
-					    NWAM_AUX_STATE_INITIALIZED,
-					    WIRELESS_RETRY_INTERVAL);
-				} else {
-					nlog(LOG_DEBUG,
-					    "nwamd_ncu_state_machine: "
-					    "wifi connected, start monitoring");
-					(void) strlcpy(linkname, ncu->ncu_name,
-					    sizeof (linkname));
-					nwamd_wlan_monitor_signal(linkname);
-				}
+			status = dladm_wlan_validate(dld_handle,
+			    link->nwamd_link_id, &ctrl_conn, NULL);
+			if (status != DLADM_STATUS_OK) {
+				nlog(LOG_ERR, "nwamd_ncu_state_machine(%s): "
+				    "err connecting to wpa_s ctrlif (%d)",
+				    ncu->ncu_name, status);
 			}
+
+			if (wpa_request(ctrl_conn, 1, reconf)) {
+				nlog(LOG_ERR, "nwamd_ncu_state_machine(%s): err"
+				    " reconfiguring wpa_s", ncu->ncu_name);
+			}
+			wpa_ctrl_close(ctrl_conn);
 		}
 
 		/* If not in ONLINE/OFFLINE state yet, change state */
@@ -420,19 +363,18 @@
 
 	case NWAM_AUX_STATE_CONDITIONS_NOT_MET:
 		/*
-		 * Link/interface is moving offline.  Nothing to do except
-		 * for WiFi, where we disconnect.  Don't unplumb IP on
-		 * a link since it may be a transient change.
+		 * Interface is moving offline.
+		 * Don't unplumb IP on a link since it may be a transient change
 		 */
-		if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) {
-			if (link->nwamd_link_media == DL_WIFI) {
-				(void) dladm_wlan_disconnect(dld_handle,
-				    link->nwamd_link_id);
-				link->nwamd_link_wifi_connected = B_FALSE;
-				nwamd_set_selected_connected(ncu, B_FALSE,
-				    B_FALSE);
-			}
-		} else {
+		if (ncu->ncu_type == NWAM_NCU_TYPE_LINK && is_wireless) {
+			dladm_status_t status;
+			status = dladm_wlan_disconnect(dld_handle,
+			    link->nwamd_link_id);
+			if (status != DLADM_STATUS_OK)
+				nlog(LOG_ERR, "nwamd_ncu_state_machine"
+				    "(%s): err removing wpa_s inst(%d)",
+				    ncu->ncu_name, status);
+		} else if (ncu->ncu_type == NWAM_NCU_TYPE_INTERFACE) {
 			/*
 			 * Unplumb here. In the future we may elaborate on
 			 * the approach used and not unplumb for WiFi
@@ -460,12 +402,14 @@
 		 * For WiFi links disconnect, and for IP interfaces we unplumb.
 		 */
 		if (ncu->ncu_type == NWAM_NCU_TYPE_LINK) {
-			if (link->nwamd_link_media == DL_WIFI) {
-				(void) dladm_wlan_disconnect(dld_handle,
+			if (is_wireless) {
+				dladm_status_t status;
+				status = dladm_wlan_disconnect(dld_handle,
 				    link->nwamd_link_id);
-				link->nwamd_link_wifi_connected = B_FALSE;
-				nwamd_set_selected_connected(ncu, B_FALSE,
-				    B_FALSE);
+				if (status != DLADM_STATUS_OK)
+					nlog(LOG_ERR, "nwamd_ncu_state_machine"
+					    "(%s): err removing wpa_s inst(%d)",
+					    ncu->ncu_name, status);
 			}
 			nwamd_dlpi_delete_link(object);
 		} else {
@@ -1082,7 +1026,6 @@
 		    &rv->ncu_link.nwamd_link_media);
 		(void) pthread_mutex_init(
 		    &rv->ncu_link.nwamd_link_wifi_mutex, NULL);
-		rv->ncu_link.nwamd_link_wifi_priority = MAXINT;
 	} else {
 		(void) bzero(&rv->ncu_if, sizeof (nwamd_if_t));
 	}
@@ -1101,6 +1044,8 @@
 			int i;
 
 			free(l->nwamd_link_wifi_key);
+			free(l->nwamd_link_wifi_eap);
+			free(l->nwamd_link_wifi_scan.nwamd_wifi_sres);
 			free(l->nwamd_link_mac_addr);
 			for (i = 0; i < l->nwamd_link_num_autopush; i++)
 				free(l->nwamd_link_autopush[i]);
@@ -1247,7 +1192,6 @@
 	/* IP NCU has the default values, so nothing else to do */
 	err = nwam_ncu_commit(ncuh, 0);
 
-finish:
 	nwam_ncu_free(ncuh);
 	if (err != NWAM_SUCCESS) {
 		nlog(LOG_ERR,
@@ -1754,48 +1698,39 @@
 				    NWAM_AUX_STATE_MANUAL_DISABLE);
 			}
 			goto done;
-		} else {
-			if (object->nwamd_object_state == NWAM_STATE_DISABLED) {
-				int64_t c;
+		} else if (object->nwamd_object_state == NWAM_STATE_DISABLED) {
+			int64_t c;
 
-				/*
-				 * Try to activate the NCU if manual or
-				 * prioritized (when priority <= current).
-				 */
-				(void) pthread_mutex_lock(&active_ncp_mutex);
-				c = current_ncu_priority_group;
-				(void) pthread_mutex_unlock(&active_ncp_mutex);
-				if (link->nwamd_link_activation_mode ==
-				    NWAM_ACTIVATION_MODE_MANUAL ||
-				    (link->nwamd_link_activation_mode ==
-				    NWAM_ACTIVATION_MODE_PRIORITIZED &&
-				    link->nwamd_link_priority_mode <= c)) {
-					nwamd_object_set_state
-					    (NWAM_OBJECT_TYPE_NCU,
-					    object->nwamd_object_name,
-					    NWAM_STATE_OFFLINE_TO_ONLINE,
-					    NWAM_AUX_STATE_INITIALIZED);
-				} else {
-					nwamd_object_set_state
-					    (NWAM_OBJECT_TYPE_NCU,
-					    object->nwamd_object_name,
-					    NWAM_STATE_OFFLINE_TO_ONLINE,
-					    NWAM_AUX_STATE_INITIALIZED);
-				}
-				goto done;
+			/*
+			 * Try to activate the NCU if manual or
+			 * prioritized (when priority <= current).
+			 */
+			(void) pthread_mutex_lock(&active_ncp_mutex);
+			c = current_ncu_priority_group;
+			(void) pthread_mutex_unlock(&active_ncp_mutex);
+			if (link->nwamd_link_activation_mode ==
+			    NWAM_ACTIVATION_MODE_MANUAL ||
+			    (link->nwamd_link_activation_mode ==
+			    NWAM_ACTIVATION_MODE_PRIORITIZED &&
+			    link->nwamd_link_priority_mode <= c)) {
+				nwamd_object_set_state
+				    (NWAM_OBJECT_TYPE_NCU,
+				    object->nwamd_object_name,
+				    NWAM_STATE_OFFLINE_TO_ONLINE,
+				    NWAM_AUX_STATE_INITIALIZED);
+			} else {
+				/* wrong logic ?? */
+				nwamd_object_set_state
+				    (NWAM_OBJECT_TYPE_NCU,
+				    object->nwamd_object_name,
+				    NWAM_STATE_OFFLINE,
+				    NWAM_AUX_STATE_INITIALIZED);
 			}
+			goto done;
 		}
 
 		switch (type) {
 		case NWAM_NCU_TYPE_LINK:
-			if (ncu->ncu_link.nwamd_link_media == DL_WIFI) {
-				/*
-				 * Do rescan.  If the current state and the
-				 * active priority-group do not allow wireless
-				 * network selection, then it won't happen.
-				 */
-				(void) nwamd_wlan_scan(ncu->ncu_name);
-			}
 			break;
 		case NWAM_NCU_TYPE_INTERFACE:
 			/*
@@ -1814,6 +1749,8 @@
 				    NWAM_AUX_STATE_CONDITIONS_NOT_MET;
 			}
 			break;
+		default:
+			break;
 		}
 	}
 
@@ -2035,6 +1972,7 @@
 	 * State machine for NCUs
 	 */
 	switch (new_state) {
+	case NWAM_STATE_ONLINE:
 	case NWAM_STATE_OFFLINE_TO_ONLINE:
 		if (enabled) {
 			nwamd_ncu_state_machine(event->event_object);
@@ -2050,15 +1988,6 @@
 		nwamd_ncu_state_machine(event->event_object);
 		break;
 
-	case NWAM_STATE_ONLINE:
-		/*
-		 * We usually don't need to do anything when we're in the
-		 * ONLINE state.  However, for  WiFi we can be in INIT or
-		 * SCAN aux states while being ONLINE.
-		 */
-		nwamd_ncu_state_machine(event->event_object);
-		break;
-
 	case NWAM_STATE_OFFLINE:
 		/* Reassess priority group now member is offline */
 		if (prioritized) {
--- a/usr/src/cmd/cmd-inet/lib/nwamd/ncu.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/ncu.h	Wed May 29 08:31:24 2013 +0200
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #ifndef _NCU_H
@@ -28,9 +29,6 @@
 
 #include <dhcpagent_ipc.h>
 #include <dhcpagent_util.h>
-#include <libdladm.h>
-#include <libdlpi.h>
-#include <libdlwlan.h>
 #include <libinetutil.h>
 #include <libipadm.h>
 #include <libnwam.h>
@@ -44,10 +42,6 @@
 extern pthread_mutex_t active_ncp_mutex;
 extern pthread_mutex_t active_loc_mutex;
 extern char active_loc[];
-extern uint64_t wireless_scan_interval;
-extern dladm_wlan_strength_t wireless_scan_level;
-extern boolean_t wireless_autoconf;
-extern boolean_t wireless_strict_bssid;
 
 /*
  * NCPs are collections of NCUs.  At the moment there is one NCP in the system
@@ -71,30 +65,18 @@
 
 /* Stores details of last/current WiFi scans */
 typedef struct nwamd_wifi_scan {
-	char nwamd_wifi_scan_link[NWAM_MAX_NAME_LEN];
-	nwam_wlan_t nwamd_wifi_scan_last[NWAMD_MAX_NUM_WLANS];
-	uint_t nwamd_wifi_scan_last_num;
-	nwam_wlan_t nwamd_wifi_scan_curr[NWAMD_MAX_NUM_WLANS];
-	uint_t nwamd_wifi_scan_curr_num;
-	boolean_t nwamd_wifi_scan_changed;
-	uint32_t nwamd_wifi_scan_last_time;
+	uint_t nwamd_wifi_sres_num;
+	nwam_wlan_t *nwamd_wifi_sres;
 } nwamd_wifi_scan_t;
 
 typedef struct nwamd_link {
 	pthread_mutex_t nwamd_link_wifi_mutex;
 	pthread_t nwamd_link_wifi_scan_thread;
 	pthread_t nwamd_link_wifi_monitor_thread;
-	char nwamd_link_wifi_essid[DLADM_STRSIZE];
-	char nwamd_link_wifi_bssid[DLADM_STRSIZE];
-	char nwamd_link_wifi_keyname[DLADM_STRSIZE];
-	char nwamd_link_wifi_signal_strength[DLADM_STRSIZE];
-	boolean_t nwamd_link_wifi_add_to_known_wlans;
-	boolean_t nwamd_link_wifi_connected;
-	uint32_t nwamd_link_wifi_security_mode;
+	nwam_wlan_t nwamd_link_wifi_wlan;
 	dladm_wlan_key_t *nwamd_link_wifi_key;
+	dladm_wlan_eap_t *nwamd_link_wifi_eap;
 	nwamd_wifi_scan_t nwamd_link_wifi_scan;
-	uint64_t nwamd_link_wifi_priority;
-	boolean_t nwamd_link_wifi_autoconf;
 	uint32_t nwamd_link_id;
 	uint32_t nwamd_link_media;
 	uint64_t nwamd_link_flags;
@@ -159,12 +141,6 @@
 	volatile uint32_t *guard;
 };
 
-#define	WIRELESS_SCAN_INTERVAL_DEFAULT		120
-#define	WIRELESS_SCAN_INTERVAL_MIN		30
-#define	WIRELESS_SCAN_REQUESTED_INTERVAL_MIN	10
-#define	WIRELESS_MONITOR_SIGNAL_INTERVAL	10
-#define	WIRELESS_RETRY_INTERVAL			30
-#define	WIRELESS_SCAN_LEVEL_DEFAULT		DLADM_WLAN_STRENGTH_WEAK
 #define	NWAMD_DHCP_RETRIES			5
 #define	NWAMD_DHCP_RETRY_WAIT_TIME		10
 #define	NWAMD_READONLY_RETRY_INTERVAL		5
@@ -181,18 +157,12 @@
 extern void nwamd_ncu_free(nwamd_ncu_t *);
 
 /* WLAN functions */
-extern void nwamd_set_selected_connected(nwamd_ncu_t *, boolean_t, boolean_t);
-extern nwam_error_t nwamd_wlan_select(const char *, const char *, const char *,
-    uint32_t, boolean_t);
-extern nwam_error_t nwamd_wlan_set_key(const char *, const char *, const char *,
-    uint32_t, uint_t, char *);
+extern nwam_error_t nwamd_wlan_select(const char *, const nwam_wlan_t *,
+    const dladm_wlan_key_t *, const dladm_wlan_eap_t *);
 extern nwam_error_t nwamd_wlan_scan(const char *);
+extern nwam_error_t nwamd_wlan_parse_scanres(const char *);
 extern void nwamd_wlan_connect(const char *);
 extern boolean_t nwamd_wlan_connected(nwamd_object_t);
-extern void nwamd_wlan_monitor_signal(const char *);
-extern void nwamd_ncu_create_periodic_scan_event(nwamd_object_t);
-extern dladm_wlan_key_t *nwamd_wlan_get_key_named(const char *, uint32_t);
-extern void nwamd_set_key_name(const char *, const char *, char *, size_t);
 
 /* Link functions */
 extern link_state_t nwamd_get_link_state(const char *);
--- a/usr/src/cmd/cmd-inet/lib/nwamd/ncu_ip.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/ncu_ip.c	Wed May 29 08:31:24 2013 +0200
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #include <arpa/inet.h>
@@ -147,7 +148,7 @@
 {
 	dhcp_symbol_t *entry;
 	dhcp_optnum_t optnum;
-	dhcp_ipc_request_t *request;
+	dhcp_ipc_request_t *request = NULL;
 	dhcp_ipc_reply_t *reply;
 	DHCP_OPT *opt;
 	size_t opt_len;
@@ -862,8 +863,9 @@
 	if (evm->nwe_data.nwe_if_state.nwe_addr_valid) {
 		struct nwam_event_if_state *if_state;
 		char addrstr[INET6_ADDRSTRLEN];
-		boolean_t static_addr, addr_added;
-		boolean_t v4dhcp_running, v6dhcp_running, stateless_running;
+		boolean_t static_addr = B_FALSE, addr_added;
+		boolean_t v4dhcp_running = B_FALSE, v6dhcp_running = B_FALSE;
+		boolean_t stateless_running = B_FALSE;
 		ipadm_addr_info_t *ai = NULL, *addrinfo = NULL;
 		boolean_t stateless_ai_found = B_FALSE;
 		boolean_t stateful_ai_found = B_FALSE;
--- a/usr/src/cmd/cmd-inet/lib/nwamd/ncu_phys.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/ncu_phys.c	Wed May 29 08:31:24 2013 +0200
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #include <assert.h>
@@ -29,12 +30,10 @@
 #include <errno.h>
 #include <execinfo.h>
 #include <kstat.h>
-#include <libdladm.h>
 #include <libdllink.h>
-#include <libdlstat.h>
 #include <libdlwlan.h>
 #include <libnwam.h>
-#include <limits.h>
+#include <libdlstat.h>
 #include <pthread.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -50,9 +49,9 @@
 #include "events.h"
 #include "llp.h"
 #include "objects.h"
+#include "known_wlans.h"
 #include "ncp.h"
 #include "ncu.h"
-#include "known_wlans.h"
 #include "util.h"
 
 /*
@@ -60,11 +59,33 @@
  * Mostly WiFi code.
  */
 
+#define	NEED_ENC(sec)	(sec > DLADM_WLAN_SECMODE_NONE && \
+			sec <= DLADM_WLAN_SECMODE_EAP)
+
+/*
+ * We need to ensure scan or connect threads do not run concurrently
+ * on any links - otherwise we get radio interference.  Acquire this
+ * lock on entering scan/connect threads to prevent this.
+ */
+pthread_mutex_t wireless_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+static void
+scanconnect_entry(void)
+{
+	(void) pthread_mutex_lock(&wireless_mutex);
+}
+
+static void
+scanconnect_exit(void)
+{
+	(void) pthread_mutex_unlock(&wireless_mutex);
+}
+
 /*
  * Get link state from kstats. Used to determine initial link state for
  * cases where drivers do not support DL_NOTE_LINK_UP/DOWN.  If link
- * state is LINK_STATE_UNKNOWN, we assume the link is up and the IP NCU
- * timeout will cause us to move on to other links.
+ * state is LINK_STATE_UNKNOWN and link is wired, we assume the link is up and
+ * the IP NCU timeout will cause us to move on to other links.
  */
 link_state_t
 nwamd_get_link_state(const char *name)
@@ -149,8 +170,8 @@
 	status = dladm_set_linkprop(dld_handle, ncu->ncu_link.nwamd_link_id,
 	    "mtu", &cp, 1, DLADM_OPT_ACTIVE);
 	if (status != DLADM_STATUS_OK) {
-		nlog(LOG_ERR, "nwamd_set_unset_link_properties: "
-		    "dladm_set_linkprop failed: %s",
+		nlog(LOG_ERR, "nwamd_set_unset_link_properties(%s): "
+		    "dladm_set_linkprop failed: %s", ncu->ncu_name,
 		    dladm_status2str(status, errmsg));
 	}
 
@@ -218,454 +239,6 @@
 	free(hwaddr);
 }
 
-#define	WLAN_ENC(sec)						\
-	((sec == DLADM_WLAN_SECMODE_WPA ? "WPA" : 		\
-	(sec == DLADM_WLAN_SECMODE_WEP ? "WEP" : "none")))
-
-#define	NEED_ENC(sec)						\
-	(sec == DLADM_WLAN_SECMODE_WPA || sec == DLADM_WLAN_SECMODE_WEP)
-
-#define	WIRELESS_LAN_INIT_COUNT	8
-
-/*
- * The variable wireless_scan_level specifies the signal level
- * that we will initiate connections to previously-visited APs
- * at when we are in the connected state.
- */
-dladm_wlan_strength_t wireless_scan_level = DLADM_WLAN_STRENGTH_WEAK;
-
-/*
- * The variable wireless_scan_interval specifies how often the periodic
- * scan occurs.
- */
-uint64_t wireless_scan_interval = WIRELESS_SCAN_INTERVAL_DEFAULT;
-
-/*
- * The variable wireless_autoconf specifies if we use dladm_wlan_autoconf()
- * to connect.
- */
-boolean_t wireless_autoconf = B_FALSE;
-
-/*
- * The variable wireless_strict_bssid specifies if we only connect
- * to WLANs with BSSIDs that we previously connected to.
- */
-boolean_t wireless_strict_bssid = B_FALSE;
-
-/*
- * We need to ensure scan or connect threads do not run concurrently
- * on any links - otherwise we get radio interference.  Acquire this
- * lock on entering scan/connect threads to prevent this.
- */
-pthread_mutex_t wireless_mutex = PTHREAD_MUTEX_INITIALIZER;
-
-static void
-scanconnect_entry(void)
-{
-	(void) pthread_mutex_lock(&wireless_mutex);
-}
-
-static void
-scanconnect_exit(void)
-{
-	(void) pthread_mutex_unlock(&wireless_mutex);
-}
-
-/*
- * Below are functions used to handle storage/retrieval of keys
- * for a given WLAN. The keys are stored/retrieved using dladm_set_secobj()
- * and dladm_get_secobj().
- */
-
-/*
- * Convert key hexascii string to raw secobj value. This
- * code is very similar to convert_secobj() in dladm.c, it would
- * be good to have a libdladm function to convert values.
- */
-static int
-key_string_to_secobj_value(char *buf, uint8_t *obj_val, uint_t *obj_lenp,
-    dladm_secobj_class_t class)
-{
-	size_t buf_len = strlen(buf);
-
-	nlog(LOG_DEBUG, "before: key_string_to_secobj_value: buf_len = %d",
-	    buf_len);
-	if (buf_len == 0) {
-		/* length zero means "delete" */
-		return (0);
-	}
-
-	if (buf[buf_len - 1] == '\n')
-		buf[--buf_len] = '\0';
-
-	nlog(LOG_DEBUG, "after: key_string_to_secobj_value: buf_len = %d",
-	    buf_len);
-
-	if (class == DLADM_SECOBJ_CLASS_WPA) {
-		/*
-		 * Per IEEE802.11i spec, the Pre-shared key (PSK) length should
-		 * be between 8 and 63.
-		 */
-		if (buf_len < 8 || buf_len > 63) {
-			nlog(LOG_ERR,
-			    "key_string_to_secobj_value:"
-			    " invalid WPA key length: buf_len = %d", buf_len);
-			return (-1);
-		}
-		(void) memcpy(obj_val, buf, (uint_t)buf_len);
-		*obj_lenp = buf_len;
-		return (0);
-	}
-
-	switch (buf_len) {
-	case 5:		/* ASCII key sizes */
-	case 13:
-		(void) memcpy(obj_val, buf, (uint_t)buf_len);
-		*obj_lenp = (uint_t)buf_len;
-		break;
-	case 10:
-	case 26:	/* Hex key sizes, not preceded by 0x */
-		if (hexascii_to_octet(buf, (uint_t)buf_len, obj_val, obj_lenp)
-		    != 0) {
-			nlog(LOG_ERR,
-			    "key_string_to_secobj_value: invalid WEP key");
-			return (-1);
-		}
-		break;
-	case 12:
-	case 28:	/* Hex key sizes, preceded by 0x */
-		if (strncmp(buf, "0x", 2) != 0 ||
-		    hexascii_to_octet(buf + 2, (uint_t)buf_len - 2, obj_val,
-		    obj_lenp) != 0) {
-			nlog(LOG_ERR,
-			    "key_string_to_secobj_value: invalid WEP key");
-			return (-1);
-		}
-		break;
-	default:
-		syslog(LOG_ERR,
-		    "key_string_to_secobj_value: invalid WEP key length");
-		return (-1);
-	}
-	return (0);
-}
-
-/*
- * Callback used on each known WLAN:
- * return 1 if a secobj, linked with an existing kwown wlan, has the same name
- * of the secobj that is being created.
- */
-
-static int
-find_keyname_cb(nwam_known_wlan_handle_t kwh, void *new_keyname)
-{
-	nwam_error_t err;
-	nwam_value_t old_key;
-
-	char **old_keyname;
-	uint_t num_old_keyname, i;
-
-	if ((err = nwam_known_wlan_get_prop_value(kwh,
-	    NWAM_KNOWN_WLAN_PROP_KEYNAME, &old_key)) != NWAM_SUCCESS) {
-		nlog(LOG_ERR, "find_keyname_cb: nwam_known_wlan_get_prop: %s",
-		    nwam_strerror(err));
-		return (0);
-	}
-	if ((err = nwam_value_get_string_array(old_key, &old_keyname,
-	    &num_old_keyname))
-	    != NWAM_SUCCESS) {
-		nlog(LOG_ERR, "find_keyname_cb: nwam_value_get_string: %s",
-		    nwam_strerror(err));
-		nwam_value_free(old_key);
-		return (0);
-	}
-	nwam_value_free(old_key);
-	for (i = 0; i < num_old_keyname; i++) {
-		if (strcmp(old_keyname[i], (const char *)new_keyname) == 0)
-			/* Found matching keyname so terminate walk */
-			return (1);
-	}
-	return (0);
-}
-
-/*
- * Print the key name format into the appropriate field, then convert any ":"
- * characters to ".", as ":[1-4]" is the slot indicator, which otherwise
- * would trip us up.  Invalid characters for secobj names are ignored.
- * The fourth parameter is expected to be of size DLADM_SECOBJ_NAME_MAX.
- *
- * (Note that much of the system uses DLADM_WLAN_MAX_KEYNAME_LEN, which is 64
- * rather than 32, but that dladm_get_secobj will fail if a length greater than
- * DLD_SECOBJ_NAME_MAX is seen, and that's 32.  This is all horribly broken.)
- */
-void
-nwamd_set_key_name(const char *essid, const char *bssid, char *name, size_t nsz)
-{
-	int i, j;
-	char secobj_name[DLADM_WLAN_MAX_KEYNAME_LEN];
-
-	/* create a concatenated string with essid and bssid */
-	if (bssid == NULL || bssid[0] == '\0') {
-		(void) snprintf(secobj_name, sizeof (secobj_name), "nwam-%s",
-		    essid);
-	} else {
-		(void) snprintf(secobj_name, sizeof (secobj_name), "nwam-%s-%s",
-		    essid, bssid);
-	}
-
-	/* copy only valid chars to the return string, terminating with \0 */
-	i = 0; /* index into secobj_name */
-	j = 0; /* index into name */
-	while (secobj_name[i] != '\0') {
-		if (j == nsz - 1)
-			break;
-
-		if (secobj_name[i] == ':') {
-			name[j] = '.';
-			j++;
-		} else if (isalnum(secobj_name[i]) ||
-		    secobj_name[i] == '.' || secobj_name[i] == '-' ||
-		    secobj_name[i] == '_') {
-			name[j] = secobj_name[i];
-			j++;
-		}
-		i++;
-	}
-	name[j] = '\0';
-}
-
-nwam_error_t
-nwamd_wlan_set_key(const char *linkname, const char *essid, const char *bssid,
-    uint32_t security_mode, uint_t keyslot, char *raw_key)
-{
-	nwamd_object_t ncu_obj;
-	nwamd_ncu_t *ncu;
-	nwamd_link_t *link;
-	int ret = 0;
-	uint8_t obj_val[DLADM_SECOBJ_VAL_MAX];
-	uint_t obj_len = sizeof (obj_val);
-	char obj_name[DLADM_SECOBJ_NAME_MAX];
-	char obj_tempname[DLADM_SECOBJ_NAME_MAX];
-	dladm_status_t status;
-	char errmsg[DLADM_STRSIZE];
-	dladm_secobj_class_t class;
-
-	if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
-	    == NULL) {
-		nlog(LOG_ERR, "nwamd_wlan_set_key: could not find object  "
-		    "for link %s", linkname);
-		return (NWAM_ENTITY_NOT_FOUND);
-	}
-	ncu = ncu_obj->nwamd_object_data;
-	link = &ncu->ncu_link;
-
-	class = (security_mode == DLADM_WLAN_SECMODE_WEP ?
-	    DLADM_SECOBJ_CLASS_WEP : DLADM_SECOBJ_CLASS_WPA);
-	if (key_string_to_secobj_value(raw_key, obj_val, &obj_len,
-	    class) != 0) {
-		/* above function logs internally on failure */
-		nwamd_object_release(ncu_obj);
-		return (NWAM_ERROR_INTERNAL);
-	}
-
-	nlog(LOG_DEBUG, "nwamd_wlan_set_key: running for link %s", linkname);
-	/*
-	 * Name key object for this WLAN so it can be later retrieved.
-	 * (bssid is appended if an object, with the same keyname,
-	 * already exists and is associated to a known wlan)
-	 */
-	nwamd_set_key_name(essid, NULL, obj_tempname, sizeof (obj_tempname));
-	(void) nwam_walk_known_wlans(find_keyname_cb, obj_tempname, 0, &ret);
-	/*
-	 * We also check if the keyval is the same. The user might want
-	 * to use the same key for more APs with the same ESSID.
-	 * This can result in a known wlan with multiple BSSIDs
-	 */
-	if (ret == 1) {
-		dladm_wlan_key_t *old_secobj = nwamd_wlan_get_key_named(
-		    obj_tempname, security_mode);
-		nlog(LOG_DEBUG, "found existing obj_name %s", obj_tempname);
-		ret = memcmp((*old_secobj).wk_val, obj_val, obj_len);
-		nwamd_set_key_name(essid, ret ? bssid : NULL, obj_name,
-		    sizeof (obj_name));
-		free(old_secobj);
-	} else {
-		nwamd_set_key_name(essid, NULL, obj_name,
-		    sizeof (obj_name));
-	}
-	nlog(LOG_DEBUG, "store_key: obj_name is %s", obj_name);
-
-	/*
-	 * We have validated the new key, so remove the old one.
-	 * This will actually delete the keyobj only if the user had set
-	 * a wrong key and is replacing it with a new one for the same AP.
-	 */
-	status = dladm_unset_secobj(dld_handle, obj_name,
-	    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
-	if (status != DLADM_STATUS_OK && status != DLADM_STATUS_NOTFOUND) {
-		nlog(LOG_ERR, "store_key: could not remove old secure object "
-		    "'%s' for key: %s", obj_name,
-		    dladm_status2str(status, errmsg));
-		nwamd_object_release(ncu_obj);
-		return (NWAM_ERROR_INTERNAL);
-	}
-
-	/* if we're just deleting the key, then we're done */
-	if (raw_key[0] == '\0') {
-		nwamd_object_release(ncu_obj);
-		return (NWAM_SUCCESS);
-	}
-
-	status = dladm_set_secobj(dld_handle, obj_name, class,
-	    obj_val, obj_len,
-	    DLADM_OPT_CREATE | DLADM_OPT_PERSIST | DLADM_OPT_ACTIVE);
-	if (status != DLADM_STATUS_OK) {
-		nlog(LOG_ERR, "store_key: could not create secure object "
-		    "'%s' for key: %s", obj_name,
-		    dladm_status2str(status, errmsg));
-		nwamd_object_release(ncu_obj);
-		return (NWAM_ERROR_INTERNAL);
-	}
-	link->nwamd_link_wifi_key = nwamd_wlan_get_key_named(obj_name,
-	    security_mode);
-	(void) strlcpy(link->nwamd_link_wifi_keyname, obj_name,
-	    sizeof (link->nwamd_link_wifi_keyname));
-	link->nwamd_link_wifi_security_mode = security_mode;
-	if (security_mode == DLADM_WLAN_SECMODE_WEP) {
-		link->nwamd_link_wifi_key->wk_idx =
-		    (keyslot >= 1 && keyslot <= 4) ? keyslot : 1;
-	}
-
-	/* If link NCU is offline* or online, (re)connect. */
-	switch (ncu_obj->nwamd_object_state) {
-	case NWAM_STATE_ONLINE:
-		/* if changing the key of the connected WLAN, reconnect */
-		if (strcmp(essid, link->nwamd_link_wifi_essid) == 0)
-			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
-			    ncu_obj->nwamd_object_name, NWAM_STATE_ONLINE,
-			    NWAM_AUX_STATE_LINK_WIFI_CONNECTING);
-		break;
-	case NWAM_STATE_OFFLINE_TO_ONLINE:
-		/* if we are waiting for the key, connect */
-		if (ncu_obj->nwamd_object_aux_state ==
-		    NWAM_AUX_STATE_LINK_WIFI_NEED_KEY)
-			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
-			    ncu_obj->nwamd_object_name,
-			    NWAM_STATE_OFFLINE_TO_ONLINE,
-			    NWAM_AUX_STATE_LINK_WIFI_CONNECTING);
-		break;
-	default:
-		break;
-	}
-	nwamd_object_release(ncu_obj);
-
-	return (NWAM_SUCCESS);
-}
-
-/*
- * returns NULL if no key was recovered from libdladm.  Passing in
- * security mode of 0 means we don't care what key type it is.
- */
-dladm_wlan_key_t *
-nwamd_wlan_get_key_named(const char *name, uint32_t security_mode)
-{
-	dladm_status_t status;
-	char errmsg[DLADM_STRSIZE];
-	dladm_wlan_key_t *cooked_key;
-	dladm_secobj_class_t class;
-
-	if (security_mode == DLADM_WLAN_SECMODE_NONE)
-		return (NULL);
-
-	/*
-	 * Newly-allocated key must be freed by caller, or by
-	 * subsequent call to nwamd_wlan_get_key_named().
-	 */
-	if ((cooked_key = malloc(sizeof (dladm_wlan_key_t))) == NULL) {
-		nlog(LOG_ERR, "nwamd_wlan_get_key_named: malloc failed");
-		return (NULL);
-	}
-
-	/*
-	 * Set name appropriately to retrieve key for this WLAN.  Note that we
-	 * cannot use the actual wk_name buffer size, as it's two times too
-	 * large for dladm_get_secobj.
-	 */
-	(void) strlcpy(cooked_key->wk_name, name, DLADM_SECOBJ_NAME_MAX);
-	nlog(LOG_DEBUG, "nwamd_wlan_get_key_named: len = %d, object = %s\n",
-	    strlen(cooked_key->wk_name), cooked_key->wk_name);
-	cooked_key->wk_len = sizeof (cooked_key->wk_val);
-	cooked_key->wk_idx = 1;
-
-	/* Try the kernel first, then fall back to persistent storage. */
-	status = dladm_get_secobj(dld_handle, cooked_key->wk_name, &class,
-	    cooked_key->wk_val, &cooked_key->wk_len,
-	    DLADM_OPT_ACTIVE);
-	if (status != DLADM_STATUS_OK) {
-		nlog(LOG_DEBUG, "nwamd_wlan_get_key_named: "
-		    "dladm_get_secobj(TEMP) failed: %s",
-		    dladm_status2str(status, errmsg));
-		status = dladm_get_secobj(dld_handle, cooked_key->wk_name,
-		    &class, cooked_key->wk_val, &cooked_key->wk_len,
-		    DLADM_OPT_PERSIST);
-	}
-
-	switch (status) {
-	case DLADM_STATUS_OK:
-		nlog(LOG_DEBUG, "nwamd_wlan_get_key_named: "
-		    "dladm_get_secobj succeeded: len %d", cooked_key->wk_len);
-		break;
-	case DLADM_STATUS_NOTFOUND:
-		/*
-		 * We do not want an error in the case that the secobj
-		 * is not found, since we then prompt for it.
-		 */
-		free(cooked_key);
-		return (NULL);
-	default:
-		nlog(LOG_ERR, "nwamd_wlan_get_key_named: could not get key "
-		    "from secure object '%s': %s", cooked_key->wk_name,
-		    dladm_status2str(status, errmsg));
-		free(cooked_key);
-		return (NULL);
-	}
-
-	if (security_mode != 0) {
-		switch (class) {
-		case DLADM_SECOBJ_CLASS_WEP:
-			if (security_mode == DLADM_WLAN_SECMODE_WEP)
-				return (cooked_key);
-			break;
-		case DLADM_SECOBJ_CLASS_WPA:
-			if (security_mode == DLADM_WLAN_SECMODE_WPA)
-				return (cooked_key);
-			break;
-		default:
-			/* shouldn't happen */
-			nlog(LOG_ERR, "nwamd_wlan_get_key: invalid class %d",
-			    class);
-			break;
-		}
-		/* key type mismatch */
-		nlog(LOG_ERR, "nwamd_wlan_get_key: key type mismatch"
-		    " from secure object '%s'", cooked_key->wk_name);
-		free(cooked_key);
-		return (NULL);
-	}
-
-	return (cooked_key);
-}
-
-static dladm_wlan_key_t *
-nwamd_wlan_get_key(const char *essid, const char *bssid, uint32_t security_mode)
-{
-	char keyname[DLADM_SECOBJ_NAME_MAX];
-
-	nwamd_set_key_name(essid, bssid, keyname, DLADM_SECOBJ_NAME_MAX);
-
-	return (nwamd_wlan_get_key_named(keyname, security_mode));
-}
-
 /*
  * Checks if a wireless network can be selected or not.  A wireless network
  * CANNOT be selected if the NCU is DISABLED, or the NCU is OFFLINE or
@@ -682,6 +255,7 @@
 
 	(void) pthread_mutex_lock(&active_ncp_mutex);
 	if (object->nwamd_object_state == NWAM_STATE_DISABLED ||
+	    object->nwamd_object_state == NWAM_STATE_UNINITIALIZED ||
 	    ((object->nwamd_object_state == NWAM_STATE_OFFLINE ||
 	    object->nwamd_object_state == NWAM_STATE_ONLINE_TO_OFFLINE) &&
 	    ncu->ncu_link.nwamd_link_activation_mode ==
@@ -697,128 +271,14 @@
 	return (B_TRUE);
 }
 
-/*
- * Update the selected and/or connected values for the
- * scan data.  If these change, we need to trigger a scan
- * event since the updated values need to be communicated
- * to the GUI.
- */
-void
-nwamd_set_selected_connected(nwamd_ncu_t *ncu, boolean_t selected,
-    boolean_t connected)
-{
-	nwamd_link_t *link = &ncu->ncu_link;
-	nwamd_wifi_scan_t *s = &link->nwamd_link_wifi_scan;
-	int i;
-	boolean_t trigger_scan_event = B_FALSE;
-
-	for (i = 0; i < s->nwamd_wifi_scan_curr_num; i++) {
-		if (strcmp(s->nwamd_wifi_scan_curr[i].nww_essid,
-		    link->nwamd_link_wifi_essid) != 0 ||
-		    (link->nwamd_link_wifi_bssid[0] != '\0' &&
-		    strcmp(s->nwamd_wifi_scan_curr[i].nww_bssid,
-		    link->nwamd_link_wifi_bssid) != 0))
-			continue;
-		if (selected) {
-			if (!s->nwamd_wifi_scan_curr[i].nww_selected)
-				trigger_scan_event = B_TRUE;
-			s->nwamd_wifi_scan_curr[i].nww_selected = B_TRUE;
-		} else {
-			if (s->nwamd_wifi_scan_curr[i].nww_selected)
-				trigger_scan_event = B_TRUE;
-			s->nwamd_wifi_scan_curr[i].nww_selected = B_FALSE;
-		}
-		if (connected) {
-			if (!s->nwamd_wifi_scan_curr[i].nww_connected)
-				trigger_scan_event = B_TRUE;
-			s->nwamd_wifi_scan_curr[i].nww_connected = B_TRUE;
-		} else {
-			if (s->nwamd_wifi_scan_curr[i].nww_connected)
-				trigger_scan_event = B_TRUE;
-			s->nwamd_wifi_scan_curr[i].nww_connected = B_FALSE;
-		}
-	}
-
-	if (trigger_scan_event || s->nwamd_wifi_scan_changed) {
-		nwamd_event_t scan_event = nwamd_event_init_wlan
-		    (ncu->ncu_name, NWAM_EVENT_TYPE_WLAN_SCAN_REPORT, connected,
-		    s->nwamd_wifi_scan_curr, s->nwamd_wifi_scan_curr_num);
-		if (scan_event != NULL) {
-			/* Avoid sending same scan data multiple times */
-			s->nwamd_wifi_scan_changed = B_FALSE;
-			nwamd_event_enqueue(scan_event);
-		}
-	}
-}
-
-/*
- * Callback used on each known WLAN - if the BSSID is matched, set
- * the ESSID of the hidden WLAN to the known WLAN name.
- */
-static int
-find_bssid_cb(nwam_known_wlan_handle_t kwh, void *data)
-{
-	nwamd_link_t *link = data;
-	nwam_error_t err;
-	nwam_value_t bssidval;
-	char **bssids, *name;
-	uint_t num_bssids, i;
-
-	if ((err = nwam_known_wlan_get_prop_value(kwh,
-	    NWAM_KNOWN_WLAN_PROP_BSSIDS, &bssidval)) != NWAM_SUCCESS) {
-		nlog(LOG_ERR, "find_bssid_cb: nwam_known_wlan_get_prop: %s",
-		    nwam_strerror(err));
-		return (0);
-	}
-	if ((err = nwam_value_get_string_array(bssidval, &bssids, &num_bssids))
-	    != NWAM_SUCCESS) {
-		nlog(LOG_ERR, "find_bssid_cb: nwam_value_get_string_array: %s",
-		    nwam_strerror(err));
-		nwam_value_free(bssidval);
-		return (0);
-	}
-	for (i = 0; i < num_bssids; i++) {
-		if (strcmp(bssids[i], link->nwamd_link_wifi_bssid) == 0) {
-			if ((err = nwam_known_wlan_get_name(kwh, &name))
-			    != NWAM_SUCCESS) {
-				nlog(LOG_ERR, "find_bssid_cb: "
-				    "nwam_known_wlan_get_name: %s",
-				    nwam_strerror(err));
-				continue;
-			}
-			(void) strlcpy(link->nwamd_link_wifi_essid, name,
-			    sizeof (link->nwamd_link_wifi_essid));
-			free(name);
-			nwam_value_free(bssidval);
-			/* Found ESSID for BSSID so terminate walk */
-			return (1);
-		}
-	}
-	nwam_value_free(bssidval);
-
-	return (0);
-}
-
-/*
- * We may have encountered a BSSID for a hidden WLAN before and as a result
- * may have a known WLAN entry with this BSSID.  Walk known WLANs, searching
- * for a BSSID match.  Called with object lock held.
- */
-static void
-check_if_hidden_wlan_was_visited(nwamd_link_t *link)
-{
-	(void) nwam_walk_known_wlans(find_bssid_cb, link,
-	    NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER, NULL);
-}
-
 nwam_error_t
-nwamd_wlan_select(const char *linkname, const char *essid, const char *bssid,
-    uint32_t security_mode, boolean_t add_to_known_wlans)
+nwamd_wlan_select(const char *linkname, const nwam_wlan_t *mywlan,
+    const dladm_wlan_key_t *key_data, const dladm_wlan_eap_t *eap_data)
 {
 	nwamd_object_t ncu_obj;
 	nwamd_ncu_t *ncu;
 	nwamd_link_t *link;
-	boolean_t found_key = B_FALSE;
+	char tmpbuf[DLADM_WLAN_BSSID_LEN * 3];
 
 	if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
 	    == NULL) {
@@ -834,463 +294,232 @@
 	 * state or priority-group, then stop.
 	 */
 	if (!wireless_selection_possible(ncu_obj)) {
+		nlog(LOG_ERR, "nwamd_wlan_select: wireless selection not "
+		    "possible. Invalid state for link %s", linkname);
 		nwamd_object_release(ncu_obj);
 		return (NWAM_ENTITY_INVALID_STATE);
 	}
 
-	/* unset selected, connected flag for previously connected wlan */
-	nwamd_set_selected_connected(ncu, B_FALSE, B_FALSE);
-
-	/* Disconnect to allow new selection to go ahead */
-	(void) dladm_wlan_disconnect(dld_handle, link->nwamd_link_id);
-
-	(void) strlcpy(link->nwamd_link_wifi_essid, essid,
-	    sizeof (link->nwamd_link_wifi_essid));
-	(void) strlcpy(link->nwamd_link_wifi_bssid, bssid,
-	    sizeof (link->nwamd_link_wifi_bssid));
-	link->nwamd_link_wifi_security_mode = security_mode;
-	link->nwamd_link_wifi_add_to_known_wlans = add_to_known_wlans;
-
-	/* If this is a hidden wlan, then essid is empty */
-	if (link->nwamd_link_wifi_essid[0] == '\0')
-		check_if_hidden_wlan_was_visited(link);
-
-	/* set selected flag for newly-selected WLAN */
-	nwamd_set_selected_connected(ncu, B_TRUE, B_FALSE);
+	(void) memcpy(&link->nwamd_link_wifi_wlan, mywlan,
+	    sizeof (nwam_wlan_t));
 
-	/* does this WLAN require a key? If so go to NEED_KEY */
-	if (NEED_ENC(link->nwamd_link_wifi_security_mode)) {
-		/*
-		 * nwam secobjs can have two formats: nwam-ESSID-BSSID and
-		 * nwam-ESSID. There is no reason for searching through known
-		 * wlan keynames since this is only the selection process.
-		 */
-		if ((link->nwamd_link_wifi_key = nwamd_wlan_get_key
-		    (link->nwamd_link_wifi_essid, link->nwamd_link_wifi_bssid,
-		    link->nwamd_link_wifi_security_mode)) != NULL) {
-			/*
-			 * Found old key format,
-			 * known wlans with similar names might exist
-			 */
-			nwamd_set_key_name(link->nwamd_link_wifi_essid,
-			    link->nwamd_link_wifi_bssid,
-			    link->nwamd_link_wifi_keyname,
-			    DLADM_SECOBJ_NAME_MAX);
-			nlog(LOG_DEBUG, "nwamd_wlan_select: got old format "
-			    "WLAN key %s",
-			    link->nwamd_link_wifi_keyname);
-			found_key = B_TRUE;
-		} else if ((link->nwamd_link_wifi_key = nwamd_wlan_get_key
-		    (link->nwamd_link_wifi_essid, NULL,
-		    link->nwamd_link_wifi_security_mode)) != NULL) {
-			nwamd_set_key_name(link->nwamd_link_wifi_essid, NULL,
-			    link->nwamd_link_wifi_keyname,
-			    DLADM_SECOBJ_NAME_MAX);
-			nlog(LOG_DEBUG, "nwamd_wlan_select: got WLAN key %s",
-			    link->nwamd_link_wifi_keyname);
-			found_key = B_TRUE;
-		} else {
-			nlog(LOG_ERR, "nwamd_wlan_select: could not "
-			    "find key for WLAN '%s'",
-			    link->nwamd_link_wifi_essid);
-		}
-	} else {
+	if (link->nwamd_link_wifi_key != NULL) {
 		free(link->nwamd_link_wifi_key);
 		link->nwamd_link_wifi_key = NULL;
-		link->nwamd_link_wifi_keyname[0] = '\0';
+	}
+	if (key_data != NULL) {
+		link->nwamd_link_wifi_key = malloc(sizeof (dladm_wlan_key_t));
+		(void) memcpy(link->nwamd_link_wifi_key, key_data,
+		    sizeof (dladm_wlan_key_t));
 	}
 
-	if (NEED_ENC(link->nwamd_link_wifi_security_mode) && !found_key) {
-		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
-		    ncu_obj->nwamd_object_name,
-		    NWAM_STATE_OFFLINE_TO_ONLINE,
-		    NWAM_AUX_STATE_LINK_WIFI_NEED_KEY);
-	} else {
-		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
-		    ncu_obj->nwamd_object_name, NWAM_STATE_OFFLINE_TO_ONLINE,
-		    NWAM_AUX_STATE_LINK_WIFI_CONNECTING);
+	if (link->nwamd_link_wifi_eap != NULL) {
+		free(link->nwamd_link_wifi_eap);
+		link->nwamd_link_wifi_eap = NULL;
+	}
+	if (eap_data != NULL) {
+		link->nwamd_link_wifi_eap = malloc(sizeof (dladm_wlan_eap_t));
+		(void) memcpy(link->nwamd_link_wifi_eap, eap_data,
+		    sizeof (dladm_wlan_eap_t));
 	}
+
+	nlog(LOG_DEBUG, "nwamd_wlan_select: selecting target wlan (essid %s, "
+	    "bssid %s) for link %s",
+	    link->nwamd_link_wifi_wlan.nww_essid,
+	    dladm_wlan_bssid2str(link->nwamd_link_wifi_wlan.nww_bssid, tmpbuf),
+	    linkname);
+
 	nwamd_object_release(ncu_obj);
 
+	/* start connect thread */
+	nwamd_wlan_connect(linkname);
+
 	return (NWAM_SUCCESS);
 }
 
 /*
- * See if BSSID is in visited list of BSSIDs for known WLAN. Used for
- * strict BSSID matching (depends on wireless_strict_bssid property value).
- */
-static int
-bssid_match(nwam_known_wlan_handle_t kwh, void *bssid)
-{
-	nwam_value_t bssidsval;
-	nwam_error_t err;
-	char **bssids;
-	uint_t nelem, i;
-	int found = 0;
-
-	if ((err = nwam_known_wlan_get_prop_value(kwh,
-	    NWAM_KNOWN_WLAN_PROP_BSSIDS, &bssidsval)) != NWAM_SUCCESS) {
-		nlog(LOG_ERR, "bssid_match: %s", nwam_strerror(err));
-		return (0);
-	}
-	if ((err = nwam_value_get_string_array(bssidsval, &bssids, &nelem))
-	    != NWAM_SUCCESS) {
-		nwam_value_free(bssidsval);
-		return (0);
-	}
-	for (i = 0; i < nelem; i++) {
-		if (strcmp((const char *)bssid, bssids[i]) == 0) {
-			found = 1;
-			break;
-		}
-	}
-	nwam_value_free(bssidsval);
-
-	return (found);
-}
-
-/* Find most prioritized AP with strongest signal in scan data. */
-static int
-find_best_wlan_cb(nwam_known_wlan_handle_t kwh, void *data)
-{
-	nwamd_ncu_t *ncu = data;
-	nwamd_link_t *link = &ncu->ncu_link;
-	nwamd_wifi_scan_t *s = &link->nwamd_link_wifi_scan;
-	nwam_error_t err;
-	char *name = NULL;
-	int i;
-	dladm_wlan_strength_t curr_strength = 0;
-	dladm_wlan_strength_t max_strength = 0;
-	boolean_t found = B_FALSE;
-
-	if ((err = nwam_known_wlan_get_name(kwh, &name)) != NWAM_SUCCESS) {
-		nlog(LOG_ERR, "find_best_wlan_cb: could not look up name: %s",
-		    nwam_strerror(err));
-		return (0);
-	}
-
-	if (link->nwamd_link_wifi_connected) {
-		(void) dladm_wlan_str2strength
-		    (link->nwamd_link_wifi_signal_strength, &curr_strength);
-	}
-
-	/*
-	 * If we're >= scan level, don't pick another Known WLAN if still
-	 * connected (even if a Known WLAN with higher priority is available).
-	 * If the user wants to connect to a different Known WLAN, it can be
-	 * done from the GUI or select-wifi subcommand of nwamadm(1M).
-	 */
-	if (curr_strength >= wireless_scan_level &&
-	    link->nwamd_link_wifi_connected) {
-		free(name);
-		return (1);
-	}
-
-	for (i = 0; i < s->nwamd_wifi_scan_curr_num; i++) {
-		nwam_wlan_t *cur_wlan = &(s->nwamd_wifi_scan_curr[i]);
-		int b_match = bssid_match(kwh, cur_wlan->nww_bssid);
-
-		/*
-		 * We need to either match the scanned essid, or in the case
-		 * where the essid was not broadcast, match the scanned bssid.
-		 */
-		if (strcmp(cur_wlan->nww_essid, name) != 0 &&
-		    !(cur_wlan->nww_essid[0] == '\0' && b_match))
-			continue;
-		/*
-		 * If wireless_strict_bssid is specified, need to match
-		 * BSSID too.
-		 */
-		if (wireless_strict_bssid && !b_match)
-			continue;
-		/*
-		 * Found a match. Since we walk known WLANs in
-		 * priority order, it's guaranteed to be the
-		 * most prioritized. It may not be the strongest though -
-		 * we continue the walk and record the strength along
-		 * with the ESSID and BSSID, so that if we encounter
-		 * another AP with the same ESSID but a higher signal strength,
-		 * we will choose it - but only if the currently-connected
-		 * WLAN is at or below wireless_scan_level.
-		 */
-		(void) dladm_wlan_str2strength
-		    (cur_wlan->nww_signal_strength, &curr_strength);
-
-		if (curr_strength > max_strength) {
-			(void) strlcpy(link->nwamd_link_wifi_essid,
-			    cur_wlan->nww_essid,
-			    sizeof (link->nwamd_link_wifi_essid));
-			/*
-			 * Set BSSID if wireless_strict_bssid is specified or
-			 * if this is a hidden WLAN.  Store the BSSID here and
-			 * then later determine the hidden WLAN's name in the
-			 * connect thread.
-			 */
-			if (wireless_strict_bssid ||
-			    cur_wlan->nww_essid[0] == '\0') {
-				(void) strlcpy(link->nwamd_link_wifi_bssid,
-				    cur_wlan->nww_bssid,
-				    sizeof (link->nwamd_link_wifi_bssid));
-			}
-			(void) strlcpy(link->nwamd_link_wifi_signal_strength,
-			    cur_wlan->nww_signal_strength,
-			    sizeof (link->nwamd_link_wifi_signal_strength));
-			link->nwamd_link_wifi_security_mode =
-			    cur_wlan->nww_security_mode;
-			found = B_TRUE;
-		}
-		(void) dladm_wlan_str2strength
-		    (link->nwamd_link_wifi_signal_strength, &max_strength);
-	}
-	free(name);
-	return (found ? 1 : 0);
-}
-
-static boolean_t
-nwamd_find_known_wlan(nwamd_object_t ncu_obj)
-{
-	nwamd_ncu_t *ncu = ncu_obj->nwamd_object_data;
-	int ret;
-
-	/*
-	 * Walk known WLANs, finding lowest priority (preferred) WLAN
-	 * in our scan results.
-	 */
-	(void) nwam_walk_known_wlans(find_best_wlan_cb, ncu,
-	    NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER, &ret);
-
-	return (ret == 1);
-}
-
-/*
  * WLAN scan code for WIFI link NCUs.
  */
 
-/* Create periodic scan event for object.  Called with object lock held. */
-void
-nwamd_ncu_create_periodic_scan_event(nwamd_object_t ncu_obj)
-{
-	nwamd_event_t scan_event;
-
-	if (wireless_scan_interval == 0) {
-		nlog(LOG_DEBUG, "nwamd_ncu_create_periodic_scan_event: "
-		    "wireless_scan_interval set to 0 so no periodic scanning");
-		return;
-	}
-	scan_event = nwamd_event_init(NWAM_EVENT_TYPE_PERIODIC_SCAN,
-	    NWAM_OBJECT_TYPE_NCU, 0, ncu_obj->nwamd_object_name);
-	if (scan_event != NULL) {
-		nwamd_event_enqueue_timed(scan_event,
-		    wireless_scan_interval > WIRELESS_SCAN_INTERVAL_MIN ?
-		    wireless_scan_interval : WIRELESS_SCAN_INTERVAL_MIN);
-	}
-}
-
-/* Handle periodic scan event (which puts link into WIFI_INIT state */
-void
-nwamd_ncu_handle_periodic_scan_event(nwamd_event_t event)
-{
-	nwamd_object_t ncu_obj;
-	nwamd_ncu_t *ncu;
-
-	ncu_obj = nwamd_object_find(NWAM_OBJECT_TYPE_NCU,
-	    event->event_object);
-	if (ncu_obj == NULL) {
-		nlog(LOG_ERR, "nwamd_ncu_handle_periodic_scan_event: "
-		    "no object %s", event->event_object);
-		return;
-	}
-	ncu = ncu_obj->nwamd_object_data;
-
-	/* Only rescan if state is offline* or online */
-	nlog(LOG_DEBUG, "nwamd_ncu_handle_periodic_scan_event: doing rescan..");
-
-	if (ncu_obj->nwamd_object_state == NWAM_STATE_OFFLINE_TO_ONLINE ||
-	    ncu_obj->nwamd_object_state == NWAM_STATE_ONLINE) {
-		/* rescan, then create periodic scan event */
-		(void) nwamd_wlan_scan(ncu->ncu_name);
-		nwamd_ncu_create_periodic_scan_event(ncu_obj);
-	}
-	nwamd_object_release(ncu_obj);
-}
-
 static boolean_t
-get_scan_results(void *arg, dladm_wlan_attr_t *attrp)
+fill_wifi_scan(void *arg, dladm_wlan_attr_t *attrp)
 {
 	nwamd_wifi_scan_t *s = arg;
-	const char *linkname = s->nwamd_wifi_scan_link;
-	char essid_name[DLADM_STRSIZE];
-	char bssid_name[DLADM_STRSIZE];
-	char strength[DLADM_STRSIZE];
-	uint_t i, index = 0;
-	boolean_t found = B_FALSE;
+	uint_t index = 0;
+	int wlanid = -1;
+	char tmpbuf[DLADM_WLAN_BSSID_LEN * 3];
+
+	if (s == NULL || attrp == NULL) {
+		nlog(LOG_ERR, "fill_wifi_scan: invalid args");
+		return (B_FALSE);
+	}
+
+	index = s->nwamd_wifi_sres_num;
+	s->nwamd_wifi_sres = realloc(s->nwamd_wifi_sres,
+	    sizeof (nwam_wlan_t) * (index + 1));
+
+	if (s->nwamd_wifi_sres == NULL) {
+		nlog(LOG_ERR, "fill_wifi_scan: no memory");
+		return (B_FALSE);
+	}
+	(void) memset(&s->nwamd_wifi_sres[index], 0, sizeof (nwam_wlan_t));
 
-	(void) dladm_wlan_essid2str(&attrp->wa_essid, essid_name);
-	(void) dladm_wlan_bssid2str(&attrp->wa_bssid, bssid_name);
-	(void) dladm_wlan_strength2str(&attrp->wa_strength, strength);
+	if (attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) {
+		(void) memcpy(s->nwamd_wifi_sres[index].nww_essid,
+		    attrp->wa_essid.we_bytes, attrp->wa_essid.we_length);
+		s->nwamd_wifi_sres[index].nww_esslen =
+		    attrp->wa_essid.we_length;
+	}
+
+	(void) memcpy(s->nwamd_wifi_sres[index].nww_bssid,
+	    attrp->wa_bssid.wb_bytes, DLADM_WLAN_BSSID_LEN);
 
-	index = s->nwamd_wifi_scan_curr_num;
-	if (index == NWAMD_MAX_NUM_WLANS) {
-		nlog(LOG_ERR, "get_scan_results: truncating WLAN scan results "
-		    "for link %s: ommiting (%s, %s)", linkname, essid_name,
-		    bssid_name);
+	s->nwamd_wifi_sres[index].nww_security_mode = attrp->wa_secmode;
+	s->nwamd_wifi_sres[index].nww_freq = attrp->wa_freq;
+	s->nwamd_wifi_sres[index].nww_strength = attrp->wa_strength;
+	s->nwamd_wifi_sres[index].nww_rate = attrp->wa_rates.wr_rates[0];
+	s->nwamd_wifi_sres[index].nww_scanid = s->nwamd_wifi_sres_num;
+	(void) strncpy(s->nwamd_wifi_sres[index].nww_ietxt, attrp->wa_ietxt,
+	    sizeof (attrp->wa_ietxt));
+
+	nlog(LOG_DEBUG, "fill_wifi_scan(%d): ESSID %s, BSSID %s", index,
+	    s->nwamd_wifi_sres[index].nww_essid, dladm_wlan_bssid2str(
+	    s->nwamd_wifi_sres[index].nww_bssid, tmpbuf));
+
+	s->nwamd_wifi_sres_num++;
+
+	if (nwam_walk_known_wlans(find_matching_wlan_cb,
+	    &s->nwamd_wifi_sres[index], &wlanid) != NWAM_WALK_HALTED) {
+		s->nwamd_wifi_sres[index].nww_wlanid = 0;
 		return (B_TRUE);
 	}
 
-	(void) strlcpy(s->nwamd_wifi_scan_curr[index].nww_essid, essid_name,
-	    sizeof (s->nwamd_wifi_scan_curr[index].nww_essid));
-	(void) strlcpy(s->nwamd_wifi_scan_curr[index].nww_bssid, bssid_name,
-	    sizeof (s->nwamd_wifi_scan_curr[index].nww_bssid));
-	(void) strlcpy(s->nwamd_wifi_scan_curr[index].nww_signal_strength,
-	    strength,
-	    sizeof (s->nwamd_wifi_scan_curr[index].nww_signal_strength));
-	s->nwamd_wifi_scan_curr[index].nww_security_mode = attrp->wa_secmode;
-	s->nwamd_wifi_scan_curr[index].nww_speed = attrp->wa_speed;
-	s->nwamd_wifi_scan_curr[index].nww_channel = attrp->wa_channel;
-	s->nwamd_wifi_scan_curr[index].nww_bsstype = attrp->wa_bsstype;
-
-	/*
-	 * We fill in actual values for selected/connected/key later when we
-	 * reacquire the object lock.
-	 */
-	s->nwamd_wifi_scan_curr[index].nww_selected = B_FALSE;
-	s->nwamd_wifi_scan_curr[index].nww_connected = B_FALSE;
-	s->nwamd_wifi_scan_curr[index].nww_have_key = B_FALSE;
-	s->nwamd_wifi_scan_curr[index].nww_keyindex = 1;
-	s->nwamd_wifi_scan_curr_num++;
-
-	/* Check if this AP was in previous scan results */
-	for (i = 0; i < s->nwamd_wifi_scan_last_num; i++) {
-		found = (strcmp(s->nwamd_wifi_scan_last[i].nww_essid,
-		    essid_name) == 0 &&
-		    strcmp(s->nwamd_wifi_scan_last[i].nww_bssid,
-		    bssid_name) == 0);
-		if (found)
-			break;
-	}
-	if (!found)
-		s->nwamd_wifi_scan_changed = B_TRUE;
-
-	nlog(LOG_DEBUG, "get_scan_results(%s, %d): ESSID %s, BSSID %s",
-	    linkname, index, essid_name, bssid_name);
+	if (wlanid > 0 && wlanid == s->nwamd_wifi_sres[index].nww_wlanid)
+		nlog(LOG_DEBUG, "fill_wifi_scan(%d): found known wlan %d",
+		    index, wlanid);
 
 	return (B_TRUE);
 }
 
 /*
- * Check if we're connected to the expected WLAN, or in the case of autoconf
- * record the WLAN we're connected to.
+ * Check if we're connected to the expected WLAN,
  */
 boolean_t
 nwamd_wlan_connected(nwamd_object_t ncu_obj)
 {
 	nwamd_ncu_t *ncu = ncu_obj->nwamd_object_data;
 	nwamd_link_t *link = &ncu->ncu_link;
-	dladm_wlan_linkattr_t attr;
-	char essid[DLADM_STRSIZE];
-	char bssid[DLADM_STRSIZE];
-	boolean_t connected = B_FALSE;
-	int retries = 0;
+	nwam_wlan_t currwlan;
+	boolean_t connected;
+
+	if (dladm_wlan_get_linkstatus(dld_handle, link->nwamd_link_id,
+	    &connected, sizeof (connected)) != DLADM_STATUS_OK)
+		return (B_FALSE);
+
+	if (connected) {
+		char tmpbuf[DLADM_WLAN_BSSID_LEN * 3];
+		(void) memset(&currwlan, 0, sizeof (nwam_wlan_t));
+		if (dladm_wlan_get_essid(dld_handle, link->nwamd_link_id,
+		    currwlan.nww_essid, &currwlan.nww_esslen))
+			return (B_FALSE);
+		if (dladm_wlan_get_bssid(dld_handle, link->nwamd_link_id,
+		    currwlan.nww_bssid))
+			return (B_FALSE);
+		nlog(LOG_DEBUG, "nwamd_wlan_connected(%s): associated to %s %s",
+		    ncu->ncu_name, currwlan.nww_essid,
+		    dladm_wlan_bssid2str(currwlan.nww_bssid, tmpbuf));
+	} else
+		return (B_FALSE);
 
 	/*
-	 * This is awful, but some wireless drivers
-	 * (particularly 'ath') will erroneously report
-	 * "disconnected" if queried right after a scan.  If we
-	 * see 'down' reported here, we retry a few times to
-	 * make sure it's really down.
-	 */
-	while (retries++ < 4) {
-		if (dladm_wlan_get_linkattr(dld_handle, link->nwamd_link_id,
-		    &attr) != DLADM_STATUS_OK) {
-			attr.la_status = DLADM_WLAN_LINK_DISCONNECTED;
-		} else if (attr.la_status == DLADM_WLAN_LINK_CONNECTED) {
-			break;
-		}
-	}
-
-	if (attr.la_status == DLADM_WLAN_LINK_CONNECTED) {
-		(void) dladm_wlan_essid2str(&attr.la_wlan_attr.wa_essid, essid);
-		(void) dladm_wlan_bssid2str(&attr.la_wlan_attr.wa_bssid, bssid);
-		connected = B_TRUE;
-		nlog(LOG_DEBUG, "nwamd_wlan_connected: %s connected to %s %s",
-		    ncu->ncu_name, essid, bssid);
-	} else {
-		return (B_FALSE);
-	}
-	/*
-	 * If we're using autoconf,  we have no control over what we connect to,
-	 * so rather than verifying ESSSID, simply record ESSID/BSSID.
+	 * Are we connected to expected WLAN?
 	 */
-	if (link->nwamd_link_wifi_autoconf) {
-		(void) strlcpy(link->nwamd_link_wifi_essid, essid,
-		    sizeof (link->nwamd_link_wifi_essid));
-		(void) strlcpy(link->nwamd_link_wifi_bssid, bssid,
-		    sizeof (link->nwamd_link_wifi_bssid));
-	}
-	/*
-	 * Are we connected to expected WLAN? Note:
-	 * we'd like to verify BSSID, but we cannot due to CR 6772510.
-	 */
-	if (strcmp(essid, link->nwamd_link_wifi_essid) == 0) {
-		/* Update connected signal strength */
-		(void) dladm_wlan_strength2str(&attr.la_wlan_attr.wa_strength,
-		    link->nwamd_link_wifi_signal_strength);
-
-		/* Store current BSSID */
-		(void) strlcpy(link->nwamd_link_wifi_bssid, bssid,
-		    sizeof (link->nwamd_link_wifi_bssid));
-
-		if (attr.la_wlan_attr.wa_strength < wireless_scan_level) {
-			/*
-			 * We're connected, but we've dropped below
-			 * scan threshold.  Initiate a scan.
-			 */
-			nlog(LOG_DEBUG, "nwamd_wlan_connected: "
-			    "connected but signal under threshold...");
-			(void) nwamd_wlan_scan(ncu->ncu_name);
-		}
-		return (connected);
-	} else if (strlen(essid) == 0) {
-		/*
-		 * For hidden WLANs, no ESSID is specified, so we cannot verify
-		 * WLAN name.
-		 */
-		nlog(LOG_DEBUG,
-		    "nwamd_wlan_connected: connected to hidden WLAN, cannot "
-		    "verify connection details");
-		return (connected);
+	if (link->nwamd_link_wifi_wlan.nww_esslen == currwlan.nww_esslen &&
+	    memcmp(currwlan.nww_essid, link->nwamd_link_wifi_wlan.nww_essid,
+	    link->nwamd_link_wifi_wlan.nww_esslen) == 0 &&
+	    memcmp(currwlan.nww_bssid, link->nwamd_link_wifi_wlan.nww_bssid,
+	    DLADM_WLAN_BSSID_LEN) == 0) {
+		return (B_TRUE);
 	} else {
 		(void) nlog(LOG_ERR,
 		    "nwamd_wlan_connected: wrong AP on %s; expected %s %s",
-		    ncu->ncu_name, link->nwamd_link_wifi_essid,
-		    link->nwamd_link_wifi_bssid);
-		(void) dladm_wlan_disconnect(dld_handle, link->nwamd_link_id);
-		link->nwamd_link_wifi_connected = B_FALSE;
+		    ncu->ncu_name, link->nwamd_link_wifi_wlan.nww_essid,
+		    link->nwamd_link_wifi_wlan.nww_bssid);
 		return (B_FALSE);
 	}
 }
 
-/*
- * WLAN scan thread. Called with the per-link WiFi mutex held.
- */
-static void *
-wlan_scan_thread(void *arg)
+nwam_error_t
+nwamd_wlan_scan(const char *linkname)
 {
-	char *linkname = arg;
+	struct wpa_ctrl *ctrl_conn = NULL;
+	char *scancmd[] = {"SCAN"};
+	int rc = 0;
+	dladm_status_t status;
+
 	nwamd_object_t ncu_obj;
 	nwamd_ncu_t *ncu;
 	nwamd_link_t *link;
-	dladm_status_t status;
-	char essid[DLADM_STRSIZE];
-	char bssid[DLADM_STRSIZE];
-	uint32_t now, link_id;
-	nwamd_wifi_scan_t s;
-	int i;
+
+	if (linkname == NULL) {
+		nlog(LOG_ERR, "nwamd_wlan_scan: bad arg");
+		return (NWAM_INVALID_ARG);
+	}
+
+	nlog(LOG_DEBUG, "nwamd_wlan_scan: WLAN scan for %s", linkname);
 
 	if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
 	    == NULL) {
-		nlog(LOG_ERR, "wlan_scan_thread: could not find object  "
+		nlog(LOG_ERR, "nwamd_wlan_scan: could not find object "
 		    "for link %s", linkname);
+		return (NWAM_ENTITY_NOT_FOUND);
+	}
+
+	ncu = ncu_obj->nwamd_object_data;
+	link = &ncu->ncu_link;
+
+	status = dladm_wlan_validate(dld_handle, link->nwamd_link_id,
+	    &ctrl_conn, NULL);
+	if (status != DLADM_STATUS_OK) {
+		nlog(LOG_ERR, "nwamd_wlan_scan(%s): failed connecting to wpa_s "
+		    "ctrlif. (err %d)", linkname, status);
+		nwamd_object_release(ncu_obj);
+		return (NWAM_ERROR_BIND);
+	}
+
+	rc = wpa_request(ctrl_conn, 1, scancmd);
+
+	nwamd_object_release(ncu_obj);
+	wpa_ctrl_close(ctrl_conn);
+
+	if (rc) {
+		nlog(LOG_ERR, "nwamd_wlan_scan: send scan request to wpa_s "
+		    "error %d", rc);
+		return (NWAM_ERROR_INTERNAL);
+	}
+
+	return (NWAM_SUCCESS);
+}
+
+/*
+ * WLAN parse scan results thread. Called with the per-link WiFi mutex held.
+ */
+static void *
+wlan_parse_scanres_thread(void *arg)
+{
+	char *linkname = arg;
+
+	nwamd_object_t ncu_obj;
+	nwamd_ncu_t *ncu;
+	nwamd_link_t *link;
+	nwamd_event_t scan_event;
+
+	dladm_status_t status;
+
+	if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
+	    == NULL) {
+		nlog(LOG_ERR, "wlan_parse_scanres_thread: could not find object"
+		    " for link %s", linkname);
 		free(linkname);
 		return (NULL);
 	}
@@ -1298,216 +527,63 @@
 	ncu = ncu_obj->nwamd_object_data;
 	link = &ncu->ncu_link;
 
-	/*
-	 * It is possible multiple scan threads have queued up waiting for the
-	 * object lock.  We try to prevent excessive scanning by limiting the
-	 * interval between scans to WIRELESS_SCAN_REQUESTED_INTERVAL_MIN sec.
-	 */
-	now = NSEC_TO_SEC(gethrtime());
-	if ((now - link->nwamd_link_wifi_scan.nwamd_wifi_scan_last_time) <
-	    WIRELESS_SCAN_REQUESTED_INTERVAL_MIN) {
-		nlog(LOG_DEBUG, "wlan_scan_thread: last scan for %s "
-		    "was < %d sec ago, ignoring scan request",
-		    linkname, WIRELESS_SCAN_REQUESTED_INTERVAL_MIN);
+	if (link->nwamd_link_wifi_scan.nwamd_wifi_sres != NULL)
+		free(link->nwamd_link_wifi_scan.nwamd_wifi_sres);
+	link->nwamd_link_wifi_scan.nwamd_wifi_sres_num = 0;
+	link->nwamd_link_wifi_scan.nwamd_wifi_sres = NULL;
+
+	nlog(LOG_DEBUG, "wlan_parse_scanres_thread: parsing scan results on %s",
+	    ncu->ncu_name);
+
+	scanconnect_entry();
+	status = dladm_wlan_parse_esslist(dld_handle, link->nwamd_link_id,
+	    &link->nwamd_link_wifi_scan, fill_wifi_scan);
+	scanconnect_exit();
+
+	if (status != DLADM_STATUS_OK) {
+		char errbuf[DLADM_STRSIZE];
+		nlog(LOG_ERR, "wlan_parse_scanres_thread: cannot scan link %s"
+		    " error(%d): %s", ncu->ncu_name, status,
+		    dladm_status2str(status, errbuf));
 		nwamd_object_release(ncu_obj);
 		free(linkname);
 		return (NULL);
 	}
 
-	/*
-	 * Prepare scan data - copy link name and copy previous "current"
-	 * scan results from the nwamd_link_t to the last scan results for
-	 * the next scan so that we can compare results to find if things
-	 * have changed since last time.
-	 */
-	(void) bzero(&s, sizeof (nwamd_wifi_scan_t));
-	(void) strlcpy(s.nwamd_wifi_scan_link, ncu->ncu_name,
-	    sizeof (s.nwamd_wifi_scan_link));
-	s.nwamd_wifi_scan_last_num =
-	    link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr_num;
-	if (s.nwamd_wifi_scan_last_num > 0) {
-		(void) memcpy(s.nwamd_wifi_scan_last,
-		    link->nwamd_link_wifi_scan.nwamd_wifi_scan_curr,
-		    s.nwamd_wifi_scan_last_num * sizeof (nwam_wlan_t));
-	}
-	link_id = link->nwamd_link_id;
-	nwamd_object_release(ncu_obj);
-
-	nlog(LOG_DEBUG, "wlan_scan_thread: initiating scan on %s",
-	    s.nwamd_wifi_scan_link);
-
-	scanconnect_entry();
-	status = dladm_wlan_scan(dld_handle, link_id, &s, get_scan_results);
-	s.nwamd_wifi_scan_last_time = NSEC_TO_SEC(gethrtime());
-	if (!s.nwamd_wifi_scan_changed) {
-		/* Scan may have lost WLANs, if so this qualifies as change */
-		s.nwamd_wifi_scan_changed = (s.nwamd_wifi_scan_curr_num !=
-		    s.nwamd_wifi_scan_last_num);
-	}
-	scanconnect_exit();
-
-	if (status != DLADM_STATUS_OK) {
-		nlog(LOG_ERR, "wlan_scan_thread: cannot scan link %s",
-		    s.nwamd_wifi_scan_link);
-		free(linkname);
-		return (NULL);
+	if (link->nwamd_link_wifi_scan.nwamd_wifi_sres_num != 0) {
+		scan_event = nwamd_event_init_wlan
+		    (ncu->ncu_name, NWAM_EVENT_TYPE_WLAN_SCAN_REPORT, NULL,
+		    link->nwamd_link_wifi_scan.nwamd_wifi_sres_num);
+		if (scan_event == NULL) {
+			nlog(LOG_ERR,
+			    "wlan_parse_scanres_thread: failed to init"
+			    "wlan scan report event");
+		}
+		nwamd_event_enqueue(scan_event);
 	}
 
-	if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
-	    == NULL) {
-		nlog(LOG_ERR, "wlan_scan_thread: could not find object  "
-		    "for link %s after doing scan", linkname);
-		free(linkname);
-		return (NULL);
-	}
-	ncu = ncu_obj->nwamd_object_data;
-	link = &ncu->ncu_link;
-
-	/* For new scan data, add key info from known WLANs */
-	for (i = 0; i < s.nwamd_wifi_scan_curr_num; i++) {
-		if (NEED_ENC(s.nwamd_wifi_scan_curr[i].nww_security_mode)) {
-			char keyname[NWAM_MAX_VALUE_LEN];
-			dladm_wlan_key_t *key = NULL;
-
-			/*
-			 * If strict_bssid is true, we start checking for
-			 * known wlans with the same BSSID.
-			 * This would prevent the selection of secobjs
-			 * that actually are referenced by different kwl
-			 * with the same ESSID.
-			 */
-			if (wireless_strict_bssid) {
-				int b_match = 0;
-				(void) nwam_walk_known_wlans(bssid_match,
-				    s.nwamd_wifi_scan_curr[i].nww_bssid, 0,
-				    &b_match);
-				if (b_match == 0)
-					continue;
-			}
-
-			if (known_wlan_get_keyname
-			    (s.nwamd_wifi_scan_curr[i].nww_essid, keyname)
-			    == NWAM_SUCCESS &&
-			    (key = nwamd_wlan_get_key_named(keyname,
-			    s.nwamd_wifi_scan_curr[i].nww_security_mode))
-			    != NULL) {
-				s.nwamd_wifi_scan_curr[i].nww_have_key =
-				    B_TRUE;
-				s.nwamd_wifi_scan_curr[i].nww_keyindex =
-				    s.nwamd_wifi_scan_curr[i].
-				    nww_security_mode ==
-				    DLADM_WLAN_SECMODE_WEP ?
-				    key->wk_idx : 1;
-				nlog(LOG_DEBUG, "found matching keyname for \
-				    %s", s.nwamd_wifi_scan_curr[i].nww_bssid);
-				free(key);
-			}
-		}
-	}
-	/* Copy scan data into nwamd_link_t */
-	link->nwamd_link_wifi_scan = s;
-	/* Set selected, connected and send scan event if we've got new data */
-	nwamd_set_selected_connected(ncu,
-	    link->nwamd_link_wifi_essid[0] != '\0',
-	    link->nwamd_link_wifi_connected);
-
-	/*
-	 * If wireless selection is not possible because of the current
-	 * state or priority-group, then this was just a scan request.
-	 * Nothing else to do.
-	 */
-	if (!wireless_selection_possible(ncu_obj)) {
-		nwamd_object_release(ncu_obj);
-		free(linkname);
-		return (NULL);
-	}
-
-	/*
-	 * Check if WLAN is on our known WLAN list. If no
-	 * previously-visited WLANs are found in scan data, set
-	 * new state to NEED_SELECTION (provided we're not currently
-	 * connected, as can be the case during a periodic scan or
-	 * monitor-triggered scan where the signal strength recovers.
-	 */
-	if (!nwamd_find_known_wlan(ncu_obj)) {
-		if (!nwamd_wlan_connected(ncu_obj)) {
-			if (link->nwamd_link_wifi_connected) {
-				nlog(LOG_DEBUG, "wlan_scan_thread: "
-				    "unexpected disconnect after scan");
-				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
-				    ncu_obj->nwamd_object_name,
-				    NWAM_STATE_ONLINE_TO_OFFLINE,
-				    NWAM_AUX_STATE_DOWN);
-			} else {
-				nlog(LOG_DEBUG, "wlan_scan_thread: "
-				    "no known WLANs - ask user");
-				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
-				    ncu_obj->nwamd_object_name,
-				    NWAM_STATE_OFFLINE_TO_ONLINE,
-				    NWAM_AUX_STATE_LINK_WIFI_NEED_SELECTION);
-			}
-		} else {
-			/* still connected. if not online, change to online */
-			nlog(LOG_DEBUG, "wlan_scan_thread: still connected to "
-			    "%s %s", link->nwamd_link_wifi_essid,
-			    link->nwamd_link_wifi_bssid);
-			if (ncu_obj->nwamd_object_state != NWAM_STATE_ONLINE) {
-				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
-				    ncu_obj->nwamd_object_name,
-				    NWAM_STATE_OFFLINE_TO_ONLINE,
-				    NWAM_AUX_STATE_UP);
-			}
-		}
-		nwamd_object_release(ncu_obj);
-
-	} else {
-		nlog(LOG_DEBUG, "wlan_scan_thread: found known WLAN %s %s",
-		    link->nwamd_link_wifi_essid, link->nwamd_link_wifi_bssid);
-
-		if (!nwamd_wlan_connected(ncu_obj)) {
-			/* Copy selected ESSID/BSSID, unlock, call select */
-			(void) strlcpy(essid, link->nwamd_link_wifi_essid,
-			    sizeof (essid));
-			(void) strlcpy(bssid, link->nwamd_link_wifi_bssid,
-			    sizeof (bssid));
-			nwamd_object_release(ncu_obj);
-			(void) nwamd_wlan_select(linkname, essid, bssid,
-			    link->nwamd_link_wifi_security_mode, B_TRUE);
-		} else {
-			/* still connected.  if not online, change to online */
-			nlog(LOG_DEBUG, "wlan_scan_thread: still connected to "
-			    "known WLAN %s %s", link->nwamd_link_wifi_essid,
-			    link->nwamd_link_wifi_bssid);
-			if (ncu_obj->nwamd_object_state != NWAM_STATE_ONLINE) {
-				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
-				    ncu_obj->nwamd_object_name,
-				    NWAM_STATE_OFFLINE_TO_ONLINE,
-				    NWAM_AUX_STATE_UP);
-			}
-			nwamd_object_release(ncu_obj);
-		}
-	}
+	nwamd_object_release(ncu_obj);
 	free(linkname);
 	return (NULL);
 }
 
 nwam_error_t
-nwamd_wlan_scan(const char *linkname)
+nwamd_wlan_parse_scanres(const char *linkname)
 {
 	pthread_t wifi_thread;
 	char *link = strdup(linkname);
 
 	if (link == NULL) {
-		nlog(LOG_ERR, "nwamd_wlan_scan: out of memory");
+		nlog(LOG_ERR, "nwamd_wlan_parse_scanres: out of memory");
 		return (NWAM_NO_MEMORY);
 	}
 
-	nlog(LOG_DEBUG, "nwamd_wlan_scan: WLAN scan for %s",
-	    link);
+	nlog(LOG_DEBUG, "nwamd_wlan_parse_scanres: got scanres for %s", link);
 
-	if (pthread_create(&wifi_thread, NULL, wlan_scan_thread,
+	if (pthread_create(&wifi_thread, NULL, wlan_parse_scanres_thread,
 	    link) != 0) {
-		nlog(LOG_ERR, "nwamd_wlan_scan: could not start scan");
+		nlog(LOG_ERR, "nwamd_wlan_parse_scanres: could not start"
+		    " wlan_parse_scanres_thread");
 		free(link);
 		return (NWAM_ERROR_INTERNAL);
 	}
@@ -1519,25 +595,6 @@
 /*
  * WLAN connection code.
  */
-
-static dladm_status_t
-do_connect(uint32_t link_id, dladm_wlan_attr_t *attrp, dladm_wlan_key_t *key,
-    uint_t keycount, uint_t flags)
-{
-	dladm_status_t status;
-	char errmsg[DLADM_STRSIZE];
-
-	scanconnect_entry();
-	status = dladm_wlan_connect(dld_handle, link_id, attrp,
-	    DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT, key, keycount, flags);
-	scanconnect_exit();
-
-	nlog(LOG_DEBUG, "nwamd_do_connect: dladm_wlan_connect returned %s",
-	    dladm_status2str(status, errmsg));
-
-	return (status);
-}
-
 static void *
 wlan_connect_thread(void *arg)
 {
@@ -1545,17 +602,13 @@
 	nwamd_object_t ncu_obj;
 	nwamd_ncu_t *ncu;
 	nwamd_link_t *link;
-	nwam_error_t err;
-	uint_t	keycount;
-	uint32_t link_id;
-	dladm_wlan_key_t *key = NULL;
 	dladm_wlan_attr_t attr;
 	dladm_status_t status;
-	boolean_t autoconf = B_FALSE;
+	char errbuf[DLADM_STRSIZE];
 
 	if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
 	    == NULL) {
-		nlog(LOG_ERR, "wlan_connect_thread: could not find object  "
+		nlog(LOG_ERR, "wlan_connect_thread: could not find object "
 		    "for link %s", linkname);
 		free(linkname);
 		return (NULL);
@@ -1565,151 +618,85 @@
 	link = &ncu->ncu_link;
 
 	if (!wireless_selection_possible(ncu_obj)) {
-		nlog(LOG_DEBUG, "wlan_connect_thread: %s in invalid state or "
-		    "has lower priority", ncu->ncu_name);
+		nlog(LOG_ERR, "wlan_connect_thread: %s in invalid state or "
+		    "has lower priority", linkname);
 		goto done;
 	}
 
-	/* If it is already connected to the required AP, just return. */
-	if (nwamd_wlan_connected(ncu_obj)) {
-		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
-		    ncu_obj->nwamd_object_name,
-		    ncu_obj->nwamd_object_state, NWAM_AUX_STATE_UP);
+	/* we are connecting to a known wlan */
+	if (link->nwamd_link_wifi_wlan.nww_wlanid != 0) {
+		char *select_request[] = {"SELECT_NETWORK", NULL};
+		char wlanid[16];
+		int idlen;
+		struct wpa_ctrl *ctrl_conn = NULL;
+
+		idlen = snprintf(wlanid, sizeof (wlanid), "%u",
+		    link->nwamd_link_wifi_wlan.nww_wlanid);
+		if (idlen < 1 || idlen >= sizeof (wlanid)) {
+			nlog(LOG_ERR, "wlan_connect_thread: invalid wlan id");
+			goto done;
+		}
+		select_request[1] = wlanid;
+
+		status = dladm_wlan_validate(dld_handle, link->nwamd_link_id,
+		    &ctrl_conn, NULL);
+		if (status != DLADM_STATUS_OK) {
+			nlog(LOG_ERR, "wlan_connect_thread: failed connecting"
+			    "to wpa_s interface (err: %d)", status);
+			goto done;
+		}
+
+		if (wpa_request(ctrl_conn, 2, select_request))
+			nlog(LOG_ERR, "wlan_connect_thread: failed selecting "
+			    "known wlan %u", wlanid);
+		else
+			nlog(LOG_DEBUG, "wlan_connect_thread: connecting to "
+			    "known wlan %u", wlanid);
+
+		wpa_ctrl_close(ctrl_conn);
 		goto done;
 	}
 
 	(void) memset(&attr, 0, sizeof (attr));
-	if (dladm_wlan_str2essid(link->nwamd_link_wifi_essid, &attr.wa_essid)
-	    != DLADM_STATUS_OK) {
-		nlog(LOG_ERR, "wlan_connect_thread: invalid ESSID '%s' "
-		    "for '%s'", link->nwamd_link_wifi_essid, ncu->ncu_name);
+	if (link->nwamd_link_wifi_wlan.nww_esslen != 0) {
+		(void) memcpy(attr.wa_essid.we_bytes,
+		    link->nwamd_link_wifi_wlan.nww_essid,
+		    link->nwamd_link_wifi_wlan.nww_esslen);
+		attr.wa_essid.we_length = link->nwamd_link_wifi_wlan.nww_esslen;
+		attr.wa_valid = DLADM_WLAN_ATTR_ESSID;
+	} else if (NEED_ENC(link->nwamd_link_wifi_wlan.nww_security_mode)) {
+		nlog(LOG_ERR, "wlan_connect_thread: ESSID is mandatory "
+		    "for non-plaintext AP!");
 		goto done;
 	}
-	attr.wa_valid = DLADM_WLAN_ATTR_ESSID;
-
-	/* note: bssid logic here is non-functional */
-	if (link->nwamd_link_wifi_bssid[0] != '\0') {
-		if (dladm_wlan_str2bssid(link->nwamd_link_wifi_bssid,
-		    &attr.wa_bssid) != DLADM_STATUS_OK) {
-			nlog(LOG_ERR, "wlan_connect_thread: invalid BSSID '%s'",
-			    "for '%s'", link->nwamd_link_wifi_bssid,
-			    ncu->ncu_name);
-		} else {
-			attr.wa_valid |= DLADM_WLAN_ATTR_BSSID;
-		}
-	}
-
-	/* First check for the key */
-	if (NEED_ENC(link->nwamd_link_wifi_security_mode)) {
-		if (link->nwamd_link_wifi_key == NULL) {
-			nlog(LOG_ERR, "wlan_connect_thread: could not find "
-			    "key for WLAN '%s'", link->nwamd_link_wifi_essid);
-			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
-			    ncu_obj->nwamd_object_name,
-			    NWAM_STATE_OFFLINE_TO_ONLINE,
-			    NWAM_AUX_STATE_LINK_WIFI_NEED_KEY);
-			goto done;
-		}
-		/* Make a copy of the key as we need to unlock the object */
-		if ((key = calloc(1, sizeof (dladm_wlan_key_t))) == NULL) {
-			nlog(LOG_ERR, "wlan_connect_thread: out of memory");
-			goto done;
-		}
-		(void) memcpy(key, link->nwamd_link_wifi_key,
-		    sizeof (dladm_wlan_key_t));
-
-		attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
-		attr.wa_secmode = link->nwamd_link_wifi_security_mode;
-		keycount = 1;
-		nlog(LOG_DEBUG, "wlan_connect_thread: retrieved key");
-	} else {
-		key = NULL;
-		keycount = 0;
-	}
 
-	/*
-	 * Connect; only scan if a bssid was not specified.  If it times out,
-	 * try a second time using autoconf.  Drop the object lock during the
-	 * connect attempt since connecting may take some time, and access to
-	 * the link object during that period would be impossible if we held the
-	 * lock.
-	 */
-
-	link->nwamd_link_wifi_autoconf = B_FALSE;
-	link_id = link->nwamd_link_id;
-
-	nwamd_object_release(ncu_obj);
-
-	status = do_connect(link_id, &attr, key, keycount,
-	    DLADM_WLAN_CONNECT_NOSCAN);
-	if (status != DLADM_STATUS_OK) {
-		/* Connect failed, try autoconf */
-		if (!wireless_autoconf || (status = do_connect(link_id, &attr,
-		    NULL, 0, 0)) != DLADM_STATUS_OK) {
-			nlog(LOG_ERR, "wlan_connect_thread: connect failed for "
-			    "%s", linkname);
-			goto done_unlocked;
-		}
-		if (status == DLADM_STATUS_OK)
-			autoconf = B_TRUE;
-	}
-
-	/* Connect succeeded, reacquire object */
-	if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK, linkname))
-	    == NULL) {
-		nlog(LOG_ERR, "wlan_connect_thread: could not find object  "
-		    "for link %s", linkname);
-		goto done_unlocked;
+	if (link->nwamd_link_wifi_wlan.nww_bssid[0] != 0) {
+		(void) memcpy(attr.wa_bssid.wb_bytes,
+		    link->nwamd_link_wifi_wlan.nww_bssid, DLADM_WLAN_BSSID_LEN);
+		attr.wa_valid = DLADM_WLAN_ATTR_BSSID;
 	}
 
-	ncu = ncu_obj->nwamd_object_data;
-	link = &ncu->ncu_link;
-
-	if (autoconf)
-		link->nwamd_link_wifi_autoconf = B_TRUE;
-
-	/*
-	 * If WLAN is WEP/WPA, we would like to test the connection as the key
-	 * may be wrong.  It is difficult to find a reliable test that works
-	 * across APs however.  Do nothing for now.
-	 */
-	link->nwamd_link_wifi_connected = nwamd_wlan_connected(ncu_obj);
+	attr.wa_secmode = link->nwamd_link_wifi_wlan.nww_security_mode;
+	attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
+	if (attr.wa_secmode != DLADM_WLAN_SECMODE_NONE)
+		nlog(LOG_DEBUG, "wlan_connect_thread: retrieved key");
 
-	if (link->nwamd_link_wifi_connected) {
-		if (link->nwamd_link_wifi_add_to_known_wlans) {
-			/* add to known WLANs */
-			nlog(LOG_DEBUG, "wlan_connect_thread: "
-			    "add '%s' to known WLANs",
-			    link->nwamd_link_wifi_essid);
-			if ((err = nwam_known_wlan_add_to_known_wlans
-			    (link->nwamd_link_wifi_essid,
-			    link->nwamd_link_wifi_bssid[0] != '\0' ?
-			    link->nwamd_link_wifi_bssid : NULL,
-			    link->nwamd_link_wifi_security_mode,
-			    link->nwamd_link_wifi_security_mode ==
-			    DLADM_WLAN_SECMODE_WEP ?
-			    (uint_t)link->nwamd_link_wifi_key->wk_idx : 1,
-			    NEED_ENC(link->nwamd_link_wifi_security_mode) ?
-			    link->nwamd_link_wifi_keyname : NULL))
-			    != NWAM_SUCCESS) {
-				nlog(LOG_ERR, "wlan_connect_thread: "
-				    "could not add to known WLANs: %s",
-				    nwam_strerror(err));
-			}
-		}
-		nwamd_set_selected_connected(ncu, B_TRUE, B_TRUE);
-		nlog(LOG_DEBUG, "wlan_connect_thread: connect "
-		    "succeeded, setting state online");
-		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
-		    ncu_obj->nwamd_object_name, NWAM_STATE_ONLINE,
-		    NWAM_AUX_STATE_UP);
+	scanconnect_entry();
+	status = dladm_wlan_connect(dld_handle, link->nwamd_link_id, &attr,
+	    link->nwamd_link_wifi_key, link->nwamd_link_wifi_eap);
+	scanconnect_exit();
+
+	if (status != DLADM_STATUS_OK) {
+		nlog(LOG_ERR, "wlan_connect_thread: connect failed for %s"
+		    " error:'%s'", linkname, dladm_status2str(status, errbuf));
+	} else {
+		nlog(LOG_DEBUG, "wlan_connect_thread: connecting to %s for %s",
+		    attr.wa_essid.we_bytes, linkname);
 	}
 
 done:
 	nwamd_object_release(ncu_obj);
-done_unlocked:
 	free(linkname);
-	free(key);
 
 	return (NULL);
 }
@@ -1735,105 +722,6 @@
 	(void) pthread_detach(wifi_thread);
 }
 
-/*
- * Launch signal strength-monitoring thread which periodically
- * checks connection and signal strength.  If we become disconnected
- * or signal drops below threshold specified by wireless_scan_level,
- * initiate a scan.  The scan initiation is taken care of by
- * the call to nwamd_wlan_connected().
- */
-static void *
-wlan_monitor_signal_thread(void *arg)
-{
-	char *linkname = arg;
-	nwamd_object_t ncu_obj;
-	nwamd_ncu_t *ncu;
-	nwamd_link_t *link;
-	boolean_t first_time = B_TRUE;
-
-	for (;;) {
-		if ((ncu_obj = nwamd_ncu_object_find(NWAM_NCU_TYPE_LINK,
-		    linkname)) == NULL) {
-			nlog(LOG_ERR, "wlan_monitor_signal_thread: could "
-			    "not find object for link %s", linkname);
-			break;
-		}
-		ncu = ncu_obj->nwamd_object_data;
-		link = &ncu->ncu_link;
-
-		/* If the NCU is DISABLED/OFFLINE, exit the monitoring thread */
-		if (ncu_obj->nwamd_object_state == NWAM_STATE_OFFLINE ||
-		    ncu_obj->nwamd_object_state == NWAM_STATE_DISABLED) {
-			nlog(LOG_INFO, "wlan_monitor_signal_thread: "
-			    "%s is %s, stopping thread", linkname,
-			    nwam_state_to_string(ncu_obj->nwamd_object_state));
-			link->nwamd_link_wifi_monitor_thread = 0;
-			nwamd_object_release(ncu_obj);
-			break;
-		}
-
-		/*
-		 * First time thru loop, we check if there is another
-		 * link monitoring thread in operation - if so exit this
-		 * thread.
-		 */
-		if (first_time) {
-			first_time = B_FALSE;
-
-			if (link->nwamd_link_wifi_monitor_thread != 0) {
-				/* Already have a monitor thread for link? */
-				nwamd_object_release(ncu_obj);
-				break;
-			} else {
-				link->nwamd_link_wifi_monitor_thread =
-				    pthread_self();
-			}
-		}
-		if (!nwamd_wlan_connected(ncu_obj)) {
-			nlog(LOG_ERR, "wlan_monitor_signal_thread: "
-			    "disconnect occured for WLAN on link %s", linkname);
-			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
-			    ncu_obj->nwamd_object_name,
-			    NWAM_STATE_ONLINE_TO_OFFLINE,
-			    NWAM_AUX_STATE_DOWN);
-			link->nwamd_link_wifi_monitor_thread = 0;
-			nwamd_object_release(ncu_obj);
-			break;
-		}
-		nwamd_object_release(ncu_obj);
-		(void) sleep(WIRELESS_MONITOR_SIGNAL_INTERVAL);
-	}
-	free(linkname);
-
-	return (NULL);
-}
-
-void
-nwamd_wlan_monitor_signal(const char *linkname)
-{
-	pthread_t wifi_thread;
-	char *link = strdup(linkname);
-
-	if (link == NULL) {
-		nlog(LOG_ERR, "nwamd_wlan_monitor_signal: out of memory");
-		return;
-	}
-
-	nlog(LOG_DEBUG, "nwamd_wlan_monitor_signal: WLAN monitor for %s",
-	    link);
-
-	if (pthread_create(&wifi_thread, NULL, wlan_monitor_signal_thread,
-	    link) != 0) {
-		nlog(LOG_ERR, "nwamd_wlan_monitor_signal: could not monitor "
-		    "link %s", link);
-		free(link);
-		return;
-	}
-
-	/* detach thread so that it doesn't become a zombie */
-	(void) pthread_detach(wifi_thread);
-}
-
 void
 nwamd_ncu_handle_link_state_event(nwamd_event_t event)
 {
@@ -1854,21 +742,13 @@
 	evm = event->event_msg;
 
 	/*
-	 * We ignore link state events for WiFi because it is very flaky.
-	 * Instead we use the monitor thread and drive WiFi state changes from
-	 * there.
-	 */
-	if (link->nwamd_link_media == DL_WIFI) {
-		nwamd_object_release(ncu_obj);
-		return;
-	}
-
-	/*
 	 * If it's a link up event and we're not disabled, go online.
 	 */
 	if (evm->nwe_data.nwe_link_state.nwe_link_up &&
 	    ncu_obj->nwamd_object_state != NWAM_STATE_DISABLED) {
 
+		boolean_t wifi = (link->nwamd_link_media == DL_WIFI);
+
 		if (link->nwamd_link_activation_mode ==
 		    NWAM_ACTIVATION_MODE_PRIORITIZED) {
 			int64_t priority_group;
@@ -1904,6 +784,7 @@
 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
 				    event->event_object,
 				    NWAM_STATE_OFFLINE_TO_ONLINE,
+				    wifi ? NWAM_AUX_STATE_LINK_WIFI_ASSOCIATED :
 				    NWAM_AUX_STATE_UP);
 			} else {
 				nlog(LOG_DEBUG,
@@ -1921,6 +802,7 @@
 				nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
 				    event->event_object,
 				    NWAM_STATE_OFFLINE_TO_ONLINE,
+				    wifi ? NWAM_AUX_STATE_LINK_WIFI_ASSOCIATED :
 				    NWAM_AUX_STATE_UP);
 				nwamd_object_release(ncu_obj);
 				nwamd_ncp_deactivate_priority_group
@@ -1938,6 +820,7 @@
 
 			nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU,
 			    event->event_object, NWAM_STATE_OFFLINE_TO_ONLINE,
+			    wifi ? NWAM_AUX_STATE_LINK_WIFI_ASSOCIATED :
 			    NWAM_AUX_STATE_UP);
 		}
 	}
--- a/usr/src/cmd/cmd-inet/lib/nwamd/objects.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/objects.c	Wed May 29 08:31:24 2013 +0200
@@ -22,6 +22,7 @@
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #include <assert.h>
@@ -78,7 +79,6 @@
 	{ NWAM_EVENT_TYPE_OBJECT_FINI, nwamd_ncu_handle_fini_event },
 	{ NWAM_EVENT_TYPE_OBJECT_ACTION, nwamd_ncu_handle_action_event },
 	{ NWAM_EVENT_TYPE_OBJECT_STATE, nwamd_ncu_handle_state_event },
-	{ NWAM_EVENT_TYPE_PERIODIC_SCAN, nwamd_ncu_handle_periodic_scan_event },
 	{ NWAM_EVENT_TYPE_NOOP, NULL }
 };
 
--- a/usr/src/cmd/cmd-inet/lib/nwamd/objects.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/objects.h	Wed May 29 08:31:24 2013 +0200
@@ -22,6 +22,7 @@
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #ifndef _OBJECTS_H
@@ -150,7 +151,6 @@
 
 extern void nwamd_ncp_handle_action_event(nwamd_event_t);
 extern void nwamd_ncp_handle_state_event(nwamd_event_t);
-extern void nwamd_ncu_handle_periodic_scan_event(nwamd_event_t);
 extern void nwamd_ncp_handle_enable_event(nwamd_event_t);
 extern void nwamd_handle_upgrade(nwamd_event_t);
 
--- a/usr/src/cmd/cmd-inet/lib/nwamd/util.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/util.h	Wed May 29 08:31:24 2013 +0200
@@ -22,13 +22,13 @@
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #ifndef _UTIL_H
 #define	_UTIL_H
 
 #include <dhcpagent_ipc.h>
-#include <libdlwlan.h>
 #include <libnwam.h>
 #include <pthread.h>
 #include <string.h>
@@ -49,12 +49,8 @@
 #define	OUR_FMRI				NWAM_FMRI
 #define	OUR_PG					NWAM_PG
 #define	OUR_DEBUG_PROP_NAME			"debug"
-#define	OUR_AUTOCONF_PROP_NAME			"autoconf"
-#define	OUR_STRICT_BSSID_PROP_NAME		"strict_bssid"
 #define	OUR_ACTIVE_NCP_PROP_NAME		NWAM_PROP_ACTIVE_NCP
 #define	OUR_CONDITION_CHECK_INTERVAL_PROP_NAME	"condition_check_interval"
-#define	OUR_WIRELESS_SCAN_INTERVAL_PROP_NAME	"scan_interval"
-#define	OUR_WIRELESS_SCAN_LEVEL_PROP_NAME	"scan_level"
 #define	OUR_NCU_WAIT_TIME_PROP_NAME		"ncu_wait_time"
 #define	OUR_VERSION_PROP_NAME			"version"
 #define	NET_LOC_FMRI				"svc:/network/location:default"
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/lib/nwamd/wpa_s_events.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,348 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy is of the CDDL is also available via the Internet
+ * at http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
+ */
+
+/*
+ * routines to retrieve wpa_supplicant control events
+ * from the wpa_supplicant instance control interface
+ */
+
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <libdllink.h>
+#include <libdlwlan.h>
+
+#include "events.h"
+#include "ncp.h"
+#include "ncu.h"
+#include "objects.h"
+#include "util.h"
+
+/*
+ * events we handle:
+ * WPA_EVENT_CONNECTED   "CTRL-EVENT-CONNECTED "
+ * WPA_EVENT_DISCONNECTED   "CTRL-EVENT-DISCONNECTED "
+ * WPA_EVENT_ASSOC_REJECT   "CTRL-EVENT-ASSOC-REJECT "
+ * WPA_EVENT_TERMINATING   "CTRL-EVENT-TERMINATING "
+ * WPA_EVENT_EAP_TLS_CERT_ERROR   "CTRL-EVENT-EAP-TLS-CERT-ERROR "
+ * WPA_EVENT_EAP_FAILURE   "CTRL-EVENT-EAP-FAILURE "
+ * WPA_EVENT_SCAN_RESULTS   "CTRL-EVENT-SCAN-RESULTS "
+ *
+ */
+
+static void
+wpa_s_process_ctrl_event(const char *ev_id, const char *ev_extra,
+    const char *ifname)
+{
+	nwamd_event_t link_event = NULL;
+	nwam_error_t err;
+	char bssid_str[DLADM_WLAN_BSSID_LEN*3];
+	char *object_name;
+
+	if (strcmp(ev_id, WPA_EVENT_SCAN_RESULTS) == 0) {
+		/* this event occurs when at least 1 node is in nodes table */
+		nlog(LOG_DEBUG, "wpa_s_event_handler: new scan "
+		    "results for link %s", ifname);
+		/* async */
+		if (nwamd_wlan_parse_scanres(ifname))
+			nlog(LOG_ERR, "wpa_s_event_handler(%s):"
+			    " failed to invoke"
+			    " nwamd_wlan_parse_scanres",
+			    ifname);
+		return;
+
+	} else if (strcmp(ev_id, WPA_EVENT_CONNECTED) == 0) {
+
+		nwam_wlan_t enst_wlan;
+
+		if ((err = nwam_ncu_name_to_typed_name(ifname,
+		    NWAM_NCU_TYPE_LINK, &object_name)) != NWAM_SUCCESS) {
+			nlog(LOG_ERR, "wpa_s_event_handler(%s): "
+			    "nwam_ncu_name_to_typed_name: %s", ifname,
+			    nwam_strerror(err));
+			return;
+		}
+		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, object_name,
+		    NWAM_STATE_OFFLINE_TO_ONLINE,
+		    NWAM_AUX_STATE_LINK_WIFI_CONNECTED);
+
+		free(object_name);
+
+		if (sscanf(ev_extra, "- Connection to %17s completed (auth) "
+		    "[id=%15u id_str=%32s]", bssid_str, &enst_wlan.nww_wlanid,
+		    enst_wlan.nww_essid) == 3) {
+			(void) dladm_wlan_str2bssid(bssid_str,
+			    enst_wlan.nww_bssid);
+		} else if (sscanf(ev_extra, "- Connection to %17s completed "
+		    "(reauth) [id=%15u id_str=%32s]", bssid_str,
+		    &enst_wlan.nww_wlanid, enst_wlan.nww_essid) == 3) {
+			(void) dladm_wlan_str2bssid(bssid_str,
+			    enst_wlan.nww_bssid);
+		} else {
+			nlog(LOG_ERR, "wpa_s_event_handler(%s):"
+			    " Failed parsing connect event", ifname);
+		}
+
+		link_event = nwamd_event_init_wlan(ifname,
+		    NWAM_EVENT_TYPE_WLAN_CONNECTION_REPORT, &enst_wlan, 1);
+
+	} else if (strcmp(ev_id, WPA_EVENT_DISCONNECTED) == 0) {
+
+		nwam_wlan_t disc_wlan;
+
+		if ((err = nwam_ncu_name_to_typed_name(ifname,
+		    NWAM_NCU_TYPE_LINK, &object_name)) != NWAM_SUCCESS) {
+			nlog(LOG_ERR, "wpa_s_event_handler(%s): "
+			    "nwam_ncu_name_to_typed_name: %s", ifname,
+			    nwam_strerror(err));
+			return;
+		}
+		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, object_name,
+		    NWAM_STATE_ONLINE_TO_OFFLINE, NWAM_AUX_STATE_DOWN);
+
+		free(object_name);
+
+		if (sscanf(ev_extra, "bssid=%17s reason=%u", bssid_str,
+		    &disc_wlan.nww_wlanid) != 2)
+			nlog(LOG_ERR, "wpa_s_event_handler(%s):"
+			    " Failed parsing disassoc event");
+
+		(void) dladm_wlan_str2bssid(bssid_str, disc_wlan.nww_bssid);
+
+		link_event = nwamd_event_init_wlan(ifname,
+		    NWAM_EVENT_TYPE_WLAN_DISASSOCIATION_REPORT, &disc_wlan, 1);
+
+	} else if ((strcmp(ev_id, WPA_EVENT_ASSOC_REJECT) == 0) ||
+	    (strcmp(ev_id, WPA_EVENT_EAP_TLS_CERT_ERROR) == 0) ||
+	    (strcmp(ev_id, WPA_EVENT_EAP_FAILURE) == 0)) {
+
+		nwam_wlan_t rej_wlan;
+
+		if (strcmp(ev_id, WPA_EVENT_ASSOC_REJECT) == 0 &&
+		    sscanf(ev_extra, "bssid=%17s status_code=%u", bssid_str,
+		    &rej_wlan.nww_wlanid) != 2) {
+			nlog(LOG_ERR, "wpa_s_event_handler(%s):"
+			    " Failed parsing reject event");
+			return;
+		}
+
+		(void) dladm_wlan_str2bssid(bssid_str, rej_wlan.nww_bssid);
+		link_event = nwamd_event_init_wlan(ifname,
+		    NWAM_EVENT_TYPE_WLAN_WRONG_KEY, &rej_wlan, 1);
+
+	} else if (strcmp(ev_id, WPA_EVENT_TERMINATING) == 0) {
+
+		nwam_error_t err;
+		char *object_name;
+		if ((err = nwam_ncu_name_to_typed_name(ifname,
+		    NWAM_NCU_TYPE_LINK, &object_name)) != NWAM_SUCCESS) {
+			nlog(LOG_ERR, "wpa_s_event_handler(%s): "
+			    "nwam_ncu_name_to_typed_name: %s", ifname,
+			    nwam_strerror(err));
+			return;
+		}
+		nwamd_object_set_state(NWAM_OBJECT_TYPE_NCU, object_name,
+		    NWAM_STATE_ONLINE_TO_OFFLINE, NWAM_AUX_STATE_DOWN);
+
+		free(object_name);
+
+	} else
+		return;
+
+	/* Create event for link */
+	if (link_event != NULL)
+		nwamd_event_enqueue(link_event);
+	else
+		nlog(LOG_ERR, "wpa_s_event_handler(%s): failed initializing "
+		    "wlan report event (%s)", ifname, ev_id);
+
+	nlog(LOG_DEBUG, "wpa_s_event_handler(%s): %s (%s)", ifname, ev_id,
+	    ev_extra);
+}
+
+static void *
+wpa_s_event_handler(void *arg)
+{
+	dladm_status_t status;
+	datalink_id_t linkid;
+
+	struct wpa_ctrl *ctrl_conn = NULL;
+	char ifname[MAXLINKNAMELEN];
+
+	nlog(LOG_DEBUG, "wpa_s_event_handler: wakeup");
+	if (arg != NULL) {
+		(void) memcpy(&linkid, arg, sizeof (linkid));
+		free(arg);
+	} else {
+		nlog(LOG_ERR, "wpa_s_event_handler: invalid args");
+		return (NULL);
+	}
+retry:
+	(void) memset(ifname, 0, sizeof (ifname));
+	status = dladm_wlan_validate(dld_handle, linkid, &ctrl_conn, ifname);
+	if (status != DLADM_STATUS_OK) {
+		if (status != DLADM_STATUS_LINKINVAL) {
+			nlog(LOG_ERR, "wpa_s_event_handler: failed "
+			    "validating wpa_s instance (err %d)", status);
+			if (status == DLADM_STATUS_NOTFOUND) {
+				nlog(LOG_ERR, "install wpa_supplicant pkg!!!");
+				return (NULL);
+			}
+			goto retry;
+		} else {
+			nlog(LOG_ERR, "wpa_s_event_handler: "
+			    "invalid link type (err %d)", status);
+			return (NULL);
+		}
+	}
+
+	if (wpa_ctrl_attach(ctrl_conn)) {
+		nlog(LOG_ERR, "wpa_s_event_handler: failed attaching to "
+		    "wpa_s instance ctrl_if socket");
+		wpa_ctrl_close(ctrl_conn);
+		goto retry;
+	}
+
+	if (wpa_ctrl_pending(ctrl_conn) < 0) {
+		nlog(LOG_ERR, "wpa_s_event_handler: "
+		    "Connection to wpa_supplicant lost. Returning");
+		(void) wpa_ctrl_detach(ctrl_conn);
+		wpa_ctrl_close(ctrl_conn);
+		goto retry;
+	}
+
+	nlog(LOG_DEBUG, "wpa_s_event_handler(%s): waiting wpa_s ctrl events",
+	    ifname);
+
+	for (;;) {
+		char *ev_id = NULL;
+		char *ev_extra = NULL;
+		int rc;
+
+		if ((rc = wpa_ctrl_pending(ctrl_conn)) < 0) {
+			nlog(LOG_ERR, "wpa_s_event_handler(%s): "
+			    "Connection to wpa_supplicant lost. Returning",
+			    ifname);
+			(void) wpa_ctrl_detach(ctrl_conn);
+			wpa_ctrl_close(ctrl_conn);
+			break;
+		} else if (rc == 0)
+			continue;
+
+		if (!wpa_get_event(ctrl_conn, &ev_id, &ev_extra))
+			continue;
+
+		(void) wpa_s_process_ctrl_event(ev_id, ev_extra, ifname);
+
+		free(ev_id);
+		if (ev_extra != NULL)
+			free(ev_extra);
+	}
+	goto retry;
+} /* THREAD */
+
+static int
+/* LINTED E_FUNC_ARG_UNUSED */
+nwamd_wpa_s_monitor_init(dladm_handle_t handle, datalink_id_t linkid, void *arg)
+{
+	int rc;
+	pthread_attr_t attr;
+	datalink_id_t *thp_linkid = NULL;
+
+	nlog(LOG_DEBUG, "nwamd_wpa_s_monitor_init");
+
+	rc = pthread_attr_init(&attr);
+	if (rc != 0) {
+		nlog(LOG_ERR, "nwamd_wpa_s_monitor_init: "
+		    "pthread_attr_init failed: %s", strerror(rc));
+		return (DLADM_WALK_CONTINUE);
+	}
+
+	rc = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+	if (rc != 0) {
+		nlog(LOG_ERR, "nwamd_wpa_s_monitor_init: "
+		    "pthread_attr_setdetachstate failed: %s",
+		    strerror(rc));
+		(void) pthread_attr_destroy(&attr);
+		return (DLADM_WALK_CONTINUE);
+	}
+
+	thp_linkid = malloc(sizeof (linkid));
+	if (thp_linkid == NULL)
+		return (DLADM_WALK_CONTINUE);
+
+	(void) memcpy(thp_linkid, &linkid, sizeof (linkid));
+
+	rc = pthread_create(NULL, &attr, wpa_s_event_handler, thp_linkid);
+	if (rc != 0) {
+		nlog(LOG_ERR, "nwamd_wpa_s_monitor_init: couldn't start "
+		    "wpa_s_event_handler thread: %s", strerror(rc));
+		(void) pthread_attr_destroy(&attr);
+		return (DLADM_WALK_CONTINUE);
+	}
+
+	return (DLADM_WALK_CONTINUE);
+}
+
+void
+nwamd_wpa_s_events_init(void)
+{
+	dladm_status_t status;
+
+	nlog(LOG_DEBUG, "nwamd_wpa_s_events_init");
+
+	status = dladm_walk_datalink_id(nwamd_wpa_s_monitor_init, dld_handle,
+	    NULL, DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_PERSIST);
+	if (status != DLADM_STATUS_OK)
+		nlog(LOG_ERR, "nwamd_wpa_s_events_init: failed while walking"
+		    " wifi links");
+}
+
+static int
+/* LINTED E_FUNC_ARG_UNUSED */
+nwamd_wpa_s_monitor_fini(dladm_handle_t handle, datalink_id_t linkid, void *arg)
+{
+	dladm_status_t	status;
+
+	nlog(LOG_DEBUG, "nwamd_wpa_s_monitor_fini");
+
+	status = dladm_wlan_disconnect(handle, linkid);
+	if (status != DLADM_STATUS_OK && status != DLADM_STATUS_LINKINVAL) {
+		char errbuf[DLADM_STRSIZE];
+		nlog(LOG_ERR, "nwamd_wpa_s_monitor_fini: dladm_wlan_disconnect "
+		    "returned. err(%d) %s", status,
+		    dladm_status2str(status, errbuf));
+		return (DLADM_WALK_CONTINUE);
+	}
+
+	return (DLADM_WALK_CONTINUE);
+}
+
+void
+nwamd_wpa_s_events_fini(void)
+{
+	dladm_status_t status;
+
+	nlog(LOG_DEBUG, "nwamd_wpa_s_events_fini");
+
+	status = dladm_walk_datalink_id(nwamd_wpa_s_monitor_fini, dld_handle,
+	    NULL, DATALINK_CLASS_PHYS, DL_WIFI, DLADM_OPT_PERSIST);
+	if (status != DLADM_STATUS_OK)
+		nlog(LOG_ERR, "nwamd_wpa_s_events_fini: failed to walk"
+		    " wifi links");
+}
--- a/usr/src/cmd/cmd-inet/usr.lib/Makefile	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/usr.lib/Makefile	Wed May 29 08:31:24 2013 +0200
@@ -26,7 +26,7 @@
 SUBDIRS=	bridged dhcp dsvclockd ilbd in.chargend in.daytimed \
 		in.discardd in.echod in.dhcpd in.mpathd in.ndpd \
 		in.ripngd in.timed inetd mdnsd ncaconfd pppoe \
-		slpd vrrpd wanboot wpad
+		slpd vrrpd wanboot wpa_supplicant
 
 MSGSUBDIRS=	dsvclockd ilbd in.dhcpd inetd ncaconfd vrrpd wanboot
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/Makefile	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,70 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
+# Use is subject to license terms.
+# Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
+#
+
+include	../../../Makefile.cmd
+
+SUBDIR =	wpa_supplicant
+MANIFEST =	wpa_supplicant.xml
+SVCMETHOD=	svc-wpa_supplicant
+
+ROOTMANIFESTDIR =	$(ROOTSVCNETWORK)
+
+$(ROOTMANIFEST):= FILEMODE = 0444
+$(ROOTSVCMETHOD):= FILEMODE = 0555
+
+WPADEFS =	defs.h
+WPACTRL =	wpa_ctrl.h
+COMMONDIR =	src/common
+WPAHDRDIR =	$(ROOT)/usr/include
+
+all:=		TARGET= all
+install:=	TARGET= install
+clean:=		TARGET= clean
+clobber:=	TARGET= clobber
+
+include ../Makefile.lib
+
+install_h:	$(WPADEFS) $(WPACTRL)
+
+all lint clean clobber:		$(SUBDIR)
+
+install:	install_h $(SUBDIR) $(ROOTMANIFEST) $(ROOTSVCMETHOD)
+
+check:		$(CHKMANIFEST)
+
+$(SUBDIR):	FRC
+		@cd $@; pwd; $(MAKE) $(TARGET)
+
+FRC:
+
+$(WPADEFS):
+	@cd $(COMMONDIR); $(RM) $(WPAHDRDIR)/wpa_defs.h; \
+	$(CP) $@ $(WPAHDRDIR)/wpa_defs.h; cd ../../
+
+$(WPACTRL):
+	@cd $(COMMONDIR); $(RM) $(WPAHDRDIR)/$@; \
+	$(CP) $@ $(WPAHDRDIR); cd ../../
+
+include ../../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/README	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,56 @@
+wpa_supplicant and hostapd
+--------------------------
+
+Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+All Rights Reserved.
+
+These programs are licensed under the BSD license (the one with
+advertisement clause removed).
+
+If you are submitting changes to the project, please see CONTRIBUTIONS
+file for more instructions.
+
+
+This package may include either wpa_supplicant, hostapd, or both. See
+README file respective subdirectories (wpa_supplicant/README or
+hostapd/README) for more details.
+
+Source code files were moved around in v0.6.x releases and compared to
+earlier releases, the programs are now built by first going to a
+subdirectory (wpa_supplicant or hostapd) and creating build
+configuration (.config) and running 'make' there (for Linux/BSD/cygwin
+builds).
+
+
+License
+-------
+
+This software may be distributed, used, and modified under the terms of
+BSD license:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name(s) of the above-listed copyright holder(s) nor the
+   names of its contributors may be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/THIRDPARTYLICENSE	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,22 @@
+wpa_supplicant and hostapd
+--------------------------
+
+Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+All Rights Reserved.
+
+
+See the README file for the current license terms.
+
+This software was previously distributed under BSD/GPL v2 dual license
+terms that allowed either of those license alternatives to be
+selected. As of February 11, 2012, the project has chosen to use only
+the BSD license option for future distribution. As such, the GPL v2
+license option is no longer used. It should be noted that the BSD
+license option (the one with advertisement clause removed) is compatible
+with GPL and as such, does not prevent use of this software in projects
+that use GPL.
+
+Some of the files may still include pointers to GPL version 2 license
+terms. However, such copyright and license notifications are maintained
+only for attribution purposes and any distribution of this software
+after February 11, 2012 is no longer under the GPL v2 option.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/THIRDPARTYLICENSE.descrip	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,1 @@
+PORTIONS OF WPA FUNCTIONALITY
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/ap/ap_config.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,539 @@
+/*
+ * hostapd / Configuration definitions and helpers functions
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HOSTAPD_CONFIG_H
+#define HOSTAPD_CONFIG_H
+
+#include "common/defs.h"
+#include "ip_addr.h"
+#include "common/wpa_common.h"
+#include "common/ieee802_11_common.h"
+#include "wps/wps.h"
+
+#define MAX_STA_COUNT 2007
+#define MAX_VLAN_ID 4094
+
+typedef u8 macaddr[ETH_ALEN];
+
+struct mac_acl_entry {
+	macaddr addr;
+	int vlan_id;
+};
+
+struct hostapd_radius_servers;
+struct ft_remote_r0kh;
+struct ft_remote_r1kh;
+
+#define HOSTAPD_MAX_SSID_LEN 32
+
+#define NUM_WEP_KEYS 4
+struct hostapd_wep_keys {
+	u8 idx;
+	u8 *key[NUM_WEP_KEYS];
+	size_t len[NUM_WEP_KEYS];
+	int keys_set;
+	size_t default_len; /* key length used for dynamic key generation */
+};
+
+typedef enum hostap_security_policy {
+	SECURITY_PLAINTEXT = 0,
+	SECURITY_STATIC_WEP = 1,
+	SECURITY_IEEE_802_1X = 2,
+	SECURITY_WPA_PSK = 3,
+	SECURITY_WPA = 4
+} secpolicy;
+
+struct hostapd_ssid {
+	u8 ssid[HOSTAPD_MAX_SSID_LEN];
+	size_t ssid_len;
+	unsigned int ssid_set:1;
+	unsigned int utf8_ssid:1;
+
+	char vlan[IFNAMSIZ + 1];
+	secpolicy security_policy;
+
+	struct hostapd_wpa_psk *wpa_psk;
+	char *wpa_passphrase;
+	char *wpa_psk_file;
+
+	struct hostapd_wep_keys wep;
+
+#define DYNAMIC_VLAN_DISABLED 0
+#define DYNAMIC_VLAN_OPTIONAL 1
+#define DYNAMIC_VLAN_REQUIRED 2
+	int dynamic_vlan;
+#define DYNAMIC_VLAN_NAMING_WITHOUT_DEVICE 0
+#define DYNAMIC_VLAN_NAMING_WITH_DEVICE 1
+#define DYNAMIC_VLAN_NAMING_END 2
+	int vlan_naming;
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	char *vlan_tagged_interface;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+	struct hostapd_wep_keys **dyn_vlan_keys;
+	size_t max_dyn_vlan_keys;
+};
+
+
+#define VLAN_ID_WILDCARD -1
+
+struct hostapd_vlan {
+	struct hostapd_vlan *next;
+	int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
+	char ifname[IFNAMSIZ + 1];
+	int dynamic_vlan;
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+
+#define DVLAN_CLEAN_BR 	0x1
+#define DVLAN_CLEAN_VLAN	0x2
+#define DVLAN_CLEAN_VLAN_PORT	0x4
+#define DVLAN_CLEAN_WLAN_PORT	0x8
+	int clean;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+};
+
+#define PMK_LEN 32
+struct hostapd_sta_wpa_psk_short {
+	struct hostapd_sta_wpa_psk_short *next;
+	u8 psk[PMK_LEN];
+};
+
+struct hostapd_wpa_psk {
+	struct hostapd_wpa_psk *next;
+	int group;
+	u8 psk[PMK_LEN];
+	u8 addr[ETH_ALEN];
+};
+
+struct hostapd_eap_user {
+	struct hostapd_eap_user *next;
+	u8 *identity;
+	size_t identity_len;
+	struct {
+		int vendor;
+		u32 method;
+	} methods[EAP_MAX_METHODS];
+	u8 *password;
+	size_t password_len;
+	int phase2;
+	int force_version;
+	unsigned int wildcard_prefix:1;
+	unsigned int password_hash:1; /* whether password is hashed with
+				       * nt_password_hash() */
+	int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
+};
+
+struct hostapd_radius_attr {
+	u8 type;
+	struct wpabuf *val;
+	struct hostapd_radius_attr *next;
+};
+
+
+#define NUM_TX_QUEUES 4
+
+struct hostapd_tx_queue_params {
+	int aifs;
+	int cwmin;
+	int cwmax;
+	int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
+};
+
+
+#define MAX_ROAMING_CONSORTIUM_LEN 15
+
+struct hostapd_roaming_consortium {
+	u8 len;
+	u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
+};
+
+struct hostapd_lang_string {
+	u8 lang[3];
+	u8 name_len;
+	u8 name[252];
+};
+
+#define MAX_NAI_REALMS 10
+#define MAX_NAI_REALMLEN 255
+#define MAX_NAI_EAP_METHODS 5
+#define MAX_NAI_AUTH_TYPES 4
+struct hostapd_nai_realm_data {
+	u8 encoding;
+	char realm_buf[MAX_NAI_REALMLEN + 1];
+	char *realm[MAX_NAI_REALMS];
+	u8 eap_method_count;
+	struct hostapd_nai_realm_eap {
+		u8 eap_method;
+		u8 num_auths;
+		u8 auth_id[MAX_NAI_AUTH_TYPES];
+		u8 auth_val[MAX_NAI_AUTH_TYPES];
+	} eap_method[MAX_NAI_EAP_METHODS];
+};
+
+/**
+ * struct hostapd_bss_config - Per-BSS configuration
+ */
+struct hostapd_bss_config {
+	char iface[IFNAMSIZ + 1];
+	char bridge[IFNAMSIZ + 1];
+	char wds_bridge[IFNAMSIZ + 1];
+
+	enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
+
+	unsigned int logger_syslog; /* module bitfield */
+	unsigned int logger_stdout; /* module bitfield */
+
+	char *dump_log_name; /* file name for state dump (SIGUSR1) */
+
+	int max_num_sta; /* maximum number of STAs in station table */
+
+	int dtim_period;
+
+	int ieee802_1x; /* use IEEE 802.1X */
+	int eapol_version;
+	int eap_server; /* Use internal EAP server instead of external
+			 * RADIUS server */
+	struct hostapd_eap_user *eap_user;
+	char *eap_user_sqlite;
+	char *eap_sim_db;
+	struct hostapd_ip_addr own_ip_addr;
+	char *nas_identifier;
+	struct hostapd_radius_servers *radius;
+	int acct_interim_interval;
+	int radius_request_cui;
+	struct hostapd_radius_attr *radius_auth_req_attr;
+	struct hostapd_radius_attr *radius_acct_req_attr;
+	int radius_das_port;
+	unsigned int radius_das_time_window;
+	int radius_das_require_event_timestamp;
+	struct hostapd_ip_addr radius_das_client_addr;
+	u8 *radius_das_shared_secret;
+	size_t radius_das_shared_secret_len;
+
+	struct hostapd_ssid ssid;
+
+	char *eap_req_id_text; /* optional displayable message sent with
+				* EAP Request-Identity */
+	size_t eap_req_id_text_len;
+	int eapol_key_index_workaround;
+
+	size_t default_wep_key_len;
+	int individual_wep_key_len;
+	int wep_rekeying_period;
+	int broadcast_key_idx_min, broadcast_key_idx_max;
+	int eap_reauth_period;
+
+	int ieee802_11f; /* use IEEE 802.11f (IAPP) */
+	char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
+					* frames */
+
+	enum {
+		ACCEPT_UNLESS_DENIED = 0,
+		DENY_UNLESS_ACCEPTED = 1,
+		USE_EXTERNAL_RADIUS_AUTH = 2
+	} macaddr_acl;
+	struct mac_acl_entry *accept_mac;
+	int num_accept_mac;
+	struct mac_acl_entry *deny_mac;
+	int num_deny_mac;
+	int wds_sta;
+	int isolate;
+
+	int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
+			* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
+
+	int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
+	int wpa_key_mgmt;
+#ifdef CONFIG_IEEE80211W
+	enum mfp_options ieee80211w;
+	/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
+	unsigned int assoc_sa_query_max_timeout;
+	/* dot11AssociationSAQueryRetryTimeout (in TUs) */
+	int assoc_sa_query_retry_timeout;
+#endif /* CONFIG_IEEE80211W */
+	enum {
+		PSK_RADIUS_IGNORED = 0,
+		PSK_RADIUS_ACCEPTED = 1,
+		PSK_RADIUS_REQUIRED = 2
+	} wpa_psk_radius;
+	int wpa_pairwise;
+	int wpa_group;
+	int wpa_group_rekey;
+	int wpa_strict_rekey;
+	int wpa_gmk_rekey;
+	int wpa_ptk_rekey;
+	int rsn_pairwise;
+	int rsn_preauth;
+	char *rsn_preauth_interfaces;
+	int peerkey;
+
+#ifdef CONFIG_IEEE80211R
+	/* IEEE 802.11r - Fast BSS Transition */
+	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
+	u8 r1_key_holder[FT_R1KH_ID_LEN];
+	u32 r0_key_lifetime;
+	u32 reassociation_deadline;
+	struct ft_remote_r0kh *r0kh_list;
+	struct ft_remote_r1kh *r1kh_list;
+	int pmk_r1_push;
+	int ft_over_ds;
+#endif /* CONFIG_IEEE80211R */
+
+	char *ctrl_interface; /* directory for UNIX domain sockets */
+#ifndef CONFIG_NATIVE_WINDOWS
+	gid_t ctrl_interface_gid;
+#endif /* CONFIG_NATIVE_WINDOWS */
+	int ctrl_interface_gid_set;
+
+	char *ca_cert;
+	char *server_cert;
+	char *private_key;
+	char *private_key_passwd;
+	int check_crl;
+	char *dh_file;
+	u8 *pac_opaque_encr_key;
+	u8 *eap_fast_a_id;
+	size_t eap_fast_a_id_len;
+	char *eap_fast_a_id_info;
+	int eap_fast_prov;
+	int pac_key_lifetime;
+	int pac_key_refresh_time;
+	int eap_sim_aka_result_ind;
+	int tnc;
+	int fragment_size;
+	u16 pwd_group;
+
+	char *radius_server_clients;
+	int radius_server_auth_port;
+	int radius_server_ipv6;
+
+	char *test_socket; /* UNIX domain socket path for driver_test */
+
+	int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group
+				 * address instead of individual address
+				 * (for driver_wired.c).
+				 */
+
+	int ap_max_inactivity;
+	int ignore_broadcast_ssid;
+
+	int wmm_enabled;
+	int wmm_uapsd;
+
+	struct hostapd_vlan *vlan, *vlan_tail;
+
+	macaddr bssid;
+
+	/*
+	 * Maximum listen interval that STAs can use when associating with this
+	 * BSS. If a STA tries to use larger value, the association will be
+	 * denied with status code 51.
+	 */
+	u16 max_listen_interval;
+
+	int disable_pmksa_caching;
+	int okc; /* Opportunistic Key Caching */
+
+	int wps_state;
+#ifdef CONFIG_WPS
+	int ap_setup_locked;
+	u8 uuid[16];
+	char *wps_pin_requests;
+	char *device_name;
+	char *manufacturer;
+	char *model_name;
+	char *model_number;
+	char *serial_number;
+	u8 device_type[WPS_DEV_TYPE_LEN];
+	char *config_methods;
+	u8 os_version[4];
+	char *ap_pin;
+	int skip_cred_build;
+	u8 *extra_cred;
+	size_t extra_cred_len;
+	int wps_cred_processing;
+	u8 *ap_settings;
+	size_t ap_settings_len;
+	char *upnp_iface;
+	char *friendly_name;
+	char *manufacturer_url;
+	char *model_description;
+	char *model_url;
+	char *upc;
+	struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+	int wps_nfc_dev_pw_id;
+	struct wpabuf *wps_nfc_dh_pubkey;
+	struct wpabuf *wps_nfc_dh_privkey;
+	struct wpabuf *wps_nfc_dev_pw;
+#endif /* CONFIG_WPS */
+	int pbc_in_m1;
+
+#define P2P_ENABLED BIT(0)
+#define P2P_GROUP_OWNER BIT(1)
+#define P2P_GROUP_FORMATION BIT(2)
+#define P2P_MANAGE BIT(3)
+#define P2P_ALLOW_CROSS_CONNECTION BIT(4)
+	int p2p;
+
+	int disassoc_low_ack;
+	int skip_inactivity_poll;
+
+#define TDLS_PROHIBIT BIT(0)
+#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
+	int tdls;
+	int disable_11n;
+	int disable_11ac;
+
+	/* IEEE 802.11v */
+	int time_advertisement;
+	char *time_zone;
+	int wnm_sleep_mode;
+	int bss_transition;
+
+	/* IEEE 802.11u - Interworking */
+	int interworking;
+	int access_network_type;
+	int internet;
+	int asra;
+	int esr;
+	int uesa;
+	int venue_info_set;
+	u8 venue_group;
+	u8 venue_type;
+	u8 hessid[ETH_ALEN];
+
+	/* IEEE 802.11u - Roaming Consortium list */
+	unsigned int roaming_consortium_count;
+	struct hostapd_roaming_consortium *roaming_consortium;
+
+	/* IEEE 802.11u - Venue Name duples */
+	unsigned int venue_name_count;
+	struct hostapd_lang_string *venue_name;
+
+	/* IEEE 802.11u - Network Authentication Type */
+	u8 *network_auth_type;
+	size_t network_auth_type_len;
+
+	/* IEEE 802.11u - IP Address Type Availability */
+	u8 ipaddr_type_availability;
+	u8 ipaddr_type_configured;
+
+	/* IEEE 802.11u - 3GPP Cellular Network */
+	u8 *anqp_3gpp_cell_net;
+	size_t anqp_3gpp_cell_net_len;
+
+	/* IEEE 802.11u - Domain Name */
+	u8 *domain_name;
+	size_t domain_name_len;
+
+	unsigned int nai_realm_count;
+	struct hostapd_nai_realm_data *nai_realm_data;
+
+	u16 gas_comeback_delay;
+	int gas_frag_limit;
+
+#ifdef CONFIG_HS20
+	int hs20;
+	int disable_dgaf;
+	unsigned int hs20_oper_friendly_name_count;
+	struct hostapd_lang_string *hs20_oper_friendly_name;
+	u8 *hs20_wan_metrics;
+	u8 *hs20_connection_capability;
+	size_t hs20_connection_capability_len;
+	u8 *hs20_operating_class;
+	u8 hs20_operating_class_len;
+#endif /* CONFIG_HS20 */
+
+	u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
+
+#ifdef CONFIG_RADIUS_TEST
+	char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
+
+	struct wpabuf *vendor_elements;
+};
+
+
+/**
+ * struct hostapd_config - Per-radio interface configuration
+ */
+struct hostapd_config {
+	struct hostapd_bss_config *bss, *last_bss;
+	size_t num_bss;
+
+	u16 beacon_int;
+	int rts_threshold;
+	int fragm_threshold;
+	u8 send_probe_response;
+	u8 channel;
+	enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
+	enum {
+		LONG_PREAMBLE = 0,
+		SHORT_PREAMBLE = 1
+	} preamble;
+
+	int *supported_rates;
+	int *basic_rates;
+
+	const struct wpa_driver_ops *driver;
+
+	int ap_table_max_size;
+	int ap_table_expiration_time;
+
+	char country[3]; /* first two octets: country code as described in
+			  * ISO/IEC 3166-1. Third octet:
+			  * ' ' (ascii 32): all environments
+			  * 'O': Outdoor environemnt only
+			  * 'I': Indoor environment only
+			  */
+
+	int ieee80211d;
+
+	struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
+
+	/*
+	 * WMM AC parameters, in same order as 802.1D, i.e.
+	 * 0 = BE (best effort)
+	 * 1 = BK (background)
+	 * 2 = VI (video)
+	 * 3 = VO (voice)
+	 */
+	struct hostapd_wmm_ac_params wmm_ac_params[4];
+
+	int ht_op_mode_fixed;
+	u16 ht_capab;
+	int ieee80211n;
+	int secondary_channel;
+	int require_ht;
+	u32 vht_capab;
+	int ieee80211ac;
+	int require_vht;
+	u8 vht_oper_chwidth;
+	u8 vht_oper_centr_freq_seg0_idx;
+	u8 vht_oper_centr_freq_seg1_idx;
+};
+
+
+int hostapd_mac_comp(const void *a, const void *b);
+int hostapd_mac_comp_empty(const void *a);
+struct hostapd_config * hostapd_config_defaults(void);
+void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
+void hostapd_config_free(struct hostapd_config *conf);
+int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
+			  const u8 *addr, int *vlan_id);
+int hostapd_rate_found(int *list, int rate);
+int hostapd_wep_key_cmp(struct hostapd_wep_keys *a,
+			struct hostapd_wep_keys *b);
+const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
+			   const u8 *addr, const u8 *prev_psk);
+int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
+					int vlan_id);
+struct hostapd_radius_attr *
+hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
+
+#endif /* HOSTAPD_CONFIG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/ap/hostapd.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,309 @@
+/*
+ * hostapd / Initialization and configuration
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HOSTAPD_H
+#define HOSTAPD_H
+
+#include "common/defs.h"
+#include "ap_config.h"
+
+struct wpa_driver_ops;
+struct wpa_ctrl_dst;
+struct radius_server_data;
+struct upnp_wps_device_sm;
+struct hostapd_data;
+struct sta_info;
+struct hostap_sta_driver_data;
+struct ieee80211_ht_capabilities;
+struct full_dynamic_vlan;
+enum wps_event;
+union wps_event_data;
+
+struct hostapd_iface;
+
+struct hapd_interfaces {
+	int (*reload_config)(struct hostapd_iface *iface);
+	struct hostapd_config * (*config_read_cb)(const char *config_fname);
+	int (*ctrl_iface_init)(struct hostapd_data *hapd);
+	void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
+	int (*for_each_interface)(struct hapd_interfaces *interfaces,
+				  int (*cb)(struct hostapd_iface *iface,
+					    void *ctx), void *ctx);
+	int (*driver_init)(struct hostapd_iface *iface);
+
+	size_t count;
+	int global_ctrl_sock;
+	char *global_iface_path;
+	char *global_iface_name;
+	struct hostapd_iface **iface;
+};
+
+
+struct hostapd_probereq_cb {
+	int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid,
+		  const u8 *ie, size_t ie_len, int ssi_signal);
+	void *ctx;
+};
+
+#define HOSTAPD_RATE_BASIC 0x00000001
+
+struct hostapd_rate_data {
+	int rate; /* rate in 100 kbps */
+	int flags; /* HOSTAPD_RATE_ flags */
+};
+
+struct hostapd_frame_info {
+	u32 channel;
+	u32 datarate;
+	int ssi_signal; /* dBm */
+};
+
+
+/**
+ * struct hostapd_data - hostapd per-BSS data structure
+ */
+struct hostapd_data {
+	struct hostapd_iface *iface;
+	struct hostapd_config *iconf;
+	struct hostapd_bss_config *conf;
+	int interface_added; /* virtual interface added for this BSS */
+
+	u8 own_addr[ETH_ALEN];
+
+	int num_sta; /* number of entries in sta_list */
+	struct sta_info *sta_list; /* STA info list head */
+#define STA_HASH_SIZE 256
+#define STA_HASH(sta) (sta[5])
+	struct sta_info *sta_hash[STA_HASH_SIZE];
+
+	/*
+	 * Bitfield for indicating which AIDs are allocated. Only AID values
+	 * 1-2007 are used and as such, the bit at index 0 corresponds to AID
+	 * 1.
+	 */
+#define AID_WORDS ((2008 + 31) / 32)
+	u32 sta_aid[AID_WORDS];
+
+	const struct wpa_driver_ops *driver;
+	void *drv_priv;
+
+	void (*new_assoc_sta_cb)(struct hostapd_data *hapd,
+				 struct sta_info *sta, int reassoc);
+
+	void *msg_ctx; /* ctx for wpa_msg() calls */
+	void *msg_ctx_parent; /* parent interface ctx for wpa_msg() calls */
+
+	struct radius_client_data *radius;
+	u32 acct_session_id_hi, acct_session_id_lo;
+	struct radius_das_data *radius_das;
+
+	struct iapp_data *iapp;
+
+	struct hostapd_cached_radius_acl *acl_cache;
+	struct hostapd_acl_query_data *acl_queries;
+
+	struct wpa_authenticator *wpa_auth;
+	struct eapol_authenticator *eapol_auth;
+
+	struct rsn_preauth_interface *preauth_iface;
+	time_t michael_mic_failure;
+	int michael_mic_failures;
+	int tkip_countermeasures;
+
+	int ctrl_sock;
+	struct wpa_ctrl_dst *ctrl_dst;
+
+	void *ssl_ctx;
+	void *eap_sim_db_priv;
+	struct radius_server_data *radius_srv;
+
+	int parameter_set_count;
+
+	/* Time Advertisement */
+	u8 time_update_counter;
+	struct wpabuf *time_adv;
+
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	struct full_dynamic_vlan *full_dynamic_vlan;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+	struct l2_packet_data *l2;
+	struct wps_context *wps;
+
+	int beacon_set_done;
+	struct wpabuf *wps_beacon_ie;
+	struct wpabuf *wps_probe_resp_ie;
+#ifdef CONFIG_WPS
+	unsigned int ap_pin_failures;
+	unsigned int ap_pin_failures_consecutive;
+	struct upnp_wps_device_sm *wps_upnp;
+	unsigned int ap_pin_lockout_time;
+#endif /* CONFIG_WPS */
+
+	struct hostapd_probereq_cb *probereq_cb;
+	size_t num_probereq_cb;
+
+	void (*public_action_cb)(void *ctx, const u8 *buf, size_t len,
+				 int freq);
+	void *public_action_cb_ctx;
+
+	int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len,
+				int freq);
+	void *vendor_action_cb_ctx;
+
+	void (*wps_reg_success_cb)(void *ctx, const u8 *mac_addr,
+				   const u8 *uuid_e);
+	void *wps_reg_success_cb_ctx;
+
+	void (*wps_event_cb)(void *ctx, enum wps_event event,
+			     union wps_event_data *data);
+	void *wps_event_cb_ctx;
+
+	void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr,
+				  int authorized, const u8 *p2p_dev_addr);
+	void *sta_authorized_cb_ctx;
+
+	void (*setup_complete_cb)(void *ctx);
+	void *setup_complete_cb_ctx;
+
+#ifdef CONFIG_P2P
+	struct p2p_data *p2p;
+	struct p2p_group *p2p_group;
+	struct wpabuf *p2p_beacon_ie;
+	struct wpabuf *p2p_probe_resp_ie;
+
+	/* Number of non-P2P association stations */
+	int num_sta_no_p2p;
+
+	/* Periodic NoA (used only when no non-P2P clients in the group) */
+	int noa_enabled;
+	int noa_start;
+	int noa_duration;
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+	size_t gas_frag_limit;
+#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_SQLITE
+	struct hostapd_eap_user tmp_eap_user;
+#endif /* CONFIG_SQLITE */
+};
+
+
+/**
+ * struct hostapd_iface - hostapd per-interface data structure
+ */
+struct hostapd_iface {
+	struct hapd_interfaces *interfaces;
+	void *owner;
+	char *config_fname;
+	struct hostapd_config *conf;
+
+	size_t num_bss;
+	struct hostapd_data **bss;
+
+	int num_ap; /* number of entries in ap_list */
+	struct ap_info *ap_list; /* AP info list head */
+	struct ap_info *ap_hash[STA_HASH_SIZE];
+	struct ap_info *ap_iter_list;
+
+	unsigned int drv_flags;
+
+	/*
+	 * A bitmap of supported protocols for probe response offload. See
+	 * struct wpa_driver_capa in driver.h
+	 */
+	unsigned int probe_resp_offloads;
+
+	struct hostapd_hw_modes *hw_features;
+	int num_hw_features;
+	struct hostapd_hw_modes *current_mode;
+	/* Rates that are currently used (i.e., filtered copy of
+	 * current_mode->channels */
+	int num_rates;
+	struct hostapd_rate_data *current_rates;
+	int *basic_rates;
+	int freq;
+
+	u16 hw_flags;
+
+	/* Number of associated Non-ERP stations (i.e., stations using 802.11b
+	 * in 802.11g BSS) */
+	int num_sta_non_erp;
+
+	/* Number of associated stations that do not support Short Slot Time */
+	int num_sta_no_short_slot_time;
+
+	/* Number of associated stations that do not support Short Preamble */
+	int num_sta_no_short_preamble;
+
+	int olbc; /* Overlapping Legacy BSS Condition */
+
+	/* Number of HT associated stations that do not support greenfield */
+	int num_sta_ht_no_gf;
+
+	/* Number of associated non-HT stations */
+	int num_sta_no_ht;
+
+	/* Number of HT associated stations 20 MHz */
+	int num_sta_ht_20mhz;
+
+	/* Overlapping BSS information */
+	int olbc_ht;
+
+	u16 ht_op_mode;
+	void (*scan_cb)(struct hostapd_iface *iface);
+};
+
+/* hostapd.c */
+int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
+			       int (*cb)(struct hostapd_iface *iface,
+					 void *ctx), void *ctx);
+int hostapd_reload_config(struct hostapd_iface *iface);
+struct hostapd_data *
+hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
+		       struct hostapd_config *conf,
+		       struct hostapd_bss_config *bss);
+int hostapd_setup_interface(struct hostapd_iface *iface);
+int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
+void hostapd_interface_deinit(struct hostapd_iface *iface);
+void hostapd_interface_free(struct hostapd_iface *iface);
+void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			   int reassoc);
+void hostapd_interface_deinit_free(struct hostapd_iface *iface);
+int hostapd_enable_iface(struct hostapd_iface *hapd_iface);
+int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
+int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
+int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
+int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
+
+/* utils.c */
+int hostapd_register_probereq_cb(struct hostapd_data *hapd,
+				 int (*cb)(void *ctx, const u8 *sa,
+					   const u8 *da, const u8 *bssid,
+					   const u8 *ie, size_t ie_len,
+					   int ssi_signal),
+				 void *ctx);
+void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
+
+/* drv_callbacks.c (TODO: move to somewhere else?) */
+int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
+			const u8 *ie, size_t ielen, int reassoc);
+void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
+void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
+int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
+			 const u8 *bssid, const u8 *ie, size_t ie_len,
+			 int ssi_signal);
+void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
+			     int offset);
+
+const struct hostapd_eap_user *
+hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
+		     size_t identity_len, int phase2);
+
+#endif /* HOSTAPD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/defs.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,325 @@
+/*
+ * WPA Supplicant - Common definitions
+ * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DEFS_H
+#define DEFS_H
+
+#ifdef FALSE
+#undef FALSE
+#endif
+#ifdef TRUE
+#undef TRUE
+#endif
+typedef enum { FALSE = 0, TRUE = 1 } Boolean;
+
+#ifndef _WPASILLUMOS
+#define BIT(x) (1 << (x))
+#endif /* _WPASILLUMOS */
+
+#define WPA_CIPHER_NONE BIT(0)
+#define WPA_CIPHER_WEP40 BIT(1)
+#define WPA_CIPHER_WEP104 BIT(2)
+#define WPA_CIPHER_TKIP BIT(3)
+#define WPA_CIPHER_CCMP BIT(4)
+#ifdef CONFIG_IEEE80211W
+#define WPA_CIPHER_AES_128_CMAC BIT(5)
+#endif /* CONFIG_IEEE80211W */
+#define WPA_CIPHER_GCMP BIT(6)
+#define WPA_CIPHER_SMS4 BIT(7)
+
+#define WPA_KEY_MGMT_IEEE8021X BIT(0)
+#define WPA_KEY_MGMT_PSK BIT(1)
+#define WPA_KEY_MGMT_NONE BIT(2)
+#define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3)
+#define WPA_KEY_MGMT_WPA_NONE BIT(4)
+#define WPA_KEY_MGMT_FT_IEEE8021X BIT(5)
+#define WPA_KEY_MGMT_FT_PSK BIT(6)
+#define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
+#define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
+#define WPA_KEY_MGMT_WPS BIT(9)
+#define WPA_KEY_MGMT_SAE BIT(10)
+#define WPA_KEY_MGMT_FT_SAE BIT(11)
+#define WPA_KEY_MGMT_WAPI_PSK BIT(12)
+#define WPA_KEY_MGMT_WAPI_CERT BIT(13)
+#define WPA_KEY_MGMT_CCKM BIT(14)
+
+#ifdef _WPASILLUMOS
+static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
+			 WPA_KEY_MGMT_FT_IEEE8021X |
+			 WPA_KEY_MGMT_CCKM |
+			 WPA_KEY_MGMT_IEEE8021X_SHA256));
+}
+
+static inline int wpa_key_mgmt_wpa_psk(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_PSK |
+			 WPA_KEY_MGMT_FT_PSK |
+			 WPA_KEY_MGMT_PSK_SHA256 |
+			 WPA_KEY_MGMT_SAE));
+}
+
+static inline int wpa_key_mgmt_ft(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_FT_PSK |
+			 WPA_KEY_MGMT_FT_IEEE8021X |
+			 WPA_KEY_MGMT_FT_SAE));
+}
+
+static inline int wpa_key_mgmt_sae(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_SAE |
+			 WPA_KEY_MGMT_FT_SAE));
+}
+
+static inline int wpa_key_mgmt_sha256(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
+			 WPA_KEY_MGMT_IEEE8021X_SHA256));
+}
+
+static inline int wpa_key_mgmt_wpa(int akm)
+{
+	return wpa_key_mgmt_wpa_ieee8021x(akm) ||
+		wpa_key_mgmt_wpa_psk(akm);
+}
+
+static inline int wpa_key_mgmt_wpa_any(int akm)
+{
+	return wpa_key_mgmt_wpa(akm) || (akm & WPA_KEY_MGMT_WPA_NONE);
+}
+
+static inline int wpa_key_mgmt_cckm(int akm)
+{
+	return akm == WPA_KEY_MGMT_CCKM;
+}
+#endif /* _WPASILLUMOS */
+
+#define WPA_PROTO_WPA BIT(0)
+#define WPA_PROTO_RSN BIT(1)
+#define WPA_PROTO_WAPI BIT(2)
+
+#define WPA_AUTH_ALG_OPEN BIT(0)
+#define WPA_AUTH_ALG_SHARED BIT(1)
+#define WPA_AUTH_ALG_LEAP BIT(2)
+#define WPA_AUTH_ALG_FT BIT(3)
+#define WPA_AUTH_ALG_SAE BIT(4)
+
+
+enum wpa_alg {
+	WPA_ALG_NONE,
+	WPA_ALG_WEP,
+	WPA_ALG_TKIP,
+	WPA_ALG_CCMP,
+	WPA_ALG_IGTK,
+	WPA_ALG_PMK,
+	WPA_ALG_GCMP,
+	WPA_ALG_SMS4,
+	WPA_ALG_KRK
+};
+
+/**
+ * enum wpa_cipher - Cipher suites
+ */
+enum wpa_cipher {
+	CIPHER_NONE,
+	CIPHER_WEP40,
+	CIPHER_TKIP,
+	CIPHER_CCMP,
+	CIPHER_WEP104,
+	CIPHER_GCMP,
+	CIPHER_SMS4
+};
+
+/**
+ * enum wpa_key_mgmt - Key management suites
+ */
+enum wpa_key_mgmt {
+	KEY_MGMT_802_1X,
+	KEY_MGMT_PSK,
+	KEY_MGMT_NONE,
+	KEY_MGMT_802_1X_NO_WPA,
+	KEY_MGMT_WPA_NONE,
+	KEY_MGMT_FT_802_1X,
+	KEY_MGMT_FT_PSK,
+	KEY_MGMT_802_1X_SHA256,
+	KEY_MGMT_PSK_SHA256,
+	KEY_MGMT_WPS,
+	KEY_MGMT_SAE,
+	KEY_MGMT_FT_SAE,
+	KEY_MGMT_WAPI_PSK,
+	KEY_MGMT_WAPI_CERT,
+	KEY_MGMT_CCKM
+};
+
+/**
+ * enum wpa_states - wpa_supplicant state
+ *
+ * These enumeration values are used to indicate the current wpa_supplicant
+ * state (wpa_s->wpa_state). The current state can be retrieved with
+ * wpa_supplicant_get_state() function and the state can be changed by calling
+ * wpa_supplicant_set_state(). In WPA state machine (wpa.c and preauth.c), the
+ * wrapper functions wpa_sm_get_state() and wpa_sm_set_state() should be used
+ * to access the state variable.
+ */
+enum wpa_states {
+	/**
+	 * WPA_DISCONNECTED - Disconnected state
+	 *
+	 * This state indicates that client is not associated, but is likely to
+	 * start looking for an access point. This state is entered when a
+	 * connection is lost.
+	 */
+	WPA_DISCONNECTED,
+
+	/**
+	 * WPA_INTERFACE_DISABLED - Interface disabled
+	 *
+	 * This stat eis entered if the network interface is disabled, e.g.,
+	 * due to rfkill. wpa_supplicant refuses any new operations that would
+	 * use the radio until the interface has been enabled.
+	 */
+	WPA_INTERFACE_DISABLED,
+
+	/**
+	 * WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
+	 *
+	 * This state is entered if there are no enabled networks in the
+	 * configuration. wpa_supplicant is not trying to associate with a new
+	 * network and external interaction (e.g., ctrl_iface call to add or
+	 * enable a network) is needed to start association.
+	 */
+	WPA_INACTIVE,
+
+	/**
+	 * WPA_SCANNING - Scanning for a network
+	 *
+	 * This state is entered when wpa_supplicant starts scanning for a
+	 * network.
+	 */
+	WPA_SCANNING,
+
+	/**
+	 * WPA_AUTHENTICATING - Trying to authenticate with a BSS/SSID
+	 *
+	 * This state is entered when wpa_supplicant has found a suitable BSS
+	 * to authenticate with and the driver is configured to try to
+	 * authenticate with this BSS. This state is used only with drivers
+	 * that use wpa_supplicant as the SME.
+	 */
+	WPA_AUTHENTICATING,
+
+	/**
+	 * WPA_ASSOCIATING - Trying to associate with a BSS/SSID
+	 *
+	 * This state is entered when wpa_supplicant has found a suitable BSS
+	 * to associate with and the driver is configured to try to associate
+	 * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this
+	 * state is entered when the driver is configured to try to associate
+	 * with a network using the configured SSID and security policy.
+	 */
+	WPA_ASSOCIATING,
+
+	/**
+	 * WPA_ASSOCIATED - Association completed
+	 *
+	 * This state is entered when the driver reports that association has
+	 * been successfully completed with an AP. If IEEE 802.1X is used
+	 * (with or without WPA/WPA2), wpa_supplicant remains in this state
+	 * until the IEEE 802.1X/EAPOL authentication has been completed.
+	 */
+	WPA_ASSOCIATED,
+
+	/**
+	 * WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress
+	 *
+	 * This state is entered when WPA/WPA2 4-Way Handshake is started. In
+	 * case of WPA-PSK, this happens when receiving the first EAPOL-Key
+	 * frame after association. In case of WPA-EAP, this state is entered
+	 * when the IEEE 802.1X/EAPOL authentication has been completed.
+	 */
+	WPA_4WAY_HANDSHAKE,
+
+	/**
+	 * WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress
+	 *
+	 * This state is entered when 4-Way Key Handshake has been completed
+	 * (i.e., when the supplicant sends out message 4/4) and when Group
+	 * Key rekeying is started by the AP (i.e., when supplicant receives
+	 * message 1/2).
+	 */
+	WPA_GROUP_HANDSHAKE,
+
+	/**
+	 * WPA_COMPLETED - All authentication completed
+	 *
+	 * This state is entered when the full authentication process is
+	 * completed. In case of WPA2, this happens when the 4-Way Handshake is
+	 * successfully completed. With WPA, this state is entered after the
+	 * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is
+	 * completed after dynamic keys are received (or if not used, after
+	 * the EAP authentication has been completed). With static WEP keys and
+	 * plaintext connections, this state is entered when an association
+	 * has been completed.
+	 *
+	 * This state indicates that the supplicant has completed its
+	 * processing for the association phase and that data connection is
+	 * fully configured.
+	 */
+	WPA_COMPLETED
+};
+
+#define MLME_SETPROTECTION_PROTECT_TYPE_NONE 0
+#define MLME_SETPROTECTION_PROTECT_TYPE_RX 1
+#define MLME_SETPROTECTION_PROTECT_TYPE_TX 2
+#define MLME_SETPROTECTION_PROTECT_TYPE_RX_TX 3
+
+#define MLME_SETPROTECTION_KEY_TYPE_GROUP 0
+#define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1
+
+
+/**
+ * enum mfp_options - Management frame protection (IEEE 802.11w) options
+ */
+enum mfp_options {
+	NO_MGMT_FRAME_PROTECTION = 0,
+	MGMT_FRAME_PROTECTION_OPTIONAL = 1,
+	MGMT_FRAME_PROTECTION_REQUIRED = 2
+};
+#define MGMT_FRAME_PROTECTION_DEFAULT 3
+
+/**
+ * enum hostapd_hw_mode - Hardware mode
+ */
+enum hostapd_hw_mode {
+	HOSTAPD_MODE_IEEE80211B,
+	HOSTAPD_MODE_IEEE80211G,
+	HOSTAPD_MODE_IEEE80211A,
+	HOSTAPD_MODE_IEEE80211AD,
+	NUM_HOSTAPD_MODES
+};
+
+/**
+ * enum wpa_ctrl_req_type - Control interface request types
+ */
+enum wpa_ctrl_req_type {
+	WPA_CTRL_REQ_UNKNOWN,
+	WPA_CTRL_REQ_EAP_IDENTITY,
+	WPA_CTRL_REQ_EAP_PASSWORD,
+	WPA_CTRL_REQ_EAP_NEW_PASSWORD,
+	WPA_CTRL_REQ_EAP_PIN,
+	WPA_CTRL_REQ_EAP_OTP,
+	WPA_CTRL_REQ_EAP_PASSPHRASE,
+	NUM_WPA_CTRL_REQS
+};
+
+/* Maximum number of EAP methods to store for EAP server user information */
+#define EAP_MAX_METHODS 8
+
+#endif /* DEFS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/eapol_common.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,81 @@
+/*
+ * EAPOL definitions shared between hostapd and wpa_supplicant
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAPOL_COMMON_H
+#define EAPOL_COMMON_H
+
+/* IEEE Std 802.1X-2004 */
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct ieee802_1x_hdr {
+	u8 version;
+	u8 type;
+	be16 length;
+	/* followed by length octets of data */
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#define EAPOL_VERSION 2
+
+enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
+       IEEE802_1X_TYPE_EAPOL_START = 1,
+       IEEE802_1X_TYPE_EAPOL_LOGOFF = 2,
+       IEEE802_1X_TYPE_EAPOL_KEY = 3,
+       IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4
+};
+
+enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
+       EAPOL_KEY_TYPE_WPA = 254 };
+
+
+#define IEEE8021X_REPLAY_COUNTER_LEN 8
+#define IEEE8021X_KEY_SIGN_LEN 16
+#define IEEE8021X_KEY_IV_LEN 16
+
+#define IEEE8021X_KEY_INDEX_FLAG 0x80
+#define IEEE8021X_KEY_INDEX_MASK 0x03
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct ieee802_1x_eapol_key {
+	u8 type;
+	/* Note: key_length is unaligned */
+	u8 key_length[2];
+	/* does not repeat within the life of the keying material used to
+	 * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
+	u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
+	u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
+	u8 key_index; /* key flag in the most significant bit:
+		       * 0 = broadcast (default key),
+		       * 1 = unicast (key mapping key); key index is in the
+		       * 7 least significant bits */
+	/* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
+	 * the key */
+	u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
+
+	/* followed by key: if packet body length = 44 + key length, then the
+	 * key field (of key_length bytes) contains the key in encrypted form;
+	 * if packet body length = 44, key field is absent and key_length
+	 * represents the number of least significant octets from
+	 * MS-MPPE-Send-Key attribute to be used as the keying material;
+	 * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#endif /* EAPOL_COMMON_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/ieee802_11_common.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,103 @@
+/*
+ * IEEE 802.11 Common routines
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_11_COMMON_H
+#define IEEE802_11_COMMON_H
+
+/* Parsed Information Elements */
+struct ieee802_11_elems {
+	const u8 *ssid;
+	const u8 *supp_rates;
+	const u8 *fh_params;
+	const u8 *ds_params;
+	const u8 *cf_params;
+	const u8 *tim;
+	const u8 *ibss_params;
+	const u8 *challenge;
+	const u8 *erp_info;
+	const u8 *ext_supp_rates;
+	const u8 *wpa_ie;
+	const u8 *rsn_ie;
+	const u8 *wmm; /* WMM Information or Parameter Element */
+	const u8 *wmm_tspec;
+	const u8 *wps_ie;
+	const u8 *power_cap;
+	const u8 *supp_channels;
+	const u8 *mdie;
+	const u8 *ftie;
+	const u8 *timeout_int;
+	const u8 *ht_capabilities;
+	const u8 *ht_operation;
+	const u8 *vht_capabilities;
+	const u8 *vht_operation;
+	const u8 *vendor_ht_cap;
+	const u8 *p2p;
+	const u8 *wfd;
+	const u8 *link_id;
+	const u8 *interworking;
+	const u8 *hs20;
+	const u8 *ext_capab;
+	const u8 *bss_max_idle_period;
+	const u8 *ssid_list;
+
+	u8 ssid_len;
+	u8 supp_rates_len;
+	u8 fh_params_len;
+	u8 ds_params_len;
+	u8 cf_params_len;
+	u8 tim_len;
+	u8 ibss_params_len;
+	u8 challenge_len;
+	u8 erp_info_len;
+	u8 ext_supp_rates_len;
+	u8 wpa_ie_len;
+	u8 rsn_ie_len;
+	u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
+	u8 wmm_tspec_len;
+	u8 wps_ie_len;
+	u8 power_cap_len;
+	u8 supp_channels_len;
+	u8 mdie_len;
+	u8 ftie_len;
+	u8 timeout_int_len;
+	u8 ht_capabilities_len;
+	u8 ht_operation_len;
+	u8 vht_capabilities_len;
+	u8 vht_operation_len;
+	u8 vendor_ht_cap_len;
+	u8 p2p_len;
+	u8 wfd_len;
+	u8 interworking_len;
+	u8 hs20_len;
+	u8 ext_capab_len;
+	u8 ssid_list_len;
+};
+
+typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
+
+ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
+				struct ieee802_11_elems *elems,
+				int show_errors);
+int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
+struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
+					    u32 oui_type);
+struct ieee80211_hdr;
+const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len);
+
+struct hostapd_wmm_ac_params {
+	int cwmin;
+	int cwmax;
+	int aifs;
+	int txop_limit; /* in units of 32us */
+	int admission_control_mandatory;
+};
+
+int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
+			  const char *name, const char *val);
+
+#endif /* IEEE802_11_COMMON_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/ieee802_11_defs.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,1085 @@
+/*
+ * IEEE 802.11 Frame type definitions
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2008 Intel Corporation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_11_DEFS_H
+#define IEEE802_11_DEFS_H
+
+/* IEEE 802.11 defines */
+
+#define WLAN_FC_PVER		0x0003
+#define WLAN_FC_TODS		0x0100
+#define WLAN_FC_FROMDS		0x0200
+#define WLAN_FC_MOREFRAG	0x0400
+#define WLAN_FC_RETRY		0x0800
+#define WLAN_FC_PWRMGT		0x1000
+#define WLAN_FC_MOREDATA	0x2000
+#define WLAN_FC_ISWEP		0x4000
+#define WLAN_FC_ORDER		0x8000
+
+#define WLAN_FC_GET_TYPE(fc)	(((fc) & 0x000c) >> 2)
+#define WLAN_FC_GET_STYPE(fc)	(((fc) & 0x00f0) >> 4)
+
+#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
+#define WLAN_GET_SEQ_SEQ(seq) \
+	(((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4)
+
+#define WLAN_FC_TYPE_MGMT		0
+#define WLAN_FC_TYPE_CTRL		1
+#define WLAN_FC_TYPE_DATA		2
+
+/* management */
+#define WLAN_FC_STYPE_ASSOC_REQ		0
+#define WLAN_FC_STYPE_ASSOC_RESP	1
+#define WLAN_FC_STYPE_REASSOC_REQ	2
+#define WLAN_FC_STYPE_REASSOC_RESP	3
+#define WLAN_FC_STYPE_PROBE_REQ		4
+#define WLAN_FC_STYPE_PROBE_RESP	5
+#define WLAN_FC_STYPE_BEACON		8
+#define WLAN_FC_STYPE_ATIM		9
+#define WLAN_FC_STYPE_DISASSOC		10
+#define WLAN_FC_STYPE_AUTH		11
+#define WLAN_FC_STYPE_DEAUTH		12
+#define WLAN_FC_STYPE_ACTION		13
+
+/* control */
+#define WLAN_FC_STYPE_PSPOLL		10
+#define WLAN_FC_STYPE_RTS		11
+#define WLAN_FC_STYPE_CTS		12
+#define WLAN_FC_STYPE_ACK		13
+#define WLAN_FC_STYPE_CFEND		14
+#define WLAN_FC_STYPE_CFENDACK		15
+
+/* data */
+#define WLAN_FC_STYPE_DATA		0
+#define WLAN_FC_STYPE_DATA_CFACK	1
+#define WLAN_FC_STYPE_DATA_CFPOLL	2
+#define WLAN_FC_STYPE_DATA_CFACKPOLL	3
+#define WLAN_FC_STYPE_NULLFUNC		4
+#define WLAN_FC_STYPE_CFACK		5
+#define WLAN_FC_STYPE_CFPOLL		6
+#define WLAN_FC_STYPE_CFACKPOLL		7
+#define WLAN_FC_STYPE_QOS_DATA		8
+#define WLAN_FC_STYPE_QOS_DATA_CFACK	9
+#define WLAN_FC_STYPE_QOS_DATA_CFPOLL	10
+#define WLAN_FC_STYPE_QOS_DATA_CFACKPOLL	11
+#define WLAN_FC_STYPE_QOS_NULL		12
+#define WLAN_FC_STYPE_QOS_CFPOLL	14
+#define WLAN_FC_STYPE_QOS_CFACKPOLL	15
+
+/* Authentication algorithms */
+#define WLAN_AUTH_OPEN			0
+#define WLAN_AUTH_SHARED_KEY		1
+#define WLAN_AUTH_FT			2
+#define WLAN_AUTH_SAE			3
+#define WLAN_AUTH_LEAP			128
+
+#define WLAN_AUTH_CHALLENGE_LEN 128
+
+#define WLAN_CAPABILITY_ESS BIT(0)
+#define WLAN_CAPABILITY_IBSS BIT(1)
+#define WLAN_CAPABILITY_CF_POLLABLE BIT(2)
+#define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3)
+#define WLAN_CAPABILITY_PRIVACY BIT(4)
+#define WLAN_CAPABILITY_SHORT_PREAMBLE BIT(5)
+#define WLAN_CAPABILITY_PBCC BIT(6)
+#define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7)
+#define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8)
+#define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10)
+#define WLAN_CAPABILITY_DSSS_OFDM BIT(13)
+
+/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
+#define WLAN_STATUS_SUCCESS 0
+#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
+#define WLAN_STATUS_TDLS_WAKEUP_ALTERNATE 2
+#define WLAN_STATUS_TDLS_WAKEUP_REJECT 3
+#define WLAN_STATUS_SECURITY_DISABLED 5
+#define WLAN_STATUS_UNACCEPTABLE_LIFETIME 6
+#define WLAN_STATUS_NOT_IN_SAME_BSS 7
+#define WLAN_STATUS_CAPS_UNSUPPORTED 10
+#define WLAN_STATUS_REASSOC_NO_ASSOC 11
+#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
+#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
+#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
+#define WLAN_STATUS_CHALLENGE_FAIL 15
+#define WLAN_STATUS_AUTH_TIMEOUT 16
+#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
+#define WLAN_STATUS_ASSOC_DENIED_RATES 18
+/* IEEE 802.11b */
+#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
+#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
+#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+/* IEEE 802.11h */
+#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
+#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
+#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
+/* IEEE 802.11g */
+#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
+#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 26
+#define WLAN_STATUS_ASSOC_DENIED_NO_HT 27
+#define WLAN_STATUS_R0KH_UNREACHABLE 28
+#define WLAN_STATUS_ASSOC_DENIED_NO_PCO 29
+/* IEEE 802.11w */
+#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
+#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
+#define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32
+#define WLAN_STATUS_REQUEST_DECLINED 37
+#define WLAN_STATUS_INVALID_PARAMETERS 38
+/* IEEE 802.11i */
+#define WLAN_STATUS_INVALID_IE 40
+#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
+#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42
+#define WLAN_STATUS_AKMP_NOT_VALID 43
+#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44
+#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45
+#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46
+#define WLAN_STATUS_TS_NOT_CREATED 47
+#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48
+#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49
+#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50
+#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
+/* IEEE 802.11r */
+#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
+#define WLAN_STATUS_INVALID_PMKID 53
+#define WLAN_STATUS_INVALID_MDIE 54
+#define WLAN_STATUS_INVALID_FTIE 55
+#define WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED 59
+#define WLAN_STATUS_NO_OUTSTANDING_GAS_REQ 60
+#define WLAN_STATUS_GAS_RESP_NOT_RECEIVED 61
+#define WLAN_STATUS_STA_TIMED_OUT_WAITING_FOR_GAS_RESP 62
+#define WLAN_STATUS_GAS_RESP_LARGER_THAN_LIMIT 63
+#define WLAN_STATUS_REQ_REFUSED_HOME 64
+#define WLAN_STATUS_ADV_SRV_UNREACHABLE 65
+#define WLAN_STATUS_REQ_REFUSED_SSPN 67
+#define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68
+#define WLAN_STATUS_INVALID_RSNIE 72
+#define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76
+#define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77
+#define WLAN_STATUS_TRANSMISSION_FAILURE 79
+
+/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
+#define WLAN_REASON_UNSPECIFIED 1
+#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
+#define WLAN_REASON_DEAUTH_LEAVING 3
+#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
+#define WLAN_REASON_DISASSOC_AP_BUSY 5
+#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
+#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
+#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
+#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
+/* IEEE 802.11h */
+#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10
+#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11
+/* IEEE 802.11i */
+#define WLAN_REASON_INVALID_IE 13
+#define WLAN_REASON_MICHAEL_MIC_FAILURE 14
+#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15
+#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16
+#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17
+#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18
+#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19
+#define WLAN_REASON_AKMP_NOT_VALID 20
+#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21
+#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22
+#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
+#define WLAN_REASON_CIPHER_SUITE_REJECTED 24
+#define WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE 25
+#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26
+/* IEEE 802.11e */
+#define WLAN_REASON_DISASSOC_LOW_ACK 34
+
+
+/* Information Element IDs */
+#define WLAN_EID_SSID 0
+#define WLAN_EID_SUPP_RATES 1
+#define WLAN_EID_FH_PARAMS 2
+#define WLAN_EID_DS_PARAMS 3
+#define WLAN_EID_CF_PARAMS 4
+#define WLAN_EID_TIM 5
+#define WLAN_EID_IBSS_PARAMS 6
+#define WLAN_EID_COUNTRY 7
+#define WLAN_EID_CHALLENGE 16
+/* EIDs defined by IEEE 802.11h - START */
+#define WLAN_EID_PWR_CONSTRAINT 32
+#define WLAN_EID_PWR_CAPABILITY 33
+#define WLAN_EID_TPC_REQUEST 34
+#define WLAN_EID_TPC_REPORT 35
+#define WLAN_EID_SUPPORTED_CHANNELS 36
+#define WLAN_EID_CHANNEL_SWITCH 37
+#define WLAN_EID_MEASURE_REQUEST 38
+#define WLAN_EID_MEASURE_REPORT 39
+#define WLAN_EID_QUITE 40
+#define WLAN_EID_IBSS_DFS 41
+/* EIDs defined by IEEE 802.11h - END */
+#define WLAN_EID_ERP_INFO 42
+#define WLAN_EID_HT_CAP 45
+#define WLAN_EID_RSN 48
+#define WLAN_EID_EXT_SUPP_RATES 50
+#define WLAN_EID_MOBILITY_DOMAIN 54
+#define WLAN_EID_FAST_BSS_TRANSITION 55
+#define WLAN_EID_TIMEOUT_INTERVAL 56
+#define WLAN_EID_RIC_DATA 57
+#define WLAN_EID_HT_OPERATION 61
+#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
+#define WLAN_EID_WAPI 68
+#define WLAN_EID_TIME_ADVERTISEMENT 69
+#define WLAN_EID_20_40_BSS_COEXISTENCE 72
+#define WLAN_EID_20_40_BSS_INTOLERANT 73
+#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
+#define WLAN_EID_MMIE 76
+#define WLAN_EID_SSID_LIST 84
+#define WLAN_EID_BSS_MAX_IDLE_PERIOD 90
+#define WLAN_EID_TFS_REQ 91
+#define WLAN_EID_TFS_RESP 92
+#define WLAN_EID_WNMSLEEP 93
+#define WLAN_EID_TIME_ZONE 98
+#define WLAN_EID_LINK_ID 101
+#define WLAN_EID_INTERWORKING 107
+#define WLAN_EID_ADV_PROTO 108
+#define WLAN_EID_ROAMING_CONSORTIUM 111
+#define WLAN_EID_EXT_CAPAB 127
+#define WLAN_EID_CCKM 156
+#define WLAN_EID_VHT_CAP 191
+#define WLAN_EID_VHT_OPERATION 192
+#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
+#define WLAN_EID_VHT_WIDE_BW_CHSWITCH  194
+#define WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE 195
+#define WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER 196
+#define WLAN_EID_VHT_AID 197
+#define WLAN_EID_VHT_QUIET_CHANNEL 198
+#define WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION 199
+#define WLAN_EID_VENDOR_SPECIFIC 221
+
+
+/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */
+#define WLAN_ACTION_SPECTRUM_MGMT 0
+#define WLAN_ACTION_QOS 1
+#define WLAN_ACTION_DLS 2
+#define WLAN_ACTION_BLOCK_ACK 3
+#define WLAN_ACTION_PUBLIC 4
+#define WLAN_ACTION_RADIO_MEASUREMENT 5
+#define WLAN_ACTION_FT 6
+#define WLAN_ACTION_HT 7
+#define WLAN_ACTION_SA_QUERY 8
+#define WLAN_ACTION_WNM 10
+#define WLAN_ACTION_UNPROTECTED_WNM 11
+#define WLAN_ACTION_TDLS 12
+#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
+#define WLAN_ACTION_VENDOR_SPECIFIC 127
+
+/* Public action codes */
+#define WLAN_PA_20_40_BSS_COEX 0
+#define WLAN_PA_VENDOR_SPECIFIC 9
+#define WLAN_PA_GAS_INITIAL_REQ 10
+#define WLAN_PA_GAS_INITIAL_RESP 11
+#define WLAN_PA_GAS_COMEBACK_REQ 12
+#define WLAN_PA_GAS_COMEBACK_RESP 13
+#define WLAN_TDLS_DISCOVERY_RESPONSE 14
+
+/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
+#define WLAN_SA_QUERY_REQUEST 0
+#define WLAN_SA_QUERY_RESPONSE 1
+
+#define WLAN_SA_QUERY_TR_ID_LEN 2
+
+/* TDLS action codes */
+#define WLAN_TDLS_SETUP_REQUEST 0
+#define WLAN_TDLS_SETUP_RESPONSE 1
+#define WLAN_TDLS_SETUP_CONFIRM 2
+#define WLAN_TDLS_TEARDOWN 3
+#define WLAN_TDLS_PEER_TRAFFIC_INDICATION 4
+#define WLAN_TDLS_CHANNEL_SWITCH_REQUEST 5
+#define WLAN_TDLS_CHANNEL_SWITCH_RESPONSE 6
+#define WLAN_TDLS_PEER_PSM_REQUEST 7
+#define WLAN_TDLS_PEER_PSM_RESPONSE 8
+#define WLAN_TDLS_PEER_TRAFFIC_RESPONSE 9
+#define WLAN_TDLS_DISCOVERY_REQUEST 10
+
+/* Timeout Interval Type */
+#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
+#define WLAN_TIMEOUT_KEY_LIFETIME 2
+#define WLAN_TIMEOUT_ASSOC_COMEBACK 3
+
+/* Interworking element (IEEE 802.11u) - Access Network Options */
+#define INTERWORKING_ANO_ACCESS_NETWORK_MASK 0x0f
+#define INTERWORKING_ANO_INTERNET 0x10
+#define INTERWORKING_ANO_ASRA 0x20
+#define INTERWORKING_ANO_ESR 0x40
+#define INTERWORKING_ANO_UESA 0x80
+
+#define INTERWORKING_ANT_PRIVATE 0
+#define INTERWORKING_ANT_PRIVATE_WITH_GUEST 1
+#define INTERWORKING_ANT_CHARGEABLE_PUBLIC 2
+#define INTERWORKING_ANT_FREE_PUBLIC 3
+#define INTERWORKING_ANT_PERSONAL_DEVICE 4
+#define INTERWORKING_ANT_EMERGENCY_SERVICES 5
+#define INTERWORKING_ANT_TEST 6
+#define INTERWORKING_ANT_WILDCARD 15
+
+/* Advertisement Protocol ID definitions (IEEE Std 802.11u-2011) */
+enum adv_proto_id {
+	ACCESS_NETWORK_QUERY_PROTOCOL = 0,
+	MIH_INFO_SERVICE = 1,
+	MIH_CMD_AND_EVENT_DISCOVERY = 2,
+	EMERGENCY_ALERT_SYSTEM = 3,
+	ADV_PROTO_VENDOR_SPECIFIC = 221
+};
+
+/* Access Network Query Protocol info ID definitions (IEEE Std 802.11u-2011) */
+enum anqp_info_id {
+	ANQP_QUERY_LIST = 256,
+	ANQP_CAPABILITY_LIST = 257,
+	ANQP_VENUE_NAME = 258,
+	ANQP_EMERGENCY_CALL_NUMBER = 259,
+	ANQP_NETWORK_AUTH_TYPE = 260,
+	ANQP_ROAMING_CONSORTIUM = 261,
+	ANQP_IP_ADDR_TYPE_AVAILABILITY = 262,
+	ANQP_NAI_REALM = 263,
+	ANQP_3GPP_CELLULAR_NETWORK = 264,
+	ANQP_AP_GEOSPATIAL_LOCATION = 265,
+	ANQP_AP_CIVIC_LOCATION = 266,
+	ANQP_AP_LOCATION_PUBLIC_URI = 267,
+	ANQP_DOMAIN_NAME = 268,
+	ANQP_EMERGENCY_ALERT_URI = 269,
+	ANQP_EMERGENCY_NAI = 271,
+	ANQP_VENDOR_SPECIFIC = 56797
+};
+
+/* NAI Realm list - EAP Method subfield - Authentication Parameter ID */
+enum nai_realm_eap_auth_param {
+	NAI_REALM_EAP_AUTH_EXPANDED_EAP_METHOD = 1,
+	NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH = 2,
+	NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD = 3,
+	NAI_REALM_EAP_AUTH_EXPANDED_INNER_EAP_METHOD = 4,
+	NAI_REALM_EAP_AUTH_CRED_TYPE = 5,
+	NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE = 6,
+	NAI_REALM_EAP_AUTH_VENDOR_SPECIFIC = 221
+};
+
+enum nai_realm_eap_auth_inner_non_eap {
+	NAI_REALM_INNER_NON_EAP_PAP = 1,
+	NAI_REALM_INNER_NON_EAP_CHAP = 2,
+	NAI_REALM_INNER_NON_EAP_MSCHAP = 3,
+	NAI_REALM_INNER_NON_EAP_MSCHAPV2 = 4
+};
+
+enum nai_realm_eap_cred_type {
+	NAI_REALM_CRED_TYPE_SIM = 1,
+	NAI_REALM_CRED_TYPE_USIM = 2,
+	NAI_REALM_CRED_TYPE_NFC_SECURE_ELEMENT = 3,
+	NAI_REALM_CRED_TYPE_HARDWARE_TOKEN = 4,
+	NAI_REALM_CRED_TYPE_SOFTOKEN = 5,
+	NAI_REALM_CRED_TYPE_CERTIFICATE = 6,
+	NAI_REALM_CRED_TYPE_USERNAME_PASSWORD = 7,
+	NAI_REALM_CRED_TYPE_NONE = 8,
+	NAI_REALM_CRED_TYPE_ANONYMOUS = 9,
+	NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10
+};
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct ieee80211_hdr {
+	le16 frame_control;
+	le16 duration_id;
+	u8 addr1[6];
+	u8 addr2[6];
+	u8 addr3[6];
+	le16 seq_ctrl;
+	/* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame
+	 */
+} STRUCT_PACKED;
+
+#define IEEE80211_DA_FROMDS addr1
+#define IEEE80211_BSSID_FROMDS addr2
+#define IEEE80211_SA_FROMDS addr3
+
+#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr))
+
+#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4))
+
+struct ieee80211_mgmt {
+	le16 frame_control;
+	le16 duration;
+	u8 da[6];
+	u8 sa[6];
+	u8 bssid[6];
+	le16 seq_ctrl;
+	union {
+		struct {
+			le16 auth_alg;
+			le16 auth_transaction;
+			le16 status_code;
+			/* possibly followed by Challenge text */
+			u8 variable[0];
+		} STRUCT_PACKED auth;
+		struct {
+			le16 reason_code;
+			u8 variable[0];
+		} STRUCT_PACKED deauth;
+		struct {
+			le16 capab_info;
+			le16 listen_interval;
+			/* followed by SSID and Supported rates */
+			u8 variable[0];
+		} STRUCT_PACKED assoc_req;
+		struct {
+			le16 capab_info;
+			le16 status_code;
+			le16 aid;
+			/* followed by Supported rates */
+			u8 variable[0];
+		} STRUCT_PACKED assoc_resp, reassoc_resp;
+		struct {
+			le16 capab_info;
+			le16 listen_interval;
+			u8 current_ap[6];
+			/* followed by SSID and Supported rates */
+			u8 variable[0];
+		} STRUCT_PACKED reassoc_req;
+		struct {
+			le16 reason_code;
+			u8 variable[0];
+		} STRUCT_PACKED disassoc;
+		struct {
+			u8 timestamp[8];
+			le16 beacon_int;
+			le16 capab_info;
+			/* followed by some of SSID, Supported rates,
+			 * FH Params, DS Params, CF Params, IBSS Params, TIM */
+			u8 variable[0];
+		} STRUCT_PACKED beacon;
+		struct {
+			/* only variable items: SSID, Supported rates */
+			u8 variable[0];
+		} STRUCT_PACKED probe_req;
+		struct {
+			u8 timestamp[8];
+			le16 beacon_int;
+			le16 capab_info;
+			/* followed by some of SSID, Supported rates,
+			 * FH Params, DS Params, CF Params, IBSS Params */
+			u8 variable[0];
+		} STRUCT_PACKED probe_resp;
+		struct {
+			u8 category;
+			union {
+				struct {
+					u8 action_code;
+					u8 dialog_token;
+					u8 status_code;
+					u8 variable[0];
+				} STRUCT_PACKED wmm_action;
+				struct{
+					u8 action_code;
+					u8 element_id;
+					u8 length;
+					u8 switch_mode;
+					u8 new_chan;
+					u8 switch_count;
+				} STRUCT_PACKED chan_switch;
+				struct {
+					u8 action;
+					u8 sta_addr[ETH_ALEN];
+					u8 target_ap_addr[ETH_ALEN];
+					u8 variable[0]; /* FT Request */
+				} STRUCT_PACKED ft_action_req;
+				struct {
+					u8 action;
+					u8 sta_addr[ETH_ALEN];
+					u8 target_ap_addr[ETH_ALEN];
+					le16 status_code;
+					u8 variable[0]; /* FT Request */
+				} STRUCT_PACKED ft_action_resp;
+				struct {
+					u8 action;
+					u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+				} STRUCT_PACKED sa_query_req;
+				struct {
+					u8 action; /* */
+					u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+				} STRUCT_PACKED sa_query_resp;
+				struct {
+					u8 action;
+					u8 dialogtoken;
+					u8 variable[0];
+				} STRUCT_PACKED wnm_sleep_req;
+				struct {
+					u8 action;
+					u8 dialogtoken;
+					le16 keydata_len;
+					u8 variable[0];
+				} STRUCT_PACKED wnm_sleep_resp;
+				struct {
+					u8 action;
+					u8 variable[0];
+				} STRUCT_PACKED public_action;
+				struct {
+					u8 action; /* 9 */
+					u8 oui[3];
+					/* Vendor-specific content */
+					u8 variable[0];
+				} STRUCT_PACKED vs_public_action;
+				struct {
+					u8 action; /* 7 */
+					u8 dialog_token;
+					u8 req_mode;
+					le16 disassoc_timer;
+					u8 validity_interval;
+					/* BSS Termination Duration (optional),
+					 * Session Information URL (optional),
+					 * BSS Transition Candidate List
+					 * Entries */
+					u8 variable[0];
+				} STRUCT_PACKED bss_tm_req;
+				struct {
+					u8 action; /* 8 */
+					u8 dialog_token;
+					u8 status_code;
+					u8 bss_termination_delay;
+					/* Target BSSID (optional),
+					 * BSS Transition Candidate List
+					 * Entries (optional) */
+					u8 variable[0];
+				} STRUCT_PACKED bss_tm_resp;
+			} u;
+		} STRUCT_PACKED action;
+	} u;
+} STRUCT_PACKED;
+
+
+/* Rx MCS bitmask is in the first 77 bits of supported_mcs_set */
+#define IEEE80211_HT_MCS_MASK_LEN 10
+
+struct ieee80211_ht_capabilities {
+	le16 ht_capabilities_info;
+	u8 a_mpdu_params;
+	u8 supported_mcs_set[16];
+	le16 ht_extended_capabilities;
+	le32 tx_bf_capability_info;
+	u8 asel_capabilities;
+} STRUCT_PACKED;
+
+
+struct ieee80211_ht_operation {
+	u8 control_chan;
+	u8 ht_param;
+	le16 operation_mode;
+	le16 stbc_param;
+	u8 basic_set[16];
+} STRUCT_PACKED;
+
+
+struct ieee80211_vht_capabilities {
+	le32 vht_capabilities_info;
+	u8 vht_supported_mcs_set[8];
+} STRUCT_PACKED;
+
+struct ieee80211_vht_operation {
+	u8 vht_op_info_chwidth;
+	u8 vht_op_info_chan_center_freq_seg0_idx;
+	u8 vht_op_info_chan_center_freq_seg1_idx;
+	le16 vht_basic_mcs_set;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#define ERP_INFO_NON_ERP_PRESENT BIT(0)
+#define ERP_INFO_USE_PROTECTION BIT(1)
+#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2)
+
+
+#define HT_CAP_INFO_LDPC_CODING_CAP		((u16) BIT(0))
+#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET	((u16) BIT(1))
+#define HT_CAP_INFO_SMPS_MASK			((u16) (BIT(2) | BIT(3)))
+#define HT_CAP_INFO_SMPS_STATIC			((u16) 0)
+#define HT_CAP_INFO_SMPS_DYNAMIC		((u16) BIT(2))
+#define HT_CAP_INFO_SMPS_DISABLED		((u16) (BIT(2) | BIT(3)))
+#define HT_CAP_INFO_GREEN_FIELD			((u16) BIT(4))
+#define HT_CAP_INFO_SHORT_GI20MHZ		((u16) BIT(5))
+#define HT_CAP_INFO_SHORT_GI40MHZ		((u16) BIT(6))
+#define HT_CAP_INFO_TX_STBC			((u16) BIT(7))
+#define HT_CAP_INFO_RX_STBC_MASK		((u16) (BIT(8) | BIT(9)))
+#define HT_CAP_INFO_RX_STBC_1			((u16) BIT(8))
+#define HT_CAP_INFO_RX_STBC_12			((u16) BIT(9))
+#define HT_CAP_INFO_RX_STBC_123			((u16) (BIT(8) | BIT(9)))
+#define HT_CAP_INFO_DELAYED_BA			((u16) BIT(10))
+#define HT_CAP_INFO_MAX_AMSDU_SIZE		((u16) BIT(11))
+#define HT_CAP_INFO_DSSS_CCK40MHZ		((u16) BIT(12))
+#define HT_CAP_INFO_PSMP_SUPP			((u16) BIT(13))
+#define HT_CAP_INFO_40MHZ_INTOLERANT		((u16) BIT(14))
+#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT	((u16) BIT(15))
+
+
+#define EXT_HT_CAP_INFO_PCO			((u16) BIT(0))
+#define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET	1
+#define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET	8
+#define EXT_HT_CAP_INFO_HTC_SUPPORTED		((u16) BIT(10))
+#define EXT_HT_CAP_INFO_RD_RESPONDER		((u16) BIT(11))
+
+
+#define TX_BEAMFORM_CAP_TXBF_CAP ((u32) BIT(0))
+#define TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1))
+#define TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2))
+#define TX_BEAMFORM_CAP_RX_ZLF_CAP ((u32) BIT(3))
+#define TX_BEAMFORM_CAP_TX_ZLF_CAP ((u32) BIT(4))
+#define TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP ((u32) BIT(5))
+#define TX_BEAMFORM_CAP_CALIB_OFFSET 6
+#define TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8))
+#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP ((u32) BIT(9))
+#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP ((u32) BIT(10))
+#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11
+#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13
+#define TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15
+#define TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET 17
+#define TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19
+#define TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21
+#define TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23
+#define TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25
+
+
+#define ASEL_CAPABILITY_ASEL_CAPABLE ((u8) BIT(0))
+#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1))
+#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2))
+#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3))
+#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4))
+#define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5))
+#define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6))
+
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK	((u8) BIT(0) | BIT(1))
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE		((u8) BIT(0))
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW		((u8) BIT(0) | BIT(1))
+#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH		((u8) BIT(2))
+#define HT_INFO_HT_PARAM_RIFS_MODE			((u8) BIT(3))
+#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY		((u8) BIT(4))
+#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY	((u8) BIT(5))
+
+
+#define OP_MODE_PURE                    0
+#define OP_MODE_MAY_BE_LEGACY_STAS      1
+#define OP_MODE_20MHZ_HT_STA_ASSOCED    2
+#define OP_MODE_MIXED                   3
+
+#define HT_INFO_OPERATION_MODE_OP_MODE_MASK	\
+		(0x0001 | 0x0002)
+#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET		0
+#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT	((u8) BIT(2))
+#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT	((u8) BIT(3))
+#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT	((u8) BIT(4))
+
+#define HT_INFO_STBC_PARAM_DUAL_BEACON			((u16) BIT(6))
+#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT		((u16) BIT(7))
+#define HT_INFO_STBC_PARAM_SECONDARY_BCN		((u16) BIT(8))
+#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED	((u16) BIT(9))
+#define HT_INFO_STBC_PARAM_PCO_ACTIVE			((u16) BIT(10))
+#define HT_INFO_STBC_PARAM_PCO_PHASE			((u16) BIT(11))
+
+#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
+#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
+
+/* VHT Defines */
+#define VHT_CAP_MAX_MPDU_LENGTH_7991                ((u32) BIT(0))
+#define VHT_CAP_MAX_MPDU_LENGTH_11454               ((u32) BIT(1))
+#define VHT_CAP_SUPP_CHAN_WIDTH_160MHZ              ((u32) BIT(2))
+#define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ     ((u32) BIT(3))
+#define VHT_CAP_RXLDPC                              ((u32) BIT(4))
+#define VHT_CAP_SHORT_GI_80                         ((u32) BIT(5))
+#define VHT_CAP_SHORT_GI_160                        ((u32) BIT(6))
+#define VHT_CAP_TXSTBC                              ((u32) BIT(7))
+#define VHT_CAP_RXSTBC_1                            ((u32) BIT(8))
+#define VHT_CAP_RXSTBC_2                            ((u32) BIT(9))
+#define VHT_CAP_RXSTBC_3                            ((u32) BIT(8) | BIT(9))
+#define VHT_CAP_RXSTBC_4                            ((u32) BIT(10))
+#define VHT_CAP_SU_BEAMFORMER_CAPABLE               ((u32) BIT(11))
+#define VHT_CAP_SU_BEAMFORMEE_CAPABLE               ((u32) BIT(12))
+#define VHT_CAP_BEAMFORMER_ANTENNAS_MAX             ((u32) BIT(13) | BIT(14))
+#define VHT_CAP_SOUNDING_DIMENTION_MAX              ((u32) BIT(16) | BIT(17))
+#define VHT_CAP_MU_BEAMFORMER_CAPABLE               ((u32) BIT(19))
+#define VHT_CAP_MU_BEAMFORMEE_CAPABLE               ((u32) BIT(20))
+#define VHT_CAP_VHT_TXOP_PS                         ((u32) BIT(21))
+#define VHT_CAP_HTC_VHT                             ((u32) BIT(22))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT          ((u32) BIT(23))
+#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB   ((u32) BIT(27))
+#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB     ((u32) BIT(26) | BIT(27))
+#define VHT_CAP_RX_ANTENNA_PATTERN                  ((u32) BIT(28))
+#define VHT_CAP_TX_ANTENNA_PATTERN                  ((u32) BIT(29))
+
+#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
+				* 00:50:F2 */
+#define WPA_IE_VENDOR_TYPE 0x0050f201
+#define WPS_IE_VENDOR_TYPE 0x0050f204
+#define OUI_WFA 0x506f9a
+#define P2P_IE_VENDOR_TYPE 0x506f9a09
+#define WFD_IE_VENDOR_TYPE 0x506f9a0a
+#define WFD_OUI_TYPE 10
+#define HS20_IE_VENDOR_TYPE 0x506f9a10
+
+#define WMM_OUI_TYPE 2
+#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
+#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1
+#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2
+#define WMM_VERSION 1
+
+#define WMM_ACTION_CODE_ADDTS_REQ 0
+#define WMM_ACTION_CODE_ADDTS_RESP 1
+#define WMM_ACTION_CODE_DELTS 2
+
+#define WMM_ADDTS_STATUS_ADMISSION_ACCEPTED 0
+#define WMM_ADDTS_STATUS_INVALID_PARAMETERS 1
+/* 2 - Reserved */
+#define WMM_ADDTS_STATUS_REFUSED 3
+/* 4-255 - Reserved */
+
+/* WMM TSPEC Direction Field Values */
+#define WMM_TSPEC_DIRECTION_UPLINK 0
+#define WMM_TSPEC_DIRECTION_DOWNLINK 1
+/* 2 - Reserved */
+#define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3
+
+/*
+ * WMM Information Element (used in (Re)Association Request frames; may also be
+ * used in Beacon frames)
+ */
+struct wmm_information_element {
+	/* Element ID: 221 (0xdd); Length: 7 */
+	/* required fields for WMM version 1 */
+	u8 oui[3]; /* 00:50:f2 */
+	u8 oui_type; /* 2 */
+	u8 oui_subtype; /* 0 */
+	u8 version; /* 1 for WMM version 1.0 */
+	u8 qos_info; /* AP/STA specific QoS info */
+
+} STRUCT_PACKED;
+
+#define WMM_QOSINFO_STA_AC_MASK 0x0f
+#define WMM_QOSINFO_STA_SP_MASK 0x03
+#define WMM_QOSINFO_STA_SP_SHIFT 5
+
+#define WMM_AC_AIFSN_MASK 0x0f
+#define WMM_AC_AIFNS_SHIFT 0
+#define WMM_AC_ACM 0x10
+#define WMM_AC_ACI_MASK 0x60
+#define WMM_AC_ACI_SHIFT 5
+
+#define WMM_AC_ECWMIN_MASK 0x0f
+#define WMM_AC_ECWMIN_SHIFT 0
+#define WMM_AC_ECWMAX_MASK 0xf0
+#define WMM_AC_ECWMAX_SHIFT 4
+
+struct wmm_ac_parameter {
+	u8 aci_aifsn; /* AIFSN, ACM, ACI */
+	u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */
+	le16 txop_limit;
+}  STRUCT_PACKED;
+
+/*
+ * WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association
+ * Response frmaes)
+ */
+struct wmm_parameter_element {
+	/* Element ID: 221 (0xdd); Length: 24 */
+	/* required fields for WMM version 1 */
+	u8 oui[3]; /* 00:50:f2 */
+	u8 oui_type; /* 2 */
+	u8 oui_subtype; /* 1 */
+	u8 version; /* 1 for WMM version 1.0 */
+	u8 qos_info; /* AP/STA specific QoS info */
+	u8 reserved; /* 0 */
+	struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
+
+} STRUCT_PACKED;
+
+/* WMM TSPEC Element */
+struct wmm_tspec_element {
+	u8 eid; /* 221 = 0xdd */
+	u8 length; /* 6 + 55 = 61 */
+	u8 oui[3]; /* 00:50:f2 */
+	u8 oui_type; /* 2 */
+	u8 oui_subtype; /* 2 */
+	u8 version; /* 1 */
+	/* WMM TSPEC body (55 octets): */
+	u8 ts_info[3];
+	le16 nominal_msdu_size;
+	le16 maximum_msdu_size;
+	le32 minimum_service_interval;
+	le32 maximum_service_interval;
+	le32 inactivity_interval;
+	le32 suspension_interval;
+	le32 service_start_time;
+	le32 minimum_data_rate;
+	le32 mean_data_rate;
+	le32 peak_data_rate;
+	le32 maximum_burst_size;
+	le32 delay_bound;
+	le32 minimum_phy_rate;
+	le16 surplus_bandwidth_allowance;
+	le16 medium_time;
+} STRUCT_PACKED;
+
+
+/* Access Categories / ACI to AC coding */
+enum {
+	WMM_AC_BE = 0 /* Best Effort */,
+	WMM_AC_BK = 1 /* Background */,
+	WMM_AC_VI = 2 /* Video */,
+	WMM_AC_VO = 3 /* Voice */
+};
+
+
+#define HS20_INDICATION_OUI_TYPE 16
+#define HS20_ANQP_OUI_TYPE 17
+#define HS20_STYPE_QUERY_LIST 1
+#define HS20_STYPE_CAPABILITY_LIST 2
+#define HS20_STYPE_OPERATOR_FRIENDLY_NAME 3
+#define HS20_STYPE_WAN_METRICS 4
+#define HS20_STYPE_CONNECTION_CAPABILITY 5
+#define HS20_STYPE_NAI_HOME_REALM_QUERY 6
+#define HS20_STYPE_OPERATING_CLASS 7
+
+/* Wi-Fi Direct (P2P) */
+
+#define P2P_OUI_TYPE 9
+
+enum p2p_attr_id {
+	P2P_ATTR_STATUS = 0,
+	P2P_ATTR_MINOR_REASON_CODE = 1,
+	P2P_ATTR_CAPABILITY = 2,
+	P2P_ATTR_DEVICE_ID = 3,
+	P2P_ATTR_GROUP_OWNER_INTENT = 4,
+	P2P_ATTR_CONFIGURATION_TIMEOUT = 5,
+	P2P_ATTR_LISTEN_CHANNEL = 6,
+	P2P_ATTR_GROUP_BSSID = 7,
+	P2P_ATTR_EXT_LISTEN_TIMING = 8,
+	P2P_ATTR_INTENDED_INTERFACE_ADDR = 9,
+	P2P_ATTR_MANAGEABILITY = 10,
+	P2P_ATTR_CHANNEL_LIST = 11,
+	P2P_ATTR_NOTICE_OF_ABSENCE = 12,
+	P2P_ATTR_DEVICE_INFO = 13,
+	P2P_ATTR_GROUP_INFO = 14,
+	P2P_ATTR_GROUP_ID = 15,
+	P2P_ATTR_INTERFACE = 16,
+	P2P_ATTR_OPERATING_CHANNEL = 17,
+	P2P_ATTR_INVITATION_FLAGS = 18,
+	P2P_ATTR_VENDOR_SPECIFIC = 221
+};
+
+#define P2P_MAX_GO_INTENT 15
+
+/* P2P Capability - Device Capability bitmap */
+#define P2P_DEV_CAPAB_SERVICE_DISCOVERY BIT(0)
+#define P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY BIT(1)
+#define P2P_DEV_CAPAB_CONCURRENT_OPER BIT(2)
+#define P2P_DEV_CAPAB_INFRA_MANAGED BIT(3)
+#define P2P_DEV_CAPAB_DEVICE_LIMIT BIT(4)
+#define P2P_DEV_CAPAB_INVITATION_PROCEDURE BIT(5)
+
+/* P2P Capability - Group Capability bitmap */
+#define P2P_GROUP_CAPAB_GROUP_OWNER BIT(0)
+#define P2P_GROUP_CAPAB_PERSISTENT_GROUP BIT(1)
+#define P2P_GROUP_CAPAB_GROUP_LIMIT BIT(2)
+#define P2P_GROUP_CAPAB_INTRA_BSS_DIST BIT(3)
+#define P2P_GROUP_CAPAB_CROSS_CONN BIT(4)
+#define P2P_GROUP_CAPAB_PERSISTENT_RECONN BIT(5)
+#define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6)
+
+/* Invitation Flags */
+#define P2P_INVITATION_FLAGS_TYPE BIT(0)
+
+/* P2P Manageability */
+#define P2P_MAN_DEVICE_MANAGEMENT BIT(0)
+#define P2P_MAN_CROSS_CONNECTION_PERMITTED BIT(1)
+#define P2P_MAN_COEXISTENCE_OPTIONAL BIT(2)
+
+enum p2p_status_code {
+	P2P_SC_SUCCESS = 0,
+	P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE = 1,
+	P2P_SC_FAIL_INCOMPATIBLE_PARAMS = 2,
+	P2P_SC_FAIL_LIMIT_REACHED = 3,
+	P2P_SC_FAIL_INVALID_PARAMS = 4,
+	P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE = 5,
+	P2P_SC_FAIL_PREV_PROTOCOL_ERROR = 6,
+	P2P_SC_FAIL_NO_COMMON_CHANNELS = 7,
+	P2P_SC_FAIL_UNKNOWN_GROUP = 8,
+	P2P_SC_FAIL_BOTH_GO_INTENT_15 = 9,
+	P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10,
+	P2P_SC_FAIL_REJECTED_BY_USER = 11,
+};
+
+#define P2P_WILDCARD_SSID "DIRECT-"
+#define P2P_WILDCARD_SSID_LEN 7
+
+/* P2P action frames */
+enum p2p_act_frame_type {
+	P2P_NOA = 0,
+	P2P_PRESENCE_REQ = 1,
+	P2P_PRESENCE_RESP = 2,
+	P2P_GO_DISC_REQ = 3
+};
+
+/* P2P public action frames */
+enum p2p_action_frame_type {
+	P2P_GO_NEG_REQ = 0,
+	P2P_GO_NEG_RESP = 1,
+	P2P_GO_NEG_CONF = 2,
+	P2P_INVITATION_REQ = 3,
+	P2P_INVITATION_RESP = 4,
+	P2P_DEV_DISC_REQ = 5,
+	P2P_DEV_DISC_RESP = 6,
+	P2P_PROV_DISC_REQ = 7,
+	P2P_PROV_DISC_RESP = 8
+};
+
+enum p2p_service_protocol_type {
+	P2P_SERV_ALL_SERVICES = 0,
+	P2P_SERV_BONJOUR = 1,
+	P2P_SERV_UPNP = 2,
+	P2P_SERV_WS_DISCOVERY = 3,
+	P2P_SERV_WIFI_DISPLAY = 4,
+	P2P_SERV_VENDOR_SPECIFIC = 255
+};
+
+enum p2p_sd_status {
+	P2P_SD_SUCCESS = 0,
+	P2P_SD_PROTO_NOT_AVAILABLE = 1,
+	P2P_SD_REQUESTED_INFO_NOT_AVAILABLE = 2,
+	P2P_SD_BAD_REQUEST = 3
+};
+
+
+enum wifi_display_subelem {
+	WFD_SUBELEM_DEVICE_INFO = 0,
+	WFD_SUBELEM_ASSOCIATED_BSSID = 1,
+	WFD_SUBELEM_AUDIO_FORMATS = 2,
+	WFD_SUBELEM_VIDEO_FORMATS = 3,
+	WFD_SUBELEM_3D_VIDEO_FORMATS = 4,
+	WFD_SUBELEM_CONTENT_PROTECTION = 5,
+	WFD_SUBELEM_COUPLED_SINK = 6,
+	WFD_SUBELEM_EXT_CAPAB = 7,
+	WFD_SUBELEM_LOCAL_IP_ADDRESS = 8,
+	WFD_SUBELEM_SESSION_INFO = 9
+};
+
+
+#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
+
+#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
+
+/* cipher suite selectors */
+#define WLAN_CIPHER_SUITE_USE_GROUP	0x000FAC00
+#define WLAN_CIPHER_SUITE_WEP40		0x000FAC01
+#define WLAN_CIPHER_SUITE_TKIP		0x000FAC02
+/* reserved: 				0x000FAC03 */
+#define WLAN_CIPHER_SUITE_CCMP		0x000FAC04
+#define WLAN_CIPHER_SUITE_WEP104	0x000FAC05
+#define WLAN_CIPHER_SUITE_AES_CMAC	0x000FAC06
+#define WLAN_CIPHER_SUITE_NO_GROUP_ADDR	0x000FAC07
+#define WLAN_CIPHER_SUITE_GCMP		0x000FAC08
+
+#define WLAN_CIPHER_SUITE_SMS4		0x00147201
+
+#define WLAN_CIPHER_SUITE_CKIP		0x00409600
+#define WLAN_CIPHER_SUITE_CKIP_CMIC	0x00409601
+#define WLAN_CIPHER_SUITE_CMIC		0x00409602
+#define WLAN_CIPHER_SUITE_KRK		0x004096FF /* for nl80211 use only */
+
+/* AKM suite selectors */
+#define WLAN_AKM_SUITE_8021X		0x000FAC01
+#define WLAN_AKM_SUITE_PSK		0x000FAC02
+#define WLAN_AKM_SUITE_CCKM		0x00409600
+
+
+/* IEEE 802.11v - WNM Action field values */
+enum wnm_action {
+	WNM_EVENT_REQ = 0,
+	WNM_EVENT_REPORT = 1,
+	WNM_DIAGNOSTIC_REQ = 2,
+	WNM_DIAGNOSTIC_REPORT = 3,
+	WNM_LOCATION_CFG_REQ = 4,
+	WNM_LOCATION_CFG_RESP = 5,
+	WNM_BSS_TRANS_MGMT_QUERY = 6,
+	WNM_BSS_TRANS_MGMT_REQ = 7,
+	WNM_BSS_TRANS_MGMT_RESP = 8,
+	WNM_FMS_REQ = 9,
+	WNM_FMS_RESP = 10,
+	WNM_COLLOCATED_INTERFERENCE_REQ = 11,
+	WNM_COLLOCATED_INTERFERENCE_REPORT = 12,
+	WNM_TFS_REQ = 13,
+	WNM_TFS_RESP = 14,
+	WNM_TFS_NOTIFY = 15,
+	WNM_SLEEP_MODE_REQ = 16,
+	WNM_SLEEP_MODE_RESP = 17,
+	WNM_TIM_BROADCAST_REQ = 18,
+	WNM_TIM_BROADCAST_RESP = 19,
+	WNM_QOS_TRAFFIC_CAPAB_UPDATE = 20,
+	WNM_CHANNEL_USAGE_REQ = 21,
+	WNM_CHANNEL_USAGE_RESP = 22,
+	WNM_DMS_REQ = 23,
+	WNM_DMS_RESP = 24,
+	WNM_TIMING_MEASUREMENT_REQ = 25,
+	WNM_NOTIFICATION_REQ = 26,
+	WNM_NOTIFICATION_RESP = 27
+};
+
+/* IEEE 802.11v - BSS Transition Management Request - Request Mode */
+#define WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED BIT(0)
+#define WNM_BSS_TM_REQ_ABRIDGED BIT(1)
+#define WNM_BSS_TM_REQ_DISASSOC_IMMINENT BIT(2)
+#define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
+#define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
+
+/* IEEE Std 802.11-2012, 8.4.2.62 20/40 BSS Coexistence element */
+#define WLAN_20_40_BSS_COEX_INFO_REQ            BIT(0)
+#define WLAN_20_40_BSS_COEX_40MHZ_INTOL         BIT(1)
+#define WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ     BIT(2)
+#define WLAN_20_40_BSS_COEX_OBSS_EXEMPT_REQ     BIT(3)
+#define WLAN_20_40_BSS_COEX_OBSS_EXEMPT_GRNT    BIT(4)
+
+struct ieee80211_2040_bss_coex_ie {
+	u8 element_id;
+	u8 length;
+	u8 coex_param;
+} STRUCT_PACKED;
+
+struct ieee80211_2040_intol_chan_report {
+	u8 element_id;
+	u8 length;
+	u8 op_class;
+	u8 variable[0];	/* Channel List */
+} STRUCT_PACKED;
+
+/* IEEE 802.11v - WNM-Sleep Mode element */
+struct wnm_sleep_element {
+	u8 eid;     /* WLAN_EID_WNMSLEEP */
+	u8 len;
+	u8 action_type; /* WNM_SLEEP_ENTER/WNM_SLEEP_MODE_EXIT */
+	u8 status;
+	le16 intval;
+} STRUCT_PACKED;
+
+#define WNM_SLEEP_MODE_ENTER 0
+#define WNM_SLEEP_MODE_EXIT 1
+
+enum wnm_sleep_mode_response_status {
+	WNM_STATUS_SLEEP_ACCEPT = 0,
+	WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE = 1,
+	WNM_STATUS_DENIED_ACTION = 2,
+	WNM_STATUS_DENIED_TMP = 3,
+	WNM_STATUS_DENIED_KEY = 4,
+	WNM_STATUS_DENIED_OTHER_WNM_SERVICE = 5
+};
+
+/* WNM-Sleep Mode subelement IDs */
+enum wnm_sleep_mode_subelement_id {
+	WNM_SLEEP_SUBELEM_GTK = 0,
+	WNM_SLEEP_SUBELEM_IGTK = 1
+};
+
+#endif /* IEEE802_11_DEFS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/version.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,10 @@
+#ifndef VERSION_H
+#define VERSION_H
+
+#ifndef VERSION_STR_POSTFIX
+#define VERSION_STR_POSTFIX ""
+#endif /* VERSION_STR_POSTFIX */
+
+#define VERSION_STR "2.0" VERSION_STR_POSTFIX
+
+#endif /* VERSION_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/wpa_common.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,1216 @@
+/*
+ * WPA/RSN - Shared functions for supplicant and authenticator
+ * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/md5.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "ieee802_11_defs.h"
+#include "defs.h"
+#include "wpa_common.h"
+
+
+/**
+ * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
+ * @key: EAPOL-Key Key Confirmation Key (KCK)
+ * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
+ * @buf: Pointer to the beginning of the EAPOL header (version field)
+ * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
+ * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
+ * Returns: 0 on success, -1 on failure
+ *
+ * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
+ * to be cleared (all zeroes) when calling this function.
+ *
+ * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
+ * description of the Key MIC calculation. It includes packet data from the
+ * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
+ * happened during final editing of the standard and the correct behavior is
+ * defined in the last draft (IEEE 802.11i/D10).
+ */
+int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
+		      u8 *mic)
+{
+	u8 hash[SHA1_MAC_LEN];
+
+	switch (ver) {
+#ifndef CONFIG_FIPS
+	case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
+		return hmac_md5(key, 16, buf, len, mic);
+#endif /* CONFIG_FIPS */
+	case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
+		if (hmac_sha1(key, 16, buf, len, hash))
+			return -1;
+		os_memcpy(mic, hash, MD5_MAC_LEN);
+		break;
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
+	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
+		return omac1_aes_128(key, buf, len, mic);
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
+ * @pmk: Pairwise master key
+ * @pmk_len: Length of PMK
+ * @label: Label to use in derivation
+ * @addr1: AA or SA
+ * @addr2: SA or AA
+ * @nonce1: ANonce or SNonce
+ * @nonce2: SNonce or ANonce
+ * @ptk: Buffer for pairwise transient key
+ * @ptk_len: Length of PTK
+ * @use_sha256: Whether to use SHA256-based KDF
+ *
+ * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
+ * PTK = PRF-X(PMK, "Pairwise key expansion",
+ *             Min(AA, SA) || Max(AA, SA) ||
+ *             Min(ANonce, SNonce) || Max(ANonce, SNonce))
+ *
+ * STK = PRF-X(SMK, "Peer key expansion",
+ *             Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
+ *             Min(INonce, PNonce) || Max(INonce, PNonce))
+ */
+void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
+		    const u8 *addr1, const u8 *addr2,
+		    const u8 *nonce1, const u8 *nonce2,
+		    u8 *ptk, size_t ptk_len, int use_sha256)
+{
+	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
+
+	if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
+		os_memcpy(data, addr1, ETH_ALEN);
+		os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
+	} else {
+		os_memcpy(data, addr2, ETH_ALEN);
+		os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
+	}
+
+	if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
+		os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
+		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
+			  WPA_NONCE_LEN);
+	} else {
+		os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
+		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
+			  WPA_NONCE_LEN);
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (use_sha256)
+		sha256_prf(pmk, pmk_len, label, data, sizeof(data),
+			   ptk, ptk_len);
+	else
+#endif /* CONFIG_IEEE80211W */
+		sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
+			 ptk_len);
+
+	wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
+		   MAC2STR(addr1), MAC2STR(addr2));
+	wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
+	wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
+}
+
+
+#ifdef CONFIG_IEEE80211R
+int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
+	       u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
+	       const u8 *ftie, size_t ftie_len,
+	       const u8 *rsnie, size_t rsnie_len,
+	       const u8 *ric, size_t ric_len, u8 *mic)
+{
+	u8 *buf, *pos;
+	size_t buf_len;
+
+	buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
+	buf = os_malloc(buf_len);
+	if (buf == NULL)
+		return -1;
+
+	pos = buf;
+	os_memcpy(pos, sta_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+	os_memcpy(pos, ap_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+	*pos++ = transaction_seqnum;
+	if (rsnie) {
+		os_memcpy(pos, rsnie, rsnie_len);
+		pos += rsnie_len;
+	}
+	if (mdie) {
+		os_memcpy(pos, mdie, mdie_len);
+		pos += mdie_len;
+	}
+	if (ftie) {
+		struct rsn_ftie *_ftie;
+		os_memcpy(pos, ftie, ftie_len);
+		if (ftie_len < 2 + sizeof(*_ftie)) {
+			os_free(buf);
+			return -1;
+		}
+		_ftie = (struct rsn_ftie *) (pos + 2);
+		os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
+		pos += ftie_len;
+	}
+	if (ric) {
+		os_memcpy(pos, ric, ric_len);
+		pos += ric_len;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
+	if (omac1_aes_128(kck, buf, pos - buf, mic)) {
+		os_free(buf);
+		return -1;
+	}
+
+	os_free(buf);
+
+	return 0;
+}
+
+
+static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
+			     struct wpa_ft_ies *parse)
+{
+	const u8 *end, *pos;
+
+	parse->ftie = ie;
+	parse->ftie_len = ie_len;
+
+	pos = ie + sizeof(struct rsn_ftie);
+	end = ie + ie_len;
+
+	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+		switch (pos[0]) {
+		case FTIE_SUBELEM_R1KH_ID:
+			if (pos[1] != FT_R1KH_ID_LEN) {
+				wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
+					   "length in FTIE: %d", pos[1]);
+				return -1;
+			}
+			parse->r1kh_id = pos + 2;
+			break;
+		case FTIE_SUBELEM_GTK:
+			parse->gtk = pos + 2;
+			parse->gtk_len = pos[1];
+			break;
+		case FTIE_SUBELEM_R0KH_ID:
+			if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
+				wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
+					   "length in FTIE: %d", pos[1]);
+				return -1;
+			}
+			parse->r0kh_id = pos + 2;
+			parse->r0kh_id_len = pos[1];
+			break;
+#ifdef CONFIG_IEEE80211W
+		case FTIE_SUBELEM_IGTK:
+			parse->igtk = pos + 2;
+			parse->igtk_len = pos[1];
+			break;
+#endif /* CONFIG_IEEE80211W */
+		}
+
+		pos += 2 + pos[1];
+	}
+
+	return 0;
+}
+
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
+		     struct wpa_ft_ies *parse)
+{
+	const u8 *end, *pos;
+	struct wpa_ie_data data;
+	int ret;
+	const struct rsn_ftie *ftie;
+	int prot_ie_count = 0;
+
+	os_memset(parse, 0, sizeof(*parse));
+	if (ies == NULL)
+		return 0;
+
+	pos = ies;
+	end = ies + ies_len;
+	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+		switch (pos[0]) {
+		case WLAN_EID_RSN:
+			parse->rsn = pos + 2;
+			parse->rsn_len = pos[1];
+			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
+						   parse->rsn_len + 2,
+						   &data);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
+					   "RSN IE: %d", ret);
+				return -1;
+			}
+			if (data.num_pmkid == 1 && data.pmkid)
+				parse->rsn_pmkid = data.pmkid;
+			break;
+		case WLAN_EID_MOBILITY_DOMAIN:
+			parse->mdie = pos + 2;
+			parse->mdie_len = pos[1];
+			break;
+		case WLAN_EID_FAST_BSS_TRANSITION:
+			if (pos[1] < sizeof(*ftie))
+				return -1;
+			ftie = (const struct rsn_ftie *) (pos + 2);
+			prot_ie_count = ftie->mic_control[1];
+			if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
+				return -1;
+			break;
+		case WLAN_EID_TIMEOUT_INTERVAL:
+			parse->tie = pos + 2;
+			parse->tie_len = pos[1];
+			break;
+		case WLAN_EID_RIC_DATA:
+			if (parse->ric == NULL)
+				parse->ric = pos;
+			break;
+		}
+
+		pos += 2 + pos[1];
+	}
+
+	if (prot_ie_count == 0)
+		return 0; /* no MIC */
+
+	/*
+	 * Check that the protected IE count matches with IEs included in the
+	 * frame.
+	 */
+	if (parse->rsn)
+		prot_ie_count--;
+	if (parse->mdie)
+		prot_ie_count--;
+	if (parse->ftie)
+		prot_ie_count--;
+	if (prot_ie_count < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
+			   "the protected IE count");
+		return -1;
+	}
+
+	if (prot_ie_count == 0 && parse->ric) {
+		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
+			   "included in protected IE count");
+		return -1;
+	}
+
+	/* Determine the end of the RIC IE(s) */
+	pos = parse->ric;
+	while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
+	       prot_ie_count) {
+		prot_ie_count--;
+		pos += 2 + pos[1];
+	}
+	parse->ric_len = pos - parse->ric;
+	if (prot_ie_count) {
+		wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
+			   "frame", (int) prot_ie_count);
+		return -1;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+#ifndef CONFIG_NO_WPA2
+static int rsn_selector_to_bitfield(const u8 *s)
+{
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
+		return WPA_CIPHER_NONE;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40)
+		return WPA_CIPHER_WEP40;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
+		return WPA_CIPHER_TKIP;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
+		return WPA_CIPHER_CCMP;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104)
+		return WPA_CIPHER_WEP104;
+#ifdef CONFIG_IEEE80211W
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
+		return WPA_CIPHER_AES_128_CMAC;
+#endif /* CONFIG_IEEE80211W */
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
+		return WPA_CIPHER_GCMP;
+	return 0;
+}
+
+
+static int rsn_key_mgmt_to_bitfield(const u8 *s)
+{
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
+		return WPA_KEY_MGMT_IEEE8021X;
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
+		return WPA_KEY_MGMT_PSK;
+#ifdef CONFIG_IEEE80211R
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
+		return WPA_KEY_MGMT_FT_IEEE8021X;
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
+		return WPA_KEY_MGMT_FT_PSK;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
+		return WPA_KEY_MGMT_IEEE8021X_SHA256;
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
+		return WPA_KEY_MGMT_PSK_SHA256;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
+		return WPA_KEY_MGMT_SAE;
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
+		return WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
+	return 0;
+}
+#endif /* CONFIG_NO_WPA2 */
+
+
+/**
+ * wpa_parse_wpa_ie_rsn - Parse RSN IE
+ * @rsn_ie: Buffer containing RSN IE
+ * @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
+ * @data: Pointer to structure that will be filled in with parsed data
+ * Returns: 0 on success, <0 on failure
+ */
+int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
+			 struct wpa_ie_data *data)
+{
+#ifndef CONFIG_NO_WPA2
+	const struct rsn_ie_hdr *hdr;
+	const u8 *pos;
+	int left;
+	int i, count;
+
+	os_memset(data, 0, sizeof(*data));
+	data->proto = WPA_PROTO_RSN;
+	data->pairwise_cipher = WPA_CIPHER_CCMP;
+	data->group_cipher = WPA_CIPHER_CCMP;
+	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+	data->capabilities = 0;
+	data->pmkid = NULL;
+	data->num_pmkid = 0;
+#ifdef CONFIG_IEEE80211W
+	data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+#else /* CONFIG_IEEE80211W */
+	data->mgmt_group_cipher = 0;
+#endif /* CONFIG_IEEE80211W */
+
+	if (rsn_ie_len == 0) {
+		/* No RSN IE - fail silently */
+		return -1;
+	}
+
+	if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
+		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
+			   __func__, (unsigned long) rsn_ie_len);
+		return -1;
+	}
+
+	hdr = (const struct rsn_ie_hdr *) rsn_ie;
+
+	if (hdr->elem_id != WLAN_EID_RSN ||
+	    hdr->len != rsn_ie_len - 2 ||
+	    WPA_GET_LE16(hdr->version) != RSN_VERSION) {
+		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
+			   __func__);
+		return -2;
+	}
+
+	pos = (const u8 *) (hdr + 1);
+	left = rsn_ie_len - sizeof(*hdr);
+
+	if (left >= RSN_SELECTOR_LEN) {
+		data->group_cipher = rsn_selector_to_bitfield(pos);
+#ifdef CONFIG_IEEE80211W
+		if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) {
+			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group "
+				   "cipher", __func__);
+			return -1;
+		}
+#endif /* CONFIG_IEEE80211W */
+		pos += RSN_SELECTOR_LEN;
+		left -= RSN_SELECTOR_LEN;
+	} else if (left > 0) {
+		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
+			   __func__, left);
+		return -3;
+	}
+
+	if (left >= 2) {
+		data->pairwise_cipher = 0;
+		count = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
+				   "count %u left %u", __func__, count, left);
+			return -4;
+		}
+		for (i = 0; i < count; i++) {
+			data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
+			pos += RSN_SELECTOR_LEN;
+			left -= RSN_SELECTOR_LEN;
+		}
+#ifdef CONFIG_IEEE80211W
+		if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
+			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
+				   "pairwise cipher", __func__);
+			return -1;
+		}
+#endif /* CONFIG_IEEE80211W */
+	} else if (left == 1) {
+		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
+			   __func__);
+		return -5;
+	}
+
+	if (left >= 2) {
+		data->key_mgmt = 0;
+		count = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
+				   "count %u left %u", __func__, count, left);
+			return -6;
+		}
+		for (i = 0; i < count; i++) {
+			data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
+			pos += RSN_SELECTOR_LEN;
+			left -= RSN_SELECTOR_LEN;
+		}
+	} else if (left == 1) {
+		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
+			   __func__);
+		return -7;
+	}
+
+	if (left >= 2) {
+		data->capabilities = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+	}
+
+	if (left >= 2) {
+		data->num_pmkid = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (left < (int) data->num_pmkid * PMKID_LEN) {
+			wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
+				   "(num_pmkid=%lu left=%d)",
+				   __func__, (unsigned long) data->num_pmkid,
+				   left);
+			data->num_pmkid = 0;
+			return -9;
+		} else {
+			data->pmkid = pos;
+			pos += data->num_pmkid * PMKID_LEN;
+			left -= data->num_pmkid * PMKID_LEN;
+		}
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (left >= 4) {
+		data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
+		if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
+			wpa_printf(MSG_DEBUG, "%s: Unsupported management "
+				   "group cipher 0x%x", __func__,
+				   data->mgmt_group_cipher);
+			return -10;
+		}
+		pos += RSN_SELECTOR_LEN;
+		left -= RSN_SELECTOR_LEN;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	if (left > 0) {
+		wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
+			   __func__, left);
+	}
+
+	return 0;
+#else /* CONFIG_NO_WPA2 */
+	return -1;
+#endif /* CONFIG_NO_WPA2 */
+}
+
+
+static int wpa_selector_to_bitfield(const u8 *s)
+{
+	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
+		return WPA_CIPHER_NONE;
+	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
+		return WPA_CIPHER_WEP40;
+	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
+		return WPA_CIPHER_TKIP;
+	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
+		return WPA_CIPHER_CCMP;
+	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
+		return WPA_CIPHER_WEP104;
+	return 0;
+}
+
+
+static int wpa_key_mgmt_to_bitfield(const u8 *s)
+{
+	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
+		return WPA_KEY_MGMT_IEEE8021X;
+	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
+		return WPA_KEY_MGMT_PSK;
+	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
+		return WPA_KEY_MGMT_WPA_NONE;
+	return 0;
+}
+
+
+int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
+			 struct wpa_ie_data *data)
+{
+	const struct wpa_ie_hdr *hdr;
+	const u8 *pos;
+	int left;
+	int i, count;
+
+	os_memset(data, 0, sizeof(*data));
+	data->proto = WPA_PROTO_WPA;
+	data->pairwise_cipher = WPA_CIPHER_TKIP;
+	data->group_cipher = WPA_CIPHER_TKIP;
+	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+	data->capabilities = 0;
+	data->pmkid = NULL;
+	data->num_pmkid = 0;
+	data->mgmt_group_cipher = 0;
+
+	if (wpa_ie_len == 0) {
+		/* No WPA IE - fail silently */
+		return -1;
+	}
+
+	if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
+		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
+			   __func__, (unsigned long) wpa_ie_len);
+		return -1;
+	}
+
+	hdr = (const struct wpa_ie_hdr *) wpa_ie;
+
+	if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
+	    hdr->len != wpa_ie_len - 2 ||
+	    RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
+	    WPA_GET_LE16(hdr->version) != WPA_VERSION) {
+		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
+			   __func__);
+		return -2;
+	}
+
+	pos = (const u8 *) (hdr + 1);
+	left = wpa_ie_len - sizeof(*hdr);
+
+	if (left >= WPA_SELECTOR_LEN) {
+		data->group_cipher = wpa_selector_to_bitfield(pos);
+		pos += WPA_SELECTOR_LEN;
+		left -= WPA_SELECTOR_LEN;
+	} else if (left > 0) {
+		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
+			   __func__, left);
+		return -3;
+	}
+
+	if (left >= 2) {
+		data->pairwise_cipher = 0;
+		count = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
+				   "count %u left %u", __func__, count, left);
+			return -4;
+		}
+		for (i = 0; i < count; i++) {
+			data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
+			pos += WPA_SELECTOR_LEN;
+			left -= WPA_SELECTOR_LEN;
+		}
+	} else if (left == 1) {
+		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
+			   __func__);
+		return -5;
+	}
+
+	if (left >= 2) {
+		data->key_mgmt = 0;
+		count = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
+				   "count %u left %u", __func__, count, left);
+			return -6;
+		}
+		for (i = 0; i < count; i++) {
+			data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
+			pos += WPA_SELECTOR_LEN;
+			left -= WPA_SELECTOR_LEN;
+		}
+	} else if (left == 1) {
+		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
+			   __func__);
+		return -7;
+	}
+
+	if (left >= 2) {
+		data->capabilities = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+	}
+
+	if (left > 0) {
+		wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
+			   __func__, left);
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_IEEE80211R
+
+/**
+ * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
+ *
+ * IEEE Std 802.11r-2008 - 8.5.1.5.3
+ */
+void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
+		       const u8 *ssid, size_t ssid_len,
+		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
+		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
+{
+	u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
+	       FT_R0KH_ID_MAX_LEN + ETH_ALEN];
+	u8 *pos, r0_key_data[48], hash[32];
+	const u8 *addr[2];
+	size_t len[2];
+
+	/*
+	 * R0-Key-Data = KDF-384(XXKey, "FT-R0",
+	 *                       SSIDlength || SSID || MDID || R0KHlength ||
+	 *                       R0KH-ID || S0KH-ID)
+	 * XXKey is either the second 256 bits of MSK or PSK.
+	 * PMK-R0 = L(R0-Key-Data, 0, 256)
+	 * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
+	 */
+	if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
+		return;
+	pos = buf;
+	*pos++ = ssid_len;
+	os_memcpy(pos, ssid, ssid_len);
+	pos += ssid_len;
+	os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
+	pos += MOBILITY_DOMAIN_ID_LEN;
+	*pos++ = r0kh_id_len;
+	os_memcpy(pos, r0kh_id, r0kh_id_len);
+	pos += r0kh_id_len;
+	os_memcpy(pos, s0kh_id, ETH_ALEN);
+	pos += ETH_ALEN;
+
+	sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
+		   r0_key_data, sizeof(r0_key_data));
+	os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
+
+	/*
+	 * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
+	 */
+	addr[0] = (const u8 *) "FT-R0N";
+	len[0] = 6;
+	addr[1] = r0_key_data + PMK_LEN;
+	len[1] = 16;
+
+	sha256_vector(2, addr, len, hash);
+	os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
+}
+
+
+/**
+ * wpa_derive_pmk_r1_name - Derive PMKR1Name
+ *
+ * IEEE Std 802.11r-2008 - 8.5.1.5.4
+ */
+void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
+			    const u8 *s1kh_id, u8 *pmk_r1_name)
+{
+	u8 hash[32];
+	const u8 *addr[4];
+	size_t len[4];
+
+	/*
+	 * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
+	 *                                  R1KH-ID || S1KH-ID))
+	 */
+	addr[0] = (const u8 *) "FT-R1N";
+	len[0] = 6;
+	addr[1] = pmk_r0_name;
+	len[1] = WPA_PMK_NAME_LEN;
+	addr[2] = r1kh_id;
+	len[2] = FT_R1KH_ID_LEN;
+	addr[3] = s1kh_id;
+	len[3] = ETH_ALEN;
+
+	sha256_vector(4, addr, len, hash);
+	os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
+}
+
+
+/**
+ * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
+ *
+ * IEEE Std 802.11r-2008 - 8.5.1.5.4
+ */
+void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+		       const u8 *r1kh_id, const u8 *s1kh_id,
+		       u8 *pmk_r1, u8 *pmk_r1_name)
+{
+	u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
+	u8 *pos;
+
+	/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
+	pos = buf;
+	os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
+	pos += FT_R1KH_ID_LEN;
+	os_memcpy(pos, s1kh_id, ETH_ALEN);
+	pos += ETH_ALEN;
+
+	sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
+
+	wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
+}
+
+
+/**
+ * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
+ *
+ * IEEE Std 802.11r-2008 - 8.5.1.5.5
+ */
+void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+		       const u8 *sta_addr, const u8 *bssid,
+		       const u8 *pmk_r1_name,
+		       u8 *ptk, size_t ptk_len, u8 *ptk_name)
+{
+	u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
+	u8 *pos, hash[32];
+	const u8 *addr[6];
+	size_t len[6];
+
+	/*
+	 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
+	 *                  BSSID || STA-ADDR)
+	 */
+	pos = buf;
+	os_memcpy(pos, snonce, WPA_NONCE_LEN);
+	pos += WPA_NONCE_LEN;
+	os_memcpy(pos, anonce, WPA_NONCE_LEN);
+	pos += WPA_NONCE_LEN;
+	os_memcpy(pos, bssid, ETH_ALEN);
+	pos += ETH_ALEN;
+	os_memcpy(pos, sta_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+
+	sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
+
+	/*
+	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
+	 *                                ANonce || BSSID || STA-ADDR))
+	 */
+	addr[0] = pmk_r1_name;
+	len[0] = WPA_PMK_NAME_LEN;
+	addr[1] = (const u8 *) "FT-PTKN";
+	len[1] = 7;
+	addr[2] = snonce;
+	len[2] = WPA_NONCE_LEN;
+	addr[3] = anonce;
+	len[3] = WPA_NONCE_LEN;
+	addr[4] = bssid;
+	len[4] = ETH_ALEN;
+	addr[5] = sta_addr;
+	len[5] = ETH_ALEN;
+
+	sha256_vector(6, addr, len, hash);
+	os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
+}
+
+#endif /* CONFIG_IEEE80211R */
+
+
+/**
+ * rsn_pmkid - Calculate PMK identifier
+ * @pmk: Pairwise master key
+ * @pmk_len: Length of pmk in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @pmkid: Buffer for PMKID
+ * @use_sha256: Whether to use SHA256-based KDF
+ *
+ * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
+ * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
+ */
+void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
+	       u8 *pmkid, int use_sha256)
+{
+	char *title = "PMK Name";
+	const u8 *addr[3];
+	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
+	unsigned char hash[SHA256_MAC_LEN];
+
+	addr[0] = (u8 *) title;
+	addr[1] = aa;
+	addr[2] = spa;
+
+#ifdef CONFIG_IEEE80211W
+	if (use_sha256)
+		hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
+	else
+#endif /* CONFIG_IEEE80211W */
+		hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
+	os_memcpy(pmkid, hash, PMKID_LEN);
+}
+
+
+/**
+ * wpa_cipher_txt - Convert cipher suite to a text string
+ * @cipher: Cipher suite (WPA_CIPHER_* enum)
+ * Returns: Pointer to a text string of the cipher suite name
+ */
+const char * wpa_cipher_txt(int cipher)
+{
+	switch (cipher) {
+	case WPA_CIPHER_NONE:
+		return "NONE";
+	case WPA_CIPHER_WEP40:
+		return "WEP-40";
+	case WPA_CIPHER_WEP104:
+		return "WEP-104";
+	case WPA_CIPHER_TKIP:
+		return "TKIP";
+	case WPA_CIPHER_CCMP:
+		return "CCMP";
+	case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
+		return "CCMP+TKIP";
+	case WPA_CIPHER_GCMP:
+		return "GCMP";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+/**
+ * wpa_key_mgmt_txt - Convert key management suite to a text string
+ * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum)
+ * @proto: WPA/WPA2 version (WPA_PROTO_*)
+ * Returns: Pointer to a text string of the key management suite name
+ */
+const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
+{
+	switch (key_mgmt) {
+	case WPA_KEY_MGMT_IEEE8021X:
+		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
+			return "WPA2+WPA/IEEE 802.1X/EAP";
+		return proto == WPA_PROTO_RSN ?
+			"WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
+	case WPA_KEY_MGMT_PSK:
+		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
+			return "WPA2-PSK+WPA-PSK";
+		return proto == WPA_PROTO_RSN ?
+			"WPA2-PSK" : "WPA-PSK";
+	case WPA_KEY_MGMT_NONE:
+		return "NONE";
+	case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
+		return "IEEE 802.1X (no WPA)";
+#ifdef CONFIG_IEEE80211R
+	case WPA_KEY_MGMT_FT_IEEE8021X:
+		return "FT-EAP";
+	case WPA_KEY_MGMT_FT_PSK:
+		return "FT-PSK";
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	case WPA_KEY_MGMT_IEEE8021X_SHA256:
+		return "WPA2-EAP-SHA256";
+	case WPA_KEY_MGMT_PSK_SHA256:
+		return "WPA2-PSK-SHA256";
+#endif /* CONFIG_IEEE80211W */
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+int wpa_compare_rsn_ie(int ft_initial_assoc,
+		       const u8 *ie1, size_t ie1len,
+		       const u8 *ie2, size_t ie2len)
+{
+	if (ie1 == NULL || ie2 == NULL)
+		return -1;
+
+	if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0)
+		return 0; /* identical IEs */
+
+#ifdef CONFIG_IEEE80211R
+	if (ft_initial_assoc) {
+		struct wpa_ie_data ie1d, ie2d;
+		/*
+		 * The PMKID-List in RSN IE is different between Beacon/Probe
+		 * Response/(Re)Association Request frames and EAPOL-Key
+		 * messages in FT initial mobility domain association. Allow
+		 * for this, but verify that other parts of the RSN IEs are
+		 * identical.
+		 */
+		if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 ||
+		    wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0)
+			return -1;
+		if (ie1d.proto == ie2d.proto &&
+		    ie1d.pairwise_cipher == ie2d.pairwise_cipher &&
+		    ie1d.group_cipher == ie2d.group_cipher &&
+		    ie1d.key_mgmt == ie2d.key_mgmt &&
+		    ie1d.capabilities == ie2d.capabilities &&
+		    ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher)
+			return 0;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	return -1;
+}
+
+
+#ifdef CONFIG_IEEE80211R
+int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
+{
+	u8 *start, *end, *rpos, *rend;
+	int added = 0;
+
+	start = ies;
+	end = ies + ies_len;
+
+	while (start < end) {
+		if (*start == WLAN_EID_RSN)
+			break;
+		start += 2 + start[1];
+	}
+	if (start >= end) {
+		wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
+			   "IEs data");
+		return -1;
+	}
+	wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
+		    start, 2 + start[1]);
+
+	/* Find start of PMKID-Count */
+	rpos = start + 2;
+	rend = rpos + start[1];
+
+	/* Skip Version and Group Data Cipher Suite */
+	rpos += 2 + 4;
+	/* Skip Pairwise Cipher Suite Count and List */
+	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
+	/* Skip AKM Suite Count and List */
+	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
+
+	if (rpos == rend) {
+		/* Add RSN Capabilities */
+		os_memmove(rpos + 2, rpos, end - rpos);
+		*rpos++ = 0;
+		*rpos++ = 0;
+	} else {
+		/* Skip RSN Capabilities */
+		rpos += 2;
+		if (rpos > rend) {
+			wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
+				   "IEs data");
+			return -1;
+		}
+	}
+
+	if (rpos == rend) {
+		/* No PMKID-Count field included; add it */
+		os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos);
+		WPA_PUT_LE16(rpos, 1);
+		rpos += 2;
+		os_memcpy(rpos, pmkid, PMKID_LEN);
+		added += 2 + PMKID_LEN;
+		start[1] += 2 + PMKID_LEN;
+	} else {
+		/* PMKID-Count was included; use it */
+		if (WPA_GET_LE16(rpos) != 0) {
+			wpa_printf(MSG_ERROR, "FT: Unexpected PMKID "
+				   "in RSN IE in EAPOL-Key data");
+			return -1;
+		}
+		WPA_PUT_LE16(rpos, 1);
+		rpos += 2;
+		os_memmove(rpos + PMKID_LEN, rpos, end - rpos);
+		os_memcpy(rpos, pmkid, PMKID_LEN);
+		added += PMKID_LEN;
+		start[1] += PMKID_LEN;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
+		    "(PMKID inserted)", start, 2 + start[1]);
+
+	return added;
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+int wpa_cipher_key_len(int cipher)
+{
+	switch (cipher) {
+	case WPA_CIPHER_CCMP:
+	case WPA_CIPHER_GCMP:
+		return 16;
+	case WPA_CIPHER_TKIP:
+		return 32;
+	case WPA_CIPHER_WEP104:
+		return 13;
+	case WPA_CIPHER_WEP40:
+		return 5;
+	}
+
+	return 0;
+}
+
+
+int wpa_cipher_rsc_len(int cipher)
+{
+	switch (cipher) {
+	case WPA_CIPHER_CCMP:
+	case WPA_CIPHER_GCMP:
+	case WPA_CIPHER_TKIP:
+		return 6;
+	case WPA_CIPHER_WEP104:
+	case WPA_CIPHER_WEP40:
+		return 0;
+	}
+
+	return 0;
+}
+
+
+int wpa_cipher_to_alg(int cipher)
+{
+	switch (cipher) {
+	case WPA_CIPHER_CCMP:
+		return WPA_ALG_CCMP;
+	case WPA_CIPHER_GCMP:
+		return WPA_ALG_GCMP;
+	case WPA_CIPHER_TKIP:
+		return WPA_ALG_TKIP;
+	case WPA_CIPHER_WEP104:
+	case WPA_CIPHER_WEP40:
+		return WPA_ALG_WEP;
+	}
+	return WPA_ALG_NONE;
+}
+
+
+int wpa_cipher_valid_pairwise(int cipher)
+{
+	return cipher == WPA_CIPHER_CCMP ||
+		cipher == WPA_CIPHER_GCMP ||
+		cipher == WPA_CIPHER_TKIP;
+}
+
+
+u32 wpa_cipher_to_suite(int proto, int cipher)
+{
+	if (cipher & WPA_CIPHER_CCMP)
+		return (proto == WPA_PROTO_RSN ?
+			RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
+	if (cipher & WPA_CIPHER_GCMP)
+		return RSN_CIPHER_SUITE_GCMP;
+	if (cipher & WPA_CIPHER_TKIP)
+		return (proto == WPA_PROTO_RSN ?
+			RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
+	if (cipher & WPA_CIPHER_WEP104)
+		return (proto == WPA_PROTO_RSN ?
+			RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104);
+	if (cipher & WPA_CIPHER_WEP40)
+		return (proto == WPA_PROTO_RSN ?
+			RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40);
+	if (cipher & WPA_CIPHER_NONE)
+		return (proto == WPA_PROTO_RSN ?
+			RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
+	return 0;
+}
+
+
+int rsn_cipher_put_suites(u8 *pos, int ciphers)
+{
+	int num_suites = 0;
+
+	if (ciphers & WPA_CIPHER_CCMP) {
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (ciphers & WPA_CIPHER_GCMP) {
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (ciphers & WPA_CIPHER_TKIP) {
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (ciphers & WPA_CIPHER_NONE) {
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+
+	return num_suites;
+}
+
+
+int wpa_cipher_put_suites(u8 *pos, int ciphers)
+{
+	int num_suites = 0;
+
+	if (ciphers & WPA_CIPHER_CCMP) {
+		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
+		pos += WPA_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (ciphers & WPA_CIPHER_TKIP) {
+		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
+		pos += WPA_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (ciphers & WPA_CIPHER_NONE) {
+		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
+		pos += WPA_SELECTOR_LEN;
+		num_suites++;
+	}
+
+	return num_suites;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/wpa_common.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,394 @@
+/*
+ * WPA definitions shared between hostapd and wpa_supplicant
+ * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_COMMON_H
+#define WPA_COMMON_H
+
+#define WPA_MAX_SSID_LEN 32
+
+/* IEEE 802.11i */
+#define PMKID_LEN 16
+#define PMK_LEN 32
+#define WPA_REPLAY_COUNTER_LEN 8
+#define WPA_NONCE_LEN 32
+#define WPA_KEY_RSC_LEN 8
+#define WPA_GMK_LEN 32
+#define WPA_GTK_MAX_LEN 32
+
+#define WPA_SELECTOR_LEN 4
+#define WPA_VERSION 1
+#define RSN_SELECTOR_LEN 4
+#define RSN_VERSION 1
+
+#define RSN_SELECTOR(a, b, c, d) \
+	((((u32) (a)) << 24) | (((u32) (b)) << 16) | (((u32) (c)) << 8) | \
+	 (u32) (d))
+
+#define WPA_AUTH_KEY_MGMT_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
+#define WPA_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
+#define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
+#define WPA_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0)
+#define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
+#define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
+#define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
+#if 0
+#define WPA_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x50, 0xf2, 3)
+#endif
+#define WPA_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x50, 0xf2, 4)
+#define WPA_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x50, 0xf2, 5)
+
+
+#define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
+#define RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
+#ifdef CONFIG_IEEE80211R
+#define RSN_AUTH_KEY_MGMT_FT_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
+#define RSN_AUTH_KEY_MGMT_FT_PSK RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
+#endif /* CONFIG_IEEE80211R */
+#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
+#define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
+#define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
+#define RSN_AUTH_KEY_MGMT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
+#define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
+#define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
+
+#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
+#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
+#define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
+#if 0
+#define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
+#endif
+#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
+#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
+#ifdef CONFIG_IEEE80211W
+#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
+#endif /* CONFIG_IEEE80211W */
+#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
+#define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
+
+/* EAPOL-Key Key Data Encapsulation
+ * GroupKey and PeerKey require encryption, otherwise, encryption is optional.
+ */
+#define RSN_KEY_DATA_GROUPKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
+#if 0
+#define RSN_KEY_DATA_STAKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
+#endif
+#define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
+#define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
+#ifdef CONFIG_PEERKEY
+#define RSN_KEY_DATA_SMK RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
+#define RSN_KEY_DATA_NONCE RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
+#define RSN_KEY_DATA_LIFETIME RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
+#define RSN_KEY_DATA_ERROR RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211W
+#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
+#endif /* CONFIG_IEEE80211W */
+#define RSN_KEY_DATA_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 10)
+#define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
+#define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
+
+#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
+
+#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val))
+#define RSN_SELECTOR_GET(a) WPA_GET_BE32((const u8 *) (a))
+
+#define RSN_NUM_REPLAY_COUNTERS_1 0
+#define RSN_NUM_REPLAY_COUNTERS_2 1
+#define RSN_NUM_REPLAY_COUNTERS_4 2
+#define RSN_NUM_REPLAY_COUNTERS_16 3
+
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+#ifdef CONFIG_IEEE80211W
+#define WPA_IGTK_LEN 16
+#endif /* CONFIG_IEEE80211W */
+
+
+/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */
+#define WPA_CAPABILITY_PREAUTH BIT(0)
+#define WPA_CAPABILITY_NO_PAIRWISE BIT(1)
+/* B2-B3: PTKSA Replay Counter */
+/* B4-B5: GTKSA Replay Counter */
+#define WPA_CAPABILITY_MFPR BIT(6)
+#define WPA_CAPABILITY_MFPC BIT(7)
+/* B8: Reserved */
+#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9)
+#define WPA_CAPABILITY_SPP_A_MSDU_CAPABLE BIT(10)
+#define WPA_CAPABILITY_SPP_A_MSDU_REQUIRED BIT(11)
+#define WPA_CAPABILITY_PBAC BIT(12)
+#define WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST BIT(13)
+/* B14-B15: Reserved */
+
+
+/* IEEE 802.11r */
+#define MOBILITY_DOMAIN_ID_LEN 2
+#define FT_R0KH_ID_MAX_LEN 48
+#define FT_R1KH_ID_LEN 6
+#define WPA_PMK_NAME_LEN 16
+
+
+/* IEEE 802.11, 8.5.2 EAPOL-Key frames */
+#define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2)))
+#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0)
+#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1)
+#define WPA_KEY_INFO_TYPE_AES_128_CMAC 3
+#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */
+/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */
+#define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5))
+#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4
+#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */
+#define WPA_KEY_INFO_TXRX BIT(6) /* group */
+#define WPA_KEY_INFO_ACK BIT(7)
+#define WPA_KEY_INFO_MIC BIT(8)
+#define WPA_KEY_INFO_SECURE BIT(9)
+#define WPA_KEY_INFO_ERROR BIT(10)
+#define WPA_KEY_INFO_REQUEST BIT(11)
+#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */
+#define WPA_KEY_INFO_SMK_MESSAGE BIT(13)
+
+
+struct wpa_eapol_key {
+	u8 type;
+	/* Note: key_info, key_length, and key_data_length are unaligned */
+	u8 key_info[2]; /* big endian */
+	u8 key_length[2]; /* big endian */
+	u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
+	u8 key_nonce[WPA_NONCE_LEN];
+	u8 key_iv[16];
+	u8 key_rsc[WPA_KEY_RSC_LEN];
+	u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
+	u8 key_mic[16];
+	u8 key_data_length[2]; /* big endian */
+	/* followed by key_data_length bytes of key_data */
+} STRUCT_PACKED;
+
+/**
+ * struct wpa_ptk - WPA Pairwise Transient Key
+ * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
+ */
+struct wpa_ptk {
+	u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */
+	u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */
+	u8 tk1[16]; /* Temporal Key 1 (TK1) */
+	union {
+		u8 tk2[16]; /* Temporal Key 2 (TK2) */
+		struct {
+			u8 tx_mic_key[8];
+			u8 rx_mic_key[8];
+		} auth;
+	} u;
+} STRUCT_PACKED;
+
+
+/* WPA IE version 1
+ * 00-50-f2:1 (OUI:OUI type)
+ * 0x01 0x00 (version; little endian)
+ * (all following fields are optional:)
+ * Group Suite Selector (4 octets) (default: TKIP)
+ * Pairwise Suite Count (2 octets, little endian) (default: 1)
+ * Pairwise Suite List (4 * n octets) (default: TKIP)
+ * Authenticated Key Management Suite Count (2 octets, little endian)
+ *    (default: 1)
+ * Authenticated Key Management Suite List (4 * n octets)
+ *    (default: unspec 802.1X)
+ * WPA Capabilities (2 octets, little endian) (default: 0)
+ */
+
+struct wpa_ie_hdr {
+	u8 elem_id;
+	u8 len;
+	u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */
+	u8 version[2]; /* little endian */
+} STRUCT_PACKED;
+
+
+/* 1/4: PMKID
+ * 2/4: RSN IE
+ * 3/4: one or two RSN IEs + GTK IE (encrypted)
+ * 4/4: empty
+ * 1/2: GTK IE (encrypted)
+ * 2/2: empty
+ */
+
+/* RSN IE version 1
+ * 0x01 0x00 (version; little endian)
+ * (all following fields are optional:)
+ * Group Suite Selector (4 octets) (default: CCMP)
+ * Pairwise Suite Count (2 octets, little endian) (default: 1)
+ * Pairwise Suite List (4 * n octets) (default: CCMP)
+ * Authenticated Key Management Suite Count (2 octets, little endian)
+ *    (default: 1)
+ * Authenticated Key Management Suite List (4 * n octets)
+ *    (default: unspec 802.1X)
+ * RSN Capabilities (2 octets, little endian) (default: 0)
+ * PMKID Count (2 octets) (default: 0)
+ * PMKID List (16 * n octets)
+ * Management Group Cipher Suite (4 octets) (default: AES-128-CMAC)
+ */
+
+struct rsn_ie_hdr {
+	u8 elem_id; /* WLAN_EID_RSN */
+	u8 len;
+	u8 version[2]; /* little endian */
+} STRUCT_PACKED;
+
+
+#ifdef CONFIG_PEERKEY
+enum {
+	STK_MUI_4WAY_STA_AP = 1,
+	STK_MUI_4WAY_STAT_STA = 2,
+	STK_MUI_GTK = 3,
+	STK_MUI_SMK = 4
+};
+
+enum {
+	STK_ERR_STA_NR = 1,
+	STK_ERR_STA_NRSN = 2,
+	STK_ERR_CPHR_NS = 3,
+	STK_ERR_NO_STSL = 4
+};
+#endif /* CONFIG_PEERKEY */
+
+struct rsn_error_kde {
+	be16 mui;
+	be16 error_type;
+} STRUCT_PACKED;
+
+#ifdef CONFIG_IEEE80211W
+struct wpa_igtk_kde {
+	u8 keyid[2];
+	u8 pn[6];
+	u8 igtk[WPA_IGTK_LEN];
+} STRUCT_PACKED;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_IEEE80211R
+struct rsn_mdie {
+	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
+	u8 ft_capab;
+} STRUCT_PACKED;
+
+#define RSN_FT_CAPAB_FT_OVER_DS BIT(0)
+#define RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP BIT(1)
+
+struct rsn_ftie {
+	u8 mic_control[2];
+	u8 mic[16];
+	u8 anonce[WPA_NONCE_LEN];
+	u8 snonce[WPA_NONCE_LEN];
+	/* followed by optional parameters */
+} STRUCT_PACKED;
+
+#define FTIE_SUBELEM_R1KH_ID 1
+#define FTIE_SUBELEM_GTK 2
+#define FTIE_SUBELEM_R0KH_ID 3
+#define FTIE_SUBELEM_IGTK 4
+
+struct rsn_rdie {
+	u8 id;
+	u8 descr_count;
+	le16 status_code;
+} STRUCT_PACKED;
+
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
+		      u8 *mic);
+void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
+		    const u8 *addr1, const u8 *addr2,
+		    const u8 *nonce1, const u8 *nonce2,
+		    u8 *ptk, size_t ptk_len, int use_sha256);
+
+#ifdef CONFIG_IEEE80211R
+int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
+	       u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
+	       const u8 *ftie, size_t ftie_len,
+	       const u8 *rsnie, size_t rsnie_len,
+	       const u8 *ric, size_t ric_len, u8 *mic);
+void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
+		       const u8 *ssid, size_t ssid_len,
+		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
+		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
+void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
+			    const u8 *s1kh_id, u8 *pmk_r1_name);
+void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+		       const u8 *r1kh_id, const u8 *s1kh_id,
+		       u8 *pmk_r1, u8 *pmk_r1_name);
+void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+		       const u8 *sta_addr, const u8 *bssid,
+		       const u8 *pmk_r1_name,
+		       u8 *ptk, size_t ptk_len, u8 *ptk_name);
+#endif /* CONFIG_IEEE80211R */
+
+struct wpa_ie_data {
+	int proto;
+	int pairwise_cipher;
+	int group_cipher;
+	int key_mgmt;
+	int capabilities;
+	size_t num_pmkid;
+	const u8 *pmkid;
+	int mgmt_group_cipher;
+};
+
+
+int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
+			 struct wpa_ie_data *data);
+int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
+			 struct wpa_ie_data *data);
+
+void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
+	       u8 *pmkid, int use_sha256);
+
+const char * wpa_cipher_txt(int cipher);
+const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
+int wpa_compare_rsn_ie(int ft_initial_assoc,
+		       const u8 *ie1, size_t ie1len,
+		       const u8 *ie2, size_t ie2len);
+int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid);
+
+struct wpa_ft_ies {
+	const u8 *mdie;
+	size_t mdie_len;
+	const u8 *ftie;
+	size_t ftie_len;
+	const u8 *r1kh_id;
+	const u8 *gtk;
+	size_t gtk_len;
+	const u8 *r0kh_id;
+	size_t r0kh_id_len;
+	const u8 *rsn;
+	size_t rsn_len;
+	const u8 *rsn_pmkid;
+	const u8 *tie;
+	size_t tie_len;
+	const u8 *igtk;
+	size_t igtk_len;
+	const u8 *ric;
+	size_t ric_len;
+};
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse);
+
+int wpa_cipher_key_len(int cipher);
+int wpa_cipher_rsc_len(int cipher);
+int wpa_cipher_to_alg(int cipher);
+int wpa_cipher_valid_pairwise(int cipher);
+u32 wpa_cipher_to_suite(int proto, int cipher);
+int rsn_cipher_put_suites(u8 *pos, int ciphers);
+int wpa_cipher_put_suites(u8 *pos, int ciphers);
+
+#endif /* WPA_COMMON_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/common/wpa_ctrl.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,322 @@
+/*
+ * wpa_supplicant/hostapd control interface library
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_CTRL_H
+#define WPA_CTRL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* wpa_supplicant control interface - fixed message prefixes */
+
+/** Interactive request for identity/password/pin */
+#define WPA_CTRL_REQ "CTRL-REQ-"
+
+/** Response to identity/password/pin request */
+#define WPA_CTRL_RSP "CTRL-RSP-"
+
+/* Event messages with fixed prefix */
+/** Authentication completed successfully and data connection enabled */
+#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "
+/** Disconnected, data connection is not available */
+#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
+/** Association rejected during connection attempt */
+#define WPA_EVENT_ASSOC_REJECT "CTRL-EVENT-ASSOC-REJECT "
+/** wpa_supplicant is exiting */
+#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
+/** Password change was completed successfully */
+#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED "
+/** EAP-Request/Notification received */
+#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION "
+/** EAP authentication started (EAP-Request/Identity received) */
+#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED "
+/** EAP method proposed by the server */
+#define WPA_EVENT_EAP_PROPOSED_METHOD "CTRL-EVENT-EAP-PROPOSED-METHOD "
+/** EAP method selected */
+#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
+/** EAP peer certificate from TLS */
+#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT "
+/** EAP TLS certificate chain validation error */
+#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
+/** EAP authentication completed successfully */
+#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
+/** EAP authentication failed (EAP-Failure received) */
+#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
+/** Network block temporarily disabled (e.g., due to authentication failure) */
+#define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED "
+/** Temporarily disabled network block re-enabled */
+#define WPA_EVENT_REENABLED "CTRL-EVENT-SSID-REENABLED "
+/** New scan results available */
+#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
+/** wpa_supplicant state change */
+#define WPA_EVENT_STATE_CHANGE "CTRL-EVENT-STATE-CHANGE "
+/** A new BSS entry was added (followed by BSS entry id and BSSID) */
+#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED "
+/** A BSS entry was removed (followed by BSS entry id and BSSID) */
+#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED "
+
+/** WPS overlap detected in PBC mode */
+#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
+/** Available WPS AP with active PBC found in scan results */
+#define WPS_EVENT_AP_AVAILABLE_PBC "WPS-AP-AVAILABLE-PBC "
+/** Available WPS AP with our address as authorized in scan results */
+#define WPS_EVENT_AP_AVAILABLE_AUTH "WPS-AP-AVAILABLE-AUTH "
+/** Available WPS AP with recently selected PIN registrar found in scan results
+ */
+#define WPS_EVENT_AP_AVAILABLE_PIN "WPS-AP-AVAILABLE-PIN "
+/** Available WPS AP found in scan results */
+#define WPS_EVENT_AP_AVAILABLE "WPS-AP-AVAILABLE "
+/** A new credential received */
+#define WPS_EVENT_CRED_RECEIVED "WPS-CRED-RECEIVED "
+/** M2D received */
+#define WPS_EVENT_M2D "WPS-M2D "
+/** WPS registration failed after M2/M2D */
+#define WPS_EVENT_FAIL "WPS-FAIL "
+/** WPS registration completed successfully */
+#define WPS_EVENT_SUCCESS "WPS-SUCCESS "
+/** WPS enrollment attempt timed out and was terminated */
+#define WPS_EVENT_TIMEOUT "WPS-TIMEOUT "
+
+#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN "
+
+#define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK "
+
+/* WPS ER events */
+#define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD "
+#define WPS_EVENT_ER_AP_REMOVE "WPS-ER-AP-REMOVE "
+#define WPS_EVENT_ER_ENROLLEE_ADD "WPS-ER-ENROLLEE-ADD "
+#define WPS_EVENT_ER_ENROLLEE_REMOVE "WPS-ER-ENROLLEE-REMOVE "
+#define WPS_EVENT_ER_AP_SETTINGS "WPS-ER-AP-SETTINGS "
+#define WPS_EVENT_ER_SET_SEL_REG "WPS-ER-AP-SET-SEL-REG "
+
+/** P2P device found */
+#define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND "
+
+/** P2P device lost */
+#define P2P_EVENT_DEVICE_LOST "P2P-DEVICE-LOST "
+
+/** A P2P device requested GO negotiation, but we were not ready to start the
+ * negotiation */
+#define P2P_EVENT_GO_NEG_REQUEST "P2P-GO-NEG-REQUEST "
+#define P2P_EVENT_GO_NEG_SUCCESS "P2P-GO-NEG-SUCCESS "
+#define P2P_EVENT_GO_NEG_FAILURE "P2P-GO-NEG-FAILURE "
+#define P2P_EVENT_GROUP_FORMATION_SUCCESS "P2P-GROUP-FORMATION-SUCCESS "
+#define P2P_EVENT_GROUP_FORMATION_FAILURE "P2P-GROUP-FORMATION-FAILURE "
+#define P2P_EVENT_GROUP_STARTED "P2P-GROUP-STARTED "
+#define P2P_EVENT_GROUP_REMOVED "P2P-GROUP-REMOVED "
+#define P2P_EVENT_CROSS_CONNECT_ENABLE "P2P-CROSS-CONNECT-ENABLE "
+#define P2P_EVENT_CROSS_CONNECT_DISABLE "P2P-CROSS-CONNECT-DISABLE "
+/* parameters: <peer address> <PIN> */
+#define P2P_EVENT_PROV_DISC_SHOW_PIN "P2P-PROV-DISC-SHOW-PIN "
+/* parameters: <peer address> */
+#define P2P_EVENT_PROV_DISC_ENTER_PIN "P2P-PROV-DISC-ENTER-PIN "
+/* parameters: <peer address> */
+#define P2P_EVENT_PROV_DISC_PBC_REQ "P2P-PROV-DISC-PBC-REQ "
+/* parameters: <peer address> */
+#define P2P_EVENT_PROV_DISC_PBC_RESP "P2P-PROV-DISC-PBC-RESP "
+/* parameters: <peer address> <status> */
+#define P2P_EVENT_PROV_DISC_FAILURE "P2P-PROV-DISC-FAILURE"
+/* parameters: <freq> <src addr> <dialog token> <update indicator> <TLVs> */
+#define P2P_EVENT_SERV_DISC_REQ "P2P-SERV-DISC-REQ "
+/* parameters: <src addr> <update indicator> <TLVs> */
+#define P2P_EVENT_SERV_DISC_RESP "P2P-SERV-DISC-RESP "
+#define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
+#define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
+#define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
+
+#define INTERWORKING_AP "INTERWORKING-AP "
+#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
+
+#define GAS_RESPONSE_INFO "GAS-RESPONSE-INFO "
+
+/* hostapd control interface - fixed message prefixes */
+#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
+#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
+#define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS "
+#define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED "
+#define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED "
+#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED "
+#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
+#define AP_STA_CONNECTED "AP-STA-CONNECTED "
+#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
+
+
+/* BSS command information masks */
+
+#define WPA_BSS_MASK_ALL		0xFFFFFFFF
+#define WPA_BSS_MASK_ID			BIT(0)
+#define WPA_BSS_MASK_BSSID		BIT(1)
+#define WPA_BSS_MASK_FREQ		BIT(2)
+#define WPA_BSS_MASK_BEACON_INT		BIT(3)
+#define WPA_BSS_MASK_CAPABILITIES	BIT(4)
+#define WPA_BSS_MASK_QUAL		BIT(5)
+#define WPA_BSS_MASK_NOISE		BIT(6)
+#define WPA_BSS_MASK_LEVEL		BIT(7)
+#define WPA_BSS_MASK_TSF		BIT(8)
+#define WPA_BSS_MASK_AGE		BIT(9)
+#define WPA_BSS_MASK_IE			BIT(10)
+#define WPA_BSS_MASK_FLAGS		BIT(11)
+#define WPA_BSS_MASK_SSID		BIT(12)
+#define WPA_BSS_MASK_WPS_SCAN		BIT(13)
+#define WPA_BSS_MASK_P2P_SCAN		BIT(14)
+#define WPA_BSS_MASK_INTERNETW		BIT(15)
+#define WPA_BSS_MASK_WIFI_DISPLAY	BIT(16)
+
+
+/* wpa_supplicant/hostapd control interface access */
+
+/**
+ * wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd
+ * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
+ * Returns: Pointer to abstract control interface data or %NULL on failure
+ *
+ * This function is used to open a control interface to wpa_supplicant/hostapd.
+ * ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path
+ * is configured in wpa_supplicant/hostapd and other programs using the control
+ * interface need to use matching path configuration.
+ */
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
+
+
+/**
+ * wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ *
+ * This function is used to close a control interface.
+ */
+void wpa_ctrl_close(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_request - Send a command to wpa_supplicant/hostapd
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * @cmd: Command; usually, ASCII text, e.g., "PING"
+ * @cmd_len: Length of the cmd in bytes
+ * @reply: Buffer for the response
+ * @reply_len: Reply buffer length
+ * @msg_cb: Callback function for unsolicited messages or %NULL if not used
+ * Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout
+ *
+ * This function is used to send commands to wpa_supplicant/hostapd. Received
+ * response will be written to reply and reply_len is set to the actual length
+ * of the reply. This function will block for up to two seconds while waiting
+ * for the reply. If unsolicited messages are received, the blocking time may
+ * be longer.
+ *
+ * msg_cb can be used to register a callback function that will be called for
+ * unsolicited messages received while waiting for the command response. These
+ * messages may be received if wpa_ctrl_request() is called at the same time as
+ * wpa_supplicant/hostapd is sending such a message. This can happen only if
+ * the program has used wpa_ctrl_attach() to register itself as a monitor for
+ * event messages. Alternatively to msg_cb, programs can register two control
+ * interface connections and use one of them for commands and the other one for
+ * receiving event messages, in other words, call wpa_ctrl_attach() only for
+ * the control interface connection that will be used for event messages.
+ */
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+		     char *reply, size_t *reply_len,
+		     void (*msg_cb)(char *msg, size_t len));
+
+
+/**
+ * wpa_ctrl_attach - Register as an event monitor for the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: 0 on success, -1 on failure, -2 on timeout
+ *
+ * This function registers the control interface connection as a monitor for
+ * wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the
+ * control interface connection starts receiving event messages that can be
+ * read with wpa_ctrl_recv().
+ */
+int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_detach - Unregister event monitor from the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: 0 on success, -1 on failure, -2 on timeout
+ *
+ * This function unregisters the control interface connection as a monitor for
+ * wpa_supplicant/hostapd events, i.e., cancels the registration done with
+ * wpa_ctrl_attach().
+ */
+int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_recv - Receive a pending control interface message
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * @reply: Buffer for the message data
+ * @reply_len: Length of the reply buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function will receive a pending control interface message. This
+ * function will block if no messages are available. The received response will
+ * be written to reply and reply_len is set to the actual length of the reply.
+ * wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach()
+ * must have been used to register the control interface as an event monitor.
+ */
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);
+
+
+/**
+ * wpa_ctrl_pending - Check whether there are pending event messages
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: 1 if there are pending messages, 0 if no, or -1 on error
+ *
+ * This function will check whether there are any pending control interface
+ * message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is
+ * only used for event messages, i.e., wpa_ctrl_attach() must have been used to
+ * register the control interface as an event monitor.
+ */
+int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_get_fd - Get file descriptor used by the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: File descriptor used for the connection
+ *
+ * This function can be used to get the file descriptor that is used for the
+ * control interface connection. The returned value can be used, e.g., with
+ * select() while waiting for multiple events.
+ *
+ * The returned file descriptor must not be used directly for sending or
+ * receiving packets; instead, the library functions wpa_ctrl_request() and
+ * wpa_ctrl_recv() must be used for this.
+ */
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
+
+char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl);
+
+#ifdef ANDROID
+/**
+ * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
+ * may be left over from clients that were previously connected to
+ * wpa_supplicant. This keeps these files from being orphaned in the
+ * event of crashes that prevented them from being removed as part
+ * of the normal orderly shutdown.
+ */
+void wpa_ctrl_cleanup(void);
+#endif /* ANDROID */
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+/* Port range for multiple wpa_supplicant instances and multiple VIFs */
+#define WPA_CTRL_IFACE_PORT 9877
+#define WPA_CTRL_IFACE_PORT_LIMIT 50 /* decremented from start */
+#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
+#define WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT 20 /* incremented from start */
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* WPA_CTRL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/aes-unwrap.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,73 @@
+/*
+ * AES key unwrap (128-bit KEK, RFC3394)
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "aes.h"
+#include "aes_wrap.h"
+
+/**
+ * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * @kek: Key encryption key (KEK)
+ * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
+ * bytes
+ * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits
+ * @plain: Plaintext key, n * 64 bits
+ * Returns: 0 on success, -1 on failure (e.g., integrity verification failed)
+ */
+int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
+{
+	u8 a[8], *r, b[16];
+	int i, j;
+	void *ctx;
+
+	/* 1) Initialize variables. */
+	os_memcpy(a, cipher, 8);
+	r = plain;
+	os_memcpy(r, cipher + 8, 8 * n);
+
+	ctx = aes_decrypt_init(kek, 16);
+	if (ctx == NULL)
+		return -1;
+
+	/* 2) Compute intermediate values.
+	 * For j = 5 to 0
+	 *     For i = n to 1
+	 *         B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i
+	 *         A = MSB(64, B)
+	 *         R[i] = LSB(64, B)
+	 */
+	for (j = 5; j >= 0; j--) {
+		r = plain + (n - 1) * 8;
+		for (i = n; i >= 1; i--) {
+			os_memcpy(b, a, 8);
+			b[7] ^= n * j + i;
+
+			os_memcpy(b + 8, r, 8);
+			aes_decrypt(ctx, b, b);
+			os_memcpy(a, b, 8);
+			os_memcpy(r, b + 8, 8);
+			r -= 8;
+		}
+	}
+	aes_decrypt_deinit(ctx);
+
+	/* 3) Output results.
+	 *
+	 * These are already in @plain due to the location of temporary
+	 * variables. Just verify that the IV matches with the expected value.
+	 */
+	for (i = 0; i < 8; i++) {
+		if (a[i] != 0xa6)
+			return -1;
+	}
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/aes.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,21 @@
+/*
+ * AES functions
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AES_H
+#define AES_H
+
+#define AES_BLOCK_SIZE 16
+
+void * aes_encrypt_init(const u8 *key, size_t len);
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
+void aes_encrypt_deinit(void *ctx);
+void * aes_decrypt_init(const u8 *key, size_t len);
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
+void aes_decrypt_deinit(void *ctx);
+
+#endif /* AES_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/aes_wrap.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,64 @@
+/*
+ * AES-based functions
+ *
+ * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * - One-Key CBC MAC (OMAC1) hash with AES-128
+ * - AES-128 CTR mode encryption
+ * - AES-128 EAX mode encryption/decryption
+ * - AES-128 CBC
+ * - AES-GCM
+ * - AES-CCM
+ *
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AES_WRAP_H
+#define AES_WRAP_H
+
+int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher);
+int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain);
+int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem,
+				      const u8 *addr[], const size_t *len,
+				      u8 *mac);
+int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len,
+			       u8 *mac);
+int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
+int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
+				     u8 *data, size_t data_len);
+int __must_check aes_128_eax_encrypt(const u8 *key,
+				     const u8 *nonce, size_t nonce_len,
+				     const u8 *hdr, size_t hdr_len,
+				     u8 *data, size_t data_len, u8 *tag);
+int __must_check aes_128_eax_decrypt(const u8 *key,
+				     const u8 *nonce, size_t nonce_len,
+				     const u8 *hdr, size_t hdr_len,
+				     u8 *data, size_t data_len, const u8 *tag);
+int __must_check aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
+				     size_t data_len);
+int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
+				     size_t data_len);
+int __must_check aes_gcm_ae(const u8 *key, size_t key_len,
+			    const u8 *iv, size_t iv_len,
+			    const u8 *plain, size_t plain_len,
+			    const u8 *aad, size_t aad_len,
+			    u8 *crypt, u8 *tag);
+int __must_check aes_gcm_ad(const u8 *key, size_t key_len,
+			    const u8 *iv, size_t iv_len,
+			    const u8 *crypt, size_t crypt_len,
+			    const u8 *aad, size_t aad_len, const u8 *tag,
+			    u8 *plain);
+int __must_check aes_gmac(const u8 *key, size_t key_len,
+			  const u8 *iv, size_t iv_len,
+			  const u8 *aad, size_t aad_len, u8 *tag);
+int __must_check aes_ccm_ae(const u8 *key, size_t key_len, const u8 *nonce,
+			    size_t M, const u8 *plain, size_t plain_len,
+			    const u8 *aad, size_t aad_len, u8 *crypt, u8 *auth);
+int __must_check aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce,
+			    size_t M, const u8 *crypt, size_t crypt_len,
+			    const u8 *aad, size_t aad_len, const u8 *auth,
+			    u8 *plain);
+
+#endif /* AES_WRAP_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/crypto.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,460 @@
+/*
+ * WPA Supplicant / wrapper functions for crypto libraries
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file defines the cryptographic functions that need to be implemented
+ * for wpa_supplicant and hostapd. When TLS is not used, internal
+ * implementation of MD5, SHA1, and AES is used and no external libraries are
+ * required. When TLS is enabled (e.g., by enabling EAP-TLS or EAP-PEAP), the
+ * crypto library used by the TLS implementation is expected to be used for
+ * non-TLS needs, too, in order to save space by not implementing these
+ * functions twice.
+ *
+ * Wrapper code for using each crypto library is in its own file (crypto*.c)
+ * and one of these files is build and linked in to provide the functions
+ * defined here.
+ */
+
+#ifndef CRYPTO_H
+#define CRYPTO_H
+
+/**
+ * md4_vector - MD4 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
+
+/**
+ * md5_vector - MD5 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
+
+
+/**
+ * sha1_vector - SHA-1 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		u8 *mac);
+
+/**
+ * fips186_2-prf - NIST FIPS Publication 186-2 change notice 1 PRF
+ * @seed: Seed/key for the PRF
+ * @seed_len: Seed length in bytes
+ * @x: Buffer for PRF output
+ * @xlen: Output length in bytes
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function implements random number generation specified in NIST FIPS
+ * Publication 186-2 for EAP-SIM. This PRF uses a function that is similar to
+ * SHA-1, but has different message padding.
+ */
+int __must_check fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x,
+			       size_t xlen);
+
+/**
+ * sha256_vector - SHA256 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		  u8 *mac);
+
+/**
+ * des_encrypt - Encrypt one block with DES
+ * @clear: 8 octets (in)
+ * @key: 7 octets (in) (no parity bits included)
+ * @cypher: 8 octets (out)
+ */
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher);
+
+/**
+ * aes_encrypt_init - Initialize AES for encryption
+ * @key: Encryption key
+ * @len: Key length in bytes (usually 16, i.e., 128 bits)
+ * Returns: Pointer to context data or %NULL on failure
+ */
+void * aes_encrypt_init(const u8 *key, size_t len);
+
+/**
+ * aes_encrypt - Encrypt one AES block
+ * @ctx: Context pointer from aes_encrypt_init()
+ * @plain: Plaintext data to be encrypted (16 bytes)
+ * @crypt: Buffer for the encrypted data (16 bytes)
+ */
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
+
+/**
+ * aes_encrypt_deinit - Deinitialize AES encryption
+ * @ctx: Context pointer from aes_encrypt_init()
+ */
+void aes_encrypt_deinit(void *ctx);
+
+/**
+ * aes_decrypt_init - Initialize AES for decryption
+ * @key: Decryption key
+ * @len: Key length in bytes (usually 16, i.e., 128 bits)
+ * Returns: Pointer to context data or %NULL on failure
+ */
+void * aes_decrypt_init(const u8 *key, size_t len);
+
+/**
+ * aes_decrypt - Decrypt one AES block
+ * @ctx: Context pointer from aes_encrypt_init()
+ * @crypt: Encrypted data (16 bytes)
+ * @plain: Buffer for the decrypted data (16 bytes)
+ */
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
+
+/**
+ * aes_decrypt_deinit - Deinitialize AES decryption
+ * @ctx: Context pointer from aes_encrypt_init()
+ */
+void aes_decrypt_deinit(void *ctx);
+
+
+enum crypto_hash_alg {
+	CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,
+	CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1,
+	CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256
+};
+
+struct crypto_hash;
+
+/**
+ * crypto_hash_init - Initialize hash/HMAC function
+ * @alg: Hash algorithm
+ * @key: Key for keyed hash (e.g., HMAC) or %NULL if not needed
+ * @key_len: Length of the key in bytes
+ * Returns: Pointer to hash context to use with other hash functions or %NULL
+ * on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+				      size_t key_len);
+
+/**
+ * crypto_hash_update - Add data to hash calculation
+ * @ctx: Context pointer from crypto_hash_init()
+ * @data: Data buffer to add
+ * @len: Length of the buffer
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len);
+
+/**
+ * crypto_hash_finish - Complete hash calculation
+ * @ctx: Context pointer from crypto_hash_init()
+ * @hash: Buffer for hash value or %NULL if caller is just freeing the hash
+ * context
+ * @len: Pointer to length of the buffer or %NULL if caller is just freeing the
+ * hash context; on return, this is set to the actual length of the hash value
+ * Returns: 0 on success, -1 if buffer is too small (len set to needed length),
+ * or -2 on other failures (including failed crypto_hash_update() operations)
+ *
+ * This function calculates the hash value and frees the context buffer that
+ * was used for hash calculation.
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *hash, size_t *len);
+
+
+enum crypto_cipher_alg {
+	CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES,
+	CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4
+};
+
+struct crypto_cipher;
+
+/**
+ * crypto_cipher_init - Initialize block/stream cipher function
+ * @alg: Cipher algorithm
+ * @iv: Initialization vector for block ciphers or %NULL for stream ciphers
+ * @key: Cipher key
+ * @key_len: Length of key in bytes
+ * Returns: Pointer to cipher context to use with other cipher functions or
+ * %NULL on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len);
+
+/**
+ * crypto_cipher_encrypt - Cipher encrypt
+ * @ctx: Context pointer from crypto_cipher_init()
+ * @plain: Plaintext to cipher
+ * @crypt: Resulting ciphertext
+ * @len: Length of the plaintext
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int __must_check crypto_cipher_encrypt(struct crypto_cipher *ctx,
+				       const u8 *plain, u8 *crypt, size_t len);
+
+/**
+ * crypto_cipher_decrypt - Cipher decrypt
+ * @ctx: Context pointer from crypto_cipher_init()
+ * @crypt: Ciphertext to decrypt
+ * @plain: Resulting plaintext
+ * @len: Length of the cipher text
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int __must_check crypto_cipher_decrypt(struct crypto_cipher *ctx,
+				       const u8 *crypt, u8 *plain, size_t len);
+
+/**
+ * crypto_cipher_decrypt - Free cipher context
+ * @ctx: Context pointer from crypto_cipher_init()
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_cipher_deinit(struct crypto_cipher *ctx);
+
+
+struct crypto_public_key;
+struct crypto_private_key;
+
+/**
+ * crypto_public_key_import - Import an RSA public key
+ * @key: Key buffer (DER encoded RSA public key)
+ * @len: Key buffer length in bytes
+ * Returns: Pointer to the public key or %NULL on failure
+ *
+ * This function can just return %NULL if the crypto library supports X.509
+ * parsing. In that case, crypto_public_key_from_cert() is used to import the
+ * public key from a certificate.
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len);
+
+/**
+ * crypto_private_key_import - Import an RSA private key
+ * @key: Key buffer (DER encoded RSA private key)
+ * @len: Key buffer length in bytes
+ * @passwd: Key encryption password or %NULL if key is not encrypted
+ * Returns: Pointer to the private key or %NULL on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_private_key * crypto_private_key_import(const u8 *key,
+						      size_t len,
+						      const char *passwd);
+
+/**
+ * crypto_public_key_from_cert - Import an RSA public key from a certificate
+ * @buf: DER encoded X.509 certificate
+ * @len: Certificate buffer length in bytes
+ * Returns: Pointer to public key or %NULL on failure
+ *
+ * This function can just return %NULL if the crypto library does not support
+ * X.509 parsing. In that case, internal code will be used to parse the
+ * certificate and public key is imported using crypto_public_key_import().
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
+						       size_t len);
+
+/**
+ * crypto_public_key_encrypt_pkcs1_v15 - Public key encryption (PKCS #1 v1.5)
+ * @key: Public key
+ * @in: Plaintext buffer
+ * @inlen: Length of plaintext buffer in bytes
+ * @out: Output buffer for encrypted data
+ * @outlen: Length of output buffer in bytes; set to used length on success
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int __must_check crypto_public_key_encrypt_pkcs1_v15(
+	struct crypto_public_key *key, const u8 *in, size_t inlen,
+	u8 *out, size_t *outlen);
+
+/**
+ * crypto_private_key_decrypt_pkcs1_v15 - Private key decryption (PKCS #1 v1.5)
+ * @key: Private key
+ * @in: Encrypted buffer
+ * @inlen: Length of encrypted buffer in bytes
+ * @out: Output buffer for encrypted data
+ * @outlen: Length of output buffer in bytes; set to used length on success
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int __must_check crypto_private_key_decrypt_pkcs1_v15(
+	struct crypto_private_key *key, const u8 *in, size_t inlen,
+	u8 *out, size_t *outlen);
+
+/**
+ * crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1)
+ * @key: Private key from crypto_private_key_import()
+ * @in: Plaintext buffer
+ * @inlen: Length of plaintext buffer in bytes
+ * @out: Output buffer for encrypted (signed) data
+ * @outlen: Length of output buffer in bytes; set to used length on success
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int __must_check crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
+					       const u8 *in, size_t inlen,
+					       u8 *out, size_t *outlen);
+
+/**
+ * crypto_public_key_free - Free public key
+ * @key: Public key
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_public_key_free(struct crypto_public_key *key);
+
+/**
+ * crypto_private_key_free - Free private key
+ * @key: Private key from crypto_private_key_import()
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_private_key_free(struct crypto_private_key *key);
+
+/**
+ * crypto_public_key_decrypt_pkcs1 - Decrypt PKCS #1 signature
+ * @key: Public key
+ * @crypt: Encrypted signature data (using the private key)
+ * @crypt_len: Encrypted signature data length
+ * @plain: Buffer for plaintext (at least crypt_len bytes)
+ * @plain_len: Plaintext length (max buffer size on input, real len on output);
+ * Returns: 0 on success, -1 on failure
+ */
+int __must_check crypto_public_key_decrypt_pkcs1(
+	struct crypto_public_key *key, const u8 *crypt, size_t crypt_len,
+	u8 *plain, size_t *plain_len);
+
+/**
+ * crypto_global_init - Initialize crypto wrapper
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int __must_check crypto_global_init(void);
+
+/**
+ * crypto_global_deinit - Deinitialize crypto wrapper
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_global_deinit(void);
+
+/**
+ * crypto_mod_exp - Modular exponentiation of large integers
+ * @base: Base integer (big endian byte array)
+ * @base_len: Length of base integer in bytes
+ * @power: Power integer (big endian byte array)
+ * @power_len: Length of power integer in bytes
+ * @modulus: Modulus integer (big endian byte array)
+ * @modulus_len: Length of modulus integer in bytes
+ * @result: Buffer for the result
+ * @result_len: Result length (max buffer size on input, real len on output)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function calculates result = base ^ power mod modulus. modules_len is
+ * used as the maximum size of modulus buffer. It is set to the used size on
+ * success.
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int __must_check crypto_mod_exp(const u8 *base, size_t base_len,
+				const u8 *power, size_t power_len,
+				const u8 *modulus, size_t modulus_len,
+				u8 *result, size_t *result_len);
+
+/**
+ * rc4_skip - XOR RC4 stream to given data with skip-stream-start
+ * @key: RC4 key
+ * @keylen: RC4 key length
+ * @skip: number of bytes to skip from the beginning of the RC4 stream
+ * @data: data to be XOR'ed with RC4 stream
+ * @data_len: buf length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Generate RC4 pseudo random stream for the given key, skip beginning of the
+ * stream, and XOR the end result with the data buffer to perform RC4
+ * encryption/decryption.
+ */
+int rc4_skip(const u8 *key, size_t keylen, size_t skip,
+	     u8 *data, size_t data_len);
+
+/**
+ * crypto_get_random - Generate cryptographically strong pseudy-random bytes
+ * @buf: Buffer for data
+ * @len: Number of bytes to generate
+ * Returns: 0 on success, -1 on failure
+ *
+ * If the PRNG does not have enough entropy to ensure unpredictable byte
+ * sequence, this functions must return -1.
+ */
+int crypto_get_random(void *buf, size_t len);
+
+#endif /* CRYPTO_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/crypto_openssl.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,820 @@
+/*
+ * WPA Supplicant / wrapper functions for libcrypto
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <openssl/opensslv.h>
+#include <openssl/err.h>
+#include <openssl/des.h>
+#include <openssl/aes.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/dh.h>
+#include <openssl/hmac.h>
+#include <openssl/rand.h>
+#ifdef CONFIG_OPENSSL_CMAC
+#include <openssl/cmac.h>
+#endif /* CONFIG_OPENSSL_CMAC */
+
+#include "common.h"
+#include "wpabuf.h"
+#include "dh_group5.h"
+#include "crypto.h"
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000
+#define DES_key_schedule des_key_schedule
+#define DES_cblock des_cblock
+#define DES_set_key(key, schedule) des_set_key((key), *(schedule))
+#define DES_ecb_encrypt(input, output, ks, enc) \
+	des_ecb_encrypt((input), (output), *(ks), (enc))
+#endif /* openssl < 0.9.7 */
+
+static BIGNUM * get_group5_prime(void)
+{
+#if OPENSSL_VERSION_NUMBER < 0x00908000
+	static const unsigned char RFC3526_PRIME_1536[] = {
+		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
+		0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
+		0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
+		0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+		0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
+		0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
+		0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
+		0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+		0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
+		0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
+		0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
+		0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+		0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
+		0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
+		0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
+		0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+	};
+        return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL);
+#else /* openssl < 0.9.8 */
+	return get_rfc3526_prime_1536(NULL);
+#endif /* openssl < 0.9.8 */
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x00908000
+#ifndef OPENSSL_NO_SHA256
+#ifndef OPENSSL_FIPS
+#define NO_SHA256_WRAPPER
+#endif
+#endif
+
+#endif /* openssl < 0.9.8 */
+
+#ifdef OPENSSL_NO_SHA256
+#define NO_SHA256_WRAPPER
+#endif
+
+static int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
+				 const u8 *addr[], const size_t *len, u8 *mac)
+{
+	EVP_MD_CTX ctx;
+	size_t i;
+	unsigned int mac_len;
+
+	EVP_MD_CTX_init(&ctx);
+	if (!EVP_DigestInit_ex(&ctx, type, NULL)) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+	for (i = 0; i < num_elem; i++) {
+		if (!EVP_DigestUpdate(&ctx, addr[i], len[i])) {
+			wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestUpdate "
+				   "failed: %s",
+				   ERR_error_string(ERR_get_error(), NULL));
+			return -1;
+		}
+	}
+	if (!EVP_DigestFinal(&ctx, mac, &mac_len)) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return openssl_digest_vector(EVP_md4(), num_elem, addr, len, mac);
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+	u8 pkey[8], next, tmp;
+	int i;
+	DES_key_schedule ks;
+
+	/* Add parity bits to the key */
+	next = 0;
+	for (i = 0; i < 7; i++) {
+		tmp = key[i];
+		pkey[i] = (tmp >> i) | next | 1;
+		next = tmp << (7 - i);
+	}
+	pkey[i] = next | 1;
+
+	DES_set_key(&pkey, &ks);
+	DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks,
+			DES_ENCRYPT);
+}
+
+
+int rc4_skip(const u8 *key, size_t keylen, size_t skip,
+	     u8 *data, size_t data_len)
+{
+#ifdef OPENSSL_NO_RC4
+	return -1;
+#else /* OPENSSL_NO_RC4 */
+	EVP_CIPHER_CTX ctx;
+	int outl;
+	int res = -1;
+	unsigned char skip_buf[16];
+
+	EVP_CIPHER_CTX_init(&ctx);
+	if (!EVP_CIPHER_CTX_set_padding(&ctx, 0) ||
+	    !EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, NULL, NULL, 1) ||
+	    !EVP_CIPHER_CTX_set_key_length(&ctx, keylen) ||
+	    !EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1))
+		goto out;
+
+	while (skip >= sizeof(skip_buf)) {
+		size_t len = skip;
+		if (len > sizeof(skip_buf))
+			len = sizeof(skip_buf);
+		if (!EVP_CipherUpdate(&ctx, skip_buf, &outl, skip_buf, len))
+			goto out;
+		skip -= len;
+	}
+
+	if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len))
+		res = 0;
+
+out:
+	EVP_CIPHER_CTX_cleanup(&ctx);
+	return res;
+#endif /* OPENSSL_NO_RC4 */
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return openssl_digest_vector(EVP_md5(), num_elem, addr, len, mac);
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return openssl_digest_vector(EVP_sha1(), num_elem, addr, len, mac);
+}
+
+
+#ifndef NO_SHA256_WRAPPER
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		  u8 *mac)
+{
+	return openssl_digest_vector(EVP_sha256(), num_elem, addr, len, mac);
+}
+#endif /* NO_SHA256_WRAPPER */
+
+
+static const EVP_CIPHER * aes_get_evp_cipher(size_t keylen)
+{
+	switch (keylen) {
+	case 16:
+		return EVP_aes_128_ecb();
+	case 24:
+		return EVP_aes_192_ecb();
+	case 32:
+		return EVP_aes_256_ecb();
+	}
+
+	return NULL;
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+	EVP_CIPHER_CTX *ctx;
+	const EVP_CIPHER *type;
+
+	type = aes_get_evp_cipher(len);
+	if (type == NULL)
+		return NULL;
+
+	ctx = os_malloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+	EVP_CIPHER_CTX_init(ctx);
+	if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
+		os_free(ctx);
+		return NULL;
+	}
+	EVP_CIPHER_CTX_set_padding(ctx, 0);
+	return ctx;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+	EVP_CIPHER_CTX *c = ctx;
+	int clen = 16;
+	if (EVP_EncryptUpdate(c, crypt, &clen, plain, 16) != 1) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_EncryptUpdate failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+	}
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+	EVP_CIPHER_CTX *c = ctx;
+	u8 buf[16];
+	int len = sizeof(buf);
+	if (EVP_EncryptFinal_ex(c, buf, &len) != 1) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_EncryptFinal_ex failed: "
+			   "%s", ERR_error_string(ERR_get_error(), NULL));
+	}
+	if (len != 0) {
+		wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
+			   "in AES encrypt", len);
+	}
+	EVP_CIPHER_CTX_cleanup(c);
+	os_free(c);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+	EVP_CIPHER_CTX *ctx;
+	const EVP_CIPHER *type;
+
+	type = aes_get_evp_cipher(len);
+	if (type == NULL)
+		return NULL;
+
+	ctx = os_malloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+	EVP_CIPHER_CTX_init(ctx);
+	if (EVP_DecryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
+		os_free(ctx);
+		return NULL;
+	}
+	EVP_CIPHER_CTX_set_padding(ctx, 0);
+	return ctx;
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+	EVP_CIPHER_CTX *c = ctx;
+	int plen = 16;
+	if (EVP_DecryptUpdate(c, plain, &plen, crypt, 16) != 1) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DecryptUpdate failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+	}
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+	EVP_CIPHER_CTX *c = ctx;
+	u8 buf[16];
+	int len = sizeof(buf);
+	if (EVP_DecryptFinal_ex(c, buf, &len) != 1) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DecryptFinal_ex failed: "
+			   "%s", ERR_error_string(ERR_get_error(), NULL));
+	}
+	if (len != 0) {
+		wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
+			   "in AES decrypt", len);
+	}
+	EVP_CIPHER_CTX_cleanup(c);
+	os_free(ctx);
+}
+
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+		   const u8 *power, size_t power_len,
+		   const u8 *modulus, size_t modulus_len,
+		   u8 *result, size_t *result_len)
+{
+	BIGNUM *bn_base, *bn_exp, *bn_modulus, *bn_result;
+	int ret = -1;
+	BN_CTX *ctx;
+
+	ctx = BN_CTX_new();
+	if (ctx == NULL)
+		return -1;
+
+	bn_base = BN_bin2bn(base, base_len, NULL);
+	bn_exp = BN_bin2bn(power, power_len, NULL);
+	bn_modulus = BN_bin2bn(modulus, modulus_len, NULL);
+	bn_result = BN_new();
+
+	if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL ||
+	    bn_result == NULL)
+		goto error;
+
+	if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1)
+		goto error;
+
+	*result_len = BN_bn2bin(bn_result, result);
+	ret = 0;
+
+error:
+	BN_free(bn_base);
+	BN_free(bn_exp);
+	BN_free(bn_modulus);
+	BN_free(bn_result);
+	BN_CTX_free(ctx);
+	return ret;
+}
+
+
+struct crypto_cipher {
+	EVP_CIPHER_CTX enc;
+	EVP_CIPHER_CTX dec;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len)
+{
+	struct crypto_cipher *ctx;
+	const EVP_CIPHER *cipher;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	switch (alg) {
+#ifndef OPENSSL_NO_RC4
+	case CRYPTO_CIPHER_ALG_RC4:
+		cipher = EVP_rc4();
+		break;
+#endif /* OPENSSL_NO_RC4 */
+#ifndef OPENSSL_NO_AES
+	case CRYPTO_CIPHER_ALG_AES:
+		switch (key_len) {
+		case 16:
+			cipher = EVP_aes_128_cbc();
+			break;
+		case 24:
+			cipher = EVP_aes_192_cbc();
+			break;
+		case 32:
+			cipher = EVP_aes_256_cbc();
+			break;
+		default:
+			os_free(ctx);
+			return NULL;
+		}
+		break;
+#endif /* OPENSSL_NO_AES */
+#ifndef OPENSSL_NO_DES
+	case CRYPTO_CIPHER_ALG_3DES:
+		cipher = EVP_des_ede3_cbc();
+		break;
+	case CRYPTO_CIPHER_ALG_DES:
+		cipher = EVP_des_cbc();
+		break;
+#endif /* OPENSSL_NO_DES */
+#ifndef OPENSSL_NO_RC2
+	case CRYPTO_CIPHER_ALG_RC2:
+		cipher = EVP_rc2_ecb();
+		break;
+#endif /* OPENSSL_NO_RC2 */
+	default:
+		os_free(ctx);
+		return NULL;
+	}
+
+	EVP_CIPHER_CTX_init(&ctx->enc);
+	EVP_CIPHER_CTX_set_padding(&ctx->enc, 0);
+	if (!EVP_EncryptInit_ex(&ctx->enc, cipher, NULL, NULL, NULL) ||
+	    !EVP_CIPHER_CTX_set_key_length(&ctx->enc, key_len) ||
+	    !EVP_EncryptInit_ex(&ctx->enc, NULL, NULL, key, iv)) {
+		EVP_CIPHER_CTX_cleanup(&ctx->enc);
+		os_free(ctx);
+		return NULL;
+	}
+
+	EVP_CIPHER_CTX_init(&ctx->dec);
+	EVP_CIPHER_CTX_set_padding(&ctx->dec, 0);
+	if (!EVP_DecryptInit_ex(&ctx->dec, cipher, NULL, NULL, NULL) ||
+	    !EVP_CIPHER_CTX_set_key_length(&ctx->dec, key_len) ||
+	    !EVP_DecryptInit_ex(&ctx->dec, NULL, NULL, key, iv)) {
+		EVP_CIPHER_CTX_cleanup(&ctx->enc);
+		EVP_CIPHER_CTX_cleanup(&ctx->dec);
+		os_free(ctx);
+		return NULL;
+	}
+
+	return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+			  u8 *crypt, size_t len)
+{
+	int outl;
+	if (!EVP_EncryptUpdate(&ctx->enc, crypt, &outl, plain, len))
+		return -1;
+	return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+			  u8 *plain, size_t len)
+{
+	int outl;
+	outl = len;
+	if (!EVP_DecryptUpdate(&ctx->dec, plain, &outl, crypt, len))
+		return -1;
+	return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+	EVP_CIPHER_CTX_cleanup(&ctx->enc);
+	EVP_CIPHER_CTX_cleanup(&ctx->dec);
+	os_free(ctx);
+}
+
+
+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
+{
+	DH *dh;
+	struct wpabuf *pubkey = NULL, *privkey = NULL;
+	size_t publen, privlen;
+
+	*priv = NULL;
+	*publ = NULL;
+
+	dh = DH_new();
+	if (dh == NULL)
+		return NULL;
+
+	dh->g = BN_new();
+	if (dh->g == NULL || BN_set_word(dh->g, 2) != 1)
+		goto err;
+
+	dh->p = get_group5_prime();
+	if (dh->p == NULL)
+		goto err;
+
+	if (DH_generate_key(dh) != 1)
+		goto err;
+
+	publen = BN_num_bytes(dh->pub_key);
+	pubkey = wpabuf_alloc(publen);
+	if (pubkey == NULL)
+		goto err;
+	privlen = BN_num_bytes(dh->priv_key);
+	privkey = wpabuf_alloc(privlen);
+	if (privkey == NULL)
+		goto err;
+
+	BN_bn2bin(dh->pub_key, wpabuf_put(pubkey, publen));
+	BN_bn2bin(dh->priv_key, wpabuf_put(privkey, privlen));
+
+	*priv = privkey;
+	*publ = pubkey;
+	return dh;
+
+err:
+	wpabuf_free(pubkey);
+	wpabuf_free(privkey);
+	DH_free(dh);
+	return NULL;
+}
+
+
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
+{
+	DH *dh;
+
+	dh = DH_new();
+	if (dh == NULL)
+		return NULL;
+
+	dh->g = BN_new();
+	if (dh->g == NULL || BN_set_word(dh->g, 2) != 1)
+		goto err;
+
+	dh->p = get_group5_prime();
+	if (dh->p == NULL)
+		goto err;
+
+	dh->priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL);
+	if (dh->priv_key == NULL)
+		goto err;
+
+	dh->pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL);
+	if (dh->pub_key == NULL)
+		goto err;
+
+	if (DH_generate_key(dh) != 1)
+		goto err;
+
+	return dh;
+
+err:
+	DH_free(dh);
+	return NULL;
+}
+
+
+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
+				  const struct wpabuf *own_private)
+{
+	BIGNUM *pub_key;
+	struct wpabuf *res = NULL;
+	size_t rlen;
+	DH *dh = ctx;
+	int keylen;
+
+	if (ctx == NULL)
+		return NULL;
+
+	pub_key = BN_bin2bn(wpabuf_head(peer_public), wpabuf_len(peer_public),
+			    NULL);
+	if (pub_key == NULL)
+		return NULL;
+
+	rlen = DH_size(dh);
+	res = wpabuf_alloc(rlen);
+	if (res == NULL)
+		goto err;
+
+	keylen = DH_compute_key(wpabuf_mhead(res), pub_key, dh);
+	if (keylen < 0)
+		goto err;
+	wpabuf_put(res, keylen);
+	BN_free(pub_key);
+
+	return res;
+
+err:
+	BN_free(pub_key);
+	wpabuf_free(res);
+	return NULL;
+}
+
+
+void dh5_free(void *ctx)
+{
+	DH *dh;
+	if (ctx == NULL)
+		return;
+	dh = ctx;
+	DH_free(dh);
+}
+
+
+struct crypto_hash {
+	HMAC_CTX ctx;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+				      size_t key_len)
+{
+	struct crypto_hash *ctx;
+	const EVP_MD *md;
+
+	switch (alg) {
+#ifndef OPENSSL_NO_MD5
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		md = EVP_md5();
+		break;
+#endif /* OPENSSL_NO_MD5 */
+#ifndef OPENSSL_NO_SHA
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		md = EVP_sha1();
+		break;
+#endif /* OPENSSL_NO_SHA */
+#ifndef OPENSSL_NO_SHA256
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		md = EVP_sha256();
+		break;
+#endif /* CONFIG_SHA256 */
+#endif /* OPENSSL_NO_SHA256 */
+	default:
+		return NULL;
+	}
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+	HMAC_CTX_init(&ctx->ctx);
+
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+	HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL);
+#else /* openssl < 0.9.9 */
+	if (HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL) != 1) {
+		os_free(ctx);
+		return NULL;
+	}
+#endif /* openssl < 0.9.9 */
+
+	return ctx;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+	if (ctx == NULL)
+		return;
+	HMAC_Update(&ctx->ctx, data, len);
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+	unsigned int mdlen;
+	int res;
+
+	if (ctx == NULL)
+		return -2;
+
+	if (mac == NULL || len == NULL) {
+		os_free(ctx);
+		return 0;
+	}
+
+	mdlen = *len;
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+	HMAC_Final(&ctx->ctx, mac, &mdlen);
+	res = 1;
+#else /* openssl < 0.9.9 */
+	res = HMAC_Final(&ctx->ctx, mac, &mdlen);
+#endif /* openssl < 0.9.9 */
+	HMAC_CTX_cleanup(&ctx->ctx);
+	os_free(ctx);
+
+	if (res == 1) {
+		*len = mdlen;
+		return 0;
+	}
+
+	return -1;
+}
+
+
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+		int iterations, u8 *buf, size_t buflen)
+{
+#if OPENSSL_VERSION_NUMBER < 0x00908000
+	if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase),
+				   (unsigned char *) ssid,
+				   ssid_len, 4096, buflen, buf) != 1)
+		return -1;
+#else /* openssl < 0.9.8 */
+	if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
+				   ssid_len, 4096, buflen, buf) != 1)
+		return -1;
+#endif /* openssl < 0.9.8 */
+	return 0;
+}
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac)
+{
+	HMAC_CTX ctx;
+	size_t i;
+	unsigned int mdlen;
+	int res;
+
+	HMAC_CTX_init(&ctx);
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+	HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL);
+#else /* openssl < 0.9.9 */
+	if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL) != 1)
+		return -1;
+#endif /* openssl < 0.9.9 */
+
+	for (i = 0; i < num_elem; i++)
+		HMAC_Update(&ctx, addr[i], len[i]);
+
+	mdlen = 20;
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+	HMAC_Final(&ctx, mac, &mdlen);
+	res = 1;
+#else /* openssl < 0.9.9 */
+	res = HMAC_Final(&ctx, mac, &mdlen);
+#endif /* openssl < 0.9.9 */
+	HMAC_CTX_cleanup(&ctx);
+
+	return res == 1 ? 0 : -1;
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	       u8 *mac)
+{
+	return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	HMAC_CTX ctx;
+	size_t i;
+	unsigned int mdlen;
+	int res;
+
+	HMAC_CTX_init(&ctx);
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+	HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL);
+#else /* openssl < 0.9.9 */
+	if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL) != 1)
+		return -1;
+#endif /* openssl < 0.9.9 */
+
+	for (i = 0; i < num_elem; i++)
+		HMAC_Update(&ctx, addr[i], len[i]);
+
+	mdlen = 32;
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+	HMAC_Final(&ctx, mac, &mdlen);
+	res = 1;
+#else /* openssl < 0.9.9 */
+	res = HMAC_Final(&ctx, mac, &mdlen);
+#endif /* openssl < 0.9.9 */
+	HMAC_CTX_cleanup(&ctx);
+
+	return res == 1 ? 0 : -1;
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+int crypto_get_random(void *buf, size_t len)
+{
+	if (RAND_bytes(buf, len) != 1)
+		return -1;
+	return 0;
+}
+
+
+#ifdef CONFIG_OPENSSL_CMAC
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+			 const u8 *addr[], const size_t *len, u8 *mac)
+{
+	CMAC_CTX *ctx;
+	int ret = -1;
+	size_t outlen, i;
+
+	ctx = CMAC_CTX_new();
+	if (ctx == NULL)
+		return -1;
+
+	if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
+		goto fail;
+	for (i = 0; i < num_elem; i++) {
+		if (!CMAC_Update(ctx, addr[i], len[i]))
+			goto fail;
+	}
+	if (!CMAC_Final(ctx, mac, &outlen) || outlen != 16)
+		goto fail;
+
+	ret = 0;
+fail:
+	CMAC_CTX_free(ctx);
+	return ret;
+}
+
+
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+	return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
+}
+#endif /* CONFIG_OPENSSL_CMAC */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/dh_group5.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,18 @@
+/*
+ * Diffie-Hellman group 5 operations
+ * Copyright (c) 2009, 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DH_GROUP5_H
+#define DH_GROUP5_H
+
+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ);
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ);
+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
+				  const struct wpabuf *own_private);
+void dh5_free(void *ctx);
+
+#endif /* DH_GROUP5_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/md5.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,105 @@
+/*
+ * MD5 hash implementation and interface functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "md5.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_md5_vector - HMAC-MD5 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash (16 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+		    const u8 *addr[], const size_t *len, u8 *mac)
+{
+	u8 k_pad[64]; /* padding - key XORd with ipad/opad */
+	u8 tk[16];
+	const u8 *_addr[6];
+	size_t i, _len[6];
+
+	if (num_elem > 5) {
+		/*
+		 * Fixed limit on the number of fragments to avoid having to
+		 * allocate memory (which could fail).
+		 */
+		return -1;
+	}
+
+        /* if key is longer than 64 bytes reset it to key = MD5(key) */
+        if (key_len > 64) {
+		if (md5_vector(1, &key, &key_len, tk))
+			return -1;
+		key = tk;
+		key_len = 16;
+        }
+
+	/* the HMAC_MD5 transform looks like:
+	 *
+	 * MD5(K XOR opad, MD5(K XOR ipad, text))
+	 *
+	 * where K is an n byte key
+	 * ipad is the byte 0x36 repeated 64 times
+	 * opad is the byte 0x5c repeated 64 times
+	 * and text is the data being protected */
+
+	/* start out by storing key in ipad */
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+
+	/* XOR key with ipad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x36;
+
+	/* perform inner MD5 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	for (i = 0; i < num_elem; i++) {
+		_addr[i + 1] = addr[i];
+		_len[i + 1] = len[i];
+	}
+	if (md5_vector(1 + num_elem, _addr, _len, mac))
+		return -1;
+
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+	/* XOR key with opad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x5c;
+
+	/* perform outer MD5 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	_addr[1] = mac;
+	_len[1] = MD5_MAC_LEN;
+	return md5_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_md5 - HMAC-MD5 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (16 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	      u8 *mac)
+{
+	return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/md5.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,19 @@
+/*
+ * MD5 hash implementation and interface functions
+ * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MD5_H
+#define MD5_H
+
+#define MD5_MAC_LEN 16
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+		    const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	     u8 *mac);
+
+#endif /* MD5_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/ms_funcs.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,526 @@
+/*
+ * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+#include "ms_funcs.h"
+#include "crypto.h"
+
+/**
+ * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding
+ * @utf8_string: UTF-8 string (IN)
+ * @utf8_string_len: Length of utf8_string (IN)
+ * @ucs2_buffer: UCS-2 buffer (OUT)
+ * @ucs2_buffer_size: Length of UCS-2 buffer (IN)
+ * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string
+ * Returns: 0 on success, -1 on failure
+ */
+static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
+                        u8 *ucs2_buffer, size_t ucs2_buffer_size,
+                        size_t *ucs2_string_size)
+{
+	size_t i, j;
+
+	for (i = 0, j = 0; i < utf8_string_len; i++) {
+		u8 c = utf8_string[i];
+		if (j >= ucs2_buffer_size) {
+			/* input too long */
+			return -1;
+		}
+		if (c <= 0x7F) {
+			WPA_PUT_LE16(ucs2_buffer + j, c);
+			j += 2;
+		} else if (i == utf8_string_len - 1 ||
+			   j >= ucs2_buffer_size - 1) {
+			/* incomplete surrogate */
+			return -1;
+		} else {
+			u8 c2 = utf8_string[++i];
+			if ((c & 0xE0) == 0xC0) {
+				/* two-byte encoding */
+				WPA_PUT_LE16(ucs2_buffer + j,
+					     ((c & 0x1F) << 6) | (c2 & 0x3F));
+				j += 2;
+			} else if (i == utf8_string_len ||
+				   j >= ucs2_buffer_size - 1) {
+				/* incomplete surrogate */
+				return -1;
+			} else {
+				/* three-byte encoding */
+				u8 c3 = utf8_string[++i];
+				WPA_PUT_LE16(ucs2_buffer + j,
+					     ((c & 0xF) << 12) |
+					     ((c2 & 0x3F) << 6) | (c3 & 0x3F));
+			}
+		}
+	}
+
+	if (ucs2_string_size)
+		*ucs2_string_size = j / 2;
+	return 0;
+}
+
+
+/**
+ * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @challenge: 8-octet Challenge (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
+			  const u8 *username, size_t username_len,
+			  u8 *challenge)
+{
+	u8 hash[SHA1_MAC_LEN];
+	const unsigned char *addr[3];
+	size_t len[3];
+
+	addr[0] = peer_challenge;
+	len[0] = 16;
+	addr[1] = auth_challenge;
+	len[1] = 16;
+	addr[2] = username;
+	len[2] = username_len;
+
+	if (sha1_vector(3, addr, len, hash))
+		return -1;
+	os_memcpy(challenge, hash, 8);
+	return 0;
+}
+
+
+/**
+ * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
+ * @password_len: Length of password
+ * @password_hash: 16-octet PasswordHash (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int nt_password_hash(const u8 *password, size_t password_len,
+		      u8 *password_hash)
+{
+	u8 buf[512], *pos;
+	size_t len, max_len;
+
+	max_len = sizeof(buf);
+	if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
+		return -1;
+
+	len *= 2;
+	pos = buf;
+	return md4_vector(1, (const u8 **) &pos, &len, password_hash);
+}
+
+
+/**
+ * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @password_hash_hash: 16-octet PasswordHashHash (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
+{
+	size_t len = 16;
+	return md4_vector(1, &password_hash, &len, password_hash_hash);
+}
+
+
+/**
+ * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
+ * @challenge: 8-octet Challenge (IN)
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @response: 24-octet Response (OUT)
+ */
+void challenge_response(const u8 *challenge, const u8 *password_hash,
+			u8 *response)
+{
+	u8 zpwd[7];
+	des_encrypt(challenge, password_hash, response);
+	des_encrypt(challenge, password_hash + 7, response + 8);
+	zpwd[0] = password_hash[14];
+	zpwd[1] = password_hash[15];
+	os_memset(zpwd + 2, 0, 5);
+	des_encrypt(challenge, zpwd, response + 16);
+}
+
+
+/**
+ * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
+ * @password_len: Length of password
+ * @response: 24-octet Response (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
+			 const u8 *username, size_t username_len,
+			 const u8 *password, size_t password_len,
+			 u8 *response)
+{
+	u8 challenge[8];
+	u8 password_hash[16];
+
+	if (challenge_hash(peer_challenge, auth_challenge, username,
+			   username_len, challenge))
+		return -1;
+	if (nt_password_hash(password, password_len, password_hash))
+		return -1;
+	challenge_response(challenge, password_hash, response);
+	return 0;
+}
+
+
+/**
+ * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @response: 24-octet Response (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int generate_nt_response_pwhash(const u8 *auth_challenge,
+				const u8 *peer_challenge,
+				const u8 *username, size_t username_len,
+				const u8 *password_hash,
+				u8 *response)
+{
+	u8 challenge[8];
+
+	if (challenge_hash(peer_challenge, auth_challenge,
+			   username, username_len,
+			   challenge))
+		return -1;
+	challenge_response(challenge, password_hash, response);
+	return 0;
+}
+
+
+/**
+ * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @nt_response: 24-octet NT-Response (IN)
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
+ * encoded as a 42-octet ASCII string (S=hexdump_of_response)
+ * Returns: 0 on success, -1 on failure
+ */
+int generate_authenticator_response_pwhash(
+	const u8 *password_hash,
+	const u8 *peer_challenge, const u8 *auth_challenge,
+	const u8 *username, size_t username_len,
+	const u8 *nt_response, u8 *response)
+{
+	static const u8 magic1[39] = {
+		0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
+		0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
+		0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
+		0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
+	};
+	static const u8 magic2[41] = {
+		0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
+		0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
+		0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
+		0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
+		0x6E
+	};
+
+	u8 password_hash_hash[16], challenge[8];
+	const unsigned char *addr1[3];
+	const size_t len1[3] = { 16, 24, sizeof(magic1) };
+	const unsigned char *addr2[3];
+	const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
+
+	addr1[0] = password_hash_hash;
+	addr1[1] = nt_response;
+	addr1[2] = magic1;
+
+	addr2[0] = response;
+	addr2[1] = challenge;
+	addr2[2] = magic2;
+
+	if (hash_nt_password_hash(password_hash, password_hash_hash))
+		return -1;
+	if (sha1_vector(3, addr1, len1, response))
+		return -1;
+
+	if (challenge_hash(peer_challenge, auth_challenge, username,
+			   username_len, challenge))
+		return -1;
+	return sha1_vector(3, addr2, len2, response);
+}
+
+
+/**
+ * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
+ * @password_len: Length of password
+ * @nt_response: 24-octet NT-Response (IN)
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
+ * encoded as a 42-octet ASCII string (S=hexdump_of_response)
+ * Returns: 0 on success, -1 on failure
+ */
+int generate_authenticator_response(const u8 *password, size_t password_len,
+				    const u8 *peer_challenge,
+				    const u8 *auth_challenge,
+				    const u8 *username, size_t username_len,
+				    const u8 *nt_response, u8 *response)
+{
+	u8 password_hash[16];
+	if (nt_password_hash(password, password_len, password_hash))
+		return -1;
+	return generate_authenticator_response_pwhash(
+		password_hash, peer_challenge, auth_challenge,
+		username, username_len, nt_response, response);
+}
+
+
+/**
+ * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
+ * @challenge: 8-octet Challenge (IN)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
+ * @password_len: Length of password
+ * @response: 24-octet Response (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int nt_challenge_response(const u8 *challenge, const u8 *password,
+			  size_t password_len, u8 *response)
+{
+	u8 password_hash[16];
+	if (nt_password_hash(password, password_len, password_hash))
+		return -1;
+	challenge_response(challenge, password_hash, response);
+	return 0;
+}
+
+
+/**
+ * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
+ * @password_hash_hash: 16-octet PasswordHashHash (IN)
+ * @nt_response: 24-octet NTResponse (IN)
+ * @master_key: 16-octet MasterKey (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
+		   u8 *master_key)
+{
+	static const u8 magic1[27] = {
+		0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
+		0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
+		0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
+	};
+	const unsigned char *addr[3];
+	const size_t len[3] = { 16, 24, sizeof(magic1) };
+	u8 hash[SHA1_MAC_LEN];
+
+	addr[0] = password_hash_hash;
+	addr[1] = nt_response;
+	addr[2] = magic1;
+
+	if (sha1_vector(3, addr, len, hash))
+		return -1;
+	os_memcpy(master_key, hash, 16);
+	return 0;
+}
+
+
+/**
+ * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
+ * @master_key: 16-octet MasterKey (IN)
+ * @session_key: 8-to-16 octet SessionKey (OUT)
+ * @session_key_len: SessionKeyLength (Length of session_key) (IN)
+ * @is_send: IsSend (IN, BOOLEAN)
+ * @is_server: IsServer (IN, BOOLEAN)
+ * Returns: 0 on success, -1 on failure
+ */
+int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
+			    size_t session_key_len, int is_send,
+			    int is_server)
+{
+	static const u8 magic2[84] = {
+		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
+		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
+		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+		0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
+		0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
+		0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
+		0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+		0x6b, 0x65, 0x79, 0x2e
+	};
+	static const u8 magic3[84] = {
+		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
+		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
+		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+		0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
+		0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
+		0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
+		0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
+		0x6b, 0x65, 0x79, 0x2e
+	};
+	static const u8 shs_pad1[40] = {
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
+
+	static const u8 shs_pad2[40] = {
+		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
+	};
+	u8 digest[SHA1_MAC_LEN];
+	const unsigned char *addr[4];
+	const size_t len[4] = { 16, 40, 84, 40 };
+
+	addr[0] = master_key;
+	addr[1] = shs_pad1;
+	if (is_send) {
+		addr[2] = is_server ? magic3 : magic2;
+	} else {
+		addr[2] = is_server ? magic2 : magic3;
+	}
+	addr[3] = shs_pad2;
+
+	if (sha1_vector(4, addr, len, digest))
+		return -1;
+
+	if (session_key_len > SHA1_MAC_LEN)
+		session_key_len = SHA1_MAC_LEN;
+	os_memcpy(session_key, digest, session_key_len);
+	return 0;
+}
+
+
+#define PWBLOCK_LEN 516
+
+/**
+ * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
+ * @password_len: Length of password
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @pw_block: 516-byte PwBlock (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int encrypt_pw_block_with_password_hash(
+	const u8 *password, size_t password_len,
+	const u8 *password_hash, u8 *pw_block)
+{
+	size_t ucs2_len, offset;
+	u8 *pos;
+
+	os_memset(pw_block, 0, PWBLOCK_LEN);
+
+	if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0)
+		return -1;
+
+	if (ucs2_len > 256)
+		return -1;
+
+	offset = (256 - ucs2_len) * 2;
+	if (offset != 0) {
+		os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
+		if (os_get_random(pw_block, offset) < 0)
+			return -1;
+	}
+	/*
+	 * PasswordLength is 4 octets, but since the maximum password length is
+	 * 256, only first two (in little endian byte order) can be non-zero.
+	 */
+	pos = &pw_block[2 * 256];
+	WPA_PUT_LE16(pos, password_len * 2);
+	rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
+	return 0;
+}
+
+
+/**
+ * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
+ * @new_password_len: Length of new_password
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
+ * @old_password_len: Length of old_password
+ * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int new_password_encrypted_with_old_nt_password_hash(
+	const u8 *new_password, size_t new_password_len,
+	const u8 *old_password, size_t old_password_len,
+	u8 *encrypted_pw_block)
+{
+	u8 password_hash[16];
+
+	if (nt_password_hash(old_password, old_password_len, password_hash))
+		return -1;
+	if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
+						password_hash,
+						encrypted_pw_block))
+		return -1;
+	return 0;
+}
+
+
+/**
+ * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
+ * @password_hash: 16-octer PasswordHash (IN)
+ * @block: 16-octet Block (IN)
+ * @cypher: 16-octer Cypher (OUT)
+ */
+void nt_password_hash_encrypted_with_block(const u8 *password_hash,
+					   const u8 *block, u8 *cypher)
+{
+	des_encrypt(password_hash, block, cypher);
+	des_encrypt(password_hash + 8, block + 7, cypher + 8);
+}
+
+
+/**
+ * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
+ * @new_password_len: Length of new_password
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
+ * @old_password_len: Length of old_password
+ * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int old_nt_password_hash_encrypted_with_new_nt_password_hash(
+	const u8 *new_password, size_t new_password_len,
+	const u8 *old_password, size_t old_password_len,
+	u8 *encrypted_password_hash)
+{
+	u8 old_password_hash[16], new_password_hash[16];
+
+	if (nt_password_hash(old_password, old_password_len,
+			     old_password_hash) ||
+	    nt_password_hash(new_password, new_password_len,
+			     new_password_hash))
+		return -1;
+	nt_password_hash_encrypted_with_block(old_password_hash,
+					      new_password_hash,
+					      encrypted_password_hash);
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/ms_funcs.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,58 @@
+/*
+ * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MS_FUNCS_H
+#define MS_FUNCS_H
+
+int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
+			 const u8 *username, size_t username_len,
+			 const u8 *password, size_t password_len,
+			 u8 *response);
+int generate_nt_response_pwhash(const u8 *auth_challenge,
+				const u8 *peer_challenge,
+				const u8 *username, size_t username_len,
+				const u8 *password_hash,
+				u8 *response);
+int generate_authenticator_response(const u8 *password, size_t password_len,
+				    const u8 *peer_challenge,
+				    const u8 *auth_challenge,
+				    const u8 *username, size_t username_len,
+				    const u8 *nt_response, u8 *response);
+int generate_authenticator_response_pwhash(
+	const u8 *password_hash,
+	const u8 *peer_challenge, const u8 *auth_challenge,
+	const u8 *username, size_t username_len,
+	const u8 *nt_response, u8 *response);
+int nt_challenge_response(const u8 *challenge, const u8 *password,
+			  size_t password_len, u8 *response);
+
+void challenge_response(const u8 *challenge, const u8 *password_hash,
+			u8 *response);
+int nt_password_hash(const u8 *password, size_t password_len,
+		     u8 *password_hash);
+int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash);
+int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
+		   u8 *master_key);
+int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
+			    size_t session_key_len, int is_send,
+			    int is_server);
+int __must_check encrypt_pw_block_with_password_hash(
+	const u8 *password, size_t password_len,
+	const u8 *password_hash, u8 *pw_block);
+int __must_check new_password_encrypted_with_old_nt_password_hash(
+	const u8 *new_password, size_t new_password_len,
+	const u8 *old_password, size_t old_password_len,
+	u8 *encrypted_pw_block);
+void nt_password_hash_encrypted_with_block(const u8 *password_hash,
+					   const u8 *block, u8 *cypher);
+int old_nt_password_hash_encrypted_with_new_nt_password_hash(
+	const u8 *new_password, size_t new_password_len,
+	const u8 *old_password, size_t old_password_len,
+	u8 *encrypted_password_hash);
+
+#endif /* MS_FUNCS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/random.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,446 @@
+/*
+ * Random number generator
+ * Copyright (c) 2010-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This random number generator is used to provide additional entropy to the
+ * one provided by the operating system (os_get_random()) for session key
+ * generation. The os_get_random() output is expected to be secure and the
+ * implementation here is expected to provide only limited protection against
+ * cases where os_get_random() cannot provide strong randomness. This
+ * implementation shall not be assumed to be secure as the sole source of
+ * randomness. The random_get_bytes() function mixes in randomness from
+ * os_get_random() and as such, calls to os_get_random() can be replaced with
+ * calls to random_get_bytes() without reducing security.
+ *
+ * The design here follows partially the design used in the Linux
+ * drivers/char/random.c, but the implementation here is simpler and not as
+ * strong. This is a compromise to reduce duplicated CPU effort and to avoid
+ * extra code/memory size. As pointed out above, os_get_random() needs to be
+ * guaranteed to be secure for any of the security assumptions to hold.
+ */
+
+#include "utils/includes.h"
+#ifdef __linux__
+#include <fcntl.h>
+#endif /* __linux__ */
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/crypto.h"
+#include "sha1.h"
+#include "random.h"
+
+#define POOL_WORDS 32
+#define POOL_WORDS_MASK (POOL_WORDS - 1)
+#define POOL_TAP1 26
+#define POOL_TAP2 20
+#define POOL_TAP3 14
+#define POOL_TAP4 7
+#define POOL_TAP5 1
+#define EXTRACT_LEN 16
+#define MIN_READY_MARK 2
+
+static u32 pool[POOL_WORDS];
+static unsigned int input_rotate = 0;
+static unsigned int pool_pos = 0;
+static u8 dummy_key[20];
+#ifdef __linux__
+static size_t dummy_key_avail = 0;
+static int random_fd = -1;
+#endif /* __linux__ */
+static unsigned int own_pool_ready = 0;
+#define RANDOM_ENTROPY_SIZE 20
+static char *random_entropy_file = NULL;
+static int random_entropy_file_read = 0;
+
+#define MIN_COLLECT_ENTROPY 1000
+static unsigned int entropy = 0;
+static unsigned int total_collected = 0;
+
+
+static void random_write_entropy(void);
+
+
+static u32 __ROL32(u32 x, u32 y)
+{
+	return (x << (y & 31)) | (x >> (32 - (y & 31)));
+}
+
+
+static void random_mix_pool(const void *buf, size_t len)
+{
+	static const u32 twist[8] = {
+		0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
+		0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278
+	};
+	const u8 *pos = buf;
+	u32 w;
+
+	wpa_hexdump_key(MSG_EXCESSIVE, "random_mix_pool", buf, len);
+
+	while (len--) {
+		w = __ROL32(*pos++, input_rotate & 31);
+		input_rotate += pool_pos ? 7 : 14;
+		pool_pos = (pool_pos - 1) & POOL_WORDS_MASK;
+		w ^= pool[pool_pos];
+		w ^= pool[(pool_pos + POOL_TAP1) & POOL_WORDS_MASK];
+		w ^= pool[(pool_pos + POOL_TAP2) & POOL_WORDS_MASK];
+		w ^= pool[(pool_pos + POOL_TAP3) & POOL_WORDS_MASK];
+		w ^= pool[(pool_pos + POOL_TAP4) & POOL_WORDS_MASK];
+		w ^= pool[(pool_pos + POOL_TAP5) & POOL_WORDS_MASK];
+		pool[pool_pos] = (w >> 3) ^ twist[w & 7];
+	}
+}
+
+
+static void random_extract(u8 *out)
+{
+	unsigned int i;
+	u8 hash[SHA1_MAC_LEN];
+	u32 *hash_ptr;
+	u32 buf[POOL_WORDS / 2];
+
+	/* First, add hash back to pool to make backtracking more difficult. */
+	hmac_sha1(dummy_key, sizeof(dummy_key), (const u8 *) pool,
+		  sizeof(pool), hash);
+	random_mix_pool(hash, sizeof(hash));
+	/* Hash half the pool to extra data */
+	for (i = 0; i < POOL_WORDS / 2; i++)
+		buf[i] = pool[(pool_pos - i) & POOL_WORDS_MASK];
+	hmac_sha1(dummy_key, sizeof(dummy_key), (const u8 *) buf,
+		  sizeof(buf), hash);
+	/*
+	 * Fold the hash to further reduce any potential output pattern.
+	 * Though, compromise this to reduce CPU use for the most common output
+	 * length (32) and return 16 bytes from instead of only half.
+	 */
+	hash_ptr = (u32 *) hash;
+	hash_ptr[0] ^= hash_ptr[4];
+	os_memcpy(out, hash, EXTRACT_LEN);
+}
+
+
+void random_add_randomness(const void *buf, size_t len)
+{
+	struct os_time t;
+	static unsigned int count = 0;
+
+	count++;
+	if (entropy > MIN_COLLECT_ENTROPY && (count & 0x3ff) != 0) {
+		/*
+		 * No need to add more entropy at this point, so save CPU and
+		 * skip the update.
+		 */
+		return;
+	}
+	wpa_printf(MSG_EXCESSIVE, "Add randomness: count=%u entropy=%u",
+		   count, entropy);
+
+	os_get_time(&t);
+	wpa_hexdump_key(MSG_EXCESSIVE, "random pool",
+			(const u8 *) pool, sizeof(pool));
+	random_mix_pool(&t, sizeof(t));
+	random_mix_pool(buf, len);
+	wpa_hexdump_key(MSG_EXCESSIVE, "random pool",
+			(const u8 *) pool, sizeof(pool));
+	entropy++;
+	total_collected++;
+}
+
+
+int random_get_bytes(void *buf, size_t len)
+{
+	int ret;
+	u8 *bytes = buf;
+	size_t left;
+
+	wpa_printf(MSG_MSGDUMP, "Get randomness: len=%u entropy=%u",
+		   (unsigned int) len, entropy);
+
+	/* Start with assumed strong randomness from OS */
+	ret = os_get_random(buf, len);
+	wpa_hexdump_key(MSG_EXCESSIVE, "random from os_get_random",
+			buf, len);
+
+	/* Mix in additional entropy extracted from the internal pool */
+	left = len;
+	while (left) {
+		size_t siz, i;
+		u8 tmp[EXTRACT_LEN];
+		random_extract(tmp);
+		wpa_hexdump_key(MSG_EXCESSIVE, "random from internal pool",
+				tmp, sizeof(tmp));
+		siz = left > EXTRACT_LEN ? EXTRACT_LEN : left;
+		for (i = 0; i < siz; i++)
+			*bytes++ ^= tmp[i];
+		left -= siz;
+	}
+
+#ifdef CONFIG_FIPS
+	/* Mix in additional entropy from the crypto module */
+	left = len;
+	while (left) {
+		size_t siz, i;
+		u8 tmp[EXTRACT_LEN];
+		if (crypto_get_random(tmp, sizeof(tmp)) < 0) {
+			wpa_printf(MSG_ERROR, "random: No entropy available "
+				   "for generating strong random bytes");
+			return -1;
+		}
+		wpa_hexdump_key(MSG_EXCESSIVE, "random from crypto module",
+				tmp, sizeof(tmp));
+		siz = left > EXTRACT_LEN ? EXTRACT_LEN : left;
+		for (i = 0; i < siz; i++)
+			*bytes++ ^= tmp[i];
+		left -= siz;
+	}
+#endif /* CONFIG_FIPS */
+
+	wpa_hexdump_key(MSG_EXCESSIVE, "mixed random", buf, len);
+
+	if (entropy < len)
+		entropy = 0;
+	else
+		entropy -= len;
+
+	return ret;
+}
+
+
+int random_pool_ready(void)
+{
+#ifdef __linux__
+	int fd;
+	ssize_t res;
+
+	/*
+	 * Make sure that there is reasonable entropy available before allowing
+	 * some key derivation operations to proceed.
+	 */
+
+	if (dummy_key_avail == sizeof(dummy_key))
+		return 1; /* Already initialized - good to continue */
+
+	/*
+	 * Try to fetch some more data from the kernel high quality
+	 * /dev/random. There may not be enough data available at this point,
+	 * so use non-blocking read to avoid blocking the application
+	 * completely.
+	 */
+	fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+	if (fd < 0) {
+#ifndef CONFIG_NO_STDOUT_DEBUG
+		int error = errno;
+		perror("open(/dev/random)");
+		wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
+			   strerror(error));
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+		return -1;
+	}
+
+	res = read(fd, dummy_key + dummy_key_avail,
+		   sizeof(dummy_key) - dummy_key_avail);
+	if (res < 0) {
+		wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
+			   "%s", strerror(errno));
+		res = 0;
+	}
+	wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from "
+		   "/dev/random", (unsigned) res,
+		   (unsigned) (sizeof(dummy_key) - dummy_key_avail));
+	dummy_key_avail += res;
+	close(fd);
+
+	if (dummy_key_avail == sizeof(dummy_key)) {
+		if (own_pool_ready < MIN_READY_MARK)
+			own_pool_ready = MIN_READY_MARK;
+		random_write_entropy();
+		return 1;
+	}
+
+	wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
+		   "random data available from /dev/random",
+		   (unsigned) dummy_key_avail, (unsigned) sizeof(dummy_key));
+
+	if (own_pool_ready >= MIN_READY_MARK ||
+	    total_collected + 10 * own_pool_ready > MIN_COLLECT_ENTROPY) {
+		wpa_printf(MSG_INFO, "random: Allow operation to proceed "
+			   "based on internal entropy");
+		return 1;
+	}
+
+	wpa_printf(MSG_INFO, "random: Not enough entropy pool available for "
+		   "secure operations");
+	return 0;
+#else /* __linux__ */
+	/* TODO: could do similar checks on non-Linux platforms */
+	return 1;
+#endif /* __linux__ */
+}
+
+
+void random_mark_pool_ready(void)
+{
+	own_pool_ready++;
+	wpa_printf(MSG_DEBUG, "random: Mark internal entropy pool to be "
+		   "ready (count=%u/%u)", own_pool_ready, MIN_READY_MARK);
+	random_write_entropy();
+}
+
+
+#ifdef __linux__
+
+static void random_close_fd(void)
+{
+	if (random_fd >= 0) {
+		eloop_unregister_read_sock(random_fd);
+		close(random_fd);
+		random_fd = -1;
+	}
+}
+
+
+static void random_read_fd(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	ssize_t res;
+
+	if (dummy_key_avail == sizeof(dummy_key)) {
+		random_close_fd();
+		return;
+	}
+
+	res = read(sock, dummy_key + dummy_key_avail,
+		   sizeof(dummy_key) - dummy_key_avail);
+	if (res < 0) {
+		wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
+			   "%s", strerror(errno));
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from /dev/random",
+		   (unsigned) res,
+		   (unsigned) (sizeof(dummy_key) - dummy_key_avail));
+	dummy_key_avail += res;
+
+	if (dummy_key_avail == sizeof(dummy_key)) {
+		random_close_fd();
+		if (own_pool_ready < MIN_READY_MARK)
+			own_pool_ready = MIN_READY_MARK;
+		random_write_entropy();
+	}
+}
+
+#endif /* __linux__ */
+
+
+static void random_read_entropy(void)
+{
+	char *buf;
+	size_t len;
+
+	if (!random_entropy_file)
+		return;
+
+	buf = os_readfile(random_entropy_file, &len);
+	if (buf == NULL)
+		return; /* entropy file not yet available */
+
+	if (len != 1 + RANDOM_ENTROPY_SIZE) {
+		wpa_printf(MSG_DEBUG, "random: Invalid entropy file %s",
+			   random_entropy_file);
+		os_free(buf);
+		return;
+	}
+
+	own_pool_ready = (u8) buf[0];
+	random_add_randomness(buf + 1, RANDOM_ENTROPY_SIZE);
+	random_entropy_file_read = 1;
+	os_free(buf);
+	wpa_printf(MSG_DEBUG, "random: Added entropy from %s "
+		   "(own_pool_ready=%u)",
+		   random_entropy_file, own_pool_ready);
+}
+
+
+static void random_write_entropy(void)
+{
+	char buf[RANDOM_ENTROPY_SIZE];
+	FILE *f;
+	u8 opr;
+	int fail = 0;
+
+	if (!random_entropy_file)
+		return;
+
+	if (random_get_bytes(buf, RANDOM_ENTROPY_SIZE) < 0)
+		return;
+
+	f = fopen(random_entropy_file, "wb");
+	if (f == NULL) {
+		wpa_printf(MSG_ERROR, "random: Could not open entropy file %s "
+			   "for writing", random_entropy_file);
+		return;
+	}
+
+	opr = own_pool_ready > 0xff ? 0xff : own_pool_ready;
+	if (fwrite(&opr, 1, 1, f) != 1 ||
+	    fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f) != 1)
+		fail = 1;
+	fclose(f);
+	if (fail) {
+		wpa_printf(MSG_ERROR, "random: Could not write entropy data "
+			   "to %s", random_entropy_file);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "random: Updated entropy file %s "
+		   "(own_pool_ready=%u)",
+		   random_entropy_file, own_pool_ready);
+}
+
+
+void random_init(const char *entropy_file)
+{
+	os_free(random_entropy_file);
+	if (entropy_file)
+		random_entropy_file = os_strdup(entropy_file);
+	else
+		random_entropy_file = NULL;
+	random_read_entropy();
+
+#ifdef __linux__
+	if (random_fd >= 0)
+		return;
+
+	random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+	if (random_fd < 0) {
+#ifndef CONFIG_NO_STDOUT_DEBUG
+		int error = errno;
+		perror("open(/dev/random)");
+		wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
+			   strerror(error));
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "random: Trying to read entropy from "
+		   "/dev/random");
+
+	eloop_register_read_sock(random_fd, random_read_fd, NULL, NULL);
+#endif /* __linux__ */
+
+	random_write_entropy();
+}
+
+
+void random_deinit(void)
+{
+#ifdef __linux__
+	random_close_fd();
+#endif /* __linux__ */
+	random_write_entropy();
+	os_free(random_entropy_file);
+	random_entropy_file = NULL;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/random.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,28 @@
+/*
+ * Random number generator
+ * Copyright (c) 2010-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RANDOM_H
+#define RANDOM_H
+
+#ifdef CONFIG_NO_RANDOM_POOL
+#define random_init(e) do { } while (0)
+#define random_deinit() do { } while (0)
+#define random_add_randomness(b, l) do { } while (0)
+#define random_get_bytes(b, l) os_get_random((b), (l))
+#define random_pool_ready() 1
+#define random_mark_pool_ready() do { } while (0)
+#else /* CONFIG_NO_RANDOM_POOL */
+void random_init(const char *entropy_file);
+void random_deinit(void);
+void random_add_randomness(const void *buf, size_t len);
+int random_get_bytes(void *buf, size_t len);
+int random_pool_ready(void);
+void random_mark_pool_ready(void);
+#endif /* CONFIG_NO_RANDOM_POOL */
+
+#endif /* RANDOM_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/sha1-prf.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,66 @@
+/*
+ * SHA1-based PRF
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+#include "crypto.h"
+
+
+/**
+ * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1)
+ * @key: Key for PRF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ * Returns: 0 on success, -1 of failure
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key (e.g., PMK in IEEE 802.11i).
+ */
+int sha1_prf(const u8 *key, size_t key_len, const char *label,
+	     const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+{
+	u8 counter = 0;
+	size_t pos, plen;
+	u8 hash[SHA1_MAC_LEN];
+	size_t label_len = os_strlen(label) + 1;
+	const unsigned char *addr[3];
+	size_t len[3];
+
+	addr[0] = (u8 *) label;
+	len[0] = label_len;
+	addr[1] = data;
+	len[1] = data_len;
+	addr[2] = &counter;
+	len[2] = 1;
+
+	pos = 0;
+	while (pos < buf_len) {
+		plen = buf_len - pos;
+		if (plen >= SHA1_MAC_LEN) {
+			if (hmac_sha1_vector(key, key_len, 3, addr, len,
+					     &buf[pos]))
+				return -1;
+			pos += SHA1_MAC_LEN;
+		} else {
+			if (hmac_sha1_vector(key, key_len, 3, addr, len,
+					     hash))
+				return -1;
+			os_memcpy(&buf[pos], hash, plen);
+			break;
+		}
+		counter++;
+	}
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/sha1-tlsprf.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,99 @@
+/*
+ * TLS PRF (SHA1 + MD5)
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+#include "md5.h"
+
+
+/**
+ * tls_prf_sha1_md5 - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
+ * @secret: Key for PRF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
+ */
+int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
+		     const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+	size_t L_S1, L_S2, i;
+	const u8 *S1, *S2;
+	u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN];
+	u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN];
+	int MD5_pos, SHA1_pos;
+	const u8 *MD5_addr[3];
+	size_t MD5_len[3];
+	const unsigned char *SHA1_addr[3];
+	size_t SHA1_len[3];
+
+	if (secret_len & 1)
+		return -1;
+
+	MD5_addr[0] = A_MD5;
+	MD5_len[0] = MD5_MAC_LEN;
+	MD5_addr[1] = (unsigned char *) label;
+	MD5_len[1] = os_strlen(label);
+	MD5_addr[2] = seed;
+	MD5_len[2] = seed_len;
+
+	SHA1_addr[0] = A_SHA1;
+	SHA1_len[0] = SHA1_MAC_LEN;
+	SHA1_addr[1] = (unsigned char *) label;
+	SHA1_len[1] = os_strlen(label);
+	SHA1_addr[2] = seed;
+	SHA1_len[2] = seed_len;
+
+	/* RFC 2246, Chapter 5
+	 * A(0) = seed, A(i) = HMAC(secret, A(i-1))
+	 * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
+	 * PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed)
+	 */
+
+	L_S1 = L_S2 = (secret_len + 1) / 2;
+	S1 = secret;
+	S2 = secret + L_S1;
+	if (secret_len & 1) {
+		/* The last byte of S1 will be shared with S2 */
+		S2--;
+	}
+
+	hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5);
+	hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1);
+
+	MD5_pos = MD5_MAC_LEN;
+	SHA1_pos = SHA1_MAC_LEN;
+	for (i = 0; i < outlen; i++) {
+		if (MD5_pos == MD5_MAC_LEN) {
+			hmac_md5_vector(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5);
+			MD5_pos = 0;
+			hmac_md5(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5);
+		}
+		if (SHA1_pos == SHA1_MAC_LEN) {
+			hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len,
+					 P_SHA1);
+			SHA1_pos = 0;
+			hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1);
+		}
+
+		out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos];
+
+		MD5_pos++;
+		SHA1_pos++;
+	}
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/sha1.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,27 @@
+/*
+ * SHA1 hash implementation and interface functions
+ * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA1_H
+#define SHA1_H
+
+#define SHA1_MAC_LEN 20
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	       u8 *mac);
+int sha1_prf(const u8 *key, size_t key_len, const char *label,
+	     const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
+	       const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len);
+int __must_check tls_prf_sha1_md5(const u8 *secret, size_t secret_len,
+				  const char *label, const u8 *seed,
+				  size_t seed_len, u8 *out, size_t outlen);
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+		int iterations, u8 *buf, size_t buflen);
+#endif /* SHA1_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/sha256.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,24 @@
+/*
+ * SHA256 hash implementation and interface functions
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA256_H
+#define SHA256_H
+
+#define SHA256_MAC_LEN 32
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac);
+void sha256_prf(const u8 *key, size_t key_len, const char *label,
+	      const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+void tls_prf_sha256(const u8 *secret, size_t secret_len,
+		    const char *label, const u8 *seed, size_t seed_len,
+		    u8 *out, size_t outlen);
+
+#endif /* SHA256_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/tls.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,529 @@
+/*
+ * SSL/TLS interface definition
+ * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TLS_H
+#define TLS_H
+
+struct tls_connection;
+
+struct tls_keys {
+	const u8 *master_key; /* TLS master secret */
+	size_t master_key_len;
+	const u8 *client_random;
+	size_t client_random_len;
+	const u8 *server_random;
+	size_t server_random_len;
+};
+
+enum tls_event {
+	TLS_CERT_CHAIN_SUCCESS,
+	TLS_CERT_CHAIN_FAILURE,
+	TLS_PEER_CERTIFICATE,
+	TLS_ALERT
+};
+
+/*
+ * Note: These are used as identifier with external programs and as such, the
+ * values must not be changed.
+ */
+enum tls_fail_reason {
+	TLS_FAIL_UNSPECIFIED = 0,
+	TLS_FAIL_UNTRUSTED = 1,
+	TLS_FAIL_REVOKED = 2,
+	TLS_FAIL_NOT_YET_VALID = 3,
+	TLS_FAIL_EXPIRED = 4,
+	TLS_FAIL_SUBJECT_MISMATCH = 5,
+	TLS_FAIL_ALTSUBJECT_MISMATCH = 6,
+	TLS_FAIL_BAD_CERTIFICATE = 7,
+	TLS_FAIL_SERVER_CHAIN_PROBE = 8
+};
+
+union tls_event_data {
+	struct {
+		int depth;
+		const char *subject;
+		enum tls_fail_reason reason;
+		const char *reason_txt;
+		const struct wpabuf *cert;
+	} cert_fail;
+
+	struct {
+		int depth;
+		const char *subject;
+		const struct wpabuf *cert;
+		const u8 *hash;
+		size_t hash_len;
+	} peer_cert;
+
+	struct {
+		int is_local;
+		const char *type;
+		const char *description;
+	} alert;
+};
+
+struct tls_config {
+	const char *opensc_engine_path;
+	const char *pkcs11_engine_path;
+	const char *pkcs11_module_path;
+	int fips_mode;
+	int cert_in_cb;
+
+	void (*event_cb)(void *ctx, enum tls_event ev,
+			 union tls_event_data *data);
+	void *cb_ctx;
+};
+
+#define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0)
+#define TLS_CONN_DISABLE_TIME_CHECKS BIT(1)
+#define TLS_CONN_DISABLE_SESSION_TICKET BIT(2)
+
+/**
+ * struct tls_connection_params - Parameters for TLS connection
+ * @ca_cert: File or reference name for CA X.509 certificate in PEM or DER
+ * format
+ * @ca_cert_blob: ca_cert as inlined data or %NULL if not used
+ * @ca_cert_blob_len: ca_cert_blob length
+ * @ca_path: Path to CA certificates (OpenSSL specific)
+ * @subject_match: String to match in the subject of the peer certificate or
+ * %NULL to allow all subjects
+ * @altsubject_match: String to match in the alternative subject of the peer
+ * certificate or %NULL to allow all alternative subjects
+ * @client_cert: File or reference name for client X.509 certificate in PEM or
+ * DER format
+ * @client_cert_blob: client_cert as inlined data or %NULL if not used
+ * @client_cert_blob_len: client_cert_blob length
+ * @private_key: File or reference name for client private key in PEM or DER
+ * format (traditional format (RSA PRIVATE KEY) or PKCS#8 (PRIVATE KEY)
+ * @private_key_blob: private_key as inlined data or %NULL if not used
+ * @private_key_blob_len: private_key_blob length
+ * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
+ * passphrase is used.
+ * @dh_file: File name for DH/DSA data in PEM format, or %NULL if not used
+ * @dh_blob: dh_file as inlined data or %NULL if not used
+ * @dh_blob_len: dh_blob length
+ * @engine: 1 = use engine (e.g., a smartcard) for private key operations
+ * (this is OpenSSL specific for now)
+ * @engine_id: engine id string (this is OpenSSL specific for now)
+ * @ppin: pointer to the pin variable in the configuration
+ * (this is OpenSSL specific for now)
+ * @key_id: the private key's id when using engine (this is OpenSSL
+ * specific for now)
+ * @cert_id: the certificate's id when using engine
+ * @ca_cert_id: the CA certificate's id when using engine
+ * @flags: Parameter options (TLS_CONN_*)
+ *
+ * TLS connection parameters to be configured with tls_connection_set_params()
+ * and tls_global_set_params().
+ *
+ * Certificates and private key can be configured either as a reference name
+ * (file path or reference to certificate store) or by providing the same data
+ * as a pointer to the data in memory. Only one option will be used for each
+ * field.
+ */
+struct tls_connection_params {
+	const char *ca_cert;
+	const u8 *ca_cert_blob;
+	size_t ca_cert_blob_len;
+	const char *ca_path;
+	const char *subject_match;
+	const char *altsubject_match;
+	const char *client_cert;
+	const u8 *client_cert_blob;
+	size_t client_cert_blob_len;
+	const char *private_key;
+	const u8 *private_key_blob;
+	size_t private_key_blob_len;
+	const char *private_key_passwd;
+	const char *dh_file;
+	const u8 *dh_blob;
+	size_t dh_blob_len;
+
+	/* OpenSSL specific variables */
+	int engine;
+	const char *engine_id;
+	const char *pin;
+	const char *key_id;
+	const char *cert_id;
+	const char *ca_cert_id;
+
+	unsigned int flags;
+};
+
+
+/**
+ * tls_init - Initialize TLS library
+ * @conf: Configuration data for TLS library
+ * Returns: Context data to be used as tls_ctx in calls to other functions,
+ * or %NULL on failure.
+ *
+ * Called once during program startup and once for each RSN pre-authentication
+ * session. In other words, there can be two concurrent TLS contexts. If global
+ * library initialization is needed (i.e., one that is shared between both
+ * authentication types), the TLS library wrapper should maintain a reference
+ * counter and do global initialization only when moving from 0 to 1 reference.
+ */
+void * tls_init(const struct tls_config *conf);
+
+/**
+ * tls_deinit - Deinitialize TLS library
+ * @tls_ctx: TLS context data from tls_init()
+ *
+ * Called once during program shutdown and once for each RSN pre-authentication
+ * session. If global library deinitialization is needed (i.e., one that is
+ * shared between both authentication types), the TLS library wrapper should
+ * maintain a reference counter and do global deinitialization only when moving
+ * from 1 to 0 references.
+ */
+void tls_deinit(void *tls_ctx);
+
+/**
+ * tls_get_errors - Process pending errors
+ * @tls_ctx: TLS context data from tls_init()
+ * Returns: Number of found error, 0 if no errors detected.
+ *
+ * Process all pending TLS errors.
+ */
+int tls_get_errors(void *tls_ctx);
+
+/**
+ * tls_connection_init - Initialize a new TLS connection
+ * @tls_ctx: TLS context data from tls_init()
+ * Returns: Connection context data, conn for other function calls
+ */
+struct tls_connection * tls_connection_init(void *tls_ctx);
+
+/**
+ * tls_connection_deinit - Free TLS connection data
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ *
+ * Release all resources allocated for TLS connection.
+ */
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn);
+
+/**
+ * tls_connection_established - Has the TLS connection been completed?
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: 1 if TLS connection has been completed, 0 if not.
+ */
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
+
+/**
+ * tls_connection_shutdown - Shutdown TLS connection
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: 0 on success, -1 on failure
+ *
+ * Shutdown current TLS connection without releasing all resources. New
+ * connection can be started by using the same conn without having to call
+ * tls_connection_init() or setting certificates etc. again. The new
+ * connection should try to use session resumption.
+ */
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn);
+
+enum {
+	TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,
+	TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2
+};
+
+/**
+ * tls_connection_set_params - Set TLS connection parameters
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @params: Connection parameters
+ * Returns: 0 on success, -1 on failure,
+ * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
+ * PKCS#11 engine failure, or
+ * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
+ * PKCS#11 engine private key.
+ */
+int __must_check
+tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			  const struct tls_connection_params *params);
+
+/**
+ * tls_global_set_params - Set TLS parameters for all TLS connection
+ * @tls_ctx: TLS context data from tls_init()
+ * @params: Global TLS parameters
+ * Returns: 0 on success, -1 on failure,
+ * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
+ * PKCS#11 engine failure, or
+ * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
+ * PKCS#11 engine private key.
+ */
+int __must_check tls_global_set_params(
+	void *tls_ctx, const struct tls_connection_params *params);
+
+/**
+ * tls_global_set_verify - Set global certificate verification options
+ * @tls_ctx: TLS context data from tls_init()
+ * @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
+ * 2 = verify CRL for all certificates
+ * Returns: 0 on success, -1 on failure
+ */
+int __must_check tls_global_set_verify(void *tls_ctx, int check_crl);
+
+/**
+ * tls_connection_set_verify - Set certificate verification options
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @verify_peer: 1 = verify peer certificate
+ * Returns: 0 on success, -1 on failure
+ */
+int __must_check tls_connection_set_verify(void *tls_ctx,
+					   struct tls_connection *conn,
+					   int verify_peer);
+
+/**
+ * tls_connection_get_keys - Get master key and random data from TLS connection
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @keys: Structure of key/random data (filled on success)
+ * Returns: 0 on success, -1 on failure
+ */
+int __must_check tls_connection_get_keys(void *tls_ctx,
+					 struct tls_connection *conn,
+					 struct tls_keys *keys);
+
+/**
+ * tls_connection_prf - Use TLS-PRF to derive keying material
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @label: Label (e.g., description of the key) for PRF
+ * @server_random_first: seed is 0 = client_random|server_random,
+ * 1 = server_random|client_random
+ * @out: Buffer for output data from TLS-PRF
+ * @out_len: Length of the output buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is optional to implement if tls_connection_get_keys() provides
+ * access to master secret and server/client random values. If these values are
+ * not exported from the TLS library, tls_connection_prf() is required so that
+ * further keying material can be derived from the master secret. If not
+ * implemented, the function will still need to be defined, but it can just
+ * return -1. Example implementation of this function is in tls_prf_sha1_md5()
+ * when it is called with seed set to client_random|server_random (or
+ * server_random|client_random).
+ */
+int __must_check  tls_connection_prf(void *tls_ctx,
+				     struct tls_connection *conn,
+				     const char *label,
+				     int server_random_first,
+				     u8 *out, size_t out_len);
+
+/**
+ * tls_connection_handshake - Process TLS handshake (client side)
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @in_data: Input data from TLS server
+ * @appl_data: Pointer to application data pointer, or %NULL if dropped
+ * Returns: Output data, %NULL on failure
+ *
+ * The caller is responsible for freeing the returned output data. If the final
+ * handshake message includes application data, this is decrypted and
+ * appl_data (if not %NULL) is set to point this data. The caller is
+ * responsible for freeing appl_data.
+ *
+ * This function is used during TLS handshake. The first call is done with
+ * in_data == %NULL and the library is expected to return ClientHello packet.
+ * This packet is then send to the server and a response from server is given
+ * to TLS library by calling this function again with in_data pointing to the
+ * TLS message from the server.
+ *
+ * If the TLS handshake fails, this function may return %NULL. However, if the
+ * TLS library has a TLS alert to send out, that should be returned as the
+ * output data. In this case, tls_connection_get_failed() must return failure
+ * (> 0).
+ *
+ * tls_connection_established() should return 1 once the TLS handshake has been
+ * completed successfully.
+ */
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+					 struct tls_connection *conn,
+					 const struct wpabuf *in_data,
+					 struct wpabuf **appl_data);
+
+struct wpabuf * tls_connection_handshake2(void *tls_ctx,
+					  struct tls_connection *conn,
+					  const struct wpabuf *in_data,
+					  struct wpabuf **appl_data,
+					  int *more_data_needed);
+
+/**
+ * tls_connection_server_handshake - Process TLS handshake (server side)
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @in_data: Input data from TLS peer
+ * @appl_data: Pointer to application data pointer, or %NULL if dropped
+ * Returns: Output data, %NULL on failure
+ *
+ * The caller is responsible for freeing the returned output data.
+ */
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+						struct tls_connection *conn,
+						const struct wpabuf *in_data,
+						struct wpabuf **appl_data);
+
+/**
+ * tls_connection_encrypt - Encrypt data into TLS tunnel
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @in_data: Plaintext data to be encrypted
+ * Returns: Encrypted TLS data or %NULL on failure
+ *
+ * This function is used after TLS handshake has been completed successfully to
+ * send data in the encrypted tunnel. The caller is responsible for freeing the
+ * returned output data.
+ */
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data);
+
+/**
+ * tls_connection_decrypt - Decrypt data from TLS tunnel
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @in_data: Encrypted TLS data
+ * Returns: Decrypted TLS data or %NULL on failure
+ *
+ * This function is used after TLS handshake has been completed successfully to
+ * receive data from the encrypted tunnel. The caller is responsible for
+ * freeing the returned output data.
+ */
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data);
+
+struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
+					struct tls_connection *conn,
+					const struct wpabuf *in_data,
+					int *more_data_needed);
+
+/**
+ * tls_connection_resumed - Was session resumption used
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: 1 if current session used session resumption, 0 if not
+ */
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn);
+
+enum {
+	TLS_CIPHER_NONE,
+	TLS_CIPHER_RC4_SHA /* 0x0005 */,
+	TLS_CIPHER_AES128_SHA /* 0x002f */,
+	TLS_CIPHER_RSA_DHE_AES128_SHA /* 0x0031 */,
+	TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */
+};
+
+/**
+ * tls_connection_set_cipher_list - Configure acceptable cipher suites
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
+ * (TLS_CIPHER_*).
+ * Returns: 0 on success, -1 on failure
+ */
+int __must_check tls_connection_set_cipher_list(void *tls_ctx,
+						struct tls_connection *conn,
+						u8 *ciphers);
+
+/**
+ * tls_get_cipher - Get current cipher name
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @buf: Buffer for the cipher name
+ * @buflen: buf size
+ * Returns: 0 on success, -1 on failure
+ *
+ * Get the name of the currently used cipher.
+ */
+int __must_check tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+				char *buf, size_t buflen);
+
+/**
+ * tls_connection_enable_workaround - Enable TLS workaround options
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to enable connection-specific workaround options for
+ * buffer SSL/TLS implementations.
+ */
+int __must_check tls_connection_enable_workaround(void *tls_ctx,
+						  struct tls_connection *conn);
+
+/**
+ * tls_connection_client_hello_ext - Set TLS extension for ClientHello
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @ext_type: Extension type
+ * @data: Extension payload (%NULL to remove extension)
+ * @data_len: Extension payload length
+ * Returns: 0 on success, -1 on failure
+ */
+int __must_check tls_connection_client_hello_ext(void *tls_ctx,
+						 struct tls_connection *conn,
+						 int ext_type, const u8 *data,
+						 size_t data_len);
+
+/**
+ * tls_connection_get_failed - Get connection failure status
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ *
+ * Returns >0 if connection has failed, 0 if not.
+ */
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn);
+
+/**
+ * tls_connection_get_read_alerts - Get connection read alert status
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: Number of times a fatal read (remote end reported error) has
+ * happened during this connection.
+ */
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn);
+
+/**
+ * tls_connection_get_write_alerts - Get connection write alert status
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: Number of times a fatal write (locally detected error) has happened
+ * during this connection.
+ */
+int tls_connection_get_write_alerts(void *tls_ctx,
+				    struct tls_connection *conn);
+
+/**
+ * tls_connection_get_keyblock_size - Get TLS key_block size
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: Size of the key_block for the negotiated cipher suite or -1 on
+ * failure
+ */
+int tls_connection_get_keyblock_size(void *tls_ctx,
+				     struct tls_connection *conn);
+
+/**
+ * tls_capabilities - Get supported TLS capabilities
+ * @tls_ctx: TLS context data from tls_init()
+ * Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*)
+ */
+unsigned int tls_capabilities(void *tls_ctx);
+
+typedef int (*tls_session_ticket_cb)
+(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
+ const u8 *server_random, u8 *master_secret);
+
+int __must_check  tls_connection_set_session_ticket_cb(
+	void *tls_ctx, struct tls_connection *conn,
+	tls_session_ticket_cb cb, void *ctx);
+
+#endif /* TLS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/crypto/tls_openssl.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,3042 @@
+/*
+ * SSL/TLS interface functions for OpenSSL
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#ifndef CONFIG_SMARTCARD
+#ifndef OPENSSL_NO_ENGINE
+#define OPENSSL_NO_ENGINE
+#endif
+#endif
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/pkcs12.h>
+#include <openssl/x509v3.h>
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif /* OPENSSL_NO_ENGINE */
+
+#ifdef ANDROID
+#include <openssl/pem.h>
+#include "keystore_get.h"
+#endif /* ANDROID */
+
+#include "common.h"
+#include "crypto.h"
+#include "tls.h"
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#define OPENSSL_d2i_TYPE const unsigned char **
+#else
+#define OPENSSL_d2i_TYPE unsigned char **
+#endif
+
+#ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT
+#ifdef SSL_OP_NO_TICKET
+/*
+ * Session ticket override patch was merged into OpenSSL 0.9.9 tree on
+ * 2008-11-15. This version uses a bit different API compared to the old patch.
+ */
+#define CONFIG_OPENSSL_TICKET_OVERRIDE
+#endif
+#endif
+
+static int tls_openssl_ref_count = 0;
+
+struct tls_global {
+	void (*event_cb)(void *ctx, enum tls_event ev,
+			 union tls_event_data *data);
+	void *cb_ctx;
+	int cert_in_cb;
+};
+
+static struct tls_global *tls_global = NULL;
+
+
+struct tls_connection {
+	SSL *ssl;
+	BIO *ssl_in, *ssl_out;
+#ifndef OPENSSL_NO_ENGINE
+	ENGINE *engine;        /* functional reference to the engine */
+	EVP_PKEY *private_key; /* the private key if using engine */
+#endif /* OPENSSL_NO_ENGINE */
+	char *subject_match, *altsubject_match;
+	int read_alerts, write_alerts, failed;
+
+	tls_session_ticket_cb session_ticket_cb;
+	void *session_ticket_cb_ctx;
+
+	/* SessionTicket received from OpenSSL hello_extension_cb (server) */
+	u8 *session_ticket;
+	size_t session_ticket_len;
+
+	unsigned int ca_cert_verify:1;
+	unsigned int cert_probe:1;
+	unsigned int server_cert_only:1;
+
+	u8 srv_cert_hash[32];
+
+	unsigned int flags;
+};
+
+
+#ifdef CONFIG_NO_STDOUT_DEBUG
+
+static void _tls_show_errors(void)
+{
+	unsigned long err;
+
+	while ((err = ERR_get_error())) {
+		/* Just ignore the errors, since stdout is disabled */
+	}
+}
+#define tls_show_errors(l, f, t) _tls_show_errors()
+
+#else /* CONFIG_NO_STDOUT_DEBUG */
+
+static void tls_show_errors(int level, const char *func, const char *txt)
+{
+	unsigned long err;
+
+	wpa_printf(level, "OpenSSL: %s - %s %s",
+		   func, txt, ERR_error_string(ERR_get_error(), NULL));
+
+	while ((err = ERR_get_error())) {
+		wpa_printf(MSG_INFO, "OpenSSL: pending error: %s",
+			   ERR_error_string(err, NULL));
+	}
+}
+
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+
+/* Windows CryptoAPI and access to certificate stores */
+#include <wincrypt.h>
+
+#ifdef __MINGW32_VERSION
+/*
+ * MinGW does not yet include all the needed definitions for CryptoAPI, so
+ * define here whatever extra is needed.
+ */
+#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16)
+#define CERT_STORE_READONLY_FLAG 0x00008000
+#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
+
+#endif /* __MINGW32_VERSION */
+
+
+struct cryptoapi_rsa_data {
+	const CERT_CONTEXT *cert;
+	HCRYPTPROV crypt_prov;
+	DWORD key_spec;
+	BOOL free_crypt_prov;
+};
+
+
+static void cryptoapi_error(const char *msg)
+{
+	wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u",
+		   msg, (unsigned int) GetLastError());
+}
+
+
+static int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from,
+				 unsigned char *to, RSA *rsa, int padding)
+{
+	wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
+	return 0;
+}
+
+
+static int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from,
+				 unsigned char *to, RSA *rsa, int padding)
+{
+	wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
+	return 0;
+}
+
+
+static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from,
+				  unsigned char *to, RSA *rsa, int padding)
+{
+	struct cryptoapi_rsa_data *priv =
+		(struct cryptoapi_rsa_data *) rsa->meth->app_data;
+	HCRYPTHASH hash;
+	DWORD hash_size, len, i;
+	unsigned char *buf = NULL;
+	int ret = 0;
+
+	if (priv == NULL) {
+		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
+		       ERR_R_PASSED_NULL_PARAMETER);
+		return 0;
+	}
+
+	if (padding != RSA_PKCS1_PADDING) {
+		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
+		       RSA_R_UNKNOWN_PADDING_TYPE);
+		return 0;
+	}
+
+	if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) {
+		wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported",
+			   __func__);
+		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
+		       RSA_R_INVALID_MESSAGE_LENGTH);
+		return 0;
+	}
+
+	if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash))
+	{
+		cryptoapi_error("CryptCreateHash failed");
+		return 0;
+	}
+
+	len = sizeof(hash_size);
+	if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len,
+			       0)) {
+		cryptoapi_error("CryptGetHashParam failed");
+		goto err;
+	}
+
+	if ((int) hash_size != flen) {
+		wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)",
+			   (unsigned) hash_size, flen);
+		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
+		       RSA_R_INVALID_MESSAGE_LENGTH);
+		goto err;
+	}
+	if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) {
+		cryptoapi_error("CryptSetHashParam failed");
+		goto err;
+	}
+
+	len = RSA_size(rsa);
+	buf = os_malloc(len);
+	if (buf == NULL) {
+		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
+		goto err;
+	}
+
+	if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) {
+		cryptoapi_error("CryptSignHash failed");
+		goto err;
+	}
+
+	for (i = 0; i < len; i++)
+		to[i] = buf[len - i - 1];
+	ret = len;
+
+err:
+	os_free(buf);
+	CryptDestroyHash(hash);
+
+	return ret;
+}
+
+
+static int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from,
+				  unsigned char *to, RSA *rsa, int padding)
+{
+	wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
+	return 0;
+}
+
+
+static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv)
+{
+	if (priv == NULL)
+		return;
+	if (priv->crypt_prov && priv->free_crypt_prov)
+		CryptReleaseContext(priv->crypt_prov, 0);
+	if (priv->cert)
+		CertFreeCertificateContext(priv->cert);
+	os_free(priv);
+}
+
+
+static int cryptoapi_finish(RSA *rsa)
+{
+	cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data);
+	os_free((void *) rsa->meth);
+	rsa->meth = NULL;
+	return 1;
+}
+
+
+static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store)
+{
+	HCERTSTORE cs;
+	const CERT_CONTEXT *ret = NULL;
+
+	cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0,
+			   store | CERT_STORE_OPEN_EXISTING_FLAG |
+			   CERT_STORE_READONLY_FLAG, L"MY");
+	if (cs == NULL) {
+		cryptoapi_error("Failed to open 'My system store'");
+		return NULL;
+	}
+
+	if (strncmp(name, "cert://", 7) == 0) {
+		unsigned short wbuf[255];
+		MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255);
+		ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING |
+						 PKCS_7_ASN_ENCODING,
+						 0, CERT_FIND_SUBJECT_STR,
+						 wbuf, NULL);
+	} else if (strncmp(name, "hash://", 7) == 0) {
+		CRYPT_HASH_BLOB blob;
+		int len;
+		const char *hash = name + 7;
+		unsigned char *buf;
+
+		len = os_strlen(hash) / 2;
+		buf = os_malloc(len);
+		if (buf && hexstr2bin(hash, buf, len) == 0) {
+			blob.cbData = len;
+			blob.pbData = buf;
+			ret = CertFindCertificateInStore(cs,
+							 X509_ASN_ENCODING |
+							 PKCS_7_ASN_ENCODING,
+							 0, CERT_FIND_HASH,
+							 &blob, NULL);
+		}
+		os_free(buf);
+	}
+
+	CertCloseStore(cs, 0);
+
+	return ret;
+}
+
+
+static int tls_cryptoapi_cert(SSL *ssl, const char *name)
+{
+	X509 *cert = NULL;
+	RSA *rsa = NULL, *pub_rsa;
+	struct cryptoapi_rsa_data *priv;
+	RSA_METHOD *rsa_meth;
+
+	if (name == NULL ||
+	    (strncmp(name, "cert://", 7) != 0 &&
+	     strncmp(name, "hash://", 7) != 0))
+		return -1;
+
+	priv = os_zalloc(sizeof(*priv));
+	rsa_meth = os_zalloc(sizeof(*rsa_meth));
+	if (priv == NULL || rsa_meth == NULL) {
+		wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory "
+			   "for CryptoAPI RSA method");
+		os_free(priv);
+		os_free(rsa_meth);
+		return -1;
+	}
+
+	priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER);
+	if (priv->cert == NULL) {
+		priv->cert = cryptoapi_find_cert(
+			name, CERT_SYSTEM_STORE_LOCAL_MACHINE);
+	}
+	if (priv->cert == NULL) {
+		wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate "
+			   "'%s'", name);
+		goto err;
+	}
+
+	cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &priv->cert->pbCertEncoded,
+			priv->cert->cbCertEncoded);
+	if (cert == NULL) {
+		wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER "
+			   "encoding");
+		goto err;
+	}
+
+	if (!CryptAcquireCertificatePrivateKey(priv->cert,
+					       CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
+					       NULL, &priv->crypt_prov,
+					       &priv->key_spec,
+					       &priv->free_crypt_prov)) {
+		cryptoapi_error("Failed to acquire a private key for the "
+				"certificate");
+		goto err;
+	}
+
+	rsa_meth->name = "Microsoft CryptoAPI RSA Method";
+	rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc;
+	rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec;
+	rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc;
+	rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec;
+	rsa_meth->finish = cryptoapi_finish;
+	rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
+	rsa_meth->app_data = (char *) priv;
+
+	rsa = RSA_new();
+	if (rsa == NULL) {
+		SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,
+		       ERR_R_MALLOC_FAILURE);
+		goto err;
+	}
+
+	if (!SSL_use_certificate(ssl, cert)) {
+		RSA_free(rsa);
+		rsa = NULL;
+		goto err;
+	}
+	pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
+	X509_free(cert);
+	cert = NULL;
+
+	rsa->n = BN_dup(pub_rsa->n);
+	rsa->e = BN_dup(pub_rsa->e);
+	if (!RSA_set_method(rsa, rsa_meth))
+		goto err;
+
+	if (!SSL_use_RSAPrivateKey(ssl, rsa))
+		goto err;
+	RSA_free(rsa);
+
+	return 0;
+
+err:
+	if (cert)
+		X509_free(cert);
+	if (rsa)
+		RSA_free(rsa);
+	else {
+		os_free(rsa_meth);
+		cryptoapi_free_data(priv);
+	}
+	return -1;
+}
+
+
+static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
+{
+	HCERTSTORE cs;
+	PCCERT_CONTEXT ctx = NULL;
+	X509 *cert;
+	char buf[128];
+	const char *store;
+#ifdef UNICODE
+	WCHAR *wstore;
+#endif /* UNICODE */
+
+	if (name == NULL || strncmp(name, "cert_store://", 13) != 0)
+		return -1;
+
+	store = name + 13;
+#ifdef UNICODE
+	wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR));
+	if (wstore == NULL)
+		return -1;
+	wsprintf(wstore, L"%S", store);
+	cs = CertOpenSystemStore(0, wstore);
+	os_free(wstore);
+#else /* UNICODE */
+	cs = CertOpenSystemStore(0, store);
+#endif /* UNICODE */
+	if (cs == NULL) {
+		wpa_printf(MSG_DEBUG, "%s: failed to open system cert store "
+			   "'%s': error=%d", __func__, store,
+			   (int) GetLastError());
+		return -1;
+	}
+
+	while ((ctx = CertEnumCertificatesInStore(cs, ctx))) {
+		cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ctx->pbCertEncoded,
+				ctx->cbCertEncoded);
+		if (cert == NULL) {
+			wpa_printf(MSG_INFO, "CryptoAPI: Could not process "
+				   "X509 DER encoding for CA cert");
+			continue;
+		}
+
+		X509_NAME_oneline(X509_get_subject_name(cert), buf,
+				  sizeof(buf));
+		wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
+			   "system certificate store: subject='%s'", buf);
+
+		if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+			tls_show_errors(MSG_WARNING, __func__,
+					"Failed to add ca_cert to OpenSSL "
+					"certificate store");
+		}
+
+		X509_free(cert);
+	}
+
+	if (!CertCloseStore(cs, 0)) {
+		wpa_printf(MSG_DEBUG, "%s: failed to close system cert store "
+			   "'%s': error=%d", __func__, name + 13,
+			   (int) GetLastError());
+	}
+
+	return 0;
+}
+
+
+#else /* CONFIG_NATIVE_WINDOWS */
+
+static int tls_cryptoapi_cert(SSL *ssl, const char *name)
+{
+	return -1;
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static void ssl_info_cb(const SSL *ssl, int where, int ret)
+{
+	const char *str;
+	int w;
+
+	wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret);
+	w = where & ~SSL_ST_MASK;
+	if (w & SSL_ST_CONNECT)
+		str = "SSL_connect";
+	else if (w & SSL_ST_ACCEPT)
+		str = "SSL_accept";
+	else
+		str = "undefined";
+
+	if (where & SSL_CB_LOOP) {
+		wpa_printf(MSG_DEBUG, "SSL: %s:%s",
+			   str, SSL_state_string_long(ssl));
+	} else if (where & SSL_CB_ALERT) {
+		wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s",
+			   where & SSL_CB_READ ?
+			   "read (remote end reported an error)" :
+			   "write (local SSL3 detected an error)",
+			   SSL_alert_type_string_long(ret),
+			   SSL_alert_desc_string_long(ret));
+		if ((ret >> 8) == SSL3_AL_FATAL) {
+			struct tls_connection *conn =
+				SSL_get_app_data((SSL *) ssl);
+			if (where & SSL_CB_READ)
+				conn->read_alerts++;
+			else
+				conn->write_alerts++;
+		}
+		if (tls_global->event_cb != NULL) {
+			union tls_event_data ev;
+			os_memset(&ev, 0, sizeof(ev));
+			ev.alert.is_local = !(where & SSL_CB_READ);
+			ev.alert.type = SSL_alert_type_string_long(ret);
+			ev.alert.description = SSL_alert_desc_string_long(ret);
+			tls_global->event_cb(tls_global->cb_ctx, TLS_ALERT,
+					     &ev);
+		}
+	} else if (where & SSL_CB_EXIT && ret <= 0) {
+		wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
+			   str, ret == 0 ? "failed" : "error",
+			   SSL_state_string_long(ssl));
+	}
+}
+
+#ifndef OPENSSL_NO_ENGINE
+#ifndef __sun
+/**
+ * tls_engine_load_dynamic_generic - load any openssl engine
+ * @pre: an array of commands and values that load an engine initialized
+ *       in the engine specific function
+ * @post: an array of commands and values that initialize an already loaded
+ *        engine (or %NULL if not required)
+ * @id: the engine id of the engine to load (only required if post is not %NULL
+ *
+ * This function is a generic function that loads any openssl engine.
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int tls_engine_load_dynamic_generic(const char *pre[],
+					   const char *post[], const char *id)
+{
+	ENGINE *engine;
+	const char *dynamic_id = "dynamic";
+
+	engine = ENGINE_by_id(id);
+	if (engine) {
+		ENGINE_free(engine);
+		wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
+			   "available", id);
+		return 0;
+	}
+	ERR_clear_error();
+
+	engine = ENGINE_by_id(dynamic_id);
+	if (engine == NULL) {
+		wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
+			   dynamic_id,
+			   ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+
+	/* Perform the pre commands. This will load the engine. */
+	while (pre && pre[0]) {
+		wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]);
+		if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) {
+			wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: "
+				   "%s %s [%s]", pre[0], pre[1],
+				   ERR_error_string(ERR_get_error(), NULL));
+			ENGINE_free(engine);
+			return -1;
+		}
+		pre += 2;
+	}
+
+	/*
+	 * Free the reference to the "dynamic" engine. The loaded engine can
+	 * now be looked up using ENGINE_by_id().
+	 */
+	ENGINE_free(engine);
+
+	engine = ENGINE_by_id(id);
+	if (engine == NULL) {
+		wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
+			   id, ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+
+	while (post && post[0]) {
+		wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
+		if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
+			wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:"
+				" %s %s [%s]", post[0], post[1],
+				   ERR_error_string(ERR_get_error(), NULL));
+			ENGINE_remove(engine);
+			ENGINE_free(engine);
+			return -1;
+		}
+		post += 2;
+	}
+	ENGINE_free(engine);
+
+	return 0;
+}
+
+
+/**
+ * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc
+ * @pkcs11_so_path: pksc11_so_path from the configuration
+ * @pcks11_module_path: pkcs11_module_path from the configuration
+ */
+static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path,
+					  const char *pkcs11_module_path)
+{
+	char *engine_id = "pkcs11";
+	const char *pre_cmd[] = {
+		"SO_PATH", NULL /* pkcs11_so_path */,
+		"ID", NULL /* engine_id */,
+		"LIST_ADD", "1",
+		/* "NO_VCHECK", "1", */
+		"LOAD", NULL,
+		NULL, NULL
+	};
+	const char *post_cmd[] = {
+		"MODULE_PATH", NULL /* pkcs11_module_path */,
+		NULL, NULL
+	};
+
+	if (!pkcs11_so_path || !pkcs11_module_path)
+		return 0;
+
+	pre_cmd[1] = pkcs11_so_path;
+	pre_cmd[3] = engine_id;
+	post_cmd[1] = pkcs11_module_path;
+
+	wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
+		   pkcs11_so_path);
+
+	return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id);
+}
+
+
+/**
+ * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc
+ * @opensc_so_path: opensc_so_path from the configuration
+ */
+static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
+{
+	char *engine_id = "opensc";
+	const char *pre_cmd[] = {
+		"SO_PATH", NULL /* opensc_so_path */,
+		"ID", NULL /* engine_id */,
+		"LIST_ADD", "1",
+		"LOAD", NULL,
+		NULL, NULL
+	};
+
+	if (!opensc_so_path)
+		return 0;
+
+	pre_cmd[1] = opensc_so_path;
+	pre_cmd[3] = engine_id;
+
+	wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s",
+		   opensc_so_path);
+
+	return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id);
+}
+#endif /* __sun */
+#endif /* OPENSSL_NO_ENGINE */
+
+
+void * tls_init(const struct tls_config *conf)
+{
+	SSL_CTX *ssl;
+
+	if (tls_openssl_ref_count == 0) {
+		tls_global = os_zalloc(sizeof(*tls_global));
+		if (tls_global == NULL)
+			return NULL;
+		if (conf) {
+			tls_global->event_cb = conf->event_cb;
+			tls_global->cb_ctx = conf->cb_ctx;
+			tls_global->cert_in_cb = conf->cert_in_cb;
+		}
+
+#ifdef CONFIG_FIPS
+#ifdef OPENSSL_FIPS
+		if (conf && conf->fips_mode) {
+			if (!FIPS_mode_set(1)) {
+				wpa_printf(MSG_ERROR, "Failed to enable FIPS "
+					   "mode");
+				ERR_load_crypto_strings();
+				ERR_print_errors_fp(stderr);
+				os_free(tls_global);
+				tls_global = NULL;
+				return NULL;
+			} else
+				wpa_printf(MSG_INFO, "Running in FIPS mode");
+		}
+#else /* OPENSSL_FIPS */
+		if (conf && conf->fips_mode) {
+			wpa_printf(MSG_ERROR, "FIPS mode requested, but not "
+				   "supported");
+			os_free(tls_global);
+			tls_global = NULL;
+			return NULL;
+		}
+#endif /* OPENSSL_FIPS */
+#endif /* CONFIG_FIPS */
+		SSL_load_error_strings();
+		SSL_library_init();
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+		EVP_add_digest(EVP_sha256());
+#endif /* OPENSSL_NO_SHA256 */
+		/* TODO: if /dev/urandom is available, PRNG is seeded
+		 * automatically. If this is not the case, random data should
+		 * be added here. */
+
+#ifdef PKCS12_FUNCS
+#ifndef OPENSSL_NO_RC2
+		/*
+		 * 40-bit RC2 is commonly used in PKCS#12 files, so enable it.
+		 * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8
+		 * versions, but it looks like OpenSSL 1.0.0 does not do that
+		 * anymore.
+		 */
+		EVP_add_cipher(EVP_rc2_40_cbc());
+#endif /* OPENSSL_NO_RC2 */
+		PKCS12_PBE_add();
+#endif  /* PKCS12_FUNCS */
+	}
+	tls_openssl_ref_count++;
+
+	ssl = SSL_CTX_new(TLSv1_method());
+	if (ssl == NULL)
+		return NULL;
+
+	SSL_CTX_set_info_callback(ssl, ssl_info_cb);
+
+#ifndef OPENSSL_NO_ENGINE
+#ifdef __sun
+	wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 engine plugin");
+	ENGINE_load_pk11();
+#else /* __sun */
+
+	if (conf &&
+	    (conf->opensc_engine_path || conf->pkcs11_engine_path ||
+	     conf->pkcs11_module_path)) {
+		wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
+		ERR_load_ENGINE_strings();
+		ENGINE_load_dynamic();
+
+		if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
+		    tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
+						   conf->pkcs11_module_path)) {
+			tls_deinit(ssl);
+			return NULL;
+		}
+	}
+#endif /* __sun */
+#endif /* OPENSSL_NO_ENGINE */
+
+	return ssl;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+	SSL_CTX *ssl = ssl_ctx;
+	SSL_CTX_free(ssl);
+
+	tls_openssl_ref_count--;
+	if (tls_openssl_ref_count == 0) {
+#ifndef OPENSSL_NO_ENGINE
+		ENGINE_cleanup();
+#endif /* OPENSSL_NO_ENGINE */
+		CRYPTO_cleanup_all_ex_data();
+		ERR_remove_state(0);
+		ERR_free_strings();
+		EVP_cleanup();
+		os_free(tls_global);
+		tls_global = NULL;
+	}
+}
+
+
+static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
+			   const char *pin, const char *key_id,
+			   const char *cert_id, const char *ca_cert_id)
+{
+#ifndef OPENSSL_NO_ENGINE
+	int ret = -1;
+	if (engine_id == NULL) {
+		wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
+		return -1;
+	}
+	if (pin == NULL) {
+		wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set");
+		return -1;
+	}
+	if (key_id == NULL) {
+		wpa_printf(MSG_ERROR, "ENGINE: Key Id not set");
+		return -1;
+	}
+
+	ERR_clear_error();
+	conn->engine = ENGINE_by_id(engine_id);
+	if (!conn->engine) {
+		wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]",
+			   engine_id, ERR_error_string(ERR_get_error(), NULL));
+		goto err;
+	}
+	if (ENGINE_init(conn->engine) != 1) {
+		wpa_printf(MSG_ERROR, "ENGINE: engine init failed "
+			   "(engine: %s) [%s]", engine_id,
+			   ERR_error_string(ERR_get_error(), NULL));
+		goto err;
+	}
+	wpa_printf(MSG_DEBUG, "ENGINE: engine initialized");
+
+	if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
+		wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]",
+			   ERR_error_string(ERR_get_error(), NULL));
+		goto err;
+	}
+	/* load private key first in-case PIN is required for cert */
+	conn->private_key = ENGINE_load_private_key(conn->engine,
+						    key_id, NULL, NULL);
+	if (!conn->private_key) {
+		wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id"
+				" '%s' [%s]", key_id,
+			   ERR_error_string(ERR_get_error(), NULL));
+		ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+		goto err;
+	}
+
+	/* handle a certificate and/or CA certificate */
+	if (cert_id || ca_cert_id) {
+		const char *cmd_name = "LOAD_CERT_CTRL";
+
+		/* test if the engine supports a LOAD_CERT_CTRL */
+		if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
+				 0, (void *)cmd_name, NULL)) {
+			wpa_printf(MSG_ERROR, "ENGINE: engine does not support"
+				   " loading certificates");
+			ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+			goto err;
+		}
+	}
+
+	return 0;
+
+err:
+	if (conn->engine) {
+		ENGINE_free(conn->engine);
+		conn->engine = NULL;
+	}
+
+	if (conn->private_key) {
+		EVP_PKEY_free(conn->private_key);
+		conn->private_key = NULL;
+	}
+
+	return ret;
+#else /* OPENSSL_NO_ENGINE */
+	return 0;
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+static void tls_engine_deinit(struct tls_connection *conn)
+{
+#ifndef OPENSSL_NO_ENGINE
+	wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
+	if (conn->private_key) {
+		EVP_PKEY_free(conn->private_key);
+		conn->private_key = NULL;
+	}
+	if (conn->engine) {
+		ENGINE_finish(conn->engine);
+		conn->engine = NULL;
+	}
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+int tls_get_errors(void *ssl_ctx)
+{
+	int count = 0;
+	unsigned long err;
+
+	while ((err = ERR_get_error())) {
+		wpa_printf(MSG_INFO, "TLS - SSL error: %s",
+			   ERR_error_string(err, NULL));
+		count++;
+	}
+
+	return count;
+}
+
+struct tls_connection * tls_connection_init(void *ssl_ctx)
+{
+	SSL_CTX *ssl = ssl_ctx;
+	struct tls_connection *conn;
+	long options;
+
+	conn = os_zalloc(sizeof(*conn));
+	if (conn == NULL)
+		return NULL;
+	conn->ssl = SSL_new(ssl);
+	if (conn->ssl == NULL) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to initialize new SSL connection");
+		os_free(conn);
+		return NULL;
+	}
+
+	SSL_set_app_data(conn->ssl, conn);
+	options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
+		SSL_OP_SINGLE_DH_USE;
+#ifdef SSL_OP_NO_COMPRESSION
+	options |= SSL_OP_NO_COMPRESSION;
+#endif /* SSL_OP_NO_COMPRESSION */
+	SSL_set_options(conn->ssl, options);
+
+	conn->ssl_in = BIO_new(BIO_s_mem());
+	if (!conn->ssl_in) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to create a new BIO for ssl_in");
+		SSL_free(conn->ssl);
+		os_free(conn);
+		return NULL;
+	}
+
+	conn->ssl_out = BIO_new(BIO_s_mem());
+	if (!conn->ssl_out) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to create a new BIO for ssl_out");
+		SSL_free(conn->ssl);
+		BIO_free(conn->ssl_in);
+		os_free(conn);
+		return NULL;
+	}
+
+	SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out);
+
+	return conn;
+}
+
+
+void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return;
+	SSL_free(conn->ssl);
+	tls_engine_deinit(conn);
+	os_free(conn->subject_match);
+	os_free(conn->altsubject_match);
+	os_free(conn->session_ticket);
+	os_free(conn);
+}
+
+
+int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
+{
+	return conn ? SSL_is_init_finished(conn->ssl) : 0;
+}
+
+
+int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+
+	/* Shutdown previous TLS connection without notifying the peer
+	 * because the connection was already terminated in practice
+	 * and "close notify" shutdown alert would confuse AS. */
+	SSL_set_quiet_shutdown(conn->ssl, 1);
+	SSL_shutdown(conn->ssl);
+	return 0;
+}
+
+
+static int tls_match_altsubject_component(X509 *cert, int type,
+					  const char *value, size_t len)
+{
+	GENERAL_NAME *gen;
+	void *ext;
+	int i, found = 0;
+
+	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+
+	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
+		gen = sk_GENERAL_NAME_value(ext, i);
+		if (gen->type != type)
+			continue;
+		if (os_strlen((char *) gen->d.ia5->data) == len &&
+		    os_memcmp(value, gen->d.ia5->data, len) == 0)
+			found++;
+	}
+
+	return found;
+}
+
+
+static int tls_match_altsubject(X509 *cert, const char *match)
+{
+	int type;
+	const char *pos, *end;
+	size_t len;
+
+	pos = match;
+	do {
+		if (os_strncmp(pos, "EMAIL:", 6) == 0) {
+			type = GEN_EMAIL;
+			pos += 6;
+		} else if (os_strncmp(pos, "DNS:", 4) == 0) {
+			type = GEN_DNS;
+			pos += 4;
+		} else if (os_strncmp(pos, "URI:", 4) == 0) {
+			type = GEN_URI;
+			pos += 4;
+		} else {
+			wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName "
+				   "match '%s'", pos);
+			return 0;
+		}
+		end = os_strchr(pos, ';');
+		while (end) {
+			if (os_strncmp(end + 1, "EMAIL:", 6) == 0 ||
+			    os_strncmp(end + 1, "DNS:", 4) == 0 ||
+			    os_strncmp(end + 1, "URI:", 4) == 0)
+				break;
+			end = os_strchr(end + 1, ';');
+		}
+		if (end)
+			len = end - pos;
+		else
+			len = os_strlen(pos);
+		if (tls_match_altsubject_component(cert, type, pos, len) > 0)
+			return 1;
+		pos = end + 1;
+	} while (end);
+
+	return 0;
+}
+
+
+static enum tls_fail_reason openssl_tls_fail_reason(int err)
+{
+	switch (err) {
+	case X509_V_ERR_CERT_REVOKED:
+		return TLS_FAIL_REVOKED;
+	case X509_V_ERR_CERT_NOT_YET_VALID:
+	case X509_V_ERR_CRL_NOT_YET_VALID:
+		return TLS_FAIL_NOT_YET_VALID;
+	case X509_V_ERR_CERT_HAS_EXPIRED:
+	case X509_V_ERR_CRL_HAS_EXPIRED:
+		return TLS_FAIL_EXPIRED;
+	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+	case X509_V_ERR_UNABLE_TO_GET_CRL:
+	case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
+	case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+	case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+	case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+	case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+	case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+	case X509_V_ERR_INVALID_CA:
+		return TLS_FAIL_UNTRUSTED;
+	case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+	case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+	case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+	case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+	case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+	case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+	case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+	case X509_V_ERR_CERT_UNTRUSTED:
+	case X509_V_ERR_CERT_REJECTED:
+		return TLS_FAIL_BAD_CERTIFICATE;
+	default:
+		return TLS_FAIL_UNSPECIFIED;
+	}
+}
+
+
+static struct wpabuf * get_x509_cert(X509 *cert)
+{
+	struct wpabuf *buf;
+	u8 *tmp;
+
+	int cert_len = i2d_X509(cert, NULL);
+	if (cert_len <= 0)
+		return NULL;
+
+	buf = wpabuf_alloc(cert_len);
+	if (buf == NULL)
+		return NULL;
+
+	tmp = wpabuf_put(buf, cert_len);
+	i2d_X509(cert, &tmp);
+	return buf;
+}
+
+
+static void openssl_tls_fail_event(struct tls_connection *conn,
+				   X509 *err_cert, int err, int depth,
+				   const char *subject, const char *err_str,
+				   enum tls_fail_reason reason)
+{
+	union tls_event_data ev;
+	struct wpabuf *cert = NULL;
+
+	if (tls_global->event_cb == NULL)
+		return;
+
+	cert = get_x509_cert(err_cert);
+	os_memset(&ev, 0, sizeof(ev));
+	ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
+		reason : openssl_tls_fail_reason(err);
+	ev.cert_fail.depth = depth;
+	ev.cert_fail.subject = subject;
+	ev.cert_fail.reason_txt = err_str;
+	ev.cert_fail.cert = cert;
+	tls_global->event_cb(tls_global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+	wpabuf_free(cert);
+}
+
+
+static void openssl_tls_cert_event(struct tls_connection *conn,
+				   X509 *err_cert, int depth,
+				   const char *subject)
+{
+	struct wpabuf *cert = NULL;
+	union tls_event_data ev;
+#ifdef CONFIG_SHA256
+	u8 hash[32];
+#endif /* CONFIG_SHA256 */
+
+	if (tls_global->event_cb == NULL)
+		return;
+
+	os_memset(&ev, 0, sizeof(ev));
+	if (conn->cert_probe || tls_global->cert_in_cb) {
+		cert = get_x509_cert(err_cert);
+		ev.peer_cert.cert = cert;
+	}
+#ifdef CONFIG_SHA256
+	if (cert) {
+		const u8 *addr[1];
+		size_t len[1];
+		addr[0] = wpabuf_head(cert);
+		len[0] = wpabuf_len(cert);
+		if (sha256_vector(1, addr, len, hash) == 0) {
+			ev.peer_cert.hash = hash;
+			ev.peer_cert.hash_len = sizeof(hash);
+		}
+	}
+#endif /* CONFIG_SHA256 */
+	ev.peer_cert.depth = depth;
+	ev.peer_cert.subject = subject;
+	tls_global->event_cb(tls_global->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+	wpabuf_free(cert);
+}
+
+
+static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+	char buf[256];
+	X509 *err_cert;
+	int err, depth;
+	SSL *ssl;
+	struct tls_connection *conn;
+	char *match, *altmatch;
+	const char *err_str;
+
+	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
+	err = X509_STORE_CTX_get_error(x509_ctx);
+	depth = X509_STORE_CTX_get_error_depth(x509_ctx);
+	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
+					 SSL_get_ex_data_X509_STORE_CTX_idx());
+	X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
+
+	conn = SSL_get_app_data(ssl);
+	if (conn == NULL)
+		return 0;
+	match = conn->subject_match;
+	altmatch = conn->altsubject_match;
+
+	if (!preverify_ok && !conn->ca_cert_verify)
+		preverify_ok = 1;
+	if (!preverify_ok && depth > 0 && conn->server_cert_only)
+		preverify_ok = 1;
+	if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
+	    (err == X509_V_ERR_CERT_HAS_EXPIRED ||
+	     err == X509_V_ERR_CERT_NOT_YET_VALID)) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Ignore certificate validity "
+			   "time mismatch");
+		preverify_ok = 1;
+	}
+
+	err_str = X509_verify_cert_error_string(err);
+
+#ifdef CONFIG_SHA256
+	if (preverify_ok && depth == 0 && conn->server_cert_only) {
+		struct wpabuf *cert;
+		cert = get_x509_cert(err_cert);
+		if (!cert) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch "
+				   "server certificate data");
+			preverify_ok = 0;
+		} else {
+			u8 hash[32];
+			const u8 *addr[1];
+			size_t len[1];
+			addr[0] = wpabuf_head(cert);
+			len[0] = wpabuf_len(cert);
+			if (sha256_vector(1, addr, len, hash) < 0 ||
+			    os_memcmp(conn->srv_cert_hash, hash, 32) != 0) {
+				err_str = "Server certificate mismatch";
+				err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
+				preverify_ok = 0;
+			}
+			wpabuf_free(cert);
+		}
+	}
+#endif /* CONFIG_SHA256 */
+
+	if (!preverify_ok) {
+		wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
+			   " error %d (%s) depth %d for '%s'", err, err_str,
+			   depth, buf);
+		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+				       err_str, TLS_FAIL_UNSPECIFIED);
+		return preverify_ok;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d "
+		   "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
+		   preverify_ok, err, err_str,
+		   conn->ca_cert_verify, depth, buf);
+	if (depth == 0 && match && os_strstr(buf, match) == NULL) {
+		wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
+			   "match with '%s'", buf, match);
+		preverify_ok = 0;
+		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+				       "Subject mismatch",
+				       TLS_FAIL_SUBJECT_MISMATCH);
+	} else if (depth == 0 && altmatch &&
+		   !tls_match_altsubject(err_cert, altmatch)) {
+		wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
+			   "'%s' not found", altmatch);
+		preverify_ok = 0;
+		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+				       "AltSubject mismatch",
+				       TLS_FAIL_ALTSUBJECT_MISMATCH);
+	} else
+		openssl_tls_cert_event(conn, err_cert, depth, buf);
+
+	if (conn->cert_probe && preverify_ok && depth == 0) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate "
+			   "on probe-only run");
+		preverify_ok = 0;
+		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+				       "Server certificate chain probe",
+				       TLS_FAIL_SERVER_CHAIN_PROBE);
+	}
+
+	if (preverify_ok && tls_global->event_cb != NULL)
+		tls_global->event_cb(tls_global->cb_ctx,
+				     TLS_CERT_CHAIN_SUCCESS, NULL);
+
+	return preverify_ok;
+}
+
+
+#ifndef OPENSSL_NO_STDIO
+static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
+{
+	SSL_CTX *ssl_ctx = _ssl_ctx;
+	X509_LOOKUP *lookup;
+	int ret = 0;
+
+	lookup = X509_STORE_add_lookup(ssl_ctx->cert_store,
+				       X509_LOOKUP_file());
+	if (lookup == NULL) {
+		tls_show_errors(MSG_WARNING, __func__,
+				"Failed add lookup for X509 store");
+		return -1;
+	}
+
+	if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) {
+		unsigned long err = ERR_peek_error();
+		tls_show_errors(MSG_WARNING, __func__,
+				"Failed load CA in DER format");
+		if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
+		    ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
+				   "cert already in hash table error",
+				   __func__);
+		} else
+			ret = -1;
+	}
+
+	return ret;
+}
+#endif /* OPENSSL_NO_STDIO */
+
+
+#ifdef ANDROID
+static BIO * BIO_from_keystore(const char *key)
+{
+	BIO *bio = NULL;
+	char value[KEYSTORE_MESSAGE_SIZE];
+	int length = keystore_get(key, strlen(key), value);
+	if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
+		BIO_write(bio, value, length);
+	return bio;
+}
+#endif /* ANDROID */
+
+
+static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
+				  const char *ca_cert, const u8 *ca_cert_blob,
+				  size_t ca_cert_blob_len, const char *ca_path)
+{
+	SSL_CTX *ssl_ctx = _ssl_ctx;
+
+	/*
+	 * Remove previously configured trusted CA certificates before adding
+	 * new ones.
+	 */
+	X509_STORE_free(ssl_ctx->cert_store);
+	ssl_ctx->cert_store = X509_STORE_new();
+	if (ssl_ctx->cert_store == NULL) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
+			   "certificate store", __func__);
+		return -1;
+	}
+
+	SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+	conn->ca_cert_verify = 1;
+
+	if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate "
+			   "chain");
+		conn->cert_probe = 1;
+		conn->ca_cert_verify = 0;
+		return 0;
+	}
+
+	if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) {
+#ifdef CONFIG_SHA256
+		const char *pos = ca_cert + 7;
+		if (os_strncmp(pos, "server/sha256/", 14) != 0) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert "
+				   "hash value '%s'", ca_cert);
+			return -1;
+		}
+		pos += 14;
+		if (os_strlen(pos) != 32 * 2) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 "
+				   "hash length in ca_cert '%s'", ca_cert);
+			return -1;
+		}
+		if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash "
+				   "value in ca_cert '%s'", ca_cert);
+			return -1;
+		}
+		conn->server_cert_only = 1;
+		wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server "
+			   "certificate match");
+		return 0;
+#else /* CONFIG_SHA256 */
+		wpa_printf(MSG_INFO, "No SHA256 included in the build - "
+			   "cannot validate server certificate hash");
+		return -1;
+#endif /* CONFIG_SHA256 */
+	}
+
+	if (ca_cert_blob) {
+		X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ca_cert_blob,
+				      ca_cert_blob_len);
+		if (cert == NULL) {
+			tls_show_errors(MSG_WARNING, __func__,
+					"Failed to parse ca_cert_blob");
+			return -1;
+		}
+
+		if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+			unsigned long err = ERR_peek_error();
+			tls_show_errors(MSG_WARNING, __func__,
+					"Failed to add ca_cert_blob to "
+					"certificate store");
+			if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
+			    ERR_GET_REASON(err) ==
+			    X509_R_CERT_ALREADY_IN_HASH_TABLE) {
+				wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
+					   "cert already in hash table error",
+					   __func__);
+			} else {
+				X509_free(cert);
+				return -1;
+			}
+		}
+		X509_free(cert);
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob "
+			   "to certificate store", __func__);
+		return 0;
+	}
+
+#ifdef ANDROID
+	if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
+		BIO *bio = BIO_from_keystore(&ca_cert[11]);
+		STACK_OF(X509_INFO) *stack = NULL;
+		int i;
+
+		if (bio) {
+			stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
+			BIO_free(bio);
+		}
+		if (!stack)
+			return -1;
+
+		for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
+			X509_INFO *info = sk_X509_INFO_value(stack, i);
+			if (info->x509) {
+				X509_STORE_add_cert(ssl_ctx->cert_store,
+						    info->x509);
+			}
+			if (info->crl) {
+				X509_STORE_add_crl(ssl_ctx->cert_store,
+						   info->crl);
+			}
+		}
+		sk_X509_INFO_pop_free(stack, X509_INFO_free);
+		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+		return 0;
+	}
+#endif /* ANDROID */
+
+#ifdef CONFIG_NATIVE_WINDOWS
+	if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) ==
+	    0) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from "
+			   "system certificate store");
+		return 0;
+	}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	if (ca_cert || ca_path) {
+#ifndef OPENSSL_NO_STDIO
+		if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) !=
+		    1) {
+			tls_show_errors(MSG_WARNING, __func__,
+					"Failed to load root certificates");
+			if (ca_cert &&
+			    tls_load_ca_der(ssl_ctx, ca_cert) == 0) {
+				wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded "
+					   "DER format CA certificate",
+					   __func__);
+			} else
+				return -1;
+		} else {
+			wpa_printf(MSG_DEBUG, "TLS: Trusted root "
+				   "certificate(s) loaded");
+			tls_get_errors(ssl_ctx);
+		}
+#else /* OPENSSL_NO_STDIO */
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
+			   __func__);
+		return -1;
+#endif /* OPENSSL_NO_STDIO */
+	} else {
+		/* No ca_cert configured - do not try to verify server
+		 * certificate */
+		conn->ca_cert_verify = 0;
+	}
+
+	return 0;
+}
+
+
+static int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert)
+{
+	if (ca_cert) {
+		if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
+		{
+			tls_show_errors(MSG_WARNING, __func__,
+					"Failed to load root certificates");
+			return -1;
+		}
+
+		wpa_printf(MSG_DEBUG, "TLS: Trusted root "
+			   "certificate(s) loaded");
+
+#ifndef OPENSSL_NO_STDIO
+		/* Add the same CAs to the client certificate requests */
+		SSL_CTX_set_client_CA_list(ssl_ctx,
+					   SSL_load_client_CA_file(ca_cert));
+#endif /* OPENSSL_NO_STDIO */
+	}
+
+	return 0;
+}
+
+
+int tls_global_set_verify(void *ssl_ctx, int check_crl)
+{
+	int flags;
+
+	if (check_crl) {
+		X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx);
+		if (cs == NULL) {
+			tls_show_errors(MSG_INFO, __func__, "Failed to get "
+					"certificate store when enabling "
+					"check_crl");
+			return -1;
+		}
+		flags = X509_V_FLAG_CRL_CHECK;
+		if (check_crl == 2)
+			flags |= X509_V_FLAG_CRL_CHECK_ALL;
+		X509_STORE_set_flags(cs, flags);
+	}
+	return 0;
+}
+
+
+static int tls_connection_set_subject_match(struct tls_connection *conn,
+					    const char *subject_match,
+					    const char *altsubject_match)
+{
+	os_free(conn->subject_match);
+	conn->subject_match = NULL;
+	if (subject_match) {
+		conn->subject_match = os_strdup(subject_match);
+		if (conn->subject_match == NULL)
+			return -1;
+	}
+
+	os_free(conn->altsubject_match);
+	conn->altsubject_match = NULL;
+	if (altsubject_match) {
+		conn->altsubject_match = os_strdup(altsubject_match);
+		if (conn->altsubject_match == NULL)
+			return -1;
+	}
+
+	return 0;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+			      int verify_peer)
+{
+	static int counter = 0;
+
+	if (conn == NULL)
+		return -1;
+
+	if (verify_peer) {
+		conn->ca_cert_verify = 1;
+		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
+			       SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
+			       SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
+	} else {
+		conn->ca_cert_verify = 0;
+		SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
+	}
+
+	SSL_set_accept_state(conn->ssl);
+
+	/*
+	 * Set session id context in order to avoid fatal errors when client
+	 * tries to resume a session. However, set the context to a unique
+	 * value in order to effectively disable session resumption for now
+	 * since not all areas of the server code are ready for it (e.g.,
+	 * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS
+	 * handshake).
+	 */
+	counter++;
+	SSL_set_session_id_context(conn->ssl,
+				   (const unsigned char *) &counter,
+				   sizeof(counter));
+
+	return 0;
+}
+
+
+static int tls_connection_client_cert(struct tls_connection *conn,
+				      const char *client_cert,
+				      const u8 *client_cert_blob,
+				      size_t client_cert_blob_len)
+{
+	if (client_cert == NULL && client_cert_blob == NULL)
+		return 0;
+
+	if (client_cert_blob &&
+	    SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob,
+				     client_cert_blob_len) == 1) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> "
+			   "OK");
+		return 0;
+	} else if (client_cert_blob) {
+		tls_show_errors(MSG_DEBUG, __func__,
+				"SSL_use_certificate_ASN1 failed");
+	}
+
+	if (client_cert == NULL)
+		return -1;
+
+#ifdef ANDROID
+	if (os_strncmp("keystore://", client_cert, 11) == 0) {
+		BIO *bio = BIO_from_keystore(&client_cert[11]);
+		X509 *x509 = NULL;
+		int ret = -1;
+		if (bio) {
+			x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+			BIO_free(bio);
+		}
+		if (x509) {
+			if (SSL_use_certificate(conn->ssl, x509) == 1)
+				ret = 0;
+			X509_free(x509);
+		}
+		return ret;
+	}
+#endif /* ANDROID */
+
+#ifndef OPENSSL_NO_STDIO
+	if (SSL_use_certificate_file(conn->ssl, client_cert,
+				     SSL_FILETYPE_ASN1) == 1) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)"
+			   " --> OK");
+		return 0;
+	}
+
+	if (SSL_use_certificate_file(conn->ssl, client_cert,
+				     SSL_FILETYPE_PEM) == 1) {
+		ERR_clear_error();
+		wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)"
+			   " --> OK");
+		return 0;
+	}
+
+	tls_show_errors(MSG_DEBUG, __func__,
+			"SSL_use_certificate_file failed");
+#else /* OPENSSL_NO_STDIO */
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
+#endif /* OPENSSL_NO_STDIO */
+
+	return -1;
+}
+
+
+static int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert)
+{
+#ifndef OPENSSL_NO_STDIO
+	if (client_cert == NULL)
+		return 0;
+
+	if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
+					 SSL_FILETYPE_ASN1) != 1 &&
+	    SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert) != 1 &&
+	    SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
+					 SSL_FILETYPE_PEM) != 1) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to load client certificate");
+		return -1;
+	}
+	return 0;
+#else /* OPENSSL_NO_STDIO */
+	if (client_cert == NULL)
+		return 0;
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
+	return -1;
+#endif /* OPENSSL_NO_STDIO */
+}
+
+
+static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
+{
+	if (password == NULL) {
+		return 0;
+	}
+	os_strlcpy(buf, (char *) password, size);
+	return os_strlen(buf);
+}
+
+
+#ifdef PKCS12_FUNCS
+static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
+			    const char *passwd)
+{
+	EVP_PKEY *pkey;
+	X509 *cert;
+	STACK_OF(X509) *certs;
+	int res = 0;
+	char buf[256];
+
+	pkey = NULL;
+	cert = NULL;
+	certs = NULL;
+	if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) {
+		tls_show_errors(MSG_DEBUG, __func__,
+				"Failed to parse PKCS12 file");
+		PKCS12_free(p12);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data");
+
+	if (cert) {
+		X509_NAME_oneline(X509_get_subject_name(cert), buf,
+				  sizeof(buf));
+		wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: "
+			   "subject='%s'", buf);
+		if (ssl) {
+			if (SSL_use_certificate(ssl, cert) != 1)
+				res = -1;
+		} else {
+			if (SSL_CTX_use_certificate(ssl_ctx, cert) != 1)
+				res = -1;
+		}
+		X509_free(cert);
+	}
+
+	if (pkey) {
+		wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12");
+		if (ssl) {
+			if (SSL_use_PrivateKey(ssl, pkey) != 1)
+				res = -1;
+		} else {
+			if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1)
+				res = -1;
+		}
+		EVP_PKEY_free(pkey);
+	}
+
+	if (certs) {
+		while ((cert = sk_X509_pop(certs)) != NULL) {
+			X509_NAME_oneline(X509_get_subject_name(cert), buf,
+					  sizeof(buf));
+			wpa_printf(MSG_DEBUG, "TLS: additional certificate"
+				   " from PKCS12: subject='%s'", buf);
+			/*
+			 * There is no SSL equivalent for the chain cert - so
+			 * always add it to the context...
+			 */
+			if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) {
+				res = -1;
+				break;
+			}
+		}
+		sk_X509_free(certs);
+	}
+
+	PKCS12_free(p12);
+
+	if (res < 0)
+		tls_get_errors(ssl_ctx);
+
+	return res;
+}
+#endif  /* PKCS12_FUNCS */
+
+
+static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
+			   const char *passwd)
+{
+#ifdef PKCS12_FUNCS
+	FILE *f;
+	PKCS12 *p12;
+
+	f = fopen(private_key, "rb");
+	if (f == NULL)
+		return -1;
+
+	p12 = d2i_PKCS12_fp(f, NULL);
+	fclose(f);
+
+	if (p12 == NULL) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to use PKCS#12 file");
+		return -1;
+	}
+
+	return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
+
+#else /* PKCS12_FUNCS */
+	wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read "
+		   "p12/pfx files");
+	return -1;
+#endif  /* PKCS12_FUNCS */
+}
+
+
+static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
+				const u8 *blob, size_t len, const char *passwd)
+{
+#ifdef PKCS12_FUNCS
+	PKCS12 *p12;
+
+	p12 = d2i_PKCS12(NULL, (OPENSSL_d2i_TYPE) &blob, len);
+	if (p12 == NULL) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to use PKCS#12 blob");
+		return -1;
+	}
+
+	return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
+
+#else /* PKCS12_FUNCS */
+	wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse "
+		   "p12/pfx blobs");
+	return -1;
+#endif  /* PKCS12_FUNCS */
+}
+
+
+#ifndef OPENSSL_NO_ENGINE
+static int tls_engine_get_cert(struct tls_connection *conn,
+			       const char *cert_id,
+			       X509 **cert)
+{
+	/* this runs after the private key is loaded so no PIN is required */
+	struct {
+		const char *cert_id;
+		X509 *cert;
+	} params;
+	params.cert_id = cert_id;
+	params.cert = NULL;
+
+	if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL",
+			     0, &params, NULL, 1)) {
+		wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id"
+			   " '%s' [%s]", cert_id,
+			   ERR_error_string(ERR_get_error(), NULL));
+		return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+	}
+	if (!params.cert) {
+		wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id"
+			   " '%s'", cert_id);
+		return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+	}
+	*cert = params.cert;
+	return 0;
+}
+#endif /* OPENSSL_NO_ENGINE */
+
+
+static int tls_connection_engine_client_cert(struct tls_connection *conn,
+					     const char *cert_id)
+{
+#ifndef OPENSSL_NO_ENGINE
+	X509 *cert;
+
+	if (tls_engine_get_cert(conn, cert_id, &cert))
+		return -1;
+
+	if (!SSL_use_certificate(conn->ssl, cert)) {
+		tls_show_errors(MSG_ERROR, __func__,
+				"SSL_use_certificate failed");
+                X509_free(cert);
+		return -1;
+	}
+	X509_free(cert);
+	wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> "
+		   "OK");
+	return 0;
+
+#else /* OPENSSL_NO_ENGINE */
+	return -1;
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+static int tls_connection_engine_ca_cert(void *_ssl_ctx,
+					 struct tls_connection *conn,
+					 const char *ca_cert_id)
+{
+#ifndef OPENSSL_NO_ENGINE
+	X509 *cert;
+	SSL_CTX *ssl_ctx = _ssl_ctx;
+
+	if (tls_engine_get_cert(conn, ca_cert_id, &cert))
+		return -1;
+
+	/* start off the same as tls_connection_ca_cert */
+	X509_STORE_free(ssl_ctx->cert_store);
+	ssl_ctx->cert_store = X509_STORE_new();
+	if (ssl_ctx->cert_store == NULL) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
+			   "certificate store", __func__);
+		X509_free(cert);
+		return -1;
+	}
+	if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+		unsigned long err = ERR_peek_error();
+		tls_show_errors(MSG_WARNING, __func__,
+				"Failed to add CA certificate from engine "
+				"to certificate store");
+		if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
+		    ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert"
+				   " already in hash table error",
+				   __func__);
+		} else {
+			X509_free(cert);
+			return -1;
+		}
+	}
+	X509_free(cert);
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine "
+		   "to certificate store", __func__);
+	SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+	conn->ca_cert_verify = 1;
+
+	return 0;
+
+#else /* OPENSSL_NO_ENGINE */
+	return -1;
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+static int tls_connection_engine_private_key(struct tls_connection *conn)
+{
+#ifndef OPENSSL_NO_ENGINE
+	if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
+		tls_show_errors(MSG_ERROR, __func__,
+				"ENGINE: cannot use private key for TLS");
+		return -1;
+	}
+	if (!SSL_check_private_key(conn->ssl)) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Private key failed verification");
+		return -1;
+	}
+	return 0;
+#else /* OPENSSL_NO_ENGINE */
+	wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but "
+		   "engine support was not compiled in");
+	return -1;
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+static int tls_connection_private_key(void *_ssl_ctx,
+				      struct tls_connection *conn,
+				      const char *private_key,
+				      const char *private_key_passwd,
+				      const u8 *private_key_blob,
+				      size_t private_key_blob_len)
+{
+	SSL_CTX *ssl_ctx = _ssl_ctx;
+	char *passwd;
+	int ok;
+
+	if (private_key == NULL && private_key_blob == NULL)
+		return 0;
+
+	if (private_key_passwd) {
+		passwd = os_strdup(private_key_passwd);
+		if (passwd == NULL)
+			return -1;
+	} else
+		passwd = NULL;
+
+	SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
+	SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
+
+	ok = 0;
+	while (private_key_blob) {
+		if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
+					    (u8 *) private_key_blob,
+					    private_key_blob_len) == 1) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
+				   "ASN1(EVP_PKEY_RSA) --> OK");
+			ok = 1;
+			break;
+		}
+
+		if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl,
+					    (u8 *) private_key_blob,
+					    private_key_blob_len) == 1) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
+				   "ASN1(EVP_PKEY_DSA) --> OK");
+			ok = 1;
+			break;
+		}
+
+		if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
+					       (u8 *) private_key_blob,
+					       private_key_blob_len) == 1) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: "
+				   "SSL_use_RSAPrivateKey_ASN1 --> OK");
+			ok = 1;
+			break;
+		}
+
+		if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob,
+					 private_key_blob_len, passwd) == 0) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
+				   "OK");
+			ok = 1;
+			break;
+		}
+
+		break;
+	}
+
+#ifdef ANDROID
+	if (!ok && private_key &&
+	    os_strncmp("keystore://", private_key, 11) == 0) {
+		BIO *bio = BIO_from_keystore(&private_key[11]);
+		EVP_PKEY *pkey = NULL;
+		if (bio) {
+			pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+			BIO_free(bio);
+		}
+		if (pkey) {
+			if (SSL_use_PrivateKey(conn->ssl, pkey) == 1) {
+				wpa_printf(MSG_DEBUG, "OpenSSL: Private key "
+					   "from keystore");
+				ok = 1;
+			}
+			EVP_PKEY_free(pkey);
+		}
+	}
+#endif /* ANDROID */
+
+	while (!ok && private_key) {
+#ifndef OPENSSL_NO_STDIO
+		if (SSL_use_PrivateKey_file(conn->ssl, private_key,
+					    SSL_FILETYPE_ASN1) == 1) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: "
+				   "SSL_use_PrivateKey_File (DER) --> OK");
+			ok = 1;
+			break;
+		}
+
+		if (SSL_use_PrivateKey_file(conn->ssl, private_key,
+					    SSL_FILETYPE_PEM) == 1) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: "
+				   "SSL_use_PrivateKey_File (PEM) --> OK");
+			ok = 1;
+			break;
+		}
+#else /* OPENSSL_NO_STDIO */
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
+			   __func__);
+#endif /* OPENSSL_NO_STDIO */
+
+		if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd)
+		    == 0) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
+				   "--> OK");
+			ok = 1;
+			break;
+		}
+
+		if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to "
+				   "access certificate store --> OK");
+			ok = 1;
+			break;
+		}
+
+		break;
+	}
+
+	if (!ok) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to load private key");
+		os_free(passwd);
+		return -1;
+	}
+	ERR_clear_error();
+	SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
+	os_free(passwd);
+
+	if (!SSL_check_private_key(conn->ssl)) {
+		tls_show_errors(MSG_INFO, __func__, "Private key failed "
+				"verification");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully");
+	return 0;
+}
+
+
+static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key,
+				  const char *private_key_passwd)
+{
+	char *passwd;
+
+	if (private_key == NULL)
+		return 0;
+
+	if (private_key_passwd) {
+		passwd = os_strdup(private_key_passwd);
+		if (passwd == NULL)
+			return -1;
+	} else
+		passwd = NULL;
+
+	SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
+	SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
+	if (
+#ifndef OPENSSL_NO_STDIO
+	    SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
+					SSL_FILETYPE_ASN1) != 1 &&
+	    SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
+					SSL_FILETYPE_PEM) != 1 &&
+#endif /* OPENSSL_NO_STDIO */
+	    tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to load private key");
+		os_free(passwd);
+		ERR_clear_error();
+		return -1;
+	}
+	os_free(passwd);
+	ERR_clear_error();
+	SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
+
+	if (!SSL_CTX_check_private_key(ssl_ctx)) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Private key failed verification");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int tls_connection_dh(struct tls_connection *conn, const char *dh_file)
+{
+#ifdef OPENSSL_NO_DH
+	if (dh_file == NULL)
+		return 0;
+	wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
+		   "dh_file specified");
+	return -1;
+#else /* OPENSSL_NO_DH */
+	DH *dh;
+	BIO *bio;
+
+	/* TODO: add support for dh_blob */
+	if (dh_file == NULL)
+		return 0;
+	if (conn == NULL)
+		return -1;
+
+	bio = BIO_new_file(dh_file, "r");
+	if (bio == NULL) {
+		wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
+			   dh_file, ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+	dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+	BIO_free(bio);
+#ifndef OPENSSL_NO_DSA
+	while (dh == NULL) {
+		DSA *dsa;
+		wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
+			   " trying to parse as DSA params", dh_file,
+			   ERR_error_string(ERR_get_error(), NULL));
+		bio = BIO_new_file(dh_file, "r");
+		if (bio == NULL)
+			break;
+		dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
+		BIO_free(bio);
+		if (!dsa) {
+			wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
+				   "'%s': %s", dh_file,
+				   ERR_error_string(ERR_get_error(), NULL));
+			break;
+		}
+
+		wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
+		dh = DSA_dup_DH(dsa);
+		DSA_free(dsa);
+		if (dh == NULL) {
+			wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
+				   "params into DH params");
+			break;
+		}
+		break;
+	}
+#endif /* !OPENSSL_NO_DSA */
+	if (dh == NULL) {
+		wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
+			   "'%s'", dh_file);
+		return -1;
+	}
+
+	if (SSL_set_tmp_dh(conn->ssl, dh) != 1) {
+		wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
+			   "%s", dh_file,
+			   ERR_error_string(ERR_get_error(), NULL));
+		DH_free(dh);
+		return -1;
+	}
+	DH_free(dh);
+	return 0;
+#endif /* OPENSSL_NO_DH */
+}
+
+
+static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
+{
+#ifdef OPENSSL_NO_DH
+	if (dh_file == NULL)
+		return 0;
+	wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
+		   "dh_file specified");
+	return -1;
+#else /* OPENSSL_NO_DH */
+	DH *dh;
+	BIO *bio;
+
+	/* TODO: add support for dh_blob */
+	if (dh_file == NULL)
+		return 0;
+	if (ssl_ctx == NULL)
+		return -1;
+
+	bio = BIO_new_file(dh_file, "r");
+	if (bio == NULL) {
+		wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
+			   dh_file, ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+	dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+	BIO_free(bio);
+#ifndef OPENSSL_NO_DSA
+	while (dh == NULL) {
+		DSA *dsa;
+		wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
+			   " trying to parse as DSA params", dh_file,
+			   ERR_error_string(ERR_get_error(), NULL));
+		bio = BIO_new_file(dh_file, "r");
+		if (bio == NULL)
+			break;
+		dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
+		BIO_free(bio);
+		if (!dsa) {
+			wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
+				   "'%s': %s", dh_file,
+				   ERR_error_string(ERR_get_error(), NULL));
+			break;
+		}
+
+		wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
+		dh = DSA_dup_DH(dsa);
+		DSA_free(dsa);
+		if (dh == NULL) {
+			wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
+				   "params into DH params");
+			break;
+		}
+		break;
+	}
+#endif /* !OPENSSL_NO_DSA */
+	if (dh == NULL) {
+		wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
+			   "'%s'", dh_file);
+		return -1;
+	}
+
+	if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) {
+		wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
+			   "%s", dh_file,
+			   ERR_error_string(ERR_get_error(), NULL));
+		DH_free(dh);
+		return -1;
+	}
+	DH_free(dh);
+	return 0;
+#endif /* OPENSSL_NO_DH */
+}
+
+
+int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
+			    struct tls_keys *keys)
+{
+#ifdef CONFIG_FIPS
+	wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
+		   "mode");
+	return -1;
+#else /* CONFIG_FIPS */
+	SSL *ssl;
+
+	if (conn == NULL || keys == NULL)
+		return -1;
+	ssl = conn->ssl;
+	if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
+		return -1;
+
+	os_memset(keys, 0, sizeof(*keys));
+	keys->master_key = ssl->session->master_key;
+	keys->master_key_len = ssl->session->master_key_length;
+	keys->client_random = ssl->s3->client_random;
+	keys->client_random_len = SSL3_RANDOM_SIZE;
+	keys->server_random = ssl->s3->server_random;
+	keys->server_random_len = SSL3_RANDOM_SIZE;
+
+	return 0;
+#endif /* CONFIG_FIPS */
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+	SSL *ssl;
+	if (conn == NULL)
+		return -1;
+	if (server_random_first)
+		return -1;
+	ssl = conn->ssl;
+	if (SSL_export_keying_material(ssl, out, out_len, label,
+				       os_strlen(label), NULL, 0, 0) == 1) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF");
+		return 0;
+	}
+#endif
+	return -1;
+}
+
+
+static struct wpabuf *
+openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data,
+		  int server)
+{
+	int res;
+	struct wpabuf *out_data;
+
+	/*
+	 * Give TLS handshake data from the server (if available) to OpenSSL
+	 * for processing.
+	 */
+	if (in_data &&
+	    BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data))
+	    < 0) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Handshake failed - BIO_write");
+		return NULL;
+	}
+
+	/* Initiate TLS handshake or continue the existing handshake */
+	if (server)
+		res = SSL_accept(conn->ssl);
+	else
+		res = SSL_connect(conn->ssl);
+	if (res != 1) {
+		int err = SSL_get_error(conn->ssl, res);
+		if (err == SSL_ERROR_WANT_READ)
+			wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want "
+				   "more data");
+		else if (err == SSL_ERROR_WANT_WRITE)
+			wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to "
+				   "write");
+		else {
+			tls_show_errors(MSG_INFO, __func__, "SSL_connect");
+			conn->failed++;
+		}
+	}
+
+	/* Get the TLS handshake data to be sent to the server */
+	res = BIO_ctrl_pending(conn->ssl_out);
+	wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
+	out_data = wpabuf_alloc(res);
+	if (out_data == NULL) {
+		wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
+			   "handshake output (%d bytes)", res);
+		if (BIO_reset(conn->ssl_out) < 0) {
+			tls_show_errors(MSG_INFO, __func__,
+					"BIO_reset failed");
+		}
+		return NULL;
+	}
+	res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data),
+				      res);
+	if (res < 0) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Handshake failed - BIO_read");
+		if (BIO_reset(conn->ssl_out) < 0) {
+			tls_show_errors(MSG_INFO, __func__,
+					"BIO_reset failed");
+		}
+		wpabuf_free(out_data);
+		return NULL;
+	}
+	wpabuf_put(out_data, res);
+
+	return out_data;
+}
+
+
+static struct wpabuf *
+openssl_get_appl_data(struct tls_connection *conn, size_t max_len)
+{
+	struct wpabuf *appl_data;
+	int res;
+
+	appl_data = wpabuf_alloc(max_len + 100);
+	if (appl_data == NULL)
+		return NULL;
+
+	res = SSL_read(conn->ssl, wpabuf_mhead(appl_data),
+		       wpabuf_size(appl_data));
+	if (res < 0) {
+		int err = SSL_get_error(conn->ssl, res);
+		if (err == SSL_ERROR_WANT_READ ||
+		    err == SSL_ERROR_WANT_WRITE) {
+			wpa_printf(MSG_DEBUG, "SSL: No Application Data "
+				   "included");
+		} else {
+			tls_show_errors(MSG_INFO, __func__,
+					"Failed to read possible "
+					"Application Data");
+		}
+		wpabuf_free(appl_data);
+		return NULL;
+	}
+
+	wpabuf_put(appl_data, res);
+	wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished "
+			    "message", appl_data);
+
+	return appl_data;
+}
+
+
+static struct wpabuf *
+openssl_connection_handshake(struct tls_connection *conn,
+			     const struct wpabuf *in_data,
+			     struct wpabuf **appl_data, int server)
+{
+	struct wpabuf *out_data;
+
+	if (appl_data)
+		*appl_data = NULL;
+
+	out_data = openssl_handshake(conn, in_data, server);
+	if (out_data == NULL)
+		return NULL;
+
+	if (SSL_is_init_finished(conn->ssl) && appl_data && in_data)
+		*appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data));
+
+	return out_data;
+}
+
+
+struct wpabuf *
+tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
+			 const struct wpabuf *in_data,
+			 struct wpabuf **appl_data)
+{
+	return openssl_connection_handshake(conn, in_data, appl_data, 0);
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+						struct tls_connection *conn,
+						const struct wpabuf *in_data,
+						struct wpabuf **appl_data)
+{
+	return openssl_connection_handshake(conn, in_data, appl_data, 1);
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	int res;
+	struct wpabuf *buf;
+
+	if (conn == NULL)
+		return NULL;
+
+	/* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */
+	if ((res = BIO_reset(conn->ssl_in)) < 0 ||
+	    (res = BIO_reset(conn->ssl_out)) < 0) {
+		tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
+		return NULL;
+	}
+	res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data));
+	if (res < 0) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Encryption failed - SSL_write");
+		return NULL;
+	}
+
+	/* Read encrypted data to be sent to the server */
+	buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
+	if (buf == NULL)
+		return NULL;
+	res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf));
+	if (res < 0) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Encryption failed - BIO_read");
+		wpabuf_free(buf);
+		return NULL;
+	}
+	wpabuf_put(buf, res);
+
+	return buf;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	int res;
+	struct wpabuf *buf;
+
+	/* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */
+	res = BIO_write(conn->ssl_in, wpabuf_head(in_data),
+			wpabuf_len(in_data));
+	if (res < 0) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Decryption failed - BIO_write");
+		return NULL;
+	}
+	if (BIO_reset(conn->ssl_out) < 0) {
+		tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
+		return NULL;
+	}
+
+	/* Read decrypted data for further processing */
+	/*
+	 * Even though we try to disable TLS compression, it is possible that
+	 * this cannot be done with all TLS libraries. Add extra buffer space
+	 * to handle the possibility of the decrypted data being longer than
+	 * input data.
+	 */
+	buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
+	if (buf == NULL)
+		return NULL;
+	res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
+	if (res < 0) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Decryption failed - SSL_read");
+		wpabuf_free(buf);
+		return NULL;
+	}
+	wpabuf_put(buf, res);
+
+	return buf;
+}
+
+
+int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
+{
+	return conn ? conn->ssl->hit : 0;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
+{
+	char buf[100], *pos, *end;
+	u8 *c;
+	int ret;
+
+	if (conn == NULL || conn->ssl == NULL || ciphers == NULL)
+		return -1;
+
+	buf[0] = '\0';
+	pos = buf;
+	end = pos + sizeof(buf);
+
+	c = ciphers;
+	while (*c != TLS_CIPHER_NONE) {
+		const char *suite;
+
+		switch (*c) {
+		case TLS_CIPHER_RC4_SHA:
+			suite = "RC4-SHA";
+			break;
+		case TLS_CIPHER_AES128_SHA:
+			suite = "AES128-SHA";
+			break;
+		case TLS_CIPHER_RSA_DHE_AES128_SHA:
+			suite = "DHE-RSA-AES128-SHA";
+			break;
+		case TLS_CIPHER_ANON_DH_AES128_SHA:
+			suite = "ADH-AES128-SHA";
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "TLS: Unsupported "
+				   "cipher selection: %d", *c);
+			return -1;
+		}
+		ret = os_snprintf(pos, end - pos, ":%s", suite);
+		if (ret < 0 || ret >= end - pos)
+			break;
+		pos += ret;
+
+		c++;
+	}
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
+
+	if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Cipher suite configuration failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
+		   char *buf, size_t buflen)
+{
+	const char *name;
+	if (conn == NULL || conn->ssl == NULL)
+		return -1;
+
+	name = SSL_get_cipher(conn->ssl);
+	if (name == NULL)
+		return -1;
+
+	os_strlcpy(buf, name, buflen);
+	return 0;
+}
+
+
+int tls_connection_enable_workaround(void *ssl_ctx,
+				     struct tls_connection *conn)
+{
+	SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
+
+	return 0;
+}
+
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+/* ClientHello TLS extensions require a patch to openssl, so this function is
+ * commented out unless explicitly needed for EAP-FAST in order to be able to
+ * build this file with unmodified openssl. */
+int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
+				    int ext_type, const u8 *data,
+				    size_t data_len)
+{
+	if (conn == NULL || conn->ssl == NULL || ext_type != 35)
+		return -1;
+
+#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
+	if (SSL_set_session_ticket_ext(conn->ssl, (void *) data,
+				       data_len) != 1)
+		return -1;
+#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+	if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data,
+				    data_len) != 1)
+		return -1;
+#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+
+	return 0;
+}
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+
+
+int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->failed;
+}
+
+
+int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->read_alerts;
+}
+
+
+int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->write_alerts;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+	int ret;
+	unsigned long err;
+
+	if (conn == NULL)
+		return -1;
+
+	while ((err = ERR_get_error())) {
+		wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
+			   __func__, ERR_error_string(err, NULL));
+	}
+
+	if (params->engine) {
+		wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
+		ret = tls_engine_init(conn, params->engine_id, params->pin,
+				      params->key_id, params->cert_id,
+				      params->ca_cert_id);
+		if (ret)
+			return ret;
+	}
+	if (tls_connection_set_subject_match(conn,
+					     params->subject_match,
+					     params->altsubject_match))
+		return -1;
+
+	if (params->engine && params->ca_cert_id) {
+		if (tls_connection_engine_ca_cert(tls_ctx, conn,
+						  params->ca_cert_id))
+			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
+	} else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+					  params->ca_cert_blob,
+					  params->ca_cert_blob_len,
+					  params->ca_path))
+		return -1;
+
+	if (params->engine && params->cert_id) {
+		if (tls_connection_engine_client_cert(conn, params->cert_id))
+			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
+	} else if (tls_connection_client_cert(conn, params->client_cert,
+					      params->client_cert_blob,
+					      params->client_cert_blob_len))
+		return -1;
+
+	if (params->engine && params->key_id) {
+		wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
+		if (tls_connection_engine_private_key(conn))
+			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
+	} else if (tls_connection_private_key(tls_ctx, conn,
+					      params->private_key,
+					      params->private_key_passwd,
+					      params->private_key_blob,
+					      params->private_key_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'",
+			   params->private_key);
+		return -1;
+	}
+
+	if (tls_connection_dh(conn, params->dh_file)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
+			   params->dh_file);
+		return -1;
+	}
+
+#ifdef SSL_OP_NO_TICKET
+	if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
+		SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
+	else
+		SSL_clear_options(conn->ssl, SSL_OP_NO_TICKET);
+#endif /*  SSL_OP_NO_TICKET */
+
+	conn->flags = params->flags;
+
+	tls_get_errors(tls_ctx);
+
+	return 0;
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+	SSL_CTX *ssl_ctx = tls_ctx;
+	unsigned long err;
+
+	while ((err = ERR_get_error())) {
+		wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
+			   __func__, ERR_error_string(err, NULL));
+	}
+
+	if (tls_global_ca_cert(ssl_ctx, params->ca_cert))
+		return -1;
+
+	if (tls_global_client_cert(ssl_ctx, params->client_cert))
+		return -1;
+
+	if (tls_global_private_key(ssl_ctx, params->private_key,
+				   params->private_key_passwd))
+		return -1;
+
+	if (tls_global_dh(ssl_ctx, params->dh_file)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
+			   params->dh_file);
+		return -1;
+	}
+
+#ifdef SSL_OP_NO_TICKET
+	if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
+		SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
+	else
+		SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
+#endif /*  SSL_OP_NO_TICKET */
+
+	return 0;
+}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	const EVP_CIPHER *c;
+	const EVP_MD *h;
+	int md_size;
+
+	if (conn == NULL || conn->ssl == NULL ||
+	    conn->ssl->enc_read_ctx == NULL ||
+	    conn->ssl->enc_read_ctx->cipher == NULL ||
+	    conn->ssl->read_hash == NULL)
+		return -1;
+
+	c = conn->ssl->enc_read_ctx->cipher;
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+	h = EVP_MD_CTX_md(conn->ssl->read_hash);
+#else
+	h = conn->ssl->read_hash;
+#endif
+	if (h)
+		md_size = EVP_MD_size(h);
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+	else if (conn->ssl->s3)
+		md_size = conn->ssl->s3->tmp.new_mac_secret_size;
+#endif
+	else
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d "
+		   "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
+		   EVP_CIPHER_iv_length(c));
+	return 2 * (EVP_CIPHER_key_length(c) +
+		    md_size +
+		    EVP_CIPHER_iv_length(c));
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+	return 0;
+}
+
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+/* Pre-shared secred requires a patch to openssl, so this function is
+ * commented out unless explicitly needed for EAP-FAST in order to be able to
+ * build this file with unmodified openssl. */
+
+static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
+			   STACK_OF(SSL_CIPHER) *peer_ciphers,
+			   SSL_CIPHER **cipher, void *arg)
+{
+	struct tls_connection *conn = arg;
+	int ret;
+
+	if (conn == NULL || conn->session_ticket_cb == NULL)
+		return 0;
+
+	ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
+				      conn->session_ticket,
+				      conn->session_ticket_len,
+				      s->s3->client_random,
+				      s->s3->server_random, secret);
+	os_free(conn->session_ticket);
+	conn->session_ticket = NULL;
+
+	if (ret <= 0)
+		return 0;
+
+	*secret_len = SSL_MAX_MASTER_KEY_LENGTH;
+	return 1;
+}
+
+
+#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
+static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
+				     int len, void *arg)
+{
+	struct tls_connection *conn = arg;
+
+	if (conn == NULL || conn->session_ticket_cb == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len);
+
+	os_free(conn->session_ticket);
+	conn->session_ticket = NULL;
+
+	wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
+		    "extension", data, len);
+
+	conn->session_ticket = os_malloc(len);
+	if (conn->session_ticket == NULL)
+		return 0;
+
+	os_memcpy(conn->session_ticket, data, len);
+	conn->session_ticket_len = len;
+
+	return 1;
+}
+#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+#ifdef SSL_OP_NO_TICKET
+static void tls_hello_ext_cb(SSL *s, int client_server, int type,
+			     unsigned char *data, int len, void *arg)
+{
+	struct tls_connection *conn = arg;
+
+	if (conn == NULL || conn->session_ticket_cb == NULL)
+		return;
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
+		   type, len);
+
+	if (type == TLSEXT_TYPE_session_ticket && !client_server) {
+		os_free(conn->session_ticket);
+		conn->session_ticket = NULL;
+
+		wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
+			    "extension", data, len);
+		conn->session_ticket = os_malloc(len);
+		if (conn->session_ticket == NULL)
+			return;
+
+		os_memcpy(conn->session_ticket, data, len);
+		conn->session_ticket_len = len;
+	}
+}
+#else /* SSL_OP_NO_TICKET */
+static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg)
+{
+	struct tls_connection *conn = arg;
+
+	if (conn == NULL || conn->session_ticket_cb == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
+		   ext->type, ext->length);
+
+	os_free(conn->session_ticket);
+	conn->session_ticket = NULL;
+
+	if (ext->type == 35) {
+		wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
+			    "extension", ext->data, ext->length);
+		conn->session_ticket = os_malloc(ext->length);
+		if (conn->session_ticket == NULL)
+			return SSL_AD_INTERNAL_ERROR;
+
+		os_memcpy(conn->session_ticket, ext->data, ext->length);
+		conn->session_ticket_len = ext->length;
+	}
+
+	return 0;
+}
+#endif /* SSL_OP_NO_TICKET */
+#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+					 struct tls_connection *conn,
+					 tls_session_ticket_cb cb,
+					 void *ctx)
+{
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+	conn->session_ticket_cb = cb;
+	conn->session_ticket_cb_ctx = ctx;
+
+	if (cb) {
+		if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
+					      conn) != 1)
+			return -1;
+#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
+		SSL_set_session_ticket_ext_cb(conn->ssl,
+					      tls_session_ticket_ext_cb, conn);
+#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+#ifdef SSL_OP_NO_TICKET
+		SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb);
+		SSL_set_tlsext_debug_arg(conn->ssl, conn);
+#else /* SSL_OP_NO_TICKET */
+		if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb,
+					       conn) != 1)
+			return -1;
+#endif /* SSL_OP_NO_TICKET */
+#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+	} else {
+		if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
+			return -1;
+#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
+		SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL);
+#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+#ifdef SSL_OP_NO_TICKET
+		SSL_set_tlsext_debug_callback(conn->ssl, NULL);
+		SSL_set_tlsext_debug_arg(conn->ssl, conn);
+#else /* SSL_OP_NO_TICKET */
+		if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1)
+			return -1;
+#endif /* SSL_OP_NO_TICKET */
+#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+	}
+
+	return 0;
+#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+	return -1;
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/drivers/driver.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,3732 @@
+/*
+ * Driver interface definition
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file defines a driver interface used by both %wpa_supplicant and
+ * hostapd. The first part of the file defines data structures used in various
+ * driver operations. This is followed by the struct wpa_driver_ops that each
+ * driver wrapper will beed to define with callback functions for requesting
+ * driver operations. After this, there are definitions for driver event
+ * reporting with wpa_supplicant_event() and some convenience helper functions
+ * that can be used to report events.
+ */
+
+#ifndef DRIVER_H
+#define DRIVER_H
+
+#define WPA_SUPPLICANT_DRIVER_VERSION 4
+
+#include "common/defs.h"
+
+#define HOSTAPD_CHAN_DISABLED 0x00000001
+#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
+#define HOSTAPD_CHAN_NO_IBSS 0x00000004
+#define HOSTAPD_CHAN_RADAR 0x00000008
+#define HOSTAPD_CHAN_HT40PLUS 0x00000010
+#define HOSTAPD_CHAN_HT40MINUS 0x00000020
+#define HOSTAPD_CHAN_HT40 0x00000040
+
+/**
+ * struct hostapd_channel_data - Channel information
+ */
+struct hostapd_channel_data {
+	/**
+	 * chan - Channel number (IEEE 802.11)
+	 */
+	short chan;
+
+	/**
+	 * freq - Frequency in MHz
+	 */
+	int freq;
+
+	/**
+	 * flag - Channel flags (HOSTAPD_CHAN_*)
+	 */
+	int flag;
+
+	/**
+	 * max_tx_power - maximum transmit power in dBm
+	 */
+	u8 max_tx_power;
+};
+
+#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
+
+/**
+ * struct hostapd_hw_modes - Supported hardware mode information
+ */
+struct hostapd_hw_modes {
+	/**
+	 * mode - Hardware mode
+	 */
+	enum hostapd_hw_mode mode;
+
+	/**
+	 * num_channels - Number of entries in the channels array
+	 */
+	int num_channels;
+
+	/**
+	 * channels - Array of supported channels
+	 */
+	struct hostapd_channel_data *channels;
+
+	/**
+	 * num_rates - Number of entries in the rates array
+	 */
+	int num_rates;
+
+	/**
+	 * rates - Array of supported rates in 100 kbps units
+	 */
+	int *rates;
+
+	/**
+	 * ht_capab - HT (IEEE 802.11n) capabilities
+	 */
+	u16 ht_capab;
+
+	/**
+	 * mcs_set - MCS (IEEE 802.11n) rate parameters
+	 */
+	u8 mcs_set[16];
+
+	/**
+	 * a_mpdu_params - A-MPDU (IEEE 802.11n) parameters
+	 */
+	u8 a_mpdu_params;
+
+	/**
+	 * vht_capab - VHT (IEEE 802.11ac) capabilities
+	 */
+	u32 vht_capab;
+
+	/**
+	 * vht_mcs_set - VHT MCS (IEEE 802.11ac) rate parameters
+	 */
+	u8 vht_mcs_set[8];
+
+	unsigned int flags; /* HOSTAPD_MODE_FLAG_* */
+};
+
+
+#define IEEE80211_MODE_INFRA	0
+#define IEEE80211_MODE_IBSS	1
+#define IEEE80211_MODE_AP	2
+
+#define IEEE80211_CAP_ESS	0x0001
+#define IEEE80211_CAP_IBSS	0x0002
+#define IEEE80211_CAP_PRIVACY	0x0010
+
+#define WPA_SCAN_QUAL_INVALID		BIT(0)
+#define WPA_SCAN_NOISE_INVALID		BIT(1)
+#define WPA_SCAN_LEVEL_INVALID		BIT(2)
+#define WPA_SCAN_LEVEL_DBM		BIT(3)
+#define WPA_SCAN_AUTHENTICATED		BIT(4)
+#define WPA_SCAN_ASSOCIATED		BIT(5)
+
+/**
+ * struct wpa_scan_res - Scan result for an BSS/IBSS
+ * @flags: information flags about the BSS/IBSS (WPA_SCAN_*)
+ * @bssid: BSSID
+ * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
+ * @beacon_int: beacon interval in TUs (host byte order)
+ * @caps: capability information field in host byte order
+ * @qual: signal quality
+ * @noise: noise level
+ * @level: signal level
+ * @tsf: Timestamp
+ * @age: Age of the information in milliseconds (i.e., how many milliseconds
+ * ago the last Beacon or Probe Response frame was received)
+ * @ie_len: length of the following IE field in octets
+ * @beacon_ie_len: length of the following Beacon IE field in octets
+ *
+ * This structure is used as a generic format for scan results from the
+ * driver. Each driver interface implementation is responsible for converting
+ * the driver or OS specific scan results into this format.
+ *
+ * If the driver does not support reporting all IEs, the IE data structure is
+ * constructed of the IEs that are available. This field will also need to
+ * include SSID in IE format. All drivers are encouraged to be extended to
+ * report all IEs to make it easier to support future additions.
+ */
+struct wpa_scan_res {
+	unsigned int flags;
+	u8 bssid[ETH_ALEN];
+	int freq;
+	u16 beacon_int;
+	u16 caps;
+	int qual;
+	int noise;
+	int level;
+	u64 tsf;
+	unsigned int age;
+	size_t ie_len;
+	size_t beacon_ie_len;
+	/*
+	 * Followed by ie_len octets of IEs from Probe Response frame (or if
+	 * the driver does not indicate source of IEs, these may also be from
+	 * Beacon frame). After the first set of IEs, another set of IEs may
+	 * follow (with beacon_ie_len octets of data) if the driver provides
+	 * both IE sets.
+	 */
+};
+
+/**
+ * struct wpa_scan_results - Scan results
+ * @res: Array of pointers to allocated variable length scan result entries
+ * @num: Number of entries in the scan result array
+ */
+struct wpa_scan_results {
+	struct wpa_scan_res **res;
+	size_t num;
+};
+
+/**
+ * struct wpa_interface_info - Network interface information
+ * @next: Pointer to the next interface or NULL if this is the last one
+ * @ifname: Interface name that can be used with init() or init2()
+ * @desc: Human readable adapter description (e.g., vendor/model) or NULL if
+ *	not available
+ * @drv_name: struct wpa_driver_ops::name (note: unlike other strings, this one
+ *	is not an allocated copy, i.e., get_interfaces() caller will not free
+ *	this)
+ */
+struct wpa_interface_info {
+	struct wpa_interface_info *next;
+	char *ifname;
+	char *desc;
+	const char *drv_name;
+};
+
+#define WPAS_MAX_SCAN_SSIDS 16
+
+/**
+ * struct wpa_driver_scan_params - Scan parameters
+ * Data for struct wpa_driver_ops::scan2().
+ */
+struct wpa_driver_scan_params {
+	/**
+	 * ssids - SSIDs to scan for
+	 */
+	struct wpa_driver_scan_ssid {
+		/**
+		 * ssid - specific SSID to scan for (ProbeReq)
+		 * %NULL or zero-length SSID is used to indicate active scan
+		 * with wildcard SSID.
+		 */
+		const u8 *ssid;
+		/**
+		 * ssid_len: Length of the SSID in octets
+		 */
+		size_t ssid_len;
+	} ssids[WPAS_MAX_SCAN_SSIDS];
+
+	/**
+	 * num_ssids - Number of entries in ssids array
+	 * Zero indicates a request for a passive scan.
+	 */
+	size_t num_ssids;
+
+	/**
+	 * extra_ies - Extra IE(s) to add into Probe Request or %NULL
+	 */
+	const u8 *extra_ies;
+
+	/**
+	 * extra_ies_len - Length of extra_ies in octets
+	 */
+	size_t extra_ies_len;
+
+	/**
+	 * freqs - Array of frequencies to scan or %NULL for all frequencies
+	 *
+	 * The frequency is set in MHz. The array is zero-terminated.
+	 */
+	int *freqs;
+
+	/**
+	 * filter_ssids - Filter for reporting SSIDs
+	 *
+	 * This optional parameter can be used to request the driver wrapper to
+	 * filter scan results to include only the specified SSIDs. %NULL
+	 * indicates that no filtering is to be done. This can be used to
+	 * reduce memory needs for scan results in environments that have large
+	 * number of APs with different SSIDs.
+	 *
+	 * The driver wrapper is allowed to take this allocated buffer into its
+	 * own use by setting the pointer to %NULL. In that case, the driver
+	 * wrapper is responsible for freeing the buffer with os_free() once it
+	 * is not needed anymore.
+	 */
+	struct wpa_driver_scan_filter {
+		u8 ssid[32];
+		size_t ssid_len;
+	} *filter_ssids;
+
+	/**
+	 * num_filter_ssids - Number of entries in filter_ssids array
+	 */
+	size_t num_filter_ssids;
+
+	/**
+	 * filter_rssi - Filter by RSSI
+	 *
+	 * The driver may filter scan results in firmware to reduce host
+	 * wakeups and thereby save power. Specify the RSSI threshold in s32
+	 * dBm.
+	 */
+	s32 filter_rssi;
+
+	/**
+	 * p2p_probe - Used to disable CCK (802.11b) rates for P2P probes
+	 *
+	 * When set, the driver is expected to remove rates 1, 2, 5.5, and 11
+	 * Mbps from the support rates element(s) in the Probe Request frames
+	 * and not to transmit the frames at any of those rates.
+	 */
+	u8 p2p_probe;
+};
+
+/**
+ * struct wpa_driver_auth_params - Authentication parameters
+ * Data for struct wpa_driver_ops::authenticate().
+ */
+struct wpa_driver_auth_params {
+	int freq;
+	const u8 *bssid;
+	const u8 *ssid;
+	size_t ssid_len;
+	int auth_alg;
+	const u8 *ie;
+	size_t ie_len;
+	const u8 *wep_key[4];
+	size_t wep_key_len[4];
+	int wep_tx_keyidx;
+	int local_state_change;
+
+	/**
+	 * p2p - Whether this connection is a P2P group
+	 */
+	int p2p;
+
+	const u8 *sae_data;
+	size_t sae_data_len;
+
+};
+
+enum wps_mode {
+	WPS_MODE_NONE /* no WPS provisioning being used */,
+	WPS_MODE_OPEN /* WPS provisioning with AP that is in open mode */,
+	WPS_MODE_PRIVACY /* WPS provisioning with AP that is using protection
+			  */
+};
+
+/**
+ * struct wpa_driver_associate_params - Association parameters
+ * Data for struct wpa_driver_ops::associate().
+ */
+struct wpa_driver_associate_params {
+	/**
+	 * bssid - BSSID of the selected AP
+	 * This can be %NULL, if ap_scan=2 mode is used and the driver is
+	 * responsible for selecting with which BSS to associate. */
+	const u8 *bssid;
+
+	/**
+	 * ssid - The selected SSID
+	 */
+	const u8 *ssid;
+
+	/**
+	 * ssid_len - Length of the SSID (1..32)
+	 */
+	size_t ssid_len;
+
+	/**
+	 * freq - Frequency of the channel the selected AP is using
+	 * Frequency that the selected AP is using (in MHz as
+	 * reported in the scan results)
+	 */
+	int freq;
+
+	/**
+	 * bg_scan_period - Background scan period in seconds, 0 to disable
+	 * background scan, or -1 to indicate no change to default driver
+	 * configuration
+	 */
+	int bg_scan_period;
+
+	/**
+	 * wpa_ie - WPA information element for (Re)Association Request
+	 * WPA information element to be included in (Re)Association
+	 * Request (including information element id and length). Use
+	 * of this WPA IE is optional. If the driver generates the WPA
+	 * IE, it can use pairwise_suite, group_suite, and
+	 * key_mgmt_suite to select proper algorithms. In this case,
+	 * the driver has to notify wpa_supplicant about the used WPA
+	 * IE by generating an event that the interface code will
+	 * convert into EVENT_ASSOCINFO data (see below).
+	 *
+	 * When using WPA2/IEEE 802.11i, wpa_ie is used for RSN IE
+	 * instead. The driver can determine which version is used by
+	 * looking at the first byte of the IE (0xdd for WPA, 0x30 for
+	 * WPA2/RSN).
+	 *
+	 * When using WPS, wpa_ie is used for WPS IE instead of WPA/RSN IE.
+	 */
+	const u8 *wpa_ie;
+
+	/**
+	 * wpa_ie_len - length of the wpa_ie
+	 */
+	size_t wpa_ie_len;
+
+	/**
+	 * wpa_proto - Bitfield of WPA_PROTO_* values to indicate WPA/WPA2
+	 */
+	unsigned int wpa_proto;
+
+	/**
+	 * pairwise_suite - Selected pairwise cipher suite
+	 *
+	 * This is usually ignored if @wpa_ie is used.
+	 */
+	enum wpa_cipher pairwise_suite;
+
+	/**
+	 * group_suite - Selected group cipher suite
+	 *
+	 * This is usually ignored if @wpa_ie is used.
+	 */
+	enum wpa_cipher group_suite;
+
+	/**
+	 * key_mgmt_suite - Selected key management suite
+	 *
+	 * This is usually ignored if @wpa_ie is used.
+	 */
+	enum wpa_key_mgmt key_mgmt_suite;
+
+	/**
+	 * auth_alg - Allowed authentication algorithms
+	 * Bit field of WPA_AUTH_ALG_*
+	 */
+	int auth_alg;
+
+	/**
+	 * mode - Operation mode (infra/ibss) IEEE80211_MODE_*
+	 */
+	int mode;
+
+	/**
+	 * wep_key - WEP keys for static WEP configuration
+	 */
+	const u8 *wep_key[4];
+
+	/**
+	 * wep_key_len - WEP key length for static WEP configuration
+	 */
+	size_t wep_key_len[4];
+
+	/**
+	 * wep_tx_keyidx - WEP TX key index for static WEP configuration
+	 */
+	int wep_tx_keyidx;
+
+	/**
+	 * mgmt_frame_protection - IEEE 802.11w management frame protection
+	 */
+	enum mfp_options mgmt_frame_protection;
+
+	/**
+	 * ft_ies - IEEE 802.11r / FT information elements
+	 * If the supplicant is using IEEE 802.11r (FT) and has the needed keys
+	 * for fast transition, this parameter is set to include the IEs that
+	 * are to be sent in the next FT Authentication Request message.
+	 * update_ft_ies() handler is called to update the IEs for further
+	 * FT messages in the sequence.
+	 *
+	 * The driver should use these IEs only if the target AP is advertising
+	 * the same mobility domain as the one included in the MDIE here.
+	 *
+	 * In ap_scan=2 mode, the driver can use these IEs when moving to a new
+	 * AP after the initial association. These IEs can only be used if the
+	 * target AP is advertising support for FT and is using the same MDIE
+	 * and SSID as the current AP.
+	 *
+	 * The driver is responsible for reporting the FT IEs received from the
+	 * AP's response using wpa_supplicant_event() with EVENT_FT_RESPONSE
+	 * type. update_ft_ies() handler will then be called with the FT IEs to
+	 * include in the next frame in the authentication sequence.
+	 */
+	const u8 *ft_ies;
+
+	/**
+	 * ft_ies_len - Length of ft_ies in bytes
+	 */
+	size_t ft_ies_len;
+
+	/**
+	 * ft_md - FT Mobility domain (6 octets) (also included inside ft_ies)
+	 *
+	 * This value is provided to allow the driver interface easier access
+	 * to the current mobility domain. This value is set to %NULL if no
+	 * mobility domain is currently active.
+	 */
+	const u8 *ft_md;
+
+	/**
+	 * passphrase - RSN passphrase for PSK
+	 *
+	 * This value is made available only for WPA/WPA2-Personal (PSK) and
+	 * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is
+	 * the 8..63 character ASCII passphrase, if available. Please note that
+	 * this can be %NULL if passphrase was not used to generate the PSK. In
+	 * that case, the psk field must be used to fetch the PSK.
+	 */
+	const char *passphrase;
+
+	/**
+	 * psk - RSN PSK (alternative for passphrase for PSK)
+	 *
+	 * This value is made available only for WPA/WPA2-Personal (PSK) and
+	 * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is
+	 * the 32-octet (256-bit) PSK, if available. The driver wrapper should
+	 * be prepared to handle %NULL value as an error.
+	 */
+	const u8 *psk;
+
+	/**
+	 * drop_unencrypted - Enable/disable unencrypted frame filtering
+	 *
+	 * Configure the driver to drop all non-EAPOL frames (both receive and
+	 * transmit paths). Unencrypted EAPOL frames (ethertype 0x888e) must
+	 * still be allowed for key negotiation.
+	 */
+	int drop_unencrypted;
+
+	/**
+	 * prev_bssid - Previously used BSSID in this ESS
+	 *
+	 * When not %NULL, this is a request to use reassociation instead of
+	 * association.
+	 */
+	const u8 *prev_bssid;
+
+	/**
+	 * wps - WPS mode
+	 *
+	 * If the driver needs to do special configuration for WPS association,
+	 * this variable provides more information on what type of association
+	 * is being requested. Most drivers should not need ot use this.
+	 */
+	enum wps_mode wps;
+
+	/**
+	 * p2p - Whether this connection is a P2P group
+	 */
+	int p2p;
+
+	/**
+	 * uapsd - UAPSD parameters for the network
+	 * -1 = do not change defaults
+	 * AP mode: 1 = enabled, 0 = disabled
+	 * STA mode: bits 0..3 UAPSD enabled for VO,VI,BK,BE
+	 */
+	int uapsd;
+
+	/**
+	 * fixed_bssid - Whether to force this BSSID in IBSS mode
+	 * 1 = Fix this BSSID and prevent merges.
+	 * 0 = Do not fix BSSID.
+	 */
+	int fixed_bssid;
+
+	/**
+	 * disable_ht - Disable HT (IEEE 802.11n) for this connection
+	 */
+	int disable_ht;
+
+	/**
+	 * HT Capabilities over-rides. Only bits set in the mask will be used,
+	 * and not all values are used by the kernel anyway. Currently, MCS,
+	 * MPDU and MSDU fields are used.
+	 */
+	const u8 *htcaps;       /* struct ieee80211_ht_capabilities * */
+	const u8 *htcaps_mask;  /* struct ieee80211_ht_capabilities * */
+};
+
+enum hide_ssid {
+	NO_SSID_HIDING,
+	HIDDEN_SSID_ZERO_LEN,
+	HIDDEN_SSID_ZERO_CONTENTS
+};
+
+struct wpa_driver_ap_params {
+	/**
+	 * head - Beacon head from IEEE 802.11 header to IEs before TIM IE
+	 */
+	const u8 *head;
+
+	/**
+	 * head_len - Length of the head buffer in octets
+	 */
+	size_t head_len;
+
+	/**
+	 * tail - Beacon tail following TIM IE
+	 */
+	const u8 *tail;
+
+	/**
+	 * tail_len - Length of the tail buffer in octets
+	 */
+	size_t tail_len;
+
+	/**
+	 * dtim_period - DTIM period
+	 */
+	int dtim_period;
+
+	/**
+	 * beacon_int - Beacon interval
+	 */
+	int beacon_int;
+
+	/**
+	 * basic_rates: -1 terminated array of basic rates in 100 kbps
+	 *
+	 * This parameter can be used to set a specific basic rate set for the
+	 * BSS. If %NULL, default basic rate set is used.
+	 */
+	int *basic_rates;
+
+	/**
+	 * proberesp - Probe Response template
+	 *
+	 * This is used by drivers that reply to Probe Requests internally in
+	 * AP mode and require the full Probe Response template.
+	 */
+	const u8 *proberesp;
+
+	/**
+	 * proberesp_len - Length of the proberesp buffer in octets
+	 */
+	size_t proberesp_len;
+
+	/**
+	 * ssid - The SSID to use in Beacon/Probe Response frames
+	 */
+	const u8 *ssid;
+
+	/**
+	 * ssid_len - Length of the SSID (1..32)
+	 */
+	size_t ssid_len;
+
+	/**
+	 * hide_ssid - Whether to hide the SSID
+	 */
+	enum hide_ssid hide_ssid;
+
+	/**
+	 * pairwise_ciphers - WPA_CIPHER_* bitfield
+	 */
+	unsigned int pairwise_ciphers;
+
+	/**
+	 * group_cipher - WPA_CIPHER_*
+	 */
+	unsigned int group_cipher;
+
+	/**
+	 * key_mgmt_suites - WPA_KEY_MGMT_* bitfield
+	 */
+	unsigned int key_mgmt_suites;
+
+	/**
+	 * auth_algs - WPA_AUTH_ALG_* bitfield
+	 */
+	unsigned int auth_algs;
+
+	/**
+	 * wpa_version - WPA_PROTO_* bitfield
+	 */
+	unsigned int wpa_version;
+
+	/**
+	 * privacy - Whether privacy is used in the BSS
+	 */
+	int privacy;
+
+	/**
+	 * beacon_ies - WPS/P2P IE(s) for Beacon frames
+	 *
+	 * This is used to add IEs like WPS IE and P2P IE by drivers that do
+	 * not use the full Beacon template.
+	 */
+	const struct wpabuf *beacon_ies;
+
+	/**
+	 * proberesp_ies - P2P/WPS IE(s) for Probe Response frames
+	 *
+	 * This is used to add IEs like WPS IE and P2P IE by drivers that
+	 * reply to Probe Request frames internally.
+	 */
+	const struct wpabuf *proberesp_ies;
+
+	/**
+	 * assocresp_ies - WPS IE(s) for (Re)Association Response frames
+	 *
+	 * This is used to add IEs like WPS IE by drivers that reply to
+	 * (Re)Association Request frames internally.
+	 */
+	const struct wpabuf *assocresp_ies;
+
+	/**
+	 * isolate - Whether to isolate frames between associated stations
+	 *
+	 * If this is non-zero, the AP is requested to disable forwarding of
+	 * frames between associated stations.
+	 */
+	int isolate;
+
+	/**
+	 * cts_protect - Whether CTS protection is enabled
+	 */
+	int cts_protect;
+
+	/**
+	 * preamble - Whether short preamble is enabled
+	 */
+	int preamble;
+
+	/**
+	 * short_slot_time - Whether short slot time is enabled
+	 *
+	 * 0 = short slot time disable, 1 = short slot time enabled, -1 = do
+	 * not set (e.g., when 802.11g mode is not in use)
+	 */
+	int short_slot_time;
+
+	/**
+	 * ht_opmode - HT operation mode or -1 if HT not in use
+	 */
+	int ht_opmode;
+
+	/**
+	 * interworking - Whether Interworking is enabled
+	 */
+	int interworking;
+
+	/**
+	 * hessid - Homogeneous ESS identifier or %NULL if not set
+	 */
+	const u8 *hessid;
+
+	/**
+	 * access_network_type - Access Network Type (0..15)
+	 *
+	 * This is used for filtering Probe Request frames when Interworking is
+	 * enabled.
+	 */
+	u8 access_network_type;
+
+	/**
+	 * ap_max_inactivity - Timeout in seconds to detect STA's inactivity
+	 *
+	 * This is used by driver which advertises this capability.
+	 */
+	int ap_max_inactivity;
+
+	/**
+	 * disable_dgaf - Whether group-addressed frames are disabled
+	 */
+	int disable_dgaf;
+};
+
+/**
+ * struct wpa_driver_capa - Driver capability information
+ */
+struct wpa_driver_capa {
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA		0x00000001
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2		0x00000002
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK	0x00000004
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK	0x00000008
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE	0x00000010
+#define WPA_DRIVER_CAPA_KEY_MGMT_FT		0x00000020
+#define WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK		0x00000040
+#define WPA_DRIVER_CAPA_KEY_MGMT_WAPI_PSK	0x00000080
+	unsigned int key_mgmt;
+
+#define WPA_DRIVER_CAPA_ENC_WEP40	0x00000001
+#define WPA_DRIVER_CAPA_ENC_WEP104	0x00000002
+#define WPA_DRIVER_CAPA_ENC_TKIP	0x00000004
+#define WPA_DRIVER_CAPA_ENC_CCMP	0x00000008
+#define WPA_DRIVER_CAPA_ENC_WEP128	0x00000010
+#define WPA_DRIVER_CAPA_ENC_GCMP	0x00000020
+	unsigned int enc;
+
+#define WPA_DRIVER_AUTH_OPEN		0x00000001
+#define WPA_DRIVER_AUTH_SHARED		0x00000002
+#define WPA_DRIVER_AUTH_LEAP		0x00000004
+	unsigned int auth;
+
+/* Driver generated WPA/RSN IE */
+#define WPA_DRIVER_FLAGS_DRIVER_IE	0x00000001
+/* Driver needs static WEP key setup after association command */
+#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
+/* unused: 0x00000004 */
+/* Driver takes care of RSN 4-way handshake internally; PMK is configured with
+ * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
+#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008
+#define WPA_DRIVER_FLAGS_WIRED		0x00000010
+/* Driver provides separate commands for authentication and association (SME in
+ * wpa_supplicant). */
+#define WPA_DRIVER_FLAGS_SME		0x00000020
+/* Driver supports AP mode */
+#define WPA_DRIVER_FLAGS_AP		0x00000040
+/* Driver needs static WEP key setup after association has been completed */
+#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE	0x00000080
+/* Driver takes care of P2P management operations */
+#define WPA_DRIVER_FLAGS_P2P_MGMT	0x00000100
+/* Driver supports concurrent P2P operations */
+#define WPA_DRIVER_FLAGS_P2P_CONCURRENT	0x00000200
+/*
+ * Driver uses the initial interface as a dedicated management interface, i.e.,
+ * it cannot be used for P2P group operations or non-P2P purposes.
+ */
+#define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE	0x00000400
+/* This interface is P2P capable (P2P Device, GO, or P2P Client */
+#define WPA_DRIVER_FLAGS_P2P_CAPABLE	0x00000800
+/* Driver supports concurrent operations on multiple channels */
+#define WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT	0x00001000
+/*
+ * Driver uses the initial interface for P2P management interface and non-P2P
+ * purposes (e.g., connect to infra AP), but this interface cannot be used for
+ * P2P group operations.
+ */
+#define WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P		0x00002000
+/*
+ * Driver is known to use sane error codes, i.e., when it indicates that
+ * something (e.g., association) fails, there was indeed a failure and the
+ * operation does not end up getting completed successfully later.
+ */
+#define WPA_DRIVER_FLAGS_SANE_ERROR_CODES		0x00004000
+/* Driver supports off-channel TX */
+#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX			0x00008000
+/* Driver indicates TX status events for EAPOL Data frames */
+#define WPA_DRIVER_FLAGS_EAPOL_TX_STATUS		0x00010000
+/* Driver indicates TX status events for Deauth/Disassoc frames */
+#define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS		0x00020000
+/* Driver supports roaming (BSS selection) in firmware */
+#define WPA_DRIVER_FLAGS_BSS_SELECTION			0x00040000
+/* Driver supports operating as a TDLS peer */
+#define WPA_DRIVER_FLAGS_TDLS_SUPPORT			0x00080000
+/* Driver requires external TDLS setup/teardown/discovery */
+#define WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP		0x00100000
+/* Driver indicates support for Probe Response offloading in AP mode */
+#define WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD		0x00200000
+/* Driver supports U-APSD in AP mode */
+#define WPA_DRIVER_FLAGS_AP_UAPSD			0x00400000
+/* Driver supports inactivity timer in AP mode */
+#define WPA_DRIVER_FLAGS_INACTIVITY_TIMER		0x00800000
+/* Driver expects user space implementation of MLME in AP mode */
+#define WPA_DRIVER_FLAGS_AP_MLME			0x01000000
+/* Driver supports SAE with user space SME */
+#define WPA_DRIVER_FLAGS_SAE				0x02000000
+/* Driver makes use of OBSS scan mechanism in wpa_supplicant */
+#define WPA_DRIVER_FLAGS_OBSS_SCAN			0x04000000
+	unsigned int flags;
+
+	int max_scan_ssids;
+	int max_sched_scan_ssids;
+	int sched_scan_supported;
+	int max_match_sets;
+
+	/**
+	 * max_remain_on_chan - Maximum remain-on-channel duration in msec
+	 */
+	unsigned int max_remain_on_chan;
+
+	/**
+	 * max_stations - Maximum number of associated stations the driver
+	 * supports in AP mode
+	 */
+	unsigned int max_stations;
+
+	/**
+	 * probe_resp_offloads - Bitmap of supported protocols by the driver
+	 * for Probe Response offloading.
+	 */
+/* Driver Probe Response offloading support for WPS ver. 1 */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS		0x00000001
+/* Driver Probe Response offloading support for WPS ver. 2 */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2		0x00000002
+/* Driver Probe Response offloading support for P2P */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P		0x00000004
+/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING	0x00000008
+	unsigned int probe_resp_offloads;
+};
+
+
+struct hostapd_data;
+
+struct hostap_sta_driver_data {
+	unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes;
+	unsigned long current_tx_rate;
+	unsigned long inactive_msec;
+	unsigned long flags;
+	unsigned long num_ps_buf_frames;
+	unsigned long tx_retry_failed;
+	unsigned long tx_retry_count;
+	int last_rssi;
+	int last_ack_rssi;
+};
+
+struct hostapd_sta_add_params {
+	const u8 *addr;
+	u16 aid;
+	u16 capability;
+	const u8 *supp_rates;
+	size_t supp_rates_len;
+	u16 listen_interval;
+	const struct ieee80211_ht_capabilities *ht_capabilities;
+	u32 flags; /* bitmask of WPA_STA_* flags */
+	int set; /* Set STA parameters instead of add */
+	u8 qosinfo;
+};
+
+struct hostapd_freq_params {
+	int mode;
+	int freq;
+	int channel;
+	int ht_enabled;
+	int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
+				 * secondary channel below primary, 1 = HT40
+				 * enabled, secondary channel above primary */
+};
+
+enum wpa_driver_if_type {
+	/**
+	 * WPA_IF_STATION - Station mode interface
+	 */
+	WPA_IF_STATION,
+
+	/**
+	 * WPA_IF_AP_VLAN - AP mode VLAN interface
+	 *
+	 * This interface shares its address and Beacon frame with the main
+	 * BSS.
+	 */
+	WPA_IF_AP_VLAN,
+
+	/**
+	 * WPA_IF_AP_BSS - AP mode BSS interface
+	 *
+	 * This interface has its own address and Beacon frame.
+	 */
+	WPA_IF_AP_BSS,
+
+	/**
+	 * WPA_IF_P2P_GO - P2P Group Owner
+	 */
+	WPA_IF_P2P_GO,
+
+	/**
+	 * WPA_IF_P2P_CLIENT - P2P Client
+	 */
+	WPA_IF_P2P_CLIENT,
+
+	/**
+	 * WPA_IF_P2P_GROUP - P2P Group interface (will become either
+	 * WPA_IF_P2P_GO or WPA_IF_P2P_CLIENT, but the role is not yet known)
+	 */
+	WPA_IF_P2P_GROUP
+};
+
+struct wpa_init_params {
+	void *global_priv;
+	const u8 *bssid;
+	const char *ifname;
+	const u8 *ssid;
+	size_t ssid_len;
+	const char *test_socket;
+	int use_pae_group_addr;
+	char **bridge;
+	size_t num_bridge;
+
+	u8 *own_addr; /* buffer for writing own MAC address */
+};
+
+
+struct wpa_bss_params {
+	/** Interface name (for multi-SSID/VLAN support) */
+	const char *ifname;
+	/** Whether IEEE 802.1X or WPA/WPA2 is enabled */
+	int enabled;
+
+	int wpa;
+	int ieee802_1x;
+	int wpa_group;
+	int wpa_pairwise;
+	int wpa_key_mgmt;
+	int rsn_preauth;
+	enum mfp_options ieee80211w;
+};
+
+#define WPA_STA_AUTHORIZED BIT(0)
+#define WPA_STA_WMM BIT(1)
+#define WPA_STA_SHORT_PREAMBLE BIT(2)
+#define WPA_STA_MFP BIT(3)
+#define WPA_STA_TDLS_PEER BIT(4)
+
+/**
+ * struct p2p_params - P2P parameters for driver-based P2P management
+ */
+struct p2p_params {
+	const char *dev_name;
+	u8 pri_dev_type[8];
+#define DRV_MAX_SEC_DEV_TYPES 5
+	u8 sec_dev_type[DRV_MAX_SEC_DEV_TYPES][8];
+	size_t num_sec_dev_types;
+};
+
+enum tdls_oper {
+	TDLS_DISCOVERY_REQ,
+	TDLS_SETUP,
+	TDLS_TEARDOWN,
+	TDLS_ENABLE_LINK,
+	TDLS_DISABLE_LINK,
+	TDLS_ENABLE,
+	TDLS_DISABLE
+};
+
+enum wnm_oper {
+	WNM_SLEEP_ENTER_CONFIRM,
+	WNM_SLEEP_ENTER_FAIL,
+	WNM_SLEEP_EXIT_CONFIRM,
+	WNM_SLEEP_EXIT_FAIL,
+	WNM_SLEEP_TFS_REQ_IE_ADD,   /* STA requests driver to add TFS req IE */
+	WNM_SLEEP_TFS_REQ_IE_NONE,  /* STA requests empty TFS req IE */
+	WNM_SLEEP_TFS_REQ_IE_SET,   /* AP requests driver to set TFS req IE for
+				     * a STA */
+	WNM_SLEEP_TFS_RESP_IE_ADD,  /* AP requests driver to add TFS resp IE
+				     * for a STA */
+	WNM_SLEEP_TFS_RESP_IE_NONE, /* AP requests empty TFS resp IE */
+	WNM_SLEEP_TFS_RESP_IE_SET,  /* AP requests driver to set TFS resp IE
+				     * for a STA */
+	WNM_SLEEP_TFS_IE_DEL        /* AP delete the TFS IE */
+};
+
+/**
+ * struct wpa_signal_info - Information about channel signal quality
+ */
+struct wpa_signal_info {
+	u32 frequency;
+	int above_threshold;
+	int current_signal;
+	int current_noise;
+	int current_txrate;
+};
+
+/**
+ * struct wpa_driver_ops - Driver interface API definition
+ *
+ * This structure defines the API that each driver interface needs to implement
+ * for core wpa_supplicant code. All driver specific functionality is captured
+ * in this wrapper.
+ */
+struct wpa_driver_ops {
+	/** Name of the driver interface */
+	const char *name;
+	/** One line description of the driver interface */
+	const char *desc;
+
+	/**
+	 * get_bssid - Get the current BSSID
+	 * @priv: private driver interface data
+	 * @bssid: buffer for BSSID (ETH_ALEN = 6 bytes)
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Query kernel driver for the current BSSID and copy it to bssid.
+	 * Setting bssid to 00:00:00:00:00:00 is recommended if the STA is not
+	 * associated.
+	 */
+	int (*get_bssid)(void *priv, u8 *bssid);
+
+	/**
+	 * get_ssid - Get the current SSID
+	 * @priv: private driver interface data
+	 * @ssid: buffer for SSID (at least 32 bytes)
+	 *
+	 * Returns: Length of the SSID on success, -1 on failure
+	 *
+	 * Query kernel driver for the current SSID and copy it to ssid.
+	 * Returning zero is recommended if the STA is not associated.
+	 *
+	 * Note: SSID is an array of octets, i.e., it is not nul terminated and
+	 * can, at least in theory, contain control characters (including nul)
+	 * and as such, should be processed as binary data, not a printable
+	 * string.
+	 */
+	int (*get_ssid)(void *priv, u8 *ssid);
+
+	/**
+	 * set_key - Configure encryption key
+	 * @ifname: Interface name (for multi-SSID/VLAN support)
+	 * @priv: private driver interface data
+	 * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
+	 *	%WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK,
+	 *	%WPA_ALG_GCMP);
+	 *	%WPA_ALG_NONE clears the key.
+	 * @addr: Address of the peer STA (BSSID of the current AP when setting
+	 *	pairwise key in station mode), ff:ff:ff:ff:ff:ff for
+	 *	broadcast keys, %NULL for default keys that are used both for
+	 *	broadcast and unicast; when clearing keys, %NULL is used to
+	 *	indicate that both the broadcast-only and default key of the
+	 *	specified key index is to be cleared
+	 * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for
+	 *	IGTK
+	 * @set_tx: configure this key as the default Tx key (only used when
+	 *	driver does not support separate unicast/individual key
+	 * @seq: sequence number/packet number, seq_len octets, the next
+	 *	packet number to be used for in replay protection; configured
+	 *	for Rx keys (in most cases, this is only used with broadcast
+	 *	keys and set to zero for unicast keys); %NULL if not set
+	 * @seq_len: length of the seq, depends on the algorithm:
+	 *	TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets
+	 * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
+	 *	8-byte Rx Mic Key
+	 * @key_len: length of the key buffer in octets (WEP: 5 or 13,
+	 *	TKIP: 32, CCMP/GCMP: 16, IGTK: 16)
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Configure the given key for the kernel driver. If the driver
+	 * supports separate individual keys (4 default keys + 1 individual),
+	 * addr can be used to determine whether the key is default or
+	 * individual. If only 4 keys are supported, the default key with key
+	 * index 0 is used as the individual key. STA must be configured to use
+	 * it as the default Tx key (set_tx is set) and accept Rx for all the
+	 * key indexes. In most cases, WPA uses only key indexes 1 and 2 for
+	 * broadcast keys, so key index 0 is available for this kind of
+	 * configuration.
+	 *
+	 * Please note that TKIP keys include separate TX and RX MIC keys and
+	 * some drivers may expect them in different order than wpa_supplicant
+	 * is using. If the TX/RX keys are swapped, all TKIP encrypted packets
+	 * will trigger Michael MIC errors. This can be fixed by changing the
+	 * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key
+	 * in driver_*.c set_key() implementation, see driver_ndis.c for an
+	 * example on how this can be done.
+	 */
+	int (*set_key)(const char *ifname, void *priv, enum wpa_alg alg,
+		       const u8 *addr, int key_idx, int set_tx,
+		       const u8 *seq, size_t seq_len,
+		       const u8 *key, size_t key_len);
+
+	/**
+	 * init - Initialize driver interface
+	 * @ctx: context to be used when calling wpa_supplicant functions,
+	 * e.g., wpa_supplicant_event()
+	 * @ifname: interface name, e.g., wlan0
+	 *
+	 * Returns: Pointer to private data, %NULL on failure
+	 *
+	 * Initialize driver interface, including event processing for kernel
+	 * driver events (e.g., associated, scan results, Michael MIC failure).
+	 * This function can allocate a private configuration data area for
+	 * @ctx, file descriptor, interface name, etc. information that may be
+	 * needed in future driver operations. If this is not used, non-NULL
+	 * value will need to be returned because %NULL is used to indicate
+	 * failure. The returned value will be used as 'void *priv' data for
+	 * all other driver_ops functions.
+	 *
+	 * The main event loop (eloop.c) of wpa_supplicant can be used to
+	 * register callback for read sockets (eloop_register_read_sock()).
+	 *
+	 * See below for more information about events and
+	 * wpa_supplicant_event() function.
+	 */
+	void * (*init)(void *ctx, const char *ifname);
+
+	/**
+	 * deinit - Deinitialize driver interface
+	 * @priv: private driver interface data from init()
+	 *
+	 * Shut down driver interface and processing of driver events. Free
+	 * private data buffer if one was allocated in init() handler.
+	 */
+	void (*deinit)(void *priv);
+
+	/**
+	 * set_param - Set driver configuration parameters
+	 * @priv: private driver interface data from init()
+	 * @param: driver specific configuration parameters
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Optional handler for notifying driver interface about configuration
+	 * parameters (driver_param).
+	 */
+	int (*set_param)(void *priv, const char *param);
+
+	/**
+	 * set_countermeasures - Enable/disable TKIP countermeasures
+	 * @priv: private driver interface data
+	 * @enabled: 1 = countermeasures enabled, 0 = disabled
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Configure TKIP countermeasures. When these are enabled, the driver
+	 * should drop all received and queued frames that are using TKIP.
+	 */
+	int (*set_countermeasures)(void *priv, int enabled);
+
+	/**
+	 * deauthenticate - Request driver to deauthenticate
+	 * @priv: private driver interface data
+	 * @addr: peer address (BSSID of the AP)
+	 * @reason_code: 16-bit reason code to be sent in the deauthentication
+	 *	frame
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*deauthenticate)(void *priv, const u8 *addr, int reason_code);
+
+	/**
+	 * associate - Request driver to associate
+	 * @priv: private driver interface data
+	 * @params: association parameters
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*associate)(void *priv,
+			 struct wpa_driver_associate_params *params);
+
+	/**
+	 * add_pmkid - Add PMKSA cache entry to the driver
+	 * @priv: private driver interface data
+	 * @bssid: BSSID for the PMKSA cache entry
+	 * @pmkid: PMKID for the PMKSA cache entry
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is called when a new PMK is received, as a result of
+	 * either normal authentication or RSN pre-authentication.
+	 *
+	 * If the driver generates RSN IE, i.e., it does not use wpa_ie in
+	 * associate(), add_pmkid() can be used to add new PMKSA cache entries
+	 * in the driver. If the driver uses wpa_ie from wpa_supplicant, this
+	 * driver_ops function does not need to be implemented. Likewise, if
+	 * the driver does not support WPA, this function is not needed.
+	 */
+	int (*add_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid);
+
+	/**
+	 * remove_pmkid - Remove PMKSA cache entry to the driver
+	 * @priv: private driver interface data
+	 * @bssid: BSSID for the PMKSA cache entry
+	 * @pmkid: PMKID for the PMKSA cache entry
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is called when the supplicant drops a PMKSA cache
+	 * entry for any reason.
+	 *
+	 * If the driver generates RSN IE, i.e., it does not use wpa_ie in
+	 * associate(), remove_pmkid() can be used to synchronize PMKSA caches
+	 * between the driver and wpa_supplicant. If the driver uses wpa_ie
+	 * from wpa_supplicant, this driver_ops function does not need to be
+	 * implemented. Likewise, if the driver does not support WPA, this
+	 * function is not needed.
+	 */
+	int (*remove_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid);
+
+	/**
+	 * flush_pmkid - Flush PMKSA cache
+	 * @priv: private driver interface data
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is called when the supplicant drops all PMKSA cache
+	 * entries for any reason.
+	 *
+	 * If the driver generates RSN IE, i.e., it does not use wpa_ie in
+	 * associate(), remove_pmkid() can be used to synchronize PMKSA caches
+	 * between the driver and wpa_supplicant. If the driver uses wpa_ie
+	 * from wpa_supplicant, this driver_ops function does not need to be
+	 * implemented. Likewise, if the driver does not support WPA, this
+	 * function is not needed.
+	 */
+	int (*flush_pmkid)(void *priv);
+
+	/**
+	 * get_capa - Get driver capabilities
+	 * @priv: private driver interface data
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Get driver/firmware/hardware capabilities.
+	 */
+	int (*get_capa)(void *priv, struct wpa_driver_capa *capa);
+
+	/**
+	 * poll - Poll driver for association information
+	 * @priv: private driver interface data
+	 *
+	 * This is an option callback that can be used when the driver does not
+	 * provide event mechanism for association events. This is called when
+	 * receiving WPA EAPOL-Key messages that require association
+	 * information. The driver interface is supposed to generate associnfo
+	 * event before returning from this callback function. In addition, the
+	 * driver interface should generate an association event after having
+	 * sent out associnfo.
+	 */
+	void (*poll)(void *priv);
+
+	/**
+	 * get_ifname - Get interface name
+	 * @priv: private driver interface data
+	 *
+	 * Returns: Pointer to the interface name. This can differ from the
+	 * interface name used in init() call. Init() is called first.
+	 *
+	 * This optional function can be used to allow the driver interface to
+	 * replace the interface name with something else, e.g., based on an
+	 * interface mapping from a more descriptive name.
+	 */
+	const char * (*get_ifname)(void *priv);
+
+	/**
+	 * get_mac_addr - Get own MAC address
+	 * @priv: private driver interface data
+	 *
+	 * Returns: Pointer to own MAC address or %NULL on failure
+	 *
+	 * This optional function can be used to get the own MAC address of the
+	 * device from the driver interface code. This is only needed if the
+	 * l2_packet implementation for the OS does not provide easy access to
+	 * a MAC address. */
+	const u8 * (*get_mac_addr)(void *priv);
+
+	/**
+	 * send_eapol - Optional function for sending EAPOL packets
+	 * @priv: private driver interface data
+	 * @dest: Destination MAC address
+	 * @proto: Ethertype
+	 * @data: EAPOL packet starting with IEEE 802.1X header
+	 * @data_len: Size of the EAPOL packet
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This optional function can be used to override l2_packet operations
+	 * with driver specific functionality. If this function pointer is set,
+	 * l2_packet module is not used at all and the driver interface code is
+	 * responsible for receiving and sending all EAPOL packets. The
+	 * received EAPOL packets are sent to core code with EVENT_EAPOL_RX
+	 * event. The driver interface is required to implement get_mac_addr()
+	 * handler if send_eapol() is used.
+	 */
+	int (*send_eapol)(void *priv, const u8 *dest, u16 proto,
+			  const u8 *data, size_t data_len);
+
+	/**
+	 * set_operstate - Sets device operating state to DORMANT or UP
+	 * @priv: private driver interface data
+	 * @state: 0 = dormant, 1 = up
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function that can be used on operating systems
+	 * that support a concept of controlling network device state from user
+	 * space applications. This function, if set, gets called with
+	 * state = 1 when authentication has been completed and with state = 0
+	 * when connection is lost.
+	 */
+	int (*set_operstate)(void *priv, int state);
+
+	/**
+	 * mlme_setprotection - MLME-SETPROTECTION.request primitive
+	 * @priv: Private driver interface data
+	 * @addr: Address of the station for which to set protection (may be
+	 * %NULL for group keys)
+	 * @protect_type: MLME_SETPROTECTION_PROTECT_TYPE_*
+	 * @key_type: MLME_SETPROTECTION_KEY_TYPE_*
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function that can be used to set the driver to
+	 * require protection for Tx and/or Rx frames. This uses the layer
+	 * interface defined in IEEE 802.11i-2004 clause 10.3.22.1
+	 * (MLME-SETPROTECTION.request). Many drivers do not use explicit
+	 * set protection operation; instead, they set protection implicitly
+	 * based on configured keys.
+	 */
+	int (*mlme_setprotection)(void *priv, const u8 *addr, int protect_type,
+				  int key_type);
+
+	/**
+	 * get_hw_feature_data - Get hardware support data (channels and rates)
+	 * @priv: Private driver interface data
+	 * @num_modes: Variable for returning the number of returned modes
+	 * flags: Variable for returning hardware feature flags
+	 * Returns: Pointer to allocated hardware data on success or %NULL on
+	 * failure. Caller is responsible for freeing this.
+	 */
+	struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv,
+							 u16 *num_modes,
+							 u16 *flags);
+
+	/**
+	 * send_mlme - Send management frame from MLME
+	 * @priv: Private driver interface data
+	 * @data: IEEE 802.11 management frame with IEEE 802.11 header
+	 * @data_len: Size of the management frame
+	 * @noack: Do not wait for this frame to be acked (disable retries)
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
+			 int noack);
+
+	/**
+	 * update_ft_ies - Update FT (IEEE 802.11r) IEs
+	 * @priv: Private driver interface data
+	 * @md: Mobility domain (2 octets) (also included inside ies)
+	 * @ies: FT IEs (MDIE, FTIE, ...) or %NULL to remove IEs
+	 * @ies_len: Length of FT IEs in bytes
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * The supplicant uses this callback to let the driver know that keying
+	 * material for FT is available and that the driver can use the
+	 * provided IEs in the next message in FT authentication sequence.
+	 *
+	 * This function is only needed for driver that support IEEE 802.11r
+	 * (Fast BSS Transition).
+	 */
+	int (*update_ft_ies)(void *priv, const u8 *md, const u8 *ies,
+			     size_t ies_len);
+
+	/**
+	 * send_ft_action - Send FT Action frame (IEEE 802.11r)
+	 * @priv: Private driver interface data
+	 * @action: Action field value
+	 * @target_ap: Target AP address
+	 * @ies: FT IEs (MDIE, FTIE, ...) (FT Request action frame body)
+	 * @ies_len: Length of FT IEs in bytes
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * The supplicant uses this callback to request the driver to transmit
+	 * an FT Action frame (action category 6) for over-the-DS fast BSS
+	 * transition.
+	 */
+	int (*send_ft_action)(void *priv, u8 action, const u8 *target_ap,
+			      const u8 *ies, size_t ies_len);
+
+	/**
+	 * get_scan_results2 - Fetch the latest scan results
+	 * @priv: private driver interface data
+	 *
+	 * Returns: Allocated buffer of scan results (caller is responsible for
+	 * freeing the data structure) on success, NULL on failure
+	 */
+	 struct wpa_scan_results * (*get_scan_results2)(void *priv);
+
+	/**
+	 * set_country - Set country
+	 * @priv: Private driver interface data
+	 * @alpha2: country to which to switch to
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is for drivers which support some form
+	 * of setting a regulatory domain.
+	 */
+	int (*set_country)(void *priv, const char *alpha2);
+
+	/**
+	 * global_init - Global driver initialization
+	 * Returns: Pointer to private data (global), %NULL on failure
+	 *
+	 * This optional function is called to initialize the driver wrapper
+	 * for global data, i.e., data that applies to all interfaces. If this
+	 * function is implemented, global_deinit() will also need to be
+	 * implemented to free the private data. The driver will also likely
+	 * use init2() function instead of init() to get the pointer to global
+	 * data available to per-interface initializer.
+	 */
+	void * (*global_init)(void);
+
+	/**
+	 * global_deinit - Global driver deinitialization
+	 * @priv: private driver global data from global_init()
+	 *
+	 * Terminate any global driver related functionality and free the
+	 * global data structure.
+	 */
+	void (*global_deinit)(void *priv);
+
+	/**
+	 * init2 - Initialize driver interface (with global data)
+	 * @ctx: context to be used when calling wpa_supplicant functions,
+	 * e.g., wpa_supplicant_event()
+	 * @ifname: interface name, e.g., wlan0
+	 * @global_priv: private driver global data from global_init()
+	 * Returns: Pointer to private data, %NULL on failure
+	 *
+	 * This function can be used instead of init() if the driver wrapper
+	 * uses global data.
+	 */
+	void * (*init2)(void *ctx, const char *ifname, void *global_priv);
+
+	/**
+	 * get_interfaces - Get information about available interfaces
+	 * @global_priv: private driver global data from global_init()
+	 * Returns: Allocated buffer of interface information (caller is
+	 * responsible for freeing the data structure) on success, NULL on
+	 * failure
+	 */
+	struct wpa_interface_info * (*get_interfaces)(void *global_priv);
+
+	/**
+	 * scan2 - Request the driver to initiate scan
+	 * @priv: private driver interface data
+	 * @params: Scan parameters
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Once the scan results are ready, the driver should report scan
+	 * results event for wpa_supplicant which will eventually request the
+	 * results with wpa_driver_get_scan_results2().
+	 */
+	int (*scan2)(void *priv, struct wpa_driver_scan_params *params);
+
+	/**
+	 * authenticate - Request driver to authenticate
+	 * @priv: private driver interface data
+	 * @params: authentication parameters
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function that can be used with drivers that
+	 * support separate authentication and association steps, i.e., when
+	 * wpa_supplicant can act as the SME. If not implemented, associate()
+	 * function is expected to take care of IEEE 802.11 authentication,
+	 * too.
+	 */
+	int (*authenticate)(void *priv,
+			    struct wpa_driver_auth_params *params);
+
+	/**
+	 * set_ap - Set Beacon and Probe Response information for AP mode
+	 * @priv: Private driver interface data
+	 * @params: Parameters to use in AP mode
+	 *
+	 * This function is used to configure Beacon template and/or extra IEs
+	 * to add for Beacon and Probe Response frames for the driver in
+	 * AP mode. The driver is responsible for building the full Beacon
+	 * frame by concatenating the head part with TIM IE generated by the
+	 * driver/firmware and finishing with the tail part. Depending on the
+	 * driver architectue, this can be done either by using the full
+	 * template or the set of additional IEs (e.g., WPS and P2P IE).
+	 * Similarly, Probe Response processing depends on the driver design.
+	 * If the driver (or firmware) takes care of replying to Probe Request
+	 * frames, the extra IEs provided here needs to be added to the Probe
+	 * Response frames.
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_ap)(void *priv, struct wpa_driver_ap_params *params);
+
+	/**
+	 * hapd_init - Initialize driver interface (hostapd only)
+	 * @hapd: Pointer to hostapd context
+	 * @params: Configuration for the driver wrapper
+	 * Returns: Pointer to private data, %NULL on failure
+	 *
+	 * This function is used instead of init() or init2() when the driver
+	 * wrapper is used with hostapd.
+	 */
+	void * (*hapd_init)(struct hostapd_data *hapd,
+			    struct wpa_init_params *params);
+
+	/**
+	 * hapd_deinit - Deinitialize driver interface (hostapd only)
+	 * @priv: Private driver interface data from hapd_init()
+	 */
+	void (*hapd_deinit)(void *priv);
+
+	/**
+	 * set_ieee8021x - Enable/disable IEEE 802.1X support (AP only)
+	 * @priv: Private driver interface data
+	 * @params: BSS parameters
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function to configure the kernel driver to
+	 * enable/disable IEEE 802.1X support and set WPA/WPA2 parameters. This
+	 * can be left undefined (set to %NULL) if IEEE 802.1X support is
+	 * always enabled and the driver uses set_ap() to set WPA/RSN IE
+	 * for Beacon frames.
+	 *
+	 * DEPRECATED - use set_ap() instead
+	 */
+	int (*set_ieee8021x)(void *priv, struct wpa_bss_params *params);
+
+	/**
+	 * set_privacy - Enable/disable privacy (AP only)
+	 * @priv: Private driver interface data
+	 * @enabled: 1 = privacy enabled, 0 = disabled
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function to configure privacy field in the
+	 * kernel driver for Beacon frames. This can be left undefined (set to
+	 * %NULL) if the driver uses the Beacon template from set_ap().
+	 *
+	 * DEPRECATED - use set_ap() instead
+	 */
+	int (*set_privacy)(void *priv, int enabled);
+
+	/**
+	 * get_seqnum - Fetch the current TSC/packet number (AP only)
+	 * @ifname: The interface name (main or virtual)
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the station or %NULL for group keys
+	 * @idx: Key index
+	 * @seq: Buffer for returning the latest used TSC/packet number
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is used to fetch the last used TSC/packet number for
+	 * a TKIP, CCMP, GCMP, or BIP/IGTK key. It is mainly used with group
+	 * keys, so there is no strict requirement on implementing support for
+	 * unicast keys (i.e., addr != %NULL).
+	 */
+	int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr,
+			  int idx, u8 *seq);
+
+	/**
+	 * flush - Flush all association stations (AP only)
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function requests the driver to disassociate all associated
+	 * stations. This function does not need to be implemented if the
+	 * driver does not process association frames internally.
+	 */
+	int (*flush)(void *priv);
+
+	/**
+	 * set_generic_elem - Add IEs into Beacon/Probe Response frames (AP)
+	 * @priv: Private driver interface data
+	 * @elem: Information elements
+	 * @elem_len: Length of the elem buffer in octets
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function to add information elements in the
+	 * kernel driver for Beacon and Probe Response frames. This can be left
+	 * undefined (set to %NULL) if the driver uses the Beacon template from
+	 * set_ap().
+	 *
+	 * DEPRECATED - use set_ap() instead
+	 */
+	int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len);
+
+	/**
+	 * read_sta_data - Fetch station data
+	 * @priv: Private driver interface data
+	 * @data: Buffer for returning station information
+	 * @addr: MAC address of the station
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*read_sta_data)(void *priv, struct hostap_sta_driver_data *data,
+			     const u8 *addr);
+
+	/**
+	 * hapd_send_eapol - Send an EAPOL packet (AP only)
+	 * @priv: private driver interface data
+	 * @addr: Destination MAC address
+	 * @data: EAPOL packet starting with IEEE 802.1X header
+	 * @data_len: Length of the EAPOL packet in octets
+	 * @encrypt: Whether the frame should be encrypted
+	 * @own_addr: Source MAC address
+	 * @flags: WPA_STA_* flags for the destination station
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*hapd_send_eapol)(void *priv, const u8 *addr, const u8 *data,
+			       size_t data_len, int encrypt,
+			       const u8 *own_addr, u32 flags);
+
+	/**
+	 * sta_deauth - Deauthenticate a station (AP only)
+	 * @priv: Private driver interface data
+	 * @own_addr: Source address and BSSID for the Deauthentication frame
+	 * @addr: MAC address of the station to deauthenticate
+	 * @reason: Reason code for the Deauthentiation frame
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function requests a specific station to be deauthenticated and
+	 * a Deauthentication frame to be sent to it.
+	 */
+	int (*sta_deauth)(void *priv, const u8 *own_addr, const u8 *addr,
+			  int reason);
+
+	/**
+	 * sta_disassoc - Disassociate a station (AP only)
+	 * @priv: Private driver interface data
+	 * @own_addr: Source address and BSSID for the Disassociation frame
+	 * @addr: MAC address of the station to disassociate
+	 * @reason: Reason code for the Disassociation frame
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function requests a specific station to be disassociated and
+	 * a Disassociation frame to be sent to it.
+	 */
+	int (*sta_disassoc)(void *priv, const u8 *own_addr, const u8 *addr,
+			    int reason);
+
+	/**
+	 * sta_remove - Remove a station entry (AP only)
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the station to be removed
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*sta_remove)(void *priv, const u8 *addr);
+
+	/**
+	 * hapd_get_ssid - Get the current SSID (AP only)
+	 * @priv: Private driver interface data
+	 * @buf: Buffer for returning the SSID
+	 * @len: Maximum length of the buffer
+	 * Returns: Length of the SSID on success, -1 on failure
+	 *
+	 * This function need not be implemented if the driver uses Beacon
+	 * template from set_ap() and does not reply to Probe Request frames.
+	 */
+	int (*hapd_get_ssid)(void *priv, u8 *buf, int len);
+
+	/**
+	 * hapd_set_ssid - Set SSID (AP only)
+	 * @priv: Private driver interface data
+	 * @buf: SSID
+	 * @len: Length of the SSID in octets
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * DEPRECATED - use set_ap() instead
+	 */
+	int (*hapd_set_ssid)(void *priv, const u8 *buf, int len);
+
+	/**
+	 * hapd_set_countermeasures - Enable/disable TKIP countermeasures (AP)
+	 * @priv: Private driver interface data
+	 * @enabled: 1 = countermeasures enabled, 0 = disabled
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This need not be implemented if the driver does not take care of
+	 * association processing.
+	 */
+	int (*hapd_set_countermeasures)(void *priv, int enabled);
+
+	/**
+	 * sta_add - Add a station entry
+	 * @priv: Private driver interface data
+	 * @params: Station parameters
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is used to add a station entry to the driver once the
+	 * station has completed association. This is only used if the driver
+	 * does not take care of association processing.
+	 *
+	 * With TDLS, this function is also used to add or set (params->set 1)
+	 * TDLS peer entries.
+	 */
+	int (*sta_add)(void *priv, struct hostapd_sta_add_params *params);
+
+	/**
+	 * get_inact_sec - Get station inactivity duration (AP only)
+	 * @priv: Private driver interface data
+	 * @addr: Station address
+	 * Returns: Number of seconds station has been inactive, -1 on failure
+	 */
+	int (*get_inact_sec)(void *priv, const u8 *addr);
+
+	/**
+	 * sta_clear_stats - Clear station statistics (AP only)
+	 * @priv: Private driver interface data
+	 * @addr: Station address
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*sta_clear_stats)(void *priv, const u8 *addr);
+
+	/**
+	 * set_freq - Set channel/frequency (AP only)
+	 * @priv: Private driver interface data
+	 * @freq: Channel parameters
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_freq)(void *priv, struct hostapd_freq_params *freq);
+
+	/**
+	 * set_rts - Set RTS threshold
+	 * @priv: Private driver interface data
+	 * @rts: RTS threshold in octets
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_rts)(void *priv, int rts);
+
+	/**
+	 * set_frag - Set fragmentation threshold
+	 * @priv: Private driver interface data
+	 * @frag: Fragmentation threshold in octets
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_frag)(void *priv, int frag);
+
+	/**
+	 * sta_set_flags - Set station flags (AP only)
+	 * @priv: Private driver interface data
+	 * @addr: Station address
+	 * @total_flags: Bitmap of all WPA_STA_* flags currently set
+	 * @flags_or: Bitmap of WPA_STA_* flags to add
+	 * @flags_and: Bitmap of WPA_STA_* flags to us as a mask
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*sta_set_flags)(void *priv, const u8 *addr,
+			     int total_flags, int flags_or, int flags_and);
+
+	/**
+	 * set_tx_queue_params - Set TX queue parameters
+	 * @priv: Private driver interface data
+	 * @queue: Queue number (0 = VO, 1 = VI, 2 = BE, 3 = BK)
+	 * @aifs: AIFS
+	 * @cw_min: cwMin
+	 * @cw_max: cwMax
+	 * @burst_time: Maximum length for bursting in 0.1 msec units
+	 */
+	int (*set_tx_queue_params)(void *priv, int queue, int aifs, int cw_min,
+				   int cw_max, int burst_time);
+
+	/**
+	 * if_add - Add a virtual interface
+	 * @priv: Private driver interface data
+	 * @type: Interface type
+	 * @ifname: Interface name for the new virtual interface
+	 * @addr: Local address to use for the interface or %NULL to use the
+	 *	parent interface address
+	 * @bss_ctx: BSS context for %WPA_IF_AP_BSS interfaces
+	 * @drv_priv: Pointer for overwriting the driver context or %NULL if
+	 *	not allowed (applies only to %WPA_IF_AP_BSS type)
+	 * @force_ifname: Buffer for returning an interface name that the
+	 *	driver ended up using if it differs from the requested ifname
+	 * @if_addr: Buffer for returning the allocated interface address
+	 *	(this may differ from the requested addr if the driver cannot
+	 *	change interface address)
+	 * @bridge: Bridge interface to use or %NULL if no bridge configured
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*if_add)(void *priv, enum wpa_driver_if_type type,
+		      const char *ifname, const u8 *addr, void *bss_ctx,
+		      void **drv_priv, char *force_ifname, u8 *if_addr,
+		      const char *bridge);
+
+	/**
+	 * if_remove - Remove a virtual interface
+	 * @priv: Private driver interface data
+	 * @type: Interface type
+	 * @ifname: Interface name of the virtual interface to be removed
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*if_remove)(void *priv, enum wpa_driver_if_type type,
+			 const char *ifname);
+
+	/**
+	 * set_sta_vlan - Bind a station into a specific interface (AP only)
+	 * @priv: Private driver interface data
+	 * @ifname: Interface (main or virtual BSS or VLAN)
+	 * @addr: MAC address of the associated station
+	 * @vlan_id: VLAN ID
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is used to bind a station to a specific virtual
+	 * interface. It is only used if when virtual interfaces are supported,
+	 * e.g., to assign stations to different VLAN interfaces based on
+	 * information from a RADIUS server. This allows separate broadcast
+	 * domains to be used with a single BSS.
+	 */
+	int (*set_sta_vlan)(void *priv, const u8 *addr, const char *ifname,
+			    int vlan_id);
+
+	/**
+	 * commit - Optional commit changes handler (AP only)
+	 * @priv: driver private data
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This optional handler function can be registered if the driver
+	 * interface implementation needs to commit changes (e.g., by setting
+	 * network interface up) at the end of initial configuration. If set,
+	 * this handler will be called after initial setup has been completed.
+	 */
+	int (*commit)(void *priv);
+
+	/**
+	 * send_ether - Send an ethernet packet (AP only)
+	 * @priv: private driver interface data
+	 * @dst: Destination MAC address
+	 * @src: Source MAC address
+	 * @proto: Ethertype
+	 * @data: EAPOL packet starting with IEEE 802.1X header
+	 * @data_len: Length of the EAPOL packet in octets
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*send_ether)(void *priv, const u8 *dst, const u8 *src, u16 proto,
+			  const u8 *data, size_t data_len);
+
+	/**
+	 * set_radius_acl_auth - Notification of RADIUS ACL change
+	 * @priv: Private driver interface data
+	 * @mac: MAC address of the station
+	 * @accepted: Whether the station was accepted
+	 * @session_timeout: Session timeout for the station
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_radius_acl_auth)(void *priv, const u8 *mac, int accepted, 
+				   u32 session_timeout);
+
+	/**
+	 * set_radius_acl_expire - Notification of RADIUS ACL expiration
+	 * @priv: Private driver interface data
+	 * @mac: MAC address of the station
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_radius_acl_expire)(void *priv, const u8 *mac);
+
+	/**
+	 * set_ap_wps_ie - Add WPS IE(s) into Beacon/Probe Response frames (AP)
+	 * @priv: Private driver interface data
+	 * @beacon: WPS IE(s) for Beacon frames or %NULL to remove extra IE(s)
+	 * @proberesp: WPS IE(s) for Probe Response frames or %NULL to remove
+	 *	extra IE(s)
+	 * @assocresp: WPS IE(s) for (Re)Association Response frames or %NULL
+	 *	to remove extra IE(s)
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function to add WPS IE in the kernel driver for
+	 * Beacon and Probe Response frames. This can be left undefined (set
+	 * to %NULL) if the driver uses the Beacon template from set_ap()
+	 * and does not process Probe Request frames. If the driver takes care
+	 * of (Re)Association frame processing, the assocresp buffer includes
+	 * WPS IE(s) that need to be added to (Re)Association Response frames
+	 * whenever a (Re)Association Request frame indicated use of WPS.
+	 *
+	 * This will also be used to add P2P IE(s) into Beacon/Probe Response
+	 * frames when operating as a GO. The driver is responsible for adding
+	 * timing related attributes (e.g., NoA) in addition to the IEs
+	 * included here by appending them after these buffers. This call is
+	 * also used to provide Probe Response IEs for P2P Listen state
+	 * operations for drivers that generate the Probe Response frames
+	 * internally.
+	 *
+	 * DEPRECATED - use set_ap() instead
+	 */
+	int (*set_ap_wps_ie)(void *priv, const struct wpabuf *beacon,
+			     const struct wpabuf *proberesp,
+			     const struct wpabuf *assocresp);
+
+	/**
+	 * set_supp_port - Set IEEE 802.1X Supplicant Port status
+	 * @priv: Private driver interface data
+	 * @authorized: Whether the port is authorized
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_supp_port)(void *priv, int authorized);
+
+	/**
+	 * set_wds_sta - Bind a station into a 4-address WDS (AP only)
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the associated station
+	 * @aid: Association ID
+	 * @val: 1 = bind to 4-address WDS; 0 = unbind
+	 * @bridge_ifname: Bridge interface to use for the WDS station or %NULL
+	 *	to indicate that bridge is not to be used
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_wds_sta)(void *priv, const u8 *addr, int aid, int val,
+	                   const char *bridge_ifname);
+
+	/**
+	 * send_action - Transmit an Action frame
+	 * @priv: Private driver interface data
+	 * @freq: Frequency (in MHz) of the channel
+	 * @wait: Time to wait off-channel for a response (in ms), or zero
+	 * @dst: Destination MAC address (Address 1)
+	 * @src: Source MAC address (Address 2)
+	 * @bssid: BSSID (Address 3)
+	 * @data: Frame body
+	 * @data_len: data length in octets
+	 @ @no_cck: Whether CCK rates must not be used to transmit this frame
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This command can be used to request the driver to transmit an action
+	 * frame to the specified destination.
+	 *
+	 * If the %WPA_DRIVER_FLAGS_OFFCHANNEL_TX flag is set, the frame will
+	 * be transmitted on the given channel and the device will wait for a
+	 * response on that channel for the given wait time.
+	 *
+	 * If the flag is not set, the wait time will be ignored. In this case,
+	 * if a remain-on-channel duration is in progress, the frame must be
+	 * transmitted on that channel; alternatively the frame may be sent on
+	 * the current operational channel (if in associated state in station
+	 * mode or while operating as an AP.)
+	 */
+	int (*send_action)(void *priv, unsigned int freq, unsigned int wait,
+			   const u8 *dst, const u8 *src, const u8 *bssid,
+			   const u8 *data, size_t data_len, int no_cck);
+
+	/**
+	 * send_action_cancel_wait - Cancel action frame TX wait
+	 * @priv: Private driver interface data
+	 *
+	 * This command cancels the wait time associated with sending an action
+	 * frame. It is only available when %WPA_DRIVER_FLAGS_OFFCHANNEL_TX is
+	 * set in the driver flags.
+	 */
+	void (*send_action_cancel_wait)(void *priv);
+
+	/**
+	 * remain_on_channel - Remain awake on a channel
+	 * @priv: Private driver interface data
+	 * @freq: Frequency (in MHz) of the channel
+	 * @duration: Duration in milliseconds
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This command is used to request the driver to remain awake on the
+	 * specified channel for the specified duration and report received
+	 * Action frames with EVENT_RX_ACTION events. Optionally, received
+	 * Probe Request frames may also be requested to be reported by calling
+	 * probe_req_report(). These will be reported with EVENT_RX_PROBE_REQ.
+	 *
+	 * The driver may not be at the requested channel when this function
+	 * returns, i.e., the return code is only indicating whether the
+	 * request was accepted. The caller will need to wait until the
+	 * EVENT_REMAIN_ON_CHANNEL event indicates that the driver has
+	 * completed the channel change. This may take some time due to other
+	 * need for the radio and the caller should be prepared to timing out
+	 * its wait since there are no guarantees on when this request can be
+	 * executed.
+	 */
+	int (*remain_on_channel)(void *priv, unsigned int freq,
+				 unsigned int duration);
+
+	/**
+	 * cancel_remain_on_channel - Cancel remain-on-channel operation
+	 * @priv: Private driver interface data
+	 *
+	 * This command can be used to cancel a remain-on-channel operation
+	 * before its originally requested duration has passed. This could be
+	 * used, e.g., when remain_on_channel() is used to request extra time
+	 * to receive a response to an Action frame and the response is
+	 * received when there is still unneeded time remaining on the
+	 * remain-on-channel operation.
+	 */
+	int (*cancel_remain_on_channel)(void *priv);
+
+	/**
+	 * probe_req_report - Request Probe Request frames to be indicated
+	 * @priv: Private driver interface data
+	 * @report: Whether to report received Probe Request frames
+	 * Returns: 0 on success, -1 on failure (or if not supported)
+	 *
+	 * This command can be used to request the driver to indicate when
+	 * Probe Request frames are received with EVENT_RX_PROBE_REQ events.
+	 * Since this operation may require extra resources, e.g., due to less
+	 * optimal hardware/firmware RX filtering, many drivers may disable
+	 * Probe Request reporting at least in station mode. This command is
+	 * used to notify the driver when the Probe Request frames need to be
+	 * reported, e.g., during remain-on-channel operations.
+	 */
+	int (*probe_req_report)(void *priv, int report);
+
+	/**
+	 * deinit_ap - Deinitialize AP mode
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure (or if not supported)
+	 *
+	 * This optional function can be used to disable AP mode related
+	 * configuration and change the driver mode to station mode to allow
+	 * normal station operations like scanning to be completed.
+	 */
+	int (*deinit_ap)(void *priv);
+
+	/**
+	 * deinit_p2p_cli - Deinitialize P2P client mode
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure (or if not supported)
+	 *
+	 * This optional function can be used to disable P2P client mode. It
+	 * can be used to change the interface type back to station mode.
+	 */
+	int (*deinit_p2p_cli)(void *priv);
+
+	/**
+	 * suspend - Notification on system suspend/hibernate event
+	 * @priv: Private driver interface data
+	 */
+	void (*suspend)(void *priv);
+
+	/**
+	 * resume - Notification on system resume/thaw event
+	 * @priv: Private driver interface data
+	 */
+	void (*resume)(void *priv);
+
+	/**
+	 * signal_monitor - Set signal monitoring parameters
+	 * @priv: Private driver interface data
+	 * @threshold: Threshold value for signal change events; 0 = disabled
+	 * @hysteresis: Minimum change in signal strength before indicating a
+	 *	new event
+	 * Returns: 0 on success, -1 on failure (or if not supported)
+	 *
+	 * This function can be used to configure monitoring of signal strength
+	 * with the current AP. Whenever signal strength drops below the
+	 * %threshold value or increases above it, EVENT_SIGNAL_CHANGE event
+	 * should be generated assuming the signal strength has changed at
+	 * least %hysteresis from the previously indicated signal change event.
+	 */
+	int (*signal_monitor)(void *priv, int threshold, int hysteresis);
+
+	/**
+	 * send_frame - Send IEEE 802.11 frame (testing use only)
+	 * @priv: Private driver interface data
+	 * @data: IEEE 802.11 frame with IEEE 802.11 header
+	 * @data_len: Size of the frame
+	 * @encrypt: Whether to encrypt the frame (if keys are set)
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is only used for debugging purposes and is not
+	 * required to be implemented for normal operations.
+	 */
+	int (*send_frame)(void *priv, const u8 *data, size_t data_len,
+			  int encrypt);
+
+	/**
+	 * shared_freq - Get operating frequency of shared interface(s)
+	 * @priv: Private driver interface data
+	 * Returns: Operating frequency in MHz, 0 if no shared operation in
+	 * use, or -1 on failure
+	 *
+	 * This command can be used to request the current operating frequency
+	 * of any virtual interface that shares the same radio to provide
+	 * information for channel selection for other virtual interfaces.
+	 */
+	int (*shared_freq)(void *priv);
+
+	/**
+	 * get_noa - Get current Notice of Absence attribute payload
+	 * @priv: Private driver interface data
+	 * @buf: Buffer for returning NoA
+	 * @buf_len: Buffer length in octets
+	 * Returns: Number of octets used in buf, 0 to indicate no NoA is being
+	 * advertized, or -1 on failure
+	 *
+	 * This function is used to fetch the current Notice of Absence
+	 * attribute value from GO.
+	 */
+	int (*get_noa)(void *priv, u8 *buf, size_t buf_len);
+
+	/**
+	 * set_noa - Set Notice of Absence parameters for GO (testing)
+	 * @priv: Private driver interface data
+	 * @count: Count
+	 * @start: Start time in ms from next TBTT
+	 * @duration: Duration in ms
+	 * Returns: 0 on success or -1 on failure
+	 *
+	 * This function is used to set Notice of Absence parameters for GO. It
+	 * is used only for testing. To disable NoA, all parameters are set to
+	 * 0.
+	 */
+	int (*set_noa)(void *priv, u8 count, int start, int duration);
+
+	/**
+	 * set_p2p_powersave - Set P2P power save options
+	 * @priv: Private driver interface data
+	 * @legacy_ps: 0 = disable, 1 = enable, 2 = maximum PS, -1 = no change
+	 * @opp_ps: 0 = disable, 1 = enable, -1 = no change
+	 * @ctwindow: 0.. = change (msec), -1 = no change
+	 * Returns: 0 on success or -1 on failure
+	 */
+	int (*set_p2p_powersave)(void *priv, int legacy_ps, int opp_ps,
+				 int ctwindow);
+
+	/**
+	 * ampdu - Enable/disable aggregation
+	 * @priv: Private driver interface data
+	 * @ampdu: 1/0 = enable/disable A-MPDU aggregation
+	 * Returns: 0 on success or -1 on failure
+	 */
+	int (*ampdu)(void *priv, int ampdu);
+
+	/**
+	 * get_radio_name - Get physical radio name for the device
+	 * @priv: Private driver interface data
+	 * Returns: Radio name or %NULL if not known
+	 *
+	 * The returned data must not be modified by the caller. It is assumed
+	 * that any interface that has the same radio name as another is
+	 * sharing the same physical radio. This information can be used to
+	 * share scan results etc. information between the virtual interfaces
+	 * to speed up various operations.
+	 */
+	const char * (*get_radio_name)(void *priv);
+
+	/**
+	 * p2p_find - Start P2P Device Discovery
+	 * @priv: Private driver interface data
+	 * @timeout: Timeout for find operation in seconds or 0 for no timeout
+	 * @type: Device Discovery type (enum p2p_discovery_type)
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_find)(void *priv, unsigned int timeout, int type);
+
+	/**
+	 * p2p_stop_find - Stop P2P Device Discovery
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_stop_find)(void *priv);
+
+	/**
+	 * p2p_listen - Start P2P Listen state for specified duration
+	 * @priv: Private driver interface data
+	 * @timeout: Listen state duration in milliseconds
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function can be used to request the P2P module to keep the
+	 * device discoverable on the listen channel for an extended set of
+	 * time. At least in its current form, this is mainly used for testing
+	 * purposes and may not be of much use for normal P2P operations.
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_listen)(void *priv, unsigned int timeout);
+
+	/**
+	 * p2p_connect - Start P2P group formation (GO negotiation)
+	 * @priv: Private driver interface data
+	 * @peer_addr: MAC address of the peer P2P client
+	 * @wps_method: enum p2p_wps_method value indicating config method
+	 * @go_intent: Local GO intent value (1..15)
+	 * @own_interface_addr: Intended interface address to use with the
+	 *	group
+	 * @force_freq: The only allowed channel frequency in MHz or 0
+	 * @persistent_group: Whether to create persistent group
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_connect)(void *priv, const u8 *peer_addr, int wps_method,
+			   int go_intent, const u8 *own_interface_addr,
+			   unsigned int force_freq, int persistent_group);
+
+	/**
+	 * wps_success_cb - Report successfully completed WPS provisioning
+	 * @priv: Private driver interface data
+	 * @peer_addr: Peer address
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is used to report successfully completed WPS
+	 * provisioning during group formation in both GO/Registrar and
+	 * client/Enrollee roles.
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*wps_success_cb)(void *priv, const u8 *peer_addr);
+
+	/**
+	 * p2p_group_formation_failed - Report failed WPS provisioning
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is used to report failed group formation. This can
+	 * happen either due to failed WPS provisioning or due to 15 second
+	 * timeout during the provisioning phase.
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_group_formation_failed)(void *priv);
+
+	/**
+	 * p2p_set_params - Set P2P parameters
+	 * @priv: Private driver interface data
+	 * @params: P2P parameters
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_set_params)(void *priv, const struct p2p_params *params);
+
+	/**
+	 * p2p_prov_disc_req - Send Provision Discovery Request
+	 * @priv: Private driver interface data
+	 * @peer_addr: MAC address of the peer P2P client
+	 * @config_methods: WPS Config Methods value (only one bit set)
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function can be used to request a discovered P2P peer to
+	 * display a PIN (config_methods = WPS_CONFIG_DISPLAY) or be prepared
+	 * to enter a PIN from us (config_methods = WPS_CONFIG_KEYPAD). The
+	 * Provision Discovery Request frame is transmitted once immediately
+	 * and if no response is received, the frame will be sent again
+	 * whenever the target device is discovered during device dsicovery
+	 * (start with a p2p_find() call). Response from the peer is indicated
+	 * with the EVENT_P2P_PROV_DISC_RESPONSE event.
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_prov_disc_req)(void *priv, const u8 *peer_addr,
+				 u16 config_methods, int join);
+
+	/**
+	 * p2p_sd_request - Schedule a service discovery query
+	 * @priv: Private driver interface data
+	 * @dst: Destination peer or %NULL to apply for all peers
+	 * @tlvs: P2P Service Query TLV(s)
+	 * Returns: Reference to the query or 0 on failure
+	 *
+	 * Response to the query is indicated with the
+	 * EVENT_P2P_SD_RESPONSE driver event.
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	u64 (*p2p_sd_request)(void *priv, const u8 *dst,
+			      const struct wpabuf *tlvs);
+
+	/**
+	 * p2p_sd_cancel_request - Cancel a pending service discovery query
+	 * @priv: Private driver interface data
+	 * @req: Query reference from p2p_sd_request()
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_sd_cancel_request)(void *priv, u64 req);
+
+	/**
+	 * p2p_sd_response - Send response to a service discovery query
+	 * @priv: Private driver interface data
+	 * @freq: Frequency from EVENT_P2P_SD_REQUEST event
+	 * @dst: Destination address from EVENT_P2P_SD_REQUEST event
+	 * @dialog_token: Dialog token from EVENT_P2P_SD_REQUEST event
+	 * @resp_tlvs: P2P Service Response TLV(s)
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is called as a response to the request indicated with
+	 * the EVENT_P2P_SD_REQUEST driver event.
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_sd_response)(void *priv, int freq, const u8 *dst,
+			       u8 dialog_token,
+			       const struct wpabuf *resp_tlvs);
+
+	/**
+	 * p2p_service_update - Indicate a change in local services
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function needs to be called whenever there is a change in
+	 * availability of the local services. This will increment the
+	 * Service Update Indicator value which will be used in SD Request and
+	 * Response frames.
+	 *
+	 * This function is only used if the driver implements P2P management,
+	 * i.e., if it sets WPA_DRIVER_FLAGS_P2P_MGMT in
+	 * struct wpa_driver_capa.
+	 */
+	int (*p2p_service_update)(void *priv);
+
+	/**
+	 * p2p_reject - Reject peer device (explicitly block connections)
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the peer
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*p2p_reject)(void *priv, const u8 *addr);
+
+	/**
+	 * p2p_invite - Invite a P2P Device into a group
+	 * @priv: Private driver interface data
+	 * @peer: Device Address of the peer P2P Device
+	 * @role: Local role in the group
+	 * @bssid: Group BSSID or %NULL if not known
+	 * @ssid: Group SSID
+	 * @ssid_len: Length of ssid in octets
+	 * @go_dev_addr: Forced GO Device Address or %NULL if none
+	 * @persistent_group: Whether this is to reinvoke a persistent group
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*p2p_invite)(void *priv, const u8 *peer, int role,
+			  const u8 *bssid, const u8 *ssid, size_t ssid_len,
+			  const u8 *go_dev_addr, int persistent_group);
+
+	/**
+	 * send_tdls_mgmt - for sending TDLS management packets
+	 * @priv: private driver interface data
+	 * @dst: Destination (peer) MAC address
+	 * @action_code: TDLS action code for the mssage
+	 * @dialog_token: Dialog Token to use in the message (if needed)
+	 * @status_code: Status Code or Reason Code to use (if needed)
+	 * @buf: TDLS IEs to add to the message
+	 * @len: Length of buf in octets
+	 * Returns: 0 on success, negative (<0) on failure
+	 *
+	 * This optional function can be used to send packet to driver which is
+	 * responsible for receiving and sending all TDLS packets.
+	 */
+	int (*send_tdls_mgmt)(void *priv, const u8 *dst, u8 action_code,
+			      u8 dialog_token, u16 status_code,
+			      const u8 *buf, size_t len);
+
+	/**
+	 * tdls_oper - Ask the driver to perform high-level TDLS operations
+	 * @priv: Private driver interface data
+	 * @oper: TDLS high-level operation. See %enum tdls_oper
+	 * @peer: Destination (peer) MAC address
+	 * Returns: 0 on success, negative (<0) on failure
+	 *
+	 * This optional function can be used to send high-level TDLS commands
+	 * to the driver.
+	 */
+	int (*tdls_oper)(void *priv, enum tdls_oper oper, const u8 *peer);
+
+	/**
+	 * wnm_oper - Notify driver of the WNM frame reception
+	 * @priv: Private driver interface data
+	 * @oper: WNM operation. See %enum wnm_oper
+	 * @peer: Destination (peer) MAC address
+	 * @buf: Buffer for the driver to fill in (for getting IE)
+	 * @buf_len: Return the len of buf
+	 * Returns: 0 on success, negative (<0) on failure
+	 */
+	int (*wnm_oper)(void *priv, enum wnm_oper oper, const u8 *peer,
+			u8 *buf, u16 *buf_len);
+
+	/**
+	 * signal_poll - Get current connection information
+	 * @priv: Private driver interface data
+	 * @signal_info: Connection info structure
+         */
+	int (*signal_poll)(void *priv, struct wpa_signal_info *signal_info);
+
+	/**
+	 * set_authmode - Set authentication algorithm(s) for static WEP
+	 * @priv: Private driver interface data
+	 * @authmode: 1=Open System, 2=Shared Key, 3=both
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function can be used to set authentication algorithms for AP
+	 * mode when static WEP is used. If the driver uses user space MLME/SME
+	 * implementation, there is no need to implement this function.
+	 *
+	 * DEPRECATED - use set_ap() instead
+	 */
+	int (*set_authmode)(void *priv, int authmode);
+
+	/**
+	 * set_rekey_info - Set rekey information
+	 * @priv: Private driver interface data
+	 * @kek: Current KEK
+	 * @kck: Current KCK
+	 * @replay_ctr: Current EAPOL-Key Replay Counter
+	 *
+	 * This optional function can be used to provide information for the
+	 * driver/firmware to process EAPOL-Key frames in Group Key Handshake
+	 * while the host (including wpa_supplicant) is sleeping.
+	 */
+	void (*set_rekey_info)(void *priv, const u8 *kek, const u8 *kck,
+			       const u8 *replay_ctr);
+
+	/**
+	 * sta_assoc - Station association indication
+	 * @priv: Private driver interface data
+	 * @own_addr: Source address and BSSID for association frame
+	 * @addr: MAC address of the station to associate
+	 * @reassoc: flag to indicate re-association
+	 * @status: association response status code
+	 * @ie: assoc response ie buffer
+	 * @len: ie buffer length
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function indicates the driver to send (Re)Association
+	 * Response frame to the station.
+	 */
+	 int (*sta_assoc)(void *priv, const u8 *own_addr, const u8 *addr,
+			  int reassoc, u16 status, const u8 *ie, size_t len);
+
+	/**
+	 * sta_auth - Station authentication indication
+	 * @priv: Private driver interface data
+	 * @own_addr: Source address and BSSID for authentication frame
+	 * @addr: MAC address of the station to associate
+	 * @seq: authentication sequence number
+	 * @status: authentication response status code
+	 * @ie: authentication frame ie buffer
+	 * @len: ie buffer length
+	 *
+	 * This function indicates the driver to send Authentication frame
+	 * to the station.
+	 */
+	 int (*sta_auth)(void *priv, const u8 *own_addr, const u8 *addr,
+			 u16 seq, u16 status, const u8 *ie, size_t len);
+
+	/**
+	 * add_tspec - Add traffic stream
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the station to associate
+	 * @tspec_ie: tspec ie buffer
+	 * @tspec_ielen: tspec ie length
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function adds the traffic steam for the station
+	 * and fills the medium_time in tspec_ie.
+	 */
+	 int (*add_tspec)(void *priv, const u8 *addr, u8 *tspec_ie,
+			  size_t tspec_ielen);
+
+	/**
+	 * add_sta_node - Add a station node in the driver
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of the station to add
+	 * @auth_alg: authentication algorithm used by the station
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function adds the station node in the driver, when
+	 * the station gets added by FT-over-DS.
+	 */
+	int (*add_sta_node)(void *priv, const u8 *addr, u16 auth_alg);
+
+	/**
+	 * sched_scan - Request the driver to initiate scheduled scan
+	 * @priv: Private driver interface data
+	 * @params: Scan parameters
+	 * @interval: Interval between scan cycles in milliseconds
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This operation should be used for scheduled scan offload to
+	 * the hardware. Every time scan results are available, the
+	 * driver should report scan results event for wpa_supplicant
+	 * which will eventually request the results with
+	 * wpa_driver_get_scan_results2(). This operation is optional
+	 * and if not provided or if it returns -1, we fall back to
+	 * normal host-scheduled scans.
+	 */
+	int (*sched_scan)(void *priv, struct wpa_driver_scan_params *params,
+			  u32 interval);
+
+	/**
+	 * stop_sched_scan - Request the driver to stop a scheduled scan
+	 * @priv: Private driver interface data
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This should cause the scheduled scan to be stopped and
+	 * results should stop being sent. Must be supported if
+	 * sched_scan is supported.
+	 */
+	int (*stop_sched_scan)(void *priv);
+
+	/**
+	 * poll_client - Probe (null data or such) the given station
+	 * @priv: Private driver interface data
+	 * @own_addr: MAC address of sending interface
+	 * @addr: MAC address of the station to probe
+	 * @qos: Indicates whether station is QoS station
+	 *
+	 * This function is used to verify whether an associated station is
+	 * still present. This function does not need to be implemented if the
+	 * driver provides such inactivity polling mechanism.
+	 */
+	void (*poll_client)(void *priv, const u8 *own_addr,
+			    const u8 *addr, int qos);
+
+	/**
+	 * radio_disable - Disable/enable radio
+	 * @priv: Private driver interface data
+	 * @disabled: 1=disable 0=enable radio
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This optional command is for testing purposes. It can be used to
+	 * disable the radio on a testbed device to simulate out-of-radio-range
+	 * conditions.
+	 */
+	int (*radio_disable)(void *priv, int disabled);
+
+	/**
+	 * switch_channel - Announce channel switch and migrate the GO to the
+	 * given frequency
+	 * @priv: Private driver interface data
+	 * @freq: Frequency in MHz
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is used to move the GO to the legacy STA channel to
+	 * avoid frequency conflict in single channel concurrency.
+	 */
+	int (*switch_channel)(void *priv, unsigned int freq);
+};
+
+
+/**
+ * enum wpa_event_type - Event type for wpa_supplicant_event() calls
+ */
+enum wpa_event_type {
+	/**
+	 * EVENT_ASSOC - Association completed
+	 *
+	 * This event needs to be delivered when the driver completes IEEE
+	 * 802.11 association or reassociation successfully.
+	 * wpa_driver_ops::get_bssid() is expected to provide the current BSSID
+	 * after this event has been generated. In addition, optional
+	 * EVENT_ASSOCINFO may be generated just before EVENT_ASSOC to provide
+	 * more information about the association. If the driver interface gets
+	 * both of these events at the same time, it can also include the
+	 * assoc_info data in EVENT_ASSOC call.
+	 */
+	EVENT_ASSOC,
+
+	/**
+	 * EVENT_DISASSOC - Association lost
+	 *
+	 * This event should be called when association is lost either due to
+	 * receiving deauthenticate or disassociate frame from the AP or when
+	 * sending either of these frames to the current AP. If the driver
+	 * supports separate deauthentication event, EVENT_DISASSOC should only
+	 * be used for disassociation and EVENT_DEAUTH for deauthentication.
+	 * In AP mode, union wpa_event_data::disassoc_info is required.
+	 */
+	EVENT_DISASSOC,
+
+	/**
+	 * EVENT_MICHAEL_MIC_FAILURE - Michael MIC (TKIP) detected
+	 *
+	 * This event must be delivered when a Michael MIC error is detected by
+	 * the local driver. Additional data for event processing is
+	 * provided with union wpa_event_data::michael_mic_failure. This
+	 * information is used to request new encyption key and to initiate
+	 * TKIP countermeasures if needed.
+	 */
+	EVENT_MICHAEL_MIC_FAILURE,
+
+	/**
+	 * EVENT_SCAN_RESULTS - Scan results available
+	 *
+	 * This event must be called whenever scan results are available to be
+	 * fetched with struct wpa_driver_ops::get_scan_results(). This event
+	 * is expected to be used some time after struct wpa_driver_ops::scan()
+	 * is called. If the driver provides an unsolicited event when the scan
+	 * has been completed, this event can be used to trigger
+	 * EVENT_SCAN_RESULTS call. If such event is not available from the
+	 * driver, the driver wrapper code is expected to use a registered
+	 * timeout to generate EVENT_SCAN_RESULTS call after the time that the
+	 * scan is expected to be completed. Optional information about
+	 * completed scan can be provided with union wpa_event_data::scan_info.
+	 */
+	EVENT_SCAN_RESULTS,
+
+	/**
+	 * EVENT_ASSOCINFO - Report optional extra information for association
+	 *
+	 * This event can be used to report extra association information for
+	 * EVENT_ASSOC processing. This extra information includes IEs from
+	 * association frames and Beacon/Probe Response frames in union
+	 * wpa_event_data::assoc_info. EVENT_ASSOCINFO must be send just before
+	 * EVENT_ASSOC. Alternatively, the driver interface can include
+	 * assoc_info data in the EVENT_ASSOC call if it has all the
+	 * information available at the same point.
+	 */
+	EVENT_ASSOCINFO,
+
+	/**
+	 * EVENT_INTERFACE_STATUS - Report interface status changes
+	 *
+	 * This optional event can be used to report changes in interface
+	 * status (interface added/removed) using union
+	 * wpa_event_data::interface_status. This can be used to trigger
+	 * wpa_supplicant to stop and re-start processing for the interface,
+	 * e.g., when a cardbus card is ejected/inserted.
+	 */
+	EVENT_INTERFACE_STATUS,
+
+	/**
+	 * EVENT_PMKID_CANDIDATE - Report a candidate AP for pre-authentication
+	 *
+	 * This event can be used to inform wpa_supplicant about candidates for
+	 * RSN (WPA2) pre-authentication. If wpa_supplicant is not responsible
+	 * for scan request (ap_scan=2 mode), this event is required for
+	 * pre-authentication. If wpa_supplicant is performing scan request
+	 * (ap_scan=1), this event is optional since scan results can be used
+	 * to add pre-authentication candidates. union
+	 * wpa_event_data::pmkid_candidate is used to report the BSSID of the
+	 * candidate and priority of the candidate, e.g., based on the signal
+	 * strength, in order to try to pre-authenticate first with candidates
+	 * that are most likely targets for re-association.
+	 *
+	 * EVENT_PMKID_CANDIDATE can be called whenever the driver has updates
+	 * on the candidate list. In addition, it can be called for the current
+	 * AP and APs that have existing PMKSA cache entries. wpa_supplicant
+	 * will automatically skip pre-authentication in cases where a valid
+	 * PMKSA exists. When more than one candidate exists, this event should
+	 * be generated once for each candidate.
+	 *
+	 * Driver will be notified about successful pre-authentication with
+	 * struct wpa_driver_ops::add_pmkid() calls.
+	 */
+	EVENT_PMKID_CANDIDATE,
+
+	/**
+	 * EVENT_STKSTART - Request STK handshake (MLME-STKSTART.request)
+	 *
+	 * This event can be used to inform wpa_supplicant about desire to set
+	 * up secure direct link connection between two stations as defined in
+	 * IEEE 802.11e with a new PeerKey mechanism that replaced the original
+	 * STAKey negotiation. The caller will need to set peer address for the
+	 * event.
+	 */
+	EVENT_STKSTART,
+
+	/**
+	 * EVENT_TDLS - Request TDLS operation
+	 *
+	 * This event can be used to request a TDLS operation to be performed.
+	 */
+	EVENT_TDLS,
+
+	/**
+	 * EVENT_FT_RESPONSE - Report FT (IEEE 802.11r) response IEs
+	 *
+	 * The driver is expected to report the received FT IEs from
+	 * FT authentication sequence from the AP. The FT IEs are included in
+	 * the extra information in union wpa_event_data::ft_ies.
+	 */
+	EVENT_FT_RESPONSE,
+
+	/**
+	 * EVENT_IBSS_RSN_START - Request RSN authentication in IBSS
+	 *
+	 * The driver can use this event to inform wpa_supplicant about a STA
+	 * in an IBSS with which protected frames could be exchanged. This
+	 * event starts RSN authentication with the other STA to authenticate
+	 * the STA and set up encryption keys with it.
+	 */
+	EVENT_IBSS_RSN_START,
+
+	/**
+	 * EVENT_AUTH - Authentication result
+	 *
+	 * This event should be called when authentication attempt has been
+	 * completed. This is only used if the driver supports separate
+	 * authentication step (struct wpa_driver_ops::authenticate).
+	 * Information about authentication result is included in
+	 * union wpa_event_data::auth.
+	 */
+	EVENT_AUTH,
+
+	/**
+	 * EVENT_DEAUTH - Authentication lost
+	 *
+	 * This event should be called when authentication is lost either due
+	 * to receiving deauthenticate frame from the AP or when sending that
+	 * frame to the current AP.
+	 * In AP mode, union wpa_event_data::deauth_info is required.
+	 */
+	EVENT_DEAUTH,
+
+	/**
+	 * EVENT_ASSOC_REJECT - Association rejected
+	 *
+	 * This event should be called when (re)association attempt has been
+	 * rejected by the AP. Information about the association response is
+	 * included in union wpa_event_data::assoc_reject.
+	 */
+	EVENT_ASSOC_REJECT,
+
+	/**
+	 * EVENT_AUTH_TIMED_OUT - Authentication timed out
+	 */
+	EVENT_AUTH_TIMED_OUT,
+
+	/**
+	 * EVENT_ASSOC_TIMED_OUT - Association timed out
+	 */
+	EVENT_ASSOC_TIMED_OUT,
+
+	/**
+	 * EVENT_FT_RRB_RX - FT (IEEE 802.11r) RRB frame received
+	 */
+	EVENT_FT_RRB_RX,
+
+	/**
+	 * EVENT_WPS_BUTTON_PUSHED - Report hardware push button press for WPS
+	 */
+	EVENT_WPS_BUTTON_PUSHED,
+
+	/**
+	 * EVENT_TX_STATUS - Report TX status
+	 */
+	EVENT_TX_STATUS,
+
+	/**
+	 * EVENT_RX_FROM_UNKNOWN - Report RX from unknown STA
+	 */
+	EVENT_RX_FROM_UNKNOWN,
+
+	/**
+	 * EVENT_RX_MGMT - Report RX of a management frame
+	 */
+	EVENT_RX_MGMT,
+
+	/**
+	 * EVENT_RX_ACTION - Action frame received
+	 *
+	 * This event is used to indicate when an Action frame has been
+	 * received. Information about the received frame is included in
+	 * union wpa_event_data::rx_action.
+	 */
+	EVENT_RX_ACTION,
+
+	/**
+	 * EVENT_REMAIN_ON_CHANNEL - Remain-on-channel duration started
+	 *
+	 * This event is used to indicate when the driver has started the
+	 * requested remain-on-channel duration. Information about the
+	 * operation is included in union wpa_event_data::remain_on_channel.
+	 */
+	EVENT_REMAIN_ON_CHANNEL,
+
+	/**
+	 * EVENT_CANCEL_REMAIN_ON_CHANNEL - Remain-on-channel timed out
+	 *
+	 * This event is used to indicate when the driver has completed
+	 * remain-on-channel duration, i.e., may noot be available on the
+	 * requested channel anymore. Information about the
+	 * operation is included in union wpa_event_data::remain_on_channel.
+	 */
+	EVENT_CANCEL_REMAIN_ON_CHANNEL,
+
+	/**
+	 * EVENT_MLME_RX - Report reception of frame for MLME (test use only)
+	 *
+	 * This event is used only by driver_test.c and userspace MLME.
+	 */
+	EVENT_MLME_RX,
+
+	/**
+	 * EVENT_RX_PROBE_REQ - Indicate received Probe Request frame
+	 *
+	 * This event is used to indicate when a Probe Request frame has been
+	 * received. Information about the received frame is included in
+	 * union wpa_event_data::rx_probe_req. The driver is required to report
+	 * these events only after successfully completed probe_req_report()
+	 * commands to request the events (i.e., report parameter is non-zero)
+	 * in station mode. In AP mode, Probe Request frames should always be
+	 * reported.
+	 */
+	EVENT_RX_PROBE_REQ,
+
+	/**
+	 * EVENT_NEW_STA - New wired device noticed
+	 *
+	 * This event is used to indicate that a new device has been detected
+	 * in a network that does not use association-like functionality (i.e.,
+	 * mainly wired Ethernet). This can be used to start EAPOL
+	 * authenticator when receiving a frame from a device. The address of
+	 * the device is included in union wpa_event_data::new_sta.
+	 */
+	EVENT_NEW_STA,
+
+	/**
+	 * EVENT_EAPOL_RX - Report received EAPOL frame
+	 *
+	 * When in AP mode with hostapd, this event is required to be used to
+	 * deliver the receive EAPOL frames from the driver. With
+	 * %wpa_supplicant, this event is used only if the send_eapol() handler
+	 * is used to override the use of l2_packet for EAPOL frame TX.
+	 */
+	EVENT_EAPOL_RX,
+
+	/**
+	 * EVENT_SIGNAL_CHANGE - Indicate change in signal strength
+	 *
+	 * This event is used to indicate changes in the signal strength
+	 * observed in frames received from the current AP if signal strength
+	 * monitoring has been enabled with signal_monitor().
+	 */
+	EVENT_SIGNAL_CHANGE,
+
+	/**
+	 * EVENT_INTERFACE_ENABLED - Notify that interface was enabled
+	 *
+	 * This event is used to indicate that the interface was enabled after
+	 * having been previously disabled, e.g., due to rfkill.
+	 */
+	EVENT_INTERFACE_ENABLED,
+
+	/**
+	 * EVENT_INTERFACE_DISABLED - Notify that interface was disabled
+	 *
+	 * This event is used to indicate that the interface was disabled,
+	 * e.g., due to rfkill.
+	 */
+	EVENT_INTERFACE_DISABLED,
+
+	/**
+	 * EVENT_CHANNEL_LIST_CHANGED - Channel list changed
+	 *
+	 * This event is used to indicate that the channel list has changed,
+	 * e.g., because of a regulatory domain change triggered by scan
+	 * results including an AP advertising a country code.
+	 */
+	EVENT_CHANNEL_LIST_CHANGED,
+
+	/**
+	 * EVENT_INTERFACE_UNAVAILABLE - Notify that interface is unavailable
+	 *
+	 * This event is used to indicate that the driver cannot maintain this
+	 * interface in its operation mode anymore. The most likely use for
+	 * this is to indicate that AP mode operation is not available due to
+	 * operating channel would need to be changed to a DFS channel when
+	 * the driver does not support radar detection and another virtual
+	 * interfaces caused the operating channel to change. Other similar
+	 * resource conflicts could also trigger this for station mode
+	 * interfaces.
+	 */
+	EVENT_INTERFACE_UNAVAILABLE,
+
+	/**
+	 * EVENT_BEST_CHANNEL
+	 *
+	 * Driver generates this event whenever it detects a better channel
+	 * (e.g., based on RSSI or channel use). This information can be used
+	 * to improve channel selection for a new AP/P2P group.
+	 */
+	EVENT_BEST_CHANNEL,
+
+	/**
+	 * EVENT_UNPROT_DEAUTH - Unprotected Deauthentication frame received
+	 *
+	 * This event should be called when a Deauthentication frame is dropped
+	 * due to it not being protected (MFP/IEEE 802.11w).
+	 * union wpa_event_data::unprot_deauth is required to provide more
+	 * details of the frame.
+	 */
+	EVENT_UNPROT_DEAUTH,
+
+	/**
+	 * EVENT_UNPROT_DISASSOC - Unprotected Disassociation frame received
+	 *
+	 * This event should be called when a Disassociation frame is dropped
+	 * due to it not being protected (MFP/IEEE 802.11w).
+	 * union wpa_event_data::unprot_disassoc is required to provide more
+	 * details of the frame.
+	 */
+	EVENT_UNPROT_DISASSOC,
+
+	/**
+	 * EVENT_STATION_LOW_ACK
+	 *
+	 * Driver generates this event whenever it detected that a particular
+	 * station was lost. Detection can be through massive transmission
+	 * failures for example.
+	 */
+	EVENT_STATION_LOW_ACK,
+
+	/**
+	 * EVENT_P2P_DEV_FOUND - Report a discovered P2P device
+	 *
+	 * This event is used only if the driver implements P2P management
+	 * internally. Event data is stored in
+	 * union wpa_event_data::p2p_dev_found.
+	 */
+	EVENT_P2P_DEV_FOUND,
+
+	/**
+	 * EVENT_P2P_GO_NEG_REQ_RX - Report reception of GO Negotiation Request
+	 *
+	 * This event is used only if the driver implements P2P management
+	 * internally. Event data is stored in
+	 * union wpa_event_data::p2p_go_neg_req_rx.
+	 */
+	EVENT_P2P_GO_NEG_REQ_RX,
+
+	/**
+	 * EVENT_P2P_GO_NEG_COMPLETED - Report completion of GO Negotiation
+	 *
+	 * This event is used only if the driver implements P2P management
+	 * internally. Event data is stored in
+	 * union wpa_event_data::p2p_go_neg_completed.
+	 */
+	EVENT_P2P_GO_NEG_COMPLETED,
+
+	EVENT_P2P_PROV_DISC_REQUEST,
+	EVENT_P2P_PROV_DISC_RESPONSE,
+	EVENT_P2P_SD_REQUEST,
+	EVENT_P2P_SD_RESPONSE,
+
+	/**
+	 * EVENT_IBSS_PEER_LOST - IBSS peer not reachable anymore
+	 */
+	EVENT_IBSS_PEER_LOST,
+
+	/**
+	 * EVENT_DRIVER_GTK_REKEY - Device/driver did GTK rekey
+	 *
+	 * This event carries the new replay counter to notify wpa_supplicant
+	 * of the current EAPOL-Key Replay Counter in case the driver/firmware
+	 * completed Group Key Handshake while the host (including
+	 * wpa_supplicant was sleeping).
+	 */
+	EVENT_DRIVER_GTK_REKEY,
+
+	/**
+	 * EVENT_SCHED_SCAN_STOPPED - Scheduled scan was stopped
+	 */
+	EVENT_SCHED_SCAN_STOPPED,
+
+	/**
+	 * EVENT_DRIVER_CLIENT_POLL_OK - Station responded to poll
+	 *
+	 * This event indicates that the station responded to the poll
+	 * initiated with @poll_client.
+	 */
+	EVENT_DRIVER_CLIENT_POLL_OK,
+
+	/**
+	 * EVENT_EAPOL_TX_STATUS - notify of EAPOL TX status
+	 */
+	EVENT_EAPOL_TX_STATUS,
+
+	/**
+	 * EVENT_CH_SWITCH - AP or GO decided to switch channels
+	 *
+	 * Described in wpa_event_data.ch_switch
+	 * */
+	EVENT_CH_SWITCH,
+
+	/**
+	 * EVENT_WNM - Request WNM operation
+	 *
+	 * This event can be used to request a WNM operation to be performed.
+	 */
+	EVENT_WNM
+};
+
+
+/**
+ * union wpa_event_data - Additional data for wpa_supplicant_event() calls
+ */
+union wpa_event_data {
+	/**
+	 * struct assoc_info - Data for EVENT_ASSOC and EVENT_ASSOCINFO events
+	 *
+	 * This structure is optional for EVENT_ASSOC calls and required for
+	 * EVENT_ASSOCINFO calls. By using EVENT_ASSOC with this data, the
+	 * driver interface does not need to generate separate EVENT_ASSOCINFO
+	 * calls.
+	 */
+	struct assoc_info {
+		/**
+		 * reassoc - Flag to indicate association or reassociation
+		 */
+		int reassoc;
+
+		/**
+		 * req_ies - (Re)Association Request IEs
+		 *
+		 * If the driver generates WPA/RSN IE, this event data must be
+		 * returned for WPA handshake to have needed information. If
+		 * wpa_supplicant-generated WPA/RSN IE is used, this
+		 * information event is optional.
+		 *
+		 * This should start with the first IE (fixed fields before IEs
+		 * are not included).
+		 */
+		const u8 *req_ies;
+
+		/**
+		 * req_ies_len - Length of req_ies in bytes
+		 */
+		size_t req_ies_len;
+
+		/**
+		 * resp_ies - (Re)Association Response IEs
+		 *
+		 * Optional association data from the driver. This data is not
+		 * required WPA, but may be useful for some protocols and as
+		 * such, should be reported if this is available to the driver
+		 * interface.
+		 *
+		 * This should start with the first IE (fixed fields before IEs
+		 * are not included).
+		 */
+		const u8 *resp_ies;
+
+		/**
+		 * resp_ies_len - Length of resp_ies in bytes
+		 */
+		size_t resp_ies_len;
+
+		/**
+		 * beacon_ies - Beacon or Probe Response IEs
+		 *
+		 * Optional Beacon/ProbeResp data: IEs included in Beacon or
+		 * Probe Response frames from the current AP (i.e., the one
+		 * that the client just associated with). This information is
+		 * used to update WPA/RSN IE for the AP. If this field is not
+		 * set, the results from previous scan will be used. If no
+		 * data for the new AP is found, scan results will be requested
+		 * again (without scan request). At this point, the driver is
+		 * expected to provide WPA/RSN IE for the AP (if WPA/WPA2 is
+		 * used).
+		 *
+		 * This should start with the first IE (fixed fields before IEs
+		 * are not included).
+		 */
+		const u8 *beacon_ies;
+
+		/**
+		 * beacon_ies_len - Length of beacon_ies */
+		size_t beacon_ies_len;
+
+		/**
+		 * freq - Frequency of the operational channel in MHz
+		 */
+		unsigned int freq;
+
+		/**
+		 * addr - Station address (for AP mode)
+		 */
+		const u8 *addr;
+	} assoc_info;
+
+	/**
+	 * struct disassoc_info - Data for EVENT_DISASSOC events
+	 */
+	struct disassoc_info {
+		/**
+		 * addr - Station address (for AP mode)
+		 */
+		const u8 *addr;
+
+		/**
+		 * reason_code - Reason Code (host byte order) used in
+		 *	Deauthentication frame
+		 */
+		u16 reason_code;
+
+		/**
+		 * ie - Optional IE(s) in Disassociation frame
+		 */
+		const u8 *ie;
+
+		/**
+		 * ie_len - Length of ie buffer in octets
+		 */
+		size_t ie_len;
+
+		/**
+		 * locally_generated - Whether the frame was locally generated
+		 */
+		int locally_generated;
+	} disassoc_info;
+
+	/**
+	 * struct deauth_info - Data for EVENT_DEAUTH events
+	 */
+	struct deauth_info {
+		/**
+		 * addr - Station address (for AP mode)
+		 */
+		const u8 *addr;
+
+		/**
+		 * reason_code - Reason Code (host byte order) used in
+		 *	Deauthentication frame
+		 */
+		u16 reason_code;
+
+		/**
+		 * ie - Optional IE(s) in Deauthentication frame
+		 */
+		const u8 *ie;
+
+		/**
+		 * ie_len - Length of ie buffer in octets
+		 */
+		size_t ie_len;
+
+		/**
+		 * locally_generated - Whether the frame was locally generated
+		 */
+		int locally_generated;
+	} deauth_info;
+
+	/**
+	 * struct michael_mic_failure - Data for EVENT_MICHAEL_MIC_FAILURE
+	 */
+	struct michael_mic_failure {
+		int unicast;
+		const u8 *src;
+	} michael_mic_failure;
+
+	/**
+	 * struct interface_status - Data for EVENT_INTERFACE_STATUS
+	 */
+	struct interface_status {
+		char ifname[100];
+		enum {
+			EVENT_INTERFACE_ADDED, EVENT_INTERFACE_REMOVED
+		} ievent;
+	} interface_status;
+
+	/**
+	 * struct pmkid_candidate - Data for EVENT_PMKID_CANDIDATE
+	 */
+	struct pmkid_candidate {
+		/** BSSID of the PMKID candidate */
+		u8 bssid[ETH_ALEN];
+		/** Smaller the index, higher the priority */
+		int index;
+		/** Whether RSN IE includes pre-authenticate flag */
+		int preauth;
+	} pmkid_candidate;
+
+	/**
+	 * struct stkstart - Data for EVENT_STKSTART
+	 */
+	struct stkstart {
+		u8 peer[ETH_ALEN];
+	} stkstart;
+
+	/**
+	 * struct tdls - Data for EVENT_TDLS
+	 */
+	struct tdls {
+		u8 peer[ETH_ALEN];
+		enum {
+			TDLS_REQUEST_SETUP,
+			TDLS_REQUEST_TEARDOWN
+		} oper;
+		u16 reason_code; /* for teardown */
+	} tdls;
+
+	/**
+	 * struct wnm - Data for EVENT_WNM
+	 */
+	struct wnm {
+		u8 addr[ETH_ALEN];
+		enum {
+			WNM_OPER_SLEEP,
+		} oper;
+		enum {
+			WNM_SLEEP_ENTER,
+			WNM_SLEEP_EXIT
+		} sleep_action;
+		int sleep_intval;
+		u16 reason_code;
+		u8 *buf;
+		u16 buf_len;
+	} wnm;
+
+	/**
+	 * struct ft_ies - FT information elements (EVENT_FT_RESPONSE)
+	 *
+	 * During FT (IEEE 802.11r) authentication sequence, the driver is
+	 * expected to use this event to report received FT IEs (MDIE, FTIE,
+	 * RSN IE, TIE, possible resource request) to the supplicant. The FT
+	 * IEs for the next message will be delivered through the
+	 * struct wpa_driver_ops::update_ft_ies() callback.
+	 */
+	struct ft_ies {
+		const u8 *ies;
+		size_t ies_len;
+		int ft_action;
+		u8 target_ap[ETH_ALEN];
+		/** Optional IE(s), e.g., WMM TSPEC(s), for RIC-Request */
+		const u8 *ric_ies;
+		/** Length of ric_ies buffer in octets */
+		size_t ric_ies_len;
+	} ft_ies;
+
+	/**
+	 * struct ibss_rsn_start - Data for EVENT_IBSS_RSN_START
+	 */
+	struct ibss_rsn_start {
+		u8 peer[ETH_ALEN];
+	} ibss_rsn_start;
+
+	/**
+	 * struct auth_info - Data for EVENT_AUTH events
+	 */
+	struct auth_info {
+		u8 peer[ETH_ALEN];
+		u8 bssid[ETH_ALEN];
+		u16 auth_type;
+		u16 auth_transaction;
+		u16 status_code;
+		const u8 *ies;
+		size_t ies_len;
+	} auth;
+
+	/**
+	 * struct assoc_reject - Data for EVENT_ASSOC_REJECT events
+	 */
+	struct assoc_reject {
+		/**
+		 * bssid - BSSID of the AP that rejected association
+		 */
+		const u8 *bssid;
+
+		/**
+		 * resp_ies - (Re)Association Response IEs
+		 *
+		 * Optional association data from the driver. This data is not
+		 * required WPA, but may be useful for some protocols and as
+		 * such, should be reported if this is available to the driver
+		 * interface.
+		 *
+		 * This should start with the first IE (fixed fields before IEs
+		 * are not included).
+		 */
+		const u8 *resp_ies;
+
+		/**
+		 * resp_ies_len - Length of resp_ies in bytes
+		 */
+		size_t resp_ies_len;
+
+		/**
+		 * status_code - Status Code from (Re)association Response
+		 */
+		u16 status_code;
+	} assoc_reject;
+
+	struct timeout_event {
+		u8 addr[ETH_ALEN];
+	} timeout_event;
+
+	/**
+	 * struct ft_rrb_rx - Data for EVENT_FT_RRB_RX events
+	 */
+	struct ft_rrb_rx {
+		const u8 *src;
+		const u8 *data;
+		size_t data_len;
+	} ft_rrb_rx;
+
+	/**
+	 * struct tx_status - Data for EVENT_TX_STATUS events
+	 */
+	struct tx_status {
+		u16 type;
+		u16 stype;
+		const u8 *dst;
+		const u8 *data;
+		size_t data_len;
+		int ack;
+	} tx_status;
+
+	/**
+	 * struct rx_from_unknown - Data for EVENT_RX_FROM_UNKNOWN events
+	 */
+	struct rx_from_unknown {
+		const u8 *bssid;
+		const u8 *addr;
+		int wds;
+	} rx_from_unknown;
+
+	/**
+	 * struct rx_mgmt - Data for EVENT_RX_MGMT events
+	 */
+	struct rx_mgmt {
+		const u8 *frame;
+		size_t frame_len;
+		u32 datarate;
+		int ssi_signal; /* dBm */
+	} rx_mgmt;
+
+	/**
+	 * struct rx_action - Data for EVENT_RX_ACTION events
+	 */
+	struct rx_action {
+		/**
+		 * da - Destination address of the received Action frame
+		 */
+		const u8 *da;
+
+		/**
+		 * sa - Source address of the received Action frame
+		 */
+		const u8 *sa;
+
+		/**
+		 * bssid - Address 3 of the received Action frame
+		 */
+		const u8 *bssid;
+
+		/**
+		 * category - Action frame category
+		 */
+		u8 category;
+
+		/**
+		 * data - Action frame body after category field
+		 */
+		const u8 *data;
+
+		/**
+		 * len - Length of data in octets
+		 */
+		size_t len;
+
+		/**
+		 * freq - Frequency (in MHz) on which the frame was received
+		 */
+		int freq;
+	} rx_action;
+
+	/**
+	 * struct remain_on_channel - Data for EVENT_REMAIN_ON_CHANNEL events
+	 *
+	 * This is also used with EVENT_CANCEL_REMAIN_ON_CHANNEL events.
+	 */
+	struct remain_on_channel {
+		/**
+		 * freq - Channel frequency in MHz
+		 */
+		unsigned int freq;
+
+		/**
+		 * duration - Duration to remain on the channel in milliseconds
+		 */
+		unsigned int duration;
+	} remain_on_channel;
+
+	/**
+	 * struct scan_info - Optional data for EVENT_SCAN_RESULTS events
+	 * @aborted: Whether the scan was aborted
+	 * @freqs: Scanned frequencies in MHz (%NULL = all channels scanned)
+	 * @num_freqs: Number of entries in freqs array
+	 * @ssids: Scanned SSIDs (%NULL or zero-length SSID indicates wildcard
+	 *	SSID)
+	 * @num_ssids: Number of entries in ssids array
+	 */
+	struct scan_info {
+		int aborted;
+		const int *freqs;
+		size_t num_freqs;
+		struct wpa_driver_scan_ssid ssids[WPAS_MAX_SCAN_SSIDS];
+		size_t num_ssids;
+	} scan_info;
+
+	/**
+	 * struct mlme_rx - Data for EVENT_MLME_RX events
+	 */
+	struct mlme_rx {
+		const u8 *buf;
+		size_t len;
+		int freq;
+		int channel;
+		int ssi;
+	} mlme_rx;
+
+	/**
+	 * struct rx_probe_req - Data for EVENT_RX_PROBE_REQ events
+	 */
+	struct rx_probe_req {
+		/**
+		 * sa - Source address of the received Probe Request frame
+		 */
+		const u8 *sa;
+
+		/**
+		 * da - Destination address of the received Probe Request frame
+		 *	or %NULL if not available
+		 */
+		const u8 *da;
+
+		/**
+		 * bssid - BSSID of the received Probe Request frame or %NULL
+		 *	if not available
+		 */
+		const u8 *bssid;
+
+		/**
+		 * ie - IEs from the Probe Request body
+		 */
+		const u8 *ie;
+
+		/**
+		 * ie_len - Length of ie buffer in octets
+		 */
+		size_t ie_len;
+
+		/**
+		 * signal - signal strength in dBm (or 0 if not available)
+		 */
+		int ssi_signal;
+	} rx_probe_req;
+
+	/**
+	 * struct new_sta - Data for EVENT_NEW_STA events
+	 */
+	struct new_sta {
+		const u8 *addr;
+	} new_sta;
+
+	/**
+	 * struct eapol_rx - Data for EVENT_EAPOL_RX events
+	 */
+	struct eapol_rx {
+		const u8 *src;
+		const u8 *data;
+		size_t data_len;
+	} eapol_rx;
+
+	/**
+	 * signal_change - Data for EVENT_SIGNAL_CHANGE events
+	 */
+	struct wpa_signal_info signal_change;
+
+	/**
+	 * struct best_channel - Data for EVENT_BEST_CHANNEL events
+	 * @freq_24: Best 2.4 GHz band channel frequency in MHz
+	 * @freq_5: Best 5 GHz band channel frequency in MHz
+	 * @freq_overall: Best channel frequency in MHz
+	 *
+	 * 0 can be used to indicate no preference in either band.
+	 */
+	struct best_channel {
+		int freq_24;
+		int freq_5;
+		int freq_overall;
+	} best_chan;
+
+	struct unprot_deauth {
+		const u8 *sa;
+		const u8 *da;
+		u16 reason_code;
+	} unprot_deauth;
+
+	struct unprot_disassoc {
+		const u8 *sa;
+		const u8 *da;
+		u16 reason_code;
+	} unprot_disassoc;
+
+	/**
+	 * struct low_ack - Data for EVENT_STATION_LOW_ACK events
+	 * @addr: station address
+	 */
+	struct low_ack {
+		u8 addr[ETH_ALEN];
+	} low_ack;
+
+	/**
+	 * struct p2p_dev_found - Data for EVENT_P2P_DEV_FOUND
+	 */
+	struct p2p_dev_found {
+		const u8 *addr;
+		const u8 *dev_addr;
+		const u8 *pri_dev_type;
+		const char *dev_name;
+		u16 config_methods;
+		u8 dev_capab;
+		u8 group_capab;
+	} p2p_dev_found;
+
+	/**
+	 * struct p2p_go_neg_req_rx - Data for EVENT_P2P_GO_NEG_REQ_RX
+	 */
+	struct p2p_go_neg_req_rx {
+		const u8 *src;
+		u16 dev_passwd_id;
+	} p2p_go_neg_req_rx;
+
+	/**
+	 * struct p2p_go_neg_completed - Data for EVENT_P2P_GO_NEG_COMPLETED
+	 */
+	struct p2p_go_neg_completed {
+		struct p2p_go_neg_results *res;
+	} p2p_go_neg_completed;
+
+	struct p2p_prov_disc_req {
+		const u8 *peer;
+		u16 config_methods;
+		const u8 *dev_addr;
+		const u8 *pri_dev_type;
+		const char *dev_name;
+		u16 supp_config_methods;
+		u8 dev_capab;
+		u8 group_capab;
+	} p2p_prov_disc_req;
+
+	struct p2p_prov_disc_resp {
+		const u8 *peer;
+		u16 config_methods;
+	} p2p_prov_disc_resp;
+
+	struct p2p_sd_req {
+		int freq;
+		const u8 *sa;
+		u8 dialog_token;
+		u16 update_indic;
+		const u8 *tlvs;
+		size_t tlvs_len;
+	} p2p_sd_req;
+
+	struct p2p_sd_resp {
+		const u8 *sa;
+		u16 update_indic;
+		const u8 *tlvs;
+		size_t tlvs_len;
+	} p2p_sd_resp;
+
+	/**
+	 * struct ibss_peer_lost - Data for EVENT_IBSS_PEER_LOST
+	 */
+	struct ibss_peer_lost {
+		u8 peer[ETH_ALEN];
+	} ibss_peer_lost;
+
+	/**
+	 * struct driver_gtk_rekey - Data for EVENT_DRIVER_GTK_REKEY
+	 */
+	struct driver_gtk_rekey {
+		const u8 *bssid;
+		const u8 *replay_ctr;
+	} driver_gtk_rekey;
+
+	/**
+	 * struct client_poll - Data for EVENT_DRIVER_CLIENT_POLL_OK events
+	 * @addr: station address
+	 */
+	struct client_poll {
+		u8 addr[ETH_ALEN];
+	} client_poll;
+
+	/**
+	 * struct eapol_tx_status
+	 * @dst: Original destination
+	 * @data: Data starting with IEEE 802.1X header (!)
+	 * @data_len: Length of data
+	 * @ack: Indicates ack or lost frame
+	 *
+	 * This corresponds to hapd_send_eapol if the frame sent
+	 * there isn't just reported as EVENT_TX_STATUS.
+	 */
+	struct eapol_tx_status {
+		const u8 *dst;
+		const u8 *data;
+		int data_len;
+		int ack;
+	} eapol_tx_status;
+
+	/**
+	 * struct ch_switch
+	 * @freq: Frequency of new channel in MHz
+	 * @ht_enabled: Whether this is an HT channel
+	 * @ch_offset: Secondary channel offset
+	 */
+	struct ch_switch {
+		int freq;
+		int ht_enabled;
+		int ch_offset;
+	} ch_switch;
+};
+
+/**
+ * wpa_supplicant_event - Report a driver event for wpa_supplicant
+ * @ctx: Context pointer (wpa_s); this is the ctx variable registered
+ *	with struct wpa_driver_ops::init()
+ * @event: event type (defined above)
+ * @data: possible extra data for the event
+ *
+ * Driver wrapper code should call this function whenever an event is received
+ * from the driver.
+ */
+void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
+			  union wpa_event_data *data);
+
+
+/*
+ * The following inline functions are provided for convenience to simplify
+ * event indication for some of the common events.
+ */
+
+static inline void drv_event_assoc(void *ctx, const u8 *addr, const u8 *ie,
+				   size_t ielen, int reassoc)
+{
+	union wpa_event_data event;
+	os_memset(&event, 0, sizeof(event));
+	event.assoc_info.reassoc = reassoc;
+	event.assoc_info.req_ies = ie;
+	event.assoc_info.req_ies_len = ielen;
+	event.assoc_info.addr = addr;
+	wpa_supplicant_event(ctx, EVENT_ASSOC, &event);
+}
+
+static inline void drv_event_disassoc(void *ctx, const u8 *addr)
+{
+	union wpa_event_data event;
+	os_memset(&event, 0, sizeof(event));
+	event.disassoc_info.addr = addr;
+	wpa_supplicant_event(ctx, EVENT_DISASSOC, &event);
+}
+
+static inline void drv_event_eapol_rx(void *ctx, const u8 *src, const u8 *data,
+				      size_t data_len)
+{
+	union wpa_event_data event;
+	os_memset(&event, 0, sizeof(event));
+	event.eapol_rx.src = src;
+	event.eapol_rx.data = data;
+	event.eapol_rx.data_len = data_len;
+	wpa_supplicant_event(ctx, EVENT_EAPOL_RX, &event);
+}
+
+/* driver_common.c */
+void wpa_scan_results_free(struct wpa_scan_results *res);
+
+/* Convert wpa_event_type to a string for logging */
+const char * event_to_string(enum wpa_event_type event);
+
+#endif /* DRIVER_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/drivers/driver_common.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,86 @@
+/*
+ * Common driver-related functions
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include "utils/common.h"
+#include "driver.h"
+
+void wpa_scan_results_free(struct wpa_scan_results *res)
+{
+	size_t i;
+
+	if (res == NULL)
+		return;
+
+	for (i = 0; i < res->num; i++)
+		os_free(res->res[i]);
+	os_free(res->res);
+	os_free(res);
+}
+
+
+const char * event_to_string(enum wpa_event_type event)
+{
+#define E2S(n) case EVENT_ ## n: return #n
+	switch (event) {
+	E2S(ASSOC);
+	E2S(DISASSOC);
+	E2S(MICHAEL_MIC_FAILURE);
+	E2S(SCAN_RESULTS);
+	E2S(ASSOCINFO);
+	E2S(INTERFACE_STATUS);
+	E2S(PMKID_CANDIDATE);
+	E2S(STKSTART);
+	E2S(TDLS);
+	E2S(FT_RESPONSE);
+	E2S(IBSS_RSN_START);
+	E2S(AUTH);
+	E2S(DEAUTH);
+	E2S(ASSOC_REJECT);
+	E2S(AUTH_TIMED_OUT);
+	E2S(ASSOC_TIMED_OUT);
+	E2S(FT_RRB_RX);
+	E2S(WPS_BUTTON_PUSHED);
+	E2S(TX_STATUS);
+	E2S(RX_FROM_UNKNOWN);
+	E2S(RX_MGMT);
+	E2S(RX_ACTION);
+	E2S(REMAIN_ON_CHANNEL);
+	E2S(CANCEL_REMAIN_ON_CHANNEL);
+	E2S(MLME_RX);
+	E2S(RX_PROBE_REQ);
+	E2S(NEW_STA);
+	E2S(EAPOL_RX);
+	E2S(SIGNAL_CHANGE);
+	E2S(INTERFACE_ENABLED);
+	E2S(INTERFACE_DISABLED);
+	E2S(CHANNEL_LIST_CHANGED);
+	E2S(INTERFACE_UNAVAILABLE);
+	E2S(BEST_CHANNEL);
+	E2S(UNPROT_DEAUTH);
+	E2S(UNPROT_DISASSOC);
+	E2S(STATION_LOW_ACK);
+	E2S(P2P_DEV_FOUND);
+	E2S(P2P_GO_NEG_REQ_RX);
+	E2S(P2P_GO_NEG_COMPLETED);
+	E2S(P2P_PROV_DISC_REQUEST);
+	E2S(P2P_PROV_DISC_RESPONSE);
+	E2S(P2P_SD_REQUEST);
+	E2S(P2P_SD_RESPONSE);
+	E2S(IBSS_PEER_LOST);
+	E2S(DRIVER_GTK_REKEY);
+	E2S(SCHED_SCAN_STOPPED);
+	E2S(DRIVER_CLIENT_POLL_OK);
+	E2S(EAPOL_TX_STATUS);
+	E2S(CH_SWITCH);
+	E2S(WNM);
+	}
+
+	return "UNKNOWN";
+#undef E2S
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/drivers/driver_solaris.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,677 @@
+/*
+ * WPA Supplicant - driver interaction with Solaris dladm layer
+ * Copyright (c) 2004, Sam Leffler <sam@errno.com>
+ * Copyright (c) 2008, Sun Microsystems, Inc.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>
+ *
+ * Sun elects to license this software under the BSD license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <stddef.h>
+
+#include "includes.h"
+#include "common.h"
+#include "driver.h"
+#include "common/ieee802_11_defs.h"
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <door.h>
+#include <libdlwlan.h>
+#include <libdllink.h>
+#include <libdlpi.h>
+#include <inet/wifi_ioctl.h>
+
+typedef struct {
+	char link_name[MAXLINKNAMELEN];
+	char door_file[MAXLINKNAMELEN*2];
+	int door_id; /* descriptor returned by door_create() */
+	dladm_handle_t handle; /* dld_fd for link management */
+	dlpi_handle_t dlpi_handle; /* holds device driver registered */
+	datalink_id_t linkid; /* uninque link id used in dladm functions */
+	void *ctx; /* as of now wpa_s cookie is not used */
+} illumos_priv;
+
+static void
+solaris_event_handler(void *cookie, char *argp, size_t asize, door_desc_t *dp,
+    uint_t n_desc)
+{
+	wl_event_t *event = (wl_event_t *)argp;
+
+	/* Door lost. Do not remove/move this check! */
+	if (argp == DOOR_UNREF_DATA) {
+		wpa_printf(MSG_ERROR, "%s: Door lost", __func__);
+		return;
+	}
+
+	switch (event->wpa_ev_type) {
+	case EVENT_SCAN_RESULTS:
+	case EVENT_ASSOC:
+	case EVENT_DISASSOC:
+		wpa_supplicant_event(cookie, event->wpa_ev_type, NULL);
+		break;
+	case EVENT_INTERFACE_STATUS:
+		{
+		union wpa_event_data event_data;
+		os_memcpy(event_data.interface_status.ifname,
+		    event->wpa_ev_beacon, sizeof (event->wpa_ev_beacon));
+		event_data.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+		wpa_supplicant_event(cookie, event->wpa_ev_type, &event_data);
+		}
+		break;
+	case EVENT_ASSOC_REJECT:
+		{
+		union wpa_event_data event_data;
+		event_data.assoc_reject.bssid =
+		    malloc(sizeof (event->wpa_ev_beacon));
+		os_memcpy((void *)event_data.assoc_reject.bssid,
+		    event->wpa_ev_beacon, sizeof (event->wpa_ev_beacon));
+		event_data.assoc_reject.status_code = event->wpa_ev_reason;
+		wpa_supplicant_event(cookie, event->wpa_ev_type, &event_data);
+		}
+		break;
+	case EVENT_ASSOC_TIMED_OUT:
+		{
+		union wpa_event_data event_data;
+		os_memcpy(event_data.timeout_event.addr,
+		    event->wpa_ev_beacon, sizeof (event->wpa_ev_beacon));
+		wpa_supplicant_event(cookie, event->wpa_ev_type, &event_data);
+		}
+		break;
+	default:
+		wpa_printf(MSG_ERROR, "%s: Unsupported event type", __func__);
+	    	break;
+	}
+
+	if (door_return(NULL, 0, NULL, 0) == -1)
+		wpa_printf(MSG_ERROR, "%s: failed to return control to client"
+		    " after door invocation", __func__);
+}
+
+/*
+ * The data item, cookie, is associated  with the  door  descriptor,
+ * and is passed as an argument to the invoked function server_procedure during
+ * door_call(3C) invocations.
+ */
+static int
+solaris_door_setup(illumos_priv *data, void *cookie)
+{
+	struct stat statbuf;
+	int newfd;
+	wpa_printf(MSG_DEBUG, "%s: door path=(%s)", __func__, data->door_file);
+	/*
+	 * Create the door
+	 */
+	data->door_id = door_create(solaris_event_handler, cookie,
+	    DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
+
+	/*
+	 * TODO: we could use one door descriptor for every wpa_s instance
+	 * and wifi interface. This can be done binding more server thread
+	 * to the door descriptor. The client then would check the wpa_s unique
+	 * cookie value to select the proper thread and the thread event handler
+	 * would not process events with a different cookie value.
+	 * In this way we could delete the ieee80211_register_door calls in
+	 * every device driver
+	 */
+
+	if (data->door_id < 0) {
+		wpa_printf(MSG_ERROR, "%s: failed to create door descriptor \
+		    error= %s", __func__, strerror(errno));
+		return (-1);
+	}
+
+	if (stat(data->door_file, &statbuf) == 0) {
+		if (S_ISDOOR(statbuf.st_mode))
+			fdetach(data->door_file);
+	} else if ((newfd = creat(data->door_file, S_IRUSR | S_IWUSR)) != -1) {
+		if (close(newfd)) {
+			wpa_printf(MSG_ERROR, "%s: failed to close door file \
+			    descriptor. error= %s", __func__, strerror(errno));
+			return (-1);
+		}
+	} else {
+		wpa_printf(MSG_ERROR, "%s: failed to create door file \
+		    descriptor. error= %s", __func__, strerror(errno));
+		return (-1);
+	}
+
+	/*
+	 * Advertise the door in the file system namespace.
+	 */
+	if (fattach(data->door_id, data->door_file) == -1) {
+		wpa_printf(MSG_ERROR, "%s: failed to attach door file. \
+			    error= %s", __func__, strerror(errno));
+		return (-1);
+	}
+
+	return (0);
+}
+
+static void
+solaris_door_destroy(const illumos_priv *data)
+{
+	struct stat statbuf;
+	wpa_printf(MSG_DEBUG, "%s: (%s)", __func__, data->door_file);
+
+	if (stat(data->door_file, &statbuf) == -1) {
+		wpa_printf(MSG_ERROR, "%s: door file (%s) does not exist.\
+		    error= %s", __func__, data->door_file, strerror(errno));
+		return;
+	} else if (S_ISDOOR(statbuf.st_mode)) {
+		if (fdetach(data->door_file) < 0)
+			wpa_printf(MSG_ERROR, "%s: failed to fdetach %s: %s",
+			    __func__, data->door_file, strerror(errno));
+		else if (remove(data->door_file))
+			wpa_printf(MSG_ERROR, "%s: failed to remove %s: %s",
+			    __func__, data->door_file, strerror(errno));
+	} else if (remove(data->door_file)) {
+		wpa_printf(MSG_ERROR, "%s: failed to remove %s: %s", __func__,
+		    data->door_file, strerror(errno));
+	}
+
+	if (door_revoke(data->door_id) == -1)
+		wpa_printf(MSG_ERROR, "%s: door_revoke(%d) error= %s", __func__,
+		    data->door_id, strerror(errno));
+}
+
+/*
+ *
+ * ctx - Context to be used when calling wpa_supplicant functions e.g.,
+ * wpa_supplicant_event().
+ * Returns pointer to private data, NULL on failure.
+ * This function is called by wpa_drv_init defined in driver_i.h
+ * ctx points to a new wpa_supplicant data structure that will be fully
+ * allocated with parameters by wpa_supplicant_driver_init if
+ * this function returns correclty
+ */
+static void *
+wpa_driver_solaris_init(void *ctx, const char *ifname)
+{
+	illumos_priv *data = NULL;
+	dladm_status_t status;
+	uint32_t flags;
+	uint32_t media;
+	int res;
+
+	data = os_zalloc(sizeof (illumos_priv));
+	if (data == NULL)
+		return (NULL);
+
+	wpa_printf(MSG_DEBUG, "%s:Initializing interface %s", __func__, ifname);
+
+	/*
+	 * Hold this link open to prevent device driver from unregistering
+	 */
+	if ((res = dlpi_open(ifname, &data->dlpi_handle, 0)) != DLPI_SUCCESS) {
+		wpa_printf(MSG_ERROR, "%s: Failed to open link '%s' (err:%d)",
+		    __func__, ifname, res);
+		return (NULL);
+	}
+
+	if ((status = dladm_open(&data->handle)) != DLADM_STATUS_OK) {
+		char errbuf[DLADM_STRSIZE];
+		wpa_printf(MSG_ERROR, "%s: FAILED to open dladm handle (%s)",
+		    __func__, dladm_status2str(status, errbuf));
+		dlpi_close(data->dlpi_handle);
+		os_free(data);
+		return (NULL);
+	}
+
+	if ((status = dladm_name2info(data->handle, ifname, &data->linkid,
+	    &flags, NULL, &media)) != DLADM_STATUS_OK) {
+		wpa_printf(MSG_ERROR, "%s: Invalid link name '%s'", __func__,
+		    ifname);
+		dlpi_close(data->dlpi_handle);
+		dladm_close(data->handle);
+		os_free(data);
+		return (NULL);
+	} else if (media != DL_WIFI || !(flags & DLADM_OPT_ACTIVE)) {
+		wpa_printf(MSG_ERROR, "%s: Invalid link '%s'", __func__,
+		    ifname);
+		dlpi_close(data->dlpi_handle);
+		dladm_close(data->handle);
+		os_free(data);
+		return (NULL);
+	}
+
+	res = os_snprintf(data->door_file, sizeof (data->door_file), "%s_%s",
+	    WPA_DOOR, ifname);
+	if (res < 1 || res >= sizeof (data->door_file)) {
+		dlpi_close(data->dlpi_handle);
+		dladm_close(data->handle);
+		os_free(data);
+		return (NULL);
+	}
+	res = os_strlcpy(data->link_name, ifname, sizeof (data->link_name));
+	if (res < 1 || res >= sizeof (data->link_name)) {
+		dlpi_close(data->dlpi_handle);
+		dladm_close(data->handle);
+		os_free(data);
+		return (NULL);
+	}
+
+	data->ctx = ctx;
+
+	/*
+	 * Setup door file to communicate with driver
+	 */
+	if (solaris_door_setup(data, ctx) != 0) {
+		if (data->door_id > 0)
+			door_revoke(data->door_id);
+		dlpi_close(data->dlpi_handle);
+		dladm_close(data->handle);
+		os_free(data);
+		return (NULL);
+	}
+	return (data);
+}
+
+/*
+ * Free the private data. We must ensure all data is freed correclty with
+ * additional checks on return values
+ */
+static void
+wpa_driver_solaris_deinit(void *priv)
+{
+	illumos_priv *data = priv;
+
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+
+	solaris_door_destroy(data);
+	dladm_close(data->handle);
+	/* after this call the device driver will unregister from net80211 */
+	dlpi_close(data->dlpi_handle);
+
+	os_free(data);
+}
+
+/*
+ * bssid buffer for BSSID (ETH_ALEN = 6 bytes)
+ * Query kernel driver for the current BSSID and copy it to bssid.
+ * Setting bssid to 00:00:00:00:00:00 is recommended if the STA
+ * is not associated.
+ */
+static int
+wpa_driver_solaris_get_bssid(void *priv, u8 *bssid)
+{
+	const illumos_priv *data = priv;
+	if (dladm_wlan_get_bssid(data->handle, data->linkid, bssid))
+		return (-1);
+	wpa_printf(MSG_DEBUG, "%s: ieee80211com bssid = " MACSTR, __func__,
+	    MAC2STR(bssid));
+	return (0);
+}
+
+/*
+ * ssid buffer for SSID (at least 32 bytes)
+ * Returns length of the SSID on success, -1 on failure.
+ * Query kernel driver for the current SSID and copy it to ssid.
+ * Returning zero is recommended if the STA is not associated.
+ * Note: SSID is an array of octets, i.e., it is not nul terminated and
+ * can, at least in theory, contain control characters (including nul)
+ * and as such, should be processed as binary data,
+ * not a printable string.
+ */
+static int
+wpa_driver_solaris_get_ssid(void *priv, u8 *ssid)
+{
+	const illumos_priv *data = priv;
+	uint8_t essid_len;
+	if (dladm_wlan_get_essid(data->handle, data->linkid, ssid, &essid_len))
+		return (-1);
+	wpa_printf(MSG_DEBUG, "%s: ieee80211com essid = %s len=%d", __func__,
+	    ssid, essid_len);
+	return (essid_len);
+}
+
+static int
+wpa_driver_solaris_scan2(void *priv, struct wpa_driver_scan_params *params)
+{
+	const illumos_priv *data = priv;
+	dladm_status_t status;
+
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+	if ((status = dladm_wlan_cmd(data->link_name, WL_SCAN)) !=
+	    DLADM_STATUS_OK) {
+		char errbuf[DLADM_STRSIZE];
+		wpa_printf(MSG_ERROR, "%s: Scan Command Failed (err:%s)",
+		    __func__, dladm_status2str(status, errbuf));
+		return (-1);
+	}
+	return (0);
+}
+
+static void
+illumos_fill_results(wl_ess_conf_t *wlp, struct wpa_scan_results *results)
+{
+	struct wpa_scan_res *entry, **tmp;
+	size_t extra_len;
+	int i;
+	u8 *pos;
+
+	extra_len = 2 + wlp->wl_ess_conf_essid.wl_essid_length;
+	extra_len += wlp->wl_ess_conf_wpa_ie.wpa_ie_len;
+
+	entry = os_zalloc(sizeof (*entry) + extra_len);
+	if (entry == NULL)
+		return;
+
+	os_memcpy(entry->bssid, wlp->wl_ess_conf_bssid.wl_bssid_bssid,
+	    DLADM_WLAN_BSSID_LEN);
+	wl_phy_conf_t *phyp = &wlp->wl_ess_conf_phys;
+	wl_ofdm_t *wlop = &phyp->wl_phy_ofdm_conf;
+	entry->freq = wlop->wl_ofdm_frequency;
+	entry->beacon_int = wlp->wl_ess_conf_beacon_period;
+	entry->caps = wlp->wl_ess_conf_caps;
+	entry->level = wlp->wl_ess_conf_sl;
+	for (i = 0; i < wlp->wl_ess_conf_rates.wl_rates_num; i++) {
+		if (wlp->wl_ess_conf_rates.wl_rates_rates[i] > entry->qual)
+			entry->qual = wlp->wl_ess_conf_rates.wl_rates_rates[i];
+	}
+	entry->tsf = wlp->wl_ess_conf_beacon_tsf;
+	entry->age = wlp->wl_ess_conf_beacon_age;
+
+	pos = (u8 *)(entry + 1);
+
+	*pos++ = WLAN_EID_SSID;
+	*pos++ = wlp->wl_ess_conf_essid.wl_essid_length;
+	if (wlp->wl_ess_conf_essid.wl_essid_length != 0) {
+		os_memcpy(pos, wlp->wl_ess_conf_essid.wl_essid_essid,
+		    wlp->wl_ess_conf_essid.wl_essid_length);
+	}
+	pos += wlp->wl_ess_conf_essid.wl_essid_length;
+
+	if (wlp->wl_ess_conf_wpa_ie.wpa_ie_len != 0) {
+		os_memcpy(pos, wlp->wl_ess_conf_wpa_ie.wpa_ie,
+		    wlp->wl_ess_conf_wpa_ie.wpa_ie_len);
+		pos += wlp->wl_ess_conf_wpa_ie.wpa_ie_len;
+	}
+
+	entry->ie_len = pos - (u8 *)(entry + 1);
+
+	tmp = os_realloc(results->res,
+	    (results->num + 1) * sizeof (struct wpa_scan_res *));
+	if (tmp == NULL) {
+		os_free(entry);
+		return;
+	}
+	tmp[results->num++] = entry;
+	results->res = tmp;
+}
+
+static struct wpa_scan_results *
+wpa_driver_solaris_get_scan_results2(void *priv)
+{
+	const illumos_priv *data = priv;
+	wl_ess_conf_t *wlp = NULL;
+	wl_ess_list_t *wls = NULL;
+	struct wpa_scan_results *results = NULL;
+	dladm_status_t status;
+	int i;
+
+	/*
+	 * WLDP_BUFSIZE can contain more than 2800 wl_ess_conf_t.
+	 * we should use initially a smaller buffer. we start with 25.
+	 */
+	wls = calloc(25, sizeof (wl_ess_conf_t));
+	if (wls == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Cannot allocate "
+		    "space for scan results", __func__);
+		return (NULL);
+	}
+
+	if ((status = dladm_wlan_get_esslist(data->handle, data->linkid, wls,
+	    sizeof (wl_ess_conf_t) * 25)) != DLADM_STATUS_OK) {
+		if (status == DLADM_STATUS_TOOSMALL) {
+			wls = realloc(wls, WLDP_BUFSIZE);
+			if (wls == NULL) {
+				os_free(wls);
+				wpa_printf(MSG_ERROR, "%s: Cannot allocate more"
+				    "space for scan results", __func__);
+				return (NULL);
+			}
+			os_memset(wls, 0, WLDP_BUFSIZE);
+			if ((status = dladm_wlan_get_esslist(data->handle,
+			    data->linkid, wls, WLDP_BUFSIZE)) !=
+			    DLADM_STATUS_OK) {
+				wpa_printf(MSG_ERROR, "%s: Cannot get scan "
+				    "results err(%d)", __func__, status);
+				os_free(wls);
+				return (NULL);
+			}
+		} else {
+			wpa_printf(MSG_ERROR, "%s: Cannot get scan results"
+			    "err(%d)", __func__, status);
+			os_free(wls);
+			return (NULL);
+		}
+	}
+
+	results = os_zalloc(sizeof (struct wpa_scan_results));
+	if (results == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Cannot allocate "
+		    "space for scan results", __func__);
+		os_free(wls);
+		return (NULL);
+	}
+
+	if (wls->wl_ess_list_num == 0) {
+		wpa_printf(MSG_ERROR, "%s: Retrieved 0 scan results", __func__);
+		os_free(wls);
+		return (results);
+	}
+
+	wlp = wls->wl_ess_list_ess;
+	for (i = 0; i < wls->wl_ess_list_num; i++, wlp++)
+		illumos_fill_results(wlp, results);
+
+	wpa_printf(MSG_DEBUG, "%s: Retrieved %u BSSes from scan results",
+	    __func__, results->num);
+
+	os_free(wls);
+	return (results);
+}
+
+static int
+wpa_driver_solaris_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)
+{
+	const illumos_priv *data = priv;
+
+	dladm_status_t status;
+
+	if (alg != WPA_ALG_NONE) {
+		if (alg == WPA_ALG_WEP) {
+			wpa_printf(MSG_DEBUG,
+		    	    "%s: alg=%d key_idx=%d key_len=%zu", __func__, alg,
+		    	    key_idx, key_len);
+		} else {
+			wpa_printf(MSG_DEBUG,
+		    	    "%s: alg=%d addr=" MACSTR " key_idx=%d set_tx=%d "
+		    	    "seq_len=%zu key_len=%zu", __func__, alg,
+		    	    MAC2STR(addr), key_idx, set_tx, seq_len, key_len);
+		}
+	} else {
+		wpa_printf(MSG_DEBUG, "%s: del key %d", __func__, key_idx);
+	}
+
+	status = dladm_wlan_set_key(data->handle, data->linkid, alg, addr,
+	    key_idx, set_tx, seq, seq_len, key, key_len);
+	if (status != DLADM_STATUS_OK) {
+		char errbuf[DLADM_STRSIZE];
+		wpa_printf(MSG_ERROR, "%s: dladm_wlan_set_wpa_key error(%d) %s",
+		    __func__, status, dladm_status2str(status, errbuf));
+		return (-1);
+	}
+
+	return (0);
+}
+
+/**
+ * deauthenticate - Request driver to deauthenticate
+ * @priv: private driver interface data
+ * @addr: peer address (BSSID of the AP)
+ * @reason_code: 16-bit reason code to be sent in the deauthentication
+ *	frame
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int
+wpa_driver_solaris_deauthenticate(void *priv, const u8 *addr, int reason_code)
+{
+	const illumos_priv *data = priv;
+	wpa_printf(MSG_DEBUG, "%s", __func__);
+	if (dladm_wlan_set_mlme(data->handle, data->linkid, B_FALSE,
+	    reason_code, addr))
+		return (-1);
+	return (0);
+}
+
+/*
+ * @returns - 0 on success, -1 on failure
+ */
+static int
+wpa_driver_solaris_associate(void *priv,
+    struct wpa_driver_associate_params *params)
+{
+	const illumos_priv *data = priv;
+	wpa_printf(MSG_DEBUG,
+	    "%s: ssid '%.*s', mode %d, auth_alg %d, freq %d, wpa_proto %u,"
+	    "wpa_ie_len %u, pairwise %u, group %u, key_mgmt %u",
+	    __func__,
+	    params->ssid_len, params->ssid,
+	    params->mode,
+	    params->auth_alg,
+	    params->freq,
+	    params->wpa_proto,
+	    params->wpa_ie_len,
+	    params->pairwise_suite,
+	    params->group_suite,
+	    params->key_mgmt_suite);
+
+	if (dladm_wlan_set_bsstype(data->handle, data->linkid, params->mode))
+		return (-1);
+
+	if (dladm_wlan_set_authmode(data->handle, data->linkid,
+	    params->auth_alg))
+		return (-1);
+
+	/* These calls are already logged in kernel messages */
+	if (params->mode) {
+		if (dladm_wlan_set_channel(data->handle, data->linkid,
+		    params->freq))
+			return (-1);
+		if (dladm_wlan_createibss(data->handle, data->linkid))
+			return (-1);
+	}
+
+	/* wep */
+	if (params->key_mgmt_suite == KEY_MGMT_NONE && params->wpa_proto == 0 &&
+	    params->wep_key[params->wep_tx_keyidx] != NULL &&
+	    params->wep_key_len[params->wep_tx_keyidx] != 0) {
+		wpa_printf(MSG_DEBUG, "%s: Static Wep Secmode", __func__);
+	/* wpa-psk + wpa-eap */
+	} else if ((params->key_mgmt_suite <= KEY_MGMT_PSK ||
+	    params->key_mgmt_suite == KEY_MGMT_WPA_NONE) &&
+	    params->wpa_proto != 0 && params->wpa_ie != NULL &&
+	    params->wpa_ie_len != 0) {
+		if (dladm_wlan_set_wpa(data->handle, data->linkid))
+			return (-1);
+		wpa_printf(MSG_DEBUG, "%s: set wpa TRUE", __func__);
+		if (dladm_wlan_set_wpa_ie(data->handle, data->linkid,
+		    params->wpa_ie, params->wpa_ie_len))
+			return (-1);
+		wpa_printf(MSG_DEBUG, "%s: set wpa_ie, ie_len=%d", __func__,
+		    params->wpa_ie_len);
+	/* none */
+	} else if (params->key_mgmt_suite == KEY_MGMT_NONE &&
+	    params->wpa_proto == 0) {
+		wpa_printf(MSG_DEBUG, "%s: Plaintext, No Security", __func__);
+	} else {
+		wpa_printf(MSG_ERROR, "%s: Unsupported Secmode", __func__);
+		return (-1);
+	}
+
+	if (params->bssid != NULL) {
+		if (dladm_wlan_set_mlme(data->handle, data->linkid, B_TRUE, 0,
+		    params->bssid))
+			return (-1);
+	} else if (params->ssid != NULL) {
+		if (dladm_wlan_set_essid(data->handle, data->linkid,
+		    params->ssid, params->ssid_len))
+			return (-1);
+		wpa_printf(MSG_DEBUG, "%s: set ssid, ssid_len=%d", __func__,
+		    params->ssid_len);
+	} else {
+		wpa_printf(MSG_ERROR, "%s: both ESSID and BSSID are null",
+		    __func__);
+		return (-1);
+	}
+
+	return (0);
+}
+
+#define	IEEE80211_C_WPA			0x01800000
+
+/*
+ * NOT-USED
+ * static int
+ * wpa_driver_solaris_get_capa(void *priv, struct wpa_driver_capa *capa)
+ * {
+ *	const illumos_priv *data = priv;
+ *	wl_capability_t drivercaps;
+ *	if (dladm_wlan_get_capability(data->handle, data->linkid, &drivercaps,
+ *	    sizeof (drivercaps)))
+ *		return (-1);
+ *	wpa_printf(MSG_DEBUG, "%s: drv caps = %x", __func__, drivercaps);
+ *	capa->key_mgmt = 0x0000001F;
+ *	capa->enc = 0x0000000F;
+ *	capa->auth = 0x00000003;
+ * 	if (!(drivercaps & IEEE80211_C_WPA))
+ *		capa->key_mgmt = 0x00000000;
+ *	return (0);
+ * }
+ */
+
+/*
+ * Configure TKIP countermeasures. When these are enabled,
+ * the driver should drop all received and queued frames that are using TKIP.
+ */
+static int
+wpa_driver_solaris_set_countermeasures(void *priv, int enabled)
+{
+	const illumos_priv *data = priv;
+
+	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+	if (dladm_wlan_set_counterm(data->handle, data->linkid,
+	    enabled ? B_TRUE : B_FALSE))
+		return (-1);
+	return (0);
+}
+
+/*
+ * static int
+ * wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
+ * {
+ *	wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+ *	return set80211param(priv, IEEE80211_IOC_DROPUNENCRYPTED, enabled);
+ * }
+ */
+const struct wpa_driver_ops wpa_driver_solaris_ops = {
+	.name			= "solaris",
+	.desc			= "Solaris DLAPI wireless driver",
+	.init			= wpa_driver_solaris_init,
+	.deinit			= wpa_driver_solaris_deinit,
+	.get_bssid		= wpa_driver_solaris_get_bssid,
+	.get_ssid		= wpa_driver_solaris_get_ssid,
+	.set_key		= wpa_driver_solaris_set_key,
+	.associate		= wpa_driver_solaris_associate,
+	.deauthenticate		= wpa_driver_solaris_deauthenticate,
+	.get_scan_results2	= wpa_driver_solaris_get_scan_results2,
+	.set_countermeasures	= wpa_driver_solaris_set_countermeasures,
+	.scan2			= wpa_driver_solaris_scan2,
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/drivers/drivers.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,90 @@
+/*
+ * Driver interface list
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+
+#ifdef CONFIG_DRIVER_WEXT
+extern struct wpa_driver_ops wpa_driver_wext_ops; /* driver_wext.c */
+#endif /* CONFIG_DRIVER_WEXT */
+#ifdef CONFIG_DRIVER_NL80211
+extern struct wpa_driver_ops wpa_driver_nl80211_ops; /* driver_nl80211.c */
+#endif /* CONFIG_DRIVER_NL80211 */
+#ifdef CONFIG_DRIVER_HOSTAP
+extern struct wpa_driver_ops wpa_driver_hostap_ops; /* driver_hostap.c */
+#endif /* CONFIG_DRIVER_HOSTAP */
+#ifdef CONFIG_DRIVER_MADWIFI
+extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
+#endif /* CONFIG_DRIVER_MADWIFI */
+#ifdef CONFIG_DRIVER_BSD
+extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
+#endif /* CONFIG_DRIVER_BSD */
+#ifdef CONFIG_DRIVER_NDIS
+extern struct wpa_driver_ops wpa_driver_ndis_ops; /* driver_ndis.c */
+#endif /* CONFIG_DRIVER_NDIS */
+#ifdef CONFIG_DRIVER_WIRED
+extern struct wpa_driver_ops wpa_driver_wired_ops; /* driver_wired.c */
+#endif /* CONFIG_DRIVER_WIRED */
+#ifdef CONFIG_DRIVER_TEST
+extern struct wpa_driver_ops wpa_driver_test_ops; /* driver_test.c */
+#endif /* CONFIG_DRIVER_TEST */
+#ifdef CONFIG_DRIVER_ROBOSWITCH
+/* driver_roboswitch.c */
+extern struct wpa_driver_ops wpa_driver_roboswitch_ops;
+#endif /* CONFIG_DRIVER_ROBOSWITCH */
+#ifdef CONFIG_DRIVER_ATHEROS
+extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */
+#endif /* CONFIG_DRIVER_ATHEROS */
+#ifdef CONFIG_DRIVER_NONE
+extern struct wpa_driver_ops wpa_driver_none_ops; /* driver_none.c */
+#endif /* CONFIG_DRIVER_NONE */
+#ifdef CONFIG_DRIVER_SOLARIS
+extern struct wpa_driver_ops wpa_driver_solaris_ops; /* driver_solaris.c */
+#endif /* CONFIG_DRIVER_SOLARIS */
+
+
+struct wpa_driver_ops *wpa_drivers[] =
+{
+#ifdef CONFIG_DRIVER_WEXT
+	&wpa_driver_wext_ops,
+#endif /* CONFIG_DRIVER_WEXT */
+#ifdef CONFIG_DRIVER_NL80211
+	&wpa_driver_nl80211_ops,
+#endif /* CONFIG_DRIVER_NL80211 */
+#ifdef CONFIG_DRIVER_HOSTAP
+	&wpa_driver_hostap_ops,
+#endif /* CONFIG_DRIVER_HOSTAP */
+#ifdef CONFIG_DRIVER_MADWIFI
+	&wpa_driver_madwifi_ops,
+#endif /* CONFIG_DRIVER_MADWIFI */
+#ifdef CONFIG_DRIVER_BSD
+	&wpa_driver_bsd_ops,
+#endif /* CONFIG_DRIVER_BSD */
+#ifdef CONFIG_DRIVER_NDIS
+	&wpa_driver_ndis_ops,
+#endif /* CONFIG_DRIVER_NDIS */
+#ifdef CONFIG_DRIVER_WIRED
+	&wpa_driver_wired_ops,
+#endif /* CONFIG_DRIVER_WIRED */
+#ifdef CONFIG_DRIVER_TEST
+	&wpa_driver_test_ops,
+#endif /* CONFIG_DRIVER_TEST */
+#ifdef CONFIG_DRIVER_ROBOSWITCH
+	&wpa_driver_roboswitch_ops,
+#endif /* CONFIG_DRIVER_ROBOSWITCH */
+#ifdef CONFIG_DRIVER_ATHEROS
+	&wpa_driver_atheros_ops,
+#endif /* CONFIG_DRIVER_ATHEROS */
+#ifdef CONFIG_DRIVER_NONE
+	&wpa_driver_none_ops,
+#endif /* CONFIG_DRIVER_NONE */
+#ifdef CONFIG_DRIVER_SOLARIS
+	&wpa_driver_solaris_ops,
+#endif /* CONFIG_DRIVER_SOLARIS */
+	NULL
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/chap.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,28 @@
+/*
+ * CHAP-MD5 (RFC 1994)
+ * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/crypto.h"
+#include "chap.h"
+
+int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge,
+	      size_t challenge_len, u8 *response)
+{
+	const u8 *addr[3];
+	size_t len[3];
+
+	addr[0] = &id;
+	len[0] = 1;
+	addr[1] = secret;
+	len[1] = secret_len;
+	addr[2] = challenge;
+	len[2] = challenge_len;
+	return md5_vector(3, addr, len, response);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/chap.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,17 @@
+/*
+ * CHAP-MD5 (RFC 1994)
+ * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CHAP_H
+#define CHAP_H
+
+#define CHAP_MD5_LEN 16
+
+int chap_md5(u8 id, const u8 *secret, size_t secret_len, const u8 *challenge,
+	     size_t challenge_len, u8 *response);
+
+#endif /* CHAP_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_common.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,205 @@
+/*
+ * EAP common peer/server definitions
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_defs.h"
+#include "eap_common.h"
+
+/**
+ * eap_hdr_len_valid - Validate EAP header length field
+ * @msg: EAP frame (starting with EAP header)
+ * @min_payload: Minimum payload length needed
+ * Returns: 1 for valid header, 0 for invalid
+ *
+ * This is a helper function that does minimal validation of EAP messages. The
+ * length field is verified to be large enough to include the header and not
+ * too large to go beyond the end of the buffer.
+ */
+int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload)
+{
+	const struct eap_hdr *hdr;
+	size_t len;
+
+	if (msg == NULL)
+		return 0;
+
+	hdr = wpabuf_head(msg);
+
+	if (wpabuf_len(msg) < sizeof(*hdr)) {
+		wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
+		return 0;
+	}
+
+	len = be_to_host16(hdr->length);
+	if (len < sizeof(*hdr) + min_payload || len > wpabuf_len(msg)) {
+		wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
+		return 0;
+	}
+
+	return 1;
+}
+
+
+/**
+ * eap_hdr_validate - Validate EAP header
+ * @vendor: Expected EAP Vendor-Id (0 = IETF)
+ * @eap_type: Expected EAP type number
+ * @msg: EAP frame (starting with EAP header)
+ * @plen: Pointer to variable to contain the returned payload length
+ * Returns: Pointer to EAP payload (after type field), or %NULL on failure
+ *
+ * This is a helper function for EAP method implementations. This is usually
+ * called in the beginning of struct eap_method::process() function to verify
+ * that the received EAP request packet has a valid header. This function is
+ * able to process both legacy and expanded EAP headers and in most cases, the
+ * caller can just use the returned payload pointer (into *plen) for processing
+ * the payload regardless of whether the packet used the expanded EAP header or
+ * not.
+ */
+const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+			    const struct wpabuf *msg, size_t *plen)
+{
+	const struct eap_hdr *hdr;
+	const u8 *pos;
+	size_t len;
+
+	if (!eap_hdr_len_valid(msg, 1))
+		return NULL;
+
+	hdr = wpabuf_head(msg);
+	len = be_to_host16(hdr->length);
+	pos = (const u8 *) (hdr + 1);
+
+	if (*pos == EAP_TYPE_EXPANDED) {
+		int exp_vendor;
+		u32 exp_type;
+		if (len < sizeof(*hdr) + 8) {
+			wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP "
+				   "length");
+			return NULL;
+		}
+		pos++;
+		exp_vendor = WPA_GET_BE24(pos);
+		pos += 3;
+		exp_type = WPA_GET_BE32(pos);
+		pos += 4;
+		if (exp_vendor != vendor || exp_type != (u32) eap_type) {
+			wpa_printf(MSG_INFO, "EAP: Invalid expanded frame "
+				   "type");
+			return NULL;
+		}
+
+		*plen = len - sizeof(*hdr) - 8;
+		return pos;
+	} else {
+		if (vendor != EAP_VENDOR_IETF || *pos != eap_type) {
+			wpa_printf(MSG_INFO, "EAP: Invalid frame type");
+			return NULL;
+		}
+		*plen = len - sizeof(*hdr) - 1;
+		return pos + 1;
+	}
+}
+
+
+/**
+ * eap_msg_alloc - Allocate a buffer for an EAP message
+ * @vendor: Vendor-Id (0 = IETF)
+ * @type: EAP type
+ * @payload_len: Payload length in bytes (data after Type)
+ * @code: Message Code (EAP_CODE_*)
+ * @identifier: Identifier
+ * Returns: Pointer to the allocated message buffer or %NULL on error
+ *
+ * This function can be used to allocate a buffer for an EAP message and fill
+ * in the EAP header. This function is automatically using expanded EAP header
+ * if the selected Vendor-Id is not IETF. In other words, most EAP methods do
+ * not need to separately select which header type to use when using this
+ * function to allocate the message buffers. The returned buffer has room for
+ * payload_len bytes and has the EAP header and Type field already filled in.
+ */
+struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
+			      u8 code, u8 identifier)
+{
+	struct wpabuf *buf;
+	struct eap_hdr *hdr;
+	size_t len;
+
+	len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) +
+		payload_len;
+	buf = wpabuf_alloc(len);
+	if (buf == NULL)
+		return NULL;
+
+	hdr = wpabuf_put(buf, sizeof(*hdr));
+	hdr->code = code;
+	hdr->identifier = identifier;
+	hdr->length = host_to_be16(len);
+
+	if (vendor == EAP_VENDOR_IETF) {
+		wpabuf_put_u8(buf, type);
+	} else {
+		wpabuf_put_u8(buf, EAP_TYPE_EXPANDED);
+		wpabuf_put_be24(buf, vendor);
+		wpabuf_put_be32(buf, type);
+	}
+
+	return buf;
+}
+
+
+/**
+ * eap_update_len - Update EAP header length
+ * @msg: EAP message from eap_msg_alloc
+ *
+ * This function updates the length field in the EAP header to match with the
+ * current length for the buffer. This allows eap_msg_alloc() to be used to
+ * allocate a larger buffer than the exact message length (e.g., if exact
+ * message length is not yet known).
+ */
+void eap_update_len(struct wpabuf *msg)
+{
+	struct eap_hdr *hdr;
+	hdr = wpabuf_mhead(msg);
+	if (wpabuf_len(msg) < sizeof(*hdr))
+		return;
+	hdr->length = host_to_be16(wpabuf_len(msg));
+}
+
+
+/**
+ * eap_get_id - Get EAP Identifier from wpabuf
+ * @msg: Buffer starting with an EAP header
+ * Returns: The Identifier field from the EAP header
+ */
+u8 eap_get_id(const struct wpabuf *msg)
+{
+	const struct eap_hdr *eap;
+
+	if (wpabuf_len(msg) < sizeof(*eap))
+		return 0;
+
+	eap = wpabuf_head(msg);
+	return eap->identifier;
+}
+
+
+/**
+ * eap_get_id - Get EAP Type from wpabuf
+ * @msg: Buffer starting with an EAP header
+ * Returns: The EAP Type after the EAP header
+ */
+EapType eap_get_type(const struct wpabuf *msg)
+{
+	if (wpabuf_len(msg) < sizeof(struct eap_hdr) + 1)
+		return EAP_TYPE_NONE;
+
+	return ((const u8 *) wpabuf_head(msg))[sizeof(struct eap_hdr)];
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_common.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,23 @@
+/*
+ * EAP common peer/server definitions
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_COMMON_H
+#define EAP_COMMON_H
+
+#include "wpabuf.h"
+
+int eap_hdr_len_valid(const struct wpabuf *msg, size_t min_payload);
+const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+			    const struct wpabuf *msg, size_t *plen);
+struct wpabuf * eap_msg_alloc(int vendor, EapType type, size_t payload_len,
+			      u8 code, u8 identifier);
+void eap_update_len(struct wpabuf *msg);
+u8 eap_get_id(const struct wpabuf *msg);
+EapType eap_get_type(const struct wpabuf *msg);
+
+#endif /* EAP_COMMON_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_defs.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,84 @@
+/*
+ * EAP server/peer: Shared EAP definitions
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_DEFS_H
+#define EAP_DEFS_H
+
+/* RFC 3748 - Extensible Authentication Protocol (EAP) */
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct eap_hdr {
+	u8 code;
+	u8 identifier;
+	be16 length; /* including code and identifier; network byte order */
+	/* followed by length-4 octets of data */
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,
+       EAP_CODE_FAILURE = 4 };
+
+/* EAP Request and Response data begins with one octet Type. Success and
+ * Failure do not have additional data. */
+
+/*
+ * EAP Method Types as allocated by IANA:
+ * http://www.iana.org/assignments/eap-numbers
+ */
+typedef enum {
+	EAP_TYPE_NONE = 0,
+	EAP_TYPE_IDENTITY = 1 /* RFC 3748 */,
+	EAP_TYPE_NOTIFICATION = 2 /* RFC 3748 */,
+	EAP_TYPE_NAK = 3 /* Response only, RFC 3748 */,
+	EAP_TYPE_MD5 = 4, /* RFC 3748 */
+	EAP_TYPE_OTP = 5 /* RFC 3748 */,
+	EAP_TYPE_GTC = 6, /* RFC 3748 */
+	EAP_TYPE_TLS = 13 /* RFC 2716 */,
+	EAP_TYPE_LEAP = 17 /* Cisco proprietary */,
+	EAP_TYPE_SIM = 18 /* RFC 4186 */,
+	EAP_TYPE_TTLS = 21 /* RFC 5281 */,
+	EAP_TYPE_AKA = 23 /* RFC 4187 */,
+	EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */,
+	EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */,
+	EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */,
+	EAP_TYPE_TNC = 38 /* TNC IF-T v1.0-r3; note: tentative assignment;
+			   * type 38 has previously been allocated for
+			   * EAP-HTTP Digest, (funk.com) */,
+	EAP_TYPE_FAST = 43 /* RFC 4851 */,
+	EAP_TYPE_PAX = 46 /* RFC 4746 */,
+	EAP_TYPE_PSK = 47 /* RFC 4764 */,
+	EAP_TYPE_SAKE = 48 /* RFC 4763 */,
+	EAP_TYPE_IKEV2 = 49 /* RFC 5106 */,
+	EAP_TYPE_AKA_PRIME = 50 /* RFC 5448 */,
+	EAP_TYPE_GPSK = 51 /* RFC 5433 */,
+	EAP_TYPE_PWD = 52 /* RFC 5931 */,
+	EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
+} EapType;
+
+
+/* SMI Network Management Private Enterprise Code for vendor specific types */
+enum {
+	EAP_VENDOR_IETF = 0,
+	EAP_VENDOR_MICROSOFT = 0x000137 /* Microsoft */,
+	EAP_VENDOR_WFA = 0x00372A /* Wi-Fi Alliance */,
+	EAP_VENDOR_HOSTAP = 39068 /* hostapd/wpa_supplicant project */
+};
+
+#define EAP_VENDOR_UNAUTH_TLS EAP_VENDOR_HOSTAP
+#define EAP_VENDOR_TYPE_UNAUTH_TLS 1
+
+#define EAP_MSK_LEN 64
+#define EAP_EMSK_LEN 64
+
+#endif /* EAP_DEFS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_peap_common.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,85 @@
+/*
+ * EAP-PEAP common routines
+ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/sha1.h"
+#include "eap_peap_common.h"
+
+int peap_prfplus(int version, const u8 *key, size_t key_len,
+		 const char *label, const u8 *seed, size_t seed_len,
+		 u8 *buf, size_t buf_len)
+{
+	unsigned char counter = 0;
+	size_t pos, plen;
+	u8 hash[SHA1_MAC_LEN];
+	size_t label_len = os_strlen(label);
+	u8 extra[2];
+	const unsigned char *addr[5];
+	size_t len[5];
+
+	addr[0] = hash;
+	len[0] = 0;
+	addr[1] = (unsigned char *) label;
+	len[1] = label_len;
+	addr[2] = seed;
+	len[2] = seed_len;
+
+	if (version == 0) {
+		/*
+		 * PRF+(K, S, LEN) = T1 | T2 | ... | Tn
+		 * T1 = HMAC-SHA1(K, S | 0x01 | 0x00 | 0x00)
+		 * T2 = HMAC-SHA1(K, T1 | S | 0x02 | 0x00 | 0x00)
+		 * ...
+		 * Tn = HMAC-SHA1(K, Tn-1 | S | n | 0x00 | 0x00)
+		 */
+
+		extra[0] = 0;
+		extra[1] = 0;
+
+		addr[3] = &counter;
+		len[3] = 1;
+		addr[4] = extra;
+		len[4] = 2;
+	} else {
+		/*
+		 * PRF (K,S,LEN) = T1 | T2 | T3 | T4 | ... where:
+		 * T1 = HMAC-SHA1(K, S | LEN | 0x01)
+		 * T2 = HMAC-SHA1 (K, T1 | S | LEN | 0x02)
+		 * T3 = HMAC-SHA1 (K, T2 | S | LEN | 0x03)
+		 * T4 = HMAC-SHA1 (K, T3 | S | LEN | 0x04)
+		 *   ...
+		 */
+
+		extra[0] = buf_len & 0xff;
+
+		addr[3] = extra;
+		len[3] = 1;
+		addr[4] = &counter;
+		len[4] = 1;
+	}
+
+	pos = 0;
+	while (pos < buf_len) {
+		counter++;
+		plen = buf_len - pos;
+		if (hmac_sha1_vector(key, key_len, 5, addr, len, hash) < 0)
+			return -1;
+		if (plen >= SHA1_MAC_LEN) {
+			os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
+			pos += SHA1_MAC_LEN;
+		} else {
+			os_memcpy(&buf[pos], hash, plen);
+			break;
+		}
+		len[0] = SHA1_MAC_LEN;
+	}
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_peap_common.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,16 @@
+/*
+ * EAP-PEAP common routines
+ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_PEAP_COMMON_H
+#define EAP_PEAP_COMMON_H
+
+int peap_prfplus(int version, const u8 *key, size_t key_len,
+		 const char *label, const u8 *seed, size_t seed_len,
+		 u8 *buf, size_t buf_len);
+
+#endif /* EAP_PEAP_COMMON_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_tlv_common.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,112 @@
+/*
+ * EAP-TLV definitions (draft-josefsson-pppext-eap-tls-eap-10.txt)
+ * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_TLV_COMMON_H
+#define EAP_TLV_COMMON_H
+
+/* EAP-TLV TLVs (draft-josefsson-ppext-eap-tls-eap-10.txt) */
+#define EAP_TLV_RESULT_TLV 3 /* Acknowledged Result */
+#define EAP_TLV_NAK_TLV 4
+#define EAP_TLV_ERROR_CODE_TLV 5
+#define EAP_TLV_CONNECTION_BINDING_TLV 6
+#define EAP_TLV_VENDOR_SPECIFIC_TLV 7
+#define EAP_TLV_URI_TLV 8
+#define EAP_TLV_EAP_PAYLOAD_TLV 9
+#define EAP_TLV_INTERMEDIATE_RESULT_TLV 10
+#define EAP_TLV_PAC_TLV 11 /* RFC 5422, Section 4.2 */
+#define EAP_TLV_CRYPTO_BINDING_TLV 12
+#define EAP_TLV_CALLING_STATION_ID_TLV 13
+#define EAP_TLV_CALLED_STATION_ID_TLV 14
+#define EAP_TLV_NAS_PORT_TYPE_TLV 15
+#define EAP_TLV_SERVER_IDENTIFIER_TLV 16
+#define EAP_TLV_IDENTITY_TYPE_TLV 17
+#define EAP_TLV_SERVER_TRUSTED_ROOT_TLV 18
+#define EAP_TLV_REQUEST_ACTION_TLV 19
+#define EAP_TLV_PKCS7_TLV 20
+
+#define EAP_TLV_RESULT_SUCCESS 1
+#define EAP_TLV_RESULT_FAILURE 2
+
+#define EAP_TLV_TYPE_MANDATORY 0x8000
+#define EAP_TLV_TYPE_MASK 0x3fff
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct eap_tlv_hdr {
+	be16 tlv_type;
+	be16 length;
+} STRUCT_PACKED;
+
+struct eap_tlv_nak_tlv {
+	be16 tlv_type;
+	be16 length;
+	be32 vendor_id;
+	be16 nak_type;
+} STRUCT_PACKED;
+
+struct eap_tlv_result_tlv {
+	be16 tlv_type;
+	be16 length;
+	be16 status;
+} STRUCT_PACKED;
+
+/* RFC 4851, Section 4.2.7 - Intermediate-Result TLV */
+struct eap_tlv_intermediate_result_tlv {
+	be16 tlv_type;
+	be16 length;
+	be16 status;
+	/* Followed by optional TLVs */
+} STRUCT_PACKED;
+
+/* RFC 4851, Section 4.2.8 - Crypto-Binding TLV */
+struct eap_tlv_crypto_binding_tlv {
+	be16 tlv_type;
+	be16 length;
+	u8 reserved;
+	u8 version;
+	u8 received_version;
+	u8 subtype;
+	u8 nonce[32];
+	u8 compound_mac[20];
+} STRUCT_PACKED;
+
+struct eap_tlv_pac_ack_tlv {
+	be16 tlv_type;
+	be16 length;
+	be16 pac_type;
+	be16 pac_len;
+	be16 result;
+} STRUCT_PACKED;
+
+/* RFC 4851, Section 4.2.9 - Request-Action TLV */
+struct eap_tlv_request_action_tlv {
+	be16 tlv_type;
+	be16 length;
+	be16 action;
+} STRUCT_PACKED;
+
+/* RFC 5422, Section 4.2.6 - PAC-Type TLV */
+struct eap_tlv_pac_type_tlv {
+	be16 tlv_type; /* PAC_TYPE_PAC_TYPE */
+	be16 length;
+	be16 pac_type;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_REQUEST 0
+#define EAP_TLV_CRYPTO_BINDING_SUBTYPE_RESPONSE 1
+
+#define EAP_TLV_ACTION_PROCESS_TLV 1
+#define EAP_TLV_ACTION_NEGOTIATE_EAP 2
+
+#endif /* EAP_TLV_COMMON_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_ttls.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,65 @@
+/*
+ * EAP server/peer: EAP-TTLS (RFC 5281)
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_TTLS_H
+#define EAP_TTLS_H
+
+struct ttls_avp {
+	be32 avp_code;
+	be32 avp_length; /* 8-bit flags, 24-bit length;
+			  * length includes AVP header */
+	/* optional 32-bit Vendor-ID */
+	/* Data */
+};
+
+struct ttls_avp_vendor {
+	be32 avp_code;
+	be32 avp_length; /* 8-bit flags, 24-bit length;
+			  * length includes AVP header */
+	be32 vendor_id;
+	/* Data */
+};
+
+#define AVP_FLAGS_VENDOR 0x80
+#define AVP_FLAGS_MANDATORY 0x40
+
+#define AVP_PAD(start, pos) \
+do { \
+	int __pad; \
+	__pad = (4 - (((pos) - (start)) & 3)) & 3; \
+	os_memset((pos), 0, __pad); \
+	pos += __pad; \
+} while (0)
+
+
+/* RFC 2865 */
+#define RADIUS_ATTR_USER_NAME 1
+#define RADIUS_ATTR_USER_PASSWORD 2
+#define RADIUS_ATTR_CHAP_PASSWORD 3
+#define RADIUS_ATTR_REPLY_MESSAGE 18
+#define RADIUS_ATTR_CHAP_CHALLENGE 60
+#define RADIUS_ATTR_EAP_MESSAGE 79
+
+/* RFC 2548 */
+#define RADIUS_VENDOR_ID_MICROSOFT 311
+#define RADIUS_ATTR_MS_CHAP_RESPONSE 1
+#define RADIUS_ATTR_MS_CHAP_ERROR 2
+#define RADIUS_ATTR_MS_CHAP_NT_ENC_PW 6
+#define RADIUS_ATTR_MS_CHAP_CHALLENGE 11
+#define RADIUS_ATTR_MS_CHAP2_RESPONSE 25
+#define RADIUS_ATTR_MS_CHAP2_SUCCESS 26
+#define RADIUS_ATTR_MS_CHAP2_CPW 27
+
+#define EAP_TTLS_MSCHAPV2_CHALLENGE_LEN 16
+#define EAP_TTLS_MSCHAPV2_RESPONSE_LEN 50
+#define EAP_TTLS_MSCHAP_CHALLENGE_LEN 8
+#define EAP_TTLS_MSCHAP_RESPONSE_LEN 50
+#define EAP_TTLS_CHAP_CHALLENGE_LEN 16
+#define EAP_TTLS_CHAP_PASSWORD_LEN 16
+
+#endif /* EAP_TTLS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_common/eap_wsc_common.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,27 @@
+/*
+ * EAP-WSC definitions for Wi-Fi Protected Setup
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_WSC_COMMON_H
+#define EAP_WSC_COMMON_H
+
+#define EAP_VENDOR_TYPE_WSC 1
+
+#define WSC_FLAGS_MF 0x01
+#define WSC_FLAGS_LF 0x02
+
+#define WSC_ID_REGISTRAR "WFA-SimpleConfig-Registrar-1-0"
+#define WSC_ID_REGISTRAR_LEN 30
+#define WSC_ID_ENROLLEE "WFA-SimpleConfig-Enrollee-1-0"
+#define WSC_ID_ENROLLEE_LEN 29
+
+#define WSC_FRAGMENT_SIZE 1400
+
+
+struct wpabuf * eap_wsc_build_frag_ack(u8 id, u8 code);
+
+#endif /* EAP_WSC_COMMON_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,2339 @@
+/*
+ * EAP peer state machines (RFC 4137)
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file implements the Peer State Machine as defined in RFC 4137. The used
+ * states and state transitions match mostly with the RFC. However, there are
+ * couple of additional transitions for working around small issues noticed
+ * during testing. These exceptions are explained in comments within the
+ * functions in this file. The method functions, m.func(), are similar to the
+ * ones used in RFC 4137, but some small changes have used here to optimize
+ * operations and to add functionality needed for fast re-authentication
+ * (session resumption).
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "pcsc_funcs.h"
+#include "state_machine.h"
+#include "ext_password.h"
+#include "crypto/crypto.h"
+#include "crypto/tls.h"
+#include "common/wpa_ctrl.h"
+#include "eap_common/eap_wsc_common.h"
+#include "eap_i.h"
+#include "eap_config.h"
+
+#define STATE_MACHINE_DATA struct eap_sm
+#define STATE_MACHINE_DEBUG_PREFIX "EAP"
+
+#define EAP_MAX_AUTH_ROUNDS 50
+#define EAP_CLIENT_TIMEOUT_DEFAULT 60
+
+
+static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
+				  EapType method);
+static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id);
+static void eap_sm_processIdentity(struct eap_sm *sm,
+				   const struct wpabuf *req);
+static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req);
+static struct wpabuf * eap_sm_buildNotify(int id);
+static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req);
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static const char * eap_sm_method_state_txt(EapMethodState state);
+static const char * eap_sm_decision_txt(EapDecision decision);
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+
+
+
+static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
+{
+	return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
+}
+
+
+static void eapol_set_bool(struct eap_sm *sm, enum eapol_bool_var var,
+			   Boolean value)
+{
+	sm->eapol_cb->set_bool(sm->eapol_ctx, var, value);
+}
+
+
+static unsigned int eapol_get_int(struct eap_sm *sm, enum eapol_int_var var)
+{
+	return sm->eapol_cb->get_int(sm->eapol_ctx, var);
+}
+
+
+static void eapol_set_int(struct eap_sm *sm, enum eapol_int_var var,
+			  unsigned int value)
+{
+	sm->eapol_cb->set_int(sm->eapol_ctx, var, value);
+}
+
+
+static struct wpabuf * eapol_get_eapReqData(struct eap_sm *sm)
+{
+	return sm->eapol_cb->get_eapReqData(sm->eapol_ctx);
+}
+
+
+static void eap_notify_status(struct eap_sm *sm, const char *status,
+				      const char *parameter)
+{
+	wpa_printf(MSG_DEBUG, "EAP: Status notification: %s (param=%s)",
+		   status, parameter);
+	if (sm->eapol_cb->notify_status)
+		sm->eapol_cb->notify_status(sm->eapol_ctx, status, parameter);
+}
+
+
+static void eap_deinit_prev_method(struct eap_sm *sm, const char *txt)
+{
+	ext_password_free(sm->ext_pw_buf);
+	sm->ext_pw_buf = NULL;
+
+	if (sm->m == NULL || sm->eap_method_priv == NULL)
+		return;
+
+	wpa_printf(MSG_DEBUG, "EAP: deinitialize previously used EAP method "
+		   "(%d, %s) at %s", sm->selectedMethod, sm->m->name, txt);
+	sm->m->deinit(sm, sm->eap_method_priv);
+	sm->eap_method_priv = NULL;
+	sm->m = NULL;
+}
+
+
+/**
+ * eap_allowed_method - Check whether EAP method is allowed
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @vendor: Vendor-Id for expanded types or 0 = IETF for legacy types
+ * @method: EAP type
+ * Returns: 1 = allowed EAP method, 0 = not allowed
+ */
+int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	int i;
+	struct eap_method_type *m;
+
+	if (config == NULL || config->eap_methods == NULL)
+		return 1;
+
+	m = config->eap_methods;
+	for (i = 0; m[i].vendor != EAP_VENDOR_IETF ||
+		     m[i].method != EAP_TYPE_NONE; i++) {
+		if (m[i].vendor == vendor && m[i].method == method)
+			return 1;
+	}
+	return 0;
+}
+
+
+/*
+ * This state initializes state machine variables when the machine is
+ * activated (portEnabled = TRUE). This is also used when re-starting
+ * authentication (eapRestart == TRUE).
+ */
+SM_STATE(EAP, INITIALIZE)
+{
+	SM_ENTRY(EAP, INITIALIZE);
+	if (sm->fast_reauth && sm->m && sm->m->has_reauth_data &&
+	    sm->m->has_reauth_data(sm, sm->eap_method_priv) &&
+	    !sm->prev_failure) {
+		wpa_printf(MSG_DEBUG, "EAP: maintaining EAP method data for "
+			   "fast reauthentication");
+		sm->m->deinit_for_reauth(sm, sm->eap_method_priv);
+	} else {
+		eap_deinit_prev_method(sm, "INITIALIZE");
+	}
+	sm->selectedMethod = EAP_TYPE_NONE;
+	sm->methodState = METHOD_NONE;
+	sm->allowNotifications = TRUE;
+	sm->decision = DECISION_FAIL;
+	sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
+	eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
+	eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
+	eapol_set_bool(sm, EAPOL_eapFail, FALSE);
+	os_free(sm->eapKeyData);
+	sm->eapKeyData = NULL;
+	sm->eapKeyAvailable = FALSE;
+	eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
+	sm->lastId = -1; /* new session - make sure this does not match with
+			  * the first EAP-Packet */
+	/*
+	 * RFC 4137 does not reset eapResp and eapNoResp here. However, this
+	 * seemed to be able to trigger cases where both were set and if EAPOL
+	 * state machine uses eapNoResp first, it may end up not sending a real
+	 * reply correctly. This occurred when the workaround in FAIL state set
+	 * eapNoResp = TRUE.. Maybe that workaround needs to be fixed to do
+	 * something else(?)
+	 */
+	eapol_set_bool(sm, EAPOL_eapResp, FALSE);
+	eapol_set_bool(sm, EAPOL_eapNoResp, FALSE);
+	sm->num_rounds = 0;
+	sm->prev_failure = 0;
+}
+
+
+/*
+ * This state is reached whenever service from the lower layer is interrupted
+ * or unavailable (portEnabled == FALSE). Immediate transition to INITIALIZE
+ * occurs when the port becomes enabled.
+ */
+SM_STATE(EAP, DISABLED)
+{
+	SM_ENTRY(EAP, DISABLED);
+	sm->num_rounds = 0;
+	/*
+	 * RFC 4137 does not describe clearing of idleWhile here, but doing so
+	 * allows the timer tick to be stopped more quickly when EAP is not in
+	 * use.
+	 */
+	eapol_set_int(sm, EAPOL_idleWhile, 0);
+}
+
+
+/*
+ * The state machine spends most of its time here, waiting for something to
+ * happen. This state is entered unconditionally from INITIALIZE, DISCARD, and
+ * SEND_RESPONSE states.
+ */
+SM_STATE(EAP, IDLE)
+{
+	SM_ENTRY(EAP, IDLE);
+}
+
+
+/*
+ * This state is entered when an EAP packet is received (eapReq == TRUE) to
+ * parse the packet header.
+ */
+SM_STATE(EAP, RECEIVED)
+{
+	const struct wpabuf *eapReqData;
+
+	SM_ENTRY(EAP, RECEIVED);
+	eapReqData = eapol_get_eapReqData(sm);
+	/* parse rxReq, rxSuccess, rxFailure, reqId, reqMethod */
+	eap_sm_parseEapReq(sm, eapReqData);
+	sm->num_rounds++;
+}
+
+
+/*
+ * This state is entered when a request for a new type comes in. Either the
+ * correct method is started, or a Nak response is built.
+ */
+SM_STATE(EAP, GET_METHOD)
+{
+	int reinit;
+	EapType method;
+	const struct eap_method *eap_method;
+
+	SM_ENTRY(EAP, GET_METHOD);
+
+	if (sm->reqMethod == EAP_TYPE_EXPANDED)
+		method = sm->reqVendorMethod;
+	else
+		method = sm->reqMethod;
+
+	eap_method = eap_peer_get_eap_method(sm->reqVendor, method);
+
+	if (!eap_sm_allowMethod(sm, sm->reqVendor, method)) {
+		wpa_printf(MSG_DEBUG, "EAP: vendor %u method %u not allowed",
+			   sm->reqVendor, method);
+		wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
+			"vendor=%u method=%u -> NAK",
+			sm->reqVendor, method);
+		eap_notify_status(sm, "refuse proposed method",
+				  eap_method ?  eap_method->name : "unknown");
+		goto nak;
+	}
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_PROPOSED_METHOD
+		"vendor=%u method=%u", sm->reqVendor, method);
+
+	eap_notify_status(sm, "accept proposed method",
+			  eap_method ?  eap_method->name : "unknown");
+	/*
+	 * RFC 4137 does not define specific operation for fast
+	 * re-authentication (session resumption). The design here is to allow
+	 * the previously used method data to be maintained for
+	 * re-authentication if the method support session resumption.
+	 * Otherwise, the previously used method data is freed and a new method
+	 * is allocated here.
+	 */
+	if (sm->fast_reauth &&
+	    sm->m && sm->m->vendor == sm->reqVendor &&
+	    sm->m->method == method &&
+	    sm->m->has_reauth_data &&
+	    sm->m->has_reauth_data(sm, sm->eap_method_priv)) {
+		wpa_printf(MSG_DEBUG, "EAP: Using previous method data"
+			   " for fast re-authentication");
+		reinit = 1;
+	} else {
+		eap_deinit_prev_method(sm, "GET_METHOD");
+		reinit = 0;
+	}
+
+	sm->selectedMethod = sm->reqMethod;
+	if (sm->m == NULL)
+		sm->m = eap_method;
+	if (!sm->m) {
+		wpa_printf(MSG_DEBUG, "EAP: Could not find selected method: "
+			   "vendor %d method %d",
+			   sm->reqVendor, method);
+		goto nak;
+	}
+
+	sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
+
+	wpa_printf(MSG_DEBUG, "EAP: Initialize selected EAP method: "
+		   "vendor %u method %u (%s)",
+		   sm->reqVendor, method, sm->m->name);
+	if (reinit)
+		sm->eap_method_priv = sm->m->init_for_reauth(
+			sm, sm->eap_method_priv);
+	else
+		sm->eap_method_priv = sm->m->init(sm);
+
+	if (sm->eap_method_priv == NULL) {
+		struct eap_peer_config *config = eap_get_config(sm);
+		wpa_msg(sm->msg_ctx, MSG_INFO,
+			"EAP: Failed to initialize EAP method: vendor %u "
+			"method %u (%s)",
+			sm->reqVendor, method, sm->m->name);
+		sm->m = NULL;
+		sm->methodState = METHOD_NONE;
+		sm->selectedMethod = EAP_TYPE_NONE;
+		if (sm->reqMethod == EAP_TYPE_TLS && config &&
+		    (config->pending_req_pin ||
+		     config->pending_req_passphrase)) {
+			/*
+			 * Return without generating Nak in order to allow
+			 * entering of PIN code or passphrase to retry the
+			 * current EAP packet.
+			 */
+			wpa_printf(MSG_DEBUG, "EAP: Pending PIN/passphrase "
+				   "request - skip Nak");
+			return;
+		}
+
+		goto nak;
+	}
+
+	sm->methodState = METHOD_INIT;
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_METHOD
+		"EAP vendor %u method %u (%s) selected",
+		sm->reqVendor, method, sm->m->name);
+	return;
+
+nak:
+	wpabuf_free(sm->eapRespData);
+	sm->eapRespData = NULL;
+	sm->eapRespData = eap_sm_buildNak(sm, sm->reqId);
+}
+
+
+/*
+ * The method processing happens here. The request from the authenticator is
+ * processed, and an appropriate response packet is built.
+ */
+SM_STATE(EAP, METHOD)
+{
+	struct wpabuf *eapReqData;
+	struct eap_method_ret ret;
+	int min_len = 1;
+
+	SM_ENTRY(EAP, METHOD);
+	if (sm->m == NULL) {
+		wpa_printf(MSG_WARNING, "EAP::METHOD - method not selected");
+		return;
+	}
+
+	eapReqData = eapol_get_eapReqData(sm);
+	if (sm->m->vendor == EAP_VENDOR_IETF && sm->m->method == EAP_TYPE_LEAP)
+		min_len = 0; /* LEAP uses EAP-Success without payload */
+	if (!eap_hdr_len_valid(eapReqData, min_len))
+		return;
+
+	/*
+	 * Get ignore, methodState, decision, allowNotifications, and
+	 * eapRespData. RFC 4137 uses three separate method procedure (check,
+	 * process, and buildResp) in this state. These have been combined into
+	 * a single function call to m->process() in order to optimize EAP
+	 * method implementation interface a bit. These procedures are only
+	 * used from within this METHOD state, so there is no need to keep
+	 * these as separate C functions.
+	 *
+	 * The RFC 4137 procedures return values as follows:
+	 * ignore = m.check(eapReqData)
+	 * (methodState, decision, allowNotifications) = m.process(eapReqData)
+	 * eapRespData = m.buildResp(reqId)
+	 */
+	os_memset(&ret, 0, sizeof(ret));
+	ret.ignore = sm->ignore;
+	ret.methodState = sm->methodState;
+	ret.decision = sm->decision;
+	ret.allowNotifications = sm->allowNotifications;
+	wpabuf_free(sm->eapRespData);
+	sm->eapRespData = NULL;
+	sm->eapRespData = sm->m->process(sm, sm->eap_method_priv, &ret,
+					 eapReqData);
+	wpa_printf(MSG_DEBUG, "EAP: method process -> ignore=%s "
+		   "methodState=%s decision=%s",
+		   ret.ignore ? "TRUE" : "FALSE",
+		   eap_sm_method_state_txt(ret.methodState),
+		   eap_sm_decision_txt(ret.decision));
+
+	sm->ignore = ret.ignore;
+	if (sm->ignore)
+		return;
+	sm->methodState = ret.methodState;
+	sm->decision = ret.decision;
+	sm->allowNotifications = ret.allowNotifications;
+
+	if (sm->m->isKeyAvailable && sm->m->getKey &&
+	    sm->m->isKeyAvailable(sm, sm->eap_method_priv)) {
+		os_free(sm->eapKeyData);
+		sm->eapKeyData = sm->m->getKey(sm, sm->eap_method_priv,
+					       &sm->eapKeyDataLen);
+	}
+}
+
+
+/*
+ * This state signals the lower layer that a response packet is ready to be
+ * sent.
+ */
+SM_STATE(EAP, SEND_RESPONSE)
+{
+	SM_ENTRY(EAP, SEND_RESPONSE);
+	wpabuf_free(sm->lastRespData);
+	if (sm->eapRespData) {
+		if (sm->workaround)
+			os_memcpy(sm->last_md5, sm->req_md5, 16);
+		sm->lastId = sm->reqId;
+		sm->lastRespData = wpabuf_dup(sm->eapRespData);
+		eapol_set_bool(sm, EAPOL_eapResp, TRUE);
+	} else
+		sm->lastRespData = NULL;
+	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+	eapol_set_int(sm, EAPOL_idleWhile, sm->ClientTimeout);
+}
+
+
+/*
+ * This state signals the lower layer that the request was discarded, and no
+ * response packet will be sent at this time.
+ */
+SM_STATE(EAP, DISCARD)
+{
+	SM_ENTRY(EAP, DISCARD);
+	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+	eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+}
+
+
+/*
+ * Handles requests for Identity method and builds a response.
+ */
+SM_STATE(EAP, IDENTITY)
+{
+	const struct wpabuf *eapReqData;
+
+	SM_ENTRY(EAP, IDENTITY);
+	eapReqData = eapol_get_eapReqData(sm);
+	if (!eap_hdr_len_valid(eapReqData, 1))
+		return;
+	eap_sm_processIdentity(sm, eapReqData);
+	wpabuf_free(sm->eapRespData);
+	sm->eapRespData = NULL;
+	sm->eapRespData = eap_sm_buildIdentity(sm, sm->reqId, 0);
+}
+
+
+/*
+ * Handles requests for Notification method and builds a response.
+ */
+SM_STATE(EAP, NOTIFICATION)
+{
+	const struct wpabuf *eapReqData;
+
+	SM_ENTRY(EAP, NOTIFICATION);
+	eapReqData = eapol_get_eapReqData(sm);
+	if (!eap_hdr_len_valid(eapReqData, 1))
+		return;
+	eap_sm_processNotify(sm, eapReqData);
+	wpabuf_free(sm->eapRespData);
+	sm->eapRespData = NULL;
+	sm->eapRespData = eap_sm_buildNotify(sm->reqId);
+}
+
+
+/*
+ * This state retransmits the previous response packet.
+ */
+SM_STATE(EAP, RETRANSMIT)
+{
+	SM_ENTRY(EAP, RETRANSMIT);
+	wpabuf_free(sm->eapRespData);
+	if (sm->lastRespData)
+		sm->eapRespData = wpabuf_dup(sm->lastRespData);
+	else
+		sm->eapRespData = NULL;
+}
+
+
+/*
+ * This state is entered in case of a successful completion of authentication
+ * and state machine waits here until port is disabled or EAP authentication is
+ * restarted.
+ */
+SM_STATE(EAP, SUCCESS)
+{
+	SM_ENTRY(EAP, SUCCESS);
+	if (sm->eapKeyData != NULL)
+		sm->eapKeyAvailable = TRUE;
+	eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
+
+	/*
+	 * RFC 4137 does not clear eapReq here, but this seems to be required
+	 * to avoid processing the same request twice when state machine is
+	 * initialized.
+	 */
+	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+
+	/*
+	 * RFC 4137 does not set eapNoResp here, but this seems to be required
+	 * to get EAPOL Supplicant backend state machine into SUCCESS state. In
+	 * addition, either eapResp or eapNoResp is required to be set after
+	 * processing the received EAP frame.
+	 */
+	eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+		"EAP authentication completed successfully");
+}
+
+
+/*
+ * This state is entered in case of a failure and state machine waits here
+ * until port is disabled or EAP authentication is restarted.
+ */
+SM_STATE(EAP, FAILURE)
+{
+	SM_ENTRY(EAP, FAILURE);
+	eapol_set_bool(sm, EAPOL_eapFail, TRUE);
+
+	/*
+	 * RFC 4137 does not clear eapReq here, but this seems to be required
+	 * to avoid processing the same request twice when state machine is
+	 * initialized.
+	 */
+	eapol_set_bool(sm, EAPOL_eapReq, FALSE);
+
+	/*
+	 * RFC 4137 does not set eapNoResp here. However, either eapResp or
+	 * eapNoResp is required to be set after processing the received EAP
+	 * frame.
+	 */
+	eapol_set_bool(sm, EAPOL_eapNoResp, TRUE);
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_FAILURE
+		"EAP authentication failed");
+
+	sm->prev_failure = 1;
+}
+
+
+static int eap_success_workaround(struct eap_sm *sm, int reqId, int lastId)
+{
+	/*
+	 * At least Microsoft IAS and Meetinghouse Aegis seem to be sending
+	 * EAP-Success/Failure with lastId + 1 even though RFC 3748 and
+	 * RFC 4137 require that reqId == lastId. In addition, it looks like
+	 * Ringmaster v2.1.2.0 would be using lastId + 2 in EAP-Success.
+	 *
+	 * Accept this kind of Id if EAP workarounds are enabled. These are
+	 * unauthenticated plaintext messages, so this should have minimal
+	 * security implications (bit easier to fake EAP-Success/Failure).
+	 */
+	if (sm->workaround && (reqId == ((lastId + 1) & 0xff) ||
+			       reqId == ((lastId + 2) & 0xff))) {
+		wpa_printf(MSG_DEBUG, "EAP: Workaround for unexpected "
+			   "identifier field in EAP Success: "
+			   "reqId=%d lastId=%d (these are supposed to be "
+			   "same)", reqId, lastId);
+		return 1;
+	}
+	wpa_printf(MSG_DEBUG, "EAP: EAP-Success Id mismatch - reqId=%d "
+		   "lastId=%d", reqId, lastId);
+	return 0;
+}
+
+
+/*
+ * RFC 4137 - Appendix A.1: EAP Peer State Machine - State transitions
+ */
+
+static void eap_peer_sm_step_idle(struct eap_sm *sm)
+{
+	/*
+	 * The first three transitions are from RFC 4137. The last two are
+	 * local additions to handle special cases with LEAP and PEAP server
+	 * not sending EAP-Success in some cases.
+	 */
+	if (eapol_get_bool(sm, EAPOL_eapReq))
+		SM_ENTER(EAP, RECEIVED);
+	else if ((eapol_get_bool(sm, EAPOL_altAccept) &&
+		  sm->decision != DECISION_FAIL) ||
+		 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
+		  sm->decision == DECISION_UNCOND_SUCC))
+		SM_ENTER(EAP, SUCCESS);
+	else if (eapol_get_bool(sm, EAPOL_altReject) ||
+		 (eapol_get_int(sm, EAPOL_idleWhile) == 0 &&
+		  sm->decision != DECISION_UNCOND_SUCC) ||
+		 (eapol_get_bool(sm, EAPOL_altAccept) &&
+		  sm->methodState != METHOD_CONT &&
+		  sm->decision == DECISION_FAIL))
+		SM_ENTER(EAP, FAILURE);
+	else if (sm->selectedMethod == EAP_TYPE_LEAP &&
+		 sm->leap_done && sm->decision != DECISION_FAIL &&
+		 sm->methodState == METHOD_DONE)
+		SM_ENTER(EAP, SUCCESS);
+	else if (sm->selectedMethod == EAP_TYPE_PEAP &&
+		 sm->peap_done && sm->decision != DECISION_FAIL &&
+		 sm->methodState == METHOD_DONE)
+		SM_ENTER(EAP, SUCCESS);
+}
+
+
+static int eap_peer_req_is_duplicate(struct eap_sm *sm)
+{
+	int duplicate;
+
+	duplicate = (sm->reqId == sm->lastId) && sm->rxReq;
+	if (sm->workaround && duplicate &&
+	    os_memcmp(sm->req_md5, sm->last_md5, 16) != 0) {
+		/*
+		 * RFC 4137 uses (reqId == lastId) as the only verification for
+		 * duplicate EAP requests. However, this misses cases where the
+		 * AS is incorrectly using the same id again; and
+		 * unfortunately, such implementations exist. Use MD5 hash as
+		 * an extra verification for the packets being duplicate to
+		 * workaround these issues.
+		 */
+		wpa_printf(MSG_DEBUG, "EAP: AS used the same Id again, but "
+			   "EAP packets were not identical");
+		wpa_printf(MSG_DEBUG, "EAP: workaround - assume this is not a "
+			   "duplicate packet");
+		duplicate = 0;
+	}
+
+	return duplicate;
+}
+
+
+static void eap_peer_sm_step_received(struct eap_sm *sm)
+{
+	int duplicate = eap_peer_req_is_duplicate(sm);
+
+	/*
+	 * Two special cases below for LEAP are local additions to work around
+	 * odd LEAP behavior (EAP-Success in the middle of authentication and
+	 * then swapped roles). Other transitions are based on RFC 4137.
+	 */
+	if (sm->rxSuccess && sm->decision != DECISION_FAIL &&
+	    (sm->reqId == sm->lastId ||
+	     eap_success_workaround(sm, sm->reqId, sm->lastId)))
+		SM_ENTER(EAP, SUCCESS);
+	else if (sm->methodState != METHOD_CONT &&
+		 ((sm->rxFailure &&
+		   sm->decision != DECISION_UNCOND_SUCC) ||
+		  (sm->rxSuccess && sm->decision == DECISION_FAIL &&
+		   (sm->selectedMethod != EAP_TYPE_LEAP ||
+		    sm->methodState != METHOD_MAY_CONT))) &&
+		 (sm->reqId == sm->lastId ||
+		  eap_success_workaround(sm, sm->reqId, sm->lastId)))
+		SM_ENTER(EAP, FAILURE);
+	else if (sm->rxReq && duplicate)
+		SM_ENTER(EAP, RETRANSMIT);
+	else if (sm->rxReq && !duplicate &&
+		 sm->reqMethod == EAP_TYPE_NOTIFICATION &&
+		 sm->allowNotifications)
+		SM_ENTER(EAP, NOTIFICATION);
+	else if (sm->rxReq && !duplicate &&
+		 sm->selectedMethod == EAP_TYPE_NONE &&
+		 sm->reqMethod == EAP_TYPE_IDENTITY)
+		SM_ENTER(EAP, IDENTITY);
+	else if (sm->rxReq && !duplicate &&
+		 sm->selectedMethod == EAP_TYPE_NONE &&
+		 sm->reqMethod != EAP_TYPE_IDENTITY &&
+		 sm->reqMethod != EAP_TYPE_NOTIFICATION)
+		SM_ENTER(EAP, GET_METHOD);
+	else if (sm->rxReq && !duplicate &&
+		 sm->reqMethod == sm->selectedMethod &&
+		 sm->methodState != METHOD_DONE)
+		SM_ENTER(EAP, METHOD);
+	else if (sm->selectedMethod == EAP_TYPE_LEAP &&
+		 (sm->rxSuccess || sm->rxResp))
+		SM_ENTER(EAP, METHOD);
+	else
+		SM_ENTER(EAP, DISCARD);
+}
+
+
+static void eap_peer_sm_step_local(struct eap_sm *sm)
+{
+	switch (sm->EAP_state) {
+	case EAP_INITIALIZE:
+		SM_ENTER(EAP, IDLE);
+		break;
+	case EAP_DISABLED:
+		if (eapol_get_bool(sm, EAPOL_portEnabled) &&
+		    !sm->force_disabled)
+			SM_ENTER(EAP, INITIALIZE);
+		break;
+	case EAP_IDLE:
+		eap_peer_sm_step_idle(sm);
+		break;
+	case EAP_RECEIVED:
+		eap_peer_sm_step_received(sm);
+		break;
+	case EAP_GET_METHOD:
+		if (sm->selectedMethod == sm->reqMethod)
+			SM_ENTER(EAP, METHOD);
+		else
+			SM_ENTER(EAP, SEND_RESPONSE);
+		break;
+	case EAP_METHOD:
+		if (sm->ignore)
+			SM_ENTER(EAP, DISCARD);
+		else
+			SM_ENTER(EAP, SEND_RESPONSE);
+		break;
+	case EAP_SEND_RESPONSE:
+		SM_ENTER(EAP, IDLE);
+		break;
+	case EAP_DISCARD:
+		SM_ENTER(EAP, IDLE);
+		break;
+	case EAP_IDENTITY:
+		SM_ENTER(EAP, SEND_RESPONSE);
+		break;
+	case EAP_NOTIFICATION:
+		SM_ENTER(EAP, SEND_RESPONSE);
+		break;
+	case EAP_RETRANSMIT:
+		SM_ENTER(EAP, SEND_RESPONSE);
+		break;
+	case EAP_SUCCESS:
+		break;
+	case EAP_FAILURE:
+		break;
+	}
+}
+
+
+SM_STEP(EAP)
+{
+	/* Global transitions */
+	if (eapol_get_bool(sm, EAPOL_eapRestart) &&
+	    eapol_get_bool(sm, EAPOL_portEnabled))
+		SM_ENTER_GLOBAL(EAP, INITIALIZE);
+	else if (!eapol_get_bool(sm, EAPOL_portEnabled) || sm->force_disabled)
+		SM_ENTER_GLOBAL(EAP, DISABLED);
+	else if (sm->num_rounds > EAP_MAX_AUTH_ROUNDS) {
+		/* RFC 4137 does not place any limit on number of EAP messages
+		 * in an authentication session. However, some error cases have
+		 * ended up in a state were EAP messages were sent between the
+		 * peer and server in a loop (e.g., TLS ACK frame in both
+		 * direction). Since this is quite undesired outcome, limit the
+		 * total number of EAP round-trips and abort authentication if
+		 * this limit is exceeded.
+		 */
+		if (sm->num_rounds == EAP_MAX_AUTH_ROUNDS + 1) {
+			wpa_msg(sm->msg_ctx, MSG_INFO, "EAP: more than %d "
+				"authentication rounds - abort",
+				EAP_MAX_AUTH_ROUNDS);
+			sm->num_rounds++;
+			SM_ENTER_GLOBAL(EAP, FAILURE);
+		}
+	} else {
+		/* Local transitions */
+		eap_peer_sm_step_local(sm);
+	}
+}
+
+
+static Boolean eap_sm_allowMethod(struct eap_sm *sm, int vendor,
+				  EapType method)
+{
+	if (!eap_allowed_method(sm, vendor, method)) {
+		wpa_printf(MSG_DEBUG, "EAP: configuration does not allow: "
+			   "vendor %u method %u", vendor, method);
+		return FALSE;
+	}
+	if (eap_peer_get_eap_method(vendor, method))
+		return TRUE;
+	wpa_printf(MSG_DEBUG, "EAP: not included in build: "
+		   "vendor %u method %u", vendor, method);
+	return FALSE;
+}
+
+
+static struct wpabuf * eap_sm_build_expanded_nak(
+	struct eap_sm *sm, int id, const struct eap_method *methods,
+	size_t count)
+{
+	struct wpabuf *resp;
+	int found = 0;
+	const struct eap_method *m;
+
+	wpa_printf(MSG_DEBUG, "EAP: Building expanded EAP-Nak");
+
+	/* RFC 3748 - 5.3.2: Expanded Nak */
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_EXPANDED,
+			     8 + 8 * (count + 1), EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	wpabuf_put_be24(resp, EAP_VENDOR_IETF);
+	wpabuf_put_be32(resp, EAP_TYPE_NAK);
+
+	for (m = methods; m; m = m->next) {
+		if (sm->reqVendor == m->vendor &&
+		    sm->reqVendorMethod == m->method)
+			continue; /* do not allow the current method again */
+		if (eap_allowed_method(sm, m->vendor, m->method)) {
+			wpa_printf(MSG_DEBUG, "EAP: allowed type: "
+				   "vendor=%u method=%u",
+				   m->vendor, m->method);
+			wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
+			wpabuf_put_be24(resp, m->vendor);
+			wpabuf_put_be32(resp, m->method);
+
+			found++;
+		}
+	}
+	if (!found) {
+		wpa_printf(MSG_DEBUG, "EAP: no more allowed methods");
+		wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
+		wpabuf_put_be24(resp, EAP_VENDOR_IETF);
+		wpabuf_put_be32(resp, EAP_TYPE_NONE);
+	}
+
+	eap_update_len(resp);
+
+	return resp;
+}
+
+
+static struct wpabuf * eap_sm_buildNak(struct eap_sm *sm, int id)
+{
+	struct wpabuf *resp;
+	u8 *start;
+	int found = 0, expanded_found = 0;
+	size_t count;
+	const struct eap_method *methods, *m;
+
+	wpa_printf(MSG_DEBUG, "EAP: Building EAP-Nak (requested type %u "
+		   "vendor=%u method=%u not allowed)", sm->reqMethod,
+		   sm->reqVendor, sm->reqVendorMethod);
+	methods = eap_peer_get_methods(&count);
+	if (methods == NULL)
+		return NULL;
+	if (sm->reqMethod == EAP_TYPE_EXPANDED)
+		return eap_sm_build_expanded_nak(sm, id, methods, count);
+
+	/* RFC 3748 - 5.3.1: Legacy Nak */
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK,
+			     sizeof(struct eap_hdr) + 1 + count + 1,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	start = wpabuf_put(resp, 0);
+	for (m = methods; m; m = m->next) {
+		if (m->vendor == EAP_VENDOR_IETF && m->method == sm->reqMethod)
+			continue; /* do not allow the current method again */
+		if (eap_allowed_method(sm, m->vendor, m->method)) {
+			if (m->vendor != EAP_VENDOR_IETF) {
+				if (expanded_found)
+					continue;
+				expanded_found = 1;
+				wpabuf_put_u8(resp, EAP_TYPE_EXPANDED);
+			} else
+				wpabuf_put_u8(resp, m->method);
+			found++;
+		}
+	}
+	if (!found)
+		wpabuf_put_u8(resp, EAP_TYPE_NONE);
+	wpa_hexdump(MSG_DEBUG, "EAP: allowed methods", start, found);
+
+	eap_update_len(resp);
+
+	return resp;
+}
+
+
+static void eap_sm_processIdentity(struct eap_sm *sm, const struct wpabuf *req)
+{
+	const u8 *pos;
+	size_t msg_len;
+
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_STARTED
+		"EAP authentication started");
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, req,
+			       &msg_len);
+	if (pos == NULL)
+		return;
+
+	/*
+	 * RFC 3748 - 5.1: Identity
+	 * Data field may contain a displayable message in UTF-8. If this
+	 * includes NUL-character, only the data before that should be
+	 * displayed. Some EAP implementasitons may piggy-back additional
+	 * options after the NUL.
+	 */
+	/* TODO: could save displayable message so that it can be shown to the
+	 * user in case of interaction is required */
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Identity data",
+			  pos, msg_len);
+}
+
+
+#ifdef PCSC_FUNCS
+
+/*
+ * Rules for figuring out MNC length based on IMSI for SIM cards that do not
+ * include MNC length field.
+ */
+static int mnc_len_from_imsi(const char *imsi)
+{
+	char mcc_str[4];
+	unsigned int mcc;
+
+	os_memcpy(mcc_str, imsi, 3);
+	mcc_str[3] = '\0';
+	mcc = atoi(mcc_str);
+
+	if (mcc == 244)
+		return 2; /* Networks in Finland use 2-digit MNC */
+
+	return -1;
+}
+
+
+static int eap_sm_append_3gpp_realm(struct eap_sm *sm, char *imsi,
+				    size_t max_len, size_t *imsi_len)
+{
+	int mnc_len;
+	char *pos, mnc[4];
+
+	if (*imsi_len + 36 > max_len) {
+		wpa_printf(MSG_WARNING, "No room for realm in IMSI buffer");
+		return -1;
+	}
+
+	/* MNC (2 or 3 digits) */
+	mnc_len = scard_get_mnc_len(sm->scard_ctx);
+	if (mnc_len < 0)
+		mnc_len = mnc_len_from_imsi(imsi);
+	if (mnc_len < 0) {
+		wpa_printf(MSG_INFO, "Failed to get MNC length from (U)SIM "
+			   "assuming 3");
+		mnc_len = 3;
+	}
+
+	if (mnc_len == 2) {
+		mnc[0] = '0';
+		mnc[1] = imsi[3];
+		mnc[2] = imsi[4];
+	} else if (mnc_len == 3) {
+		mnc[0] = imsi[3];
+		mnc[1] = imsi[4];
+		mnc[2] = imsi[5];
+	}
+	mnc[3] = '\0';
+
+	pos = imsi + *imsi_len;
+	pos += os_snprintf(pos, imsi + max_len - pos,
+			   "@wlan.mnc%s.mcc%c%c%c.3gppnetwork.org",
+			   mnc, imsi[0], imsi[1], imsi[2]);
+	*imsi_len = pos - imsi;
+
+	return 0;
+}
+
+
+static int eap_sm_imsi_identity(struct eap_sm *sm,
+				struct eap_peer_config *conf)
+{
+	enum { EAP_SM_SIM, EAP_SM_AKA, EAP_SM_AKA_PRIME } method = EAP_SM_SIM;
+	char imsi[100];
+	size_t imsi_len;
+	struct eap_method_type *m = conf->eap_methods;
+	int i;
+
+	imsi_len = sizeof(imsi);
+	if (scard_get_imsi(sm->scard_ctx, imsi, &imsi_len)) {
+		wpa_printf(MSG_WARNING, "Failed to get IMSI from SIM");
+		return -1;
+	}
+
+	wpa_hexdump_ascii(MSG_DEBUG, "IMSI", (u8 *) imsi, imsi_len);
+
+	if (imsi_len < 7) {
+		wpa_printf(MSG_WARNING, "Too short IMSI for SIM identity");
+		return -1;
+	}
+
+	if (eap_sm_append_3gpp_realm(sm, imsi, sizeof(imsi), &imsi_len) < 0) {
+		wpa_printf(MSG_WARNING, "Could not add realm to SIM identity");
+		return -1;
+	}
+	wpa_hexdump_ascii(MSG_DEBUG, "IMSI + realm", (u8 *) imsi, imsi_len);
+
+	for (i = 0; m && (m[i].vendor != EAP_VENDOR_IETF ||
+			  m[i].method != EAP_TYPE_NONE); i++) {
+		if (m[i].vendor == EAP_VENDOR_IETF &&
+		    m[i].method == EAP_TYPE_AKA_PRIME) {
+			method = EAP_SM_AKA_PRIME;
+			break;
+		}
+
+		if (m[i].vendor == EAP_VENDOR_IETF &&
+		    m[i].method == EAP_TYPE_AKA) {
+			method = EAP_SM_AKA;
+			break;
+		}
+	}
+
+	os_free(conf->identity);
+	conf->identity = os_malloc(1 + imsi_len);
+	if (conf->identity == NULL) {
+		wpa_printf(MSG_WARNING, "Failed to allocate buffer for "
+			   "IMSI-based identity");
+		return -1;
+	}
+
+	switch (method) {
+	case EAP_SM_SIM:
+		conf->identity[0] = '1';
+		break;
+	case EAP_SM_AKA:
+		conf->identity[0] = '0';
+		break;
+	case EAP_SM_AKA_PRIME:
+		conf->identity[0] = '6';
+		break;
+	}
+	os_memcpy(conf->identity + 1, imsi, imsi_len);
+	conf->identity_len = 1 + imsi_len;
+
+	return 0;
+}
+
+#endif /* PCSC_FUNCS */
+
+
+static int eap_sm_set_scard_pin(struct eap_sm *sm,
+				struct eap_peer_config *conf)
+{
+#ifdef PCSC_FUNCS
+	if (scard_set_pin(sm->scard_ctx, conf->pin)) {
+		/*
+		 * Make sure the same PIN is not tried again in order to avoid
+		 * blocking SIM.
+		 */
+		os_free(conf->pin);
+		conf->pin = NULL;
+
+		wpa_printf(MSG_WARNING, "PIN validation failed");
+		eap_sm_request_pin(sm);
+		return -1;
+	}
+	return 0;
+#else /* PCSC_FUNCS */
+	return -1;
+#endif /* PCSC_FUNCS */
+}
+
+static int eap_sm_get_scard_identity(struct eap_sm *sm,
+				     struct eap_peer_config *conf)
+{
+#ifdef PCSC_FUNCS
+	if (eap_sm_set_scard_pin(sm, conf))
+		return -1;
+
+	return eap_sm_imsi_identity(sm, conf);
+#else /* PCSC_FUNCS */
+	return -1;
+#endif /* PCSC_FUNCS */
+}
+
+
+/**
+ * eap_sm_buildIdentity - Build EAP-Identity/Response for the current network
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @id: EAP identifier for the packet
+ * @encrypted: Whether the packet is for encrypted tunnel (EAP phase 2)
+ * Returns: Pointer to the allocated EAP-Identity/Response packet or %NULL on
+ * failure
+ *
+ * This function allocates and builds an EAP-Identity/Response packet for the
+ * current network. The caller is responsible for freeing the returned data.
+ */
+struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	struct wpabuf *resp;
+	const u8 *identity;
+	size_t identity_len;
+
+	if (config == NULL) {
+		wpa_printf(MSG_WARNING, "EAP: buildIdentity: configuration "
+			   "was not available");
+		return NULL;
+	}
+
+	if (sm->m && sm->m->get_identity &&
+	    (identity = sm->m->get_identity(sm, sm->eap_method_priv,
+					    &identity_len)) != NULL) {
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP: using method re-auth "
+				  "identity", identity, identity_len);
+	} else if (!encrypted && config->anonymous_identity) {
+		identity = config->anonymous_identity;
+		identity_len = config->anonymous_identity_len;
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP: using anonymous identity",
+				  identity, identity_len);
+	} else {
+		identity = config->identity;
+		identity_len = config->identity_len;
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP: using real identity",
+				  identity, identity_len);
+	}
+
+	if (identity == NULL) {
+		wpa_printf(MSG_WARNING, "EAP: buildIdentity: identity "
+			   "configuration was not available");
+		if (config->pcsc) {
+			if (eap_sm_get_scard_identity(sm, config) < 0)
+				return NULL;
+			identity = config->identity;
+			identity_len = config->identity_len;
+			wpa_hexdump_ascii(MSG_DEBUG, "permanent identity from "
+					  "IMSI", identity, identity_len);
+		} else {
+			eap_sm_request_identity(sm);
+			return NULL;
+		}
+	} else if (config->pcsc) {
+		if (eap_sm_set_scard_pin(sm, config) < 0)
+			return NULL;
+	}
+
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, identity_len,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	wpabuf_put_data(resp, identity, identity_len);
+
+	return resp;
+}
+
+
+static void eap_sm_processNotify(struct eap_sm *sm, const struct wpabuf *req)
+{
+	const u8 *pos;
+	char *msg;
+	size_t i, msg_len;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, req,
+			       &msg_len);
+	if (pos == NULL)
+		return;
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP: EAP-Request Notification data",
+			  pos, msg_len);
+
+	msg = os_malloc(msg_len + 1);
+	if (msg == NULL)
+		return;
+	for (i = 0; i < msg_len; i++)
+		msg[i] = isprint(pos[i]) ? (char) pos[i] : '_';
+	msg[msg_len] = '\0';
+	wpa_msg(sm->msg_ctx, MSG_INFO, "%s%s",
+		WPA_EVENT_EAP_NOTIFICATION, msg);
+	os_free(msg);
+}
+
+
+static struct wpabuf * eap_sm_buildNotify(int id)
+{
+	struct wpabuf *resp;
+
+	wpa_printf(MSG_DEBUG, "EAP: Generating EAP-Response Notification");
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NOTIFICATION, 0,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	return resp;
+}
+
+
+static void eap_sm_parseEapReq(struct eap_sm *sm, const struct wpabuf *req)
+{
+	const struct eap_hdr *hdr;
+	size_t plen;
+	const u8 *pos;
+
+	sm->rxReq = sm->rxResp = sm->rxSuccess = sm->rxFailure = FALSE;
+	sm->reqId = 0;
+	sm->reqMethod = EAP_TYPE_NONE;
+	sm->reqVendor = EAP_VENDOR_IETF;
+	sm->reqVendorMethod = EAP_TYPE_NONE;
+
+	if (req == NULL || wpabuf_len(req) < sizeof(*hdr))
+		return;
+
+	hdr = wpabuf_head(req);
+	plen = be_to_host16(hdr->length);
+	if (plen > wpabuf_len(req)) {
+		wpa_printf(MSG_DEBUG, "EAP: Ignored truncated EAP-Packet "
+			   "(len=%lu plen=%lu)",
+			   (unsigned long) wpabuf_len(req),
+			   (unsigned long) plen);
+		return;
+	}
+
+	sm->reqId = hdr->identifier;
+
+	if (sm->workaround) {
+		const u8 *addr[1];
+		addr[0] = wpabuf_head(req);
+		md5_vector(1, addr, &plen, sm->req_md5);
+	}
+
+	switch (hdr->code) {
+	case EAP_CODE_REQUEST:
+		if (plen < sizeof(*hdr) + 1) {
+			wpa_printf(MSG_DEBUG, "EAP: Too short EAP-Request - "
+				   "no Type field");
+			return;
+		}
+		sm->rxReq = TRUE;
+		pos = (const u8 *) (hdr + 1);
+		sm->reqMethod = *pos++;
+		if (sm->reqMethod == EAP_TYPE_EXPANDED) {
+			if (plen < sizeof(*hdr) + 8) {
+				wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
+					   "expanded EAP-Packet (plen=%lu)",
+					   (unsigned long) plen);
+				return;
+			}
+			sm->reqVendor = WPA_GET_BE24(pos);
+			pos += 3;
+			sm->reqVendorMethod = WPA_GET_BE32(pos);
+		}
+		wpa_printf(MSG_DEBUG, "EAP: Received EAP-Request id=%d "
+			   "method=%u vendor=%u vendorMethod=%u",
+			   sm->reqId, sm->reqMethod, sm->reqVendor,
+			   sm->reqVendorMethod);
+		break;
+	case EAP_CODE_RESPONSE:
+		if (sm->selectedMethod == EAP_TYPE_LEAP) {
+			/*
+			 * LEAP differs from RFC 4137 by using reversed roles
+			 * for mutual authentication and because of this, we
+			 * need to accept EAP-Response frames if LEAP is used.
+			 */
+			if (plen < sizeof(*hdr) + 1) {
+				wpa_printf(MSG_DEBUG, "EAP: Too short "
+					   "EAP-Response - no Type field");
+				return;
+			}
+			sm->rxResp = TRUE;
+			pos = (const u8 *) (hdr + 1);
+			sm->reqMethod = *pos;
+			wpa_printf(MSG_DEBUG, "EAP: Received EAP-Response for "
+				   "LEAP method=%d id=%d",
+				   sm->reqMethod, sm->reqId);
+			break;
+		}
+		wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Response");
+		break;
+	case EAP_CODE_SUCCESS:
+		wpa_printf(MSG_DEBUG, "EAP: Received EAP-Success");
+		eap_notify_status(sm, "completion", "success");
+		sm->rxSuccess = TRUE;
+		break;
+	case EAP_CODE_FAILURE:
+		wpa_printf(MSG_DEBUG, "EAP: Received EAP-Failure");
+		eap_notify_status(sm, "completion", "failure");
+		sm->rxFailure = TRUE;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAP: Ignored EAP-Packet with unknown "
+			   "code %d", hdr->code);
+		break;
+	}
+}
+
+
+static void eap_peer_sm_tls_event(void *ctx, enum tls_event ev,
+				  union tls_event_data *data)
+{
+	struct eap_sm *sm = ctx;
+	char *hash_hex = NULL;
+
+	switch (ev) {
+	case TLS_CERT_CHAIN_SUCCESS:
+		eap_notify_status(sm, "remote certificate verification",
+				  "success");
+		break;
+	case TLS_CERT_CHAIN_FAILURE:
+		wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_TLS_CERT_ERROR
+			"reason=%d depth=%d subject='%s' err='%s'",
+			data->cert_fail.reason,
+			data->cert_fail.depth,
+			data->cert_fail.subject,
+			data->cert_fail.reason_txt);
+		eap_notify_status(sm, "remote certificate verification",
+				  data->cert_fail.reason_txt);
+		break;
+	case TLS_PEER_CERTIFICATE:
+		if (!sm->eapol_cb->notify_cert)
+			break;
+
+		if (data->peer_cert.hash) {
+			size_t len = data->peer_cert.hash_len * 2 + 1;
+			hash_hex = os_malloc(len);
+			if (hash_hex) {
+				wpa_snprintf_hex(hash_hex, len,
+						 data->peer_cert.hash,
+						 data->peer_cert.hash_len);
+			}
+		}
+
+		sm->eapol_cb->notify_cert(sm->eapol_ctx,
+					  data->peer_cert.depth,
+					  data->peer_cert.subject,
+					  hash_hex, data->peer_cert.cert);
+		break;
+	case TLS_ALERT:
+		if (data->alert.is_local)
+			eap_notify_status(sm, "local TLS alert",
+					  data->alert.description);
+		else
+			eap_notify_status(sm, "remote TLS alert",
+					  data->alert.description);
+		break;
+	}
+
+	os_free(hash_hex);
+}
+
+
+/**
+ * eap_peer_sm_init - Allocate and initialize EAP peer state machine
+ * @eapol_ctx: Context data to be used with eapol_cb calls
+ * @eapol_cb: Pointer to EAPOL callback functions
+ * @msg_ctx: Context data for wpa_msg() calls
+ * @conf: EAP configuration
+ * Returns: Pointer to the allocated EAP state machine or %NULL on failure
+ *
+ * This function allocates and initializes an EAP state machine. In addition,
+ * this initializes TLS library for the new EAP state machine. eapol_cb pointer
+ * will be in use until eap_peer_sm_deinit() is used to deinitialize this EAP
+ * state machine. Consequently, the caller must make sure that this data
+ * structure remains alive while the EAP state machine is active.
+ */
+struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
+				 struct eapol_callbacks *eapol_cb,
+				 void *msg_ctx, struct eap_config *conf)
+{
+	struct eap_sm *sm;
+	struct tls_config tlsconf;
+
+	sm = os_zalloc(sizeof(*sm));
+	if (sm == NULL)
+		return NULL;
+	sm->eapol_ctx = eapol_ctx;
+	sm->eapol_cb = eapol_cb;
+	sm->msg_ctx = msg_ctx;
+	sm->ClientTimeout = EAP_CLIENT_TIMEOUT_DEFAULT;
+	sm->wps = conf->wps;
+
+	os_memset(&tlsconf, 0, sizeof(tlsconf));
+	tlsconf.opensc_engine_path = conf->opensc_engine_path;
+	tlsconf.pkcs11_engine_path = conf->pkcs11_engine_path;
+	tlsconf.pkcs11_module_path = conf->pkcs11_module_path;
+#ifdef CONFIG_FIPS
+	tlsconf.fips_mode = 1;
+#endif /* CONFIG_FIPS */
+	tlsconf.event_cb = eap_peer_sm_tls_event;
+	tlsconf.cb_ctx = sm;
+	tlsconf.cert_in_cb = conf->cert_in_cb;
+	sm->ssl_ctx = tls_init(&tlsconf);
+	if (sm->ssl_ctx == NULL) {
+		wpa_printf(MSG_WARNING, "SSL: Failed to initialize TLS "
+			   "context.");
+		os_free(sm);
+		return NULL;
+	}
+
+	sm->ssl_ctx2 = tls_init(&tlsconf);
+	if (sm->ssl_ctx2 == NULL) {
+		wpa_printf(MSG_INFO, "SSL: Failed to initialize TLS "
+			   "context (2).");
+		/* Run without separate TLS context within TLS tunnel */
+	}
+
+	return sm;
+}
+
+
+/**
+ * eap_peer_sm_deinit - Deinitialize and free an EAP peer state machine
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * This function deinitializes EAP state machine and frees all allocated
+ * resources.
+ */
+void eap_peer_sm_deinit(struct eap_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	eap_deinit_prev_method(sm, "EAP deinit");
+	eap_sm_abort(sm);
+	if (sm->ssl_ctx2)
+		tls_deinit(sm->ssl_ctx2);
+	tls_deinit(sm->ssl_ctx);
+	os_free(sm);
+}
+
+
+/**
+ * eap_peer_sm_step - Step EAP peer state machine
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * Returns: 1 if EAP state was changed or 0 if not
+ *
+ * This function advances EAP state machine to a new state to match with the
+ * current variables. This should be called whenever variables used by the EAP
+ * state machine have changed.
+ */
+int eap_peer_sm_step(struct eap_sm *sm)
+{
+	int res = 0;
+	do {
+		sm->changed = FALSE;
+		SM_STEP_RUN(EAP);
+		if (sm->changed)
+			res = 1;
+	} while (sm->changed);
+	return res;
+}
+
+
+/**
+ * eap_sm_abort - Abort EAP authentication
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * Release system resources that have been allocated for the authentication
+ * session without fully deinitializing the EAP state machine.
+ */
+void eap_sm_abort(struct eap_sm *sm)
+{
+	wpabuf_free(sm->lastRespData);
+	sm->lastRespData = NULL;
+	wpabuf_free(sm->eapRespData);
+	sm->eapRespData = NULL;
+	os_free(sm->eapKeyData);
+	sm->eapKeyData = NULL;
+
+	/* This is not clearly specified in the EAP statemachines draft, but
+	 * it seems necessary to make sure that some of the EAPOL variables get
+	 * cleared for the next authentication. */
+	eapol_set_bool(sm, EAPOL_eapSuccess, FALSE);
+}
+
+
+#ifdef CONFIG_CTRL_IFACE
+static const char * eap_sm_state_txt(int state)
+{
+	switch (state) {
+	case EAP_INITIALIZE:
+		return "INITIALIZE";
+	case EAP_DISABLED:
+		return "DISABLED";
+	case EAP_IDLE:
+		return "IDLE";
+	case EAP_RECEIVED:
+		return "RECEIVED";
+	case EAP_GET_METHOD:
+		return "GET_METHOD";
+	case EAP_METHOD:
+		return "METHOD";
+	case EAP_SEND_RESPONSE:
+		return "SEND_RESPONSE";
+	case EAP_DISCARD:
+		return "DISCARD";
+	case EAP_IDENTITY:
+		return "IDENTITY";
+	case EAP_NOTIFICATION:
+		return "NOTIFICATION";
+	case EAP_RETRANSMIT:
+		return "RETRANSMIT";
+	case EAP_SUCCESS:
+		return "SUCCESS";
+	case EAP_FAILURE:
+		return "FAILURE";
+	default:
+		return "UNKNOWN";
+	}
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static const char * eap_sm_method_state_txt(EapMethodState state)
+{
+	switch (state) {
+	case METHOD_NONE:
+		return "NONE";
+	case METHOD_INIT:
+		return "INIT";
+	case METHOD_CONT:
+		return "CONT";
+	case METHOD_MAY_CONT:
+		return "MAY_CONT";
+	case METHOD_DONE:
+		return "DONE";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+static const char * eap_sm_decision_txt(EapDecision decision)
+{
+	switch (decision) {
+	case DECISION_FAIL:
+		return "FAIL";
+	case DECISION_COND_SUCC:
+		return "COND_SUCC";
+	case DECISION_UNCOND_SUCC:
+		return "UNCOND_SUCC";
+	default:
+		return "UNKNOWN";
+	}
+}
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+
+
+#ifdef CONFIG_CTRL_IFACE
+
+/**
+ * eap_sm_get_status - Get EAP state machine status
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @buf: Buffer for status information
+ * @buflen: Maximum buffer length
+ * @verbose: Whether to include verbose status information
+ * Returns: Number of bytes written to buf.
+ *
+ * Query EAP state machine for status information. This function fills in a
+ * text area with current status information from the EAPOL state machine. If
+ * the buffer (buf) is not large enough, status information will be truncated
+ * to fit the buffer.
+ */
+int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen, int verbose)
+{
+	int len, ret;
+
+	if (sm == NULL)
+		return 0;
+
+	len = os_snprintf(buf, buflen,
+			  "EAP state=%s\n",
+			  eap_sm_state_txt(sm->EAP_state));
+	if (len < 0 || (size_t) len >= buflen)
+		return 0;
+
+	if (sm->selectedMethod != EAP_TYPE_NONE) {
+		const char *name;
+		if (sm->m) {
+			name = sm->m->name;
+		} else {
+			const struct eap_method *m =
+				eap_peer_get_eap_method(EAP_VENDOR_IETF,
+							sm->selectedMethod);
+			if (m)
+				name = m->name;
+			else
+				name = "?";
+		}
+		ret = os_snprintf(buf + len, buflen - len,
+				  "selectedMethod=%d (EAP-%s)\n",
+				  sm->selectedMethod, name);
+		if (ret < 0 || (size_t) ret >= buflen - len)
+			return len;
+		len += ret;
+
+		if (sm->m && sm->m->get_status) {
+			len += sm->m->get_status(sm, sm->eap_method_priv,
+						 buf + len, buflen - len,
+						 verbose);
+		}
+	}
+
+	if (verbose) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  "reqMethod=%d\n"
+				  "methodState=%s\n"
+				  "decision=%s\n"
+				  "ClientTimeout=%d\n",
+				  sm->reqMethod,
+				  eap_sm_method_state_txt(sm->methodState),
+				  eap_sm_decision_txt(sm->decision),
+				  sm->ClientTimeout);
+		if (ret < 0 || (size_t) ret >= buflen - len)
+			return len;
+		len += ret;
+	}
+
+	return len;
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static void eap_sm_request(struct eap_sm *sm, enum wpa_ctrl_req_type field,
+			   const char *msg, size_t msglen)
+{
+	struct eap_peer_config *config;
+	char *txt = NULL, *tmp;
+
+	if (sm == NULL)
+		return;
+	config = eap_get_config(sm);
+	if (config == NULL)
+		return;
+
+	switch (field) {
+	case WPA_CTRL_REQ_EAP_IDENTITY:
+		config->pending_req_identity++;
+		break;
+	case WPA_CTRL_REQ_EAP_PASSWORD:
+		config->pending_req_password++;
+		break;
+	case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
+		config->pending_req_new_password++;
+		break;
+	case WPA_CTRL_REQ_EAP_PIN:
+		config->pending_req_pin++;
+		break;
+	case WPA_CTRL_REQ_EAP_OTP:
+		if (msg) {
+			tmp = os_malloc(msglen + 3);
+			if (tmp == NULL)
+				return;
+			tmp[0] = '[';
+			os_memcpy(tmp + 1, msg, msglen);
+			tmp[msglen + 1] = ']';
+			tmp[msglen + 2] = '\0';
+			txt = tmp;
+			os_free(config->pending_req_otp);
+			config->pending_req_otp = tmp;
+			config->pending_req_otp_len = msglen + 3;
+		} else {
+			if (config->pending_req_otp == NULL)
+				return;
+			txt = config->pending_req_otp;
+		}
+		break;
+	case WPA_CTRL_REQ_EAP_PASSPHRASE:
+		config->pending_req_passphrase++;
+		break;
+	default:
+		return;
+	}
+
+	if (sm->eapol_cb->eap_param_needed)
+		sm->eapol_cb->eap_param_needed(sm->eapol_ctx, field, txt);
+}
+#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+#define eap_sm_request(sm, type, msg, msglen) do { } while (0)
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+
+const char * eap_sm_get_method_name(struct eap_sm *sm)
+{
+	if (sm->m == NULL)
+		return "UNKNOWN";
+	return sm->m->name;
+}
+
+
+/**
+ * eap_sm_request_identity - Request identity from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * EAP methods can call this function to request identity information for the
+ * current network. This is normally called when the identity is not included
+ * in the network configuration. The request will be sent to monitor programs
+ * through the control interface.
+ */
+void eap_sm_request_identity(struct eap_sm *sm)
+{
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_IDENTITY, NULL, 0);
+}
+
+
+/**
+ * eap_sm_request_password - Request password from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * EAP methods can call this function to request password information for the
+ * current network. This is normally called when the password is not included
+ * in the network configuration. The request will be sent to monitor programs
+ * through the control interface.
+ */
+void eap_sm_request_password(struct eap_sm *sm)
+{
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSWORD, NULL, 0);
+}
+
+
+/**
+ * eap_sm_request_new_password - Request new password from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * EAP methods can call this function to request new password information for
+ * the current network. This is normally called when the EAP method indicates
+ * that the current password has expired and password change is required. The
+ * request will be sent to monitor programs through the control interface.
+ */
+void eap_sm_request_new_password(struct eap_sm *sm)
+{
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_NEW_PASSWORD, NULL, 0);
+}
+
+
+/**
+ * eap_sm_request_pin - Request SIM or smart card PIN from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * EAP methods can call this function to request SIM or smart card PIN
+ * information for the current network. This is normally called when the PIN is
+ * not included in the network configuration. The request will be sent to
+ * monitor programs through the control interface.
+ */
+void eap_sm_request_pin(struct eap_sm *sm)
+{
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_PIN, NULL, 0);
+}
+
+
+/**
+ * eap_sm_request_otp - Request one time password from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @msg: Message to be displayed to the user when asking for OTP
+ * @msg_len: Length of the user displayable message
+ *
+ * EAP methods can call this function to request open time password (OTP) for
+ * the current network. The request will be sent to monitor programs through
+ * the control interface.
+ */
+void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len)
+{
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_OTP, msg, msg_len);
+}
+
+
+/**
+ * eap_sm_request_passphrase - Request passphrase from user (ctrl_iface)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * EAP methods can call this function to request passphrase for a private key
+ * for the current network. This is normally called when the passphrase is not
+ * included in the network configuration. The request will be sent to monitor
+ * programs through the control interface.
+ */
+void eap_sm_request_passphrase(struct eap_sm *sm)
+{
+	eap_sm_request(sm, WPA_CTRL_REQ_EAP_PASSPHRASE, NULL, 0);
+}
+
+
+/**
+ * eap_sm_notify_ctrl_attached - Notification of attached monitor
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * Notify EAP state machines that a monitor was attached to the control
+ * interface to trigger re-sending of pending requests for user input.
+ */
+void eap_sm_notify_ctrl_attached(struct eap_sm *sm)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+
+	if (config == NULL)
+		return;
+
+	/* Re-send any pending requests for user data since a new control
+	 * interface was added. This handles cases where the EAP authentication
+	 * starts immediately after system startup when the user interface is
+	 * not yet running. */
+	if (config->pending_req_identity)
+		eap_sm_request_identity(sm);
+	if (config->pending_req_password)
+		eap_sm_request_password(sm);
+	if (config->pending_req_new_password)
+		eap_sm_request_new_password(sm);
+	if (config->pending_req_otp)
+		eap_sm_request_otp(sm, NULL, 0);
+	if (config->pending_req_pin)
+		eap_sm_request_pin(sm);
+	if (config->pending_req_passphrase)
+		eap_sm_request_passphrase(sm);
+}
+
+
+static int eap_allowed_phase2_type(int vendor, int type)
+{
+	if (vendor != EAP_VENDOR_IETF)
+		return 0;
+	return type != EAP_TYPE_PEAP && type != EAP_TYPE_TTLS &&
+		type != EAP_TYPE_FAST;
+}
+
+
+/**
+ * eap_get_phase2_type - Get EAP type for the given EAP phase 2 method name
+ * @name: EAP method name, e.g., MD5
+ * @vendor: Buffer for returning EAP Vendor-Id
+ * Returns: EAP method type or %EAP_TYPE_NONE if not found
+ *
+ * This function maps EAP type names into EAP type numbers that are allowed for
+ * Phase 2, i.e., for tunneled authentication. Phase 2 is used, e.g., with
+ * EAP-PEAP, EAP-TTLS, and EAP-FAST.
+ */
+u32 eap_get_phase2_type(const char *name, int *vendor)
+{
+	int v;
+	u8 type = eap_peer_get_type(name, &v);
+	if (eap_allowed_phase2_type(v, type)) {
+		*vendor = v;
+		return type;
+	}
+	*vendor = EAP_VENDOR_IETF;
+	return EAP_TYPE_NONE;
+}
+
+
+/**
+ * eap_get_phase2_types - Get list of allowed EAP phase 2 types
+ * @config: Pointer to a network configuration
+ * @count: Pointer to a variable to be filled with number of returned EAP types
+ * Returns: Pointer to allocated type list or %NULL on failure
+ *
+ * This function generates an array of allowed EAP phase 2 (tunneled) types for
+ * the given network configuration.
+ */
+struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
+					      size_t *count)
+{
+	struct eap_method_type *buf;
+	u32 method;
+	int vendor;
+	size_t mcount;
+	const struct eap_method *methods, *m;
+
+	methods = eap_peer_get_methods(&mcount);
+	if (methods == NULL)
+		return NULL;
+	*count = 0;
+	buf = os_malloc(mcount * sizeof(struct eap_method_type));
+	if (buf == NULL)
+		return NULL;
+
+	for (m = methods; m; m = m->next) {
+		vendor = m->vendor;
+		method = m->method;
+		if (eap_allowed_phase2_type(vendor, method)) {
+			if (vendor == EAP_VENDOR_IETF &&
+			    method == EAP_TYPE_TLS && config &&
+			    config->private_key2 == NULL)
+				continue;
+			buf[*count].vendor = vendor;
+			buf[*count].method = method;
+			(*count)++;
+		}
+	}
+
+	return buf;
+}
+
+
+/**
+ * eap_set_fast_reauth - Update fast_reauth setting
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @enabled: 1 = Fast reauthentication is enabled, 0 = Disabled
+ */
+void eap_set_fast_reauth(struct eap_sm *sm, int enabled)
+{
+	sm->fast_reauth = enabled;
+}
+
+
+/**
+ * eap_set_workaround - Update EAP workarounds setting
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @workaround: 1 = Enable EAP workarounds, 0 = Disable EAP workarounds
+ */
+void eap_set_workaround(struct eap_sm *sm, unsigned int workaround)
+{
+	sm->workaround = workaround;
+}
+
+
+/**
+ * eap_get_config - Get current network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * Returns: Pointer to the current network configuration or %NULL if not found
+ *
+ * EAP peer methods should avoid using this function if they can use other
+ * access functions, like eap_get_config_identity() and
+ * eap_get_config_password(), that do not require direct access to
+ * struct eap_peer_config.
+ */
+struct eap_peer_config * eap_get_config(struct eap_sm *sm)
+{
+	return sm->eapol_cb->get_config(sm->eapol_ctx);
+}
+
+
+/**
+ * eap_get_config_identity - Get identity from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Buffer for the length of the identity
+ * Returns: Pointer to the identity or %NULL if not found
+ */
+const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return NULL;
+	*len = config->identity_len;
+	return config->identity;
+}
+
+
+static int eap_get_ext_password(struct eap_sm *sm,
+				struct eap_peer_config *config)
+{
+	char *name;
+
+	if (config->password == NULL)
+		return -1;
+
+	name = os_zalloc(config->password_len + 1);
+	if (name == NULL)
+		return -1;
+	os_memcpy(name, config->password, config->password_len);
+
+	ext_password_free(sm->ext_pw_buf);
+	sm->ext_pw_buf = ext_password_get(sm->ext_pw, name);
+	os_free(name);
+
+	return sm->ext_pw_buf == NULL ? -1 : 0;
+}
+
+
+/**
+ * eap_get_config_password - Get password from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Buffer for the length of the password
+ * Returns: Pointer to the password or %NULL if not found
+ */
+const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return NULL;
+
+	if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+		if (eap_get_ext_password(sm, config) < 0)
+			return NULL;
+		*len = wpabuf_len(sm->ext_pw_buf);
+		return wpabuf_head(sm->ext_pw_buf);
+	}
+
+	*len = config->password_len;
+	return config->password;
+}
+
+
+/**
+ * eap_get_config_password2 - Get password from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Buffer for the length of the password
+ * @hash: Buffer for returning whether the password is stored as a
+ * NtPasswordHash instead of plaintext password; can be %NULL if this
+ * information is not needed
+ * Returns: Pointer to the password or %NULL if not found
+ */
+const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return NULL;
+
+	if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+		if (eap_get_ext_password(sm, config) < 0)
+			return NULL;
+		*len = wpabuf_len(sm->ext_pw_buf);
+		return wpabuf_head(sm->ext_pw_buf);
+	}
+
+	*len = config->password_len;
+	if (hash)
+		*hash = !!(config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH);
+	return config->password;
+}
+
+
+/**
+ * eap_get_config_new_password - Get new password from network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Buffer for the length of the new password
+ * Returns: Pointer to the new password or %NULL if not found
+ */
+const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return NULL;
+	*len = config->new_password_len;
+	return config->new_password;
+}
+
+
+/**
+ * eap_get_config_otp - Get one-time password from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Buffer for the length of the one-time password
+ * Returns: Pointer to the one-time password or %NULL if not found
+ */
+const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return NULL;
+	*len = config->otp_len;
+	return config->otp;
+}
+
+
+/**
+ * eap_clear_config_otp - Clear used one-time password
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * This function clears a used one-time password (OTP) from the current network
+ * configuration. This should be called when the OTP has been used and is not
+ * needed anymore.
+ */
+void eap_clear_config_otp(struct eap_sm *sm)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return;
+	os_memset(config->otp, 0, config->otp_len);
+	os_free(config->otp);
+	config->otp = NULL;
+	config->otp_len = 0;
+}
+
+
+/**
+ * eap_get_config_phase1 - Get phase1 data from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * Returns: Pointer to the phase1 data or %NULL if not found
+ */
+const char * eap_get_config_phase1(struct eap_sm *sm)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return NULL;
+	return config->phase1;
+}
+
+
+/**
+ * eap_get_config_phase2 - Get phase2 data from the network configuration
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * Returns: Pointer to the phase1 data or %NULL if not found
+ */
+const char * eap_get_config_phase2(struct eap_sm *sm)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return NULL;
+	return config->phase2;
+}
+
+
+int eap_get_config_fragment_size(struct eap_sm *sm)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL)
+		return -1;
+	return config->fragment_size;
+}
+
+
+/**
+ * eap_key_available - Get key availability (eapKeyAvailable variable)
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * Returns: 1 if EAP keying material is available, 0 if not
+ */
+int eap_key_available(struct eap_sm *sm)
+{
+	return sm ? sm->eapKeyAvailable : 0;
+}
+
+
+/**
+ * eap_notify_success - Notify EAP state machine about external success trigger
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * This function is called when external event, e.g., successful completion of
+ * WPA-PSK key handshake, is indicating that EAP state machine should move to
+ * success state. This is mainly used with security modes that do not use EAP
+ * state machine (e.g., WPA-PSK).
+ */
+void eap_notify_success(struct eap_sm *sm)
+{
+	if (sm) {
+		sm->decision = DECISION_COND_SUCC;
+		sm->EAP_state = EAP_SUCCESS;
+	}
+}
+
+
+/**
+ * eap_notify_lower_layer_success - Notification of lower layer success
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * Notify EAP state machines that a lower layer has detected a successful
+ * authentication. This is used to recover from dropped EAP-Success messages.
+ */
+void eap_notify_lower_layer_success(struct eap_sm *sm)
+{
+	if (sm == NULL)
+		return;
+
+	if (eapol_get_bool(sm, EAPOL_eapSuccess) ||
+	    sm->decision == DECISION_FAIL ||
+	    (sm->methodState != METHOD_MAY_CONT &&
+	     sm->methodState != METHOD_DONE))
+		return;
+
+	if (sm->eapKeyData != NULL)
+		sm->eapKeyAvailable = TRUE;
+	eapol_set_bool(sm, EAPOL_eapSuccess, TRUE);
+	wpa_msg(sm->msg_ctx, MSG_INFO, WPA_EVENT_EAP_SUCCESS
+		"EAP authentication completed successfully (based on lower "
+		"layer success)");
+}
+
+
+/**
+ * eap_get_eapKeyData - Get master session key (MSK) from EAP state machine
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @len: Pointer to variable that will be set to number of bytes in the key
+ * Returns: Pointer to the EAP keying data or %NULL on failure
+ *
+ * Fetch EAP keying material (MSK, eapKeyData) from the EAP state machine. The
+ * key is available only after a successful authentication. EAP state machine
+ * continues to manage the key data and the caller must not change or free the
+ * returned data.
+ */
+const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len)
+{
+	if (sm == NULL || sm->eapKeyData == NULL) {
+		*len = 0;
+		return NULL;
+	}
+
+	*len = sm->eapKeyDataLen;
+	return sm->eapKeyData;
+}
+
+
+/**
+ * eap_get_eapKeyData - Get EAP response data
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * Returns: Pointer to the EAP response (eapRespData) or %NULL on failure
+ *
+ * Fetch EAP response (eapRespData) from the EAP state machine. This data is
+ * available when EAP state machine has processed an incoming EAP request. The
+ * EAP state machine does not maintain a reference to the response after this
+ * function is called and the caller is responsible for freeing the data.
+ */
+struct wpabuf * eap_get_eapRespData(struct eap_sm *sm)
+{
+	struct wpabuf *resp;
+
+	if (sm == NULL || sm->eapRespData == NULL)
+		return NULL;
+
+	resp = sm->eapRespData;
+	sm->eapRespData = NULL;
+
+	return resp;
+}
+
+
+/**
+ * eap_sm_register_scard_ctx - Notification of smart card context
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @ctx: Context data for smart card operations
+ *
+ * Notify EAP state machines of context data for smart card operations. This
+ * context data will be used as a parameter for scard_*() functions.
+ */
+void eap_register_scard_ctx(struct eap_sm *sm, void *ctx)
+{
+	if (sm)
+		sm->scard_ctx = ctx;
+}
+
+
+/**
+ * eap_set_config_blob - Set or add a named configuration blob
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @blob: New value for the blob
+ *
+ * Adds a new configuration blob or replaces the current value of an existing
+ * blob.
+ */
+void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob)
+{
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	sm->eapol_cb->set_config_blob(sm->eapol_ctx, blob);
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+}
+
+
+/**
+ * eap_get_config_blob - Get a named configuration blob
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @name: Name of the blob
+ * Returns: Pointer to blob data or %NULL if not found
+ */
+const struct wpa_config_blob * eap_get_config_blob(struct eap_sm *sm,
+						   const char *name)
+{
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	return sm->eapol_cb->get_config_blob(sm->eapol_ctx, name);
+#else /* CONFIG_NO_CONFIG_BLOBS */
+	return NULL;
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+}
+
+
+/**
+ * eap_set_force_disabled - Set force_disabled flag
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @disabled: 1 = EAP disabled, 0 = EAP enabled
+ *
+ * This function is used to force EAP state machine to be disabled when it is
+ * not in use (e.g., with WPA-PSK or plaintext connections).
+ */
+void eap_set_force_disabled(struct eap_sm *sm, int disabled)
+{
+	sm->force_disabled = disabled;
+}
+
+
+ /**
+ * eap_notify_pending - Notify that EAP method is ready to re-process a request
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ *
+ * An EAP method can perform a pending operation (e.g., to get a response from
+ * an external process). Once the response is available, this function can be
+ * used to request EAPOL state machine to retry delivering the previously
+ * received (and still unanswered) EAP request to EAP state machine.
+ */
+void eap_notify_pending(struct eap_sm *sm)
+{
+	sm->eapol_cb->notify_pending(sm->eapol_ctx);
+}
+
+
+/**
+ * eap_invalidate_cached_session - Mark cached session data invalid
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ */
+void eap_invalidate_cached_session(struct eap_sm *sm)
+{
+	if (sm)
+		eap_deinit_prev_method(sm, "invalidate");
+}
+
+
+int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf)
+{
+	if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
+	    os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
+		return 0; /* Not a WPS Enrollee */
+
+	if (conf->phase1 == NULL || os_strstr(conf->phase1, "pbc=1") == NULL)
+		return 0; /* Not using PBC */
+
+	return 1;
+}
+
+
+int eap_is_wps_pin_enrollee(struct eap_peer_config *conf)
+{
+	if (conf->identity_len != WSC_ID_ENROLLEE_LEN ||
+	    os_memcmp(conf->identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN))
+		return 0; /* Not a WPS Enrollee */
+
+	if (conf->phase1 == NULL || os_strstr(conf->phase1, "pin=") == NULL)
+		return 0; /* Not using PIN */
+
+	return 1;
+}
+
+
+void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext)
+{
+	ext_password_free(sm->ext_pw_buf);
+	sm->ext_pw_buf = NULL;
+	sm->ext_pw = ext;
+}
+
+
+/**
+ * eap_set_anon_id - Set or add anonymous identity
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @id: Anonymous identity (e.g., EAP-SIM pseudonym) or %NULL to clear
+ * @len: Length of anonymous identity in octets
+ */
+void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len)
+{
+	if (sm->eapol_cb->set_anon_id)
+		sm->eapol_cb->set_anon_id(sm->eapol_ctx, id, len);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,323 @@
+/*
+ * EAP peer state machine functions (RFC 4137)
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_H
+#define EAP_H
+
+#include "common/defs.h"
+#include "eap_common/eap_defs.h"
+#include "eap_peer/eap_methods.h"
+
+struct eap_sm;
+struct wpa_config_blob;
+struct wpabuf;
+
+struct eap_method_type {
+	int vendor;
+	u32 method;
+};
+
+#ifdef IEEE8021X_EAPOL
+
+/**
+ * enum eapol_bool_var - EAPOL boolean state variables for EAP state machine
+ *
+ * These variables are used in the interface between EAP peer state machine and
+ * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is
+ * expected to maintain these variables and register a callback functions for
+ * EAP state machine to get and set the variables.
+ */
+enum eapol_bool_var {
+	/**
+	 * EAPOL_eapSuccess - EAP SUCCESS state reached
+	 *
+	 * EAP state machine reads and writes this value.
+	 */
+	EAPOL_eapSuccess,
+
+	/**
+	 * EAPOL_eapRestart - Lower layer request to restart authentication
+	 *
+	 * Set to TRUE in lower layer, FALSE in EAP state machine.
+	 */
+	EAPOL_eapRestart,
+
+	/**
+	 * EAPOL_eapFail - EAP FAILURE state reached
+	 *
+	 * EAP state machine writes this value.
+	 */
+	EAPOL_eapFail,
+
+	/**
+	 * EAPOL_eapResp - Response to send
+	 *
+	 * Set to TRUE in EAP state machine, FALSE in lower layer.
+	 */
+	EAPOL_eapResp,
+
+	/**
+	 * EAPOL_eapNoResp - Request has been process; no response to send
+	 *
+	 * Set to TRUE in EAP state machine, FALSE in lower layer.
+	 */
+	EAPOL_eapNoResp,
+
+	/**
+	 * EAPOL_eapReq - EAP request available from lower layer
+	 *
+	 * Set to TRUE in lower layer, FALSE in EAP state machine.
+	 */
+	EAPOL_eapReq,
+
+	/**
+	 * EAPOL_portEnabled - Lower layer is ready for communication
+	 *
+	 * EAP state machines reads this value.
+	 */
+	EAPOL_portEnabled,
+
+	/**
+	 * EAPOL_altAccept - Alternate indication of success (RFC3748)
+	 *
+	 * EAP state machines reads this value.
+	 */
+	EAPOL_altAccept,
+
+	/**
+	 * EAPOL_altReject - Alternate indication of failure (RFC3748)
+	 *
+	 * EAP state machines reads this value.
+	 */
+	EAPOL_altReject
+};
+
+/**
+ * enum eapol_int_var - EAPOL integer state variables for EAP state machine
+ *
+ * These variables are used in the interface between EAP peer state machine and
+ * lower layer. These are defined in RFC 4137, Sect. 4.1. Lower layer code is
+ * expected to maintain these variables and register a callback functions for
+ * EAP state machine to get and set the variables.
+ */
+enum eapol_int_var {
+	/**
+	 * EAPOL_idleWhile - Outside time for EAP peer timeout
+	 *
+	 * This integer variable is used to provide an outside timer that the
+	 * external (to EAP state machine) code must decrement by one every
+	 * second until the value reaches zero. This is used in the same way as
+	 * EAPOL state machine timers. EAP state machine reads and writes this
+	 * value.
+	 */
+	EAPOL_idleWhile
+};
+
+/**
+ * struct eapol_callbacks - Callback functions from EAP to lower layer
+ *
+ * This structure defines the callback functions that EAP state machine
+ * requires from the lower layer (usually EAPOL state machine) for updating
+ * state variables and requesting information. eapol_ctx from
+ * eap_peer_sm_init() call will be used as the ctx parameter for these
+ * callback functions.
+ */
+struct eapol_callbacks {
+	/**
+	 * get_config - Get pointer to the current network configuration
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 */
+	struct eap_peer_config * (*get_config)(void *ctx);
+
+	/**
+	 * get_bool - Get a boolean EAPOL state variable
+	 * @variable: EAPOL boolean variable to get
+	 * Returns: Value of the EAPOL variable
+	 */
+	Boolean (*get_bool)(void *ctx, enum eapol_bool_var variable);
+
+	/**
+	 * set_bool - Set a boolean EAPOL state variable
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @variable: EAPOL boolean variable to set
+	 * @value: Value for the EAPOL variable
+	 */
+	void (*set_bool)(void *ctx, enum eapol_bool_var variable,
+			 Boolean value);
+
+	/**
+	 * get_int - Get an integer EAPOL state variable
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @variable: EAPOL integer variable to get
+	 * Returns: Value of the EAPOL variable
+	 */
+	unsigned int (*get_int)(void *ctx, enum eapol_int_var variable);
+
+	/**
+	 * set_int - Set an integer EAPOL state variable
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @variable: EAPOL integer variable to set
+	 * @value: Value for the EAPOL variable
+	 */
+	void (*set_int)(void *ctx, enum eapol_int_var variable,
+			unsigned int value);
+
+	/**
+	 * get_eapReqData - Get EAP-Request data
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @len: Pointer to variable that will be set to eapReqDataLen
+	 * Returns: Reference to eapReqData (EAP state machine will not free
+	 * this) or %NULL if eapReqData not available.
+	 */
+	struct wpabuf * (*get_eapReqData)(void *ctx);
+
+	/**
+	 * set_config_blob - Set named configuration blob
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @blob: New value for the blob
+	 *
+	 * Adds a new configuration blob or replaces the current value of an
+	 * existing blob.
+	 */
+	void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
+
+	/**
+	 * get_config_blob - Get a named configuration blob
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @name: Name of the blob
+	 * Returns: Pointer to blob data or %NULL if not found
+	 */
+	const struct wpa_config_blob * (*get_config_blob)(void *ctx,
+							  const char *name);
+
+	/**
+	 * notify_pending - Notify that a pending request can be retried
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 *
+	 * An EAP method can perform a pending operation (e.g., to get a
+	 * response from an external process). Once the response is available,
+	 * this callback function can be used to request EAPOL state machine to
+	 * retry delivering the previously received (and still unanswered) EAP
+	 * request to EAP state machine.
+	 */
+	void (*notify_pending)(void *ctx);
+
+	/**
+	 * eap_param_needed - Notify that EAP parameter is needed
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY)
+	 * @txt: User readable text describing the required parameter
+	 */
+	void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field,
+				 const char *txt);
+
+	/**
+	 * notify_cert - Notification of a peer certificate
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @depth: Depth in certificate chain (0 = server)
+	 * @subject: Subject of the peer certificate
+	 * @cert_hash: SHA-256 hash of the certificate
+	 * @cert: Peer certificate
+	 */
+	void (*notify_cert)(void *ctx, int depth, const char *subject,
+			    const char *cert_hash, const struct wpabuf *cert);
+
+	/**
+	 * notify_status - Notification of the current EAP state
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @status: Step in the process of EAP authentication
+	 * @parameter: Step-specific parameter, e.g., EAP method name
+	 */
+	void (*notify_status)(void *ctx, const char *status,
+			      const char *parameter);
+
+	/**
+	 * set_anon_id - Set or add anonymous identity
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @id: Anonymous identity (e.g., EAP-SIM pseudonym) or %NULL to clear
+	 * @len: Length of anonymous identity in octets
+	 */
+	void (*set_anon_id)(void *ctx, const u8 *id, size_t len);
+};
+
+/**
+ * struct eap_config - Configuration for EAP state machine
+ */
+struct eap_config {
+	/**
+	 * opensc_engine_path - OpenSC engine for OpenSSL engine support
+	 *
+	 * Usually, path to engine_opensc.so.
+	 */
+	const char *opensc_engine_path;
+	/**
+	 * pkcs11_engine_path - PKCS#11 engine for OpenSSL engine support
+	 *
+	 * Usually, path to engine_pkcs11.so.
+	 */
+	const char *pkcs11_engine_path;
+	/**
+	 * pkcs11_module_path - OpenSC PKCS#11 module for OpenSSL engine
+	 *
+	 * Usually, path to opensc-pkcs11.so.
+	 */
+	const char *pkcs11_module_path;
+	/**
+	 * wps - WPS context data
+	 *
+	 * This is only used by EAP-WSC and can be left %NULL if not available.
+	 */
+	struct wps_context *wps;
+
+	/**
+	 * cert_in_cb - Include server certificates in callback
+	 */
+	int cert_in_cb;
+};
+
+struct eap_sm * eap_peer_sm_init(void *eapol_ctx,
+				 struct eapol_callbacks *eapol_cb,
+				 void *msg_ctx, struct eap_config *conf);
+void eap_peer_sm_deinit(struct eap_sm *sm);
+int eap_peer_sm_step(struct eap_sm *sm);
+void eap_sm_abort(struct eap_sm *sm);
+int eap_sm_get_status(struct eap_sm *sm, char *buf, size_t buflen,
+		      int verbose);
+const char * eap_sm_get_method_name(struct eap_sm *sm);
+struct wpabuf * eap_sm_buildIdentity(struct eap_sm *sm, int id, int encrypted);
+void eap_sm_request_identity(struct eap_sm *sm);
+void eap_sm_request_password(struct eap_sm *sm);
+void eap_sm_request_new_password(struct eap_sm *sm);
+void eap_sm_request_pin(struct eap_sm *sm);
+void eap_sm_request_otp(struct eap_sm *sm, const char *msg, size_t msg_len);
+void eap_sm_request_passphrase(struct eap_sm *sm);
+void eap_sm_notify_ctrl_attached(struct eap_sm *sm);
+u32 eap_get_phase2_type(const char *name, int *vendor);
+struct eap_method_type * eap_get_phase2_types(struct eap_peer_config *config,
+					      size_t *count);
+void eap_set_fast_reauth(struct eap_sm *sm, int enabled);
+void eap_set_workaround(struct eap_sm *sm, unsigned int workaround);
+void eap_set_force_disabled(struct eap_sm *sm, int disabled);
+int eap_key_available(struct eap_sm *sm);
+void eap_notify_success(struct eap_sm *sm);
+void eap_notify_lower_layer_success(struct eap_sm *sm);
+const u8 * eap_get_eapKeyData(struct eap_sm *sm, size_t *len);
+struct wpabuf * eap_get_eapRespData(struct eap_sm *sm);
+void eap_register_scard_ctx(struct eap_sm *sm, void *ctx);
+void eap_invalidate_cached_session(struct eap_sm *sm);
+
+int eap_is_wps_pbc_enrollee(struct eap_peer_config *conf);
+int eap_is_wps_pin_enrollee(struct eap_peer_config *conf);
+
+struct ext_password_data;
+void eap_sm_set_ext_pw_ctx(struct eap_sm *sm, struct ext_password_data *ext);
+void eap_set_anon_id(struct eap_sm *sm, const u8 *id, size_t len);
+
+#endif /* IEEE8021X_EAPOL */
+
+#endif /* EAP_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_config.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,669 @@
+/*
+ * EAP peer configuration data
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_CONFIG_H
+#define EAP_CONFIG_H
+
+/**
+ * struct eap_peer_config - EAP peer configuration/credentials
+ */
+struct eap_peer_config {
+	/**
+	 * identity - EAP Identity
+	 *
+	 * This field is used to set the real user identity or NAI (for
+	 * EAP-PSK/PAX/SAKE/GPSK).
+	 */
+	u8 *identity;
+
+	/**
+	 * identity_len - EAP Identity length
+	 */
+	size_t identity_len;
+
+	/**
+	 * anonymous_identity -  Anonymous EAP Identity
+	 *
+	 * This field is used for unencrypted use with EAP types that support
+	 * different tunnelled identity, e.g., EAP-TTLS, in order to reveal the
+	 * real identity (identity field) only to the authentication server.
+	 *
+	 * If not set, the identity field will be used for both unencrypted and
+	 * protected fields.
+	 *
+	 * This field can also be used with EAP-SIM/AKA/AKA' to store the
+	 * pseudonym identity.
+	 */
+	u8 *anonymous_identity;
+
+	/**
+	 * anonymous_identity_len - Length of anonymous_identity
+	 */
+	size_t anonymous_identity_len;
+
+	/**
+	 * password - Password string for EAP
+	 *
+	 * This field can include either the plaintext password (default
+	 * option) or a NtPasswordHash (16-byte MD4 hash of the unicode
+	 * presentation of the password) if flags field has
+	 * EAP_CONFIG_FLAGS_PASSWORD_NTHASH bit set to 1. NtPasswordHash can
+	 * only be used with authentication mechanism that use this hash as the
+	 * starting point for operation: MSCHAP and MSCHAPv2 (EAP-MSCHAPv2,
+	 * EAP-TTLS/MSCHAPv2, EAP-TTLS/MSCHAP, LEAP).
+	 *
+	 * In addition, this field is used to configure a pre-shared key for
+	 * EAP-PSK/PAX/SAKE/GPSK. The length of the PSK must be 16 for EAP-PSK
+	 * and EAP-PAX and 32 for EAP-SAKE. EAP-GPSK can use a variable length
+	 * PSK.
+	 */
+	u8 *password;
+
+	/**
+	 * password_len - Length of password field
+	 */
+	size_t password_len;
+
+	/**
+	 * ca_cert - File path to CA certificate file (PEM/DER)
+	 *
+	 * This file can have one or more trusted CA certificates. If ca_cert
+	 * and ca_path are not included, server certificate will not be
+	 * verified. This is insecure and a trusted CA certificate should
+	 * always be configured when using EAP-TLS/TTLS/PEAP. Full path to the
+	 * file should be used since working directory may change when
+	 * wpa_supplicant is run in the background.
+	 *
+	 * Alternatively, a named configuration blob can be used by setting
+	 * this to blob://blob_name.
+	 *
+	 * Alternatively, this can be used to only perform matching of the
+	 * server certificate (SHA-256 hash of the DER encoded X.509
+	 * certificate). In this case, the possible CA certificates in the
+	 * server certificate chain are ignored and only the server certificate
+	 * is verified. This is configured with the following format:
+	 * hash:://server/sha256/cert_hash_in_hex
+	 * For example: "hash://server/sha256/
+	 * 5a1bc1296205e6fdbe3979728efe3920798885c1c4590b5f90f43222d239ca6a"
+	 *
+	 * On Windows, trusted CA certificates can be loaded from the system
+	 * certificate store by setting this to cert_store://name, e.g.,
+	 * ca_cert="cert_store://CA" or ca_cert="cert_store://ROOT".
+	 * Note that when running wpa_supplicant as an application, the user
+	 * certificate store (My user account) is used, whereas computer store
+	 * (Computer account) is used when running wpasvc as a service.
+	 */
+	u8 *ca_cert;
+
+	/**
+	 * ca_path - Directory path for CA certificate files (PEM)
+	 *
+	 * This path may contain multiple CA certificates in OpenSSL format.
+	 * Common use for this is to point to system trusted CA list which is
+	 * often installed into directory like /etc/ssl/certs. If configured,
+	 * these certificates are added to the list of trusted CAs. ca_cert
+	 * may also be included in that case, but it is not required.
+	 */
+	u8 *ca_path;
+
+	/**
+	 * client_cert - File path to client certificate file (PEM/DER)
+	 *
+	 * This field is used with EAP method that use TLS authentication.
+	 * Usually, this is only configured for EAP-TLS, even though this could
+	 * in theory be used with EAP-TTLS and EAP-PEAP, too. Full path to the
+	 * file should be used since working directory may change when
+	 * wpa_supplicant is run in the background.
+	 *
+	 * Alternatively, a named configuration blob can be used by setting
+	 * this to blob://blob_name.
+	 */
+	u8 *client_cert;
+
+	/**
+	 * private_key - File path to client private key file (PEM/DER/PFX)
+	 *
+	 * When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
+	 * commented out. Both the private key and certificate will be read
+	 * from the PKCS#12 file in this case. Full path to the file should be
+	 * used since working directory may change when wpa_supplicant is run
+	 * in the background.
+	 *
+	 * Windows certificate store can be used by leaving client_cert out and
+	 * configuring private_key in one of the following formats:
+	 *
+	 * cert://substring_to_match
+	 *
+	 * hash://certificate_thumbprint_in_hex
+	 *
+	 * For example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
+	 *
+	 * Note that when running wpa_supplicant as an application, the user
+	 * certificate store (My user account) is used, whereas computer store
+	 * (Computer account) is used when running wpasvc as a service.
+	 *
+	 * Alternatively, a named configuration blob can be used by setting
+	 * this to blob://blob_name.
+	 */
+	u8 *private_key;
+
+	/**
+	 * private_key_passwd - Password for private key file
+	 *
+	 * If left out, this will be asked through control interface.
+	 */
+	u8 *private_key_passwd;
+
+	/**
+	 * dh_file - File path to DH/DSA parameters file (in PEM format)
+	 *
+	 * This is an optional configuration file for setting parameters for an
+	 * ephemeral DH key exchange. In most cases, the default RSA
+	 * authentication does not use this configuration. However, it is
+	 * possible setup RSA to use ephemeral DH key exchange. In addition,
+	 * ciphers with DSA keys always use ephemeral DH keys. This can be used
+	 * to achieve forward secrecy. If the file is in DSA parameters format,
+	 * it will be automatically converted into DH params. Full path to the
+	 * file should be used since working directory may change when
+	 * wpa_supplicant is run in the background.
+	 *
+	 * Alternatively, a named configuration blob can be used by setting
+	 * this to blob://blob_name.
+	 */
+	u8 *dh_file;
+
+	/**
+	 * subject_match - Constraint for server certificate subject
+	 *
+	 * This substring is matched against the subject of the authentication
+	 * server certificate. If this string is set, the server sertificate is
+	 * only accepted if it contains this string in the subject. The subject
+	 * string is in following format:
+	 *
+	 * /C=US/ST=CA/L=San Francisco/CN=Test AS/emailAddress=as@n.example.com
+	 */
+	u8 *subject_match;
+
+	/**
+	 * altsubject_match - Constraint for server certificate alt. subject
+	 *
+	 * Semicolon separated string of entries to be matched against the
+	 * alternative subject name of the authentication server certificate.
+	 * If this string is set, the server sertificate is only accepted if it
+	 * contains one of the entries in an alternative subject name
+	 * extension.
+	 *
+	 * altSubjectName string is in following format: TYPE:VALUE
+	 *
+	 * Example: EMAIL:server@example.com
+	 * Example: DNS:server.example.com;DNS:server2.example.com
+	 *
+	 * Following types are supported: EMAIL, DNS, URI
+	 */
+	u8 *altsubject_match;
+
+	/**
+	 * ca_cert2 - File path to CA certificate file (PEM/DER) (Phase 2)
+	 *
+	 * This file can have one or more trusted CA certificates. If ca_cert2
+	 * and ca_path2 are not included, server certificate will not be
+	 * verified. This is insecure and a trusted CA certificate should
+	 * always be configured. Full path to the file should be used since
+	 * working directory may change when wpa_supplicant is run in the
+	 * background.
+	 *
+	 * This field is like ca_cert, but used for phase 2 (inside
+	 * EAP-TTLS/PEAP/FAST tunnel) authentication.
+	 *
+	 * Alternatively, a named configuration blob can be used by setting
+	 * this to blob://blob_name.
+	 */
+	u8 *ca_cert2;
+
+	/**
+	 * ca_path2 - Directory path for CA certificate files (PEM) (Phase 2)
+	 *
+	 * This path may contain multiple CA certificates in OpenSSL format.
+	 * Common use for this is to point to system trusted CA list which is
+	 * often installed into directory like /etc/ssl/certs. If configured,
+	 * these certificates are added to the list of trusted CAs. ca_cert
+	 * may also be included in that case, but it is not required.
+	 *
+	 * This field is like ca_path, but used for phase 2 (inside
+	 * EAP-TTLS/PEAP/FAST tunnel) authentication.
+	 */
+	u8 *ca_path2;
+
+	/**
+	 * client_cert2 - File path to client certificate file
+	 *
+	 * This field is like client_cert, but used for phase 2 (inside
+	 * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
+	 * file should be used since working directory may change when
+	 * wpa_supplicant is run in the background.
+	 *
+	 * Alternatively, a named configuration blob can be used by setting
+	 * this to blob://blob_name.
+	 */
+	u8 *client_cert2;
+
+	/**
+	 * private_key2 - File path to client private key file
+	 *
+	 * This field is like private_key, but used for phase 2 (inside
+	 * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
+	 * file should be used since working directory may change when
+	 * wpa_supplicant is run in the background.
+	 *
+	 * Alternatively, a named configuration blob can be used by setting
+	 * this to blob://blob_name.
+	 */
+	u8 *private_key2;
+
+	/**
+	 * private_key2_passwd -  Password for private key file
+	 *
+	 * This field is like private_key_passwd, but used for phase 2 (inside
+	 * EAP-TTLS/PEAP/FAST tunnel) authentication.
+	 */
+	u8 *private_key2_passwd;
+
+	/**
+	 * dh_file2 - File path to DH/DSA parameters file (in PEM format)
+	 *
+	 * This field is like dh_file, but used for phase 2 (inside
+	 * EAP-TTLS/PEAP/FAST tunnel) authentication. Full path to the
+	 * file should be used since working directory may change when
+	 * wpa_supplicant is run in the background.
+	 *
+	 * Alternatively, a named configuration blob can be used by setting
+	 * this to blob://blob_name.
+	 */
+	u8 *dh_file2;
+
+	/**
+	 * subject_match2 - Constraint for server certificate subject
+	 *
+	 * This field is like subject_match, but used for phase 2 (inside
+	 * EAP-TTLS/PEAP/FAST tunnel) authentication.
+	 */
+	u8 *subject_match2;
+
+	/**
+	 * altsubject_match2 - Constraint for server certificate alt. subject
+	 *
+	 * This field is like altsubject_match, but used for phase 2 (inside
+	 * EAP-TTLS/PEAP/FAST tunnel) authentication.
+	 */
+	u8 *altsubject_match2;
+
+	/**
+	 * eap_methods - Allowed EAP methods
+	 *
+	 * (vendor=EAP_VENDOR_IETF,method=EAP_TYPE_NONE) terminated list of
+	 * allowed EAP methods or %NULL if all methods are accepted.
+	 */
+	struct eap_method_type *eap_methods;
+
+	/**
+	 * phase1 - Phase 1 (outer authentication) parameters
+	 *
+	 * String with field-value pairs, e.g., "peapver=0" or
+	 * "peapver=1 peaplabel=1".
+	 *
+	 * 'peapver' can be used to force which PEAP version (0 or 1) is used.
+	 *
+	 * 'peaplabel=1' can be used to force new label, "client PEAP
+	 * encryption",	to be used during key derivation when PEAPv1 or newer.
+	 *
+	 * Most existing PEAPv1 implementation seem to be using the old label,
+	 * "client EAP encryption", and wpa_supplicant is now using that as the
+	 * default value.
+	 *
+	 * Some servers, e.g., Radiator, may require peaplabel=1 configuration
+	 * to interoperate with PEAPv1; see eap_testing.txt for more details.
+	 *
+	 * 'peap_outer_success=0' can be used to terminate PEAP authentication
+	 * on tunneled EAP-Success. This is required with some RADIUS servers
+	 * that implement draft-josefsson-pppext-eap-tls-eap-05.txt (e.g.,
+	 * Lucent NavisRadius v4.4.0 with PEAP in "IETF Draft 5" mode).
+	 *
+	 * include_tls_length=1 can be used to force wpa_supplicant to include
+	 * TLS Message Length field in all TLS messages even if they are not
+	 * fragmented.
+	 *
+	 * sim_min_num_chal=3 can be used to configure EAP-SIM to require three
+	 * challenges (by default, it accepts 2 or 3).
+	 *
+	 * result_ind=1 can be used to enable EAP-SIM and EAP-AKA to use
+	 * protected result indication.
+	 *
+	 * fast_provisioning option can be used to enable in-line provisioning
+	 * of EAP-FAST credentials (PAC):
+	 * 0 = disabled,
+	 * 1 = allow unauthenticated provisioning,
+	 * 2 = allow authenticated provisioning,
+	 * 3 = allow both unauthenticated and authenticated provisioning
+	 *
+	 * fast_max_pac_list_len=num option can be used to set the maximum
+	 * number of PAC entries to store in a PAC list (default: 10).
+	 *
+	 * fast_pac_format=binary option can be used to select binary format
+	 * for storing PAC entries in order to save some space (the default
+	 * text format uses about 2.5 times the size of minimal binary format).
+	 *
+	 * crypto_binding option can be used to control PEAPv0 cryptobinding
+	 * behavior:
+	 * 0 = do not use cryptobinding (default)
+	 * 1 = use cryptobinding if server supports it
+	 * 2 = require cryptobinding
+	 *
+	 * EAP-WSC (WPS) uses following options: pin=Device_Password and
+	 * uuid=Device_UUID
+	 */
+	char *phase1;
+
+	/**
+	 * phase2 - Phase2 (inner authentication with TLS tunnel) parameters
+	 *
+	 * String with field-value pairs, e.g., "auth=MSCHAPV2" for EAP-PEAP or
+	 * "autheap=MSCHAPV2 autheap=MD5" for EAP-TTLS.
+	 */
+	char *phase2;
+
+	/**
+	 * pcsc - Parameters for PC/SC smartcard interface for USIM and GSM SIM
+	 *
+	 * This field is used to configure PC/SC smartcard interface.
+	 * Currently, the only configuration is whether this field is %NULL (do
+	 * not use PC/SC) or non-NULL (e.g., "") to enable PC/SC.
+	 *
+	 * This field is used for EAP-SIM and EAP-AKA.
+	 */
+	char *pcsc;
+
+	/**
+	 * pin - PIN for USIM, GSM SIM, and smartcards
+	 *
+	 * This field is used to configure PIN for SIM and smartcards for
+	 * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
+	 * smartcard is used for private key operations.
+	 *
+	 * If left out, this will be asked through control interface.
+	 */
+	char *pin;
+
+	/**
+	 * engine - Enable OpenSSL engine (e.g., for smartcard access)
+	 *
+	 * This is used if private key operations for EAP-TLS are performed
+	 * using a smartcard.
+	 */
+	int engine;
+
+	/**
+	 * engine_id - Engine ID for OpenSSL engine
+	 *
+	 * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
+	 * engine.
+	 *
+	 * This is used if private key operations for EAP-TLS are performed
+	 * using a smartcard.
+	 */
+	char *engine_id;
+
+	/**
+	 * engine2 - Enable OpenSSL engine (e.g., for smartcard) (Phase 2)
+	 *
+	 * This is used if private key operations for EAP-TLS are performed
+	 * using a smartcard.
+	 *
+	 * This field is like engine, but used for phase 2 (inside
+	 * EAP-TTLS/PEAP/FAST tunnel) authentication.
+	 */
+	int engine2;
+
+
+	/**
+	 * pin2 - PIN for USIM, GSM SIM, and smartcards (Phase 2)
+	 *
+	 * This field is used to configure PIN for SIM and smartcards for
+	 * EAP-SIM and EAP-AKA. In addition, this is used with EAP-TLS if a
+	 * smartcard is used for private key operations.
+	 *
+	 * This field is like pin2, but used for phase 2 (inside
+	 * EAP-TTLS/PEAP/FAST tunnel) authentication.
+	 *
+	 * If left out, this will be asked through control interface.
+	 */
+	char *pin2;
+
+	/**
+	 * engine2_id - Engine ID for OpenSSL engine (Phase 2)
+	 *
+	 * "opensc" to select OpenSC engine or "pkcs11" to select PKCS#11
+	 * engine.
+	 *
+	 * This is used if private key operations for EAP-TLS are performed
+	 * using a smartcard.
+	 *
+	 * This field is like engine_id, but used for phase 2 (inside
+	 * EAP-TTLS/PEAP/FAST tunnel) authentication.
+	 */
+	char *engine2_id;
+
+
+	/**
+	 * key_id - Key ID for OpenSSL engine
+	 *
+	 * This is used if private key operations for EAP-TLS are performed
+	 * using a smartcard.
+	 */
+	char *key_id;
+
+	/**
+	 * cert_id - Cert ID for OpenSSL engine
+	 *
+	 * This is used if the certificate operations for EAP-TLS are performed
+	 * using a smartcard.
+	 */
+	char *cert_id;
+
+	/**
+	 * ca_cert_id - CA Cert ID for OpenSSL engine
+	 *
+	 * This is used if the CA certificate for EAP-TLS is on a smartcard.
+	 */
+	char *ca_cert_id;
+
+	/**
+	 * key2_id - Key ID for OpenSSL engine (phase2)
+	 *
+	 * This is used if private key operations for EAP-TLS are performed
+	 * using a smartcard.
+	 */
+	char *key2_id;
+
+	/**
+	 * cert2_id - Cert ID for OpenSSL engine (phase2)
+	 *
+	 * This is used if the certificate operations for EAP-TLS are performed
+	 * using a smartcard.
+	 */
+	char *cert2_id;
+
+	/**
+	 * ca_cert2_id - CA Cert ID for OpenSSL engine (phase2)
+	 *
+	 * This is used if the CA certificate for EAP-TLS is on a smartcard.
+	 */
+	char *ca_cert2_id;
+
+	/**
+	 * otp - One-time-password
+	 *
+	 * This field should not be set in configuration step. It is only used
+	 * internally when OTP is entered through the control interface.
+	 */
+	u8 *otp;
+
+	/**
+	 * otp_len - Length of the otp field
+	 */
+	size_t otp_len;
+
+	/**
+	 * pending_req_identity - Whether there is a pending identity request
+	 *
+	 * This field should not be set in configuration step. It is only used
+	 * internally when control interface is used to request needed
+	 * information.
+	 */
+	int pending_req_identity;
+
+	/**
+	 * pending_req_password - Whether there is a pending password request
+	 *
+	 * This field should not be set in configuration step. It is only used
+	 * internally when control interface is used to request needed
+	 * information.
+	 */
+	int pending_req_password;
+
+	/**
+	 * pending_req_pin - Whether there is a pending PIN request
+	 *
+	 * This field should not be set in configuration step. It is only used
+	 * internally when control interface is used to request needed
+	 * information.
+	 */
+	int pending_req_pin;
+
+	/**
+	 * pending_req_new_password - Pending password update request
+	 *
+	 * This field should not be set in configuration step. It is only used
+	 * internally when control interface is used to request needed
+	 * information.
+	 */
+	int pending_req_new_password;
+
+	/**
+	 * pending_req_passphrase - Pending passphrase request
+	 *
+	 * This field should not be set in configuration step. It is only used
+	 * internally when control interface is used to request needed
+	 * information.
+	 */
+	int pending_req_passphrase;
+
+	/**
+	 * pending_req_otp - Whether there is a pending OTP request
+	 *
+	 * This field should not be set in configuration step. It is only used
+	 * internally when control interface is used to request needed
+	 * information.
+	 */
+	char *pending_req_otp;
+
+	/**
+	 * pending_req_otp_len - Length of the pending OTP request
+	 */
+	size_t pending_req_otp_len;
+
+	/**
+	 * pac_file - File path or blob name for the PAC entries (EAP-FAST)
+	 *
+	 * wpa_supplicant will need to be able to create this file and write
+	 * updates to it when PAC is being provisioned or refreshed. Full path
+	 * to the file should be used since working directory may change when
+	 * wpa_supplicant is run in the background.
+	 * Alternatively, a named configuration blob can be used by setting
+	 * this to blob://blob_name.
+	 */
+	char *pac_file;
+
+	/**
+	 * mschapv2_retry - MSCHAPv2 retry in progress
+	 *
+	 * This field is used internally by EAP-MSCHAPv2 and should not be set
+	 * as part of configuration.
+	 */
+	int mschapv2_retry;
+
+	/**
+	 * new_password - New password for password update
+	 *
+	 * This field is used during MSCHAPv2 password update. This is normally
+	 * requested from the user through the control interface and not set
+	 * from configuration.
+	 */
+	u8 *new_password;
+
+	/**
+	 * new_password_len - Length of new_password field
+	 */
+	size_t new_password_len;
+
+	/**
+	 * fragment_size - Maximum EAP fragment size in bytes (default 1398)
+	 *
+	 * This value limits the fragment size for EAP methods that support
+	 * fragmentation (e.g., EAP-TLS and EAP-PEAP). This value should be set
+	 * small enough to make the EAP messages fit in MTU of the network
+	 * interface used for EAPOL. The default value is suitable for most
+	 * cases.
+	 */
+	int fragment_size;
+
+#define EAP_CONFIG_FLAGS_PASSWORD_NTHASH BIT(0)
+#define EAP_CONFIG_FLAGS_EXT_PASSWORD BIT(1)
+	/**
+	 * flags - Network configuration flags (bitfield)
+	 *
+	 * This variable is used for internal flags to describe further details
+	 * for the network parameters.
+	 * bit 0 = password is represented as a 16-byte NtPasswordHash value
+	 *         instead of plaintext password
+	 * bit 1 = password is stored in external storage; the value in the
+	 *         password field is the name of that external entry
+	 */
+	u32 flags;
+};
+
+
+/**
+ * struct wpa_config_blob - Named configuration blob
+ *
+ * This data structure is used to provide storage for binary objects to store
+ * abstract information like certificates and private keys inlined with the
+ * configuration data.
+ */
+struct wpa_config_blob {
+	/**
+	 * name - Blob name
+	 */
+	char *name;
+
+	/**
+	 * data - Pointer to binary data
+	 */
+	u8 *data;
+
+	/**
+	 * len - Length of binary data
+	 */
+	size_t len;
+
+	/**
+	 * next - Pointer to next blob in the configuration
+	 */
+	struct wpa_config_blob *next;
+};
+
+#endif /* EAP_CONFIG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_gtc.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,145 @@
+/*
+ * EAP peer method: EAP-GTC (RFC 3748)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_i.h"
+
+
+struct eap_gtc_data {
+	int prefix;
+};
+
+
+static void * eap_gtc_init(struct eap_sm *sm)
+{
+	struct eap_gtc_data *data;
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	if (sm->m && sm->m->vendor == EAP_VENDOR_IETF &&
+	    sm->m->method == EAP_TYPE_FAST) {
+		wpa_printf(MSG_DEBUG, "EAP-GTC: EAP-FAST tunnel - use prefix "
+			   "with challenge/response");
+		data->prefix = 1;
+	}
+	return data;
+}
+
+
+static void eap_gtc_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_gtc_data *data = priv;
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_gtc_process(struct eap_sm *sm, void *priv,
+				       struct eap_method_ret *ret,
+				       const struct wpabuf *reqData)
+{
+	struct eap_gtc_data *data = priv;
+	struct wpabuf *resp;
+	const u8 *pos, *password, *identity;
+	size_t password_len, identity_len, len, plen;
+	int otp;
+	u8 id;
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC, reqData, &len);
+	if (pos == NULL) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	id = eap_get_id(reqData);
+
+	wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-GTC: Request message", pos, len);
+	if (data->prefix &&
+	    (len < 10 || os_memcmp(pos, "CHALLENGE=", 10) != 0)) {
+		wpa_printf(MSG_DEBUG, "EAP-GTC: Challenge did not start with "
+			   "expected prefix");
+
+		/* Send an empty response in order to allow tunneled
+		 * acknowledgement of the failure. This will also cover the
+		 * error case which seems to use EAP-MSCHAPv2 like error
+		 * reporting with EAP-GTC inside EAP-FAST tunnel. */
+		resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC,
+				     0, EAP_CODE_RESPONSE, id);
+		return resp;
+	}
+
+	password = eap_get_config_otp(sm, &password_len);
+	if (password)
+		otp = 1;
+	else {
+		password = eap_get_config_password(sm, &password_len);
+		otp = 0;
+	}
+
+	if (password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-GTC: Password not configured");
+		eap_sm_request_otp(sm, (const char *) pos, len);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	ret->ignore = FALSE;
+
+	ret->methodState = data->prefix ? METHOD_MAY_CONT : METHOD_DONE;
+	ret->decision = DECISION_COND_SUCC;
+	ret->allowNotifications = FALSE;
+
+	plen = password_len;
+	identity = eap_get_config_identity(sm, &identity_len);
+	if (identity == NULL)
+		return NULL;
+	if (data->prefix)
+		plen += 9 + identity_len + 1;
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, plen,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+	if (data->prefix) {
+		wpabuf_put_data(resp, "RESPONSE=", 9);
+		wpabuf_put_data(resp, identity, identity_len);
+		wpabuf_put_u8(resp, '\0');
+	}
+	wpabuf_put_data(resp, password, password_len);
+	wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-GTC: Response",
+			      wpabuf_head_u8(resp) + sizeof(struct eap_hdr) +
+			      1, plen);
+
+	if (otp) {
+		wpa_printf(MSG_DEBUG, "EAP-GTC: Forgetting used password");
+		eap_clear_config_otp(sm);
+	}
+
+	return resp;
+}
+
+
+int eap_peer_gtc_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+				    EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_gtc_init;
+	eap->deinit = eap_gtc_deinit;
+	eap->process = eap_gtc_process;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_i.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,354 @@
+/*
+ * EAP peer state machines internal structures (RFC 4137)
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_I_H
+#define EAP_I_H
+
+#include "wpabuf.h"
+#include "eap_peer/eap.h"
+#include "eap_common/eap_common.h"
+
+/* RFC 4137 - EAP Peer state machine */
+
+typedef enum {
+	DECISION_FAIL, DECISION_COND_SUCC, DECISION_UNCOND_SUCC
+} EapDecision;
+
+typedef enum {
+	METHOD_NONE, METHOD_INIT, METHOD_CONT, METHOD_MAY_CONT, METHOD_DONE
+} EapMethodState;
+
+/**
+ * struct eap_method_ret - EAP return values from struct eap_method::process()
+ *
+ * These structure contains OUT variables for the interface between peer state
+ * machine and methods (RFC 4137, Sect. 4.2). eapRespData will be returned as
+ * the return value of struct eap_method::process() so it is not included in
+ * this structure.
+ */
+struct eap_method_ret {
+	/**
+	 * ignore - Whether method decided to drop the current packed (OUT)
+	 */
+	Boolean ignore;
+
+	/**
+	 * methodState - Method-specific state (IN/OUT)
+	 */
+	EapMethodState methodState;
+
+	/**
+	 * decision - Authentication decision (OUT)
+	 */
+	EapDecision decision;
+
+	/**
+	 * allowNotifications - Whether method allows notifications (OUT)
+	 */
+	Boolean allowNotifications;
+};
+
+
+/**
+ * struct eap_method - EAP method interface
+ * This structure defines the EAP method interface. Each method will need to
+ * register its own EAP type, EAP name, and set of function pointers for method
+ * specific operations. This interface is based on section 4.4 of RFC 4137.
+ */
+struct eap_method {
+	/**
+	 * vendor - EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
+	 */
+	int vendor;
+
+	/**
+	 * method - EAP type number (EAP_TYPE_*)
+	 */
+	EapType method;
+
+	/**
+	 * name - Name of the method (e.g., "TLS")
+	 */
+	const char *name;
+
+	/**
+	 * init - Initialize an EAP method
+	 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+	 * Returns: Pointer to allocated private data, or %NULL on failure
+	 *
+	 * This function is used to initialize the EAP method explicitly
+	 * instead of using METHOD_INIT state as specific in RFC 4137. The
+	 * method is expected to initialize it method-specific state and return
+	 * a pointer that will be used as the priv argument to other calls.
+	 */
+	void * (*init)(struct eap_sm *sm);
+
+	/**
+	 * deinit - Deinitialize an EAP method
+	 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+	 * @priv: Pointer to private EAP method data from eap_method::init()
+	 *
+	 * Deinitialize the EAP method and free any allocated private data.
+	 */
+	void (*deinit)(struct eap_sm *sm, void *priv);
+
+	/**
+	 * process - Process an EAP request
+	 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+	 * @priv: Pointer to private EAP method data from eap_method::init()
+	 * @ret: Return values from EAP request validation and processing
+	 * @reqData: EAP request to be processed (eapReqData)
+	 * Returns: Pointer to allocated EAP response packet (eapRespData)
+	 *
+	 * This function is a combination of m.check(), m.process(), and
+	 * m.buildResp() procedures defined in section 4.4 of RFC 4137 In other
+	 * words, this function validates the incoming request, processes it,
+	 * and build a response packet. m.check() and m.process() return values
+	 * are returned through struct eap_method_ret *ret variable. Caller is
+	 * responsible for freeing the returned EAP response packet.
+	 */
+	struct wpabuf * (*process)(struct eap_sm *sm, void *priv,
+				   struct eap_method_ret *ret,
+				   const struct wpabuf *reqData);
+
+	/**
+	 * isKeyAvailable - Find out whether EAP method has keying material
+	 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+	 * @priv: Pointer to private EAP method data from eap_method::init()
+	 * Returns: %TRUE if key material (eapKeyData) is available
+	 */
+	Boolean (*isKeyAvailable)(struct eap_sm *sm, void *priv);
+
+	/**
+	 * getKey - Get EAP method specific keying material (eapKeyData)
+	 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+	 * @priv: Pointer to private EAP method data from eap_method::init()
+	 * @len: Pointer to variable to store key length (eapKeyDataLen)
+	 * Returns: Keying material (eapKeyData) or %NULL if not available
+	 *
+	 * This function can be used to get the keying material from the EAP
+	 * method. The key may already be stored in the method-specific private
+	 * data or this function may derive the key.
+	 */
+	u8 * (*getKey)(struct eap_sm *sm, void *priv, size_t *len);
+
+	/**
+	 * get_status - Get EAP method status
+	 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+	 * @priv: Pointer to private EAP method data from eap_method::init()
+	 * @buf: Buffer for status information
+	 * @buflen: Maximum buffer length
+	 * @verbose: Whether to include verbose status information
+	 * Returns: Number of bytes written to buf
+	 *
+	 * Query EAP method for status information. This function fills in a
+	 * text area with current status information from the EAP method. If
+	 * the buffer (buf) is not large enough, status information will be
+	 * truncated to fit the buffer.
+	 */
+	int (*get_status)(struct eap_sm *sm, void *priv, char *buf,
+			  size_t buflen, int verbose);
+
+	/**
+	 * has_reauth_data - Whether method is ready for fast reauthentication
+	 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+	 * @priv: Pointer to private EAP method data from eap_method::init()
+	 * Returns: %TRUE or %FALSE based on whether fast reauthentication is
+	 * possible
+	 *
+	 * This function is an optional handler that only EAP methods
+	 * supporting fast re-authentication need to implement.
+	 */
+	Boolean (*has_reauth_data)(struct eap_sm *sm, void *priv);
+
+	/**
+	 * deinit_for_reauth - Release data that is not needed for fast re-auth
+	 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+	 * @priv: Pointer to private EAP method data from eap_method::init()
+	 *
+	 * This function is an optional handler that only EAP methods
+	 * supporting fast re-authentication need to implement. This is called
+	 * when authentication has been completed and EAP state machine is
+	 * requesting that enough state information is maintained for fast
+	 * re-authentication
+	 */
+	void (*deinit_for_reauth)(struct eap_sm *sm, void *priv);
+
+	/**
+	 * init_for_reauth - Prepare for start of fast re-authentication
+	 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+	 * @priv: Pointer to private EAP method data from eap_method::init()
+	 *
+	 * This function is an optional handler that only EAP methods
+	 * supporting fast re-authentication need to implement. This is called
+	 * when EAP authentication is started and EAP state machine is
+	 * requesting fast re-authentication to be used.
+	 */
+	void * (*init_for_reauth)(struct eap_sm *sm, void *priv);
+
+	/**
+	 * get_identity - Get method specific identity for re-authentication
+	 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+	 * @priv: Pointer to private EAP method data from eap_method::init()
+	 * @len: Length of the returned identity
+	 * Returns: Pointer to the method specific identity or %NULL if default
+	 * identity is to be used
+	 *
+	 * This function is an optional handler that only EAP methods
+	 * that use method specific identity need to implement.
+	 */
+	const u8 * (*get_identity)(struct eap_sm *sm, void *priv, size_t *len);
+
+	/**
+	 * free - Free EAP method data
+	 * @method: Pointer to the method data registered with
+	 * eap_peer_method_register().
+	 *
+	 * This function will be called when the EAP method is being
+	 * unregistered. If the EAP method allocated resources during
+	 * registration (e.g., allocated struct eap_method), they should be
+	 * freed in this function. No other method functions will be called
+	 * after this call. If this function is not defined (i.e., function
+	 * pointer is %NULL), a default handler is used to release the method
+	 * data with free(method). This is suitable for most cases.
+	 */
+	void (*free)(struct eap_method *method);
+
+#define EAP_PEER_METHOD_INTERFACE_VERSION 1
+	/**
+	 * version - Version of the EAP peer method interface
+	 *
+	 * The EAP peer method implementation should set this variable to
+	 * EAP_PEER_METHOD_INTERFACE_VERSION. This is used to verify that the
+	 * EAP method is using supported API version when using dynamically
+	 * loadable EAP methods.
+	 */
+	int version;
+
+	/**
+	 * next - Pointer to the next EAP method
+	 *
+	 * This variable is used internally in the EAP method registration code
+	 * to create a linked list of registered EAP methods.
+	 */
+	struct eap_method *next;
+
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+	/**
+	 * dl_handle - Handle for the dynamic library
+	 *
+	 * This variable is used internally in the EAP method registration code
+	 * to store a handle for the dynamic library. If the method is linked
+	 * in statically, this is %NULL.
+	 */
+	void *dl_handle;
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+
+	/**
+	 * get_emsk - Get EAP method specific keying extended material (EMSK)
+	 * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+	 * @priv: Pointer to private EAP method data from eap_method::init()
+	 * @len: Pointer to a variable to store EMSK length
+	 * Returns: EMSK or %NULL if not available
+	 *
+	 * This function can be used to get the extended keying material from
+	 * the EAP method. The key may already be stored in the method-specific
+	 * private data or this function may derive the key.
+	 */
+	u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len);
+};
+
+
+/**
+ * struct eap_sm - EAP state machine data
+ */
+struct eap_sm {
+	enum {
+		EAP_INITIALIZE, EAP_DISABLED, EAP_IDLE, EAP_RECEIVED,
+		EAP_GET_METHOD, EAP_METHOD, EAP_SEND_RESPONSE, EAP_DISCARD,
+		EAP_IDENTITY, EAP_NOTIFICATION, EAP_RETRANSMIT, EAP_SUCCESS,
+		EAP_FAILURE
+	} EAP_state;
+	/* Long-term local variables */
+	EapType selectedMethod;
+	EapMethodState methodState;
+	int lastId;
+	struct wpabuf *lastRespData;
+	EapDecision decision;
+	/* Short-term local variables */
+	Boolean rxReq;
+	Boolean rxSuccess;
+	Boolean rxFailure;
+	int reqId;
+	EapType reqMethod;
+	int reqVendor;
+	u32 reqVendorMethod;
+	Boolean ignore;
+	/* Constants */
+	int ClientTimeout;
+
+	/* Miscellaneous variables */
+	Boolean allowNotifications; /* peer state machine <-> methods */
+	struct wpabuf *eapRespData; /* peer to lower layer */
+	Boolean eapKeyAvailable; /* peer to lower layer */
+	u8 *eapKeyData; /* peer to lower layer */
+	size_t eapKeyDataLen; /* peer to lower layer */
+	const struct eap_method *m; /* selected EAP method */
+	/* not defined in RFC 4137 */
+	Boolean changed;
+	void *eapol_ctx;
+	struct eapol_callbacks *eapol_cb;
+	void *eap_method_priv;
+	int init_phase2;
+	int fast_reauth;
+
+	Boolean rxResp /* LEAP only */;
+	Boolean leap_done;
+	Boolean peap_done;
+	u8 req_md5[16]; /* MD5() of the current EAP packet */
+	u8 last_md5[16]; /* MD5() of the previously received EAP packet; used
+			  * in duplicate request detection. */
+
+	void *msg_ctx;
+	void *scard_ctx;
+	void *ssl_ctx;
+	void *ssl_ctx2;
+
+	unsigned int workaround;
+
+	/* Optional challenges generated in Phase 1 (EAP-FAST) */
+	u8 *peer_challenge, *auth_challenge;
+
+	int num_rounds;
+	int force_disabled;
+
+	struct wps_context *wps;
+
+	int prev_failure;
+
+	struct ext_password_data *ext_pw;
+	struct wpabuf *ext_pw_buf;
+};
+
+const u8 * eap_get_config_identity(struct eap_sm *sm, size_t *len);
+const u8 * eap_get_config_password(struct eap_sm *sm, size_t *len);
+const u8 * eap_get_config_password2(struct eap_sm *sm, size_t *len, int *hash);
+const u8 * eap_get_config_new_password(struct eap_sm *sm, size_t *len);
+const u8 * eap_get_config_otp(struct eap_sm *sm, size_t *len);
+void eap_clear_config_otp(struct eap_sm *sm);
+const char * eap_get_config_phase1(struct eap_sm *sm);
+const char * eap_get_config_phase2(struct eap_sm *sm);
+int eap_get_config_fragment_size(struct eap_sm *sm);
+struct eap_peer_config * eap_get_config(struct eap_sm *sm);
+void eap_set_config_blob(struct eap_sm *sm, struct wpa_config_blob *blob);
+const struct wpa_config_blob *
+eap_get_config_blob(struct eap_sm *sm, const char *name);
+void eap_notify_pending(struct eap_sm *sm);
+int eap_allowed_method(struct eap_sm *sm, int vendor, u32 method);
+
+#endif /* EAP_I_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_md5.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,120 @@
+/*
+ * EAP peer method: EAP-MD5 (RFC 3748 and RFC 1994)
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_i.h"
+#include "eap_common/chap.h"
+
+
+static void * eap_md5_init(struct eap_sm *sm)
+{
+	/* No need for private data. However, must return non-NULL to indicate
+	 * success. */
+	return (void *) 1;
+}
+
+
+static void eap_md5_deinit(struct eap_sm *sm, void *priv)
+{
+}
+
+
+static struct wpabuf * eap_md5_process(struct eap_sm *sm, void *priv,
+				       struct eap_method_ret *ret,
+				       const struct wpabuf *reqData)
+{
+	struct wpabuf *resp;
+	const u8 *pos, *challenge, *password;
+	u8 *rpos, id;
+	size_t len, challenge_len, password_len;
+
+	password = eap_get_config_password(sm, &password_len);
+	if (password == NULL) {
+		wpa_printf(MSG_INFO, "EAP-MD5: Password not configured");
+		eap_sm_request_password(sm);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5, reqData, &len);
+	if (pos == NULL || len == 0) {
+		wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame (pos=%p len=%lu)",
+			   pos, (unsigned long) len);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	/*
+	 * CHAP Challenge:
+	 * Value-Size (1 octet) | Value(Challenge) | Name(optional)
+	 */
+	challenge_len = *pos++;
+	if (challenge_len == 0 || challenge_len > len - 1) {
+		wpa_printf(MSG_INFO, "EAP-MD5: Invalid challenge "
+			   "(challenge_len=%lu len=%lu)",
+			   (unsigned long) challenge_len, (unsigned long) len);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	ret->ignore = FALSE;
+	challenge = pos;
+	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge",
+		    challenge, challenge_len);
+
+	wpa_printf(MSG_DEBUG, "EAP-MD5: Generating Challenge Response");
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_COND_SUCC;
+	ret->allowNotifications = TRUE;
+
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, 1 + CHAP_MD5_LEN,
+			     EAP_CODE_RESPONSE, eap_get_id(reqData));
+	if (resp == NULL)
+		return NULL;
+
+	/*
+	 * CHAP Response:
+	 * Value-Size (1 octet) | Value(Response) | Name(optional)
+	 */
+	wpabuf_put_u8(resp, CHAP_MD5_LEN);
+
+	id = eap_get_id(resp);
+	rpos = wpabuf_put(resp, CHAP_MD5_LEN);
+	if (chap_md5(id, password, password_len, challenge, challenge_len,
+		     rpos)) {
+		wpa_printf(MSG_INFO, "EAP-MD5: CHAP MD5 operation failed");
+		ret->ignore = TRUE;
+		wpabuf_free(resp);
+		return NULL;
+	}
+	wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", rpos, CHAP_MD5_LEN);
+
+	return resp;
+}
+
+
+int eap_peer_md5_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+				    EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_md5_init;
+	eap->deinit = eap_md5_deinit;
+	eap->process = eap_md5_process;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_methods.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,369 @@
+/*
+ * EAP peer: Method registration
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+#include <dlfcn.h>
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+
+#include "common.h"
+#include "eap_i.h"
+#include "eap_methods.h"
+
+
+static struct eap_method *eap_methods = NULL;
+
+
+/**
+ * eap_peer_get_eap_method - Get EAP method based on type number
+ * @vendor: EAP Vendor-Id (0 = IETF)
+ * @method: EAP type number
+ * Returns: Pointer to EAP method or %NULL if not found
+ */
+const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method)
+{
+	struct eap_method *m;
+	for (m = eap_methods; m; m = m->next) {
+		if (m->vendor == vendor && m->method == method)
+			return m;
+	}
+	return NULL;
+}
+
+
+/**
+ * eap_peer_get_type - Get EAP type for the given EAP method name
+ * @name: EAP method name, e.g., TLS
+ * @vendor: Buffer for returning EAP Vendor-Id
+ * Returns: EAP method type or %EAP_TYPE_NONE if not found
+ *
+ * This function maps EAP type names into EAP type numbers based on the list of
+ * EAP methods included in the build.
+ */
+EapType eap_peer_get_type(const char *name, int *vendor)
+{
+	struct eap_method *m;
+	for (m = eap_methods; m; m = m->next) {
+		if (os_strcmp(m->name, name) == 0) {
+			*vendor = m->vendor;
+			return m->method;
+		}
+	}
+	*vendor = EAP_VENDOR_IETF;
+	return EAP_TYPE_NONE;
+}
+
+
+/**
+ * eap_get_name - Get EAP method name for the given EAP type
+ * @vendor: EAP Vendor-Id (0 = IETF)
+ * @type: EAP method type
+ * Returns: EAP method name, e.g., TLS, or %NULL if not found
+ *
+ * This function maps EAP type numbers into EAP type names based on the list of
+ * EAP methods included in the build.
+ */
+const char * eap_get_name(int vendor, EapType type)
+{
+	struct eap_method *m;
+	if (vendor == EAP_VENDOR_IETF && type == EAP_TYPE_EXPANDED)
+		return "expanded";
+	for (m = eap_methods; m; m = m->next) {
+		if (m->vendor == vendor && m->method == type)
+			return m->name;
+	}
+	return NULL;
+}
+
+
+/**
+ * eap_get_names - Get space separated list of names for supported EAP methods
+ * @buf: Buffer for names
+ * @buflen: Buffer length
+ * Returns: Number of characters written into buf (not including nul
+ * termination)
+ */
+size_t eap_get_names(char *buf, size_t buflen)
+{
+	char *pos, *end;
+	struct eap_method *m;
+	int ret;
+
+	if (buflen == 0)
+		return 0;
+
+	pos = buf;
+	end = pos + buflen;
+
+	for (m = eap_methods; m; m = m->next) {
+		ret = os_snprintf(pos, end - pos, "%s%s",
+				  m == eap_methods ? "" : " ", m->name);
+		if (ret < 0 || ret >= end - pos)
+			break;
+		pos += ret;
+	}
+	buf[buflen - 1] = '\0';
+
+	return pos - buf;
+}
+
+
+/**
+ * eap_get_names_as_string_array - Get supported EAP methods as string array
+ * @num: Buffer for returning the number of items in array, not including %NULL
+ * terminator. This parameter can be %NULL if the length is not needed.
+ * Returns: A %NULL-terminated array of strings, or %NULL on error.
+ *
+ * This function returns the list of names for all supported EAP methods as an
+ * array of strings. The caller must free the returned array items and the
+ * array.
+ */
+char ** eap_get_names_as_string_array(size_t *num)
+{
+	struct eap_method *m;
+	size_t array_len = 0;
+	char **array;
+	int i = 0, j;
+
+	for (m = eap_methods; m; m = m->next)
+		array_len++;
+
+	array = os_zalloc(sizeof(char *) * (array_len + 1));
+	if (array == NULL)
+		return NULL;
+
+	for (m = eap_methods; m; m = m->next) {
+		array[i++] = os_strdup(m->name);
+		if (array[i - 1] == NULL) {
+			for (j = 0; j < i; j++)
+				os_free(array[j]);
+			os_free(array);
+			return NULL;
+		}
+	}
+	array[i] = NULL;
+
+	if (num)
+		*num = array_len;
+
+	return array;
+}
+
+
+/**
+ * eap_peer_get_methods - Get a list of enabled EAP peer methods
+ * @count: Set to number of available methods
+ * Returns: List of enabled EAP peer methods
+ */
+const struct eap_method * eap_peer_get_methods(size_t *count)
+{
+	int c = 0;
+	struct eap_method *m;
+
+	for (m = eap_methods; m; m = m->next)
+		c++;
+	
+	*count = c;
+	return eap_methods;
+}
+
+
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+/**
+ * eap_peer_method_load - Load a dynamic EAP method library (shared object)
+ * @so: File path for the shared object file to load
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_peer_method_load(const char *so)
+{
+	void *handle;
+	int (*dyn_init)(void);
+	int ret;
+
+	handle = dlopen(so, RTLD_LAZY);
+	if (handle == NULL) {
+		wpa_printf(MSG_ERROR, "EAP: Failed to open dynamic EAP method "
+			   "'%s': %s", so, dlerror());
+		return -1;
+	}
+
+	dyn_init = dlsym(handle, "eap_peer_method_dynamic_init");
+	if (dyn_init == NULL) {
+		dlclose(handle);
+		wpa_printf(MSG_ERROR, "EAP: Invalid EAP method '%s' - no "
+			   "eap_peer_method_dynamic_init()", so);
+		return -1;
+	}
+
+	ret = dyn_init();
+	if (ret) {
+		dlclose(handle);
+		wpa_printf(MSG_ERROR, "EAP: Failed to add EAP method '%s' - "
+			   "ret %d", so, ret);
+		return ret;
+	}
+
+	/* Store the handle for this shared object. It will be freed with
+	 * dlclose() when the EAP method is unregistered. */
+	eap_methods->dl_handle = handle;
+
+	wpa_printf(MSG_DEBUG, "EAP: Loaded dynamic EAP method: '%s'", so);
+
+	return 0;
+}
+
+
+/**
+ * eap_peer_method_unload - Unload a dynamic EAP method library (shared object)
+ * @method: Pointer to the dynamically loaded EAP method
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to unload EAP methods that have been previously
+ * loaded with eap_peer_method_load(). Before unloading the method, all
+ * references to the method must be removed to make sure that no dereferences
+ * of freed memory will occur after unloading.
+ */
+int eap_peer_method_unload(struct eap_method *method)
+{
+	struct eap_method *m, *prev;
+	void *handle;
+
+	m = eap_methods;
+	prev = NULL;
+	while (m) {
+		if (m == method)
+			break;
+		prev = m;
+		m = m->next;
+	}
+
+	if (m == NULL || m->dl_handle == NULL)
+		return -1;
+
+	if (prev)
+		prev->next = m->next;
+	else
+		eap_methods = m->next;
+
+	handle = m->dl_handle;
+
+	if (m->free)
+		m->free(m);
+	else
+		eap_peer_method_free(m);
+
+	dlclose(handle);
+
+	return 0;
+}
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+
+
+/**
+ * eap_peer_method_alloc - Allocate EAP peer method structure
+ * @version: Version of the EAP peer method interface (set to
+ * EAP_PEER_METHOD_INTERFACE_VERSION)
+ * @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
+ * @method: EAP type number (EAP_TYPE_*)
+ * @name: Name of the method (e.g., "TLS")
+ * Returns: Allocated EAP method structure or %NULL on failure
+ *
+ * The returned structure should be freed with eap_peer_method_free() when it
+ * is not needed anymore.
+ */
+struct eap_method * eap_peer_method_alloc(int version, int vendor,
+					  EapType method, const char *name)
+{
+	struct eap_method *eap;
+	eap = os_zalloc(sizeof(*eap));
+	if (eap == NULL)
+		return NULL;
+	eap->version = version;
+	eap->vendor = vendor;
+	eap->method = method;
+	eap->name = name;
+	return eap;
+}
+
+
+/**
+ * eap_peer_method_free - Free EAP peer method structure
+ * @method: Method structure allocated with eap_peer_method_alloc()
+ */
+void eap_peer_method_free(struct eap_method *method)
+{
+	os_free(method);
+}
+
+
+/**
+ * eap_peer_method_register - Register an EAP peer method
+ * @method: EAP method to register
+ * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method
+ * has already been registered
+ *
+ * Each EAP peer method needs to call this function to register itself as a
+ * supported EAP method.
+ */
+int eap_peer_method_register(struct eap_method *method)
+{
+	struct eap_method *m, *last = NULL;
+
+	if (method == NULL || method->name == NULL ||
+	    method->version != EAP_PEER_METHOD_INTERFACE_VERSION)
+		return -1;
+
+	for (m = eap_methods; m; m = m->next) {
+		if ((m->vendor == method->vendor &&
+		     m->method == method->method) ||
+		    os_strcmp(m->name, method->name) == 0)
+			return -2;
+		last = m;
+	}
+
+	if (last)
+		last->next = method;
+	else
+		eap_methods = method;
+
+	return 0;
+}
+
+
+/**
+ * eap_peer_unregister_methods - Unregister EAP peer methods
+ *
+ * This function is called at program termination to unregister all EAP peer
+ * methods.
+ */
+void eap_peer_unregister_methods(void)
+{
+	struct eap_method *m;
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+	void *handle;
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+
+	while (eap_methods) {
+		m = eap_methods;
+		eap_methods = eap_methods->next;
+
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+		handle = m->dl_handle;
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+
+		if (m->free)
+			m->free(m);
+		else
+			eap_peer_method_free(m);
+
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+		if (handle)
+			dlclose(handle);
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_methods.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,109 @@
+/*
+ * EAP peer: Method registration
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_METHODS_H
+#define EAP_METHODS_H
+
+#include "eap_common/eap_defs.h"
+
+const struct eap_method * eap_peer_get_eap_method(int vendor, EapType method);
+const struct eap_method * eap_peer_get_methods(size_t *count);
+
+struct eap_method * eap_peer_method_alloc(int version, int vendor,
+					  EapType method, const char *name);
+void eap_peer_method_free(struct eap_method *method);
+int eap_peer_method_register(struct eap_method *method);
+
+
+#ifdef IEEE8021X_EAPOL
+
+EapType eap_peer_get_type(const char *name, int *vendor);
+const char * eap_get_name(int vendor, EapType type);
+size_t eap_get_names(char *buf, size_t buflen);
+char ** eap_get_names_as_string_array(size_t *num);
+void eap_peer_unregister_methods(void);
+
+#else /* IEEE8021X_EAPOL */
+
+static inline EapType eap_peer_get_type(const char *name, int *vendor)
+{
+	*vendor = EAP_VENDOR_IETF;
+	return EAP_TYPE_NONE;
+}
+
+static inline const char * eap_get_name(int vendor, EapType type)
+{
+	return NULL;
+}
+
+static inline size_t eap_get_names(char *buf, size_t buflen)
+{
+	return 0;
+}
+
+static inline int eap_peer_register_methods(void)
+{
+	return 0;
+}
+
+static inline void eap_peer_unregister_methods(void)
+{
+}
+
+static inline char ** eap_get_names_as_string_array(size_t *num)
+{
+	return NULL;
+}
+
+#endif /* IEEE8021X_EAPOL */
+
+
+#ifdef CONFIG_DYNAMIC_EAP_METHODS
+
+int eap_peer_method_load(const char *so);
+int eap_peer_method_unload(struct eap_method *method);
+
+#else /* CONFIG_DYNAMIC_EAP_METHODS */
+
+static inline int eap_peer_method_load(const char *so)
+{
+	return 0;
+}
+
+static inline int eap_peer_method_unload(struct eap_method *method)
+{
+	return 0;
+}
+
+#endif /* CONFIG_DYNAMIC_EAP_METHODS */
+
+/* EAP peer method registration calls for statically linked in methods */
+int eap_peer_md5_register(void);
+int eap_peer_tls_register(void);
+int eap_peer_unauth_tls_register(void);
+int eap_peer_mschapv2_register(void);
+int eap_peer_peap_register(void);
+int eap_peer_ttls_register(void);
+int eap_peer_gtc_register(void);
+int eap_peer_otp_register(void);
+int eap_peer_sim_register(void);
+int eap_peer_leap_register(void);
+int eap_peer_psk_register(void);
+int eap_peer_aka_register(void);
+int eap_peer_aka_prime_register(void);
+int eap_peer_fast_register(void);
+int eap_peer_pax_register(void);
+int eap_peer_sake_register(void);
+int eap_peer_gpsk_register(void);
+int eap_peer_wsc_register(void);
+int eap_peer_ikev2_register(void);
+int eap_peer_vendor_test_register(void);
+int eap_peer_tnc_register(void);
+int eap_peer_pwd_register(void);
+
+#endif /* EAP_METHODS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_mschapv2.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,879 @@
+/*
+ * EAP peer method: EAP-MSCHAPV2 (draft-kamath-pppext-eap-mschapv2-00.txt)
+ * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file implements EAP peer part of EAP-MSCHAPV2 method (EAP type 26).
+ * draft-kamath-pppext-eap-mschapv2-00.txt defines the Microsoft EAP CHAP
+ * Extensions Protocol, Version 2, for mutual authentication and key
+ * derivation. This encapsulates MS-CHAP-v2 protocol which is defined in
+ * RFC 2759. Use of EAP-MSCHAPV2 derived keys with MPPE cipher is described in
+ * RFC 3079.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/ms_funcs.h"
+#include "crypto/random.h"
+#include "common/wpa_ctrl.h"
+#include "mschapv2.h"
+#include "eap_i.h"
+#include "eap_config.h"
+
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct eap_mschapv2_hdr {
+	u8 op_code; /* MSCHAPV2_OP_* */
+	u8 mschapv2_id; /* usually same as EAP identifier; must be changed
+			 * for challenges, but not for success/failure */
+	u8 ms_length[2]; /* Note: misaligned; length - 5 */
+	/* followed by data */
+} STRUCT_PACKED;
+
+/* Response Data field */
+struct ms_response {
+	u8 peer_challenge[MSCHAPV2_CHAL_LEN];
+	u8 reserved[8];
+	u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];
+	u8 flags;
+} STRUCT_PACKED;
+
+/* Change-Password Data field */
+struct ms_change_password {
+	u8 encr_password[516];
+	u8 encr_hash[16];
+	u8 peer_challenge[MSCHAPV2_CHAL_LEN];
+	u8 reserved[8];
+	u8 nt_response[MSCHAPV2_NT_RESPONSE_LEN];
+	u8 flags[2];
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#define MSCHAPV2_OP_CHALLENGE 1
+#define MSCHAPV2_OP_RESPONSE 2
+#define MSCHAPV2_OP_SUCCESS 3
+#define MSCHAPV2_OP_FAILURE 4
+#define MSCHAPV2_OP_CHANGE_PASSWORD 7
+
+#define ERROR_RESTRICTED_LOGON_HOURS 646
+#define ERROR_ACCT_DISABLED 647
+#define ERROR_PASSWD_EXPIRED 648
+#define ERROR_NO_DIALIN_PERMISSION 649
+#define ERROR_AUTHENTICATION_FAILURE 691
+#define ERROR_CHANGING_PASSWORD 709
+
+#define PASSWD_CHANGE_CHAL_LEN 16
+#define MSCHAPV2_KEY_LEN 16
+
+
+struct eap_mschapv2_data {
+	u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN];
+	int auth_response_valid;
+
+	int prev_error;
+	u8 passwd_change_challenge[PASSWD_CHANGE_CHAL_LEN];
+	int passwd_change_challenge_valid;
+	int passwd_change_version;
+
+	/* Optional challenge values generated in EAP-FAST Phase 1 negotiation
+	 */
+	u8 *peer_challenge;
+	u8 *auth_challenge;
+
+	int phase2;
+	u8 master_key[MSCHAPV2_MASTER_KEY_LEN];
+	int master_key_valid;
+	int success;
+
+	struct wpabuf *prev_challenge;
+};
+
+
+static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv);
+
+
+static void * eap_mschapv2_init(struct eap_sm *sm)
+{
+	struct eap_mschapv2_data *data;
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	if (sm->peer_challenge) {
+		data->peer_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
+		if (data->peer_challenge == NULL) {
+			eap_mschapv2_deinit(sm, data);
+			return NULL;
+		}
+		os_memcpy(data->peer_challenge, sm->peer_challenge,
+			  MSCHAPV2_CHAL_LEN);
+	}
+
+	if (sm->auth_challenge) {
+		data->auth_challenge = os_malloc(MSCHAPV2_CHAL_LEN);
+		if (data->auth_challenge == NULL) {
+			eap_mschapv2_deinit(sm, data);
+			return NULL;
+		}
+		os_memcpy(data->auth_challenge, sm->auth_challenge,
+			  MSCHAPV2_CHAL_LEN);
+	}
+
+	data->phase2 = sm->init_phase2;
+
+	return data;
+}
+
+
+static void eap_mschapv2_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_mschapv2_data *data = priv;
+	os_free(data->peer_challenge);
+	os_free(data->auth_challenge);
+	wpabuf_free(data->prev_challenge);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_mschapv2_challenge_reply(
+	struct eap_sm *sm, struct eap_mschapv2_data *data, u8 id,
+	u8 mschapv2_id, const u8 *auth_challenge)
+{
+	struct wpabuf *resp;
+	struct eap_mschapv2_hdr *ms;
+	u8 *peer_challenge;
+	int ms_len;
+	struct ms_response *r;
+	size_t identity_len, password_len;
+	const u8 *identity, *password;
+	int pwhash;
+
+	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Generating Challenge Response");
+
+	identity = eap_get_config_identity(sm, &identity_len);
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
+	if (identity == NULL || password == NULL)
+		return NULL;
+
+	ms_len = sizeof(*ms) + 1 + sizeof(*r) + identity_len;
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	ms = wpabuf_put(resp, sizeof(*ms));
+	ms->op_code = MSCHAPV2_OP_RESPONSE;
+	ms->mschapv2_id = mschapv2_id;
+	if (data->prev_error) {
+		/*
+		 * TODO: this does not seem to be enough when processing two
+		 * or more failure messages. IAS did not increment mschapv2_id
+		 * in its own packets, but it seemed to expect the peer to
+		 * increment this for all packets(?).
+		 */
+		ms->mschapv2_id++;
+	}
+	WPA_PUT_BE16(ms->ms_length, ms_len);
+
+	wpabuf_put_u8(resp, sizeof(*r)); /* Value-Size */
+
+	/* Response */
+	r = wpabuf_put(resp, sizeof(*r));
+	peer_challenge = r->peer_challenge;
+	if (data->peer_challenge) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge generated "
+			   "in Phase 1");
+		peer_challenge = data->peer_challenge;
+		os_memset(r->peer_challenge, 0, MSCHAPV2_CHAL_LEN);
+	} else if (random_get_bytes(peer_challenge, MSCHAPV2_CHAL_LEN)) {
+		wpabuf_free(resp);
+		return NULL;
+	}
+	os_memset(r->reserved, 0, 8);
+	if (data->auth_challenge) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge generated "
+			   "in Phase 1");
+		auth_challenge = data->auth_challenge;
+	}
+	if (mschapv2_derive_response(identity, identity_len, password,
+				     password_len, pwhash, auth_challenge,
+				     peer_challenge, r->nt_response,
+				     data->auth_response, data->master_key)) {
+		wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to derive "
+			   "response");
+		wpabuf_free(resp);
+		return NULL;
+	}
+	data->auth_response_valid = 1;
+	data->master_key_valid = 1;
+
+	r->flags = 0; /* reserved, must be zero */
+
+	wpabuf_put_data(resp, identity, identity_len);
+	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
+		   "(response)", id, ms->mschapv2_id);
+	return resp;
+}
+
+
+/**
+ * eap_mschapv2_process - Process an EAP-MSCHAPv2 challenge message
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Pointer to private EAP method data from eap_mschapv2_init()
+ * @ret: Return values from EAP request validation and processing
+ * @req: Pointer to EAP-MSCHAPv2 header from the request
+ * @req_len: Length of the EAP-MSCHAPv2 data
+ * @id: EAP identifier used in the request
+ * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
+ * no reply available
+ */
+static struct wpabuf * eap_mschapv2_challenge(
+	struct eap_sm *sm, struct eap_mschapv2_data *data,
+	struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req,
+	size_t req_len, u8 id)
+{
+	size_t len, challenge_len;
+	const u8 *pos, *challenge;
+
+	if (eap_get_config_identity(sm, &len) == NULL ||
+	    eap_get_config_password(sm, &len) == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received challenge");
+	if (req_len < sizeof(*req) + 1) {
+		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge data "
+			   "(len %lu)", (unsigned long) req_len);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	pos = (const u8 *) (req + 1);
+	challenge_len = *pos++;
+	len = req_len - sizeof(*req) - 1;
+	if (challenge_len != MSCHAPV2_CHAL_LEN) {
+		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid challenge length "
+			   "%lu", (unsigned long) challenge_len);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (len < challenge_len) {
+		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Too short challenge"
+			   " packet: len=%lu challenge_len=%lu",
+			   (unsigned long) len, (unsigned long) challenge_len);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (data->passwd_change_challenge_valid) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Using challenge from the "
+			   "failure message");
+		challenge = data->passwd_change_challenge;
+	} else
+		challenge = pos;
+	pos += challenge_len;
+	len -= challenge_len;
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Authentication Servername",
+		    pos, len);
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+	ret->allowNotifications = TRUE;
+
+	return eap_mschapv2_challenge_reply(sm, data, id, req->mschapv2_id,
+					    challenge);
+}
+
+
+static void eap_mschapv2_password_changed(struct eap_sm *sm,
+					  struct eap_mschapv2_data *data)
+{
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config && config->new_password) {
+		wpa_msg(sm->msg_ctx, MSG_INFO,
+			WPA_EVENT_PASSWORD_CHANGED
+			"EAP-MSCHAPV2: Password changed successfully");
+		data->prev_error = 0;
+		os_free(config->password);
+		if (config->flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+			/* TODO: update external storage */
+		} else if (config->flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH) {
+			config->password = os_malloc(16);
+			config->password_len = 16;
+			if (config->password) {
+				nt_password_hash(config->new_password,
+						 config->new_password_len,
+						 config->password);
+			}
+			os_free(config->new_password);
+		} else {
+			config->password = config->new_password;
+			config->password_len = config->new_password_len;
+		}
+		config->new_password = NULL;
+		config->new_password_len = 0;
+	}
+}
+
+
+/**
+ * eap_mschapv2_process - Process an EAP-MSCHAPv2 success message
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Pointer to private EAP method data from eap_mschapv2_init()
+ * @ret: Return values from EAP request validation and processing
+ * @req: Pointer to EAP-MSCHAPv2 header from the request
+ * @req_len: Length of the EAP-MSCHAPv2 data
+ * @id: EAP identifier used in th erequest
+ * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
+ * no reply available
+ */
+static struct wpabuf * eap_mschapv2_success(struct eap_sm *sm,
+					    struct eap_mschapv2_data *data,
+					    struct eap_method_ret *ret,
+					    const struct eap_mschapv2_hdr *req,
+					    size_t req_len, u8 id)
+{
+	struct wpabuf *resp;
+	const u8 *pos;
+	size_t len;
+
+	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received success");
+	len = req_len - sizeof(*req);
+	pos = (const u8 *) (req + 1);
+	if (!data->auth_response_valid ||
+	    mschapv2_verify_auth_response(data->auth_response, pos, len)) {
+		wpa_printf(MSG_WARNING, "EAP-MSCHAPV2: Invalid authenticator "
+			   "response in success request");
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_FAIL;
+		return NULL;
+	}
+	pos += 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN;
+	len -= 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN;
+	while (len > 0 && *pos == ' ') {
+		pos++;
+		len--;
+	}
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Success message",
+			  pos, len);
+	wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Authentication succeeded");
+
+	/* Note: Only op_code of the EAP-MSCHAPV2 header is included in success
+	 * message. */
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Failed to allocate "
+			   "buffer for success response");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	wpabuf_put_u8(resp, MSCHAPV2_OP_SUCCESS); /* op_code */
+
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_UNCOND_SUCC;
+	ret->allowNotifications = FALSE;
+	data->success = 1;
+
+	if (data->prev_error == ERROR_PASSWD_EXPIRED)
+		eap_mschapv2_password_changed(sm, data);
+
+	return resp;
+}
+
+
+static int eap_mschapv2_failure_txt(struct eap_sm *sm,
+				    struct eap_mschapv2_data *data, char *txt)
+{
+	char *pos, *msg = "";
+	int retry = 1;
+	struct eap_peer_config *config = eap_get_config(sm);
+
+	/* For example:
+	 * E=691 R=1 C=<32 octets hex challenge> V=3 M=Authentication Failure
+	 */
+
+	pos = txt;
+
+	if (pos && os_strncmp(pos, "E=", 2) == 0) {
+		pos += 2;
+		data->prev_error = atoi(pos);
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: error %d",
+			   data->prev_error);
+		pos = os_strchr(pos, ' ');
+		if (pos)
+			pos++;
+	}
+
+	if (pos && os_strncmp(pos, "R=", 2) == 0) {
+		pos += 2;
+		retry = atoi(pos);
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: retry is %sallowed",
+			   retry == 1 ? "" : "not ");
+		pos = os_strchr(pos, ' ');
+		if (pos)
+			pos++;
+	}
+
+	if (pos && os_strncmp(pos, "C=", 2) == 0) {
+		int hex_len;
+		pos += 2;
+		hex_len = os_strchr(pos, ' ') - (char *) pos;
+		if (hex_len == PASSWD_CHANGE_CHAL_LEN * 2) {
+			if (hexstr2bin(pos, data->passwd_change_challenge,
+				       PASSWD_CHANGE_CHAL_LEN)) {
+				wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid "
+					   "failure challenge");
+			} else {
+				wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: failure "
+					    "challenge",
+					    data->passwd_change_challenge,
+					    PASSWD_CHANGE_CHAL_LEN);
+				data->passwd_change_challenge_valid = 1;
+			}
+		} else {
+			wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: invalid failure "
+				   "challenge len %d", hex_len);
+		}
+		pos = os_strchr(pos, ' ');
+		if (pos)
+			pos++;
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: required challenge field "
+			   "was not present in failure message");
+	}
+
+	if (pos && os_strncmp(pos, "V=", 2) == 0) {
+		pos += 2;
+		data->passwd_change_version = atoi(pos);
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: password changing "
+			   "protocol version %d", data->passwd_change_version);
+		pos = os_strchr(pos, ' ');
+		if (pos)
+			pos++;
+	}
+
+	if (pos && os_strncmp(pos, "M=", 2) == 0) {
+		pos += 2;
+		msg = pos;
+	}
+	wpa_msg(sm->msg_ctx, MSG_WARNING,
+		"EAP-MSCHAPV2: failure message: '%s' (retry %sallowed, error "
+		"%d)",
+		msg, retry == 1 ? "" : "not ", data->prev_error);
+	if (data->prev_error == ERROR_PASSWD_EXPIRED &&
+	    data->passwd_change_version == 3 && config) {
+		if (config->new_password == NULL) {
+			wpa_msg(sm->msg_ctx, MSG_INFO,
+				"EAP-MSCHAPV2: Password expired - password "
+				"change required");
+			eap_sm_request_new_password(sm);
+		}
+	} else if (retry == 1 && config) {
+		/* TODO: could prevent the current password from being used
+		 * again at least for some period of time */
+		if (!config->mschapv2_retry)
+			eap_sm_request_identity(sm);
+		eap_sm_request_password(sm);
+		config->mschapv2_retry = 1;
+	} else if (config) {
+		/* TODO: prevent retries using same username/password */
+		config->mschapv2_retry = 0;
+	}
+
+	return retry == 1;
+}
+
+
+static struct wpabuf * eap_mschapv2_change_password(
+	struct eap_sm *sm, struct eap_mschapv2_data *data,
+	struct eap_method_ret *ret, const struct eap_mschapv2_hdr *req, u8 id)
+{
+	struct wpabuf *resp;
+	int ms_len;
+	const u8 *username, *password, *new_password;
+	size_t username_len, password_len, new_password_len;
+	struct eap_mschapv2_hdr *ms;
+	struct ms_change_password *cp;
+	u8 password_hash[16], password_hash_hash[16];
+	int pwhash;
+
+	username = eap_get_config_identity(sm, &username_len);
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
+	new_password = eap_get_config_new_password(sm, &new_password_len);
+	if (username == NULL || password == NULL || new_password == NULL)
+		return NULL;
+
+	username = mschapv2_remove_domain(username, &username_len);
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_COND_SUCC;
+	ret->allowNotifications = TRUE;
+
+	ms_len = sizeof(*ms) + sizeof(*cp);
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, ms_len,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	ms = wpabuf_put(resp, sizeof(*ms));
+	ms->op_code = MSCHAPV2_OP_CHANGE_PASSWORD;
+	ms->mschapv2_id = req->mschapv2_id + 1;
+	WPA_PUT_BE16(ms->ms_length, ms_len);
+	cp = wpabuf_put(resp, sizeof(*cp));
+
+	/* Encrypted-Password */
+	if (pwhash) {
+		if (encrypt_pw_block_with_password_hash(
+			    new_password, new_password_len,
+			    password, cp->encr_password))
+			goto fail;
+	} else {
+		if (new_password_encrypted_with_old_nt_password_hash(
+			    new_password, new_password_len,
+			    password, password_len, cp->encr_password))
+			goto fail;
+	}
+
+	/* Encrypted-Hash */
+	if (pwhash) {
+		u8 new_password_hash[16];
+		nt_password_hash(new_password, new_password_len,
+				 new_password_hash);
+		nt_password_hash_encrypted_with_block(password,
+						      new_password_hash,
+						      cp->encr_hash);
+	} else {
+		old_nt_password_hash_encrypted_with_new_nt_password_hash(
+			new_password, new_password_len,
+			password, password_len, cp->encr_hash);
+	}
+
+	/* Peer-Challenge */
+	if (random_get_bytes(cp->peer_challenge, MSCHAPV2_CHAL_LEN))
+		goto fail;
+
+	/* Reserved, must be zero */
+	os_memset(cp->reserved, 0, 8);
+
+	/* NT-Response */
+	wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: auth_challenge",
+		    data->passwd_change_challenge, PASSWD_CHANGE_CHAL_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: peer_challenge",
+		    cp->peer_challenge, MSCHAPV2_CHAL_LEN);
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: username",
+			  username, username_len);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-MSCHAPV2: new password",
+			      new_password, new_password_len);
+	generate_nt_response(data->passwd_change_challenge, cp->peer_challenge,
+			     username, username_len,
+			     new_password, new_password_len,
+			     cp->nt_response);
+	wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: NT-Response",
+		    cp->nt_response, MSCHAPV2_NT_RESPONSE_LEN);
+
+	/* Authenticator response is not really needed yet, but calculate it
+	 * here so that challenges need not be saved. */
+	generate_authenticator_response(new_password, new_password_len,
+					cp->peer_challenge,
+					data->passwd_change_challenge,
+					username, username_len,
+					cp->nt_response, data->auth_response);
+	data->auth_response_valid = 1;
+
+	/* Likewise, generate master_key here since we have the needed data
+	 * available. */
+	nt_password_hash(new_password, new_password_len, password_hash);
+	hash_nt_password_hash(password_hash, password_hash_hash);
+	get_master_key(password_hash_hash, cp->nt_response, data->master_key);
+	data->master_key_valid = 1;
+
+	/* Flags */
+	os_memset(cp->flags, 0, 2);
+
+	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: TX identifier %d mschapv2_id %d "
+		   "(change pw)", id, ms->mschapv2_id);
+
+	return resp;
+
+fail:
+	wpabuf_free(resp);
+	return NULL;
+}
+
+
+/**
+ * eap_mschapv2_process - Process an EAP-MSCHAPv2 failure message
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Pointer to private EAP method data from eap_mschapv2_init()
+ * @ret: Return values from EAP request validation and processing
+ * @req: Pointer to EAP-MSCHAPv2 header from the request
+ * @req_len: Length of the EAP-MSCHAPv2 data
+ * @id: EAP identifier used in th erequest
+ * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
+ * no reply available
+ */
+static struct wpabuf * eap_mschapv2_failure(struct eap_sm *sm,
+					    struct eap_mschapv2_data *data,
+					    struct eap_method_ret *ret,
+					    const struct eap_mschapv2_hdr *req,
+					    size_t req_len, u8 id)
+{
+	struct wpabuf *resp;
+	const u8 *msdata = (const u8 *) (req + 1);
+	char *buf;
+	size_t len = req_len - sizeof(*req);
+	int retry = 0;
+
+	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received failure");
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-MSCHAPV2: Failure data",
+			  msdata, len);
+	/*
+	 * eap_mschapv2_failure_txt() expects a nul terminated string, so we
+	 * must allocate a large enough temporary buffer to create that since
+	 * the received message does not include nul termination.
+	 */
+	buf = os_malloc(len + 1);
+	if (buf) {
+		os_memcpy(buf, msdata, len);
+		buf[len] = '\0';
+		retry = eap_mschapv2_failure_txt(sm, data, buf);
+		os_free(buf);
+	}
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_FAIL;
+	ret->allowNotifications = FALSE;
+
+	if (data->prev_error == ERROR_PASSWD_EXPIRED &&
+	    data->passwd_change_version == 3) {
+		struct eap_peer_config *config = eap_get_config(sm);
+		if (config && config->new_password)
+			return eap_mschapv2_change_password(sm, data, ret, req,
+							    id);
+		if (config && config->pending_req_new_password)
+			return NULL;
+	} else if (retry && data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
+		/* TODO: could try to retry authentication, e.g, after having
+		 * changed the username/password. In this case, EAP MS-CHAP-v2
+		 * Failure Response would not be sent here. */
+		return NULL;
+	}
+
+	/* Note: Only op_code of the EAP-MSCHAPV2 header is included in failure
+	 * message. */
+	resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, 1,
+			     EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+
+	wpabuf_put_u8(resp, MSCHAPV2_OP_FAILURE); /* op_code */
+
+	return resp;
+}
+
+
+static int eap_mschapv2_check_config(struct eap_sm *sm)
+{
+	size_t len;
+
+	if (eap_get_config_identity(sm, &len) == NULL) {
+		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Identity not configured");
+		eap_sm_request_identity(sm);
+		return -1;
+	}
+
+	if (eap_get_config_password(sm, &len) == NULL) {
+		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
+		eap_sm_request_password(sm);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int eap_mschapv2_check_mslen(struct eap_sm *sm, size_t len,
+				    const struct eap_mschapv2_hdr *ms)
+{
+	size_t ms_len = WPA_GET_BE16(ms->ms_length);
+
+	if (ms_len == len)
+		return 0;
+
+	wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid header: len=%lu "
+		   "ms_len=%lu", (unsigned long) len, (unsigned long) ms_len);
+	if (sm->workaround) {
+		/* Some authentication servers use invalid ms_len,
+		 * ignore it for interoperability. */
+		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: workaround, ignore"
+			   " invalid ms_len %lu (len %lu)",
+			   (unsigned long) ms_len,
+			   (unsigned long) len);
+		return 0;
+	}
+
+	return -1;
+}
+
+
+static void eap_mschapv2_copy_challenge(struct eap_mschapv2_data *data,
+					const struct wpabuf *reqData)
+{
+	/*
+	 * Store a copy of the challenge message, so that it can be processed
+	 * again in case retry is allowed after a possible failure.
+	 */
+	wpabuf_free(data->prev_challenge);
+	data->prev_challenge = wpabuf_dup(reqData);
+}
+
+
+/**
+ * eap_mschapv2_process - Process an EAP-MSCHAPv2 request
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @priv: Pointer to private EAP method data from eap_mschapv2_init()
+ * @ret: Return values from EAP request validation and processing
+ * @reqData: EAP request to be processed (eapReqData)
+ * Returns: Pointer to allocated EAP response packet (eapRespData) or %NULL if
+ * no reply available
+ */
+static struct wpabuf * eap_mschapv2_process(struct eap_sm *sm, void *priv,
+					    struct eap_method_ret *ret,
+					    const struct wpabuf *reqData)
+{
+	struct eap_mschapv2_data *data = priv;
+	struct eap_peer_config *config = eap_get_config(sm);
+	const struct eap_mschapv2_hdr *ms;
+	int using_prev_challenge = 0;
+	const u8 *pos;
+	size_t len;
+	u8 id;
+
+	if (eap_mschapv2_check_config(sm)) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (config->mschapv2_retry && data->prev_challenge &&
+	    data->prev_error == ERROR_AUTHENTICATION_FAILURE) {
+		wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Replacing pending packet "
+			   "with the previous challenge");
+
+		reqData = data->prev_challenge;
+		using_prev_challenge = 1;
+		config->mschapv2_retry = 0;
+	}
+
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqData,
+			       &len);
+	if (pos == NULL || len < sizeof(*ms) + 1) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	ms = (const struct eap_mschapv2_hdr *) pos;
+	if (eap_mschapv2_check_mslen(sm, len, ms)) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	id = eap_get_id(reqData);
+	wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: RX identifier %d mschapv2_id %d",
+		   id, ms->mschapv2_id);
+
+	switch (ms->op_code) {
+	case MSCHAPV2_OP_CHALLENGE:
+		if (!using_prev_challenge)
+			eap_mschapv2_copy_challenge(data, reqData);
+		return eap_mschapv2_challenge(sm, data, ret, ms, len, id);
+	case MSCHAPV2_OP_SUCCESS:
+		return eap_mschapv2_success(sm, data, ret, ms, len, id);
+	case MSCHAPV2_OP_FAILURE:
+		return eap_mschapv2_failure(sm, data, ret, ms, len, id);
+	default:
+		wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Unknown op %d - ignored",
+			   ms->op_code);
+		ret->ignore = TRUE;
+		return NULL;
+	}
+}
+
+
+static Boolean eap_mschapv2_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_mschapv2_data *data = priv;
+	return data->success && data->master_key_valid;
+}
+
+
+static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_mschapv2_data *data = priv;
+	u8 *key;
+	int key_len;
+
+	if (!data->master_key_valid || !data->success)
+		return NULL;
+
+	key_len = 2 * MSCHAPV2_KEY_LEN;
+
+	key = os_malloc(key_len);
+	if (key == NULL)
+		return NULL;
+
+	/* MSK = server MS-MPPE-Recv-Key | MS-MPPE-Send-Key, i.e.,
+	 *	peer MS-MPPE-Send-Key | MS-MPPE-Recv-Key */
+	get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 1, 0);
+	get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
+				MSCHAPV2_KEY_LEN, 0, 0);
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key",
+			key, key_len);
+
+	*len = key_len;
+	return key;
+}
+
+
+/**
+ * eap_peer_mschapv2_register - Register EAP-MSCHAPv2 peer method
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to register EAP-MSCHAPv2 peer method into the EAP
+ * method list.
+ */
+int eap_peer_mschapv2_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+				    EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
+				    "MSCHAPV2");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_mschapv2_init;
+	eap->deinit = eap_mschapv2_deinit;
+	eap->process = eap_mschapv2_process;
+	eap->isKeyAvailable = eap_mschapv2_isKeyAvailable;
+	eap->getKey = eap_mschapv2_getKey;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_peap.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,1287 @@
+/*
+ * EAP peer method: EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-10.txt)
+ * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/sha1.h"
+#include "crypto/tls.h"
+#include "eap_common/eap_tlv_common.h"
+#include "eap_common/eap_peap_common.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "eap_config.h"
+#include "tncc.h"
+
+
+/* Maximum supported PEAP version
+ * 0 = Microsoft's PEAP version 0; draft-kamath-pppext-peapv0-00.txt
+ * 1 = draft-josefsson-ppext-eap-tls-eap-05.txt
+ * 2 = draft-josefsson-ppext-eap-tls-eap-10.txt
+ */
+#define EAP_PEAP_VERSION 1
+
+
+static void eap_peap_deinit(struct eap_sm *sm, void *priv);
+
+
+struct eap_peap_data {
+	struct eap_ssl_data ssl;
+
+	int peap_version, force_peap_version, force_new_label;
+
+	const struct eap_method *phase2_method;
+	void *phase2_priv;
+	int phase2_success;
+	int phase2_eap_success;
+	int phase2_eap_started;
+
+	struct eap_method_type phase2_type;
+	struct eap_method_type *phase2_types;
+	size_t num_phase2_types;
+
+	int peap_outer_success; /* 0 = PEAP terminated on Phase 2 inner
+				 * EAP-Success
+				 * 1 = reply with tunneled EAP-Success to inner
+				 * EAP-Success and expect AS to send outer
+				 * (unencrypted) EAP-Success after this
+				 * 2 = reply with PEAP/TLS ACK to inner
+				 * EAP-Success and expect AS to send outer
+				 * (unencrypted) EAP-Success after this */
+	int resuming; /* starting a resumed session */
+	int reauth; /* reauthentication */
+	u8 *key_data;
+
+	struct wpabuf *pending_phase2_req;
+	enum { NO_BINDING, OPTIONAL_BINDING, REQUIRE_BINDING } crypto_binding;
+	int crypto_binding_used;
+	u8 binding_nonce[32];
+	u8 ipmk[40];
+	u8 cmk[20];
+	int soh; /* Whether IF-TNCCS-SOH (Statement of Health; Microsoft NAP)
+		  * is enabled. */
+};
+
+
+static int eap_peap_parse_phase1(struct eap_peap_data *data,
+				 const char *phase1)
+{
+	const char *pos;
+
+	pos = os_strstr(phase1, "peapver=");
+	if (pos) {
+		data->force_peap_version = atoi(pos + 8);
+		data->peap_version = data->force_peap_version;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Forced PEAP version %d",
+			   data->force_peap_version);
+	}
+
+	if (os_strstr(phase1, "peaplabel=1")) {
+		data->force_new_label = 1;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Force new label for key "
+			   "derivation");
+	}
+
+	if (os_strstr(phase1, "peap_outer_success=0")) {
+		data->peap_outer_success = 0;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: terminate authentication on "
+			   "tunneled EAP-Success");
+	} else if (os_strstr(phase1, "peap_outer_success=1")) {
+		data->peap_outer_success = 1;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: send tunneled EAP-Success "
+			   "after receiving tunneled EAP-Success");
+	} else if (os_strstr(phase1, "peap_outer_success=2")) {
+		data->peap_outer_success = 2;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: send PEAP/TLS ACK after "
+			   "receiving tunneled EAP-Success");
+	}
+
+	if (os_strstr(phase1, "crypto_binding=0")) {
+		data->crypto_binding = NO_BINDING;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Do not use cryptobinding");
+	} else if (os_strstr(phase1, "crypto_binding=1")) {
+		data->crypto_binding = OPTIONAL_BINDING;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Optional cryptobinding");
+	} else if (os_strstr(phase1, "crypto_binding=2")) {
+		data->crypto_binding = REQUIRE_BINDING;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Require cryptobinding");
+	}
+
+#ifdef EAP_TNC
+	if (os_strstr(phase1, "tnc=soh2")) {
+		data->soh = 2;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
+	} else if (os_strstr(phase1, "tnc=soh1")) {
+		data->soh = 1;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 1 enabled");
+	} else if (os_strstr(phase1, "tnc=soh")) {
+		data->soh = 2;
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: SoH version 2 enabled");
+	}
+#endif /* EAP_TNC */
+
+	return 0;
+}
+
+
+static void * eap_peap_init(struct eap_sm *sm)
+{
+	struct eap_peap_data *data;
+	struct eap_peer_config *config = eap_get_config(sm);
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	sm->peap_done = FALSE;
+	data->peap_version = EAP_PEAP_VERSION;
+	data->force_peap_version = -1;
+	data->peap_outer_success = 2;
+	data->crypto_binding = OPTIONAL_BINDING;
+
+	if (config && config->phase1 &&
+	    eap_peap_parse_phase1(data, config->phase1) < 0) {
+		eap_peap_deinit(sm, data);
+		return NULL;
+	}
+
+	if (eap_peer_select_phase2_methods(config, "auth=",
+					   &data->phase2_types,
+					   &data->num_phase2_types) < 0) {
+		eap_peap_deinit(sm, data);
+		return NULL;
+	}
+
+	data->phase2_type.vendor = EAP_VENDOR_IETF;
+	data->phase2_type.method = EAP_TYPE_NONE;
+
+	if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_PEAP)) {
+		wpa_printf(MSG_INFO, "EAP-PEAP: Failed to initialize SSL.");
+		eap_peap_deinit(sm, data);
+		return NULL;
+	}
+
+	return data;
+}
+
+
+static void eap_peap_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_peap_data *data = priv;
+	if (data == NULL)
+		return;
+	if (data->phase2_priv && data->phase2_method)
+		data->phase2_method->deinit(sm, data->phase2_priv);
+	os_free(data->phase2_types);
+	eap_peer_tls_ssl_deinit(sm, &data->ssl);
+	os_free(data->key_data);
+	wpabuf_free(data->pending_phase2_req);
+	os_free(data);
+}
+
+
+/**
+ * eap_tlv_build_nak - Build EAP-TLV NAK message
+ * @id: EAP identifier for the header
+ * @nak_type: TLV type (EAP_TLV_*)
+ * Returns: Buffer to the allocated EAP-TLV NAK message or %NULL on failure
+ *
+ * This function builds an EAP-TLV NAK message. The caller is responsible for
+ * freeing the returned buffer.
+ */
+static struct wpabuf * eap_tlv_build_nak(int id, u16 nak_type)
+{
+	struct wpabuf *msg;
+
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, 10,
+			    EAP_CODE_RESPONSE, id);
+	if (msg == NULL)
+		return NULL;
+
+	wpabuf_put_u8(msg, 0x80); /* Mandatory */
+	wpabuf_put_u8(msg, EAP_TLV_NAK_TLV);
+	wpabuf_put_be16(msg, 6); /* Length */
+	wpabuf_put_be32(msg, 0); /* Vendor-Id */
+	wpabuf_put_be16(msg, nak_type); /* NAK-Type */
+
+	return msg;
+}
+
+
+static int eap_peap_get_isk(struct eap_sm *sm, struct eap_peap_data *data,
+			    u8 *isk, size_t isk_len)
+{
+	u8 *key;
+	size_t key_len;
+
+	os_memset(isk, 0, isk_len);
+	if (data->phase2_method == NULL || data->phase2_priv == NULL ||
+	    data->phase2_method->isKeyAvailable == NULL ||
+	    data->phase2_method->getKey == NULL)
+		return 0;
+
+	if (!data->phase2_method->isKeyAvailable(sm, data->phase2_priv) ||
+	    (key = data->phase2_method->getKey(sm, data->phase2_priv,
+					       &key_len)) == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not get key material "
+			   "from Phase 2");
+		return -1;
+	}
+
+	if (key_len > isk_len)
+		key_len = isk_len;
+	os_memcpy(isk, key, key_len);
+	os_free(key);
+
+	return 0;
+}
+
+
+static int eap_peap_derive_cmk(struct eap_sm *sm, struct eap_peap_data *data)
+{
+	u8 *tk;
+	u8 isk[32], imck[60];
+
+	/*
+	 * Tunnel key (TK) is the first 60 octets of the key generated by
+	 * phase 1 of PEAP (based on TLS).
+	 */
+	tk = data->key_data;
+	if (tk == NULL)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TK", tk, 60);
+
+	if (data->reauth &&
+	    tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
+		/* Fast-connect: IPMK|CMK = TK */
+		os_memcpy(data->ipmk, tk, 40);
+		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK from TK",
+				data->ipmk, 40);
+		os_memcpy(data->cmk, tk + 40, 20);
+		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK from TK",
+				data->cmk, 20);
+		return 0;
+	}
+
+	if (eap_peap_get_isk(sm, data, isk, sizeof(isk)) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: ISK", isk, sizeof(isk));
+
+	/*
+	 * IPMK Seed = "Inner Methods Compound Keys" | ISK
+	 * TempKey = First 40 octets of TK
+	 * IPMK|CMK = PRF+(TempKey, IPMK Seed, 60)
+	 * (note: draft-josefsson-pppext-eap-tls-eap-10.txt includes a space
+	 * in the end of the label just before ISK; is that just a typo?)
+	 */
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: TempKey", tk, 40);
+	if (peap_prfplus(data->peap_version, tk, 40,
+			 "Inner Methods Compound Keys",
+			 isk, sizeof(isk), imck, sizeof(imck)) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IMCK (IPMKj)",
+			imck, sizeof(imck));
+
+	os_memcpy(data->ipmk, imck, 40);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: IPMK (S-IPMKj)", data->ipmk, 40);
+	os_memcpy(data->cmk, imck + 40, 20);
+	wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CMK (CMKj)", data->cmk, 20);
+
+	return 0;
+}
+
+
+static int eap_tlv_add_cryptobinding(struct eap_sm *sm,
+				     struct eap_peap_data *data,
+				     struct wpabuf *buf)
+{
+	u8 *mac;
+	u8 eap_type = EAP_TYPE_PEAP;
+	const u8 *addr[2];
+	size_t len[2];
+	u16 tlv_type;
+
+	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
+	addr[0] = wpabuf_put(buf, 0);
+	len[0] = 60;
+	addr[1] = &eap_type;
+	len[1] = 1;
+
+	tlv_type = EAP_TLV_CRYPTO_BINDING_TLV;
+	if (data->peap_version >= 2)
+		tlv_type |= EAP_TLV_TYPE_MANDATORY;
+	wpabuf_put_be16(buf, tlv_type);
+	wpabuf_put_be16(buf, 56);
+
+	wpabuf_put_u8(buf, 0); /* Reserved */
+	wpabuf_put_u8(buf, data->peap_version); /* Version */
+	wpabuf_put_u8(buf, data->peap_version); /* RecvVersion */
+	wpabuf_put_u8(buf, 1); /* SubType: 0 = Request, 1 = Response */
+	wpabuf_put_data(buf, data->binding_nonce, 32); /* Nonce */
+	mac = wpabuf_put(buf, 20); /* Compound_MAC */
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC CMK", data->cmk, 20);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 1",
+		    addr[0], len[0]);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC data 2",
+		    addr[1], len[1]);
+	hmac_sha1_vector(data->cmk, 20, 2, addr, len, mac);
+	wpa_hexdump(MSG_MSGDUMP, "EAP-PEAP: Compound_MAC", mac, SHA1_MAC_LEN);
+	data->crypto_binding_used = 1;
+
+	return 0;
+}
+
+
+/**
+ * eap_tlv_build_result - Build EAP-TLV Result message
+ * @id: EAP identifier for the header
+ * @status: Status (EAP_TLV_RESULT_SUCCESS or EAP_TLV_RESULT_FAILURE)
+ * Returns: Buffer to the allocated EAP-TLV Result message or %NULL on failure
+ *
+ * This function builds an EAP-TLV Result message. The caller is responsible
+ * for freeing the returned buffer.
+ */
+static struct wpabuf * eap_tlv_build_result(struct eap_sm *sm,
+					    struct eap_peap_data *data,
+					    int crypto_tlv_used,
+					    int id, u16 status)
+{
+	struct wpabuf *msg;
+	size_t len;
+
+	if (data->crypto_binding == NO_BINDING)
+		crypto_tlv_used = 0;
+
+	len = 6;
+	if (crypto_tlv_used)
+		len += 60; /* Cryptobinding TLV */
+	msg = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_TLV, len,
+			    EAP_CODE_RESPONSE, id);
+	if (msg == NULL)
+		return NULL;
+
+	wpabuf_put_u8(msg, 0x80); /* Mandatory */
+	wpabuf_put_u8(msg, EAP_TLV_RESULT_TLV);
+	wpabuf_put_be16(msg, 2); /* Length */
+	wpabuf_put_be16(msg, status); /* Status */
+
+	if (crypto_tlv_used && eap_tlv_add_cryptobinding(sm, data, msg)) {
+		wpabuf_free(msg);
+		return NULL;
+	}
+
+	return msg;
+}
+
+
+static int eap_tlv_validate_cryptobinding(struct eap_sm *sm,
+					  struct eap_peap_data *data,
+					  const u8 *crypto_tlv,
+					  size_t crypto_tlv_len)
+{
+	u8 buf[61], mac[SHA1_MAC_LEN];
+	const u8 *pos;
+
+	if (eap_peap_derive_cmk(sm, data) < 0) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Could not derive CMK");
+		return -1;
+	}
+
+	if (crypto_tlv_len != 4 + 56) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid cryptobinding TLV "
+			   "length %d", (int) crypto_tlv_len);
+		return -1;
+	}
+
+	pos = crypto_tlv;
+	pos += 4; /* TLV header */
+	if (pos[1] != data->peap_version) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV Version "
+			   "mismatch (was %d; expected %d)",
+			   pos[1], data->peap_version);
+		return -1;
+	}
+
+	if (pos[3] != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Unexpected Cryptobinding TLV "
+			   "SubType %d", pos[3]);
+		return -1;
+	}
+	pos += 4;
+	os_memcpy(data->binding_nonce, pos, 32);
+	pos += 32; /* Nonce */
+
+	/* Compound_MAC: HMAC-SHA1-160(cryptobinding TLV | EAP type) */
+	os_memcpy(buf, crypto_tlv, 60);
+	os_memset(buf + 4 + 4 + 32, 0, 20); /* Compound_MAC */
+	buf[60] = EAP_TYPE_PEAP;
+	wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Compound_MAC data",
+		    buf, sizeof(buf));
+	hmac_sha1(data->cmk, 20, buf, sizeof(buf), mac);
+
+	if (os_memcmp(mac, pos, SHA1_MAC_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Invalid Compound_MAC in "
+			   "cryptobinding TLV");
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Received MAC",
+			    pos, SHA1_MAC_LEN);
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Expected MAC",
+			    mac, SHA1_MAC_LEN);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: Valid cryptobinding TLV received");
+
+	return 0;
+}
+
+
+/**
+ * eap_tlv_process - Process a received EAP-TLV message and generate a response
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @ret: Return values from EAP request validation and processing
+ * @req: EAP-TLV request to be processed. The caller must have validated that
+ * the buffer is large enough to contain full request (hdr->length bytes) and
+ * that the EAP type is EAP_TYPE_TLV.
+ * @resp: Buffer to return a pointer to the allocated response message. This
+ * field should be initialized to %NULL before the call. The value will be
+ * updated if a response message is generated. The caller is responsible for
+ * freeing the allocated message.
+ * @force_failure: Force negotiation to fail
+ * Returns: 0 on success, -1 on failure
+ */
+static int eap_tlv_process(struct eap_sm *sm, struct eap_peap_data *data,
+			   struct eap_method_ret *ret,
+			   const struct wpabuf *req, struct wpabuf **resp,
+			   int force_failure)
+{
+	size_t left, tlv_len;
+	const u8 *pos;
+	const u8 *result_tlv = NULL, *crypto_tlv = NULL;
+	size_t result_tlv_len = 0, crypto_tlv_len = 0;
+	int tlv_type, mandatory;
+
+	/* Parse TLVs */
+	pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_TLV, req, &left);
+	if (pos == NULL)
+		return -1;
+	wpa_hexdump(MSG_DEBUG, "EAP-TLV: Received TLVs", pos, left);
+	while (left >= 4) {
+		mandatory = !!(pos[0] & 0x80);
+		tlv_type = WPA_GET_BE16(pos) & 0x3fff;
+		pos += 2;
+		tlv_len = WPA_GET_BE16(pos);
+		pos += 2;
+		left -= 4;
+		if (tlv_len > left) {
+			wpa_printf(MSG_DEBUG, "EAP-TLV: TLV underrun "
+				   "(tlv_len=%lu left=%lu)",
+				   (unsigned long) tlv_len,
+				   (unsigned long) left);
+			return -1;
+		}
+		switch (tlv_type) {
+		case EAP_TLV_RESULT_TLV:
+			result_tlv = pos;
+			result_tlv_len = tlv_len;
+			break;
+		case EAP_TLV_CRYPTO_BINDING_TLV:
+			crypto_tlv = pos;
+			crypto_tlv_len = tlv_len;
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "EAP-TLV: Unsupported TLV Type "
+				   "%d%s", tlv_type,
+				   mandatory ? " (mandatory)" : "");
+			if (mandatory) {
+				/* NAK TLV and ignore all TLVs in this packet.
+				 */
+				*resp = eap_tlv_build_nak(eap_get_id(req),
+							  tlv_type);
+				return *resp == NULL ? -1 : 0;
+			}
+			/* Ignore this TLV, but process other TLVs */
+			break;
+		}
+
+		pos += tlv_len;
+		left -= tlv_len;
+	}
+	if (left) {
+		wpa_printf(MSG_DEBUG, "EAP-TLV: Last TLV too short in "
+			   "Request (left=%lu)", (unsigned long) left);
+		return -1;
+	}
+
+	/* Process supported TLVs */
+	if (crypto_tlv && data->crypto_binding != NO_BINDING) {
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Cryptobinding TLV",
+			    crypto_tlv, crypto_tlv_len);
+		if (eap_tlv_validate_cryptobinding(sm, data, crypto_tlv - 4,
+						   crypto_tlv_len + 4) < 0) {
+			if (result_tlv == NULL)
+				return -1;
+			force_failure = 1;
+			crypto_tlv = NULL; /* do not include Cryptobinding TLV
+					    * in response, if the received
+					    * cryptobinding was invalid. */
+		}
+	} else if (!crypto_tlv && data->crypto_binding == REQUIRE_BINDING) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: No cryptobinding TLV");
+		return -1;
+	}
+
+	if (result_tlv) {
+		int status, resp_status;
+		wpa_hexdump(MSG_DEBUG, "EAP-TLV: Result TLV",
+			    result_tlv, result_tlv_len);
+		if (result_tlv_len < 2) {
+			wpa_printf(MSG_INFO, "EAP-TLV: Too short Result TLV "
+				   "(len=%lu)",
+				   (unsigned long) result_tlv_len);
+			return -1;
+		}
+		status = WPA_GET_BE16(result_tlv);
+		if (status == EAP_TLV_RESULT_SUCCESS) {
+			wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Success "
+				   "- EAP-TLV/Phase2 Completed");
+			if (force_failure) {
+				wpa_printf(MSG_INFO, "EAP-TLV: Earlier failure"
+					   " - force failed Phase 2");
+				resp_status = EAP_TLV_RESULT_FAILURE;
+				ret->decision = DECISION_FAIL;
+			} else {
+				resp_status = EAP_TLV_RESULT_SUCCESS;
+				ret->decision = DECISION_UNCOND_SUCC;
+			}
+		} else if (status == EAP_TLV_RESULT_FAILURE) {
+			wpa_printf(MSG_INFO, "EAP-TLV: TLV Result - Failure");
+			resp_status = EAP_TLV_RESULT_FAILURE;
+			ret->decision = DECISION_FAIL;
+		} else {
+			wpa_printf(MSG_INFO, "EAP-TLV: Unknown TLV Result "
+				   "Status %d", status);
+			resp_status = EAP_TLV_RESULT_FAILURE;
+			ret->decision = DECISION_FAIL;
+		}
+		ret->methodState = METHOD_DONE;
+
+		*resp = eap_tlv_build_result(sm, data, crypto_tlv != NULL,
+					     eap_get_id(req), resp_status);
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_peapv2_tlv_eap_payload(struct wpabuf *buf)
+{
+	struct wpabuf *e;
+	struct eap_tlv_hdr *tlv;
+
+	if (buf == NULL)
+		return NULL;
+
+	/* Encapsulate EAP packet in EAP-Payload TLV */
+	wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Add EAP-Payload TLV");
+	e = wpabuf_alloc(sizeof(*tlv) + wpabuf_len(buf));
+	if (e == NULL) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAPv2: Failed to allocate memory "
+			   "for TLV encapsulation");
+		wpabuf_free(buf);
+		return NULL;
+	}
+	tlv = wpabuf_put(e, sizeof(*tlv));
+	tlv->tlv_type = host_to_be16(EAP_TLV_TYPE_MANDATORY |
+				     EAP_TLV_EAP_PAYLOAD_TLV);
+	tlv->length = host_to_be16(wpabuf_len(buf));
+	wpabuf_put_buf(e, buf);
+	wpabuf_free(buf);
+	return e;
+}
+
+
+static int eap_peap_phase2_request(struct eap_sm *sm,
+				   struct eap_peap_data *data,
+				   struct eap_method_ret *ret,
+				   struct wpabuf *req,
+				   struct wpabuf **resp)
+{
+	struct eap_hdr *hdr = wpabuf_mhead(req);
+	size_t len = be_to_host16(hdr->length);
+	u8 *pos;
+	struct eap_method_ret iret;
+	struct eap_peer_config *config = eap_get_config(sm);
+
+	if (len <= sizeof(struct eap_hdr)) {
+		wpa_printf(MSG_INFO, "EAP-PEAP: too short "
+			   "Phase 2 request (len=%lu)", (unsigned long) len);
+		return -1;
+	}
+	pos = (u8 *) (hdr + 1);
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Request: type=%d", *pos);
+	switch (*pos) {
+	case EAP_TYPE_IDENTITY:
+		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
+		break;
+	case EAP_TYPE_TLV:
+		os_memset(&iret, 0, sizeof(iret));
+		if (eap_tlv_process(sm, data, &iret, req, resp,
+				    data->phase2_eap_started &&
+				    !data->phase2_eap_success)) {
+			ret->methodState = METHOD_DONE;
+			ret->decision = DECISION_FAIL;
+			return -1;
+		}
+		if (iret.methodState == METHOD_DONE ||
+		    iret.methodState == METHOD_MAY_CONT) {
+			ret->methodState = iret.methodState;
+			ret->decision = iret.decision;
+			data->phase2_success = 1;
+		}
+		break;
+	case EAP_TYPE_EXPANDED:
+#ifdef EAP_TNC
+		if (data->soh) {
+			const u8 *epos;
+			size_t eleft;
+
+			epos = eap_hdr_validate(EAP_VENDOR_MICROSOFT, 0x21,
+						req, &eleft);
+			if (epos) {
+				struct wpabuf *buf;
+				wpa_printf(MSG_DEBUG,
+					   "EAP-PEAP: SoH EAP Extensions");
+				buf = tncc_process_soh_request(data->soh,
+							       epos, eleft);
+				if (buf) {
+					*resp = eap_msg_alloc(
+						EAP_VENDOR_MICROSOFT, 0x21,
+						wpabuf_len(buf),
+						EAP_CODE_RESPONSE,
+						hdr->identifier);
+					if (*resp == NULL) {
+						ret->methodState = METHOD_DONE;
+						ret->decision = DECISION_FAIL;
+						return -1;
+					}
+					wpabuf_put_buf(*resp, buf);
+					wpabuf_free(buf);
+					break;
+				}
+			}
+		}
+#endif /* EAP_TNC */
+		/* fall through */
+	default:
+		if (data->phase2_type.vendor == EAP_VENDOR_IETF &&
+		    data->phase2_type.method == EAP_TYPE_NONE) {
+			size_t i;
+			for (i = 0; i < data->num_phase2_types; i++) {
+				if (data->phase2_types[i].vendor !=
+				    EAP_VENDOR_IETF ||
+				    data->phase2_types[i].method != *pos)
+					continue;
+
+				data->phase2_type.vendor =
+					data->phase2_types[i].vendor;
+				data->phase2_type.method =
+					data->phase2_types[i].method;
+				wpa_printf(MSG_DEBUG, "EAP-PEAP: Selected "
+					   "Phase 2 EAP vendor %d method %d",
+					   data->phase2_type.vendor,
+					   data->phase2_type.method);
+				break;
+			}
+		}
+		if (*pos != data->phase2_type.method ||
+		    *pos == EAP_TYPE_NONE) {
+			if (eap_peer_tls_phase2_nak(data->phase2_types,
+						    data->num_phase2_types,
+						    hdr, resp))
+				return -1;
+			return 0;
+		}
+
+		if (data->phase2_priv == NULL) {
+			data->phase2_method = eap_peer_get_eap_method(
+				data->phase2_type.vendor,
+				data->phase2_type.method);
+			if (data->phase2_method) {
+				sm->init_phase2 = 1;
+				data->phase2_priv =
+					data->phase2_method->init(sm);
+				sm->init_phase2 = 0;
+			}
+		}
+		if (data->phase2_priv == NULL || data->phase2_method == NULL) {
+			wpa_printf(MSG_INFO, "EAP-PEAP: failed to initialize "
+				   "Phase 2 EAP method %d", *pos);
+			ret->methodState = METHOD_DONE;
+			ret->decision = DECISION_FAIL;
+			return -1;
+		}
+		data->phase2_eap_started = 1;
+		os_memset(&iret, 0, sizeof(iret));
+		*resp = data->phase2_method->process(sm, data->phase2_priv,
+						     &iret, req);
+		if ((iret.methodState == METHOD_DONE ||
+		     iret.methodState == METHOD_MAY_CONT) &&
+		    (iret.decision == DECISION_UNCOND_SUCC ||
+		     iret.decision == DECISION_COND_SUCC)) {
+			data->phase2_eap_success = 1;
+			data->phase2_success = 1;
+		}
+		break;
+	}
+
+	if (*resp == NULL &&
+	    (config->pending_req_identity || config->pending_req_password ||
+	     config->pending_req_otp || config->pending_req_new_password)) {
+		wpabuf_free(data->pending_phase2_req);
+		data->pending_phase2_req = wpabuf_alloc_copy(hdr, len);
+	}
+
+	return 0;
+}
+
+
+static int eap_peap_decrypt(struct eap_sm *sm, struct eap_peap_data *data,
+			    struct eap_method_ret *ret,
+			    const struct eap_hdr *req,
+			    const struct wpabuf *in_data,
+			    struct wpabuf **out_data)
+{
+	struct wpabuf *in_decrypted = NULL;
+	int res, skip_change = 0;
+	struct eap_hdr *hdr, *rhdr;
+	struct wpabuf *resp = NULL;
+	size_t len;
+
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
+		   " Phase 2", (unsigned long) wpabuf_len(in_data));
+
+	if (data->pending_phase2_req) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Pending Phase 2 request - "
+			   "skip decryption and use old data");
+		/* Clear TLS reassembly state. */
+		eap_peer_tls_reset_input(&data->ssl);
+		in_decrypted = data->pending_phase2_req;
+		data->pending_phase2_req = NULL;
+		skip_change = 1;
+		goto continue_req;
+	}
+
+	if (wpabuf_len(in_data) == 0 && sm->workaround &&
+	    data->phase2_success) {
+		/*
+		 * Cisco ACS seems to be using TLS ACK to terminate
+		 * EAP-PEAPv0/GTC. Try to reply with TLS ACK.
+		 */
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Received TLS ACK, but "
+			   "expected data - acknowledge with TLS ACK since "
+			   "Phase 2 has been completed");
+		ret->decision = DECISION_COND_SUCC;
+		ret->methodState = METHOD_DONE;
+		return 1;
+	} else if (wpabuf_len(in_data) == 0) {
+		/* Received TLS ACK - requesting more fragments */
+		return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
+					    data->peap_version,
+					    req->identifier, NULL, out_data);
+	}
+
+	res = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
+	if (res)
+		return res;
+
+continue_req:
+	wpa_hexdump_buf(MSG_DEBUG, "EAP-PEAP: Decrypted Phase 2 EAP",
+			in_decrypted);
+
+	hdr = wpabuf_mhead(in_decrypted);
+	if (wpabuf_len(in_decrypted) == 5 && hdr->code == EAP_CODE_REQUEST &&
+	    be_to_host16(hdr->length) == 5 &&
+	    eap_get_type(in_decrypted) == EAP_TYPE_IDENTITY) {
+		/* At least FreeRADIUS seems to send full EAP header with
+		 * EAP Request Identity */
+		skip_change = 1;
+	}
+	if (wpabuf_len(in_decrypted) >= 5 && hdr->code == EAP_CODE_REQUEST &&
+	    eap_get_type(in_decrypted) == EAP_TYPE_TLV) {
+		skip_change = 1;
+	}
+
+	if (data->peap_version == 0 && !skip_change) {
+		struct eap_hdr *nhdr;
+		struct wpabuf *nmsg = wpabuf_alloc(sizeof(struct eap_hdr) +
+						   wpabuf_len(in_decrypted));
+		if (nmsg == NULL) {
+			wpabuf_free(in_decrypted);
+			return 0;
+		}
+		nhdr = wpabuf_put(nmsg, sizeof(*nhdr));
+		wpabuf_put_buf(nmsg, in_decrypted);
+		nhdr->code = req->code;
+		nhdr->identifier = req->identifier;
+		nhdr->length = host_to_be16(sizeof(struct eap_hdr) +
+					    wpabuf_len(in_decrypted));
+
+		wpabuf_free(in_decrypted);
+		in_decrypted = nmsg;
+	}
+
+	if (data->peap_version >= 2) {
+		struct eap_tlv_hdr *tlv;
+		struct wpabuf *nmsg;
+
+		if (wpabuf_len(in_decrypted) < sizeof(*tlv) + sizeof(*hdr)) {
+			wpa_printf(MSG_INFO, "EAP-PEAPv2: Too short Phase 2 "
+				   "EAP TLV");
+			wpabuf_free(in_decrypted);
+			return 0;
+		}
+		tlv = wpabuf_mhead(in_decrypted);
+		if ((be_to_host16(tlv->tlv_type) & 0x3fff) !=
+		    EAP_TLV_EAP_PAYLOAD_TLV) {
+			wpa_printf(MSG_INFO, "EAP-PEAPv2: Not an EAP TLV");
+			wpabuf_free(in_decrypted);
+			return 0;
+		}
+		if (sizeof(*tlv) + be_to_host16(tlv->length) >
+		    wpabuf_len(in_decrypted)) {
+			wpa_printf(MSG_INFO, "EAP-PEAPv2: Invalid EAP TLV "
+				   "length");
+			wpabuf_free(in_decrypted);
+			return 0;
+		}
+		hdr = (struct eap_hdr *) (tlv + 1);
+		if (be_to_host16(hdr->length) > be_to_host16(tlv->length)) {
+			wpa_printf(MSG_INFO, "EAP-PEAPv2: No room for full "
+				   "EAP packet in EAP TLV");
+			wpabuf_free(in_decrypted);
+			return 0;
+		}
+
+		nmsg = wpabuf_alloc(be_to_host16(hdr->length));
+		if (nmsg == NULL) {
+			wpabuf_free(in_decrypted);
+			return 0;
+		}
+
+		wpabuf_put_data(nmsg, hdr, be_to_host16(hdr->length));
+		wpabuf_free(in_decrypted);
+		in_decrypted = nmsg;
+	}
+
+	hdr = wpabuf_mhead(in_decrypted);
+	if (wpabuf_len(in_decrypted) < sizeof(*hdr)) {
+		wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
+			   "EAP frame (len=%lu)",
+			   (unsigned long) wpabuf_len(in_decrypted));
+		wpabuf_free(in_decrypted);
+		return 0;
+	}
+	len = be_to_host16(hdr->length);
+	if (len > wpabuf_len(in_decrypted)) {
+		wpa_printf(MSG_INFO, "EAP-PEAP: Length mismatch in "
+			   "Phase 2 EAP frame (len=%lu hdr->length=%lu)",
+			   (unsigned long) wpabuf_len(in_decrypted),
+			   (unsigned long) len);
+		wpabuf_free(in_decrypted);
+		return 0;
+	}
+	if (len < wpabuf_len(in_decrypted)) {
+		wpa_printf(MSG_INFO, "EAP-PEAP: Odd.. Phase 2 EAP header has "
+			   "shorter length than full decrypted data "
+			   "(%lu < %lu)",
+			   (unsigned long) len,
+			   (unsigned long) wpabuf_len(in_decrypted));
+	}
+	wpa_printf(MSG_DEBUG, "EAP-PEAP: received Phase 2: code=%d "
+		   "identifier=%d length=%lu", hdr->code, hdr->identifier,
+		   (unsigned long) len);
+	switch (hdr->code) {
+	case EAP_CODE_REQUEST:
+		if (eap_peap_phase2_request(sm, data, ret, in_decrypted,
+					    &resp)) {
+			wpabuf_free(in_decrypted);
+			wpa_printf(MSG_INFO, "EAP-PEAP: Phase2 Request "
+				   "processing failed");
+			return 0;
+		}
+		break;
+	case EAP_CODE_SUCCESS:
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Success");
+		if (data->peap_version == 1) {
+			/* EAP-Success within TLS tunnel is used to indicate
+			 * shutdown of the TLS channel. The authentication has
+			 * been completed. */
+			if (data->phase2_eap_started &&
+			    !data->phase2_eap_success) {
+				wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 "
+					   "Success used to indicate success, "
+					   "but Phase 2 EAP was not yet "
+					   "completed successfully");
+				ret->methodState = METHOD_DONE;
+				ret->decision = DECISION_FAIL;
+				wpabuf_free(in_decrypted);
+				return 0;
+			}
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: Version 1 - "
+				   "EAP-Success within TLS tunnel - "
+				   "authentication completed");
+			ret->decision = DECISION_UNCOND_SUCC;
+			ret->methodState = METHOD_DONE;
+			data->phase2_success = 1;
+			if (data->peap_outer_success == 2) {
+				wpabuf_free(in_decrypted);
+				wpa_printf(MSG_DEBUG, "EAP-PEAP: Use TLS ACK "
+					   "to finish authentication");
+				return 1;
+			} else if (data->peap_outer_success == 1) {
+				/* Reply with EAP-Success within the TLS
+				 * channel to complete the authentication. */
+				resp = wpabuf_alloc(sizeof(struct eap_hdr));
+				if (resp) {
+					rhdr = wpabuf_put(resp, sizeof(*rhdr));
+					rhdr->code = EAP_CODE_SUCCESS;
+					rhdr->identifier = hdr->identifier;
+					rhdr->length =
+						host_to_be16(sizeof(*rhdr));
+				}
+			} else {
+				/* No EAP-Success expected for Phase 1 (outer,
+				 * unencrypted auth), so force EAP state
+				 * machine to SUCCESS state. */
+				sm->peap_done = TRUE;
+			}
+		} else {
+			/* FIX: ? */
+		}
+		break;
+	case EAP_CODE_FAILURE:
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Phase 2 Failure");
+		ret->decision = DECISION_FAIL;
+		ret->methodState = METHOD_MAY_CONT;
+		ret->allowNotifications = FALSE;
+		/* Reply with EAP-Failure within the TLS channel to complete
+		 * failure reporting. */
+		resp = wpabuf_alloc(sizeof(struct eap_hdr));
+		if (resp) {
+			rhdr = wpabuf_put(resp, sizeof(*rhdr));
+			rhdr->code = EAP_CODE_FAILURE;
+			rhdr->identifier = hdr->identifier;
+			rhdr->length = host_to_be16(sizeof(*rhdr));
+		}
+		break;
+	default:
+		wpa_printf(MSG_INFO, "EAP-PEAP: Unexpected code=%d in "
+			   "Phase 2 EAP header", hdr->code);
+		break;
+	}
+
+	wpabuf_free(in_decrypted);
+
+	if (resp) {
+		int skip_change2 = 0;
+		struct wpabuf *rmsg, buf;
+
+		wpa_hexdump_buf_key(MSG_DEBUG,
+				    "EAP-PEAP: Encrypting Phase 2 data", resp);
+		/* PEAP version changes */
+		if (data->peap_version >= 2) {
+			resp = eap_peapv2_tlv_eap_payload(resp);
+			if (resp == NULL)
+				return -1;
+		}
+		if (wpabuf_len(resp) >= 5 &&
+		    wpabuf_head_u8(resp)[0] == EAP_CODE_RESPONSE &&
+		    eap_get_type(resp) == EAP_TYPE_TLV)
+			skip_change2 = 1;
+		rmsg = resp;
+		if (data->peap_version == 0 && !skip_change2) {
+			wpabuf_set(&buf, wpabuf_head_u8(resp) +
+				   sizeof(struct eap_hdr),
+				   wpabuf_len(resp) - sizeof(struct eap_hdr));
+			rmsg = &buf;
+		}
+
+		if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_PEAP,
+					 data->peap_version, req->identifier,
+					 rmsg, out_data)) {
+			wpa_printf(MSG_INFO, "EAP-PEAP: Failed to encrypt "
+				   "a Phase 2 frame");
+		}
+		wpabuf_free(resp);
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf * eap_peap_process(struct eap_sm *sm, void *priv,
+					struct eap_method_ret *ret,
+					const struct wpabuf *reqData)
+{
+	const struct eap_hdr *req;
+	size_t left;
+	int res;
+	u8 flags, id;
+	struct wpabuf *resp;
+	const u8 *pos;
+	struct eap_peap_data *data = priv;
+
+	pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_PEAP, ret,
+					reqData, &left, &flags);
+	if (pos == NULL)
+		return NULL;
+	req = wpabuf_head(reqData);
+	id = req->identifier;
+
+	if (flags & EAP_TLS_FLAGS_START) {
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Start (server ver=%d, own "
+			   "ver=%d)", flags & EAP_TLS_VERSION_MASK,
+			data->peap_version);
+		if ((flags & EAP_TLS_VERSION_MASK) < data->peap_version)
+			data->peap_version = flags & EAP_TLS_VERSION_MASK;
+		if (data->force_peap_version >= 0 &&
+		    data->force_peap_version != data->peap_version) {
+			wpa_printf(MSG_WARNING, "EAP-PEAP: Failed to select "
+				   "forced PEAP version %d",
+				   data->force_peap_version);
+			ret->methodState = METHOD_DONE;
+			ret->decision = DECISION_FAIL;
+			ret->allowNotifications = FALSE;
+			return NULL;
+		}
+		wpa_printf(MSG_DEBUG, "EAP-PEAP: Using PEAP version %d",
+			   data->peap_version);
+		left = 0; /* make sure that this frame is empty, even though it
+			   * should always be, anyway */
+	}
+
+	resp = NULL;
+	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
+	    !data->resuming) {
+		struct wpabuf msg;
+		wpabuf_set(&msg, pos, left);
+		res = eap_peap_decrypt(sm, data, ret, req, &msg, &resp);
+	} else {
+		res = eap_peer_tls_process_helper(sm, &data->ssl,
+						  EAP_TYPE_PEAP,
+						  data->peap_version, id, pos,
+						  left, &resp);
+
+		if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+			char *label;
+			wpa_printf(MSG_DEBUG,
+				   "EAP-PEAP: TLS done, proceed to Phase 2");
+			os_free(data->key_data);
+			/* draft-josefsson-ppext-eap-tls-eap-05.txt
+			 * specifies that PEAPv1 would use "client PEAP
+			 * encryption" as the label. However, most existing
+			 * PEAPv1 implementations seem to be using the old
+			 * label, "client EAP encryption", instead. Use the old
+			 * label by default, but allow it to be configured with
+			 * phase1 parameter peaplabel=1. */
+			if (data->peap_version > 1 || data->force_new_label)
+				label = "client PEAP encryption";
+			else
+				label = "client EAP encryption";
+			wpa_printf(MSG_DEBUG, "EAP-PEAP: using label '%s' in "
+				   "key derivation", label);
+			data->key_data =
+				eap_peer_tls_derive_key(sm, &data->ssl, label,
+							EAP_TLS_KEY_LEN);
+			if (data->key_data) {
+				wpa_hexdump_key(MSG_DEBUG, 
+						"EAP-PEAP: Derived key",
+						data->key_data,
+						EAP_TLS_KEY_LEN);
+			} else {
+				wpa_printf(MSG_DEBUG, "EAP-PEAP: Failed to "
+					   "derive key");
+			}
+
+			if (sm->workaround && data->resuming) {
+				/*
+				 * At least few RADIUS servers (Aegis v1.1.6;
+				 * but not v1.1.4; and Cisco ACS) seem to be
+				 * terminating PEAPv1 (Aegis) or PEAPv0 (Cisco
+				 * ACS) session resumption with outer
+				 * EAP-Success. This does not seem to follow
+				 * draft-josefsson-pppext-eap-tls-eap-05.txt
+				 * section 4.2, so only allow this if EAP
+				 * workarounds are enabled.
+				 */
+				wpa_printf(MSG_DEBUG, "EAP-PEAP: Workaround - "
+					   "allow outer EAP-Success to "
+					   "terminate PEAP resumption");
+				ret->decision = DECISION_COND_SUCC;
+				data->phase2_success = 1;
+			}
+
+			data->resuming = 0;
+		}
+
+		if (res == 2) {
+			struct wpabuf msg;
+			/*
+			 * Application data included in the handshake message.
+			 */
+			wpabuf_free(data->pending_phase2_req);
+			data->pending_phase2_req = resp;
+			resp = NULL;
+			wpabuf_set(&msg, pos, left);
+			res = eap_peap_decrypt(sm, data, ret, req, &msg,
+					       &resp);
+		}
+	}
+
+	if (ret->methodState == METHOD_DONE) {
+		ret->allowNotifications = FALSE;
+	}
+
+	if (res == 1) {
+		wpabuf_free(resp);
+		return eap_peer_tls_build_ack(id, EAP_TYPE_PEAP,
+					      data->peap_version);
+	}
+
+	return resp;
+}
+
+
+static Boolean eap_peap_has_reauth_data(struct eap_sm *sm, void *priv)
+{
+	struct eap_peap_data *data = priv;
+	return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
+		data->phase2_success;
+}
+
+
+static void eap_peap_deinit_for_reauth(struct eap_sm *sm, void *priv)
+{
+	struct eap_peap_data *data = priv;
+	wpabuf_free(data->pending_phase2_req);
+	data->pending_phase2_req = NULL;
+	data->crypto_binding_used = 0;
+}
+
+
+static void * eap_peap_init_for_reauth(struct eap_sm *sm, void *priv)
+{
+	struct eap_peap_data *data = priv;
+	os_free(data->key_data);
+	data->key_data = NULL;
+	if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
+		os_free(data);
+		return NULL;
+	}
+	if (data->phase2_priv && data->phase2_method &&
+	    data->phase2_method->init_for_reauth)
+		data->phase2_method->init_for_reauth(sm, data->phase2_priv);
+	data->phase2_success = 0;
+	data->phase2_eap_success = 0;
+	data->phase2_eap_started = 0;
+	data->resuming = 1;
+	data->reauth = 1;
+	sm->peap_done = FALSE;
+	return priv;
+}
+
+
+static int eap_peap_get_status(struct eap_sm *sm, void *priv, char *buf,
+			       size_t buflen, int verbose)
+{
+	struct eap_peap_data *data = priv;
+	int len, ret;
+
+	len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
+	if (data->phase2_method) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  "EAP-PEAPv%d Phase2 method=%s\n",
+				  data->peap_version,
+				  data->phase2_method->name);
+		if (ret < 0 || (size_t) ret >= buflen - len)
+			return len;
+		len += ret;
+	}
+	return len;
+}
+
+
+static Boolean eap_peap_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_peap_data *data = priv;
+	return data->key_data != NULL && data->phase2_success;
+}
+
+
+static u8 * eap_peap_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_peap_data *data = priv;
+	u8 *key;
+
+	if (data->key_data == NULL || !data->phase2_success)
+		return NULL;
+
+	key = os_malloc(EAP_TLS_KEY_LEN);
+	if (key == NULL)
+		return NULL;
+
+	*len = EAP_TLS_KEY_LEN;
+
+	if (data->crypto_binding_used) {
+		u8 csk[128];
+		/*
+		 * Note: It looks like Microsoft implementation requires null
+		 * termination for this label while the one used for deriving
+		 * IPMK|CMK did not use null termination.
+		 */
+		if (peap_prfplus(data->peap_version, data->ipmk, 40,
+				 "Session Key Generating Function",
+				 (u8 *) "\00", 1, csk, sizeof(csk)) < 0) {
+			os_free(key);
+			return NULL;
+		}
+		wpa_hexdump_key(MSG_DEBUG, "EAP-PEAP: CSK", csk, sizeof(csk));
+		os_memcpy(key, csk, EAP_TLS_KEY_LEN);
+		wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Derived key",
+			    key, EAP_TLS_KEY_LEN);
+	} else
+		os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
+
+	return key;
+}
+
+
+int eap_peer_peap_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+				    EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_peap_init;
+	eap->deinit = eap_peap_deinit;
+	eap->process = eap_peap_process;
+	eap->isKeyAvailable = eap_peap_isKeyAvailable;
+	eap->getKey = eap_peap_getKey;
+	eap->get_status = eap_peap_get_status;
+	eap->has_reauth_data = eap_peap_has_reauth_data;
+	eap->deinit_for_reauth = eap_peap_deinit_for_reauth;
+	eap->init_for_reauth = eap_peap_init_for_reauth;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_tls.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,348 @@
+/*
+ * EAP peer method: EAP-TLS (RFC 2716)
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/tls.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "eap_config.h"
+
+
+static void eap_tls_deinit(struct eap_sm *sm, void *priv);
+
+
+struct eap_tls_data {
+	struct eap_ssl_data ssl;
+	u8 *key_data;
+	void *ssl_ctx;
+	u8 eap_type;
+};
+
+
+static void * eap_tls_init(struct eap_sm *sm)
+{
+	struct eap_tls_data *data;
+	struct eap_peer_config *config = eap_get_config(sm);
+	if (config == NULL ||
+	    ((sm->init_phase2 ? config->private_key2 : config->private_key)
+	     == NULL &&
+	     (sm->init_phase2 ? config->engine2 : config->engine) == 0)) {
+		wpa_printf(MSG_INFO, "EAP-TLS: Private key not configured");
+		return NULL;
+	}
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
+		sm->ssl_ctx;
+
+	if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TLS)) {
+		wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
+		eap_tls_deinit(sm, data);
+		if (config->engine) {
+			wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting Smartcard "
+				   "PIN");
+			eap_sm_request_pin(sm);
+			sm->ignore = TRUE;
+		} else if (config->private_key && !config->private_key_passwd)
+		{
+			wpa_printf(MSG_DEBUG, "EAP-TLS: Requesting private "
+				   "key passphrase");
+			eap_sm_request_passphrase(sm);
+			sm->ignore = TRUE;
+		}
+		return NULL;
+	}
+
+	data->eap_type = EAP_TYPE_TLS;
+
+	return data;
+}
+
+
+#ifdef EAP_UNAUTH_TLS
+static void * eap_unauth_tls_init(struct eap_sm *sm)
+{
+	struct eap_tls_data *data;
+	struct eap_peer_config *config = eap_get_config(sm);
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+
+	data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
+		sm->ssl_ctx;
+
+	if (eap_peer_tls_ssl_init(sm, &data->ssl, config,
+				  EAP_UNAUTH_TLS_TYPE)) {
+		wpa_printf(MSG_INFO, "EAP-TLS: Failed to initialize SSL.");
+		eap_tls_deinit(sm, data);
+		return NULL;
+	}
+
+	data->eap_type = EAP_UNAUTH_TLS_TYPE;
+
+	return data;
+}
+#endif /* EAP_UNAUTH_TLS */
+
+
+static void eap_tls_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_tls_data *data = priv;
+	if (data == NULL)
+		return;
+	eap_peer_tls_ssl_deinit(sm, &data->ssl);
+	os_free(data->key_data);
+	os_free(data);
+}
+
+
+static struct wpabuf * eap_tls_failure(struct eap_sm *sm,
+				       struct eap_tls_data *data,
+				       struct eap_method_ret *ret, int res,
+				       struct wpabuf *resp, u8 id)
+{
+	wpa_printf(MSG_DEBUG, "EAP-TLS: TLS processing failed");
+
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_FAIL;
+
+	if (res == -1) {
+		struct eap_peer_config *config = eap_get_config(sm);
+		if (config) {
+			/*
+			 * The TLS handshake failed. So better forget the old
+			 * PIN. It may be wrong, we cannot be sure but trying
+			 * the wrong one again might block it on the card--so
+			 * better ask the user again.
+			 */
+			os_free(config->pin);
+			config->pin = NULL;
+		}
+	}
+
+	if (resp) {
+		/*
+		 * This is likely an alert message, so send it instead of just
+		 * ACKing the error.
+		 */
+		return resp;
+	}
+
+	return eap_peer_tls_build_ack(id, data->eap_type, 0);
+}
+
+
+static void eap_tls_success(struct eap_sm *sm, struct eap_tls_data *data,
+			    struct eap_method_ret *ret)
+{
+	wpa_printf(MSG_DEBUG, "EAP-TLS: Done");
+
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_UNCOND_SUCC;
+
+	os_free(data->key_data);
+	data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
+						 "client EAP encryption",
+						 EAP_TLS_KEY_LEN +
+						 EAP_EMSK_LEN);
+	if (data->key_data) {
+		wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived key",
+				data->key_data, EAP_TLS_KEY_LEN);
+		wpa_hexdump_key(MSG_DEBUG, "EAP-TLS: Derived EMSK",
+				data->key_data + EAP_TLS_KEY_LEN,
+				EAP_EMSK_LEN);
+	} else {
+		wpa_printf(MSG_INFO, "EAP-TLS: Failed to derive key");
+	}
+}
+
+
+static struct wpabuf * eap_tls_process(struct eap_sm *sm, void *priv,
+				       struct eap_method_ret *ret,
+				       const struct wpabuf *reqData)
+{
+	size_t left;
+	int res;
+	struct wpabuf *resp;
+	u8 flags, id;
+	const u8 *pos;
+	struct eap_tls_data *data = priv;
+
+	pos = eap_peer_tls_process_init(sm, &data->ssl, data->eap_type, ret,
+					reqData, &left, &flags);
+	if (pos == NULL)
+		return NULL;
+	id = eap_get_id(reqData);
+
+	if (flags & EAP_TLS_FLAGS_START) {
+		wpa_printf(MSG_DEBUG, "EAP-TLS: Start");
+		left = 0; /* make sure that this frame is empty, even though it
+			   * should always be, anyway */
+	}
+
+	resp = NULL;
+	res = eap_peer_tls_process_helper(sm, &data->ssl, data->eap_type, 0,
+					  id, pos, left, &resp);
+
+	if (res < 0) {
+		return eap_tls_failure(sm, data, ret, res, resp, id);
+	}
+
+	if (tls_connection_established(data->ssl_ctx, data->ssl.conn))
+		eap_tls_success(sm, data, ret);
+
+	if (res == 1) {
+		wpabuf_free(resp);
+		return eap_peer_tls_build_ack(id, data->eap_type, 0);
+	}
+
+	return resp;
+}
+
+
+static Boolean eap_tls_has_reauth_data(struct eap_sm *sm, void *priv)
+{
+	struct eap_tls_data *data = priv;
+	return tls_connection_established(data->ssl_ctx, data->ssl.conn);
+}
+
+
+static void eap_tls_deinit_for_reauth(struct eap_sm *sm, void *priv)
+{
+}
+
+
+static void * eap_tls_init_for_reauth(struct eap_sm *sm, void *priv)
+{
+	struct eap_tls_data *data = priv;
+	os_free(data->key_data);
+	data->key_data = NULL;
+	if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
+		os_free(data);
+		return NULL;
+	}
+	return priv;
+}
+
+
+static int eap_tls_get_status(struct eap_sm *sm, void *priv, char *buf,
+			      size_t buflen, int verbose)
+{
+	struct eap_tls_data *data = priv;
+	return eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
+}
+
+
+static Boolean eap_tls_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_tls_data *data = priv;
+	return data->key_data != NULL;
+}
+
+
+static u8 * eap_tls_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_tls_data *data = priv;
+	u8 *key;
+
+	if (data->key_data == NULL)
+		return NULL;
+
+	key = os_malloc(EAP_TLS_KEY_LEN);
+	if (key == NULL)
+		return NULL;
+
+	*len = EAP_TLS_KEY_LEN;
+	os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
+
+	return key;
+}
+
+
+static u8 * eap_tls_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_tls_data *data = priv;
+	u8 *key;
+
+	if (data->key_data == NULL)
+		return NULL;
+
+	key = os_malloc(EAP_EMSK_LEN);
+	if (key == NULL)
+		return NULL;
+
+	*len = EAP_EMSK_LEN;
+	os_memcpy(key, data->key_data + EAP_TLS_KEY_LEN, EAP_EMSK_LEN);
+
+	return key;
+}
+
+
+int eap_peer_tls_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+				    EAP_VENDOR_IETF, EAP_TYPE_TLS, "TLS");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_tls_init;
+	eap->deinit = eap_tls_deinit;
+	eap->process = eap_tls_process;
+	eap->isKeyAvailable = eap_tls_isKeyAvailable;
+	eap->getKey = eap_tls_getKey;
+	eap->get_status = eap_tls_get_status;
+	eap->has_reauth_data = eap_tls_has_reauth_data;
+	eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
+	eap->init_for_reauth = eap_tls_init_for_reauth;
+	eap->get_emsk = eap_tls_get_emsk;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}
+
+
+#ifdef EAP_UNAUTH_TLS
+int eap_peer_unauth_tls_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+				    EAP_VENDOR_UNAUTH_TLS,
+				    EAP_VENDOR_TYPE_UNAUTH_TLS, "UNAUTH-TLS");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_unauth_tls_init;
+	eap->deinit = eap_tls_deinit;
+	eap->process = eap_tls_process;
+	eap->isKeyAvailable = eap_tls_isKeyAvailable;
+	eap->getKey = eap_tls_getKey;
+	eap->get_status = eap_tls_get_status;
+	eap->has_reauth_data = eap_tls_has_reauth_data;
+	eap->deinit_for_reauth = eap_tls_deinit_for_reauth;
+	eap->init_for_reauth = eap_tls_init_for_reauth;
+	eap->get_emsk = eap_tls_get_emsk;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}
+#endif /* EAP_UNAUTH_TLS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_tls_common.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,1063 @@
+/*
+ * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/sha1.h"
+#include "crypto/tls.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "eap_config.h"
+
+
+static struct wpabuf * eap_tls_msg_alloc(EapType type, size_t payload_len,
+					 u8 code, u8 identifier)
+{
+	if (type == EAP_UNAUTH_TLS_TYPE)
+		return eap_msg_alloc(EAP_VENDOR_UNAUTH_TLS,
+				     EAP_VENDOR_TYPE_UNAUTH_TLS, payload_len,
+				     code, identifier);
+	return eap_msg_alloc(EAP_VENDOR_IETF, type, payload_len, code,
+			     identifier);
+}
+
+
+static int eap_tls_check_blob(struct eap_sm *sm, const char **name,
+			      const u8 **data, size_t *data_len)
+{
+	const struct wpa_config_blob *blob;
+
+	if (*name == NULL || os_strncmp(*name, "blob://", 7) != 0)
+		return 0;
+
+	blob = eap_get_config_blob(sm, *name + 7);
+	if (blob == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Named configuration blob '%s' not "
+			   "found", __func__, *name + 7);
+		return -1;
+	}
+
+	*name = NULL;
+	*data = blob->data;
+	*data_len = blob->len;
+
+	return 0;
+}
+
+
+static void eap_tls_params_flags(struct tls_connection_params *params,
+				 const char *txt)
+{
+	if (txt == NULL)
+		return;
+	if (os_strstr(txt, "tls_allow_md5=1"))
+		params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5;
+	if (os_strstr(txt, "tls_disable_time_checks=1"))
+		params->flags |= TLS_CONN_DISABLE_TIME_CHECKS;
+	if (os_strstr(txt, "tls_disable_session_ticket=1"))
+		params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
+	if (os_strstr(txt, "tls_disable_session_ticket=0"))
+		params->flags &= ~TLS_CONN_DISABLE_SESSION_TICKET;
+}
+
+
+static void eap_tls_params_from_conf1(struct tls_connection_params *params,
+				      struct eap_peer_config *config)
+{
+	params->ca_cert = (char *) config->ca_cert;
+	params->ca_path = (char *) config->ca_path;
+	params->client_cert = (char *) config->client_cert;
+	params->private_key = (char *) config->private_key;
+	params->private_key_passwd = (char *) config->private_key_passwd;
+	params->dh_file = (char *) config->dh_file;
+	params->subject_match = (char *) config->subject_match;
+	params->altsubject_match = (char *) config->altsubject_match;
+	params->engine = config->engine;
+	params->engine_id = config->engine_id;
+	params->pin = config->pin;
+	params->key_id = config->key_id;
+	params->cert_id = config->cert_id;
+	params->ca_cert_id = config->ca_cert_id;
+	eap_tls_params_flags(params, config->phase1);
+}
+
+
+static void eap_tls_params_from_conf2(struct tls_connection_params *params,
+				      struct eap_peer_config *config)
+{
+	params->ca_cert = (char *) config->ca_cert2;
+	params->ca_path = (char *) config->ca_path2;
+	params->client_cert = (char *) config->client_cert2;
+	params->private_key = (char *) config->private_key2;
+	params->private_key_passwd = (char *) config->private_key2_passwd;
+	params->dh_file = (char *) config->dh_file2;
+	params->subject_match = (char *) config->subject_match2;
+	params->altsubject_match = (char *) config->altsubject_match2;
+	params->engine = config->engine2;
+	params->engine_id = config->engine2_id;
+	params->pin = config->pin2;
+	params->key_id = config->key2_id;
+	params->cert_id = config->cert2_id;
+	params->ca_cert_id = config->ca_cert2_id;
+	eap_tls_params_flags(params, config->phase2);
+}
+
+
+static int eap_tls_params_from_conf(struct eap_sm *sm,
+				    struct eap_ssl_data *data,
+				    struct tls_connection_params *params,
+				    struct eap_peer_config *config, int phase2)
+{
+	os_memset(params, 0, sizeof(*params));
+	if (sm->workaround && data->eap_type != EAP_TYPE_FAST) {
+		/*
+		 * Some deployed authentication servers seem to be unable to
+		 * handle the TLS Session Ticket extension (they are supposed
+		 * to ignore unrecognized TLS extensions, but end up rejecting
+		 * the ClientHello instead). As a workaround, disable use of
+		 * TLS Sesson Ticket extension for EAP-TLS, EAP-PEAP, and
+		 * EAP-TTLS (EAP-FAST uses session ticket, so any server that
+		 * supports EAP-FAST does not need this workaround).
+		 */
+		params->flags |= TLS_CONN_DISABLE_SESSION_TICKET;
+	}
+	if (phase2) {
+		wpa_printf(MSG_DEBUG, "TLS: using phase2 config options");
+		eap_tls_params_from_conf2(params, config);
+	} else {
+		wpa_printf(MSG_DEBUG, "TLS: using phase1 config options");
+		eap_tls_params_from_conf1(params, config);
+	}
+
+	/*
+	 * Use blob data, if available. Otherwise, leave reference to external
+	 * file as-is.
+	 */
+	if (eap_tls_check_blob(sm, &params->ca_cert, &params->ca_cert_blob,
+			       &params->ca_cert_blob_len) ||
+	    eap_tls_check_blob(sm, &params->client_cert,
+			       &params->client_cert_blob,
+			       &params->client_cert_blob_len) ||
+	    eap_tls_check_blob(sm, &params->private_key,
+			       &params->private_key_blob,
+			       &params->private_key_blob_len) ||
+	    eap_tls_check_blob(sm, &params->dh_file, &params->dh_blob,
+			       &params->dh_blob_len)) {
+		wpa_printf(MSG_INFO, "SSL: Failed to get configuration blobs");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int eap_tls_init_connection(struct eap_sm *sm,
+				   struct eap_ssl_data *data,
+				   struct eap_peer_config *config,
+				   struct tls_connection_params *params)
+{
+	int res;
+
+	data->conn = tls_connection_init(data->ssl_ctx);
+	if (data->conn == NULL) {
+		wpa_printf(MSG_INFO, "SSL: Failed to initialize new TLS "
+			   "connection");
+		return -1;
+	}
+
+	res = tls_connection_set_params(data->ssl_ctx, data->conn, params);
+	if (res == TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED) {
+		/*
+		 * At this point with the pkcs11 engine the PIN might be wrong.
+		 * We reset the PIN in the configuration to be sure to not use
+		 * it again and the calling function must request a new one.
+		 */
+		os_free(config->pin);
+		config->pin = NULL;
+	} else if (res == TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load private key");
+		/*
+		 * We do not know exactly but maybe the PIN was wrong,
+		 * so ask for a new one.
+		 */
+		os_free(config->pin);
+		config->pin = NULL;
+		eap_sm_request_pin(sm);
+		sm->ignore = TRUE;
+		tls_connection_deinit(data->ssl_ctx, data->conn);
+		data->conn = NULL;
+		return -1;
+	} else if (res) {
+		wpa_printf(MSG_INFO, "TLS: Failed to set TLS connection "
+			   "parameters");
+		tls_connection_deinit(data->ssl_ctx, data->conn);
+		data->conn = NULL;
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * eap_peer_tls_ssl_init - Initialize shared TLS functionality
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @config: Pointer to the network configuration
+ * @eap_type: EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to initialize shared TLS functionality for EAP-TLS,
+ * EAP-PEAP, EAP-TTLS, and EAP-FAST.
+ */
+int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
+			  struct eap_peer_config *config, u8 eap_type)
+{
+	struct tls_connection_params params;
+
+	if (config == NULL)
+		return -1;
+
+	data->eap = sm;
+	data->eap_type = eap_type;
+	data->phase2 = sm->init_phase2;
+	data->ssl_ctx = sm->init_phase2 && sm->ssl_ctx2 ? sm->ssl_ctx2 :
+		sm->ssl_ctx;
+	if (eap_tls_params_from_conf(sm, data, &params, config, data->phase2) <
+	    0)
+		return -1;
+
+	if (eap_tls_init_connection(sm, data, config, &params) < 0)
+		return -1;
+
+	data->tls_out_limit = config->fragment_size;
+	if (data->phase2) {
+		/* Limit the fragment size in the inner TLS authentication
+		 * since the outer authentication with EAP-PEAP does not yet
+		 * support fragmentation */
+		if (data->tls_out_limit > 100)
+			data->tls_out_limit -= 100;
+	}
+
+	if (config->phase1 &&
+	    os_strstr(config->phase1, "include_tls_length=1")) {
+		wpa_printf(MSG_DEBUG, "TLS: Include TLS Message Length in "
+			   "unfragmented packets");
+		data->include_tls_length = 1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * eap_peer_tls_ssl_deinit - Deinitialize shared TLS functionality
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ *
+ * This function deinitializes shared TLS functionality that was initialized
+ * with eap_peer_tls_ssl_init().
+ */
+void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data)
+{
+	tls_connection_deinit(data->ssl_ctx, data->conn);
+	eap_peer_tls_reset_input(data);
+	eap_peer_tls_reset_output(data);
+}
+
+
+/**
+ * eap_peer_tls_derive_key - Derive a key based on TLS session data
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @label: Label string for deriving the keys, e.g., "client EAP encryption"
+ * @len: Length of the key material to generate (usually 64 for MSK)
+ * Returns: Pointer to allocated key on success or %NULL on failure
+ *
+ * This function uses TLS-PRF to generate pseudo-random data based on the TLS
+ * session data (client/server random and master key). Each key type may use a
+ * different label to bind the key usage into the generated material.
+ *
+ * The caller is responsible for freeing the returned buffer.
+ */
+u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
+			     const char *label, size_t len)
+{
+#ifndef CONFIG_FIPS
+	struct tls_keys keys;
+#endif /* CONFIG_FIPS */
+	u8 *rnd = NULL, *out;
+
+	out = os_malloc(len);
+	if (out == NULL)
+		return NULL;
+
+	/* First, try to use TLS library function for PRF, if available. */
+	if (tls_connection_prf(data->ssl_ctx, data->conn, label, 0, out, len)
+	    == 0)
+		return out;
+
+#ifndef CONFIG_FIPS
+	/*
+	 * TLS library did not support key generation, so get the needed TLS
+	 * session parameters and use an internal implementation of TLS PRF to
+	 * derive the key.
+	 */
+	if (tls_connection_get_keys(data->ssl_ctx, data->conn, &keys))
+		goto fail;
+
+	if (keys.client_random == NULL || keys.server_random == NULL ||
+	    keys.master_key == NULL)
+		goto fail;
+
+	rnd = os_malloc(keys.client_random_len + keys.server_random_len);
+	if (rnd == NULL)
+		goto fail;
+	os_memcpy(rnd, keys.client_random, keys.client_random_len);
+	os_memcpy(rnd + keys.client_random_len, keys.server_random,
+		  keys.server_random_len);
+
+	if (tls_prf_sha1_md5(keys.master_key, keys.master_key_len,
+			     label, rnd, keys.client_random_len +
+			     keys.server_random_len, out, len))
+		goto fail;
+
+	os_free(rnd);
+	return out;
+
+fail:
+#endif /* CONFIG_FIPS */
+	os_free(out);
+	os_free(rnd);
+	return NULL;
+}
+
+
+/**
+ * eap_peer_tls_reassemble_fragment - Reassemble a received fragment
+ * @data: Data for TLS processing
+ * @in_data: Next incoming TLS segment
+ * Returns: 0 on success, 1 if more data is needed for the full message, or
+ * -1 on error
+ */
+static int eap_peer_tls_reassemble_fragment(struct eap_ssl_data *data,
+					    const struct wpabuf *in_data)
+{
+	size_t tls_in_len, in_len;
+
+	tls_in_len = data->tls_in ? wpabuf_len(data->tls_in) : 0;
+	in_len = in_data ? wpabuf_len(in_data) : 0;
+
+	if (tls_in_len + in_len == 0) {
+		/* No message data received?! */
+		wpa_printf(MSG_WARNING, "SSL: Invalid reassembly state: "
+			   "tls_in_left=%lu tls_in_len=%lu in_len=%lu",
+			   (unsigned long) data->tls_in_left,
+			   (unsigned long) tls_in_len,
+			   (unsigned long) in_len);
+		eap_peer_tls_reset_input(data);
+		return -1;
+	}
+
+	if (tls_in_len + in_len > 65536) {
+		/*
+		 * Limit length to avoid rogue servers from causing large
+		 * memory allocations.
+		 */
+		wpa_printf(MSG_INFO, "SSL: Too long TLS fragment (size over "
+			   "64 kB)");
+		eap_peer_tls_reset_input(data);
+		return -1;
+	}
+
+	if (in_len > data->tls_in_left) {
+		/* Sender is doing something odd - reject message */
+		wpa_printf(MSG_INFO, "SSL: more data than TLS message length "
+			   "indicated");
+		eap_peer_tls_reset_input(data);
+		return -1;
+	}
+
+	if (wpabuf_resize(&data->tls_in, in_len) < 0) {
+		wpa_printf(MSG_INFO, "SSL: Could not allocate memory for TLS "
+			   "data");
+		eap_peer_tls_reset_input(data);
+		return -1;
+	}
+	if (in_data)
+		wpabuf_put_buf(data->tls_in, in_data);
+	data->tls_in_left -= in_len;
+
+	if (data->tls_in_left > 0) {
+		wpa_printf(MSG_DEBUG, "SSL: Need %lu bytes more input "
+			   "data", (unsigned long) data->tls_in_left);
+		return 1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * eap_peer_tls_data_reassemble - Reassemble TLS data
+ * @data: Data for TLS processing
+ * @in_data: Next incoming TLS segment
+ * @need_more_input: Variable for returning whether more input data is needed
+ * to reassemble this TLS packet
+ * Returns: Pointer to output data, %NULL on error or when more data is needed
+ * for the full message (in which case, *need_more_input is also set to 1).
+ *
+ * This function reassembles TLS fragments. Caller must not free the returned
+ * data buffer since an internal pointer to it is maintained.
+ */
+static const struct wpabuf * eap_peer_tls_data_reassemble(
+	struct eap_ssl_data *data, const struct wpabuf *in_data,
+	int *need_more_input)
+{
+	*need_more_input = 0;
+
+	if (data->tls_in_left > wpabuf_len(in_data) || data->tls_in) {
+		/* Message has fragments */
+		int res = eap_peer_tls_reassemble_fragment(data, in_data);
+		if (res) {
+			if (res == 1)
+				*need_more_input = 1;
+			return NULL;
+		}
+
+		/* Message is now fully reassembled. */
+	} else {
+		/* No fragments in this message, so just make a copy of it. */
+		data->tls_in_left = 0;
+		data->tls_in = wpabuf_dup(in_data);
+		if (data->tls_in == NULL)
+			return NULL;
+	}
+
+	return data->tls_in;
+}
+
+
+/**
+ * eap_tls_process_input - Process incoming TLS message
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @in_data: Message received from the server
+ * @in_len: Length of in_data
+ * @out_data: Buffer for returning a pointer to application data (if available)
+ * Returns: 0 on success, 1 if more input data is needed, 2 if application data
+ * is available, -1 on failure
+ */
+static int eap_tls_process_input(struct eap_sm *sm, struct eap_ssl_data *data,
+				 const u8 *in_data, size_t in_len,
+				 struct wpabuf **out_data)
+{
+	const struct wpabuf *msg;
+	int need_more_input;
+	struct wpabuf *appl_data;
+	struct wpabuf buf;
+
+	wpabuf_set(&buf, in_data, in_len);
+	msg = eap_peer_tls_data_reassemble(data, &buf, &need_more_input);
+	if (msg == NULL)
+		return need_more_input ? 1 : -1;
+
+	/* Full TLS message reassembled - continue handshake processing */
+	if (data->tls_out) {
+		/* This should not happen.. */
+		wpa_printf(MSG_INFO, "SSL: eap_tls_process_input - pending "
+			   "tls_out data even though tls_out_len = 0");
+		wpabuf_free(data->tls_out);
+		WPA_ASSERT(data->tls_out == NULL);
+	}
+	appl_data = NULL;
+	data->tls_out = tls_connection_handshake(data->ssl_ctx, data->conn,
+						 msg, &appl_data);
+
+	eap_peer_tls_reset_input(data);
+
+	if (appl_data &&
+	    tls_connection_established(data->ssl_ctx, data->conn) &&
+	    !tls_connection_get_failed(data->ssl_ctx, data->conn)) {
+		wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application data",
+				    appl_data);
+		*out_data = appl_data;
+		return 2;
+	}
+
+	wpabuf_free(appl_data);
+
+	return 0;
+}
+
+
+/**
+ * eap_tls_process_output - Process outgoing TLS message
+ * @data: Data for TLS processing
+ * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
+ * @peap_version: Version number for EAP-PEAP/TTLS
+ * @id: EAP identifier for the response
+ * @ret: Return value to use on success
+ * @out_data: Buffer for returning the allocated output buffer
+ * Returns: ret (0 or 1) on success, -1 on failure
+ */
+static int eap_tls_process_output(struct eap_ssl_data *data, EapType eap_type,
+				  int peap_version, u8 id, int ret,
+				  struct wpabuf **out_data)
+{
+	size_t len;
+	u8 *flags;
+	int more_fragments, length_included;
+
+	if (data->tls_out == NULL)
+		return -1;
+	len = wpabuf_len(data->tls_out) - data->tls_out_pos;
+	wpa_printf(MSG_DEBUG, "SSL: %lu bytes left to be sent out (of total "
+		   "%lu bytes)",
+		   (unsigned long) len,
+		   (unsigned long) wpabuf_len(data->tls_out));
+
+	/*
+	 * Limit outgoing message to the configured maximum size. Fragment
+	 * message if needed.
+	 */
+	if (len > data->tls_out_limit) {
+		more_fragments = 1;
+		len = data->tls_out_limit;
+		wpa_printf(MSG_DEBUG, "SSL: sending %lu bytes, more fragments "
+			   "will follow", (unsigned long) len);
+	} else
+		more_fragments = 0;
+
+	length_included = data->tls_out_pos == 0 &&
+		(wpabuf_len(data->tls_out) > data->tls_out_limit ||
+		 data->include_tls_length);
+	if (!length_included &&
+	    eap_type == EAP_TYPE_PEAP && peap_version == 0 &&
+	    !tls_connection_established(data->eap->ssl_ctx, data->conn)) {
+		/*
+		 * Windows Server 2008 NPS really wants to have the TLS Message
+		 * length included in phase 0 even for unfragmented frames or
+		 * it will get very confused with Compound MAC calculation and
+		 * Outer TLVs.
+		 */
+		length_included = 1;
+	}
+
+	*out_data = eap_tls_msg_alloc(eap_type, 1 + length_included * 4 + len,
+				      EAP_CODE_RESPONSE, id);
+	if (*out_data == NULL)
+		return -1;
+
+	flags = wpabuf_put(*out_data, 1);
+	*flags = peap_version;
+	if (more_fragments)
+		*flags |= EAP_TLS_FLAGS_MORE_FRAGMENTS;
+	if (length_included) {
+		*flags |= EAP_TLS_FLAGS_LENGTH_INCLUDED;
+		wpabuf_put_be32(*out_data, wpabuf_len(data->tls_out));
+	}
+
+	wpabuf_put_data(*out_data,
+			wpabuf_head_u8(data->tls_out) + data->tls_out_pos,
+			len);
+	data->tls_out_pos += len;
+
+	if (!more_fragments)
+		eap_peer_tls_reset_output(data);
+
+	return ret;
+}
+
+
+/**
+ * eap_peer_tls_process_helper - Process TLS handshake message
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
+ * @peap_version: Version number for EAP-PEAP/TTLS
+ * @id: EAP identifier for the response
+ * @in_data: Message received from the server
+ * @in_len: Length of in_data
+ * @out_data: Buffer for returning a pointer to the response message
+ * Returns: 0 on success, 1 if more input data is needed, 2 if application data
+ * is available, or -1 on failure
+ *
+ * This function can be used to process TLS handshake messages. It reassembles
+ * the received fragments and uses a TLS library to process the messages. The
+ * response data from the TLS library is fragmented to suitable output messages
+ * that the caller can send out.
+ *
+ * out_data is used to return the response message if the return value of this
+ * function is 0, 2, or -1. In case of failure, the message is likely a TLS
+ * alarm message. The caller is responsible for freeing the allocated buffer if
+ * *out_data is not %NULL.
+ *
+ * This function is called for each received TLS message during the TLS
+ * handshake after eap_peer_tls_process_init() call and possible processing of
+ * TLS Flags field. Once the handshake has been completed, i.e., when
+ * tls_connection_established() returns 1, EAP method specific decrypting of
+ * the tunneled data is used.
+ */
+int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
+				EapType eap_type, int peap_version,
+				u8 id, const u8 *in_data, size_t in_len,
+				struct wpabuf **out_data)
+{
+	int ret = 0;
+
+	*out_data = NULL;
+
+	if (data->tls_out && wpabuf_len(data->tls_out) > 0 && in_len > 0) {
+		wpa_printf(MSG_DEBUG, "SSL: Received non-ACK when output "
+			   "fragments are waiting to be sent out");
+		return -1;
+	}
+
+	if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) {
+		/*
+		 * No more data to send out - expect to receive more data from
+		 * the AS.
+		 */
+		int res = eap_tls_process_input(sm, data, in_data, in_len,
+						out_data);
+		if (res) {
+			/*
+			 * Input processing failed (res = -1) or more data is
+			 * needed (res = 1).
+			 */
+			return res;
+		}
+
+		/*
+		 * The incoming message has been reassembled and processed. The
+		 * response was allocated into data->tls_out buffer.
+		 */
+	}
+
+	if (data->tls_out == NULL) {
+		/*
+		 * No outgoing fragments remaining from the previous message
+		 * and no new message generated. This indicates an error in TLS
+		 * processing.
+		 */
+		eap_peer_tls_reset_output(data);
+		return -1;
+	}
+
+	if (tls_connection_get_failed(data->ssl_ctx, data->conn)) {
+		/* TLS processing has failed - return error */
+		wpa_printf(MSG_DEBUG, "SSL: Failed - tls_out available to "
+			   "report error");
+		ret = -1;
+		/* TODO: clean pin if engine used? */
+	}
+
+	if (data->tls_out == NULL || wpabuf_len(data->tls_out) == 0) {
+		/*
+		 * TLS negotiation should now be complete since all other cases
+		 * needing more data should have been caught above based on
+		 * the TLS Message Length field.
+		 */
+		wpa_printf(MSG_DEBUG, "SSL: No data to be sent out");
+		wpabuf_free(data->tls_out);
+		data->tls_out = NULL;
+		return 1;
+	}
+
+	/* Send the pending message (in fragments, if needed). */
+	return eap_tls_process_output(data, eap_type, peap_version, id, ret,
+				      out_data);
+}
+
+
+/**
+ * eap_peer_tls_build_ack - Build a TLS ACK frame
+ * @id: EAP identifier for the response
+ * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
+ * @peap_version: Version number for EAP-PEAP/TTLS
+ * Returns: Pointer to the allocated ACK frame or %NULL on failure
+ */
+struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
+				       int peap_version)
+{
+	struct wpabuf *resp;
+
+	resp = eap_tls_msg_alloc(eap_type, 1, EAP_CODE_RESPONSE, id);
+	if (resp == NULL)
+		return NULL;
+	wpa_printf(MSG_DEBUG, "SSL: Building ACK (type=%d id=%d ver=%d)",
+		   (int) eap_type, id, peap_version);
+	wpabuf_put_u8(resp, peap_version); /* Flags */
+	return resp;
+}
+
+
+/**
+ * eap_peer_tls_reauth_init - Re-initialize shared TLS for session resumption
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data)
+{
+	eap_peer_tls_reset_input(data);
+	eap_peer_tls_reset_output(data);
+	return tls_connection_shutdown(data->ssl_ctx, data->conn);
+}
+
+
+/**
+ * eap_peer_tls_status - Get TLS status
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @buf: Buffer for status information
+ * @buflen: Maximum buffer length
+ * @verbose: Whether to include verbose status information
+ * Returns: Number of bytes written to buf.
+ */
+int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
+			char *buf, size_t buflen, int verbose)
+{
+	char name[128];
+	int len = 0, ret;
+
+	if (tls_get_cipher(data->ssl_ctx, data->conn, name, sizeof(name)) == 0)
+	{
+		ret = os_snprintf(buf + len, buflen - len,
+				  "EAP TLS cipher=%s\n", name);
+		if (ret < 0 || (size_t) ret >= buflen - len)
+			return len;
+		len += ret;
+	}
+
+	return len;
+}
+
+
+/**
+ * eap_peer_tls_process_init - Initial validation/processing of EAP requests
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
+ * @ret: Return values from EAP request validation and processing
+ * @reqData: EAP request to be processed (eapReqData)
+ * @len: Buffer for returning length of the remaining payload
+ * @flags: Buffer for returning TLS flags
+ * Returns: Pointer to payload after TLS flags and length or %NULL on failure
+ *
+ * This function validates the EAP header and processes the optional TLS
+ * Message Length field. If this is the first fragment of a TLS message, the
+ * TLS reassembly code is initialized to receive the indicated number of bytes.
+ *
+ * EAP-TLS, EAP-PEAP, EAP-TTLS, and EAP-FAST methods are expected to use this
+ * function as the first step in processing received messages. They will need
+ * to process the flags (apart from Message Length Included) that are returned
+ * through the flags pointer and the message payload that will be returned (and
+ * the length is returned through the len pointer). Return values (ret) are set
+ * for continuation of EAP method processing. The caller is responsible for
+ * setting these to indicate completion (either success or failure) based on
+ * the authentication result.
+ */
+const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
+				     struct eap_ssl_data *data,
+				     EapType eap_type,
+				     struct eap_method_ret *ret,
+				     const struct wpabuf *reqData,
+				     size_t *len, u8 *flags)
+{
+	const u8 *pos;
+	size_t left;
+	unsigned int tls_msg_len;
+
+	if (tls_get_errors(data->ssl_ctx)) {
+		wpa_printf(MSG_INFO, "SSL: TLS errors detected");
+		ret->ignore = TRUE;
+		return NULL;
+	}
+
+	if (eap_type == EAP_UNAUTH_TLS_TYPE)
+		pos = eap_hdr_validate(EAP_VENDOR_UNAUTH_TLS,
+				       EAP_VENDOR_TYPE_UNAUTH_TLS, reqData,
+				       &left);
+	else
+		pos = eap_hdr_validate(EAP_VENDOR_IETF, eap_type, reqData,
+				       &left);
+	if (pos == NULL) {
+		ret->ignore = TRUE;
+		return NULL;
+	}
+	if (left == 0) {
+		wpa_printf(MSG_DEBUG, "SSL: Invalid TLS message: no Flags "
+			   "octet included");
+		if (!sm->workaround) {
+			ret->ignore = TRUE;
+			return NULL;
+		}
+
+		wpa_printf(MSG_DEBUG, "SSL: Workaround - assume no Flags "
+			   "indicates ACK frame");
+		*flags = 0;
+	} else {
+		*flags = *pos++;
+		left--;
+	}
+	wpa_printf(MSG_DEBUG, "SSL: Received packet(len=%lu) - "
+		   "Flags 0x%02x", (unsigned long) wpabuf_len(reqData),
+		   *flags);
+	if (*flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
+		if (left < 4) {
+			wpa_printf(MSG_INFO, "SSL: Short frame with TLS "
+				   "length");
+			ret->ignore = TRUE;
+			return NULL;
+		}
+		tls_msg_len = WPA_GET_BE32(pos);
+		wpa_printf(MSG_DEBUG, "SSL: TLS Message Length: %d",
+			   tls_msg_len);
+		if (data->tls_in_left == 0) {
+			data->tls_in_total = tls_msg_len;
+			data->tls_in_left = tls_msg_len;
+			wpabuf_free(data->tls_in);
+			data->tls_in = NULL;
+		}
+		pos += 4;
+		left -= 4;
+
+		if (left > tls_msg_len) {
+			wpa_printf(MSG_INFO, "SSL: TLS Message Length (%d "
+				   "bytes) smaller than this fragment (%d "
+				   "bytes)", (int) tls_msg_len, (int) left);
+			ret->ignore = TRUE;
+			return NULL;
+		}
+	}
+
+	ret->ignore = FALSE;
+	ret->methodState = METHOD_MAY_CONT;
+	ret->decision = DECISION_FAIL;
+	ret->allowNotifications = TRUE;
+
+	*len = left;
+	return pos;
+}
+
+
+/**
+ * eap_peer_tls_reset_input - Reset input buffers
+ * @data: Data for TLS processing
+ *
+ * This function frees any allocated memory for input buffers and resets input
+ * state.
+ */
+void eap_peer_tls_reset_input(struct eap_ssl_data *data)
+{
+	data->tls_in_left = data->tls_in_total = 0;
+	wpabuf_free(data->tls_in);
+	data->tls_in = NULL;
+}
+
+
+/**
+ * eap_peer_tls_reset_output - Reset output buffers
+ * @data: Data for TLS processing
+ *
+ * This function frees any allocated memory for output buffers and resets
+ * output state.
+ */
+void eap_peer_tls_reset_output(struct eap_ssl_data *data)
+{
+	data->tls_out_pos = 0;
+	wpabuf_free(data->tls_out);
+	data->tls_out = NULL;
+}
+
+
+/**
+ * eap_peer_tls_decrypt - Decrypt received phase 2 TLS message
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @in_data: Message received from the server
+ * @in_decrypted: Buffer for returning a pointer to the decrypted message
+ * Returns: 0 on success, 1 if more input data is needed, or -1 on failure
+ */
+int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,
+			 const struct wpabuf *in_data,
+			 struct wpabuf **in_decrypted)
+{
+	const struct wpabuf *msg;
+	int need_more_input;
+
+	msg = eap_peer_tls_data_reassemble(data, in_data, &need_more_input);
+	if (msg == NULL)
+		return need_more_input ? 1 : -1;
+
+	*in_decrypted = tls_connection_decrypt(data->ssl_ctx, data->conn, msg);
+	eap_peer_tls_reset_input(data);
+	if (*in_decrypted == NULL) {
+		wpa_printf(MSG_INFO, "SSL: Failed to decrypt Phase 2 data");
+		return -1;
+	}
+	return 0;
+}
+
+
+/**
+ * eap_peer_tls_encrypt - Encrypt phase 2 TLS message
+ * @sm: Pointer to EAP state machine allocated with eap_peer_sm_init()
+ * @data: Data for TLS processing
+ * @eap_type: EAP type (EAP_TYPE_TLS, EAP_TYPE_PEAP, ...)
+ * @peap_version: Version number for EAP-PEAP/TTLS
+ * @id: EAP identifier for the response
+ * @in_data: Plaintext phase 2 data to encrypt or %NULL to continue fragments
+ * @out_data: Buffer for returning a pointer to the encrypted response message
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
+			 EapType eap_type, int peap_version, u8 id,
+			 const struct wpabuf *in_data,
+			 struct wpabuf **out_data)
+{
+	if (in_data) {
+		eap_peer_tls_reset_output(data);
+		data->tls_out = tls_connection_encrypt(data->ssl_ctx,
+						       data->conn, in_data);
+		if (data->tls_out == NULL) {
+			wpa_printf(MSG_INFO, "SSL: Failed to encrypt Phase 2 "
+				   "data (in_len=%lu)",
+				   (unsigned long) wpabuf_len(in_data));
+			eap_peer_tls_reset_output(data);
+			return -1;
+		}
+	}
+
+	return eap_tls_process_output(data, eap_type, peap_version, id, 0,
+				      out_data);
+}
+
+
+/**
+ * eap_peer_select_phase2_methods - Select phase 2 EAP method
+ * @config: Pointer to the network configuration
+ * @prefix: 'phase2' configuration prefix, e.g., "auth="
+ * @types: Buffer for returning allocated list of allowed EAP methods
+ * @num_types: Buffer for returning number of allocated EAP methods
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to parse EAP method list and select allowed methods
+ * for Phase2 authentication.
+ */
+int eap_peer_select_phase2_methods(struct eap_peer_config *config,
+				   const char *prefix,
+				   struct eap_method_type **types,
+				   size_t *num_types)
+{
+	char *start, *pos, *buf;
+	struct eap_method_type *methods = NULL, *_methods;
+	u8 method;
+	size_t num_methods = 0, prefix_len;
+
+	if (config == NULL || config->phase2 == NULL)
+		goto get_defaults;
+
+	start = buf = os_strdup(config->phase2);
+	if (buf == NULL)
+		return -1;
+
+	prefix_len = os_strlen(prefix);
+
+	while (start && *start != '\0') {
+		int vendor;
+		pos = os_strstr(start, prefix);
+		if (pos == NULL)
+			break;
+		if (start != pos && *(pos - 1) != ' ') {
+			start = pos + prefix_len;
+			continue;
+		}
+
+		start = pos + prefix_len;
+		pos = os_strchr(start, ' ');
+		if (pos)
+			*pos++ = '\0';
+		method = eap_get_phase2_type(start, &vendor);
+		if (vendor == EAP_VENDOR_IETF && method == EAP_TYPE_NONE) {
+			wpa_printf(MSG_ERROR, "TLS: Unsupported Phase2 EAP "
+				   "method '%s'", start);
+		} else {
+			num_methods++;
+			_methods = os_realloc_array(methods, num_methods,
+						    sizeof(*methods));
+			if (_methods == NULL) {
+				os_free(methods);
+				os_free(buf);
+				return -1;
+			}
+			methods = _methods;
+			methods[num_methods - 1].vendor = vendor;
+			methods[num_methods - 1].method = method;
+		}
+
+		start = pos;
+	}
+
+	os_free(buf);
+
+get_defaults:
+	if (methods == NULL)
+		methods = eap_get_phase2_types(config, &num_methods);
+
+	if (methods == NULL) {
+		wpa_printf(MSG_ERROR, "TLS: No Phase2 EAP methods available");
+		return -1;
+	}
+	wpa_hexdump(MSG_DEBUG, "TLS: Phase2 EAP types",
+		    (u8 *) methods,
+		    num_methods * sizeof(struct eap_method_type));
+
+	*types = methods;
+	*num_types = num_methods;
+
+	return 0;
+}
+
+
+/**
+ * eap_peer_tls_phase2_nak - Generate EAP-Nak for Phase 2
+ * @types: Buffer for returning allocated list of allowed EAP methods
+ * @num_types: Buffer for returning number of allocated EAP methods
+ * @hdr: EAP-Request header (and the following EAP type octet)
+ * @resp: Buffer for returning the EAP-Nak message
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,
+			    struct eap_hdr *hdr, struct wpabuf **resp)
+{
+	u8 *pos = (u8 *) (hdr + 1);
+	size_t i;
+
+	/* TODO: add support for expanded Nak */
+	wpa_printf(MSG_DEBUG, "TLS: Phase 2 Request: Nak type=%d", *pos);
+	wpa_hexdump(MSG_DEBUG, "TLS: Allowed Phase2 EAP types",
+		    (u8 *) types, num_types * sizeof(struct eap_method_type));
+	*resp = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_NAK, num_types,
+			      EAP_CODE_RESPONSE, hdr->identifier);
+	if (*resp == NULL)
+		return -1;
+
+	for (i = 0; i < num_types; i++) {
+		if (types[i].vendor == EAP_VENDOR_IETF &&
+		    types[i].method < 256)
+			wpabuf_put_u8(*resp, types[i].method);
+	}
+
+	eap_update_len(*resp);
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_tls_common.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,128 @@
+/*
+ * EAP peer: EAP-TLS/PEAP/TTLS/FAST common functions
+ * Copyright (c) 2004-2009, 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_TLS_COMMON_H
+#define EAP_TLS_COMMON_H
+
+/**
+ * struct eap_ssl_data - TLS data for EAP methods
+ */
+struct eap_ssl_data {
+	/**
+	 * conn - TLS connection context data from tls_connection_init()
+	 */
+	struct tls_connection *conn;
+
+	/**
+	 * tls_out - TLS message to be sent out in fragments
+	 */
+	struct wpabuf *tls_out;
+
+	/**
+	 * tls_out_pos - The current position in the outgoing TLS message
+	 */
+	size_t tls_out_pos;
+
+	/**
+	 * tls_out_limit - Maximum fragment size for outgoing TLS messages
+	 */
+	size_t tls_out_limit;
+
+	/**
+	 * tls_in - Received TLS message buffer for re-assembly
+	 */
+	struct wpabuf *tls_in;
+
+	/**
+	 * tls_in_left - Number of remaining bytes in the incoming TLS message
+	 */
+	size_t tls_in_left;
+
+	/**
+	 * tls_in_total - Total number of bytes in the incoming TLS message
+	 */
+	size_t tls_in_total;
+
+	/**
+	 * phase2 - Whether this TLS connection is used in EAP phase 2 (tunnel)
+	 */
+	int phase2;
+
+	/**
+	 * include_tls_length - Whether the TLS length field is included even
+	 * if the TLS data is not fragmented
+	 */
+	int include_tls_length;
+
+	/**
+	 * eap - EAP state machine allocated with eap_peer_sm_init()
+	 */
+	struct eap_sm *eap;
+
+	/**
+	 * ssl_ctx - TLS library context to use for the connection
+	 */
+	void *ssl_ctx;
+
+	/**
+	 * eap_type - EAP method used in Phase 1 (EAP_TYPE_TLS/PEAP/TTLS/FAST)
+	 */
+	u8 eap_type;
+};
+
+
+/* EAP TLS Flags */
+#define EAP_TLS_FLAGS_LENGTH_INCLUDED 0x80
+#define EAP_TLS_FLAGS_MORE_FRAGMENTS 0x40
+#define EAP_TLS_FLAGS_START 0x20
+#define EAP_TLS_VERSION_MASK 0x07
+
+ /* could be up to 128 bytes, but only the first 64 bytes are used */
+#define EAP_TLS_KEY_LEN 64
+
+/* dummy type used as a flag for UNAUTH-TLS */
+#define EAP_UNAUTH_TLS_TYPE 255
+
+
+int eap_peer_tls_ssl_init(struct eap_sm *sm, struct eap_ssl_data *data,
+			  struct eap_peer_config *config, u8 eap_type);
+void eap_peer_tls_ssl_deinit(struct eap_sm *sm, struct eap_ssl_data *data);
+u8 * eap_peer_tls_derive_key(struct eap_sm *sm, struct eap_ssl_data *data,
+			     const char *label, size_t len);
+int eap_peer_tls_process_helper(struct eap_sm *sm, struct eap_ssl_data *data,
+				EapType eap_type, int peap_version,
+				u8 id, const u8 *in_data, size_t in_len,
+				struct wpabuf **out_data);
+struct wpabuf * eap_peer_tls_build_ack(u8 id, EapType eap_type,
+				       int peap_version);
+int eap_peer_tls_reauth_init(struct eap_sm *sm, struct eap_ssl_data *data);
+int eap_peer_tls_status(struct eap_sm *sm, struct eap_ssl_data *data,
+			char *buf, size_t buflen, int verbose);
+const u8 * eap_peer_tls_process_init(struct eap_sm *sm,
+				     struct eap_ssl_data *data,
+				     EapType eap_type,
+				     struct eap_method_ret *ret,
+				     const struct wpabuf *reqData,
+				     size_t *len, u8 *flags);
+void eap_peer_tls_reset_input(struct eap_ssl_data *data);
+void eap_peer_tls_reset_output(struct eap_ssl_data *data);
+int eap_peer_tls_decrypt(struct eap_sm *sm, struct eap_ssl_data *data,
+			 const struct wpabuf *in_data,
+			 struct wpabuf **in_decrypted);
+int eap_peer_tls_encrypt(struct eap_sm *sm, struct eap_ssl_data *data,
+			 EapType eap_type, int peap_version, u8 id,
+			 const struct wpabuf *in_data,
+			 struct wpabuf **out_data);
+int eap_peer_select_phase2_methods(struct eap_peer_config *config,
+				   const char *prefix,
+				   struct eap_method_type **types,
+				   size_t *num_types);
+int eap_peer_tls_phase2_nak(struct eap_method_type *types, size_t num_types,
+			    struct eap_hdr *hdr, struct wpabuf **resp);
+
+#endif /* EAP_TLS_COMMON_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/eap_ttls.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,1639 @@
+/*
+ * EAP peer method: EAP-TTLS (RFC 5281)
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/ms_funcs.h"
+#include "crypto/sha1.h"
+#include "crypto/tls.h"
+#include "eap_common/chap.h"
+#include "eap_common/eap_ttls.h"
+#include "mschapv2.h"
+#include "eap_i.h"
+#include "eap_tls_common.h"
+#include "eap_config.h"
+
+
+#define EAP_TTLS_VERSION 0
+
+
+static void eap_ttls_deinit(struct eap_sm *sm, void *priv);
+
+
+struct eap_ttls_data {
+	struct eap_ssl_data ssl;
+
+	int ttls_version;
+
+	const struct eap_method *phase2_method;
+	void *phase2_priv;
+	int phase2_success;
+	int phase2_start;
+
+	enum phase2_types {
+		EAP_TTLS_PHASE2_EAP,
+		EAP_TTLS_PHASE2_MSCHAPV2,
+		EAP_TTLS_PHASE2_MSCHAP,
+		EAP_TTLS_PHASE2_PAP,
+		EAP_TTLS_PHASE2_CHAP
+	} phase2_type;
+	struct eap_method_type phase2_eap_type;
+	struct eap_method_type *phase2_eap_types;
+	size_t num_phase2_eap_types;
+
+	u8 auth_response[MSCHAPV2_AUTH_RESPONSE_LEN];
+	int auth_response_valid;
+	u8 master_key[MSCHAPV2_MASTER_KEY_LEN]; /* MSCHAPv2 master key */
+	u8 ident;
+	int resuming; /* starting a resumed session */
+	int reauth; /* reauthentication */
+	u8 *key_data;
+
+	struct wpabuf *pending_phase2_req;
+
+#ifdef EAP_TNC
+	int ready_for_tnc;
+	int tnc_started;
+#endif /* EAP_TNC */
+};
+
+
+static void * eap_ttls_init(struct eap_sm *sm)
+{
+	struct eap_ttls_data *data;
+	struct eap_peer_config *config = eap_get_config(sm);
+	char *selected;
+
+	data = os_zalloc(sizeof(*data));
+	if (data == NULL)
+		return NULL;
+	data->ttls_version = EAP_TTLS_VERSION;
+	selected = "EAP";
+	data->phase2_type = EAP_TTLS_PHASE2_EAP;
+
+	if (config && config->phase2) {
+		if (os_strstr(config->phase2, "autheap=")) {
+			selected = "EAP";
+			data->phase2_type = EAP_TTLS_PHASE2_EAP;
+		} else if (os_strstr(config->phase2, "auth=MSCHAPV2")) {
+			selected = "MSCHAPV2";
+			data->phase2_type = EAP_TTLS_PHASE2_MSCHAPV2;
+		} else if (os_strstr(config->phase2, "auth=MSCHAP")) {
+			selected = "MSCHAP";
+			data->phase2_type = EAP_TTLS_PHASE2_MSCHAP;
+		} else if (os_strstr(config->phase2, "auth=PAP")) {
+			selected = "PAP";
+			data->phase2_type = EAP_TTLS_PHASE2_PAP;
+		} else if (os_strstr(config->phase2, "auth=CHAP")) {
+			selected = "CHAP";
+			data->phase2_type = EAP_TTLS_PHASE2_CHAP;
+		}
+	}
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase2 type: %s", selected);
+
+	if (data->phase2_type == EAP_TTLS_PHASE2_EAP) {
+		if (eap_peer_select_phase2_methods(config, "autheap=",
+						   &data->phase2_eap_types,
+						   &data->num_phase2_eap_types)
+		    < 0) {
+			eap_ttls_deinit(sm, data);
+			return NULL;
+		}
+
+		data->phase2_eap_type.vendor = EAP_VENDOR_IETF;
+		data->phase2_eap_type.method = EAP_TYPE_NONE;
+	}
+
+	if (eap_peer_tls_ssl_init(sm, &data->ssl, config, EAP_TYPE_TTLS)) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to initialize SSL.");
+		eap_ttls_deinit(sm, data);
+		return NULL;
+	}
+
+	return data;
+}
+
+
+static void eap_ttls_phase2_eap_deinit(struct eap_sm *sm,
+				       struct eap_ttls_data *data)
+{
+	if (data->phase2_priv && data->phase2_method) {
+		data->phase2_method->deinit(sm, data->phase2_priv);
+		data->phase2_method = NULL;
+		data->phase2_priv = NULL;
+	}
+}
+
+
+static void eap_ttls_deinit(struct eap_sm *sm, void *priv)
+{
+	struct eap_ttls_data *data = priv;
+	if (data == NULL)
+		return;
+	eap_ttls_phase2_eap_deinit(sm, data);
+	os_free(data->phase2_eap_types);
+	eap_peer_tls_ssl_deinit(sm, &data->ssl);
+	os_free(data->key_data);
+	wpabuf_free(data->pending_phase2_req);
+	os_free(data);
+}
+
+
+static u8 * eap_ttls_avp_hdr(u8 *avphdr, u32 avp_code, u32 vendor_id,
+			     int mandatory, size_t len)
+{
+	struct ttls_avp_vendor *avp;
+	u8 flags;
+	size_t hdrlen;
+
+	avp = (struct ttls_avp_vendor *) avphdr;
+	flags = mandatory ? AVP_FLAGS_MANDATORY : 0;
+	if (vendor_id) {
+		flags |= AVP_FLAGS_VENDOR;
+		hdrlen = sizeof(*avp);
+		avp->vendor_id = host_to_be32(vendor_id);
+	} else {
+		hdrlen = sizeof(struct ttls_avp);
+	}
+
+	avp->avp_code = host_to_be32(avp_code);
+	avp->avp_length = host_to_be32((flags << 24) | (u32) (hdrlen + len));
+
+	return avphdr + hdrlen;
+}
+
+
+static u8 * eap_ttls_avp_add(u8 *start, u8 *avphdr, u32 avp_code,
+			     u32 vendor_id, int mandatory,
+			     const u8 *data, size_t len)
+{
+	u8 *pos;
+	pos = eap_ttls_avp_hdr(avphdr, avp_code, vendor_id, mandatory, len);
+	os_memcpy(pos, data, len);
+	pos += len;
+	AVP_PAD(start, pos);
+	return pos;
+}
+
+
+static int eap_ttls_avp_encapsulate(struct wpabuf **resp, u32 avp_code,
+				    int mandatory)
+{
+	struct wpabuf *msg;
+	u8 *avp, *pos;
+
+	msg = wpabuf_alloc(sizeof(struct ttls_avp) + wpabuf_len(*resp) + 4);
+	if (msg == NULL) {
+		wpabuf_free(*resp);
+		*resp = NULL;
+		return -1;
+	}
+
+	avp = wpabuf_mhead(msg);
+	pos = eap_ttls_avp_hdr(avp, avp_code, 0, mandatory, wpabuf_len(*resp));
+	os_memcpy(pos, wpabuf_head(*resp), wpabuf_len(*resp));
+	pos += wpabuf_len(*resp);
+	AVP_PAD(avp, pos);
+	wpabuf_free(*resp);
+	wpabuf_put(msg, pos - avp);
+	*resp = msg;
+	return 0;
+}
+
+
+static int eap_ttls_v0_derive_key(struct eap_sm *sm,
+				  struct eap_ttls_data *data)
+{
+	os_free(data->key_data);
+	data->key_data = eap_peer_tls_derive_key(sm, &data->ssl,
+						 "ttls keying material",
+						 EAP_TLS_KEY_LEN);
+	if (!data->key_data) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to derive key");
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: Derived key",
+			data->key_data, EAP_TLS_KEY_LEN);
+
+	return 0;
+}
+
+
+static u8 * eap_ttls_implicit_challenge(struct eap_sm *sm,
+					struct eap_ttls_data *data, size_t len)
+{
+	return eap_peer_tls_derive_key(sm, &data->ssl, "ttls challenge", len);
+}
+
+
+static void eap_ttls_phase2_select_eap_method(struct eap_ttls_data *data,
+					      u8 method)
+{
+	size_t i;
+	for (i = 0; i < data->num_phase2_eap_types; i++) {
+		if (data->phase2_eap_types[i].vendor != EAP_VENDOR_IETF ||
+		    data->phase2_eap_types[i].method != method)
+			continue;
+
+		data->phase2_eap_type.vendor =
+			data->phase2_eap_types[i].vendor;
+		data->phase2_eap_type.method =
+			data->phase2_eap_types[i].method;
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected "
+			   "Phase 2 EAP vendor %d method %d",
+			   data->phase2_eap_type.vendor,
+			   data->phase2_eap_type.method);
+		break;
+	}
+}
+
+
+static int eap_ttls_phase2_eap_process(struct eap_sm *sm,
+				       struct eap_ttls_data *data,
+				       struct eap_method_ret *ret,
+				       struct eap_hdr *hdr, size_t len,
+				       struct wpabuf **resp)
+{
+	struct wpabuf msg;
+	struct eap_method_ret iret;
+
+	os_memset(&iret, 0, sizeof(iret));
+	wpabuf_set(&msg, hdr, len);
+	*resp = data->phase2_method->process(sm, data->phase2_priv, &iret,
+					     &msg);
+	if ((iret.methodState == METHOD_DONE ||
+	     iret.methodState == METHOD_MAY_CONT) &&
+	    (iret.decision == DECISION_UNCOND_SUCC ||
+	     iret.decision == DECISION_COND_SUCC ||
+	     iret.decision == DECISION_FAIL)) {
+		ret->methodState = iret.methodState;
+		ret->decision = iret.decision;
+	}
+
+	return 0;
+}
+
+
+static int eap_ttls_phase2_request_eap_method(struct eap_sm *sm,
+					      struct eap_ttls_data *data,
+					      struct eap_method_ret *ret,
+					      struct eap_hdr *hdr, size_t len,
+					      u8 method, struct wpabuf **resp)
+{
+#ifdef EAP_TNC
+	if (data->tnc_started && data->phase2_method &&
+	    data->phase2_priv && method == EAP_TYPE_TNC &&
+	    data->phase2_eap_type.method == EAP_TYPE_TNC)
+		return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len,
+						   resp);
+
+	if (data->ready_for_tnc && !data->tnc_started &&
+	    method == EAP_TYPE_TNC) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed "
+			   "EAP method");
+		data->tnc_started = 1;
+	}
+
+	if (data->tnc_started) {
+		if (data->phase2_eap_type.vendor != EAP_VENDOR_IETF ||
+		    data->phase2_eap_type.method == EAP_TYPE_TNC) {
+			wpa_printf(MSG_DEBUG, "EAP-TTLS: Unexpected EAP "
+				   "type %d for TNC", method);
+			return -1;
+		}
+
+		data->phase2_eap_type.vendor = EAP_VENDOR_IETF;
+		data->phase2_eap_type.method = method;
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Selected "
+			   "Phase 2 EAP vendor %d method %d (TNC)",
+			   data->phase2_eap_type.vendor,
+			   data->phase2_eap_type.method);
+
+		if (data->phase2_type == EAP_TTLS_PHASE2_EAP)
+			eap_ttls_phase2_eap_deinit(sm, data);
+	}
+#endif /* EAP_TNC */
+
+	if (data->phase2_eap_type.vendor == EAP_VENDOR_IETF &&
+	    data->phase2_eap_type.method == EAP_TYPE_NONE)
+		eap_ttls_phase2_select_eap_method(data, method);
+
+	if (method != data->phase2_eap_type.method || method == EAP_TYPE_NONE)
+	{
+		if (eap_peer_tls_phase2_nak(data->phase2_eap_types,
+					    data->num_phase2_eap_types,
+					    hdr, resp))
+			return -1;
+		return 0;
+	}
+
+	if (data->phase2_priv == NULL) {
+		data->phase2_method = eap_peer_get_eap_method(
+			EAP_VENDOR_IETF, method);
+		if (data->phase2_method) {
+			sm->init_phase2 = 1;
+			data->phase2_priv = data->phase2_method->init(sm);
+			sm->init_phase2 = 0;
+		}
+	}
+	if (data->phase2_priv == NULL || data->phase2_method == NULL) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: failed to initialize "
+			   "Phase 2 EAP method %d", method);
+		return -1;
+	}
+
+	return eap_ttls_phase2_eap_process(sm, data, ret, hdr, len, resp);
+}
+
+
+static int eap_ttls_phase2_request_eap(struct eap_sm *sm,
+				       struct eap_ttls_data *data,
+				       struct eap_method_ret *ret,
+				       struct eap_hdr *hdr,
+				       struct wpabuf **resp)
+{
+	size_t len = be_to_host16(hdr->length);
+	u8 *pos;
+	struct eap_peer_config *config = eap_get_config(sm);
+
+	if (len <= sizeof(struct eap_hdr)) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: too short "
+			   "Phase 2 request (len=%lu)", (unsigned long) len);
+		return -1;
+	}
+	pos = (u8 *) (hdr + 1);
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP Request: type=%d", *pos);
+	switch (*pos) {
+	case EAP_TYPE_IDENTITY:
+		*resp = eap_sm_buildIdentity(sm, hdr->identifier, 1);
+		break;
+	default:
+		if (eap_ttls_phase2_request_eap_method(sm, data, ret, hdr, len,
+						       *pos, resp) < 0)
+			return -1;
+		break;
+	}
+
+	if (*resp == NULL &&
+	    (config->pending_req_identity || config->pending_req_password ||
+	     config->pending_req_otp)) {
+		return 0;
+	}
+
+	if (*resp == NULL)
+		return -1;
+
+	wpa_hexdump_buf(MSG_DEBUG, "EAP-TTLS: AVP encapsulate EAP Response",
+			*resp);
+	return eap_ttls_avp_encapsulate(resp, RADIUS_ATTR_EAP_MESSAGE, 1);
+}
+
+
+static int eap_ttls_phase2_request_mschapv2(struct eap_sm *sm,
+					    struct eap_ttls_data *data,
+					    struct eap_method_ret *ret,
+					    struct wpabuf **resp)
+{
+#ifdef EAP_MSCHAPv2
+	struct wpabuf *msg;
+	u8 *buf, *pos, *challenge, *peer_challenge;
+	const u8 *identity, *password;
+	size_t identity_len, password_len;
+	int pwhash;
+
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAPV2 Request");
+
+	identity = eap_get_config_identity(sm, &identity_len);
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
+	if (identity == NULL || password == NULL)
+		return -1;
+
+	msg = wpabuf_alloc(identity_len + 1000);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR,
+			   "EAP-TTLS/MSCHAPV2: Failed to allocate memory");
+		return -1;
+	}
+	pos = buf = wpabuf_mhead(msg);
+
+	/* User-Name */
+	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
+			       identity, identity_len);
+
+	/* MS-CHAP-Challenge */
+	challenge = eap_ttls_implicit_challenge(
+		sm, data, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN + 1);
+	if (challenge == NULL) {
+		wpabuf_free(msg);
+		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
+			   "implicit challenge");
+		return -1;
+	}
+
+	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE,
+			       RADIUS_VENDOR_ID_MICROSOFT, 1,
+			       challenge, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN);
+
+	/* MS-CHAP2-Response */
+	pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP2_RESPONSE,
+			       RADIUS_VENDOR_ID_MICROSOFT, 1,
+			       EAP_TTLS_MSCHAPV2_RESPONSE_LEN);
+	data->ident = challenge[EAP_TTLS_MSCHAPV2_CHALLENGE_LEN];
+	*pos++ = data->ident;
+	*pos++ = 0; /* Flags */
+	if (os_get_random(pos, EAP_TTLS_MSCHAPV2_CHALLENGE_LEN) < 0) {
+		os_free(challenge);
+		wpabuf_free(msg);
+		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to get "
+			   "random data for peer challenge");
+		return -1;
+	}
+	peer_challenge = pos;
+	pos += EAP_TTLS_MSCHAPV2_CHALLENGE_LEN;
+	os_memset(pos, 0, 8); /* Reserved, must be zero */
+	pos += 8;
+	if (mschapv2_derive_response(identity, identity_len, password,
+				     password_len, pwhash, challenge,
+				     peer_challenge, pos, data->auth_response,
+				     data->master_key)) {
+		os_free(challenge);
+		wpabuf_free(msg);
+		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAPV2: Failed to derive "
+			   "response");
+		return -1;
+	}
+	data->auth_response_valid = 1;
+
+	pos += 24;
+	os_free(challenge);
+	AVP_PAD(buf, pos);
+
+	wpabuf_put(msg, pos - buf);
+	*resp = msg;
+
+	if (sm->workaround) {
+		/* At least FreeRADIUS seems to be terminating
+		 * EAP-TTLS/MSHCAPV2 without the expected MS-CHAP-v2 Success
+		 * packet. */
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: EAP workaround - "
+			   "allow success without tunneled response");
+		ret->methodState = METHOD_MAY_CONT;
+		ret->decision = DECISION_COND_SUCC;
+	}
+
+	return 0;
+#else /* EAP_MSCHAPv2 */
+	wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
+	return -1;
+#endif /* EAP_MSCHAPv2 */
+}
+
+
+static int eap_ttls_phase2_request_mschap(struct eap_sm *sm,
+					  struct eap_ttls_data *data,
+					  struct eap_method_ret *ret,
+					  struct wpabuf **resp)
+{
+	struct wpabuf *msg;
+	u8 *buf, *pos, *challenge;
+	const u8 *identity, *password;
+	size_t identity_len, password_len;
+	int pwhash;
+
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 MSCHAP Request");
+
+	identity = eap_get_config_identity(sm, &identity_len);
+	password = eap_get_config_password2(sm, &password_len, &pwhash);
+	if (identity == NULL || password == NULL)
+		return -1;
+
+	msg = wpabuf_alloc(identity_len + 1000);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR,
+			   "EAP-TTLS/MSCHAP: Failed to allocate memory");
+		return -1;
+	}
+	pos = buf = wpabuf_mhead(msg);
+
+	/* User-Name */
+	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
+			       identity, identity_len);
+
+	/* MS-CHAP-Challenge */
+	challenge = eap_ttls_implicit_challenge(
+		sm, data, EAP_TTLS_MSCHAP_CHALLENGE_LEN + 1);
+	if (challenge == NULL) {
+		wpabuf_free(msg);
+		wpa_printf(MSG_ERROR, "EAP-TTLS/MSCHAP: Failed to derive "
+			   "implicit challenge");
+		return -1;
+	}
+
+	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_MS_CHAP_CHALLENGE,
+			       RADIUS_VENDOR_ID_MICROSOFT, 1,
+			       challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN);
+
+	/* MS-CHAP-Response */
+	pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_MS_CHAP_RESPONSE,
+			       RADIUS_VENDOR_ID_MICROSOFT, 1,
+			       EAP_TTLS_MSCHAP_RESPONSE_LEN);
+	data->ident = challenge[EAP_TTLS_MSCHAP_CHALLENGE_LEN];
+	*pos++ = data->ident;
+	*pos++ = 1; /* Flags: Use NT style passwords */
+	os_memset(pos, 0, 24); /* LM-Response */
+	pos += 24;
+	if (pwhash) {
+		challenge_response(challenge, password, pos); /* NT-Response */
+		wpa_hexdump_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password hash",
+				password, 16);
+	} else {
+		nt_challenge_response(challenge, password, password_len,
+				      pos); /* NT-Response */
+		wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: MSCHAP password",
+				      password, password_len);
+	}
+	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP implicit challenge",
+		    challenge, EAP_TTLS_MSCHAP_CHALLENGE_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: MSCHAP response", pos, 24);
+	pos += 24;
+	os_free(challenge);
+	AVP_PAD(buf, pos);
+
+	wpabuf_put(msg, pos - buf);
+	*resp = msg;
+
+	/* EAP-TTLS/MSCHAP does not provide tunneled success
+	 * notification, so assume that Phase2 succeeds. */
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_COND_SUCC;
+
+	return 0;
+}
+
+
+static int eap_ttls_phase2_request_pap(struct eap_sm *sm,
+				       struct eap_ttls_data *data,
+				       struct eap_method_ret *ret,
+				       struct wpabuf **resp)
+{
+	struct wpabuf *msg;
+	u8 *buf, *pos;
+	size_t pad;
+	const u8 *identity, *password;
+	size_t identity_len, password_len;
+
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 PAP Request");
+
+	identity = eap_get_config_identity(sm, &identity_len);
+	password = eap_get_config_password(sm, &password_len);
+	if (identity == NULL || password == NULL)
+		return -1;
+
+	msg = wpabuf_alloc(identity_len + password_len + 100);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR,
+			   "EAP-TTLS/PAP: Failed to allocate memory");
+		return -1;
+	}
+	pos = buf = wpabuf_mhead(msg);
+
+	/* User-Name */
+	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
+			       identity, identity_len);
+
+	/* User-Password; in RADIUS, this is encrypted, but EAP-TTLS encrypts
+	 * the data, so no separate encryption is used in the AVP itself.
+	 * However, the password is padded to obfuscate its length. */
+	pad = password_len == 0 ? 16 : (16 - (password_len & 15)) & 15;
+	pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_USER_PASSWORD, 0, 1,
+			       password_len + pad);
+	os_memcpy(pos, password, password_len);
+	pos += password_len;
+	os_memset(pos, 0, pad);
+	pos += pad;
+	AVP_PAD(buf, pos);
+
+	wpabuf_put(msg, pos - buf);
+	*resp = msg;
+
+	/* EAP-TTLS/PAP does not provide tunneled success notification,
+	 * so assume that Phase2 succeeds. */
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_COND_SUCC;
+
+	return 0;
+}
+
+
+static int eap_ttls_phase2_request_chap(struct eap_sm *sm,
+					struct eap_ttls_data *data,
+					struct eap_method_ret *ret,
+					struct wpabuf **resp)
+{
+	struct wpabuf *msg;
+	u8 *buf, *pos, *challenge;
+	const u8 *identity, *password;
+	size_t identity_len, password_len;
+
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: Phase 2 CHAP Request");
+
+	identity = eap_get_config_identity(sm, &identity_len);
+	password = eap_get_config_password(sm, &password_len);
+	if (identity == NULL || password == NULL)
+		return -1;
+
+	msg = wpabuf_alloc(identity_len + 1000);
+	if (msg == NULL) {
+		wpa_printf(MSG_ERROR,
+			   "EAP-TTLS/CHAP: Failed to allocate memory");
+		return -1;
+	}
+	pos = buf = wpabuf_mhead(msg);
+
+	/* User-Name */
+	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_USER_NAME, 0, 1,
+			       identity, identity_len);
+
+	/* CHAP-Challenge */
+	challenge = eap_ttls_implicit_challenge(
+		sm, data, EAP_TTLS_CHAP_CHALLENGE_LEN + 1);
+	if (challenge == NULL) {
+		wpabuf_free(msg);
+		wpa_printf(MSG_ERROR, "EAP-TTLS/CHAP: Failed to derive "
+			   "implicit challenge");
+		return -1;
+	}
+
+	pos = eap_ttls_avp_add(buf, pos, RADIUS_ATTR_CHAP_CHALLENGE, 0, 1,
+			       challenge, EAP_TTLS_CHAP_CHALLENGE_LEN);
+
+	/* CHAP-Password */
+	pos = eap_ttls_avp_hdr(pos, RADIUS_ATTR_CHAP_PASSWORD, 0, 1,
+			       1 + EAP_TTLS_CHAP_PASSWORD_LEN);
+	data->ident = challenge[EAP_TTLS_CHAP_CHALLENGE_LEN];
+	*pos++ = data->ident;
+
+	/* MD5(Ident + Password + Challenge) */
+	chap_md5(data->ident, password, password_len, challenge,
+		 EAP_TTLS_CHAP_CHALLENGE_LEN, pos);
+
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: CHAP username",
+			  identity, identity_len);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "EAP-TTLS: CHAP password",
+			      password, password_len);
+	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP implicit challenge",
+		    challenge, EAP_TTLS_CHAP_CHALLENGE_LEN);
+	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: CHAP password",
+		    pos, EAP_TTLS_CHAP_PASSWORD_LEN);
+	pos += EAP_TTLS_CHAP_PASSWORD_LEN;
+	os_free(challenge);
+	AVP_PAD(buf, pos);
+
+	wpabuf_put(msg, pos - buf);
+	*resp = msg;
+
+	/* EAP-TTLS/CHAP does not provide tunneled success
+	 * notification, so assume that Phase2 succeeds. */
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_COND_SUCC;
+
+	return 0;
+}
+
+
+static int eap_ttls_phase2_request(struct eap_sm *sm,
+				   struct eap_ttls_data *data,
+				   struct eap_method_ret *ret,
+				   struct eap_hdr *hdr,
+				   struct wpabuf **resp)
+{
+	int res = 0;
+	size_t len;
+	enum phase2_types phase2_type = data->phase2_type;
+
+#ifdef EAP_TNC
+	if (data->tnc_started) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Processing TNC");
+		phase2_type = EAP_TTLS_PHASE2_EAP;
+	}
+#endif /* EAP_TNC */
+
+	if (phase2_type == EAP_TTLS_PHASE2_MSCHAPV2 ||
+	    phase2_type == EAP_TTLS_PHASE2_MSCHAP ||
+	    phase2_type == EAP_TTLS_PHASE2_PAP ||
+	    phase2_type == EAP_TTLS_PHASE2_CHAP) {
+		if (eap_get_config_identity(sm, &len) == NULL) {
+			wpa_printf(MSG_INFO,
+				   "EAP-TTLS: Identity not configured");
+			eap_sm_request_identity(sm);
+			if (eap_get_config_password(sm, &len) == NULL)
+				eap_sm_request_password(sm);
+			return 0;
+		}
+
+		if (eap_get_config_password(sm, &len) == NULL) {
+			wpa_printf(MSG_INFO,
+				   "EAP-TTLS: Password not configured");
+			eap_sm_request_password(sm);
+			return 0;
+		}
+	}
+
+	switch (phase2_type) {
+	case EAP_TTLS_PHASE2_EAP:
+		res = eap_ttls_phase2_request_eap(sm, data, ret, hdr, resp);
+		break;
+	case EAP_TTLS_PHASE2_MSCHAPV2:
+		res = eap_ttls_phase2_request_mschapv2(sm, data, ret, resp);
+		break;
+	case EAP_TTLS_PHASE2_MSCHAP:
+		res = eap_ttls_phase2_request_mschap(sm, data, ret, resp);
+		break;
+	case EAP_TTLS_PHASE2_PAP:
+		res = eap_ttls_phase2_request_pap(sm, data, ret, resp);
+		break;
+	case EAP_TTLS_PHASE2_CHAP:
+		res = eap_ttls_phase2_request_chap(sm, data, ret, resp);
+		break;
+	default:
+		wpa_printf(MSG_ERROR, "EAP-TTLS: Phase 2 - Unknown");
+		res = -1;
+		break;
+	}
+
+	if (res < 0) {
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_FAIL;
+	}
+
+	return res;
+}
+
+
+struct ttls_parse_avp {
+	u8 *mschapv2;
+	u8 *eapdata;
+	size_t eap_len;
+	int mschapv2_error;
+};
+
+
+static int eap_ttls_parse_attr_eap(const u8 *dpos, size_t dlen,
+				   struct ttls_parse_avp *parse)
+{
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP - EAP Message");
+	if (parse->eapdata == NULL) {
+		parse->eapdata = os_malloc(dlen);
+		if (parse->eapdata == NULL) {
+			wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
+				   "memory for Phase 2 EAP data");
+			return -1;
+		}
+		os_memcpy(parse->eapdata, dpos, dlen);
+		parse->eap_len = dlen;
+	} else {
+		u8 *neweap = os_realloc(parse->eapdata, parse->eap_len + dlen);
+		if (neweap == NULL) {
+			wpa_printf(MSG_WARNING, "EAP-TTLS: Failed to allocate "
+				   "memory for Phase 2 EAP data");
+			return -1;
+		}
+		os_memcpy(neweap + parse->eap_len, dpos, dlen);
+		parse->eapdata = neweap;
+		parse->eap_len += dlen;
+	}
+
+	return 0;
+}
+
+
+static int eap_ttls_parse_avp(u8 *pos, size_t left,
+			      struct ttls_parse_avp *parse)
+{
+	struct ttls_avp *avp;
+	u32 avp_code, avp_length, vendor_id = 0;
+	u8 avp_flags, *dpos;
+	size_t dlen;
+
+	avp = (struct ttls_avp *) pos;
+	avp_code = be_to_host32(avp->avp_code);
+	avp_length = be_to_host32(avp->avp_length);
+	avp_flags = (avp_length >> 24) & 0xff;
+	avp_length &= 0xffffff;
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP: code=%d flags=0x%02x "
+		   "length=%d", (int) avp_code, avp_flags,
+		   (int) avp_length);
+
+	if (avp_length > left) {
+		wpa_printf(MSG_WARNING, "EAP-TTLS: AVP overflow "
+			   "(len=%d, left=%lu) - dropped",
+			   (int) avp_length, (unsigned long) left);
+		return -1;
+	}
+
+	if (avp_length < sizeof(*avp)) {
+		wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid AVP length %d",
+			   avp_length);
+		return -1;
+	}
+
+	dpos = (u8 *) (avp + 1);
+	dlen = avp_length - sizeof(*avp);
+	if (avp_flags & AVP_FLAGS_VENDOR) {
+		if (dlen < 4) {
+			wpa_printf(MSG_WARNING, "EAP-TTLS: Vendor AVP "
+				   "underflow");
+			return -1;
+		}
+		vendor_id = WPA_GET_BE32(dpos);
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: AVP vendor_id %d",
+			   (int) vendor_id);
+		dpos += 4;
+		dlen -= 4;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: AVP data", dpos, dlen);
+
+	if (vendor_id == 0 && avp_code == RADIUS_ATTR_EAP_MESSAGE) {
+		if (eap_ttls_parse_attr_eap(dpos, dlen, parse) < 0)
+			return -1;
+	} else if (vendor_id == 0 && avp_code == RADIUS_ATTR_REPLY_MESSAGE) {
+		/* This is an optional message that can be displayed to
+		 * the user. */
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: AVP - Reply-Message",
+				  dpos, dlen);
+	} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
+		   avp_code == RADIUS_ATTR_MS_CHAP2_SUCCESS) {
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP2-Success",
+				  dpos, dlen);
+		if (dlen != 43) {
+			wpa_printf(MSG_WARNING, "EAP-TTLS: Unexpected "
+				   "MS-CHAP2-Success length "
+				   "(len=%lu, expected 43)",
+				   (unsigned long) dlen);
+			return -1;
+		}
+		parse->mschapv2 = dpos;
+	} else if (vendor_id == RADIUS_VENDOR_ID_MICROSOFT &&
+		   avp_code == RADIUS_ATTR_MS_CHAP_ERROR) {
+		wpa_hexdump_ascii(MSG_DEBUG, "EAP-TTLS: MS-CHAP-Error",
+				  dpos, dlen);
+		parse->mschapv2_error = 1;
+	} else if (avp_flags & AVP_FLAGS_MANDATORY) {
+		wpa_printf(MSG_WARNING, "EAP-TTLS: Unsupported mandatory AVP "
+			   "code %d vendor_id %d - dropped",
+			   (int) avp_code, (int) vendor_id);
+		return -1;
+	} else {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Ignoring unsupported AVP "
+			   "code %d vendor_id %d",
+			   (int) avp_code, (int) vendor_id);
+	}
+
+	return avp_length;
+}
+
+
+static int eap_ttls_parse_avps(struct wpabuf *in_decrypted,
+			       struct ttls_parse_avp *parse)
+{
+	u8 *pos;
+	size_t left, pad;
+	int avp_length;
+
+	pos = wpabuf_mhead(in_decrypted);
+	left = wpabuf_len(in_decrypted);
+	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Decrypted Phase 2 AVPs", pos, left);
+	if (left < sizeof(struct ttls_avp)) {
+		wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 AVP frame"
+			   " len=%lu expected %lu or more - dropped",
+			   (unsigned long) left,
+			   (unsigned long) sizeof(struct ttls_avp));
+		return -1;
+	}
+
+	/* Parse AVPs */
+	os_memset(parse, 0, sizeof(*parse));
+
+	while (left > 0) {
+		avp_length = eap_ttls_parse_avp(pos, left, parse);
+		if (avp_length < 0)
+			return -1;
+
+		pad = (4 - (avp_length & 3)) & 3;
+		pos += avp_length + pad;
+		if (left < avp_length + pad)
+			left = 0;
+		else
+			left -= avp_length + pad;
+	}
+
+	return 0;
+}
+
+
+static u8 * eap_ttls_fake_identity_request(void)
+{
+	struct eap_hdr *hdr;
+	u8 *buf;
+
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: empty data in beginning of "
+		   "Phase 2 - use fake EAP-Request Identity");
+	buf = os_malloc(sizeof(*hdr) + 1);
+	if (buf == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-TTLS: failed to allocate "
+			   "memory for fake EAP-Identity Request");
+		return NULL;
+	}
+
+	hdr = (struct eap_hdr *) buf;
+	hdr->code = EAP_CODE_REQUEST;
+	hdr->identifier = 0;
+	hdr->length = host_to_be16(sizeof(*hdr) + 1);
+	buf[sizeof(*hdr)] = EAP_TYPE_IDENTITY;
+
+	return buf;
+}
+
+
+static int eap_ttls_encrypt_response(struct eap_sm *sm,
+				     struct eap_ttls_data *data,
+				     struct wpabuf *resp, u8 identifier,
+				     struct wpabuf **out_data)
+{
+	if (resp == NULL)
+		return 0;
+
+	wpa_hexdump_buf_key(MSG_DEBUG, "EAP-TTLS: Encrypting Phase 2 data",
+			    resp);
+	if (eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS,
+				 data->ttls_version, identifier,
+				 resp, out_data)) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: Failed to encrypt a Phase 2 "
+			   "frame");
+		return -1;
+	}
+	wpabuf_free(resp);
+
+	return 0;
+}
+
+
+static int eap_ttls_process_phase2_eap(struct eap_sm *sm,
+				       struct eap_ttls_data *data,
+				       struct eap_method_ret *ret,
+				       struct ttls_parse_avp *parse,
+				       struct wpabuf **resp)
+{
+	struct eap_hdr *hdr;
+	size_t len;
+
+	if (parse->eapdata == NULL) {
+		wpa_printf(MSG_WARNING, "EAP-TTLS: No EAP Message in the "
+			   "packet - dropped");
+		return -1;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "EAP-TTLS: Phase 2 EAP",
+		    parse->eapdata, parse->eap_len);
+	hdr = (struct eap_hdr *) parse->eapdata;
+
+	if (parse->eap_len < sizeof(*hdr)) {
+		wpa_printf(MSG_WARNING, "EAP-TTLS: Too short Phase 2 EAP "
+			   "frame (len=%lu, expected %lu or more) - dropped",
+			   (unsigned long) parse->eap_len,
+			   (unsigned long) sizeof(*hdr));
+		return -1;
+	}
+	len = be_to_host16(hdr->length);
+	if (len > parse->eap_len) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: Length mismatch in Phase 2 "
+			   "EAP frame (EAP hdr len=%lu, EAP data len in "
+			   "AVP=%lu)",
+			   (unsigned long) len,
+			   (unsigned long) parse->eap_len);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: received Phase 2: code=%d "
+		   "identifier=%d length=%lu",
+		   hdr->code, hdr->identifier, (unsigned long) len);
+	switch (hdr->code) {
+	case EAP_CODE_REQUEST:
+		if (eap_ttls_phase2_request(sm, data, ret, hdr, resp)) {
+			wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request "
+				   "processing failed");
+			return -1;
+		}
+		break;
+	default:
+		wpa_printf(MSG_INFO, "EAP-TTLS: Unexpected code=%d in "
+			   "Phase 2 EAP header", hdr->code);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int eap_ttls_process_phase2_mschapv2(struct eap_sm *sm,
+					    struct eap_ttls_data *data,
+					    struct eap_method_ret *ret,
+					    struct ttls_parse_avp *parse)
+{
+#ifdef EAP_MSCHAPv2
+	if (parse->mschapv2_error) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS/MSCHAPV2: Received "
+			   "MS-CHAP-Error - failed");
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_FAIL;
+		/* Reply with empty data to ACK error */
+		return 1;
+	}
+
+	if (parse->mschapv2 == NULL) {
+#ifdef EAP_TNC
+		if (data->phase2_success && parse->eapdata) {
+			/*
+			 * Allow EAP-TNC to be started after successfully
+			 * completed MSCHAPV2.
+			 */
+			return 1;
+		}
+#endif /* EAP_TNC */
+		wpa_printf(MSG_WARNING, "EAP-TTLS: no MS-CHAP2-Success AVP "
+			   "received for Phase2 MSCHAPV2");
+		return -1;
+	}
+	if (parse->mschapv2[0] != data->ident) {
+		wpa_printf(MSG_WARNING, "EAP-TTLS: Ident mismatch for Phase 2 "
+			   "MSCHAPV2 (received Ident 0x%02x, expected 0x%02x)",
+			   parse->mschapv2[0], data->ident);
+		return -1;
+	}
+	if (!data->auth_response_valid ||
+	    mschapv2_verify_auth_response(data->auth_response,
+					  parse->mschapv2 + 1, 42)) {
+		wpa_printf(MSG_WARNING, "EAP-TTLS: Invalid authenticator "
+			   "response in Phase 2 MSCHAPV2 success request");
+		return -1;
+	}
+
+	wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 MSCHAPV2 "
+		   "authentication succeeded");
+	ret->methodState = METHOD_DONE;
+	ret->decision = DECISION_UNCOND_SUCC;
+	data->phase2_success = 1;
+
+	/*
+	 * Reply with empty data; authentication server will reply
+	 * with EAP-Success after this.
+	 */
+	return 1;
+#else /* EAP_MSCHAPv2 */
+	wpa_printf(MSG_ERROR, "EAP-TTLS: MSCHAPv2 not included in the build");
+	return -1;
+#endif /* EAP_MSCHAPv2 */
+}
+
+
+#ifdef EAP_TNC
+static int eap_ttls_process_tnc_start(struct eap_sm *sm,
+				      struct eap_ttls_data *data,
+				      struct eap_method_ret *ret,
+				      struct ttls_parse_avp *parse,
+				      struct wpabuf **resp)
+{
+	/* TNC uses inner EAP method after non-EAP TTLS phase 2. */
+	if (parse->eapdata == NULL) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received "
+			   "unexpected tunneled data (no EAP)");
+		return -1;
+	}
+
+	if (!data->ready_for_tnc) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received "
+			   "EAP after non-EAP, but not ready for TNC");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: Start TNC after completed "
+		   "non-EAP method");
+	data->tnc_started = 1;
+
+	if (eap_ttls_process_phase2_eap(sm, data, ret, parse, resp) < 0)
+		return -1;
+
+	return 0;
+}
+#endif /* EAP_TNC */
+
+
+static int eap_ttls_process_decrypted(struct eap_sm *sm,
+				      struct eap_ttls_data *data,
+				      struct eap_method_ret *ret,
+				      u8 identifier,
+				      struct ttls_parse_avp *parse,
+				      struct wpabuf *in_decrypted,
+				      struct wpabuf **out_data)
+{
+	struct wpabuf *resp = NULL;
+	struct eap_peer_config *config = eap_get_config(sm);
+	int res;
+	enum phase2_types phase2_type = data->phase2_type;
+
+#ifdef EAP_TNC
+	if (data->tnc_started)
+		phase2_type = EAP_TTLS_PHASE2_EAP;
+#endif /* EAP_TNC */
+
+	switch (phase2_type) {
+	case EAP_TTLS_PHASE2_EAP:
+		if (eap_ttls_process_phase2_eap(sm, data, ret, parse, &resp) <
+		    0)
+			return -1;
+		break;
+	case EAP_TTLS_PHASE2_MSCHAPV2:
+		res = eap_ttls_process_phase2_mschapv2(sm, data, ret, parse);
+#ifdef EAP_TNC
+		if (res == 1 && parse->eapdata && data->phase2_success) {
+			/*
+			 * TNC may be required as the next
+			 * authentication method within the tunnel.
+			 */
+			ret->methodState = METHOD_MAY_CONT;
+			data->ready_for_tnc = 1;
+			if (eap_ttls_process_tnc_start(sm, data, ret, parse,
+						       &resp) == 0)
+				break;
+		}
+#endif /* EAP_TNC */
+		return res;
+	case EAP_TTLS_PHASE2_MSCHAP:
+	case EAP_TTLS_PHASE2_PAP:
+	case EAP_TTLS_PHASE2_CHAP:
+#ifdef EAP_TNC
+		if (eap_ttls_process_tnc_start(sm, data, ret, parse, &resp) <
+		    0)
+			return -1;
+		break;
+#else /* EAP_TNC */
+		/* EAP-TTLS/{MSCHAP,PAP,CHAP} should not send any TLS tunneled
+		 * requests to the supplicant */
+		wpa_printf(MSG_INFO, "EAP-TTLS: Phase 2 received unexpected "
+			   "tunneled data");
+		return -1;
+#endif /* EAP_TNC */
+	}
+
+	if (resp) {
+		if (eap_ttls_encrypt_response(sm, data, resp, identifier,
+					      out_data) < 0)
+			return -1;
+	} else if (config->pending_req_identity ||
+		   config->pending_req_password ||
+		   config->pending_req_otp ||
+		   config->pending_req_new_password) {
+		wpabuf_free(data->pending_phase2_req);
+		data->pending_phase2_req = wpabuf_dup(in_decrypted);
+	}
+
+	return 0;
+}
+
+
+static int eap_ttls_implicit_identity_request(struct eap_sm *sm,
+					      struct eap_ttls_data *data,
+					      struct eap_method_ret *ret,
+					      u8 identifier,
+					      struct wpabuf **out_data)
+{
+	int retval = 0;
+	struct eap_hdr *hdr;
+	struct wpabuf *resp;
+
+	hdr = (struct eap_hdr *) eap_ttls_fake_identity_request();
+	if (hdr == NULL) {
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_FAIL;
+		return -1;
+	}
+
+	resp = NULL;
+	if (eap_ttls_phase2_request(sm, data, ret, hdr, &resp)) {
+		wpa_printf(MSG_INFO, "EAP-TTLS: Phase2 Request "
+			   "processing failed");
+		retval = -1;
+	} else {
+		struct eap_peer_config *config = eap_get_config(sm);
+		if (resp == NULL &&
+		    (config->pending_req_identity ||
+		     config->pending_req_password ||
+		     config->pending_req_otp ||
+		     config->pending_req_new_password)) {
+			/*
+			 * Use empty buffer to force implicit request
+			 * processing when EAP request is re-processed after
+			 * user input.
+			 */
+			wpabuf_free(data->pending_phase2_req);
+			data->pending_phase2_req = wpabuf_alloc(0);
+		}
+
+		retval = eap_ttls_encrypt_response(sm, data, resp, identifier,
+						   out_data);
+	}
+
+	os_free(hdr);
+
+	if (retval < 0) {
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_FAIL;
+	}
+
+	return retval;
+}
+
+
+static int eap_ttls_phase2_start(struct eap_sm *sm, struct eap_ttls_data *data,
+				 struct eap_method_ret *ret, u8 identifier,
+				 struct wpabuf **out_data)
+{
+	data->phase2_start = 0;
+
+	/*
+	 * EAP-TTLS does not use Phase2 on fast re-auth; this must be done only
+	 * if TLS part was indeed resuming a previous session. Most
+	 * Authentication Servers terminate EAP-TTLS before reaching this
+	 * point, but some do not. Make wpa_supplicant stop phase 2 here, if
+	 * needed.
+	 */
+	if (data->reauth &&
+	    tls_connection_resumed(sm->ssl_ctx, data->ssl.conn)) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Session resumption - "
+			   "skip phase 2");
+		*out_data = eap_peer_tls_build_ack(identifier, EAP_TYPE_TTLS,
+						   data->ttls_version);
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_UNCOND_SUCC;
+		data->phase2_success = 1;
+		return 0;
+	}
+
+	return eap_ttls_implicit_identity_request(sm, data, ret, identifier,
+						  out_data);
+}
+
+
+static int eap_ttls_decrypt(struct eap_sm *sm, struct eap_ttls_data *data,
+			    struct eap_method_ret *ret, u8 identifier,
+			    const struct wpabuf *in_data,
+			    struct wpabuf **out_data)
+{
+	struct wpabuf *in_decrypted = NULL;
+	int retval = 0;
+	struct ttls_parse_avp parse;
+
+	os_memset(&parse, 0, sizeof(parse));
+
+	wpa_printf(MSG_DEBUG, "EAP-TTLS: received %lu bytes encrypted data for"
+		   " Phase 2",
+		   in_data ? (unsigned long) wpabuf_len(in_data) : 0);
+
+	if (data->pending_phase2_req) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Pending Phase 2 request - "
+			   "skip decryption and use old data");
+		/* Clear TLS reassembly state. */
+		eap_peer_tls_reset_input(&data->ssl);
+
+		in_decrypted = data->pending_phase2_req;
+		data->pending_phase2_req = NULL;
+		if (wpabuf_len(in_decrypted) == 0) {
+			wpabuf_free(in_decrypted);
+			return eap_ttls_implicit_identity_request(
+				sm, data, ret, identifier, out_data);
+		}
+		goto continue_req;
+	}
+
+	if ((in_data == NULL || wpabuf_len(in_data) == 0) &&
+	    data->phase2_start) {
+		return eap_ttls_phase2_start(sm, data, ret, identifier,
+					     out_data);
+	}
+
+	if (in_data == NULL || wpabuf_len(in_data) == 0) {
+		/* Received TLS ACK - requesting more fragments */
+		return eap_peer_tls_encrypt(sm, &data->ssl, EAP_TYPE_TTLS,
+					    data->ttls_version,
+					    identifier, NULL, out_data);
+	}
+
+	retval = eap_peer_tls_decrypt(sm, &data->ssl, in_data, &in_decrypted);
+	if (retval)
+		goto done;
+
+continue_req:
+	data->phase2_start = 0;
+
+	if (eap_ttls_parse_avps(in_decrypted, &parse) < 0) {
+		retval = -1;
+		goto done;
+	}
+
+	retval = eap_ttls_process_decrypted(sm, data, ret, identifier,
+					    &parse, in_decrypted, out_data);
+
+done:
+	wpabuf_free(in_decrypted);
+	os_free(parse.eapdata);
+
+	if (retval < 0) {
+		ret->methodState = METHOD_DONE;
+		ret->decision = DECISION_FAIL;
+	}
+
+	return retval;
+}
+
+
+static int eap_ttls_process_handshake(struct eap_sm *sm,
+				      struct eap_ttls_data *data,
+				      struct eap_method_ret *ret,
+				      u8 identifier,
+				      const u8 *in_data, size_t in_len,
+				      struct wpabuf **out_data)
+{
+	int res;
+
+	res = eap_peer_tls_process_helper(sm, &data->ssl, EAP_TYPE_TTLS,
+					  data->ttls_version, identifier,
+					  in_data, in_len, out_data);
+
+	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: TLS done, proceed to "
+			   "Phase 2");
+		if (data->resuming) {
+			wpa_printf(MSG_DEBUG, "EAP-TTLS: fast reauth - may "
+				   "skip Phase 2");
+			ret->decision = DECISION_COND_SUCC;
+			ret->methodState = METHOD_MAY_CONT;
+		}
+		data->phase2_start = 1;
+		eap_ttls_v0_derive_key(sm, data);
+
+		if (*out_data == NULL || wpabuf_len(*out_data) == 0) {
+			if (eap_ttls_decrypt(sm, data, ret, identifier,
+					     NULL, out_data)) {
+				wpa_printf(MSG_WARNING, "EAP-TTLS: "
+					   "failed to process early "
+					   "start for Phase 2");
+			}
+			res = 0;
+		}
+		data->resuming = 0;
+	}
+
+	if (res == 2) {
+		struct wpabuf msg;
+		/*
+		 * Application data included in the handshake message.
+		 */
+		wpabuf_free(data->pending_phase2_req);
+		data->pending_phase2_req = *out_data;
+		*out_data = NULL;
+		wpabuf_set(&msg, in_data, in_len);
+		res = eap_ttls_decrypt(sm, data, ret, identifier, &msg,
+				       out_data);
+	}
+
+	return res;
+}
+
+
+static void eap_ttls_check_auth_status(struct eap_sm *sm, 
+				       struct eap_ttls_data *data,
+				       struct eap_method_ret *ret)
+{
+	if (ret->methodState == METHOD_DONE) {
+		ret->allowNotifications = FALSE;
+		if (ret->decision == DECISION_UNCOND_SUCC ||
+		    ret->decision == DECISION_COND_SUCC) {
+			wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
+				   "completed successfully");
+			data->phase2_success = 1;
+#ifdef EAP_TNC
+			if (!data->ready_for_tnc && !data->tnc_started) {
+				/*
+				 * TNC may be required as the next
+				 * authentication method within the tunnel.
+				 */
+				ret->methodState = METHOD_MAY_CONT;
+				data->ready_for_tnc = 1;
+			}
+#endif /* EAP_TNC */
+		}
+	} else if (ret->methodState == METHOD_MAY_CONT &&
+		   (ret->decision == DECISION_UNCOND_SUCC ||
+		    ret->decision == DECISION_COND_SUCC)) {
+			wpa_printf(MSG_DEBUG, "EAP-TTLS: Authentication "
+				   "completed successfully (MAY_CONT)");
+			data->phase2_success = 1;
+	}
+}
+
+
+static struct wpabuf * eap_ttls_process(struct eap_sm *sm, void *priv,
+					struct eap_method_ret *ret,
+					const struct wpabuf *reqData)
+{
+	size_t left;
+	int res;
+	u8 flags, id;
+	struct wpabuf *resp;
+	const u8 *pos;
+	struct eap_ttls_data *data = priv;
+
+	pos = eap_peer_tls_process_init(sm, &data->ssl, EAP_TYPE_TTLS, ret,
+					reqData, &left, &flags);
+	if (pos == NULL)
+		return NULL;
+	id = eap_get_id(reqData);
+
+	if (flags & EAP_TLS_FLAGS_START) {
+		wpa_printf(MSG_DEBUG, "EAP-TTLS: Start (server ver=%d, own "
+			   "ver=%d)", flags & EAP_TLS_VERSION_MASK,
+			   data->ttls_version);
+
+		/* RFC 5281, Ch. 9.2:
+		 * "This packet MAY contain additional information in the form
+		 * of AVPs, which may provide useful hints to the client"
+		 * For now, ignore any potential extra data.
+		 */
+		left = 0;
+	}
+
+	resp = NULL;
+	if (tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
+	    !data->resuming) {
+		struct wpabuf msg;
+		wpabuf_set(&msg, pos, left);
+		res = eap_ttls_decrypt(sm, data, ret, id, &msg, &resp);
+	} else {
+		res = eap_ttls_process_handshake(sm, data, ret, id,
+						 pos, left, &resp);
+	}
+
+	eap_ttls_check_auth_status(sm, data, ret);
+
+	/* FIX: what about res == -1? Could just move all error processing into
+	 * the other functions and get rid of this res==1 case here. */
+	if (res == 1) {
+		wpabuf_free(resp);
+		return eap_peer_tls_build_ack(id, EAP_TYPE_TTLS,
+					      data->ttls_version);
+	}
+	return resp;
+}
+
+
+static Boolean eap_ttls_has_reauth_data(struct eap_sm *sm, void *priv)
+{
+	struct eap_ttls_data *data = priv;
+	return tls_connection_established(sm->ssl_ctx, data->ssl.conn) &&
+		data->phase2_success;
+}
+
+
+static void eap_ttls_deinit_for_reauth(struct eap_sm *sm, void *priv)
+{
+	struct eap_ttls_data *data = priv;
+	wpabuf_free(data->pending_phase2_req);
+	data->pending_phase2_req = NULL;
+#ifdef EAP_TNC
+	data->ready_for_tnc = 0;
+	data->tnc_started = 0;
+#endif /* EAP_TNC */
+}
+
+
+static void * eap_ttls_init_for_reauth(struct eap_sm *sm, void *priv)
+{
+	struct eap_ttls_data *data = priv;
+	os_free(data->key_data);
+	data->key_data = NULL;
+	if (eap_peer_tls_reauth_init(sm, &data->ssl)) {
+		os_free(data);
+		return NULL;
+	}
+	if (data->phase2_priv && data->phase2_method &&
+	    data->phase2_method->init_for_reauth)
+		data->phase2_method->init_for_reauth(sm, data->phase2_priv);
+	data->phase2_start = 0;
+	data->phase2_success = 0;
+	data->resuming = 1;
+	data->reauth = 1;
+	return priv;
+}
+
+
+static int eap_ttls_get_status(struct eap_sm *sm, void *priv, char *buf,
+			       size_t buflen, int verbose)
+{
+	struct eap_ttls_data *data = priv;
+	int len, ret;
+
+	len = eap_peer_tls_status(sm, &data->ssl, buf, buflen, verbose);
+	ret = os_snprintf(buf + len, buflen - len,
+			  "EAP-TTLSv%d Phase2 method=",
+			  data->ttls_version);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+	switch (data->phase2_type) {
+	case EAP_TTLS_PHASE2_EAP:
+		ret = os_snprintf(buf + len, buflen - len, "EAP-%s\n",
+				  data->phase2_method ?
+				  data->phase2_method->name : "?");
+		break;
+	case EAP_TTLS_PHASE2_MSCHAPV2:
+		ret = os_snprintf(buf + len, buflen - len, "MSCHAPV2\n");
+		break;
+	case EAP_TTLS_PHASE2_MSCHAP:
+		ret = os_snprintf(buf + len, buflen - len, "MSCHAP\n");
+		break;
+	case EAP_TTLS_PHASE2_PAP:
+		ret = os_snprintf(buf + len, buflen - len, "PAP\n");
+		break;
+	case EAP_TTLS_PHASE2_CHAP:
+		ret = os_snprintf(buf + len, buflen - len, "CHAP\n");
+		break;
+	default:
+		ret = 0;
+		break;
+	}
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	return len;
+}
+
+
+static Boolean eap_ttls_isKeyAvailable(struct eap_sm *sm, void *priv)
+{
+	struct eap_ttls_data *data = priv;
+	return data->key_data != NULL && data->phase2_success;
+}
+
+
+static u8 * eap_ttls_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+	struct eap_ttls_data *data = priv;
+	u8 *key;
+
+	if (data->key_data == NULL || !data->phase2_success)
+		return NULL;
+
+	key = os_malloc(EAP_TLS_KEY_LEN);
+	if (key == NULL)
+		return NULL;
+
+	*len = EAP_TLS_KEY_LEN;
+	os_memcpy(key, data->key_data, EAP_TLS_KEY_LEN);
+
+	return key;
+}
+
+
+int eap_peer_ttls_register(void)
+{
+	struct eap_method *eap;
+	int ret;
+
+	eap = eap_peer_method_alloc(EAP_PEER_METHOD_INTERFACE_VERSION,
+				    EAP_VENDOR_IETF, EAP_TYPE_TTLS, "TTLS");
+	if (eap == NULL)
+		return -1;
+
+	eap->init = eap_ttls_init;
+	eap->deinit = eap_ttls_deinit;
+	eap->process = eap_ttls_process;
+	eap->isKeyAvailable = eap_ttls_isKeyAvailable;
+	eap->getKey = eap_ttls_getKey;
+	eap->get_status = eap_ttls_get_status;
+	eap->has_reauth_data = eap_ttls_has_reauth_data;
+	eap->deinit_for_reauth = eap_ttls_deinit_for_reauth;
+	eap->init_for_reauth = eap_ttls_init_for_reauth;
+
+	ret = eap_peer_method_register(eap);
+	if (ret)
+		eap_peer_method_free(eap);
+	return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/mschapv2.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,124 @@
+/*
+ * MSCHAPV2 (RFC 2759)
+ * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/ms_funcs.h"
+#include "mschapv2.h"
+
+const u8 * mschapv2_remove_domain(const u8 *username, size_t *len)
+{
+	size_t i;
+
+	/*
+	 * MSCHAPv2 does not include optional domain name in the
+	 * challenge-response calculation, so remove domain prefix
+	 * (if present).
+	 */
+
+	for (i = 0; i < *len; i++) {
+		if (username[i] == '\\') {
+			*len -= i + 1;
+			return username + i + 1;
+		}
+	}
+
+	return username;
+}
+
+
+int mschapv2_derive_response(const u8 *identity, size_t identity_len,
+			     const u8 *password, size_t password_len,
+			     int pwhash,
+			     const u8 *auth_challenge,
+			     const u8 *peer_challenge,
+			     u8 *nt_response, u8 *auth_response,
+			     u8 *master_key)
+{
+	const u8 *username;
+	size_t username_len;
+	u8 password_hash[16], password_hash_hash[16];
+
+	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Identity",
+			  identity, identity_len);
+	username_len = identity_len;
+	username = mschapv2_remove_domain(identity, &username_len);
+	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: Username",
+			  username, username_len);
+
+	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: auth_challenge",
+		    auth_challenge, MSCHAPV2_CHAL_LEN);
+	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: peer_challenge",
+		    peer_challenge, MSCHAPV2_CHAL_LEN);
+	wpa_hexdump_ascii(MSG_DEBUG, "MSCHAPV2: username",
+			  username, username_len);
+	/* Authenticator response is not really needed yet, but calculate it
+	 * here so that challenges need not be saved. */
+	if (pwhash) {
+		wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: password hash",
+				password, password_len);
+		if (generate_nt_response_pwhash(auth_challenge, peer_challenge,
+						username, username_len,
+						password, nt_response) ||
+		    generate_authenticator_response_pwhash(
+			    password, peer_challenge, auth_challenge,
+			    username, username_len, nt_response,
+			    auth_response))
+			return -1;
+	} else {
+		wpa_hexdump_ascii_key(MSG_DEBUG, "MSCHAPV2: password",
+				      password, password_len);
+		if (generate_nt_response(auth_challenge, peer_challenge,
+					 username, username_len,
+					 password, password_len,
+					 nt_response) ||
+		    generate_authenticator_response(password, password_len,
+						    peer_challenge,
+						    auth_challenge,
+						    username, username_len,
+						    nt_response,
+						    auth_response))
+			return -1;
+	}
+	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: NT Response",
+		    nt_response, MSCHAPV2_NT_RESPONSE_LEN);
+	wpa_hexdump(MSG_DEBUG, "MSCHAPV2: Auth Response",
+		    auth_response, MSCHAPV2_AUTH_RESPONSE_LEN);
+
+	/* Generate master_key here since we have the needed data available. */
+	if (pwhash) {
+		if (hash_nt_password_hash(password, password_hash_hash))
+			return -1;
+	} else {
+		if (nt_password_hash(password, password_len, password_hash) ||
+		    hash_nt_password_hash(password_hash, password_hash_hash))
+			return -1;
+	}
+	if (get_master_key(password_hash_hash, nt_response, master_key))
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "MSCHAPV2: Master Key",
+			master_key, MSCHAPV2_MASTER_KEY_LEN);
+
+	return 0;
+}
+
+
+int mschapv2_verify_auth_response(const u8 *auth_response,
+				  const u8 *buf, size_t buf_len)
+{
+	u8 recv_response[MSCHAPV2_AUTH_RESPONSE_LEN];
+	if (buf_len < 2 + 2 * MSCHAPV2_AUTH_RESPONSE_LEN ||
+	    buf[0] != 'S' || buf[1] != '=' ||
+	    hexstr2bin((char *) (buf + 2), recv_response,
+		       MSCHAPV2_AUTH_RESPONSE_LEN) ||
+	    os_memcmp(auth_response, recv_response,
+		      MSCHAPV2_AUTH_RESPONSE_LEN) != 0)
+		return -1;
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/mschapv2.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,28 @@
+/*
+ * MSCHAPV2 (RFC 2759)
+ * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MSCHAPV2_H
+#define MSCHAPV2_H
+
+#define MSCHAPV2_CHAL_LEN 16
+#define MSCHAPV2_NT_RESPONSE_LEN 24
+#define MSCHAPV2_AUTH_RESPONSE_LEN 20
+#define MSCHAPV2_MASTER_KEY_LEN 16
+
+const u8 * mschapv2_remove_domain(const u8 *username, size_t *len);
+int mschapv2_derive_response(const u8 *username, size_t username_len,
+			     const u8 *password, size_t password_len,
+			     int pwhash,
+			     const u8 *auth_challenge,
+			     const u8 *peer_challenge,
+			     u8 *nt_response, u8 *auth_response,
+			     u8 *master_key);
+int mschapv2_verify_auth_response(const u8 *auth_response,
+				  const u8 *buf, size_t buf_len);
+
+#endif /* MSCHAPV2_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_peer/tncc.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,36 @@
+/*
+ * EAP-TNC - TNCC (IF-IMC and IF-TNCCS)
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TNCC_H
+#define TNCC_H
+
+struct tncc_data;
+
+struct tncc_data * tncc_init(void);
+void tncc_deinit(struct tncc_data *tncc);
+void tncc_init_connection(struct tncc_data *tncc);
+size_t tncc_total_send_len(struct tncc_data *tncc);
+u8 * tncc_copy_send_buf(struct tncc_data *tncc, u8 *pos);
+char * tncc_if_tnccs_start(struct tncc_data *tncc);
+char * tncc_if_tnccs_end(void);
+
+enum tncc_process_res {
+	TNCCS_PROCESS_ERROR = -1,
+	TNCCS_PROCESS_OK_NO_RECOMMENDATION = 0,
+	TNCCS_RECOMMENDATION_ERROR,
+	TNCCS_RECOMMENDATION_ALLOW,
+	TNCCS_RECOMMENDATION_NONE,
+	TNCCS_RECOMMENDATION_ISOLATE
+};
+
+enum tncc_process_res tncc_process_if_tnccs(struct tncc_data *tncc,
+					    const u8 *msg, size_t len);
+
+struct wpabuf * tncc_process_soh_request(int ver, const u8 *data, size_t len);
+
+#endif /* TNCC_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eap_server/eap_methods.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,49 @@
+/*
+ * EAP server method registration
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_SERVER_METHODS_H
+#define EAP_SERVER_METHODS_H
+
+#include "eap_common/eap_defs.h"
+
+const struct eap_method * eap_server_get_eap_method(int vendor,
+						    EapType method);
+struct eap_method * eap_server_method_alloc(int version, int vendor,
+					    EapType method, const char *name);
+void eap_server_method_free(struct eap_method *method);
+int eap_server_method_register(struct eap_method *method);
+
+EapType eap_server_get_type(const char *name, int *vendor);
+void eap_server_unregister_methods(void);
+const char * eap_server_get_name(int vendor, EapType type);
+
+/* EAP server method registration calls for statically linked in methods */
+int eap_server_identity_register(void);
+int eap_server_md5_register(void);
+int eap_server_tls_register(void);
+int eap_server_unauth_tls_register(void);
+int eap_server_mschapv2_register(void);
+int eap_server_peap_register(void);
+int eap_server_tlv_register(void);
+int eap_server_gtc_register(void);
+int eap_server_ttls_register(void);
+int eap_server_sim_register(void);
+int eap_server_aka_register(void);
+int eap_server_aka_prime_register(void);
+int eap_server_pax_register(void);
+int eap_server_psk_register(void);
+int eap_server_sake_register(void);
+int eap_server_gpsk_register(void);
+int eap_server_vendor_test_register(void);
+int eap_server_fast_register(void);
+int eap_server_wsc_register(void);
+int eap_server_ikev2_register(void);
+int eap_server_tnc_register(void);
+int eap_server_pwd_register(void);
+
+#endif /* EAP_SERVER_METHODS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eapol_supp/eapol_supp_sm.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,1938 @@
+/*
+ * EAPOL supplicant state machines
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "state_machine.h"
+#include "wpabuf.h"
+#include "eloop.h"
+#include "crypto/crypto.h"
+#include "crypto/md5.h"
+#include "common/eapol_common.h"
+#include "eap_peer/eap.h"
+#include "eapol_supp_sm.h"
+
+#define STATE_MACHINE_DATA struct eapol_sm
+#define STATE_MACHINE_DEBUG_PREFIX "EAPOL"
+
+
+/* IEEE 802.1X-2004 - Supplicant - EAPOL state machines */
+
+/**
+ * struct eapol_sm - Internal data for EAPOL state machines
+ */
+struct eapol_sm {
+	/* Timers */
+	unsigned int authWhile;
+	unsigned int heldWhile;
+	unsigned int startWhen;
+	unsigned int idleWhile; /* for EAP state machine */
+	int timer_tick_enabled;
+
+	/* Global variables */
+	Boolean eapFail;
+	Boolean eapolEap;
+	Boolean eapSuccess;
+	Boolean initialize;
+	Boolean keyDone;
+	Boolean keyRun;
+	PortControl portControl;
+	Boolean portEnabled;
+	PortStatus suppPortStatus;  /* dot1xSuppControlledPortStatus */
+	Boolean portValid;
+	Boolean suppAbort;
+	Boolean suppFail;
+	Boolean suppStart;
+	Boolean suppSuccess;
+	Boolean suppTimeout;
+
+	/* Supplicant PAE state machine */
+	enum {
+		SUPP_PAE_UNKNOWN = 0,
+		SUPP_PAE_DISCONNECTED = 1,
+		SUPP_PAE_LOGOFF = 2,
+		SUPP_PAE_CONNECTING = 3,
+		SUPP_PAE_AUTHENTICATING = 4,
+		SUPP_PAE_AUTHENTICATED = 5,
+		/* unused(6) */
+		SUPP_PAE_HELD = 7,
+		SUPP_PAE_RESTART = 8,
+		SUPP_PAE_S_FORCE_AUTH = 9,
+		SUPP_PAE_S_FORCE_UNAUTH = 10
+	} SUPP_PAE_state; /* dot1xSuppPaeState */
+	/* Variables */
+	Boolean userLogoff;
+	Boolean logoffSent;
+	unsigned int startCount;
+	Boolean eapRestart;
+	PortControl sPortMode;
+	/* Constants */
+	unsigned int heldPeriod; /* dot1xSuppHeldPeriod */
+	unsigned int startPeriod; /* dot1xSuppStartPeriod */
+	unsigned int maxStart; /* dot1xSuppMaxStart */
+
+	/* Key Receive state machine */
+	enum {
+		KEY_RX_UNKNOWN = 0,
+		KEY_RX_NO_KEY_RECEIVE, KEY_RX_KEY_RECEIVE
+	} KEY_RX_state;
+	/* Variables */
+	Boolean rxKey;
+
+	/* Supplicant Backend state machine */
+	enum {
+		SUPP_BE_UNKNOWN = 0,
+		SUPP_BE_INITIALIZE = 1,
+		SUPP_BE_IDLE = 2,
+		SUPP_BE_REQUEST = 3,
+		SUPP_BE_RECEIVE = 4,
+		SUPP_BE_RESPONSE = 5,
+		SUPP_BE_FAIL = 6,
+		SUPP_BE_TIMEOUT = 7, 
+		SUPP_BE_SUCCESS = 8
+	} SUPP_BE_state; /* dot1xSuppBackendPaeState */
+	/* Variables */
+	Boolean eapNoResp;
+	Boolean eapReq;
+	Boolean eapResp;
+	/* Constants */
+	unsigned int authPeriod; /* dot1xSuppAuthPeriod */
+
+	/* Statistics */
+	unsigned int dot1xSuppEapolFramesRx;
+	unsigned int dot1xSuppEapolFramesTx;
+	unsigned int dot1xSuppEapolStartFramesTx;
+	unsigned int dot1xSuppEapolLogoffFramesTx;
+	unsigned int dot1xSuppEapolRespFramesTx;
+	unsigned int dot1xSuppEapolReqIdFramesRx;
+	unsigned int dot1xSuppEapolReqFramesRx;
+	unsigned int dot1xSuppInvalidEapolFramesRx;
+	unsigned int dot1xSuppEapLengthErrorFramesRx;
+	unsigned int dot1xSuppLastEapolFrameVersion;
+	unsigned char dot1xSuppLastEapolFrameSource[6];
+
+	/* Miscellaneous variables (not defined in IEEE 802.1X-2004) */
+	Boolean changed;
+	struct eap_sm *eap;
+	struct eap_peer_config *config;
+	Boolean initial_req;
+	u8 *last_rx_key;
+	size_t last_rx_key_len;
+	struct wpabuf *eapReqData; /* for EAP */
+	Boolean altAccept; /* for EAP */
+	Boolean altReject; /* for EAP */
+	Boolean replay_counter_valid;
+	u8 last_replay_counter[16];
+	struct eapol_config conf;
+	struct eapol_ctx *ctx;
+	enum { EAPOL_CB_IN_PROGRESS = 0, EAPOL_CB_SUCCESS, EAPOL_CB_FAILURE }
+		cb_status;
+	Boolean cached_pmk;
+
+	Boolean unicast_key_received, broadcast_key_received;
+};
+
+
+static void eapol_sm_txLogoff(struct eapol_sm *sm);
+static void eapol_sm_txStart(struct eapol_sm *sm);
+static void eapol_sm_processKey(struct eapol_sm *sm);
+static void eapol_sm_getSuppRsp(struct eapol_sm *sm);
+static void eapol_sm_txSuppRsp(struct eapol_sm *sm);
+static void eapol_sm_abortSupp(struct eapol_sm *sm);
+static void eapol_sm_abort_cached(struct eapol_sm *sm);
+static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx);
+static void eapol_sm_set_port_authorized(struct eapol_sm *sm);
+static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm);
+
+
+/* Port Timers state machine - implemented as a function that will be called
+ * once a second as a registered event loop timeout */
+static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
+{
+	struct eapol_sm *sm = timeout_ctx;
+
+	if (sm->authWhile > 0) {
+		sm->authWhile--;
+		if (sm->authWhile == 0)
+			wpa_printf(MSG_DEBUG, "EAPOL: authWhile --> 0");
+	}
+	if (sm->heldWhile > 0) {
+		sm->heldWhile--;
+		if (sm->heldWhile == 0)
+			wpa_printf(MSG_DEBUG, "EAPOL: heldWhile --> 0");
+	}
+	if (sm->startWhen > 0) {
+		sm->startWhen--;
+		if (sm->startWhen == 0)
+			wpa_printf(MSG_DEBUG, "EAPOL: startWhen --> 0");
+	}
+	if (sm->idleWhile > 0) {
+		sm->idleWhile--;
+		if (sm->idleWhile == 0)
+			wpa_printf(MSG_DEBUG, "EAPOL: idleWhile --> 0");
+	}
+
+	if (sm->authWhile | sm->heldWhile | sm->startWhen | sm->idleWhile) {
+		eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx,
+				       sm);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAPOL: disable timer tick");
+		sm->timer_tick_enabled = 0;
+	}
+	eapol_sm_step(sm);
+}
+
+
+static void eapol_enable_timer_tick(struct eapol_sm *sm)
+{
+	if (sm->timer_tick_enabled)
+		return;
+	wpa_printf(MSG_DEBUG, "EAPOL: enable timer tick");
+	sm->timer_tick_enabled = 1;
+	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
+	eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
+}
+
+
+SM_STATE(SUPP_PAE, LOGOFF)
+{
+	SM_ENTRY(SUPP_PAE, LOGOFF);
+	eapol_sm_txLogoff(sm);
+	sm->logoffSent = TRUE;
+	sm->suppPortStatus = Unauthorized;
+	eapol_sm_set_port_unauthorized(sm);
+}
+
+
+SM_STATE(SUPP_PAE, DISCONNECTED)
+{
+	SM_ENTRY(SUPP_PAE, DISCONNECTED);
+	sm->sPortMode = Auto;
+	sm->startCount = 0;
+	sm->logoffSent = FALSE;
+	sm->suppPortStatus = Unauthorized;
+	eapol_sm_set_port_unauthorized(sm);
+	sm->suppAbort = TRUE;
+
+	sm->unicast_key_received = FALSE;
+	sm->broadcast_key_received = FALSE;
+
+	/*
+	 * IEEE Std 802.1X-2004 does not clear heldWhile here, but doing so
+	 * allows the timer tick to be stopped more quickly when the port is
+	 * not enabled. Since this variable is used only within HELD state,
+	 * clearing it on initialization does not change actual state machine
+	 * behavior.
+	 */
+	sm->heldWhile = 0;
+}
+
+
+SM_STATE(SUPP_PAE, CONNECTING)
+{
+	int send_start = sm->SUPP_PAE_state == SUPP_PAE_CONNECTING;
+	SM_ENTRY(SUPP_PAE, CONNECTING);
+	if (send_start) {
+		sm->startWhen = sm->startPeriod;
+		sm->startCount++;
+	} else {
+		/*
+		 * Do not send EAPOL-Start immediately since in most cases,
+		 * Authenticator is going to start authentication immediately
+		 * after association and an extra EAPOL-Start is just going to
+		 * delay authentication. Use a short timeout to send the first
+		 * EAPOL-Start if Authenticator does not start authentication.
+		 */
+#ifdef CONFIG_WPS
+		/* Reduce latency on starting WPS negotiation. */
+		sm->startWhen = 1;
+#else /* CONFIG_WPS */
+		sm->startWhen = 3;
+#endif /* CONFIG_WPS */
+	}
+	eapol_enable_timer_tick(sm);
+	sm->eapolEap = FALSE;
+	if (send_start)
+		eapol_sm_txStart(sm);
+}
+
+
+SM_STATE(SUPP_PAE, AUTHENTICATING)
+{
+	SM_ENTRY(SUPP_PAE, AUTHENTICATING);
+	sm->startCount = 0;
+	sm->suppSuccess = FALSE;
+	sm->suppFail = FALSE;
+	sm->suppTimeout = FALSE;
+	sm->keyRun = FALSE;
+	sm->keyDone = FALSE;
+	sm->suppStart = TRUE;
+}
+
+
+SM_STATE(SUPP_PAE, HELD)
+{
+	SM_ENTRY(SUPP_PAE, HELD);
+	sm->heldWhile = sm->heldPeriod;
+	eapol_enable_timer_tick(sm);
+	sm->suppPortStatus = Unauthorized;
+	eapol_sm_set_port_unauthorized(sm);
+	sm->cb_status = EAPOL_CB_FAILURE;
+}
+
+
+SM_STATE(SUPP_PAE, AUTHENTICATED)
+{
+	SM_ENTRY(SUPP_PAE, AUTHENTICATED);
+	sm->suppPortStatus = Authorized;
+	eapol_sm_set_port_authorized(sm);
+	sm->cb_status = EAPOL_CB_SUCCESS;
+}
+
+
+SM_STATE(SUPP_PAE, RESTART)
+{
+	SM_ENTRY(SUPP_PAE, RESTART);
+	sm->eapRestart = TRUE;
+}
+
+
+SM_STATE(SUPP_PAE, S_FORCE_AUTH)
+{
+	SM_ENTRY(SUPP_PAE, S_FORCE_AUTH);
+	sm->suppPortStatus = Authorized;
+	eapol_sm_set_port_authorized(sm);
+	sm->sPortMode = ForceAuthorized;
+}
+
+
+SM_STATE(SUPP_PAE, S_FORCE_UNAUTH)
+{
+	SM_ENTRY(SUPP_PAE, S_FORCE_UNAUTH);
+	sm->suppPortStatus = Unauthorized;
+	eapol_sm_set_port_unauthorized(sm);
+	sm->sPortMode = ForceUnauthorized;
+	eapol_sm_txLogoff(sm);
+}
+
+
+SM_STEP(SUPP_PAE)
+{
+	if ((sm->userLogoff && !sm->logoffSent) &&
+	    !(sm->initialize || !sm->portEnabled))
+		SM_ENTER_GLOBAL(SUPP_PAE, LOGOFF);
+	else if (((sm->portControl == Auto) &&
+		  (sm->sPortMode != sm->portControl)) ||
+		 sm->initialize || !sm->portEnabled)
+		SM_ENTER_GLOBAL(SUPP_PAE, DISCONNECTED);
+	else if ((sm->portControl == ForceAuthorized) &&
+		 (sm->sPortMode != sm->portControl) &&
+		 !(sm->initialize || !sm->portEnabled))
+		SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_AUTH);
+	else if ((sm->portControl == ForceUnauthorized) &&
+		 (sm->sPortMode != sm->portControl) &&
+		 !(sm->initialize || !sm->portEnabled))
+		SM_ENTER_GLOBAL(SUPP_PAE, S_FORCE_UNAUTH);
+	else switch (sm->SUPP_PAE_state) {
+	case SUPP_PAE_UNKNOWN:
+		break;
+	case SUPP_PAE_LOGOFF:
+		if (!sm->userLogoff)
+			SM_ENTER(SUPP_PAE, DISCONNECTED);
+		break;
+	case SUPP_PAE_DISCONNECTED:
+		SM_ENTER(SUPP_PAE, CONNECTING);
+		break;
+	case SUPP_PAE_CONNECTING:
+		if (sm->startWhen == 0 && sm->startCount < sm->maxStart)
+			SM_ENTER(SUPP_PAE, CONNECTING);
+		else if (sm->startWhen == 0 &&
+			 sm->startCount >= sm->maxStart &&
+			 sm->portValid)
+			SM_ENTER(SUPP_PAE, AUTHENTICATED);
+		else if (sm->eapSuccess || sm->eapFail)
+			SM_ENTER(SUPP_PAE, AUTHENTICATING);
+		else if (sm->eapolEap)
+			SM_ENTER(SUPP_PAE, RESTART);
+		else if (sm->startWhen == 0 &&
+			 sm->startCount >= sm->maxStart &&
+			 !sm->portValid)
+			SM_ENTER(SUPP_PAE, HELD);
+		break;
+	case SUPP_PAE_AUTHENTICATING:
+		if (sm->eapSuccess && !sm->portValid &&
+		    sm->conf.accept_802_1x_keys &&
+		    sm->conf.required_keys == 0) {
+			wpa_printf(MSG_DEBUG, "EAPOL: IEEE 802.1X for "
+				   "plaintext connection; no EAPOL-Key frames "
+				   "required");
+			sm->portValid = TRUE;
+			if (sm->ctx->eapol_done_cb)
+				sm->ctx->eapol_done_cb(sm->ctx->ctx);
+		}
+		if (sm->eapSuccess && sm->portValid)
+			SM_ENTER(SUPP_PAE, AUTHENTICATED);
+		else if (sm->eapFail || (sm->keyDone && !sm->portValid))
+			SM_ENTER(SUPP_PAE, HELD);
+		else if (sm->suppTimeout)
+			SM_ENTER(SUPP_PAE, CONNECTING);
+		break;
+	case SUPP_PAE_HELD:
+		if (sm->heldWhile == 0)
+			SM_ENTER(SUPP_PAE, CONNECTING);
+		else if (sm->eapolEap)
+			SM_ENTER(SUPP_PAE, RESTART);
+		break;
+	case SUPP_PAE_AUTHENTICATED:
+		if (sm->eapolEap && sm->portValid)
+			SM_ENTER(SUPP_PAE, RESTART);
+		else if (!sm->portValid)
+			SM_ENTER(SUPP_PAE, DISCONNECTED);
+		break;
+	case SUPP_PAE_RESTART:
+		if (!sm->eapRestart)
+			SM_ENTER(SUPP_PAE, AUTHENTICATING);
+		break;
+	case SUPP_PAE_S_FORCE_AUTH:
+		break;
+	case SUPP_PAE_S_FORCE_UNAUTH:
+		break;
+	}
+}
+
+
+SM_STATE(KEY_RX, NO_KEY_RECEIVE)
+{
+	SM_ENTRY(KEY_RX, NO_KEY_RECEIVE);
+}
+
+
+SM_STATE(KEY_RX, KEY_RECEIVE)
+{
+	SM_ENTRY(KEY_RX, KEY_RECEIVE);
+	eapol_sm_processKey(sm);
+	sm->rxKey = FALSE;
+}
+
+
+SM_STEP(KEY_RX)
+{
+	if (sm->initialize || !sm->portEnabled)
+		SM_ENTER_GLOBAL(KEY_RX, NO_KEY_RECEIVE);
+	switch (sm->KEY_RX_state) {
+	case KEY_RX_UNKNOWN:
+		break;
+	case KEY_RX_NO_KEY_RECEIVE:
+		if (sm->rxKey)
+			SM_ENTER(KEY_RX, KEY_RECEIVE);
+		break;
+	case KEY_RX_KEY_RECEIVE:
+		if (sm->rxKey)
+			SM_ENTER(KEY_RX, KEY_RECEIVE);
+		break;
+	}
+}
+
+
+SM_STATE(SUPP_BE, REQUEST)
+{
+	SM_ENTRY(SUPP_BE, REQUEST);
+	sm->authWhile = 0;
+	sm->eapReq = TRUE;
+	eapol_sm_getSuppRsp(sm);
+}
+
+
+SM_STATE(SUPP_BE, RESPONSE)
+{
+	SM_ENTRY(SUPP_BE, RESPONSE);
+	eapol_sm_txSuppRsp(sm);
+	sm->eapResp = FALSE;
+}
+
+
+SM_STATE(SUPP_BE, SUCCESS)
+{
+	SM_ENTRY(SUPP_BE, SUCCESS);
+	sm->keyRun = TRUE;
+	sm->suppSuccess = TRUE;
+
+	if (eap_key_available(sm->eap)) {
+		/* New key received - clear IEEE 802.1X EAPOL-Key replay
+		 * counter */
+		sm->replay_counter_valid = FALSE;
+	}
+}
+
+
+SM_STATE(SUPP_BE, FAIL)
+{
+	SM_ENTRY(SUPP_BE, FAIL);
+	sm->suppFail = TRUE;
+}
+
+
+SM_STATE(SUPP_BE, TIMEOUT)
+{
+	SM_ENTRY(SUPP_BE, TIMEOUT);
+	sm->suppTimeout = TRUE;
+}
+
+
+SM_STATE(SUPP_BE, IDLE)
+{
+	SM_ENTRY(SUPP_BE, IDLE);
+	sm->suppStart = FALSE;
+	sm->initial_req = TRUE;
+}
+
+
+SM_STATE(SUPP_BE, INITIALIZE)
+{
+	SM_ENTRY(SUPP_BE, INITIALIZE);
+	eapol_sm_abortSupp(sm);
+	sm->suppAbort = FALSE;
+
+	/*
+	 * IEEE Std 802.1X-2004 does not clear authWhile here, but doing so
+	 * allows the timer tick to be stopped more quickly when the port is
+	 * not enabled. Since this variable is used only within RECEIVE state,
+	 * clearing it on initialization does not change actual state machine
+	 * behavior.
+	 */
+	sm->authWhile = 0;
+}
+
+
+SM_STATE(SUPP_BE, RECEIVE)
+{
+	SM_ENTRY(SUPP_BE, RECEIVE);
+	sm->authWhile = sm->authPeriod;
+	eapol_enable_timer_tick(sm);
+	sm->eapolEap = FALSE;
+	sm->eapNoResp = FALSE;
+	sm->initial_req = FALSE;
+}
+
+
+SM_STEP(SUPP_BE)
+{
+	if (sm->initialize || sm->suppAbort)
+		SM_ENTER_GLOBAL(SUPP_BE, INITIALIZE);
+	else switch (sm->SUPP_BE_state) {
+	case SUPP_BE_UNKNOWN:
+		break;
+	case SUPP_BE_REQUEST:
+		/*
+		 * IEEE Std 802.1X-2004 has transitions from REQUEST to FAIL
+		 * and SUCCESS based on eapFail and eapSuccess, respectively.
+		 * However, IEEE Std 802.1X-2004 is also specifying that
+		 * eapNoResp should be set in conjunction with eapSuccess and
+		 * eapFail which would mean that more than one of the
+		 * transitions here would be activated at the same time.
+		 * Skipping RESPONSE and/or RECEIVE states in these cases can
+		 * cause problems and the direct transitions to do not seem
+		 * correct. Because of this, the conditions for these
+		 * transitions are verified only after eapNoResp. They are
+		 * unlikely to be used since eapNoResp should always be set if
+		 * either of eapSuccess or eapFail is set.
+		 */
+		if (sm->eapResp && sm->eapNoResp) {
+			wpa_printf(MSG_DEBUG, "EAPOL: SUPP_BE REQUEST: both "
+				   "eapResp and eapNoResp set?!");
+		}
+		if (sm->eapResp)
+			SM_ENTER(SUPP_BE, RESPONSE);
+		else if (sm->eapNoResp)
+			SM_ENTER(SUPP_BE, RECEIVE);
+		else if (sm->eapFail)
+			SM_ENTER(SUPP_BE, FAIL);
+		else if (sm->eapSuccess)
+			SM_ENTER(SUPP_BE, SUCCESS);
+		break;
+	case SUPP_BE_RESPONSE:
+		SM_ENTER(SUPP_BE, RECEIVE);
+		break;
+	case SUPP_BE_SUCCESS:
+		SM_ENTER(SUPP_BE, IDLE);
+		break;
+	case SUPP_BE_FAIL:
+		SM_ENTER(SUPP_BE, IDLE);
+		break;
+	case SUPP_BE_TIMEOUT:
+		SM_ENTER(SUPP_BE, IDLE);
+		break;
+	case SUPP_BE_IDLE:
+		if (sm->eapFail && sm->suppStart)
+			SM_ENTER(SUPP_BE, FAIL);
+		else if (sm->eapolEap && sm->suppStart)
+			SM_ENTER(SUPP_BE, REQUEST);
+		else if (sm->eapSuccess && sm->suppStart)
+			SM_ENTER(SUPP_BE, SUCCESS);
+		break;
+	case SUPP_BE_INITIALIZE:
+		SM_ENTER(SUPP_BE, IDLE);
+		break;
+	case SUPP_BE_RECEIVE:
+		if (sm->eapolEap)
+			SM_ENTER(SUPP_BE, REQUEST);
+		else if (sm->eapFail)
+			SM_ENTER(SUPP_BE, FAIL);
+		else if (sm->authWhile == 0)
+			SM_ENTER(SUPP_BE, TIMEOUT);
+		else if (sm->eapSuccess)
+			SM_ENTER(SUPP_BE, SUCCESS);
+		break;
+	}
+}
+
+
+static void eapol_sm_txLogoff(struct eapol_sm *sm)
+{
+	wpa_printf(MSG_DEBUG, "EAPOL: txLogoff");
+	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
+			    IEEE802_1X_TYPE_EAPOL_LOGOFF, (u8 *) "", 0);
+	sm->dot1xSuppEapolLogoffFramesTx++;
+	sm->dot1xSuppEapolFramesTx++;
+}
+
+
+static void eapol_sm_txStart(struct eapol_sm *sm)
+{
+	wpa_printf(MSG_DEBUG, "EAPOL: txStart");
+	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
+			    IEEE802_1X_TYPE_EAPOL_START, (u8 *) "", 0);
+	sm->dot1xSuppEapolStartFramesTx++;
+	sm->dot1xSuppEapolFramesTx++;
+}
+
+
+#define IEEE8021X_ENCR_KEY_LEN 32
+#define IEEE8021X_SIGN_KEY_LEN 32
+
+struct eap_key_data {
+	u8 encr_key[IEEE8021X_ENCR_KEY_LEN];
+	u8 sign_key[IEEE8021X_SIGN_KEY_LEN];
+};
+
+
+static void eapol_sm_processKey(struct eapol_sm *sm)
+{
+#ifndef CONFIG_FIPS
+	struct ieee802_1x_hdr *hdr;
+	struct ieee802_1x_eapol_key *key;
+	struct eap_key_data keydata;
+	u8 orig_key_sign[IEEE8021X_KEY_SIGN_LEN], datakey[32];
+	u8 ekey[IEEE8021X_KEY_IV_LEN + IEEE8021X_ENCR_KEY_LEN];
+	int key_len, res, sign_key_len, encr_key_len;
+	u16 rx_key_length;
+	size_t plen;
+
+	wpa_printf(MSG_DEBUG, "EAPOL: processKey");
+	if (sm->last_rx_key == NULL)
+		return;
+
+	if (!sm->conf.accept_802_1x_keys) {
+		wpa_printf(MSG_WARNING, "EAPOL: Received IEEE 802.1X EAPOL-Key"
+			   " even though this was not accepted - "
+			   "ignoring this packet");
+		return;
+	}
+
+	if (sm->last_rx_key_len < sizeof(*hdr) + sizeof(*key))
+		return;
+	hdr = (struct ieee802_1x_hdr *) sm->last_rx_key;
+	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
+	plen = be_to_host16(hdr->length);
+	if (sizeof(*hdr) + plen > sm->last_rx_key_len || plen < sizeof(*key)) {
+		wpa_printf(MSG_WARNING, "EAPOL: Too short EAPOL-Key frame");
+		return;
+	}
+	rx_key_length = WPA_GET_BE16(key->key_length);
+	wpa_printf(MSG_DEBUG, "EAPOL: RX IEEE 802.1X ver=%d type=%d len=%d "
+		   "EAPOL-Key: type=%d key_length=%d key_index=0x%x",
+		   hdr->version, hdr->type, be_to_host16(hdr->length),
+		   key->type, rx_key_length, key->key_index);
+
+	eapol_sm_notify_lower_layer_success(sm, 1);
+	sign_key_len = IEEE8021X_SIGN_KEY_LEN;
+	encr_key_len = IEEE8021X_ENCR_KEY_LEN;
+	res = eapol_sm_get_key(sm, (u8 *) &keydata, sizeof(keydata));
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "EAPOL: Could not get master key for "
+			   "decrypting EAPOL-Key keys");
+		return;
+	}
+	if (res == 16) {
+		/* LEAP derives only 16 bytes of keying material. */
+		res = eapol_sm_get_key(sm, (u8 *) &keydata, 16);
+		if (res) {
+			wpa_printf(MSG_DEBUG, "EAPOL: Could not get LEAP "
+				   "master key for decrypting EAPOL-Key keys");
+			return;
+		}
+		sign_key_len = 16;
+		encr_key_len = 16;
+		os_memcpy(keydata.sign_key, keydata.encr_key, 16);
+	} else if (res) {
+		wpa_printf(MSG_DEBUG, "EAPOL: Could not get enough master key "
+			   "data for decrypting EAPOL-Key keys (res=%d)", res);
+		return;
+	}
+
+	/* The key replay_counter must increase when same master key */
+	if (sm->replay_counter_valid &&
+	    os_memcmp(sm->last_replay_counter, key->replay_counter,
+		      IEEE8021X_REPLAY_COUNTER_LEN) >= 0) {
+		wpa_printf(MSG_WARNING, "EAPOL: EAPOL-Key replay counter did "
+			   "not increase - ignoring key");
+		wpa_hexdump(MSG_DEBUG, "EAPOL: last replay counter",
+			    sm->last_replay_counter,
+			    IEEE8021X_REPLAY_COUNTER_LEN);
+		wpa_hexdump(MSG_DEBUG, "EAPOL: received replay counter",
+			    key->replay_counter, IEEE8021X_REPLAY_COUNTER_LEN);
+		return;
+	}
+
+	/* Verify key signature (HMAC-MD5) */
+	os_memcpy(orig_key_sign, key->key_signature, IEEE8021X_KEY_SIGN_LEN);
+	os_memset(key->key_signature, 0, IEEE8021X_KEY_SIGN_LEN);
+	hmac_md5(keydata.sign_key, sign_key_len,
+		 sm->last_rx_key, sizeof(*hdr) + be_to_host16(hdr->length),
+		 key->key_signature);
+	if (os_memcmp(orig_key_sign, key->key_signature,
+		      IEEE8021X_KEY_SIGN_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "EAPOL: Invalid key signature in "
+			   "EAPOL-Key packet");
+		os_memcpy(key->key_signature, orig_key_sign,
+			  IEEE8021X_KEY_SIGN_LEN);
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "EAPOL: EAPOL-Key key signature verified");
+
+	key_len = plen - sizeof(*key);
+	if (key_len > 32 || rx_key_length > 32) {
+		wpa_printf(MSG_WARNING, "EAPOL: Too long key data length %d",
+			   key_len ? key_len : rx_key_length);
+		return;
+	}
+	if (key_len == rx_key_length) {
+		os_memcpy(ekey, key->key_iv, IEEE8021X_KEY_IV_LEN);
+		os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
+			  encr_key_len);
+		os_memcpy(datakey, key + 1, key_len);
+		rc4_skip(ekey, IEEE8021X_KEY_IV_LEN + encr_key_len, 0,
+			 datakey, key_len);
+		wpa_hexdump_key(MSG_DEBUG, "EAPOL: Decrypted(RC4) key",
+				datakey, key_len);
+	} else if (key_len == 0) {
+		/*
+		 * IEEE 802.1X-2004 specifies that least significant Key Length
+		 * octets from MS-MPPE-Send-Key are used as the key if the key
+		 * data is not present. This seems to be meaning the beginning
+		 * of the MS-MPPE-Send-Key. In addition, MS-MPPE-Send-Key in
+		 * Supplicant corresponds to MS-MPPE-Recv-Key in Authenticator.
+		 * Anyway, taking the beginning of the keying material from EAP
+		 * seems to interoperate with Authenticators.
+		 */
+		key_len = rx_key_length;
+		os_memcpy(datakey, keydata.encr_key, key_len);
+		wpa_hexdump_key(MSG_DEBUG, "EAPOL: using part of EAP keying "
+				"material data encryption key",
+				datakey, key_len);
+	} else {
+		wpa_printf(MSG_DEBUG, "EAPOL: Invalid key data length %d "
+			   "(key_length=%d)", key_len, rx_key_length);
+		return;
+	}
+
+	sm->replay_counter_valid = TRUE;
+	os_memcpy(sm->last_replay_counter, key->replay_counter,
+		  IEEE8021X_REPLAY_COUNTER_LEN);
+
+	wpa_printf(MSG_DEBUG, "EAPOL: Setting dynamic WEP key: %s keyidx %d "
+		   "len %d",
+		   key->key_index & IEEE8021X_KEY_INDEX_FLAG ?
+		   "unicast" : "broadcast",
+		   key->key_index & IEEE8021X_KEY_INDEX_MASK, key_len);
+
+	if (sm->ctx->set_wep_key &&
+	    sm->ctx->set_wep_key(sm->ctx->ctx,
+				 key->key_index & IEEE8021X_KEY_INDEX_FLAG,
+				 key->key_index & IEEE8021X_KEY_INDEX_MASK,
+				 datakey, key_len) < 0) {
+		wpa_printf(MSG_WARNING, "EAPOL: Failed to set WEP key to the "
+			   " driver.");
+	} else {
+		if (key->key_index & IEEE8021X_KEY_INDEX_FLAG)
+			sm->unicast_key_received = TRUE;
+		else
+			sm->broadcast_key_received = TRUE;
+
+		if ((sm->unicast_key_received ||
+		     !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_UNICAST)) &&
+		    (sm->broadcast_key_received ||
+		     !(sm->conf.required_keys & EAPOL_REQUIRE_KEY_BROADCAST)))
+		{
+			wpa_printf(MSG_DEBUG, "EAPOL: all required EAPOL-Key "
+				   "frames received");
+			sm->portValid = TRUE;
+			if (sm->ctx->eapol_done_cb)
+				sm->ctx->eapol_done_cb(sm->ctx->ctx);
+		}
+	}
+#endif /* CONFIG_FIPS */
+}
+
+
+static void eapol_sm_getSuppRsp(struct eapol_sm *sm)
+{
+	wpa_printf(MSG_DEBUG, "EAPOL: getSuppRsp");
+	/* EAP layer processing; no special code is needed, since Supplicant
+	 * Backend state machine is waiting for eapNoResp or eapResp to be set
+	 * and these are only set in the EAP state machine when the processing
+	 * has finished. */
+}
+
+
+static void eapol_sm_txSuppRsp(struct eapol_sm *sm)
+{
+	struct wpabuf *resp;
+
+	wpa_printf(MSG_DEBUG, "EAPOL: txSuppRsp");
+	resp = eap_get_eapRespData(sm->eap);
+	if (resp == NULL) {
+		wpa_printf(MSG_WARNING, "EAPOL: txSuppRsp - EAP response data "
+			   "not available");
+		return;
+	}
+
+	/* Send EAP-Packet from the EAP layer to the Authenticator */
+	sm->ctx->eapol_send(sm->ctx->eapol_send_ctx,
+			    IEEE802_1X_TYPE_EAP_PACKET, wpabuf_head(resp),
+			    wpabuf_len(resp));
+
+	/* eapRespData is not used anymore, so free it here */
+	wpabuf_free(resp);
+
+	if (sm->initial_req)
+		sm->dot1xSuppEapolReqIdFramesRx++;
+	else
+		sm->dot1xSuppEapolReqFramesRx++;
+	sm->dot1xSuppEapolRespFramesTx++;
+	sm->dot1xSuppEapolFramesTx++;
+}
+
+
+static void eapol_sm_abortSupp(struct eapol_sm *sm)
+{
+	/* release system resources that may have been allocated for the
+	 * authentication session */
+	os_free(sm->last_rx_key);
+	sm->last_rx_key = NULL;
+	wpabuf_free(sm->eapReqData);
+	sm->eapReqData = NULL;
+	eap_sm_abort(sm->eap);
+}
+
+
+static void eapol_sm_step_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	eapol_sm_step(timeout_ctx);
+}
+
+
+static void eapol_sm_set_port_authorized(struct eapol_sm *sm)
+{
+	if (sm->ctx->port_cb)
+		sm->ctx->port_cb(sm->ctx->ctx, 1);
+}
+
+
+static void eapol_sm_set_port_unauthorized(struct eapol_sm *sm)
+{
+	if (sm->ctx->port_cb)
+		sm->ctx->port_cb(sm->ctx->ctx, 0);
+}
+
+
+/**
+ * eapol_sm_step - EAPOL state machine step function
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * This function is called to notify the state machine about changed external
+ * variables. It will step through the EAPOL state machines in loop to process
+ * all triggered state changes.
+ */
+void eapol_sm_step(struct eapol_sm *sm)
+{
+	int i;
+
+	/* In theory, it should be ok to run this in loop until !changed.
+	 * However, it is better to use a limit on number of iterations to
+	 * allow events (e.g., SIGTERM) to stop the program cleanly if the
+	 * state machine were to generate a busy loop. */
+	for (i = 0; i < 100; i++) {
+		sm->changed = FALSE;
+		SM_STEP_RUN(SUPP_PAE);
+		SM_STEP_RUN(KEY_RX);
+		SM_STEP_RUN(SUPP_BE);
+		if (eap_peer_sm_step(sm->eap))
+			sm->changed = TRUE;
+		if (!sm->changed)
+			break;
+	}
+
+	if (sm->changed) {
+		/* restart EAPOL state machine step from timeout call in order
+		 * to allow other events to be processed. */
+		eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
+		eloop_register_timeout(0, 0, eapol_sm_step_timeout, NULL, sm);
+	}
+
+	if (sm->ctx->cb && sm->cb_status != EAPOL_CB_IN_PROGRESS) {
+		int success = sm->cb_status == EAPOL_CB_SUCCESS ? 1 : 0;
+		sm->cb_status = EAPOL_CB_IN_PROGRESS;
+		sm->ctx->cb(sm, success, sm->ctx->cb_ctx);
+	}
+}
+
+
+#ifdef CONFIG_CTRL_IFACE
+static const char *eapol_supp_pae_state(int state)
+{
+	switch (state) {
+	case SUPP_PAE_LOGOFF:
+		return "LOGOFF";
+	case SUPP_PAE_DISCONNECTED:
+		return "DISCONNECTED";
+	case SUPP_PAE_CONNECTING:
+		return "CONNECTING";
+	case SUPP_PAE_AUTHENTICATING:
+		return "AUTHENTICATING";
+	case SUPP_PAE_HELD:
+		return "HELD";
+	case SUPP_PAE_AUTHENTICATED:
+		return "AUTHENTICATED";
+	case SUPP_PAE_RESTART:
+		return "RESTART";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+static const char *eapol_supp_be_state(int state)
+{
+	switch (state) {
+	case SUPP_BE_REQUEST:
+		return "REQUEST";
+	case SUPP_BE_RESPONSE:
+		return "RESPONSE";
+	case SUPP_BE_SUCCESS:
+		return "SUCCESS";
+	case SUPP_BE_FAIL:
+		return "FAIL";
+	case SUPP_BE_TIMEOUT:
+		return "TIMEOUT";
+	case SUPP_BE_IDLE:
+		return "IDLE";
+	case SUPP_BE_INITIALIZE:
+		return "INITIALIZE";
+	case SUPP_BE_RECEIVE:
+		return "RECEIVE";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+static const char * eapol_port_status(PortStatus status)
+{
+	if (status == Authorized)
+		return "Authorized";
+	else
+		return "Unauthorized";
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static const char * eapol_port_control(PortControl ctrl)
+{
+	switch (ctrl) {
+	case Auto:
+		return "Auto";
+	case ForceUnauthorized:
+		return "ForceUnauthorized";
+	case ForceAuthorized:
+		return "ForceAuthorized";
+	default:
+		return "Unknown";
+	}
+}
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+
+
+/**
+ * eapol_sm_configure - Set EAPOL variables
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @heldPeriod: dot1xSuppHeldPeriod
+ * @authPeriod: dot1xSuppAuthPeriod
+ * @startPeriod: dot1xSuppStartPeriod
+ * @maxStart: dot1xSuppMaxStart
+ *
+ * Set configurable EAPOL state machine variables. Each variable can be set to
+ * the given value or ignored if set to -1 (to set only some of the variables).
+ */
+void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
+			int startPeriod, int maxStart)
+{
+	if (sm == NULL)
+		return;
+	if (heldPeriod >= 0)
+		sm->heldPeriod = heldPeriod;
+	if (authPeriod >= 0)
+		sm->authPeriod = authPeriod;
+	if (startPeriod >= 0)
+		sm->startPeriod = startPeriod;
+	if (maxStart >= 0)
+		sm->maxStart = maxStart;
+}
+
+
+/**
+ * eapol_sm_get_method_name - Get EAPOL method name
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * Returns: Static string containing name of current eap method or NULL
+ */
+const char * eapol_sm_get_method_name(struct eapol_sm *sm)
+{
+	if (sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED ||
+	    sm->suppPortStatus != Authorized)
+		return NULL;
+
+	return eap_sm_get_method_name(sm->eap);
+}
+
+
+#ifdef CONFIG_CTRL_IFACE
+/**
+ * eapol_sm_get_status - Get EAPOL state machine status
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @buf: Buffer for status information
+ * @buflen: Maximum buffer length
+ * @verbose: Whether to include verbose status information
+ * Returns: Number of bytes written to buf.
+ *
+ * Query EAPOL state machine for status information. This function fills in a
+ * text area with current status information from the EAPOL state machine. If
+ * the buffer (buf) is not large enough, status information will be truncated
+ * to fit the buffer.
+ */
+int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
+			int verbose)
+{
+	int len, ret;
+	if (sm == NULL)
+		return 0;
+
+	len = os_snprintf(buf, buflen,
+			  "Supplicant PAE state=%s\n"
+			  "suppPortStatus=%s\n",
+			  eapol_supp_pae_state(sm->SUPP_PAE_state),
+			  eapol_port_status(sm->suppPortStatus));
+	if (len < 0 || (size_t) len >= buflen)
+		return 0;
+
+	if (verbose) {
+		ret = os_snprintf(buf + len, buflen - len,
+				  "heldPeriod=%u\n"
+				  "authPeriod=%u\n"
+				  "startPeriod=%u\n"
+				  "maxStart=%u\n"
+				  "portControl=%s\n"
+				  "Supplicant Backend state=%s\n",
+				  sm->heldPeriod,
+				  sm->authPeriod,
+				  sm->startPeriod,
+				  sm->maxStart,
+				  eapol_port_control(sm->portControl),
+				  eapol_supp_be_state(sm->SUPP_BE_state));
+		if (ret < 0 || (size_t) ret >= buflen - len)
+			return len;
+		len += ret;
+	}
+
+	len += eap_sm_get_status(sm->eap, buf + len, buflen - len, verbose);
+
+	return len;
+}
+
+
+/**
+ * eapol_sm_get_mib - Get EAPOL state machine MIBs
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @buf: Buffer for MIB information
+ * @buflen: Maximum buffer length
+ * Returns: Number of bytes written to buf.
+ *
+ * Query EAPOL state machine for MIB information. This function fills in a
+ * text area with current MIB information from the EAPOL state machine. If
+ * the buffer (buf) is not large enough, MIB information will be truncated to
+ * fit the buffer.
+ */
+int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen)
+{
+	size_t len;
+	int ret;
+
+	if (sm == NULL)
+		return 0;
+	ret = os_snprintf(buf, buflen,
+			  "dot1xSuppPaeState=%d\n"
+			  "dot1xSuppHeldPeriod=%u\n"
+			  "dot1xSuppAuthPeriod=%u\n"
+			  "dot1xSuppStartPeriod=%u\n"
+			  "dot1xSuppMaxStart=%u\n"
+			  "dot1xSuppSuppControlledPortStatus=%s\n"
+			  "dot1xSuppBackendPaeState=%d\n",
+			  sm->SUPP_PAE_state,
+			  sm->heldPeriod,
+			  sm->authPeriod,
+			  sm->startPeriod,
+			  sm->maxStart,
+			  sm->suppPortStatus == Authorized ?
+			  "Authorized" : "Unauthorized",
+			  sm->SUPP_BE_state);
+
+	if (ret < 0 || (size_t) ret >= buflen)
+		return 0;
+	len = ret;
+
+	ret = os_snprintf(buf + len, buflen - len,
+			  "dot1xSuppEapolFramesRx=%u\n"
+			  "dot1xSuppEapolFramesTx=%u\n"
+			  "dot1xSuppEapolStartFramesTx=%u\n"
+			  "dot1xSuppEapolLogoffFramesTx=%u\n"
+			  "dot1xSuppEapolRespFramesTx=%u\n"
+			  "dot1xSuppEapolReqIdFramesRx=%u\n"
+			  "dot1xSuppEapolReqFramesRx=%u\n"
+			  "dot1xSuppInvalidEapolFramesRx=%u\n"
+			  "dot1xSuppEapLengthErrorFramesRx=%u\n"
+			  "dot1xSuppLastEapolFrameVersion=%u\n"
+			  "dot1xSuppLastEapolFrameSource=" MACSTR "\n",
+			  sm->dot1xSuppEapolFramesRx,
+			  sm->dot1xSuppEapolFramesTx,
+			  sm->dot1xSuppEapolStartFramesTx,
+			  sm->dot1xSuppEapolLogoffFramesTx,
+			  sm->dot1xSuppEapolRespFramesTx,
+			  sm->dot1xSuppEapolReqIdFramesRx,
+			  sm->dot1xSuppEapolReqFramesRx,
+			  sm->dot1xSuppInvalidEapolFramesRx,
+			  sm->dot1xSuppEapLengthErrorFramesRx,
+			  sm->dot1xSuppLastEapolFrameVersion,
+			  MAC2STR(sm->dot1xSuppLastEapolFrameSource));
+
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	return len;
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
+/**
+ * eapol_sm_rx_eapol - Process received EAPOL frames
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @src: Source MAC address of the EAPOL packet
+ * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
+ * @len: Length of the EAPOL frame
+ * Returns: 1 = EAPOL frame processed, 0 = not for EAPOL state machine,
+ * -1 failure
+ */
+int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
+		      size_t len)
+{
+	const struct ieee802_1x_hdr *hdr;
+	const struct ieee802_1x_eapol_key *key;
+	int data_len;
+	int res = 1;
+	size_t plen;
+
+	if (sm == NULL)
+		return 0;
+	sm->dot1xSuppEapolFramesRx++;
+	if (len < sizeof(*hdr)) {
+		sm->dot1xSuppInvalidEapolFramesRx++;
+		return 0;
+	}
+	hdr = (const struct ieee802_1x_hdr *) buf;
+	sm->dot1xSuppLastEapolFrameVersion = hdr->version;
+	os_memcpy(sm->dot1xSuppLastEapolFrameSource, src, ETH_ALEN);
+	if (hdr->version < EAPOL_VERSION) {
+		/* TODO: backwards compatibility */
+	}
+	plen = be_to_host16(hdr->length);
+	if (plen > len - sizeof(*hdr)) {
+		sm->dot1xSuppEapLengthErrorFramesRx++;
+		return 0;
+	}
+#ifdef CONFIG_WPS
+	if (sm->conf.workaround &&
+	    plen < len - sizeof(*hdr) &&
+	    hdr->type == IEEE802_1X_TYPE_EAP_PACKET &&
+	    len - sizeof(*hdr) > sizeof(struct eap_hdr)) {
+		const struct eap_hdr *ehdr =
+			(const struct eap_hdr *) (hdr + 1);
+		u16 elen;
+
+		elen = be_to_host16(ehdr->length);
+		if (elen > plen && elen <= len - sizeof(*hdr)) {
+			/*
+			 * Buffalo WHR-G125 Ver.1.47 seems to send EAP-WPS
+			 * packets with too short EAPOL header length field
+			 * (14 octets). This is fixed in firmware Ver.1.49.
+			 * As a workaround, fix the EAPOL header based on the
+			 * correct length in the EAP packet.
+			 */
+			wpa_printf(MSG_DEBUG, "EAPOL: Workaround - fix EAPOL "
+				   "payload length based on EAP header: "
+				   "%d -> %d", (int) plen, elen);
+			plen = elen;
+		}
+	}
+#endif /* CONFIG_WPS */
+	data_len = plen + sizeof(*hdr);
+
+	switch (hdr->type) {
+	case IEEE802_1X_TYPE_EAP_PACKET:
+		if (sm->cached_pmk) {
+			/* Trying to use PMKSA caching, but Authenticator did
+			 * not seem to have a matching entry. Need to restart
+			 * EAPOL state machines.
+			 */
+			eapol_sm_abort_cached(sm);
+		}
+		wpabuf_free(sm->eapReqData);
+		sm->eapReqData = wpabuf_alloc_copy(hdr + 1, plen);
+		if (sm->eapReqData) {
+			wpa_printf(MSG_DEBUG, "EAPOL: Received EAP-Packet "
+				   "frame");
+			sm->eapolEap = TRUE;
+			eapol_sm_step(sm);
+		}
+		break;
+	case IEEE802_1X_TYPE_EAPOL_KEY:
+		if (plen < sizeof(*key)) {
+			wpa_printf(MSG_DEBUG, "EAPOL: Too short EAPOL-Key "
+				   "frame received");
+			break;
+		}
+		key = (const struct ieee802_1x_eapol_key *) (hdr + 1);
+		if (key->type == EAPOL_KEY_TYPE_WPA ||
+		    key->type == EAPOL_KEY_TYPE_RSN) {
+			/* WPA Supplicant takes care of this frame. */
+			wpa_printf(MSG_DEBUG, "EAPOL: Ignoring WPA EAPOL-Key "
+				   "frame in EAPOL state machines");
+			res = 0;
+			break;
+		}
+		if (key->type != EAPOL_KEY_TYPE_RC4) {
+			wpa_printf(MSG_DEBUG, "EAPOL: Ignored unknown "
+				   "EAPOL-Key type %d", key->type);
+			break;
+		}
+		os_free(sm->last_rx_key);
+		sm->last_rx_key = os_malloc(data_len);
+		if (sm->last_rx_key) {
+			wpa_printf(MSG_DEBUG, "EAPOL: Received EAPOL-Key "
+				   "frame");
+			os_memcpy(sm->last_rx_key, buf, data_len);
+			sm->last_rx_key_len = data_len;
+			sm->rxKey = TRUE;
+			eapol_sm_step(sm);
+		}
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "EAPOL: Received unknown EAPOL type %d",
+			   hdr->type);
+		sm->dot1xSuppInvalidEapolFramesRx++;
+		break;
+	}
+
+	return res;
+}
+
+
+/**
+ * eapol_sm_notify_tx_eapol_key - Notification about transmitted EAPOL packet
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * Notify EAPOL state machine about transmitted EAPOL packet from an external
+ * component, e.g., WPA. This will update the statistics.
+ */
+void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
+{
+	if (sm)
+		sm->dot1xSuppEapolFramesTx++;
+}
+
+
+/**
+ * eapol_sm_notify_portEnabled - Notification about portEnabled change
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @enabled: New portEnabled value
+ *
+ * Notify EAPOL state machine about new portEnabled value.
+ */
+void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled)
+{
+	if (sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
+		   "portEnabled=%d", enabled);
+	sm->portEnabled = enabled;
+	eapol_sm_step(sm);
+}
+
+
+/**
+ * eapol_sm_notify_portValid - Notification about portValid change
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @valid: New portValid value
+ *
+ * Notify EAPOL state machine about new portValid value.
+ */
+void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid)
+{
+	if (sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
+		   "portValid=%d", valid);
+	sm->portValid = valid;
+	eapol_sm_step(sm);
+}
+
+
+/**
+ * eapol_sm_notify_eap_success - Notification of external EAP success trigger
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @success: %TRUE = set success, %FALSE = clear success
+ *
+ * Notify the EAPOL state machine that external event has forced EAP state to
+ * success (success = %TRUE). This can be cleared by setting success = %FALSE.
+ *
+ * This function is called to update EAP state when WPA-PSK key handshake has
+ * been completed successfully since WPA-PSK does not use EAP state machine.
+ */
+void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success)
+{
+	if (sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
+		   "EAP success=%d", success);
+	sm->eapSuccess = success;
+	sm->altAccept = success;
+	if (success)
+		eap_notify_success(sm->eap);
+	eapol_sm_step(sm);
+}
+
+
+/**
+ * eapol_sm_notify_eap_fail - Notification of external EAP failure trigger
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @fail: %TRUE = set failure, %FALSE = clear failure
+ *
+ * Notify EAPOL state machine that external event has forced EAP state to
+ * failure (fail = %TRUE). This can be cleared by setting fail = %FALSE.
+ */
+void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
+{
+	if (sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
+		   "EAP fail=%d", fail);
+	sm->eapFail = fail;
+	sm->altReject = fail;
+	eapol_sm_step(sm);
+}
+
+
+/**
+ * eapol_sm_notify_config - Notification of EAPOL configuration change
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @config: Pointer to current network EAP configuration
+ * @conf: Pointer to EAPOL configuration data
+ *
+ * Notify EAPOL state machine that configuration has changed. config will be
+ * stored as a backpointer to network configuration. This can be %NULL to clear
+ * the stored pointed. conf will be copied to local EAPOL/EAP configuration
+ * data. If conf is %NULL, this part of the configuration change will be
+ * skipped.
+ */
+void eapol_sm_notify_config(struct eapol_sm *sm,
+			    struct eap_peer_config *config,
+			    const struct eapol_config *conf)
+{
+	if (sm == NULL)
+		return;
+
+	sm->config = config;
+
+	if (conf == NULL)
+		return;
+
+	sm->conf.accept_802_1x_keys = conf->accept_802_1x_keys;
+	sm->conf.required_keys = conf->required_keys;
+	sm->conf.fast_reauth = conf->fast_reauth;
+	sm->conf.workaround = conf->workaround;
+	if (sm->eap) {
+		eap_set_fast_reauth(sm->eap, conf->fast_reauth);
+		eap_set_workaround(sm->eap, conf->workaround);
+		eap_set_force_disabled(sm->eap, conf->eap_disabled);
+	}
+}
+
+
+/**
+ * eapol_sm_get_key - Get master session key (MSK) from EAP
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @key: Pointer for key buffer
+ * @len: Number of bytes to copy to key
+ * Returns: 0 on success (len of key available), maximum available key len
+ * (>0) if key is available but it is shorter than len, or -1 on failure.
+ *
+ * Fetch EAP keying material (MSK, eapKeyData) from EAP state machine. The key
+ * is available only after a successful authentication.
+ */
+int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
+{
+	const u8 *eap_key;
+	size_t eap_len;
+
+	if (sm == NULL || !eap_key_available(sm->eap)) {
+		wpa_printf(MSG_DEBUG, "EAPOL: EAP key not available");
+		return -1;
+	}
+	eap_key = eap_get_eapKeyData(sm->eap, &eap_len);
+	if (eap_key == NULL) {
+		wpa_printf(MSG_DEBUG, "EAPOL: Failed to get eapKeyData");
+		return -1;
+	}
+	if (len > eap_len) {
+		wpa_printf(MSG_DEBUG, "EAPOL: Requested key length (%lu) not "
+			   "available (len=%lu)",
+			   (unsigned long) len, (unsigned long) eap_len);
+		return eap_len;
+	}
+	os_memcpy(key, eap_key, len);
+	wpa_printf(MSG_DEBUG, "EAPOL: Successfully fetched key (len=%lu)",
+		   (unsigned long) len);
+	return 0;
+}
+
+
+/**
+ * eapol_sm_notify_logoff - Notification of logon/logoff commands
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @logoff: Whether command was logoff
+ *
+ * Notify EAPOL state machines that user requested logon/logoff.
+ */
+void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
+{
+	if (sm) {
+		sm->userLogoff = logoff;
+		eapol_sm_step(sm);
+	}
+}
+
+
+/**
+ * eapol_sm_notify_pmkid_attempt - Notification of successful PMKSA caching
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * Notify EAPOL state machines that PMKSA caching was successful. This is used
+ * to move EAPOL and EAP state machines into authenticated/successful state.
+ */
+void eapol_sm_notify_cached(struct eapol_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "EAPOL: PMKSA caching was used - skip EAPOL");
+	sm->eapSuccess = TRUE;
+	eap_notify_success(sm->eap);
+	eapol_sm_step(sm);
+}
+
+
+/**
+ * eapol_sm_notify_pmkid_attempt - Notification of PMKSA caching
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @attempt: Whether PMKSA caching is tried
+ *
+ * Notify EAPOL state machines whether PMKSA caching is used.
+ */
+void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt)
+{
+	if (sm == NULL)
+		return;
+	if (attempt) {
+		wpa_printf(MSG_DEBUG, "RSN: Trying to use cached PMKSA");
+		sm->cached_pmk = TRUE;
+	} else {
+		wpa_printf(MSG_DEBUG, "RSN: Do not try to use cached PMKSA");
+		sm->cached_pmk = FALSE;
+	}
+}
+
+
+static void eapol_sm_abort_cached(struct eapol_sm *sm)
+{
+	wpa_printf(MSG_DEBUG, "RSN: Authenticator did not accept PMKID, "
+		   "doing full EAP authentication");
+	if (sm == NULL)
+		return;
+	sm->cached_pmk = FALSE;
+	sm->SUPP_PAE_state = SUPP_PAE_CONNECTING;
+	sm->suppPortStatus = Unauthorized;
+	eapol_sm_set_port_unauthorized(sm);
+
+	/* Make sure we do not start sending EAPOL-Start frames first, but
+	 * instead move to RESTART state to start EAPOL authentication. */
+	sm->startWhen = 3;
+	eapol_enable_timer_tick(sm);
+
+	if (sm->ctx->aborted_cached)
+		sm->ctx->aborted_cached(sm->ctx->ctx);
+}
+
+
+/**
+ * eapol_sm_register_scard_ctx - Notification of smart card context
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @ctx: Context data for smart card operations
+ *
+ * Notify EAPOL state machines of context data for smart card operations. This
+ * context data will be used as a parameter for scard_*() functions.
+ */
+void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx)
+{
+	if (sm) {
+		sm->ctx->scard_ctx = ctx;
+		eap_register_scard_ctx(sm->eap, ctx);
+	}
+}
+
+
+/**
+ * eapol_sm_notify_portControl - Notification of portControl changes
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @portControl: New value for portControl variable
+ *
+ * Notify EAPOL state machines that portControl variable has changed.
+ */
+void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl)
+{
+	if (sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "EAPOL: External notification - "
+		   "portControl=%s", eapol_port_control(portControl));
+	sm->portControl = portControl;
+	eapol_sm_step(sm);
+}
+
+
+/**
+ * eapol_sm_notify_ctrl_attached - Notification of attached monitor
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * Notify EAPOL state machines that a monitor was attached to the control
+ * interface to trigger re-sending of pending requests for user input.
+ */
+void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	eap_sm_notify_ctrl_attached(sm->eap);
+}
+
+
+/**
+ * eapol_sm_notify_ctrl_response - Notification of received user input
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * Notify EAPOL state machines that a control response, i.e., user
+ * input, was received in order to trigger retrying of a pending EAP request.
+ */
+void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	if (sm->eapReqData && !sm->eapReq) {
+		wpa_printf(MSG_DEBUG, "EAPOL: received control response (user "
+			   "input) notification - retrying pending EAP "
+			   "Request");
+		sm->eapolEap = TRUE;
+		sm->eapReq = TRUE;
+		eapol_sm_step(sm);
+	}
+}
+
+
+/**
+ * eapol_sm_request_reauth - Request reauthentication
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * This function can be used to request EAPOL reauthentication, e.g., when the
+ * current PMKSA entry is nearing expiration.
+ */
+void eapol_sm_request_reauth(struct eapol_sm *sm)
+{
+	if (sm == NULL || sm->SUPP_PAE_state != SUPP_PAE_AUTHENTICATED)
+		return;
+	eapol_sm_txStart(sm);
+}
+
+
+/**
+ * eapol_sm_notify_lower_layer_success - Notification of lower layer success
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ * @in_eapol_sm: Whether the caller is already running inside EAPOL state
+ * machine loop (eapol_sm_step())
+ *
+ * Notify EAPOL (and EAP) state machines that a lower layer has detected a
+ * successful authentication. This is used to recover from dropped EAP-Success
+ * messages.
+ */
+void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm)
+{
+	if (sm == NULL)
+		return;
+	eap_notify_lower_layer_success(sm->eap);
+	if (!in_eapol_sm)
+		eapol_sm_step(sm);
+}
+
+
+/**
+ * eapol_sm_invalidate_cached_session - Mark cached EAP session data invalid
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ */
+void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
+{
+	if (sm)
+		eap_invalidate_cached_session(sm->eap);
+}
+
+
+static struct eap_peer_config * eapol_sm_get_config(void *ctx)
+{
+	struct eapol_sm *sm = ctx;
+	return sm ? sm->config : NULL;
+}
+
+
+static struct wpabuf * eapol_sm_get_eapReqData(void *ctx)
+{
+	struct eapol_sm *sm = ctx;
+	if (sm == NULL || sm->eapReqData == NULL)
+		return NULL;
+
+	return sm->eapReqData;
+}
+
+
+static Boolean eapol_sm_get_bool(void *ctx, enum eapol_bool_var variable)
+{
+	struct eapol_sm *sm = ctx;
+	if (sm == NULL)
+		return FALSE;
+	switch (variable) {
+	case EAPOL_eapSuccess:
+		return sm->eapSuccess;
+	case EAPOL_eapRestart:
+		return sm->eapRestart;
+	case EAPOL_eapFail:
+		return sm->eapFail;
+	case EAPOL_eapResp:
+		return sm->eapResp;
+	case EAPOL_eapNoResp:
+		return sm->eapNoResp;
+	case EAPOL_eapReq:
+		return sm->eapReq;
+	case EAPOL_portEnabled:
+		return sm->portEnabled;
+	case EAPOL_altAccept:
+		return sm->altAccept;
+	case EAPOL_altReject:
+		return sm->altReject;
+	}
+	return FALSE;
+}
+
+
+static void eapol_sm_set_bool(void *ctx, enum eapol_bool_var variable,
+			      Boolean value)
+{
+	struct eapol_sm *sm = ctx;
+	if (sm == NULL)
+		return;
+	switch (variable) {
+	case EAPOL_eapSuccess:
+		sm->eapSuccess = value;
+		break;
+	case EAPOL_eapRestart:
+		sm->eapRestart = value;
+		break;
+	case EAPOL_eapFail:
+		sm->eapFail = value;
+		break;
+	case EAPOL_eapResp:
+		sm->eapResp = value;
+		break;
+	case EAPOL_eapNoResp:
+		sm->eapNoResp = value;
+		break;
+	case EAPOL_eapReq:
+		sm->eapReq = value;
+		break;
+	case EAPOL_portEnabled:
+		sm->portEnabled = value;
+		break;
+	case EAPOL_altAccept:
+		sm->altAccept = value;
+		break;
+	case EAPOL_altReject:
+		sm->altReject = value;
+		break;
+	}
+}
+
+
+static unsigned int eapol_sm_get_int(void *ctx, enum eapol_int_var variable)
+{
+	struct eapol_sm *sm = ctx;
+	if (sm == NULL)
+		return 0;
+	switch (variable) {
+	case EAPOL_idleWhile:
+		return sm->idleWhile;
+	}
+	return 0;
+}
+
+
+static void eapol_sm_set_int(void *ctx, enum eapol_int_var variable,
+			     unsigned int value)
+{
+	struct eapol_sm *sm = ctx;
+	if (sm == NULL)
+		return;
+	switch (variable) {
+	case EAPOL_idleWhile:
+		sm->idleWhile = value;
+		if (sm->idleWhile > 0)
+			eapol_enable_timer_tick(sm);
+		break;
+	}
+}
+
+
+static void eapol_sm_set_config_blob(void *ctx, struct wpa_config_blob *blob)
+{
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	struct eapol_sm *sm = ctx;
+	if (sm && sm->ctx && sm->ctx->set_config_blob)
+		sm->ctx->set_config_blob(sm->ctx->ctx, blob);
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+}
+
+
+static const struct wpa_config_blob *
+eapol_sm_get_config_blob(void *ctx, const char *name)
+{
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	struct eapol_sm *sm = ctx;
+	if (sm && sm->ctx && sm->ctx->get_config_blob)
+		return sm->ctx->get_config_blob(sm->ctx->ctx, name);
+	else
+		return NULL;
+#else /* CONFIG_NO_CONFIG_BLOBS */
+	return NULL;
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+}
+
+
+static void eapol_sm_notify_pending(void *ctx)
+{
+	struct eapol_sm *sm = ctx;
+	if (sm == NULL)
+		return;
+	if (sm->eapReqData && !sm->eapReq) {
+		wpa_printf(MSG_DEBUG, "EAPOL: received notification from EAP "
+			   "state machine - retrying pending EAP Request");
+		sm->eapolEap = TRUE;
+		sm->eapReq = TRUE;
+		eapol_sm_step(sm);
+	}
+}
+
+
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static void eapol_sm_eap_param_needed(void *ctx, enum wpa_ctrl_req_type field,
+				      const char *txt)
+{
+	struct eapol_sm *sm = ctx;
+	wpa_printf(MSG_DEBUG, "EAPOL: EAP parameter needed");
+	if (sm->ctx->eap_param_needed)
+		sm->ctx->eap_param_needed(sm->ctx->ctx, field, txt);
+}
+#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+#define eapol_sm_eap_param_needed NULL
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+
+static void eapol_sm_notify_cert(void *ctx, int depth, const char *subject,
+				 const char *cert_hash,
+				 const struct wpabuf *cert)
+{
+	struct eapol_sm *sm = ctx;
+	if (sm->ctx->cert_cb)
+		sm->ctx->cert_cb(sm->ctx->ctx, depth, subject,
+				 cert_hash, cert);
+}
+
+
+static void eapol_sm_notify_status(void *ctx, const char *status,
+				   const char *parameter)
+{
+	struct eapol_sm *sm = ctx;
+
+	if (sm->ctx->status_cb)
+		sm->ctx->status_cb(sm->ctx->ctx, status, parameter);
+}
+
+
+static void eapol_sm_set_anon_id(void *ctx, const u8 *id, size_t len)
+{
+	struct eapol_sm *sm = ctx;
+
+	if (sm->ctx->set_anon_id)
+		sm->ctx->set_anon_id(sm->ctx->ctx, id, len);
+}
+
+
+static struct eapol_callbacks eapol_cb =
+{
+	eapol_sm_get_config,
+	eapol_sm_get_bool,
+	eapol_sm_set_bool,
+	eapol_sm_get_int,
+	eapol_sm_set_int,
+	eapol_sm_get_eapReqData,
+	eapol_sm_set_config_blob,
+	eapol_sm_get_config_blob,
+	eapol_sm_notify_pending,
+	eapol_sm_eap_param_needed,
+	eapol_sm_notify_cert,
+	eapol_sm_notify_status,
+	eapol_sm_set_anon_id
+};
+
+
+/**
+ * eapol_sm_init - Initialize EAPOL state machine
+ * @ctx: Pointer to EAPOL context data; this needs to be an allocated buffer
+ * and EAPOL state machine will free it in eapol_sm_deinit()
+ * Returns: Pointer to the allocated EAPOL state machine or %NULL on failure
+ *
+ * Allocate and initialize an EAPOL state machine.
+ */
+struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
+{
+	struct eapol_sm *sm;
+	struct eap_config conf;
+	sm = os_zalloc(sizeof(*sm));
+	if (sm == NULL)
+		return NULL;
+	sm->ctx = ctx;
+
+	sm->portControl = Auto;
+
+	/* Supplicant PAE state machine */
+	sm->heldPeriod = 60;
+	sm->startPeriod = 30;
+	sm->maxStart = 3;
+
+	/* Supplicant Backend state machine */
+	sm->authPeriod = 30;
+
+	os_memset(&conf, 0, sizeof(conf));
+	conf.opensc_engine_path = ctx->opensc_engine_path;
+	conf.pkcs11_engine_path = ctx->pkcs11_engine_path;
+	conf.pkcs11_module_path = ctx->pkcs11_module_path;
+	conf.wps = ctx->wps;
+	conf.cert_in_cb = ctx->cert_in_cb;
+
+	sm->eap = eap_peer_sm_init(sm, &eapol_cb, sm->ctx->msg_ctx, &conf);
+	if (sm->eap == NULL) {
+		os_free(sm);
+		return NULL;
+	}
+
+	/* Initialize EAPOL state machines */
+	sm->initialize = TRUE;
+	eapol_sm_step(sm);
+	sm->initialize = FALSE;
+	eapol_sm_step(sm);
+
+	sm->timer_tick_enabled = 1;
+	eloop_register_timeout(1, 0, eapol_port_timers_tick, NULL, sm);
+
+	return sm;
+}
+
+
+/**
+ * eapol_sm_deinit - Deinitialize EAPOL state machine
+ * @sm: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ *
+ * Deinitialize and free EAPOL state machine.
+ */
+void eapol_sm_deinit(struct eapol_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	eloop_cancel_timeout(eapol_sm_step_timeout, NULL, sm);
+	eloop_cancel_timeout(eapol_port_timers_tick, NULL, sm);
+	eap_peer_sm_deinit(sm->eap);
+	os_free(sm->last_rx_key);
+	wpabuf_free(sm->eapReqData);
+	os_free(sm->ctx);
+	os_free(sm);
+}
+
+
+void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
+			     struct ext_password_data *ext)
+{
+	if (sm && sm->eap)
+		eap_sm_set_ext_pw_ctx(sm->eap, ext);
+}
+
+
+int eapol_sm_failed(struct eapol_sm *sm)
+{
+	if (sm == NULL)
+		return 0;
+	return !sm->eapSuccess && sm->eapFail;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/eapol_supp/eapol_supp_sm.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,391 @@
+/*
+ * EAPOL supplicant state machines
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAPOL_SUPP_SM_H
+#define EAPOL_SUPP_SM_H
+
+#include "common/defs.h"
+
+typedef enum { Unauthorized, Authorized } PortStatus;
+typedef enum { Auto, ForceUnauthorized, ForceAuthorized } PortControl;
+
+/**
+ * struct eapol_config - Per network configuration for EAPOL state machines
+ */
+struct eapol_config {
+	/**
+	 * accept_802_1x_keys - Accept IEEE 802.1X (non-WPA) EAPOL-Key frames
+	 *
+	 * This variable should be set to 1 when using EAPOL state machines
+	 * with non-WPA security policy to generate dynamic WEP keys. When
+	 * using WPA, this should be set to 0 so that WPA state machine can
+	 * process the EAPOL-Key frames.
+	 */
+	int accept_802_1x_keys;
+
+#define EAPOL_REQUIRE_KEY_UNICAST BIT(0)
+#define EAPOL_REQUIRE_KEY_BROADCAST BIT(1)
+	/**
+	 * required_keys - Which EAPOL-Key packets are required
+	 *
+	 * This variable determines which EAPOL-Key packets are required before
+	 * marking connection authenticated. This is a bit field of
+	 * EAPOL_REQUIRE_KEY_UNICAST and EAPOL_REQUIRE_KEY_BROADCAST flags.
+	 */
+	int required_keys;
+
+	/**
+	 * fast_reauth - Whether fast EAP reauthentication is enabled
+	 */
+	int fast_reauth;
+
+	/**
+	 * workaround - Whether EAP workarounds are enabled
+	 */
+	unsigned int workaround;
+
+	/**
+	 * eap_disabled - Whether EAP is disabled
+	 */
+	int eap_disabled;
+};
+
+struct eapol_sm;
+struct wpa_config_blob;
+
+/**
+ * struct eapol_ctx - Global (for all networks) EAPOL state machine context
+ */
+struct eapol_ctx {
+	/**
+	 * ctx - Pointer to arbitrary upper level context
+	 */
+	void *ctx;
+
+	/**
+	 * preauth - IEEE 802.11i/RSN pre-authentication
+	 *
+	 * This EAPOL state machine is used for IEEE 802.11i/RSN
+	 * pre-authentication
+	 */
+	int preauth;
+
+	/**
+	 * cb - Function to be called when EAPOL negotiation has been completed
+	 * @eapol: Pointer to EAPOL state machine data
+	 * @success: Whether the authentication was completed successfully
+	 * @ctx: Pointer to context data (cb_ctx)
+	 *
+	 * This optional callback function will be called when the EAPOL
+	 * authentication has been completed. This allows the owner of the
+	 * EAPOL state machine to process the key and terminate the EAPOL state
+	 * machine. Currently, this is used only in RSN pre-authentication.
+	 */
+	void (*cb)(struct eapol_sm *eapol, int success, void *ctx);
+
+	/**
+	 * cb_ctx - Callback context for cb()
+	 */
+	void *cb_ctx;
+
+	/**
+	 * msg_ctx - Callback context for wpa_msg() calls
+	 */
+	void *msg_ctx;
+
+	/**
+	 * scard_ctx - Callback context for PC/SC scard_*() function calls
+	 *
+	 * This context can be updated with eapol_sm_register_scard_ctx().
+	 */
+	void *scard_ctx;
+
+	/**
+	 * eapol_send_ctx - Callback context for eapol_send() calls
+	 */
+	void *eapol_send_ctx;
+
+	/**
+	 * eapol_done_cb - Function to be called at successful completion
+	 * @ctx: Callback context (ctx)
+	 *
+	 * This function is called at the successful completion of EAPOL
+	 * authentication. If dynamic WEP keys are used, this is called only
+	 * after all the expected keys have been received.
+	 */
+	void (*eapol_done_cb)(void *ctx);
+
+	/**
+	 * eapol_send - Send EAPOL packets
+	 * @ctx: Callback context (eapol_send_ctx)
+	 * @type: EAPOL type (IEEE802_1X_TYPE_*)
+	 * @buf: Pointer to EAPOL payload
+	 * @len: Length of the EAPOL payload
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*eapol_send)(void *ctx, int type, const u8 *buf, size_t len);
+
+	/**
+	 * set_wep_key - Configure WEP keys
+	 * @ctx: Callback context (ctx)
+	 * @unicast: Non-zero = unicast, 0 = multicast/broadcast key
+	 * @keyidx: Key index (0..3)
+	 * @key: WEP key
+	 * @keylen: Length of the WEP key
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_wep_key)(void *ctx, int unicast, int keyidx,
+			   const u8 *key, size_t keylen);
+
+	/**
+	 * set_config_blob - Set or add a named configuration blob
+	 * @ctx: Callback context (ctx)
+	 * @blob: New value for the blob
+	 *
+	 * Adds a new configuration blob or replaces the current value of an
+	 * existing blob.
+	 */
+	void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
+
+	/**
+	 * get_config_blob - Get a named configuration blob
+	 * @ctx: Callback context (ctx)
+	 * @name: Name of the blob
+	 * Returns: Pointer to blob data or %NULL if not found
+	 */
+	const struct wpa_config_blob * (*get_config_blob)(void *ctx,
+							  const char *name);
+
+	/**
+	 * aborted_cached - Notify that cached PMK attempt was aborted
+	 * @ctx: Callback context (ctx)
+	 */
+	void (*aborted_cached)(void *ctx);
+
+	/**
+	 * opensc_engine_path - Path to the OpenSSL engine for opensc
+	 *
+	 * This is an OpenSSL specific configuration option for loading OpenSC
+	 * engine (engine_opensc.so); if %NULL, this engine is not loaded.
+	 */
+	const char *opensc_engine_path;
+
+	/**
+	 * pkcs11_engine_path - Path to the OpenSSL engine for PKCS#11
+	 *
+	 * This is an OpenSSL specific configuration option for loading PKCS#11
+	 * engine (engine_pkcs11.so); if %NULL, this engine is not loaded.
+	 */
+	const char *pkcs11_engine_path;
+
+	/**
+	 * pkcs11_module_path - Path to the OpenSSL OpenSC/PKCS#11 module
+	 *
+	 * This is an OpenSSL specific configuration option for configuring
+	 * path to OpenSC/PKCS#11 engine (opensc-pkcs11.so); if %NULL, this
+	 * module is not loaded.
+	 */
+	const char *pkcs11_module_path;
+
+	/**
+	 * wps - WPS context data
+	 *
+	 * This is only used by EAP-WSC and can be left %NULL if not available.
+	 */
+	struct wps_context *wps;
+
+	/**
+	 * eap_param_needed - Notify that EAP parameter is needed
+	 * @ctx: Callback context (ctx)
+	 * @field: Field indicator (e.g., WPA_CTRL_REQ_EAP_IDENTITY)
+	 * @txt: User readable text describing the required parameter
+	 */
+	void (*eap_param_needed)(void *ctx, enum wpa_ctrl_req_type field,
+				 const char *txt);
+
+	/**
+	 * port_cb - Set port authorized/unauthorized callback (optional)
+	 * @ctx: Callback context (ctx)
+	 * @authorized: Whether the supplicant port is now in authorized state
+	 */
+	void (*port_cb)(void *ctx, int authorized);
+
+	/**
+	 * cert_cb - Notification of a peer certificate
+	 * @ctx: Callback context (ctx)
+	 * @depth: Depth in certificate chain (0 = server)
+	 * @subject: Subject of the peer certificate
+	 * @cert_hash: SHA-256 hash of the certificate
+	 * @cert: Peer certificate
+	 */
+	void (*cert_cb)(void *ctx, int depth, const char *subject,
+			const char *cert_hash, const struct wpabuf *cert);
+
+	/**
+	 * cert_in_cb - Include server certificates in callback
+	 */
+	int cert_in_cb;
+
+	/**
+	 * status_cb - Notification of a change in EAP status
+	 * @ctx: Callback context (ctx)
+	 * @status: Step in the process of EAP authentication
+	 * @parameter: Step-specific parameter, e.g., EAP method name
+	 */
+	void (*status_cb)(void *ctx, const char *status,
+			  const char *parameter);
+
+	/**
+	 * set_anon_id - Set or add anonymous identity
+	 * @ctx: eapol_ctx from eap_peer_sm_init() call
+	 * @id: Anonymous identity (e.g., EAP-SIM pseudonym)
+	 * @len: Length of anonymous identity in octets
+	 */
+	void (*set_anon_id)(void *ctx, const u8 *id, size_t len);
+};
+
+
+struct eap_peer_config;
+struct ext_password_data;
+
+#ifdef IEEE8021X_EAPOL
+struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx);
+void eapol_sm_deinit(struct eapol_sm *sm);
+void eapol_sm_step(struct eapol_sm *sm);
+int eapol_sm_get_status(struct eapol_sm *sm, char *buf, size_t buflen,
+			int verbose);
+int eapol_sm_get_mib(struct eapol_sm *sm, char *buf, size_t buflen);
+void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod, int authPeriod,
+			int startPeriod, int maxStart);
+int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src, const u8 *buf,
+		      size_t len);
+void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm);
+void eapol_sm_notify_portEnabled(struct eapol_sm *sm, Boolean enabled);
+void eapol_sm_notify_portValid(struct eapol_sm *sm, Boolean valid);
+void eapol_sm_notify_eap_success(struct eapol_sm *sm, Boolean success);
+void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail);
+void eapol_sm_notify_config(struct eapol_sm *sm,
+			    struct eap_peer_config *config,
+			    const struct eapol_config *conf);
+int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len);
+void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff);
+void eapol_sm_notify_cached(struct eapol_sm *sm);
+void eapol_sm_notify_pmkid_attempt(struct eapol_sm *sm, int attempt);
+void eapol_sm_register_scard_ctx(struct eapol_sm *sm, void *ctx);
+void eapol_sm_notify_portControl(struct eapol_sm *sm, PortControl portControl);
+void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm);
+void eapol_sm_notify_ctrl_response(struct eapol_sm *sm);
+void eapol_sm_request_reauth(struct eapol_sm *sm);
+void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm, int in_eapol_sm);
+void eapol_sm_invalidate_cached_session(struct eapol_sm *sm);
+const char * eapol_sm_get_method_name(struct eapol_sm *sm);
+void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
+			     struct ext_password_data *ext);
+int eapol_sm_failed(struct eapol_sm *sm);
+#else /* IEEE8021X_EAPOL */
+static inline struct eapol_sm *eapol_sm_init(struct eapol_ctx *ctx)
+{
+	free(ctx);
+	return (struct eapol_sm *) 1;
+}
+static inline void eapol_sm_deinit(struct eapol_sm *sm)
+{
+}
+static inline void eapol_sm_step(struct eapol_sm *sm)
+{
+}
+static inline int eapol_sm_get_status(struct eapol_sm *sm, char *buf,
+				      size_t buflen, int verbose)
+{
+	return 0;
+}
+static inline int eapol_sm_get_mib(struct eapol_sm *sm, char *buf,
+				   size_t buflen)
+{
+	return 0;
+}
+static inline void eapol_sm_configure(struct eapol_sm *sm, int heldPeriod,
+				      int authPeriod, int startPeriod,
+				      int maxStart)
+{
+}
+static inline int eapol_sm_rx_eapol(struct eapol_sm *sm, const u8 *src,
+				    const u8 *buf, size_t len)
+{
+	return 0;
+}
+static inline void eapol_sm_notify_tx_eapol_key(struct eapol_sm *sm)
+{
+}
+static inline void eapol_sm_notify_portEnabled(struct eapol_sm *sm,
+					       Boolean enabled)
+{
+}
+static inline void eapol_sm_notify_portValid(struct eapol_sm *sm,
+					     Boolean valid)
+{
+}
+static inline void eapol_sm_notify_eap_success(struct eapol_sm *sm,
+					       Boolean success)
+{
+}
+static inline void eapol_sm_notify_eap_fail(struct eapol_sm *sm, Boolean fail)
+{
+}
+static inline void eapol_sm_notify_config(struct eapol_sm *sm,
+					  struct eap_peer_config *config,
+					  struct eapol_config *conf)
+{
+}
+static inline int eapol_sm_get_key(struct eapol_sm *sm, u8 *key, size_t len)
+{
+	return -1;
+}
+static inline void eapol_sm_notify_logoff(struct eapol_sm *sm, Boolean logoff)
+{
+}
+static inline void eapol_sm_notify_cached(struct eapol_sm *sm)
+{
+}
+#define eapol_sm_notify_pmkid_attempt(sm, attempt) do { } while (0)
+#define eapol_sm_register_scard_ctx(sm, ctx) do { } while (0)
+static inline void eapol_sm_notify_portControl(struct eapol_sm *sm,
+					       PortControl portControl)
+{
+}
+static inline void eapol_sm_notify_ctrl_attached(struct eapol_sm *sm)
+{
+}
+static inline void eapol_sm_notify_ctrl_response(struct eapol_sm *sm)
+{
+}
+static inline void eapol_sm_request_reauth(struct eapol_sm *sm)
+{
+}
+static inline void eapol_sm_notify_lower_layer_success(struct eapol_sm *sm,
+						       int in_eapol_sm)
+{
+}
+static inline void eapol_sm_invalidate_cached_session(struct eapol_sm *sm)
+{
+}
+static inline const char * eapol_sm_get_method_name(struct eapol_sm *sm)
+{
+	return NULL;
+}
+static inline void eapol_sm_set_ext_pw_ctx(struct eapol_sm *sm,
+					   struct ext_password_data *ext)
+{
+}
+static inline int eapol_sm_failed(struct eapol_sm *sm)
+{
+	return 0;
+}
+#endif /* IEEE8021X_EAPOL */
+
+#endif /* EAPOL_SUPP_SM_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/l2_packet/l2_packet.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,124 @@
+/*
+ * WPA Supplicant - Layer2 packet interface definition
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file defines an interface for layer 2 (link layer) packet sending and
+ * receiving. l2_packet_linux.c is one implementation for such a layer 2
+ * implementation using Linux packet sockets and l2_packet_pcap.c another one
+ * using libpcap and libdnet. When porting %wpa_supplicant to other operating
+ * systems, a new l2_packet implementation may need to be added.
+ */
+
+#ifndef L2_PACKET_H
+#define L2_PACKET_H
+
+/**
+ * struct l2_packet_data - Internal l2_packet data structure
+ *
+ * This structure is used by the l2_packet implementation to store its private
+ * data. Other files use a pointer to this data when calling the l2_packet
+ * functions, but the contents of this structure should not be used directly
+ * outside l2_packet implementation.
+ */
+struct l2_packet_data;
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct l2_ethhdr {
+	u8 h_dest[ETH_ALEN];
+	u8 h_source[ETH_ALEN];
+	be16 h_proto;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+/**
+ * l2_packet_init - Initialize l2_packet interface
+ * @ifname: Interface name
+ * @own_addr: Optional own MAC address if available from driver interface or
+ *	%NULL if not available
+ * @protocol: Ethernet protocol number in host byte order
+ * @rx_callback: Callback function that will be called for each received packet
+ * @rx_callback_ctx: Callback data (ctx) for calls to rx_callback()
+ * @l2_hdr: 1 = include layer 2 header, 0 = do not include header
+ * Returns: Pointer to internal data or %NULL on failure
+ *
+ * rx_callback function will be called with src_addr pointing to the source
+ * address (MAC address) of the the packet. If l2_hdr is set to 0, buf
+ * points to len bytes of the payload after the layer 2 header and similarly,
+ * TX buffers start with payload. This behavior can be changed by setting
+ * l2_hdr=1 to include the layer 2 header in the data buffer.
+ */
+struct l2_packet_data * l2_packet_init(
+	const char *ifname, const u8 *own_addr, unsigned short protocol,
+	void (*rx_callback)(void *ctx, const u8 *src_addr,
+			    const u8 *buf, size_t len),
+	void *rx_callback_ctx, int l2_hdr);
+
+/**
+ * l2_packet_deinit - Deinitialize l2_packet interface
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ */
+void l2_packet_deinit(struct l2_packet_data *l2);
+
+/**
+ * l2_packet_get_own_addr - Get own layer 2 address
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ * @addr: Buffer for the own address (6 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr);
+
+/**
+ * l2_packet_send - Send a packet
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ * @dst_addr: Destination address for the packet (only used if l2_hdr == 0)
+ * @proto: Protocol/ethertype for the packet in host byte order (only used if
+ * l2_hdr == 0)
+ * @buf: Packet contents to be sent; including layer 2 header if l2_hdr was
+ * set to 1 in l2_packet_init() call. Otherwise, only the payload of the packet
+ * is included.
+ * @len: Length of the buffer (including l2 header only if l2_hdr == 1)
+ * Returns: >=0 on success, <0 on failure
+ */
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+		   const u8 *buf, size_t len);
+
+/**
+ * l2_packet_get_ip_addr - Get the current IP address from the interface
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ * @buf: Buffer for the IP address in text format
+ * @len: Maximum buffer length
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to get the current IP address from the interface
+ * bound to the l2_packet. This is mainly for status information and the IP
+ * address will be stored as an ASCII string. This function is not essential
+ * for %wpa_supplicant operation, so full implementation is not required.
+ * l2_packet implementation will need to define the function, but it can return
+ * -1 if the IP address information is not available.
+ */
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len);
+
+
+/**
+ * l2_packet_notify_auth_start - Notify l2_packet about start of authentication
+ * @l2: Pointer to internal l2_packet data from l2_packet_init()
+ *
+ * This function is called when authentication is expected to start, e.g., when
+ * association has been completed, in order to prepare l2_packet implementation
+ * for EAPOL frames. This function is used mainly if the l2_packet code needs
+ * to do polling in which case it can increasing polling frequency. This can
+ * also be an empty function if the l2_packet implementation does not benefit
+ * from knowing about the starting authentication.
+ */
+void l2_packet_notify_auth_start(struct l2_packet_data *l2);
+
+#endif /* L2_PACKET_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/l2_packet/l2_packet_solaris.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,211 @@
+/*
+ * WPA Supplicant - Layer2 packet handling with Solaris
+ * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * Copyright (c) 2007, Sun Microsystems, Inc.
+ * Copyright (c) 2011, James Lee <jlee@thestaticvoid.com>
+ *
+ * Sun elects to license this software under the BSD license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <libdlpi.h>
+#include <sys/ethernet.h>
+#include <netinet/in.h>
+
+#include "includes.h"
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+
+#define	IEEE80211_ADDR_LEN	6
+#define	IEEE80211_MTU_MAX	2304
+
+struct l2_packet_data {
+	dlpi_handle_t   dh; /* dlpi handle for EAPOL frames */
+	char		ifname[DLPI_LINKNAME_MAX];
+	uint8_t		own_addr[IEEE80211_ADDR_LEN];
+	void		(*rx_callback)(void *, const unsigned char *,
+			    const unsigned char *, size_t);
+	void		*rx_callback_ctx;
+	int		l2_hdr;
+};
+
+static int
+link_init(struct l2_packet_data *l2)
+{
+	int retval;
+	uint8_t paddr[DLPI_PHYSADDR_MAX];
+	size_t paddrlen = sizeof (paddr);
+
+	retval = dlpi_bind(l2->dh, DLPI_ANY_SAP, NULL);
+	if (retval != DLPI_SUCCESS) {
+		wpa_printf(MSG_ERROR, "cannot bind on %s: %s", l2->ifname,
+		    dlpi_strerror(retval));
+		return (-1);
+	}
+
+	retval = dlpi_promiscon(l2->dh, DL_PROMISC_SAP);
+	if (retval != DLPI_SUCCESS) {
+		wpa_printf(MSG_ERROR, "cannot enable promiscous mode (SAP) on "
+		    "%s: %s", l2->ifname, dlpi_strerror(retval));
+		return (-1);
+	}
+
+	retval = dlpi_get_physaddr(l2->dh, DL_CURR_PHYS_ADDR, paddr, &paddrlen);
+	if (retval != DLPI_SUCCESS) {
+		wpa_printf(MSG_ERROR, "cannot get physical address for %s: %s",
+		    l2->ifname, dlpi_strerror(retval));
+		return (-1);
+	}
+	if (paddrlen != sizeof (l2->own_addr)) {
+		wpa_printf(MSG_ERROR, "physical address for %s is not %d bytes",
+		    l2->ifname, sizeof (l2->own_addr));
+		return (-1);
+	}
+	os_memcpy(l2->own_addr, paddr, sizeof (l2->own_addr));
+
+	return (0);
+}
+
+/*
+ * layer2 packet handling.
+ */
+int
+l2_packet_get_own_addr(struct l2_packet_data *l2, uint8_t *addr)
+{
+	os_memcpy(addr, l2->own_addr, sizeof (l2->own_addr));
+	return (0);
+}
+
+int
+l2_packet_send(struct l2_packet_data *l2, const uint8_t *dst_addr,
+    uint16_t proto, const uint8_t *buf, size_t buflen)
+{
+	int retval;
+
+	if (l2->l2_hdr) {
+		retval = dlpi_send(l2->dh, NULL, 0, buf, buflen, NULL);
+	} else {
+		struct l2_ethhdr *eth = NULL;
+
+		eth = os_zalloc(sizeof (struct l2_ethhdr) + buflen);
+		if (eth == NULL)
+			return (-1);
+
+		os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
+		os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
+		eth->h_proto = htons(proto);
+		os_memcpy(eth + 1, buf, buflen);
+		retval = dlpi_send(l2->dh, NULL, 0, eth,
+		    sizeof (struct l2_ethhdr) + buflen, NULL);
+		os_free(eth);
+	}
+
+	if (retval != DLPI_SUCCESS) {
+		wpa_printf(MSG_ERROR, "l2_packet_send: cannot send "
+		    "message on %s: %s", l2->ifname, dlpi_strerror(retval));
+		return (-1);
+	}
+
+	return (0);
+}
+
+static void
+l2_packet_receive(int fd, void *eloop_ctx, void *sock_ctx)
+{
+	struct l2_packet_data *l2 = eloop_ctx;
+	uint64_t packet[IEEE80211_MTU_MAX / sizeof (uint64_t)];
+	unsigned char *buf = NULL;
+	size_t buflen = sizeof (packet);
+	struct l2_ethhdr *ethhdr = NULL;
+	int retval;
+
+	retval = dlpi_recv(l2->dh, NULL, NULL, packet, &buflen, 0, NULL);
+	if (retval != DLPI_SUCCESS) {
+		wpa_printf(MSG_ERROR, "l2_packet_receive: cannot receive "
+		    "message on %s: %s", l2->ifname, dlpi_strerror(retval));
+		return;
+	}
+
+	ethhdr = (struct l2_ethhdr *) packet;
+
+	if (buflen < sizeof (*ethhdr) ||
+	    (ntohs(ethhdr->h_proto) != ETHERTYPE_EAPOL &&
+	    ntohs(ethhdr->h_proto) != ETHERTYPE_RSN_PREAUTH))
+		return;
+
+	if (l2->l2_hdr) {
+		buf = (unsigned char *) ethhdr;
+	} else {
+		buf = (unsigned char *) (ethhdr + 1);
+		buflen -= sizeof (*ethhdr);
+	}
+
+	l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, buflen);
+}
+
+struct l2_packet_data *
+l2_packet_init(const char *ifname, const uint8_t *own_addr,
+    unsigned short protocol, void (*rx_callback)(void *, const unsigned char *,
+    const unsigned char *, size_t), void *rx_callback_ctx, int l2_hdr)
+{
+	int retval;
+	struct l2_packet_data *l2 = NULL;
+
+	l2 = os_zalloc(sizeof (struct l2_packet_data));
+	if (l2 == NULL)
+		return (NULL);
+
+	os_strlcpy(l2->ifname, ifname, sizeof (l2->ifname));
+	l2->rx_callback = rx_callback;
+	l2->rx_callback_ctx = rx_callback_ctx;
+	l2->l2_hdr = l2_hdr;
+
+	retval = dlpi_open(l2->ifname, &l2->dh, DLPI_RAW);
+	if (retval != DLPI_SUCCESS) {
+		wpa_printf(MSG_ERROR, "unable to open DLPI link %s: %s",
+		    l2->ifname, dlpi_strerror(retval));
+		os_free(l2);
+		return (NULL);
+	}
+
+	/* NOTE: link_init() sets l2->own_addr */
+	if (link_init(l2) < 0) {
+		dlpi_close(l2->dh);
+		free(l2);
+		return (NULL);
+	}
+
+	eloop_register_read_sock(dlpi_fd(l2->dh), l2_packet_receive, l2, NULL);
+
+	return (l2);
+}
+
+void
+l2_packet_deinit(struct l2_packet_data *l2)
+{
+	if (l2 == NULL)
+		return;
+
+	eloop_unregister_read_sock(dlpi_fd(l2->dh));
+	dlpi_close(l2->dh);
+	os_free(l2);
+}
+
+int
+l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+	/* Not implemented */
+	return (-1);
+}
+
+void
+l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+	/* Not implemented */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/p2p/p2p.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,1783 @@
+/*
+ * Wi-Fi Direct - P2P module
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef P2P_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;
+
+	int ht40;
+
+	/**
+	 * ssid - SSID of the group
+	 */
+	u8 ssid[32];
+
+	/**
+	 * ssid_len - Length of SSID in octets
+	 */
+	size_t ssid_len;
+
+	/**
+	 * psk - WPA pre-shared key (256 bits) (GO only)
+	 */
+	u8 psk[32];
+
+	/**
+	 * psk_set - Whether PSK field is configured (GO only)
+	 */
+	int psk_set;
+
+	/**
+	 * passphrase - WPA2-Personal passphrase for the group (GO only)
+	 */
+	char passphrase[64];
+
+	/**
+	 * 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_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];
+
+	/**
+	 * wfd_subelems - Wi-Fi Display subelements from WFD IE(s)
+	 */
+	struct wpabuf *wfd_subelems;
+};
+
+enum p2p_prov_disc_status {
+	P2P_PROV_DISC_SUCCESS,
+	P2P_PROV_DISC_TIMEOUT,
+	P2P_PROV_DISC_REJECTED,
+	P2P_PROV_DISC_TIMEOUT_JOIN,
+};
+
+struct p2p_channel {
+	u8 op_class;
+	u8 chan;
+};
+
+/**
+ * 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;
+
+	/**
+	 * num_pref_chan - Number of pref_chan entries
+	 */
+	unsigned int num_pref_chan;
+
+	/**
+	 * pref_chan - Preferred channels for GO Negotiation
+	 */
+	struct p2p_channel *pref_chan;
+
+	/**
+	 * pri_dev_type - Primary Device Type (see WPS)
+	 */
+	u8 pri_dev_type[8];
+
+	/**
+	 * 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;
+
+	/**
+	 * max_listen - Maximum listen duration in ms
+	 */
+	unsigned int max_listen;
+
+	/**
+	 * 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
+	 * @dev_id: Device ID to search for or %NULL to find all devices
+	 * @pw_id: Device Password ID
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This callback function is used to request a P2P scan or search
+	 * operation to be completed. Type type argument specifies which type
+	 * of scan is to be done. @P2P_SCAN_SOCIAL indicates that only the
+	 * social channels (1, 6, 11) should be scanned. @P2P_SCAN_FULL
+	 * indicates that all channels are to be scanned.
+	 * @P2P_SCAN_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, const u8 *dev_id, u16 pw_id);
+
+	/**
+	 * 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);
+
+	/**
+	 * go_connected - Check whether we are connected to a GO
+	 * @ctx: Callback context from cb_ctx
+	 * @dev_addr: P2P Device Address of a GO
+	 * Returns: 1 if we are connected as a P2P client to the specified GO
+	 * or 0 if not.
+	 */
+	int (*go_connected)(void *ctx, const u8 *dev_addr);
+};
+
+
+/* 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.
+ * @dev_id: Device ID to search for or %NULL to find all devices
+ * @search_delay: Extra delay in milliseconds between search iterations
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_find(struct p2p_data *p2p, unsigned int timeout,
+	     enum p2p_discovery_type type,
+	     unsigned int num_req_dev_types, const u8 *req_dev_types,
+	     const u8 *dev_id, unsigned int search_delay);
+
+/**
+ * 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)
+ * @force_ssid: Forced SSID for the group if we become GO or %NULL to generate
+ *	a new SSID
+ * @force_ssid_len: Length of $force_ssid buffer
+ * @pd_before_go_neg: Whether to send Provision Discovery prior to GO
+ *	Negotiation as an interoperability workaround when initiating group
+ *	formation
+ * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
+ *	force_freq == 0)
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_connect(struct p2p_data *p2p, const u8 *peer_addr,
+		enum p2p_wps_method wps_method,
+		int go_intent, const u8 *own_interface_addr,
+		unsigned int force_freq, int persistent_group,
+		const u8 *force_ssid, size_t force_ssid_len,
+		int pd_before_go_neg, unsigned int pref_freq);
+
+/**
+ * p2p_authorize - Authorize P2P group formation (GO negotiation)
+ * @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)
+ * @force_ssid: Forced SSID for the group if we become GO or %NULL to generate
+ *	a new SSID
+ * @force_ssid_len: Length of $force_ssid buffer
+ * @pref_freq: Preferred operating frequency in MHz or 0 (this is only used if
+ *	force_freq == 0)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is like p2p_connect(), but the actual group negotiation is not
+ * 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,
+		  const u8 *force_ssid, size_t force_ssid_len,
+		  unsigned int pref_freq);
+
+/**
+ * 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)
+ * @user_initiated_pd: Flag to indicate if initiated by user or not
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to request a discovered P2P peer to display a PIN
+ * (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,
+		      int user_initiated_pd);
+
+/**
+ * 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);
+
+#ifdef CONFIG_WIFI_DISPLAY
+void * p2p_sd_request_wfd(struct p2p_data *p2p, const u8 *dst,
+			  const struct wpabuf *tlvs);
+#endif /* CONFIG_WIFI_DISPLAY */
+
+/**
+ * p2p_sd_cancel_request - Cancel a pending service discovery query
+ * @p2p: P2P module context from p2p_init()
+ * @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 Device Address
+ *
+ * This function is used to clear stored WPS provisioning info for the given
+ * peer.
+ */
+void p2p_clear_provisioning_info(struct p2p_data *p2p, const u8 *addr);
+
+
+/* Event notifications from lower layer driver operations */
+
+/**
+ * enum p2p_probe_req_status
+ *
+ * @P2P_PREQ_MALFORMED: frame was not well-formed
+ * @P2P_PREQ_NOT_LISTEN: device isn't in listen state, frame ignored
+ * @P2P_PREQ_NOT_P2P: frame was not a P2P probe request
+ * @P2P_PREQ_P2P_NOT_PROCESSED: frame was P2P but wasn't processed
+ * @P2P_PREQ_P2P_PROCESSED: frame has been processed by P2P
+ */
+enum p2p_probe_req_status {
+	P2P_PREQ_MALFORMED,
+	P2P_PREQ_NOT_LISTEN,
+	P2P_PREQ_NOT_P2P,
+	P2P_PREQ_NOT_PROCESSED,
+	P2P_PREQ_PROCESSED
+};
+
+/**
+ * p2p_probe_req_rx - Report reception of a Probe Request frame
+ * @p2p: P2P module context from p2p_init()
+ * @addr: Source MAC address
+ * @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: value indicating the type and status of the probe request
+ */
+enum p2p_probe_req_status
+p2p_probe_req_rx(struct p2p_data *p2p, const u8 *addr, const u8 *dst,
+		 const u8 *bssid, const u8 *ie, size_t ie_len);
+
+/**
+ * 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
+ * @age: Age of the scan result in milliseconds
+ * @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,
+			 unsigned int age, 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;
+
+	/**
+	 * ssid - Group SSID
+	 */
+	u8 ssid[32];
+
+	/**
+	 * ssid_len - Length of SSID
+	 */
+	size_t ssid_len;
+
+	/**
+	 * cb_ctx - Context to use with callback functions
+	 */
+	void *cb_ctx;
+
+	/**
+	 * 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_match_dev_id - Match P2P Device Address in group with requested device id
+ */
+int p2p_group_match_dev_id(struct p2p_group *group, struct wpabuf *p2p);
+
+/**
+ * p2p_group_go_discover - Send GO Discoverability Request to a group client
+ * @group: P2P group context from p2p_group_init()
+ * Returns: 0 on success (frame scheduled); -1 if client was not found
+ */
+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_parse_dev_addr_in_p2p_ie - Parse P2P Device Address from a concatenated
+ * P2P IE
+ * @p2p_ie: P2P IE
+ * @dev_addr: Buffer for returning P2P Device Address
+ * Returns: 0 on success or -1 if P2P Device Address could not be parsed
+ */
+int p2p_parse_dev_addr_in_p2p_ie(struct wpabuf *p2p_ie, u8 *dev_addr);
+
+/**
+ * p2p_parse_dev_addr - Parse P2P Device Address from P2P IE(s)
+ * @ies: Information elements from scan results
+ * @ies_len: ies buffer length in octets
+ * @dev_addr: Buffer for returning P2P Device Address
+ * Returns: 0 on success or -1 if P2P Device Address could not be parsed
+ */
+int p2p_parse_dev_addr(const u8 *ies, size_t ies_len, u8 *dev_addr);
+
+/**
+ * p2p_assoc_req_ie - Build P2P IE for (Re)Association Request frame
+ * @p2p: P2P module context from p2p_init()
+ * @bssid: BSSID
+ * @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
+ * @dev_id: Device ID to search for or %NULL for any
+ */
+void p2p_scan_ie(struct p2p_data *p2p, struct wpabuf *ies, const u8 *dev_id);
+
+/**
+ * p2p_scan_ie_buf_len - Get maximum buffer length needed for p2p_scan_ie
+ * @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
+ * @p2p: P2P module context from p2p_init()
+ * @addr: P2P Device Address of the peer or %NULL to indicate the first peer
+ * @next: Whether to select the peer entry following the one indicated by addr
+ * Returns: Pointer to peer info or %NULL if not found
+ */
+const struct p2p_peer_info * p2p_get_peer_info(struct p2p_data *p2p,
+					       const u8 *addr, int next);
+
+/**
+ * p2p_get_peer_info_txt - Get internal P2P peer information in text format
+ * @info: Pointer to P2P peer info from p2p_get_peer_info()
+ * @buf: Buffer for returning text
+ * @buflen: Maximum buffer length
+ * Returns: Number of octets written to the buffer or -1 on failure
+ *
+ * Note: This information is internal to the P2P module and subject to change.
+ * As such, this should not really be used by external programs for purposes
+ * other than debugging.
+ */
+int p2p_get_peer_info_txt(const struct p2p_peer_info *info,
+			  char *buf, size_t buflen);
+
+/**
+ * p2p_peer_known - Check whether P2P peer is known
+ * @p2p: P2P module context from p2p_init()
+ * @addr: P2P Device Address of the peer
+ * Returns: 1 if the specified device is in the P2P peer table or 0 if not
+ */
+int p2p_peer_known(struct p2p_data *p2p, const u8 *addr);
+
+/**
+ * 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);
+
+/**
+ * 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_group_is_client_connected - Check whether a specific client is connected
+ * @group: P2P group context from p2p_group_init()
+ * @addr: P2P Device Address of the client
+ * Returns: 1 if client is connected or 0 if not
+ */
+int p2p_group_is_client_connected(struct p2p_group *group, const u8 *dev_addr);
+
+/**
+ * p2p_get_peer_found - Get P2P peer info structure of a found peer
+ * @p2p: P2P module context from p2p_init()
+ * @addr: P2P Device Address of the peer or %NULL to indicate the first peer
+ * @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_set_pref_chan - Set P2P preferred channel list
+ * @p2p: P2P module context from p2p_init()
+ * @num_pref_chan: Number of entries in pref_chan list
+ * @pref_chan: Preferred channels or %NULL to remove preferences
+ * Returns: 0 on success, -1 on failure
+ */
+int p2p_set_pref_chan(struct p2p_data *p2p, unsigned int num_pref_chan,
+		      const struct p2p_channel *pref_chan);
+
+/**
+ * p2p_in_progress - Check whether a P2P operation is progress
+ * @p2p: P2P module context from p2p_init()
+ * Returns: 0 if P2P module is idle or 1 if an operation is in progress
+ */
+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);
+
+/**
+ * p2p_set_config_timeout - Set local config timeouts
+ * @p2p: P2P module context from p2p_init()
+ * @go_timeout: Time in 10 ms units it takes to start the GO mode
+ * @client_timeout: Time in 10 ms units it takes to start the client mode
+ */
+void p2p_set_config_timeout(struct p2p_data *p2p, u8 go_timeout,
+			    u8 client_timeout);
+
+void p2p_increase_search_delay(struct p2p_data *p2p, unsigned int delay);
+
+int p2p_set_wfd_ie_beacon(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_probe_req(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_probe_resp(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_assoc_req(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_invitation(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_prov_disc_req(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_prov_disc_resp(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_ie_go_neg(struct p2p_data *p2p, struct wpabuf *ie);
+int p2p_set_wfd_dev_info(struct p2p_data *p2p, const struct wpabuf *elem);
+int p2p_set_wfd_assoc_bssid(struct p2p_data *p2p, const struct wpabuf *elem);
+int p2p_set_wfd_coupled_sink_info(struct p2p_data *p2p,
+				  const struct wpabuf *elem);
+struct wpabuf * wifi_display_encaps(struct wpabuf *subelems);
+
+/**
+ * p2p_set_disc_int - Set min/max discoverable interval for p2p_find
+ * @p2p: P2P module context from p2p_init()
+ * @min_disc_int: minDiscoverableInterval (in units of 100 TU); default 1
+ * @max_disc_int: maxDiscoverableInterval (in units of 100 TU); default 3
+ * @max_disc_tu: Maximum number of TUs (1.024 ms) for discoverable interval; or
+ *	-1 not to limit
+ * Returns: 0 on success, or -1 on failure
+ *
+ * This function can be used to configure minDiscoverableInterval and
+ * maxDiscoverableInterval parameters for the Listen state during device
+ * discovery (p2p_find). A random number of 100 TU units is picked for each
+ * Listen state iteration from [min_disc_int,max_disc_int] range.
+ *
+ * max_disc_tu can be used to futher limit the discoverable duration. However,
+ * it should be noted that use of this parameter is not recommended since it
+ * would not be compliant with the P2P specification.
+ */
+int p2p_set_disc_int(struct p2p_data *p2p, int min_disc_int, int max_disc_int,
+		     int max_disc_tu);
+
+#endif /* P2P_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/peerkey.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,1174 @@
+/*
+ * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
+ * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#ifdef CONFIG_PEERKEY
+
+#include "common.h"
+#include "eloop.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "common/ieee802_11_defs.h"
+#include "wpa.h"
+#include "wpa_i.h"
+#include "wpa_ie.h"
+#include "peerkey.h"
+
+
+static u8 * wpa_add_ie(u8 *pos, const u8 *ie, size_t ie_len)
+{
+	os_memcpy(pos, ie, ie_len);
+	return pos + ie_len;
+}
+
+
+static u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len)
+{
+	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
+	*pos++ = RSN_SELECTOR_LEN + data_len;
+	RSN_SELECTOR_PUT(pos, kde);
+	pos += RSN_SELECTOR_LEN;
+	os_memcpy(pos, data, data_len);
+	pos += data_len;
+	return pos;
+}
+
+
+static void wpa_supplicant_smk_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+#if 0
+	struct wpa_sm *sm = eloop_ctx;
+	struct wpa_peerkey *peerkey = timeout_ctx;
+#endif
+	/* TODO: time out SMK and any STK that was generated using this SMK */
+}
+
+
+static void wpa_supplicant_peerkey_free(struct wpa_sm *sm,
+					struct wpa_peerkey *peerkey)
+{
+	eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
+	os_free(peerkey);
+}
+
+
+static int wpa_supplicant_send_smk_error(struct wpa_sm *sm, const u8 *dst,
+					 const u8 *peer,
+					 u16 mui, u16 error_type, int ver)
+{
+	size_t rlen;
+	struct wpa_eapol_key *err;
+	struct rsn_error_kde error;
+	u8 *rbuf, *pos;
+	size_t kde_len;
+	u16 key_info;
+
+	kde_len = 2 + RSN_SELECTOR_LEN + sizeof(error);
+	if (peer)
+		kde_len += 2 + RSN_SELECTOR_LEN + ETH_ALEN;
+
+	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
+				  NULL, sizeof(*err) + kde_len, &rlen,
+				  (void *) &err);
+	if (rbuf == NULL)
+		return -1;
+
+	err->type = EAPOL_KEY_TYPE_RSN;
+	key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
+		WPA_KEY_INFO_SECURE | WPA_KEY_INFO_ERROR |
+		WPA_KEY_INFO_REQUEST;
+	WPA_PUT_BE16(err->key_info, key_info);
+	WPA_PUT_BE16(err->key_length, 0);
+	os_memcpy(err->replay_counter, sm->request_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
+
+	WPA_PUT_BE16(err->key_data_length, (u16) kde_len);
+	pos = (u8 *) (err + 1);
+
+	if (peer) {
+		/* Peer MAC Address KDE */
+		pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN);
+	}
+
+	/* Error KDE */
+	error.mui = host_to_be16(mui);
+	error.error_type = host_to_be16(error_type);
+	wpa_add_kde(pos, RSN_KEY_DATA_ERROR, (u8 *) &error, sizeof(error));
+
+	if (peer) {
+		wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error (peer "
+			   MACSTR " mui %d error_type %d)",
+			   MAC2STR(peer), mui, error_type);
+	} else {
+		wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK Error "
+			   "(mui %d error_type %d)", mui, error_type);
+	}
+
+	wpa_eapol_key_send(sm, sm->ptk.kck, ver, dst, ETH_P_EAPOL,
+			   rbuf, rlen, err->key_mic);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_send_smk_m3(struct wpa_sm *sm,
+				      const unsigned char *src_addr,
+				      const struct wpa_eapol_key *key,
+				      int ver, struct wpa_peerkey *peerkey)
+{
+	size_t rlen;
+	struct wpa_eapol_key *reply;
+	u8 *rbuf, *pos;
+	size_t kde_len;
+	u16 key_info;
+
+	/* KDEs: Peer RSN IE, Initiator MAC Address, Initiator Nonce */
+	kde_len = peerkey->rsnie_p_len +
+		2 + RSN_SELECTOR_LEN + ETH_ALEN +
+		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN;
+
+	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
+				  NULL, sizeof(*reply) + kde_len, &rlen,
+				  (void *) &reply);
+	if (rbuf == NULL)
+		return -1;
+
+	reply->type = EAPOL_KEY_TYPE_RSN;
+	key_info = ver | WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
+		WPA_KEY_INFO_SECURE;
+	WPA_PUT_BE16(reply->key_info, key_info);
+	WPA_PUT_BE16(reply->key_length, 0);
+	os_memcpy(reply->replay_counter, key->replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+
+	os_memcpy(reply->key_nonce, peerkey->pnonce, WPA_NONCE_LEN);
+
+	WPA_PUT_BE16(reply->key_data_length, (u16) kde_len);
+	pos = (u8 *) (reply + 1);
+
+	/* Peer RSN IE */
+	pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len);
+
+	/* Initiator MAC Address KDE */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peerkey->addr, ETH_ALEN);
+
+	/* Initiator Nonce */
+	wpa_add_kde(pos, RSN_KEY_DATA_NONCE, peerkey->inonce, WPA_NONCE_LEN);
+
+	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key SMK M3");
+	wpa_eapol_key_send(sm, sm->ptk.kck, ver, src_addr, ETH_P_EAPOL,
+			   rbuf, rlen, reply->key_mic);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_process_smk_m2(
+	struct wpa_sm *sm, const unsigned char *src_addr,
+	const struct wpa_eapol_key *key, size_t extra_len, int ver)
+{
+	struct wpa_peerkey *peerkey;
+	struct wpa_eapol_ie_parse kde;
+	struct wpa_ie_data ie;
+	int cipher;
+	struct rsn_ie_hdr *hdr;
+	u8 *pos;
+
+	wpa_printf(MSG_DEBUG, "RSN: Received SMK M2");
+
+	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
+		wpa_printf(MSG_INFO, "RSN: SMK handshake not allowed for "
+			   "the current network");
+		return -1;
+	}
+
+	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
+	    0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M2");
+		return -1;
+	}
+
+	if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
+	    kde.mac_addr_len < ETH_ALEN) {
+		wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
+			   "SMK M2");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "RSN: SMK M2 - SMK initiator " MACSTR,
+		   MAC2STR(kde.mac_addr));
+
+	if (kde.rsn_ie_len > PEERKEY_MAX_IE_LEN) {
+		wpa_printf(MSG_INFO, "RSN: Too long Initiator RSN IE in SMK "
+			   "M2");
+		return -1;
+	}
+
+	if (wpa_parse_wpa_ie_rsn(kde.rsn_ie, kde.rsn_ie_len, &ie) < 0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse RSN IE in SMK M2");
+		return -1;
+	}
+
+	cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher;
+	if (cipher & WPA_CIPHER_CCMP) {
+		wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
+		cipher = WPA_CIPHER_CCMP;
+	} else if (cipher & WPA_CIPHER_GCMP) {
+		wpa_printf(MSG_DEBUG, "RSN: Using GCMP for PeerKey");
+		cipher = WPA_CIPHER_GCMP;
+	} else if (cipher & WPA_CIPHER_TKIP) {
+		wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
+		cipher = WPA_CIPHER_TKIP;
+	} else {
+		wpa_printf(MSG_INFO, "RSN: No acceptable cipher in SMK M2");
+		wpa_supplicant_send_smk_error(sm, src_addr, kde.mac_addr,
+					      STK_MUI_SMK, STK_ERR_CPHR_NS,
+					      ver);
+		return -1;
+	}
+
+	/* TODO: find existing entry and if found, use that instead of adding
+	 * a new one; how to handle the case where both ends initiate at the
+	 * same time? */
+	peerkey = os_zalloc(sizeof(*peerkey));
+	if (peerkey == NULL)
+		return -1;
+	os_memcpy(peerkey->addr, kde.mac_addr, ETH_ALEN);
+	os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
+	os_memcpy(peerkey->rsnie_i, kde.rsn_ie, kde.rsn_ie_len);
+	peerkey->rsnie_i_len = kde.rsn_ie_len;
+	peerkey->cipher = cipher;
+#ifdef CONFIG_IEEE80211W
+	if (ie.key_mgmt & (WPA_KEY_MGMT_IEEE8021X_SHA256 |
+			   WPA_KEY_MGMT_PSK_SHA256))
+		peerkey->use_sha256 = 1;
+#endif /* CONFIG_IEEE80211W */
+
+	if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Failed to get random data for PNonce");
+		wpa_supplicant_peerkey_free(sm, peerkey);
+		return -1;
+	}
+
+	hdr = (struct rsn_ie_hdr *) peerkey->rsnie_p;
+	hdr->elem_id = WLAN_EID_RSN;
+	WPA_PUT_LE16(hdr->version, RSN_VERSION);
+	pos = (u8 *) (hdr + 1);
+	/* Group Suite can be anything for SMK RSN IE; receiver will just
+	 * ignore it. */
+	RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+	pos += RSN_SELECTOR_LEN;
+	/* Include only the selected cipher in pairwise cipher suite */
+	WPA_PUT_LE16(pos, 1);
+	pos += 2;
+	RSN_SELECTOR_PUT(pos, wpa_cipher_to_suite(WPA_PROTO_RSN, cipher));
+	pos += RSN_SELECTOR_LEN;
+
+	hdr->len = (pos - peerkey->rsnie_p) - 2;
+	peerkey->rsnie_p_len = pos - peerkey->rsnie_p;
+	wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake",
+		    peerkey->rsnie_p, peerkey->rsnie_p_len);
+
+	wpa_supplicant_send_smk_m3(sm, src_addr, key, ver, peerkey);
+
+	peerkey->next = sm->peerkey;
+	sm->peerkey = peerkey;
+
+	return 0;
+}
+
+
+/**
+ * rsn_smkid - Derive SMK identifier
+ * @smk: Station master key (32 bytes)
+ * @pnonce: Peer Nonce
+ * @mac_p: Peer MAC address
+ * @inonce: Initiator Nonce
+ * @mac_i: Initiator MAC address
+ * @use_sha256: Whether to use SHA256-based KDF
+ *
+ * 8.5.1.4 Station to station (STK) key hierarchy
+ * SMKID = HMAC-SHA1-128(SMK, "SMK Name" || PNonce || MAC_P || INonce || MAC_I)
+ */
+static void rsn_smkid(const u8 *smk, const u8 *pnonce, const u8 *mac_p,
+		      const u8 *inonce, const u8 *mac_i, u8 *smkid,
+		      int use_sha256)
+{
+	char *title = "SMK Name";
+	const u8 *addr[5];
+	const size_t len[5] = { 8, WPA_NONCE_LEN, ETH_ALEN, WPA_NONCE_LEN,
+				ETH_ALEN };
+	unsigned char hash[SHA256_MAC_LEN];
+
+	addr[0] = (u8 *) title;
+	addr[1] = pnonce;
+	addr[2] = mac_p;
+	addr[3] = inonce;
+	addr[4] = mac_i;
+
+#ifdef CONFIG_IEEE80211W
+	if (use_sha256)
+		hmac_sha256_vector(smk, PMK_LEN, 5, addr, len, hash);
+	else
+#endif /* CONFIG_IEEE80211W */
+		hmac_sha1_vector(smk, PMK_LEN, 5, addr, len, hash);
+	os_memcpy(smkid, hash, PMKID_LEN);
+}
+
+
+static void wpa_supplicant_send_stk_1_of_4(struct wpa_sm *sm,
+					   struct wpa_peerkey *peerkey)
+{
+	size_t mlen;
+	struct wpa_eapol_key *msg;
+	u8 *mbuf;
+	size_t kde_len;
+	u16 key_info, ver;
+
+	kde_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
+
+	mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+				  sizeof(*msg) + kde_len, &mlen,
+				  (void *) &msg);
+	if (mbuf == NULL)
+		return;
+
+	msg->type = EAPOL_KEY_TYPE_RSN;
+
+	if (peerkey->cipher != WPA_CIPHER_TKIP)
+		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
+	else
+		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+
+	key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK;
+	WPA_PUT_BE16(msg->key_info, key_info);
+
+	if (peerkey->cipher != WPA_CIPHER_TKIP)
+		WPA_PUT_BE16(msg->key_length, 16);
+	else
+		WPA_PUT_BE16(msg->key_length, 32);
+
+	os_memcpy(msg->replay_counter, peerkey->replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
+
+	WPA_PUT_BE16(msg->key_data_length, kde_len);
+	wpa_add_kde((u8 *) (msg + 1), RSN_KEY_DATA_PMKID,
+		    peerkey->smkid, PMKID_LEN);
+
+	if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"RSN: Failed to get random data for INonce (STK)");
+		os_free(mbuf);
+		return;
+	}
+	wpa_hexdump(MSG_DEBUG, "RSN: INonce for STK 4-Way Handshake",
+		    peerkey->inonce, WPA_NONCE_LEN);
+	os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
+
+	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 1/4 to " MACSTR,
+		   MAC2STR(peerkey->addr));
+	wpa_eapol_key_send(sm, NULL, ver, peerkey->addr, ETH_P_EAPOL,
+			   mbuf, mlen, NULL);
+}
+
+
+static void wpa_supplicant_send_stk_3_of_4(struct wpa_sm *sm,
+					   struct wpa_peerkey *peerkey)
+{
+	size_t mlen;
+	struct wpa_eapol_key *msg;
+	u8 *mbuf, *pos;
+	size_t kde_len;
+	u16 key_info, ver;
+	be32 lifetime;
+
+	kde_len = peerkey->rsnie_i_len +
+		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
+
+	mbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+				  sizeof(*msg) + kde_len, &mlen,
+				  (void *) &msg);
+	if (mbuf == NULL)
+		return;
+
+	msg->type = EAPOL_KEY_TYPE_RSN;
+
+	if (peerkey->cipher != WPA_CIPHER_TKIP)
+		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
+	else
+		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+
+	key_info = ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_ACK |
+		WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
+	WPA_PUT_BE16(msg->key_info, key_info);
+
+	if (peerkey->cipher != WPA_CIPHER_TKIP)
+		WPA_PUT_BE16(msg->key_length, 16);
+	else
+		WPA_PUT_BE16(msg->key_length, 32);
+
+	os_memcpy(msg->replay_counter, peerkey->replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	inc_byte_array(peerkey->replay_counter, WPA_REPLAY_COUNTER_LEN);
+
+	WPA_PUT_BE16(msg->key_data_length, kde_len);
+	pos = (u8 *) (msg + 1);
+	pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
+	lifetime = host_to_be32(peerkey->lifetime);
+	wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
+		    (u8 *) &lifetime, sizeof(lifetime));
+
+	os_memcpy(msg->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
+
+	wpa_printf(MSG_DEBUG, "RSN: Sending EAPOL-Key STK 3/4 to " MACSTR,
+		   MAC2STR(peerkey->addr));
+	wpa_eapol_key_send(sm, peerkey->stk.kck, ver, peerkey->addr,
+			   ETH_P_EAPOL, mbuf, mlen, msg->key_mic);
+}
+
+
+static int wpa_supplicant_process_smk_m4(struct wpa_peerkey *peerkey,
+					 struct wpa_eapol_ie_parse *kde)
+{
+	wpa_printf(MSG_DEBUG, "RSN: Received SMK M4 (Initiator " MACSTR ")",
+		   MAC2STR(kde->mac_addr));
+
+	if (os_memcmp(kde->smk + PMK_LEN, peerkey->pnonce, WPA_NONCE_LEN) != 0)
+	{
+		wpa_printf(MSG_INFO, "RSN: PNonce in SMK KDE does not "
+			   "match with the one used in SMK M3");
+		return -1;
+	}
+
+	if (os_memcmp(kde->nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) {
+		wpa_printf(MSG_INFO, "RSN: INonce in SMK M4 did not "
+			   "match with the one received in SMK M2");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_process_smk_m5(struct wpa_sm *sm,
+					 const unsigned char *src_addr,
+					 const struct wpa_eapol_key *key,
+					 int ver,
+					 struct wpa_peerkey *peerkey,
+					 struct wpa_eapol_ie_parse *kde)
+{
+	int cipher;
+	struct wpa_ie_data ie;
+
+	wpa_printf(MSG_DEBUG, "RSN: Received SMK M5 (Peer " MACSTR ")",
+		   MAC2STR(kde->mac_addr));
+	if (kde->rsn_ie == NULL || kde->rsn_ie_len > PEERKEY_MAX_IE_LEN ||
+	    wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0) {
+		wpa_printf(MSG_INFO, "RSN: No RSN IE in SMK M5");
+		/* TODO: abort negotiation */
+		return -1;
+	}
+
+	if (os_memcmp(key->key_nonce, peerkey->inonce, WPA_NONCE_LEN) != 0) {
+		wpa_printf(MSG_INFO, "RSN: Key Nonce in SMK M5 does "
+			   "not match with INonce used in SMK M1");
+		return -1;
+	}
+
+	if (os_memcmp(kde->smk + PMK_LEN, peerkey->inonce, WPA_NONCE_LEN) != 0)
+	{
+		wpa_printf(MSG_INFO, "RSN: INonce in SMK KDE does not "
+			   "match with the one used in SMK M1");
+		return -1;
+	}
+
+	os_memcpy(peerkey->rsnie_p, kde->rsn_ie, kde->rsn_ie_len);
+	peerkey->rsnie_p_len = kde->rsn_ie_len;
+	os_memcpy(peerkey->pnonce, kde->nonce, WPA_NONCE_LEN);
+
+	cipher = ie.pairwise_cipher & sm->allowed_pairwise_cipher;
+	if (cipher & WPA_CIPHER_CCMP) {
+		wpa_printf(MSG_DEBUG, "RSN: Using CCMP for PeerKey");
+		peerkey->cipher = WPA_CIPHER_CCMP;
+	} else if (cipher & WPA_CIPHER_GCMP) {
+		wpa_printf(MSG_DEBUG, "RSN: Using GCMP for PeerKey");
+		peerkey->cipher = WPA_CIPHER_GCMP;
+	} else if (cipher & WPA_CIPHER_TKIP) {
+		wpa_printf(MSG_DEBUG, "RSN: Using TKIP for PeerKey");
+		peerkey->cipher = WPA_CIPHER_TKIP;
+	} else {
+		wpa_printf(MSG_INFO, "RSN: SMK Peer STA " MACSTR " selected "
+			   "unacceptable cipher", MAC2STR(kde->mac_addr));
+		wpa_supplicant_send_smk_error(sm, src_addr, kde->mac_addr,
+					      STK_MUI_SMK, STK_ERR_CPHR_NS,
+					      ver);
+		/* TODO: abort negotiation */
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_process_smk_m45(
+	struct wpa_sm *sm, const unsigned char *src_addr,
+	const struct wpa_eapol_key *key, size_t extra_len, int ver)
+{
+	struct wpa_peerkey *peerkey;
+	struct wpa_eapol_ie_parse kde;
+	u32 lifetime;
+	struct os_time now;
+
+	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
+		wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
+			   "the current network");
+		return -1;
+	}
+
+	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
+	    0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M4/M5");
+		return -1;
+	}
+
+	if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
+	    kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN ||
+	    kde.smk == NULL || kde.smk_len < PMK_LEN + WPA_NONCE_LEN ||
+	    kde.lifetime == NULL || kde.lifetime_len < 4) {
+		wpa_printf(MSG_INFO, "RSN: No MAC Address, Nonce, SMK, or "
+			   "Lifetime KDE in SMK M4/M5");
+		return -1;
+	}
+
+	for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
+		if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) == 0 &&
+		    os_memcmp(peerkey->initiator ? peerkey->inonce :
+			   peerkey->pnonce,
+			   key->key_nonce, WPA_NONCE_LEN) == 0)
+			break;
+	}
+	if (peerkey == NULL) {
+		wpa_printf(MSG_INFO, "RSN: No matching SMK handshake found "
+			   "for SMK M4/M5: peer " MACSTR,
+			   MAC2STR(kde.mac_addr));
+		return -1;
+	}
+
+	if (peerkey->initiator) {
+		if (wpa_supplicant_process_smk_m5(sm, src_addr, key, ver,
+						  peerkey, &kde) < 0)
+			return -1;
+	} else {
+		if (wpa_supplicant_process_smk_m4(peerkey, &kde) < 0)
+			return -1;
+	}
+
+	os_memcpy(peerkey->smk, kde.smk, PMK_LEN);
+	peerkey->smk_complete = 1;
+	wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", peerkey->smk, PMK_LEN);
+	lifetime = WPA_GET_BE32(kde.lifetime);
+	wpa_printf(MSG_DEBUG, "RSN: SMK lifetime %u seconds", lifetime);
+	if (lifetime > 1000000000)
+		lifetime = 1000000000; /* avoid overflowing expiration time */
+	peerkey->lifetime = lifetime;
+	os_get_time(&now);
+	peerkey->expiration = now.sec + lifetime;
+	eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
+			       sm, peerkey);
+
+	if (peerkey->initiator) {
+		rsn_smkid(peerkey->smk, peerkey->pnonce, peerkey->addr,
+			  peerkey->inonce, sm->own_addr, peerkey->smkid,
+			  peerkey->use_sha256);
+		wpa_supplicant_send_stk_1_of_4(sm, peerkey);
+	} else {
+		rsn_smkid(peerkey->smk, peerkey->pnonce, sm->own_addr,
+			  peerkey->inonce, peerkey->addr, peerkey->smkid,
+			  peerkey->use_sha256);
+	}
+	wpa_hexdump(MSG_DEBUG, "RSN: SMKID", peerkey->smkid, PMKID_LEN);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_process_smk_error(
+	struct wpa_sm *sm, const unsigned char *src_addr,
+	const struct wpa_eapol_key *key, size_t extra_len)
+{
+	struct wpa_eapol_ie_parse kde;
+	struct rsn_error_kde error;
+	u8 peer[ETH_ALEN];
+	u16 error_type;
+
+	wpa_printf(MSG_DEBUG, "RSN: Received SMK Error");
+
+	if (!sm->peerkey_enabled || sm->proto != WPA_PROTO_RSN) {
+		wpa_printf(MSG_DEBUG, "RSN: SMK handshake not allowed for "
+			   "the current network");
+		return -1;
+	}
+
+	if (wpa_supplicant_parse_ies((const u8 *) (key + 1), extra_len, &kde) <
+	    0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
+		return -1;
+	}
+
+	if (kde.error == NULL || kde.error_len < sizeof(error)) {
+		wpa_printf(MSG_INFO, "RSN: No Error KDE in SMK Error");
+		return -1;
+	}
+
+	if (kde.mac_addr && kde.mac_addr_len >= ETH_ALEN)
+		os_memcpy(peer, kde.mac_addr, ETH_ALEN);
+	else
+		os_memset(peer, 0, ETH_ALEN);
+	os_memcpy(&error, kde.error, sizeof(error));
+	error_type = be_to_host16(error.error_type);
+	wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+		"RSN: SMK Error KDE received: MUI %d error_type %d peer "
+		MACSTR,
+		be_to_host16(error.mui), error_type,
+		MAC2STR(peer));
+
+	if (kde.mac_addr &&
+	    (error_type == STK_ERR_STA_NR || error_type == STK_ERR_STA_NRSN ||
+	     error_type == STK_ERR_CPHR_NS)) {
+		struct wpa_peerkey *peerkey;
+
+		for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
+			if (os_memcmp(peerkey->addr, kde.mac_addr, ETH_ALEN) ==
+			    0)
+				break;
+		}
+		if (peerkey == NULL) {
+			wpa_printf(MSG_DEBUG, "RSN: No matching SMK handshake "
+				   "found for SMK Error");
+			return -1;
+		}
+		/* TODO: abort SMK/STK handshake and remove all related keys */
+	}
+
+	return 0;
+}
+
+
+static void wpa_supplicant_process_stk_1_of_4(struct wpa_sm *sm,
+					      struct wpa_peerkey *peerkey,
+					      const struct wpa_eapol_key *key,
+					      u16 ver)
+{
+	struct wpa_eapol_ie_parse ie;
+	const u8 *kde;
+	size_t len, kde_buf_len;
+	struct wpa_ptk *stk;
+	u8 buf[8], *kde_buf, *pos;
+	be32 lifetime;
+
+	wpa_printf(MSG_DEBUG, "RSN: RX message 1 of STK 4-Way Handshake from "
+		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
+
+	os_memset(&ie, 0, sizeof(ie));
+
+	/* RSN: msg 1/4 should contain SMKID for the selected SMK */
+	kde = (const u8 *) (key + 1);
+	len = WPA_GET_BE16(key->key_data_length);
+	wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", kde, len);
+	if (wpa_supplicant_parse_ies(kde, len, &ie) < 0 || ie.pmkid == NULL) {
+		wpa_printf(MSG_DEBUG, "RSN: No SMKID in STK 1/4");
+		return;
+	}
+	if (os_memcmp(ie.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
+		wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 1/4",
+			    ie.pmkid, PMKID_LEN);
+		return;
+	}
+
+	if (random_get_bytes(peerkey->pnonce, WPA_NONCE_LEN)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"RSN: Failed to get random data for PNonce");
+		return;
+	}
+	wpa_hexdump(MSG_DEBUG, "WPA: Renewed PNonce",
+		    peerkey->pnonce, WPA_NONCE_LEN);
+
+	/* Calculate STK which will be stored as a temporary STK until it has
+	 * been verified when processing message 3/4. */
+	stk = &peerkey->tstk;
+	wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
+		       sm->own_addr, peerkey->addr,
+		       peerkey->pnonce, key->key_nonce,
+		       (u8 *) stk, sizeof(*stk),
+		       peerkey->use_sha256);
+	/* Supplicant: swap tx/rx Mic keys */
+	os_memcpy(buf, stk->u.auth.tx_mic_key, 8);
+	os_memcpy(stk->u.auth.tx_mic_key, stk->u.auth.rx_mic_key, 8);
+	os_memcpy(stk->u.auth.rx_mic_key, buf, 8);
+	peerkey->tstk_set = 1;
+
+	kde_buf_len = peerkey->rsnie_p_len +
+		2 + RSN_SELECTOR_LEN + sizeof(lifetime) +
+		2 + RSN_SELECTOR_LEN + PMKID_LEN;
+	kde_buf = os_malloc(kde_buf_len);
+	if (kde_buf == NULL)
+		return;
+	pos = kde_buf;
+	pos = wpa_add_ie(pos, peerkey->rsnie_p, peerkey->rsnie_p_len);
+	lifetime = host_to_be32(peerkey->lifetime);
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
+			  (u8 *) &lifetime, sizeof(lifetime));
+	wpa_add_kde(pos, RSN_KEY_DATA_PMKID, peerkey->smkid, PMKID_LEN);
+
+	if (wpa_supplicant_send_2_of_4(sm, peerkey->addr, key, ver,
+				       peerkey->pnonce, kde_buf, kde_buf_len,
+				       stk)) {
+		os_free(kde_buf);
+		return;
+	}
+	os_free(kde_buf);
+
+	os_memcpy(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN);
+}
+
+
+static void wpa_supplicant_update_smk_lifetime(struct wpa_sm *sm,
+					       struct wpa_peerkey *peerkey,
+					       struct wpa_eapol_ie_parse *kde)
+{
+	u32 lifetime;
+	struct os_time now;
+
+	if (kde->lifetime == NULL || kde->lifetime_len < sizeof(lifetime))
+		return;
+
+	lifetime = WPA_GET_BE32(kde->lifetime);
+
+	if (lifetime >= peerkey->lifetime) {
+		wpa_printf(MSG_DEBUG, "RSN: Peer used SMK lifetime %u seconds "
+			   "which is larger than or equal to own value %u "
+			   "seconds - ignored", lifetime, peerkey->lifetime);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "RSN: Peer used shorter SMK lifetime %u seconds "
+		   "(own was %u seconds) - updated",
+		   lifetime, peerkey->lifetime);
+	peerkey->lifetime = lifetime;
+
+	os_get_time(&now);
+	peerkey->expiration = now.sec + lifetime;
+	eloop_cancel_timeout(wpa_supplicant_smk_timeout, sm, peerkey);
+	eloop_register_timeout(lifetime, 0, wpa_supplicant_smk_timeout,
+			       sm, peerkey);
+}
+
+
+static void wpa_supplicant_process_stk_2_of_4(struct wpa_sm *sm,
+					      struct wpa_peerkey *peerkey,
+					      const struct wpa_eapol_key *key,
+					      u16 ver)
+{
+	struct wpa_eapol_ie_parse kde;
+	const u8 *keydata;
+	size_t len;
+
+	wpa_printf(MSG_DEBUG, "RSN: RX message 2 of STK 4-Way Handshake from "
+		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
+
+	os_memset(&kde, 0, sizeof(kde));
+
+	/* RSN: msg 2/4 should contain SMKID for the selected SMK and RSN IE
+	 * from the peer. It may also include Lifetime KDE. */
+	keydata = (const u8 *) (key + 1);
+	len = WPA_GET_BE16(key->key_data_length);
+	wpa_hexdump(MSG_DEBUG, "RSN: msg 2/4 key data", keydata, len);
+	if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0 ||
+	    kde.pmkid == NULL || kde.rsn_ie == NULL) {
+		wpa_printf(MSG_DEBUG, "RSN: No SMKID or RSN IE in STK 2/4");
+		return;
+	}
+
+	if (os_memcmp(kde.pmkid, peerkey->smkid, PMKID_LEN) != 0) {
+		wpa_hexdump(MSG_DEBUG, "RSN: Unknown SMKID in STK 2/4",
+			    kde.pmkid, PMKID_LEN);
+		return;
+	}
+
+	if (kde.rsn_ie_len != peerkey->rsnie_p_len ||
+	    os_memcmp(kde.rsn_ie, peerkey->rsnie_p, kde.rsn_ie_len) != 0) {
+		wpa_printf(MSG_INFO, "RSN: Peer RSN IE in SMK and STK "
+			   "handshakes did not match");
+		wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in SMK handshake",
+			    peerkey->rsnie_p, peerkey->rsnie_p_len);
+		wpa_hexdump(MSG_DEBUG, "RSN: Peer RSN IE in STK handshake",
+			    kde.rsn_ie, kde.rsn_ie_len);
+		return;
+	}
+
+	wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde);
+
+	wpa_supplicant_send_stk_3_of_4(sm, peerkey);
+	os_memcpy(peerkey->pnonce, key->key_nonce, WPA_NONCE_LEN);
+}
+
+
+static void wpa_supplicant_process_stk_3_of_4(struct wpa_sm *sm,
+					      struct wpa_peerkey *peerkey,
+					      const struct wpa_eapol_key *key,
+					      u16 ver)
+{
+	struct wpa_eapol_ie_parse kde;
+	const u8 *keydata;
+	size_t len, key_len;
+	const u8 *_key;
+	u8 key_buf[32], rsc[6];
+
+	wpa_printf(MSG_DEBUG, "RSN: RX message 3 of STK 4-Way Handshake from "
+		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
+
+	os_memset(&kde, 0, sizeof(kde));
+
+	/* RSN: msg 3/4 should contain Initiator RSN IE. It may also include
+	 * Lifetime KDE. */
+	keydata = (const u8 *) (key + 1);
+	len = WPA_GET_BE16(key->key_data_length);
+	wpa_hexdump(MSG_DEBUG, "RSN: msg 3/4 key data", keydata, len);
+	if (wpa_supplicant_parse_ies(keydata, len, &kde) < 0) {
+		wpa_printf(MSG_DEBUG, "RSN: Failed to parse key data in "
+			   "STK 3/4");
+		return;
+	}
+
+	if (kde.rsn_ie_len != peerkey->rsnie_i_len ||
+	    os_memcmp(kde.rsn_ie, peerkey->rsnie_i, kde.rsn_ie_len) != 0) {
+		wpa_printf(MSG_INFO, "RSN: Initiator RSN IE in SMK and STK "
+			   "handshakes did not match");
+		wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in SMK "
+			    "handshake",
+			    peerkey->rsnie_i, peerkey->rsnie_i_len);
+		wpa_hexdump(MSG_DEBUG, "RSN: Initiator RSN IE in STK "
+			    "handshake",
+			    kde.rsn_ie, kde.rsn_ie_len);
+		return;
+	}
+
+	if (os_memcmp(peerkey->inonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
+		wpa_printf(MSG_WARNING, "RSN: INonce from message 1 of STK "
+			   "4-Way Handshake differs from 3 of STK 4-Way "
+			   "Handshake - drop packet (src=" MACSTR ")",
+			   MAC2STR(peerkey->addr));
+		return;
+	}
+
+	wpa_supplicant_update_smk_lifetime(sm, peerkey, &kde);
+
+	if (wpa_supplicant_send_4_of_4(sm, peerkey->addr, key, ver,
+				       WPA_GET_BE16(key->key_info),
+				       NULL, 0, &peerkey->stk))
+		return;
+
+	_key = (u8 *) peerkey->stk.tk1;
+	if (peerkey->cipher == WPA_CIPHER_TKIP) {
+		/* Swap Tx/Rx keys for Michael MIC */
+		os_memcpy(key_buf, _key, 16);
+		os_memcpy(key_buf + 16, peerkey->stk.u.auth.rx_mic_key, 8);
+		os_memcpy(key_buf + 24, peerkey->stk.u.auth.tx_mic_key, 8);
+		_key = key_buf;
+		key_len = 32;
+	} else
+		key_len = 16;
+
+	os_memset(rsc, 0, 6);
+	if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
+			   rsc, sizeof(rsc), _key, key_len) < 0) {
+		wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
+			   "driver.");
+		return;
+	}
+}
+
+
+static void wpa_supplicant_process_stk_4_of_4(struct wpa_sm *sm,
+					      struct wpa_peerkey *peerkey,
+					      const struct wpa_eapol_key *key,
+					      u16 ver)
+{
+	u8 rsc[6];
+
+	wpa_printf(MSG_DEBUG, "RSN: RX message 4 of STK 4-Way Handshake from "
+		   MACSTR " (ver=%d)", MAC2STR(peerkey->addr), ver);
+
+	os_memset(rsc, 0, 6);
+	if (wpa_sm_set_key(sm, peerkey->cipher, peerkey->addr, 0, 1,
+			   rsc, sizeof(rsc), (u8 *) peerkey->stk.tk1,
+			   peerkey->cipher == WPA_CIPHER_TKIP ? 32 : 16) < 0) {
+		wpa_printf(MSG_WARNING, "RSN: Failed to set STK to the "
+			   "driver.");
+		return;
+	}
+}
+
+
+/**
+ * peerkey_verify_eapol_key_mic - Verify PeerKey MIC
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @peerkey: Pointer to the PeerKey data for the peer
+ * @key: Pointer to the EAPOL-Key frame header
+ * @ver: Version bits from EAPOL-Key Key Info
+ * @buf: Pointer to the beginning of EAPOL-Key frame
+ * @len: Length of the EAPOL-Key frame
+ * Returns: 0 on success, -1 on failure
+ */
+int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
+				 struct wpa_peerkey *peerkey,
+				 struct wpa_eapol_key *key, u16 ver,
+				 const u8 *buf, size_t len)
+{
+	u8 mic[16];
+	int ok = 0;
+
+	if (peerkey->initiator && !peerkey->stk_set) {
+		wpa_pmk_to_ptk(peerkey->smk, PMK_LEN, "Peer key expansion",
+			       sm->own_addr, peerkey->addr,
+			       peerkey->inonce, key->key_nonce,
+			       (u8 *) &peerkey->stk, sizeof(peerkey->stk),
+			       peerkey->use_sha256);
+		peerkey->stk_set = 1;
+	}
+
+	os_memcpy(mic, key->key_mic, 16);
+	if (peerkey->tstk_set) {
+		os_memset(key->key_mic, 0, 16);
+		wpa_eapol_key_mic(peerkey->tstk.kck, ver, buf, len,
+				  key->key_mic);
+		if (os_memcmp(mic, key->key_mic, 16) != 0) {
+			wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
+				   "when using TSTK - ignoring TSTK");
+		} else {
+			ok = 1;
+			peerkey->tstk_set = 0;
+			peerkey->stk_set = 1;
+			os_memcpy(&peerkey->stk, &peerkey->tstk,
+				  sizeof(peerkey->stk));
+		}
+	}
+
+	if (!ok && peerkey->stk_set) {
+		os_memset(key->key_mic, 0, 16);
+		wpa_eapol_key_mic(peerkey->stk.kck, ver, buf, len,
+				  key->key_mic);
+		if (os_memcmp(mic, key->key_mic, 16) != 0) {
+			wpa_printf(MSG_WARNING, "RSN: Invalid EAPOL-Key MIC "
+				   "- dropping packet");
+			return -1;
+		}
+		ok = 1;
+	}
+
+	if (!ok) {
+		wpa_printf(MSG_WARNING, "RSN: Could not verify EAPOL-Key MIC "
+			   "- dropping packet");
+		return -1;
+	}
+
+	os_memcpy(peerkey->replay_counter, key->replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	peerkey->replay_counter_set = 1;
+	return 0;
+}
+
+
+/**
+ * wpa_sm_stkstart - Send EAPOL-Key Request for STK handshake (STK M1)
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @peer: MAC address of the peer STA
+ * Returns: 0 on success, or -1 on failure
+ *
+ * Send an EAPOL-Key Request to the current authenticator to start STK
+ * handshake with the peer.
+ */
+int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
+{
+	size_t rlen, kde_len;
+	struct wpa_eapol_key *req;
+	int key_info, ver;
+	u8 bssid[ETH_ALEN], *rbuf, *pos, *count_pos;
+	u16 count;
+	struct rsn_ie_hdr *hdr;
+	struct wpa_peerkey *peerkey;
+	struct wpa_ie_data ie;
+
+	if (sm->proto != WPA_PROTO_RSN || !sm->ptk_set || !sm->peerkey_enabled)
+		return -1;
+
+	if (sm->ap_rsn_ie &&
+	    wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &ie) == 0 &&
+	    !(ie.capabilities & WPA_CAPABILITY_PEERKEY_ENABLED)) {
+		wpa_printf(MSG_DEBUG, "RSN: Current AP does not support STK");
+		return -1;
+	}
+
+	if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
+		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
+	else
+		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+
+	if (wpa_sm_get_bssid(sm, bssid) < 0) {
+		wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key "
+			   "SMK M1");
+		return -1;
+	}
+
+	/* TODO: find existing entry and if found, use that instead of adding
+	 * a new one */
+	peerkey = os_zalloc(sizeof(*peerkey));
+	if (peerkey == NULL)
+		return -1;
+	peerkey->initiator = 1;
+	os_memcpy(peerkey->addr, peer, ETH_ALEN);
+#ifdef CONFIG_IEEE80211W
+	if (wpa_key_mgmt_sha256(sm->key_mgmt))
+		peerkey->use_sha256 = 1;
+#endif /* CONFIG_IEEE80211W */
+
+	/* SMK M1:
+	 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
+	 *           MIC=MIC, DataKDs=(RSNIE_I, MAC_P KDE))
+	 */
+
+	hdr = (struct rsn_ie_hdr *) peerkey->rsnie_i;
+	hdr->elem_id = WLAN_EID_RSN;
+	WPA_PUT_LE16(hdr->version, RSN_VERSION);
+	pos = (u8 *) (hdr + 1);
+	/* Group Suite can be anything for SMK RSN IE; receiver will just
+	 * ignore it. */
+	RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+	pos += RSN_SELECTOR_LEN;
+	count_pos = pos;
+	pos += 2;
+
+	count = rsn_cipher_put_suites(pos, sm->allowed_pairwise_cipher);
+	pos += count * RSN_SELECTOR_LEN;
+	WPA_PUT_LE16(count_pos, count);
+
+	hdr->len = (pos - peerkey->rsnie_i) - 2;
+	peerkey->rsnie_i_len = pos - peerkey->rsnie_i;
+	wpa_hexdump(MSG_DEBUG, "WPA: RSN IE for SMK handshake",
+		    peerkey->rsnie_i, peerkey->rsnie_i_len);
+
+	kde_len = peerkey->rsnie_i_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
+
+	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+				  sizeof(*req) + kde_len, &rlen,
+				  (void *) &req);
+	if (rbuf == NULL) {
+		wpa_supplicant_peerkey_free(sm, peerkey);
+		return -1;
+	}
+
+	req->type = EAPOL_KEY_TYPE_RSN;
+	key_info = WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_MIC |
+		WPA_KEY_INFO_SECURE | WPA_KEY_INFO_REQUEST | ver;
+	WPA_PUT_BE16(req->key_info, key_info);
+	WPA_PUT_BE16(req->key_length, 0);
+	os_memcpy(req->replay_counter, sm->request_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
+
+	if (random_get_bytes(peerkey->inonce, WPA_NONCE_LEN)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Failed to get random data for INonce");
+		os_free(rbuf);
+		wpa_supplicant_peerkey_free(sm, peerkey);
+		return -1;
+	}
+	os_memcpy(req->key_nonce, peerkey->inonce, WPA_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPA: INonce for SMK handshake",
+		    req->key_nonce, WPA_NONCE_LEN);
+
+	WPA_PUT_BE16(req->key_data_length, (u16) kde_len);
+	pos = (u8 *) (req + 1);
+
+	/* Initiator RSN IE */
+	pos = wpa_add_ie(pos, peerkey->rsnie_i, peerkey->rsnie_i_len);
+	/* Peer MAC address KDE */
+	wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN);
+
+	wpa_printf(MSG_INFO, "RSN: Sending EAPOL-Key SMK M1 Request (peer "
+		   MACSTR ")", MAC2STR(peer));
+	wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
+			   rbuf, rlen, req->key_mic);
+
+	peerkey->next = sm->peerkey;
+	sm->peerkey = peerkey;
+
+	return 0;
+}
+
+
+/**
+ * peerkey_deinit - Free PeerKey values
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+void peerkey_deinit(struct wpa_sm *sm)
+{
+	struct wpa_peerkey *prev, *peerkey = sm->peerkey;
+	while (peerkey) {
+		prev = peerkey;
+		peerkey = peerkey->next;
+		os_free(prev);
+	}
+	sm->peerkey = NULL;
+}
+
+
+void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
+			   struct wpa_eapol_key *key, u16 key_info, u16 ver)
+{
+	if ((key_info & (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) ==
+	    (WPA_KEY_INFO_MIC | WPA_KEY_INFO_ACK)) {
+		/* 3/4 STK 4-Way Handshake */
+		wpa_supplicant_process_stk_3_of_4(sm, peerkey, key, ver);
+	} else if (key_info & WPA_KEY_INFO_ACK) {
+		/* 1/4 STK 4-Way Handshake */
+		wpa_supplicant_process_stk_1_of_4(sm, peerkey, key, ver);
+	} else if (key_info & WPA_KEY_INFO_SECURE) {
+		/* 4/4 STK 4-Way Handshake */
+		wpa_supplicant_process_stk_4_of_4(sm, peerkey, key, ver);
+	} else {
+		/* 2/4 STK 4-Way Handshake */
+		wpa_supplicant_process_stk_2_of_4(sm, peerkey, key, ver);
+	}
+}
+
+
+void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
+			  struct wpa_eapol_key *key, size_t extra_len,
+			  u16 key_info, u16 ver)
+{
+	if (key_info & WPA_KEY_INFO_ERROR) {
+		/* SMK Error */
+		wpa_supplicant_process_smk_error(sm, src_addr, key, extra_len);
+	} else if (key_info & WPA_KEY_INFO_ACK) {
+		/* SMK M2 */
+		wpa_supplicant_process_smk_m2(sm, src_addr, key, extra_len,
+					      ver);
+	} else {
+		/* SMK M4 or M5 */
+		wpa_supplicant_process_smk_m45(sm, src_addr, key, extra_len,
+					       ver);
+	}
+}
+
+#endif /* CONFIG_PEERKEY */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/peerkey.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,81 @@
+/*
+ * WPA Supplicant - PeerKey for Direct Link Setup (DLS)
+ * Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PEERKEY_H
+#define PEERKEY_H
+
+#define PEERKEY_MAX_IE_LEN 80
+struct wpa_peerkey {
+	struct wpa_peerkey *next;
+	int initiator; /* whether this end was initator for SMK handshake */
+	u8 addr[ETH_ALEN]; /* other end MAC address */
+	u8 inonce[WPA_NONCE_LEN]; /* Initiator Nonce */
+	u8 pnonce[WPA_NONCE_LEN]; /* Peer Nonce */
+	u8 rsnie_i[PEERKEY_MAX_IE_LEN]; /* Initiator RSN IE */
+	size_t rsnie_i_len;
+	u8 rsnie_p[PEERKEY_MAX_IE_LEN]; /* Peer RSN IE */
+	size_t rsnie_p_len;
+	u8 smk[PMK_LEN];
+	int smk_complete;
+	u8 smkid[PMKID_LEN];
+	u32 lifetime;
+	os_time_t expiration;
+	int cipher; /* Selected cipher (WPA_CIPHER_*) */
+	u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
+	int replay_counter_set;
+	int use_sha256; /* whether AKMP indicate SHA256-based derivations */
+
+	struct wpa_ptk stk, tstk;
+	int stk_set, tstk_set;
+};
+
+
+#ifdef CONFIG_PEERKEY
+
+int peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
+				 struct wpa_peerkey *peerkey,
+				 struct wpa_eapol_key *key, u16 ver,
+				 const u8 *buf, size_t len);
+void peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
+			   struct wpa_eapol_key *key, u16 key_info, u16 ver);
+void peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
+			  struct wpa_eapol_key *key, size_t extra_len,
+			  u16 key_info, u16 ver);
+void peerkey_deinit(struct wpa_sm *sm);
+
+#else /* CONFIG_PEERKEY */
+
+static inline int
+peerkey_verify_eapol_key_mic(struct wpa_sm *sm,
+			     struct wpa_peerkey *peerkey,
+			     struct wpa_eapol_key *key, u16 ver,
+			     const u8 *buf, size_t len)
+{
+	return -1;
+}
+
+static inline void
+peerkey_rx_eapol_4way(struct wpa_sm *sm, struct wpa_peerkey *peerkey,
+		      struct wpa_eapol_key *key, u16 key_info, u16 ver)
+{
+}
+
+static inline void
+peerkey_rx_eapol_smk(struct wpa_sm *sm, const u8 *src_addr,
+		     struct wpa_eapol_key *key, size_t extra_len,
+		     u16 key_info, u16 ver)
+{
+}
+
+static inline void peerkey_deinit(struct wpa_sm *sm)
+{
+}
+
+#endif /* CONFIG_PEERKEY */
+
+#endif /* PEERKEY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/pmksa_cache.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,512 @@
+/*
+ * WPA Supplicant - RSN PMKSA cache
+ * Copyright (c) 2004-2009, 2011-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "wpa.h"
+#include "wpa_i.h"
+#include "pmksa_cache.h"
+
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+
+static const int pmksa_cache_max_entries = 32;
+
+struct rsn_pmksa_cache {
+	struct rsn_pmksa_cache_entry *pmksa; /* PMKSA cache */
+	int pmksa_count; /* number of entries in PMKSA cache */
+	struct wpa_sm *sm; /* TODO: get rid of this reference(?) */
+
+	void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx,
+			enum pmksa_free_reason reason);
+	void *ctx;
+};
+
+
+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
+
+
+static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
+{
+	os_free(entry);
+}
+
+
+static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+				   struct rsn_pmksa_cache_entry *entry,
+				   enum pmksa_free_reason reason)
+{
+	wpa_sm_remove_pmkid(pmksa->sm, entry->aa, entry->pmkid);
+	pmksa->pmksa_count--;
+	pmksa->free_cb(entry, pmksa->ctx, reason);
+	_pmksa_cache_free_entry(entry);
+}
+
+
+static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
+{
+	struct rsn_pmksa_cache *pmksa = eloop_ctx;
+	struct os_time now;
+
+	os_get_time(&now);
+	while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
+		struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
+		pmksa->pmksa = entry->next;
+		wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
+			   MACSTR, MAC2STR(entry->aa));
+		pmksa_cache_free_entry(pmksa, entry, PMKSA_EXPIRE);
+	}
+
+	pmksa_cache_set_expiration(pmksa);
+}
+
+
+static void pmksa_cache_reauth(void *eloop_ctx, void *timeout_ctx)
+{
+	struct rsn_pmksa_cache *pmksa = eloop_ctx;
+	pmksa->sm->cur_pmksa = NULL;
+	eapol_sm_request_reauth(pmksa->sm->eapol);
+}
+
+
+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
+{
+	int sec;
+	struct rsn_pmksa_cache_entry *entry;
+	struct os_time now;
+
+	eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
+	eloop_cancel_timeout(pmksa_cache_reauth, pmksa, NULL);
+	if (pmksa->pmksa == NULL)
+		return;
+	os_get_time(&now);
+	sec = pmksa->pmksa->expiration - now.sec;
+	if (sec < 0)
+		sec = 0;
+	eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
+
+	entry = pmksa->sm->cur_pmksa ? pmksa->sm->cur_pmksa :
+		pmksa_cache_get(pmksa, pmksa->sm->bssid, NULL, NULL);
+	if (entry) {
+		sec = pmksa->pmksa->reauth_time - now.sec;
+		if (sec < 0)
+			sec = 0;
+		eloop_register_timeout(sec, 0, pmksa_cache_reauth, pmksa,
+				       NULL);
+	}
+}
+
+
+/**
+ * pmksa_cache_add - Add a PMKSA cache entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @pmk: The new pairwise master key
+ * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @network_ctx: Network configuration context for this PMK
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: Pointer to the added PMKSA cache entry or %NULL on error
+ *
+ * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
+ * cache. If an old entry is already in the cache for the same Authenticator,
+ * this entry will be replaced with the new entry. PMKID will be calculated
+ * based on the PMK and the driver interface is notified of the new PMKID.
+ */
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+		const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
+{
+	struct rsn_pmksa_cache_entry *entry, *pos, *prev;
+	struct os_time now;
+
+	if (pmk_len > PMK_LEN)
+		return NULL;
+
+	entry = os_zalloc(sizeof(*entry));
+	if (entry == NULL)
+		return NULL;
+	os_memcpy(entry->pmk, pmk, pmk_len);
+	entry->pmk_len = pmk_len;
+	rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
+		  wpa_key_mgmt_sha256(akmp));
+	os_get_time(&now);
+	entry->expiration = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime;
+	entry->reauth_time = now.sec + pmksa->sm->dot11RSNAConfigPMKLifetime *
+		pmksa->sm->dot11RSNAConfigPMKReauthThreshold / 100;
+	entry->akmp = akmp;
+	os_memcpy(entry->aa, aa, ETH_ALEN);
+	entry->network_ctx = network_ctx;
+
+	/* Replace an old entry for the same Authenticator (if found) with the
+	 * new entry */
+	pos = pmksa->pmksa;
+	prev = NULL;
+	while (pos) {
+		if (os_memcmp(aa, pos->aa, ETH_ALEN) == 0) {
+			if (pos->pmk_len == pmk_len &&
+			    os_memcmp(pos->pmk, pmk, pmk_len) == 0 &&
+			    os_memcmp(pos->pmkid, entry->pmkid, PMKID_LEN) ==
+			    0) {
+				wpa_printf(MSG_DEBUG, "WPA: reusing previous "
+					   "PMKSA entry");
+				os_free(entry);
+				return pos;
+			}
+			if (prev == NULL)
+				pmksa->pmksa = pos->next;
+			else
+				prev->next = pos->next;
+			wpa_printf(MSG_DEBUG, "RSN: Replace PMKSA entry for "
+				   "the current AP");
+			pmksa_cache_free_entry(pmksa, pos, PMKSA_REPLACE);
+
+			/*
+			 * If OKC is used, there may be other PMKSA cache
+			 * entries based on the same PMK. These needs to be
+			 * flushed so that a new entry can be created based on
+			 * the new PMK.
+			 */
+			pmksa_cache_flush(pmksa, network_ctx);
+			break;
+		}
+		prev = pos;
+		pos = pos->next;
+	}
+
+	if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
+		/* Remove the oldest entry to make room for the new entry */
+		pos = pmksa->pmksa;
+
+		if (pos == pmksa->sm->cur_pmksa) {
+			/*
+			 * Never remove the current PMKSA cache entry, since
+			 * it's in use, and removing it triggers a needless
+			 * deauthentication.
+			 */
+			pos = pos->next;
+			pmksa->pmksa->next = pos ? pos->next : NULL;
+		} else
+			pmksa->pmksa = pos->next;
+
+		if (pos) {
+			wpa_printf(MSG_DEBUG, "RSN: removed the oldest idle "
+				   "PMKSA cache entry (for " MACSTR ") to "
+				   "make room for new one",
+				   MAC2STR(pos->aa));
+			pmksa_cache_free_entry(pmksa, pos, PMKSA_FREE);
+		}
+	}
+
+	/* Add the new entry; order by expiration time */
+	pos = pmksa->pmksa;
+	prev = NULL;
+	while (pos) {
+		if (pos->expiration > entry->expiration)
+			break;
+		prev = pos;
+		pos = pos->next;
+	}
+	if (prev == NULL) {
+		entry->next = pmksa->pmksa;
+		pmksa->pmksa = entry;
+		pmksa_cache_set_expiration(pmksa);
+	} else {
+		entry->next = prev->next;
+		prev->next = entry;
+	}
+	pmksa->pmksa_count++;
+	wpa_printf(MSG_DEBUG, "RSN: Added PMKSA cache entry for " MACSTR
+		   " network_ctx=%p", MAC2STR(entry->aa), network_ctx);
+	wpa_sm_add_pmkid(pmksa->sm, entry->aa, entry->pmkid);
+
+	return entry;
+}
+
+
+/**
+ * pmksa_cache_flush - Flush PMKSA cache entries for a specific network
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @network_ctx: Network configuration context or %NULL to flush all entries
+ */
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx)
+{
+	struct rsn_pmksa_cache_entry *entry, *prev = NULL, *tmp;
+	int removed = 0;
+
+	entry = pmksa->pmksa;
+	while (entry) {
+		if (entry->network_ctx == network_ctx || network_ctx == NULL) {
+			wpa_printf(MSG_DEBUG, "RSN: Flush PMKSA cache entry "
+				   "for " MACSTR, MAC2STR(entry->aa));
+			if (prev)
+				prev->next = entry->next;
+			else
+				pmksa->pmksa = entry->next;
+			tmp = entry;
+			entry = entry->next;
+			pmksa_cache_free_entry(pmksa, tmp, PMKSA_FREE);
+			removed++;
+		} else {
+			prev = entry;
+			entry = entry->next;
+		}
+	}
+	if (removed)
+		pmksa_cache_set_expiration(pmksa);
+}
+
+
+/**
+ * pmksa_cache_deinit - Free all entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ */
+void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
+{
+	struct rsn_pmksa_cache_entry *entry, *prev;
+
+	if (pmksa == NULL)
+		return;
+
+	entry = pmksa->pmksa;
+	pmksa->pmksa = NULL;
+	while (entry) {
+		prev = entry;
+		entry = entry->next;
+		os_free(prev);
+	}
+	pmksa_cache_set_expiration(pmksa);
+	os_free(pmksa);
+}
+
+
+/**
+ * pmksa_cache_get - Fetch a PMKSA cache entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @aa: Authenticator address or %NULL to match any
+ * @pmkid: PMKID or %NULL to match any
+ * @network_ctx: Network context or %NULL to match any
+ * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
+ */
+struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
+					       const u8 *aa, const u8 *pmkid,
+					       const void *network_ctx)
+{
+	struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
+	while (entry) {
+		if ((aa == NULL || os_memcmp(entry->aa, aa, ETH_ALEN) == 0) &&
+		    (pmkid == NULL ||
+		     os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0) &&
+		    (network_ctx == NULL || network_ctx == entry->network_ctx))
+			return entry;
+		entry = entry->next;
+	}
+	return NULL;
+}
+
+
+static struct rsn_pmksa_cache_entry *
+pmksa_cache_clone_entry(struct rsn_pmksa_cache *pmksa,
+			const struct rsn_pmksa_cache_entry *old_entry,
+			const u8 *aa)
+{
+	struct rsn_pmksa_cache_entry *new_entry;
+
+	new_entry = pmksa_cache_add(pmksa, old_entry->pmk, old_entry->pmk_len,
+				    aa, pmksa->sm->own_addr,
+				    old_entry->network_ctx, old_entry->akmp);
+	if (new_entry == NULL)
+		return NULL;
+
+	/* TODO: reorder entries based on expiration time? */
+	new_entry->expiration = old_entry->expiration;
+	new_entry->opportunistic = 1;
+
+	return new_entry;
+}
+
+
+/**
+ * pmksa_cache_get_opportunistic - Try to get an opportunistic PMKSA entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @network_ctx: Network configuration context
+ * @aa: Authenticator address for the new AP
+ * Returns: Pointer to a new PMKSA cache entry or %NULL if not available
+ *
+ * Try to create a new PMKSA cache entry opportunistically by guessing that the
+ * new AP is sharing the same PMK as another AP that has the same SSID and has
+ * already an entry in PMKSA cache.
+ */
+struct rsn_pmksa_cache_entry *
+pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa, void *network_ctx,
+			      const u8 *aa)
+{
+	struct rsn_pmksa_cache_entry *entry = pmksa->pmksa;
+
+	wpa_printf(MSG_DEBUG, "RSN: Consider " MACSTR " for OKC", MAC2STR(aa));
+	if (network_ctx == NULL)
+		return NULL;
+	while (entry) {
+		if (entry->network_ctx == network_ctx) {
+			entry = pmksa_cache_clone_entry(pmksa, entry, aa);
+			if (entry) {
+				wpa_printf(MSG_DEBUG, "RSN: added "
+					   "opportunistic PMKSA cache entry "
+					   "for " MACSTR, MAC2STR(aa));
+			}
+			return entry;
+		}
+		entry = entry->next;
+	}
+	return NULL;
+}
+
+
+/**
+ * pmksa_cache_get_current - Get the current used PMKSA entry
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * Returns: Pointer to the current PMKSA cache entry or %NULL if not available
+ */
+struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm)
+{
+	if (sm == NULL)
+		return NULL;
+	return sm->cur_pmksa;
+}
+
+
+/**
+ * pmksa_cache_clear_current - Clear the current PMKSA entry selection
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+void pmksa_cache_clear_current(struct wpa_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	sm->cur_pmksa = NULL;
+}
+
+
+/**
+ * pmksa_cache_set_current - Set the current PMKSA entry selection
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @pmkid: PMKID for selecting PMKSA or %NULL if not used
+ * @bssid: BSSID for PMKSA or %NULL if not used
+ * @network_ctx: Network configuration context
+ * @try_opportunistic: Whether to allow opportunistic PMKSA caching
+ * Returns: 0 if PMKSA was found or -1 if no matching entry was found
+ */
+int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
+			    const u8 *bssid, void *network_ctx,
+			    int try_opportunistic)
+{
+	struct rsn_pmksa_cache *pmksa = sm->pmksa;
+	wpa_printf(MSG_DEBUG, "RSN: PMKSA cache search - network_ctx=%p "
+		   "try_opportunistic=%d", network_ctx, try_opportunistic);
+	if (pmkid)
+		wpa_hexdump(MSG_DEBUG, "RSN: Search for PMKID",
+			    pmkid, PMKID_LEN);
+	if (bssid)
+		wpa_printf(MSG_DEBUG, "RSN: Search for BSSID " MACSTR,
+			   MAC2STR(bssid));
+
+	sm->cur_pmksa = NULL;
+	if (pmkid)
+		sm->cur_pmksa = pmksa_cache_get(pmksa, NULL, pmkid,
+						network_ctx);
+	if (sm->cur_pmksa == NULL && bssid)
+		sm->cur_pmksa = pmksa_cache_get(pmksa, bssid, NULL,
+						network_ctx);
+	if (sm->cur_pmksa == NULL && try_opportunistic && bssid)
+		sm->cur_pmksa = pmksa_cache_get_opportunistic(pmksa,
+							      network_ctx,
+							      bssid);
+	if (sm->cur_pmksa) {
+		wpa_hexdump(MSG_DEBUG, "RSN: PMKSA cache entry found - PMKID",
+			    sm->cur_pmksa->pmkid, PMKID_LEN);
+		return 0;
+	}
+	wpa_printf(MSG_DEBUG, "RSN: No PMKSA cache entry found");
+	return -1;
+}
+
+
+/**
+ * pmksa_cache_list - Dump text list of entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_init()
+ * @buf: Buffer for the list
+ * @len: Length of the buffer
+ * Returns: number of bytes written to buffer
+ *
+ * This function is used to generate a text format representation of the
+ * current PMKSA cache contents for the ctrl_iface PMKSA command.
+ */
+int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len)
+{
+	int i, ret;
+	char *pos = buf;
+	struct rsn_pmksa_cache_entry *entry;
+	struct os_time now;
+
+	os_get_time(&now);
+	ret = os_snprintf(pos, buf + len - pos,
+			  "Index / AA / PMKID / expiration (in seconds) / "
+			  "opportunistic\n");
+	if (ret < 0 || ret >= buf + len - pos)
+		return pos - buf;
+	pos += ret;
+	i = 0;
+	entry = pmksa->pmksa;
+	while (entry) {
+		i++;
+		ret = os_snprintf(pos, buf + len - pos, "%d " MACSTR " ",
+				  i, MAC2STR(entry->aa));
+		if (ret < 0 || ret >= buf + len - pos)
+			return pos - buf;
+		pos += ret;
+		pos += wpa_snprintf_hex(pos, buf + len - pos, entry->pmkid,
+					PMKID_LEN);
+		ret = os_snprintf(pos, buf + len - pos, " %d %d\n",
+				  (int) (entry->expiration - now.sec),
+				  entry->opportunistic);
+		if (ret < 0 || ret >= buf + len - pos)
+			return pos - buf;
+		pos += ret;
+		entry = entry->next;
+	}
+	return pos - buf;
+}
+
+
+/**
+ * pmksa_cache_init - Initialize PMKSA cache
+ * @free_cb: Callback function to be called when a PMKSA cache entry is freed
+ * @ctx: Context pointer for free_cb function
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * Returns: Pointer to PMKSA cache data or %NULL on failure
+ */
+struct rsn_pmksa_cache *
+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+				 void *ctx, enum pmksa_free_reason reason),
+		 void *ctx, struct wpa_sm *sm)
+{
+	struct rsn_pmksa_cache *pmksa;
+
+	pmksa = os_zalloc(sizeof(*pmksa));
+	if (pmksa) {
+		pmksa->free_cb = free_cb;
+		pmksa->ctx = ctx;
+		pmksa->sm = sm;
+	}
+
+	return pmksa;
+}
+
+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/pmksa_cache.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,130 @@
+/*
+ * wpa_supplicant - WPA2/RSN PMKSA cache functions
+ * Copyright (c) 2003-2009, 2011-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PMKSA_CACHE_H
+#define PMKSA_CACHE_H
+
+/**
+ * struct rsn_pmksa_cache_entry - PMKSA cache entry
+ */
+struct rsn_pmksa_cache_entry {
+	struct rsn_pmksa_cache_entry *next;
+	u8 pmkid[PMKID_LEN];
+	u8 pmk[PMK_LEN];
+	size_t pmk_len;
+	os_time_t expiration;
+	int akmp; /* WPA_KEY_MGMT_* */
+	u8 aa[ETH_ALEN];
+
+	os_time_t reauth_time;
+
+	/**
+	 * network_ctx - Network configuration context
+	 *
+	 * This field is only used to match PMKSA cache entries to a specific
+	 * network configuration (e.g., a specific SSID and security policy).
+	 * This can be a pointer to the configuration entry, but PMKSA caching
+	 * code does not dereference the value and this could be any kind of
+	 * identifier.
+	 */
+	void *network_ctx;
+	int opportunistic;
+};
+
+struct rsn_pmksa_cache;
+
+enum pmksa_free_reason {
+	PMKSA_FREE,
+	PMKSA_REPLACE,
+	PMKSA_EXPIRE,
+};
+
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+
+struct rsn_pmksa_cache *
+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+				 void *ctx, enum pmksa_free_reason reason),
+		 void *ctx, struct wpa_sm *sm);
+void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa);
+struct rsn_pmksa_cache_entry * pmksa_cache_get(struct rsn_pmksa_cache *pmksa,
+					       const u8 *aa, const u8 *pmkid,
+					       const void *network_ctx);
+int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf, size_t len);
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+		const u8 *aa, const u8 *spa, void *network_ctx, int akmp);
+struct rsn_pmksa_cache_entry * pmksa_cache_get_current(struct wpa_sm *sm);
+void pmksa_cache_clear_current(struct wpa_sm *sm);
+int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
+			    const u8 *bssid, void *network_ctx,
+			    int try_opportunistic);
+struct rsn_pmksa_cache_entry *
+pmksa_cache_get_opportunistic(struct rsn_pmksa_cache *pmksa,
+			      void *network_ctx, const u8 *aa);
+void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa, void *network_ctx);
+
+#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+
+static inline struct rsn_pmksa_cache *
+pmksa_cache_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+				 void *ctx, int reason),
+		 void *ctx, struct wpa_sm *sm)
+{
+	return (void *) -1;
+}
+
+static inline void pmksa_cache_deinit(struct rsn_pmksa_cache *pmksa)
+{
+}
+
+static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_get(struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *pmkid,
+		const void *network_ctx)
+{
+	return NULL;
+}
+
+static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_get_current(struct wpa_sm *sm)
+{
+	return NULL;
+}
+
+static inline int pmksa_cache_list(struct rsn_pmksa_cache *pmksa, char *buf,
+				   size_t len)
+{
+	return -1;
+}
+
+static inline struct rsn_pmksa_cache_entry *
+pmksa_cache_add(struct rsn_pmksa_cache *pmksa, const u8 *pmk, size_t pmk_len,
+		const u8 *aa, const u8 *spa, void *network_ctx, int akmp)
+{
+	return NULL;
+}
+
+static inline void pmksa_cache_clear_current(struct wpa_sm *sm)
+{
+}
+
+static inline int pmksa_cache_set_current(struct wpa_sm *sm, const u8 *pmkid,
+					  const u8 *bssid,
+					  void *network_ctx,
+					  int try_opportunistic)
+{
+	return -1;
+}
+
+static inline void pmksa_cache_flush(struct rsn_pmksa_cache *pmksa,
+				     void *network_ctx)
+{
+}
+
+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+
+#endif /* PMKSA_CACHE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/preauth.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,511 @@
+/*
+ * RSN pre-authentication (supplicant)
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa.h"
+#include "eloop.h"
+#include "l2_packet/l2_packet.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "preauth.h"
+#include "pmksa_cache.h"
+#include "wpa_i.h"
+
+
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+
+#define PMKID_CANDIDATE_PRIO_SCAN 1000
+
+
+struct rsn_pmksa_candidate {
+	struct dl_list list;
+	u8 bssid[ETH_ALEN];
+	int priority;
+};
+
+
+/**
+ * pmksa_candidate_free - Free all entries in PMKSA candidate list
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+void pmksa_candidate_free(struct wpa_sm *sm)
+{
+	struct rsn_pmksa_candidate *entry, *n;
+
+	if (sm == NULL)
+		return;
+
+	dl_list_for_each_safe(entry, n, &sm->pmksa_candidates,
+			      struct rsn_pmksa_candidate, list) {
+		dl_list_del(&entry->list);
+		os_free(entry);
+	}
+}
+
+
+static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
+				const u8 *buf, size_t len)
+{
+	struct wpa_sm *sm = ctx;
+
+	wpa_printf(MSG_DEBUG, "RX pre-auth from " MACSTR, MAC2STR(src_addr));
+	wpa_hexdump(MSG_MSGDUMP, "RX pre-auth", buf, len);
+
+	if (sm->preauth_eapol == NULL ||
+	    is_zero_ether_addr(sm->preauth_bssid) ||
+	    os_memcmp(sm->preauth_bssid, src_addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_WARNING, "RSN pre-auth frame received from "
+			   "unexpected source " MACSTR " - dropped",
+			   MAC2STR(src_addr));
+		return;
+	}
+
+	eapol_sm_rx_eapol(sm->preauth_eapol, src_addr, buf, len);
+}
+
+
+static void rsn_preauth_eapol_cb(struct eapol_sm *eapol, int success,
+				 void *ctx)
+{
+	struct wpa_sm *sm = ctx;
+	u8 pmk[PMK_LEN];
+
+	if (success) {
+		int res, pmk_len;
+		pmk_len = PMK_LEN;
+		res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
+		if (res) {
+			/*
+			 * EAP-LEAP is an exception from other EAP methods: it
+			 * uses only 16-byte PMK.
+			 */
+			res = eapol_sm_get_key(eapol, pmk, 16);
+			pmk_len = 16;
+		}
+		if (res == 0) {
+			wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from pre-auth",
+					pmk, pmk_len);
+			sm->pmk_len = pmk_len;
+			pmksa_cache_add(sm->pmksa, pmk, pmk_len,
+					sm->preauth_bssid, sm->own_addr,
+					sm->network_ctx,
+					WPA_KEY_MGMT_IEEE8021X);
+		} else {
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"RSN: failed to get master session key from "
+				"pre-auth EAPOL state machines");
+			success = 0;
+		}
+	}
+
+	wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
+		MACSTR " %s", MAC2STR(sm->preauth_bssid),
+		success ? "completed successfully" : "failed");
+
+	rsn_preauth_deinit(sm);
+	rsn_preauth_candidate_process(sm);
+}
+
+
+static void rsn_preauth_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_sm *sm = eloop_ctx;
+
+	wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "RSN: pre-authentication with "
+		MACSTR " timed out", MAC2STR(sm->preauth_bssid));
+	rsn_preauth_deinit(sm);
+	rsn_preauth_candidate_process(sm);
+}
+
+
+static int rsn_preauth_eapol_send(void *ctx, int type, const u8 *buf,
+				  size_t len)
+{
+	struct wpa_sm *sm = ctx;
+	u8 *msg;
+	size_t msglen;
+	int res;
+
+	/* TODO: could add l2_packet_sendmsg that allows fragments to avoid
+	 * extra copy here */
+
+	if (sm->l2_preauth == NULL)
+		return -1;
+
+	msg = wpa_sm_alloc_eapol(sm, type, buf, len, &msglen, NULL);
+	if (msg == NULL)
+		return -1;
+
+	wpa_hexdump(MSG_MSGDUMP, "TX EAPOL (preauth)", msg, msglen);
+	res = l2_packet_send(sm->l2_preauth, sm->preauth_bssid,
+			     ETH_P_RSN_PREAUTH, msg, msglen);
+	os_free(msg);
+	return res;
+}
+
+
+/**
+ * rsn_preauth_init - Start new RSN pre-authentication
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @dst: Authenticator address (BSSID) with which to preauthenticate
+ * @eap_conf: Current EAP configuration
+ * Returns: 0 on success, -1 on another pre-authentication is in progress,
+ * -2 on layer 2 packet initialization failure, -3 on EAPOL state machine
+ * initialization failure, -4 on memory allocation failure
+ *
+ * This function request an RSN pre-authentication with a given destination
+ * address. This is usually called for PMKSA candidates found from scan results
+ * or from driver reports. In addition, ctrl_iface PREAUTH command can trigger
+ * pre-authentication.
+ */
+int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
+		     struct eap_peer_config *eap_conf)
+{
+	struct eapol_config eapol_conf;
+	struct eapol_ctx *ctx;
+
+	if (sm->preauth_eapol)
+		return -1;
+
+	wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"RSN: starting pre-authentication with " MACSTR, MAC2STR(dst));
+
+	sm->l2_preauth = l2_packet_init(sm->ifname, sm->own_addr,
+					ETH_P_RSN_PREAUTH,
+					rsn_preauth_receive, sm, 0);
+	if (sm->l2_preauth == NULL) {
+		wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 packet "
+			   "processing for pre-authentication");
+		return -2;
+	}
+
+	if (sm->bridge_ifname) {
+		sm->l2_preauth_br = l2_packet_init(sm->bridge_ifname,
+						   sm->own_addr,
+						   ETH_P_RSN_PREAUTH,
+						   rsn_preauth_receive, sm, 0);
+		if (sm->l2_preauth_br == NULL) {
+			wpa_printf(MSG_WARNING, "RSN: Failed to initialize L2 "
+				   "packet processing (bridge) for "
+				   "pre-authentication");
+			return -2;
+		}
+	}
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL) {
+		wpa_printf(MSG_WARNING, "Failed to allocate EAPOL context.");
+		return -4;
+	}
+	ctx->ctx = sm->ctx->ctx;
+	ctx->msg_ctx = sm->ctx->ctx;
+	ctx->preauth = 1;
+	ctx->cb = rsn_preauth_eapol_cb;
+	ctx->cb_ctx = sm;
+	ctx->scard_ctx = sm->scard_ctx;
+	ctx->eapol_send = rsn_preauth_eapol_send;
+	ctx->eapol_send_ctx = sm;
+	ctx->set_config_blob = sm->ctx->set_config_blob;
+	ctx->get_config_blob = sm->ctx->get_config_blob;
+
+	sm->preauth_eapol = eapol_sm_init(ctx);
+	if (sm->preauth_eapol == NULL) {
+		os_free(ctx);
+		wpa_printf(MSG_WARNING, "RSN: Failed to initialize EAPOL "
+			   "state machines for pre-authentication");
+		return -3;
+	}
+	os_memset(&eapol_conf, 0, sizeof(eapol_conf));
+	eapol_conf.accept_802_1x_keys = 0;
+	eapol_conf.required_keys = 0;
+	eapol_conf.fast_reauth = sm->fast_reauth;
+	eapol_conf.workaround = sm->eap_workaround;
+	eapol_sm_notify_config(sm->preauth_eapol, eap_conf, &eapol_conf);
+	/*
+	 * Use a shorter startPeriod with preauthentication since the first
+	 * preauth EAPOL-Start frame may end up being dropped due to race
+	 * condition in the AP between the data receive and key configuration
+	 * after the 4-Way Handshake.
+	 */
+	eapol_sm_configure(sm->preauth_eapol, -1, -1, 5, 6);
+	os_memcpy(sm->preauth_bssid, dst, ETH_ALEN);
+
+	eapol_sm_notify_portValid(sm->preauth_eapol, TRUE);
+	/* 802.1X::portControl = Auto */
+	eapol_sm_notify_portEnabled(sm->preauth_eapol, TRUE);
+
+	eloop_register_timeout(sm->dot11RSNAConfigSATimeout, 0,
+			       rsn_preauth_timeout, sm, NULL);
+
+	return 0;
+}
+
+
+/**
+ * rsn_preauth_deinit - Abort RSN pre-authentication
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ *
+ * This function aborts the current RSN pre-authentication (if one is started)
+ * and frees resources allocated for it.
+ */
+void rsn_preauth_deinit(struct wpa_sm *sm)
+{
+	if (sm == NULL || !sm->preauth_eapol)
+		return;
+
+	eloop_cancel_timeout(rsn_preauth_timeout, sm, NULL);
+	eapol_sm_deinit(sm->preauth_eapol);
+	sm->preauth_eapol = NULL;
+	os_memset(sm->preauth_bssid, 0, ETH_ALEN);
+
+	l2_packet_deinit(sm->l2_preauth);
+	sm->l2_preauth = NULL;
+	if (sm->l2_preauth_br) {
+		l2_packet_deinit(sm->l2_preauth_br);
+		sm->l2_preauth_br = NULL;
+	}
+}
+
+
+/**
+ * rsn_preauth_candidate_process - Process PMKSA candidates
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ *
+ * Go through the PMKSA candidates and start pre-authentication if a candidate
+ * without an existing PMKSA cache entry is found. Processed candidates will be
+ * removed from the list.
+ */
+void rsn_preauth_candidate_process(struct wpa_sm *sm)
+{
+	struct rsn_pmksa_candidate *candidate, *n;
+
+	if (dl_list_empty(&sm->pmksa_candidates))
+		return;
+
+	/* TODO: drop priority for old candidate entries */
+
+	wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: processing PMKSA candidate "
+		"list");
+	if (sm->preauth_eapol ||
+	    sm->proto != WPA_PROTO_RSN ||
+	    wpa_sm_get_state(sm) != WPA_COMPLETED ||
+	    (sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X &&
+	     sm->key_mgmt != WPA_KEY_MGMT_IEEE8021X_SHA256)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: not in suitable "
+			"state for new pre-authentication");
+		return; /* invalid state for new pre-auth */
+	}
+
+	dl_list_for_each_safe(candidate, n, &sm->pmksa_candidates,
+			      struct rsn_pmksa_candidate, list) {
+		struct rsn_pmksa_cache_entry *p = NULL;
+		p = pmksa_cache_get(sm->pmksa, candidate->bssid, NULL, NULL);
+		if (os_memcmp(sm->bssid, candidate->bssid, ETH_ALEN) != 0 &&
+		    (p == NULL || p->opportunistic)) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA "
+				"candidate " MACSTR
+				" selected for pre-authentication",
+				MAC2STR(candidate->bssid));
+			dl_list_del(&candidate->list);
+			rsn_preauth_init(sm, candidate->bssid,
+					 sm->eap_conf_ctx);
+			os_free(candidate);
+			return;
+		}
+		wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA candidate "
+			MACSTR " does not need pre-authentication anymore",
+			MAC2STR(candidate->bssid));
+		/* Some drivers (e.g., NDIS) expect to get notified about the
+		 * PMKIDs again, so report the existing data now. */
+		if (p) {
+			wpa_sm_add_pmkid(sm, candidate->bssid, p->pmkid);
+		}
+
+		dl_list_del(&candidate->list);
+		os_free(candidate);
+	}
+	wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: no more pending PMKSA "
+		"candidates");
+}
+
+
+/**
+ * pmksa_candidate_add - Add a new PMKSA candidate
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @bssid: BSSID (authenticator address) of the candidate
+ * @prio: Priority (the smaller number, the higher priority)
+ * @preauth: Whether the candidate AP advertises support for pre-authentication
+ *
+ * This function is used to add PMKSA candidates for RSN pre-authentication. It
+ * is called from scan result processing and from driver events for PMKSA
+ * candidates, i.e., EVENT_PMKID_CANDIDATE events to wpa_supplicant_event().
+ */
+void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
+			 int prio, int preauth)
+{
+	struct rsn_pmksa_candidate *cand, *pos;
+
+	if (sm->network_ctx && sm->proactive_key_caching)
+		pmksa_cache_get_opportunistic(sm->pmksa, sm->network_ctx,
+					      bssid);
+
+	if (!preauth) {
+		wpa_printf(MSG_DEBUG, "RSN: Ignored PMKID candidate without "
+			   "preauth flag");
+		return;
+	}
+
+	/* If BSSID already on candidate list, update the priority of the old
+	 * entry. Do not override priority based on normal scan results. */
+	cand = NULL;
+	dl_list_for_each(pos, &sm->pmksa_candidates,
+			 struct rsn_pmksa_candidate, list) {
+		if (os_memcmp(pos->bssid, bssid, ETH_ALEN) == 0) {
+			cand = pos;
+			break;
+		}
+	}
+
+	if (cand) {
+		dl_list_del(&cand->list);
+		if (prio < PMKID_CANDIDATE_PRIO_SCAN)
+			cand->priority = prio;
+	} else {
+		cand = os_zalloc(sizeof(*cand));
+		if (cand == NULL)
+			return;
+		os_memcpy(cand->bssid, bssid, ETH_ALEN);
+		cand->priority = prio;
+	}
+
+	/* Add candidate to the list; order by increasing priority value. i.e.,
+	 * highest priority (smallest value) first. */
+	dl_list_for_each(pos, &sm->pmksa_candidates,
+			 struct rsn_pmksa_candidate, list) {
+		if (cand->priority <= pos->priority) {
+			dl_list_add(pos->list.prev, &cand->list);
+			cand = NULL;
+			break;
+		}
+	}
+	if (cand)
+		dl_list_add_tail(&sm->pmksa_candidates, &cand->list);
+
+	wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: added PMKSA cache "
+		"candidate " MACSTR " prio %d", MAC2STR(bssid), prio);
+	rsn_preauth_candidate_process(sm);
+}
+
+
+/* TODO: schedule periodic scans if current AP supports preauth */
+
+/**
+ * rsn_preauth_scan_results - Start processing scan results for canditates
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * Returns: 0 if ready to process results or -1 to skip processing
+ *
+ * This functions is used to notify RSN code about start of new scan results
+ * processing. The actual scan results will be provided by calling
+ * rsn_preauth_scan_result() for each BSS if this function returned 0.
+ */
+int rsn_preauth_scan_results(struct wpa_sm *sm)
+{
+	if (sm->ssid_len == 0)
+		return -1;
+
+	/*
+	 * TODO: is it ok to free all candidates? What about the entries
+	 * received from EVENT_PMKID_CANDIDATE?
+	 */
+	pmksa_candidate_free(sm);
+
+	return 0;
+}
+
+
+/**
+ * rsn_preauth_scan_result - Processing scan result for PMKSA canditates
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ *
+ * Add all suitable APs (Authenticators) from scan results into PMKSA
+ * candidate list.
+ */
+void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
+			     const u8 *ssid, const u8 *rsn)
+{
+	struct wpa_ie_data ie;
+	struct rsn_pmksa_cache_entry *pmksa;
+
+	if (ssid[1] != sm->ssid_len ||
+	    os_memcmp(ssid + 2, sm->ssid, sm->ssid_len) != 0)
+		return; /* Not for the current SSID */
+
+	if (os_memcmp(bssid, sm->bssid, ETH_ALEN) == 0)
+		return; /* Ignore current AP */
+
+	if (wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie))
+		return;
+
+	pmksa = pmksa_cache_get(sm->pmksa, bssid, NULL, NULL);
+	if (pmksa && (!pmksa->opportunistic ||
+		      !(ie.capabilities & WPA_CAPABILITY_PREAUTH)))
+		return;
+
+	/* Give less priority to candidates found from normal scan results. */
+	pmksa_candidate_add(sm, bssid, PMKID_CANDIDATE_PRIO_SCAN,
+			    ie.capabilities & WPA_CAPABILITY_PREAUTH);
+}
+
+
+#ifdef CONFIG_CTRL_IFACE
+/**
+ * rsn_preauth_get_status - Get pre-authentication status
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @buf: Buffer for status information
+ * @buflen: Maximum buffer length
+ * @verbose: Whether to include verbose status information
+ * Returns: Number of bytes written to buf.
+ *
+ * Query WPA2 pre-authentication for status information. This function fills in
+ * a text area with current status information. If the buffer (buf) is not
+ * large enough, status information will be truncated to fit the buffer.
+ */
+int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
+			   int verbose)
+{
+	char *pos = buf, *end = buf + buflen;
+	int res, ret;
+
+	if (sm->preauth_eapol) {
+		ret = os_snprintf(pos, end - pos, "Pre-authentication "
+				  "EAPOL state machines:\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		res = eapol_sm_get_status(sm->preauth_eapol,
+					  pos, end - pos, verbose);
+		if (res >= 0)
+			pos += res;
+	}
+
+	return pos - buf;
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
+/**
+ * rsn_preauth_in_progress - Verify whether pre-authentication is in progress
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+int rsn_preauth_in_progress(struct wpa_sm *sm)
+{
+	return sm->preauth_eapol != NULL;
+}
+
+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/preauth.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,79 @@
+/*
+ * wpa_supplicant - WPA2/RSN pre-authentication functions
+ * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PREAUTH_H
+#define PREAUTH_H
+
+struct wpa_scan_results;
+
+#if defined(IEEE8021X_EAPOL) && !defined(CONFIG_NO_WPA2)
+
+void pmksa_candidate_free(struct wpa_sm *sm);
+int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
+		     struct eap_peer_config *eap_conf);
+void rsn_preauth_deinit(struct wpa_sm *sm);
+int rsn_preauth_scan_results(struct wpa_sm *sm);
+void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
+			     const u8 *ssid, const u8 *rsn);
+void pmksa_candidate_add(struct wpa_sm *sm, const u8 *bssid,
+			 int prio, int preauth);
+void rsn_preauth_candidate_process(struct wpa_sm *sm);
+int rsn_preauth_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
+			   int verbose);
+int rsn_preauth_in_progress(struct wpa_sm *sm);
+
+#else /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+
+static inline void pmksa_candidate_free(struct wpa_sm *sm)
+{
+}
+
+static inline void rsn_preauth_candidate_process(struct wpa_sm *sm)
+{
+}
+
+static inline int rsn_preauth_init(struct wpa_sm *sm, const u8 *dst,
+				   struct eap_peer_config *eap_conf)
+{
+	return -1;
+}
+
+static inline void rsn_preauth_deinit(struct wpa_sm *sm)
+{
+}
+
+static inline int rsn_preauth_scan_results(struct wpa_sm *sm)
+{
+	return -1;
+}
+
+static inline void rsn_preauth_scan_result(struct wpa_sm *sm, const u8 *bssid,
+					   const u8 *ssid, const u8 *rsn)
+{
+}
+
+static inline void pmksa_candidate_add(struct wpa_sm *sm,
+				       const u8 *bssid,
+				       int prio, int preauth)
+{
+}
+
+static inline int rsn_preauth_get_status(struct wpa_sm *sm, char *buf,
+					 size_t buflen, int verbose)
+{
+	return 0;
+}
+
+static inline int rsn_preauth_in_progress(struct wpa_sm *sm)
+{
+	return 0;
+}
+
+#endif /* IEEE8021X_EAPOL and !CONFIG_NO_WPA2 */
+
+#endif /* PREAUTH_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/wpa.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,2702 @@
+/*
+ * WPA Supplicant - WPA state machine and EAPOL-Key processing
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "crypto/random.h"
+#include "common/ieee802_11_defs.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "wpa.h"
+#include "eloop.h"
+#include "preauth.h"
+#include "pmksa_cache.h"
+#include "wpa_i.h"
+#include "wpa_ie.h"
+#include "peerkey.h"
+
+
+/**
+ * wpa_eapol_key_send - Send WPA/RSN EAPOL-Key message
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @kck: Key Confirmation Key (KCK, part of PTK)
+ * @ver: Version field from Key Info
+ * @dest: Destination address for the frame
+ * @proto: Ethertype (usually ETH_P_EAPOL)
+ * @msg: EAPOL-Key message
+ * @msg_len: Length of message
+ * @key_mic: Pointer to the buffer to which the EAPOL-Key MIC is written
+ */
+void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
+			int ver, const u8 *dest, u16 proto,
+			u8 *msg, size_t msg_len, u8 *key_mic)
+{
+	if (is_zero_ether_addr(dest) && is_zero_ether_addr(sm->bssid)) {
+		/*
+		 * Association event was not yet received; try to fetch
+		 * BSSID from the driver.
+		 */
+		if (wpa_sm_get_bssid(sm, sm->bssid) < 0) {
+			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"WPA: Failed to read BSSID for "
+				"EAPOL-Key destination address");
+		} else {
+			dest = sm->bssid;
+			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"WPA: Use BSSID (" MACSTR
+				") as the destination for EAPOL-Key",
+				MAC2STR(dest));
+		}
+	}
+	if (key_mic &&
+	    wpa_eapol_key_mic(kck, ver, msg, msg_len, key_mic)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+			"WPA: Failed to generate EAPOL-Key "
+			"version %d MIC", ver);
+		goto out;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", kck, 16);
+	wpa_hexdump(MSG_DEBUG, "WPA: Derived Key MIC", key_mic, 16);
+	wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key", msg, msg_len);
+	wpa_sm_ether_send(sm, dest, proto, msg, msg_len);
+	eapol_sm_notify_tx_eapol_key(sm->eapol);
+out:
+	os_free(msg);
+}
+
+
+/**
+ * wpa_sm_key_request - Send EAPOL-Key Request
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @error: Indicate whether this is an Michael MIC error report
+ * @pairwise: 1 = error report for pairwise packet, 0 = for group packet
+ *
+ * Send an EAPOL-Key Request to the current authenticator. This function is
+ * used to request rekeying and it is usually called when a local Michael MIC
+ * failure is detected.
+ */
+void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise)
+{
+	size_t rlen;
+	struct wpa_eapol_key *reply;
+	int key_info, ver;
+	u8 bssid[ETH_ALEN], *rbuf;
+
+	if (wpa_key_mgmt_ft(sm->key_mgmt) || wpa_key_mgmt_sha256(sm->key_mgmt))
+		ver = WPA_KEY_INFO_TYPE_AES_128_CMAC;
+	else if (sm->pairwise_cipher != WPA_CIPHER_TKIP)
+		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
+	else
+		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+
+	if (wpa_sm_get_bssid(sm, bssid) < 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"Failed to read BSSID for EAPOL-Key request");
+		return;
+	}
+
+	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+				  sizeof(*reply), &rlen, (void *) &reply);
+	if (rbuf == NULL)
+		return;
+
+	reply->type = sm->proto == WPA_PROTO_RSN ?
+		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
+	key_info = WPA_KEY_INFO_REQUEST | ver;
+	if (sm->ptk_set)
+		key_info |= WPA_KEY_INFO_MIC;
+	if (error)
+		key_info |= WPA_KEY_INFO_ERROR;
+	if (pairwise)
+		key_info |= WPA_KEY_INFO_KEY_TYPE;
+	WPA_PUT_BE16(reply->key_info, key_info);
+	WPA_PUT_BE16(reply->key_length, 0);
+	os_memcpy(reply->replay_counter, sm->request_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	inc_byte_array(sm->request_counter, WPA_REPLAY_COUNTER_LEN);
+
+	WPA_PUT_BE16(reply->key_data_length, 0);
+
+	wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+		"WPA: Sending EAPOL-Key Request (error=%d "
+		"pairwise=%d ptk_set=%d len=%lu)",
+		error, pairwise, sm->ptk_set, (unsigned long) rlen);
+	wpa_eapol_key_send(sm, sm->ptk.kck, ver, bssid, ETH_P_EAPOL,
+			   rbuf, rlen, key_info & WPA_KEY_INFO_MIC ?
+			   reply->key_mic : NULL);
+}
+
+
+static int wpa_supplicant_get_pmk(struct wpa_sm *sm,
+				  const unsigned char *src_addr,
+				  const u8 *pmkid)
+{
+	int abort_cached = 0;
+
+	if (pmkid && !sm->cur_pmksa) {
+		/* When using drivers that generate RSN IE, wpa_supplicant may
+		 * not have enough time to get the association information
+		 * event before receiving this 1/4 message, so try to find a
+		 * matching PMKSA cache entry here. */
+		sm->cur_pmksa = pmksa_cache_get(sm->pmksa, src_addr, pmkid,
+						NULL);
+		if (sm->cur_pmksa) {
+			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"RSN: found matching PMKID from PMKSA cache");
+		} else {
+			wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"RSN: no matching PMKID found");
+			abort_cached = 1;
+		}
+	}
+
+	if (pmkid && sm->cur_pmksa &&
+	    os_memcmp(pmkid, sm->cur_pmksa->pmkid, PMKID_LEN) == 0) {
+		wpa_hexdump(MSG_DEBUG, "RSN: matched PMKID", pmkid, PMKID_LEN);
+		wpa_sm_set_pmk_from_pmksa(sm);
+		wpa_hexdump_key(MSG_DEBUG, "RSN: PMK from PMKSA cache",
+				sm->pmk, sm->pmk_len);
+		eapol_sm_notify_cached(sm->eapol);
+#ifdef CONFIG_IEEE80211R
+		sm->xxkey_len = 0;
+#endif /* CONFIG_IEEE80211R */
+	} else if (wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) && sm->eapol) {
+		int res, pmk_len;
+		pmk_len = PMK_LEN;
+		res = eapol_sm_get_key(sm->eapol, sm->pmk, PMK_LEN);
+		if (res) {
+			/*
+			 * EAP-LEAP is an exception from other EAP methods: it
+			 * uses only 16-byte PMK.
+			 */
+			res = eapol_sm_get_key(sm->eapol, sm->pmk, 16);
+			pmk_len = 16;
+		} else {
+#ifdef CONFIG_IEEE80211R
+			u8 buf[2 * PMK_LEN];
+			if (eapol_sm_get_key(sm->eapol, buf, 2 * PMK_LEN) == 0)
+			{
+				os_memcpy(sm->xxkey, buf + PMK_LEN, PMK_LEN);
+				sm->xxkey_len = PMK_LEN;
+				os_memset(buf, 0, sizeof(buf));
+			}
+#endif /* CONFIG_IEEE80211R */
+		}
+		if (res == 0) {
+			struct rsn_pmksa_cache_entry *sa = NULL;
+			wpa_hexdump_key(MSG_DEBUG, "WPA: PMK from EAPOL state "
+					"machines", sm->pmk, pmk_len);
+			sm->pmk_len = pmk_len;
+			if (sm->proto == WPA_PROTO_RSN &&
+			    !wpa_key_mgmt_ft(sm->key_mgmt)) {
+				sa = pmksa_cache_add(sm->pmksa,
+						     sm->pmk, pmk_len,
+						     src_addr, sm->own_addr,
+						     sm->network_ctx,
+						     sm->key_mgmt);
+			}
+			if (!sm->cur_pmksa && pmkid &&
+			    pmksa_cache_get(sm->pmksa, src_addr, pmkid, NULL))
+			{
+				wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+					"RSN: the new PMK matches with the "
+					"PMKID");
+				abort_cached = 0;
+			}
+
+			if (!sm->cur_pmksa)
+				sm->cur_pmksa = sa;
+		} else {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Failed to get master session key from "
+				"EAPOL state machines - key handshake "
+				"aborted");
+			if (sm->cur_pmksa) {
+				wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+					"RSN: Cancelled PMKSA caching "
+					"attempt");
+				sm->cur_pmksa = NULL;
+				abort_cached = 1;
+			} else if (!abort_cached) {
+				return -1;
+			}
+		}
+	}
+
+	if (abort_cached && wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt) &&
+	    !wpa_key_mgmt_ft(sm->key_mgmt)) {
+		/* Send EAPOL-Start to trigger full EAP authentication. */
+		u8 *buf;
+		size_t buflen;
+
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"RSN: no PMKSA entry found - trigger "
+			"full EAP authentication");
+		buf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_START,
+					 NULL, 0, &buflen, NULL);
+		if (buf) {
+			wpa_sm_ether_send(sm, sm->bssid, ETH_P_EAPOL,
+					  buf, buflen);
+			os_free(buf);
+			return -2;
+		}
+
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_send_2_of_4 - Send message 2 of WPA/RSN 4-Way Handshake
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @dst: Destination address for the frame
+ * @key: Pointer to the EAPOL-Key frame header
+ * @ver: Version bits from EAPOL-Key Key Info
+ * @nonce: Nonce value for the EAPOL-Key frame
+ * @wpa_ie: WPA/RSN IE
+ * @wpa_ie_len: Length of the WPA/RSN IE
+ * @ptk: PTK to use for keyed hash and encryption
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
+			       const struct wpa_eapol_key *key,
+			       int ver, const u8 *nonce,
+			       const u8 *wpa_ie, size_t wpa_ie_len,
+			       struct wpa_ptk *ptk)
+{
+	size_t rlen;
+	struct wpa_eapol_key *reply;
+	u8 *rbuf;
+	u8 *rsn_ie_buf = NULL;
+
+	if (wpa_ie == NULL) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No wpa_ie set - "
+			"cannot generate msg 2/4");
+		return -1;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
+		int res;
+
+		/*
+		 * Add PMKR1Name into RSN IE (PMKID-List) and add MDIE and
+		 * FTIE from (Re)Association Response.
+		 */
+		rsn_ie_buf = os_malloc(wpa_ie_len + 2 + 2 + PMKID_LEN +
+				       sm->assoc_resp_ies_len);
+		if (rsn_ie_buf == NULL)
+			return -1;
+		os_memcpy(rsn_ie_buf, wpa_ie, wpa_ie_len);
+		res = wpa_insert_pmkid(rsn_ie_buf, wpa_ie_len,
+				       sm->pmk_r1_name);
+		if (res < 0) {
+			os_free(rsn_ie_buf);
+			return -1;
+		}
+		wpa_ie_len += res;
+
+		if (sm->assoc_resp_ies) {
+			os_memcpy(rsn_ie_buf + wpa_ie_len, sm->assoc_resp_ies,
+				  sm->assoc_resp_ies_len);
+			wpa_ie_len += sm->assoc_resp_ies_len;
+		}
+
+		wpa_ie = rsn_ie_buf;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
+
+	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY,
+				  NULL, sizeof(*reply) + wpa_ie_len,
+				  &rlen, (void *) &reply);
+	if (rbuf == NULL) {
+		os_free(rsn_ie_buf);
+		return -1;
+	}
+
+	reply->type = sm->proto == WPA_PROTO_RSN ?
+		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
+	WPA_PUT_BE16(reply->key_info,
+		     ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC);
+	if (sm->proto == WPA_PROTO_RSN)
+		WPA_PUT_BE16(reply->key_length, 0);
+	else
+		os_memcpy(reply->key_length, key->key_length, 2);
+	os_memcpy(reply->replay_counter, key->replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPA: Replay Counter", reply->replay_counter,
+		    WPA_REPLAY_COUNTER_LEN);
+
+	WPA_PUT_BE16(reply->key_data_length, wpa_ie_len);
+	os_memcpy(reply + 1, wpa_ie, wpa_ie_len);
+	os_free(rsn_ie_buf);
+
+	os_memcpy(reply->key_nonce, nonce, WPA_NONCE_LEN);
+
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
+	wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
+			   rbuf, rlen, reply->key_mic);
+
+	return 0;
+}
+
+
+static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
+			  const struct wpa_eapol_key *key,
+			  struct wpa_ptk *ptk)
+{
+	size_t ptk_len = sm->pairwise_cipher != WPA_CIPHER_TKIP ? 48 : 64;
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->key_mgmt))
+		return wpa_derive_ptk_ft(sm, src_addr, key, ptk, ptk_len);
+#endif /* CONFIG_IEEE80211R */
+
+	wpa_pmk_to_ptk(sm->pmk, sm->pmk_len, "Pairwise key expansion",
+		       sm->own_addr, sm->bssid, sm->snonce, key->key_nonce,
+		       (u8 *) ptk, ptk_len,
+		       wpa_key_mgmt_sha256(sm->key_mgmt));
+	return 0;
+}
+
+
+static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
+					  const unsigned char *src_addr,
+					  const struct wpa_eapol_key *key,
+					  u16 ver)
+{
+	struct wpa_eapol_ie_parse ie;
+	struct wpa_ptk *ptk;
+	u8 buf[8];
+	int res;
+
+	if (wpa_sm_get_network_ctx(sm) == NULL) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: No SSID info "
+			"found (msg 1 of 4)");
+		return;
+	}
+
+	wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of 4-Way "
+		"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
+
+	os_memset(&ie, 0, sizeof(ie));
+
+#ifndef CONFIG_NO_WPA2
+	if (sm->proto == WPA_PROTO_RSN) {
+		/* RSN: msg 1/4 should contain PMKID for the selected PMK */
+		const u8 *_buf = (const u8 *) (key + 1);
+		size_t len = WPA_GET_BE16(key->key_data_length);
+		wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data", _buf, len);
+		if (wpa_supplicant_parse_ies(_buf, len, &ie) < 0)
+			goto failed;
+		if (ie.pmkid) {
+			wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
+				    "Authenticator", ie.pmkid, PMKID_LEN);
+		}
+	}
+#endif /* CONFIG_NO_WPA2 */
+
+	res = wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid);
+	if (res == -2) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: Do not reply to "
+			"msg 1/4 - requesting full EAP authentication");
+		return;
+	}
+	if (res)
+		goto failed;
+
+	if (sm->renew_snonce) {
+		if (random_get_bytes(sm->snonce, WPA_NONCE_LEN)) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Failed to get random data for SNonce");
+			goto failed;
+		}
+		sm->renew_snonce = 0;
+		wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce",
+			    sm->snonce, WPA_NONCE_LEN);
+	}
+
+	/* Calculate PTK which will be stored as a temporary PTK until it has
+	 * been verified when processing message 3/4. */
+	ptk = &sm->tptk;
+	wpa_derive_ptk(sm, src_addr, key, ptk);
+	/* Supplicant: swap tx/rx Mic keys */
+	os_memcpy(buf, ptk->u.auth.tx_mic_key, 8);
+	os_memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8);
+	os_memcpy(ptk->u.auth.rx_mic_key, buf, 8);
+	sm->tptk_set = 1;
+
+	if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
+				       sm->assoc_wpa_ie, sm->assoc_wpa_ie_len,
+				       ptk))
+		goto failed;
+
+	os_memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN);
+	return;
+
+failed:
+	wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
+}
+
+
+static void wpa_sm_start_preauth(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_sm *sm = eloop_ctx;
+	rsn_preauth_candidate_process(sm);
+}
+
+
+static void wpa_supplicant_key_neg_complete(struct wpa_sm *sm,
+					    const u8 *addr, int secure)
+{
+	wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+		"WPA: Key negotiation completed with "
+		MACSTR " [PTK=%s GTK=%s]", MAC2STR(addr),
+		wpa_cipher_txt(sm->pairwise_cipher),
+		wpa_cipher_txt(sm->group_cipher));
+	wpa_sm_cancel_auth_timeout(sm);
+	wpa_sm_set_state(sm, WPA_COMPLETED);
+
+	if (secure) {
+		wpa_sm_mlme_setprotection(
+			sm, addr, MLME_SETPROTECTION_PROTECT_TYPE_RX_TX,
+			MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
+		eapol_sm_notify_portValid(sm->eapol, TRUE);
+		if (wpa_key_mgmt_wpa_psk(sm->key_mgmt))
+			eapol_sm_notify_eap_success(sm->eapol, TRUE);
+		/*
+		 * Start preauthentication after a short wait to avoid a
+		 * possible race condition between the data receive and key
+		 * configuration after the 4-Way Handshake. This increases the
+		 * likelihood of the first preauth EAPOL-Start frame getting to
+		 * the target AP.
+		 */
+		eloop_register_timeout(1, 0, wpa_sm_start_preauth, sm, NULL);
+	}
+
+	if (sm->cur_pmksa && sm->cur_pmksa->opportunistic) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"RSN: Authenticator accepted "
+			"opportunistic PMKSA entry - marking it valid");
+		sm->cur_pmksa->opportunistic = 0;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
+		/* Prepare for the next transition */
+		wpa_ft_prepare_auth_request(sm, NULL);
+	}
+#endif /* CONFIG_IEEE80211R */
+}
+
+
+static void wpa_sm_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_sm *sm = eloop_ctx;
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Request PTK rekeying");
+	wpa_sm_key_request(sm, 0, 1);
+}
+
+
+static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
+				      const struct wpa_eapol_key *key)
+{
+	int keylen, rsclen;
+	enum wpa_alg alg;
+	const u8 *key_rsc;
+	u8 null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"WPA: Installing PTK to the driver");
+
+	if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Pairwise Cipher "
+			"Suite: NONE - do not use pairwise keys");
+		return 0;
+	}
+
+	if (!wpa_cipher_valid_pairwise(sm->pairwise_cipher)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Unsupported pairwise cipher %d",
+			sm->pairwise_cipher);
+		return -1;
+	}
+
+	alg = wpa_cipher_to_alg(sm->pairwise_cipher);
+	keylen = wpa_cipher_key_len(sm->pairwise_cipher);
+	rsclen = wpa_cipher_rsc_len(sm->pairwise_cipher);
+
+	if (sm->proto == WPA_PROTO_RSN) {
+		key_rsc = null_rsc;
+	} else {
+		key_rsc = key->key_rsc;
+		wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen);
+	}
+
+	if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
+			   (u8 *) sm->ptk.tk1, keylen) < 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Failed to set PTK to the "
+			"driver (alg=%d keylen=%d bssid=" MACSTR ")",
+			alg, keylen, MAC2STR(sm->bssid));
+		return -1;
+	}
+
+	if (sm->wpa_ptk_rekey) {
+		eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
+		eloop_register_timeout(sm->wpa_ptk_rekey, 0, wpa_sm_rekey_ptk,
+				       sm, NULL);
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_check_group_cipher(struct wpa_sm *sm,
+					     int group_cipher,
+					     int keylen, int maxkeylen,
+					     int *key_rsc_len,
+					     enum wpa_alg *alg)
+{
+	int klen;
+
+	*alg = wpa_cipher_to_alg(group_cipher);
+	if (*alg == WPA_ALG_NONE) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Unsupported Group Cipher %d",
+			group_cipher);
+		return -1;
+	}
+	*key_rsc_len = wpa_cipher_rsc_len(group_cipher);
+
+	klen = wpa_cipher_key_len(group_cipher);
+	if (keylen != klen || maxkeylen < klen) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Unsupported %s Group Cipher key length %d (%d)",
+			wpa_cipher_txt(group_cipher), keylen, maxkeylen);
+		return -1;
+	}
+	return 0;
+}
+
+
+struct wpa_gtk_data {
+	enum wpa_alg alg;
+	int tx, key_rsc_len, keyidx;
+	u8 gtk[32];
+	int gtk_len;
+};
+
+
+static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
+				      const struct wpa_gtk_data *gd,
+				      const u8 *key_rsc)
+{
+	const u8 *_gtk = gd->gtk;
+	u8 gtk_buf[32];
+
+	wpa_hexdump_key(MSG_DEBUG, "WPA: Group Key", gd->gtk, gd->gtk_len);
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"WPA: Installing GTK to the driver (keyidx=%d tx=%d len=%d)",
+		gd->keyidx, gd->tx, gd->gtk_len);
+	wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, gd->key_rsc_len);
+	if (sm->group_cipher == WPA_CIPHER_TKIP) {
+		/* Swap Tx/Rx keys for Michael MIC */
+		os_memcpy(gtk_buf, gd->gtk, 16);
+		os_memcpy(gtk_buf + 16, gd->gtk + 24, 8);
+		os_memcpy(gtk_buf + 24, gd->gtk + 16, 8);
+		_gtk = gtk_buf;
+	}
+	if (sm->pairwise_cipher == WPA_CIPHER_NONE) {
+		if (wpa_sm_set_key(sm, gd->alg, NULL,
+				   gd->keyidx, 1, key_rsc, gd->key_rsc_len,
+				   _gtk, gd->gtk_len) < 0) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Failed to set GTK to the driver "
+				"(Group only)");
+			return -1;
+		}
+	} else if (wpa_sm_set_key(sm, gd->alg, broadcast_ether_addr,
+				  gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len,
+				  _gtk, gd->gtk_len) < 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Failed to set GTK to "
+			"the driver (alg=%d keylen=%d keyidx=%d)",
+			gd->alg, gd->gtk_len, gd->keyidx);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_gtk_tx_bit_workaround(const struct wpa_sm *sm,
+						int tx)
+{
+	if (tx && sm->pairwise_cipher != WPA_CIPHER_NONE) {
+		/* Ignore Tx bit for GTK if a pairwise key is used. One AP
+		 * seemed to set this bit (incorrectly, since Tx is only when
+		 * doing Group Key only APs) and without this workaround, the
+		 * data connection does not work because wpa_supplicant
+		 * configured non-zero keyidx to be used for unicast. */
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: Tx bit set for GTK, but pairwise "
+			"keys are used - ignore Tx bit");
+		return 0;
+	}
+	return tx;
+}
+
+
+static int wpa_supplicant_pairwise_gtk(struct wpa_sm *sm,
+				       const struct wpa_eapol_key *key,
+				       const u8 *gtk, size_t gtk_len,
+				       int key_info)
+{
+#ifndef CONFIG_NO_WPA2
+	struct wpa_gtk_data gd;
+
+	/*
+	 * IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames - Figure 43x
+	 * GTK KDE format:
+	 * KeyID[bits 0-1], Tx [bit 2], Reserved [bits 3-7]
+	 * Reserved [bits 0-7]
+	 * GTK
+	 */
+
+	os_memset(&gd, 0, sizeof(gd));
+	wpa_hexdump_key(MSG_DEBUG, "RSN: received GTK in pairwise handshake",
+			gtk, gtk_len);
+
+	if (gtk_len < 2 || gtk_len - 2 > sizeof(gd.gtk))
+		return -1;
+
+	gd.keyidx = gtk[0] & 0x3;
+	gd.tx = wpa_supplicant_gtk_tx_bit_workaround(sm,
+						     !!(gtk[0] & BIT(2)));
+	gtk += 2;
+	gtk_len -= 2;
+
+	os_memcpy(gd.gtk, gtk, gtk_len);
+	gd.gtk_len = gtk_len;
+
+	if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
+					      gtk_len, gtk_len,
+					      &gd.key_rsc_len, &gd.alg) ||
+	    wpa_supplicant_install_gtk(sm, &gd, key->key_rsc)) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"RSN: Failed to install GTK");
+		return -1;
+	}
+
+	wpa_supplicant_key_neg_complete(sm, sm->bssid,
+					key_info & WPA_KEY_INFO_SECURE);
+	return 0;
+#else /* CONFIG_NO_WPA2 */
+	return -1;
+#endif /* CONFIG_NO_WPA2 */
+}
+
+
+static int ieee80211w_set_keys(struct wpa_sm *sm,
+			       struct wpa_eapol_ie_parse *ie)
+{
+#ifdef CONFIG_IEEE80211W
+	if (sm->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC)
+		return 0;
+
+	if (ie->igtk) {
+		const struct wpa_igtk_kde *igtk;
+		u16 keyidx;
+		if (ie->igtk_len != sizeof(*igtk))
+			return -1;
+		igtk = (const struct wpa_igtk_kde *) ie->igtk;
+		keyidx = WPA_GET_LE16(igtk->keyid);
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: IGTK keyid %d "
+			"pn %02x%02x%02x%02x%02x%02x",
+			keyidx, MAC2STR(igtk->pn));
+		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK",
+				igtk->igtk, WPA_IGTK_LEN);
+		if (keyidx > 4095) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Invalid IGTK KeyID %d", keyidx);
+			return -1;
+		}
+		if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
+				   keyidx, 0, igtk->pn, sizeof(igtk->pn),
+				   igtk->igtk, WPA_IGTK_LEN) < 0) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Failed to configure IGTK to the driver");
+			return -1;
+		}
+	}
+
+	return 0;
+#else /* CONFIG_IEEE80211W */
+	return 0;
+#endif /* CONFIG_IEEE80211W */
+}
+
+
+static void wpa_report_ie_mismatch(struct wpa_sm *sm,
+				   const char *reason, const u8 *src_addr,
+				   const u8 *wpa_ie, size_t wpa_ie_len,
+				   const u8 *rsn_ie, size_t rsn_ie_len)
+{
+	wpa_msg(sm->ctx->msg_ctx, MSG_WARNING, "WPA: %s (src=" MACSTR ")",
+		reason, MAC2STR(src_addr));
+
+	if (sm->ap_wpa_ie) {
+		wpa_hexdump(MSG_INFO, "WPA: WPA IE in Beacon/ProbeResp",
+			    sm->ap_wpa_ie, sm->ap_wpa_ie_len);
+	}
+	if (wpa_ie) {
+		if (!sm->ap_wpa_ie) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"WPA: No WPA IE in Beacon/ProbeResp");
+		}
+		wpa_hexdump(MSG_INFO, "WPA: WPA IE in 3/4 msg",
+			    wpa_ie, wpa_ie_len);
+	}
+
+	if (sm->ap_rsn_ie) {
+		wpa_hexdump(MSG_INFO, "WPA: RSN IE in Beacon/ProbeResp",
+			    sm->ap_rsn_ie, sm->ap_rsn_ie_len);
+	}
+	if (rsn_ie) {
+		if (!sm->ap_rsn_ie) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"WPA: No RSN IE in Beacon/ProbeResp");
+		}
+		wpa_hexdump(MSG_INFO, "WPA: RSN IE in 3/4 msg",
+			    rsn_ie, rsn_ie_len);
+	}
+
+	wpa_sm_deauthenticate(sm, WLAN_REASON_IE_IN_4WAY_DIFFERS);
+}
+
+
+#ifdef CONFIG_IEEE80211R
+
+static int ft_validate_mdie(struct wpa_sm *sm,
+			    const unsigned char *src_addr,
+			    struct wpa_eapol_ie_parse *ie,
+			    const u8 *assoc_resp_mdie)
+{
+	struct rsn_mdie *mdie;
+
+	mdie = (struct rsn_mdie *) (ie->mdie + 2);
+	if (ie->mdie == NULL || ie->mdie_len < 2 + sizeof(*mdie) ||
+	    os_memcmp(mdie->mobility_domain, sm->mobility_domain,
+		      MOBILITY_DOMAIN_ID_LEN) != 0) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: MDIE in msg 3/4 did "
+			"not match with the current mobility domain");
+		return -1;
+	}
+
+	if (assoc_resp_mdie &&
+	    (assoc_resp_mdie[1] != ie->mdie[1] ||
+	     os_memcmp(assoc_resp_mdie, ie->mdie, 2 + ie->mdie[1]) != 0)) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: MDIE mismatch");
+		wpa_hexdump(MSG_DEBUG, "FT: MDIE in EAPOL-Key msg 3/4",
+			    ie->mdie, 2 + ie->mdie[1]);
+		wpa_hexdump(MSG_DEBUG, "FT: MDIE in (Re)Association Response",
+			    assoc_resp_mdie, 2 + assoc_resp_mdie[1]);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int ft_validate_ftie(struct wpa_sm *sm,
+			    const unsigned char *src_addr,
+			    struct wpa_eapol_ie_parse *ie,
+			    const u8 *assoc_resp_ftie)
+{
+	if (ie->ftie == NULL) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"FT: No FTIE in EAPOL-Key msg 3/4");
+		return -1;
+	}
+
+	if (assoc_resp_ftie == NULL)
+		return 0;
+
+	if (assoc_resp_ftie[1] != ie->ftie[1] ||
+	    os_memcmp(assoc_resp_ftie, ie->ftie, 2 + ie->ftie[1]) != 0) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: FTIE mismatch");
+		wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 3/4",
+			    ie->ftie, 2 + ie->ftie[1]);
+		wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)Association Response",
+			    assoc_resp_ftie, 2 + assoc_resp_ftie[1]);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int ft_validate_rsnie(struct wpa_sm *sm,
+			     const unsigned char *src_addr,
+			     struct wpa_eapol_ie_parse *ie)
+{
+	struct wpa_ie_data rsn;
+
+	if (!ie->rsn_ie)
+		return 0;
+
+	/*
+	 * Verify that PMKR1Name from EAPOL-Key message 3/4
+	 * matches with the value we derived.
+	 */
+	if (wpa_parse_wpa_ie_rsn(ie->rsn_ie, ie->rsn_ie_len, &rsn) < 0 ||
+	    rsn.num_pmkid != 1 || rsn.pmkid == NULL) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "FT: No PMKR1Name in "
+			"FT 4-way handshake message 3/4");
+		return -1;
+	}
+
+	if (os_memcmp(rsn.pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"FT: PMKR1Name mismatch in "
+			"FT 4-way handshake message 3/4");
+		wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Authenticator",
+			    rsn.pmkid, WPA_PMK_NAME_LEN);
+		wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
+			    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_validate_ie_ft(struct wpa_sm *sm,
+					 const unsigned char *src_addr,
+					 struct wpa_eapol_ie_parse *ie)
+{
+	const u8 *pos, *end, *mdie = NULL, *ftie = NULL;
+
+	if (sm->assoc_resp_ies) {
+		pos = sm->assoc_resp_ies;
+		end = pos + sm->assoc_resp_ies_len;
+		while (pos + 2 < end) {
+			if (pos + 2 + pos[1] > end)
+				break;
+			switch (*pos) {
+			case WLAN_EID_MOBILITY_DOMAIN:
+				mdie = pos;
+				break;
+			case WLAN_EID_FAST_BSS_TRANSITION:
+				ftie = pos;
+				break;
+			}
+			pos += 2 + pos[1];
+		}
+	}
+
+	if (ft_validate_mdie(sm, src_addr, ie, mdie) < 0 ||
+	    ft_validate_ftie(sm, src_addr, ie, ftie) < 0 ||
+	    ft_validate_rsnie(sm, src_addr, ie) < 0)
+		return -1;
+
+	return 0;
+}
+
+#endif /* CONFIG_IEEE80211R */
+
+
+static int wpa_supplicant_validate_ie(struct wpa_sm *sm,
+				      const unsigned char *src_addr,
+				      struct wpa_eapol_ie_parse *ie)
+{
+	if (sm->ap_wpa_ie == NULL && sm->ap_rsn_ie == NULL) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: No WPA/RSN IE for this AP known. "
+			"Trying to get from scan results");
+		if (wpa_sm_get_beacon_ie(sm) < 0) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Could not find AP from "
+				"the scan results");
+		} else {
+			wpa_msg(sm->ctx->msg_ctx, MSG_DEBUG,
+				"WPA: Found the current AP from "
+				"updated scan results");
+		}
+	}
+
+	if (ie->wpa_ie == NULL && ie->rsn_ie == NULL &&
+	    (sm->ap_wpa_ie || sm->ap_rsn_ie)) {
+		wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match "
+				       "with IE in Beacon/ProbeResp (no IE?)",
+				       src_addr, ie->wpa_ie, ie->wpa_ie_len,
+				       ie->rsn_ie, ie->rsn_ie_len);
+		return -1;
+	}
+
+	if ((ie->wpa_ie && sm->ap_wpa_ie &&
+	     (ie->wpa_ie_len != sm->ap_wpa_ie_len ||
+	      os_memcmp(ie->wpa_ie, sm->ap_wpa_ie, ie->wpa_ie_len) != 0)) ||
+	    (ie->rsn_ie && sm->ap_rsn_ie &&
+	     wpa_compare_rsn_ie(wpa_key_mgmt_ft(sm->key_mgmt),
+				sm->ap_rsn_ie, sm->ap_rsn_ie_len,
+				ie->rsn_ie, ie->rsn_ie_len))) {
+		wpa_report_ie_mismatch(sm, "IE in 3/4 msg does not match "
+				       "with IE in Beacon/ProbeResp",
+				       src_addr, ie->wpa_ie, ie->wpa_ie_len,
+				       ie->rsn_ie, ie->rsn_ie_len);
+		return -1;
+	}
+
+	if (sm->proto == WPA_PROTO_WPA &&
+	    ie->rsn_ie && sm->ap_rsn_ie == NULL && sm->rsn_enabled) {
+		wpa_report_ie_mismatch(sm, "Possible downgrade attack "
+				       "detected - RSN was enabled and RSN IE "
+				       "was in msg 3/4, but not in "
+				       "Beacon/ProbeResp",
+				       src_addr, ie->wpa_ie, ie->wpa_ie_len,
+				       ie->rsn_ie, ie->rsn_ie_len);
+		return -1;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->key_mgmt) &&
+	    wpa_supplicant_validate_ie_ft(sm, src_addr, ie) < 0)
+		return -1;
+#endif /* CONFIG_IEEE80211R */
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_send_4_of_4 - Send message 4 of WPA/RSN 4-Way Handshake
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @dst: Destination address for the frame
+ * @key: Pointer to the EAPOL-Key frame header
+ * @ver: Version bits from EAPOL-Key Key Info
+ * @key_info: Key Info
+ * @kde: KDEs to include the EAPOL-Key frame
+ * @kde_len: Length of KDEs
+ * @ptk: PTK to use for keyed hash and encryption
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
+			       const struct wpa_eapol_key *key,
+			       u16 ver, u16 key_info,
+			       const u8 *kde, size_t kde_len,
+			       struct wpa_ptk *ptk)
+{
+	size_t rlen;
+	struct wpa_eapol_key *reply;
+	u8 *rbuf;
+
+	if (kde)
+		wpa_hexdump(MSG_DEBUG, "WPA: KDE for msg 4/4", kde, kde_len);
+
+	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+				  sizeof(*reply) + kde_len,
+				  &rlen, (void *) &reply);
+	if (rbuf == NULL)
+		return -1;
+
+	reply->type = sm->proto == WPA_PROTO_RSN ?
+		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
+	key_info &= WPA_KEY_INFO_SECURE;
+	key_info |= ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC;
+	WPA_PUT_BE16(reply->key_info, key_info);
+	if (sm->proto == WPA_PROTO_RSN)
+		WPA_PUT_BE16(reply->key_length, 0);
+	else
+		os_memcpy(reply->key_length, key->key_length, 2);
+	os_memcpy(reply->replay_counter, key->replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+
+	WPA_PUT_BE16(reply->key_data_length, kde_len);
+	if (kde)
+		os_memcpy(reply + 1, kde, kde_len);
+
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
+	wpa_eapol_key_send(sm, ptk->kck, ver, dst, ETH_P_EAPOL,
+			   rbuf, rlen, reply->key_mic);
+
+	return 0;
+}
+
+
+static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
+					  const struct wpa_eapol_key *key,
+					  u16 ver)
+{
+	u16 key_info, keylen, len;
+	const u8 *pos;
+	struct wpa_eapol_ie_parse ie;
+
+	wpa_sm_set_state(sm, WPA_4WAY_HANDSHAKE);
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 3 of 4-Way "
+		"Handshake from " MACSTR " (ver=%d)", MAC2STR(sm->bssid), ver);
+
+	key_info = WPA_GET_BE16(key->key_info);
+
+	pos = (const u8 *) (key + 1);
+	len = WPA_GET_BE16(key->key_data_length);
+	wpa_hexdump(MSG_DEBUG, "WPA: IE KeyData", pos, len);
+	if (wpa_supplicant_parse_ies(pos, len, &ie) < 0)
+		goto failed;
+	if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: GTK IE in unencrypted key data");
+		goto failed;
+	}
+#ifdef CONFIG_IEEE80211W
+	if (ie.igtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: IGTK KDE in unencrypted key data");
+		goto failed;
+	}
+
+	if (ie.igtk && ie.igtk_len != sizeof(struct wpa_igtk_kde)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Invalid IGTK KDE length %lu",
+			(unsigned long) ie.igtk_len);
+		goto failed;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0)
+		goto failed;
+
+	if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: ANonce from message 1 of 4-Way Handshake "
+			"differs from 3 of 4-Way Handshake - drop packet (src="
+			MACSTR ")", MAC2STR(sm->bssid));
+		goto failed;
+	}
+
+	keylen = WPA_GET_BE16(key->key_length);
+	if (keylen != wpa_cipher_key_len(sm->pairwise_cipher)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Invalid %s key length %d (src=" MACSTR
+			")", wpa_cipher_txt(sm->pairwise_cipher), keylen,
+			MAC2STR(sm->bssid));
+		goto failed;
+	}
+
+	if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
+				       NULL, 0, &sm->ptk)) {
+		goto failed;
+	}
+
+	/* SNonce was successfully used in msg 3/4, so mark it to be renewed
+	 * for the next 4-Way Handshake. If msg 3 is received again, the old
+	 * SNonce will still be used to avoid changing PTK. */
+	sm->renew_snonce = 1;
+
+	if (key_info & WPA_KEY_INFO_INSTALL) {
+		if (wpa_supplicant_install_ptk(sm, key))
+			goto failed;
+	}
+
+	if (key_info & WPA_KEY_INFO_SECURE) {
+		wpa_sm_mlme_setprotection(
+			sm, sm->bssid, MLME_SETPROTECTION_PROTECT_TYPE_RX,
+			MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
+		eapol_sm_notify_portValid(sm->eapol, TRUE);
+	}
+	wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
+
+	if (ie.gtk &&
+	    wpa_supplicant_pairwise_gtk(sm, key,
+					ie.gtk, ie.gtk_len, key_info) < 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"RSN: Failed to configure GTK");
+		goto failed;
+	}
+
+	if (ieee80211w_set_keys(sm, &ie) < 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"RSN: Failed to configure IGTK");
+		goto failed;
+	}
+
+	wpa_sm_set_rekey_offload(sm);
+
+	return;
+
+failed:
+	wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
+}
+
+
+static int wpa_supplicant_process_1_of_2_rsn(struct wpa_sm *sm,
+					     const u8 *keydata,
+					     size_t keydatalen,
+					     u16 key_info,
+					     struct wpa_gtk_data *gd)
+{
+	int maxkeylen;
+	struct wpa_eapol_ie_parse ie;
+
+	wpa_hexdump(MSG_DEBUG, "RSN: msg 1/2 key data", keydata, keydatalen);
+	if (wpa_supplicant_parse_ies(keydata, keydatalen, &ie) < 0)
+		return -1;
+	if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: GTK IE in unencrypted key data");
+		return -1;
+	}
+	if (ie.gtk == NULL) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: No GTK IE in Group Key msg 1/2");
+		return -1;
+	}
+	maxkeylen = gd->gtk_len = ie.gtk_len - 2;
+
+	if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
+					      gd->gtk_len, maxkeylen,
+					      &gd->key_rsc_len, &gd->alg))
+		return -1;
+
+	wpa_hexdump(MSG_DEBUG, "RSN: received GTK in group key handshake",
+		    ie.gtk, ie.gtk_len);
+	gd->keyidx = ie.gtk[0] & 0x3;
+	gd->tx = wpa_supplicant_gtk_tx_bit_workaround(sm,
+						      !!(ie.gtk[0] & BIT(2)));
+	if (ie.gtk_len - 2 > sizeof(gd->gtk)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"RSN: Too long GTK in GTK IE (len=%lu)",
+			(unsigned long) ie.gtk_len - 2);
+		return -1;
+	}
+	os_memcpy(gd->gtk, ie.gtk + 2, ie.gtk_len - 2);
+
+	if (ieee80211w_set_keys(sm, &ie) < 0)
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"RSN: Failed to configure IGTK");
+
+	return 0;
+}
+
+
+static int wpa_supplicant_process_1_of_2_wpa(struct wpa_sm *sm,
+					     const struct wpa_eapol_key *key,
+					     size_t keydatalen, int key_info,
+					     size_t extra_len, u16 ver,
+					     struct wpa_gtk_data *gd)
+{
+	size_t maxkeylen;
+	u8 ek[32];
+
+	gd->gtk_len = WPA_GET_BE16(key->key_length);
+	maxkeylen = keydatalen;
+	if (keydatalen > extra_len) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: Truncated EAPOL-Key packet: "
+			"key_data_length=%lu > extra_len=%lu",
+			(unsigned long) keydatalen, (unsigned long) extra_len);
+		return -1;
+	}
+	if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+		if (maxkeylen < 8) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"WPA: Too short maxkeylen (%lu)",
+				(unsigned long) maxkeylen);
+			return -1;
+		}
+		maxkeylen -= 8;
+	}
+
+	if (wpa_supplicant_check_group_cipher(sm, sm->group_cipher,
+					      gd->gtk_len, maxkeylen,
+					      &gd->key_rsc_len, &gd->alg))
+		return -1;
+
+	gd->keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
+		WPA_KEY_INFO_KEY_INDEX_SHIFT;
+	if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
+		os_memcpy(ek, key->key_iv, 16);
+		os_memcpy(ek + 16, sm->ptk.kek, 16);
+		if (keydatalen > sizeof(gd->gtk)) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: RC4 key data too long (%lu)",
+				(unsigned long) keydatalen);
+			return -1;
+		}
+		os_memcpy(gd->gtk, key + 1, keydatalen);
+		if (rc4_skip(ek, 32, 256, gd->gtk, keydatalen)) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+				"WPA: RC4 failed");
+			return -1;
+		}
+	} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+		if (keydatalen % 8) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Unsupported AES-WRAP len %lu",
+				(unsigned long) keydatalen);
+			return -1;
+		}
+		if (maxkeylen > sizeof(gd->gtk)) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: AES-WRAP key data "
+				"too long (keydatalen=%lu maxkeylen=%lu)",
+				(unsigned long) keydatalen,
+				(unsigned long) maxkeylen);
+			return -1;
+		}
+		if (aes_unwrap(sm->ptk.kek, maxkeylen / 8,
+			       (const u8 *) (key + 1), gd->gtk)) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: AES unwrap failed - could not decrypt "
+				"GTK");
+			return -1;
+		}
+	} else {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Unsupported key_info type %d", ver);
+		return -1;
+	}
+	gd->tx = wpa_supplicant_gtk_tx_bit_workaround(
+		sm, !!(key_info & WPA_KEY_INFO_TXRX));
+	return 0;
+}
+
+
+static int wpa_supplicant_send_2_of_2(struct wpa_sm *sm,
+				      const struct wpa_eapol_key *key,
+				      int ver, u16 key_info)
+{
+	size_t rlen;
+	struct wpa_eapol_key *reply;
+	u8 *rbuf;
+
+	rbuf = wpa_sm_alloc_eapol(sm, IEEE802_1X_TYPE_EAPOL_KEY, NULL,
+				  sizeof(*reply), &rlen, (void *) &reply);
+	if (rbuf == NULL)
+		return -1;
+
+	reply->type = sm->proto == WPA_PROTO_RSN ?
+		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
+	key_info &= WPA_KEY_INFO_KEY_INDEX_MASK;
+	key_info |= ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE;
+	WPA_PUT_BE16(reply->key_info, key_info);
+	if (sm->proto == WPA_PROTO_RSN)
+		WPA_PUT_BE16(reply->key_length, 0);
+	else
+		os_memcpy(reply->key_length, key->key_length, 2);
+	os_memcpy(reply->replay_counter, key->replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+
+	WPA_PUT_BE16(reply->key_data_length, 0);
+
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
+	wpa_eapol_key_send(sm, sm->ptk.kck, ver, sm->bssid, ETH_P_EAPOL,
+			   rbuf, rlen, reply->key_mic);
+
+	return 0;
+}
+
+
+static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
+					  const unsigned char *src_addr,
+					  const struct wpa_eapol_key *key,
+					  int extra_len, u16 ver)
+{
+	u16 key_info, keydatalen;
+	int rekey, ret;
+	struct wpa_gtk_data gd;
+
+	os_memset(&gd, 0, sizeof(gd));
+
+	rekey = wpa_sm_get_state(sm) == WPA_COMPLETED;
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: RX message 1 of Group Key "
+		"Handshake from " MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
+
+	key_info = WPA_GET_BE16(key->key_info);
+	keydatalen = WPA_GET_BE16(key->key_data_length);
+
+	if (sm->proto == WPA_PROTO_RSN) {
+		ret = wpa_supplicant_process_1_of_2_rsn(sm,
+							(const u8 *) (key + 1),
+							keydatalen, key_info,
+							&gd);
+	} else {
+		ret = wpa_supplicant_process_1_of_2_wpa(sm, key, keydatalen,
+							key_info, extra_len,
+							ver, &gd);
+	}
+
+	wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
+
+	if (ret)
+		goto failed;
+
+	if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc) ||
+	    wpa_supplicant_send_2_of_2(sm, key, ver, key_info))
+		goto failed;
+
+	if (rekey) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Group rekeying "
+			"completed with " MACSTR " [GTK=%s]",
+			MAC2STR(sm->bssid), wpa_cipher_txt(sm->group_cipher));
+		wpa_sm_cancel_auth_timeout(sm);
+		wpa_sm_set_state(sm, WPA_COMPLETED);
+
+		wpa_sm_set_rekey_offload(sm);
+	} else {
+		wpa_supplicant_key_neg_complete(sm, sm->bssid,
+						key_info &
+						WPA_KEY_INFO_SECURE);
+	}
+	return;
+
+failed:
+	wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
+}
+
+
+static int wpa_supplicant_verify_eapol_key_mic(struct wpa_sm *sm,
+					       struct wpa_eapol_key *key,
+					       u16 ver,
+					       const u8 *buf, size_t len)
+{
+	u8 mic[16];
+	int ok = 0;
+
+	os_memcpy(mic, key->key_mic, 16);
+	if (sm->tptk_set) {
+		os_memset(key->key_mic, 0, 16);
+		wpa_eapol_key_mic(sm->tptk.kck, ver, buf, len,
+				  key->key_mic);
+		if (os_memcmp(mic, key->key_mic, 16) != 0) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Invalid EAPOL-Key MIC "
+				"when using TPTK - ignoring TPTK");
+		} else {
+			ok = 1;
+			sm->tptk_set = 0;
+			sm->ptk_set = 1;
+			os_memcpy(&sm->ptk, &sm->tptk, sizeof(sm->ptk));
+		}
+	}
+
+	if (!ok && sm->ptk_set) {
+		os_memset(key->key_mic, 0, 16);
+		wpa_eapol_key_mic(sm->ptk.kck, ver, buf, len,
+				  key->key_mic);
+		if (os_memcmp(mic, key->key_mic, 16) != 0) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Invalid EAPOL-Key MIC - "
+				"dropping packet");
+			return -1;
+		}
+		ok = 1;
+	}
+
+	if (!ok) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Could not verify EAPOL-Key MIC - "
+			"dropping packet");
+		return -1;
+	}
+
+	os_memcpy(sm->rx_replay_counter, key->replay_counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	sm->rx_replay_counter_set = 1;
+	return 0;
+}
+
+
+/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */
+static int wpa_supplicant_decrypt_key_data(struct wpa_sm *sm,
+					   struct wpa_eapol_key *key, u16 ver)
+{
+	u16 keydatalen = WPA_GET_BE16(key->key_data_length);
+
+	wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data",
+		    (u8 *) (key + 1), keydatalen);
+	if (!sm->ptk_set) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: PTK not available, cannot decrypt EAPOL-Key Key "
+			"Data");
+		return -1;
+	}
+
+	/* Decrypt key data here so that this operation does not need
+	 * to be implemented separately for each message type. */
+	if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
+		u8 ek[32];
+		os_memcpy(ek, key->key_iv, 16);
+		os_memcpy(ek + 16, sm->ptk.kek, 16);
+		if (rc4_skip(ek, 32, 256, (u8 *) (key + 1), keydatalen)) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+				"WPA: RC4 failed");
+			return -1;
+		}
+	} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
+		   ver == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+		u8 *buf;
+		if (keydatalen % 8) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Unsupported AES-WRAP len %d",
+				keydatalen);
+			return -1;
+		}
+		keydatalen -= 8; /* AES-WRAP adds 8 bytes */
+		buf = os_malloc(keydatalen);
+		if (buf == NULL) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: No memory for AES-UNWRAP buffer");
+			return -1;
+		}
+		if (aes_unwrap(sm->ptk.kek, keydatalen / 8,
+			       (u8 *) (key + 1), buf)) {
+			os_free(buf);
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: AES unwrap failed - "
+				"could not decrypt EAPOL-Key key data");
+			return -1;
+		}
+		os_memcpy(key + 1, buf, keydatalen);
+		os_free(buf);
+		WPA_PUT_BE16(key->key_data_length, keydatalen);
+	} else {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: Unsupported key_info type %d", ver);
+		return -1;
+	}
+	wpa_hexdump_key(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data",
+			(u8 *) (key + 1), keydatalen);
+	return 0;
+}
+
+
+/**
+ * wpa_sm_aborted_cached - Notify WPA that PMKSA caching was aborted
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+void wpa_sm_aborted_cached(struct wpa_sm *sm)
+{
+	if (sm && sm->cur_pmksa) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"RSN: Cancelling PMKSA caching attempt");
+		sm->cur_pmksa = NULL;
+	}
+}
+
+
+static void wpa_eapol_key_dump(struct wpa_sm *sm,
+			       const struct wpa_eapol_key *key)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	u16 key_info = WPA_GET_BE16(key->key_info);
+
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "  EAPOL-Key type=%d", key->type);
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"  key_info 0x%x (ver=%d keyidx=%d rsvd=%d %s%s%s%s%s%s%s%s)",
+		key_info, key_info & WPA_KEY_INFO_TYPE_MASK,
+		(key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
+		WPA_KEY_INFO_KEY_INDEX_SHIFT,
+		(key_info & (BIT(13) | BIT(14) | BIT(15))) >> 13,
+		key_info & WPA_KEY_INFO_KEY_TYPE ? "Pairwise" : "Group",
+		key_info & WPA_KEY_INFO_INSTALL ? " Install" : "",
+		key_info & WPA_KEY_INFO_ACK ? " Ack" : "",
+		key_info & WPA_KEY_INFO_MIC ? " MIC" : "",
+		key_info & WPA_KEY_INFO_SECURE ? " Secure" : "",
+		key_info & WPA_KEY_INFO_ERROR ? " Error" : "",
+		key_info & WPA_KEY_INFO_REQUEST ? " Request" : "",
+		key_info & WPA_KEY_INFO_ENCR_KEY_DATA ? " Encr" : "");
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"  key_length=%u key_data_length=%u",
+		WPA_GET_BE16(key->key_length),
+		WPA_GET_BE16(key->key_data_length));
+	wpa_hexdump(MSG_DEBUG, "  replay_counter",
+		    key->replay_counter, WPA_REPLAY_COUNTER_LEN);
+	wpa_hexdump(MSG_DEBUG, "  key_nonce", key->key_nonce, WPA_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "  key_iv", key->key_iv, 16);
+	wpa_hexdump(MSG_DEBUG, "  key_rsc", key->key_rsc, 8);
+	wpa_hexdump(MSG_DEBUG, "  key_id (reserved)", key->key_id, 8);
+	wpa_hexdump(MSG_DEBUG, "  key_mic", key->key_mic, 16);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+/**
+ * wpa_sm_rx_eapol - Process received WPA EAPOL frames
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @src_addr: Source MAC address of the EAPOL packet
+ * @buf: Pointer to the beginning of the EAPOL data (EAPOL header)
+ * @len: Length of the EAPOL frame
+ * Returns: 1 = WPA EAPOL-Key processed, 0 = not a WPA EAPOL-Key, -1 failure
+ *
+ * This function is called for each received EAPOL frame. Other than EAPOL-Key
+ * frames can be skipped if filtering is done elsewhere. wpa_sm_rx_eapol() is
+ * only processing WPA and WPA2 EAPOL-Key frames.
+ *
+ * The received EAPOL-Key packets are validated and valid packets are replied
+ * to. In addition, key material (PTK, GTK) is configured at the end of a
+ * successful key handshake.
+ */
+int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
+		    const u8 *buf, size_t len)
+{
+	size_t plen, data_len, extra_len;
+	struct ieee802_1x_hdr *hdr;
+	struct wpa_eapol_key *key;
+	u16 key_info, ver;
+	u8 *tmp;
+	int ret = -1;
+	struct wpa_peerkey *peerkey = NULL;
+
+#ifdef CONFIG_IEEE80211R
+	sm->ft_completed = 0;
+#endif /* CONFIG_IEEE80211R */
+
+	if (len < sizeof(*hdr) + sizeof(*key)) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: EAPOL frame too short to be a WPA "
+			"EAPOL-Key (len %lu, expecting at least %lu)",
+			(unsigned long) len,
+			(unsigned long) sizeof(*hdr) + sizeof(*key));
+		return 0;
+	}
+
+	tmp = os_malloc(len);
+	if (tmp == NULL)
+		return -1;
+	os_memcpy(tmp, buf, len);
+
+	hdr = (struct ieee802_1x_hdr *) tmp;
+	key = (struct wpa_eapol_key *) (hdr + 1);
+	plen = be_to_host16(hdr->length);
+	data_len = plen + sizeof(*hdr);
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"IEEE 802.1X RX: version=%d type=%d length=%lu",
+		hdr->version, hdr->type, (unsigned long) plen);
+
+	if (hdr->version < EAPOL_VERSION) {
+		/* TODO: backwards compatibility */
+	}
+	if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: EAPOL frame (type %u) discarded, "
+			"not a Key frame", hdr->type);
+		ret = 0;
+		goto out;
+	}
+	if (plen > len - sizeof(*hdr) || plen < sizeof(*key)) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: EAPOL frame payload size %lu "
+			"invalid (frame size %lu)",
+			(unsigned long) plen, (unsigned long) len);
+		ret = 0;
+		goto out;
+	}
+
+	if (key->type != EAPOL_KEY_TYPE_WPA && key->type != EAPOL_KEY_TYPE_RSN)
+	{
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: EAPOL-Key type (%d) unknown, discarded",
+			key->type);
+		ret = 0;
+		goto out;
+	}
+	wpa_eapol_key_dump(sm, key);
+
+	eapol_sm_notify_lower_layer_success(sm->eapol, 0);
+	wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", tmp, len);
+	if (data_len < len) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: ignoring %lu bytes after the IEEE 802.1X data",
+			(unsigned long) len - data_len);
+	}
+	key_info = WPA_GET_BE16(key->key_info);
+	ver = key_info & WPA_KEY_INFO_TYPE_MASK;
+	if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
+	    ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: Unsupported EAPOL-Key descriptor version %d",
+			ver);
+		goto out;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->key_mgmt)) {
+		/* IEEE 802.11r uses a new key_info type (AES-128-CMAC). */
+		if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"FT: AP did not use AES-128-CMAC");
+			goto out;
+		}
+	} else
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (wpa_key_mgmt_sha256(sm->key_mgmt)) {
+		if (ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"WPA: AP did not use the "
+				"negotiated AES-128-CMAC");
+			goto out;
+		}
+	} else
+#endif /* CONFIG_IEEE80211W */
+	if (sm->pairwise_cipher == WPA_CIPHER_CCMP &&
+	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: CCMP is used, but EAPOL-Key "
+			"descriptor version (%d) is not 2", ver);
+		if (sm->group_cipher != WPA_CIPHER_CCMP &&
+		    !(key_info & WPA_KEY_INFO_KEY_TYPE)) {
+			/* Earlier versions of IEEE 802.11i did not explicitly
+			 * require version 2 descriptor for all EAPOL-Key
+			 * packets, so allow group keys to use version 1 if
+			 * CCMP is not used for them. */
+			wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+				"WPA: Backwards compatibility: allow invalid "
+				"version for non-CCMP group keys");
+		} else
+			goto out;
+	}
+	if (sm->pairwise_cipher == WPA_CIPHER_GCMP &&
+	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: GCMP is used, but EAPOL-Key "
+			"descriptor version (%d) is not 2", ver);
+		goto out;
+	}
+
+#ifdef CONFIG_PEERKEY
+	for (peerkey = sm->peerkey; peerkey; peerkey = peerkey->next) {
+		if (os_memcmp(peerkey->addr, src_addr, ETH_ALEN) == 0)
+			break;
+	}
+
+	if (!(key_info & WPA_KEY_INFO_SMK_MESSAGE) && peerkey) {
+		if (!peerkey->initiator && peerkey->replay_counter_set &&
+		    os_memcmp(key->replay_counter, peerkey->replay_counter,
+			      WPA_REPLAY_COUNTER_LEN) <= 0) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"RSN: EAPOL-Key Replay Counter did not "
+				"increase (STK) - dropping packet");
+			goto out;
+		} else if (peerkey->initiator) {
+			u8 _tmp[WPA_REPLAY_COUNTER_LEN];
+			os_memcpy(_tmp, key->replay_counter,
+				  WPA_REPLAY_COUNTER_LEN);
+			inc_byte_array(_tmp, WPA_REPLAY_COUNTER_LEN);
+			if (os_memcmp(_tmp, peerkey->replay_counter,
+				      WPA_REPLAY_COUNTER_LEN) != 0) {
+				wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+					"RSN: EAPOL-Key Replay "
+					"Counter did not match (STK) - "
+					"dropping packet");
+				goto out;
+			}
+		}
+	}
+
+	if (peerkey && peerkey->initiator && (key_info & WPA_KEY_INFO_ACK)) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"RSN: Ack bit in key_info from STK peer");
+		goto out;
+	}
+#endif /* CONFIG_PEERKEY */
+
+	if (!peerkey && sm->rx_replay_counter_set &&
+	    os_memcmp(key->replay_counter, sm->rx_replay_counter,
+		      WPA_REPLAY_COUNTER_LEN) <= 0) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+			"WPA: EAPOL-Key Replay Counter did not increase - "
+			"dropping packet");
+		goto out;
+	}
+
+	if (!(key_info & (WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE))
+#ifdef CONFIG_PEERKEY
+	    && (peerkey == NULL || !peerkey->initiator)
+#endif /* CONFIG_PEERKEY */
+		) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: No Ack bit in key_info");
+		goto out;
+	}
+
+	if (key_info & WPA_KEY_INFO_REQUEST) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO,
+			"WPA: EAPOL-Key with Request bit - dropped");
+		goto out;
+	}
+
+	if ((key_info & WPA_KEY_INFO_MIC) && !peerkey &&
+	    wpa_supplicant_verify_eapol_key_mic(sm, key, ver, tmp, data_len))
+		goto out;
+
+#ifdef CONFIG_PEERKEY
+	if ((key_info & WPA_KEY_INFO_MIC) && peerkey &&
+	    peerkey_verify_eapol_key_mic(sm, peerkey, key, ver, tmp, data_len))
+		goto out;
+#endif /* CONFIG_PEERKEY */
+
+	extra_len = data_len - sizeof(*hdr) - sizeof(*key);
+
+	if (WPA_GET_BE16(key->key_data_length) > extra_len) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_INFO, "WPA: Invalid EAPOL-Key "
+			"frame - key_data overflow (%d > %lu)",
+			WPA_GET_BE16(key->key_data_length),
+			(unsigned long) extra_len);
+		goto out;
+	}
+	extra_len = WPA_GET_BE16(key->key_data_length);
+
+	if (sm->proto == WPA_PROTO_RSN &&
+	    (key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
+		if (wpa_supplicant_decrypt_key_data(sm, key, ver))
+			goto out;
+		extra_len = WPA_GET_BE16(key->key_data_length);
+	}
+
+	if (key_info & WPA_KEY_INFO_KEY_TYPE) {
+		if (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: Ignored EAPOL-Key (Pairwise) with "
+				"non-zero key index");
+			goto out;
+		}
+		if (peerkey) {
+			/* PeerKey 4-Way Handshake */
+			peerkey_rx_eapol_4way(sm, peerkey, key, key_info, ver);
+		} else if (key_info & WPA_KEY_INFO_MIC) {
+			/* 3/4 4-Way Handshake */
+			wpa_supplicant_process_3_of_4(sm, key, ver);
+		} else {
+			/* 1/4 4-Way Handshake */
+			wpa_supplicant_process_1_of_4(sm, src_addr, key,
+						      ver);
+		}
+	} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
+		/* PeerKey SMK Handshake */
+		peerkey_rx_eapol_smk(sm, src_addr, key, extra_len, key_info,
+				     ver);
+	} else {
+		if (key_info & WPA_KEY_INFO_MIC) {
+			/* 1/2 Group Key Handshake */
+			wpa_supplicant_process_1_of_2(sm, src_addr, key,
+						      extra_len, ver);
+		} else {
+			wpa_msg(sm->ctx->msg_ctx, MSG_WARNING,
+				"WPA: EAPOL-Key (Group) without Mic bit - "
+				"dropped");
+		}
+	}
+
+	ret = 1;
+
+out:
+	os_free(tmp);
+	return ret;
+}
+
+
+#ifdef CONFIG_CTRL_IFACE
+static u32 wpa_key_mgmt_suite(struct wpa_sm *sm)
+{
+	switch (sm->key_mgmt) {
+	case WPA_KEY_MGMT_IEEE8021X:
+		return (sm->proto == WPA_PROTO_RSN ?
+			RSN_AUTH_KEY_MGMT_UNSPEC_802_1X :
+			WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
+	case WPA_KEY_MGMT_PSK:
+		return (sm->proto == WPA_PROTO_RSN ?
+			RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X :
+			WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
+#ifdef CONFIG_IEEE80211R
+	case WPA_KEY_MGMT_FT_IEEE8021X:
+		return RSN_AUTH_KEY_MGMT_FT_802_1X;
+	case WPA_KEY_MGMT_FT_PSK:
+		return RSN_AUTH_KEY_MGMT_FT_PSK;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	case WPA_KEY_MGMT_IEEE8021X_SHA256:
+		return RSN_AUTH_KEY_MGMT_802_1X_SHA256;
+	case WPA_KEY_MGMT_PSK_SHA256:
+		return RSN_AUTH_KEY_MGMT_PSK_SHA256;
+#endif /* CONFIG_IEEE80211W */
+	case WPA_KEY_MGMT_CCKM:
+		return (sm->proto == WPA_PROTO_RSN ?
+			RSN_AUTH_KEY_MGMT_CCKM:
+			WPA_AUTH_KEY_MGMT_CCKM);
+	case WPA_KEY_MGMT_WPA_NONE:
+		return WPA_AUTH_KEY_MGMT_NONE;
+	default:
+		return 0;
+	}
+}
+
+
+#define RSN_SUITE "%02x-%02x-%02x-%d"
+#define RSN_SUITE_ARG(s) \
+((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
+
+/**
+ * wpa_sm_get_mib - Dump text list of MIB entries
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @buf: Buffer for the list
+ * @buflen: Length of the buffer
+ * Returns: Number of bytes written to buffer
+ *
+ * This function is used fetch dot11 MIB variables.
+ */
+int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
+{
+	char pmkid_txt[PMKID_LEN * 2 + 1];
+	int rsna, ret;
+	size_t len;
+
+	if (sm->cur_pmksa) {
+		wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt),
+				 sm->cur_pmksa->pmkid, PMKID_LEN);
+	} else
+		pmkid_txt[0] = '\0';
+
+	if ((wpa_key_mgmt_wpa_psk(sm->key_mgmt) ||
+	     wpa_key_mgmt_wpa_ieee8021x(sm->key_mgmt)) &&
+	    sm->proto == WPA_PROTO_RSN)
+		rsna = 1;
+	else
+		rsna = 0;
+
+	ret = os_snprintf(buf, buflen,
+			  "dot11RSNAOptionImplemented=TRUE\n"
+			  "dot11RSNAPreauthenticationImplemented=TRUE\n"
+			  "dot11RSNAEnabled=%s\n"
+			  "dot11RSNAPreauthenticationEnabled=%s\n"
+			  "dot11RSNAConfigVersion=%d\n"
+			  "dot11RSNAConfigPairwiseKeysSupported=5\n"
+			  "dot11RSNAConfigGroupCipherSize=%d\n"
+			  "dot11RSNAConfigPMKLifetime=%d\n"
+			  "dot11RSNAConfigPMKReauthThreshold=%d\n"
+			  "dot11RSNAConfigNumberOfPTKSAReplayCounters=1\n"
+			  "dot11RSNAConfigSATimeout=%d\n",
+			  rsna ? "TRUE" : "FALSE",
+			  rsna ? "TRUE" : "FALSE",
+			  RSN_VERSION,
+			  wpa_cipher_key_len(sm->group_cipher) * 8,
+			  sm->dot11RSNAConfigPMKLifetime,
+			  sm->dot11RSNAConfigPMKReauthThreshold,
+			  sm->dot11RSNAConfigSATimeout);
+	if (ret < 0 || (size_t) ret >= buflen)
+		return 0;
+	len = ret;
+
+	ret = os_snprintf(
+		buf + len, buflen - len,
+		"dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n"
+		"dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n"
+		"dot11RSNAGroupCipherSelected=" RSN_SUITE "\n"
+		"dot11RSNAPMKIDUsed=%s\n"
+		"dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n"
+		"dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n"
+		"dot11RSNAGroupCipherRequested=" RSN_SUITE "\n"
+		"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n"
+		"dot11RSNA4WayHandshakeFailures=%u\n",
+		RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)),
+		RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
+						  sm->pairwise_cipher)),
+		RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
+						  sm->group_cipher)),
+		pmkid_txt,
+		RSN_SUITE_ARG(wpa_key_mgmt_suite(sm)),
+		RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
+						  sm->pairwise_cipher)),
+		RSN_SUITE_ARG(wpa_cipher_to_suite(sm->proto,
+						  sm->group_cipher)),
+		sm->dot11RSNA4WayHandshakeFailures);
+	if (ret >= 0 && (size_t) ret < buflen)
+		len += ret;
+
+	return (int) len;
+}
+#endif /* CONFIG_CTRL_IFACE */
+
+
+static void wpa_sm_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
+				 void *ctx, enum pmksa_free_reason reason)
+{
+	struct wpa_sm *sm = ctx;
+	int deauth = 0;
+
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "RSN: PMKSA cache entry free_cb: "
+		MACSTR " reason=%d", MAC2STR(entry->aa), reason);
+
+	if (sm->cur_pmksa == entry) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"RSN: %s current PMKSA entry",
+			reason == PMKSA_REPLACE ? "replaced" : "removed");
+		pmksa_cache_clear_current(sm);
+
+		/*
+		 * If an entry is simply being replaced, there's no need to
+		 * deauthenticate because it will be immediately re-added.
+		 * This happens when EAP authentication is completed again
+		 * (reauth or failed PMKSA caching attempt).
+		 */
+		if (reason != PMKSA_REPLACE)
+			deauth = 1;
+	}
+
+	if (reason == PMKSA_EXPIRE &&
+	    (sm->pmk_len == entry->pmk_len &&
+	     os_memcmp(sm->pmk, entry->pmk, sm->pmk_len) == 0)) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"RSN: deauthenticating due to expired PMK");
+		pmksa_cache_clear_current(sm);
+		deauth = 1;
+	}
+
+	if (deauth) {
+		os_memset(sm->pmk, 0, sizeof(sm->pmk));
+		wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
+	}
+}
+
+
+/**
+ * wpa_sm_init - Initialize WPA state machine
+ * @ctx: Context pointer for callbacks; this needs to be an allocated buffer
+ * Returns: Pointer to the allocated WPA state machine data
+ *
+ * This function is used to allocate a new WPA state machine and the returned
+ * value is passed to all WPA state machine calls.
+ */
+struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
+{
+	struct wpa_sm *sm;
+
+	sm = os_zalloc(sizeof(*sm));
+	if (sm == NULL)
+		return NULL;
+	dl_list_init(&sm->pmksa_candidates);
+	sm->renew_snonce = 1;
+	sm->ctx = ctx;
+
+	sm->dot11RSNAConfigPMKLifetime = 43200;
+	sm->dot11RSNAConfigPMKReauthThreshold = 70;
+	sm->dot11RSNAConfigSATimeout = 60;
+
+	sm->pmksa = pmksa_cache_init(wpa_sm_pmksa_free_cb, sm, sm);
+	if (sm->pmksa == NULL) {
+		wpa_msg(sm->ctx->msg_ctx, MSG_ERROR,
+			"RSN: PMKSA cache initialization failed");
+		os_free(sm);
+		return NULL;
+	}
+
+	return sm;
+}
+
+
+/**
+ * wpa_sm_deinit - Deinitialize WPA state machine
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ */
+void wpa_sm_deinit(struct wpa_sm *sm)
+{
+	if (sm == NULL)
+		return;
+	pmksa_cache_deinit(sm->pmksa);
+	eloop_cancel_timeout(wpa_sm_start_preauth, sm, NULL);
+	eloop_cancel_timeout(wpa_sm_rekey_ptk, sm, NULL);
+	os_free(sm->assoc_wpa_ie);
+	os_free(sm->ap_wpa_ie);
+	os_free(sm->ap_rsn_ie);
+	os_free(sm->ctx);
+	peerkey_deinit(sm);
+#ifdef CONFIG_IEEE80211R
+	os_free(sm->assoc_resp_ies);
+#endif /* CONFIG_IEEE80211R */
+	os_free(sm);
+}
+
+
+/**
+ * wpa_sm_notify_assoc - Notify WPA state machine about association
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @bssid: The BSSID of the new association
+ *
+ * This function is called to let WPA state machine know that the connection
+ * was established.
+ */
+void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
+{
+	int clear_ptk = 1;
+
+	if (sm == NULL)
+		return;
+
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+		"WPA: Association event - clear replay counter");
+	os_memcpy(sm->bssid, bssid, ETH_ALEN);
+	os_memset(sm->rx_replay_counter, 0, WPA_REPLAY_COUNTER_LEN);
+	sm->rx_replay_counter_set = 0;
+	sm->renew_snonce = 1;
+	if (os_memcmp(sm->preauth_bssid, bssid, ETH_ALEN) == 0)
+		rsn_preauth_deinit(sm);
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_ft_is_completed(sm)) {
+		/*
+		 * Clear portValid to kick EAPOL state machine to re-enter
+		 * AUTHENTICATED state to get the EAPOL port Authorized.
+		 */
+		eapol_sm_notify_portValid(sm->eapol, FALSE);
+		wpa_supplicant_key_neg_complete(sm, sm->bssid, 1);
+
+		/* Prepare for the next transition */
+		wpa_ft_prepare_auth_request(sm, NULL);
+
+		clear_ptk = 0;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	if (clear_ptk) {
+		/*
+		 * IEEE 802.11, 8.4.10: Delete PTK SA on (re)association if
+		 * this is not part of a Fast BSS Transition.
+		 */
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PTK");
+		sm->ptk_set = 0;
+		sm->tptk_set = 0;
+	}
+
+#ifdef CONFIG_TDLS
+	wpa_tdls_assoc(sm);
+#endif /* CONFIG_TDLS */
+}
+
+
+/**
+ * wpa_sm_notify_disassoc - Notify WPA state machine about disassociation
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ *
+ * This function is called to let WPA state machine know that the connection
+ * was lost. This will abort any existing pre-authentication session.
+ */
+void wpa_sm_notify_disassoc(struct wpa_sm *sm)
+{
+	rsn_preauth_deinit(sm);
+	pmksa_cache_clear_current(sm);
+	if (wpa_sm_get_state(sm) == WPA_4WAY_HANDSHAKE)
+		sm->dot11RSNA4WayHandshakeFailures++;
+#ifdef CONFIG_TDLS
+	wpa_tdls_disassoc(sm);
+#endif /* CONFIG_TDLS */
+}
+
+
+/**
+ * wpa_sm_set_pmk - Set PMK
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @pmk: The new PMK
+ * @pmk_len: The length of the new PMK in bytes
+ *
+ * Configure the PMK for WPA state machine.
+ */
+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len)
+{
+	if (sm == NULL)
+		return;
+
+	sm->pmk_len = pmk_len;
+	os_memcpy(sm->pmk, pmk, pmk_len);
+
+#ifdef CONFIG_IEEE80211R
+	/* Set XXKey to be PSK for FT key derivation */
+	sm->xxkey_len = pmk_len;
+	os_memcpy(sm->xxkey, pmk, pmk_len);
+#endif /* CONFIG_IEEE80211R */
+}
+
+
+/**
+ * wpa_sm_set_pmk_from_pmksa - Set PMK based on the current PMKSA
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ *
+ * Take the PMK from the current PMKSA into use. If no PMKSA is active, the PMK
+ * will be cleared.
+ */
+void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm)
+{
+	if (sm == NULL)
+		return;
+
+	if (sm->cur_pmksa) {
+		sm->pmk_len = sm->cur_pmksa->pmk_len;
+		os_memcpy(sm->pmk, sm->cur_pmksa->pmk, sm->pmk_len);
+	} else {
+		sm->pmk_len = PMK_LEN;
+		os_memset(sm->pmk, 0, PMK_LEN);
+	}
+}
+
+
+/**
+ * wpa_sm_set_fast_reauth - Set fast reauthentication (EAP) enabled/disabled
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @fast_reauth: Whether fast reauthentication (EAP) is allowed
+ */
+void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth)
+{
+	if (sm)
+		sm->fast_reauth = fast_reauth;
+}
+
+
+/**
+ * wpa_sm_set_scard_ctx - Set context pointer for smartcard callbacks
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @scard_ctx: Context pointer for smartcard related callback functions
+ */
+void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx)
+{
+	if (sm == NULL)
+		return;
+	sm->scard_ctx = scard_ctx;
+	if (sm->preauth_eapol)
+		eapol_sm_register_scard_ctx(sm->preauth_eapol, scard_ctx);
+}
+
+
+/**
+ * wpa_sm_set_config - Notification of current configration change
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @config: Pointer to current network configuration
+ *
+ * Notify WPA state machine that configuration has changed. config will be
+ * stored as a backpointer to network configuration. This can be %NULL to clear
+ * the stored pointed.
+ */
+void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config)
+{
+	if (!sm)
+		return;
+
+	if (config) {
+		sm->network_ctx = config->network_ctx;
+		sm->peerkey_enabled = config->peerkey_enabled;
+		sm->allowed_pairwise_cipher = config->allowed_pairwise_cipher;
+		sm->proactive_key_caching = config->proactive_key_caching;
+		sm->eap_workaround = config->eap_workaround;
+		sm->eap_conf_ctx = config->eap_conf_ctx;
+		if (config->ssid) {
+			os_memcpy(sm->ssid, config->ssid, config->ssid_len);
+			sm->ssid_len = config->ssid_len;
+		} else
+			sm->ssid_len = 0;
+		sm->wpa_ptk_rekey = config->wpa_ptk_rekey;
+	} else {
+		sm->network_ctx = NULL;
+		sm->peerkey_enabled = 0;
+		sm->allowed_pairwise_cipher = 0;
+		sm->proactive_key_caching = 0;
+		sm->eap_workaround = 0;
+		sm->eap_conf_ctx = NULL;
+		sm->ssid_len = 0;
+		sm->wpa_ptk_rekey = 0;
+	}
+}
+
+
+/**
+ * wpa_sm_set_own_addr - Set own MAC address
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @addr: Own MAC address
+ */
+void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr)
+{
+	if (sm)
+		os_memcpy(sm->own_addr, addr, ETH_ALEN);
+}
+
+
+/**
+ * wpa_sm_set_ifname - Set network interface name
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ifname: Interface name
+ * @bridge_ifname: Optional bridge interface name (for pre-auth)
+ */
+void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname,
+		       const char *bridge_ifname)
+{
+	if (sm) {
+		sm->ifname = ifname;
+		sm->bridge_ifname = bridge_ifname;
+	}
+}
+
+
+/**
+ * wpa_sm_set_eapol - Set EAPOL state machine pointer
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @eapol: Pointer to EAPOL state machine allocated with eapol_sm_init()
+ */
+void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol)
+{
+	if (sm)
+		sm->eapol = eapol;
+}
+
+
+/**
+ * wpa_sm_set_param - Set WPA state machine parameters
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @param: Parameter field
+ * @value: Parameter value
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
+		     unsigned int value)
+{
+	int ret = 0;
+
+	if (sm == NULL)
+		return -1;
+
+	switch (param) {
+	case RSNA_PMK_LIFETIME:
+		if (value > 0)
+			sm->dot11RSNAConfigPMKLifetime = value;
+		else
+			ret = -1;
+		break;
+	case RSNA_PMK_REAUTH_THRESHOLD:
+		if (value > 0 && value <= 100)
+			sm->dot11RSNAConfigPMKReauthThreshold = value;
+		else
+			ret = -1;
+		break;
+	case RSNA_SA_TIMEOUT:
+		if (value > 0)
+			sm->dot11RSNAConfigSATimeout = value;
+		else
+			ret = -1;
+		break;
+	case WPA_PARAM_PROTO:
+		sm->proto = value;
+		break;
+	case WPA_PARAM_PAIRWISE:
+		sm->pairwise_cipher = value;
+		break;
+	case WPA_PARAM_GROUP:
+		sm->group_cipher = value;
+		break;
+	case WPA_PARAM_KEY_MGMT:
+		sm->key_mgmt = value;
+		break;
+#ifdef CONFIG_IEEE80211W
+	case WPA_PARAM_MGMT_GROUP:
+		sm->mgmt_group_cipher = value;
+		break;
+#endif /* CONFIG_IEEE80211W */
+	case WPA_PARAM_RSN_ENABLED:
+		sm->rsn_enabled = value;
+		break;
+	case WPA_PARAM_MFP:
+		sm->mfp = value;
+		break;
+	default:
+		break;
+	}
+
+	return ret;
+}
+
+
+/**
+ * wpa_sm_get_param - Get WPA state machine parameters
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @param: Parameter field
+ * Returns: Parameter value
+ */
+unsigned int wpa_sm_get_param(struct wpa_sm *sm, enum wpa_sm_conf_params param)
+{
+	if (sm == NULL)
+		return 0;
+
+	switch (param) {
+	case RSNA_PMK_LIFETIME:
+		return sm->dot11RSNAConfigPMKLifetime;
+	case RSNA_PMK_REAUTH_THRESHOLD:
+		return sm->dot11RSNAConfigPMKReauthThreshold;
+	case RSNA_SA_TIMEOUT:
+		return sm->dot11RSNAConfigSATimeout;
+	case WPA_PARAM_PROTO:
+		return sm->proto;
+	case WPA_PARAM_PAIRWISE:
+		return sm->pairwise_cipher;
+	case WPA_PARAM_GROUP:
+		return sm->group_cipher;
+	case WPA_PARAM_KEY_MGMT:
+		return sm->key_mgmt;
+#ifdef CONFIG_IEEE80211W
+	case WPA_PARAM_MGMT_GROUP:
+		return sm->mgmt_group_cipher;
+#endif /* CONFIG_IEEE80211W */
+	case WPA_PARAM_RSN_ENABLED:
+		return sm->rsn_enabled;
+	default:
+		return 0;
+	}
+}
+
+
+/**
+ * wpa_sm_get_status - Get WPA state machine
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @buf: Buffer for status information
+ * @buflen: Maximum buffer length
+ * @verbose: Whether to include verbose status information
+ * Returns: Number of bytes written to buf.
+ *
+ * Query WPA state machine for status information. This function fills in
+ * a text area with current status information. If the buffer (buf) is not
+ * large enough, status information will be truncated to fit the buffer.
+ */
+int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
+		      int verbose)
+{
+	char *pos = buf, *end = buf + buflen;
+	int ret;
+
+	ret = os_snprintf(pos, end - pos,
+			  "pairwise_cipher=%s\n"
+			  "group_cipher=%s\n"
+			  "key_mgmt=%s\n",
+			  wpa_cipher_txt(sm->pairwise_cipher),
+			  wpa_cipher_txt(sm->group_cipher),
+			  wpa_key_mgmt_txt(sm->key_mgmt, sm->proto));
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+	if (sm->mfp != NO_MGMT_FRAME_PROTECTION && sm->ap_rsn_ie) {
+		struct wpa_ie_data rsn;
+		if (wpa_parse_wpa_ie_rsn(sm->ap_rsn_ie, sm->ap_rsn_ie_len, &rsn)
+		    >= 0 &&
+		    rsn.capabilities & (WPA_CAPABILITY_MFPR |
+					WPA_CAPABILITY_MFPC)) {
+			ret = os_snprintf(pos, end - pos, "pmf=%d\n",
+					  (rsn.capabilities &
+					   WPA_CAPABILITY_MFPR) ? 2 : 1);
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+	}
+
+	return pos - buf;
+}
+
+
+/**
+ * wpa_sm_set_assoc_wpa_ie_default - Generate own WPA/RSN IE from configuration
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @wpa_ie: Pointer to buffer for WPA/RSN IE
+ * @wpa_ie_len: Pointer to the length of the wpa_ie buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
+				    size_t *wpa_ie_len)
+{
+	int res;
+
+	if (sm == NULL)
+		return -1;
+
+	res = wpa_gen_wpa_ie(sm, wpa_ie, *wpa_ie_len);
+	if (res < 0)
+		return -1;
+	*wpa_ie_len = res;
+
+	wpa_hexdump(MSG_DEBUG, "WPA: Set own WPA IE default",
+		    wpa_ie, *wpa_ie_len);
+
+	if (sm->assoc_wpa_ie == NULL) {
+		/*
+		 * Make a copy of the WPA/RSN IE so that 4-Way Handshake gets
+		 * the correct version of the IE even if PMKSA caching is
+		 * aborted (which would remove PMKID from IE generation).
+		 */
+		sm->assoc_wpa_ie = os_malloc(*wpa_ie_len);
+		if (sm->assoc_wpa_ie == NULL)
+			return -1;
+
+		os_memcpy(sm->assoc_wpa_ie, wpa_ie, *wpa_ie_len);
+		sm->assoc_wpa_ie_len = *wpa_ie_len;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_sm_set_assoc_wpa_ie - Set own WPA/RSN IE from (Re)AssocReq
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the WPA/RSN IE used in (Re)Association
+ * Request frame. The IE will be used to override the default value generated
+ * with wpa_sm_set_assoc_wpa_ie_default().
+ */
+int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+	if (sm == NULL)
+		return -1;
+
+	os_free(sm->assoc_wpa_ie);
+	if (ie == NULL || len == 0) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: clearing own WPA/RSN IE");
+		sm->assoc_wpa_ie = NULL;
+		sm->assoc_wpa_ie_len = 0;
+	} else {
+		wpa_hexdump(MSG_DEBUG, "WPA: set own WPA/RSN IE", ie, len);
+		sm->assoc_wpa_ie = os_malloc(len);
+		if (sm->assoc_wpa_ie == NULL)
+			return -1;
+
+		os_memcpy(sm->assoc_wpa_ie, ie, len);
+		sm->assoc_wpa_ie_len = len;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_sm_set_ap_wpa_ie - Set AP WPA IE from Beacon/ProbeResp
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the WPA IE used in Beacon / Probe Response
+ * frame.
+ */
+int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+	if (sm == NULL)
+		return -1;
+
+	os_free(sm->ap_wpa_ie);
+	if (ie == NULL || len == 0) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: clearing AP WPA IE");
+		sm->ap_wpa_ie = NULL;
+		sm->ap_wpa_ie_len = 0;
+	} else {
+		wpa_hexdump(MSG_DEBUG, "WPA: set AP WPA IE", ie, len);
+		sm->ap_wpa_ie = os_malloc(len);
+		if (sm->ap_wpa_ie == NULL)
+			return -1;
+
+		os_memcpy(sm->ap_wpa_ie, ie, len);
+		sm->ap_wpa_ie_len = len;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_sm_set_ap_rsn_ie - Set AP RSN IE from Beacon/ProbeResp
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @ie: Pointer to IE data (starting from id)
+ * @len: IE length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Inform WPA state machine about the RSN IE used in Beacon / Probe Response
+ * frame.
+ */
+int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len)
+{
+	if (sm == NULL)
+		return -1;
+
+	os_free(sm->ap_rsn_ie);
+	if (ie == NULL || len == 0) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: clearing AP RSN IE");
+		sm->ap_rsn_ie = NULL;
+		sm->ap_rsn_ie_len = 0;
+	} else {
+		wpa_hexdump(MSG_DEBUG, "WPA: set AP RSN IE", ie, len);
+		sm->ap_rsn_ie = os_malloc(len);
+		if (sm->ap_rsn_ie == NULL)
+			return -1;
+
+		os_memcpy(sm->ap_rsn_ie, ie, len);
+		sm->ap_rsn_ie_len = len;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_sm_parse_own_wpa_ie - Parse own WPA/RSN IE
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @data: Pointer to data area for parsing results
+ * Returns: 0 on success, -1 if IE is not known, or -2 on parsing failure
+ *
+ * Parse the contents of the own WPA or RSN IE from (Re)AssocReq and write the
+ * parsed data into data.
+ */
+int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data)
+{
+	if (sm == NULL)
+		return -1;
+
+	if (sm->assoc_wpa_ie == NULL) {
+		wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG,
+			"WPA: No WPA/RSN IE available from association info");
+		return -1;
+	}
+	if (wpa_parse_wpa_ie(sm->assoc_wpa_ie, sm->assoc_wpa_ie_len, data))
+		return -2;
+	return 0;
+}
+
+
+int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len)
+{
+#ifndef CONFIG_NO_WPA2
+	return pmksa_cache_list(sm->pmksa, buf, len);
+#else /* CONFIG_NO_WPA2 */
+	return -1;
+#endif /* CONFIG_NO_WPA2 */
+}
+
+
+void wpa_sm_drop_sa(struct wpa_sm *sm)
+{
+	wpa_dbg(sm->ctx->msg_ctx, MSG_DEBUG, "WPA: Clear old PMK and PTK");
+	sm->ptk_set = 0;
+	sm->tptk_set = 0;
+	os_memset(sm->pmk, 0, sizeof(sm->pmk));
+	os_memset(&sm->ptk, 0, sizeof(sm->ptk));
+	os_memset(&sm->tptk, 0, sizeof(sm->tptk));
+}
+
+
+int wpa_sm_has_ptk(struct wpa_sm *sm)
+{
+	if (sm == NULL)
+		return 0;
+	return sm->ptk_set;
+}
+
+
+void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr)
+{
+	os_memcpy(sm->rx_replay_counter, replay_ctr, WPA_REPLAY_COUNTER_LEN);
+}
+
+
+void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx)
+{
+#ifndef CONFIG_NO_WPA2
+	pmksa_cache_flush(sm->pmksa, network_ctx);
+#endif /* CONFIG_NO_WPA2 */
+}
+
+
+#ifdef CONFIG_WNM
+int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf)
+{
+	struct wpa_gtk_data gd;
+#ifdef CONFIG_IEEE80211W
+	struct wpa_igtk_kde igd;
+	u16 keyidx;
+#endif /* CONFIG_IEEE80211W */
+	u16 keyinfo;
+	u8 keylen;  /* plaintext key len */
+	u8 *key_rsc;
+
+	os_memset(&gd, 0, sizeof(gd));
+#ifdef CONFIG_IEEE80211W
+	os_memset(&igd, 0, sizeof(igd));
+#endif /* CONFIG_IEEE80211W */
+
+	keylen = wpa_cipher_key_len(sm->group_cipher);
+	gd.key_rsc_len = wpa_cipher_rsc_len(sm->group_cipher);
+	gd.alg = wpa_cipher_to_alg(sm->group_cipher);
+	if (gd.alg == WPA_ALG_NONE) {
+		wpa_printf(MSG_DEBUG, "Unsupported group cipher suite");
+		return -1;
+	}
+
+	if (subelem_id == WNM_SLEEP_SUBELEM_GTK) {
+		key_rsc = buf + 5;
+		keyinfo = WPA_GET_LE16(buf + 2);
+		gd.gtk_len = keylen;
+		if (gd.gtk_len != buf[4]) {
+			wpa_printf(MSG_DEBUG, "GTK len mismatch len %d vs %d",
+				   gd.gtk_len, buf[4]);
+			return -1;
+		}
+		gd.keyidx = keyinfo & 0x03; /* B0 - B1 */
+		gd.tx = wpa_supplicant_gtk_tx_bit_workaround(
+		         sm, !!(keyinfo & WPA_KEY_INFO_TXRX));
+
+		os_memcpy(gd.gtk, buf + 13, gd.gtk_len);
+
+		wpa_hexdump_key(MSG_DEBUG, "Install GTK (WNM SLEEP)",
+				gd.gtk, gd.gtk_len);
+		if (wpa_supplicant_install_gtk(sm, &gd, key_rsc)) {
+			wpa_printf(MSG_DEBUG, "Failed to install the GTK in "
+				   "WNM mode");
+			return -1;
+		}
+#ifdef CONFIG_IEEE80211W
+	} else if (subelem_id == WNM_SLEEP_SUBELEM_IGTK) {
+		os_memcpy(igd.keyid, buf + 2, 2);
+		os_memcpy(igd.pn, buf + 4, 6);
+
+		keyidx = WPA_GET_LE16(igd.keyid);
+		os_memcpy(igd.igtk, buf + 10, WPA_IGTK_LEN);
+
+		wpa_hexdump_key(MSG_DEBUG, "Install IGTK (WNM SLEEP)",
+				igd.igtk, WPA_IGTK_LEN);
+		if (wpa_sm_set_key(sm, WPA_ALG_IGTK, broadcast_ether_addr,
+				   keyidx, 0, igd.pn, sizeof(igd.pn),
+				   igd.igtk, WPA_IGTK_LEN) < 0) {
+			wpa_printf(MSG_DEBUG, "Failed to install the IGTK in "
+				   "WNM mode");
+			return -1;
+		}
+#endif /* CONFIG_IEEE80211W */
+	} else {
+		wpa_printf(MSG_DEBUG, "Unknown element id");
+		return -1;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_WNM */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/wpa.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,370 @@
+/*
+ * wpa_supplicant - WPA definitions
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_H
+#define WPA_H
+
+#include "common/defs.h"
+#include "common/eapol_common.h"
+#include "common/wpa_common.h"
+
+struct wpa_sm;
+struct eapol_sm;
+struct wpa_config_blob;
+
+struct wpa_sm_ctx {
+	void *ctx; /* pointer to arbitrary upper level context */
+	void *msg_ctx; /* upper level context for wpa_msg() calls */
+
+	void (*set_state)(void *ctx, enum wpa_states state);
+	enum wpa_states (*get_state)(void *ctx);
+	void (*deauthenticate)(void * ctx, int reason_code); 
+	int (*set_key)(void *ctx, enum wpa_alg alg,
+		       const u8 *addr, int key_idx, int set_tx,
+		       const u8 *seq, size_t seq_len,
+		       const u8 *key, size_t key_len);
+	void * (*get_network_ctx)(void *ctx);
+	int (*get_bssid)(void *ctx, u8 *bssid);
+	int (*ether_send)(void *ctx, const u8 *dest, u16 proto, const u8 *buf,
+			  size_t len);
+	int (*get_beacon_ie)(void *ctx);
+	void (*cancel_auth_timeout)(void *ctx);
+	u8 * (*alloc_eapol)(void *ctx, u8 type, const void *data, u16 data_len,
+			    size_t *msg_len, void **data_pos);
+	int (*add_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid);
+	int (*remove_pmkid)(void *ctx, const u8 *bssid, const u8 *pmkid);
+	void (*set_config_blob)(void *ctx, struct wpa_config_blob *blob);
+	const struct wpa_config_blob * (*get_config_blob)(void *ctx,
+							  const char *name);
+	int (*mlme_setprotection)(void *ctx, const u8 *addr,
+				  int protection_type, int key_type);
+	int (*update_ft_ies)(void *ctx, const u8 *md, const u8 *ies,
+			     size_t ies_len);
+	int (*send_ft_action)(void *ctx, u8 action, const u8 *target_ap,
+			      const u8 *ies, size_t ies_len);
+	int (*mark_authenticated)(void *ctx, const u8 *target_ap);
+#ifdef CONFIG_TDLS
+	int (*tdls_get_capa)(void *ctx, int *tdls_supported,
+			     int *tdls_ext_setup);
+	int (*send_tdls_mgmt)(void *ctx, const u8 *dst,
+			      u8 action_code, u8 dialog_token,
+			      u16 status_code, const u8 *buf, size_t len);
+	int (*tdls_oper)(void *ctx, int oper, const u8 *peer);
+	int (*tdls_peer_addset)(void *ctx, const u8 *addr, int add,
+				u16 capability, const u8 *supp_rates,
+				size_t supp_rates_len);
+#endif /* CONFIG_TDLS */
+	void (*set_rekey_offload)(void *ctx, const u8 *kek, const u8 *kck,
+				  const u8 *replay_ctr);
+};
+
+
+enum wpa_sm_conf_params {
+	RSNA_PMK_LIFETIME /* dot11RSNAConfigPMKLifetime */,
+	RSNA_PMK_REAUTH_THRESHOLD /* dot11RSNAConfigPMKReauthThreshold */,
+	RSNA_SA_TIMEOUT /* dot11RSNAConfigSATimeout */,
+	WPA_PARAM_PROTO,
+	WPA_PARAM_PAIRWISE,
+	WPA_PARAM_GROUP,
+	WPA_PARAM_KEY_MGMT,
+	WPA_PARAM_MGMT_GROUP,
+	WPA_PARAM_RSN_ENABLED,
+	WPA_PARAM_MFP
+};
+
+struct rsn_supp_config {
+	void *network_ctx;
+	int peerkey_enabled;
+	int allowed_pairwise_cipher; /* bitfield of WPA_CIPHER_* */
+	int proactive_key_caching;
+	int eap_workaround;
+	void *eap_conf_ctx;
+	const u8 *ssid;
+	size_t ssid_len;
+	int wpa_ptk_rekey;
+};
+
+#ifndef CONFIG_NO_WPA
+
+struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx);
+void wpa_sm_deinit(struct wpa_sm *sm);
+void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid);
+void wpa_sm_notify_disassoc(struct wpa_sm *sm);
+void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk, size_t pmk_len);
+void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm);
+void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth);
+void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx);
+void wpa_sm_set_config(struct wpa_sm *sm, struct rsn_supp_config *config);
+void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr);
+void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname,
+		       const char *bridge_ifname);
+void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol);
+int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm, u8 *wpa_ie,
+				    size_t *wpa_ie_len);
+int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie, size_t len);
+int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen);
+
+int wpa_sm_set_param(struct wpa_sm *sm, enum wpa_sm_conf_params param,
+		     unsigned int value);
+unsigned int wpa_sm_get_param(struct wpa_sm *sm,
+			      enum wpa_sm_conf_params param);
+
+int wpa_sm_get_status(struct wpa_sm *sm, char *buf, size_t buflen,
+		      int verbose);
+
+void wpa_sm_key_request(struct wpa_sm *sm, int error, int pairwise);
+
+int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
+		     struct wpa_ie_data *data);
+
+void wpa_sm_aborted_cached(struct wpa_sm *sm);
+int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
+		    const u8 *buf, size_t len);
+int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm, struct wpa_ie_data *data);
+int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf, size_t len);
+void wpa_sm_drop_sa(struct wpa_sm *sm);
+int wpa_sm_has_ptk(struct wpa_sm *sm);
+
+void wpa_sm_update_replay_ctr(struct wpa_sm *sm, const u8 *replay_ctr);
+
+void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm, void *network_ctx);
+
+#else /* CONFIG_NO_WPA */
+
+static inline struct wpa_sm * wpa_sm_init(struct wpa_sm_ctx *ctx)
+{
+	return (struct wpa_sm *) 1;
+}
+
+static inline void wpa_sm_deinit(struct wpa_sm *sm)
+{
+}
+
+static inline void wpa_sm_notify_assoc(struct wpa_sm *sm, const u8 *bssid)
+{
+}
+
+static inline void wpa_sm_notify_disassoc(struct wpa_sm *sm)
+{
+}
+
+static inline void wpa_sm_set_pmk(struct wpa_sm *sm, const u8 *pmk,
+				  size_t pmk_len)
+{
+}
+
+static inline void wpa_sm_set_pmk_from_pmksa(struct wpa_sm *sm)
+{
+}
+
+static inline void wpa_sm_set_fast_reauth(struct wpa_sm *sm, int fast_reauth)
+{
+}
+
+static inline void wpa_sm_set_scard_ctx(struct wpa_sm *sm, void *scard_ctx)
+{
+}
+
+static inline void wpa_sm_set_config(struct wpa_sm *sm,
+				     struct rsn_supp_config *config)
+{
+}
+
+static inline void wpa_sm_set_own_addr(struct wpa_sm *sm, const u8 *addr)
+{
+}
+
+static inline void wpa_sm_set_ifname(struct wpa_sm *sm, const char *ifname,
+				     const char *bridge_ifname)
+{
+}
+
+static inline void wpa_sm_set_eapol(struct wpa_sm *sm, struct eapol_sm *eapol)
+{
+}
+
+static inline int wpa_sm_set_assoc_wpa_ie(struct wpa_sm *sm, const u8 *ie,
+					  size_t len)
+{
+	return -1;
+}
+
+static inline int wpa_sm_set_assoc_wpa_ie_default(struct wpa_sm *sm,
+						  u8 *wpa_ie,
+						  size_t *wpa_ie_len)
+{
+	return -1;
+}
+
+static inline int wpa_sm_set_ap_wpa_ie(struct wpa_sm *sm, const u8 *ie,
+				       size_t len)
+{
+	return -1;
+}
+
+static inline int wpa_sm_set_ap_rsn_ie(struct wpa_sm *sm, const u8 *ie,
+				       size_t len)
+{
+	return -1;
+}
+
+static inline int wpa_sm_get_mib(struct wpa_sm *sm, char *buf, size_t buflen)
+{
+	return 0;
+}
+
+static inline int wpa_sm_set_param(struct wpa_sm *sm,
+				   enum wpa_sm_conf_params param,
+				   unsigned int value)
+{
+	return -1;
+}
+
+static inline unsigned int wpa_sm_get_param(struct wpa_sm *sm,
+					    enum wpa_sm_conf_params param)
+{
+	return 0;
+}
+
+static inline int wpa_sm_get_status(struct wpa_sm *sm, char *buf,
+				    size_t buflen, int verbose)
+{
+	return 0;
+}
+
+static inline void wpa_sm_key_request(struct wpa_sm *sm, int error,
+				      int pairwise)
+{
+}
+
+static inline int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
+				   struct wpa_ie_data *data)
+{
+	return -1;
+}
+
+static inline void wpa_sm_aborted_cached(struct wpa_sm *sm)
+{
+}
+
+static inline int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
+				  const u8 *buf, size_t len)
+{
+	return -1;
+}
+
+static inline int wpa_sm_parse_own_wpa_ie(struct wpa_sm *sm,
+					  struct wpa_ie_data *data)
+{
+	return -1;
+}
+
+static inline int wpa_sm_pmksa_cache_list(struct wpa_sm *sm, char *buf,
+					  size_t len)
+{
+	return -1;
+}
+
+static inline void wpa_sm_drop_sa(struct wpa_sm *sm)
+{
+}
+
+static inline int wpa_sm_has_ptk(struct wpa_sm *sm)
+{
+	return 0;
+}
+
+static inline void wpa_sm_update_replay_ctr(struct wpa_sm *sm,
+					    const u8 *replay_ctr)
+{
+}
+
+static inline void wpa_sm_pmksa_cache_flush(struct wpa_sm *sm,
+					    void *network_ctx)
+{
+}
+
+#endif /* CONFIG_NO_WPA */
+
+#ifdef CONFIG_PEERKEY
+int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer);
+#else /* CONFIG_PEERKEY */
+static inline int wpa_sm_stkstart(struct wpa_sm *sm, const u8 *peer)
+{
+	return -1;
+}
+#endif /* CONFIG_PEERKEY */
+
+#ifdef CONFIG_IEEE80211R
+
+int wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len);
+int wpa_ft_prepare_auth_request(struct wpa_sm *sm, const u8 *mdie);
+int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
+			    int ft_action, const u8 *target_ap,
+			    const u8 *ric_ies, size_t ric_ies_len);
+int wpa_ft_is_completed(struct wpa_sm *sm);
+int wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies,
+				 size_t ies_len, const u8 *src_addr);
+int wpa_ft_start_over_ds(struct wpa_sm *sm, const u8 *target_ap,
+			 const u8 *mdie);
+
+#else /* CONFIG_IEEE80211R */
+
+static inline int
+wpa_sm_set_ft_params(struct wpa_sm *sm, const u8 *ies, size_t ies_len)
+{
+	return 0;
+}
+
+static inline int wpa_ft_prepare_auth_request(struct wpa_sm *sm,
+					      const u8 *mdie)
+{
+	return 0;
+}
+
+static inline int
+wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
+			int ft_action, const u8 *target_ap)
+{
+	return 0;
+}
+
+static inline int wpa_ft_is_completed(struct wpa_sm *sm)
+{
+	return 0;
+}
+
+static inline int
+wpa_ft_validate_reassoc_resp(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
+			     const u8 *src_addr)
+{
+	return -1;
+}
+
+#endif /* CONFIG_IEEE80211R */
+
+
+/* tdls.c */
+void wpa_tdls_ap_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
+void wpa_tdls_assoc_resp_ies(struct wpa_sm *sm, const u8 *ies, size_t len);
+int wpa_tdls_start(struct wpa_sm *sm, const u8 *addr);
+int wpa_tdls_reneg(struct wpa_sm *sm, const u8 *addr);
+int wpa_tdls_send_teardown(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
+int wpa_tdls_teardown_link(struct wpa_sm *sm, const u8 *addr, u16 reason_code);
+int wpa_tdls_send_discovery_request(struct wpa_sm *sm, const u8 *addr);
+int wpa_tdls_init(struct wpa_sm *sm);
+void wpa_tdls_deinit(struct wpa_sm *sm);
+void wpa_tdls_enable(struct wpa_sm *sm, int enabled);
+void wpa_tdls_disable_link(struct wpa_sm *sm, const u8 *addr);
+int wpa_tdls_is_external_setup(struct wpa_sm *sm);
+
+int wpa_wnmsleep_install_key(struct wpa_sm *sm, u8 subelem_id, u8 *buf);
+
+#endif /* WPA_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/wpa_i.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,317 @@
+/*
+ * Internal WPA/RSN supplicant state machine definitions
+ * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_I_H
+#define WPA_I_H
+
+#include "utils/list.h"
+
+struct wpa_peerkey;
+struct wpa_tdls_peer;
+struct wpa_eapol_key;
+
+/**
+ * struct wpa_sm - Internal WPA state machine data
+ */
+struct wpa_sm {
+	u8 pmk[PMK_LEN];
+	size_t pmk_len;
+	struct wpa_ptk ptk, tptk;
+	int ptk_set, tptk_set;
+	u8 snonce[WPA_NONCE_LEN];
+	u8 anonce[WPA_NONCE_LEN]; /* ANonce from the last 1/4 msg */
+	int renew_snonce;
+	u8 rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
+	int rx_replay_counter_set;
+	u8 request_counter[WPA_REPLAY_COUNTER_LEN];
+
+	struct eapol_sm *eapol; /* EAPOL state machine from upper level code */
+
+	struct rsn_pmksa_cache *pmksa; /* PMKSA cache */
+	struct rsn_pmksa_cache_entry *cur_pmksa; /* current PMKSA entry */
+	struct dl_list pmksa_candidates;
+
+	struct l2_packet_data *l2_preauth;
+	struct l2_packet_data *l2_preauth_br;
+	struct l2_packet_data *l2_tdls;
+	u8 preauth_bssid[ETH_ALEN]; /* current RSN pre-auth peer or
+				     * 00:00:00:00:00:00 if no pre-auth is
+				     * in progress */
+	struct eapol_sm *preauth_eapol;
+
+	struct wpa_sm_ctx *ctx;
+
+	void *scard_ctx; /* context for smartcard callbacks */
+	int fast_reauth; /* whether EAP fast re-authentication is enabled */
+
+	void *network_ctx;
+	int peerkey_enabled;
+	int allowed_pairwise_cipher; /* bitfield of WPA_CIPHER_* */
+	int proactive_key_caching;
+	int eap_workaround;
+	void *eap_conf_ctx;
+	u8 ssid[32];
+	size_t ssid_len;
+	int wpa_ptk_rekey;
+
+	u8 own_addr[ETH_ALEN];
+	const char *ifname;
+	const char *bridge_ifname;
+	u8 bssid[ETH_ALEN];
+
+	unsigned int dot11RSNAConfigPMKLifetime;
+	unsigned int dot11RSNAConfigPMKReauthThreshold;
+	unsigned int dot11RSNAConfigSATimeout;
+
+	unsigned int dot11RSNA4WayHandshakeFailures;
+
+	/* Selected configuration (based on Beacon/ProbeResp WPA IE) */
+	unsigned int proto;
+	unsigned int pairwise_cipher;
+	unsigned int group_cipher;
+	unsigned int key_mgmt;
+	unsigned int mgmt_group_cipher;
+
+	int rsn_enabled; /* Whether RSN is enabled in configuration */
+	int mfp; /* 0 = disabled, 1 = optional, 2 = mandatory */
+
+	u8 *assoc_wpa_ie; /* Own WPA/RSN IE from (Re)AssocReq */
+	size_t assoc_wpa_ie_len;
+	u8 *ap_wpa_ie, *ap_rsn_ie;
+	size_t ap_wpa_ie_len, ap_rsn_ie_len;
+
+#ifdef CONFIG_PEERKEY
+	struct wpa_peerkey *peerkey;
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_TDLS
+	struct wpa_tdls_peer *tdls;
+	int tdls_prohibited;
+	int tdls_disabled;
+
+	/* The driver supports TDLS */
+	int tdls_supported;
+
+	/*
+	 * The driver requires explicit discovery/setup/teardown frames sent
+	 * to it via tdls_mgmt.
+	 */
+	int tdls_external_setup;
+#endif /* CONFIG_TDLS */
+
+#ifdef CONFIG_IEEE80211R
+	u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
+	size_t xxkey_len;
+	u8 pmk_r0[PMK_LEN];
+	u8 pmk_r0_name[WPA_PMK_NAME_LEN];
+	u8 pmk_r1[PMK_LEN];
+	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
+	u8 r0kh_id[FT_R0KH_ID_MAX_LEN];
+	size_t r0kh_id_len;
+	u8 r1kh_id[FT_R1KH_ID_LEN];
+	int ft_completed;
+	int over_the_ds_in_progress;
+	u8 target_ap[ETH_ALEN]; /* over-the-DS target AP */
+	int set_ptk_after_assoc;
+	u8 mdie_ft_capab; /* FT Capability and Policy from target AP MDIE */
+	u8 *assoc_resp_ies; /* MDIE and FTIE from (Re)Association Response */
+	size_t assoc_resp_ies_len;
+#endif /* CONFIG_IEEE80211R */
+};
+
+
+static inline void wpa_sm_set_state(struct wpa_sm *sm, enum wpa_states state)
+{
+	WPA_ASSERT(sm->ctx->set_state);
+	sm->ctx->set_state(sm->ctx->ctx, state);
+}
+
+static inline enum wpa_states wpa_sm_get_state(struct wpa_sm *sm)
+{
+	WPA_ASSERT(sm->ctx->get_state);
+	return sm->ctx->get_state(sm->ctx->ctx);
+}
+
+static inline void wpa_sm_deauthenticate(struct wpa_sm *sm, int reason_code)
+{
+	WPA_ASSERT(sm->ctx->deauthenticate);
+	sm->ctx->deauthenticate(sm->ctx->ctx, reason_code);
+}
+
+static inline int wpa_sm_set_key(struct wpa_sm *sm, enum wpa_alg alg,
+				 const u8 *addr, int key_idx, int set_tx,
+				 const u8 *seq, size_t seq_len,
+				 const u8 *key, size_t key_len)
+{
+	WPA_ASSERT(sm->ctx->set_key);
+	return sm->ctx->set_key(sm->ctx->ctx, alg, addr, key_idx, set_tx,
+				seq, seq_len, key, key_len);
+}
+
+static inline void * wpa_sm_get_network_ctx(struct wpa_sm *sm)
+{
+	WPA_ASSERT(sm->ctx->get_network_ctx);
+	return sm->ctx->get_network_ctx(sm->ctx->ctx);
+}
+
+static inline int wpa_sm_get_bssid(struct wpa_sm *sm, u8 *bssid)
+{
+	WPA_ASSERT(sm->ctx->get_bssid);
+	return sm->ctx->get_bssid(sm->ctx->ctx, bssid);
+}
+
+static inline int wpa_sm_ether_send(struct wpa_sm *sm, const u8 *dest,
+				    u16 proto, const u8 *buf, size_t len)
+{
+	WPA_ASSERT(sm->ctx->ether_send);
+	return sm->ctx->ether_send(sm->ctx->ctx, dest, proto, buf, len);
+}
+
+static inline int wpa_sm_get_beacon_ie(struct wpa_sm *sm)
+{
+	WPA_ASSERT(sm->ctx->get_beacon_ie);
+	return sm->ctx->get_beacon_ie(sm->ctx->ctx);
+}
+
+static inline void wpa_sm_cancel_auth_timeout(struct wpa_sm *sm)
+{
+	WPA_ASSERT(sm->ctx->cancel_auth_timeout);
+	sm->ctx->cancel_auth_timeout(sm->ctx->ctx);
+}
+
+static inline u8 * wpa_sm_alloc_eapol(struct wpa_sm *sm, u8 type,
+				      const void *data, u16 data_len,
+				      size_t *msg_len, void **data_pos)
+{
+	WPA_ASSERT(sm->ctx->alloc_eapol);
+	return sm->ctx->alloc_eapol(sm->ctx->ctx, type, data, data_len,
+				    msg_len, data_pos);
+}
+
+static inline int wpa_sm_add_pmkid(struct wpa_sm *sm, const u8 *bssid,
+				   const u8 *pmkid)
+{
+	WPA_ASSERT(sm->ctx->add_pmkid);
+	return sm->ctx->add_pmkid(sm->ctx->ctx, bssid, pmkid);
+}
+
+static inline int wpa_sm_remove_pmkid(struct wpa_sm *sm, const u8 *bssid,
+				      const u8 *pmkid)
+{
+	WPA_ASSERT(sm->ctx->remove_pmkid);
+	return sm->ctx->remove_pmkid(sm->ctx->ctx, bssid, pmkid);
+}
+
+static inline int wpa_sm_mlme_setprotection(struct wpa_sm *sm, const u8 *addr,
+					    int protect_type, int key_type)
+{
+	WPA_ASSERT(sm->ctx->mlme_setprotection);
+	return sm->ctx->mlme_setprotection(sm->ctx->ctx, addr, protect_type,
+					   key_type);
+}
+
+static inline int wpa_sm_update_ft_ies(struct wpa_sm *sm, const u8 *md,
+				       const u8 *ies, size_t ies_len)
+{
+	if (sm->ctx->update_ft_ies)
+		return sm->ctx->update_ft_ies(sm->ctx->ctx, md, ies, ies_len);
+	return -1;
+}
+
+static inline int wpa_sm_send_ft_action(struct wpa_sm *sm, u8 action,
+					const u8 *target_ap,
+					const u8 *ies, size_t ies_len)
+{
+	if (sm->ctx->send_ft_action)
+		return sm->ctx->send_ft_action(sm->ctx->ctx, action, target_ap,
+					       ies, ies_len);
+	return -1;
+}
+
+static inline int wpa_sm_mark_authenticated(struct wpa_sm *sm,
+					    const u8 *target_ap)
+{
+	if (sm->ctx->mark_authenticated)
+		return sm->ctx->mark_authenticated(sm->ctx->ctx, target_ap);
+	return -1;
+}
+
+static inline void wpa_sm_set_rekey_offload(struct wpa_sm *sm)
+{
+	if (!sm->ctx->set_rekey_offload)
+		return;
+	sm->ctx->set_rekey_offload(sm->ctx->ctx, sm->ptk.kek,
+				   sm->ptk.kck, sm->rx_replay_counter);
+}
+
+#ifdef CONFIG_TDLS
+static inline int wpa_sm_tdls_get_capa(struct wpa_sm *sm,
+				       int *tdls_supported,
+				       int *tdls_ext_setup)
+{
+	if (sm->ctx->tdls_get_capa)
+		return sm->ctx->tdls_get_capa(sm->ctx->ctx, tdls_supported,
+					      tdls_ext_setup);
+	return -1;
+}
+
+static inline int wpa_sm_send_tdls_mgmt(struct wpa_sm *sm, const u8 *dst,
+					u8 action_code, u8 dialog_token,
+					u16 status_code, const u8 *buf,
+					size_t len)
+{
+	if (sm->ctx->send_tdls_mgmt)
+		return sm->ctx->send_tdls_mgmt(sm->ctx->ctx, dst, action_code,
+					       dialog_token, status_code,
+					       buf, len);
+	return -1;
+}
+
+static inline int wpa_sm_tdls_oper(struct wpa_sm *sm, int oper,
+				   const u8 *peer)
+{
+	if (sm->ctx->tdls_oper)
+		return sm->ctx->tdls_oper(sm->ctx->ctx, oper, peer);
+	return -1;
+}
+
+static inline int
+wpa_sm_tdls_peer_addset(struct wpa_sm *sm, const u8 *addr, int add,
+			u16 capability, const u8 *supp_rates,
+			size_t supp_rates_len)
+{
+	if (sm->ctx->tdls_peer_addset)
+		return sm->ctx->tdls_peer_addset(sm->ctx->ctx, addr, add,
+						 capability, supp_rates,
+						 supp_rates_len);
+	return -1;
+}
+#endif /* CONFIG_TDLS */
+
+void wpa_eapol_key_send(struct wpa_sm *sm, const u8 *kck,
+			int ver, const u8 *dest, u16 proto,
+			u8 *msg, size_t msg_len, u8 *key_mic);
+int wpa_supplicant_send_2_of_4(struct wpa_sm *sm, const unsigned char *dst,
+			       const struct wpa_eapol_key *key,
+			       int ver, const u8 *nonce,
+			       const u8 *wpa_ie, size_t wpa_ie_len,
+			       struct wpa_ptk *ptk);
+int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
+			       const struct wpa_eapol_key *key,
+			       u16 ver, u16 key_info,
+			       const u8 *kde, size_t kde_len,
+			       struct wpa_ptk *ptk);
+
+int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
+		      const struct wpa_eapol_key *key,
+		      struct wpa_ptk *ptk, size_t ptk_len);
+
+void wpa_tdls_assoc(struct wpa_sm *sm);
+void wpa_tdls_disassoc(struct wpa_sm *sm);
+
+#endif /* WPA_I_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/wpa_ie.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,445 @@
+/*
+ * wpa_supplicant - WPA/RSN IE and KDE processing
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa.h"
+#include "pmksa_cache.h"
+#include "common/ieee802_11_defs.h"
+#include "wpa_i.h"
+#include "wpa_ie.h"
+
+
+/**
+ * wpa_parse_wpa_ie - Parse WPA/RSN IE
+ * @wpa_ie: Pointer to WPA or RSN IE
+ * @wpa_ie_len: Length of the WPA/RSN IE
+ * @data: Pointer to data area for parsing results
+ * Returns: 0 on success, -1 on failure
+ *
+ * Parse the contents of WPA or RSN IE and write the parsed data into data.
+ */
+int wpa_parse_wpa_ie(const u8 *wpa_ie, size_t wpa_ie_len,
+		     struct wpa_ie_data *data)
+{
+	if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN)
+		return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
+	else
+		return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
+}
+
+
+static int wpa_gen_wpa_ie_wpa(u8 *wpa_ie, size_t wpa_ie_len,
+			      int pairwise_cipher, int group_cipher,
+			      int key_mgmt)
+{
+	u8 *pos;
+	struct wpa_ie_hdr *hdr;
+	u32 suite;
+
+	if (wpa_ie_len < sizeof(*hdr) + WPA_SELECTOR_LEN +
+	    2 + WPA_SELECTOR_LEN + 2 + WPA_SELECTOR_LEN)
+		return -1;
+
+	hdr = (struct wpa_ie_hdr *) wpa_ie;
+	hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
+	RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
+	WPA_PUT_LE16(hdr->version, WPA_VERSION);
+	pos = (u8 *) (hdr + 1);
+
+	suite = wpa_cipher_to_suite(WPA_PROTO_WPA, group_cipher);
+	if (suite == 0) {
+		wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
+			   group_cipher);
+		return -1;
+	}
+	RSN_SELECTOR_PUT(pos, suite);
+	pos += WPA_SELECTOR_LEN;
+
+	*pos++ = 1;
+	*pos++ = 0;
+	suite = wpa_cipher_to_suite(WPA_PROTO_WPA, pairwise_cipher);
+	if (suite == 0 ||
+	    (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
+	     pairwise_cipher != WPA_CIPHER_NONE)) {
+		wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
+			   pairwise_cipher);
+		return -1;
+	}
+	RSN_SELECTOR_PUT(pos, suite);
+	pos += WPA_SELECTOR_LEN;
+
+	*pos++ = 1;
+	*pos++ = 0;
+	if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
+		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
+	} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
+		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
+	} else if (key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
+		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_NONE);
+	} else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
+		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_CCKM);
+	} else {
+		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
+			   key_mgmt);
+		return -1;
+	}
+	pos += WPA_SELECTOR_LEN;
+
+	/* WPA Capabilities; use defaults, so no need to include it */
+
+	hdr->len = (pos - wpa_ie) - 2;
+
+	WPA_ASSERT((size_t) (pos - wpa_ie) <= wpa_ie_len);
+
+	return pos - wpa_ie;
+}
+
+
+static int wpa_gen_wpa_ie_rsn(u8 *rsn_ie, size_t rsn_ie_len,
+			      int pairwise_cipher, int group_cipher,
+			      int key_mgmt, int mgmt_group_cipher,
+			      struct wpa_sm *sm)
+{
+#ifndef CONFIG_NO_WPA2
+	u8 *pos;
+	struct rsn_ie_hdr *hdr;
+	u16 capab;
+	u32 suite;
+
+	if (rsn_ie_len < sizeof(*hdr) + RSN_SELECTOR_LEN +
+	    2 + RSN_SELECTOR_LEN + 2 + RSN_SELECTOR_LEN + 2 +
+	    (sm->cur_pmksa ? 2 + PMKID_LEN : 0)) {
+		wpa_printf(MSG_DEBUG, "RSN: Too short IE buffer (%lu bytes)",
+			   (unsigned long) rsn_ie_len);
+		return -1;
+	}
+
+	hdr = (struct rsn_ie_hdr *) rsn_ie;
+	hdr->elem_id = WLAN_EID_RSN;
+	WPA_PUT_LE16(hdr->version, RSN_VERSION);
+	pos = (u8 *) (hdr + 1);
+
+	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, group_cipher);
+	if (suite == 0) {
+		wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
+			   group_cipher);
+		return -1;
+	}
+	RSN_SELECTOR_PUT(pos, suite);
+	pos += RSN_SELECTOR_LEN;
+
+	*pos++ = 1;
+	*pos++ = 0;
+	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, pairwise_cipher);
+	if (suite == 0 ||
+	    (!wpa_cipher_valid_pairwise(pairwise_cipher) &&
+	     pairwise_cipher != WPA_CIPHER_NONE)) {
+		wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
+			   pairwise_cipher);
+		return -1;
+	}
+	RSN_SELECTOR_PUT(pos, suite);
+	pos += RSN_SELECTOR_LEN;
+
+	*pos++ = 1;
+	*pos++ = 0;
+	if (key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
+	} else if (key_mgmt == WPA_KEY_MGMT_PSK) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
+	} else if (key_mgmt == WPA_KEY_MGMT_CCKM) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_CCKM);
+#ifdef CONFIG_IEEE80211R
+	} else if (key_mgmt == WPA_KEY_MGMT_FT_IEEE8021X) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
+	} else if (key_mgmt == WPA_KEY_MGMT_FT_PSK) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	} else if (key_mgmt == WPA_KEY_MGMT_IEEE8021X_SHA256) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
+	} else if (key_mgmt == WPA_KEY_MGMT_PSK_SHA256) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+	} else if (key_mgmt == WPA_KEY_MGMT_SAE) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+	} else if (key_mgmt == WPA_KEY_MGMT_FT_SAE) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+#endif /* CONFIG_SAE */
+	} else {
+		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
+			   key_mgmt);
+		return -1;
+	}
+	pos += RSN_SELECTOR_LEN;
+
+	/* RSN Capabilities */
+	capab = 0;
+#ifdef CONFIG_IEEE80211W
+	if (sm->mfp)
+		capab |= WPA_CAPABILITY_MFPC;
+	if (sm->mfp == 2)
+		capab |= WPA_CAPABILITY_MFPR;
+#endif /* CONFIG_IEEE80211W */
+	WPA_PUT_LE16(pos, capab);
+	pos += 2;
+
+	if (sm->cur_pmksa) {
+		/* PMKID Count (2 octets, little endian) */
+		*pos++ = 1;
+		*pos++ = 0;
+		/* PMKID */
+		os_memcpy(pos, sm->cur_pmksa->pmkid, PMKID_LEN);
+		pos += PMKID_LEN;
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (mgmt_group_cipher == WPA_CIPHER_AES_128_CMAC) {
+		if (!sm->cur_pmksa) {
+			/* PMKID Count */
+			WPA_PUT_LE16(pos, 0);
+			pos += 2;
+		}
+
+		/* Management Group Cipher Suite */
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+		pos += RSN_SELECTOR_LEN;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	hdr->len = (pos - rsn_ie) - 2;
+
+	WPA_ASSERT((size_t) (pos - rsn_ie) <= rsn_ie_len);
+
+	return pos - rsn_ie;
+#else /* CONFIG_NO_WPA2 */
+	return -1;
+#endif /* CONFIG_NO_WPA2 */
+}
+
+
+/**
+ * wpa_gen_wpa_ie - Generate WPA/RSN IE based on current security policy
+ * @sm: Pointer to WPA state machine data from wpa_sm_init()
+ * @wpa_ie: Pointer to memory area for the generated WPA/RSN IE
+ * @wpa_ie_len: Maximum length of the generated WPA/RSN IE
+ * Returns: Length of the generated WPA/RSN IE or -1 on failure
+ */
+int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len)
+{
+	if (sm->proto == WPA_PROTO_RSN)
+		return wpa_gen_wpa_ie_rsn(wpa_ie, wpa_ie_len,
+					  sm->pairwise_cipher,
+					  sm->group_cipher,
+					  sm->key_mgmt, sm->mgmt_group_cipher,
+					  sm);
+	else
+		return wpa_gen_wpa_ie_wpa(wpa_ie, wpa_ie_len,
+					  sm->pairwise_cipher,
+					  sm->group_cipher,
+					  sm->key_mgmt);
+}
+
+
+/**
+ * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_parse_generic(const u8 *pos, const u8 *end,
+			     struct wpa_eapol_ie_parse *ie)
+{
+	if (pos[1] == 0)
+		return 1;
+
+	if (pos[1] >= 6 &&
+	    RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
+	    pos[2 + WPA_SELECTOR_LEN] == 1 &&
+	    pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
+		ie->wpa_ie = pos;
+		ie->wpa_ie_len = pos[1] + 2;
+		wpa_hexdump(MSG_DEBUG, "WPA: WPA IE in EAPOL-Key",
+			    ie->wpa_ie, ie->wpa_ie_len);
+		return 0;
+	}
+
+	if (pos + 1 + RSN_SELECTOR_LEN < end &&
+	    pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
+		ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: PMKID in EAPOL-Key",
+			    pos, pos[1] + 2);
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
+		ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump_key(MSG_DEBUG, "WPA: GTK in EAPOL-Key",
+				pos, pos[1] + 2);
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
+		ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
+		ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: MAC Address in EAPOL-Key",
+			    pos, pos[1] + 2);
+		return 0;
+	}
+
+#ifdef CONFIG_PEERKEY
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
+		ie->smk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump_key(MSG_DEBUG, "WPA: SMK in EAPOL-Key",
+				pos, pos[1] + 2);
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
+		ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
+		ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: Nonce in EAPOL-Key",
+			    pos, pos[1] + 2);
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
+		ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
+		ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: Lifetime in EAPOL-Key",
+			    pos, pos[1] + 2);
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
+		ie->error = pos + 2 + RSN_SELECTOR_LEN;
+		ie->error_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump(MSG_DEBUG, "WPA: Error in EAPOL-Key",
+			    pos, pos[1] + 2);
+		return 0;
+	}
+#endif /* CONFIG_PEERKEY */
+
+#ifdef CONFIG_IEEE80211W
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
+		ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
+		wpa_hexdump_key(MSG_DEBUG, "WPA: IGTK in EAPOL-Key",
+				pos, pos[1] + 2);
+		return 0;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_parse_ies - Parse EAPOL-Key Key Data IEs
+ * @buf: Pointer to the Key Data buffer
+ * @len: Key Data Length
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
+			     struct wpa_eapol_ie_parse *ie)
+{
+	const u8 *pos, *end;
+	int ret = 0;
+
+	os_memset(ie, 0, sizeof(*ie));
+	for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
+		if (pos[0] == 0xdd &&
+		    ((pos == buf + len - 1) || pos[1] == 0)) {
+			/* Ignore padding */
+			break;
+		}
+		if (pos + 2 + pos[1] > end) {
+			wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
+				   "underflow (ie=%d len=%d pos=%d)",
+				   pos[0], pos[1], (int) (pos - buf));
+			wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
+					buf, len);
+			ret = -1;
+			break;
+		}
+		if (*pos == WLAN_EID_RSN) {
+			ie->rsn_ie = pos;
+			ie->rsn_ie_len = pos[1] + 2;
+			wpa_hexdump(MSG_DEBUG, "WPA: RSN IE in EAPOL-Key",
+				    ie->rsn_ie, ie->rsn_ie_len);
+		} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
+			ie->mdie = pos;
+			ie->mdie_len = pos[1] + 2;
+			wpa_hexdump(MSG_DEBUG, "WPA: MDIE in EAPOL-Key",
+				    ie->mdie, ie->mdie_len);
+		} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
+			ie->ftie = pos;
+			ie->ftie_len = pos[1] + 2;
+			wpa_hexdump(MSG_DEBUG, "WPA: FTIE in EAPOL-Key",
+				    ie->ftie, ie->ftie_len);
+		} else if (*pos == WLAN_EID_TIMEOUT_INTERVAL && pos[1] >= 5) {
+			if (pos[2] == WLAN_TIMEOUT_REASSOC_DEADLINE) {
+				ie->reassoc_deadline = pos;
+				wpa_hexdump(MSG_DEBUG, "WPA: Reassoc Deadline "
+					    "in EAPOL-Key",
+					    ie->reassoc_deadline, pos[1] + 2);
+			} else if (pos[2] == WLAN_TIMEOUT_KEY_LIFETIME) {
+				ie->key_lifetime = pos;
+				wpa_hexdump(MSG_DEBUG, "WPA: KeyLifetime "
+					    "in EAPOL-Key",
+					    ie->key_lifetime, pos[1] + 2);
+			} else {
+				wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized "
+					    "EAPOL-Key Key Data IE",
+					    pos, 2 + pos[1]);
+			}
+		} else if (*pos == WLAN_EID_LINK_ID) {
+			if (pos[1] >= 18) {
+				ie->lnkid = pos;
+				ie->lnkid_len = pos[1] + 2;
+			}
+		} else if (*pos == WLAN_EID_EXT_CAPAB) {
+			ie->ext_capab = pos;
+			ie->ext_capab_len = pos[1] + 2;
+		} else if (*pos == WLAN_EID_SUPP_RATES) {
+			ie->supp_rates = pos;
+			ie->supp_rates_len = pos[1] + 2;
+		} else if (*pos == WLAN_EID_EXT_SUPP_RATES) {
+			ie->ext_supp_rates = pos;
+			ie->ext_supp_rates_len = pos[1] + 2;
+		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
+			ret = wpa_parse_generic(pos, end, ie);
+			if (ret < 0)
+				break;
+			if (ret > 0) {
+				ret = 0;
+				break;
+			}
+		} else {
+			wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
+				    "Key Data IE", pos, 2 + pos[1]);
+		}
+	}
+
+	return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/rsn_supp/wpa_ie.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,58 @@
+/*
+ * wpa_supplicant - WPA/RSN IE and KDE definitions
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_IE_H
+#define WPA_IE_H
+
+struct wpa_sm;
+
+struct wpa_eapol_ie_parse {
+	const u8 *wpa_ie;
+	size_t wpa_ie_len;
+	const u8 *rsn_ie;
+	size_t rsn_ie_len;
+	const u8 *pmkid;
+	const u8 *gtk;
+	size_t gtk_len;
+	const u8 *mac_addr;
+	size_t mac_addr_len;
+#ifdef CONFIG_PEERKEY
+	const u8 *smk;
+	size_t smk_len;
+	const u8 *nonce;
+	size_t nonce_len;
+	const u8 *lifetime;
+	size_t lifetime_len;
+	const u8 *error;
+	size_t error_len;
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211W
+	const u8 *igtk;
+	size_t igtk_len;
+#endif /* CONFIG_IEEE80211W */
+	const u8 *mdie;
+	size_t mdie_len;
+	const u8 *ftie;
+	size_t ftie_len;
+	const u8 *reassoc_deadline;
+	const u8 *key_lifetime;
+	const u8 *lnkid;
+	size_t lnkid_len;
+	const u8 *ext_capab;
+	size_t ext_capab_len;
+	const u8 *supp_rates;
+	size_t supp_rates_len;
+	const u8 *ext_supp_rates;
+	size_t ext_supp_rates_len;
+};
+
+int wpa_supplicant_parse_ies(const u8 *buf, size_t len,
+			     struct wpa_eapol_ie_parse *ie);
+int wpa_gen_wpa_ie(struct wpa_sm *sm, u8 *wpa_ie, size_t wpa_ie_len);
+
+#endif /* WPA_IE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/base64.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,155 @@
+/*
+ * Base64 encoding/decoding (RFC1341)
+ * Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "os.h"
+#include "base64.h"
+
+static const unsigned char base64_table[65] =
+	"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+/**
+ * base64_encode - Base64 encode
+ * @src: Data to be encoded
+ * @len: Length of the data to be encoded
+ * @out_len: Pointer to output length variable, or %NULL if not used
+ * Returns: Allocated buffer of out_len bytes of encoded data,
+ * or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer. Returned buffer is
+ * nul terminated to make it easier to use as a C string. The nul terminator is
+ * not included in out_len.
+ */
+unsigned char * base64_encode(const unsigned char *src, size_t len,
+			      size_t *out_len)
+{
+	unsigned char *out, *pos;
+	const unsigned char *end, *in;
+	size_t olen;
+	int line_len;
+
+	olen = len * 4 / 3 + 4; /* 3-byte blocks to 4-byte */
+	olen += olen / 72; /* line feeds */
+	olen++; /* nul termination */
+	if (olen < len)
+		return NULL; /* integer overflow */
+	out = os_malloc(olen);
+	if (out == NULL)
+		return NULL;
+
+	end = src + len;
+	in = src;
+	pos = out;
+	line_len = 0;
+	while (end - in >= 3) {
+		*pos++ = base64_table[in[0] >> 2];
+		*pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)];
+		*pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)];
+		*pos++ = base64_table[in[2] & 0x3f];
+		in += 3;
+		line_len += 4;
+		if (line_len >= 72) {
+			*pos++ = '\n';
+			line_len = 0;
+		}
+	}
+
+	if (end - in) {
+		*pos++ = base64_table[in[0] >> 2];
+		if (end - in == 1) {
+			*pos++ = base64_table[(in[0] & 0x03) << 4];
+			*pos++ = '=';
+		} else {
+			*pos++ = base64_table[((in[0] & 0x03) << 4) |
+					      (in[1] >> 4)];
+			*pos++ = base64_table[(in[1] & 0x0f) << 2];
+		}
+		*pos++ = '=';
+		line_len += 4;
+	}
+
+	if (line_len)
+		*pos++ = '\n';
+
+	*pos = '\0';
+	if (out_len)
+		*out_len = pos - out;
+	return out;
+}
+
+
+/**
+ * base64_decode - Base64 decode
+ * @src: Data to be decoded
+ * @len: Length of the data to be decoded
+ * @out_len: Pointer to output length variable
+ * Returns: Allocated buffer of out_len bytes of decoded data,
+ * or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer.
+ */
+unsigned char * base64_decode(const unsigned char *src, size_t len,
+			      size_t *out_len)
+{
+	unsigned char dtable[256], *out, *pos, block[4], tmp;
+	size_t i, count, olen;
+	int pad = 0;
+
+	os_memset(dtable, 0x80, 256);
+	for (i = 0; i < sizeof(base64_table) - 1; i++)
+		dtable[base64_table[i]] = (unsigned char) i;
+	dtable['='] = 0;
+
+	count = 0;
+	for (i = 0; i < len; i++) {
+		if (dtable[src[i]] != 0x80)
+			count++;
+	}
+
+	if (count == 0 || count % 4)
+		return NULL;
+
+	olen = count / 4 * 3;
+	pos = out = os_malloc(olen);
+	if (out == NULL)
+		return NULL;
+
+	count = 0;
+	for (i = 0; i < len; i++) {
+		tmp = dtable[src[i]];
+		if (tmp == 0x80)
+			continue;
+
+		if (src[i] == '=')
+			pad++;
+		block[count] = tmp;
+		count++;
+		if (count == 4) {
+			*pos++ = (block[0] << 2) | (block[1] >> 4);
+			*pos++ = (block[1] << 4) | (block[2] >> 2);
+			*pos++ = (block[2] << 6) | block[3];
+			count = 0;
+			if (pad) {
+				if (pad == 1)
+					pos--;
+				else if (pad == 2)
+					pos -= 2;
+				else {
+					/* Invalid padding */
+					os_free(out);
+					return NULL;
+				}
+				break;
+			}
+		}
+	}
+
+	*out_len = pos - out;
+	return out;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/base64.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,17 @@
+/*
+ * Base64 encoding/decoding (RFC1341)
+ * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BASE64_H
+#define BASE64_H
+
+unsigned char * base64_encode(const unsigned char *src, size_t len,
+			      size_t *out_len);
+unsigned char * base64_decode(const unsigned char *src, size_t len,
+			      size_t *out_len);
+
+#endif /* BASE64_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/build_config.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,77 @@
+/*
+ * wpa_supplicant/hostapd - Build time configuration defines
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This header file can be used to define configuration defines that were
+ * originally defined in Makefile. This is mainly meant for IDE use or for
+ * systems that do not have suitable 'make' tool. In these cases, it may be
+ * easier to have a single place for defining all the needed C pre-processor
+ * defines.
+ */
+
+#ifndef BUILD_CONFIG_H
+#define BUILD_CONFIG_H
+
+/* Insert configuration defines, e.g., #define EAP_MD5, here, if needed. */
+
+#ifdef CONFIG_WIN32_DEFAULTS
+#define CONFIG_NATIVE_WINDOWS
+#define CONFIG_ANSI_C_EXTRA
+#define CONFIG_WINPCAP
+#define IEEE8021X_EAPOL
+#define PKCS12_FUNCS
+#define PCSC_FUNCS
+#define CONFIG_CTRL_IFACE
+#define CONFIG_CTRL_IFACE_NAMED_PIPE
+#define CONFIG_DRIVER_NDIS
+#define CONFIG_NDIS_EVENTS_INTEGRATED
+#define CONFIG_DEBUG_FILE
+#define EAP_MD5
+#define EAP_TLS
+#define EAP_MSCHAPv2
+#define EAP_PEAP
+#define EAP_TTLS
+#define EAP_GTC
+#define EAP_OTP
+#define EAP_LEAP
+#define EAP_TNC
+#define _CRT_SECURE_NO_DEPRECATE
+
+#ifdef USE_INTERNAL_CRYPTO
+#define CONFIG_TLS_INTERNAL_CLIENT
+#define CONFIG_INTERNAL_LIBTOMMATH
+#define CONFIG_CRYPTO_INTERNAL
+#endif /* USE_INTERNAL_CRYPTO */
+#endif /* CONFIG_WIN32_DEFAULTS */
+
+#ifdef CONFIG_XCODE_DEFAULTS
+#define CONFIG_DRIVER_OSX
+#define CONFIG_BACKEND_FILE
+#define IEEE8021X_EAPOL
+#define PKCS12_FUNCS
+#define CONFIG_CTRL_IFACE
+#define CONFIG_CTRL_IFACE_UNIX
+#define CONFIG_DEBUG_FILE
+#define EAP_MD5
+#define EAP_TLS
+#define EAP_MSCHAPv2
+#define EAP_PEAP
+#define EAP_TTLS
+#define EAP_GTC
+#define EAP_OTP
+#define EAP_LEAP
+#define EAP_TNC
+#define CONFIG_WPS
+#define EAP_WSC
+
+#ifdef USE_INTERNAL_CRYPTO
+#define CONFIG_TLS_INTERNAL_CLIENT
+#define CONFIG_INTERNAL_LIBTOMMATH
+#define CONFIG_CRYPTO_INTERNAL
+#endif /* USE_INTERNAL_CRYPTO */
+#endif /* CONFIG_XCODE_DEFAULTS */
+
+#endif /* BUILD_CONFIG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/common.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,612 @@
+/*
+ * wpa_supplicant/hostapd / common helper functions, etc.
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+
+
+static int hex2num(char c)
+{
+	if (c >= '0' && c <= '9')
+		return c - '0';
+	if (c >= 'a' && c <= 'f')
+		return c - 'a' + 10;
+	if (c >= 'A' && c <= 'F')
+		return c - 'A' + 10;
+	return -1;
+}
+
+
+int hex2byte(const char *hex)
+{
+	int a, b;
+	a = hex2num(*hex++);
+	if (a < 0)
+		return -1;
+	b = hex2num(*hex++);
+	if (b < 0)
+		return -1;
+	return (a << 4) | b;
+}
+
+
+/**
+ * hwaddr_aton - Convert ASCII string to MAC address (colon-delimited format)
+ * @txt: MAC address as a string (e.g., "00:11:22:33:44:55")
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
+ */
+int hwaddr_aton(const char *txt, u8 *addr)
+{
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		int a, b;
+
+		a = hex2num(*txt++);
+		if (a < 0)
+			return -1;
+		b = hex2num(*txt++);
+		if (b < 0)
+			return -1;
+		*addr++ = (a << 4) | b;
+		if (i < 5 && *txt++ != ':')
+			return -1;
+	}
+
+	return 0;
+}
+
+/**
+ * hwaddr_compact_aton - Convert ASCII string to MAC address (no colon delimitors format)
+ * @txt: MAC address as a string (e.g., "001122334455")
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * Returns: 0 on success, -1 on failure (e.g., string not a MAC address)
+ */
+int hwaddr_compact_aton(const char *txt, u8 *addr)
+{
+	int i;
+
+	for (i = 0; i < 6; i++) {
+		int a, b;
+
+		a = hex2num(*txt++);
+		if (a < 0)
+			return -1;
+		b = hex2num(*txt++);
+		if (b < 0)
+			return -1;
+		*addr++ = (a << 4) | b;
+	}
+
+	return 0;
+}
+
+/**
+ * hwaddr_aton2 - Convert ASCII string to MAC address (in any known format)
+ * @txt: MAC address as a string (e.g., 00:11:22:33:44:55 or 0011.2233.4455)
+ * @addr: Buffer for the MAC address (ETH_ALEN = 6 bytes)
+ * Returns: Characters used (> 0) on success, -1 on failure
+ */
+int hwaddr_aton2(const char *txt, u8 *addr)
+{
+	int i;
+	const char *pos = txt;
+
+	for (i = 0; i < 6; i++) {
+		int a, b;
+
+		while (*pos == ':' || *pos == '.' || *pos == '-')
+			pos++;
+
+		a = hex2num(*pos++);
+		if (a < 0)
+			return -1;
+		b = hex2num(*pos++);
+		if (b < 0)
+			return -1;
+		*addr++ = (a << 4) | b;
+	}
+
+	return pos - txt;
+}
+
+
+/**
+ * hexstr2bin - Convert ASCII hex string into binary data
+ * @hex: ASCII hex string (e.g., "01ab")
+ * @buf: Buffer for the binary data
+ * @len: Length of the text to convert in bytes (of buf); hex will be double
+ * this size
+ * Returns: 0 on success, -1 on failure (invalid hex string)
+ */
+int hexstr2bin(const char *hex, u8 *buf, size_t len)
+{
+	size_t i;
+	int a;
+	const char *ipos = hex;
+	u8 *opos = buf;
+
+	for (i = 0; i < len; i++) {
+		a = hex2byte(ipos);
+		if (a < 0)
+			return -1;
+		*opos++ = a;
+		ipos += 2;
+	}
+	return 0;
+}
+
+
+/**
+ * inc_byte_array - Increment arbitrary length byte array by one
+ * @counter: Pointer to byte array
+ * @len: Length of the counter in bytes
+ *
+ * This function increments the last byte of the counter by one and continues
+ * rolling over to more significant bytes if the byte was incremented from
+ * 0xff to 0x00.
+ */
+void inc_byte_array(u8 *counter, size_t len)
+{
+	int pos = len - 1;
+	while (pos >= 0) {
+		counter[pos]++;
+		if (counter[pos] != 0)
+			break;
+		pos--;
+	}
+}
+
+
+void wpa_get_ntp_timestamp(u8 *buf)
+{
+	struct os_time now;
+	u32 sec, usec;
+	be32 tmp;
+
+	/* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */
+	os_get_time(&now);
+	sec = now.sec + 2208988800U; /* Epoch to 1900 */
+	/* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */
+	usec = now.usec;
+	usec = 4295 * usec - (usec >> 5) - (usec >> 9);
+	tmp = host_to_be32(sec);
+	os_memcpy(buf, (u8 *) &tmp, 4);
+	tmp = host_to_be32(usec);
+	os_memcpy(buf + 4, (u8 *) &tmp, 4);
+}
+
+
+static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
+				    size_t len, int uppercase)
+{
+	size_t i;
+	char *pos = buf, *end = buf + buf_size;
+	int ret;
+	if (buf_size == 0)
+		return 0;
+	for (i = 0; i < len; i++) {
+		ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
+				  data[i]);
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return pos - buf;
+		}
+		pos += ret;
+	}
+	end[-1] = '\0';
+	return pos - buf;
+}
+
+/**
+ * wpa_snprintf_hex - Print data as a hex string into a buffer
+ * @buf: Memory area to use as the output buffer
+ * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
+ * @data: Data to be printed
+ * @len: Length of data in bytes
+ * Returns: Number of bytes written
+ */
+int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
+{
+	return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
+}
+
+
+/**
+ * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf
+ * @buf: Memory area to use as the output buffer
+ * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
+ * @data: Data to be printed
+ * @len: Length of data in bytes
+ * Returns: Number of bytes written
+ */
+int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
+			       size_t len)
+{
+	return _wpa_snprintf_hex(buf, buf_size, data, len, 1);
+}
+
+
+#ifdef CONFIG_ANSI_C_EXTRA
+
+#ifdef _WIN32_WCE
+void perror(const char *s)
+{
+	wpa_printf(MSG_ERROR, "%s: GetLastError: %d",
+		   s, (int) GetLastError());
+}
+#endif /* _WIN32_WCE */
+
+
+int optind = 1;
+int optopt;
+char *optarg;
+
+int getopt(int argc, char *const argv[], const char *optstring)
+{
+	static int optchr = 1;
+	char *cp;
+
+	if (optchr == 1) {
+		if (optind >= argc) {
+			/* all arguments processed */
+			return EOF;
+		}
+
+		if (argv[optind][0] != '-' || argv[optind][1] == '\0') {
+			/* no option characters */
+			return EOF;
+		}
+	}
+
+	if (os_strcmp(argv[optind], "--") == 0) {
+		/* no more options */
+		optind++;
+		return EOF;
+	}
+
+	optopt = argv[optind][optchr];
+	cp = os_strchr(optstring, optopt);
+	if (cp == NULL || optopt == ':') {
+		if (argv[optind][++optchr] == '\0') {
+			optchr = 1;
+			optind++;
+		}
+		return '?';
+	}
+
+	if (cp[1] == ':') {
+		/* Argument required */
+		optchr = 1;
+		if (argv[optind][optchr + 1]) {
+			/* No space between option and argument */
+			optarg = &argv[optind++][optchr + 1];
+		} else if (++optind >= argc) {
+			/* option requires an argument */
+			return '?';
+		} else {
+			/* Argument in the next argv */
+			optarg = argv[optind++];
+		}
+	} else {
+		/* No argument */
+		if (argv[optind][++optchr] == '\0') {
+			optchr = 1;
+			optind++;
+		}
+		optarg = NULL;
+	}
+	return *cp;
+}
+#endif /* CONFIG_ANSI_C_EXTRA */
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+/**
+ * wpa_unicode2ascii_inplace - Convert unicode string into ASCII
+ * @str: Pointer to string to convert
+ *
+ * This function converts a unicode string to ASCII using the same
+ * buffer for output. If UNICODE is not set, the buffer is not
+ * modified.
+ */
+void wpa_unicode2ascii_inplace(TCHAR *str)
+{
+#ifdef UNICODE
+	char *dst = (char *) str;
+	while (*str)
+		*dst++ = (char) *str++;
+	*dst = '\0';
+#endif /* UNICODE */
+}
+
+
+TCHAR * wpa_strdup_tchar(const char *str)
+{
+#ifdef UNICODE
+	TCHAR *buf;
+	buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR));
+	if (buf == NULL)
+		return NULL;
+	wsprintf(buf, L"%S", str);
+	return buf;
+#else /* UNICODE */
+	return os_strdup(str);
+#endif /* UNICODE */
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len)
+{
+	char *end = txt + maxlen;
+	size_t i;
+
+	for (i = 0; i < len; i++) {
+		if (txt + 4 > end)
+			break;
+
+		switch (data[i]) {
+		case '\"':
+			*txt++ = '\\';
+			*txt++ = '\"';
+			break;
+		case '\\':
+			*txt++ = '\\';
+			*txt++ = '\\';
+			break;
+		case '\e':
+			*txt++ = '\\';
+			*txt++ = 'e';
+			break;
+		case '\n':
+			*txt++ = '\\';
+			*txt++ = 'n';
+			break;
+		case '\r':
+			*txt++ = '\\';
+			*txt++ = 'r';
+			break;
+		case '\t':
+			*txt++ = '\\';
+			*txt++ = 't';
+			break;
+		default:
+			if (data[i] >= 32 && data[i] <= 127) {
+				*txt++ = data[i];
+			} else {
+				txt += os_snprintf(txt, end - txt, "\\x%02x",
+						   data[i]);
+			}
+			break;
+		}
+	}
+
+	*txt = '\0';
+}
+
+
+size_t printf_decode(u8 *buf, size_t maxlen, const char *str)
+{
+	const char *pos = str;
+	size_t len = 0;
+	int val;
+
+	while (*pos) {
+		if (len == maxlen)
+			break;
+		switch (*pos) {
+		case '\\':
+			pos++;
+			switch (*pos) {
+			case '\\':
+				buf[len++] = '\\';
+				pos++;
+				break;
+			case '"':
+				buf[len++] = '"';
+				pos++;
+				break;
+			case 'n':
+				buf[len++] = '\n';
+				pos++;
+				break;
+			case 'r':
+				buf[len++] = '\r';
+				pos++;
+				break;
+			case 't':
+				buf[len++] = '\t';
+				pos++;
+				break;
+			case 'e':
+				buf[len++] = '\e';
+				pos++;
+				break;
+			case 'x':
+				pos++;
+				val = hex2byte(pos);
+				if (val < 0) {
+					val = hex2num(*pos);
+					if (val < 0)
+						break;
+					buf[len++] = val;
+					pos++;
+				} else {
+					buf[len++] = val;
+					pos += 2;
+				}
+				break;
+			case '0':
+			case '1':
+			case '2':
+			case '3':
+			case '4':
+			case '5':
+			case '6':
+			case '7':
+				val = *pos++ - '0';
+				if (*pos >= '0' && *pos <= '7')
+					val = val * 8 + (*pos++ - '0');
+				if (*pos >= '0' && *pos <= '7')
+					val = val * 8 + (*pos++ - '0');
+				buf[len++] = val;
+				break;
+			default:
+				break;
+			}
+			break;
+		default:
+			buf[len++] = *pos++;
+			break;
+		}
+	}
+
+	return len;
+}
+
+
+/**
+ * wpa_ssid_txt - Convert SSID to a printable string
+ * @ssid: SSID (32-octet string)
+ * @ssid_len: Length of ssid in octets
+ * Returns: Pointer to a printable string
+ *
+ * This function can be used to convert SSIDs into printable form. In most
+ * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
+ * does not limit the used character set, so anything could be used in an SSID.
+ *
+ * This function uses a static buffer, so only one call can be used at the
+ * time, i.e., this is not re-entrant and the returned buffer must be used
+ * before calling this again.
+ */
+const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len)
+{
+	static char ssid_txt[32 * 4 + 1];
+
+	if (ssid == NULL) {
+		ssid_txt[0] = '\0';
+		return ssid_txt;
+	}
+
+	printf_encode(ssid_txt, sizeof(ssid_txt), ssid, ssid_len);
+	return ssid_txt;
+}
+
+
+void * __hide_aliasing_typecast(void *foo)
+{
+	return foo;
+}
+
+
+char * wpa_config_parse_string(const char *value, size_t *len)
+{
+	if (*value == '"') {
+		const char *pos;
+		char *str;
+		value++;
+		pos = os_strrchr(value, '"');
+		if (pos == NULL || pos[1] != '\0')
+			return NULL;
+		*len = pos - value;
+		str = os_malloc(*len + 1);
+		if (str == NULL)
+			return NULL;
+		os_memcpy(str, value, *len);
+		str[*len] = '\0';
+		return str;
+	} else if (*value == 'P' && value[1] == '"') {
+		const char *pos;
+		char *tstr, *str;
+		size_t tlen;
+		value += 2;
+		pos = os_strrchr(value, '"');
+		if (pos == NULL || pos[1] != '\0')
+			return NULL;
+		tlen = pos - value;
+		tstr = os_malloc(tlen + 1);
+		if (tstr == NULL)
+			return NULL;
+		os_memcpy(tstr, value, tlen);
+		tstr[tlen] = '\0';
+
+		str = os_malloc(tlen + 1);
+		if (str == NULL) {
+			os_free(tstr);
+			return NULL;
+		}
+
+		*len = printf_decode((u8 *) str, tlen + 1, tstr);
+		os_free(tstr);
+
+		return str;
+	} else {
+		u8 *str;
+		size_t tlen, hlen = os_strlen(value);
+		if (hlen & 1)
+			return NULL;
+		tlen = hlen / 2;
+		str = os_malloc(tlen + 1);
+		if (str == NULL)
+			return NULL;
+		if (hexstr2bin(value, str, tlen)) {
+			os_free(str);
+			return NULL;
+		}
+		str[tlen] = '\0';
+		*len = tlen;
+		return (char *) str;
+	}
+}
+
+
+int is_hex(const u8 *data, size_t len)
+{
+	size_t i;
+
+	for (i = 0; i < len; i++) {
+		if (data[i] < 32 || data[i] >= 127)
+			return 1;
+	}
+	return 0;
+}
+
+
+size_t merge_byte_arrays(u8 *res, size_t res_len,
+			 const u8 *src1, size_t src1_len,
+			 const u8 *src2, size_t src2_len)
+{
+	size_t len = 0;
+
+	os_memset(res, 0, res_len);
+
+	if (src1) {
+		if (src1_len >= res_len) {
+			os_memcpy(res, src1, res_len);
+			return res_len;
+		}
+
+		os_memcpy(res, src1, src1_len);
+		len += src1_len;
+	}
+
+	if (src2) {
+		if (len + src2_len >= res_len) {
+			os_memcpy(res + len, src2, res_len - len);
+			return res_len;
+		}
+
+		os_memcpy(res + len, src2, src2_len);
+		len += src2_len;
+	}
+
+	return len;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/common.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,501 @@
+/*
+ * wpa_supplicant/hostapd / common helper functions, etc.
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef COMMON_H
+#define COMMON_H
+
+#include "os.h"
+
+#if defined(__linux__) || defined(__GLIBC__)
+#include <endian.h>
+#include <byteswap.h>
+#endif /* __linux__ */
+
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || \
+    defined(__OpenBSD__)
+#include <sys/types.h>
+#include <sys/endian.h>
+#define __BYTE_ORDER	_BYTE_ORDER
+#define	__LITTLE_ENDIAN	_LITTLE_ENDIAN
+#define	__BIG_ENDIAN	_BIG_ENDIAN
+#ifdef __OpenBSD__
+#define bswap_16 swap16
+#define bswap_32 swap32
+#define bswap_64 swap64
+#else /* __OpenBSD__ */
+#define bswap_16 bswap16
+#define bswap_32 bswap32
+#define bswap_64 bswap64
+#endif /* __OpenBSD__ */
+#endif /* defined(__FreeBSD__) || defined(__NetBSD__) ||
+	* defined(__DragonFly__) || defined(__OpenBSD__) */
+
+#ifdef __sun
+#include <sys/byteorder.h>
+#define bswap_16 BSWAP_16
+#define bswap_32 BSWAP_32
+#ifdef _BIG_ENDIAN
+#define __BYTE_ORDER __BIG_ENDIAN
+#else
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+#endif /* __sun */
+
+#ifdef __APPLE__
+#include <sys/types.h>
+#include <machine/endian.h>
+#define __BYTE_ORDER	_BYTE_ORDER
+#define __LITTLE_ENDIAN	_LITTLE_ENDIAN
+#define __BIG_ENDIAN	_BIG_ENDIAN
+static inline unsigned short bswap_16(unsigned short v)
+{
+	return ((v & 0xff) << 8) | (v >> 8);
+}
+
+static inline unsigned int bswap_32(unsigned int v)
+{
+	return ((v & 0xff) << 24) | ((v & 0xff00) << 8) |
+		((v & 0xff0000) >> 8) | (v >> 24);
+}
+#endif /* __APPLE__ */
+
+#ifdef CONFIG_TI_COMPILER
+#define __BIG_ENDIAN 4321
+#define __LITTLE_ENDIAN 1234
+#ifdef __big_endian__
+#define __BYTE_ORDER __BIG_ENDIAN
+#else
+#define __BYTE_ORDER __LITTLE_ENDIAN
+#endif
+#endif /* CONFIG_TI_COMPILER */
+
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock.h>
+
+typedef int socklen_t;
+
+#ifndef MSG_DONTWAIT
+#define MSG_DONTWAIT 0 /* not supported */
+#endif
+
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#ifdef _MSC_VER
+#define inline __inline
+
+#undef vsnprintf
+#define vsnprintf _vsnprintf
+#undef close
+#define close closesocket
+#endif /* _MSC_VER */
+
+
+/* Define platform specific integer types */
+
+#ifdef _MSC_VER
+typedef UINT64 u64;
+typedef UINT32 u32;
+typedef UINT16 u16;
+typedef UINT8 u8;
+typedef INT64 s64;
+typedef INT32 s32;
+typedef INT16 s16;
+typedef INT8 s8;
+#define WPA_TYPES_DEFINED
+#endif /* _MSC_VER */
+
+#ifdef __vxworks
+typedef unsigned long long u64;
+typedef UINT32 u32;
+typedef UINT16 u16;
+typedef UINT8 u8;
+typedef long long s64;
+typedef INT32 s32;
+typedef INT16 s16;
+typedef INT8 s8;
+#define WPA_TYPES_DEFINED
+#endif /* __vxworks */
+
+#ifdef CONFIG_TI_COMPILER
+#ifdef _LLONG_AVAILABLE
+typedef unsigned long long u64;
+#else
+/*
+ * TODO: 64-bit variable not available. Using long as a workaround to test the
+ * build, but this will likely not work for all operations.
+ */
+typedef unsigned long u64;
+#endif
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+#define WPA_TYPES_DEFINED
+#endif /* CONFIG_TI_COMPILER */
+
+#ifndef WPA_TYPES_DEFINED
+#ifdef CONFIG_USE_INTTYPES_H
+#include <inttypes.h>
+#else
+#include <stdint.h>
+#endif
+typedef uint64_t u64;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+typedef int64_t s64;
+typedef int32_t s32;
+typedef int16_t s16;
+typedef int8_t s8;
+#define WPA_TYPES_DEFINED
+#endif /* !WPA_TYPES_DEFINED */
+
+
+/* Define platform specific byte swapping macros */
+
+#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
+
+static inline unsigned short wpa_swap_16(unsigned short v)
+{
+	return ((v & 0xff) << 8) | (v >> 8);
+}
+
+static inline unsigned int wpa_swap_32(unsigned int v)
+{
+	return ((v & 0xff) << 24) | ((v & 0xff00) << 8) |
+		((v & 0xff0000) >> 8) | (v >> 24);
+}
+
+#define le_to_host16(n) (n)
+#define host_to_le16(n) (n)
+#define be_to_host16(n) wpa_swap_16(n)
+#define host_to_be16(n) wpa_swap_16(n)
+#define le_to_host32(n) (n)
+#define be_to_host32(n) wpa_swap_32(n)
+#define host_to_be32(n) wpa_swap_32(n)
+
+#define WPA_BYTE_SWAP_DEFINED
+
+#endif /* __CYGWIN__ || CONFIG_NATIVE_WINDOWS */
+
+
+#ifndef WPA_BYTE_SWAP_DEFINED
+
+#ifndef __BYTE_ORDER
+#ifndef __LITTLE_ENDIAN
+#ifndef __BIG_ENDIAN
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#if defined(sparc)
+#define __BYTE_ORDER __BIG_ENDIAN
+#endif
+#endif /* __BIG_ENDIAN */
+#endif /* __LITTLE_ENDIAN */
+#endif /* __BYTE_ORDER */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define le_to_host16(n) ((__force u16) (le16) (n))
+#define host_to_le16(n) ((__force le16) (u16) (n))
+#define be_to_host16(n) bswap_16((__force u16) (be16) (n))
+#define host_to_be16(n) ((__force be16) bswap_16((n)))
+#define le_to_host32(n) ((__force u32) (le32) (n))
+#define host_to_le32(n) ((__force le32) (u32) (n))
+#define be_to_host32(n) bswap_32((__force u32) (be32) (n))
+#define host_to_be32(n) ((__force be32) bswap_32((n)))
+#define le_to_host64(n) ((__force u64) (le64) (n))
+#define host_to_le64(n) ((__force le64) (u64) (n))
+#define be_to_host64(n) bswap_64((__force u64) (be64) (n))
+#define host_to_be64(n) ((__force be64) bswap_64((n)))
+#elif __BYTE_ORDER == __BIG_ENDIAN
+#define le_to_host16(n) bswap_16(n)
+#define host_to_le16(n) bswap_16(n)
+#define be_to_host16(n) (n)
+#define host_to_be16(n) (n)
+#define le_to_host32(n) bswap_32(n)
+#define be_to_host32(n) (n)
+#define host_to_be32(n) (n)
+#define le_to_host64(n) bswap_64(n)
+#define host_to_le64(n) bswap_64(n)
+#define be_to_host64(n) (n)
+#define host_to_be64(n) (n)
+#ifndef WORDS_BIGENDIAN
+#define WORDS_BIGENDIAN
+#endif
+#else
+#error Could not determine CPU byte order
+#endif
+
+#define WPA_BYTE_SWAP_DEFINED
+#endif /* !WPA_BYTE_SWAP_DEFINED */
+
+
+/* Macros for handling unaligned memory accesses */
+
+#define WPA_GET_BE16(a) ((u16) (((a)[0] << 8) | (a)[1]))
+#define WPA_PUT_BE16(a, val)			\
+	do {					\
+		(a)[0] = ((u16) (val)) >> 8;	\
+		(a)[1] = ((u16) (val)) & 0xff;	\
+	} while (0)
+
+#define WPA_GET_LE16(a) ((u16) (((a)[1] << 8) | (a)[0]))
+#define WPA_PUT_LE16(a, val)			\
+	do {					\
+		(a)[1] = ((u16) (val)) >> 8;	\
+		(a)[0] = ((u16) (val)) & 0xff;	\
+	} while (0)
+
+#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \
+			 ((u32) (a)[2]))
+#define WPA_PUT_BE24(a, val)					\
+	do {							\
+		(a)[0] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
+		(a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
+		(a)[2] = (u8) (((u32) (val)) & 0xff);		\
+	} while (0)
+
+#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \
+			 (((u32) (a)[2]) << 8) | ((u32) (a)[3]))
+#define WPA_PUT_BE32(a, val)					\
+	do {							\
+		(a)[0] = (u8) ((((u32) (val)) >> 24) & 0xff);	\
+		(a)[1] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
+		(a)[2] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
+		(a)[3] = (u8) (((u32) (val)) & 0xff);		\
+	} while (0)
+
+#define WPA_GET_LE32(a) ((((u32) (a)[3]) << 24) | (((u32) (a)[2]) << 16) | \
+			 (((u32) (a)[1]) << 8) | ((u32) (a)[0]))
+#define WPA_PUT_LE32(a, val)					\
+	do {							\
+		(a)[3] = (u8) ((((u32) (val)) >> 24) & 0xff);	\
+		(a)[2] = (u8) ((((u32) (val)) >> 16) & 0xff);	\
+		(a)[1] = (u8) ((((u32) (val)) >> 8) & 0xff);	\
+		(a)[0] = (u8) (((u32) (val)) & 0xff);		\
+	} while (0)
+
+#define WPA_GET_BE64(a) ((((u64) (a)[0]) << 56) | (((u64) (a)[1]) << 48) | \
+			 (((u64) (a)[2]) << 40) | (((u64) (a)[3]) << 32) | \
+			 (((u64) (a)[4]) << 24) | (((u64) (a)[5]) << 16) | \
+			 (((u64) (a)[6]) << 8) | ((u64) (a)[7]))
+#define WPA_PUT_BE64(a, val)				\
+	do {						\
+		(a)[0] = (u8) (((u64) (val)) >> 56);	\
+		(a)[1] = (u8) (((u64) (val)) >> 48);	\
+		(a)[2] = (u8) (((u64) (val)) >> 40);	\
+		(a)[3] = (u8) (((u64) (val)) >> 32);	\
+		(a)[4] = (u8) (((u64) (val)) >> 24);	\
+		(a)[5] = (u8) (((u64) (val)) >> 16);	\
+		(a)[6] = (u8) (((u64) (val)) >> 8);	\
+		(a)[7] = (u8) (((u64) (val)) & 0xff);	\
+	} while (0)
+
+#define WPA_GET_LE64(a) ((((u64) (a)[7]) << 56) | (((u64) (a)[6]) << 48) | \
+			 (((u64) (a)[5]) << 40) | (((u64) (a)[4]) << 32) | \
+			 (((u64) (a)[3]) << 24) | (((u64) (a)[2]) << 16) | \
+			 (((u64) (a)[1]) << 8) | ((u64) (a)[0]))
+
+
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+#ifndef ETH_P_ALL
+#define ETH_P_ALL 0x0003
+#endif
+#ifndef ETH_P_80211_ENCAP
+#define ETH_P_80211_ENCAP 0x890d /* TDLS comes under this category */
+#endif
+#ifndef ETH_P_PAE
+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
+#endif /* ETH_P_PAE */
+#ifndef ETH_P_EAPOL
+#define ETH_P_EAPOL ETH_P_PAE
+#endif /* ETH_P_EAPOL */
+#ifndef ETH_P_RSN_PREAUTH
+#define ETH_P_RSN_PREAUTH 0x88c7
+#endif /* ETH_P_RSN_PREAUTH */
+#ifndef ETH_P_RRB
+#define ETH_P_RRB 0x890D
+#endif /* ETH_P_RRB */
+
+
+#ifdef __GNUC__
+#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b))))
+#define STRUCT_PACKED __attribute__ ((packed))
+#else
+#define PRINTF_FORMAT(a,b)
+#define STRUCT_PACKED
+#endif
+
+
+#ifdef CONFIG_ANSI_C_EXTRA
+
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+/* snprintf - used in number of places; sprintf() is _not_ a good replacement
+ * due to possible buffer overflow; see, e.g.,
+ * http://www.ijs.si/software/snprintf/ for portable implementation of
+ * snprintf. */
+int snprintf(char *str, size_t size, const char *format, ...);
+
+/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */
+int vsnprintf(char *str, size_t size, const char *format, va_list ap);
+#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */
+
+/* getopt - only used in main.c */
+int getopt(int argc, char *const argv[], const char *optstring);
+extern char *optarg;
+extern int optind;
+
+#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF
+#ifndef __socklen_t_defined
+typedef int socklen_t;
+#endif
+#endif
+
+/* inline - define as __inline or just define it to be empty, if needed */
+#ifdef CONFIG_NO_INLINE
+#define inline
+#else
+#define inline __inline
+#endif
+
+#ifndef __func__
+#define __func__ "__func__ not defined"
+#endif
+
+#ifndef bswap_16
+#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff))
+#endif
+
+#ifndef bswap_32
+#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \
+		     (((u32) (a) << 8) & 0xff0000) | \
+     		     (((u32) (a) >> 8) & 0xff00) | \
+     		     (((u32) (a) >> 24) & 0xff))
+#endif
+
+#ifndef MSG_DONTWAIT
+#define MSG_DONTWAIT 0
+#endif
+
+#ifdef _WIN32_WCE
+void perror(const char *s);
+#endif /* _WIN32_WCE */
+
+#endif /* CONFIG_ANSI_C_EXTRA */
+
+#ifndef MAC2STR
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+/*
+ * Compact form for string representation of MAC address
+ * To be used, e.g., for constructing dbus paths for P2P Devices
+ */
+#define COMPACT_MACSTR "%02x%02x%02x%02x%02x%02x"
+#endif
+
+#ifndef BIT
+#define BIT(x) (1 << (x))
+#endif
+
+/*
+ * Definitions for sparse validation
+ * (http://kernel.org/pub/linux/kernel/people/josh/sparse/)
+ */
+#ifdef __CHECKER__
+#define __force __attribute__((force))
+#define __bitwise __attribute__((bitwise))
+#else
+#define __force
+#define __bitwise
+#endif
+
+typedef u16 __bitwise be16;
+typedef u16 __bitwise le16;
+typedef u32 __bitwise be32;
+typedef u32 __bitwise le32;
+typedef u64 __bitwise be64;
+typedef u64 __bitwise le64;
+
+#ifndef __must_check
+#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)
+#define __must_check __attribute__((__warn_unused_result__))
+#else
+#define __must_check
+#endif /* __GNUC__ */
+#endif /* __must_check */
+
+int hwaddr_aton(const char *txt, u8 *addr);
+int hwaddr_compact_aton(const char *txt, u8 *addr);
+int hwaddr_aton2(const char *txt, u8 *addr);
+int hex2byte(const char *hex);
+int hexstr2bin(const char *hex, u8 *buf, size_t len);
+void inc_byte_array(u8 *counter, size_t len);
+void wpa_get_ntp_timestamp(u8 *buf);
+int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
+int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
+			       size_t len);
+
+#ifdef CONFIG_NATIVE_WINDOWS
+void wpa_unicode2ascii_inplace(TCHAR *str);
+TCHAR * wpa_strdup_tchar(const char *str);
+#else /* CONFIG_NATIVE_WINDOWS */
+#define wpa_unicode2ascii_inplace(s) do { } while (0)
+#define wpa_strdup_tchar(s) strdup((s))
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+void printf_encode(char *txt, size_t maxlen, const u8 *data, size_t len);
+size_t printf_decode(u8 *buf, size_t maxlen, const char *str);
+
+const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len);
+
+char * wpa_config_parse_string(const char *value, size_t *len);
+int is_hex(const u8 *data, size_t len);
+size_t merge_byte_arrays(u8 *res, size_t res_len,
+			 const u8 *src1, size_t src1_len,
+			 const u8 *src2, size_t src2_len);
+
+static inline int is_zero_ether_addr(const u8 *a)
+{
+	return !(a[0] | a[1] | a[2] | a[3] | a[4] | a[5]);
+}
+
+static inline int is_broadcast_ether_addr(const u8 *a)
+{
+	return (a[0] & a[1] & a[2] & a[3] & a[4] & a[5]) == 0xff;
+}
+
+#define broadcast_ether_addr (const u8 *) "\xff\xff\xff\xff\xff\xff"
+
+#ifdef _WPASILLUMOS
+#include "wpa_debug.h"
+#endif /* _WPASILLUMOS */
+
+/*
+ * gcc 4.4 ends up generating strict-aliasing warnings about some very common
+ * networking socket uses that do not really result in a real problem and
+ * cannot be easily avoided with union-based type-punning due to struct
+ * definitions including another struct in system header files. To avoid having
+ * to fully disable strict-aliasing warnings, provide a mechanism to hide the
+ * typecast from aliasing for now. A cleaner solution will hopefully be found
+ * in the future to handle these cases.
+ */
+void * __hide_aliasing_typecast(void *foo);
+#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a))
+
+#ifdef CONFIG_VALGRIND
+#include <valgrind/memcheck.h>
+#define WPA_MEM_DEFINED(ptr, len) VALGRIND_MAKE_MEM_DEFINED((ptr), (len))
+#else /* CONFIG_VALGRIND */
+#define WPA_MEM_DEFINED(ptr, len) do { } while (0)
+#endif /* CONFIG_VALGRIND */
+
+#endif /* COMMON_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/eloop.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,856 @@
+/*
+ * Event loop based on select() loop
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "trace.h"
+#include "list.h"
+#include "eloop.h"
+
+#ifdef CONFIG_ELOOP_POLL
+#include <assert.h>
+#include <poll.h>
+#endif /* CONFIG_ELOOP_POLL */
+
+
+struct eloop_sock {
+	int sock;
+	void *eloop_data;
+	void *user_data;
+	eloop_sock_handler handler;
+	WPA_TRACE_REF(eloop);
+	WPA_TRACE_REF(user);
+	WPA_TRACE_INFO
+};
+
+struct eloop_timeout {
+	struct dl_list list;
+	struct os_time time;
+	void *eloop_data;
+	void *user_data;
+	eloop_timeout_handler handler;
+	WPA_TRACE_REF(eloop);
+	WPA_TRACE_REF(user);
+	WPA_TRACE_INFO
+};
+
+struct eloop_signal {
+	int sig;
+	void *user_data;
+	eloop_signal_handler handler;
+	int signaled;
+};
+
+struct eloop_sock_table {
+	int count;
+	struct eloop_sock *table;
+	int changed;
+};
+
+struct eloop_data {
+	int max_sock;
+
+	int count; /* sum of all table counts */
+#ifdef CONFIG_ELOOP_POLL
+	int max_pollfd_map; /* number of pollfds_map currently allocated */
+	int max_poll_fds; /* number of pollfds currently allocated */
+	struct pollfd *pollfds;
+	struct pollfd **pollfds_map;
+#endif /* CONFIG_ELOOP_POLL */
+	struct eloop_sock_table readers;
+	struct eloop_sock_table writers;
+	struct eloop_sock_table exceptions;
+
+	struct dl_list timeout;
+
+	int signal_count;
+	struct eloop_signal *signals;
+	int signaled;
+	int pending_terminate;
+
+	int terminate;
+	int reader_table_changed;
+};
+
+static struct eloop_data eloop;
+
+
+#ifdef WPA_TRACE
+
+static void eloop_sigsegv_handler(int sig)
+{
+	wpa_trace_show("eloop SIGSEGV");
+	abort();
+}
+
+static void eloop_trace_sock_add_ref(struct eloop_sock_table *table)
+{
+	int i;
+	if (table == NULL || table->table == NULL)
+		return;
+	for (i = 0; i < table->count; i++) {
+		wpa_trace_add_ref(&table->table[i], eloop,
+				  table->table[i].eloop_data);
+		wpa_trace_add_ref(&table->table[i], user,
+				  table->table[i].user_data);
+	}
+}
+
+
+static void eloop_trace_sock_remove_ref(struct eloop_sock_table *table)
+{
+	int i;
+	if (table == NULL || table->table == NULL)
+		return;
+	for (i = 0; i < table->count; i++) {
+		wpa_trace_remove_ref(&table->table[i], eloop,
+				     table->table[i].eloop_data);
+		wpa_trace_remove_ref(&table->table[i], user,
+				     table->table[i].user_data);
+	}
+}
+
+#else /* WPA_TRACE */
+
+#define eloop_trace_sock_add_ref(table) do { } while (0)
+#define eloop_trace_sock_remove_ref(table) do { } while (0)
+
+#endif /* WPA_TRACE */
+
+
+int eloop_init(void)
+{
+	os_memset(&eloop, 0, sizeof(eloop));
+	dl_list_init(&eloop.timeout);
+#ifdef WPA_TRACE
+	signal(SIGSEGV, eloop_sigsegv_handler);
+#endif /* WPA_TRACE */
+	return 0;
+}
+
+
+static int eloop_sock_table_add_sock(struct eloop_sock_table *table,
+                                     int sock, eloop_sock_handler handler,
+                                     void *eloop_data, void *user_data)
+{
+	struct eloop_sock *tmp;
+	int new_max_sock;
+
+	if (sock > eloop.max_sock)
+		new_max_sock = sock;
+	else
+		new_max_sock = eloop.max_sock;
+
+	if (table == NULL)
+		return -1;
+
+#ifdef CONFIG_ELOOP_POLL
+	if (new_max_sock >= eloop.max_pollfd_map) {
+		struct pollfd **nmap;
+		nmap = os_realloc_array(eloop.pollfds_map, new_max_sock + 50,
+					sizeof(struct pollfd *));
+		if (nmap == NULL)
+			return -1;
+
+		eloop.max_pollfd_map = new_max_sock + 50;
+		eloop.pollfds_map = nmap;
+	}
+
+	if (eloop.count + 1 > eloop.max_poll_fds) {
+		struct pollfd *n;
+		int nmax = eloop.count + 1 + 50;
+		n = os_realloc_array(eloop.pollfds, nmax,
+				     sizeof(struct pollfd));
+		if (n == NULL)
+			return -1;
+
+		eloop.max_poll_fds = nmax;
+		eloop.pollfds = n;
+	}
+#endif /* CONFIG_ELOOP_POLL */
+
+	eloop_trace_sock_remove_ref(table);
+	tmp = os_realloc_array(table->table, table->count + 1,
+			       sizeof(struct eloop_sock));
+	if (tmp == NULL)
+		return -1;
+
+	tmp[table->count].sock = sock;
+	tmp[table->count].eloop_data = eloop_data;
+	tmp[table->count].user_data = user_data;
+	tmp[table->count].handler = handler;
+	wpa_trace_record(&tmp[table->count]);
+	table->count++;
+	table->table = tmp;
+	eloop.max_sock = new_max_sock;
+	eloop.count++;
+	table->changed = 1;
+	eloop_trace_sock_add_ref(table);
+
+	return 0;
+}
+
+
+static void eloop_sock_table_remove_sock(struct eloop_sock_table *table,
+                                         int sock)
+{
+	int i;
+
+	if (table == NULL || table->table == NULL || table->count == 0)
+		return;
+
+	for (i = 0; i < table->count; i++) {
+		if (table->table[i].sock == sock)
+			break;
+	}
+	if (i == table->count)
+		return;
+	eloop_trace_sock_remove_ref(table);
+	if (i != table->count - 1) {
+		os_memmove(&table->table[i], &table->table[i + 1],
+			   (table->count - i - 1) *
+			   sizeof(struct eloop_sock));
+	}
+	table->count--;
+	eloop.count--;
+	table->changed = 1;
+	eloop_trace_sock_add_ref(table);
+}
+
+
+#ifdef CONFIG_ELOOP_POLL
+
+static struct pollfd * find_pollfd(struct pollfd **pollfds_map, int fd, int mx)
+{
+	if (fd < mx && fd >= 0)
+		return pollfds_map[fd];
+	return NULL;
+}
+
+
+static int eloop_sock_table_set_fds(struct eloop_sock_table *readers,
+				    struct eloop_sock_table *writers,
+				    struct eloop_sock_table *exceptions,
+				    struct pollfd *pollfds,
+				    struct pollfd **pollfds_map,
+				    int max_pollfd_map)
+{
+	int i;
+	int nxt = 0;
+	int fd;
+	struct pollfd *pfd;
+
+	/* Clear pollfd lookup map. It will be re-populated below. */
+	os_memset(pollfds_map, 0, sizeof(struct pollfd *) * max_pollfd_map);
+
+	if (readers && readers->table) {
+		for (i = 0; i < readers->count; i++) {
+			fd = readers->table[i].sock;
+			assert(fd >= 0 && fd < max_pollfd_map);
+			pollfds[nxt].fd = fd;
+			pollfds[nxt].events = POLLIN;
+			pollfds[nxt].revents = 0;
+			pollfds_map[fd] = &(pollfds[nxt]);
+			nxt++;
+		}
+	}
+
+	if (writers && writers->table) {
+		for (i = 0; i < writers->count; i++) {
+			/*
+			 * See if we already added this descriptor, update it
+			 * if so.
+			 */
+			fd = writers->table[i].sock;
+			assert(fd >= 0 && fd < max_pollfd_map);
+			pfd = pollfds_map[fd];
+			if (!pfd) {
+				pfd = &(pollfds[nxt]);
+				pfd->events = 0;
+				pfd->fd = fd;
+				pollfds[i].revents = 0;
+				pollfds_map[fd] = pfd;
+				nxt++;
+			}
+			pfd->events |= POLLOUT;
+		}
+	}
+
+	/*
+	 * Exceptions are always checked when using poll, but I suppose it's
+	 * possible that someone registered a socket *only* for exception
+	 * handling. Set the POLLIN bit in this case.
+	 */
+	if (exceptions && exceptions->table) {
+		for (i = 0; i < exceptions->count; i++) {
+			/*
+			 * See if we already added this descriptor, just use it
+			 * if so.
+			 */
+			fd = exceptions->table[i].sock;
+			assert(fd >= 0 && fd < max_pollfd_map);
+			pfd = pollfds_map[fd];
+			if (!pfd) {
+				pfd = &(pollfds[nxt]);
+				pfd->events = POLLIN;
+				pfd->fd = fd;
+				pollfds[i].revents = 0;
+				pollfds_map[fd] = pfd;
+				nxt++;
+			}
+		}
+	}
+
+	return nxt;
+}
+
+
+static int eloop_sock_table_dispatch_table(struct eloop_sock_table *table,
+					   struct pollfd **pollfds_map,
+					   int max_pollfd_map,
+					   short int revents)
+{
+	int i;
+	struct pollfd *pfd;
+
+	if (!table || !table->table)
+		return 0;
+
+	table->changed = 0;
+	for (i = 0; i < table->count; i++) {
+		pfd = find_pollfd(pollfds_map, table->table[i].sock,
+				  max_pollfd_map);
+		if (!pfd)
+			continue;
+
+		if (!(pfd->revents & revents))
+			continue;
+
+		table->table[i].handler(table->table[i].sock,
+					table->table[i].eloop_data,
+					table->table[i].user_data);
+		if (table->changed)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static void eloop_sock_table_dispatch(struct eloop_sock_table *readers,
+				      struct eloop_sock_table *writers,
+				      struct eloop_sock_table *exceptions,
+				      struct pollfd **pollfds_map,
+				      int max_pollfd_map)
+{
+	if (eloop_sock_table_dispatch_table(readers, pollfds_map,
+					    max_pollfd_map, POLLIN | POLLERR |
+					    POLLHUP))
+		return; /* pollfds may be invalid at this point */
+
+	if (eloop_sock_table_dispatch_table(writers, pollfds_map,
+					    max_pollfd_map, POLLOUT))
+		return; /* pollfds may be invalid at this point */
+
+	eloop_sock_table_dispatch_table(exceptions, pollfds_map,
+					max_pollfd_map, POLLERR | POLLHUP);
+}
+
+#else /* CONFIG_ELOOP_POLL */
+
+static void eloop_sock_table_set_fds(struct eloop_sock_table *table,
+				     fd_set *fds)
+{
+	int i;
+
+	FD_ZERO(fds);
+
+	if (table->table == NULL)
+		return;
+
+	for (i = 0; i < table->count; i++)
+		FD_SET(table->table[i].sock, fds);
+}
+
+
+static void eloop_sock_table_dispatch(struct eloop_sock_table *table,
+				      fd_set *fds)
+{
+	int i;
+
+	if (table == NULL || table->table == NULL)
+		return;
+
+	table->changed = 0;
+	for (i = 0; i < table->count; i++) {
+		if (FD_ISSET(table->table[i].sock, fds)) {
+			table->table[i].handler(table->table[i].sock,
+						table->table[i].eloop_data,
+						table->table[i].user_data);
+			if (table->changed)
+				break;
+		}
+	}
+}
+
+#endif /* CONFIG_ELOOP_POLL */
+
+
+static void eloop_sock_table_destroy(struct eloop_sock_table *table)
+{
+	if (table) {
+		int i;
+		for (i = 0; i < table->count && table->table; i++) {
+			wpa_printf(MSG_INFO, "ELOOP: remaining socket: "
+				   "sock=%d eloop_data=%p user_data=%p "
+				   "handler=%p",
+				   table->table[i].sock,
+				   table->table[i].eloop_data,
+				   table->table[i].user_data,
+				   table->table[i].handler);
+			wpa_trace_dump_funcname("eloop unregistered socket "
+						"handler",
+						table->table[i].handler);
+			wpa_trace_dump("eloop sock", &table->table[i]);
+		}
+		os_free(table->table);
+	}
+}
+
+
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
+			     void *eloop_data, void *user_data)
+{
+	return eloop_register_sock(sock, EVENT_TYPE_READ, handler,
+				   eloop_data, user_data);
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+	eloop_unregister_sock(sock, EVENT_TYPE_READ);
+}
+
+
+static struct eloop_sock_table *eloop_get_sock_table(eloop_event_type type)
+{
+	switch (type) {
+	case EVENT_TYPE_READ:
+		return &eloop.readers;
+	case EVENT_TYPE_WRITE:
+		return &eloop.writers;
+	case EVENT_TYPE_EXCEPTION:
+		return &eloop.exceptions;
+	}
+
+	return NULL;
+}
+
+
+int eloop_register_sock(int sock, eloop_event_type type,
+			eloop_sock_handler handler,
+			void *eloop_data, void *user_data)
+{
+	struct eloop_sock_table *table;
+
+	table = eloop_get_sock_table(type);
+	return eloop_sock_table_add_sock(table, sock, handler,
+					 eloop_data, user_data);
+}
+
+
+void eloop_unregister_sock(int sock, eloop_event_type type)
+{
+	struct eloop_sock_table *table;
+
+	table = eloop_get_sock_table(type);
+	eloop_sock_table_remove_sock(table, sock);
+}
+
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+			   eloop_timeout_handler handler,
+			   void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *timeout, *tmp;
+	os_time_t now_sec;
+
+	timeout = os_zalloc(sizeof(*timeout));
+	if (timeout == NULL)
+		return -1;
+	if (os_get_time(&timeout->time) < 0) {
+		os_free(timeout);
+		return -1;
+	}
+	now_sec = timeout->time.sec;
+	timeout->time.sec += secs;
+	if (timeout->time.sec < now_sec) {
+		/*
+		 * Integer overflow - assume long enough timeout to be assumed
+		 * to be infinite, i.e., the timeout would never happen.
+		 */
+		wpa_printf(MSG_DEBUG, "ELOOP: Too long timeout (secs=%u) to "
+			   "ever happen - ignore it", secs);
+		os_free(timeout);
+		return 0;
+	}
+	timeout->time.usec += usecs;
+	while (timeout->time.usec >= 1000000) {
+		timeout->time.sec++;
+		timeout->time.usec -= 1000000;
+	}
+	timeout->eloop_data = eloop_data;
+	timeout->user_data = user_data;
+	timeout->handler = handler;
+	wpa_trace_add_ref(timeout, eloop, eloop_data);
+	wpa_trace_add_ref(timeout, user, user_data);
+	wpa_trace_record(timeout);
+
+	/* Maintain timeouts in order of increasing time */
+	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+		if (os_time_before(&timeout->time, &tmp->time)) {
+			dl_list_add(tmp->list.prev, &timeout->list);
+			return 0;
+		}
+	}
+	dl_list_add_tail(&eloop.timeout, &timeout->list);
+
+	return 0;
+}
+
+
+static void eloop_remove_timeout(struct eloop_timeout *timeout)
+{
+	dl_list_del(&timeout->list);
+	wpa_trace_remove_ref(timeout, eloop, timeout->eloop_data);
+	wpa_trace_remove_ref(timeout, user, timeout->user_data);
+	os_free(timeout);
+}
+
+
+int eloop_cancel_timeout(eloop_timeout_handler handler,
+			 void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *timeout, *prev;
+	int removed = 0;
+
+	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+			      struct eloop_timeout, list) {
+		if (timeout->handler == handler &&
+		    (timeout->eloop_data == eloop_data ||
+		     eloop_data == ELOOP_ALL_CTX) &&
+		    (timeout->user_data == user_data ||
+		     user_data == ELOOP_ALL_CTX)) {
+			eloop_remove_timeout(timeout);
+			removed++;
+		}
+	}
+
+	return removed;
+}
+
+
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+				void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *tmp;
+
+	dl_list_for_each(tmp, &eloop.timeout, struct eloop_timeout, list) {
+		if (tmp->handler == handler &&
+		    tmp->eloop_data == eloop_data &&
+		    tmp->user_data == user_data)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+#ifndef CONFIG_NATIVE_WINDOWS
+static void eloop_handle_alarm(int sig)
+{
+	wpa_printf(MSG_ERROR, "eloop: could not process SIGINT or SIGTERM in "
+		   "two seconds. Looks like there\n"
+		   "is a bug that ends up in a busy loop that "
+		   "prevents clean shutdown.\n"
+		   "Killing program forcefully.\n");
+	exit(1);
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static void eloop_handle_signal(int sig)
+{
+	int i;
+
+#ifndef CONFIG_NATIVE_WINDOWS
+	if ((sig == SIGINT || sig == SIGTERM) && !eloop.pending_terminate) {
+		/* Use SIGALRM to break out from potential busy loops that
+		 * would not allow the program to be killed. */
+		eloop.pending_terminate = 1;
+		signal(SIGALRM, eloop_handle_alarm);
+		alarm(2);
+	}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	eloop.signaled++;
+	for (i = 0; i < eloop.signal_count; i++) {
+		if (eloop.signals[i].sig == sig) {
+			eloop.signals[i].signaled++;
+			break;
+		}
+	}
+}
+
+
+static void eloop_process_pending_signals(void)
+{
+	int i;
+
+	if (eloop.signaled == 0)
+		return;
+	eloop.signaled = 0;
+
+	if (eloop.pending_terminate) {
+#ifndef CONFIG_NATIVE_WINDOWS
+		alarm(0);
+#endif /* CONFIG_NATIVE_WINDOWS */
+		eloop.pending_terminate = 0;
+	}
+
+	for (i = 0; i < eloop.signal_count; i++) {
+		if (eloop.signals[i].signaled) {
+			eloop.signals[i].signaled = 0;
+			eloop.signals[i].handler(eloop.signals[i].sig,
+						 eloop.signals[i].user_data);
+		}
+	}
+}
+
+
+int eloop_register_signal(int sig, eloop_signal_handler handler,
+			  void *user_data)
+{
+	struct eloop_signal *tmp;
+
+	tmp = os_realloc_array(eloop.signals, eloop.signal_count + 1,
+			       sizeof(struct eloop_signal));
+	if (tmp == NULL)
+		return -1;
+
+	tmp[eloop.signal_count].sig = sig;
+	tmp[eloop.signal_count].user_data = user_data;
+	tmp[eloop.signal_count].handler = handler;
+	tmp[eloop.signal_count].signaled = 0;
+	eloop.signal_count++;
+	eloop.signals = tmp;
+	signal(sig, eloop_handle_signal);
+
+	return 0;
+}
+
+
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+				    void *user_data)
+{
+	int ret = eloop_register_signal(SIGINT, handler, user_data);
+	if (ret == 0)
+		ret = eloop_register_signal(SIGTERM, handler, user_data);
+	return ret;
+}
+
+
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+				   void *user_data)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+	return 0;
+#else /* CONFIG_NATIVE_WINDOWS */
+	return eloop_register_signal(SIGHUP, handler, user_data);
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
+void eloop_run(void)
+{
+#ifdef CONFIG_ELOOP_POLL
+	int num_poll_fds;
+	int timeout_ms = 0;
+#else /* CONFIG_ELOOP_POLL */
+	fd_set *rfds, *wfds, *efds;
+	struct timeval _tv;
+#endif /* CONFIG_ELOOP_POLL */
+	int res;
+	struct os_time tv, now;
+
+#ifndef CONFIG_ELOOP_POLL
+	rfds = os_malloc(sizeof(*rfds));
+	wfds = os_malloc(sizeof(*wfds));
+	efds = os_malloc(sizeof(*efds));
+	if (rfds == NULL || wfds == NULL || efds == NULL)
+		goto out;
+#endif /* CONFIG_ELOOP_POLL */
+
+	while (!eloop.terminate &&
+	       (!dl_list_empty(&eloop.timeout) || eloop.readers.count > 0 ||
+		eloop.writers.count > 0 || eloop.exceptions.count > 0)) {
+		struct eloop_timeout *timeout;
+		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+					list);
+		if (timeout) {
+			os_get_time(&now);
+			if (os_time_before(&now, &timeout->time))
+				os_time_sub(&timeout->time, &now, &tv);
+			else
+				tv.sec = tv.usec = 0;
+#ifdef CONFIG_ELOOP_POLL
+			timeout_ms = tv.sec * 1000 + tv.usec / 1000;
+#else /* CONFIG_ELOOP_POLL */
+			_tv.tv_sec = tv.sec;
+			_tv.tv_usec = tv.usec;
+#endif /* CONFIG_ELOOP_POLL */
+		}
+
+#ifdef CONFIG_ELOOP_POLL
+		num_poll_fds = eloop_sock_table_set_fds(
+			&eloop.readers, &eloop.writers, &eloop.exceptions,
+			eloop.pollfds, eloop.pollfds_map,
+			eloop.max_pollfd_map);
+		res = poll(eloop.pollfds, num_poll_fds,
+			   timeout ? timeout_ms : -1);
+
+		if (res < 0 && errno != EINTR && errno != 0) {
+			perror("poll");
+			goto out;
+		}
+#else /* CONFIG_ELOOP_POLL */
+		eloop_sock_table_set_fds(&eloop.readers, rfds);
+		eloop_sock_table_set_fds(&eloop.writers, wfds);
+		eloop_sock_table_set_fds(&eloop.exceptions, efds);
+		res = select(eloop.max_sock + 1, rfds, wfds, efds,
+			     timeout ? &_tv : NULL);
+		if (res < 0 && errno != EINTR && errno != 0) {
+			perror("select");
+			goto out;
+		}
+#endif /* CONFIG_ELOOP_POLL */
+		eloop_process_pending_signals();
+
+		/* check if some registered timeouts have occurred */
+		timeout = dl_list_first(&eloop.timeout, struct eloop_timeout,
+					list);
+		if (timeout) {
+			os_get_time(&now);
+			if (!os_time_before(&now, &timeout->time)) {
+				void *eloop_data = timeout->eloop_data;
+				void *user_data = timeout->user_data;
+				eloop_timeout_handler handler =
+					timeout->handler;
+				eloop_remove_timeout(timeout);
+				handler(eloop_data, user_data);
+			}
+
+		}
+
+		if (res <= 0)
+			continue;
+
+#ifdef CONFIG_ELOOP_POLL
+		eloop_sock_table_dispatch(&eloop.readers, &eloop.writers,
+					  &eloop.exceptions, eloop.pollfds_map,
+					  eloop.max_pollfd_map);
+#else /* CONFIG_ELOOP_POLL */
+		eloop_sock_table_dispatch(&eloop.readers, rfds);
+		eloop_sock_table_dispatch(&eloop.writers, wfds);
+		eloop_sock_table_dispatch(&eloop.exceptions, efds);
+#endif /* CONFIG_ELOOP_POLL */
+	}
+
+out:
+#ifndef CONFIG_ELOOP_POLL
+	os_free(rfds);
+	os_free(wfds);
+	os_free(efds);
+#endif /* CONFIG_ELOOP_POLL */
+	return;
+}
+
+
+void eloop_terminate(void)
+{
+	eloop.terminate = 1;
+}
+
+
+void eloop_destroy(void)
+{
+	struct eloop_timeout *timeout, *prev;
+	struct os_time now;
+
+	os_get_time(&now);
+	dl_list_for_each_safe(timeout, prev, &eloop.timeout,
+			      struct eloop_timeout, list) {
+		int sec, usec;
+		sec = timeout->time.sec - now.sec;
+		usec = timeout->time.usec - now.usec;
+		if (timeout->time.usec < now.usec) {
+			sec--;
+			usec += 1000000;
+		}
+		wpa_printf(MSG_INFO, "ELOOP: remaining timeout: %d.%06d "
+			   "eloop_data=%p user_data=%p handler=%p",
+			   sec, usec, timeout->eloop_data, timeout->user_data,
+			   timeout->handler);
+		wpa_trace_dump_funcname("eloop unregistered timeout handler",
+					timeout->handler);
+		wpa_trace_dump("eloop timeout", timeout);
+		eloop_remove_timeout(timeout);
+	}
+	eloop_sock_table_destroy(&eloop.readers);
+	eloop_sock_table_destroy(&eloop.writers);
+	eloop_sock_table_destroy(&eloop.exceptions);
+	os_free(eloop.signals);
+
+#ifdef CONFIG_ELOOP_POLL
+	os_free(eloop.pollfds);
+	os_free(eloop.pollfds_map);
+#endif /* CONFIG_ELOOP_POLL */
+}
+
+
+int eloop_terminated(void)
+{
+	return eloop.terminate;
+}
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+#ifdef CONFIG_ELOOP_POLL
+	struct pollfd pfd;
+
+	if (sock < 0)
+		return;
+
+	os_memset(&pfd, 0, sizeof(pfd));
+	pfd.fd = sock;
+	pfd.events = POLLIN;
+
+	poll(&pfd, 1, -1);
+#else /* CONFIG_ELOOP_POLL */
+	fd_set rfds;
+
+	if (sock < 0)
+		return;
+
+	FD_ZERO(&rfds);
+	FD_SET(sock, &rfds);
+	select(sock + 1, &rfds, NULL, NULL, NULL);
+#endif /* CONFIG_ELOOP_POLL */
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/eloop.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,310 @@
+/*
+ * Event loop
+ * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file defines an event loop interface that supports processing events
+ * from registered timeouts (i.e., do something after N seconds), sockets
+ * (e.g., a new packet available for reading), and signals. eloop.c is an
+ * implementation of this interface using select() and sockets. This is
+ * suitable for most UNIX/POSIX systems. When porting to other operating
+ * systems, it may be necessary to replace that implementation with OS specific
+ * mechanisms.
+ */
+
+#ifndef ELOOP_H
+#define ELOOP_H
+
+/**
+ * ELOOP_ALL_CTX - eloop_cancel_timeout() magic number to match all timeouts
+ */
+#define ELOOP_ALL_CTX (void *) -1
+
+/**
+ * eloop_event_type - eloop socket event type for eloop_register_sock()
+ * @EVENT_TYPE_READ: Socket has data available for reading
+ * @EVENT_TYPE_WRITE: Socket has room for new data to be written
+ * @EVENT_TYPE_EXCEPTION: An exception has been reported
+ */
+typedef enum {
+	EVENT_TYPE_READ = 0,
+	EVENT_TYPE_WRITE,
+	EVENT_TYPE_EXCEPTION
+} eloop_event_type;
+
+/**
+ * eloop_sock_handler - eloop socket event callback type
+ * @sock: File descriptor number for the socket
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_sock_handler)(int sock, void *eloop_ctx, void *sock_ctx);
+
+/**
+ * eloop_event_handler - eloop generic event callback type
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_event_handler)(void *eloop_data, void *user_ctx);
+
+/**
+ * eloop_timeout_handler - eloop timeout event callback type
+ * @eloop_ctx: Registered callback context data (eloop_data)
+ * @sock_ctx: Registered callback context data (user_data)
+ */
+typedef void (*eloop_timeout_handler)(void *eloop_data, void *user_ctx);
+
+/**
+ * eloop_signal_handler - eloop signal event callback type
+ * @sig: Signal number
+ * @signal_ctx: Registered callback context data (user_data from
+ * eloop_register_signal(), eloop_register_signal_terminate(), or
+ * eloop_register_signal_reconfig() call)
+ */
+typedef void (*eloop_signal_handler)(int sig, void *signal_ctx);
+
+/**
+ * eloop_init() - Initialize global event loop data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function must be called before any other eloop_* function.
+ */
+int eloop_init(void);
+
+/**
+ * eloop_register_read_sock - Register handler for read events
+ * @sock: File descriptor number for the socket
+ * @handler: Callback function to be called when data is available for reading
+ * @eloop_data: Callback context data (eloop_ctx)
+ * @user_data: Callback context data (sock_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a read socket notifier for the given file descriptor. The handler
+ * function will be called whenever data is available for reading from the
+ * socket. The handler function is responsible for clearing the event after
+ * having processed it in order to avoid eloop from calling the handler again
+ * for the same event.
+ */
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
+			     void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_read_sock - Unregister handler for read events
+ * @sock: File descriptor number for the socket
+ *
+ * Unregister a read socket notifier that was previously registered with
+ * eloop_register_read_sock().
+ */
+void eloop_unregister_read_sock(int sock);
+
+/**
+ * eloop_register_sock - Register handler for socket events
+ * @sock: File descriptor number for the socket
+ * @type: Type of event to wait for
+ * @handler: Callback function to be called when the event is triggered
+ * @eloop_data: Callback context data (eloop_ctx)
+ * @user_data: Callback context data (sock_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register an event notifier for the given socket's file descriptor. The
+ * handler function will be called whenever the that event is triggered for the
+ * socket. The handler function is responsible for clearing the event after
+ * having processed it in order to avoid eloop from calling the handler again
+ * for the same event.
+ */
+int eloop_register_sock(int sock, eloop_event_type type,
+			eloop_sock_handler handler,
+			void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_sock - Unregister handler for socket events
+ * @sock: File descriptor number for the socket
+ * @type: Type of event for which sock was registered
+ *
+ * Unregister a socket event notifier that was previously registered with
+ * eloop_register_sock().
+ */
+void eloop_unregister_sock(int sock, eloop_event_type type);
+
+/**
+ * eloop_register_event - Register handler for generic events
+ * @event: Event to wait (eloop implementation specific)
+ * @event_size: Size of event data
+ * @handler: Callback function to be called when event is triggered
+ * @eloop_data: Callback context data (eloop_data)
+ * @user_data: Callback context data (user_data)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register an event handler for the given event. This function is used to
+ * register eloop implementation specific events which are mainly targeted for
+ * operating system specific code (driver interface and l2_packet) since the
+ * portable code will not be able to use such an OS-specific call. The handler
+ * function will be called whenever the event is triggered. The handler
+ * function is responsible for clearing the event after having processed it in
+ * order to avoid eloop from calling the handler again for the same event.
+ *
+ * In case of Windows implementation (eloop_win.c), event pointer is of HANDLE
+ * type, i.e., void*. The callers are likely to have 'HANDLE h' type variable,
+ * and they would call this function with eloop_register_event(h, sizeof(h),
+ * ...).
+ */
+int eloop_register_event(void *event, size_t event_size,
+			 eloop_event_handler handler,
+			 void *eloop_data, void *user_data);
+
+/**
+ * eloop_unregister_event - Unregister handler for a generic event
+ * @event: Event to cancel (eloop implementation specific)
+ * @event_size: Size of event data
+ *
+ * Unregister a generic event notifier that was previously registered with
+ * eloop_register_event().
+ */
+void eloop_unregister_event(void *event, size_t event_size);
+
+/**
+ * eloop_register_timeout - Register timeout
+ * @secs: Number of seconds to the timeout
+ * @usecs: Number of microseconds to the timeout
+ * @handler: Callback function to be called when timeout occurs
+ * @eloop_data: Callback context data (eloop_ctx)
+ * @user_data: Callback context data (sock_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a timeout that will cause the handler function to be called after
+ * given time.
+ */
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+			   eloop_timeout_handler handler,
+			   void *eloop_data, void *user_data);
+
+/**
+ * eloop_cancel_timeout - Cancel timeouts
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data or %ELOOP_ALL_CTX to match all
+ * @user_data: Matching user_data or %ELOOP_ALL_CTX to match all
+ * Returns: Number of cancelled timeouts
+ *
+ * Cancel matching <handler,eloop_data,user_data> timeouts registered with
+ * eloop_register_timeout(). ELOOP_ALL_CTX can be used as a wildcard for
+ * cancelling all timeouts regardless of eloop_data/user_data.
+ */
+int eloop_cancel_timeout(eloop_timeout_handler handler,
+			 void *eloop_data, void *user_data);
+
+/**
+ * eloop_is_timeout_registered - Check if a timeout is already registered
+ * @handler: Matching callback function
+ * @eloop_data: Matching eloop_data
+ * @user_data: Matching user_data
+ * Returns: 1 if the timeout is registered, 0 if the timeout is not registered
+ *
+ * Determine if a matching <handler,eloop_data,user_data> timeout is registered
+ * with eloop_register_timeout().
+ */
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+				void *eloop_data, void *user_data);
+
+/**
+ * eloop_register_signal - Register handler for signals
+ * @sig: Signal number (e.g., SIGHUP)
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a signal is received.
+ * The callback function is actually called only after the system signal
+ * handler has returned. This means that the normal limits for sighandlers
+ * (i.e., only "safe functions" allowed) do not apply for the registered
+ * callback.
+ */
+int eloop_register_signal(int sig, eloop_signal_handler handler,
+			  void *user_data);
+
+/**
+ * eloop_register_signal_terminate - Register handler for terminate signals
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a process termination
+ * signal is received. The callback function is actually called only after the
+ * system signal handler has returned. This means that the normal limits for
+ * sighandlers (i.e., only "safe functions" allowed) do not apply for the
+ * registered callback.
+ *
+ * This function is a more portable version of eloop_register_signal() since
+ * the knowledge of exact details of the signals is hidden in eloop
+ * implementation. In case of operating systems using signal(), this function
+ * registers handlers for SIGINT and SIGTERM.
+ */
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+				    void *user_data);
+
+/**
+ * eloop_register_signal_reconfig - Register handler for reconfig signals
+ * @handler: Callback function to be called when the signal is received
+ * @user_data: Callback context data (signal_ctx)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Register a callback function that will be called when a reconfiguration /
+ * hangup signal is received. The callback function is actually called only
+ * after the system signal handler has returned. This means that the normal
+ * limits for sighandlers (i.e., only "safe functions" allowed) do not apply
+ * for the registered callback.
+ *
+ * This function is a more portable version of eloop_register_signal() since
+ * the knowledge of exact details of the signals is hidden in eloop
+ * implementation. In case of operating systems using signal(), this function
+ * registers a handler for SIGHUP.
+ */
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+				   void *user_data);
+
+/**
+ * eloop_run - Start the event loop
+ *
+ * Start the event loop and continue running as long as there are any
+ * registered event handlers. This function is run after event loop has been
+ * initialized with event_init() and one or more events have been registered.
+ */
+void eloop_run(void);
+
+/**
+ * eloop_terminate - Terminate event loop
+ *
+ * Terminate event loop even if there are registered events. This can be used
+ * to request the program to be terminated cleanly.
+ */
+void eloop_terminate(void);
+
+/**
+ * eloop_destroy - Free any resources allocated for the event loop
+ *
+ * After calling eloop_destroy(), other eloop_* functions must not be called
+ * before re-running eloop_init().
+ */
+void eloop_destroy(void);
+
+/**
+ * eloop_terminated - Check whether event loop has been terminated
+ * Returns: 1 = event loop terminate, 0 = event loop still running
+ *
+ * This function can be used to check whether eloop_terminate() has been called
+ * to request termination of the event loop. This is normally used to abort
+ * operations that may still be queued to be run when eloop_terminate() was
+ * called.
+ */
+int eloop_terminated(void);
+
+/**
+ * eloop_wait_for_read_sock - Wait for a single reader
+ * @sock: File descriptor number for the socket
+ *
+ * Do a blocking wait for a single read socket.
+ */
+void eloop_wait_for_read_sock(int sock);
+
+#endif /* ELOOP_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/ext_password.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,33 @@
+/*
+ * External password backend
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EXT_PASSWORD_H
+#define EXT_PASSWORD_H
+
+struct ext_password_data;
+
+#ifdef CONFIG_EXT_PASSWORD
+
+struct ext_password_data * ext_password_init(const char *backend,
+					     const char *params);
+void ext_password_deinit(struct ext_password_data *data);
+
+struct wpabuf * ext_password_get(struct ext_password_data *data,
+				 const char *name);
+void ext_password_free(struct wpabuf *pw);
+
+#else /* CONFIG_EXT_PASSWORD */
+
+#define ext_password_init(b, p) ((void *) 1)
+#define ext_password_deinit(d) do { } while (0)
+#define ext_password_get(d, n) (NULL)
+#define ext_password_free(p) do { } while (0)
+
+#endif /* CONFIG_EXT_PASSWORD */
+
+#endif /* EXT_PASSWORD_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/includes.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,50 @@
+/*
+ * wpa_supplicant/hostapd - Default include files
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This header file is included into all C files so that commonly used header
+ * files can be selected with OS specific ifdef blocks in one place instead of
+ * having to have OS/C library specific selection in many files.
+ */
+
+#ifndef INCLUDES_H
+#define INCLUDES_H
+
+/* Include possible build time configuration before including anything else */
+#include "build_config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <string.h>
+#ifndef _WIN32_WCE
+#ifndef CONFIG_TI_COMPILER
+#include <signal.h>
+#include <sys/types.h>
+#endif /* CONFIG_TI_COMPILER */
+#include <errno.h>
+#endif /* _WIN32_WCE */
+#include <ctype.h>
+
+#ifndef CONFIG_TI_COMPILER
+#ifndef _MSC_VER
+#include <unistd.h>
+#endif /* _MSC_VER */
+#endif /* CONFIG_TI_COMPILER */
+
+#ifndef CONFIG_NATIVE_WINDOWS
+#ifndef CONFIG_TI_COMPILER
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#ifndef __vxworks
+#include <sys/uio.h>
+#include <sys/time.h>
+#endif /* __vxworks */
+#endif /* CONFIG_TI_COMPILER */
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#endif /* INCLUDES_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/ip_addr.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,28 @@
+/*
+ * IP address processing
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IP_ADDR_H
+#define IP_ADDR_H
+
+struct hostapd_ip_addr {
+	int af; /* AF_INET / AF_INET6 */
+	union {
+		struct in_addr v4;
+#ifdef CONFIG_IPV6
+		struct in6_addr v6;
+#endif /* CONFIG_IPV6 */
+		u8 max_len[16];
+	} u;
+};
+
+const char * hostapd_ip_txt(const struct hostapd_ip_addr *addr, char *buf,
+			    size_t buflen);
+int hostapd_ip_diff(struct hostapd_ip_addr *a, struct hostapd_ip_addr *b);
+int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr);
+
+#endif /* IP_ADDR_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/list.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,95 @@
+/*
+ * Doubly-linked list
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef LIST_H
+#define LIST_H
+
+/**
+ * struct dl_list - Doubly-linked list
+ */
+struct dl_list {
+	struct dl_list *next;
+	struct dl_list *prev;
+};
+
+static inline void dl_list_init(struct dl_list *list)
+{
+	list->next = list;
+	list->prev = list;
+}
+
+static inline void dl_list_add(struct dl_list *list, struct dl_list *item)
+{
+	item->next = list->next;
+	item->prev = list;
+	list->next->prev = item;
+	list->next = item;
+}
+
+static inline void dl_list_add_tail(struct dl_list *list, struct dl_list *item)
+{
+	dl_list_add(list->prev, item);
+}
+
+static inline void dl_list_del(struct dl_list *item)
+{
+	item->next->prev = item->prev;
+	item->prev->next = item->next;
+	item->next = NULL;
+	item->prev = NULL;
+}
+
+static inline int dl_list_empty(struct dl_list *list)
+{
+	return list->next == list;
+}
+
+static inline unsigned int dl_list_len(struct dl_list *list)
+{
+	struct dl_list *item;
+	int count = 0;
+	for (item = list->next; item != list; item = item->next)
+		count++;
+	return count;
+}
+
+#ifndef offsetof
+#define offsetof(type, member) ((long) &((type *) 0)->member)
+#endif
+
+#define dl_list_entry(item, type, member) \
+	((type *) ((char *) item - offsetof(type, member)))
+
+#define dl_list_first(list, type, member) \
+	(dl_list_empty((list)) ? NULL : \
+	 dl_list_entry((list)->next, type, member))
+
+#define dl_list_last(list, type, member) \
+	(dl_list_empty((list)) ? NULL : \
+	 dl_list_entry((list)->prev, type, member))
+
+#define dl_list_for_each(item, list, type, member) \
+	for (item = dl_list_entry((list)->next, type, member); \
+	     &item->member != (list); \
+	     item = dl_list_entry(item->member.next, type, member))
+
+#define dl_list_for_each_safe(item, n, list, type, member) \
+	for (item = dl_list_entry((list)->next, type, member), \
+		     n = dl_list_entry(item->member.next, type, member); \
+	     &item->member != (list); \
+	     item = n, n = dl_list_entry(n->member.next, type, member))
+
+#define dl_list_for_each_reverse(item, list, type, member) \
+	for (item = dl_list_entry((list)->prev, type, member); \
+	     &item->member != (list); \
+	     item = dl_list_entry(item->member.prev, type, member))
+
+#define DEFINE_DL_LIST(name) \
+	struct dl_list name = { &(name), &(name) }
+
+#endif /* LIST_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/os.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,539 @@
+/*
+ * OS specific functions
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef OS_H
+#define OS_H
+
+typedef long os_time_t;
+
+/**
+ * os_sleep - Sleep (sec, usec)
+ * @sec: Number of seconds to sleep
+ * @usec: Number of microseconds to sleep
+ */
+void os_sleep(os_time_t sec, os_time_t usec);
+
+struct os_time {
+	os_time_t sec;
+	os_time_t usec;
+};
+
+/**
+ * os_get_time - Get current time (sec, usec)
+ * @t: Pointer to buffer for the time
+ * Returns: 0 on success, -1 on failure
+ */
+int os_get_time(struct os_time *t);
+
+
+/* Helper macros for handling struct os_time */
+
+#define os_time_before(a, b) \
+	((a)->sec < (b)->sec || \
+	 ((a)->sec == (b)->sec && (a)->usec < (b)->usec))
+
+#define os_time_sub(a, b, res) do { \
+	(res)->sec = (a)->sec - (b)->sec; \
+	(res)->usec = (a)->usec - (b)->usec; \
+	if ((res)->usec < 0) { \
+		(res)->sec--; \
+		(res)->usec += 1000000; \
+	} \
+} while (0)
+
+/**
+ * os_mktime - Convert broken-down time into seconds since 1970-01-01
+ * @year: Four digit year
+ * @month: Month (1 .. 12)
+ * @day: Day of month (1 .. 31)
+ * @hour: Hour (0 .. 23)
+ * @min: Minute (0 .. 59)
+ * @sec: Second (0 .. 60)
+ * @t: Buffer for returning calendar time representation (seconds since
+ * 1970-01-01 00:00:00)
+ * Returns: 0 on success, -1 on failure
+ *
+ * Note: The result is in seconds from Epoch, i.e., in UTC, not in local time
+ * which is used by POSIX mktime().
+ */
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+	      os_time_t *t);
+
+struct os_tm {
+	int sec; /* 0..59 or 60 for leap seconds */
+	int min; /* 0..59 */
+	int hour; /* 0..23 */
+	int day; /* 1..31 */
+	int month; /* 1..12 */
+	int year; /* Four digit year */
+};
+
+int os_gmtime(os_time_t t, struct os_tm *tm);
+
+/**
+ * os_daemonize - Run in the background (detach from the controlling terminal)
+ * @pid_file: File name to write the process ID to or %NULL to skip this
+ * Returns: 0 on success, -1 on failure
+ */
+int os_daemonize(const char *pid_file);
+
+/**
+ * os_daemonize_terminate - Stop running in the background (remove pid file)
+ * @pid_file: File name to write the process ID to or %NULL to skip this
+ */
+void os_daemonize_terminate(const char *pid_file);
+
+/**
+ * os_get_random - Get cryptographically strong pseudo random data
+ * @buf: Buffer for pseudo random data
+ * @len: Length of the buffer
+ * Returns: 0 on success, -1 on failure
+ */
+int os_get_random(unsigned char *buf, size_t len);
+
+/**
+ * os_random - Get pseudo random value (not necessarily very strong)
+ * Returns: Pseudo random value
+ */
+unsigned long os_random(void);
+
+/**
+ * os_rel2abs_path - Get an absolute path for a file
+ * @rel_path: Relative path to a file
+ * Returns: Absolute path for the file or %NULL on failure
+ *
+ * This function tries to convert a relative path of a file to an absolute path
+ * in order for the file to be found even if current working directory has
+ * changed. The returned value is allocated and caller is responsible for
+ * freeing it. It is acceptable to just return the same path in an allocated
+ * buffer, e.g., return strdup(rel_path). This function is only used to find
+ * configuration files when os_daemonize() may have changed the current working
+ * directory and relative path would be pointing to a different location.
+ */
+char * os_rel2abs_path(const char *rel_path);
+
+/**
+ * os_program_init - Program initialization (called at start)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called when a programs starts. If there are any OS specific
+ * processing that is needed, it can be placed here. It is also acceptable to
+ * just return 0 if not special processing is needed.
+ */
+int os_program_init(void);
+
+/**
+ * os_program_deinit - Program deinitialization (called just before exit)
+ *
+ * This function is called just before a program exists. If there are any OS
+ * specific processing, e.g., freeing resourced allocated in os_program_init(),
+ * it should be done here. It is also acceptable for this function to do
+ * nothing.
+ */
+void os_program_deinit(void);
+
+/**
+ * os_setenv - Set environment variable
+ * @name: Name of the variable
+ * @value: Value to set to the variable
+ * @overwrite: Whether existing variable should be overwritten
+ * Returns: 0 on success, -1 on error
+ *
+ * This function is only used for wpa_cli action scripts. OS wrapper does not
+ * need to implement this if such functionality is not needed.
+ */
+int os_setenv(const char *name, const char *value, int overwrite);
+
+/**
+ * os_unsetenv - Delete environent variable
+ * @name: Name of the variable
+ * Returns: 0 on success, -1 on error
+ *
+ * This function is only used for wpa_cli action scripts. OS wrapper does not
+ * need to implement this if such functionality is not needed.
+ */
+int os_unsetenv(const char *name);
+
+/**
+ * os_readfile - Read a file to an allocated memory buffer
+ * @name: Name of the file to read
+ * @len: For returning the length of the allocated buffer
+ * Returns: Pointer to the allocated buffer or %NULL on failure
+ *
+ * This function allocates memory and reads the given file to this buffer. Both
+ * binary and text files can be read with this function. The caller is
+ * responsible for freeing the returned buffer with os_free().
+ */
+char * os_readfile(const char *name, size_t *len);
+
+/**
+ * os_zalloc - Allocate and zero memory
+ * @size: Number of bytes to allocate
+ * Returns: Pointer to allocated and zeroed memory or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+void * os_zalloc(size_t size);
+
+/**
+ * os_calloc - Allocate and zero memory for an array
+ * @nmemb: Number of members in the array
+ * @size: Number of bytes in each member
+ * Returns: Pointer to allocated and zeroed memory or %NULL on failure
+ *
+ * This function can be used as a wrapper for os_zalloc(nmemb * size) when an
+ * allocation is used for an array. The main benefit over os_zalloc() is in
+ * having an extra check to catch integer overflows in multiplication.
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+static inline void * os_calloc(size_t nmemb, size_t size)
+{
+	if (size && nmemb > (~(size_t) 0) / size)
+		return NULL;
+	return os_zalloc(nmemb * size);
+}
+
+
+/*
+ * The following functions are wrapper for standard ANSI C or POSIX functions.
+ * By default, they are just defined to use the standard function name and no
+ * os_*.c implementation is needed for them. This avoids extra function calls
+ * by allowing the C pre-processor take care of the function name mapping.
+ *
+ * If the target system uses a C library that does not provide these functions,
+ * build_config.h can be used to define the wrappers to use a different
+ * function name. This can be done on function-by-function basis since the
+ * defines here are only used if build_config.h does not define the os_* name.
+ * If needed, os_*.c file can be used to implement the functions that are not
+ * included in the C library on the target system. Alternatively,
+ * OS_NO_C_LIB_DEFINES can be defined to skip all defines here in which case
+ * these functions need to be implemented in os_*.c file for the target system.
+ */
+
+#ifdef OS_NO_C_LIB_DEFINES
+
+/**
+ * os_malloc - Allocate dynamic memory
+ * @size: Size of the buffer to allocate
+ * Returns: Allocated buffer or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+void * os_malloc(size_t size);
+
+/**
+ * os_realloc - Re-allocate dynamic memory
+ * @ptr: Old buffer from os_malloc() or os_realloc()
+ * @size: Size of the new buffer
+ * Returns: Allocated buffer or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ * If re-allocation fails, %NULL is returned and the original buffer (ptr) is
+ * not freed and caller is still responsible for freeing it.
+ */
+void * os_realloc(void *ptr, size_t size);
+
+/**
+ * os_free - Free dynamic memory
+ * @ptr: Old buffer from os_malloc() or os_realloc(); can be %NULL
+ */
+void os_free(void *ptr);
+
+/**
+ * os_memcpy - Copy memory area
+ * @dest: Destination
+ * @src: Source
+ * @n: Number of bytes to copy
+ * Returns: dest
+ *
+ * The memory areas src and dst must not overlap. os_memmove() can be used with
+ * overlapping memory.
+ */
+void * os_memcpy(void *dest, const void *src, size_t n);
+
+/**
+ * os_memmove - Copy memory area
+ * @dest: Destination
+ * @src: Source
+ * @n: Number of bytes to copy
+ * Returns: dest
+ *
+ * The memory areas src and dst may overlap.
+ */
+void * os_memmove(void *dest, const void *src, size_t n);
+
+/**
+ * os_memset - Fill memory with a constant byte
+ * @s: Memory area to be filled
+ * @c: Constant byte
+ * @n: Number of bytes started from s to fill with c
+ * Returns: s
+ */
+void * os_memset(void *s, int c, size_t n);
+
+/**
+ * os_memcmp - Compare memory areas
+ * @s1: First buffer
+ * @s2: Second buffer
+ * @n: Maximum numbers of octets to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_memcmp(const void *s1, const void *s2, size_t n);
+
+/**
+ * os_strdup - Duplicate a string
+ * @s: Source string
+ * Returns: Allocated buffer with the string copied into it or %NULL on failure
+ *
+ * Caller is responsible for freeing the returned buffer with os_free().
+ */
+char * os_strdup(const char *s);
+
+/**
+ * os_strlen - Calculate the length of a string
+ * @s: '\0' terminated string
+ * Returns: Number of characters in s (not counting the '\0' terminator)
+ */
+size_t os_strlen(const char *s);
+
+/**
+ * os_strcasecmp - Compare two strings ignoring case
+ * @s1: First string
+ * @s2: Second string
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greatred than s2
+ */
+int os_strcasecmp(const char *s1, const char *s2);
+
+/**
+ * os_strncasecmp - Compare two strings ignoring case
+ * @s1: First string
+ * @s2: Second string
+ * @n: Maximum numbers of characters to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_strncasecmp(const char *s1, const char *s2, size_t n);
+
+/**
+ * os_strchr - Locate the first occurrence of a character in string
+ * @s: String
+ * @c: Character to search for
+ * Returns: Pointer to the matched character or %NULL if not found
+ */
+char * os_strchr(const char *s, int c);
+
+/**
+ * os_strrchr - Locate the last occurrence of a character in string
+ * @s: String
+ * @c: Character to search for
+ * Returns: Pointer to the matched character or %NULL if not found
+ */
+char * os_strrchr(const char *s, int c);
+
+/**
+ * os_strcmp - Compare two strings
+ * @s1: First string
+ * @s2: Second string
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greatred than s2
+ */
+int os_strcmp(const char *s1, const char *s2);
+
+/**
+ * os_strncmp - Compare two strings
+ * @s1: First string
+ * @s2: Second string
+ * @n: Maximum numbers of characters to compare
+ * Returns: An integer less than, equal to, or greater than zero if s1 is
+ * found to be less than, to match, or be greater than s2. Only first n
+ * characters will be compared.
+ */
+int os_strncmp(const char *s1, const char *s2, size_t n);
+
+/**
+ * os_strncpy - Copy a string
+ * @dest: Destination
+ * @src: Source
+ * @n: Maximum number of characters to copy
+ * Returns: dest
+ */
+char * os_strncpy(char *dest, const char *src, size_t n);
+
+/**
+ * os_strstr - Locate a substring
+ * @haystack: String (haystack) to search from
+ * @needle: Needle to search from haystack
+ * Returns: Pointer to the beginning of the substring or %NULL if not found
+ */
+char * os_strstr(const char *haystack, const char *needle);
+
+/**
+ * os_snprintf - Print to a memory buffer
+ * @str: Memory buffer to print into
+ * @size: Maximum length of the str buffer
+ * @format: printf format
+ * Returns: Number of characters printed (not including trailing '\0').
+ *
+ * If the output buffer is truncated, number of characters which would have
+ * been written is returned. Since some C libraries return -1 in such a case,
+ * the caller must be prepared on that value, too, to indicate truncation.
+ *
+ * Note: Some C library implementations of snprintf() may not guarantee null
+ * termination in case the output is truncated. The OS wrapper function of
+ * os_snprintf() should provide this guarantee, i.e., to null terminate the
+ * output buffer if a C library version of the function is used and if that
+ * function does not guarantee null termination.
+ *
+ * If the target system does not include snprintf(), see, e.g.,
+ * http://www.ijs.si/software/snprintf/ for an example of a portable
+ * implementation of snprintf.
+ */
+int os_snprintf(char *str, size_t size, const char *format, ...);
+
+#else /* OS_NO_C_LIB_DEFINES */
+
+#ifdef WPA_TRACE
+void * os_malloc(size_t size);
+void * os_realloc(void *ptr, size_t size);
+void os_free(void *ptr);
+char * os_strdup(const char *s);
+#else /* WPA_TRACE */
+#ifndef os_malloc
+#define os_malloc(s) malloc((s))
+#endif
+#ifndef os_realloc
+#define os_realloc(p, s) realloc((p), (s))
+#endif
+#ifndef os_free
+#define os_free(p) free((p))
+#endif
+#ifndef os_strdup
+#ifdef _MSC_VER
+#define os_strdup(s) _strdup(s)
+#else
+#define os_strdup(s) strdup(s)
+#endif
+#endif
+#endif /* WPA_TRACE */
+
+#ifndef os_memcpy
+#define os_memcpy(d, s, n) memcpy((d), (s), (n))
+#endif
+#ifndef os_memmove
+#define os_memmove(d, s, n) memmove((d), (s), (n))
+#endif
+#ifndef os_memset
+#define os_memset(s, c, n) memset(s, c, n)
+#endif
+#ifndef os_memcmp
+#define os_memcmp(s1, s2, n) memcmp((s1), (s2), (n))
+#endif
+
+#ifndef os_strlen
+#define os_strlen(s) strlen(s)
+#endif
+#ifndef os_strcasecmp
+#ifdef _MSC_VER
+#define os_strcasecmp(s1, s2) _stricmp((s1), (s2))
+#else
+#define os_strcasecmp(s1, s2) strcasecmp((s1), (s2))
+#endif
+#endif
+#ifndef os_strncasecmp
+#ifdef _MSC_VER
+#define os_strncasecmp(s1, s2, n) _strnicmp((s1), (s2), (n))
+#else
+#define os_strncasecmp(s1, s2, n) strncasecmp((s1), (s2), (n))
+#endif
+#endif
+#ifndef os_strchr
+#define os_strchr(s, c) strchr((s), (c))
+#endif
+#ifndef os_strcmp
+#define os_strcmp(s1, s2) strcmp((s1), (s2))
+#endif
+#ifndef os_strncmp
+#define os_strncmp(s1, s2, n) strncmp((s1), (s2), (n))
+#endif
+#ifndef os_strncpy
+#define os_strncpy(d, s, n) strncpy((d), (s), (n))
+#endif
+#ifndef os_strrchr
+#define os_strrchr(s, c) strrchr((s), (c))
+#endif
+#ifndef os_strstr
+#define os_strstr(h, n) strstr((h), (n))
+#endif
+
+#ifndef os_snprintf
+#ifdef _MSC_VER
+#define os_snprintf _snprintf
+#else
+#define os_snprintf snprintf
+#endif
+#endif
+
+#endif /* OS_NO_C_LIB_DEFINES */
+
+
+static inline void * os_realloc_array(void *ptr, size_t nmemb, size_t size)
+{
+	if (size && nmemb > (~(size_t) 0) / size)
+		return NULL;
+	return os_realloc(ptr, nmemb * size);
+}
+
+
+/**
+ * os_strlcpy - Copy a string with size bound and NUL-termination
+ * @dest: Destination
+ * @src: Source
+ * @siz: Size of the target buffer
+ * Returns: Total length of the target string (length of src) (not including
+ * NUL-termination)
+ *
+ * This function matches in behavior with the strlcpy(3) function in OpenBSD.
+ */
+size_t os_strlcpy(char *dest, const char *src, size_t siz);
+
+
+#ifdef OS_REJECT_C_LIB_FUNCTIONS
+#define malloc OS_DO_NOT_USE_malloc
+#define realloc OS_DO_NOT_USE_realloc
+#define free OS_DO_NOT_USE_free
+#define memcpy OS_DO_NOT_USE_memcpy
+#define memmove OS_DO_NOT_USE_memmove
+#define memset OS_DO_NOT_USE_memset
+#define memcmp OS_DO_NOT_USE_memcmp
+#undef strdup
+#define strdup OS_DO_NOT_USE_strdup
+#define strlen OS_DO_NOT_USE_strlen
+#define strcasecmp OS_DO_NOT_USE_strcasecmp
+#define strncasecmp OS_DO_NOT_USE_strncasecmp
+#undef strchr
+#define strchr OS_DO_NOT_USE_strchr
+#undef strcmp
+#define strcmp OS_DO_NOT_USE_strcmp
+#undef strncmp
+#define strncmp OS_DO_NOT_USE_strncmp
+#undef strncpy
+#define strncpy OS_DO_NOT_USE_strncpy
+#define strrchr OS_DO_NOT_USE_strrchr
+#define strstr OS_DO_NOT_USE_strstr
+#undef snprintf
+#define snprintf OS_DO_NOT_USE_snprintf
+
+#define strcpy OS_DO_NOT_USE_strcpy
+#endif /* OS_REJECT_C_LIB_FUNCTIONS */
+
+#endif /* OS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/os_unix.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,488 @@
+/*
+ * OS specific functions for UNIX/POSIX systems
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include <time.h>
+
+#ifdef ANDROID
+#include <linux/capability.h>
+#include <linux/prctl.h>
+#include <private/android_filesystem_config.h>
+#endif /* ANDROID */
+
+#include "os.h"
+
+#ifdef WPA_TRACE
+
+#include "common.h"
+#include "wpa_debug.h"
+#include "trace.h"
+#include "list.h"
+
+static struct dl_list alloc_list;
+
+#define ALLOC_MAGIC 0xa84ef1b2
+#define FREED_MAGIC 0x67fd487a
+
+struct os_alloc_trace {
+	unsigned int magic;
+	struct dl_list list;
+	size_t len;
+	WPA_TRACE_INFO
+};
+
+#endif /* WPA_TRACE */
+
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+	if (sec)
+		sleep(sec);
+	if (usec)
+		usleep(usec);
+}
+
+
+int os_get_time(struct os_time *t)
+{
+	int res;
+	struct timeval tv;
+	res = gettimeofday(&tv, NULL);
+	t->sec = tv.tv_sec;
+	t->usec = tv.tv_usec;
+	return res;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+	      os_time_t *t)
+{
+	struct tm tm, *tm1;
+	time_t t_local, t1, t2;
+	os_time_t tz_offset;
+
+	if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
+	    hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
+	    sec > 60)
+		return -1;
+
+	memset(&tm, 0, sizeof(tm));
+	tm.tm_year = year - 1900;
+	tm.tm_mon = month - 1;
+	tm.tm_mday = day;
+	tm.tm_hour = hour;
+	tm.tm_min = min;
+	tm.tm_sec = sec;
+
+	t_local = mktime(&tm);
+
+	/* figure out offset to UTC */
+	tm1 = localtime(&t_local);
+	if (tm1) {
+		t1 = mktime(tm1);
+		tm1 = gmtime(&t_local);
+		if (tm1) {
+			t2 = mktime(tm1);
+			tz_offset = t2 - t1;
+		} else
+			tz_offset = 0;
+	} else
+		tz_offset = 0;
+
+	*t = (os_time_t) t_local - tz_offset;
+	return 0;
+}
+
+
+int os_gmtime(os_time_t t, struct os_tm *tm)
+{
+	struct tm *tm2;
+	time_t t2 = t;
+
+	tm2 = gmtime(&t2);
+	if (tm2 == NULL)
+		return -1;
+	tm->sec = tm2->tm_sec;
+	tm->min = tm2->tm_min;
+	tm->hour = tm2->tm_hour;
+	tm->day = tm2->tm_mday;
+	tm->month = tm2->tm_mon + 1;
+	tm->year = tm2->tm_year + 1900;
+	return 0;
+}
+
+
+#ifdef __APPLE__
+#include <fcntl.h>
+static int os_daemon(int nochdir, int noclose)
+{
+	int devnull;
+
+	if (chdir("/") < 0)
+		return -1;
+
+	devnull = open("/dev/null", O_RDWR);
+	if (devnull < 0)
+		return -1;
+
+	if (dup2(devnull, STDIN_FILENO) < 0) {
+		close(devnull);
+		return -1;
+	}
+
+	if (dup2(devnull, STDOUT_FILENO) < 0) {
+		close(devnull);
+		return -1;
+	}
+
+	if (dup2(devnull, STDERR_FILENO) < 0) {
+		close(devnull);
+		return -1;
+	}
+
+	return 0;
+}
+#else /* __APPLE__ */
+#define os_daemon daemon
+#endif /* __APPLE__ */
+
+
+int os_daemonize(const char *pid_file)
+{
+#ifdef __uClinux__
+	return -1;
+#else /* defined(__uClinux__) */
+	if (os_daemon(0, 0)) {
+		perror("daemon");
+		return -1;
+	}
+
+	if (pid_file) {
+		FILE *f = fopen(pid_file, "w");
+		if (f) {
+			fprintf(f, "%u\n", getpid());
+			fclose(f);
+		}
+	}
+
+	return -0;
+#endif /* defined(__uClinux__) */
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+	if (pid_file)
+		unlink(pid_file);
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+	FILE *f;
+	size_t rc;
+
+	f = fopen("/dev/urandom", "rb");
+	if (f == NULL) {
+		printf("Could not open /dev/urandom.\n");
+		return -1;
+	}
+
+	rc = fread(buf, 1, len, f);
+	fclose(f);
+
+	return rc != len ? -1 : 0;
+}
+
+
+unsigned long os_random(void)
+{
+	return random();
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+	char *buf = NULL, *cwd, *ret;
+	size_t len = 128, cwd_len, rel_len, ret_len;
+	int last_errno;
+
+	if (rel_path[0] == '/')
+		return os_strdup(rel_path);
+
+	for (;;) {
+		buf = os_malloc(len);
+		if (buf == NULL)
+			return NULL;
+		cwd = getcwd(buf, len);
+		if (cwd == NULL) {
+			last_errno = errno;
+			os_free(buf);
+			if (last_errno != ERANGE)
+				return NULL;
+			len *= 2;
+			if (len > 2000)
+				return NULL;
+		} else {
+			buf[len - 1] = '\0';
+			break;
+		}
+	}
+
+	cwd_len = os_strlen(cwd);
+	rel_len = os_strlen(rel_path);
+	ret_len = cwd_len + 1 + rel_len + 1;
+	ret = os_malloc(ret_len);
+	if (ret) {
+		os_memcpy(ret, cwd, cwd_len);
+		ret[cwd_len] = '/';
+		os_memcpy(ret + cwd_len + 1, rel_path, rel_len);
+		ret[ret_len - 1] = '\0';
+	}
+	os_free(buf);
+	return ret;
+}
+
+
+int os_program_init(void)
+{
+#ifdef ANDROID
+	/*
+	 * We ignore errors here since errors are normal if we
+	 * are already running as non-root.
+	 */
+	gid_t groups[] = { AID_INET, AID_WIFI, AID_KEYSTORE };
+	struct __user_cap_header_struct header;
+	struct __user_cap_data_struct cap;
+
+	setgroups(sizeof(groups)/sizeof(groups[0]), groups);
+
+	prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0);
+
+	setgid(AID_WIFI);
+	setuid(AID_WIFI);
+
+	header.version = _LINUX_CAPABILITY_VERSION;
+	header.pid = 0;
+	cap.effective = cap.permitted =
+		(1 << CAP_NET_ADMIN) | (1 << CAP_NET_RAW);
+	cap.inheritable = 0;
+	capset(&header, &cap);
+#endif /* ANDROID */
+
+#ifdef WPA_TRACE
+	dl_list_init(&alloc_list);
+#endif /* WPA_TRACE */
+	return 0;
+}
+
+
+void os_program_deinit(void)
+{
+#ifdef WPA_TRACE
+	struct os_alloc_trace *a;
+	unsigned long total = 0;
+	dl_list_for_each(a, &alloc_list, struct os_alloc_trace, list) {
+		total += a->len;
+		if (a->magic != ALLOC_MAGIC) {
+			wpa_printf(MSG_INFO, "MEMLEAK[%p]: invalid magic 0x%x "
+				   "len %lu",
+				   a, a->magic, (unsigned long) a->len);
+			continue;
+		}
+		wpa_printf(MSG_INFO, "MEMLEAK[%p]: len %lu",
+			   a, (unsigned long) a->len);
+		wpa_trace_dump("memleak", a);
+	}
+	if (total)
+		wpa_printf(MSG_INFO, "MEMLEAK: total %lu bytes",
+			   (unsigned long) total);
+#endif /* WPA_TRACE */
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+	return setenv(name, value, overwrite);
+}
+
+
+int os_unsetenv(const char *name)
+{
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
+    defined(__OpenBSD__)
+	unsetenv(name);
+	return 0;
+#else
+	return unsetenv(name);
+#endif
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+	FILE *f;
+	char *buf;
+	long pos;
+
+	f = fopen(name, "rb");
+	if (f == NULL)
+		return NULL;
+
+	if (fseek(f, 0, SEEK_END) < 0 || (pos = ftell(f)) < 0) {
+		fclose(f);
+		return NULL;
+	}
+	*len = pos;
+	if (fseek(f, 0, SEEK_SET) < 0) {
+		fclose(f);
+		return NULL;
+	}
+
+	buf = os_malloc(*len);
+	if (buf == NULL) {
+		fclose(f);
+		return NULL;
+	}
+
+	if (fread(buf, 1, *len, f) != *len) {
+		fclose(f);
+		os_free(buf);
+		return NULL;
+	}
+
+	fclose(f);
+
+	return buf;
+}
+
+
+#ifndef WPA_TRACE
+void * os_zalloc(size_t size)
+{
+	return calloc(1, size);
+}
+#endif /* WPA_TRACE */
+
+
+size_t os_strlcpy(char *dest, const char *src, size_t siz)
+{
+	const char *s = src;
+	size_t left = siz;
+
+	if (left) {
+		/* Copy string up to the maximum size of the dest buffer */
+		while (--left != 0) {
+			if ((*dest++ = *s++) == '\0')
+				break;
+		}
+	}
+
+	if (left == 0) {
+		/* Not enough room for the string; force NUL-termination */
+		if (siz != 0)
+			*dest = '\0';
+		while (*s++)
+			; /* determine total src string length */
+	}
+
+	return s - src - 1;
+}
+
+
+#ifdef WPA_TRACE
+
+void * os_malloc(size_t size)
+{
+	struct os_alloc_trace *a;
+	a = malloc(sizeof(*a) + size);
+	if (a == NULL)
+		return NULL;
+	a->magic = ALLOC_MAGIC;
+	dl_list_add(&alloc_list, &a->list);
+	a->len = size;
+	wpa_trace_record(a);
+	return a + 1;
+}
+
+
+void * os_realloc(void *ptr, size_t size)
+{
+	struct os_alloc_trace *a;
+	size_t copy_len;
+	void *n;
+
+	if (ptr == NULL)
+		return os_malloc(size);
+
+	a = (struct os_alloc_trace *) ptr - 1;
+	if (a->magic != ALLOC_MAGIC) {
+		wpa_printf(MSG_INFO, "REALLOC[%p]: invalid magic 0x%x%s",
+			   a, a->magic,
+			   a->magic == FREED_MAGIC ? " (already freed)" : "");
+		wpa_trace_show("Invalid os_realloc() call");
+		abort();
+	}
+	n = os_malloc(size);
+	if (n == NULL)
+		return NULL;
+	copy_len = a->len;
+	if (copy_len > size)
+		copy_len = size;
+	os_memcpy(n, a + 1, copy_len);
+	os_free(ptr);
+	return n;
+}
+
+
+void os_free(void *ptr)
+{
+	struct os_alloc_trace *a;
+
+	if (ptr == NULL)
+		return;
+	a = (struct os_alloc_trace *) ptr - 1;
+	if (a->magic != ALLOC_MAGIC) {
+		wpa_printf(MSG_INFO, "FREE[%p]: invalid magic 0x%x%s",
+			   a, a->magic,
+			   a->magic == FREED_MAGIC ? " (already freed)" : "");
+		wpa_trace_show("Invalid os_free() call");
+		abort();
+	}
+	dl_list_del(&a->list);
+	a->magic = FREED_MAGIC;
+
+	wpa_trace_check_ref(ptr);
+	free(a);
+}
+
+
+void * os_zalloc(size_t size)
+{
+	void *ptr = os_malloc(size);
+	if (ptr)
+		os_memset(ptr, 0, size);
+	return ptr;
+}
+
+
+char * os_strdup(const char *s)
+{
+	size_t len;
+	char *d;
+	len = os_strlen(s);
+	d = os_malloc(len + 1);
+	if (d == NULL)
+		return NULL;
+	os_memcpy(d, s, len);
+	d[len] = '\0';
+	return d;
+}
+
+#endif /* WPA_TRACE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/pcsc_funcs.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,49 @@
+/*
+ * WPA Supplicant / PC/SC smartcard interface for USIM, GSM SIM
+ * Copyright (c) 2004-2006, 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PCSC_FUNCS_H
+#define PCSC_FUNCS_H
+
+typedef enum {
+	SCARD_GSM_SIM_ONLY,
+	SCARD_USIM_ONLY,
+	SCARD_TRY_BOTH
+} scard_sim_type;
+
+
+#ifdef PCSC_FUNCS
+struct scard_data * scard_init(scard_sim_type sim_type, const char *reader);
+void scard_deinit(struct scard_data *scard);
+
+int scard_set_pin(struct scard_data *scard, const char *pin);
+int scard_get_imsi(struct scard_data *scard, char *imsi, size_t *len);
+int scard_get_mnc_len(struct scard_data *scard);
+int scard_gsm_auth(struct scard_data *scard, const unsigned char *_rand,
+		   unsigned char *sres, unsigned char *kc);
+int scard_umts_auth(struct scard_data *scard, const unsigned char *_rand,
+		    const unsigned char *autn,
+		    unsigned char *res, size_t *res_len,
+		    unsigned char *ik, unsigned char *ck, unsigned char *auts);
+int scard_get_pin_retry_counter(struct scard_data *scard);
+int scard_supports_umts(struct scard_data *scard);
+
+#else /* PCSC_FUNCS */
+
+#define scard_init(s, r) NULL
+#define scard_deinit(s) do { } while (0)
+#define scard_set_pin(s, p) -1
+#define scard_get_imsi(s, i, l) -1
+#define scard_get_mnc_len(s) -1
+#define scard_gsm_auth(s, r, s2, k) -1
+#define scard_umts_auth(s, r, a, r2, rl, i, c, a2) -1
+#define scard_get_pin_retry_counter(s) -1
+#define scard_supports_umts(s) 0
+
+#endif /* PCSC_FUNCS */
+
+#endif /* PCSC_FUNCS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/state_machine.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,138 @@
+/*
+ * wpa_supplicant/hostapd - State machine definitions
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file includes a set of pre-processor macros that can be used to
+ * implement a state machine. In addition to including this header file, each
+ * file implementing a state machine must define STATE_MACHINE_DATA to be the
+ * data structure including state variables (enum machine_state,
+ * Boolean changed), and STATE_MACHINE_DEBUG_PREFIX to be a string that is used
+ * as a prefix for all debug messages. If SM_ENTRY_MA macro is used to define
+ * a group of state machines with shared data structure, STATE_MACHINE_ADDR
+ * needs to be defined to point to the MAC address used in debug output.
+ * SM_ENTRY_M macro can be used to define similar group of state machines
+ * without this additional debug info.
+ */
+
+#ifndef STATE_MACHINE_H
+#define STATE_MACHINE_H
+
+/**
+ * SM_STATE - Declaration of a state machine function
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro is used to declare a state machine function. It is used in place
+ * of a C function definition to declare functions to be run when the state is
+ * entered by calling SM_ENTER or SM_ENTER_GLOBAL.
+ */
+#define SM_STATE(machine, state) \
+static void sm_ ## machine ## _ ## state ## _Enter(STATE_MACHINE_DATA *sm, \
+	int global)
+
+/**
+ * SM_ENTRY - State machine function entry point
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro is used inside each state machine function declared with
+ * SM_STATE. SM_ENTRY should be in the beginning of the function body, but
+ * after declaration of possible local variables. This macro prints debug
+ * information about state transition and update the state machine state.
+ */
+#define SM_ENTRY(machine, state) \
+if (!global || sm->machine ## _state != machine ## _ ## state) { \
+	sm->changed = TRUE; \
+	wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " #machine \
+		   " entering state " #state); \
+} \
+sm->machine ## _state = machine ## _ ## state;
+
+/**
+ * SM_ENTRY_M - State machine function entry point for state machine group
+ * @machine: State machine name
+ * @_state: State machine state
+ * @data: State variable prefix (full variable: prefix_state)
+ *
+ * This macro is like SM_ENTRY, but for state machine groups that use a shared
+ * data structure for more than one state machine. Both machine and prefix
+ * parameters are set to "sub-state machine" name. prefix is used to allow more
+ * than one state variable to be stored in the same data structure.
+ */
+#define SM_ENTRY_M(machine, _state, data) \
+if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \
+	sm->changed = TRUE; \
+	wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " \
+		   #machine " entering state " #_state); \
+} \
+sm->data ## _ ## state = machine ## _ ## _state;
+
+/**
+ * SM_ENTRY_MA - State machine function entry point for state machine group
+ * @machine: State machine name
+ * @_state: State machine state
+ * @data: State variable prefix (full variable: prefix_state)
+ *
+ * This macro is like SM_ENTRY_M, but a MAC address is included in debug
+ * output. STATE_MACHINE_ADDR has to be defined to point to the MAC address to
+ * be included in debug.
+ */
+#define SM_ENTRY_MA(machine, _state, data) \
+if (!global || sm->data ## _ ## state != machine ## _ ## _state) { \
+	sm->changed = TRUE; \
+	wpa_printf(MSG_DEBUG, STATE_MACHINE_DEBUG_PREFIX ": " MACSTR " " \
+		   #machine " entering state " #_state, \
+		   MAC2STR(STATE_MACHINE_ADDR)); \
+} \
+sm->data ## _ ## state = machine ## _ ## _state;
+
+/**
+ * SM_ENTER - Enter a new state machine state
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro expands to a function call to a state machine function defined
+ * with SM_STATE macro. SM_ENTER is used in a state machine step function to
+ * move the state machine to a new state.
+ */
+#define SM_ENTER(machine, state) \
+sm_ ## machine ## _ ## state ## _Enter(sm, 0)
+
+/**
+ * SM_ENTER_GLOBAL - Enter a new state machine state based on global rule
+ * @machine: State machine name
+ * @state: State machine state
+ *
+ * This macro is like SM_ENTER, but this is used when entering a new state
+ * based on a global (not specific to any particular state) rule. A separate
+ * macro is used to avoid unwanted debug message floods when the same global
+ * rule is forcing a state machine to remain in on state.
+ */
+#define SM_ENTER_GLOBAL(machine, state) \
+sm_ ## machine ## _ ## state ## _Enter(sm, 1)
+
+/**
+ * SM_STEP - Declaration of a state machine step function
+ * @machine: State machine name
+ *
+ * This macro is used to declare a state machine step function. It is used in
+ * place of a C function definition to declare a function that is used to move
+ * state machine to a new state based on state variables. This function uses
+ * SM_ENTER and SM_ENTER_GLOBAL macros to enter new state.
+ */
+#define SM_STEP(machine) \
+static void sm_ ## machine ## _Step(STATE_MACHINE_DATA *sm)
+
+/**
+ * SM_STEP_RUN - Call the state machine step function
+ * @machine: State machine name
+ *
+ * This macro expands to a function call to a state machine step function
+ * defined with SM_STEP macro.
+ */
+#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
+
+#endif /* STATE_MACHINE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/trace.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,68 @@
+/*
+ * Backtrace debugging
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TRACE_H
+#define TRACE_H
+
+#define WPA_TRACE_LEN 16
+
+#ifdef WPA_TRACE
+#include <execinfo.h>
+
+#include "list.h"
+
+#define WPA_TRACE_INFO void *btrace[WPA_TRACE_LEN]; int btrace_num;
+
+struct wpa_trace_ref {
+	struct dl_list list;
+	const void *addr;
+	WPA_TRACE_INFO
+};
+#define WPA_TRACE_REF(name) struct wpa_trace_ref wpa_trace_ref_##name
+
+#define wpa_trace_dump(title, ptr) \
+	wpa_trace_dump_func((title), (ptr)->btrace, (ptr)->btrace_num)
+void wpa_trace_dump_func(const char *title, void **btrace, int btrace_num);
+#define wpa_trace_record(ptr) \
+	(ptr)->btrace_num = backtrace((ptr)->btrace, WPA_TRACE_LEN)
+void wpa_trace_show(const char *title);
+#define wpa_trace_add_ref(ptr, name, addr) \
+	wpa_trace_add_ref_func(&(ptr)->wpa_trace_ref_##name, (addr))
+void wpa_trace_add_ref_func(struct wpa_trace_ref *ref, const void *addr);
+#define wpa_trace_remove_ref(ptr, name, addr)	\
+	do { \
+		if ((addr)) \
+			dl_list_del(&(ptr)->wpa_trace_ref_##name.list); \
+	} while (0)
+void wpa_trace_check_ref(const void *addr);
+
+#else /* WPA_TRACE */
+
+#define WPA_TRACE_INFO
+#define WPA_TRACE_REF(n)
+#define wpa_trace_dump(title, ptr) do { } while (0)
+#define wpa_trace_record(ptr) do { } while (0)
+#define wpa_trace_show(title) do { } while (0)
+#define wpa_trace_add_ref(ptr, name, addr) do { } while (0)
+#define wpa_trace_remove_ref(ptr, name, addr) do { } while (0)
+#define wpa_trace_check_ref(addr) do { } while (0)
+
+#endif /* WPA_TRACE */
+
+
+#ifdef WPA_TRACE_BFD
+
+void wpa_trace_dump_funcname(const char *title, void *pc);
+
+#else /* WPA_TRACE_BFD */
+
+#define wpa_trace_dump_funcname(title, pc) do { } while (0)
+
+#endif /* WPA_TRACE_BFD */
+
+#endif /* TRACE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/uuid.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,18 @@
+/*
+ * Universally Unique IDentifier (UUID)
+ * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef UUID_H
+#define UUID_H
+
+#define UUID_LEN 16
+
+int uuid_str2bin(const char *str, u8 *bin);
+int uuid_bin2str(const u8 *bin, char *str, size_t max_len);
+int is_nil_uuid(const u8 *uuid);
+
+#endif /* UUID_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/wpa_debug.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,688 @@
+/*
+ * wpa_supplicant/hostapd / Debug prints
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+
+#ifdef CONFIG_DEBUG_SYSLOG
+#include <syslog.h>
+
+static int wpa_debug_syslog = 0;
+#endif /* CONFIG_DEBUG_SYSLOG */
+
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+
+static FILE *wpa_debug_tracing_file = NULL;
+
+#define WPAS_TRACE_PFX "wpas <%d>: "
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
+
+int wpa_debug_level = MSG_INFO;
+int wpa_debug_show_keys = 0;
+int wpa_debug_timestamp = 0;
+
+
+#ifdef CONFIG_ANDROID_LOG
+
+#include <android/log.h>
+
+#ifndef ANDROID_LOG_NAME
+#define ANDROID_LOG_NAME	"wpa_supplicant"
+#endif /* ANDROID_LOG_NAME */
+
+static int wpa_to_android_level(int level)
+{
+	if (level == MSG_ERROR)
+		return ANDROID_LOG_ERROR;
+	if (level == MSG_WARNING)
+		return ANDROID_LOG_WARN;
+	if (level == MSG_INFO)
+		return ANDROID_LOG_INFO;
+	return ANDROID_LOG_DEBUG;
+}
+
+#endif /* CONFIG_ANDROID_LOG */
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+
+#ifdef CONFIG_DEBUG_FILE
+static FILE *out_file = NULL;
+#endif /* CONFIG_DEBUG_FILE */
+
+
+void wpa_debug_print_timestamp(void)
+{
+#ifndef CONFIG_ANDROID_LOG
+	struct os_time tv;
+
+	if (!wpa_debug_timestamp)
+		return;
+
+	os_get_time(&tv);
+#ifdef CONFIG_DEBUG_FILE
+	if (out_file) {
+		fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
+			(unsigned int) tv.usec);
+	} else
+#endif /* CONFIG_DEBUG_FILE */
+	printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
+#endif /* CONFIG_ANDROID_LOG */
+}
+
+
+#ifdef CONFIG_DEBUG_SYSLOG
+#ifndef LOG_HOSTAPD
+#define LOG_HOSTAPD LOG_DAEMON
+#endif /* LOG_HOSTAPD */
+
+void wpa_debug_open_syslog(void)
+{
+	openlog("wpa_supplicant", LOG_PID | LOG_NDELAY, LOG_HOSTAPD);
+	wpa_debug_syslog++;
+}
+
+
+void wpa_debug_close_syslog(void)
+{
+	if (wpa_debug_syslog)
+		closelog();
+}
+
+
+static int syslog_priority(int level)
+{
+	switch (level) {
+	case MSG_MSGDUMP:
+	case MSG_DEBUG:
+		return LOG_DEBUG;
+	case MSG_INFO:
+		return LOG_NOTICE;
+	case MSG_WARNING:
+		return LOG_WARNING;
+	case MSG_ERROR:
+		return LOG_ERR;
+	}
+	return LOG_INFO;
+}
+#endif /* CONFIG_DEBUG_SYSLOG */
+
+
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+
+int wpa_debug_open_linux_tracing(void)
+{
+	int mounts, trace_fd;
+	char buf[4096] = {};
+	ssize_t buflen;
+	char *line, *tmp1, *path = NULL;
+
+	mounts = open("/proc/mounts", O_RDONLY);
+	if (mounts < 0) {
+		printf("no /proc/mounts\n");
+		return -1;
+	}
+
+	buflen = read(mounts, buf, sizeof(buf) - 1);
+	close(mounts);
+	if (buflen < 0) {
+		printf("failed to read /proc/mounts\n");
+		return -1;
+	}
+
+	line = strtok_r(buf, "\n", &tmp1);
+	while (line) {
+		char *tmp2, *tmp_path, *fstype;
+		/* "<dev> <mountpoint> <fs type> ..." */
+		strtok_r(line, " ", &tmp2);
+		tmp_path = strtok_r(NULL, " ", &tmp2);
+		fstype = strtok_r(NULL, " ", &tmp2);
+		if (strcmp(fstype, "debugfs") == 0) {
+			path = tmp_path;
+			break;
+		}
+
+		line = strtok_r(NULL, "\n", &tmp1);
+	}
+
+	if (path == NULL) {
+		printf("debugfs mountpoint not found\n");
+		return -1;
+	}
+
+	snprintf(buf, sizeof(buf) - 1, "%s/tracing/trace_marker", path);
+
+	trace_fd = open(buf, O_WRONLY);
+	if (trace_fd < 0) {
+		printf("failed to open trace_marker file\n");
+		return -1;
+	}
+	wpa_debug_tracing_file = fdopen(trace_fd, "w");
+	if (wpa_debug_tracing_file == NULL) {
+		close(trace_fd);
+		printf("failed to fdopen()\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void wpa_debug_close_linux_tracing(void)
+{
+	if (wpa_debug_tracing_file == NULL)
+		return;
+	fclose(wpa_debug_tracing_file);
+	wpa_debug_tracing_file = NULL;
+}
+
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
+
+/**
+ * wpa_printf - conditional printf
+ * @level: priority level (MSG_*) of the message
+ * @fmt: printf format string, followed by optional arguments
+ *
+ * This function is used to print conditional debugging and error messages. The
+ * output may be directed to stdout, stderr, and/or syslog based on
+ * configuration.
+ *
+ * Note: New line '\n' is added to the end of the text when printing to stdout.
+ */
+void wpa_printf(int level, const char *fmt, ...)
+{
+	va_list ap;
+
+	va_start(ap, fmt);
+	if (level >= wpa_debug_level) {
+#ifdef CONFIG_ANDROID_LOG
+		__android_log_vprint(wpa_to_android_level(level),
+				     ANDROID_LOG_NAME, fmt, ap);
+#else /* CONFIG_ANDROID_LOG */
+#ifdef CONFIG_DEBUG_SYSLOG
+		if (wpa_debug_syslog) {
+			vsyslog(syslog_priority(level), fmt, ap);
+		} else {
+#endif /* CONFIG_DEBUG_SYSLOG */
+		wpa_debug_print_timestamp();
+#ifdef CONFIG_DEBUG_FILE
+		if (out_file) {
+			vfprintf(out_file, fmt, ap);
+			fprintf(out_file, "\n");
+		} else {
+#endif /* CONFIG_DEBUG_FILE */
+		vprintf(fmt, ap);
+		printf("\n");
+#ifdef CONFIG_DEBUG_FILE
+		}
+#endif /* CONFIG_DEBUG_FILE */
+#ifdef CONFIG_DEBUG_SYSLOG
+		}
+#endif /* CONFIG_DEBUG_SYSLOG */
+#endif /* CONFIG_ANDROID_LOG */
+	}
+	va_end(ap);
+
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+	if (wpa_debug_tracing_file != NULL) {
+		va_start(ap, fmt);
+		fprintf(wpa_debug_tracing_file, WPAS_TRACE_PFX, level);
+		vfprintf(wpa_debug_tracing_file, fmt, ap);
+		fprintf(wpa_debug_tracing_file, "\n");
+		fflush(wpa_debug_tracing_file);
+		va_end(ap);
+	}
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+}
+
+
+static void _wpa_hexdump(int level, const char *title, const u8 *buf,
+			 size_t len, int show)
+{
+	size_t i;
+
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+	if (wpa_debug_tracing_file != NULL) {
+		fprintf(wpa_debug_tracing_file,
+			WPAS_TRACE_PFX "%s - hexdump(len=%lu):",
+			level, title, (unsigned long) len);
+		if (buf == NULL) {
+			fprintf(wpa_debug_tracing_file, " [NULL]\n");
+		} else if (!show) {
+			fprintf(wpa_debug_tracing_file, " [REMOVED]\n");
+		} else {
+			for (i = 0; i < len; i++)
+				fprintf(wpa_debug_tracing_file,
+					" %02x", buf[i]);
+		}
+		fflush(wpa_debug_tracing_file);
+	}
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
+	if (level < wpa_debug_level)
+		return;
+#ifdef CONFIG_ANDROID_LOG
+	{
+		const char *display;
+		char *strbuf = NULL;
+		size_t slen = len;
+		if (buf == NULL) {
+			display = " [NULL]";
+		} else if (len == 0) {
+			display = "";
+		} else if (show && len) {
+			/* Limit debug message length for Android log */
+			if (slen > 32)
+				slen = 32;
+			strbuf = os_malloc(1 + 3 * slen);
+			if (strbuf == NULL) {
+				wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to "
+					   "allocate message buffer");
+				return;
+			}
+
+			for (i = 0; i < slen; i++)
+				os_snprintf(&strbuf[i * 3], 4, " %02x",
+					    buf[i]);
+
+			display = strbuf;
+		} else {
+			display = " [REMOVED]";
+		}
+
+		__android_log_print(wpa_to_android_level(level),
+				    ANDROID_LOG_NAME,
+				    "%s - hexdump(len=%lu):%s%s",
+				    title, (long unsigned int) len, display,
+				    len > slen ? " ..." : "");
+		os_free(strbuf);
+		return;
+	}
+#else /* CONFIG_ANDROID_LOG */
+#ifdef CONFIG_DEBUG_SYSLOG
+	if (wpa_debug_syslog) {
+		const char *display;
+		char *strbuf = NULL;
+
+		if (buf == NULL) {
+			display = " [NULL]";
+		} else if (len == 0) {
+			display = "";
+		} else if (show && len) {
+			strbuf = os_malloc(1 + 3 * len);
+			if (strbuf == NULL) {
+				wpa_printf(MSG_ERROR, "wpa_hexdump: Failed to "
+					   "allocate message buffer");
+				return;
+			}
+
+			for (i = 0; i < len; i++)
+				os_snprintf(&strbuf[i * 3], 4, " %02x",
+					    buf[i]);
+
+			display = strbuf;
+		} else {
+			display = " [REMOVED]";
+		}
+
+		syslog(syslog_priority(level), "%s - hexdump(len=%lu):%s",
+		       title, (unsigned long) len, display);
+		os_free(strbuf);
+		return;
+	}
+#endif /* CONFIG_DEBUG_SYSLOG */
+	wpa_debug_print_timestamp();
+#ifdef CONFIG_DEBUG_FILE
+	if (out_file) {
+		fprintf(out_file, "%s - hexdump(len=%lu):",
+			title, (unsigned long) len);
+		if (buf == NULL) {
+			fprintf(out_file, " [NULL]");
+		} else if (show) {
+			for (i = 0; i < len; i++)
+				fprintf(out_file, " %02x", buf[i]);
+		} else {
+			fprintf(out_file, " [REMOVED]");
+		}
+		fprintf(out_file, "\n");
+	} else {
+#endif /* CONFIG_DEBUG_FILE */
+	printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
+	if (buf == NULL) {
+		printf(" [NULL]");
+	} else if (show) {
+		for (i = 0; i < len; i++)
+			printf(" %02x", buf[i]);
+	} else {
+		printf(" [REMOVED]");
+	}
+	printf("\n");
+#ifdef CONFIG_DEBUG_FILE
+	}
+#endif /* CONFIG_DEBUG_FILE */
+#endif /* CONFIG_ANDROID_LOG */
+}
+
+void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
+{
+	_wpa_hexdump(level, title, buf, len, 1);
+}
+
+
+void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len)
+{
+	_wpa_hexdump(level, title, buf, len, wpa_debug_show_keys);
+}
+
+
+static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
+			       size_t len, int show)
+{
+	size_t i, llen;
+	const u8 *pos = buf;
+	const size_t line_len = 16;
+
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+	if (wpa_debug_tracing_file != NULL) {
+		fprintf(wpa_debug_tracing_file,
+			WPAS_TRACE_PFX "%s - hexdump_ascii(len=%lu):",
+			level, title, (unsigned long) len);
+		if (buf == NULL) {
+			fprintf(wpa_debug_tracing_file, " [NULL]\n");
+		} else if (!show) {
+			fprintf(wpa_debug_tracing_file, " [REMOVED]\n");
+		} else {
+			/* can do ascii processing in userspace */
+			for (i = 0; i < len; i++)
+				fprintf(wpa_debug_tracing_file,
+					" %02x", buf[i]);
+		}
+		fflush(wpa_debug_tracing_file);
+	}
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
+	if (level < wpa_debug_level)
+		return;
+#ifdef CONFIG_ANDROID_LOG
+	_wpa_hexdump(level, title, buf, len, show);
+#else /* CONFIG_ANDROID_LOG */
+	wpa_debug_print_timestamp();
+#ifdef CONFIG_DEBUG_FILE
+	if (out_file) {
+		if (!show) {
+			fprintf(out_file,
+				"%s - hexdump_ascii(len=%lu): [REMOVED]\n",
+				title, (unsigned long) len);
+			return;
+		}
+		if (buf == NULL) {
+			fprintf(out_file,
+				"%s - hexdump_ascii(len=%lu): [NULL]\n",
+				title, (unsigned long) len);
+			return;
+		}
+		fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
+			title, (unsigned long) len);
+		while (len) {
+			llen = len > line_len ? line_len : len;
+			fprintf(out_file, "    ");
+			for (i = 0; i < llen; i++)
+				fprintf(out_file, " %02x", pos[i]);
+			for (i = llen; i < line_len; i++)
+				fprintf(out_file, "   ");
+			fprintf(out_file, "   ");
+			for (i = 0; i < llen; i++) {
+				if (isprint(pos[i]))
+					fprintf(out_file, "%c", pos[i]);
+				else
+					fprintf(out_file, "_");
+			}
+			for (i = llen; i < line_len; i++)
+				fprintf(out_file, " ");
+			fprintf(out_file, "\n");
+			pos += llen;
+			len -= llen;
+		}
+	} else {
+#endif /* CONFIG_DEBUG_FILE */
+	if (!show) {
+		printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
+		       title, (unsigned long) len);
+		return;
+	}
+	if (buf == NULL) {
+		printf("%s - hexdump_ascii(len=%lu): [NULL]\n",
+		       title, (unsigned long) len);
+		return;
+	}
+	printf("%s - hexdump_ascii(len=%lu):\n", title, (unsigned long) len);
+	while (len) {
+		llen = len > line_len ? line_len : len;
+		printf("    ");
+		for (i = 0; i < llen; i++)
+			printf(" %02x", pos[i]);
+		for (i = llen; i < line_len; i++)
+			printf("   ");
+		printf("   ");
+		for (i = 0; i < llen; i++) {
+			if (isprint(pos[i]))
+				printf("%c", pos[i]);
+			else
+				printf("_");
+		}
+		for (i = llen; i < line_len; i++)
+			printf(" ");
+		printf("\n");
+		pos += llen;
+		len -= llen;
+	}
+#ifdef CONFIG_DEBUG_FILE
+	}
+#endif /* CONFIG_DEBUG_FILE */
+#endif /* CONFIG_ANDROID_LOG */
+}
+
+
+void wpa_hexdump_ascii(int level, const char *title, const u8 *buf, size_t len)
+{
+	_wpa_hexdump_ascii(level, title, buf, len, 1);
+}
+
+
+void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
+			   size_t len)
+{
+	_wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
+}
+
+
+#ifdef CONFIG_DEBUG_FILE
+static char *last_path = NULL;
+#endif /* CONFIG_DEBUG_FILE */
+
+int wpa_debug_reopen_file(void)
+{
+#ifdef CONFIG_DEBUG_FILE
+	int rv;
+	if (last_path) {
+		char *tmp = os_strdup(last_path);
+		wpa_debug_close_file();
+		rv = wpa_debug_open_file(tmp);
+		os_free(tmp);
+	} else {
+		wpa_printf(MSG_ERROR, "Last-path was not set, cannot "
+			   "re-open log file.");
+		rv = -1;
+	}
+	return rv;
+#else /* CONFIG_DEBUG_FILE */
+	return 0;
+#endif /* CONFIG_DEBUG_FILE */
+}
+
+
+int wpa_debug_open_file(const char *path)
+{
+#ifdef CONFIG_DEBUG_FILE
+	if (!path)
+		return 0;
+
+	if (last_path == NULL || os_strcmp(last_path, path) != 0) {
+		/* Save our path to enable re-open */
+		os_free(last_path);
+		last_path = os_strdup(path);
+	}
+
+	out_file = fopen(path, "a");
+	if (out_file == NULL) {
+		wpa_printf(MSG_ERROR, "wpa_debug_open_file: Failed to open "
+			   "output file, using standard output");
+		return -1;
+	}
+#ifndef _WIN32
+	setvbuf(out_file, NULL, _IOLBF, 0);
+#endif /* _WIN32 */
+#endif /* CONFIG_DEBUG_FILE */
+	return 0;
+}
+
+
+void wpa_debug_close_file(void)
+{
+#ifdef CONFIG_DEBUG_FILE
+	if (!out_file)
+		return;
+	fclose(out_file);
+	out_file = NULL;
+	os_free(last_path);
+	last_path = NULL;
+#endif /* CONFIG_DEBUG_FILE */
+}
+
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+#ifndef CONFIG_NO_WPA_MSG
+static wpa_msg_cb_func wpa_msg_cb = NULL;
+
+void wpa_msg_register_cb(wpa_msg_cb_func func)
+{
+	wpa_msg_cb = func;
+}
+
+
+static wpa_msg_get_ifname_func wpa_msg_ifname_cb = NULL;
+
+void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func)
+{
+	wpa_msg_ifname_cb = func;
+}
+
+
+void wpa_msg(void *ctx, int level, const char *fmt, ...)
+{
+	va_list ap;
+	char *buf;
+	const int buflen = 2048;
+	int len;
+	char prefix[130];
+
+	buf = os_malloc(buflen);
+	if (buf == NULL) {
+		wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message "
+			   "buffer");
+		return;
+	}
+	va_start(ap, fmt);
+	prefix[0] = '\0';
+	if (wpa_msg_ifname_cb) {
+		const char *ifname = wpa_msg_ifname_cb(ctx);
+		if (ifname) {
+			int res = os_snprintf(prefix, sizeof(prefix), "%s: ",
+					      ifname);
+			if (res < 0 || res >= (int) sizeof(prefix))
+				prefix[0] = '\0';
+		}
+	}
+	len = vsnprintf(buf, buflen, fmt, ap);
+	va_end(ap);
+	wpa_printf(level, "%s%s", prefix, buf);
+	if (wpa_msg_cb)
+		wpa_msg_cb(ctx, level, buf, len);
+	os_free(buf);
+}
+
+
+void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
+{
+	va_list ap;
+	char *buf;
+	const int buflen = 2048;
+	int len;
+
+	if (!wpa_msg_cb)
+		return;
+
+	buf = os_malloc(buflen);
+	if (buf == NULL) {
+		wpa_printf(MSG_ERROR, "wpa_msg_ctrl: Failed to allocate "
+			   "message buffer");
+		return;
+	}
+	va_start(ap, fmt);
+	len = vsnprintf(buf, buflen, fmt, ap);
+	va_end(ap);
+	wpa_msg_cb(ctx, level, buf, len);
+	os_free(buf);
+}
+#endif /* CONFIG_NO_WPA_MSG */
+
+
+#ifndef CONFIG_NO_HOSTAPD_LOGGER
+static hostapd_logger_cb_func hostapd_logger_cb = NULL;
+
+void hostapd_logger_register_cb(hostapd_logger_cb_func func)
+{
+	hostapd_logger_cb = func;
+}
+
+
+void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
+		    const char *fmt, ...)
+{
+	va_list ap;
+	char *buf;
+	const int buflen = 2048;
+	int len;
+
+	buf = os_malloc(buflen);
+	if (buf == NULL) {
+		wpa_printf(MSG_ERROR, "hostapd_logger: Failed to allocate "
+			   "message buffer");
+		return;
+	}
+	va_start(ap, fmt);
+	len = vsnprintf(buf, buflen, fmt, ap);
+	va_end(ap);
+	if (hostapd_logger_cb)
+		hostapd_logger_cb(ctx, addr, module, level, buf, len);
+	else if (addr)
+		wpa_printf(MSG_DEBUG, "hostapd_logger: STA " MACSTR " - %s",
+			   MAC2STR(addr), buf);
+	else
+		wpa_printf(MSG_DEBUG, "hostapd_logger: %s", buf);
+	os_free(buf);
+}
+#endif /* CONFIG_NO_HOSTAPD_LOGGER */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/wpa_debug.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,291 @@
+/*
+ * wpa_supplicant/hostapd / Debug prints
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_DEBUG_H
+#define WPA_DEBUG_H
+
+#include "wpabuf.h"
+
+/* Debugging function - conditional printf and hex dump. Driver wrappers can
+ * use these for debugging purposes. */
+
+enum {
+	MSG_EXCESSIVE, MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR
+};
+
+#ifdef CONFIG_NO_STDOUT_DEBUG
+
+#define wpa_debug_print_timestamp() do { } while (0)
+#define wpa_printf(args...) do { } while (0)
+#define wpa_hexdump(l,t,b,le) do { } while (0)
+#define wpa_hexdump_buf(l,t,b) do { } while (0)
+#define wpa_hexdump_key(l,t,b,le) do { } while (0)
+#define wpa_hexdump_buf_key(l,t,b) do { } while (0)
+#define wpa_hexdump_ascii(l,t,b,le) do { } while (0)
+#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0)
+#define wpa_debug_open_file(p) do { } while (0)
+#define wpa_debug_close_file() do { } while (0)
+#define wpa_dbg(args...) do { } while (0)
+
+static inline int wpa_debug_reopen_file(void)
+{
+	return 0;
+}
+
+#else /* CONFIG_NO_STDOUT_DEBUG */
+
+int wpa_debug_open_file(const char *path);
+int wpa_debug_reopen_file(void);
+void wpa_debug_close_file(void);
+
+/**
+ * wpa_debug_printf_timestamp - Print timestamp for debug output
+ *
+ * This function prints a timestamp in seconds_from_1970.microsoconds
+ * format if debug output has been configured to include timestamps in debug
+ * messages.
+ */
+void wpa_debug_print_timestamp(void);
+
+/**
+ * wpa_printf - conditional printf
+ * @level: priority level (MSG_*) of the message
+ * @fmt: printf format string, followed by optional arguments
+ *
+ * This function is used to print conditional debugging and error messages. The
+ * output may be directed to stdout, stderr, and/or syslog based on
+ * configuration.
+ *
+ * Note: New line '\n' is added to the end of the text when printing to stdout.
+ */
+void wpa_printf(int level, const char *fmt, ...)
+PRINTF_FORMAT(2, 3);
+
+/**
+ * wpa_hexdump - conditional hex dump
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the buf
+ *
+ * This function is used to print conditional debugging and error messages. The
+ * output may be directed to stdout, stderr, and/or syslog based on
+ * configuration. The contents of buf is printed out has hex dump.
+ */
+void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len);
+
+static inline void wpa_hexdump_buf(int level, const char *title,
+				   const struct wpabuf *buf)
+{
+	wpa_hexdump(level, title, buf ? wpabuf_head(buf) : NULL,
+		    buf ? wpabuf_len(buf) : 0);
+}
+
+/**
+ * wpa_hexdump_key - conditional hex dump, hide keys
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the buf
+ *
+ * This function is used to print conditional debugging and error messages. The
+ * output may be directed to stdout, stderr, and/or syslog based on
+ * configuration. The contents of buf is printed out has hex dump. This works
+ * like wpa_hexdump(), but by default, does not include secret keys (passwords,
+ * etc.) in debug output.
+ */
+void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len);
+
+static inline void wpa_hexdump_buf_key(int level, const char *title,
+				       const struct wpabuf *buf)
+{
+	wpa_hexdump_key(level, title, buf ? wpabuf_head(buf) : NULL,
+			buf ? wpabuf_len(buf) : 0);
+}
+
+/**
+ * wpa_hexdump_ascii - conditional hex dump
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the buf
+ *
+ * This function is used to print conditional debugging and error messages. The
+ * output may be directed to stdout, stderr, and/or syslog based on
+ * configuration. The contents of buf is printed out has hex dump with both
+ * the hex numbers and ASCII characters (for printable range) are shown. 16
+ * bytes per line will be shown.
+ */
+void wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
+		       size_t len);
+
+/**
+ * wpa_hexdump_ascii_key - conditional hex dump, hide keys
+ * @level: priority level (MSG_*) of the message
+ * @title: title of for the message
+ * @buf: data buffer to be dumped
+ * @len: length of the buf
+ *
+ * This function is used to print conditional debugging and error messages. The
+ * output may be directed to stdout, stderr, and/or syslog based on
+ * configuration. The contents of buf is printed out has hex dump with both
+ * the hex numbers and ASCII characters (for printable range) are shown. 16
+ * bytes per line will be shown. This works like wpa_hexdump_ascii(), but by
+ * default, does not include secret keys (passwords, etc.) in debug output.
+ */
+void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
+			   size_t len);
+
+/*
+ * wpa_dbg() behaves like wpa_msg(), but it can be removed from build to reduce
+ * binary size. As such, it should be used with debugging messages that are not
+ * needed in the control interface while wpa_msg() has to be used for anything
+ * that needs to shown to control interface monitors.
+ */
+#define wpa_dbg(args...) wpa_msg(args)
+
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+#ifdef CONFIG_NO_WPA_MSG
+#define wpa_msg(args...) do { } while (0)
+#define wpa_msg_ctrl(args...) do { } while (0)
+#define wpa_msg_register_cb(f) do { } while (0)
+#define wpa_msg_register_ifname_cb(f) do { } while (0)
+#else /* CONFIG_NO_WPA_MSG */
+/**
+ * wpa_msg - Conditional printf for default target and ctrl_iface monitors
+ * @ctx: Pointer to context data; this is the ctx variable registered
+ *	with struct wpa_driver_ops::init()
+ * @level: priority level (MSG_*) of the message
+ * @fmt: printf format string, followed by optional arguments
+ *
+ * This function is used to print conditional debugging and error messages. The
+ * output may be directed to stdout, stderr, and/or syslog based on
+ * configuration. This function is like wpa_printf(), but it also sends the
+ * same message to all attached ctrl_iface monitors.
+ *
+ * Note: New line '\n' is added to the end of the text when printing to stdout.
+ */
+void wpa_msg(void *ctx, int level, const char *fmt, ...) PRINTF_FORMAT(3, 4);
+
+/**
+ * wpa_msg_ctrl - Conditional printf for ctrl_iface monitors
+ * @ctx: Pointer to context data; this is the ctx variable registered
+ *	with struct wpa_driver_ops::init()
+ * @level: priority level (MSG_*) of the message
+ * @fmt: printf format string, followed by optional arguments
+ *
+ * This function is used to print conditional debugging and error messages.
+ * This function is like wpa_msg(), but it sends the output only to the
+ * attached ctrl_iface monitors. In other words, it can be used for frequent
+ * events that do not need to be sent to syslog.
+ */
+void wpa_msg_ctrl(void *ctx, int level, const char *fmt, ...)
+PRINTF_FORMAT(3, 4);
+
+typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt,
+				size_t len);
+
+/**
+ * wpa_msg_register_cb - Register callback function for wpa_msg() messages
+ * @func: Callback function (%NULL to unregister)
+ */
+void wpa_msg_register_cb(wpa_msg_cb_func func);
+
+typedef const char * (*wpa_msg_get_ifname_func)(void *ctx);
+void wpa_msg_register_ifname_cb(wpa_msg_get_ifname_func func);
+
+#endif /* CONFIG_NO_WPA_MSG */
+
+#ifdef CONFIG_NO_HOSTAPD_LOGGER
+#define hostapd_logger(args...) do { } while (0)
+#define hostapd_logger_register_cb(f) do { } while (0)
+#else /* CONFIG_NO_HOSTAPD_LOGGER */
+void hostapd_logger(void *ctx, const u8 *addr, unsigned int module, int level,
+		    const char *fmt, ...) PRINTF_FORMAT(5, 6);
+
+typedef void (*hostapd_logger_cb_func)(void *ctx, const u8 *addr,
+				       unsigned int module, int level,
+				       const char *txt, size_t len);
+
+/**
+ * hostapd_logger_register_cb - Register callback function for hostapd_logger()
+ * @func: Callback function (%NULL to unregister)
+ */
+void hostapd_logger_register_cb(hostapd_logger_cb_func func);
+#endif /* CONFIG_NO_HOSTAPD_LOGGER */
+
+#define HOSTAPD_MODULE_IEEE80211	0x00000001
+#define HOSTAPD_MODULE_IEEE8021X	0x00000002
+#define HOSTAPD_MODULE_RADIUS		0x00000004
+#define HOSTAPD_MODULE_WPA		0x00000008
+#define HOSTAPD_MODULE_DRIVER		0x00000010
+#define HOSTAPD_MODULE_IAPP		0x00000020
+#define HOSTAPD_MODULE_MLME		0x00000040
+
+enum hostapd_logger_level {
+	HOSTAPD_LEVEL_DEBUG_VERBOSE = 0,
+	HOSTAPD_LEVEL_DEBUG = 1,
+	HOSTAPD_LEVEL_INFO = 2,
+	HOSTAPD_LEVEL_NOTICE = 3,
+	HOSTAPD_LEVEL_WARNING = 4
+};
+
+
+#ifdef CONFIG_DEBUG_SYSLOG
+
+void wpa_debug_open_syslog(void);
+void wpa_debug_close_syslog(void);
+
+#else /* CONFIG_DEBUG_SYSLOG */
+
+static inline void wpa_debug_open_syslog(void)
+{
+}
+
+static inline void wpa_debug_close_syslog(void)
+{
+}
+
+#endif /* CONFIG_DEBUG_SYSLOG */
+
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+
+int wpa_debug_open_linux_tracing(void);
+void wpa_debug_close_linux_tracing(void);
+
+#else /* CONFIG_DEBUG_LINUX_TRACING */
+
+static inline int wpa_debug_open_linux_tracing(void)
+{
+	return 0;
+}
+
+static inline void wpa_debug_close_linux_tracing(void)
+{
+}
+
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+
+
+#ifdef EAPOL_TEST
+#define WPA_ASSERT(a)						       \
+	do {							       \
+		if (!(a)) {					       \
+			printf("WPA_ASSERT FAILED '" #a "' "	       \
+			       "%s %s:%d\n",			       \
+			       __FUNCTION__, __FILE__, __LINE__);      \
+			exit(1);				       \
+		}						       \
+	} while (0)
+#else
+#define WPA_ASSERT(a) do { } while (0)
+#endif
+
+#endif /* WPA_DEBUG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/wpabuf.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,303 @@
+/*
+ * Dynamic data buffer
+ * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "trace.h"
+#include "wpabuf.h"
+
+#ifdef WPA_TRACE
+#define WPABUF_MAGIC 0x51a974e3
+
+struct wpabuf_trace {
+	unsigned int magic;
+};
+
+static struct wpabuf_trace * wpabuf_get_trace(const struct wpabuf *buf)
+{
+	return (struct wpabuf_trace *)
+		((const u8 *) buf - sizeof(struct wpabuf_trace));
+}
+#endif /* WPA_TRACE */
+
+
+static void wpabuf_overflow(const struct wpabuf *buf, size_t len)
+{
+#ifdef WPA_TRACE
+	struct wpabuf_trace *trace = wpabuf_get_trace(buf);
+	if (trace->magic != WPABUF_MAGIC) {
+		wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x",
+			   trace->magic);
+	}
+#endif /* WPA_TRACE */
+	wpa_printf(MSG_ERROR, "wpabuf %p (size=%lu used=%lu) overflow len=%lu",
+		   buf, (unsigned long) buf->size, (unsigned long) buf->used,
+		   (unsigned long) len);
+	wpa_trace_show("wpabuf overflow");
+	abort();
+}
+
+
+int wpabuf_resize(struct wpabuf **_buf, size_t add_len)
+{
+	struct wpabuf *buf = *_buf;
+#ifdef WPA_TRACE
+	struct wpabuf_trace *trace;
+#endif /* WPA_TRACE */
+
+	if (buf == NULL) {
+		*_buf = wpabuf_alloc(add_len);
+		return *_buf == NULL ? -1 : 0;
+	}
+
+#ifdef WPA_TRACE
+	trace = wpabuf_get_trace(buf);
+	if (trace->magic != WPABUF_MAGIC) {
+		wpa_printf(MSG_ERROR, "wpabuf: invalid magic %x",
+			   trace->magic);
+		wpa_trace_show("wpabuf_resize invalid magic");
+		abort();
+	}
+#endif /* WPA_TRACE */
+
+	if (buf->used + add_len > buf->size) {
+		unsigned char *nbuf;
+		if (buf->flags & WPABUF_FLAG_EXT_DATA) {
+			nbuf = os_realloc(buf->buf, buf->used + add_len);
+			if (nbuf == NULL)
+				return -1;
+			os_memset(nbuf + buf->used, 0, add_len);
+			buf->buf = nbuf;
+		} else {
+#ifdef WPA_TRACE
+			nbuf = os_realloc(trace, sizeof(struct wpabuf_trace) +
+					  sizeof(struct wpabuf) +
+					  buf->used + add_len);
+			if (nbuf == NULL)
+				return -1;
+			trace = (struct wpabuf_trace *) nbuf;
+			buf = (struct wpabuf *) (trace + 1);
+			os_memset(nbuf + sizeof(struct wpabuf_trace) +
+				  sizeof(struct wpabuf) + buf->used, 0,
+				  add_len);
+#else /* WPA_TRACE */
+			nbuf = os_realloc(buf, sizeof(struct wpabuf) +
+					  buf->used + add_len);
+			if (nbuf == NULL)
+				return -1;
+			buf = (struct wpabuf *) nbuf;
+			os_memset(nbuf + sizeof(struct wpabuf) + buf->used, 0,
+				  add_len);
+#endif /* WPA_TRACE */
+			buf->buf = (u8 *) (buf + 1);
+			*_buf = buf;
+		}
+		buf->size = buf->used + add_len;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpabuf_alloc - Allocate a wpabuf of the given size
+ * @len: Length for the allocated buffer
+ * Returns: Buffer to the allocated wpabuf or %NULL on failure
+ */
+struct wpabuf * wpabuf_alloc(size_t len)
+{
+#ifdef WPA_TRACE
+	struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) +
+					       sizeof(struct wpabuf) + len);
+	struct wpabuf *buf;
+	if (trace == NULL)
+		return NULL;
+	trace->magic = WPABUF_MAGIC;
+	buf = (struct wpabuf *) (trace + 1);
+#else /* WPA_TRACE */
+	struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf) + len);
+	if (buf == NULL)
+		return NULL;
+#endif /* WPA_TRACE */
+
+	buf->size = len;
+	buf->buf = (u8 *) (buf + 1);
+	return buf;
+}
+
+
+struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len)
+{
+#ifdef WPA_TRACE
+	struct wpabuf_trace *trace = os_zalloc(sizeof(struct wpabuf_trace) +
+					       sizeof(struct wpabuf));
+	struct wpabuf *buf;
+	if (trace == NULL)
+		return NULL;
+	trace->magic = WPABUF_MAGIC;
+	buf = (struct wpabuf *) (trace + 1);
+#else /* WPA_TRACE */
+	struct wpabuf *buf = os_zalloc(sizeof(struct wpabuf));
+	if (buf == NULL)
+		return NULL;
+#endif /* WPA_TRACE */
+
+	buf->size = len;
+	buf->used = len;
+	buf->buf = data;
+	buf->flags |= WPABUF_FLAG_EXT_DATA;
+
+	return buf;
+}
+
+
+struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len)
+{
+	struct wpabuf *buf = wpabuf_alloc(len);
+	if (buf)
+		wpabuf_put_data(buf, data, len);
+	return buf;
+}
+
+
+struct wpabuf * wpabuf_dup(const struct wpabuf *src)
+{
+	struct wpabuf *buf = wpabuf_alloc(wpabuf_len(src));
+	if (buf)
+		wpabuf_put_data(buf, wpabuf_head(src), wpabuf_len(src));
+	return buf;
+}
+
+
+/**
+ * wpabuf_free - Free a wpabuf
+ * @buf: wpabuf buffer
+ */
+void wpabuf_free(struct wpabuf *buf)
+{
+#ifdef WPA_TRACE
+	struct wpabuf_trace *trace;
+	if (buf == NULL)
+		return;
+	trace = wpabuf_get_trace(buf);
+	if (trace->magic != WPABUF_MAGIC) {
+		wpa_printf(MSG_ERROR, "wpabuf_free: invalid magic %x",
+			   trace->magic);
+		wpa_trace_show("wpabuf_free magic mismatch");
+		abort();
+	}
+	if (buf->flags & WPABUF_FLAG_EXT_DATA)
+		os_free(buf->buf);
+	os_free(trace);
+#else /* WPA_TRACE */
+	if (buf == NULL)
+		return;
+	if (buf->flags & WPABUF_FLAG_EXT_DATA)
+		os_free(buf->buf);
+	os_free(buf);
+#endif /* WPA_TRACE */
+}
+
+
+void * wpabuf_put(struct wpabuf *buf, size_t len)
+{
+	void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
+	buf->used += len;
+	if (buf->used > buf->size) {
+		wpabuf_overflow(buf, len);
+	}
+	return tmp;
+}
+
+
+/**
+ * wpabuf_concat - Concatenate two buffers into a newly allocated one
+ * @a: First buffer
+ * @b: Second buffer
+ * Returns: wpabuf with concatenated a + b data or %NULL on failure
+ *
+ * Both buffers a and b will be freed regardless of the return value. Input
+ * buffers can be %NULL which is interpreted as an empty buffer.
+ */
+struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b)
+{
+	struct wpabuf *n = NULL;
+	size_t len = 0;
+
+	if (b == NULL)
+		return a;
+
+	if (a)
+		len += wpabuf_len(a);
+	if (b)
+		len += wpabuf_len(b);
+
+	n = wpabuf_alloc(len);
+	if (n) {
+		if (a)
+			wpabuf_put_buf(n, a);
+		if (b)
+			wpabuf_put_buf(n, b);
+	}
+
+	wpabuf_free(a);
+	wpabuf_free(b);
+
+	return n;
+}
+
+
+/**
+ * wpabuf_zeropad - Pad buffer with 0x00 octets (prefix) to specified length
+ * @buf: Buffer to be padded
+ * @len: Length for the padded buffer
+ * Returns: wpabuf padded to len octets or %NULL on failure
+ *
+ * If buf is longer than len octets or of same size, it will be returned as-is.
+ * Otherwise a new buffer is allocated and prefixed with 0x00 octets followed
+ * by the source data. The source buffer will be freed on error, i.e., caller
+ * will only be responsible on freeing the returned buffer. If buf is %NULL,
+ * %NULL will be returned.
+ */
+struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len)
+{
+	struct wpabuf *ret;
+	size_t blen;
+
+	if (buf == NULL)
+		return NULL;
+
+	blen = wpabuf_len(buf);
+	if (blen >= len)
+		return buf;
+
+	ret = wpabuf_alloc(len);
+	if (ret) {
+		os_memset(wpabuf_put(ret, len - blen), 0, len - blen);
+		wpabuf_put_buf(ret, buf);
+	}
+	wpabuf_free(buf);
+
+	return ret;
+}
+
+
+void wpabuf_printf(struct wpabuf *buf, char *fmt, ...)
+{
+	va_list ap;
+	void *tmp = wpabuf_mhead_u8(buf) + wpabuf_len(buf);
+	int res;
+
+	va_start(ap, fmt);
+	res = vsnprintf(tmp, buf->size - buf->used, fmt, ap);
+	va_end(ap);
+	if (res < 0 || (size_t) res >= buf->size - buf->used)
+		wpabuf_overflow(buf, res);
+	buf->used += res;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/utils/wpabuf.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,162 @@
+/*
+ * Dynamic data buffer
+ * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPABUF_H
+#define WPABUF_H
+
+/* wpabuf::buf is a pointer to external data */
+#define WPABUF_FLAG_EXT_DATA BIT(0)
+
+/*
+ * Internal data structure for wpabuf. Please do not touch this directly from
+ * elsewhere. This is only defined in header file to allow inline functions
+ * from this file to access data.
+ */
+struct wpabuf {
+	size_t size; /* total size of the allocated buffer */
+	size_t used; /* length of data in the buffer */
+	u8 *buf; /* pointer to the head of the buffer */
+	unsigned int flags;
+	/* optionally followed by the allocated buffer */
+};
+
+
+int wpabuf_resize(struct wpabuf **buf, size_t add_len);
+struct wpabuf * wpabuf_alloc(size_t len);
+struct wpabuf * wpabuf_alloc_ext_data(u8 *data, size_t len);
+struct wpabuf * wpabuf_alloc_copy(const void *data, size_t len);
+struct wpabuf * wpabuf_dup(const struct wpabuf *src);
+void wpabuf_free(struct wpabuf *buf);
+void * wpabuf_put(struct wpabuf *buf, size_t len);
+struct wpabuf * wpabuf_concat(struct wpabuf *a, struct wpabuf *b);
+struct wpabuf * wpabuf_zeropad(struct wpabuf *buf, size_t len);
+void wpabuf_printf(struct wpabuf *buf, char *fmt, ...) PRINTF_FORMAT(2, 3);
+
+
+/**
+ * wpabuf_size - Get the currently allocated size of a wpabuf buffer
+ * @buf: wpabuf buffer
+ * Returns: Currently allocated size of the buffer
+ */
+static inline size_t wpabuf_size(const struct wpabuf *buf)
+{
+	return buf->size;
+}
+
+/**
+ * wpabuf_len - Get the current length of a wpabuf buffer data
+ * @buf: wpabuf buffer
+ * Returns: Currently used length of the buffer
+ */
+static inline size_t wpabuf_len(const struct wpabuf *buf)
+{
+	return buf->used;
+}
+
+/**
+ * wpabuf_tailroom - Get size of available tail room in the end of the buffer
+ * @buf: wpabuf buffer
+ * Returns: Tail room (in bytes) of available space in the end of the buffer
+ */
+static inline size_t wpabuf_tailroom(const struct wpabuf *buf)
+{
+	return buf->size - buf->used;
+}
+
+/**
+ * wpabuf_head - Get pointer to the head of the buffer data
+ * @buf: wpabuf buffer
+ * Returns: Pointer to the head of the buffer data
+ */
+static inline const void * wpabuf_head(const struct wpabuf *buf)
+{
+	return buf->buf;
+}
+
+static inline const u8 * wpabuf_head_u8(const struct wpabuf *buf)
+{
+	return wpabuf_head(buf);
+}
+
+/**
+ * wpabuf_mhead - Get modifiable pointer to the head of the buffer data
+ * @buf: wpabuf buffer
+ * Returns: Pointer to the head of the buffer data
+ */
+static inline void * wpabuf_mhead(struct wpabuf *buf)
+{
+	return buf->buf;
+}
+
+static inline u8 * wpabuf_mhead_u8(struct wpabuf *buf)
+{
+	return wpabuf_mhead(buf);
+}
+
+static inline void wpabuf_put_u8(struct wpabuf *buf, u8 data)
+{
+	u8 *pos = wpabuf_put(buf, 1);
+	*pos = data;
+}
+
+static inline void wpabuf_put_le16(struct wpabuf *buf, u16 data)
+{
+	u8 *pos = wpabuf_put(buf, 2);
+	WPA_PUT_LE16(pos, data);
+}
+
+static inline void wpabuf_put_le32(struct wpabuf *buf, u32 data)
+{
+	u8 *pos = wpabuf_put(buf, 4);
+	WPA_PUT_LE32(pos, data);
+}
+
+static inline void wpabuf_put_be16(struct wpabuf *buf, u16 data)
+{
+	u8 *pos = wpabuf_put(buf, 2);
+	WPA_PUT_BE16(pos, data);
+}
+
+static inline void wpabuf_put_be24(struct wpabuf *buf, u32 data)
+{
+	u8 *pos = wpabuf_put(buf, 3);
+	WPA_PUT_BE24(pos, data);
+}
+
+static inline void wpabuf_put_be32(struct wpabuf *buf, u32 data)
+{
+	u8 *pos = wpabuf_put(buf, 4);
+	WPA_PUT_BE32(pos, data);
+}
+
+static inline void wpabuf_put_data(struct wpabuf *buf, const void *data,
+				   size_t len)
+{
+	if (data)
+		os_memcpy(wpabuf_put(buf, len), data, len);
+}
+
+static inline void wpabuf_put_buf(struct wpabuf *dst,
+				  const struct wpabuf *src)
+{
+	wpabuf_put_data(dst, wpabuf_head(src), wpabuf_len(src));
+}
+
+static inline void wpabuf_set(struct wpabuf *buf, const void *data, size_t len)
+{
+	buf->buf = (u8 *) data;
+	buf->flags = WPABUF_FLAG_EXT_DATA;
+	buf->size = buf->used = len;
+}
+
+static inline void wpabuf_put_str(struct wpabuf *dst, const char *str)
+{
+	wpabuf_put_data(dst, str, os_strlen(str));
+}
+
+#endif /* WPABUF_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/wps/wps.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,968 @@
+/*
+ * Wi-Fi Protected Setup
+ * Copyright (c) 2007-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPS_H
+#define WPS_H
+
+#include "wps_defs.h"
+
+/**
+ * enum wsc_op_code - EAP-WSC OP-Code values
+ */
+enum wsc_op_code {
+	WSC_UPnP = 0 /* No OP Code in UPnP transport */,
+	WSC_Start = 0x01,
+	WSC_ACK = 0x02,
+	WSC_NACK = 0x03,
+	WSC_MSG = 0x04,
+	WSC_Done = 0x05,
+	WSC_FRAG_ACK = 0x06
+};
+
+struct wps_registrar;
+struct upnp_wps_device_sm;
+struct wps_er;
+struct wps_parse_attr;
+
+/**
+ * struct wps_credential - WPS Credential
+ * @ssid: SSID
+ * @ssid_len: Length of SSID
+ * @auth_type: Authentication Type (WPS_AUTH_OPEN, .. flags)
+ * @encr_type: Encryption Type (WPS_ENCR_NONE, .. flags)
+ * @key_idx: Key index
+ * @key: Key
+ * @key_len: Key length in octets
+ * @mac_addr: MAC address of the Credential receiver
+ * @cred_attr: Unparsed Credential attribute data (used only in cred_cb());
+ *	this may be %NULL, if not used
+ * @cred_attr_len: Length of cred_attr in octets
+ * @ap_channel: AP channel
+ */
+struct wps_credential {
+	u8 ssid[32];
+	size_t ssid_len;
+	u16 auth_type;
+	u16 encr_type;
+	u8 key_idx;
+	u8 key[64];
+	size_t key_len;
+	u8 mac_addr[ETH_ALEN];
+	const u8 *cred_attr;
+	size_t cred_attr_len;
+	u16 ap_channel;
+};
+
+#define WPS_DEV_TYPE_LEN 8
+#define WPS_DEV_TYPE_BUFSIZE 21
+#define WPS_SEC_DEV_TYPE_MAX_LEN 128
+/* maximum number of advertised WPS vendor extension attributes */
+#define MAX_WPS_VENDOR_EXTENSIONS 10
+/* maximum size of WPS Vendor extension attribute */
+#define WPS_MAX_VENDOR_EXT_LEN 1024
+/* maximum number of parsed WPS vendor extension attributes */
+#define MAX_WPS_PARSE_VENDOR_EXT 10
+
+/**
+ * struct wps_device_data - WPS Device Data
+ * @mac_addr: Device MAC address
+ * @device_name: Device Name (0..32 octets encoded in UTF-8)
+ * @manufacturer: Manufacturer (0..64 octets encoded in UTF-8)
+ * @model_name: Model Name (0..32 octets encoded in UTF-8)
+ * @model_number: Model Number (0..32 octets encoded in UTF-8)
+ * @serial_number: Serial Number (0..32 octets encoded in UTF-8)
+ * @pri_dev_type: Primary Device Type
+ * @sec_dev_type: Array of secondary device types
+ * @num_sec_dev_type: Number of secondary device types
+ * @os_version: OS Version
+ * @rf_bands: RF bands (WPS_RF_24GHZ, WPS_RF_50GHZ flags)
+ * @p2p: Whether the device is a P2P device
+ */
+struct wps_device_data {
+	u8 mac_addr[ETH_ALEN];
+	char *device_name;
+	char *manufacturer;
+	char *model_name;
+	char *model_number;
+	char *serial_number;
+	u8 pri_dev_type[WPS_DEV_TYPE_LEN];
+#define WPS_SEC_DEVICE_TYPES 5
+	u8 sec_dev_type[WPS_SEC_DEVICE_TYPES][WPS_DEV_TYPE_LEN];
+	u8 num_sec_dev_types;
+	u32 os_version;
+	u8 rf_bands;
+	u16 config_methods;
+	struct wpabuf *vendor_ext_m1;
+	struct wpabuf *vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+
+	int p2p;
+};
+
+/**
+ * struct wps_config - WPS configuration for a single registration protocol run
+ */
+struct wps_config {
+	/**
+	 * wps - Pointer to long term WPS context
+	 */
+	struct wps_context *wps;
+
+	/**
+	 * registrar - Whether this end is a Registrar
+	 */
+	int registrar;
+
+	/**
+	 * pin - Enrollee Device Password (%NULL for Registrar or PBC)
+	 */
+	const u8 *pin;
+
+	/**
+	 * pin_len - Length on pin in octets
+	 */
+	size_t pin_len;
+
+	/**
+	 * pbc - Whether this is protocol run uses PBC
+	 */
+	int pbc;
+
+	/**
+	 * assoc_wps_ie: (Re)AssocReq WPS IE (in AP; %NULL if not AP)
+	 */
+	const struct wpabuf *assoc_wps_ie;
+
+	/**
+	 * new_ap_settings - New AP settings (%NULL if not used)
+	 *
+	 * This parameter provides new AP settings when using a wireless
+	 * stations as a Registrar to configure the AP. %NULL means that AP
+	 * will not be reconfigured, i.e., the station will only learn the
+	 * current AP settings by using AP PIN.
+	 */
+	const struct wps_credential *new_ap_settings;
+
+	/**
+	 * peer_addr: MAC address of the peer in AP; %NULL if not AP
+	 */
+	const u8 *peer_addr;
+
+	/**
+	 * use_psk_key - Use PSK format key in Credential
+	 *
+	 * Force PSK format to be used instead of ASCII passphrase when
+	 * building Credential for an Enrollee. The PSK value is set in
+	 * struct wpa_context::psk.
+	 */
+	int use_psk_key;
+
+	/**
+	 * dev_pw_id - Device Password ID for Enrollee when PIN is used
+	 */
+	u16 dev_pw_id;
+
+	/**
+	 * p2p_dev_addr - P2P Device Address from (Re)Association Request
+	 *
+	 * On AP/GO, this is set to the P2P Device Address of the associating
+	 * P2P client if a P2P IE is included in the (Re)Association Request
+	 * frame and the P2P Device Address is included. Otherwise, this is set
+	 * to %NULL to indicate the station does not have a P2P Device Address.
+	 */
+	const u8 *p2p_dev_addr;
+
+	/**
+	 * pbc_in_m1 - Do not remove PushButton config method in M1 (AP)
+	 *
+	 * This can be used to enable a workaround to allow Windows 7 to use
+	 * PBC with the AP.
+	 */
+	int pbc_in_m1;
+};
+
+struct wps_data * wps_init(const struct wps_config *cfg);
+
+void wps_deinit(struct wps_data *data);
+
+/**
+ * enum wps_process_res - WPS message processing result
+ */
+enum wps_process_res {
+	/**
+	 * WPS_DONE - Processing done
+	 */
+	WPS_DONE,
+
+	/**
+	 * WPS_CONTINUE - Processing continues
+	 */
+	WPS_CONTINUE,
+
+	/**
+	 * WPS_FAILURE - Processing failed
+	 */
+	WPS_FAILURE,
+
+	/**
+	 * WPS_PENDING - Processing continues, but waiting for an external
+	 *	event (e.g., UPnP message from an external Registrar)
+	 */
+	WPS_PENDING
+};
+enum wps_process_res wps_process_msg(struct wps_data *wps,
+				     enum wsc_op_code op_code,
+				     const struct wpabuf *msg);
+
+struct wpabuf * wps_get_msg(struct wps_data *wps, enum wsc_op_code *op_code);
+
+int wps_is_selected_pbc_registrar(const struct wpabuf *msg);
+int wps_is_selected_pin_registrar(const struct wpabuf *msg);
+int wps_ap_priority_compar(const struct wpabuf *wps_a,
+			   const struct wpabuf *wps_b);
+int wps_is_addr_authorized(const struct wpabuf *msg, const u8 *addr,
+			   int ver1_compat);
+const u8 * wps_get_uuid_e(const struct wpabuf *msg);
+int wps_is_20(const struct wpabuf *msg);
+
+struct wpabuf * wps_build_assoc_req_ie(enum wps_request_type req_type);
+struct wpabuf * wps_build_assoc_resp_ie(void);
+struct wpabuf * wps_build_probe_req_ie(u16 pw_id, struct wps_device_data *dev,
+				       const u8 *uuid,
+				       enum wps_request_type req_type,
+				       unsigned int num_req_dev_types,
+				       const u8 *req_dev_types);
+
+
+/**
+ * struct wps_registrar_config - WPS Registrar configuration
+ */
+struct wps_registrar_config {
+	/**
+	 * new_psk_cb - Callback for new PSK
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @mac_addr: MAC address of the Enrollee
+	 * @psk: The new PSK
+	 * @psk_len: The length of psk in octets
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This callback is called when a new per-device PSK is provisioned.
+	 */
+	int (*new_psk_cb)(void *ctx, const u8 *mac_addr, const u8 *psk,
+			  size_t psk_len);
+
+	/**
+	 * set_ie_cb - Callback for WPS IE changes
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @beacon_ie: WPS IE for Beacon
+	 * @probe_resp_ie: WPS IE for Probe Response
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This callback is called whenever the WPS IE in Beacon or Probe
+	 * Response frames needs to be changed (AP only). Callee is responsible
+	 * for freeing the buffers.
+	 */
+	int (*set_ie_cb)(void *ctx, struct wpabuf *beacon_ie,
+			 struct wpabuf *probe_resp_ie);
+
+	/**
+	 * pin_needed_cb - Callback for requesting a PIN
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @uuid_e: UUID-E of the unknown Enrollee
+	 * @dev: Device Data from the unknown Enrollee
+	 *
+	 * This callback is called whenever an unknown Enrollee requests to use
+	 * PIN method and a matching PIN (Device Password) is not found in
+	 * Registrar data.
+	 */
+	void (*pin_needed_cb)(void *ctx, const u8 *uuid_e,
+			      const struct wps_device_data *dev);
+
+	/**
+	 * reg_success_cb - Callback for reporting successful registration
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @mac_addr: MAC address of the Enrollee
+	 * @uuid_e: UUID-E of the Enrollee
+	 * @dev_pw: Device Password (PIN) used during registration
+	 * @dev_pw_len: Length of dev_pw in octets
+	 *
+	 * This callback is called whenever an Enrollee completes registration
+	 * successfully.
+	 */
+	void (*reg_success_cb)(void *ctx, const u8 *mac_addr,
+			       const u8 *uuid_e, const u8 *dev_pw,
+			       size_t dev_pw_len);
+
+	/**
+	 * set_sel_reg_cb - Callback for reporting selected registrar changes
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @sel_reg: Whether the Registrar is selected
+	 * @dev_passwd_id: Device Password ID to indicate with method or
+	 *	specific password the Registrar intends to use
+	 * @sel_reg_config_methods: Bit field of active config methods
+	 *
+	 * This callback is called whenever the Selected Registrar state
+	 * changes (e.g., a new PIN becomes available or PBC is invoked). This
+	 * callback is only used by External Registrar implementation;
+	 * set_ie_cb() is used by AP implementation in similar caes, but it
+	 * provides the full WPS IE data instead of just the minimal Registrar
+	 * state information.
+	 */
+	void (*set_sel_reg_cb)(void *ctx, int sel_reg, u16 dev_passwd_id,
+			       u16 sel_reg_config_methods);
+
+	/**
+	 * enrollee_seen_cb - Callback for reporting Enrollee based on ProbeReq
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @addr: MAC address of the Enrollee
+	 * @uuid_e: UUID of the Enrollee
+	 * @pri_dev_type: Primary device type
+	 * @config_methods: Config Methods
+	 * @dev_password_id: Device Password ID
+	 * @request_type: Request Type
+	 * @dev_name: Device Name (if available)
+	 */
+	void (*enrollee_seen_cb)(void *ctx, const u8 *addr, const u8 *uuid_e,
+				 const u8 *pri_dev_type, u16 config_methods,
+				 u16 dev_password_id, u8 request_type,
+				 const char *dev_name);
+
+	/**
+	 * cb_ctx: Higher layer context data for Registrar callbacks
+	 */
+	void *cb_ctx;
+
+	/**
+	 * skip_cred_build: Do not build credential
+	 *
+	 * This option can be used to disable internal code that builds
+	 * Credential attribute into M8 based on the current network
+	 * configuration and Enrollee capabilities. The extra_cred data will
+	 * then be used as the Credential(s).
+	 */
+	int skip_cred_build;
+
+	/**
+	 * extra_cred: Additional Credential attribute(s)
+	 *
+	 * This optional data (set to %NULL to disable) can be used to add
+	 * Credential attribute(s) for other networks into M8. If
+	 * skip_cred_build is set, this will also override the automatically
+	 * generated Credential attribute.
+	 */
+	const u8 *extra_cred;
+
+	/**
+	 * extra_cred_len: Length of extra_cred in octets
+	 */
+	size_t extra_cred_len;
+
+	/**
+	 * disable_auto_conf - Disable auto-configuration on first registration
+	 *
+	 * By default, the AP that is started in not configured state will
+	 * generate a random PSK and move to configured state when the first
+	 * registration protocol run is completed successfully. This option can
+	 * be used to disable this functionality and leave it up to an external
+	 * program to take care of configuration. This requires the extra_cred
+	 * to be set with a suitable Credential and skip_cred_build being used.
+	 */
+	int disable_auto_conf;
+
+	/**
+	 * static_wep_only - Whether the BSS supports only static WEP
+	 */
+	int static_wep_only;
+
+	/**
+	 * dualband - Whether this is a concurrent dualband AP
+	 */
+	int dualband;
+};
+
+
+/**
+ * enum wps_event - WPS event types
+ */
+enum wps_event {
+	/**
+	 * WPS_EV_M2D - M2D received (Registrar did not know us)
+	 */
+	WPS_EV_M2D,
+
+	/**
+	 * WPS_EV_FAIL - Registration failed
+	 */
+	WPS_EV_FAIL,
+
+	/**
+	 * WPS_EV_SUCCESS - Registration succeeded
+	 */
+	WPS_EV_SUCCESS,
+
+	/**
+	 * WPS_EV_PWD_AUTH_FAIL - Password authentication failed
+	 */
+	WPS_EV_PWD_AUTH_FAIL,
+
+	/**
+	 * WPS_EV_PBC_OVERLAP - PBC session overlap detected
+	 */
+	WPS_EV_PBC_OVERLAP,
+
+	/**
+	 * WPS_EV_PBC_TIMEOUT - PBC walktime expired before protocol run start
+	 */
+	WPS_EV_PBC_TIMEOUT,
+
+	/**
+	 * WPS_EV_ER_AP_ADD - ER: AP added
+	 */
+	WPS_EV_ER_AP_ADD,
+
+	/**
+	 * WPS_EV_ER_AP_REMOVE - ER: AP removed
+	 */
+	WPS_EV_ER_AP_REMOVE,
+
+	/**
+	 * WPS_EV_ER_ENROLLEE_ADD - ER: Enrollee added
+	 */
+	WPS_EV_ER_ENROLLEE_ADD,
+
+	/**
+	 * WPS_EV_ER_ENROLLEE_REMOVE - ER: Enrollee removed
+	 */
+	WPS_EV_ER_ENROLLEE_REMOVE,
+
+	/**
+	 * WPS_EV_ER_AP_SETTINGS - ER: AP Settings learned
+	 */
+	WPS_EV_ER_AP_SETTINGS,
+
+	/**
+	 * WPS_EV_ER_SET_SELECTED_REGISTRAR - ER: SetSelectedRegistrar event
+	 */
+	WPS_EV_ER_SET_SELECTED_REGISTRAR,
+
+	/**
+	 * WPS_EV_AP_PIN_SUCCESS - External Registrar used correct AP PIN
+	 */
+	WPS_EV_AP_PIN_SUCCESS
+};
+
+/**
+ * union wps_event_data - WPS event data
+ */
+union wps_event_data {
+	/**
+	 * struct wps_event_m2d - M2D event data
+	 */
+	struct wps_event_m2d {
+		u16 config_methods;
+		const u8 *manufacturer;
+		size_t manufacturer_len;
+		const u8 *model_name;
+		size_t model_name_len;
+		const u8 *model_number;
+		size_t model_number_len;
+		const u8 *serial_number;
+		size_t serial_number_len;
+		const u8 *dev_name;
+		size_t dev_name_len;
+		const u8 *primary_dev_type; /* 8 octets */
+		u16 config_error;
+		u16 dev_password_id;
+	} m2d;
+
+	/**
+	 * struct wps_event_fail - Registration failure information
+	 * @msg: enum wps_msg_type
+	 */
+	struct wps_event_fail {
+		int msg;
+		u16 config_error;
+		u16 error_indication;
+	} fail;
+
+	struct wps_event_pwd_auth_fail {
+		int enrollee;
+		int part;
+	} pwd_auth_fail;
+
+	struct wps_event_er_ap {
+		const u8 *uuid;
+		const u8 *mac_addr;
+		const char *friendly_name;
+		const char *manufacturer;
+		const char *manufacturer_url;
+		const char *model_description;
+		const char *model_name;
+		const char *model_number;
+		const char *model_url;
+		const char *serial_number;
+		const char *upc;
+		const u8 *pri_dev_type;
+		u8 wps_state;
+	} ap;
+
+	struct wps_event_er_enrollee {
+		const u8 *uuid;
+		const u8 *mac_addr;
+		int m1_received;
+		u16 config_methods;
+		u16 dev_passwd_id;
+		const u8 *pri_dev_type;
+		const char *dev_name;
+		const char *manufacturer;
+		const char *model_name;
+		const char *model_number;
+		const char *serial_number;
+	} enrollee;
+
+	struct wps_event_er_ap_settings {
+		const u8 *uuid;
+		const struct wps_credential *cred;
+	} ap_settings;
+
+	struct wps_event_er_set_selected_registrar {
+		const u8 *uuid;
+		int sel_reg;
+		u16 dev_passwd_id;
+		u16 sel_reg_config_methods;
+		enum {
+			WPS_ER_SET_SEL_REG_START,
+			WPS_ER_SET_SEL_REG_DONE,
+			WPS_ER_SET_SEL_REG_FAILED
+		} state;
+	} set_sel_reg;
+};
+
+/**
+ * struct upnp_pending_message - Pending PutWLANResponse messages
+ * @next: Pointer to next pending message or %NULL
+ * @addr: NewWLANEventMAC
+ * @msg: NewMessage
+ * @type: Message Type
+ */
+struct upnp_pending_message {
+	struct upnp_pending_message *next;
+	u8 addr[ETH_ALEN];
+	struct wpabuf *msg;
+	enum wps_msg_type type;
+};
+
+/**
+ * struct wps_context - Long term WPS context data
+ *
+ * This data is stored at the higher layer Authenticator or Supplicant data
+ * structures and it is maintained over multiple registration protocol runs.
+ */
+struct wps_context {
+	/**
+	 * ap - Whether the local end is an access point
+	 */
+	int ap;
+
+	/**
+	 * registrar - Pointer to WPS registrar data from wps_registrar_init()
+	 */
+	struct wps_registrar *registrar;
+
+	/**
+	 * wps_state - Current WPS state
+	 */
+	enum wps_state wps_state;
+
+	/**
+	 * ap_setup_locked - Whether AP setup is locked (only used at AP)
+	 */
+	int ap_setup_locked;
+
+	/**
+	 * uuid - Own UUID
+	 */
+	u8 uuid[16];
+
+	/**
+	 * ssid - SSID
+	 *
+	 * This SSID is used by the Registrar to fill in information for
+	 * Credentials. In addition, AP uses it when acting as an Enrollee to
+	 * notify Registrar of the current configuration.
+	 */
+	u8 ssid[32];
+
+	/**
+	 * ssid_len - Length of ssid in octets
+	 */
+	size_t ssid_len;
+
+	/**
+	 * dev - Own WPS device data
+	 */
+	struct wps_device_data dev;
+
+	/**
+	 * dh_ctx - Context data for Diffie-Hellman operation
+	 */
+	void *dh_ctx;
+
+	/**
+	 * dh_privkey - Diffie-Hellman private key
+	 */
+	struct wpabuf *dh_privkey;
+
+	/**
+	 * dh_pubkey_oob - Diffie-Hellman public key
+	 */
+	struct wpabuf *dh_pubkey;
+
+	/**
+	 * config_methods - Enabled configuration methods
+	 *
+	 * Bit field of WPS_CONFIG_*
+	 */
+	u16 config_methods;
+
+	/**
+	 * encr_types - Enabled encryption types (bit field of WPS_ENCR_*)
+	 */
+	u16 encr_types;
+
+	/**
+	 * auth_types - Authentication types (bit field of WPS_AUTH_*)
+	 */
+	u16 auth_types;
+
+	/**
+	 * network_key - The current Network Key (PSK) or %NULL to generate new
+	 *
+	 * If %NULL, Registrar will generate per-device PSK. In addition, AP
+	 * uses this when acting as an Enrollee to notify Registrar of the
+	 * current configuration.
+	 *
+	 * When using WPA/WPA2-Person, this key can be either the ASCII
+	 * passphrase (8..63 characters) or the 32-octet PSK (64 hex
+	 * characters). When this is set to the ASCII passphrase, the PSK can
+	 * be provided in the psk buffer and used per-Enrollee to control which
+	 * key type is included in the Credential (e.g., to reduce calculation
+	 * need on low-powered devices by provisioning PSK while still allowing
+	 * other devices to get the passphrase).
+	 */
+	u8 *network_key;
+
+	/**
+	 * network_key_len - Length of network_key in octets
+	 */
+	size_t network_key_len;
+
+	/**
+	 * psk - The current network PSK
+	 *
+	 * This optional value can be used to provide the current PSK if
+	 * network_key is set to the ASCII passphrase.
+	 */
+	u8 psk[32];
+
+	/**
+	 * psk_set - Whether psk value is set
+	 */
+	int psk_set;
+
+	/**
+	 * ap_settings - AP Settings override for M7 (only used at AP)
+	 *
+	 * If %NULL, AP Settings attributes will be generated based on the
+	 * current network configuration.
+	 */
+	u8 *ap_settings;
+
+	/**
+	 * ap_settings_len - Length of ap_settings in octets
+	 */
+	size_t ap_settings_len;
+
+	/**
+	 * friendly_name - Friendly Name (required for UPnP)
+	 */
+	char *friendly_name;
+
+	/**
+	 * manufacturer_url - Manufacturer URL (optional for UPnP)
+	 */
+	char *manufacturer_url;
+
+	/**
+	 * model_description - Model Description (recommended for UPnP)
+	 */
+	char *model_description;
+
+	/**
+	 * model_url - Model URL (optional for UPnP)
+	 */
+	char *model_url;
+
+	/**
+	 * upc - Universal Product Code (optional for UPnP)
+	 */
+	char *upc;
+
+	/**
+	 * cred_cb - Callback to notify that new Credentials were received
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @cred: The received Credential
+	 * Return: 0 on success, -1 on failure
+	 */
+	int (*cred_cb)(void *ctx, const struct wps_credential *cred);
+
+	/**
+	 * event_cb - Event callback (state information about progress)
+	 * @ctx: Higher layer context data (cb_ctx)
+	 * @event: Event type
+	 * @data: Event data
+	 */
+	void (*event_cb)(void *ctx, enum wps_event event,
+			 union wps_event_data *data);
+
+	/**
+	 * cb_ctx: Higher layer context data for callbacks
+	 */
+	void *cb_ctx;
+
+	struct upnp_wps_device_sm *wps_upnp;
+
+	/* Pending messages from UPnP PutWLANResponse */
+	struct upnp_pending_message *upnp_msgs;
+
+	u16 ap_nfc_dev_pw_id;
+	struct wpabuf *ap_nfc_dh_pubkey;
+	struct wpabuf *ap_nfc_dh_privkey;
+	struct wpabuf *ap_nfc_dev_pw;
+};
+
+struct wps_registrar *
+wps_registrar_init(struct wps_context *wps,
+		   const struct wps_registrar_config *cfg);
+void wps_registrar_deinit(struct wps_registrar *reg);
+int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *addr,
+			  const u8 *uuid, const u8 *pin, size_t pin_len,
+			  int timeout);
+int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid);
+int wps_registrar_wps_cancel(struct wps_registrar *reg);
+int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid);
+int wps_registrar_button_pushed(struct wps_registrar *reg,
+				const u8 *p2p_dev_addr);
+void wps_registrar_complete(struct wps_registrar *registrar, const u8 *uuid_e,
+			    const u8 *dev_pw, size_t dev_pw_len);
+void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
+				const struct wpabuf *wps_data,
+				int p2p_wildcard);
+int wps_registrar_update_ie(struct wps_registrar *reg);
+int wps_registrar_get_info(struct wps_registrar *reg, const u8 *addr,
+			   char *buf, size_t buflen);
+int wps_registrar_config_ap(struct wps_registrar *reg,
+			    struct wps_credential *cred);
+int wps_registrar_add_nfc_pw_token(struct wps_registrar *reg,
+				   const u8 *pubkey_hash, u16 pw_id,
+				   const u8 *dev_pw, size_t dev_pw_len);
+int wps_registrar_add_nfc_password_token(struct wps_registrar *reg,
+					 const u8 *oob_dev_pw,
+					 size_t oob_dev_pw_len);
+
+int wps_build_credential_wrap(struct wpabuf *msg,
+			      const struct wps_credential *cred);
+
+unsigned int wps_pin_checksum(unsigned int pin);
+unsigned int wps_pin_valid(unsigned int pin);
+unsigned int wps_generate_pin(void);
+int wps_pin_str_valid(const char *pin);
+void wps_free_pending_msgs(struct upnp_pending_message *msgs);
+
+struct wpabuf * wps_get_oob_cred(struct wps_context *wps);
+int wps_oob_use_cred(struct wps_context *wps, struct wps_parse_attr *attr);
+int wps_attr_text(struct wpabuf *data, char *buf, char *end);
+
+struct wps_er * wps_er_init(struct wps_context *wps, const char *ifname,
+			    const char *filter);
+void wps_er_refresh(struct wps_er *er);
+void wps_er_deinit(struct wps_er *er, void (*cb)(void *ctx), void *ctx);
+void wps_er_set_sel_reg(struct wps_er *er, int sel_reg, u16 dev_passwd_id,
+			u16 sel_reg_config_methods);
+int wps_er_pbc(struct wps_er *er, const u8 *uuid);
+int wps_er_learn(struct wps_er *er, const u8 *uuid, const u8 *pin,
+		 size_t pin_len);
+int wps_er_set_config(struct wps_er *er, const u8 *uuid,
+		      const struct wps_credential *cred);
+int wps_er_config(struct wps_er *er, const u8 *uuid, const u8 *pin,
+		  size_t pin_len, const struct wps_credential *cred);
+struct wpabuf * wps_er_nfc_config_token(struct wps_er *er, const u8 *uuid);
+
+int wps_dev_type_str2bin(const char *str, u8 dev_type[WPS_DEV_TYPE_LEN]);
+char * wps_dev_type_bin2str(const u8 dev_type[WPS_DEV_TYPE_LEN], char *buf,
+			    size_t buf_len);
+void uuid_gen_mac_addr(const u8 *mac_addr, u8 *uuid);
+u16 wps_config_methods_str2bin(const char *str);
+struct wpabuf * wps_build_nfc_pw_token(u16 dev_pw_id,
+				       const struct wpabuf *pubkey,
+				       const struct wpabuf *dev_pw);
+struct wpabuf * wps_nfc_token_gen(int ndef, int *id, struct wpabuf **pubkey,
+				  struct wpabuf **privkey,
+				  struct wpabuf **dev_pw);
+
+/* ndef.c */
+struct wpabuf * ndef_parse_wifi(const struct wpabuf *buf);
+struct wpabuf * ndef_build_wifi(const struct wpabuf *buf);
+struct wpabuf * ndef_build_wifi_hr(void);
+
+#ifdef CONFIG_WPS_STRICT
+int wps_validate_beacon(const struct wpabuf *wps_ie);
+int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie, int probe,
+				   const u8 *addr);
+int wps_validate_probe_req(const struct wpabuf *wps_ie, const u8 *addr);
+int wps_validate_assoc_req(const struct wpabuf *wps_ie);
+int wps_validate_assoc_resp(const struct wpabuf *wps_ie);
+int wps_validate_m1(const struct wpabuf *tlvs);
+int wps_validate_m2(const struct wpabuf *tlvs);
+int wps_validate_m2d(const struct wpabuf *tlvs);
+int wps_validate_m3(const struct wpabuf *tlvs);
+int wps_validate_m4(const struct wpabuf *tlvs);
+int wps_validate_m4_encr(const struct wpabuf *tlvs, int wps2);
+int wps_validate_m5(const struct wpabuf *tlvs);
+int wps_validate_m5_encr(const struct wpabuf *tlvs, int wps2);
+int wps_validate_m6(const struct wpabuf *tlvs);
+int wps_validate_m6_encr(const struct wpabuf *tlvs, int wps2);
+int wps_validate_m7(const struct wpabuf *tlvs);
+int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap, int wps2);
+int wps_validate_m8(const struct wpabuf *tlvs);
+int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap, int wps2);
+int wps_validate_wsc_ack(const struct wpabuf *tlvs);
+int wps_validate_wsc_nack(const struct wpabuf *tlvs);
+int wps_validate_wsc_done(const struct wpabuf *tlvs);
+int wps_validate_upnp_set_selected_registrar(const struct wpabuf *tlvs);
+#else /* CONFIG_WPS_STRICT */
+static inline int wps_validate_beacon(const struct wpabuf *wps_ie){
+	return 0;
+}
+
+static inline int wps_validate_beacon_probe_resp(const struct wpabuf *wps_ie,
+						 int probe, const u8 *addr)
+{
+	return 0;
+}
+
+static inline int wps_validate_probe_req(const struct wpabuf *wps_ie,
+					 const u8 *addr)
+{
+	return 0;
+}
+
+static inline int wps_validate_assoc_req(const struct wpabuf *wps_ie)
+{
+	return 0;
+}
+
+static inline int wps_validate_assoc_resp(const struct wpabuf *wps_ie)
+{
+	return 0;
+}
+
+static inline int wps_validate_m1(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m2(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m2d(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m3(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m4(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m4_encr(const struct wpabuf *tlvs, int wps2)
+{
+	return 0;
+}
+
+static inline int wps_validate_m5(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m5_encr(const struct wpabuf *tlvs, int wps2)
+{
+	return 0;
+}
+
+static inline int wps_validate_m6(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m6_encr(const struct wpabuf *tlvs, int wps2)
+{
+	return 0;
+}
+
+static inline int wps_validate_m7(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m7_encr(const struct wpabuf *tlvs, int ap,
+				       int wps2)
+{
+	return 0;
+}
+
+static inline int wps_validate_m8(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_m8_encr(const struct wpabuf *tlvs, int ap,
+				       int wps2)
+{
+	return 0;
+}
+
+static inline int wps_validate_wsc_ack(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_wsc_nack(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_wsc_done(const struct wpabuf *tlvs)
+{
+	return 0;
+}
+
+static inline int wps_validate_upnp_set_selected_registrar(
+	const struct wpabuf *tlvs)
+{
+	return 0;
+}
+#endif /* CONFIG_WPS_STRICT */
+
+#endif /* WPS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/src/wps/wps_defs.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,330 @@
+/*
+ * Wi-Fi Protected Setup - message definitions
+ * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPS_DEFS_H
+#define WPS_DEFS_H
+
+#ifdef CONFIG_WPS_TESTING
+
+extern int wps_version_number;
+extern int wps_testing_dummy_cred;
+#define WPS_VERSION wps_version_number
+
+#else /* CONFIG_WPS_TESTING */
+
+#ifdef CONFIG_WPS2
+#define WPS_VERSION 0x20
+#else /* CONFIG_WPS2 */
+#define WPS_VERSION 0x10
+#endif /* CONFIG_WPS2 */
+
+#endif /* CONFIG_WPS_TESTING */
+
+/* Diffie-Hellman 1536-bit MODP Group; RFC 3526, Group 5 */
+#define WPS_DH_GROUP 5
+
+#define WPS_UUID_LEN 16
+#define WPS_NONCE_LEN 16
+#define WPS_AUTHENTICATOR_LEN 8
+#define WPS_AUTHKEY_LEN 32
+#define WPS_KEYWRAPKEY_LEN 16
+#define WPS_EMSK_LEN 32
+#define WPS_PSK_LEN 16
+#define WPS_SECRET_NONCE_LEN 16
+#define WPS_HASH_LEN 32
+#define WPS_KWA_LEN 8
+#define WPS_MGMTAUTHKEY_LEN 32
+#define WPS_MGMTENCKEY_LEN 16
+#define WPS_MGMT_KEY_ID_LEN 16
+#define WPS_OOB_DEVICE_PASSWORD_MIN_LEN 16
+#define WPS_OOB_DEVICE_PASSWORD_LEN 32
+#define WPS_OOB_PUBKEY_HASH_LEN 20
+
+/* Attribute Types */
+enum wps_attribute {
+	ATTR_AP_CHANNEL = 0x1001,
+	ATTR_ASSOC_STATE = 0x1002,
+	ATTR_AUTH_TYPE = 0x1003,
+	ATTR_AUTH_TYPE_FLAGS = 0x1004,
+	ATTR_AUTHENTICATOR = 0x1005,
+	ATTR_CONFIG_METHODS = 0x1008,
+	ATTR_CONFIG_ERROR = 0x1009,
+	ATTR_CONFIRM_URL4 = 0x100a,
+	ATTR_CONFIRM_URL6 = 0x100b,
+	ATTR_CONN_TYPE = 0x100c,
+	ATTR_CONN_TYPE_FLAGS = 0x100d,
+	ATTR_CRED = 0x100e,
+	ATTR_ENCR_TYPE = 0x100f,
+	ATTR_ENCR_TYPE_FLAGS = 0x1010,
+	ATTR_DEV_NAME = 0x1011,
+	ATTR_DEV_PASSWORD_ID = 0x1012,
+	ATTR_E_HASH1 = 0x1014,
+	ATTR_E_HASH2 = 0x1015,
+	ATTR_E_SNONCE1 = 0x1016,
+	ATTR_E_SNONCE2 = 0x1017,
+	ATTR_ENCR_SETTINGS = 0x1018,
+	ATTR_ENROLLEE_NONCE = 0x101a,
+	ATTR_FEATURE_ID = 0x101b,
+	ATTR_IDENTITY = 0x101c,
+	ATTR_IDENTITY_PROOF = 0x101d,
+	ATTR_KEY_WRAP_AUTH = 0x101e,
+	ATTR_KEY_ID = 0x101f,
+	ATTR_MAC_ADDR = 0x1020,
+	ATTR_MANUFACTURER = 0x1021,
+	ATTR_MSG_TYPE = 0x1022,
+	ATTR_MODEL_NAME = 0x1023,
+	ATTR_MODEL_NUMBER = 0x1024,
+	ATTR_NETWORK_INDEX = 0x1026,
+	ATTR_NETWORK_KEY = 0x1027,
+	ATTR_NETWORK_KEY_INDEX = 0x1028,
+	ATTR_NEW_DEVICE_NAME = 0x1029,
+	ATTR_NEW_PASSWORD = 0x102a,
+	ATTR_OOB_DEVICE_PASSWORD = 0x102c,
+	ATTR_OS_VERSION = 0x102d,
+	ATTR_POWER_LEVEL = 0x102f,
+	ATTR_PSK_CURRENT = 0x1030,
+	ATTR_PSK_MAX = 0x1031,
+	ATTR_PUBLIC_KEY = 0x1032,
+	ATTR_RADIO_ENABLE = 0x1033,
+	ATTR_REBOOT = 0x1034,
+	ATTR_REGISTRAR_CURRENT = 0x1035,
+	ATTR_REGISTRAR_ESTABLISHED = 0x1036,
+	ATTR_REGISTRAR_LIST = 0x1037,
+	ATTR_REGISTRAR_MAX = 0x1038,
+	ATTR_REGISTRAR_NONCE = 0x1039,
+	ATTR_REQUEST_TYPE = 0x103a,
+	ATTR_RESPONSE_TYPE = 0x103b,
+	ATTR_RF_BANDS = 0x103c,
+	ATTR_R_HASH1 = 0x103d,
+	ATTR_R_HASH2 = 0x103e,
+	ATTR_R_SNONCE1 = 0x103f,
+	ATTR_R_SNONCE2 = 0x1040,
+	ATTR_SELECTED_REGISTRAR = 0x1041,
+	ATTR_SERIAL_NUMBER = 0x1042,
+	ATTR_WPS_STATE = 0x1044,
+	ATTR_SSID = 0x1045,
+	ATTR_TOTAL_NETWORKS = 0x1046,
+	ATTR_UUID_E = 0x1047,
+	ATTR_UUID_R = 0x1048,
+	ATTR_VENDOR_EXT = 0x1049,
+	ATTR_VERSION = 0x104a,
+	ATTR_X509_CERT_REQ = 0x104b,
+	ATTR_X509_CERT = 0x104c,
+	ATTR_EAP_IDENTITY = 0x104d,
+	ATTR_MSG_COUNTER = 0x104e,
+	ATTR_PUBKEY_HASH = 0x104f,
+	ATTR_REKEY_KEY = 0x1050,
+	ATTR_KEY_LIFETIME = 0x1051,
+	ATTR_PERMITTED_CFG_METHODS = 0x1052,
+	ATTR_SELECTED_REGISTRAR_CONFIG_METHODS = 0x1053,
+	ATTR_PRIMARY_DEV_TYPE = 0x1054,
+	ATTR_SECONDARY_DEV_TYPE_LIST = 0x1055,
+	ATTR_PORTABLE_DEV = 0x1056,
+	ATTR_AP_SETUP_LOCKED = 0x1057,
+	ATTR_APPLICATION_EXT = 0x1058,
+	ATTR_EAP_TYPE = 0x1059,
+	ATTR_IV = 0x1060,
+	ATTR_KEY_PROVIDED_AUTO = 0x1061,
+	ATTR_802_1X_ENABLED = 0x1062,
+	ATTR_APPSESSIONKEY = 0x1063,
+	ATTR_WEPTRANSMITKEY = 0x1064,
+	ATTR_REQUESTED_DEV_TYPE = 0x106a,
+	ATTR_EXTENSIBILITY_TEST = 0x10fa /* _NOT_ defined in the spec */
+};
+
+#define WPS_VENDOR_ID_WFA 14122
+
+/* WFA Vendor Extension subelements */
+enum {
+	WFA_ELEM_VERSION2 = 0x00,
+	WFA_ELEM_AUTHORIZEDMACS = 0x01,
+	WFA_ELEM_NETWORK_KEY_SHAREABLE = 0x02,
+	WFA_ELEM_REQUEST_TO_ENROLL = 0x03,
+	WFA_ELEM_SETTINGS_DELAY_TIME = 0x04
+};
+
+/* Device Password ID */
+enum wps_dev_password_id {
+	DEV_PW_DEFAULT = 0x0000,
+	DEV_PW_USER_SPECIFIED = 0x0001,
+	DEV_PW_MACHINE_SPECIFIED = 0x0002,
+	DEV_PW_REKEY = 0x0003,
+	DEV_PW_PUSHBUTTON = 0x0004,
+	DEV_PW_REGISTRAR_SPECIFIED = 0x0005
+};
+
+/* Message Type */
+enum wps_msg_type {
+	WPS_Beacon = 0x01,
+	WPS_ProbeRequest = 0x02,
+	WPS_ProbeResponse = 0x03,
+	WPS_M1 = 0x04,
+	WPS_M2 = 0x05,
+	WPS_M2D = 0x06,
+	WPS_M3 = 0x07,
+	WPS_M4 = 0x08,
+	WPS_M5 = 0x09,
+	WPS_M6 = 0x0a,
+	WPS_M7 = 0x0b,
+	WPS_M8 = 0x0c,
+	WPS_WSC_ACK = 0x0d,
+	WPS_WSC_NACK = 0x0e,
+	WPS_WSC_DONE = 0x0f
+};
+
+/* Authentication Type Flags */
+#define WPS_AUTH_OPEN 0x0001
+#define WPS_AUTH_WPAPSK 0x0002
+#define WPS_AUTH_SHARED 0x0004
+#define WPS_AUTH_WPA 0x0008
+#define WPS_AUTH_WPA2 0x0010
+#define WPS_AUTH_WPA2PSK 0x0020
+#define WPS_AUTH_TYPES (WPS_AUTH_OPEN | WPS_AUTH_WPAPSK | WPS_AUTH_SHARED | \
+			WPS_AUTH_WPA | WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)
+
+/* Encryption Type Flags */
+#define WPS_ENCR_NONE 0x0001
+#define WPS_ENCR_WEP 0x0002
+#define WPS_ENCR_TKIP 0x0004
+#define WPS_ENCR_AES 0x0008
+#define WPS_ENCR_TYPES (WPS_ENCR_NONE | WPS_ENCR_WEP | WPS_ENCR_TKIP | \
+			WPS_ENCR_AES)
+
+/* Configuration Error */
+enum wps_config_error {
+	WPS_CFG_NO_ERROR = 0,
+	WPS_CFG_OOB_IFACE_READ_ERROR = 1,
+	WPS_CFG_DECRYPTION_CRC_FAILURE = 2,
+	WPS_CFG_24_CHAN_NOT_SUPPORTED = 3,
+	WPS_CFG_50_CHAN_NOT_SUPPORTED = 4,
+	WPS_CFG_SIGNAL_TOO_WEAK = 5,
+	WPS_CFG_NETWORK_AUTH_FAILURE = 6,
+	WPS_CFG_NETWORK_ASSOC_FAILURE = 7,
+	WPS_CFG_NO_DHCP_RESPONSE = 8,
+	WPS_CFG_FAILED_DHCP_CONFIG = 9,
+	WPS_CFG_IP_ADDR_CONFLICT = 10,
+	WPS_CFG_NO_CONN_TO_REGISTRAR = 11,
+	WPS_CFG_MULTIPLE_PBC_DETECTED = 12,
+	WPS_CFG_ROGUE_SUSPECTED = 13,
+	WPS_CFG_DEVICE_BUSY = 14,
+	WPS_CFG_SETUP_LOCKED = 15,
+	WPS_CFG_MSG_TIMEOUT = 16,
+	WPS_CFG_REG_SESS_TIMEOUT = 17,
+	WPS_CFG_DEV_PASSWORD_AUTH_FAILURE = 18
+};
+
+/* Vendor specific Error Indication for WPS event messages */
+enum wps_error_indication {
+	WPS_EI_NO_ERROR,
+	WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED,
+	WPS_EI_SECURITY_WEP_PROHIBITED,
+	NUM_WPS_EI_VALUES
+};
+
+/* RF Bands */
+#define WPS_RF_24GHZ 0x01
+#define WPS_RF_50GHZ 0x02
+
+/* Config Methods */
+#define WPS_CONFIG_USBA 0x0001
+#define WPS_CONFIG_ETHERNET 0x0002
+#define WPS_CONFIG_LABEL 0x0004
+#define WPS_CONFIG_DISPLAY 0x0008
+#define WPS_CONFIG_EXT_NFC_TOKEN 0x0010
+#define WPS_CONFIG_INT_NFC_TOKEN 0x0020
+#define WPS_CONFIG_NFC_INTERFACE 0x0040
+#define WPS_CONFIG_PUSHBUTTON 0x0080
+#define WPS_CONFIG_KEYPAD 0x0100
+#ifdef CONFIG_WPS2
+#define WPS_CONFIG_VIRT_PUSHBUTTON 0x0280
+#define WPS_CONFIG_PHY_PUSHBUTTON 0x0480
+#define WPS_CONFIG_VIRT_DISPLAY 0x2008
+#define WPS_CONFIG_PHY_DISPLAY 0x4008
+#endif /* CONFIG_WPS2 */
+
+/* Connection Type Flags */
+#define WPS_CONN_ESS 0x01
+#define WPS_CONN_IBSS 0x02
+
+/* Wi-Fi Protected Setup State */
+enum wps_state {
+	WPS_STATE_NOT_CONFIGURED = 1,
+	WPS_STATE_CONFIGURED = 2
+};
+
+/* Association State */
+enum wps_assoc_state {
+	WPS_ASSOC_NOT_ASSOC = 0,
+	WPS_ASSOC_CONN_SUCCESS = 1,
+	WPS_ASSOC_CFG_FAILURE = 2,
+	WPS_ASSOC_FAILURE = 3,
+	WPS_ASSOC_IP_FAILURE = 4
+};
+
+
+#define WPS_DEV_OUI_WFA 0x0050f204
+
+enum wps_dev_categ {
+	WPS_DEV_COMPUTER = 1,
+	WPS_DEV_INPUT = 2,
+	WPS_DEV_PRINTER = 3,
+	WPS_DEV_CAMERA = 4,
+	WPS_DEV_STORAGE = 5,
+	WPS_DEV_NETWORK_INFRA = 6,
+	WPS_DEV_DISPLAY = 7,
+	WPS_DEV_MULTIMEDIA = 8,
+	WPS_DEV_GAMING = 9,
+	WPS_DEV_PHONE = 10
+};
+
+enum wps_dev_subcateg {
+	WPS_DEV_COMPUTER_PC = 1,
+	WPS_DEV_COMPUTER_SERVER = 2,
+	WPS_DEV_COMPUTER_MEDIA_CENTER = 3,
+	WPS_DEV_PRINTER_PRINTER = 1,
+	WPS_DEV_PRINTER_SCANNER = 2,
+	WPS_DEV_CAMERA_DIGITAL_STILL_CAMERA = 1,
+	WPS_DEV_STORAGE_NAS = 1,
+	WPS_DEV_NETWORK_INFRA_AP = 1,
+	WPS_DEV_NETWORK_INFRA_ROUTER = 2,
+	WPS_DEV_NETWORK_INFRA_SWITCH = 3,
+	WPS_DEV_DISPLAY_TV = 1,
+	WPS_DEV_DISPLAY_PICTURE_FRAME = 2,
+	WPS_DEV_DISPLAY_PROJECTOR = 3,
+	WPS_DEV_MULTIMEDIA_DAR = 1,
+	WPS_DEV_MULTIMEDIA_PVR = 2,
+	WPS_DEV_MULTIMEDIA_MCX = 3,
+	WPS_DEV_GAMING_XBOX = 1,
+	WPS_DEV_GAMING_XBOX360 = 2,
+	WPS_DEV_GAMING_PLAYSTATION = 3,
+	WPS_DEV_PHONE_WINDOWS_MOBILE = 1
+};
+
+
+/* Request Type */
+enum wps_request_type {
+	WPS_REQ_ENROLLEE_INFO = 0,
+	WPS_REQ_ENROLLEE = 1,
+	WPS_REQ_REGISTRAR = 2,
+	WPS_REQ_WLAN_MANAGER_REGISTRAR = 3
+};
+
+/* Response Type */
+enum wps_response_type {
+	WPS_RESP_ENROLLEE_INFO = 0,
+	WPS_RESP_ENROLLEE = 1,
+	WPS_RESP_REGISTRAR = 2,
+	WPS_RESP_AP = 3
+};
+
+/* Walk Time for push button configuration (in seconds) */
+#define WPS_PBC_WALK_TIME 120
+
+#define WPS_MAX_AUTHORIZED_MACS 5
+
+#endif /* WPS_DEFS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/svc-wpa_supplicant	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,90 @@
+#!/sbin/sh
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
+#
+
+# Standard prolog
+#
+. /lib/svc/share/smf_include.sh
+
+smf_is_globalzone || exit $SMF_EXIT_OK
+
+if [ -z $SMF_FMRI ]; then
+        echo "SMF framework variables are not initialized."
+        exit $SMF_EXIT_ERR
+fi
+
+# TODO: check known-wlans.conf if nwam is enabled
+
+# Disable globbing to prevent privilege escalations by users authorized
+# to set property values for the NTP service.
+set -f
+
+#
+# Build the command line flags
+#
+shift $#
+
+# Path to global ctrl_interface socket.
+set -- -g/var/run/wpa_supplicant-global
+# Path to PID file.
+set -- "$@" -P/var/run/wpa_supplicant.pid
+# Run daemon in the background.
+set -- "$@" -B
+# Wait for a control interface monitor before starting.
+set -- "$@" -W
+
+debug=`svcprop -c -p config/debug_enabled $SMF_FMRI`
+if [ "$debug" = "true" ]; then
+	# Increase debugging verbosity (-dd even more).
+	# Log output to specified file instead of stdout.
+	verbose=`svcprop -c -p config/verbose_debug $SMF_FMRI`
+	if [ "$verbose" = "true" ]; then
+		set -- "$@" -dd -f/var/log/wpa_supplicant.log
+	else
+		set -- "$@" -d -f/var/log/wpa_supplicant.log
+	fi
+
+	# Include keys (passwords, etc.) in debug output.
+	keys=`svcprop -c -p config/keys_debug $SMF_FMRI`
+	if [ "$keys" = "true" ]; then
+		set -- "$@" -K
+	fi
+
+	# Include timestamp in debug messages.
+	timestamps=`svcprop -c -p config/timestamps_debug $SMF_FMRI`
+	if [ "$timestamps" = "true" ]; then
+		set -- "$@" -t
+	fi;
+fi
+
+/usr/lib/inet/wpa_supplicant "$@"
+
+# TODO: check ctrl interface
+
+if [ $? = 0 ]; then
+        exit $SMF_EXIT_OK
+else
+        exit $SMF_EXIT_ERR_FATAL
+fi
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant.xml	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,152 @@
+<?xml version="1.0"?>
+<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
+<!--
+	Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+	Use is subject to license terms.
+	Copyright (c) 2012, Enrico Papi. All rights reserved.
+
+ CDDL HEADER START
+
+ The contents of this file are subject to the terms of the
+ Common Development and Distribution License (the "License").
+ You may not use this file except in compliance with the License.
+
+ You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ or http://www.opensolaris.org/os/licensing.
+ See the License for the specific language governing permissions
+ and limitations under the License.
+
+ When distributing Covered Code, include this CDDL HEADER in each
+ file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ If applicable, add the following below this CDDL HEADER, with the
+ fields enclosed by brackets "[]" replaced with your own identifying
+ information: Portions Copyright [yyyy] [name of copyright owner]
+
+ CDDL HEADER END
+
+	NOTE:  This service manifest is not editable; its contents will
+	be overwritten by package or patch operations, including
+	operating system upgrade.  Make customizations in a different
+	file.
+-->
+
+<service_bundle type='manifest' name='SUNWsupr:wpa_supplicant'>
+
+<service
+	name='network/wpa_supplicant'
+	type='service'
+	version='1'>
+
+	<single_instance/>
+
+	<dependency
+	    name='filesystem-minimal'
+	    grouping='require_all'
+	    restart_on='none'
+	    type='service'>
+	    <service_fmri value='svc:/system/filesystem/minimal' />
+	</dependency>
+
+	<dependency
+	    name='cryptosvc'
+	    grouping='optional_all'
+	    restart_on='none'
+	    type='service'>
+	    <service_fmri value='svc:/system/cryptosvc' />
+	</dependency>
+
+	<exec_method
+		type='method'
+		name='start'
+		exec='/lib/svc/method/svc-wpa_supplicant'
+		timeout_seconds='60'>
+			<method_context>
+				<method_credential
+				user='root'
+				group='netadm'
+				limit_privileges=':default'
+				privileges='basic,sys_net_config,net_rawaccess'
+				/>
+			</method_context>
+	</exec_method>
+
+	<exec_method
+		type='method'
+		name='stop'
+		exec=':kill'
+		timeout_seconds='60'>
+			<method_context>
+				<method_credential
+				user='root'
+				group='netadm'
+				limit_privileges=':default'
+				privileges='basic,sys_net_config,net_rawaccess'
+				/>
+			</method_context>
+	</exec_method>
+
+  	<!-- reparse wpa_s configuration when using nwam -->
+	<exec_method
+		type='method'
+		name='refresh'
+		exec=':kill -HUP'
+		timeout_seconds='60' />
+
+        <property_group name='general' type='framework'>
+                <!-- to start stop wpa_supplicant service
+                	(as of now only dladm is allowed) -->
+                <propval name='action_authorization' type='astring'
+                        value='solaris.smf.manage.wpa' />
+                <propval name='value_authorization' type='astring'
+			value='solaris.smf.value.wpa' />
+        </property_group>
+
+	<property_group name='config' type='application' >
+		<!-- default property settings for wpa_supplicant -->
+		<propval
+		    name='debug_enabled'
+		    type='boolean'
+		    value='false' />
+
+		<propval
+		    name='verbose_debug'
+		    type='boolean'
+		    value='false' />
+
+		<propval
+		    name='keys_debug'
+		    type='boolean'
+		    value='false' />
+
+		<propval
+		    name='timestamps_debug'
+		    type='boolean'
+		    value='false' />
+
+		<!-- to change properties -->
+		<propval
+		    name='value_authorization'
+		    type='astring'
+		    value='solaris.smf.value.wpa' />
+	</property_group>
+
+       	<instance name="default" enabled="true" />
+
+	<stability value='External' />
+
+	<template>
+		<common_name>
+			<loctext xml:lang='C'>
+			Wireless WPA Supplicant Daemon Version 1.1
+			</loctext>
+		</common_name>
+		<documentation>
+			<doc_link
+			    name='WPA Supplicant README'
+				uri='http://w1.fi/gitweb/gitweb.cgi?p=hostap-1.git;a=blob_plain;f=wpa_supplicant/README;hb=HEAD'
+				/>
+		</documentation>
+	</template>
+</service>
+
+</service_bundle>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/Makefile	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,82 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
+#
+
+PROG =		wpa_supplicant
+OBJS =		config.o notify.o bss.o eap_register.o ../src/utils/common.o \
+../src/utils/wpa_debug.o ../src/utils/wpabuf.o ../src/utils/os_unix.o \
+../src/utils/eloop.o config_solaris.o ../src/rsn_supp/wpa.o \
+../src/rsn_supp/preauth.o ../src/rsn_supp/pmksa_cache.o \
+../src/rsn_supp/peerkey.o ../src/rsn_supp/wpa_ie.o ../src/common/wpa_common.o \
+../src/eap_peer/eap_tls.o ../src/eap_peer/eap_peap.o \
+../src/eap_common/eap_peap_common.o ../src/eap_peer/eap_ttls.o \
+../src/eap_peer/eap_md5.o ../src/eap_peer/eap_mschapv2.o ../src/eap_peer/eap_gtc.o \
+../src/eap_peer/mschapv2.o ../src/eapol_supp/eapol_supp_sm.o \
+../src/eap_peer/eap.o ../src/eap_peer/eap_methods.o ../src/crypto/ms_funcs.o \
+../src/eap_common/chap.o ../src/eap_peer/eap_tls_common.o \
+../src/crypto/tls_openssl.o ../src/crypto/crypto_openssl.o \
+../src/crypto/aes-unwrap.o ../src/crypto/md5.o ../src/crypto/random.o \
+ctrl_iface.o ctrl_iface_unix.o ../src/utils/base64.o \
+../src/eap_common/eap_common.o ../src/crypto/sha1-prf.o \
+../src/crypto/sha1-tlsprf.o ../src/drivers/driver_common.o wpa_supplicant.o \
+events.o blacklist.o wpas_glue.o scan.o main.o ../src/drivers/driver_solaris.o \
+../src/drivers/drivers.o ../src/l2_packet/l2_packet_solaris.o
+
+SRCS = 		$(OBJS:%.o=%.c)
+
+include	../../../../Makefile.cmd
+
+MSGFILES=	$(OBJS)
+
+CERRWARN +=	-erroff=E_USELESS_DECLARATION
+CERRWARN +=	-erroff=E_ZERO_OR_NEGATIVE_SUBSCRIPT
+CERRWARN +=	-erroff=E_EMPTY_MBR_DECLARATION
+CERRWARN +=	-erroff=E_ZERO_SIZED_STRUCT_UNION
+CERRWARN +=	-erroff=E_DUBIOUS_ESCAPE_CHAR
+
+include ./Makefile.cflags
+
+#Illumos-gate Cflags
+C99MODE = $(C99_ENABLE)
+CFLAGS += -D_WPASILLUMOS
+CFLAGS += -_cc=-features=extensions
+
+#Wpa_s CFlags
+CFLAGS += $(WPAFLAGS) -I../src -I../src/utils
+
+LDLIBS += 	 -ldladm -ldlpi -lnwam -lsocket
+
+all install := LDLIBS += -lcrypto -lssl
+
+$(ROOTLIBINETPROG) := FILEMODE = 0555
+
+.KEEP_STATE:
+
+all:		$(PROG)
+
+%.o:		%.c
+		$(COMPILE.c) -o $@ $<
+
+$(PROG):	$(OBJS)
+		$(LINK.c) -o $@ $(OBJS) $(LDLIBS)
+		$(POST_PROCESS)
+
+include ../../Makefile.lib
+
+install:	all $(ROOTLIBINETPROG)
+
+clean:
+		$(RM) $(OBJS)
+
+include ../../../../Makefile.targ
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/Makefile.cflags	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,26 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
+#
+
+#1. Illumos config back-end and driver interface flags
+#2. EAP methods flags
+#3. OpenSSL Engine/EAP/TLS Library Flags
+#4. Control Interface flags
+#5. Debug Control Flags
+
+WPAFLAGS= 	-DCONFIG_BACKEND_SOLARIS -DCONFIG_DRIVER_SOLARIS -DCONFIG_NO_CONFIG_WRITE \
+ -DEAP_MD5 -DEAP_TLS -DEAP_MSCHAPv2 -DEAP_PEAP -DEAP_TTLS -DEAP_GTC \
+ -DIEEE8021X_EAPOL -DPKCS12_FUNCS -DCONFIG_SMARTCARD -DEAP_TLS_OPENSSL \
+ -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX \
+ -DCONFIG_DEBUG_SYSLOG -DLOG_HOSTAPD="LOG_DAEMON" -DCONFIG_DEBUG_FILE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/ap.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,56 @@
+/*
+ * WPA Supplicant - Basic AP mode support routines
+ * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AP_H
+#define AP_H
+
+int wpa_supplicant_create_ap(struct wpa_supplicant *wpa_s,
+			     struct wpa_ssid *ssid);
+void wpa_supplicant_ap_deinit(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_ap_rx_eapol(struct wpa_supplicant *wpa_s,
+				const u8 *src_addr, const u8 *buf, size_t len);
+int wpa_supplicant_ap_wps_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			      const u8 *p2p_dev_addr);
+int wpa_supplicant_ap_wps_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			      const char *pin, char *buf, size_t buflen,
+			      int timeout);
+int wpa_supplicant_ap_wps_cancel(struct wpa_supplicant *wpa_s);
+void wpas_wps_ap_pin_disable(struct wpa_supplicant *wpa_s);
+const char * wpas_wps_ap_pin_random(struct wpa_supplicant *wpa_s, int timeout);
+const char * wpas_wps_ap_pin_get(struct wpa_supplicant *wpa_s);
+int wpas_wps_ap_pin_set(struct wpa_supplicant *wpa_s, const char *pin,
+			int timeout);
+int ap_ctrl_iface_sta_first(struct wpa_supplicant *wpa_s,
+			    char *buf, size_t buflen);
+int ap_ctrl_iface_sta(struct wpa_supplicant *wpa_s, const char *txtaddr,
+		      char *buf, size_t buflen);
+int ap_ctrl_iface_sta_next(struct wpa_supplicant *wpa_s, const char *txtaddr,
+			   char *buf, size_t buflen);
+int ap_ctrl_iface_sta_deauthenticate(struct wpa_supplicant *wpa_s,
+				     const char *txtaddr);
+int ap_ctrl_iface_sta_disassociate(struct wpa_supplicant *wpa_s,
+				   const char *txtaddr);
+int ap_ctrl_iface_wpa_get_status(struct wpa_supplicant *wpa_s, char *buf,
+				 size_t buflen, int verbose);
+void ap_tx_status(void *ctx, const u8 *addr,
+		  const u8 *buf, size_t len, int ack);
+void ap_eapol_tx_status(void *ctx, const u8 *dst,
+			const u8 *data, size_t len, int ack);
+void ap_client_poll_ok(void *ctx, const u8 *addr);
+void ap_rx_from_unknown_sta(void *ctx, const u8 *addr, int wds);
+void ap_mgmt_rx(void *ctx, struct rx_mgmt *rx_mgmt);
+void ap_mgmt_tx_cb(void *ctx, const u8 *buf, size_t len, u16 stype, int ok);
+int wpa_supplicant_ap_update_beacon(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_ap_mac_addr_filter(struct wpa_supplicant *wpa_s,
+				      const u8 *addr);
+void wpa_supplicant_ap_pwd_auth_fail(struct wpa_supplicant *wpa_s);
+void wpas_ap_ch_switch(struct wpa_supplicant *wpa_s, int freq, int ht,
+		       int offset);
+
+#endif /* AP_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/autoscan.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,49 @@
+/*
+ * WPA Supplicant - auto scan
+ * Copyright (c) 2012, Intel Corporation. All rights reserved.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AUTOSCAN_H
+#define AUTOSCAN_H
+
+struct wpa_supplicant;
+
+struct autoscan_ops {
+	const char *name;
+
+	void * (*init)(struct wpa_supplicant *wpa_s, const char *params);
+	void (*deinit)(void *priv);
+
+	int (*notify_scan)(void *priv, struct wpa_scan_results *scan_res);
+};
+
+#ifdef CONFIG_AUTOSCAN
+
+int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan);
+void autoscan_deinit(struct wpa_supplicant *wpa_s);
+int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+			 struct wpa_scan_results *scan_res);
+
+#else /* CONFIG_AUTOSCAN */
+
+static inline int autoscan_init(struct wpa_supplicant *wpa_s, int req_scan)
+{
+	return 0;
+}
+
+static inline void autoscan_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int autoscan_notify_scan(struct wpa_supplicant *wpa_s,
+				       struct wpa_scan_results *scan_res)
+{
+	return 0;
+}
+
+#endif /* CONFIG_AUTOSCAN */
+
+#endif /* AUTOSCAN_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/bgscan.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,72 @@
+/*
+ * WPA Supplicant - background scan and roaming interface
+ * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BGSCAN_H
+#define BGSCAN_H
+
+struct wpa_supplicant;
+struct wpa_ssid;
+
+struct bgscan_ops {
+	const char *name;
+
+	void * (*init)(struct wpa_supplicant *wpa_s, const char *params,
+		       const struct wpa_ssid *ssid);
+	void (*deinit)(void *priv);
+
+	int (*notify_scan)(void *priv, struct wpa_scan_results *scan_res);
+	void (*notify_beacon_loss)(void *priv);
+	void (*notify_signal_change)(void *priv, int above,
+				     int current_signal,
+				     int current_noise,
+				     int current_txrate);
+};
+
+#ifdef CONFIG_BGSCAN
+
+int bgscan_init(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+void bgscan_deinit(struct wpa_supplicant *wpa_s);
+int bgscan_notify_scan(struct wpa_supplicant *wpa_s,
+		       struct wpa_scan_results *scan_res);
+void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s);
+void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s, int above,
+				 int current_signal, int current_noise,
+				 int current_txrate);
+
+#else /* CONFIG_BGSCAN */
+
+static inline int bgscan_init(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid)
+{
+	return 0;
+}
+
+static inline void bgscan_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int bgscan_notify_scan(struct wpa_supplicant *wpa_s,
+				     struct wpa_scan_results *scan_res)
+{
+	return 0;
+}
+
+static inline void bgscan_notify_beacon_loss(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void bgscan_notify_signal_change(struct wpa_supplicant *wpa_s,
+					       int above, int current_signal,
+					       int current_noise,
+					       int current_txrate)
+{
+}
+
+#endif /* CONFIG_BGSCAN */
+
+#endif /* BGSCAN_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/blacklist.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,141 @@
+/*
+ * wpa_supplicant - Temporary BSSID blacklist
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "blacklist.h"
+
+/**
+ * wpa_blacklist_get - Get the blacklist entry for a BSSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * Returns: Matching blacklist entry for the BSSID or %NULL if not found
+ */
+struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
+					 const u8 *bssid)
+{
+	struct wpa_blacklist *e;
+
+	if (wpa_s == NULL || bssid == NULL)
+		return NULL;
+
+	e = wpa_s->blacklist;
+	while (e) {
+		if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0)
+			return e;
+		e = e->next;
+	}
+
+	return NULL;
+}
+
+
+/**
+ * wpa_blacklist_add - Add an BSSID to the blacklist
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to be added to the blacklist
+ * Returns: Current blacklist count on success, -1 on failure
+ *
+ * This function adds the specified BSSID to the blacklist or increases the
+ * blacklist count if the BSSID was already listed. It should be called when
+ * an association attempt fails either due to the selected BSS rejecting
+ * association or due to timeout.
+ *
+ * This blacklist is used to force %wpa_supplicant to go through all available
+ * BSSes before retrying to associate with an BSS that rejected or timed out
+ * association. It does not prevent the listed BSS from being used; it only
+ * changes the order in which they are tried.
+ */
+int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	struct wpa_blacklist *e;
+
+	if (wpa_s == NULL || bssid == NULL)
+		return -1;
+
+	e = wpa_blacklist_get(wpa_s, bssid);
+	if (e) {
+		e->count++;
+		wpa_printf(MSG_DEBUG, "BSSID " MACSTR " blacklist count "
+			   "incremented to %d",
+			   MAC2STR(bssid), e->count);
+		return e->count;
+	}
+
+	e = os_zalloc(sizeof(*e));
+	if (e == NULL)
+		return -1;
+	os_memcpy(e->bssid, bssid, ETH_ALEN);
+	e->count = 1;
+	e->next = wpa_s->blacklist;
+	wpa_s->blacklist = e;
+	wpa_printf(MSG_DEBUG, "Added BSSID " MACSTR " into blacklist",
+		   MAC2STR(bssid));
+
+	return e->count;
+}
+
+
+/**
+ * wpa_blacklist_del - Remove an BSSID from the blacklist
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to be removed from the blacklist
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	struct wpa_blacklist *e, *prev = NULL;
+
+	if (wpa_s == NULL || bssid == NULL)
+		return -1;
+
+	e = wpa_s->blacklist;
+	while (e) {
+		if (os_memcmp(e->bssid, bssid, ETH_ALEN) == 0) {
+			if (prev == NULL) {
+				wpa_s->blacklist = e->next;
+			} else {
+				prev->next = e->next;
+			}
+			wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
+				   "blacklist", MAC2STR(bssid));
+			os_free(e);
+			return 0;
+		}
+		prev = e;
+		e = e->next;
+	}
+	return -1;
+}
+
+
+/**
+ * wpa_blacklist_clear - Clear the blacklist of all entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void wpa_blacklist_clear(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_blacklist *e, *prev;
+	int max_count = 0;
+
+	e = wpa_s->blacklist;
+	wpa_s->blacklist = NULL;
+	while (e) {
+		if (e->count > max_count)
+			max_count = e->count;
+		prev = e;
+		e = e->next;
+		wpa_printf(MSG_DEBUG, "Removed BSSID " MACSTR " from "
+			   "blacklist (clear)", MAC2STR(prev->bssid));
+		os_free(prev);
+	}
+
+	wpa_s->extra_blacklist_count += max_count;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/blacklist.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,24 @@
+/*
+ * wpa_supplicant - Temporary BSSID blacklist
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BLACKLIST_H
+#define BLACKLIST_H
+
+struct wpa_blacklist {
+	struct wpa_blacklist *next;
+	u8 bssid[ETH_ALEN];
+	int count;
+};
+
+struct wpa_blacklist * wpa_blacklist_get(struct wpa_supplicant *wpa_s,
+					 const u8 *bssid);
+int wpa_blacklist_add(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpa_blacklist_del(struct wpa_supplicant *wpa_s, const u8 *bssid);
+void wpa_blacklist_clear(struct wpa_supplicant *wpa_s);
+
+#endif /* BLACKLIST_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/bss.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,1070 @@
+/*
+ * BSS table
+ * Copyright (c) 2009-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "wpa_supplicant_i.h"
+#include "config.h"
+#include "notify.h"
+#include "scan.h"
+#include "bss.h"
+
+
+/**
+ * WPA_BSS_EXPIRATION_PERIOD - Period of expiration run in seconds
+ */
+#define WPA_BSS_EXPIRATION_PERIOD 10
+
+#define WPA_BSS_FREQ_CHANGED_FLAG	BIT(0)
+#define WPA_BSS_SIGNAL_CHANGED_FLAG	BIT(1)
+#define WPA_BSS_PRIVACY_CHANGED_FLAG	BIT(2)
+#define WPA_BSS_MODE_CHANGED_FLAG	BIT(3)
+#define WPA_BSS_WPAIE_CHANGED_FLAG	BIT(4)
+#define WPA_BSS_RSNIE_CHANGED_FLAG	BIT(5)
+#define WPA_BSS_WPS_CHANGED_FLAG	BIT(6)
+#define WPA_BSS_RATES_CHANGED_FLAG	BIT(7)
+#define WPA_BSS_IES_CHANGED_FLAG	BIT(8)
+
+
+static void wpa_bss_set_hessid(struct wpa_bss *bss)
+{
+#ifdef CONFIG_INTERWORKING
+	const u8 *ie = wpa_bss_get_ie(bss, WLAN_EID_INTERWORKING);
+	if (ie == NULL || (ie[1] != 7 && ie[1] != 9)) {
+		os_memset(bss->hessid, 0, ETH_ALEN);
+		return;
+	}
+	if (ie[1] == 7)
+		os_memcpy(bss->hessid, ie + 3, ETH_ALEN);
+	else
+		os_memcpy(bss->hessid, ie + 5, ETH_ALEN);
+#endif /* CONFIG_INTERWORKING */
+}
+
+
+/**
+ * wpa_bss_anqp_alloc - Allocate ANQP data structure for a BSS entry
+ * Returns: Allocated ANQP data structure or %NULL on failure
+ *
+ * The allocated ANQP data structure has its users count set to 1. It may be
+ * shared by multiple BSS entries and each shared entry is freed with
+ * wpa_bss_anqp_free().
+ */
+struct wpa_bss_anqp * wpa_bss_anqp_alloc(void)
+{
+	struct wpa_bss_anqp *anqp;
+	anqp = os_zalloc(sizeof(*anqp));
+	if (anqp == NULL)
+		return NULL;
+	anqp->users = 1;
+	return anqp;
+}
+
+
+/**
+ * wpa_bss_anqp_clone - Clone an ANQP data structure
+ * @anqp: ANQP data structure from wpa_bss_anqp_alloc()
+ * Returns: Cloned ANQP data structure or %NULL on failure
+ */
+static struct wpa_bss_anqp * wpa_bss_anqp_clone(struct wpa_bss_anqp *anqp)
+{
+	struct wpa_bss_anqp *n;
+
+	n = os_zalloc(sizeof(*n));
+	if (n == NULL)
+		return NULL;
+
+#define ANQP_DUP(f) if (anqp->f) n->f = wpabuf_dup(anqp->f)
+#ifdef CONFIG_INTERWORKING
+	ANQP_DUP(venue_name);
+	ANQP_DUP(network_auth_type);
+	ANQP_DUP(roaming_consortium);
+	ANQP_DUP(ip_addr_type_availability);
+	ANQP_DUP(nai_realm);
+	ANQP_DUP(anqp_3gpp);
+	ANQP_DUP(domain_name);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+	ANQP_DUP(hs20_operator_friendly_name);
+	ANQP_DUP(hs20_wan_metrics);
+	ANQP_DUP(hs20_connection_capability);
+	ANQP_DUP(hs20_operating_class);
+#endif /* CONFIG_HS20 */
+#undef ANQP_DUP
+
+	return n;
+}
+
+
+/**
+ * wpa_bss_anqp_unshare_alloc - Unshare ANQP data (if shared) in a BSS entry
+ * @bss: BSS entry
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function ensures the specific BSS entry has an ANQP data structure that
+ * is not shared with any other BSS entry.
+ */
+int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss)
+{
+	struct wpa_bss_anqp *anqp;
+
+	if (bss->anqp && bss->anqp->users > 1) {
+		/* allocated, but shared - clone an unshared copy */
+		anqp = wpa_bss_anqp_clone(bss->anqp);
+		if (anqp == NULL)
+			return -1;
+		anqp->users = 1;
+		bss->anqp->users--;
+		bss->anqp = anqp;
+		return 0;
+	}
+
+	if (bss->anqp)
+		return 0; /* already allocated and not shared */
+
+	/* not allocated - allocate a new storage area */
+	bss->anqp = wpa_bss_anqp_alloc();
+	return bss->anqp ? 0 : -1;
+}
+
+
+/**
+ * wpa_bss_anqp_free - Free an ANQP data structure
+ * @anqp: ANQP data structure from wpa_bss_anqp_alloc() or wpa_bss_anqp_clone()
+ */
+static void wpa_bss_anqp_free(struct wpa_bss_anqp *anqp)
+{
+	if (anqp == NULL)
+		return;
+
+	anqp->users--;
+	if (anqp->users > 0) {
+		/* Another BSS entry holds a pointer to this ANQP info */
+		return;
+	}
+
+#ifdef CONFIG_INTERWORKING
+	wpabuf_free(anqp->venue_name);
+	wpabuf_free(anqp->network_auth_type);
+	wpabuf_free(anqp->roaming_consortium);
+	wpabuf_free(anqp->ip_addr_type_availability);
+	wpabuf_free(anqp->nai_realm);
+	wpabuf_free(anqp->anqp_3gpp);
+	wpabuf_free(anqp->domain_name);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+	wpabuf_free(anqp->hs20_operator_friendly_name);
+	wpabuf_free(anqp->hs20_wan_metrics);
+	wpabuf_free(anqp->hs20_connection_capability);
+	wpabuf_free(anqp->hs20_operating_class);
+#endif /* CONFIG_HS20 */
+
+	os_free(anqp);
+}
+
+
+static void wpa_bss_remove(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+			   const char *reason)
+{
+	if (wpa_s->last_scan_res) {
+		unsigned int i;
+		for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+			if (wpa_s->last_scan_res[i] == bss) {
+				os_memmove(&wpa_s->last_scan_res[i],
+					   &wpa_s->last_scan_res[i + 1],
+					   (wpa_s->last_scan_res_used - i - 1)
+					   * sizeof(struct wpa_bss *));
+				wpa_s->last_scan_res_used--;
+				break;
+			}
+		}
+	}
+	dl_list_del(&bss->list);
+	dl_list_del(&bss->list_id);
+	wpa_s->num_bss--;
+	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Remove id %u BSSID " MACSTR
+		" SSID '%s' due to %s", bss->id, MAC2STR(bss->bssid),
+		wpa_ssid_txt(bss->ssid, bss->ssid_len), reason);
+	wpas_notify_bss_removed(wpa_s, bss->bssid, bss->id);
+	wpa_bss_anqp_free(bss->anqp);
+	os_free(bss);
+}
+
+
+/**
+ * wpa_bss_get - Fetch a BSS table entry based on BSSID and SSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * @ssid: SSID
+ * @ssid_len: Length of @ssid
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
+struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			     const u8 *ssid, size_t ssid_len)
+{
+	struct wpa_bss *bss;
+	if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
+		return NULL;
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0 &&
+		    bss->ssid_len == ssid_len &&
+		    os_memcmp(bss->ssid, ssid, ssid_len) == 0)
+			return bss;
+	}
+	return NULL;
+}
+
+
+static void wpa_bss_copy_res(struct wpa_bss *dst, struct wpa_scan_res *src)
+{
+	os_time_t usec;
+
+	dst->flags = src->flags;
+	os_memcpy(dst->bssid, src->bssid, ETH_ALEN);
+	dst->freq = src->freq;
+	dst->beacon_int = src->beacon_int;
+	dst->caps = src->caps;
+	dst->qual = src->qual;
+	dst->noise = src->noise;
+	dst->level = src->level;
+	dst->tsf = src->tsf;
+
+	os_get_time(&dst->last_update);
+	dst->last_update.sec -= src->age / 1000;
+	usec = (src->age % 1000) * 1000;
+	if (dst->last_update.usec < usec) {
+		dst->last_update.sec--;
+		dst->last_update.usec += 1000000;
+	}
+	dst->last_update.usec -= usec;
+}
+
+
+static int wpa_bss_known(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	struct wpa_ssid *ssid;
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (ssid->ssid == NULL || ssid->ssid_len == 0)
+			continue;
+		if (ssid->ssid_len == bss->ssid_len &&
+		    os_memcmp(ssid->ssid, bss->ssid, ssid->ssid_len) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_bss_in_use(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	return bss == wpa_s->current_bss ||
+		os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) == 0 ||
+		os_memcmp(bss->bssid, wpa_s->pending_bssid, ETH_ALEN) == 0;
+}
+
+
+static int wpa_bss_remove_oldest_unknown(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (!wpa_bss_known(wpa_s, bss)) {
+			wpa_bss_remove(wpa_s, bss, __func__);
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+static int wpa_bss_remove_oldest(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+
+	/*
+	 * Remove the oldest entry that does not match with any configured
+	 * network.
+	 */
+	if (wpa_bss_remove_oldest_unknown(wpa_s) == 0)
+		return 0;
+
+	/*
+	 * Remove the oldest entry that isn't currently in use.
+	 */
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (!wpa_bss_in_use(wpa_s, bss)) {
+			wpa_bss_remove(wpa_s, bss, __func__);
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+static struct wpa_bss * wpa_bss_add(struct wpa_supplicant *wpa_s,
+				    const u8 *ssid, size_t ssid_len,
+				    struct wpa_scan_res *res)
+{
+	struct wpa_bss *bss;
+
+	bss = os_zalloc(sizeof(*bss) + res->ie_len + res->beacon_ie_len);
+	if (bss == NULL)
+		return NULL;
+	bss->id = wpa_s->bss_next_id++;
+	bss->last_update_idx = wpa_s->bss_update_idx;
+	wpa_bss_copy_res(bss, res);
+	os_memcpy(bss->ssid, ssid, ssid_len);
+	bss->ssid_len = ssid_len;
+	bss->ie_len = res->ie_len;
+	bss->beacon_ie_len = res->beacon_ie_len;
+	os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
+	wpa_bss_set_hessid(bss);
+
+	dl_list_add_tail(&wpa_s->bss, &bss->list);
+	dl_list_add_tail(&wpa_s->bss_id, &bss->list_id);
+	wpa_s->num_bss++;
+	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Add new id %u BSSID " MACSTR
+		" SSID '%s'",
+		bss->id, MAC2STR(bss->bssid), wpa_ssid_txt(ssid, ssid_len));
+	wpas_notify_bss_added(wpa_s, bss->bssid, bss->id);
+	if (wpa_s->num_bss > wpa_s->conf->bss_max_count &&
+	    wpa_bss_remove_oldest(wpa_s) != 0) {
+		wpa_printf(MSG_ERROR, "Increasing the MAX BSS count to %d "
+			   "because all BSSes are in use. We should normally "
+			   "not get here!", (int) wpa_s->num_bss);
+		wpa_s->conf->bss_max_count = wpa_s->num_bss;
+	}
+	return bss;
+}
+
+
+static int are_ies_equal(const struct wpa_bss *old,
+			 const struct wpa_scan_res *new, u32 ie)
+{
+	const u8 *old_ie, *new_ie;
+	struct wpabuf *old_ie_buff = NULL;
+	struct wpabuf *new_ie_buff = NULL;
+	int new_ie_len, old_ie_len, ret, is_multi;
+
+	switch (ie) {
+	case WPA_IE_VENDOR_TYPE:
+		old_ie = wpa_bss_get_vendor_ie(old, ie);
+		new_ie = wpa_scan_get_vendor_ie(new, ie);
+		is_multi = 0;
+		break;
+	case WPS_IE_VENDOR_TYPE:
+		old_ie_buff = wpa_bss_get_vendor_ie_multi(old, ie);
+		new_ie_buff = wpa_scan_get_vendor_ie_multi(new, ie);
+		is_multi = 1;
+		break;
+	case WLAN_EID_RSN:
+	case WLAN_EID_SUPP_RATES:
+	case WLAN_EID_EXT_SUPP_RATES:
+		old_ie = wpa_bss_get_ie(old, ie);
+		new_ie = wpa_scan_get_ie(new, ie);
+		is_multi = 0;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "bss: %s: cannot compare IEs", __func__);
+		return 0;
+	}
+
+	if (is_multi) {
+		/* in case of multiple IEs stored in buffer */
+		old_ie = old_ie_buff ? wpabuf_head_u8(old_ie_buff) : NULL;
+		new_ie = new_ie_buff ? wpabuf_head_u8(new_ie_buff) : NULL;
+		old_ie_len = old_ie_buff ? wpabuf_len(old_ie_buff) : 0;
+		new_ie_len = new_ie_buff ? wpabuf_len(new_ie_buff) : 0;
+	} else {
+		/* in case of single IE */
+		old_ie_len = old_ie ? old_ie[1] + 2 : 0;
+		new_ie_len = new_ie ? new_ie[1] + 2 : 0;
+	}
+
+	if (!old_ie || !new_ie)
+		ret = !old_ie && !new_ie;
+	else
+		ret = (old_ie_len == new_ie_len &&
+		       os_memcmp(old_ie, new_ie, old_ie_len) == 0);
+
+	wpabuf_free(old_ie_buff);
+	wpabuf_free(new_ie_buff);
+
+	return ret;
+}
+
+
+static u32 wpa_bss_compare_res(const struct wpa_bss *old,
+			       const struct wpa_scan_res *new)
+{
+	u32 changes = 0;
+	int caps_diff = old->caps ^ new->caps;
+
+	if (old->freq != new->freq)
+		changes |= WPA_BSS_FREQ_CHANGED_FLAG;
+
+	if (old->level != new->level)
+		changes |= WPA_BSS_SIGNAL_CHANGED_FLAG;
+
+	if (caps_diff & IEEE80211_CAP_PRIVACY)
+		changes |= WPA_BSS_PRIVACY_CHANGED_FLAG;
+
+	if (caps_diff & IEEE80211_CAP_IBSS)
+		changes |= WPA_BSS_MODE_CHANGED_FLAG;
+
+	if (old->ie_len == new->ie_len &&
+	    os_memcmp(old + 1, new + 1, old->ie_len) == 0)
+		return changes;
+	changes |= WPA_BSS_IES_CHANGED_FLAG;
+
+	if (!are_ies_equal(old, new, WPA_IE_VENDOR_TYPE))
+		changes |= WPA_BSS_WPAIE_CHANGED_FLAG;
+
+	if (!are_ies_equal(old, new, WLAN_EID_RSN))
+		changes |= WPA_BSS_RSNIE_CHANGED_FLAG;
+
+	if (!are_ies_equal(old, new, WPS_IE_VENDOR_TYPE))
+		changes |= WPA_BSS_WPS_CHANGED_FLAG;
+
+	if (!are_ies_equal(old, new, WLAN_EID_SUPP_RATES) ||
+	    !are_ies_equal(old, new, WLAN_EID_EXT_SUPP_RATES))
+		changes |= WPA_BSS_RATES_CHANGED_FLAG;
+
+	return changes;
+}
+
+
+static void notify_bss_changes(struct wpa_supplicant *wpa_s, u32 changes,
+			       const struct wpa_bss *bss)
+{
+	if (changes & WPA_BSS_FREQ_CHANGED_FLAG)
+		wpas_notify_bss_freq_changed(wpa_s, bss->id);
+
+	if (changes & WPA_BSS_SIGNAL_CHANGED_FLAG)
+		wpas_notify_bss_signal_changed(wpa_s, bss->id);
+
+	if (changes & WPA_BSS_PRIVACY_CHANGED_FLAG)
+		wpas_notify_bss_privacy_changed(wpa_s, bss->id);
+
+	if (changes & WPA_BSS_MODE_CHANGED_FLAG)
+		wpas_notify_bss_mode_changed(wpa_s, bss->id);
+
+	if (changes & WPA_BSS_WPAIE_CHANGED_FLAG)
+		wpas_notify_bss_wpaie_changed(wpa_s, bss->id);
+
+	if (changes & WPA_BSS_RSNIE_CHANGED_FLAG)
+		wpas_notify_bss_rsnie_changed(wpa_s, bss->id);
+
+	if (changes & WPA_BSS_WPS_CHANGED_FLAG)
+		wpas_notify_bss_wps_changed(wpa_s, bss->id);
+
+	if (changes & WPA_BSS_IES_CHANGED_FLAG)
+		wpas_notify_bss_ies_changed(wpa_s, bss->id);
+
+	if (changes & WPA_BSS_RATES_CHANGED_FLAG)
+		wpas_notify_bss_rates_changed(wpa_s, bss->id);
+}
+
+
+static struct wpa_bss *
+wpa_bss_update(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+	       struct wpa_scan_res *res)
+{
+	u32 changes;
+
+	changes = wpa_bss_compare_res(bss, res);
+	bss->scan_miss_count = 0;
+	bss->last_update_idx = wpa_s->bss_update_idx;
+	wpa_bss_copy_res(bss, res);
+	/* Move the entry to the end of the list */
+	dl_list_del(&bss->list);
+	if (bss->ie_len + bss->beacon_ie_len >=
+	    res->ie_len + res->beacon_ie_len) {
+		os_memcpy(bss + 1, res + 1, res->ie_len + res->beacon_ie_len);
+		bss->ie_len = res->ie_len;
+		bss->beacon_ie_len = res->beacon_ie_len;
+	} else {
+		struct wpa_bss *nbss;
+		struct dl_list *prev = bss->list_id.prev;
+		dl_list_del(&bss->list_id);
+		nbss = os_realloc(bss, sizeof(*bss) + res->ie_len +
+				  res->beacon_ie_len);
+		if (nbss) {
+			unsigned int i;
+			for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+				if (wpa_s->last_scan_res[i] == bss) {
+					wpa_s->last_scan_res[i] = nbss;
+					break;
+				}
+			}
+			if (wpa_s->current_bss == bss)
+				wpa_s->current_bss = nbss;
+			bss = nbss;
+			os_memcpy(bss + 1, res + 1,
+				  res->ie_len + res->beacon_ie_len);
+			bss->ie_len = res->ie_len;
+			bss->beacon_ie_len = res->beacon_ie_len;
+		}
+		dl_list_add(prev, &bss->list_id);
+	}
+	if (changes & WPA_BSS_IES_CHANGED_FLAG)
+		wpa_bss_set_hessid(bss);
+	dl_list_add_tail(&wpa_s->bss, &bss->list);
+
+	notify_bss_changes(wpa_s, changes, bss);
+
+	return bss;
+}
+
+
+/**
+ * wpa_bss_update_start - Start a BSS table update from scan results
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is called at the start of each BSS table update round for new
+ * scan results. The actual scan result entries are indicated with calls to
+ * wpa_bss_update_scan_res() and the update round is finished with a call to
+ * wpa_bss_update_end().
+ */
+void wpa_bss_update_start(struct wpa_supplicant *wpa_s)
+{
+	wpa_s->bss_update_idx++;
+	wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Start scan result update %u",
+		wpa_s->bss_update_idx);
+	wpa_s->last_scan_res_used = 0;
+}
+
+
+/**
+ * wpa_bss_update_scan_res - Update a BSS table entry based on a scan result
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @res: Scan result
+ *
+ * This function updates a BSS table entry (or adds one) based on a scan result.
+ * This is called separately for each scan result between the calls to
+ * wpa_bss_update_start() and wpa_bss_update_end().
+ */
+void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
+			     struct wpa_scan_res *res)
+{
+	const u8 *ssid, *p2p;
+	struct wpa_bss *bss;
+
+	ssid = wpa_scan_get_ie(res, WLAN_EID_SSID);
+	if (ssid == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: No SSID IE included for "
+			MACSTR, MAC2STR(res->bssid));
+		return;
+	}
+	if (ssid[1] > 32) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "BSS: Too long SSID IE included for "
+			MACSTR, MAC2STR(res->bssid));
+		return;
+	}
+
+	p2p = wpa_scan_get_vendor_ie(res, P2P_IE_VENDOR_TYPE);
+#ifdef CONFIG_P2P
+	if (p2p == NULL &&
+	    wpa_s->p2p_group_interface != NOT_P2P_GROUP_INTERFACE) {
+		/*
+		 * If it's a P2P specific interface, then don't update
+		 * the scan result without a P2P IE.
+		 */
+		wpa_printf(MSG_DEBUG, "BSS: No P2P IE - skipping BSS " MACSTR
+			   " update for P2P interface", MAC2STR(res->bssid));
+		return;
+	}
+#endif /* CONFIG_P2P */
+	if (p2p && ssid[1] == P2P_WILDCARD_SSID_LEN &&
+	    os_memcmp(ssid + 2, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) == 0)
+		return; /* Skip P2P listen discovery results here */
+
+	/* TODO: add option for ignoring BSSes we are not interested in
+	 * (to save memory) */
+	bss = wpa_bss_get(wpa_s, res->bssid, ssid + 2, ssid[1]);
+	if (bss == NULL)
+		bss = wpa_bss_add(wpa_s, ssid + 2, ssid[1], res);
+	else
+		bss = wpa_bss_update(wpa_s, bss, res);
+
+	if (bss == NULL)
+		return;
+	if (wpa_s->last_scan_res_used >= wpa_s->last_scan_res_size) {
+		struct wpa_bss **n;
+		unsigned int siz;
+		if (wpa_s->last_scan_res_size == 0)
+			siz = 32;
+		else
+			siz = wpa_s->last_scan_res_size * 2;
+		n = os_realloc_array(wpa_s->last_scan_res, siz,
+				     sizeof(struct wpa_bss *));
+		if (n == NULL)
+			return;
+		wpa_s->last_scan_res = n;
+		wpa_s->last_scan_res_size = siz;
+	}
+
+	wpa_s->last_scan_res[wpa_s->last_scan_res_used++] = bss;
+}
+
+
+static int wpa_bss_included_in_scan(const struct wpa_bss *bss,
+				    const struct scan_info *info)
+{
+	int found;
+	size_t i;
+
+	if (info == NULL)
+		return 1;
+
+	if (info->num_freqs) {
+		found = 0;
+		for (i = 0; i < info->num_freqs; i++) {
+			if (bss->freq == info->freqs[i]) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found)
+			return 0;
+	}
+
+	if (info->num_ssids) {
+		found = 0;
+		for (i = 0; i < info->num_ssids; i++) {
+			const struct wpa_driver_scan_ssid *s = &info->ssids[i];
+			if ((s->ssid == NULL || s->ssid_len == 0) ||
+			    (s->ssid_len == bss->ssid_len &&
+			     os_memcmp(s->ssid, bss->ssid, bss->ssid_len) ==
+			     0)) {
+				found = 1;
+				break;
+			}
+		}
+		if (!found)
+			return 0;
+	}
+
+	return 1;
+}
+
+
+/**
+ * wpa_bss_update_end - End a BSS table update from scan results
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @info: Information about scan parameters
+ * @new_scan: Whether this update round was based on a new scan
+ *
+ * This function is called at the end of each BSS table update round for new
+ * scan results. The start of the update was indicated with a call to
+ * wpa_bss_update_start().
+ */
+void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
+			int new_scan)
+{
+	struct wpa_bss *bss, *n;
+
+	wpa_s->last_scan_full = 0;
+	os_get_time(&wpa_s->last_scan);
+	if (!new_scan)
+		return; /* do not expire entries without new scan */
+
+	if (info && !info->aborted && !info->freqs) {
+		size_t i;
+		if (info->num_ssids == 0) {
+			wpa_s->last_scan_full = 1;
+		} else {
+			for (i = 0; i < info->num_ssids; i++) {
+				if (info->ssids[i].ssid == NULL ||
+				    info->ssids[i].ssid_len == 0) {
+					wpa_s->last_scan_full = 1;
+					break;
+				}
+			}
+		}
+	}
+
+	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
+		if (wpa_bss_in_use(wpa_s, bss))
+			continue;
+		if (!wpa_bss_included_in_scan(bss, info))
+			continue; /* expire only BSSes that were scanned */
+		if (bss->last_update_idx < wpa_s->bss_update_idx)
+			bss->scan_miss_count++;
+		if (bss->scan_miss_count >=
+		    wpa_s->conf->bss_expiration_scan_count) {
+			wpa_bss_remove(wpa_s, bss, "no match in scan");
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "BSS: last_scan_res_used=%u/%u "
+		   "last_scan_full=%d",
+		   wpa_s->last_scan_res_used, wpa_s->last_scan_res_size,
+		   wpa_s->last_scan_full);
+}
+
+
+/**
+ * wpa_bss_flush_by_age - Flush old BSS entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @age: Maximum entry age in seconds
+ *
+ * Remove BSS entries that have not been updated during the last @age seconds.
+ */
+void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age)
+{
+	struct wpa_bss *bss, *n;
+	struct os_time t;
+
+	if (dl_list_empty(&wpa_s->bss))
+		return;
+
+	os_get_time(&t);
+	t.sec -= age;
+
+	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
+		if (wpa_bss_in_use(wpa_s, bss))
+			continue;
+
+		if (os_time_before(&bss->last_update, &t)) {
+			wpa_bss_remove(wpa_s, bss, __func__);
+		} else
+			break;
+	}
+}
+
+
+static void wpa_bss_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	wpa_bss_flush_by_age(wpa_s, wpa_s->conf->bss_expiration_age);
+	eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
+			       wpa_bss_timeout, wpa_s, NULL);
+}
+
+
+/**
+ * wpa_bss_init - Initialize BSS table
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This prepares BSS table lists and timer for periodic updates. The BSS table
+ * is deinitialized with wpa_bss_deinit() once not needed anymore.
+ */
+int wpa_bss_init(struct wpa_supplicant *wpa_s)
+{
+	dl_list_init(&wpa_s->bss);
+	dl_list_init(&wpa_s->bss_id);
+	eloop_register_timeout(WPA_BSS_EXPIRATION_PERIOD, 0,
+			       wpa_bss_timeout, wpa_s, NULL);
+	return 0;
+}
+
+
+/**
+ * wpa_bss_flush - Flush all unused BSS entries
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void wpa_bss_flush(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss, *n;
+
+	if (wpa_s->bss.next == NULL)
+		return; /* BSS table not yet initialized */
+
+	dl_list_for_each_safe(bss, n, &wpa_s->bss, struct wpa_bss, list) {
+		if (wpa_bss_in_use(wpa_s, bss))
+			continue;
+		wpa_bss_remove(wpa_s, bss, __func__);
+	}
+}
+
+
+/**
+ * wpa_bss_deinit - Deinitialize BSS table
+ * @wpa_s: Pointer to wpa_supplicant data
+ */
+void wpa_bss_deinit(struct wpa_supplicant *wpa_s)
+{
+	eloop_cancel_timeout(wpa_bss_timeout, wpa_s, NULL);
+	wpa_bss_flush(wpa_s);
+}
+
+
+/**
+ * wpa_bss_get_bssid - Fetch a BSS table entry based on BSSID
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
+struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
+				   const u8 *bssid)
+{
+	struct wpa_bss *bss;
+	if (!wpa_supplicant_filter_bssid_match(wpa_s, bssid))
+		return NULL;
+	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (os_memcmp(bss->bssid, bssid, ETH_ALEN) == 0)
+			return bss;
+	}
+	return NULL;
+}
+
+
+#ifdef CONFIG_P2P
+/**
+ * wpa_bss_get_p2p_dev_addr - Fetch a BSS table entry based on P2P Device Addr
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @dev_addr: P2P Device Address of the GO
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
+struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
+					  const u8 *dev_addr)
+{
+	struct wpa_bss *bss;
+	dl_list_for_each_reverse(bss, &wpa_s->bss, struct wpa_bss, list) {
+		u8 addr[ETH_ALEN];
+		if (p2p_parse_dev_addr((const u8 *) (bss + 1), bss->ie_len,
+				       addr) == 0 &&
+		    os_memcmp(addr, dev_addr, ETH_ALEN) == 0)
+			return bss;
+	}
+	return NULL;
+}
+#endif /* CONFIG_P2P */
+
+
+/**
+ * wpa_bss_get_id - Fetch a BSS table entry based on identifier
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @id: Unique identifier (struct wpa_bss::id) assigned for the entry
+ * Returns: Pointer to the BSS entry or %NULL if not found
+ */
+struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id)
+{
+	struct wpa_bss *bss;
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (bss->id == id)
+			return bss;
+	}
+	return NULL;
+}
+
+
+/**
+ * wpa_bss_get_ie - Fetch a specified information element from a BSS entry
+ * @bss: BSS table entry
+ * @ie: Information element identitifier (WLAN_EID_*)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the BSS
+ * entry.
+ */
+const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie)
+{
+	const u8 *end, *pos;
+
+	pos = (const u8 *) (bss + 1);
+	end = pos + bss->ie_len;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == ie)
+			return pos;
+		pos += 2 + pos[1];
+	}
+
+	return NULL;
+}
+
+
+/**
+ * wpa_bss_get_vendor_ie - Fetch a vendor information element from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the BSS
+ * entry.
+ */
+const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type)
+{
+	const u8 *end, *pos;
+
+	pos = (const u8 *) (bss + 1);
+	end = pos + bss->ie_len;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			return pos;
+		pos += 2 + pos[1];
+	}
+
+	return NULL;
+}
+
+
+/**
+ * wpa_bss_get_vendor_ie_multi - Fetch vendor IE data from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element payload or %NULL if not found
+ *
+ * This function returns concatenated payload of possibly fragmented vendor
+ * specific information elements in the BSS entry. The caller is responsible for
+ * freeing the returned buffer.
+ */
+struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
+					    u32 vendor_type)
+{
+	struct wpabuf *buf;
+	const u8 *end, *pos;
+
+	buf = wpabuf_alloc(bss->ie_len);
+	if (buf == NULL)
+		return NULL;
+
+	pos = (const u8 *) (bss + 1);
+	end = pos + bss->ie_len;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
+		pos += 2 + pos[1];
+	}
+
+	if (wpabuf_len(buf) == 0) {
+		wpabuf_free(buf);
+		buf = NULL;
+	}
+
+	return buf;
+}
+
+
+/**
+ * wpa_bss_get_vendor_ie_multi_beacon - Fetch vendor IE data from a BSS entry
+ * @bss: BSS table entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element payload or %NULL if not found
+ *
+ * This function returns concatenated payload of possibly fragmented vendor
+ * specific information elements in the BSS entry. The caller is responsible for
+ * freeing the returned buffer.
+ *
+ * This function is like wpa_bss_get_vendor_ie_multi(), but uses IE buffer only
+ * from Beacon frames instead of either Beacon or Probe Response frames.
+ */
+struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
+						   u32 vendor_type)
+{
+	struct wpabuf *buf;
+	const u8 *end, *pos;
+
+	buf = wpabuf_alloc(bss->beacon_ie_len);
+	if (buf == NULL)
+		return NULL;
+
+	pos = (const u8 *) (bss + 1);
+	pos += bss->ie_len;
+	end = pos + bss->beacon_ie_len;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
+		pos += 2 + pos[1];
+	}
+
+	if (wpabuf_len(buf) == 0) {
+		wpabuf_free(buf);
+		buf = NULL;
+	}
+
+	return buf;
+}
+
+
+/**
+ * wpa_bss_get_max_rate - Get maximum legacy TX rate supported in a BSS
+ * @bss: BSS table entry
+ * Returns: Maximum legacy rate in units of 500 kbps
+ */
+int wpa_bss_get_max_rate(const struct wpa_bss *bss)
+{
+	int rate = 0;
+	const u8 *ie;
+	int i;
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
+	for (i = 0; ie && i < ie[1]; i++) {
+		if ((ie[i + 2] & 0x7f) > rate)
+			rate = ie[i + 2] & 0x7f;
+	}
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
+	for (i = 0; ie && i < ie[1]; i++) {
+		if ((ie[i + 2] & 0x7f) > rate)
+			rate = ie[i + 2] & 0x7f;
+	}
+
+	return rate;
+}
+
+
+/**
+ * wpa_bss_get_bit_rates - Get legacy TX rates supported in a BSS
+ * @bss: BSS table entry
+ * @rates: Buffer for returning a pointer to the rates list (units of 500 kbps)
+ * Returns: number of legacy TX rates or -1 on failure
+ *
+ * The caller is responsible for freeing the returned buffer with os_free() in
+ * case of success.
+ */
+int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates)
+{
+	const u8 *ie, *ie2;
+	int i, j;
+	unsigned int len;
+	u8 *r;
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_SUPP_RATES);
+	ie2 = wpa_bss_get_ie(bss, WLAN_EID_EXT_SUPP_RATES);
+
+	len = (ie ? ie[1] : 0) + (ie2 ? ie2[1] : 0);
+
+	r = os_malloc(len);
+	if (!r)
+		return -1;
+
+	for (i = 0; ie && i < ie[1]; i++)
+		r[i] = ie[i + 2] & 0x7f;
+
+	for (j = 0; ie2 && j < ie2[1]; j++)
+		r[i + j] = ie2[j + 2] & 0x7f;
+
+	*rates = r;
+	return len;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/bss.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,125 @@
+/*
+ * BSS table
+ * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef BSS_H
+#define BSS_H
+
+struct wpa_scan_res;
+
+#define WPA_BSS_QUAL_INVALID		BIT(0)
+#define WPA_BSS_NOISE_INVALID		BIT(1)
+#define WPA_BSS_LEVEL_INVALID		BIT(2)
+#define WPA_BSS_LEVEL_DBM		BIT(3)
+#define WPA_BSS_AUTHENTICATED		BIT(4)
+#define WPA_BSS_ASSOCIATED		BIT(5)
+#define WPA_BSS_ANQP_FETCH_TRIED	BIT(6)
+
+/**
+ * struct wpa_bss_anqp - ANQP data for a BSS entry (struct wpa_bss)
+ */
+struct wpa_bss_anqp {
+	/** Number of BSS entries referring to this ANQP data instance */
+	unsigned int users;
+#ifdef CONFIG_INTERWORKING
+	struct wpabuf *venue_name;
+	struct wpabuf *network_auth_type;
+	struct wpabuf *roaming_consortium;
+	struct wpabuf *ip_addr_type_availability;
+	struct wpabuf *nai_realm;
+	struct wpabuf *anqp_3gpp;
+	struct wpabuf *domain_name;
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+	struct wpabuf *hs20_operator_friendly_name;
+	struct wpabuf *hs20_wan_metrics;
+	struct wpabuf *hs20_connection_capability;
+	struct wpabuf *hs20_operating_class;
+#endif /* CONFIG_HS20 */
+};
+
+/**
+ * struct wpa_bss - BSS table
+ *
+ * This structure is used to store information about neighboring BSSes in
+ * generic format. It is mainly updated based on scan results from the driver.
+ */
+struct wpa_bss {
+	/** List entry for struct wpa_supplicant::bss */
+	struct dl_list list;
+	/** List entry for struct wpa_supplicant::bss_id */
+	struct dl_list list_id;
+	/** Unique identifier for this BSS entry */
+	unsigned int id;
+	/** Number of counts without seeing this BSS */
+	unsigned int scan_miss_count;
+	/** Index of the last scan update */
+	unsigned int last_update_idx;
+	/** Information flags about the BSS/IBSS (WPA_BSS_*) */
+	unsigned int flags;
+	/** BSSID */
+	u8 bssid[ETH_ALEN];
+	/** HESSID */
+	u8 hessid[ETH_ALEN];
+	/** SSID */
+	u8 ssid[32];
+	/** Length of SSID */
+	size_t ssid_len;
+	/** Frequency of the channel in MHz (e.g., 2412 = channel 1) */
+	int freq;
+	/** Beacon interval in TUs (host byte order) */
+	u16 beacon_int;
+	/** Capability information field in host byte order */
+	u16 caps;
+	/** Signal quality */
+	int qual;
+	/** Noise level */
+	int noise;
+	/** Signal level */
+	int level;
+	/** Timestamp of last Beacon/Probe Response frame */
+	u64 tsf;
+	/** Time of the last update (i.e., Beacon or Probe Response RX) */
+	struct os_time last_update;
+	/** ANQP data */
+	struct wpa_bss_anqp *anqp;
+	/** Length of the following IE field in octets (from Probe Response) */
+	size_t ie_len;
+	/** Length of the following Beacon IE field in octets */
+	size_t beacon_ie_len;
+	/* followed by ie_len octets of IEs */
+	/* followed by beacon_ie_len octets of IEs */
+};
+
+void wpa_bss_update_start(struct wpa_supplicant *wpa_s);
+void wpa_bss_update_scan_res(struct wpa_supplicant *wpa_s,
+			     struct wpa_scan_res *res);
+void wpa_bss_update_end(struct wpa_supplicant *wpa_s, struct scan_info *info,
+			int new_scan);
+int wpa_bss_init(struct wpa_supplicant *wpa_s);
+void wpa_bss_deinit(struct wpa_supplicant *wpa_s);
+void wpa_bss_flush(struct wpa_supplicant *wpa_s);
+void wpa_bss_flush_by_age(struct wpa_supplicant *wpa_s, int age);
+struct wpa_bss * wpa_bss_get(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			     const u8 *ssid, size_t ssid_len);
+struct wpa_bss * wpa_bss_get_bssid(struct wpa_supplicant *wpa_s,
+				   const u8 *bssid);
+struct wpa_bss * wpa_bss_get_p2p_dev_addr(struct wpa_supplicant *wpa_s,
+					  const u8 *dev_addr);
+struct wpa_bss * wpa_bss_get_id(struct wpa_supplicant *wpa_s, unsigned int id);
+const u8 * wpa_bss_get_ie(const struct wpa_bss *bss, u8 ie);
+const u8 * wpa_bss_get_vendor_ie(const struct wpa_bss *bss, u32 vendor_type);
+struct wpabuf * wpa_bss_get_vendor_ie_multi(const struct wpa_bss *bss,
+					    u32 vendor_type);
+struct wpabuf * wpa_bss_get_vendor_ie_multi_beacon(const struct wpa_bss *bss,
+						   u32 vendor_type);
+int wpa_bss_get_max_rate(const struct wpa_bss *bss);
+int wpa_bss_get_bit_rates(const struct wpa_bss *bss, u8 **rates);
+struct wpa_bss_anqp * wpa_bss_anqp_alloc(void);
+int wpa_bss_anqp_unshare_alloc(struct wpa_bss *bss);
+
+#endif /* BSS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/config.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,3134 @@
+/*
+ * WPA Supplicant / Configuration parser and common functions
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "utils/uuid.h"
+#include "crypto/sha1.h"
+#include "rsn_supp/wpa.h"
+#include "eap_peer/eap.h"
+#include "p2p/p2p.h"
+#include "config.h"
+
+
+#if !defined(CONFIG_CTRL_IFACE) && defined(CONFIG_NO_CONFIG_WRITE)
+#define NO_CONFIG_WRITE
+#endif
+
+/*
+ * Structure for network configuration parsing. This data is used to implement
+ * a generic parser for each network block variable. The table of configuration
+ * variables is defined below in this file (ssid_fields[]).
+ */
+struct parse_data {
+	/* Configuration variable name */
+	char *name;
+
+	/* Parser function for this variable */
+	int (*parser)(const struct parse_data *data, struct wpa_ssid *ssid,
+		      int line, const char *value);
+
+#ifndef NO_CONFIG_WRITE
+	/* Writer function (i.e., to get the variable in text format from
+	 * internal presentation). */
+	char * (*writer)(const struct parse_data *data, struct wpa_ssid *ssid);
+#endif /* NO_CONFIG_WRITE */
+
+	/* Variable specific parameters for the parser. */
+	void *param1, *param2, *param3, *param4;
+
+	/* 0 = this variable can be included in debug output and ctrl_iface
+	 * 1 = this variable contains key/private data and it must not be
+	 *     included in debug output unless explicitly requested. In
+	 *     addition, this variable will not be readable through the
+	 *     ctrl_iface.
+	 */
+	int key_data;
+};
+
+
+static int wpa_config_parse_str(const struct parse_data *data,
+				struct wpa_ssid *ssid,
+				int line, const char *value)
+{
+	size_t res_len, *dst_len;
+	char **dst, *tmp;
+
+	if (os_strcmp(value, "NULL") == 0) {
+		wpa_printf(MSG_DEBUG, "Unset configuration string '%s'",
+			   data->name);
+		tmp = NULL;
+		res_len = 0;
+		goto set;
+	}
+
+	tmp = wpa_config_parse_string(value, &res_len);
+	if (tmp == NULL) {
+		wpa_printf(MSG_ERROR, "Line %d: failed to parse %s '%s'.",
+			   line, data->name,
+			   data->key_data ? "[KEY DATA REMOVED]" : value);
+		return -1;
+	}
+
+	if (data->key_data) {
+		wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
+				      (u8 *) tmp, res_len);
+	} else {
+		wpa_hexdump_ascii(MSG_MSGDUMP, data->name,
+				  (u8 *) tmp, res_len);
+	}
+
+	if (data->param3 && res_len < (size_t) data->param3) {
+		wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
+			   "min_len=%ld)", line, data->name,
+			   (unsigned long) res_len, (long) data->param3);
+		os_free(tmp);
+		return -1;
+	}
+
+	if (data->param4 && res_len > (size_t) data->param4) {
+		wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
+			   "max_len=%ld)", line, data->name,
+			   (unsigned long) res_len, (long) data->param4);
+		os_free(tmp);
+		return -1;
+	}
+
+set:
+	dst = (char **) (((u8 *) ssid) + (long) data->param1);
+	dst_len = (size_t *) (((u8 *) ssid) + (long) data->param2);
+	os_free(*dst);
+	*dst = tmp;
+	if (data->param2)
+		*dst_len = res_len;
+
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_string_ascii(const u8 *value, size_t len)
+{
+	char *buf;
+
+	buf = os_malloc(len + 3);
+	if (buf == NULL)
+		return NULL;
+	buf[0] = '"';
+	os_memcpy(buf + 1, value, len);
+	buf[len + 1] = '"';
+	buf[len + 2] = '\0';
+
+	return buf;
+}
+
+
+static char * wpa_config_write_string_hex(const u8 *value, size_t len)
+{
+	char *buf;
+
+	buf = os_zalloc(2 * len + 1);
+	if (buf == NULL)
+		return NULL;
+	wpa_snprintf_hex(buf, 2 * len + 1, value, len);
+
+	return buf;
+}
+
+
+static char * wpa_config_write_string(const u8 *value, size_t len)
+{
+	if (value == NULL)
+		return NULL;
+
+	if (is_hex(value, len))
+		return wpa_config_write_string_hex(value, len);
+	else
+		return wpa_config_write_string_ascii(value, len);
+}
+
+
+static char * wpa_config_write_str(const struct parse_data *data,
+				   struct wpa_ssid *ssid)
+{
+	size_t len;
+	char **src;
+
+	src = (char **) (((u8 *) ssid) + (long) data->param1);
+	if (*src == NULL)
+		return NULL;
+
+	if (data->param2)
+		len = *((size_t *) (((u8 *) ssid) + (long) data->param2));
+	else
+		len = os_strlen(*src);
+
+	return wpa_config_write_string((const u8 *) *src, len);
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_int(const struct parse_data *data,
+				struct wpa_ssid *ssid,
+				int line, const char *value)
+{
+	int *dst;
+
+	dst = (int *) (((u8 *) ssid) + (long) data->param1);
+	*dst = atoi(value);
+	wpa_printf(MSG_MSGDUMP, "%s=%d (0x%x)", data->name, *dst, *dst);
+
+	if (data->param3 && *dst < (long) data->param3) {
+		wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
+			   "min_value=%ld)", line, data->name, *dst,
+			   (long) data->param3);
+		*dst = (long) data->param3;
+		return -1;
+	}
+
+	if (data->param4 && *dst > (long) data->param4) {
+		wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
+			   "max_value=%ld)", line, data->name, *dst,
+			   (long) data->param4);
+		*dst = (long) data->param4;
+		return -1;
+	}
+
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_int(const struct parse_data *data,
+				   struct wpa_ssid *ssid)
+{
+	int *src, res;
+	char *value;
+
+	src = (int *) (((u8 *) ssid) + (long) data->param1);
+
+	value = os_malloc(20);
+	if (value == NULL)
+		return NULL;
+	res = os_snprintf(value, 20, "%d", *src);
+	if (res < 0 || res >= 20) {
+		os_free(value);
+		return NULL;
+	}
+	value[20 - 1] = '\0';
+	return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_bssid(const struct parse_data *data,
+				  struct wpa_ssid *ssid, int line,
+				  const char *value)
+{
+	if (value[0] == '\0' || os_strcmp(value, "\"\"") == 0 ||
+	    os_strcmp(value, "any") == 0) {
+		ssid->bssid_set = 0;
+		wpa_printf(MSG_MSGDUMP, "BSSID any");
+		return 0;
+	}
+	if (hwaddr_aton(value, ssid->bssid)) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid BSSID '%s'.",
+			   line, value);
+		return -1;
+	}
+	ssid->bssid_set = 1;
+	wpa_hexdump(MSG_MSGDUMP, "BSSID", ssid->bssid, ETH_ALEN);
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_bssid(const struct parse_data *data,
+				     struct wpa_ssid *ssid)
+{
+	char *value;
+	int res;
+
+	if (!ssid->bssid_set)
+		return NULL;
+
+	value = os_malloc(20);
+	if (value == NULL)
+		return NULL;
+	res = os_snprintf(value, 20, MACSTR, MAC2STR(ssid->bssid));
+	if (res < 0 || res >= 20) {
+		os_free(value);
+		return NULL;
+	}
+	value[20 - 1] = '\0';
+	return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_psk(const struct parse_data *data,
+				struct wpa_ssid *ssid, int line,
+				const char *value)
+{
+#ifdef CONFIG_EXT_PASSWORD
+	if (os_strncmp(value, "ext:", 4) == 0) {
+		os_free(ssid->passphrase);
+		ssid->passphrase = NULL;
+		ssid->psk_set = 0;
+		os_free(ssid->ext_psk);
+		ssid->ext_psk = os_strdup(value + 4);
+		if (ssid->ext_psk == NULL)
+			return -1;
+		wpa_printf(MSG_DEBUG, "PSK: External password '%s'",
+			   ssid->ext_psk);
+		return 0;
+	}
+#endif /* CONFIG_EXT_PASSWORD */
+
+	if (*value == '"') {
+#ifndef CONFIG_NO_PBKDF2
+		const char *pos;
+		size_t len;
+
+		value++;
+		pos = os_strrchr(value, '"');
+		if (pos)
+			len = pos - value;
+		else
+			len = os_strlen(value);
+		if (len < 8 || len > 63) {
+			wpa_printf(MSG_ERROR, "Line %d: Invalid passphrase "
+				   "length %lu (expected: 8..63) '%s'.",
+				   line, (unsigned long) len, value);
+			return -1;
+		}
+		wpa_hexdump_ascii_key(MSG_MSGDUMP, "PSK (ASCII passphrase)",
+				      (u8 *) value, len);
+		if (ssid->passphrase && os_strlen(ssid->passphrase) == len &&
+		    os_memcmp(ssid->passphrase, value, len) == 0)
+			return 0;
+		ssid->psk_set = 0;
+		os_free(ssid->passphrase);
+		ssid->passphrase = os_malloc(len + 1);
+		if (ssid->passphrase == NULL)
+			return -1;
+		os_memcpy(ssid->passphrase, value, len);
+		ssid->passphrase[len] = '\0';
+		return 0;
+#else /* CONFIG_NO_PBKDF2 */
+		wpa_printf(MSG_ERROR, "Line %d: ASCII passphrase not "
+			   "supported.", line);
+		return -1;
+#endif /* CONFIG_NO_PBKDF2 */
+	}
+
+	if (hexstr2bin(value, ssid->psk, PMK_LEN) ||
+	    value[PMK_LEN * 2] != '\0') {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
+			   line, value);
+		return -1;
+	}
+
+	os_free(ssid->passphrase);
+	ssid->passphrase = NULL;
+
+	ssid->psk_set = 1;
+	wpa_hexdump_key(MSG_MSGDUMP, "PSK", ssid->psk, PMK_LEN);
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_psk(const struct parse_data *data,
+				   struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_EXT_PASSWORD
+	if (ssid->ext_psk) {
+		size_t len = 4 + os_strlen(ssid->ext_psk) + 1;
+		char *buf = os_malloc(len);
+		if (buf == NULL)
+			return NULL;
+		os_snprintf(buf, len, "ext:%s", ssid->ext_psk);
+		return buf;
+	}
+#endif /* CONFIG_EXT_PASSWORD */
+
+	if (ssid->passphrase)
+		return wpa_config_write_string_ascii(
+			(const u8 *) ssid->passphrase,
+			os_strlen(ssid->passphrase));
+
+	if (ssid->psk_set)
+		return wpa_config_write_string_hex(ssid->psk, PMK_LEN);
+
+	return NULL;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_proto(const struct parse_data *data,
+				  struct wpa_ssid *ssid, int line,
+				  const char *value)
+{
+	int val = 0, last, errors = 0;
+	char *start, *end, *buf;
+
+	buf = os_strdup(value);
+	if (buf == NULL)
+		return -1;
+	start = buf;
+
+	while (*start != '\0') {
+		while (*start == ' ' || *start == '\t')
+			start++;
+		if (*start == '\0')
+			break;
+		end = start;
+		while (*end != ' ' && *end != '\t' && *end != '\0')
+			end++;
+		last = *end == '\0';
+		*end = '\0';
+		if (os_strcmp(start, "WPA") == 0)
+			val |= WPA_PROTO_WPA;
+		else if (os_strcmp(start, "RSN") == 0 ||
+			 os_strcmp(start, "WPA2") == 0)
+			val |= WPA_PROTO_RSN;
+		else {
+			wpa_printf(MSG_ERROR, "Line %d: invalid proto '%s'",
+				   line, start);
+			errors++;
+		}
+
+		if (last)
+			break;
+		start = end + 1;
+	}
+	os_free(buf);
+
+	if (val == 0) {
+		wpa_printf(MSG_ERROR,
+			   "Line %d: no proto values configured.", line);
+		errors++;
+	}
+
+	wpa_printf(MSG_MSGDUMP, "proto: 0x%x", val);
+	ssid->proto = val;
+	return errors ? -1 : 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_proto(const struct parse_data *data,
+				     struct wpa_ssid *ssid)
+{
+	int first = 1, ret;
+	char *buf, *pos, *end;
+
+	pos = buf = os_zalloc(10);
+	if (buf == NULL)
+		return NULL;
+	end = buf + 10;
+
+	if (ssid->proto & WPA_PROTO_WPA) {
+		ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (ssid->proto & WPA_PROTO_RSN) {
+		ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return buf;
+		pos += ret;
+		first = 0;
+	}
+
+	return buf;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_key_mgmt(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	int val = 0, last, errors = 0;
+	char *start, *end, *buf;
+
+	buf = os_strdup(value);
+	if (buf == NULL)
+		return -1;
+	start = buf;
+
+	while (*start != '\0') {
+		while (*start == ' ' || *start == '\t')
+			start++;
+		if (*start == '\0')
+			break;
+		end = start;
+		while (*end != ' ' && *end != '\t' && *end != '\0')
+			end++;
+		last = *end == '\0';
+		*end = '\0';
+		if (os_strcmp(start, "WPA-PSK") == 0)
+			val |= WPA_KEY_MGMT_PSK;
+		else if (os_strcmp(start, "WPA-EAP") == 0)
+			val |= WPA_KEY_MGMT_IEEE8021X;
+		else if (os_strcmp(start, "IEEE8021X") == 0)
+			val |= WPA_KEY_MGMT_IEEE8021X_NO_WPA;
+		else if (os_strcmp(start, "NONE") == 0)
+			val |= WPA_KEY_MGMT_NONE;
+		else if (os_strcmp(start, "WPA-NONE") == 0)
+			val |= WPA_KEY_MGMT_WPA_NONE;
+#ifdef CONFIG_IEEE80211R
+		else if (os_strcmp(start, "FT-PSK") == 0)
+			val |= WPA_KEY_MGMT_FT_PSK;
+		else if (os_strcmp(start, "FT-EAP") == 0)
+			val |= WPA_KEY_MGMT_FT_IEEE8021X;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+		else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
+			val |= WPA_KEY_MGMT_PSK_SHA256;
+		else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
+			val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WPS
+		else if (os_strcmp(start, "WPS") == 0)
+			val |= WPA_KEY_MGMT_WPS;
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_SAE
+		else if (os_strcmp(start, "SAE") == 0)
+			val |= WPA_KEY_MGMT_SAE;
+		else if (os_strcmp(start, "FT-SAE") == 0)
+			val |= WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
+		else {
+			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
+				   line, start);
+			errors++;
+		}
+
+		if (last)
+			break;
+		start = end + 1;
+	}
+	os_free(buf);
+
+	if (val == 0) {
+		wpa_printf(MSG_ERROR,
+			   "Line %d: no key_mgmt values configured.", line);
+		errors++;
+	}
+
+	wpa_printf(MSG_MSGDUMP, "key_mgmt: 0x%x", val);
+	ssid->key_mgmt = val;
+	return errors ? -1 : 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_key_mgmt(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	char *buf, *pos, *end;
+	int ret;
+
+	pos = buf = os_zalloc(50);
+	if (buf == NULL)
+		return NULL;
+	end = buf + 50;
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK) {
+		ret = os_snprintf(pos, end - pos, "%sWPA-PSK",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+		ret = os_snprintf(pos, end - pos, "%sWPA-EAP",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		ret = os_snprintf(pos, end - pos, "%sIEEE8021X",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_NONE) {
+		ret = os_snprintf(pos, end - pos, "%sNONE",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
+		ret = os_snprintf(pos, end - pos, "%sWPA-NONE",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_PSK)
+		pos += os_snprintf(pos, end - pos, "%sFT-PSK",
+				   pos == buf ? "" : " ");
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
+		pos += os_snprintf(pos, end - pos, "%sFT-EAP",
+				   pos == buf ? "" : " ");
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211W
+	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+		pos += os_snprintf(pos, end - pos, "%sWPA-PSK-SHA256",
+				   pos == buf ? "" : " ");
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
+		pos += os_snprintf(pos, end - pos, "%sWPA-EAP-SHA256",
+				   pos == buf ? "" : " ");
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_WPS
+	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
+		pos += os_snprintf(pos, end - pos, "%sWPS",
+				   pos == buf ? "" : " ");
+#endif /* CONFIG_WPS */
+
+	return buf;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_cipher(int line, const char *value)
+{
+	int val = 0, last;
+	char *start, *end, *buf;
+
+	buf = os_strdup(value);
+	if (buf == NULL)
+		return -1;
+	start = buf;
+
+	while (*start != '\0') {
+		while (*start == ' ' || *start == '\t')
+			start++;
+		if (*start == '\0')
+			break;
+		end = start;
+		while (*end != ' ' && *end != '\t' && *end != '\0')
+			end++;
+		last = *end == '\0';
+		*end = '\0';
+		if (os_strcmp(start, "CCMP") == 0)
+			val |= WPA_CIPHER_CCMP;
+		else if (os_strcmp(start, "GCMP") == 0)
+			val |= WPA_CIPHER_GCMP;
+		else if (os_strcmp(start, "TKIP") == 0)
+			val |= WPA_CIPHER_TKIP;
+		else if (os_strcmp(start, "WEP104") == 0)
+			val |= WPA_CIPHER_WEP104;
+		else if (os_strcmp(start, "WEP40") == 0)
+			val |= WPA_CIPHER_WEP40;
+		else if (os_strcmp(start, "NONE") == 0)
+			val |= WPA_CIPHER_NONE;
+		else {
+			wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+				   line, start);
+			os_free(buf);
+			return -1;
+		}
+
+		if (last)
+			break;
+		start = end + 1;
+	}
+	os_free(buf);
+
+	if (val == 0) {
+		wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
+			   line);
+		return -1;
+	}
+	return val;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_cipher(int cipher)
+{
+	char *buf, *pos, *end;
+	int ret;
+
+	pos = buf = os_zalloc(50);
+	if (buf == NULL)
+		return NULL;
+	end = buf + 50;
+
+	if (cipher & WPA_CIPHER_CCMP) {
+		ret = os_snprintf(pos, end - pos, "%sCCMP",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (cipher & WPA_CIPHER_GCMP) {
+		ret = os_snprintf(pos, end - pos, "%sGCMP",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (cipher & WPA_CIPHER_TKIP) {
+		ret = os_snprintf(pos, end - pos, "%sTKIP",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (cipher & WPA_CIPHER_WEP104) {
+		ret = os_snprintf(pos, end - pos, "%sWEP104",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (cipher & WPA_CIPHER_WEP40) {
+		ret = os_snprintf(pos, end - pos, "%sWEP40",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (cipher & WPA_CIPHER_NONE) {
+		ret = os_snprintf(pos, end - pos, "%sNONE",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	return buf;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_pairwise(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	int val;
+	val = wpa_config_parse_cipher(line, value);
+	if (val == -1)
+		return -1;
+	if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP |
+		    WPA_CIPHER_NONE)) {
+		wpa_printf(MSG_ERROR, "Line %d: not allowed pairwise cipher "
+			   "(0x%x).", line, val);
+		return -1;
+	}
+
+	wpa_printf(MSG_MSGDUMP, "pairwise: 0x%x", val);
+	ssid->pairwise_cipher = val;
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_pairwise(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	return wpa_config_write_cipher(ssid->pairwise_cipher);
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_group(const struct parse_data *data,
+				  struct wpa_ssid *ssid, int line,
+				  const char *value)
+{
+	int val;
+	val = wpa_config_parse_cipher(line, value);
+	if (val == -1)
+		return -1;
+	if (val & ~(WPA_CIPHER_CCMP | WPA_CIPHER_GCMP | WPA_CIPHER_TKIP |
+		    WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)) {
+		wpa_printf(MSG_ERROR, "Line %d: not allowed group cipher "
+			   "(0x%x).", line, val);
+		return -1;
+	}
+
+	wpa_printf(MSG_MSGDUMP, "group: 0x%x", val);
+	ssid->group_cipher = val;
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_group(const struct parse_data *data,
+				     struct wpa_ssid *ssid)
+{
+	return wpa_config_write_cipher(ssid->group_cipher);
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int wpa_config_parse_auth_alg(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	int val = 0, last, errors = 0;
+	char *start, *end, *buf;
+
+	buf = os_strdup(value);
+	if (buf == NULL)
+		return -1;
+	start = buf;
+
+	while (*start != '\0') {
+		while (*start == ' ' || *start == '\t')
+			start++;
+		if (*start == '\0')
+			break;
+		end = start;
+		while (*end != ' ' && *end != '\t' && *end != '\0')
+			end++;
+		last = *end == '\0';
+		*end = '\0';
+		if (os_strcmp(start, "OPEN") == 0)
+			val |= WPA_AUTH_ALG_OPEN;
+		else if (os_strcmp(start, "SHARED") == 0)
+			val |= WPA_AUTH_ALG_SHARED;
+		else if (os_strcmp(start, "LEAP") == 0)
+			val |= WPA_AUTH_ALG_LEAP;
+		else {
+			wpa_printf(MSG_ERROR, "Line %d: invalid auth_alg '%s'",
+				   line, start);
+			errors++;
+		}
+
+		if (last)
+			break;
+		start = end + 1;
+	}
+	os_free(buf);
+
+	if (val == 0) {
+		wpa_printf(MSG_ERROR,
+			   "Line %d: no auth_alg values configured.", line);
+		errors++;
+	}
+
+	wpa_printf(MSG_MSGDUMP, "auth_alg: 0x%x", val);
+	ssid->auth_alg = val;
+	return errors ? -1 : 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_auth_alg(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	char *buf, *pos, *end;
+	int ret;
+
+	pos = buf = os_zalloc(30);
+	if (buf == NULL)
+		return NULL;
+	end = buf + 30;
+
+	if (ssid->auth_alg & WPA_AUTH_ALG_OPEN) {
+		ret = os_snprintf(pos, end - pos, "%sOPEN",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (ssid->auth_alg & WPA_AUTH_ALG_SHARED) {
+		ret = os_snprintf(pos, end - pos, "%sSHARED",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	if (ssid->auth_alg & WPA_AUTH_ALG_LEAP) {
+		ret = os_snprintf(pos, end - pos, "%sLEAP",
+				  pos == buf ? "" : " ");
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	return buf;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+static int * wpa_config_parse_freqs(const struct parse_data *data,
+				    struct wpa_ssid *ssid, int line,
+				    const char *value)
+{
+	int *freqs;
+	size_t used, len;
+	const char *pos;
+
+	used = 0;
+	len = 10;
+	freqs = os_calloc(len + 1, sizeof(int));
+	if (freqs == NULL)
+		return NULL;
+
+	pos = value;
+	while (pos) {
+		while (*pos == ' ')
+			pos++;
+		if (used == len) {
+			int *n;
+			size_t i;
+			n = os_realloc_array(freqs, len * 2 + 1, sizeof(int));
+			if (n == NULL) {
+				os_free(freqs);
+				return NULL;
+			}
+			for (i = len; i <= len * 2; i++)
+				n[i] = 0;
+			freqs = n;
+			len *= 2;
+		}
+
+		freqs[used] = atoi(pos);
+		if (freqs[used] == 0)
+			break;
+		used++;
+		pos = os_strchr(pos + 1, ' ');
+	}
+
+	return freqs;
+}
+
+
+static int wpa_config_parse_scan_freq(const struct parse_data *data,
+				      struct wpa_ssid *ssid, int line,
+				      const char *value)
+{
+	int *freqs;
+
+	freqs = wpa_config_parse_freqs(data, ssid, line, value);
+	if (freqs == NULL)
+		return -1;
+	os_free(ssid->scan_freq);
+	ssid->scan_freq = freqs;
+
+	return 0;
+}
+
+
+static int wpa_config_parse_freq_list(const struct parse_data *data,
+				      struct wpa_ssid *ssid, int line,
+				      const char *value)
+{
+	int *freqs;
+
+	freqs = wpa_config_parse_freqs(data, ssid, line, value);
+	if (freqs == NULL)
+		return -1;
+	os_free(ssid->freq_list);
+	ssid->freq_list = freqs;
+
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_freqs(const struct parse_data *data,
+				     const int *freqs)
+{
+	char *buf, *pos, *end;
+	int i, ret;
+	size_t count;
+
+	if (freqs == NULL)
+		return NULL;
+
+	count = 0;
+	for (i = 0; freqs[i]; i++)
+		count++;
+
+	pos = buf = os_zalloc(10 * count + 1);
+	if (buf == NULL)
+		return NULL;
+	end = buf + 10 * count + 1;
+
+	for (i = 0; freqs[i]; i++) {
+		ret = os_snprintf(pos, end - pos, "%s%u",
+				  i == 0 ? "" : " ", freqs[i]);
+		if (ret < 0 || ret >= end - pos) {
+			end[-1] = '\0';
+			return buf;
+		}
+		pos += ret;
+	}
+
+	return buf;
+}
+
+
+static char * wpa_config_write_scan_freq(const struct parse_data *data,
+					 struct wpa_ssid *ssid)
+{
+	return wpa_config_write_freqs(data, ssid->scan_freq);
+}
+
+
+static char * wpa_config_write_freq_list(const struct parse_data *data,
+					 struct wpa_ssid *ssid)
+{
+	return wpa_config_write_freqs(data, ssid->freq_list);
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+#ifdef IEEE8021X_EAPOL
+static int wpa_config_parse_eap(const struct parse_data *data,
+				struct wpa_ssid *ssid, int line,
+				const char *value)
+{
+	int last, errors = 0;
+	char *start, *end, *buf;
+	struct eap_method_type *methods = NULL, *tmp;
+	size_t num_methods = 0;
+
+	buf = os_strdup(value);
+	if (buf == NULL)
+		return -1;
+	start = buf;
+
+	while (*start != '\0') {
+		while (*start == ' ' || *start == '\t')
+			start++;
+		if (*start == '\0')
+			break;
+		end = start;
+		while (*end != ' ' && *end != '\t' && *end != '\0')
+			end++;
+		last = *end == '\0';
+		*end = '\0';
+		tmp = methods;
+		methods = os_realloc_array(methods, num_methods + 1,
+					   sizeof(*methods));
+		if (methods == NULL) {
+			os_free(tmp);
+			os_free(buf);
+			return -1;
+		}
+		methods[num_methods].method = eap_peer_get_type(
+			start, &methods[num_methods].vendor);
+		if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
+		    methods[num_methods].method == EAP_TYPE_NONE) {
+			wpa_printf(MSG_ERROR, "Line %d: unknown EAP method "
+				   "'%s'", line, start);
+			wpa_printf(MSG_ERROR, "You may need to add support for"
+				   " this EAP method during wpa_supplicant\n"
+				   "build time configuration.\n"
+				   "See README for more information.");
+			errors++;
+		} else if (methods[num_methods].vendor == EAP_VENDOR_IETF &&
+			   methods[num_methods].method == EAP_TYPE_LEAP)
+			ssid->leap++;
+		else
+			ssid->non_leap++;
+		num_methods++;
+		if (last)
+			break;
+		start = end + 1;
+	}
+	os_free(buf);
+
+	tmp = methods;
+	methods = os_realloc_array(methods, num_methods + 1, sizeof(*methods));
+	if (methods == NULL) {
+		os_free(tmp);
+		return -1;
+	}
+	methods[num_methods].vendor = EAP_VENDOR_IETF;
+	methods[num_methods].method = EAP_TYPE_NONE;
+	num_methods++;
+
+	wpa_hexdump(MSG_MSGDUMP, "eap methods",
+		    (u8 *) methods, num_methods * sizeof(*methods));
+	os_free(ssid->eap.eap_methods);
+	ssid->eap.eap_methods = methods;
+	return errors ? -1 : 0;
+}
+
+
+static char * wpa_config_write_eap(const struct parse_data *data,
+				   struct wpa_ssid *ssid)
+{
+	int i, ret;
+	char *buf, *pos, *end;
+	const struct eap_method_type *eap_methods = ssid->eap.eap_methods;
+	const char *name;
+
+	if (eap_methods == NULL)
+		return NULL;
+
+	pos = buf = os_zalloc(100);
+	if (buf == NULL)
+		return NULL;
+	end = buf + 100;
+
+	for (i = 0; eap_methods[i].vendor != EAP_VENDOR_IETF ||
+		     eap_methods[i].method != EAP_TYPE_NONE; i++) {
+		name = eap_get_name(eap_methods[i].vendor,
+				    eap_methods[i].method);
+		if (name) {
+			ret = os_snprintf(pos, end - pos, "%s%s",
+					  pos == buf ? "" : " ", name);
+			if (ret < 0 || ret >= end - pos)
+				break;
+			pos += ret;
+		}
+	}
+
+	end[-1] = '\0';
+
+	return buf;
+}
+
+
+static int wpa_config_parse_password(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	u8 *hash;
+
+	if (os_strcmp(value, "NULL") == 0) {
+		wpa_printf(MSG_DEBUG, "Unset configuration string 'password'");
+		os_free(ssid->eap.password);
+		ssid->eap.password = NULL;
+		ssid->eap.password_len = 0;
+		return 0;
+	}
+
+#ifdef CONFIG_EXT_PASSWORD
+	if (os_strncmp(value, "ext:", 4) == 0) {
+		char *name = os_strdup(value + 4);
+		if (name == NULL)
+			return -1;
+		os_free(ssid->eap.password);
+		ssid->eap.password = (u8 *) name;
+		ssid->eap.password_len = os_strlen(name);
+		ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+		ssid->eap.flags |= EAP_CONFIG_FLAGS_EXT_PASSWORD;
+		return 0;
+	}
+#endif /* CONFIG_EXT_PASSWORD */
+
+	if (os_strncmp(value, "hash:", 5) != 0) {
+		char *tmp;
+		size_t res_len;
+
+		tmp = wpa_config_parse_string(value, &res_len);
+		if (tmp == NULL) {
+			wpa_printf(MSG_ERROR, "Line %d: failed to parse "
+				   "password.", line);
+			return -1;
+		}
+		wpa_hexdump_ascii_key(MSG_MSGDUMP, data->name,
+				      (u8 *) tmp, res_len);
+
+		os_free(ssid->eap.password);
+		ssid->eap.password = (u8 *) tmp;
+		ssid->eap.password_len = res_len;
+		ssid->eap.flags &= ~EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+		ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
+
+		return 0;
+	}
+
+
+	/* NtPasswordHash: hash:<32 hex digits> */
+	if (os_strlen(value + 5) != 2 * 16) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid password hash length "
+			   "(expected 32 hex digits)", line);
+		return -1;
+	}
+
+	hash = os_malloc(16);
+	if (hash == NULL)
+		return -1;
+
+	if (hexstr2bin(value + 5, hash, 16)) {
+		os_free(hash);
+		wpa_printf(MSG_ERROR, "Line %d: Invalid password hash", line);
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_MSGDUMP, data->name, hash, 16);
+
+	os_free(ssid->eap.password);
+	ssid->eap.password = hash;
+	ssid->eap.password_len = 16;
+	ssid->eap.flags |= EAP_CONFIG_FLAGS_PASSWORD_NTHASH;
+	ssid->eap.flags &= ~EAP_CONFIG_FLAGS_EXT_PASSWORD;
+
+	return 0;
+}
+
+
+static char * wpa_config_write_password(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	char *buf;
+
+	if (ssid->eap.password == NULL)
+		return NULL;
+
+#ifdef CONFIG_EXT_PASSWORD
+	if (ssid->eap.flags & EAP_CONFIG_FLAGS_EXT_PASSWORD) {
+		buf = os_zalloc(4 + ssid->eap.password_len + 1);
+		if (buf == NULL)
+			return NULL;
+		os_memcpy(buf, "ext:", 4);
+		os_memcpy(buf + 4, ssid->eap.password, ssid->eap.password_len);
+		return buf;
+	}
+#endif /* CONFIG_EXT_PASSWORD */
+
+	if (!(ssid->eap.flags & EAP_CONFIG_FLAGS_PASSWORD_NTHASH)) {
+		return wpa_config_write_string(
+			ssid->eap.password, ssid->eap.password_len);
+	}
+
+	buf = os_malloc(5 + 32 + 1);
+	if (buf == NULL)
+		return NULL;
+
+	os_memcpy(buf, "hash:", 5);
+	wpa_snprintf_hex(buf + 5, 32 + 1, ssid->eap.password, 16);
+
+	return buf;
+}
+#endif /* IEEE8021X_EAPOL */
+
+
+static int wpa_config_parse_wep_key(u8 *key, size_t *len, int line,
+				    const char *value, int idx)
+{
+	char *buf, title[20];
+	int res;
+
+	buf = wpa_config_parse_string(value, len);
+	if (buf == NULL) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key %d '%s'.",
+			   line, idx, value);
+		return -1;
+	}
+	if (*len > MAX_WEP_KEY_LEN) {
+		wpa_printf(MSG_ERROR, "Line %d: Too long WEP key %d '%s'.",
+			   line, idx, value);
+		os_free(buf);
+		return -1;
+	}
+	if (*len && *len != 5 && *len != 13 && *len != 16) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid WEP key length %u - "
+			   "this network block will be ignored",
+			   line, (unsigned int) *len);
+	}
+	os_memcpy(key, buf, *len);
+	os_free(buf);
+	res = os_snprintf(title, sizeof(title), "wep_key%d", idx);
+	if (res >= 0 && (size_t) res < sizeof(title))
+		wpa_hexdump_key(MSG_MSGDUMP, title, key, *len);
+	return 0;
+}
+
+
+static int wpa_config_parse_wep_key0(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	return wpa_config_parse_wep_key(ssid->wep_key[0],
+					&ssid->wep_key_len[0], line,
+					value, 0);
+}
+
+
+static int wpa_config_parse_wep_key1(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	return wpa_config_parse_wep_key(ssid->wep_key[1],
+					&ssid->wep_key_len[1], line,
+					value, 1);
+}
+
+
+static int wpa_config_parse_wep_key2(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	return wpa_config_parse_wep_key(ssid->wep_key[2],
+					&ssid->wep_key_len[2], line,
+					value, 2);
+}
+
+
+static int wpa_config_parse_wep_key3(const struct parse_data *data,
+				     struct wpa_ssid *ssid, int line,
+				     const char *value)
+{
+	return wpa_config_parse_wep_key(ssid->wep_key[3],
+					&ssid->wep_key_len[3], line,
+					value, 3);
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_wep_key(struct wpa_ssid *ssid, int idx)
+{
+	if (ssid->wep_key_len[idx] == 0)
+		return NULL;
+	return wpa_config_write_string(ssid->wep_key[idx],
+				       ssid->wep_key_len[idx]);
+}
+
+
+static char * wpa_config_write_wep_key0(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	return wpa_config_write_wep_key(ssid, 0);
+}
+
+
+static char * wpa_config_write_wep_key1(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	return wpa_config_write_wep_key(ssid, 1);
+}
+
+
+static char * wpa_config_write_wep_key2(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	return wpa_config_write_wep_key(ssid, 2);
+}
+
+
+static char * wpa_config_write_wep_key3(const struct parse_data *data,
+					struct wpa_ssid *ssid)
+{
+	return wpa_config_write_wep_key(ssid, 3);
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+#ifdef CONFIG_P2P
+
+static int wpa_config_parse_p2p_client_list(const struct parse_data *data,
+					    struct wpa_ssid *ssid, int line,
+					    const char *value)
+{
+	const char *pos;
+	u8 *buf, *n, addr[ETH_ALEN];
+	size_t count;
+
+	buf = NULL;
+	count = 0;
+
+	pos = value;
+	while (pos && *pos) {
+		while (*pos == ' ')
+			pos++;
+
+		if (hwaddr_aton(pos, addr)) {
+			if (count == 0) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "p2p_client_list address '%s'.",
+					   line, value);
+				os_free(buf);
+				return -1;
+			}
+			/* continue anyway since this could have been from a
+			 * truncated configuration file line */
+			wpa_printf(MSG_INFO, "Line %d: Ignore likely "
+				   "truncated p2p_client_list address '%s'",
+				   line, pos);
+		} else {
+			n = os_realloc_array(buf, count + 1, ETH_ALEN);
+			if (n == NULL) {
+				os_free(buf);
+				return -1;
+			}
+			buf = n;
+			os_memmove(buf + ETH_ALEN, buf, count * ETH_ALEN);
+			os_memcpy(buf, addr, ETH_ALEN);
+			count++;
+			wpa_hexdump(MSG_MSGDUMP, "p2p_client_list",
+				    addr, ETH_ALEN);
+		}
+
+		pos = os_strchr(pos, ' ');
+	}
+
+	os_free(ssid->p2p_client_list);
+	ssid->p2p_client_list = buf;
+	ssid->num_p2p_clients = count;
+
+	return 0;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+static char * wpa_config_write_p2p_client_list(const struct parse_data *data,
+					       struct wpa_ssid *ssid)
+{
+	char *value, *end, *pos;
+	int res;
+	size_t i;
+
+	if (ssid->p2p_client_list == NULL || ssid->num_p2p_clients == 0)
+		return NULL;
+
+	value = os_malloc(20 * ssid->num_p2p_clients);
+	if (value == NULL)
+		return NULL;
+	pos = value;
+	end = value + 20 * ssid->num_p2p_clients;
+
+	for (i = ssid->num_p2p_clients; i > 0; i--) {
+		res = os_snprintf(pos, end - pos, MACSTR " ",
+				  MAC2STR(ssid->p2p_client_list +
+					  (i - 1) * ETH_ALEN));
+		if (res < 0 || res >= end - pos) {
+			os_free(value);
+			return NULL;
+		}
+		pos += res;
+	}
+
+	if (pos > value)
+		pos[-1] = '\0';
+
+	return value;
+}
+#endif /* NO_CONFIG_WRITE */
+
+#endif /* CONFIG_P2P */
+
+/* Helper macros for network block parser */
+
+#ifdef OFFSET
+#undef OFFSET
+#endif /* OFFSET */
+/* OFFSET: Get offset of a variable within the wpa_ssid structure */
+#define OFFSET(v) ((void *) &((struct wpa_ssid *) 0)->v)
+
+/* STR: Define a string variable for an ASCII string; f = field name */
+#ifdef NO_CONFIG_WRITE
+#define _STR(f) #f, wpa_config_parse_str, OFFSET(f)
+#define _STRe(f) #f, wpa_config_parse_str, OFFSET(eap.f)
+#else /* NO_CONFIG_WRITE */
+#define _STR(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(f)
+#define _STRe(f) #f, wpa_config_parse_str, wpa_config_write_str, OFFSET(eap.f)
+#endif /* NO_CONFIG_WRITE */
+#define STR(f) _STR(f), NULL, NULL, NULL, 0
+#define STRe(f) _STRe(f), NULL, NULL, NULL, 0
+#define STR_KEY(f) _STR(f), NULL, NULL, NULL, 1
+#define STR_KEYe(f) _STRe(f), NULL, NULL, NULL, 1
+
+/* STR_LEN: Define a string variable with a separate variable for storing the
+ * data length. Unlike STR(), this can be used to store arbitrary binary data
+ * (i.e., even nul termination character). */
+#define _STR_LEN(f) _STR(f), OFFSET(f ## _len)
+#define _STR_LENe(f) _STRe(f), OFFSET(eap.f ## _len)
+#define STR_LEN(f) _STR_LEN(f), NULL, NULL, 0
+#define STR_LENe(f) _STR_LENe(f), NULL, NULL, 0
+#define STR_LEN_KEY(f) _STR_LEN(f), NULL, NULL, 1
+
+/* STR_RANGE: Like STR_LEN(), but with minimum and maximum allowed length
+ * explicitly specified. */
+#define _STR_RANGE(f, min, max) _STR_LEN(f), (void *) (min), (void *) (max)
+#define STR_RANGE(f, min, max) _STR_RANGE(f, min, max), 0
+#define STR_RANGE_KEY(f, min, max) _STR_RANGE(f, min, max), 1
+
+#ifdef NO_CONFIG_WRITE
+#define _INT(f) #f, wpa_config_parse_int, OFFSET(f), (void *) 0
+#define _INTe(f) #f, wpa_config_parse_int, OFFSET(eap.f), (void *) 0
+#else /* NO_CONFIG_WRITE */
+#define _INT(f) #f, wpa_config_parse_int, wpa_config_write_int, \
+	OFFSET(f), (void *) 0
+#define _INTe(f) #f, wpa_config_parse_int, wpa_config_write_int, \
+	OFFSET(eap.f), (void *) 0
+#endif /* NO_CONFIG_WRITE */
+
+/* INT: Define an integer variable */
+#define INT(f) _INT(f), NULL, NULL, 0
+#define INTe(f) _INTe(f), NULL, NULL, 0
+
+/* INT_RANGE: Define an integer variable with allowed value range */
+#define INT_RANGE(f, min, max) _INT(f), (void *) (min), (void *) (max), 0
+
+/* FUNC: Define a configuration variable that uses a custom function for
+ * parsing and writing the value. */
+#ifdef NO_CONFIG_WRITE
+#define _FUNC(f) #f, wpa_config_parse_ ## f, NULL, NULL, NULL, NULL
+#else /* NO_CONFIG_WRITE */
+#define _FUNC(f) #f, wpa_config_parse_ ## f, wpa_config_write_ ## f, \
+	NULL, NULL, NULL, NULL
+#endif /* NO_CONFIG_WRITE */
+#define FUNC(f) _FUNC(f), 0
+#define FUNC_KEY(f) _FUNC(f), 1
+
+/*
+ * Table of network configuration variables. This table is used to parse each
+ * network configuration variable, e.g., each line in wpa_supplicant.conf file
+ * that is inside a network block.
+ *
+ * This table is generated using the helper macros defined above and with
+ * generous help from the C pre-processor. The field name is stored as a string
+ * into .name and for STR and INT types, the offset of the target buffer within
+ * struct wpa_ssid is stored in .param1. .param2 (if not NULL) is similar
+ * offset to the field containing the length of the configuration variable.
+ * .param3 and .param4 can be used to mark the allowed range (length for STR
+ * and value for INT).
+ *
+ * For each configuration line in wpa_supplicant.conf, the parser goes through
+ * this table and select the entry that matches with the field name. The parser
+ * function (.parser) is then called to parse the actual value of the field.
+ *
+ * This kind of mechanism makes it easy to add new configuration parameters,
+ * since only one line needs to be added into this table and into the
+ * struct wpa_ssid definition if the new variable is either a string or
+ * integer. More complex types will need to use their own parser and writer
+ * functions.
+ */
+static const struct parse_data ssid_fields[] = {
+	{ STR_RANGE(ssid, 0, MAX_SSID_LEN) },
+	{ INT_RANGE(scan_ssid, 0, 1) },
+	{ FUNC(bssid) },
+	{ FUNC_KEY(psk) },
+	{ FUNC(proto) },
+	{ FUNC(key_mgmt) },
+	{ INT(bg_scan_period) },
+	{ FUNC(pairwise) },
+	{ FUNC(group) },
+	{ FUNC(auth_alg) },
+	{ FUNC(scan_freq) },
+	{ FUNC(freq_list) },
+#ifdef IEEE8021X_EAPOL
+	{ FUNC(eap) },
+	{ STR_LENe(identity) },
+	{ STR_LENe(anonymous_identity) },
+	{ FUNC_KEY(password) },
+	{ STRe(ca_cert) },
+	{ STRe(ca_path) },
+	{ STRe(client_cert) },
+	{ STRe(private_key) },
+	{ STR_KEYe(private_key_passwd) },
+	{ STRe(dh_file) },
+	{ STRe(subject_match) },
+	{ STRe(altsubject_match) },
+	{ STRe(ca_cert2) },
+	{ STRe(ca_path2) },
+	{ STRe(client_cert2) },
+	{ STRe(private_key2) },
+	{ STR_KEYe(private_key2_passwd) },
+	{ STRe(dh_file2) },
+	{ STRe(subject_match2) },
+	{ STRe(altsubject_match2) },
+	{ STRe(phase1) },
+	{ STRe(phase2) },
+	{ STRe(pcsc) },
+	{ STR_KEYe(pin) },
+	{ STRe(engine_id) },
+	{ STRe(key_id) },
+	{ STRe(cert_id) },
+	{ STRe(ca_cert_id) },
+	{ STR_KEYe(pin2) },
+	{ STRe(engine2_id) },
+	{ STRe(key2_id) },
+	{ STRe(cert2_id) },
+	{ STRe(ca_cert2_id) },
+	{ INTe(engine) },
+	{ INTe(engine2) },
+	{ INT(eapol_flags) },
+#endif /* IEEE8021X_EAPOL */
+	{ FUNC_KEY(wep_key0) },
+	{ FUNC_KEY(wep_key1) },
+	{ FUNC_KEY(wep_key2) },
+	{ FUNC_KEY(wep_key3) },
+	{ INT(wep_tx_keyidx) },
+	{ INT(priority) },
+#ifdef IEEE8021X_EAPOL
+	{ INT(eap_workaround) },
+	{ STRe(pac_file) },
+	{ INTe(fragment_size) },
+#endif /* IEEE8021X_EAPOL */
+	{ INT_RANGE(mode, 0, 4) },
+	{ INT_RANGE(proactive_key_caching, 0, 1) },
+	{ INT_RANGE(disabled, 0, 2) },
+	{ STR(id_str) },
+#ifdef CONFIG_IEEE80211W
+	{ INT_RANGE(ieee80211w, 0, 2) },
+#endif /* CONFIG_IEEE80211W */
+	{ INT_RANGE(peerkey, 0, 1) },
+	{ INT_RANGE(mixed_cell, 0, 1) },
+	{ INT_RANGE(frequency, 0, 65000) },
+	{ INT(wpa_ptk_rekey) },
+	{ STR(bgscan) },
+	{ INT_RANGE(ignore_broadcast_ssid, 0, 2) },
+#ifdef CONFIG_P2P
+	{ FUNC(p2p_client_list) },
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_HT_OVERRIDES
+	{ INT_RANGE(disable_ht, 0, 1) },
+	{ INT_RANGE(disable_ht40, -1, 1) },
+	{ INT_RANGE(disable_sgi, 0, 1) },
+	{ INT_RANGE(disable_max_amsdu, -1, 1) },
+	{ INT_RANGE(ampdu_factor, -1, 3) },
+	{ INT_RANGE(ampdu_density, -1, 7) },
+	{ STR(ht_mcs) },
+#endif /* CONFIG_HT_OVERRIDES */
+	{ INT(ap_max_inactivity) },
+	{ INT(dtim_period) },
+};
+
+#undef OFFSET
+#undef _STR
+#undef STR
+#undef STR_KEY
+#undef _STR_LEN
+#undef STR_LEN
+#undef STR_LEN_KEY
+#undef _STR_RANGE
+#undef STR_RANGE
+#undef STR_RANGE_KEY
+#undef _INT
+#undef INT
+#undef INT_RANGE
+#undef _FUNC
+#undef FUNC
+#undef FUNC_KEY
+#define NUM_SSID_FIELDS (sizeof(ssid_fields) / sizeof(ssid_fields[0]))
+
+
+/**
+ * wpa_config_add_prio_network - Add a network to priority lists
+ * @config: Configuration data from wpa_config_read()
+ * @ssid: Pointer to the network configuration to be added to the list
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to add a network block to the priority list of
+ * networks. This must be called for each network when reading in the full
+ * configuration. In addition, this can be used indirectly when updating
+ * priorities by calling wpa_config_update_prio_list().
+ */
+int wpa_config_add_prio_network(struct wpa_config *config,
+				struct wpa_ssid *ssid)
+{
+	int prio;
+	struct wpa_ssid *prev, **nlist;
+
+	/*
+	 * Add to an existing priority list if one is available for the
+	 * configured priority level for this network.
+	 */
+	for (prio = 0; prio < config->num_prio; prio++) {
+		prev = config->pssid[prio];
+		if (prev->priority == ssid->priority) {
+			while (prev->pnext)
+				prev = prev->pnext;
+			prev->pnext = ssid;
+			return 0;
+		}
+	}
+
+	/* First network for this priority - add a new priority list */
+	nlist = os_realloc_array(config->pssid, config->num_prio + 1,
+				 sizeof(struct wpa_ssid *));
+	if (nlist == NULL)
+		return -1;
+
+	for (prio = 0; prio < config->num_prio; prio++) {
+		if (nlist[prio]->priority < ssid->priority) {
+			os_memmove(&nlist[prio + 1], &nlist[prio],
+				   (config->num_prio - prio) *
+				   sizeof(struct wpa_ssid *));
+			break;
+		}
+	}
+
+	nlist[prio] = ssid;
+	config->num_prio++;
+	config->pssid = nlist;
+
+	return 0;
+}
+
+
+/**
+ * wpa_config_update_prio_list - Update network priority list
+ * @config: Configuration data from wpa_config_read()
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called to update the priority list of networks in the
+ * configuration when a network is being added or removed. This is also called
+ * if a priority for a network is changed.
+ */
+int wpa_config_update_prio_list(struct wpa_config *config)
+{
+	struct wpa_ssid *ssid;
+	int ret = 0;
+
+	os_free(config->pssid);
+	config->pssid = NULL;
+	config->num_prio = 0;
+
+	ssid = config->ssid;
+	while (ssid) {
+		ssid->pnext = NULL;
+		if (wpa_config_add_prio_network(config, ssid) < 0)
+			ret = -1;
+		ssid = ssid->next;
+	}
+
+	return ret;
+}
+
+
+#ifdef IEEE8021X_EAPOL
+static void eap_peer_config_free(struct eap_peer_config *eap)
+{
+	os_free(eap->eap_methods);
+	os_free(eap->identity);
+	os_free(eap->anonymous_identity);
+	os_free(eap->password);
+	os_free(eap->ca_cert);
+	os_free(eap->ca_path);
+	os_free(eap->client_cert);
+	os_free(eap->private_key);
+	os_free(eap->private_key_passwd);
+	os_free(eap->dh_file);
+	os_free(eap->subject_match);
+	os_free(eap->altsubject_match);
+	os_free(eap->ca_cert2);
+	os_free(eap->ca_path2);
+	os_free(eap->client_cert2);
+	os_free(eap->private_key2);
+	os_free(eap->private_key2_passwd);
+	os_free(eap->dh_file2);
+	os_free(eap->subject_match2);
+	os_free(eap->altsubject_match2);
+	os_free(eap->phase1);
+	os_free(eap->phase2);
+	os_free(eap->pcsc);
+	os_free(eap->pin);
+	os_free(eap->engine_id);
+	os_free(eap->key_id);
+	os_free(eap->cert_id);
+	os_free(eap->ca_cert_id);
+	os_free(eap->key2_id);
+	os_free(eap->cert2_id);
+	os_free(eap->ca_cert2_id);
+	os_free(eap->pin2);
+	os_free(eap->engine2_id);
+	os_free(eap->otp);
+	os_free(eap->pending_req_otp);
+	os_free(eap->pac_file);
+	os_free(eap->new_password);
+}
+#endif /* IEEE8021X_EAPOL */
+
+
+/**
+ * wpa_config_free_ssid - Free network/ssid configuration data
+ * @ssid: Configuration data for the network
+ *
+ * This function frees all resources allocated for the network configuration
+ * data.
+ */
+void wpa_config_free_ssid(struct wpa_ssid *ssid)
+{
+	os_free(ssid->ssid);
+	os_free(ssid->passphrase);
+	os_free(ssid->ext_psk);
+#ifdef IEEE8021X_EAPOL
+	eap_peer_config_free(&ssid->eap);
+#endif /* IEEE8021X_EAPOL */
+	os_free(ssid->id_str);
+	os_free(ssid->scan_freq);
+	os_free(ssid->freq_list);
+	os_free(ssid->bgscan);
+	os_free(ssid->p2p_client_list);
+#ifdef CONFIG_HT_OVERRIDES
+	os_free(ssid->ht_mcs);
+#endif /* CONFIG_HT_OVERRIDES */
+	os_free(ssid);
+}
+
+
+void wpa_config_free_cred(struct wpa_cred *cred)
+{
+	os_free(cred->realm);
+	os_free(cred->username);
+	os_free(cred->password);
+	os_free(cred->ca_cert);
+	os_free(cred->client_cert);
+	os_free(cred->private_key);
+	os_free(cred->private_key_passwd);
+	os_free(cred->imsi);
+	os_free(cred->milenage);
+	os_free(cred->domain);
+	os_free(cred->eap_method);
+	os_free(cred->phase1);
+	os_free(cred->phase2);
+	os_free(cred->excluded_ssid);
+	os_free(cred);
+}
+
+
+/**
+ * wpa_config_free - Free configuration data
+ * @config: Configuration data from wpa_config_read()
+ *
+ * This function frees all resources allocated for the configuration data by
+ * wpa_config_read().
+ */
+void wpa_config_free(struct wpa_config *config)
+{
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	struct wpa_config_blob *blob, *prevblob;
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+	struct wpa_ssid *ssid, *prev = NULL;
+	struct wpa_cred *cred, *cprev;
+
+	ssid = config->ssid;
+	while (ssid) {
+		prev = ssid;
+		ssid = ssid->next;
+		wpa_config_free_ssid(prev);
+	}
+
+	cred = config->cred;
+	while (cred) {
+		cprev = cred;
+		cred = cred->next;
+		wpa_config_free_cred(cprev);
+	}
+
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	blob = config->blobs;
+	prevblob = NULL;
+	while (blob) {
+		prevblob = blob;
+		blob = blob->next;
+		wpa_config_free_blob(prevblob);
+	}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
+	wpabuf_free(config->wps_vendor_ext_m1);
+	os_free(config->ctrl_interface);
+	os_free(config->ctrl_interface_group);
+	os_free(config->opensc_engine_path);
+	os_free(config->pkcs11_engine_path);
+	os_free(config->pkcs11_module_path);
+	os_free(config->pcsc_reader);
+	os_free(config->pcsc_pin);
+	os_free(config->driver_param);
+	os_free(config->device_name);
+	os_free(config->manufacturer);
+	os_free(config->model_name);
+	os_free(config->model_number);
+	os_free(config->serial_number);
+	os_free(config->config_methods);
+	os_free(config->p2p_ssid_postfix);
+	os_free(config->pssid);
+	os_free(config->p2p_pref_chan);
+	os_free(config->autoscan);
+	wpabuf_free(config->wps_nfc_dh_pubkey);
+	wpabuf_free(config->wps_nfc_dh_privkey);
+	wpabuf_free(config->wps_nfc_dev_pw);
+	os_free(config->ext_password_backend);
+	os_free(config);
+}
+
+
+/**
+ * wpa_config_foreach_network - Iterate over each configured network
+ * @config: Configuration data from wpa_config_read()
+ * @func: Callback function to process each network
+ * @arg: Opaque argument to pass to callback function
+ *
+ * Iterate over the set of configured networks calling the specified
+ * function for each item. We guard against callbacks removing the
+ * supplied network.
+ */
+void wpa_config_foreach_network(struct wpa_config *config,
+				void (*func)(void *, struct wpa_ssid *),
+				void *arg)
+{
+	struct wpa_ssid *ssid, *next;
+
+	ssid = config->ssid;
+	while (ssid) {
+		next = ssid->next;
+		func(arg, ssid);
+		ssid = next;
+	}
+}
+
+
+/**
+ * wpa_config_get_network - Get configured network based on id
+ * @config: Configuration data from wpa_config_read()
+ * @id: Unique network id to search for
+ * Returns: Network configuration or %NULL if not found
+ */
+struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id)
+{
+	struct wpa_ssid *ssid;
+
+	ssid = config->ssid;
+	while (ssid) {
+		if (id == ssid->id)
+			break;
+		ssid = ssid->next;
+	}
+
+	return ssid;
+}
+
+
+/**
+ * wpa_config_add_network - Add a new network with empty configuration
+ * @config: Configuration data from wpa_config_read()
+ * Returns: The new network configuration or %NULL if operation failed
+ */
+struct wpa_ssid * wpa_config_add_network(struct wpa_config *config)
+{
+	int id;
+	struct wpa_ssid *ssid, *last = NULL;
+
+	id = -1;
+	ssid = config->ssid;
+	while (ssid) {
+		if (ssid->id > id)
+			id = ssid->id;
+		last = ssid;
+		ssid = ssid->next;
+	}
+	id++;
+
+	ssid = os_zalloc(sizeof(*ssid));
+	if (ssid == NULL)
+		return NULL;
+	ssid->id = id;
+	if (last)
+		last->next = ssid;
+	else
+		config->ssid = ssid;
+
+	wpa_config_update_prio_list(config);
+
+	return ssid;
+}
+
+
+/**
+ * wpa_config_remove_network - Remove a configured network based on id
+ * @config: Configuration data from wpa_config_read()
+ * @id: Unique network id to search for
+ * Returns: 0 on success, or -1 if the network was not found
+ */
+int wpa_config_remove_network(struct wpa_config *config, int id)
+{
+	struct wpa_ssid *ssid, *prev = NULL;
+
+	ssid = config->ssid;
+	while (ssid) {
+		if (id == ssid->id)
+			break;
+		prev = ssid;
+		ssid = ssid->next;
+	}
+
+	if (ssid == NULL)
+		return -1;
+
+	if (prev)
+		prev->next = ssid->next;
+	else
+		config->ssid = ssid->next;
+
+	wpa_config_update_prio_list(config);
+	wpa_config_free_ssid(ssid);
+	return 0;
+}
+
+
+/**
+ * wpa_config_set_network_defaults - Set network default values
+ * @ssid: Pointer to network configuration data
+ */
+void wpa_config_set_network_defaults(struct wpa_ssid *ssid)
+{
+	ssid->proto = DEFAULT_PROTO;
+	ssid->pairwise_cipher = DEFAULT_PAIRWISE;
+	ssid->group_cipher = DEFAULT_GROUP;
+	ssid->key_mgmt = DEFAULT_KEY_MGMT;
+	ssid->bg_scan_period = DEFAULT_BG_SCAN_PERIOD;
+#ifdef IEEE8021X_EAPOL
+	ssid->eapol_flags = DEFAULT_EAPOL_FLAGS;
+	ssid->eap_workaround = DEFAULT_EAP_WORKAROUND;
+	ssid->eap.fragment_size = DEFAULT_FRAGMENT_SIZE;
+#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_HT_OVERRIDES
+	ssid->disable_ht = DEFAULT_DISABLE_HT;
+	ssid->disable_ht40 = DEFAULT_DISABLE_HT40;
+	ssid->disable_sgi = DEFAULT_DISABLE_SGI;
+	ssid->disable_max_amsdu = DEFAULT_DISABLE_MAX_AMSDU;
+	ssid->ampdu_factor = DEFAULT_AMPDU_FACTOR;
+	ssid->ampdu_density = DEFAULT_AMPDU_DENSITY;
+#endif /* CONFIG_HT_OVERRIDES */
+	ssid->proactive_key_caching = -1;
+#ifdef CONFIG_IEEE80211W
+	ssid->ieee80211w = MGMT_FRAME_PROTECTION_DEFAULT;
+#endif /* CONFIG_IEEE80211W */
+}
+
+
+/**
+ * wpa_config_set - Set a variable in network configuration
+ * @ssid: Pointer to network configuration data
+ * @var: Variable name, e.g., "ssid"
+ * @value: Variable value
+ * @line: Line number in configuration file or 0 if not used
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function can be used to set network configuration variables based on
+ * both the configuration file and management interface input. The value
+ * parameter must be in the same format as the text-based configuration file is
+ * using. For example, strings are using double quotation marks.
+ */
+int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
+		   int line)
+{
+	size_t i;
+	int ret = 0;
+
+	if (ssid == NULL || var == NULL || value == NULL)
+		return -1;
+
+	for (i = 0; i < NUM_SSID_FIELDS; i++) {
+		const struct parse_data *field = &ssid_fields[i];
+		if (os_strcmp(var, field->name) != 0)
+			continue;
+
+		if (field->parser(field, ssid, line, value)) {
+			if (line) {
+				wpa_printf(MSG_ERROR, "Line %d: failed to "
+					   "parse %s '%s'.", line, var, value);
+			}
+			ret = -1;
+		}
+		break;
+	}
+	if (i == NUM_SSID_FIELDS) {
+		if (line) {
+			wpa_printf(MSG_ERROR, "Line %d: unknown network field "
+				   "'%s'.", line, var);
+		}
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
+			  const char *value)
+{
+	size_t len;
+	char *buf;
+	int ret;
+
+	len = os_strlen(value);
+	buf = os_malloc(len + 3);
+	if (buf == NULL)
+		return -1;
+	buf[0] = '"';
+	os_memcpy(buf + 1, value, len);
+	buf[len + 1] = '"';
+	buf[len + 2] = '\0';
+	ret = wpa_config_set(ssid, var, buf, 0);
+	os_free(buf);
+	return ret;
+}
+
+
+/**
+ * wpa_config_get_all - Get all options from network configuration
+ * @ssid: Pointer to network configuration data
+ * @get_keys: Determines if keys/passwords will be included in returned list
+ *	(if they may be exported)
+ * Returns: %NULL terminated list of all set keys and their values in the form
+ * of [key1, val1, key2, val2, ... , NULL]
+ *
+ * This function can be used to get list of all configured network properties.
+ * The caller is responsible for freeing the returned list and all its
+ * elements.
+ */
+char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys)
+{
+	const struct parse_data *field;
+	char *key, *value;
+	size_t i;
+	char **props;
+	int fields_num;
+
+	get_keys = get_keys && ssid->export_keys;
+
+	props = os_calloc(2 * NUM_SSID_FIELDS + 1, sizeof(char *));
+	if (!props)
+		return NULL;
+
+	fields_num = 0;
+	for (i = 0; i < NUM_SSID_FIELDS; i++) {
+		field = &ssid_fields[i];
+		if (field->key_data && !get_keys)
+			continue;
+		value = field->writer(field, ssid);
+		if (value == NULL)
+			continue;
+		if (os_strlen(value) == 0) {
+			os_free(value);
+			continue;
+		}
+
+		key = os_strdup(field->name);
+		if (key == NULL) {
+			os_free(value);
+			goto err;
+		}
+
+		props[fields_num * 2] = key;
+		props[fields_num * 2 + 1] = value;
+
+		fields_num++;
+	}
+
+	return props;
+
+err:
+	value = *props;
+	while (value)
+		os_free(value++);
+	os_free(props);
+	return NULL;
+}
+
+
+#ifndef NO_CONFIG_WRITE
+/**
+ * wpa_config_get - Get a variable in network configuration
+ * @ssid: Pointer to network configuration data
+ * @var: Variable name, e.g., "ssid"
+ * Returns: Value of the variable or %NULL on failure
+ *
+ * This function can be used to get network configuration variables. The
+ * returned value is a copy of the configuration variable in text format, i.e,.
+ * the same format that the text-based configuration file and wpa_config_set()
+ * are using for the value. The caller is responsible for freeing the returned
+ * value.
+ */
+char * wpa_config_get(struct wpa_ssid *ssid, const char *var)
+{
+	size_t i;
+
+	if (ssid == NULL || var == NULL)
+		return NULL;
+
+	for (i = 0; i < NUM_SSID_FIELDS; i++) {
+		const struct parse_data *field = &ssid_fields[i];
+		if (os_strcmp(var, field->name) == 0)
+			return field->writer(field, ssid);
+	}
+
+	return NULL;
+}
+
+
+/**
+ * wpa_config_get_no_key - Get a variable in network configuration (no keys)
+ * @ssid: Pointer to network configuration data
+ * @var: Variable name, e.g., "ssid"
+ * Returns: Value of the variable or %NULL on failure
+ *
+ * This function can be used to get network configuration variable like
+ * wpa_config_get(). The only difference is that this functions does not expose
+ * key/password material from the configuration. In case a key/password field
+ * is requested, the returned value is an empty string or %NULL if the variable
+ * is not set or "*" if the variable is set (regardless of its value). The
+ * returned value is a copy of the configuration variable in text format, i.e,.
+ * the same format that the text-based configuration file and wpa_config_set()
+ * are using for the value. The caller is responsible for freeing the returned
+ * value.
+ */
+char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var)
+{
+	size_t i;
+
+	if (ssid == NULL || var == NULL)
+		return NULL;
+
+	for (i = 0; i < NUM_SSID_FIELDS; i++) {
+		const struct parse_data *field = &ssid_fields[i];
+		if (os_strcmp(var, field->name) == 0) {
+			char *res = field->writer(field, ssid);
+			if (field->key_data) {
+				if (res && res[0]) {
+					wpa_printf(MSG_DEBUG, "Do not allow "
+						   "key_data field to be "
+						   "exposed");
+					os_free(res);
+					return os_strdup("*");
+				}
+
+				os_free(res);
+				return NULL;
+			}
+			return res;
+		}
+	}
+
+	return NULL;
+}
+#endif /* NO_CONFIG_WRITE */
+
+
+/**
+ * wpa_config_update_psk - Update WPA PSK based on passphrase and SSID
+ * @ssid: Pointer to network configuration data
+ *
+ * This function must be called to update WPA PSK when either SSID or the
+ * passphrase has changed for the network configuration.
+ */
+void wpa_config_update_psk(struct wpa_ssid *ssid)
+{
+#ifndef CONFIG_NO_PBKDF2
+	pbkdf2_sha1(ssid->passphrase, ssid->ssid, ssid->ssid_len, 4096,
+		    ssid->psk, PMK_LEN);
+	wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
+			ssid->psk, PMK_LEN);
+	ssid->psk_set = 1;
+#endif /* CONFIG_NO_PBKDF2 */
+}
+
+
+int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
+			const char *value, int line)
+{
+	char *val;
+	size_t len;
+
+	if (os_strcmp(var, "priority") == 0) {
+		cred->priority = atoi(value);
+		return 0;
+	}
+
+	if (os_strcmp(var, "pcsc") == 0) {
+		cred->pcsc = atoi(value);
+		return 0;
+	}
+
+	if (os_strcmp(var, "eap") == 0) {
+		struct eap_method_type method;
+		method.method = eap_peer_get_type(value, &method.vendor);
+		if (method.vendor == EAP_VENDOR_IETF &&
+		    method.method == EAP_TYPE_NONE) {
+			wpa_printf(MSG_ERROR, "Line %d: unknown EAP type '%s' "
+				   "for a credential", line, value);
+			return -1;
+		}
+		os_free(cred->eap_method);
+		cred->eap_method = os_malloc(sizeof(*cred->eap_method));
+		if (cred->eap_method == NULL)
+			return -1;
+		os_memcpy(cred->eap_method, &method, sizeof(method));
+		return 0;
+	}
+
+	if (os_strcmp(var, "password") == 0 &&
+	    os_strncmp(value, "ext:", 4) == 0) {
+		os_free(cred->password);
+		cred->password = os_strdup(value);
+		cred->ext_password = 1;
+		return 0;
+	}
+
+	val = wpa_config_parse_string(value, &len);
+	if (val == NULL) {
+		wpa_printf(MSG_ERROR, "Line %d: invalid field '%s' string "
+			   "value '%s'.", line, var, value);
+		return -1;
+	}
+
+	if (os_strcmp(var, "realm") == 0) {
+		os_free(cred->realm);
+		cred->realm = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "username") == 0) {
+		os_free(cred->username);
+		cred->username = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "password") == 0) {
+		os_free(cred->password);
+		cred->password = val;
+		cred->ext_password = 0;
+		return 0;
+	}
+
+	if (os_strcmp(var, "ca_cert") == 0) {
+		os_free(cred->ca_cert);
+		cred->ca_cert = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "client_cert") == 0) {
+		os_free(cred->client_cert);
+		cred->client_cert = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "private_key") == 0) {
+		os_free(cred->private_key);
+		cred->private_key = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "private_key_passwd") == 0) {
+		os_free(cred->private_key_passwd);
+		cred->private_key_passwd = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "imsi") == 0) {
+		os_free(cred->imsi);
+		cred->imsi = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "milenage") == 0) {
+		os_free(cred->milenage);
+		cred->milenage = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "domain") == 0) {
+		os_free(cred->domain);
+		cred->domain = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "phase1") == 0) {
+		os_free(cred->phase1);
+		cred->phase1 = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "phase2") == 0) {
+		os_free(cred->phase2);
+		cred->phase2 = val;
+		return 0;
+	}
+
+	if (os_strcmp(var, "roaming_consortium") == 0) {
+		if (len < 3 || len > sizeof(cred->roaming_consortium)) {
+			wpa_printf(MSG_ERROR, "Line %d: invalid "
+				   "roaming_consortium length %d (3..15 "
+				   "expected)", line, (int) len);
+			os_free(val);
+			return -1;
+		}
+		os_memcpy(cred->roaming_consortium, val, len);
+		cred->roaming_consortium_len = len;
+		os_free(val);
+		return 0;
+	}
+
+	if (os_strcmp(var, "excluded_ssid") == 0) {
+		struct excluded_ssid *e;
+
+		if (len > MAX_SSID_LEN) {
+			wpa_printf(MSG_ERROR, "Line %d: invalid "
+				   "excluded_ssid length %d", line, (int) len);
+			os_free(val);
+			return -1;
+		}
+
+		e = os_realloc_array(cred->excluded_ssid,
+				     cred->num_excluded_ssid + 1,
+				     sizeof(struct excluded_ssid));
+		if (e == NULL) {
+			os_free(val);
+			return -1;
+		}
+		cred->excluded_ssid = e;
+
+		e = &cred->excluded_ssid[cred->num_excluded_ssid++];
+		os_memcpy(e->ssid, val, len);
+		e->ssid_len = len;
+
+		os_free(val);
+
+		return 0;
+	}
+
+	if (line) {
+		wpa_printf(MSG_ERROR, "Line %d: unknown cred field '%s'.",
+			   line, var);
+	}
+
+	os_free(val);
+
+	return -1;
+}
+
+
+struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id)
+{
+	struct wpa_cred *cred;
+
+	cred = config->cred;
+	while (cred) {
+		if (id == cred->id)
+			break;
+		cred = cred->next;
+	}
+
+	return cred;
+}
+
+
+struct wpa_cred * wpa_config_add_cred(struct wpa_config *config)
+{
+	int id;
+	struct wpa_cred *cred, *last = NULL;
+
+	id = -1;
+	cred = config->cred;
+	while (cred) {
+		if (cred->id > id)
+			id = cred->id;
+		last = cred;
+		cred = cred->next;
+	}
+	id++;
+
+	cred = os_zalloc(sizeof(*cred));
+	if (cred == NULL)
+		return NULL;
+	cred->id = id;
+	if (last)
+		last->next = cred;
+	else
+		config->cred = cred;
+
+	return cred;
+}
+
+
+int wpa_config_remove_cred(struct wpa_config *config, int id)
+{
+	struct wpa_cred *cred, *prev = NULL;
+
+	cred = config->cred;
+	while (cred) {
+		if (id == cred->id)
+			break;
+		prev = cred;
+		cred = cred->next;
+	}
+
+	if (cred == NULL)
+		return -1;
+
+	if (prev)
+		prev->next = cred->next;
+	else
+		config->cred = cred->next;
+
+	wpa_config_free_cred(cred);
+	return 0;
+}
+
+
+#ifndef CONFIG_NO_CONFIG_BLOBS
+/**
+ * wpa_config_get_blob - Get a named configuration blob
+ * @config: Configuration data from wpa_config_read()
+ * @name: Name of the blob
+ * Returns: Pointer to blob data or %NULL if not found
+ */
+const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config,
+						   const char *name)
+{
+	struct wpa_config_blob *blob = config->blobs;
+
+	while (blob) {
+		if (os_strcmp(blob->name, name) == 0)
+			return blob;
+		blob = blob->next;
+	}
+	return NULL;
+}
+
+
+/**
+ * wpa_config_set_blob - Set or add a named configuration blob
+ * @config: Configuration data from wpa_config_read()
+ * @blob: New value for the blob
+ *
+ * Adds a new configuration blob or replaces the current value of an existing
+ * blob.
+ */
+void wpa_config_set_blob(struct wpa_config *config,
+			 struct wpa_config_blob *blob)
+{
+	wpa_config_remove_blob(config, blob->name);
+	blob->next = config->blobs;
+	config->blobs = blob;
+}
+
+
+/**
+ * wpa_config_free_blob - Free blob data
+ * @blob: Pointer to blob to be freed
+ */
+void wpa_config_free_blob(struct wpa_config_blob *blob)
+{
+	if (blob) {
+		os_free(blob->name);
+		os_free(blob->data);
+		os_free(blob);
+	}
+}
+
+
+/**
+ * wpa_config_remove_blob - Remove a named configuration blob
+ * @config: Configuration data from wpa_config_read()
+ * @name: Name of the blob to remove
+ * Returns: 0 if blob was removed or -1 if blob was not found
+ */
+int wpa_config_remove_blob(struct wpa_config *config, const char *name)
+{
+	struct wpa_config_blob *pos = config->blobs, *prev = NULL;
+
+	while (pos) {
+		if (os_strcmp(pos->name, name) == 0) {
+			if (prev)
+				prev->next = pos->next;
+			else
+				config->blobs = pos->next;
+			wpa_config_free_blob(pos);
+			return 0;
+		}
+		prev = pos;
+		pos = pos->next;
+	}
+
+	return -1;
+}
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
+
+/**
+ * wpa_config_alloc_empty - Allocate an empty configuration
+ * @ctrl_interface: Control interface parameters, e.g., path to UNIX domain
+ * socket
+ * @driver_param: Driver parameters
+ * Returns: Pointer to allocated configuration data or %NULL on failure
+ */
+struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
+					   const char *driver_param)
+{
+	struct wpa_config *config;
+	const int aCWmin = 4, aCWmax = 10;
+	const struct hostapd_wmm_ac_params ac_bk =
+		{ aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
+	const struct hostapd_wmm_ac_params ac_be =
+		{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
+	const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
+		{ aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
+	const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
+		{ aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
+
+	config = os_zalloc(sizeof(*config));
+	if (config == NULL)
+		return NULL;
+	config->eapol_version = DEFAULT_EAPOL_VERSION;
+	config->ap_scan = DEFAULT_AP_SCAN;
+	config->fast_reauth = DEFAULT_FAST_REAUTH;
+	config->p2p_go_intent = DEFAULT_P2P_GO_INTENT;
+	config->p2p_intra_bss = DEFAULT_P2P_INTRA_BSS;
+	config->p2p_go_max_inactivity = DEFAULT_P2P_GO_MAX_INACTIVITY;
+	config->bss_max_count = DEFAULT_BSS_MAX_COUNT;
+	config->bss_expiration_age = DEFAULT_BSS_EXPIRATION_AGE;
+	config->bss_expiration_scan_count = DEFAULT_BSS_EXPIRATION_SCAN_COUNT;
+	config->max_num_sta = DEFAULT_MAX_NUM_STA;
+	config->access_network_type = DEFAULT_ACCESS_NETWORK_TYPE;
+	config->wmm_ac_params[0] = ac_be;
+	config->wmm_ac_params[1] = ac_bk;
+	config->wmm_ac_params[2] = ac_vi;
+	config->wmm_ac_params[3] = ac_vo;
+
+	if (ctrl_interface)
+		config->ctrl_interface = os_strdup(ctrl_interface);
+	if (driver_param)
+		config->driver_param = os_strdup(driver_param);
+
+	return config;
+}
+
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+/**
+ * wpa_config_debug_dump_networks - Debug dump of configured networks
+ * @config: Configuration data from wpa_config_read()
+ */
+void wpa_config_debug_dump_networks(struct wpa_config *config)
+{
+	int prio;
+	struct wpa_ssid *ssid;
+
+	for (prio = 0; prio < config->num_prio; prio++) {
+		ssid = config->pssid[prio];
+		wpa_printf(MSG_DEBUG, "Priority group %d",
+			   ssid->priority);
+		while (ssid) {
+			wpa_printf(MSG_DEBUG, "   id=%d ssid='%s'",
+				   ssid->id,
+				   wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+			ssid = ssid->pnext;
+		}
+	}
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+struct global_parse_data {
+	char *name;
+	int (*parser)(const struct global_parse_data *data,
+		      struct wpa_config *config, int line, const char *value);
+	void *param1, *param2, *param3;
+	unsigned int changed_flag;
+};
+
+
+static int wpa_global_config_parse_int(const struct global_parse_data *data,
+				       struct wpa_config *config, int line,
+				       const char *pos)
+{
+	int *dst;
+	dst = (int *) (((u8 *) config) + (long) data->param1);
+	*dst = atoi(pos);
+	wpa_printf(MSG_DEBUG, "%s=%d", data->name, *dst);
+
+	if (data->param2 && *dst < (long) data->param2) {
+		wpa_printf(MSG_ERROR, "Line %d: too small %s (value=%d "
+			   "min_value=%ld)", line, data->name, *dst,
+			   (long) data->param2);
+		*dst = (long) data->param2;
+		return -1;
+	}
+
+	if (data->param3 && *dst > (long) data->param3) {
+		wpa_printf(MSG_ERROR, "Line %d: too large %s (value=%d "
+			   "max_value=%ld)", line, data->name, *dst,
+			   (long) data->param3);
+		*dst = (long) data->param3;
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_global_config_parse_str(const struct global_parse_data *data,
+				       struct wpa_config *config, int line,
+				       const char *pos)
+{
+	size_t len;
+	char **dst, *tmp;
+
+	len = os_strlen(pos);
+	if (data->param2 && len < (size_t) data->param2) {
+		wpa_printf(MSG_ERROR, "Line %d: too short %s (len=%lu "
+			   "min_len=%ld)", line, data->name,
+			   (unsigned long) len, (long) data->param2);
+		return -1;
+	}
+
+	if (data->param3 && len > (size_t) data->param3) {
+		wpa_printf(MSG_ERROR, "Line %d: too long %s (len=%lu "
+			   "max_len=%ld)", line, data->name,
+			   (unsigned long) len, (long) data->param3);
+		return -1;
+	}
+
+	tmp = os_strdup(pos);
+	if (tmp == NULL)
+		return -1;
+
+	dst = (char **) (((u8 *) config) + (long) data->param1);
+	os_free(*dst);
+	*dst = tmp;
+	wpa_printf(MSG_DEBUG, "%s='%s'", data->name, *dst);
+
+	return 0;
+}
+
+
+static int wpa_global_config_parse_bin(const struct global_parse_data *data,
+				       struct wpa_config *config, int line,
+				       const char *pos)
+{
+	size_t len;
+	struct wpabuf **dst, *tmp;
+
+	len = os_strlen(pos);
+	if (len & 0x01)
+		return -1;
+
+	tmp = wpabuf_alloc(len / 2);
+	if (tmp == NULL)
+		return -1;
+
+	if (hexstr2bin(pos, wpabuf_put(tmp, len / 2), len / 2)) {
+		wpabuf_free(tmp);
+		return -1;
+	}
+
+	dst = (struct wpabuf **) (((u8 *) config) + (long) data->param1);
+	wpabuf_free(*dst);
+	*dst = tmp;
+	wpa_printf(MSG_DEBUG, "%s", data->name);
+
+	return 0;
+}
+
+
+static int wpa_config_process_country(const struct global_parse_data *data,
+				      struct wpa_config *config, int line,
+				      const char *pos)
+{
+	if (!pos[0] || !pos[1]) {
+		wpa_printf(MSG_DEBUG, "Invalid country set");
+		return -1;
+	}
+	config->country[0] = pos[0];
+	config->country[1] = pos[1];
+	wpa_printf(MSG_DEBUG, "country='%c%c'",
+		   config->country[0], config->country[1]);
+	return 0;
+}
+
+
+static int wpa_config_process_load_dynamic_eap(
+	const struct global_parse_data *data, struct wpa_config *config,
+	int line, const char *so)
+{
+	int ret;
+	wpa_printf(MSG_DEBUG, "load_dynamic_eap=%s", so);
+	ret = eap_peer_method_load(so);
+	if (ret == -2) {
+		wpa_printf(MSG_DEBUG, "This EAP type was already loaded - not "
+			   "reloading.");
+	} else if (ret) {
+		wpa_printf(MSG_ERROR, "Line %d: Failed to load dynamic EAP "
+			   "method '%s'.", line, so);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_WPS
+
+static int wpa_config_process_uuid(const struct global_parse_data *data,
+				   struct wpa_config *config, int line,
+				   const char *pos)
+{
+	char buf[40];
+	if (uuid_str2bin(pos, config->uuid)) {
+		wpa_printf(MSG_ERROR, "Line %d: invalid UUID", line);
+		return -1;
+	}
+	uuid_bin2str(config->uuid, buf, sizeof(buf));
+	wpa_printf(MSG_DEBUG, "uuid=%s", buf);
+	return 0;
+}
+
+
+static int wpa_config_process_device_type(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	return wps_dev_type_str2bin(pos, config->device_type);
+}
+
+
+static int wpa_config_process_os_version(const struct global_parse_data *data,
+					 struct wpa_config *config, int line,
+					 const char *pos)
+{
+	if (hexstr2bin(pos, config->os_version, 4)) {
+		wpa_printf(MSG_ERROR, "Line %d: invalid os_version", line);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "os_version=%08x",
+		   WPA_GET_BE32(config->os_version));
+	return 0;
+}
+
+
+static int wpa_config_process_wps_vendor_ext_m1(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	struct wpabuf *tmp;
+	int len = os_strlen(pos) / 2;
+	u8 *p;
+
+	if (!len) {
+		wpa_printf(MSG_ERROR, "Line %d: "
+			   "invalid wps_vendor_ext_m1", line);
+		return -1;
+	}
+
+	tmp = wpabuf_alloc(len);
+	if (tmp) {
+		p = wpabuf_put(tmp, len);
+
+		if (hexstr2bin(pos, p, len)) {
+			wpa_printf(MSG_ERROR, "Line %d: "
+				   "invalid wps_vendor_ext_m1", line);
+			wpabuf_free(tmp);
+			return -1;
+		}
+
+		wpabuf_free(config->wps_vendor_ext_m1);
+		config->wps_vendor_ext_m1 = tmp;
+	} else {
+		wpa_printf(MSG_ERROR, "Can not allocate "
+			   "memory for wps_vendor_ext_m1");
+		return -1;
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+static int wpa_config_process_sec_device_type(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	int idx;
+
+	if (config->num_sec_device_types >= MAX_SEC_DEVICE_TYPES) {
+		wpa_printf(MSG_ERROR, "Line %d: too many sec_device_type "
+			   "items", line);
+		return -1;
+	}
+
+	idx = config->num_sec_device_types;
+
+	if (wps_dev_type_str2bin(pos, config->sec_device_type[idx]))
+		return -1;
+
+	config->num_sec_device_types++;
+	return 0;
+}
+
+
+static int wpa_config_process_p2p_pref_chan(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	struct p2p_channel *pref = NULL, *n;
+	unsigned int num = 0;
+	const char *pos2;
+	u8 op_class, chan;
+
+	/* format: class:chan,class:chan,... */
+
+	while (*pos) {
+		op_class = atoi(pos);
+		pos2 = os_strchr(pos, ':');
+		if (pos2 == NULL)
+			goto fail;
+		pos2++;
+		chan = atoi(pos2);
+
+		n = os_realloc_array(pref, num + 1,
+				     sizeof(struct p2p_channel));
+		if (n == NULL)
+			goto fail;
+		pref = n;
+		pref[num].op_class = op_class;
+		pref[num].chan = chan;
+		num++;
+
+		pos = os_strchr(pos2, ',');
+		if (pos == NULL)
+			break;
+		pos++;
+	}
+
+	os_free(config->p2p_pref_chan);
+	config->p2p_pref_chan = pref;
+	config->num_p2p_pref_chan = num;
+	wpa_hexdump(MSG_DEBUG, "P2P: Preferred class/channel pairs",
+		    (u8 *) config->p2p_pref_chan,
+		    config->num_p2p_pref_chan * sizeof(struct p2p_channel));
+
+	return 0;
+
+fail:
+	os_free(pref);
+	wpa_printf(MSG_ERROR, "Line %d: Invalid p2p_pref_chan list", line);
+	return -1;
+}
+#endif /* CONFIG_P2P */
+
+
+static int wpa_config_process_hessid(
+	const struct global_parse_data *data,
+	struct wpa_config *config, int line, const char *pos)
+{
+	if (hwaddr_aton2(pos, config->hessid) < 0) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid hessid '%s'",
+			   line, pos);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+#ifdef OFFSET
+#undef OFFSET
+#endif /* OFFSET */
+/* OFFSET: Get offset of a variable within the wpa_config structure */
+#define OFFSET(v) ((void *) &((struct wpa_config *) 0)->v)
+
+#define FUNC(f) #f, wpa_config_process_ ## f, OFFSET(f), NULL, NULL
+#define FUNC_NO_VAR(f) #f, wpa_config_process_ ## f, NULL, NULL, NULL
+#define _INT(f) #f, wpa_global_config_parse_int, OFFSET(f)
+#define INT(f) _INT(f), NULL, NULL
+#define INT_RANGE(f, min, max) _INT(f), (void *) min, (void *) max
+#define _STR(f) #f, wpa_global_config_parse_str, OFFSET(f)
+#define STR(f) _STR(f), NULL, NULL
+#define STR_RANGE(f, min, max) _STR(f), (void *) min, (void *) max
+#define BIN(f) #f, wpa_global_config_parse_bin, OFFSET(f), NULL, NULL
+
+static const struct global_parse_data global_fields[] = {
+#ifdef CONFIG_CTRL_IFACE
+	{ STR(ctrl_interface), 0 },
+	{ STR(ctrl_interface_group), 0 } /* deprecated */,
+#endif /* CONFIG_CTRL_IFACE */
+	{ INT_RANGE(eapol_version, 1, 2), 0 },
+	{ INT(ap_scan), 0 },
+	{ INT(disable_scan_offload), 0 },
+	{ INT(fast_reauth), 0 },
+	{ STR(opensc_engine_path), 0 },
+	{ STR(pkcs11_engine_path), 0 },
+	{ STR(pkcs11_module_path), 0 },
+	{ STR(pcsc_reader), 0 },
+	{ STR(pcsc_pin), 0 },
+	{ STR(driver_param), 0 },
+	{ INT(dot11RSNAConfigPMKLifetime), 0 },
+	{ INT(dot11RSNAConfigPMKReauthThreshold), 0 },
+	{ INT(dot11RSNAConfigSATimeout), 0 },
+#ifndef CONFIG_NO_CONFIG_WRITE
+	{ INT(update_config), 0 },
+#endif /* CONFIG_NO_CONFIG_WRITE */
+	{ FUNC_NO_VAR(load_dynamic_eap), 0 },
+#ifdef CONFIG_WPS
+	{ FUNC(uuid), CFG_CHANGED_UUID },
+	{ STR_RANGE(device_name, 0, 32), CFG_CHANGED_DEVICE_NAME },
+	{ STR_RANGE(manufacturer, 0, 64), CFG_CHANGED_WPS_STRING },
+	{ STR_RANGE(model_name, 0, 32), CFG_CHANGED_WPS_STRING },
+	{ STR_RANGE(model_number, 0, 32), CFG_CHANGED_WPS_STRING },
+	{ STR_RANGE(serial_number, 0, 32), CFG_CHANGED_WPS_STRING },
+	{ FUNC(device_type), CFG_CHANGED_DEVICE_TYPE },
+	{ FUNC(os_version), CFG_CHANGED_OS_VERSION },
+	{ STR(config_methods), CFG_CHANGED_CONFIG_METHODS },
+	{ INT_RANGE(wps_cred_processing, 0, 2), 0 },
+	{ FUNC(wps_vendor_ext_m1), CFG_CHANGED_VENDOR_EXTENSION },
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+	{ FUNC(sec_device_type), CFG_CHANGED_SEC_DEVICE_TYPE },
+	{ INT(p2p_listen_reg_class), 0 },
+	{ INT(p2p_listen_channel), 0 },
+	{ INT(p2p_oper_reg_class), 0 },
+	{ INT(p2p_oper_channel), 0 },
+	{ INT_RANGE(p2p_go_intent, 0, 15), 0 },
+	{ STR(p2p_ssid_postfix), CFG_CHANGED_P2P_SSID_POSTFIX },
+	{ INT_RANGE(persistent_reconnect, 0, 1), 0 },
+	{ INT_RANGE(p2p_intra_bss, 0, 1), CFG_CHANGED_P2P_INTRA_BSS },
+	{ INT(p2p_group_idle), 0 },
+	{ FUNC(p2p_pref_chan), CFG_CHANGED_P2P_PREF_CHAN },
+	{ INT(p2p_go_ht40), 0 },
+	{ INT(p2p_disabled), 0 },
+	{ INT(p2p_no_group_iface), 0 },
+#endif /* CONFIG_P2P */
+	{ FUNC(country), CFG_CHANGED_COUNTRY },
+	{ INT(bss_max_count), 0 },
+	{ INT(bss_expiration_age), 0 },
+	{ INT(bss_expiration_scan_count), 0 },
+	{ INT_RANGE(filter_ssids, 0, 1), 0 },
+	{ INT_RANGE(filter_rssi, -100, 0), 0 },
+	{ INT(max_num_sta), 0 },
+	{ INT_RANGE(disassoc_low_ack, 0, 1), 0 },
+#ifdef CONFIG_HS20
+	{ INT_RANGE(hs20, 0, 1), 0 },
+#endif /* CONFIG_HS20 */
+	{ INT_RANGE(interworking, 0, 1), 0 },
+	{ FUNC(hessid), 0 },
+	{ INT_RANGE(access_network_type, 0, 15), 0 },
+	{ INT_RANGE(pbc_in_m1, 0, 1), 0 },
+	{ STR(autoscan), 0 },
+	{ INT_RANGE(wps_nfc_dev_pw_id, 0x10, 0xffff), 0 },
+	{ BIN(wps_nfc_dh_pubkey), 0 },
+	{ BIN(wps_nfc_dh_privkey), 0 },
+	{ BIN(wps_nfc_dev_pw), 0 },
+	{ STR(ext_password_backend), CFG_CHANGED_EXT_PW_BACKEND },
+	{ INT(p2p_go_max_inactivity), 0 },
+	{ INT_RANGE(auto_interworking, 0, 1), 0 },
+	{ INT(okc), 0 },
+	{ INT(pmf), 0 },
+};
+
+#undef FUNC
+#undef _INT
+#undef INT
+#undef INT_RANGE
+#undef _STR
+#undef STR
+#undef STR_RANGE
+#undef BIN
+#define NUM_GLOBAL_FIELDS (sizeof(global_fields) / sizeof(global_fields[0]))
+
+
+int wpa_config_process_global(struct wpa_config *config, char *pos, int line)
+{
+	size_t i;
+	int ret = 0;
+
+	for (i = 0; i < NUM_GLOBAL_FIELDS; i++) {
+		const struct global_parse_data *field = &global_fields[i];
+		size_t flen = os_strlen(field->name);
+		if (os_strncmp(pos, field->name, flen) != 0 ||
+		    pos[flen] != '=')
+			continue;
+
+		if (field->parser(field, config, line, pos + flen + 1)) {
+			wpa_printf(MSG_ERROR, "Line %d: failed to "
+				   "parse '%s'.", line, pos);
+			ret = -1;
+		}
+		config->changed_parameters |= field->changed_flag;
+		break;
+	}
+	if (i == NUM_GLOBAL_FIELDS) {
+#ifdef CONFIG_AP
+		if (os_strncmp(pos, "wmm_ac_", 7) == 0) {
+			char *tmp = os_strchr(pos, '=');
+			if (tmp == NULL) {
+				if (line < 0)
+					return -1;
+				wpa_printf(MSG_ERROR, "Line %d: invalid line "
+					   "'%s'", line, pos);
+				return -1;
+			}
+			*tmp++ = '\0';
+			if (hostapd_config_wmm_ac(config->wmm_ac_params, pos,
+						  tmp)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
+					   "AC item", line);
+				return -1;
+			}
+		}
+#endif /* CONFIG_AP */
+		if (line < 0)
+			return -1;
+		wpa_printf(MSG_ERROR, "Line %d: unknown global field '%s'.",
+			   line, pos);
+		ret = -1;
+	}
+
+	return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/config.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,884 @@
+/*
+ * WPA Supplicant / Configuration file structures
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CONFIG_H
+#define CONFIG_H
+
+#define DEFAULT_EAPOL_VERSION 1
+#ifdef CONFIG_NO_SCAN_PROCESSING
+#define DEFAULT_AP_SCAN 2
+#else /* CONFIG_NO_SCAN_PROCESSING */
+#define DEFAULT_AP_SCAN 1
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+#define DEFAULT_FAST_REAUTH 1
+#define DEFAULT_P2P_GO_INTENT 7
+#define DEFAULT_P2P_INTRA_BSS 1
+#define DEFAULT_P2P_GO_MAX_INACTIVITY (5 * 60)
+#define DEFAULT_BSS_MAX_COUNT 200
+#define DEFAULT_BSS_EXPIRATION_AGE 180
+#define DEFAULT_BSS_EXPIRATION_SCAN_COUNT 2
+#define DEFAULT_MAX_NUM_STA 128
+#define DEFAULT_ACCESS_NETWORK_TYPE 15
+
+#include "config_ssid.h"
+#include "wps/wps.h"
+#include "common/ieee802_11_common.h"
+
+
+struct wpa_cred {
+	/**
+	 * next - Next credential in the list
+	 *
+	 * This pointer can be used to iterate over all credentials. The head
+	 * of this list is stored in the cred field of struct wpa_config.
+	 */
+	struct wpa_cred *next;
+
+	/**
+	 * id - Unique id for the credential
+	 *
+	 * This identifier is used as a unique identifier for each credential
+	 * block when using the control interface. Each credential is allocated
+	 * an id when it is being created, either when reading the
+	 * configuration file or when a new credential is added through the
+	 * control interface.
+	 */
+	int id;
+
+	/**
+	 * priority - Priority group
+	 *
+	 * By default, all networks and credentials get the same priority group
+	 * (0). This field can be used to give higher priority for credentials
+	 * (and similarly in struct wpa_ssid for network blocks) to change the
+	 * Interworking automatic networking selection behavior. The matching
+	 * network (based on either an enabled network block or a credential)
+	 * with the highest priority value will be selected.
+	 */
+	int priority;
+
+	/**
+	 * pcsc - Use PC/SC and SIM/USIM card
+	 */
+	int pcsc;
+
+	/**
+	 * realm - Home Realm for Interworking
+	 */
+	char *realm;
+
+	/**
+	 * username - Username for Interworking network selection
+	 */
+	char *username;
+
+	/**
+	 * password - Password for Interworking network selection
+	 */
+	char *password;
+
+	/**
+	 * ext_password - Whether password is a name for external storage
+	 */
+	int ext_password;
+
+	/**
+	 * ca_cert - CA certificate for Interworking network selection
+	 */
+	char *ca_cert;
+
+	/**
+	 * client_cert - File path to client certificate file (PEM/DER)
+	 *
+	 * This field is used with Interworking networking selection for a case
+	 * where client certificate/private key is used for authentication
+	 * (EAP-TLS). Full path to the file should be used since working
+	 * directory may change when wpa_supplicant is run in the background.
+	 *
+	 * Alternatively, a named configuration blob can be used by setting
+	 * this to blob://blob_name.
+	 */
+	char *client_cert;
+
+	/**
+	 * private_key - File path to client private key file (PEM/DER/PFX)
+	 *
+	 * When PKCS#12/PFX file (.p12/.pfx) is used, client_cert should be
+	 * commented out. Both the private key and certificate will be read
+	 * from the PKCS#12 file in this case. Full path to the file should be
+	 * used since working directory may change when wpa_supplicant is run
+	 * in the background.
+	 *
+	 * Windows certificate store can be used by leaving client_cert out and
+	 * configuring private_key in one of the following formats:
+	 *
+	 * cert://substring_to_match
+	 *
+	 * hash://certificate_thumbprint_in_hex
+	 *
+	 * For example: private_key="hash://63093aa9c47f56ae88334c7b65a4"
+	 *
+	 * Note that when running wpa_supplicant as an application, the user
+	 * certificate store (My user account) is used, whereas computer store
+	 * (Computer account) is used when running wpasvc as a service.
+	 *
+	 * Alternatively, a named configuration blob can be used by setting
+	 * this to blob://blob_name.
+	 */
+	char *private_key;
+
+	/**
+	 * private_key_passwd - Password for private key file
+	 */
+	char *private_key_passwd;
+
+	/**
+	 * imsi - IMSI in <MCC> | <MNC> | '-' | <MSIN> format
+	 */
+	char *imsi;
+
+	/**
+	 * milenage - Milenage parameters for SIM/USIM simulator in
+	 *	<Ki>:<OPc>:<SQN> format
+	 */
+	char *milenage;
+
+	/**
+	 * domain - Home service provider FQDN
+	 *
+	 * This is used to compare against the Domain Name List to figure out
+	 * whether the AP is operated by the Home SP.
+	 */
+	char *domain;
+
+	/**
+	 * roaming_consortium - Roaming Consortium OI
+	 *
+	 * If roaming_consortium_len is non-zero, this field contains the
+	 * Roaming Consortium OI that can be used to determine which access
+	 * points support authentication with this credential. This is an
+	 * alternative to the use of the realm parameter. When using Roaming
+	 * Consortium to match the network, the EAP parameters need to be
+	 * pre-configured with the credential since the NAI Realm information
+	 * may not be available or fetched.
+	 */
+	u8 roaming_consortium[15];
+
+	/**
+	 * roaming_consortium_len - Length of roaming_consortium
+	 */
+	size_t roaming_consortium_len;
+
+	/**
+	 * eap_method - EAP method to use
+	 *
+	 * Pre-configured EAP method to use with this credential or %NULL to
+	 * indicate no EAP method is selected, i.e., the method will be
+	 * selected automatically based on ANQP information.
+	 */
+	struct eap_method_type *eap_method;
+
+	/**
+	 * phase1 - Phase 1 (outer authentication) parameters
+	 *
+	 * Pre-configured EAP parameters or %NULL.
+	 */
+	char *phase1;
+
+	/**
+	 * phase2 - Phase 2 (inner authentication) parameters
+	 *
+	 * Pre-configured EAP parameters or %NULL.
+	 */
+	char *phase2;
+
+	struct excluded_ssid {
+		u8 ssid[MAX_SSID_LEN];
+		size_t ssid_len;
+	} *excluded_ssid;
+	size_t num_excluded_ssid;
+};
+
+
+#define CFG_CHANGED_DEVICE_NAME BIT(0)
+#define CFG_CHANGED_CONFIG_METHODS BIT(1)
+#define CFG_CHANGED_DEVICE_TYPE BIT(2)
+#define CFG_CHANGED_OS_VERSION BIT(3)
+#define CFG_CHANGED_UUID BIT(4)
+#define CFG_CHANGED_COUNTRY BIT(5)
+#define CFG_CHANGED_SEC_DEVICE_TYPE BIT(6)
+#define CFG_CHANGED_P2P_SSID_POSTFIX BIT(7)
+#define CFG_CHANGED_WPS_STRING BIT(8)
+#define CFG_CHANGED_P2P_INTRA_BSS BIT(9)
+#define CFG_CHANGED_VENDOR_EXTENSION BIT(10)
+#define CFG_CHANGED_P2P_LISTEN_CHANNEL BIT(11)
+#define CFG_CHANGED_P2P_OPER_CHANNEL BIT(12)
+#define CFG_CHANGED_P2P_PREF_CHAN BIT(13)
+#define CFG_CHANGED_EXT_PW_BACKEND BIT(14)
+
+/**
+ * struct wpa_config - wpa_supplicant configuration data
+ *
+ * This data structure is presents the per-interface (radio) configuration
+ * data. In many cases, there is only one struct wpa_config instance, but if
+ * more than one network interface is being controlled, one instance is used
+ * for each.
+ */
+struct wpa_config {
+	/**
+	 * ssid - Head of the global network list
+	 *
+	 * This is the head for the list of all the configured networks.
+	 */
+	struct wpa_ssid *ssid;
+
+	/**
+	 * pssid - Per-priority network lists (in priority order)
+	 */
+	struct wpa_ssid **pssid;
+
+	/**
+	 * num_prio - Number of different priorities used in the pssid lists
+	 *
+	 * This indicates how many per-priority network lists are included in
+	 * pssid.
+	 */
+	int num_prio;
+
+	/**
+	 * cred - Head of the credential list
+	 *
+	 * This is the head for the list of all the configured credentials.
+	 */
+	struct wpa_cred *cred;
+
+	/**
+	 * eapol_version - IEEE 802.1X/EAPOL version number
+	 *
+	 * wpa_supplicant is implemented based on IEEE Std 802.1X-2004 which
+	 * defines EAPOL version 2. However, there are many APs that do not
+	 * handle the new version number correctly (they seem to drop the
+	 * frames completely). In order to make wpa_supplicant interoperate
+	 * with these APs, the version number is set to 1 by default. This
+	 * configuration value can be used to set it to the new version (2).
+	 */
+	int eapol_version;
+
+	/**
+	 * ap_scan - AP scanning/selection
+	 *
+	 * By default, wpa_supplicant requests driver to perform AP
+	 * scanning and then uses the scan results to select a
+	 * suitable AP. Another alternative is to allow the driver to
+	 * take care of AP scanning and selection and use
+	 * wpa_supplicant just to process EAPOL frames based on IEEE
+	 * 802.11 association information from the driver.
+	 *
+	 * 1: wpa_supplicant initiates scanning and AP selection (default).
+	 *
+	 * 0: Driver takes care of scanning, AP selection, and IEEE 802.11
+	 * association parameters (e.g., WPA IE generation); this mode can
+	 * also be used with non-WPA drivers when using IEEE 802.1X mode;
+	 * do not try to associate with APs (i.e., external program needs
+	 * to control association). This mode must also be used when using
+	 * wired Ethernet drivers.
+	 *
+	 * 2: like 0, but associate with APs using security policy and SSID
+	 * (but not BSSID); this can be used, e.g., with ndiswrapper and NDIS
+	 * drivers to enable operation with hidden SSIDs and optimized roaming;
+	 * in this mode, the network blocks in the configuration are tried
+	 * one by one until the driver reports successful association; each
+	 * network block should have explicit security policy (i.e., only one
+	 * option in the lists) for key_mgmt, pairwise, group, proto variables.
+	 */
+	int ap_scan;
+
+	/**
+	 * disable_scan_offload - Disable automatic offloading of scan requests
+	 *
+	 * By default, %wpa_supplicant tries to offload scanning if the driver
+	 * indicates support for this (sched_scan). This configuration
+	 * parameter can be used to disable this offloading mechanism.
+	 */
+	int disable_scan_offload;
+
+	/**
+	 * ctrl_interface - Parameters for the control interface
+	 *
+	 * If this is specified, %wpa_supplicant will open a control interface
+	 * that is available for external programs to manage %wpa_supplicant.
+	 * The meaning of this string depends on which control interface
+	 * mechanism is used. For all cases, the existence of this parameter
+	 * in configuration is used to determine whether the control interface
+	 * is enabled.
+	 *
+	 * For UNIX domain sockets (default on Linux and BSD): This is a
+	 * directory that will be created for UNIX domain sockets for listening
+	 * to requests from external programs (CLI/GUI, etc.) for status
+	 * information and configuration. The socket file will be named based
+	 * on the interface name, so multiple %wpa_supplicant processes can be
+	 * run at the same time if more than one interface is used.
+	 * /var/run/wpa_supplicant is the recommended directory for sockets and
+	 * by default, wpa_cli will use it when trying to connect with
+	 * %wpa_supplicant.
+	 *
+	 * Access control for the control interface can be configured
+	 * by setting the directory to allow only members of a group
+	 * to use sockets. This way, it is possible to run
+	 * %wpa_supplicant as root (since it needs to change network
+	 * configuration and open raw sockets) and still allow GUI/CLI
+	 * components to be run as non-root users. However, since the
+	 * control interface can be used to change the network
+	 * configuration, this access needs to be protected in many
+	 * cases. By default, %wpa_supplicant is configured to use gid
+	 * 0 (root). If you want to allow non-root users to use the
+	 * control interface, add a new group and change this value to
+	 * match with that group. Add users that should have control
+	 * interface access to this group.
+	 *
+	 * When configuring both the directory and group, use following format:
+	 * DIR=/var/run/wpa_supplicant GROUP=wheel
+	 * DIR=/var/run/wpa_supplicant GROUP=0
+	 * (group can be either group name or gid)
+	 *
+	 * For UDP connections (default on Windows): The value will be ignored.
+	 * This variable is just used to select that the control interface is
+	 * to be created. The value can be set to, e.g., udp
+	 * (ctrl_interface=udp).
+	 *
+	 * For Windows Named Pipe: This value can be used to set the security
+	 * descriptor for controlling access to the control interface. Security
+	 * descriptor can be set using Security Descriptor String Format (see
+	 * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/security_descriptor_string_format.asp).
+	 * The descriptor string needs to be prefixed with SDDL=. For example,
+	 * ctrl_interface=SDDL=D: would set an empty DACL (which will reject
+	 * all connections).
+	 */
+	char *ctrl_interface;
+
+	/**
+	 * ctrl_interface_group - Control interface group (DEPRECATED)
+	 *
+	 * This variable is only used for backwards compatibility. Group for
+	 * UNIX domain sockets should now be specified using GROUP=group in
+	 * ctrl_interface variable.
+	 */
+	char *ctrl_interface_group;
+
+	/**
+	 * fast_reauth - EAP fast re-authentication (session resumption)
+	 *
+	 * By default, fast re-authentication is enabled for all EAP methods
+	 * that support it. This variable can be used to disable fast
+	 * re-authentication (by setting fast_reauth=0). Normally, there is no
+	 * need to disable fast re-authentication.
+	 */
+	int fast_reauth;
+
+	/**
+	 * opensc_engine_path - Path to the OpenSSL engine for opensc
+	 *
+	 * This is an OpenSSL specific configuration option for loading OpenSC
+	 * engine (engine_opensc.so); if %NULL, this engine is not loaded.
+	 */
+	char *opensc_engine_path;
+
+	/**
+	 * pkcs11_engine_path - Path to the OpenSSL engine for PKCS#11
+	 *
+	 * This is an OpenSSL specific configuration option for loading PKCS#11
+	 * engine (engine_pkcs11.so); if %NULL, this engine is not loaded.
+	 */
+	char *pkcs11_engine_path;
+
+	/**
+	 * pkcs11_module_path - Path to the OpenSSL OpenSC/PKCS#11 module
+	 *
+	 * This is an OpenSSL specific configuration option for configuring
+	 * path to OpenSC/PKCS#11 engine (opensc-pkcs11.so); if %NULL, this
+	 * module is not loaded.
+	 */
+	char *pkcs11_module_path;
+
+	/**
+	 * pcsc_reader - PC/SC reader name prefix
+	 *
+	 * If not %NULL, PC/SC reader with a name that matches this prefix is
+	 * initialized for SIM/USIM access. Empty string can be used to match
+	 * the first available reader.
+	 */
+	char *pcsc_reader;
+
+	/**
+	 * pcsc_pin - PIN for USIM, GSM SIM, and smartcards
+	 *
+	 * This field is used to configure PIN for SIM/USIM for EAP-SIM and
+	 * EAP-AKA. If left out, this will be asked through control interface.
+	 */
+	char *pcsc_pin;
+
+	/**
+	 * driver_param - Driver interface parameters
+	 *
+	 * This text string is passed to the selected driver interface with the
+	 * optional struct wpa_driver_ops::set_param() handler. This can be
+	 * used to configure driver specific options without having to add new
+	 * driver interface functionality.
+	 */
+	char *driver_param;
+
+	/**
+	 * dot11RSNAConfigPMKLifetime - Maximum lifetime of a PMK
+	 *
+	 * dot11 MIB variable for the maximum lifetime of a PMK in the PMK
+	 * cache (unit: seconds).
+	 */
+	unsigned int dot11RSNAConfigPMKLifetime;
+
+	/**
+	 * dot11RSNAConfigPMKReauthThreshold - PMK re-authentication threshold
+	 *
+	 * dot11 MIB variable for the percentage of the PMK lifetime
+	 * that should expire before an IEEE 802.1X reauthentication occurs.
+	 */
+	unsigned int dot11RSNAConfigPMKReauthThreshold;
+
+	/**
+	 * dot11RSNAConfigSATimeout - Security association timeout
+	 *
+	 * dot11 MIB variable for the maximum time a security association
+	 * shall take to set up (unit: seconds).
+	 */
+	unsigned int dot11RSNAConfigSATimeout;
+
+	/**
+	 * update_config - Is wpa_supplicant allowed to update configuration
+	 *
+	 * This variable control whether wpa_supplicant is allow to re-write
+	 * its configuration with wpa_config_write(). If this is zero,
+	 * configuration data is only changed in memory and the external data
+	 * is not overriden. If this is non-zero, wpa_supplicant will update
+	 * the configuration data (e.g., a file) whenever configuration is
+	 * changed. This update may replace the old configuration which can
+	 * remove comments from it in case of a text file configuration.
+	 */
+	int update_config;
+
+	/**
+	 * blobs - Configuration blobs
+	 */
+	struct wpa_config_blob *blobs;
+
+	/**
+	 * uuid - Universally Unique IDentifier (UUID; see RFC 4122) for WPS
+	 */
+	u8 uuid[16];
+
+	/**
+	 * device_name - Device Name (WPS)
+	 * User-friendly description of device; up to 32 octets encoded in
+	 * UTF-8
+	 */
+	char *device_name;
+
+	/**
+	 * manufacturer - Manufacturer (WPS)
+	 * The manufacturer of the device (up to 64 ASCII characters)
+	 */
+	char *manufacturer;
+
+	/**
+	 * model_name - Model Name (WPS)
+	 * Model of the device (up to 32 ASCII characters)
+	 */
+	char *model_name;
+
+	/**
+	 * model_number - Model Number (WPS)
+	 * Additional device description (up to 32 ASCII characters)
+	 */
+	char *model_number;
+
+	/**
+	 * serial_number - Serial Number (WPS)
+	 * Serial number of the device (up to 32 characters)
+	 */
+	char *serial_number;
+
+	/**
+	 * device_type - Primary Device Type (WPS)
+	 */
+	u8 device_type[WPS_DEV_TYPE_LEN];
+
+	/**
+	 * config_methods - Config Methods
+	 *
+	 * This is a space-separated list of supported WPS configuration
+	 * methods. For example, "label virtual_display virtual_push_button
+	 * keypad".
+	 * Available methods: usba ethernet label display ext_nfc_token
+	 * int_nfc_token nfc_interface push_button keypad
+	 * virtual_display physical_display
+	 * virtual_push_button physical_push_button.
+	 */
+	char *config_methods;
+
+	/**
+	 * os_version - OS Version (WPS)
+	 * 4-octet operating system version number
+	 */
+	u8 os_version[4];
+
+	/**
+	 * country - Country code
+	 *
+	 * This is the ISO/IEC alpha2 country code for which we are operating
+	 * in
+	 */
+	char country[2];
+
+	/**
+	 * wps_cred_processing - Credential processing
+	 *
+	 *   0 = process received credentials internally
+	 *   1 = do not process received credentials; just pass them over
+	 *	ctrl_iface to external program(s)
+	 *   2 = process received credentials internally and pass them over
+	 *	ctrl_iface to external program(s)
+	 */
+	int wps_cred_processing;
+
+#define MAX_SEC_DEVICE_TYPES 5
+	/**
+	 * sec_device_types - Secondary Device Types (P2P)
+	 */
+	u8 sec_device_type[MAX_SEC_DEVICE_TYPES][WPS_DEV_TYPE_LEN];
+	int num_sec_device_types;
+
+	int p2p_listen_reg_class;
+	int p2p_listen_channel;
+	int p2p_oper_reg_class;
+	int p2p_oper_channel;
+	int p2p_go_intent;
+	char *p2p_ssid_postfix;
+	int persistent_reconnect;
+	int p2p_intra_bss;
+	unsigned int num_p2p_pref_chan;
+	struct p2p_channel *p2p_pref_chan;
+
+	struct wpabuf *wps_vendor_ext_m1;
+
+#define MAX_WPS_VENDOR_EXT 10
+	/**
+	 * wps_vendor_ext - Vendor extension attributes in WPS
+	 */
+	struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXT];
+
+	/**
+	 * p2p_group_idle - Maximum idle time in seconds for P2P group
+	 *
+	 * This value controls how long a P2P group is maintained after there
+	 * is no other members in the group. As a GO, this means no associated
+	 * stations in the group. As a P2P client, this means no GO seen in
+	 * scan results. The maximum idle time is specified in seconds with 0
+	 * indicating no time limit, i.e., the P2P group remains in active
+	 * state indefinitely until explicitly removed. As a P2P client, the
+	 * maximum idle time of P2P_MAX_CLIENT_IDLE seconds is enforced, i.e.,
+	 * this parameter is mainly meant for GO use and for P2P client, it can
+	 * only be used to reduce the default timeout to smaller value. A
+	 * special value -1 can be used to configure immediate removal of the
+	 * group for P2P client role on any disconnection after the data
+	 * connection has been established.
+	 */
+	int p2p_group_idle;
+
+	/**
+	 * bss_max_count - Maximum number of BSS entries to keep in memory
+	 */
+	unsigned int bss_max_count;
+
+	/**
+	 * bss_expiration_age - BSS entry age after which it can be expired
+	 *
+	 * This value controls the time in seconds after which a BSS entry
+	 * gets removed if it has not been updated or is not in use.
+	 */
+	unsigned int bss_expiration_age;
+
+	/**
+	 * bss_expiration_scan_count - Expire BSS after number of scans
+	 *
+	 * If the BSS entry has not been seen in this many scans, it will be
+	 * removed. A value of 1 means that entry is removed after the first
+	 * scan in which the BSSID is not seen. Larger values can be used
+	 * to avoid BSS entries disappearing if they are not visible in
+	 * every scan (e.g., low signal quality or interference).
+	 */
+	unsigned int bss_expiration_scan_count;
+
+	/**
+	 * filter_ssids - SSID-based scan result filtering
+	 *
+	 *   0 = do not filter scan results
+	 *   1 = only include configured SSIDs in scan results/BSS table
+	 */
+	int filter_ssids;
+
+	/**
+	 * filter_rssi - RSSI-based scan result filtering
+	 *
+	 * 0 = do not filter scan results
+	 * -n = filter scan results below -n dBm
+	 */
+	int filter_rssi;
+
+	/**
+	 * max_num_sta - Maximum number of STAs in an AP/P2P GO
+	 */
+	unsigned int max_num_sta;
+
+	/**
+	 * changed_parameters - Bitmap of changed parameters since last update
+	 */
+	unsigned int changed_parameters;
+
+	/**
+	 * disassoc_low_ack - Disassocicate stations with massive packet loss
+	 */
+	int disassoc_low_ack;
+
+	/**
+	 * interworking - Whether Interworking (IEEE 802.11u) is enabled
+	 */
+	int interworking;
+
+	/**
+	 * access_network_type - Access Network Type
+	 *
+	 * When Interworking is enabled, scans will be limited to APs that
+	 * advertise the specified Access Network Type (0..15; with 15
+	 * indicating wildcard match).
+	 */
+	int access_network_type;
+
+	/**
+	 * hessid - Homogenous ESS identifier
+	 *
+	 * If this is set (any octet is non-zero), scans will be used to
+	 * request response only from BSSes belonging to the specified
+	 * Homogeneous ESS. This is used only if interworking is enabled.
+	 */
+	u8 hessid[ETH_ALEN];
+
+	/**
+	 * hs20 - Hotspot 2.0
+	 */
+	int hs20;
+
+	/**
+	 * pbc_in_m1 - AP mode WPS probing workaround for PBC with Windows 7
+	 *
+	 * Windows 7 uses incorrect way of figuring out AP's WPS capabilities
+	 * by acting as a Registrar and using M1 from the AP. The config
+	 * methods attribute in that message is supposed to indicate only the
+	 * configuration method supported by the AP in Enrollee role, i.e., to
+	 * add an external Registrar. For that case, PBC shall not be used and
+	 * as such, the PushButton config method is removed from M1 by default.
+	 * If pbc_in_m1=1 is included in the configuration file, the PushButton
+	 * config method is left in M1 (if included in config_methods
+	 * parameter) to allow Windows 7 to use PBC instead of PIN (e.g., from
+	 * a label in the AP).
+	 */
+	int pbc_in_m1;
+
+	/**
+	 * autoscan - Automatic scan parameters or %NULL if none
+	 *
+	 * This is an optional set of parameters for automatic scanning
+	 * within an interface in following format:
+	 * <autoscan module name>:<module parameters>
+	 */
+	char *autoscan;
+
+	/**
+	 * wps_nfc_dev_pw_id - NFC Device Password ID for password token
+	 */
+	int wps_nfc_dev_pw_id;
+
+	/**
+	 * wps_nfc_dh_pubkey - NFC DH Public Key for password token
+	 */
+	struct wpabuf *wps_nfc_dh_pubkey;
+
+	/**
+	 * wps_nfc_dh_privkey - NFC DH Private Key for password token
+	 */
+	struct wpabuf *wps_nfc_dh_privkey;
+
+	/**
+	 * wps_nfc_dev_pw - NFC Device Password for password token
+	 */
+	struct wpabuf *wps_nfc_dev_pw;
+
+	/**
+	 * ext_password_backend - External password backend or %NULL if none
+	 *
+	 * format: <backend name>[:<optional backend parameters>]
+	 */
+	char *ext_password_backend;
+
+	/*
+	 * p2p_go_max_inactivity - Timeout in seconds to detect STA inactivity
+	 *
+	 * This timeout value is used in P2P GO mode to clean up
+	 * inactive stations.
+	 * By default: 300 seconds.
+	 */
+	int p2p_go_max_inactivity;
+
+	struct hostapd_wmm_ac_params wmm_ac_params[4];
+
+	/**
+	 * auto_interworking - Whether to use network selection automatically
+	 *
+	 * 0 = do not automatically go through Interworking network selection
+	 *     (i.e., require explicit interworking_select command for this)
+	 * 1 = perform Interworking network selection if one or more
+	 *     credentials have been configured and scan did not find a
+	 *     matching network block
+	 */
+	int auto_interworking;
+
+	/**
+	 * p2p_go_ht40 - Default mode for HT40 enable when operating as GO.
+	 *
+	 * This will take effect for p2p_group_add, p2p_connect, and p2p_invite.
+	 * Note that regulatory constraints and driver capabilities are
+	 * consulted anyway, so setting it to 1 can't do real harm.
+	 * By default: 0 (disabled)
+	 */
+	int p2p_go_ht40;
+
+	/**
+	 * p2p_disabled - Whether P2P operations are disabled for this interface
+	 */
+	int p2p_disabled;
+
+	/**
+	 * p2p_no_group_iface - Whether group interfaces can be used
+	 *
+	 * By default, wpa_supplicant will create a separate interface for P2P
+	 * group operations if the driver supports this. This functionality can
+	 * be disabled by setting this parameter to 1. In that case, the same
+	 * interface that was used for the P2P management operations is used
+	 * also for the group operation.
+	 */
+	int p2p_no_group_iface;
+
+	/**
+	 * okc - Whether to enable opportunistic key caching by default
+	 *
+	 * By default, OKC is disabled unless enabled by the per-network
+	 * proactive_key_caching=1 parameter. okc=1 can be used to change this
+	 * default behavior.
+	 */
+	int okc;
+
+	/**
+	 * pmf - Whether to enable/require PMF by default
+	 *
+	 * By default, PMF is disabled unless enabled by the per-network
+	 * ieee80211w=1 or ieee80211w=2 parameter. pmf=1/2 can be used to change
+	 * this default behavior.
+	 */
+	enum mfp_options pmf;
+};
+
+
+/* Prototypes for common functions from config.c */
+
+void wpa_config_free(struct wpa_config *ssid);
+void wpa_config_free_ssid(struct wpa_ssid *ssid);
+void wpa_config_foreach_network(struct wpa_config *config,
+				void (*func)(void *, struct wpa_ssid *),
+				void *arg);
+struct wpa_ssid * wpa_config_get_network(struct wpa_config *config, int id);
+struct wpa_ssid * wpa_config_add_network(struct wpa_config *config);
+int wpa_config_remove_network(struct wpa_config *config, int id);
+void wpa_config_set_network_defaults(struct wpa_ssid *ssid);
+int wpa_config_set(struct wpa_ssid *ssid, const char *var, const char *value,
+		   int line);
+int wpa_config_set_quoted(struct wpa_ssid *ssid, const char *var,
+			  const char *value);
+char ** wpa_config_get_all(struct wpa_ssid *ssid, int get_keys);
+char * wpa_config_get(struct wpa_ssid *ssid, const char *var);
+char * wpa_config_get_no_key(struct wpa_ssid *ssid, const char *var);
+void wpa_config_update_psk(struct wpa_ssid *ssid);
+int wpa_config_add_prio_network(struct wpa_config *config,
+				struct wpa_ssid *ssid);
+int wpa_config_update_prio_list(struct wpa_config *config);
+const struct wpa_config_blob * wpa_config_get_blob(struct wpa_config *config,
+						   const char *name);
+void wpa_config_set_blob(struct wpa_config *config,
+			 struct wpa_config_blob *blob);
+void wpa_config_free_blob(struct wpa_config_blob *blob);
+int wpa_config_remove_blob(struct wpa_config *config, const char *name);
+
+struct wpa_cred * wpa_config_get_cred(struct wpa_config *config, int id);
+struct wpa_cred * wpa_config_add_cred(struct wpa_config *config);
+int wpa_config_remove_cred(struct wpa_config *config, int id);
+void wpa_config_free_cred(struct wpa_cred *cred);
+int wpa_config_set_cred(struct wpa_cred *cred, const char *var,
+			const char *value, int line);
+
+struct wpa_config * wpa_config_alloc_empty(const char *ctrl_interface,
+					   const char *driver_param);
+#ifndef CONFIG_NO_STDOUT_DEBUG
+void wpa_config_debug_dump_networks(struct wpa_config *config);
+#else /* CONFIG_NO_STDOUT_DEBUG */
+#define wpa_config_debug_dump_networks(c) do { } while (0)
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+/* Prototypes for common functions from config.c */
+int wpa_config_process_global(struct wpa_config *config, char *pos, int line);
+
+
+/* Prototypes for backend specific functions from the selected config_*.c */
+
+/**
+ * wpa_config_read - Read and parse configuration database
+ * @name: Name of the configuration (e.g., path and file name for the
+ * configuration file)
+ * Returns: Pointer to allocated configuration data or %NULL on failure
+ *
+ * This function reads configuration data, parses its contents, and allocates
+ * data structures needed for storing configuration information. The allocated
+ * data can be freed with wpa_config_free().
+ *
+ * Each configuration backend needs to implement this function.
+ */
+struct wpa_config * wpa_config_read(const char *name);
+
+/**
+ * wpa_config_write - Write or update configuration data
+ * @name: Name of the configuration (e.g., path and file name for the
+ * configuration file)
+ * @config: Configuration data from wpa_config_read()
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function write all configuration data into an external database (e.g.,
+ * a text file) in a format that can be read with wpa_config_read(). This can
+ * be used to allow wpa_supplicant to update its configuration, e.g., when a
+ * new network is added or a password is changed.
+ *
+ * Each configuration backend needs to implement this function.
+ */
+int wpa_config_write(const char *name, struct wpa_config *config);
+
+#endif /* CONFIG_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/config_solaris.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,370 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy is of the CDDL is also available via the Internet
+ * at http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright 2012 Enrico Papi <enricop@computer.org>.  All rights reserved.
+ */
+
+/*
+ * This file implements a configuration backend for nwam. The
+ * configuration information is read from known_wlan.conf text file.
+ */
+
+#include "includes.h"
+#include "common.h"
+#include "config.h"
+
+#include <libnwam.h>
+
+#ifdef CONFIG_BACKEND_SOLARIS
+
+void wpa_config_set_illumos_ssid_prefs(struct wpa_ssid *ssid) {
+	wpa_config_set(ssid, "priority", "1", 0);
+	wpa_config_set(ssid, "key_mgmt", "NONE", 0);
+}
+
+void wpa_config_set_illumos_global_pref(struct wpa_config *config) {
+
+/*
+ * config->sta_autoconnect = 0;
+ * Add command sta_autoconnect for disabling automatic reconnection
+ * on receiving disconnection event.
+ * config->sta_autoconnect <0/1> = disable/enable automatic reconnection
+ *
+ * unsigned int wpa_config::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 wpa_config::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).
+ */
+	config->update_config = 0;
+/*
+ * Is wpa_supplicant allowed to update configuration.
+ * This variable control whether wpa_supplicant is allow to re-write its
+ * configuration with wpa_config_write(). If this is zero, configuration data is
+ * only changed in memory and the external data is not overriden.
+ * If this is non-zero, wpa_supplicant will update the configuration data
+ * (e.g., a file) whenever configuration is changed. This update may replace the
+ * old configuration which can remove comments from it in case of a text file
+ * configuration.
+ */
+}
+
+static int
+wpa_config_read_prop(const char *propname, nwam_value_t propval, void *arg)
+{
+	struct wpa_ssid *ssid = arg;
+	nwam_error_t err = NWAM_SUCCESS;
+	dladm_status_t status = DLADM_STATUS_OK;
+	char *chrbuf;
+
+	if (propname == NULL || ssid == NULL)
+		return (NWAM_INVALID_ARG);
+
+	if (strcmp(propname, NWAM_KNOWN_WLAN_PROP_SSID) == 0) {
+		err = nwam_value_get_string(propval, &chrbuf);
+		if (err != NWAM_SUCCESS)
+			goto perror;
+		if (wpa_config_set_quoted(ssid, "id_str", chrbuf))
+			goto perror;
+		if (wpa_config_set_quoted(ssid, propname, chrbuf))
+			goto perror;
+	} else if (strcmp(propname, NWAM_KNOWN_WLAN_PROP_KEYNAME) == 0) {
+		dladm_handle_t handle;
+		dladm_wlan_key_t key_data;
+		err = nwam_value_get_string(propval, &chrbuf);
+		if (err != NWAM_SUCCESS)
+			goto perror;
+		strlcpy(key_data.wk_name, chrbuf, DLADM_SECOBJ_NAME_MAX);
+		if (dladm_open(&handle) != DLADM_STATUS_OK) {
+			wpa_printf(MSG_ERROR, "%s: FAILED to open dladm handle",
+			    __func__);
+			goto perror;
+		}
+		status = dladm_get_secobj(handle, &key_data,
+		    DLADM_OPT_PERSIST | DLADM_OPT_ACTIVE);
+		if (status != DLADM_STATUS_OK) {
+			char errbuf[DLADM_STRSIZE];
+			wpa_printf(MSG_ERROR, "%s: FAILED to get secobj '%s'"
+			    ". error: %s", __func__, chrbuf,
+			    dladm_status2str(status, errbuf));
+			dladm_close(handle);
+			goto perror;
+		}
+		dladm_close(handle);
+		switch (key_data.wk_class) {
+		case DLADM_SECOBJ_CLASS_WEP:
+			{
+			char wep_keystr[10];
+			strcpy(wep_keystr, "wep_key");
+			strlcat(wep_keystr, &key_data.wk_idx, 9);
+			if (wpa_config_set(ssid, wep_keystr,
+			    (char *)key_data.wk_val, 0))
+				goto perror;
+			if (wpa_config_set(ssid, "wep_tx_keyidx",
+			    &key_data.wk_idx, 0))
+				goto perror;
+			if (wpa_config_set(ssid, "auth_alg", "SHARED", 0))
+				goto perror;
+			}
+			break;
+		case DLADM_SECOBJ_CLASS_PSK:
+			if (wpa_config_set(ssid, "key_mgmt", "WPA-PSK", 0))
+				goto perror;
+			if (wpa_config_set(ssid, "psk", (char *)key_data.wk_val,
+			    0))
+				goto perror;
+			break;
+		case DLADM_SECOBJ_CLASS_TLS:
+			{
+			char *engine_keyid;
+			if (wpa_config_set(ssid, "key_mgmt", "WPA-EAP", 0))
+				goto perror;
+			if (wpa_config_set(ssid, "eap", "TLS", 0))
+				goto perror;
+			if (wpa_config_set(ssid, "private_key_passwd",
+			    (char *)key_data.wk_val, 0))
+				goto perror;
+			if (asprintf(&engine_keyid,
+			    "\"pkcs11:object=%s;passphrasedialog=exec:"
+			    "%s\"", key_data.wk_name, PIN_FILE) <= 0)
+				goto perror;
+			if (wpa_config_set(ssid, "key_id", engine_keyid, 0))
+				goto perror;
+			free(engine_keyid);
+			if (wpa_config_set_quoted(ssid, "cert_id",
+			    key_data.wk_name))
+				goto perror;
+			}
+			break;
+		case DLADM_SECOBJ_CLASS_TTLS:
+			{
+			char phase2str[DLADM_STRSIZE];
+			memset(phase2str, 0, sizeof (phase2str));
+			if (dladm_p2ttls_2_str(key_data.wk_p2mask, phase2str,
+			    B_FALSE) < 1)
+				goto perror;
+			if (wpa_config_set(ssid, "phase2", phase2str, 0))
+				goto perror;
+			if (wpa_config_set(ssid, "key_mgmt", "WPA-EAP", 0))
+				goto perror;
+			if (wpa_config_set(ssid, "eap", "TTLS", 0))
+				goto perror;
+			if (wpa_config_set(ssid, "password",
+			    (char*)key_data.wk_val, 0))
+				goto perror;
+			}
+			break;
+		case DLADM_SECOBJ_CLASS_PEAP:
+			{
+			char phase2str[DLADM_STRSIZE];
+			memset(phase2str, 0, sizeof (phase2str));
+			if (dladm_p2peap_2_str(key_data.wk_p2mask, phase2str,
+			    B_FALSE) < 1)
+				goto perror;
+			if (wpa_config_set(ssid, "phase2", phase2str, 0))
+				goto perror;
+			if (wpa_config_set(ssid, "key_mgmt", "WPA-EAP", 0))
+				goto perror;
+			if (wpa_config_set(ssid, "eap", "PEAP", 0))
+				goto perror;
+			if (wpa_config_set(ssid, "password",
+			    (char*)key_data.wk_val, 0))
+				goto perror;
+			}
+			break;
+		default:
+			goto perror;
+		}
+	} else if (strcmp(propname, NWAM_KNOWN_WLAN_PROP_PRIORITY) == 0) {
+		uint64_t decbuf;
+		err = nwam_value_get_uint64(propval, &decbuf);
+		if (err != NWAM_SUCCESS)
+			goto perror;
+		if (asprintf(&chrbuf, "%u", decbuf) <= 0)
+			goto perror;
+		if (wpa_config_set(ssid, propname, chrbuf, 0)) {
+			free(chrbuf);
+			goto perror;
+		}
+		free(chrbuf);
+	} else if (strcmp(propname, NWAM_KNOWN_WLAN_PROP_DISABLED) == 0) {
+		boolean_t disabled = B_FALSE;
+		err = nwam_value_get_boolean(propval, &disabled);
+		if (err != NWAM_SUCCESS)
+			goto perror;
+		if (wpa_config_set(ssid, propname, disabled ? "1" : "0", 0))
+			goto perror;
+	} else {
+		/*
+		 * case	NWAM_KNOWN_WLAN_PROP_BSSID
+		 * case NWAM_KNOWN_WLAN_PROP_EAP_USER:
+		 * case NWAM_KNOWN_WLAN_PROP_EAP_ANON:
+		 * case NWAM_KNOWN_WLAN_PROP_CA_CERT:
+		 * case NWAM_KNOWN_WLAN_PROP_PRIV:
+		 * case NWAM_KNOWN_WLAN_PROP_CLI_CERT
+		 */
+		err = nwam_value_get_string(propval, &chrbuf);
+		if (err != NWAM_SUCCESS)
+			goto perror;
+		if (wpa_config_set(ssid, propname, chrbuf, 0))
+			goto perror;
+	}
+
+	return (0);
+
+perror:
+	wpa_printf(MSG_ERROR, "%s: failed to get property '%s' for known wlan"
+	    " '%d' error: %d status: %d", __func__, propname, ssid->id, err,
+	    status);
+
+	return (err ? err : -1);
+}
+
+boolean_t wpa_config_validate_network(struct wpa_ssid *ssid)
+{
+	if (ssid->passphrase) {
+		if (ssid->psk_set) {
+			wpa_printf(MSG_ERROR, "Both PSK and passphrase set.");
+			return (B_FALSE);
+		}
+		wpa_config_update_psk(ssid);
+	}
+
+	if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
+	    WPA_KEY_MGMT_PSK_SHA256)) && !ssid->psk_set) {
+		wpa_printf(MSG_ERROR, "WPA-PSK accepted for key "
+		    "management, but no PSK configured.");
+		return (B_FALSE);
+	}
+
+	if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
+	    !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
+	    !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
+		/* Group cipher cannot be stronger than the pairwise cipher. */
+		wpa_printf(MSG_DEBUG, "Removed CCMP from group cipher"
+		    " list since it was not allowed for pairwise cipher");
+		ssid->group_cipher &= ~WPA_CIPHER_CCMP;
+	}
+
+	return (B_TRUE);
+}
+
+static int wpa_config_read_wlan(nwam_known_wlan_handle_t kwh, void *arg)
+{
+	struct wpa_config *config = arg;
+	struct wpa_ssid *ssid;
+	nwam_error_t err = NWAM_SUCCESS;
+	int id = -1;
+	int ret = 0;
+	char *name;
+
+	if (config == NULL) {
+		wpa_printf(MSG_ERROR, "%s: config struct pointer is NULL",
+		    __func__);
+		return (-1);
+	}
+
+	/* the know wlan name will be used as network id */
+	err = nwam_known_wlan_get_name(kwh, &name);
+	if (err != NWAM_SUCCESS) {
+		wpa_printf(MSG_ERROR, "%s: failed to get known wlan name",
+		    __func__);
+		return (-1);
+	}
+
+	wpa_printf(MSG_MSGDUMP, "%s: parsing wlan %s ", __func__, name);
+
+	id = atoi(name);
+	free(name);
+
+	/* valid known wlan names are numeric values between 1 and INT_MAX */
+	if (id <= 0 || id >= INT_MAX) {
+		wpa_printf(MSG_ERROR, "%s: invalid wlan id %u", __func__, id);
+		return (-1);
+	}
+
+	ssid = wpa_config_add_network(config);
+	if (ssid == NULL) {
+		wpa_printf(MSG_ERROR, "%s: failed allocating ssid config",
+		    __func__);
+		return (-1);
+	}
+
+	wpa_config_set_network_defaults(ssid);
+	wpa_config_set_illumos_ssid_prefs(ssid);
+	ssid->id = id;
+
+	err = nwam_known_wlan_walk_props(kwh, wpa_config_read_prop, ssid, 0,
+	    &ret);
+	if (err != NWAM_SUCCESS || ret != 0) {
+		wpa_printf(MSG_ERROR, "%s: failed parsing prop value(err %d,"
+		    " ret %d)", __func__, err, ret);
+		wpa_config_free_ssid(ssid);
+		return (-1);
+	}
+
+	if (!wpa_config_validate_network(ssid))
+		return (-1);
+
+	return (0);
+}
+
+struct wpa_config * wpa_config_read(const char *name)
+{
+	nwam_error_t err = NWAM_SUCCESS;
+	struct wpa_config *config;
+	int ret = 0;
+
+	if (name == NULL)
+		return (NULL);
+	wpa_printf(MSG_DEBUG, "%s(%s):Reading known-wlan.conf", name, __func__);
+
+	config = wpa_config_alloc_empty(CTRL_IFACE_DIR, NULL);
+	if (config == NULL)
+		return (NULL);
+
+	wpa_config_set_illumos_global_pref(config);
+
+	err = nwam_walk_known_wlans(wpa_config_read_wlan, config, &ret);
+	if (err != NWAM_SUCCESS) {
+		wpa_printf(MSG_ERROR, "%s: nwam_walk_known_wlans failed (%d)",
+		    __func__, err);
+		wpa_printf(MSG_ERROR, "%s: Failed reading known wlan list"
+		" error: %d", __func__, ret);
+		wpa_config_free(config);
+		return (NULL);
+	}
+
+	if (wpa_config_update_prio_list(config)) {
+		wpa_printf(MSG_ERROR, "%s: Failed to add "
+		   "network blocks to priority list.", __func__);
+		return (NULL);
+	}
+
+	wpa_config_debug_dump_networks(config);
+
+	return (config);
+}
+
+int wpa_config_write(const char *name, struct wpa_config *config)
+{
+	return (-1);
+}
+
+#endif /* CONFIG_BACKEND_SOLARIS */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/config_ssid.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,571 @@
+/*
+ * WPA Supplicant / Network configuration structures
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CONFIG_SSID_H
+#define CONFIG_SSID_H
+
+#include "common/defs.h"
+#include "eap_peer/eap_config.h"
+
+#define MAX_SSID_LEN 32
+
+
+#define DEFAULT_EAP_WORKAROUND ((unsigned int) -1)
+#define DEFAULT_EAPOL_FLAGS (EAPOL_FLAG_REQUIRE_KEY_UNICAST | \
+			     EAPOL_FLAG_REQUIRE_KEY_BROADCAST)
+#define DEFAULT_PROTO (WPA_PROTO_WPA | WPA_PROTO_RSN)
+#define DEFAULT_KEY_MGMT (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_IEEE8021X)
+#define DEFAULT_PAIRWISE (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP)
+#define DEFAULT_GROUP (WPA_CIPHER_CCMP | WPA_CIPHER_TKIP | \
+		       WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40)
+#define DEFAULT_FRAGMENT_SIZE 1398
+
+#define DEFAULT_BG_SCAN_PERIOD -1
+#define DEFAULT_DISABLE_HT 0
+#define DEFAULT_DISABLE_HT40 0
+#define DEFAULT_DISABLE_SGI 0
+#define DEFAULT_DISABLE_MAX_AMSDU -1 /* no change */
+#define DEFAULT_AMPDU_FACTOR -1 /* no change */
+#define DEFAULT_AMPDU_DENSITY -1 /* no change */
+
+/**
+ * struct wpa_ssid - Network configuration data
+ *
+ * This structure includes all the configuration variables for a network. This
+ * data is included in the per-interface configuration data as an element of
+ * the network list, struct wpa_config::ssid. Each network block in the
+ * configuration is mapped to a struct wpa_ssid instance.
+ */
+struct wpa_ssid {
+	/**
+	 * next - Next network in global list
+	 *
+	 * This pointer can be used to iterate over all networks. The head of
+	 * this list is stored in the ssid field of struct wpa_config.
+	 */
+	struct wpa_ssid *next;
+
+	/**
+	 * pnext - Next network in per-priority list
+	 *
+	 * This pointer can be used to iterate over all networks in the same
+	 * priority class. The heads of these list are stored in the pssid
+	 * fields of struct wpa_config.
+	 */
+	struct wpa_ssid *pnext;
+
+	/**
+	 * id - Unique id for the network
+	 *
+	 * This identifier is used as a unique identifier for each network
+	 * block when using the control interface. Each network is allocated an
+	 * id when it is being created, either when reading the configuration
+	 * file or when a new network is added through the control interface.
+	 */
+	int id;
+
+	/**
+	 * priority - Priority group
+	 *
+	 * By default, all networks will get same priority group (0). If some
+	 * of the networks are more desirable, this field can be used to change
+	 * the order in which wpa_supplicant goes through the networks when
+	 * selecting a BSS. The priority groups will be iterated in decreasing
+	 * priority (i.e., the larger the priority value, the sooner the
+	 * network is matched against the scan results). Within each priority
+	 * group, networks will be selected based on security policy, signal
+	 * strength, etc.
+	 *
+	 * Please note that AP scanning with scan_ssid=1 and ap_scan=2 mode are
+	 * not using this priority to select the order for scanning. Instead,
+	 * they try the networks in the order that used in the configuration
+	 * file.
+	 */
+	int priority;
+
+	/**
+	 * ssid - Service set identifier (network name)
+	 *
+	 * This is the SSID for the network. For wireless interfaces, this is
+	 * used to select which network will be used. If set to %NULL (or
+	 * ssid_len=0), any SSID can be used. For wired interfaces, this must
+	 * be set to %NULL. Note: SSID may contain any characters, even nul
+	 * (ASCII 0) and as such, this should not be assumed to be a nul
+	 * terminated string. ssid_len defines how many characters are valid
+	 * and the ssid field is not guaranteed to be nul terminated.
+	 */
+	u8 *ssid;
+
+	/**
+	 * ssid_len - Length of the SSID
+	 */
+	size_t ssid_len;
+
+	/**
+	 * bssid - BSSID
+	 *
+	 * If set, this network block is used only when associating with the AP
+	 * using the configured BSSID
+	 *
+	 * If this is a persistent P2P group (disabled == 2), this is the GO
+	 * Device Address.
+	 */
+	u8 bssid[ETH_ALEN];
+
+	/**
+	 * bssid_set - Whether BSSID is configured for this network
+	 */
+	int bssid_set;
+
+	/**
+	 * psk - WPA pre-shared key (256 bits)
+	 */
+	u8 psk[32];
+
+	/**
+	 * psk_set - Whether PSK field is configured
+	 */
+	int psk_set;
+
+	/**
+	 * passphrase - WPA ASCII passphrase
+	 *
+	 * If this is set, psk will be generated using the SSID and passphrase
+	 * configured for the network. ASCII passphrase must be between 8 and
+	 * 63 characters (inclusive).
+	 */
+	char *passphrase;
+
+	/**
+	 * ext_psk - PSK/passphrase name in external storage
+	 *
+	 * If this is set, PSK/passphrase will be fetched from external storage
+	 * when requesting association with the network.
+	 */
+	char *ext_psk;
+
+	/**
+	 * pairwise_cipher - Bitfield of allowed pairwise ciphers, WPA_CIPHER_*
+	 */
+	int pairwise_cipher;
+
+	/**
+	 * group_cipher - Bitfield of allowed group ciphers, WPA_CIPHER_*
+	 */
+	int group_cipher;
+
+	/**
+	 * key_mgmt - Bitfield of allowed key management protocols
+	 *
+	 * WPA_KEY_MGMT_*
+	 */
+	int key_mgmt;
+
+	/**
+	 * bg_scan_period - Background scan period in seconds, 0 to disable, or
+	 * -1 to indicate no change to default driver configuration
+	 */
+	int bg_scan_period;
+
+	/**
+	 * proto - Bitfield of allowed protocols, WPA_PROTO_*
+	 */
+	int proto;
+
+	/**
+	 * auth_alg -  Bitfield of allowed authentication algorithms
+	 *
+	 * WPA_AUTH_ALG_*
+	 */
+	int auth_alg;
+
+	/**
+	 * scan_ssid - Scan this SSID with Probe Requests
+	 *
+	 * scan_ssid can be used to scan for APs using hidden SSIDs.
+	 * Note: Many drivers do not support this. ap_mode=2 can be used with
+	 * such drivers to use hidden SSIDs.
+	 */
+	int scan_ssid;
+
+#ifdef IEEE8021X_EAPOL
+#define EAPOL_FLAG_REQUIRE_KEY_UNICAST BIT(0)
+#define EAPOL_FLAG_REQUIRE_KEY_BROADCAST BIT(1)
+	/**
+	 * eapol_flags - Bit field of IEEE 802.1X/EAPOL options (EAPOL_FLAG_*)
+	 */
+	int eapol_flags;
+
+	/**
+	 * eap - EAP peer configuration for this network
+	 */
+	struct eap_peer_config eap;
+#endif /* IEEE8021X_EAPOL */
+
+#define NUM_WEP_KEYS 4
+#define MAX_WEP_KEY_LEN 16
+	/**
+	 * wep_key - WEP keys
+	 */
+	u8 wep_key[NUM_WEP_KEYS][MAX_WEP_KEY_LEN];
+
+	/**
+	 * wep_key_len - WEP key lengths
+	 */
+	size_t wep_key_len[NUM_WEP_KEYS];
+
+	/**
+	 * wep_tx_keyidx - Default key index for TX frames using WEP
+	 */
+	int wep_tx_keyidx;
+
+	/**
+	 * proactive_key_caching - Enable proactive key caching
+	 *
+	 * This field can be used to enable proactive key caching which is also
+	 * known as opportunistic PMKSA caching for WPA2. This is disabled (0)
+	 * by default unless default value is changed with the global okc=1
+	 * parameter. Enable by setting this to 1.
+	 *
+	 * Proactive key caching is used to make supplicant assume that the APs
+	 * are using the same PMK and generate PMKSA cache entries without
+	 * doing RSN pre-authentication. This requires support from the AP side
+	 * and is normally used with wireless switches that co-locate the
+	 * authenticator.
+	 *
+	 * Internally, special value -1 is used to indicate that the parameter
+	 * was not specified in the configuration (i.e., default behavior is
+	 * followed).
+	 */
+	int proactive_key_caching;
+
+	/**
+	 * mixed_cell - Whether mixed cells are allowed
+	 *
+	 * This option can be used to configure whether so called mixed cells,
+	 * i.e., networks that use both plaintext and encryption in the same
+	 * SSID, are allowed. This is disabled (0) by default. Enable by
+	 * setting this to 1.
+	 */
+	int mixed_cell;
+
+#ifdef IEEE8021X_EAPOL
+
+	/**
+	 * leap - Number of EAP methods using LEAP
+	 *
+	 * This field should be set to 1 if LEAP is enabled. This is used to
+	 * select IEEE 802.11 authentication algorithm.
+	 */
+	int leap;
+
+	/**
+	 * non_leap - Number of EAP methods not using LEAP
+	 *
+	 * This field should be set to >0 if any EAP method other than LEAP is
+	 * enabled. This is used to select IEEE 802.11 authentication
+	 * algorithm.
+	 */
+	int non_leap;
+
+	/**
+	 * eap_workaround - EAP workarounds enabled
+	 *
+	 * wpa_supplicant supports number of "EAP workarounds" to work around
+	 * interoperability issues with incorrectly behaving authentication
+	 * servers. This is recommended to be enabled by default because some
+	 * of the issues are present in large number of authentication servers.
+	 *
+	 * Strict EAP conformance mode can be configured by disabling
+	 * workarounds with eap_workaround = 0.
+	 */
+	unsigned int eap_workaround;
+
+#endif /* IEEE8021X_EAPOL */
+
+	/**
+	 * mode - IEEE 802.11 operation mode (Infrastucture/IBSS)
+	 *
+	 * 0 = infrastructure (Managed) mode, i.e., associate with an AP.
+	 *
+	 * 1 = IBSS (ad-hoc, peer-to-peer)
+	 *
+	 * 2 = AP (access point)
+	 *
+	 * 3 = P2P Group Owner (can be set in the configuration file)
+	 *
+	 * 4 = P2P Group Formation (used internally; not in configuration
+	 * files)
+	 *
+	 * Note: IBSS can only be used with key_mgmt NONE (plaintext and
+	 * static WEP) and key_mgmt=WPA-NONE (fixed group key TKIP/CCMP). In
+	 * addition, ap_scan has to be set to 2 for IBSS. WPA-None requires
+	 * following network block options: proto=WPA, key_mgmt=WPA-NONE,
+	 * pairwise=NONE, group=TKIP (or CCMP, but not both), and psk must also
+	 * be set (either directly or using ASCII passphrase).
+	 */
+	enum wpas_mode {
+		WPAS_MODE_INFRA = 0,
+		WPAS_MODE_IBSS = 1,
+		WPAS_MODE_AP = 2,
+		WPAS_MODE_P2P_GO = 3,
+		WPAS_MODE_P2P_GROUP_FORMATION = 4,
+	} mode;
+
+	/**
+	 * disabled - Whether this network is currently disabled
+	 *
+	 * 0 = this network can be used (default).
+	 * 1 = this network block is disabled (can be enabled through
+	 * ctrl_iface, e.g., with wpa_cli or wpa_gui).
+	 * 2 = this network block includes parameters for a persistent P2P
+	 * group (can be used with P2P ctrl_iface commands)
+	 */
+	int disabled;
+
+	/**
+	 * disabled_for_connect - Whether this network was temporarily disabled
+	 *
+	 * This flag is used to reenable all the temporarily disabled networks
+	 * after either the success or failure of a WPS connection.
+	 */
+	int disabled_for_connect;
+
+	/**
+	 * peerkey -  Whether PeerKey handshake for direct links is allowed
+	 *
+	 * This is only used when both RSN/WPA2 and IEEE 802.11e (QoS) are
+	 * enabled.
+	 *
+	 * 0 = disabled (default)
+	 * 1 = enabled
+	 */
+	int peerkey;
+
+	/**
+	 * id_str - Network identifier string for external scripts
+	 *
+	 * This value is passed to external ctrl_iface monitors in
+	 * WPA_EVENT_CONNECTED event and wpa_cli sets this as WPA_ID_STR
+	 * environment variable for action scripts.
+	 */
+	char *id_str;
+
+#ifdef CONFIG_IEEE80211W
+	/**
+	 * ieee80211w - Whether management frame protection is enabled
+	 *
+	 * This value is used to configure policy for management frame
+	 * protection (IEEE 802.11w). 0 = disabled, 1 = optional, 2 = required.
+	 * This is disabled by default unless the default value has been changed
+	 * with the global pmf=1/2 parameter.
+	 *
+	 * Internally, special value 3 is used to indicate that the parameter
+	 * was not specified in the configuration (i.e., default behavior is
+	 * followed).
+	 */
+	enum mfp_options ieee80211w;
+#endif /* CONFIG_IEEE80211W */
+
+	/**
+	 * frequency - Channel frequency in megahertz (MHz) for IBSS
+	 *
+	 * This value is used to configure the initial channel for IBSS (adhoc)
+	 * networks, e.g., 2412 = IEEE 802.11b/g channel 1. It is ignored in
+	 * the infrastructure mode. In addition, this value is only used by the
+	 * station that creates the IBSS. If an IBSS network with the
+	 * configured SSID is already present, the frequency of the network
+	 * will be used instead of this configured value.
+	 */
+	int frequency;
+
+	int ht40;
+
+	/**
+	 * wpa_ptk_rekey - Maximum lifetime for PTK in seconds
+	 *
+	 * This value can be used to enforce rekeying of PTK to mitigate some
+	 * attacks against TKIP deficiencies.
+	 */
+	int wpa_ptk_rekey;
+
+	/**
+	 * scan_freq - Array of frequencies to scan or %NULL for all
+	 *
+	 * This is an optional zero-terminated array of frequencies in
+	 * megahertz (MHz) to include in scan requests when searching for this
+	 * network. This can be used to speed up scanning when the network is
+	 * known to not use all possible channels.
+	 */
+	int *scan_freq;
+
+	/**
+	 * bgscan - Background scan and roaming parameters or %NULL if none
+	 *
+	 * This is an optional set of parameters for background scanning and
+	 * roaming within a network (ESS) in following format:
+	 * <bgscan module name>:<module parameters>
+	 */
+	char *bgscan;
+
+	/**
+	 * ignore_broadcast_ssid - Hide SSID in AP mode
+	 *
+	 * Send empty SSID in beacons and ignore probe request frames that do
+	 * not specify full SSID, i.e., require stations to know SSID.
+	 * default: disabled (0)
+	 * 1 = send empty (length=0) SSID in beacon and ignore probe request
+	 * for broadcast SSID
+	 * 2 = clear SSID (ASCII 0), but keep the original length (this may be
+	 * required with some clients that do not support empty SSID) and
+	 * ignore probe requests for broadcast SSID
+	 */
+	int ignore_broadcast_ssid;
+
+	/**
+	 * freq_list - Array of allowed frequencies or %NULL for all
+	 *
+	 * This is an optional zero-terminated array of frequencies in
+	 * megahertz (MHz) to allow for selecting the BSS. If set, scan results
+	 * that do not match any of the specified frequencies are not
+	 * considered when selecting a BSS.
+	 */
+	int *freq_list;
+
+	/**
+	 * p2p_client_list - List of P2P Clients in a persistent group (GO)
+	 *
+	 * This is a list of P2P Clients (P2P Device Address) that have joined
+	 * the persistent group. This is maintained on the GO for persistent
+	 * group entries (disabled == 2).
+	 */
+	u8 *p2p_client_list;
+
+	/**
+	 * num_p2p_clients - Number of entries in p2p_client_list
+	 */
+	size_t num_p2p_clients;
+
+#ifndef P2P_MAX_STORED_CLIENTS
+#define P2P_MAX_STORED_CLIENTS 100
+#endif /* P2P_MAX_STORED_CLIENTS */
+
+	/**
+	 * p2p_group - Network generated as a P2P group (used internally)
+	 */
+	int p2p_group;
+
+	/**
+	 * p2p_persistent_group - Whether this is a persistent group
+	 */
+	int p2p_persistent_group;
+
+	/**
+	 * temporary - Whether this network is temporary and not to be saved
+	 */
+	int temporary;
+
+	/**
+	 * export_keys - Whether keys may be exported
+	 *
+	 * This attribute will be set when keys are determined through
+	 * WPS or similar so that they may be exported.
+	 */
+	int export_keys;
+
+#ifdef CONFIG_HT_OVERRIDES
+	/**
+	 * disable_ht - Disable HT (IEEE 802.11n) for this network
+	 *
+	 * By default, use it if it is available, but this can be configured
+	 * to 1 to have it disabled.
+	 */
+	int disable_ht;
+
+	/**
+	 * disable_ht40 - Disable HT40 for this network
+	 *
+	 * By default, use it if it is available, but this can be configured
+	 * to 1 to have it disabled.
+	 */
+	int disable_ht40;
+
+	/**
+	 * disable_sgi - Disable SGI (Short Guard Interval) for this network
+	 *
+	 * By default, use it if it is available, but this can be configured
+	 * to 1 to have it disabled.
+	 */
+	int disable_sgi;
+
+	/**
+	 * disable_max_amsdu - Disable MAX A-MSDU
+	 *
+	 * A-MDSU will be 3839 bytes when disabled, or 7935
+	 * when enabled (assuming it is otherwise supported)
+	 * -1 (default) means do not apply any settings to the kernel.
+	 */
+	int disable_max_amsdu;
+
+	/**
+	 * ampdu_factor - Maximum A-MPDU Length Exponent
+	 *
+	 * Value: 0-3, see 7.3.2.56.3 in IEEE Std 802.11n-2009.
+	 */
+	int ampdu_factor;
+
+	/**
+	 * ampdu_density - Minimum A-MPDU Start Spacing
+	 *
+	 * Value: 0-7, see 7.3.2.56.3 in IEEE Std 802.11n-2009.
+	 */
+	int ampdu_density;
+
+	/**
+	 * ht_mcs - Allowed HT-MCS rates, in ASCII hex: ffff0000...
+	 *
+	 * By default (empty string): Use whatever the OS has configured.
+	 */
+	char *ht_mcs;
+#endif /* CONFIG_HT_OVERRIDES */
+
+	/**
+	 * ap_max_inactivity - Timeout in seconds to detect STA's inactivity
+	 *
+	 * This timeout value is used in AP mode to clean up inactive stations.
+	 * By default: 300 seconds.
+	 */
+	int ap_max_inactivity;
+
+	/**
+	 * dtim_period - DTIM period in Beacon intervals
+	 * By default: 2
+	 */
+	int dtim_period;
+
+	/**
+	 * auth_failures - Number of consecutive authentication failures
+	 */
+	unsigned int auth_failures;
+
+	/**
+	 * disabled_until - Network block disabled until this time if non-zero
+	 */
+	struct os_time disabled_until;
+
+	/**
+	 * parent_cred - Pointer to parent wpa_cred entry
+	 *
+	 * This pointer can be used to delete temporary networks when a wpa_cred
+	 * that was used to create them is removed. This pointer should not be
+	 * dereferences since it may not be updated in all cases.
+	 */
+	void *parent_cred;
+};
+
+#endif /* CONFIG_SSID_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/ctrl_iface.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,5545 @@
+/*
+ * WPA Supplicant / Control interface (shared code for all backends)
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/version.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
+#include "eap_peer/eap.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
+#include "rsn_supp/preauth.h"
+#include "rsn_supp/pmksa_cache.h"
+#include "l2_packet/l2_packet.h"
+#include "wps/wps.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "wps_supplicant.h"
+#include "ibss_rsn.h"
+#include "ap.h"
+#include "p2p_supplicant.h"
+#include "p2p/p2p.h"
+#include "hs20_supplicant.h"
+#include "wifi_display.h"
+#include "notify.h"
+#include "bss.h"
+#include "scan.h"
+#include "ctrl_iface.h"
+#include "interworking.h"
+#include "blacklist.h"
+#include "autoscan.h"
+#include "wnm_sta.h"
+
+extern struct wpa_driver_ops *wpa_drivers[];
+
+static int wpa_supplicant_global_iface_list(struct wpa_global *global,
+					    char *buf, int len);
+static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
+						  char *buf, int len);
+
+
+static int pno_start(struct wpa_supplicant *wpa_s)
+{
+	int ret;
+	size_t i, num_ssid;
+	struct wpa_ssid *ssid;
+	struct wpa_driver_scan_params params;
+
+	if (wpa_s->pno)
+		return 0;
+
+	if (wpa_s->wpa_state == WPA_SCANNING) {
+		wpa_supplicant_cancel_sched_scan(wpa_s);
+		wpa_supplicant_cancel_scan(wpa_s);
+	}
+
+	os_memset(&params, 0, sizeof(params));
+
+	num_ssid = 0;
+	ssid = wpa_s->conf->ssid;
+	while (ssid) {
+		if (!wpas_network_disabled(wpa_s, ssid))
+			num_ssid++;
+		ssid = ssid->next;
+	}
+	if (num_ssid > WPAS_MAX_SCAN_SSIDS) {
+		wpa_printf(MSG_DEBUG, "PNO: Use only the first %u SSIDs from "
+			   "%u", WPAS_MAX_SCAN_SSIDS, (unsigned int) num_ssid);
+		num_ssid = WPAS_MAX_SCAN_SSIDS;
+	}
+
+	if (num_ssid == 0) {
+		wpa_printf(MSG_DEBUG, "PNO: No configured SSIDs");
+		return -1;
+	}
+
+	params.filter_ssids = os_malloc(sizeof(struct wpa_driver_scan_filter) *
+					num_ssid);
+	if (params.filter_ssids == NULL)
+		return -1;
+	i = 0;
+	ssid = wpa_s->conf->ssid;
+	while (ssid) {
+		if (!wpas_network_disabled(wpa_s, ssid)) {
+			params.ssids[i].ssid = ssid->ssid;
+			params.ssids[i].ssid_len = ssid->ssid_len;
+			params.num_ssids++;
+			os_memcpy(params.filter_ssids[i].ssid, ssid->ssid,
+				  ssid->ssid_len);
+			params.filter_ssids[i].ssid_len = ssid->ssid_len;
+			params.num_filter_ssids++;
+			i++;
+			if (i == num_ssid)
+				break;
+		}
+		ssid = ssid->next;
+	}
+
+	if (wpa_s->conf->filter_rssi)
+		params.filter_rssi = wpa_s->conf->filter_rssi;
+
+	ret = wpa_drv_sched_scan(wpa_s, &params, 10 * 1000);
+	os_free(params.filter_ssids);
+	if (ret == 0)
+		wpa_s->pno = 1;
+	return ret;
+}
+
+
+static int pno_stop(struct wpa_supplicant *wpa_s)
+{
+	int ret = 0;
+
+	if (wpa_s->pno) {
+		wpa_s->pno = 0;
+		ret = wpa_drv_stop_sched_scan(wpa_s);
+	}
+
+	if (wpa_s->wpa_state == WPA_SCANNING)
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+	return ret;
+}
+
+
+static int set_bssid_filter(struct wpa_supplicant *wpa_s, char *val)
+{
+	char *pos;
+	u8 addr[ETH_ALEN], *filter = NULL, *n;
+	size_t count = 0;
+
+	pos = val;
+	while (pos) {
+		if (*pos == '\0')
+			break;
+		if (hwaddr_aton(pos, addr)) {
+			os_free(filter);
+			return -1;
+		}
+		n = os_realloc_array(filter, count + 1, ETH_ALEN);
+		if (n == NULL) {
+			os_free(filter);
+			return -1;
+		}
+		filter = n;
+		os_memcpy(filter + count * ETH_ALEN, addr, ETH_ALEN);
+		count++;
+
+		pos = os_strchr(pos, ' ');
+		if (pos)
+			pos++;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "bssid_filter", filter, count * ETH_ALEN);
+	os_free(wpa_s->bssid_filter);
+	wpa_s->bssid_filter = filter;
+	wpa_s->bssid_filter_count = count;
+
+	return 0;
+}
+
+
+static int set_disallow_aps(struct wpa_supplicant *wpa_s, char *val)
+{
+	char *pos;
+	u8 addr[ETH_ALEN], *bssid = NULL, *n;
+	struct wpa_ssid_value *ssid = NULL, *ns;
+	size_t count = 0, ssid_count = 0;
+	struct wpa_ssid *c;
+
+	/*
+	 * disallow_list ::= <ssid_spec> | <bssid_spec> | <disallow_list> | “”
+	 * SSID_SPEC ::= ssid <SSID_HEX>
+	 * BSSID_SPEC ::= bssid <BSSID_HEX>
+	 */
+
+	pos = val;
+	while (pos) {
+		if (*pos == '\0')
+			break;
+		if (os_strncmp(pos, "bssid ", 6) == 0) {
+			int res;
+			pos += 6;
+			res = hwaddr_aton2(pos, addr);
+			if (res < 0) {
+				os_free(ssid);
+				os_free(bssid);
+				wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
+					   "BSSID value '%s'", pos);
+				return -1;
+			}
+			pos += res;
+			n = os_realloc_array(bssid, count + 1, ETH_ALEN);
+			if (n == NULL) {
+				os_free(ssid);
+				os_free(bssid);
+				return -1;
+			}
+			bssid = n;
+			os_memcpy(bssid + count * ETH_ALEN, addr, ETH_ALEN);
+			count++;
+		} else if (os_strncmp(pos, "ssid ", 5) == 0) {
+			char *end;
+			pos += 5;
+
+			end = pos;
+			while (*end) {
+				if (*end == '\0' || *end == ' ')
+					break;
+				end++;
+			}
+
+			ns = os_realloc_array(ssid, ssid_count + 1,
+					      sizeof(struct wpa_ssid_value));
+			if (ns == NULL) {
+				os_free(ssid);
+				os_free(bssid);
+				return -1;
+			}
+			ssid = ns;
+
+			if ((end - pos) & 0x01 || end - pos > 2 * 32 ||
+			    hexstr2bin(pos, ssid[ssid_count].ssid,
+				       (end - pos) / 2) < 0) {
+				os_free(ssid);
+				os_free(bssid);
+				wpa_printf(MSG_DEBUG, "Invalid disallow_aps "
+					   "SSID value '%s'", pos);
+				return -1;
+			}
+			ssid[ssid_count].ssid_len = (end - pos) / 2;
+			wpa_hexdump_ascii(MSG_DEBUG, "disallow_aps SSID",
+					  ssid[ssid_count].ssid,
+					  ssid[ssid_count].ssid_len);
+			ssid_count++;
+			pos = end;
+		} else {
+			wpa_printf(MSG_DEBUG, "Unexpected disallow_aps value "
+				   "'%s'", pos);
+			os_free(ssid);
+			os_free(bssid);
+			return -1;
+		}
+
+		pos = os_strchr(pos, ' ');
+		if (pos)
+			pos++;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "disallow_aps_bssid", bssid, count * ETH_ALEN);
+	os_free(wpa_s->disallow_aps_bssid);
+	wpa_s->disallow_aps_bssid = bssid;
+	wpa_s->disallow_aps_bssid_count = count;
+
+	wpa_printf(MSG_DEBUG, "disallow_aps_ssid_count %d", (int) ssid_count);
+	os_free(wpa_s->disallow_aps_ssid);
+	wpa_s->disallow_aps_ssid = ssid;
+	wpa_s->disallow_aps_ssid_count = ssid_count;
+
+	if (!wpa_s->current_ssid || wpa_s->wpa_state < WPA_AUTHENTICATING)
+		return 0;
+
+	c = wpa_s->current_ssid;
+	if (c->mode != WPAS_MODE_INFRA && c->mode != WPAS_MODE_IBSS)
+		return 0;
+
+	if (!disallowed_bssid(wpa_s, wpa_s->bssid) &&
+	    !disallowed_ssid(wpa_s, c->ssid, c->ssid_len))
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "Disconnect and try to find another network "
+		   "because current AP was marked disallowed");
+
+#ifdef CONFIG_SME
+	wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+	wpa_s->reassociate = 1;
+	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_set(struct wpa_supplicant *wpa_s,
+					 char *cmd)
+{
+	char *value;
+	int ret = 0;
+
+	value = os_strchr(cmd, ' ');
+	if (value == NULL)
+		return -1;
+	*value++ = '\0';
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
+	if (os_strcasecmp(cmd, "EAPOL::heldPeriod") == 0) {
+		eapol_sm_configure(wpa_s->eapol,
+				   atoi(value), -1, -1, -1);
+	} else if (os_strcasecmp(cmd, "EAPOL::authPeriod") == 0) {
+		eapol_sm_configure(wpa_s->eapol,
+				   -1, atoi(value), -1, -1);
+	} else if (os_strcasecmp(cmd, "EAPOL::startPeriod") == 0) {
+		eapol_sm_configure(wpa_s->eapol,
+				   -1, -1, atoi(value), -1);
+	} else if (os_strcasecmp(cmd, "EAPOL::maxStart") == 0) {
+		eapol_sm_configure(wpa_s->eapol,
+				   -1, -1, -1, atoi(value));
+	} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKLifetime") == 0) {
+		if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
+				     atoi(value)))
+			ret = -1;
+	} else if (os_strcasecmp(cmd, "dot11RSNAConfigPMKReauthThreshold") ==
+		   0) {
+		if (wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
+				     atoi(value)))
+			ret = -1;
+	} else if (os_strcasecmp(cmd, "dot11RSNAConfigSATimeout") == 0) {
+		if (wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT, atoi(value)))
+			ret = -1;
+	} else if (os_strcasecmp(cmd, "wps_fragment_size") == 0) {
+		wpa_s->wps_fragment_size = atoi(value);
+#ifdef CONFIG_WPS_TESTING
+	} else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
+		long int val;
+		val = strtol(value, NULL, 0);
+		if (val < 0 || val > 0xff) {
+			ret = -1;
+			wpa_printf(MSG_DEBUG, "WPS: Invalid "
+				   "wps_version_number %ld", val);
+		} else {
+			wps_version_number = val;
+			wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
+				   "version %u.%u",
+				   (wps_version_number & 0xf0) >> 4,
+				   wps_version_number & 0x0f);
+		}
+	} else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
+		wps_testing_dummy_cred = atoi(value);
+		wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
+			   wps_testing_dummy_cred);
+#endif /* CONFIG_WPS_TESTING */
+	} else if (os_strcasecmp(cmd, "ampdu") == 0) {
+		if (wpa_drv_ampdu(wpa_s, atoi(value)) < 0)
+			ret = -1;
+#ifdef CONFIG_TDLS_TESTING
+	} else if (os_strcasecmp(cmd, "tdls_testing") == 0) {
+		extern unsigned int tdls_testing;
+		tdls_testing = strtol(value, NULL, 0);
+		wpa_printf(MSG_DEBUG, "TDLS: tdls_testing=0x%x", tdls_testing);
+#endif /* CONFIG_TDLS_TESTING */
+#ifdef CONFIG_TDLS
+	} else if (os_strcasecmp(cmd, "tdls_disabled") == 0) {
+		int disabled = atoi(value);
+		wpa_printf(MSG_DEBUG, "TDLS: tdls_disabled=%d", disabled);
+		if (disabled) {
+			if (wpa_drv_tdls_oper(wpa_s, TDLS_DISABLE, NULL) < 0)
+				ret = -1;
+		} else if (wpa_drv_tdls_oper(wpa_s, TDLS_ENABLE, NULL) < 0)
+			ret = -1;
+		wpa_tdls_enable(wpa_s->wpa, !disabled);
+#endif /* CONFIG_TDLS */
+	} else if (os_strcasecmp(cmd, "pno") == 0) {
+		if (atoi(value))
+			ret = pno_start(wpa_s);
+		else
+			ret = pno_stop(wpa_s);
+	} else if (os_strcasecmp(cmd, "radio_disabled") == 0) {
+		int disabled = atoi(value);
+		if (wpa_drv_radio_disable(wpa_s, disabled) < 0)
+			ret = -1;
+		else if (disabled)
+			wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
+	} else if (os_strcasecmp(cmd, "uapsd") == 0) {
+		if (os_strcmp(value, "disable") == 0)
+			wpa_s->set_sta_uapsd = 0;
+		else {
+			int be, bk, vi, vo;
+			char *pos;
+			/* format: BE,BK,VI,VO;max SP Length */
+			be = atoi(value);
+			pos = os_strchr(value, ',');
+			if (pos == NULL)
+				return -1;
+			pos++;
+			bk = atoi(pos);
+			pos = os_strchr(pos, ',');
+			if (pos == NULL)
+				return -1;
+			pos++;
+			vi = atoi(pos);
+			pos = os_strchr(pos, ',');
+			if (pos == NULL)
+				return -1;
+			pos++;
+			vo = atoi(pos);
+			/* ignore max SP Length for now */
+
+			wpa_s->set_sta_uapsd = 1;
+			wpa_s->sta_uapsd = 0;
+			if (be)
+				wpa_s->sta_uapsd |= BIT(0);
+			if (bk)
+				wpa_s->sta_uapsd |= BIT(1);
+			if (vi)
+				wpa_s->sta_uapsd |= BIT(2);
+			if (vo)
+				wpa_s->sta_uapsd |= BIT(3);
+		}
+	} else if (os_strcasecmp(cmd, "ps") == 0) {
+		ret = wpa_drv_set_p2p_powersave(wpa_s, atoi(value), -1, -1);
+#ifdef CONFIG_WIFI_DISPLAY
+	} else if (os_strcasecmp(cmd, "wifi_display") == 0) {
+		wifi_display_enable(wpa_s->global, !!atoi(value));
+#endif /* CONFIG_WIFI_DISPLAY */
+	} else if (os_strcasecmp(cmd, "bssid_filter") == 0) {
+		ret = set_bssid_filter(wpa_s, value);
+	} else if (os_strcasecmp(cmd, "disallow_aps") == 0) {
+		ret = set_disallow_aps(wpa_s, value);
+	} else if (os_strcasecmp(cmd, "no_keep_alive") == 0) {
+		wpa_s->no_keep_alive = !!atoi(value);
+	} else {
+		value[-1] = '=';
+		ret = wpa_config_process_global(wpa_s->conf, cmd, -1);
+		if (ret == 0)
+			wpa_supplicant_update_config(wpa_s);
+	}
+
+	return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_get(struct wpa_supplicant *wpa_s,
+					 char *cmd, char *buf, size_t buflen)
+{
+	int res = -1;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
+
+	if (os_strcmp(cmd, "version") == 0) {
+		res = os_snprintf(buf, buflen, "%s", VERSION_STR);
+	} else if (os_strcasecmp(cmd, "country") == 0) {
+		if (wpa_s->conf->country[0] && wpa_s->conf->country[1])
+			res = os_snprintf(buf, buflen, "%c%c",
+					  wpa_s->conf->country[0],
+					  wpa_s->conf->country[1]);
+#ifdef CONFIG_WIFI_DISPLAY
+	} else if (os_strcasecmp(cmd, "wifi_display") == 0) {
+		res = os_snprintf(buf, buflen, "%d",
+				  wpa_s->global->wifi_display);
+		if (res < 0 || (unsigned int) res >= buflen)
+			return -1;
+		return res;
+#endif /* CONFIG_WIFI_DISPLAY */
+	}
+
+	if (res < 0 || (unsigned int) res >= buflen)
+		return -1;
+	return res;
+}
+
+
+#ifdef IEEE8021X_EAPOL
+static int wpa_supplicant_ctrl_iface_preauth(struct wpa_supplicant *wpa_s,
+					     char *addr)
+{
+	u8 bssid[ETH_ALEN];
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	if (hwaddr_aton(addr, bssid)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH: invalid address "
+			   "'%s'", addr);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE PREAUTH " MACSTR, MAC2STR(bssid));
+	rsn_preauth_deinit(wpa_s->wpa);
+	if (rsn_preauth_init(wpa_s->wpa, bssid, ssid ? &ssid->eap : NULL))
+		return -1;
+
+	return 0;
+}
+#endif /* IEEE8021X_EAPOL */
+
+
+#ifdef CONFIG_PEERKEY
+/* MLME-STKSTART.request(peer) */
+static int wpa_supplicant_ctrl_iface_stkstart(
+	struct wpa_supplicant *wpa_s, char *addr)
+{
+	u8 peer[ETH_ALEN];
+
+	if (hwaddr_aton(addr, peer)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART: invalid "
+			   "address '%s'", addr);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE STKSTART " MACSTR,
+		   MAC2STR(peer));
+
+	return wpa_sm_stkstart(wpa_s->wpa, peer);
+}
+#endif /* CONFIG_PEERKEY */
+
+
+#ifdef CONFIG_TDLS
+
+static int wpa_supplicant_ctrl_iface_tdls_discover(
+	struct wpa_supplicant *wpa_s, char *addr)
+{
+	u8 peer[ETH_ALEN];
+	int ret;
+
+	if (hwaddr_aton(addr, peer)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER: invalid "
+			   "address '%s'", addr);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_DISCOVER " MACSTR,
+		   MAC2STR(peer));
+
+	if (wpa_tdls_is_external_setup(wpa_s->wpa))
+		ret = wpa_tdls_send_discovery_request(wpa_s->wpa, peer);
+	else
+		ret = wpa_drv_tdls_oper(wpa_s, TDLS_DISCOVERY_REQ, peer);
+
+	return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_tdls_setup(
+	struct wpa_supplicant *wpa_s, char *addr)
+{
+	u8 peer[ETH_ALEN];
+	int ret;
+
+	if (hwaddr_aton(addr, peer)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP: invalid "
+			   "address '%s'", addr);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_SETUP " MACSTR,
+		   MAC2STR(peer));
+
+	ret = wpa_tdls_reneg(wpa_s->wpa, peer);
+	if (ret) {
+		if (wpa_tdls_is_external_setup(wpa_s->wpa))
+			ret = wpa_tdls_start(wpa_s->wpa, peer);
+		else
+			ret = wpa_drv_tdls_oper(wpa_s, TDLS_SETUP, peer);
+	}
+
+	return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_tdls_teardown(
+	struct wpa_supplicant *wpa_s, char *addr)
+{
+	u8 peer[ETH_ALEN];
+
+	if (hwaddr_aton(addr, peer)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN: invalid "
+			   "address '%s'", addr);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE TDLS_TEARDOWN " MACSTR,
+		   MAC2STR(peer));
+
+	return wpa_tdls_teardown_link(wpa_s->wpa, peer,
+				      WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED);
+}
+
+#endif /* CONFIG_TDLS */
+
+
+#ifdef CONFIG_IEEE80211R
+static int wpa_supplicant_ctrl_iface_ft_ds(
+	struct wpa_supplicant *wpa_s, char *addr)
+{
+	u8 target_ap[ETH_ALEN];
+	struct wpa_bss *bss;
+	const u8 *mdie;
+
+	if (hwaddr_aton(addr, target_ap)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS: invalid "
+			   "address '%s'", addr);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE FT_DS " MACSTR, MAC2STR(target_ap));
+
+	bss = wpa_bss_get_bssid(wpa_s, target_ap);
+	if (bss)
+		mdie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
+	else
+		mdie = NULL;
+
+	return wpa_ft_start_over_ds(wpa_s->wpa, target_ap, mdie);
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+#ifdef CONFIG_WPS
+static int wpa_supplicant_ctrl_iface_wps_pbc(struct wpa_supplicant *wpa_s,
+					     char *cmd)
+{
+	u8 bssid[ETH_ALEN], *_bssid = bssid;
+#ifdef CONFIG_P2P
+	u8 p2p_dev_addr[ETH_ALEN];
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_AP
+	u8 *_p2p_dev_addr = NULL;
+#endif /* CONFIG_AP */
+
+	if (cmd == NULL || os_strcmp(cmd, "any") == 0) {
+		_bssid = NULL;
+#ifdef CONFIG_P2P
+	} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
+		if (hwaddr_aton(cmd + 13, p2p_dev_addr)) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid "
+				   "P2P Device Address '%s'",
+				   cmd + 13);
+			return -1;
+		}
+		_p2p_dev_addr = p2p_dev_addr;
+#endif /* CONFIG_P2P */
+	} else if (hwaddr_aton(cmd, bssid)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PBC: invalid BSSID '%s'",
+			   cmd);
+		return -1;
+	}
+
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface)
+		return wpa_supplicant_ap_wps_pbc(wpa_s, _bssid, _p2p_dev_addr);
+#endif /* CONFIG_AP */
+
+	return wpas_wps_start_pbc(wpa_s, _bssid, 0);
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_pin(struct wpa_supplicant *wpa_s,
+					     char *cmd, char *buf,
+					     size_t buflen)
+{
+	u8 bssid[ETH_ALEN], *_bssid = bssid;
+	char *pin;
+	int ret;
+
+	pin = os_strchr(cmd, ' ');
+	if (pin)
+		*pin++ = '\0';
+
+	if (os_strcmp(cmd, "any") == 0)
+		_bssid = NULL;
+	else if (os_strcmp(cmd, "get") == 0) {
+		ret = wps_generate_pin();
+		goto done;
+	} else if (hwaddr_aton(cmd, bssid)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_PIN: invalid BSSID '%s'",
+			   cmd);
+		return -1;
+	}
+
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface) {
+		int timeout = 0;
+		char *pos;
+
+		if (pin) {
+			pos = os_strchr(pin, ' ');
+			if (pos) {
+				*pos++ = '\0';
+				timeout = atoi(pos);
+			}
+		}
+
+		return wpa_supplicant_ap_wps_pin(wpa_s, _bssid, pin,
+						 buf, buflen, timeout);
+	}
+#endif /* CONFIG_AP */
+
+	if (pin) {
+		ret = wpas_wps_start_pin(wpa_s, _bssid, pin, 0,
+					 DEV_PW_DEFAULT);
+		if (ret < 0)
+			return -1;
+		ret = os_snprintf(buf, buflen, "%s", pin);
+		if (ret < 0 || (size_t) ret >= buflen)
+			return -1;
+		return ret;
+	}
+
+	ret = wpas_wps_start_pin(wpa_s, _bssid, NULL, 0, DEV_PW_DEFAULT);
+	if (ret < 0)
+		return -1;
+
+done:
+	/* Return the generated PIN */
+	ret = os_snprintf(buf, buflen, "%08d", ret);
+	if (ret < 0 || (size_t) ret >= buflen)
+		return -1;
+	return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_check_pin(
+	struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
+{
+	char pin[9];
+	size_t len;
+	char *pos;
+	int ret;
+
+	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
+			      (u8 *) cmd, os_strlen(cmd));
+	for (pos = cmd, len = 0; *pos != '\0'; pos++) {
+		if (*pos < '0' || *pos > '9')
+			continue;
+		pin[len++] = *pos;
+		if (len == 9) {
+			wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
+			return -1;
+		}
+	}
+	if (len != 4 && len != 8) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
+		return -1;
+	}
+	pin[len] = '\0';
+
+	if (len == 8) {
+		unsigned int pin_val;
+		pin_val = atoi(pin);
+		if (!wps_pin_valid(pin_val)) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
+			ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
+			if (ret < 0 || (size_t) ret >= buflen)
+				return -1;
+			return ret;
+		}
+	}
+
+	ret = os_snprintf(buf, buflen, "%s", pin);
+	if (ret < 0 || (size_t) ret >= buflen)
+		return -1;
+
+	return ret;
+}
+
+
+#ifdef CONFIG_WPS_NFC
+
+static int wpa_supplicant_ctrl_iface_wps_nfc(struct wpa_supplicant *wpa_s,
+					     char *cmd)
+{
+	u8 bssid[ETH_ALEN], *_bssid = bssid;
+
+	if (cmd == NULL || cmd[0] == '\0')
+		_bssid = NULL;
+	else if (hwaddr_aton(cmd, bssid))
+		return -1;
+
+	return wpas_wps_start_nfc(wpa_s, _bssid);
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_nfc_token(
+	struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+	int ndef;
+	struct wpabuf *buf;
+	int res;
+
+	if (os_strcmp(cmd, "WPS") == 0)
+		ndef = 0;
+	else if (os_strcmp(cmd, "NDEF") == 0)
+		ndef = 1;
+	else
+		return -1;
+
+	buf = wpas_wps_nfc_token(wpa_s, ndef);
+	if (buf == NULL)
+		return -1;
+
+	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+					 wpabuf_len(buf));
+	reply[res++] = '\n';
+	reply[res] = '\0';
+
+	wpabuf_free(buf);
+
+	return res;
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_nfc_tag_read(
+	struct wpa_supplicant *wpa_s, char *pos)
+{
+	size_t len;
+	struct wpabuf *buf;
+	int ret;
+
+	len = os_strlen(pos);
+	if (len & 0x01)
+		return -1;
+	len /= 2;
+
+	buf = wpabuf_alloc(len);
+	if (buf == NULL)
+		return -1;
+	if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
+		wpabuf_free(buf);
+		return -1;
+	}
+
+	ret = wpas_wps_nfc_tag_read(wpa_s, buf);
+	wpabuf_free(buf);
+
+	return ret;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_req_wps(struct wpa_supplicant *wpa_s,
+					      char *reply, size_t max_len)
+{
+	struct wpabuf *buf;
+	int res;
+
+	buf = wpas_wps_nfc_handover_req(wpa_s);
+	if (buf == NULL)
+		return -1;
+
+	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+					 wpabuf_len(buf));
+	reply[res++] = '\n';
+	reply[res] = '\0';
+
+	wpabuf_free(buf);
+
+	return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_req(struct wpa_supplicant *wpa_s,
+					  char *cmd, char *reply,
+					  size_t max_len)
+{
+	char *pos;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	if (os_strcmp(cmd, "NDEF") != 0)
+		return -1;
+
+	if (os_strcmp(pos, "WPS") == 0) {
+		return wpas_ctrl_nfc_get_handover_req_wps(wpa_s, reply,
+							  max_len);
+	}
+
+	return -1;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel_wps(struct wpa_supplicant *wpa_s,
+					      char *reply, size_t max_len)
+{
+	struct wpabuf *buf;
+	int res;
+
+	buf = wpas_wps_nfc_handover_sel(wpa_s);
+	if (buf == NULL)
+		return -1;
+
+	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+					 wpabuf_len(buf));
+	reply[res++] = '\n';
+	reply[res] = '\0';
+
+	wpabuf_free(buf);
+
+	return res;
+}
+
+
+static int wpas_ctrl_nfc_get_handover_sel(struct wpa_supplicant *wpa_s,
+					  char *cmd, char *reply,
+					  size_t max_len)
+{
+	char *pos;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	if (os_strcmp(cmd, "NDEF") != 0)
+		return -1;
+
+	if (os_strcmp(pos, "WPS") == 0) {
+		return wpas_ctrl_nfc_get_handover_sel_wps(wpa_s, reply,
+							  max_len);
+	}
+
+	return -1;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+					 char *cmd, char *reply,
+					 size_t max_len)
+{
+	size_t len;
+	struct wpabuf *buf;
+	int ret;
+
+	len = os_strlen(cmd);
+	if (len & 0x01)
+		return -1;
+	len /= 2;
+
+	buf = wpabuf_alloc(len);
+	if (buf == NULL)
+		return -1;
+	if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+		wpabuf_free(buf);
+		return -1;
+	}
+
+	ret = wpas_wps_nfc_rx_handover_req(wpa_s, buf);
+	wpabuf_free(buf);
+
+	return ret;
+}
+
+
+static int wpas_ctrl_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+					 char *cmd)
+{
+	size_t len;
+	struct wpabuf *buf;
+	int ret;
+
+	len = os_strlen(cmd);
+	if (len & 0x01)
+		return -1;
+	len /= 2;
+
+	buf = wpabuf_alloc(len);
+	if (buf == NULL)
+		return -1;
+	if (hexstr2bin(cmd, wpabuf_put(buf, len), len) < 0) {
+		wpabuf_free(buf);
+		return -1;
+	}
+
+	ret = wpas_wps_nfc_rx_handover_sel(wpa_s, buf);
+	wpabuf_free(buf);
+
+	return ret;
+}
+
+#endif /* CONFIG_WPS_NFC */
+
+
+static int wpa_supplicant_ctrl_iface_wps_reg(struct wpa_supplicant *wpa_s,
+					     char *cmd)
+{
+	u8 bssid[ETH_ALEN];
+	char *pin;
+	char *new_ssid;
+	char *new_auth;
+	char *new_encr;
+	char *new_key;
+	struct wps_new_ap_settings ap;
+
+	pin = os_strchr(cmd, ' ');
+	if (pin == NULL)
+		return -1;
+	*pin++ = '\0';
+
+	if (hwaddr_aton(cmd, bssid)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE WPS_REG: invalid BSSID '%s'",
+			   cmd);
+		return -1;
+	}
+
+	new_ssid = os_strchr(pin, ' ');
+	if (new_ssid == NULL)
+		return wpas_wps_start_reg(wpa_s, bssid, pin, NULL);
+	*new_ssid++ = '\0';
+
+	new_auth = os_strchr(new_ssid, ' ');
+	if (new_auth == NULL)
+		return -1;
+	*new_auth++ = '\0';
+
+	new_encr = os_strchr(new_auth, ' ');
+	if (new_encr == NULL)
+		return -1;
+	*new_encr++ = '\0';
+
+	new_key = os_strchr(new_encr, ' ');
+	if (new_key == NULL)
+		return -1;
+	*new_key++ = '\0';
+
+	os_memset(&ap, 0, sizeof(ap));
+	ap.ssid_hex = new_ssid;
+	ap.auth = new_auth;
+	ap.encr = new_encr;
+	ap.key_hex = new_key;
+	return wpas_wps_start_reg(wpa_s, bssid, pin, &ap);
+}
+
+
+#ifdef CONFIG_AP
+static int wpa_supplicant_ctrl_iface_wps_ap_pin(struct wpa_supplicant *wpa_s,
+						char *cmd, char *buf,
+						size_t buflen)
+{
+	int timeout = 300;
+	char *pos;
+	const char *pin_txt;
+
+	if (!wpa_s->ap_iface)
+		return -1;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos)
+		*pos++ = '\0';
+
+	if (os_strcmp(cmd, "disable") == 0) {
+		wpas_wps_ap_pin_disable(wpa_s);
+		return os_snprintf(buf, buflen, "OK\n");
+	}
+
+	if (os_strcmp(cmd, "random") == 0) {
+		if (pos)
+			timeout = atoi(pos);
+		pin_txt = wpas_wps_ap_pin_random(wpa_s, timeout);
+		if (pin_txt == NULL)
+			return -1;
+		return os_snprintf(buf, buflen, "%s", pin_txt);
+	}
+
+	if (os_strcmp(cmd, "get") == 0) {
+		pin_txt = wpas_wps_ap_pin_get(wpa_s);
+		if (pin_txt == NULL)
+			return -1;
+		return os_snprintf(buf, buflen, "%s", pin_txt);
+	}
+
+	if (os_strcmp(cmd, "set") == 0) {
+		char *pin;
+		if (pos == NULL)
+			return -1;
+		pin = pos;
+		pos = os_strchr(pos, ' ');
+		if (pos) {
+			*pos++ = '\0';
+			timeout = atoi(pos);
+		}
+		if (os_strlen(pin) > buflen)
+			return -1;
+		if (wpas_wps_ap_pin_set(wpa_s, pin, timeout) < 0)
+			return -1;
+		return os_snprintf(buf, buflen, "%s", pin);
+	}
+
+	return -1;
+}
+#endif /* CONFIG_AP */
+
+
+#ifdef CONFIG_WPS_ER
+static int wpa_supplicant_ctrl_iface_wps_er_pin(struct wpa_supplicant *wpa_s,
+						char *cmd)
+{
+	char *uuid = cmd, *pin, *pos;
+	u8 addr_buf[ETH_ALEN], *addr = NULL;
+	pin = os_strchr(uuid, ' ');
+	if (pin == NULL)
+		return -1;
+	*pin++ = '\0';
+	pos = os_strchr(pin, ' ');
+	if (pos) {
+		*pos++ = '\0';
+		if (hwaddr_aton(pos, addr_buf) == 0)
+			addr = addr_buf;
+	}
+	return wpas_wps_er_add_pin(wpa_s, addr, uuid, pin);
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_er_learn(struct wpa_supplicant *wpa_s,
+						  char *cmd)
+{
+	char *uuid = cmd, *pin;
+	pin = os_strchr(uuid, ' ');
+	if (pin == NULL)
+		return -1;
+	*pin++ = '\0';
+	return wpas_wps_er_learn(wpa_s, uuid, pin);
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_er_set_config(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *uuid = cmd, *id;
+	id = os_strchr(uuid, ' ');
+	if (id == NULL)
+		return -1;
+	*id++ = '\0';
+	return wpas_wps_er_set_config(wpa_s, uuid, atoi(id));
+}
+
+
+static int wpa_supplicant_ctrl_iface_wps_er_config(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pin;
+	char *new_ssid;
+	char *new_auth;
+	char *new_encr;
+	char *new_key;
+	struct wps_new_ap_settings ap;
+
+	pin = os_strchr(cmd, ' ');
+	if (pin == NULL)
+		return -1;
+	*pin++ = '\0';
+
+	new_ssid = os_strchr(pin, ' ');
+	if (new_ssid == NULL)
+		return -1;
+	*new_ssid++ = '\0';
+
+	new_auth = os_strchr(new_ssid, ' ');
+	if (new_auth == NULL)
+		return -1;
+	*new_auth++ = '\0';
+
+	new_encr = os_strchr(new_auth, ' ');
+	if (new_encr == NULL)
+		return -1;
+	*new_encr++ = '\0';
+
+	new_key = os_strchr(new_encr, ' ');
+	if (new_key == NULL)
+		return -1;
+	*new_key++ = '\0';
+
+	os_memset(&ap, 0, sizeof(ap));
+	ap.ssid_hex = new_ssid;
+	ap.auth = new_auth;
+	ap.encr = new_encr;
+	ap.key_hex = new_key;
+	return wpas_wps_er_config(wpa_s, cmd, pin, &ap);
+}
+
+
+#ifdef CONFIG_WPS_NFC
+static int wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
+	struct wpa_supplicant *wpa_s, char *cmd, char *reply, size_t max_len)
+{
+	int ndef;
+	struct wpabuf *buf;
+	int res;
+	char *uuid;
+
+	uuid = os_strchr(cmd, ' ');
+	if (uuid == NULL)
+		return -1;
+	*uuid++ = '\0';
+
+	if (os_strcmp(cmd, "WPS") == 0)
+		ndef = 0;
+	else if (os_strcmp(cmd, "NDEF") == 0)
+		ndef = 1;
+	else
+		return -1;
+
+	buf = wpas_wps_er_nfc_config_token(wpa_s, ndef, uuid);
+	if (buf == NULL)
+		return -1;
+
+	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+					 wpabuf_len(buf));
+	reply[res++] = '\n';
+	reply[res] = '\0';
+
+	wpabuf_free(buf);
+
+	return res;
+}
+#endif /* CONFIG_WPS_NFC */
+#endif /* CONFIG_WPS_ER */
+
+#endif /* CONFIG_WPS */
+
+
+#ifdef CONFIG_IBSS_RSN
+static int wpa_supplicant_ctrl_iface_ibss_rsn(
+	struct wpa_supplicant *wpa_s, char *addr)
+{
+	u8 peer[ETH_ALEN];
+
+	if (hwaddr_aton(addr, peer)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN: invalid "
+			   "address '%s'", addr);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE IBSS_RSN " MACSTR,
+		   MAC2STR(peer));
+
+	return ibss_rsn_start(wpa_s->ibss_rsn, peer);
+}
+#endif /* CONFIG_IBSS_RSN */
+
+
+static int wpa_supplicant_ctrl_iface_ctrl_rsp(struct wpa_supplicant *wpa_s,
+					      char *rsp)
+{
+#ifdef IEEE8021X_EAPOL
+	char *pos, *id_pos;
+	int id;
+	struct wpa_ssid *ssid;
+
+	pos = os_strchr(rsp, '-');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+	id_pos = pos;
+	pos = os_strchr(pos, ':');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+	id = atoi(id_pos);
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: field=%s id=%d", rsp, id);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
+			      (u8 *) pos, os_strlen(pos));
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
+			   "to update", id);
+		return -1;
+	}
+
+	return wpa_supplicant_ctrl_iface_ctrl_rsp_handle(wpa_s, ssid, rsp,
+							 pos);
+#else /* IEEE8021X_EAPOL */
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: 802.1X not included");
+	return -1;
+#endif /* IEEE8021X_EAPOL */
+}
+
+
+static int wpa_supplicant_ctrl_iface_status(struct wpa_supplicant *wpa_s,
+					    const char *params,
+					    char *buf, size_t buflen)
+{
+	char *pos, *end, tmp[30];
+	int res, verbose, wps, ret;
+
+	verbose = os_strcmp(params, "-VERBOSE") == 0;
+	wps = os_strcmp(params, "-WPS") == 0;
+	pos = buf;
+	end = buf + buflen;
+	if (wpa_s->wpa_state >= WPA_ASSOCIATED) {
+		struct wpa_ssid *ssid = wpa_s->current_ssid;
+		ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
+				  MAC2STR(wpa_s->bssid));
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		if (ssid) {
+			u8 *_ssid = ssid->ssid;
+			size_t ssid_len = ssid->ssid_len;
+			u8 ssid_buf[MAX_SSID_LEN];
+			if (ssid_len == 0) {
+				int _res = wpa_drv_get_ssid(wpa_s, ssid_buf);
+				if (_res < 0)
+					ssid_len = 0;
+				else
+					ssid_len = _res;
+				_ssid = ssid_buf;
+			}
+			ret = os_snprintf(pos, end - pos, "ssid=%s\nid=%d\n",
+					  wpa_ssid_txt(_ssid, ssid_len),
+					  ssid->id);
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+
+			if (wps && ssid->passphrase &&
+			    wpa_key_mgmt_wpa_psk(ssid->key_mgmt) &&
+			    (ssid->mode == WPAS_MODE_AP ||
+			     ssid->mode == WPAS_MODE_P2P_GO)) {
+				ret = os_snprintf(pos, end - pos,
+						  "passphrase=%s\n",
+						  ssid->passphrase);
+				if (ret < 0 || ret >= end - pos)
+					return pos - buf;
+				pos += ret;
+			}
+			if (ssid->id_str) {
+				ret = os_snprintf(pos, end - pos,
+						  "id_str=%s\n",
+						  ssid->id_str);
+				if (ret < 0 || ret >= end - pos)
+					return pos - buf;
+				pos += ret;
+			}
+
+			switch (ssid->mode) {
+			case WPAS_MODE_INFRA:
+				ret = os_snprintf(pos, end - pos,
+						  "mode=station\n");
+				break;
+			case WPAS_MODE_IBSS:
+				ret = os_snprintf(pos, end - pos,
+						  "mode=IBSS\n");
+				break;
+			case WPAS_MODE_AP:
+				ret = os_snprintf(pos, end - pos,
+						  "mode=AP\n");
+				break;
+			case WPAS_MODE_P2P_GO:
+				ret = os_snprintf(pos, end - pos,
+						  "mode=P2P GO\n");
+				break;
+			case WPAS_MODE_P2P_GROUP_FORMATION:
+				ret = os_snprintf(pos, end - pos,
+						  "mode=P2P GO - group "
+						  "formation\n");
+				break;
+			default:
+				ret = 0;
+				break;
+			}
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface) {
+			pos += ap_ctrl_iface_wpa_get_status(wpa_s, pos,
+							    end - pos,
+							    verbose);
+		} else
+#endif /* CONFIG_AP */
+		pos += wpa_sm_get_status(wpa_s->wpa, pos, end - pos, verbose);
+	}
+	ret = os_snprintf(pos, end - pos, "wpa_state=%s\n",
+			  wpa_supplicant_state_txt(wpa_s->wpa_state));
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+	if (wpa_s->l2 &&
+	    l2_packet_get_ip_addr(wpa_s->l2, tmp, sizeof(tmp)) >= 0) {
+		ret = os_snprintf(pos, end - pos, "ip_address=%s\n", tmp);
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+#ifdef CONFIG_P2P
+	if (wpa_s->global->p2p) {
+		ret = os_snprintf(pos, end - pos, "p2p_device_address=" MACSTR
+				  "\n", MAC2STR(wpa_s->global->p2p_dev_addr));
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+#endif /* CONFIG_P2P */
+
+	ret = os_snprintf(pos, end - pos, "address=" MACSTR "\n",
+			  MAC2STR(wpa_s->own_addr));
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+#ifdef CONFIG_HS20
+	if (wpa_s->current_bss &&
+	    wpa_bss_get_vendor_ie(wpa_s->current_bss, HS20_IE_VENDOR_TYPE) &&
+	    wpa_s->wpa_proto == WPA_PROTO_RSN &&
+	    wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
+		ret = os_snprintf(pos, end - pos, "hs20=1\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (wpa_s->current_ssid) {
+		struct wpa_cred *cred;
+		char *type;
+
+		for (cred = wpa_s->conf->cred; cred; cred = cred->next) {
+			if (wpa_s->current_ssid->parent_cred != cred)
+				continue;
+			if (!cred->domain)
+				continue;
+
+			ret = os_snprintf(pos, end - pos, "home_sp=%s\n",
+					  cred->domain);
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+
+			if (wpa_s->current_bss == NULL ||
+			    wpa_s->current_bss->anqp == NULL)
+				res = -1;
+			else
+				res = interworking_home_sp_cred(
+					wpa_s, cred,
+					wpa_s->current_bss->anqp->domain_name);
+			if (res > 0)
+				type = "home";
+			else if (res == 0)
+				type = "roaming";
+			else
+				type = "unknown";
+
+			ret = os_snprintf(pos, end - pos, "sp_type=%s\n", type);
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+
+			break;
+		}
+	}
+#endif /* CONFIG_HS20 */
+
+	if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		res = eapol_sm_get_status(wpa_s->eapol, pos, end - pos,
+					  verbose);
+		if (res >= 0)
+			pos += res;
+	}
+
+	res = rsn_preauth_get_status(wpa_s->wpa, pos, end - pos, verbose);
+	if (res >= 0)
+		pos += res;
+
+	return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_bssid(struct wpa_supplicant *wpa_s,
+					   char *cmd)
+{
+	char *pos;
+	int id;
+	struct wpa_ssid *ssid;
+	u8 bssid[ETH_ALEN];
+
+	/* cmd: "<network id> <BSSID>" */
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+	id = atoi(cmd);
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: id=%d bssid='%s'", id, pos);
+	if (hwaddr_aton(pos, bssid)) {
+		wpa_printf(MSG_DEBUG ,"CTRL_IFACE: invalid BSSID '%s'", pos);
+		return -1;
+	}
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
+			   "to update", id);
+		return -1;
+	}
+
+	os_memcpy(ssid->bssid, bssid, ETH_ALEN);
+	ssid->bssid_set = !is_zero_ether_addr(bssid);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_blacklist(struct wpa_supplicant *wpa_s,
+					       char *cmd, char *buf,
+					       size_t buflen)
+{
+	u8 bssid[ETH_ALEN];
+	struct wpa_blacklist *e;
+	char *pos, *end;
+	int ret;
+
+	/* cmd: "BLACKLIST [<BSSID>]" */
+	if (*cmd == '\0') {
+		pos = buf;
+		end = buf + buflen;
+		e = wpa_s->blacklist;
+		while (e) {
+			ret = os_snprintf(pos, end - pos, MACSTR "\n",
+					  MAC2STR(e->bssid));
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+			e = e->next;
+		}
+		return pos - buf;
+	}
+
+	cmd++;
+	if (os_strncmp(cmd, "clear", 5) == 0) {
+		wpa_blacklist_clear(wpa_s);
+		os_memcpy(buf, "OK\n", 3);
+		return 3;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: BLACKLIST bssid='%s'", cmd);
+	if (hwaddr_aton(cmd, bssid)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: invalid BSSID '%s'", cmd);
+		return -1;
+	}
+
+	/*
+	 * Add the BSSID twice, so its count will be 2, causing it to be
+	 * skipped when processing scan results.
+	 */
+	ret = wpa_blacklist_add(wpa_s, bssid);
+	if (ret != 0)
+		return -1;
+	ret = wpa_blacklist_add(wpa_s, bssid);
+	if (ret != 0)
+		return -1;
+	os_memcpy(buf, "OK\n", 3);
+	return 3;
+}
+
+
+extern int wpa_debug_level;
+extern int wpa_debug_timestamp;
+
+static const char * debug_level_str(int level)
+{
+	switch (level) {
+	case MSG_EXCESSIVE:
+		return "EXCESSIVE";
+	case MSG_MSGDUMP:
+		return "MSGDUMP";
+	case MSG_DEBUG:
+		return "DEBUG";
+	case MSG_INFO:
+		return "INFO";
+	case MSG_WARNING:
+		return "WARNING";
+	case MSG_ERROR:
+		return "ERROR";
+	default:
+		return "?";
+	}
+}
+
+
+static int str_to_debug_level(const char *s)
+{
+	if (os_strcasecmp(s, "EXCESSIVE") == 0)
+		return MSG_EXCESSIVE;
+	if (os_strcasecmp(s, "MSGDUMP") == 0)
+		return MSG_MSGDUMP;
+	if (os_strcasecmp(s, "DEBUG") == 0)
+		return MSG_DEBUG;
+	if (os_strcasecmp(s, "INFO") == 0)
+		return MSG_INFO;
+	if (os_strcasecmp(s, "WARNING") == 0)
+		return MSG_WARNING;
+	if (os_strcasecmp(s, "ERROR") == 0)
+		return MSG_ERROR;
+	return -1;
+}
+
+
+static int wpa_supplicant_ctrl_iface_log_level(struct wpa_supplicant *wpa_s,
+					       char *cmd, char *buf,
+					       size_t buflen)
+{
+	char *pos, *end, *stamp;
+	int ret;
+
+	if (cmd == NULL) {
+		return -1;
+	}
+
+	/* cmd: "LOG_LEVEL [<level>]" */
+	if (*cmd == '\0') {
+		pos = buf;
+		end = buf + buflen;
+		ret = os_snprintf(pos, end - pos, "Current level: %s\n"
+				  "Timestamp: %d\n",
+				  debug_level_str(wpa_debug_level),
+				  wpa_debug_timestamp);
+		if (ret < 0 || ret >= end - pos)
+			ret = 0;
+
+		return ret;
+	}
+
+	while (*cmd == ' ')
+		cmd++;
+
+	stamp = os_strchr(cmd, ' ');
+	if (stamp) {
+		*stamp++ = '\0';
+		while (*stamp == ' ') {
+			stamp++;
+		}
+	}
+
+	if (cmd && os_strlen(cmd)) {
+		int level = str_to_debug_level(cmd);
+		if (level < 0)
+			return -1;
+		wpa_debug_level = level;
+	}
+
+	if (stamp && os_strlen(stamp))
+		wpa_debug_timestamp = atoi(stamp);
+
+	os_memcpy(buf, "OK\n", 3);
+	return 3;
+}
+
+
+static int wpa_supplicant_ctrl_iface_list_networks(
+	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+{
+	char *pos, *end;
+	struct wpa_ssid *ssid;
+	int ret;
+
+	pos = buf;
+	end = buf + buflen;
+	ret = os_snprintf(pos, end - pos,
+			  "network id / ssid / bssid / flags\n");
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+	ssid = wpa_s->conf->ssid;
+	while (ssid) {
+		ret = os_snprintf(pos, end - pos, "%d\t%s",
+				  ssid->id,
+				  wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		if (ssid->bssid_set) {
+			ret = os_snprintf(pos, end - pos, "\t" MACSTR,
+					  MAC2STR(ssid->bssid));
+		} else {
+			ret = os_snprintf(pos, end - pos, "\tany");
+		}
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		ret = os_snprintf(pos, end - pos, "\t%s%s%s%s",
+				  ssid == wpa_s->current_ssid ?
+				  "[CURRENT]" : "",
+				  ssid->disabled ? "[DISABLED]" : "",
+				  ssid->disabled_until.sec ?
+				  "[TEMP-DISABLED]" : "",
+				  ssid->disabled == 2 ? "[P2P-PERSISTENT]" :
+				  "");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+
+		ssid = ssid->next;
+	}
+
+	return pos - buf;
+}
+
+
+static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
+{
+	int first = 1, ret;
+	ret = os_snprintf(pos, end - pos, "-");
+	if (ret < 0 || ret >= end - pos)
+		return pos;
+	pos += ret;
+	if (cipher & WPA_CIPHER_NONE) {
+		ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (cipher & WPA_CIPHER_WEP40) {
+		ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (cipher & WPA_CIPHER_WEP104) {
+		ret = os_snprintf(pos, end - pos, "%sWEP104",
+				  first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (cipher & WPA_CIPHER_TKIP) {
+		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (cipher & WPA_CIPHER_CCMP) {
+		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (cipher & WPA_CIPHER_GCMP) {
+		ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	return pos;
+}
+
+
+static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
+				    const u8 *ie, size_t ie_len)
+{
+	struct wpa_ie_data data;
+	int first, ret;
+
+	ret = os_snprintf(pos, end - pos, "[%s-", proto);
+	if (ret < 0 || ret >= end - pos)
+		return pos;
+	pos += ret;
+
+	if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
+		ret = os_snprintf(pos, end - pos, "?]");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		return pos;
+	}
+
+	first = 1;
+	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+		ret = os_snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
+		ret = os_snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
+		ret = os_snprintf(pos, end - pos, "%sNone", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+#ifdef CONFIG_IEEE80211R
+	if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
+		ret = os_snprintf(pos, end - pos, "%sFT/EAP",
+				  first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK) {
+		ret = os_snprintf(pos, end - pos, "%sFT/PSK",
+				  first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+		ret = os_snprintf(pos, end - pos, "%sEAP-SHA256",
+				  first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
+		ret = os_snprintf(pos, end - pos, "%sPSK-SHA256",
+				  first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
+
+	if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
+		ret = os_snprintf(pos, end - pos, "-preauth");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+	}
+
+	ret = os_snprintf(pos, end - pos, "]");
+	if (ret < 0 || ret >= end - pos)
+		return pos;
+	pos += ret;
+
+	return pos;
+}
+
+
+#ifdef CONFIG_WPS
+static char * wpa_supplicant_wps_ie_txt_buf(struct wpa_supplicant *wpa_s,
+					    char *pos, char *end,
+					    struct wpabuf *wps_ie)
+{
+	int ret;
+	const char *txt;
+
+	if (wps_ie == NULL)
+		return pos;
+	if (wps_is_selected_pbc_registrar(wps_ie))
+		txt = "[WPS-PBC]";
+#ifdef CONFIG_WPS2
+	else if (wps_is_addr_authorized(wps_ie, wpa_s->own_addr, 0))
+		txt = "[WPS-AUTH]";
+#endif /* CONFIG_WPS2 */
+	else if (wps_is_selected_pin_registrar(wps_ie))
+		txt = "[WPS-PIN]";
+	else
+		txt = "[WPS]";
+
+	ret = os_snprintf(pos, end - pos, "%s", txt);
+	if (ret >= 0 && ret < end - pos)
+		pos += ret;
+	wpabuf_free(wps_ie);
+	return pos;
+}
+#endif /* CONFIG_WPS */
+
+
+static char * wpa_supplicant_wps_ie_txt(struct wpa_supplicant *wpa_s,
+					char *pos, char *end,
+					const struct wpa_bss *bss)
+{
+#ifdef CONFIG_WPS
+	struct wpabuf *wps_ie;
+	wps_ie = wpa_bss_get_vendor_ie_multi(bss, WPS_IE_VENDOR_TYPE);
+	return wpa_supplicant_wps_ie_txt_buf(wpa_s, pos, end, wps_ie);
+#else /* CONFIG_WPS */
+	return pos;
+#endif /* CONFIG_WPS */
+}
+
+
+/* Format one result on one text line into a buffer. */
+static int wpa_supplicant_ctrl_iface_scan_result(
+	struct wpa_supplicant *wpa_s,
+	const struct wpa_bss *bss, char *buf, size_t buflen)
+{
+	char *pos, *end;
+	int ret;
+	const u8 *ie, *ie2, *p2p;
+
+	p2p = wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE);
+	if (p2p && bss->ssid_len == P2P_WILDCARD_SSID_LEN &&
+	    os_memcmp(bss->ssid, P2P_WILDCARD_SSID, P2P_WILDCARD_SSID_LEN) ==
+	    0)
+		return 0; /* Do not show P2P listen discovery results here */
+
+	pos = buf;
+	end = buf + buflen;
+
+	ret = os_snprintf(pos, end - pos, MACSTR "\t%d\t%d\t",
+			  MAC2STR(bss->bssid), bss->freq, bss->level);
+	if (ret < 0 || ret >= end - pos)
+		return -1;
+	pos += ret;
+	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+	if (ie)
+		pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1]);
+	ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+	if (ie2)
+		pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1]);
+	pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
+	if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
+		ret = os_snprintf(pos, end - pos, "[WEP]");
+		if (ret < 0 || ret >= end - pos)
+			return -1;
+		pos += ret;
+	}
+	if (bss->caps & IEEE80211_CAP_IBSS) {
+		ret = os_snprintf(pos, end - pos, "[IBSS]");
+		if (ret < 0 || ret >= end - pos)
+			return -1;
+		pos += ret;
+	}
+	if (bss->caps & IEEE80211_CAP_ESS) {
+		ret = os_snprintf(pos, end - pos, "[ESS]");
+		if (ret < 0 || ret >= end - pos)
+			return -1;
+		pos += ret;
+	}
+	if (p2p) {
+		ret = os_snprintf(pos, end - pos, "[P2P]");
+		if (ret < 0 || ret >= end - pos)
+			return -1;
+		pos += ret;
+	}
+#ifdef CONFIG_HS20
+	if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE) && ie2) {
+		ret = os_snprintf(pos, end - pos, "[HS20]");
+		if (ret < 0 || ret >= end - pos)
+			return -1;
+		pos += ret;
+	}
+#endif /* CONFIG_HS20 */
+
+	ret = os_snprintf(pos, end - pos, "\t%s",
+			  wpa_ssid_txt(bss->ssid, bss->ssid_len));
+	if (ret < 0 || ret >= end - pos)
+		return -1;
+	pos += ret;
+
+	ret = os_snprintf(pos, end - pos, "\n");
+	if (ret < 0 || ret >= end - pos)
+		return -1;
+	pos += ret;
+
+	return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_scan_results(
+	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+{
+	char *pos, *end;
+	struct wpa_bss *bss;
+	int ret;
+
+	pos = buf;
+	end = buf + buflen;
+	ret = os_snprintf(pos, end - pos, "bssid / frequency / signal level / "
+			  "flags / ssid\n");
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+	dl_list_for_each(bss, &wpa_s->bss_id, struct wpa_bss, list_id) {
+		ret = wpa_supplicant_ctrl_iface_scan_result(wpa_s, bss, pos,
+							    end - pos);
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_select_network(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int id;
+	struct wpa_ssid *ssid;
+
+	/* cmd: "<network id>" or "any" */
+	if (os_strcmp(cmd, "any") == 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK any");
+		ssid = NULL;
+	} else {
+		id = atoi(cmd);
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SELECT_NETWORK id=%d", id);
+
+		ssid = wpa_config_get_network(wpa_s->conf, id);
+		if (ssid == NULL) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+				   "network id=%d", id);
+			return -1;
+		}
+		if (ssid->disabled == 2) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
+				   "SELECT_NETWORK with persistent P2P group");
+			return -1;
+		}
+	}
+
+	wpa_supplicant_select_network(wpa_s, ssid);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_enable_network(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int id;
+	struct wpa_ssid *ssid;
+
+	/* cmd: "<network id>" or "all" */
+	if (os_strcmp(cmd, "all") == 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK all");
+		ssid = NULL;
+	} else {
+		id = atoi(cmd);
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: ENABLE_NETWORK id=%d", id);
+
+		ssid = wpa_config_get_network(wpa_s->conf, id);
+		if (ssid == NULL) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+				   "network id=%d", id);
+			return -1;
+		}
+		if (ssid->disabled == 2) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
+				   "ENABLE_NETWORK with persistent P2P group");
+			return -1;
+		}
+
+		if (os_strstr(cmd, " no-connect")) {
+			ssid->disabled = 0;
+			return 0;
+		}
+	}
+	wpa_supplicant_enable_network(wpa_s, ssid);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_disable_network(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int id;
+	struct wpa_ssid *ssid;
+
+	/* cmd: "<network id>" or "all" */
+	if (os_strcmp(cmd, "all") == 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK all");
+		ssid = NULL;
+	} else {
+		id = atoi(cmd);
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: DISABLE_NETWORK id=%d", id);
+
+		ssid = wpa_config_get_network(wpa_s->conf, id);
+		if (ssid == NULL) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+				   "network id=%d", id);
+			return -1;
+		}
+		if (ssid->disabled == 2) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Cannot use "
+				   "DISABLE_NETWORK with persistent P2P "
+				   "group");
+			return -1;
+		}
+	}
+	wpa_supplicant_disable_network(wpa_s, ssid);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_add_network(
+	struct wpa_supplicant *wpa_s, char *buf, size_t buflen)
+{
+	struct wpa_ssid *ssid;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_NETWORK");
+
+	ssid = wpa_config_add_network(wpa_s->conf);
+	if (ssid == NULL)
+		return -1;
+
+	wpas_notify_network_added(wpa_s, ssid);
+
+	ssid->disabled = 1;
+	wpa_config_set_network_defaults(ssid);
+
+	ret = os_snprintf(buf, buflen, "%d\n", ssid->id);
+	if (ret < 0 || (size_t) ret >= buflen)
+		return -1;
+	return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_remove_network(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int id;
+	struct wpa_ssid *ssid;
+
+	/* cmd: "<network id>" or "all" */
+	if (os_strcmp(cmd, "all") == 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK all");
+		ssid = wpa_s->conf->ssid;
+		while (ssid) {
+			struct wpa_ssid *remove_ssid = ssid;
+			id = ssid->id;
+			ssid = ssid->next;
+			wpas_notify_network_removed(wpa_s, remove_ssid);
+			wpa_config_remove_network(wpa_s->conf, id);
+		}
+		eapol_sm_invalidate_cached_session(wpa_s->eapol);
+		if (wpa_s->current_ssid) {
+#ifdef CONFIG_SME
+			wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+			wpa_sm_set_config(wpa_s->wpa, NULL);
+			eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+			wpa_supplicant_deauthenticate(
+				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+		}
+		return 0;
+	}
+
+	id = atoi(cmd);
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_NETWORK id=%d", id);
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid)
+		wpas_notify_network_removed(wpa_s, ssid);
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
+			   "id=%d", id);
+		return -1;
+	}
+
+	if (ssid == wpa_s->current_ssid || wpa_s->current_ssid == NULL) {
+#ifdef CONFIG_SME
+		wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+		/*
+		 * Invalidate the EAP session cache if the current or
+		 * previously used network is removed.
+		 */
+		eapol_sm_invalidate_cached_session(wpa_s->eapol);
+	}
+
+	if (ssid == wpa_s->current_ssid) {
+		wpa_sm_set_config(wpa_s->wpa, NULL);
+		eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+	}
+
+	if (wpa_config_remove_network(wpa_s->conf, id) < 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Not able to remove the "
+			   "network id=%d", id);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_set_network(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int id;
+	struct wpa_ssid *ssid;
+	char *name, *value;
+
+	/* cmd: "<network id> <variable name> <value>" */
+	name = os_strchr(cmd, ' ');
+	if (name == NULL)
+		return -1;
+	*name++ = '\0';
+
+	value = os_strchr(name, ' ');
+	if (value == NULL)
+		return -1;
+	*value++ = '\0';
+
+	id = atoi(cmd);
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_NETWORK id=%d name='%s'",
+		   id, name);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
+			      (u8 *) value, os_strlen(value));
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
+			   "id=%d", id);
+		return -1;
+	}
+
+	if (wpa_config_set(ssid, name, value, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set network "
+			   "variable '%s'", name);
+		return -1;
+	}
+
+	if (os_strcmp(name, "bssid") != 0 &&
+	    os_strcmp(name, "priority") != 0)
+		wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+
+	if (wpa_s->current_ssid == ssid || wpa_s->current_ssid == NULL) {
+		/*
+		 * Invalidate the EAP session cache if anything in the current
+		 * or previously used configuration changes.
+		 */
+		eapol_sm_invalidate_cached_session(wpa_s->eapol);
+	}
+
+	if ((os_strcmp(name, "psk") == 0 &&
+	     value[0] == '"' && ssid->ssid_len) ||
+	    (os_strcmp(name, "ssid") == 0 && ssid->passphrase))
+		wpa_config_update_psk(ssid);
+	else if (os_strcmp(name, "priority") == 0)
+		wpa_config_update_prio_list(wpa_s->conf);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_get_network(
+	struct wpa_supplicant *wpa_s, char *cmd, char *buf, size_t buflen)
+{
+	int id;
+	size_t res;
+	struct wpa_ssid *ssid;
+	char *name, *value;
+
+	/* cmd: "<network id> <variable name>" */
+	name = os_strchr(cmd, ' ');
+	if (name == NULL || buflen == 0)
+		return -1;
+	*name++ = '\0';
+
+	id = atoi(cmd);
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_NETWORK id=%d name='%s'",
+		   id, name);
+
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find network "
+			   "id=%d", id);
+		return -1;
+	}
+
+	value = wpa_config_get_no_key(ssid, name);
+	if (value == NULL) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to get network "
+			   "variable '%s'", name);
+		return -1;
+	}
+
+	res = os_strlcpy(buf, value, buflen);
+	if (res >= buflen) {
+		os_free(value);
+		return -1;
+	}
+
+	os_free(value);
+
+	return res;
+}
+
+
+static int wpa_supplicant_ctrl_iface_list_creds(struct wpa_supplicant *wpa_s,
+						char *buf, size_t buflen)
+{
+	char *pos, *end;
+	struct wpa_cred *cred;
+	int ret;
+
+	pos = buf;
+	end = buf + buflen;
+	ret = os_snprintf(pos, end - pos,
+			  "cred id / realm / username / domain / imsi\n");
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+	cred = wpa_s->conf->cred;
+	while (cred) {
+		ret = os_snprintf(pos, end - pos, "%d\t%s\t%s\t%s\t%s\n",
+				  cred->id, cred->realm ? cred->realm : "",
+				  cred->username ? cred->username : "",
+				  cred->domain ? cred->domain : "",
+				  cred->imsi ? cred->imsi : "");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+
+		cred = cred->next;
+	}
+
+	return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_add_cred(struct wpa_supplicant *wpa_s,
+					      char *buf, size_t buflen)
+{
+	struct wpa_cred *cred;
+	int ret;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: ADD_CRED");
+
+	cred = wpa_config_add_cred(wpa_s->conf);
+	if (cred == NULL)
+		return -1;
+
+	ret = os_snprintf(buf, buflen, "%d\n", cred->id);
+	if (ret < 0 || (size_t) ret >= buflen)
+		return -1;
+	return ret;
+}
+
+
+static int wpas_ctrl_remove_cred(struct wpa_supplicant *wpa_s,
+				 struct wpa_cred *cred)
+{
+	struct wpa_ssid *ssid;
+	char str[20];
+
+	if (cred == NULL || wpa_config_remove_cred(wpa_s->conf, cred->id) < 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred");
+		return -1;
+	}
+
+	/* Remove any network entry created based on the removed credential */
+	ssid = wpa_s->conf->ssid;
+	while (ssid) {
+		if (ssid->parent_cred == cred) {
+			wpa_printf(MSG_DEBUG, "Remove network id %d since it "
+				   "used the removed credential", ssid->id);
+			os_snprintf(str, sizeof(str), "%d", ssid->id);
+			ssid = ssid->next;
+			wpa_supplicant_ctrl_iface_remove_network(wpa_s, str);
+		} else
+			ssid = ssid->next;
+	}
+
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_remove_cred(struct wpa_supplicant *wpa_s,
+						 char *cmd)
+{
+	int id;
+	struct wpa_cred *cred, *prev;
+
+	/* cmd: "<cred id>", "all", or "sp_fqdn=<FQDN>" */
+	if (os_strcmp(cmd, "all") == 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED all");
+		cred = wpa_s->conf->cred;
+		while (cred) {
+			prev = cred;
+			cred = cred->next;
+			wpas_ctrl_remove_cred(wpa_s, prev);
+		}
+		return 0;
+	}
+
+	if (os_strncmp(cmd, "sp_fqdn=", 8) == 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED SP FQDN '%s'",
+			   cmd + 8);
+		cred = wpa_s->conf->cred;
+		while (cred) {
+			prev = cred;
+			cred = cred->next;
+			if (prev->domain &&
+			    os_strcmp(prev->domain, cmd + 8) == 0)
+				wpas_ctrl_remove_cred(wpa_s, prev);
+		}
+		return 0;
+	}
+
+	id = atoi(cmd);
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: REMOVE_CRED id=%d", id);
+
+	cred = wpa_config_get_cred(wpa_s->conf, id);
+	return wpas_ctrl_remove_cred(wpa_s, cred);
+}
+
+
+static int wpa_supplicant_ctrl_iface_set_cred(struct wpa_supplicant *wpa_s,
+					      char *cmd)
+{
+	int id;
+	struct wpa_cred *cred;
+	char *name, *value;
+
+	/* cmd: "<cred id> <variable name> <value>" */
+	name = os_strchr(cmd, ' ');
+	if (name == NULL)
+		return -1;
+	*name++ = '\0';
+
+	value = os_strchr(name, ' ');
+	if (value == NULL)
+		return -1;
+	*value++ = '\0';
+
+	id = atoi(cmd);
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: SET_CRED id=%d name='%s'",
+		   id, name);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: value",
+			      (u8 *) value, os_strlen(value));
+
+	cred = wpa_config_get_cred(wpa_s->conf, id);
+	if (cred == NULL) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find cred id=%d",
+			   id);
+		return -1;
+	}
+
+	if (wpa_config_set_cred(cred, name, value, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Failed to set cred "
+			   "variable '%s'", name);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+#ifndef CONFIG_NO_CONFIG_WRITE
+static int wpa_supplicant_ctrl_iface_save_config(struct wpa_supplicant *wpa_s)
+{
+	int ret;
+
+	if (!wpa_s->conf->update_config) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Not allowed "
+			   "to update configuration (update_config=0)");
+		return -1;
+	}
+
+	ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Failed to "
+			   "update configuration");
+	} else {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: SAVE_CONFIG - Configuration"
+			   " updated");
+	}
+
+	return ret;
+}
+#endif /* CONFIG_NO_CONFIG_WRITE */
+
+
+static int ctrl_iface_get_capability_pairwise(int res, char *strict,
+					      struct wpa_driver_capa *capa,
+					      char *buf, size_t buflen)
+{
+	int ret, first = 1;
+	char *pos, *end;
+	size_t len;
+
+	pos = buf;
+	end = pos + buflen;
+
+	if (res < 0) {
+		if (strict)
+			return 0;
+		len = os_strlcpy(buf, "CCMP TKIP NONE", buflen);
+		if (len >= buflen)
+			return -1;
+		return len;
+	}
+
+	if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
+		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+		ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
+		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
+		ret = os_snprintf(pos, end - pos, "%sNONE", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	return pos - buf;
+}
+
+
+static int ctrl_iface_get_capability_group(int res, char *strict,
+					   struct wpa_driver_capa *capa,
+					   char *buf, size_t buflen)
+{
+	int ret, first = 1;
+	char *pos, *end;
+	size_t len;
+
+	pos = buf;
+	end = pos + buflen;
+
+	if (res < 0) {
+		if (strict)
+			return 0;
+		len = os_strlcpy(buf, "CCMP TKIP WEP104 WEP40", buflen);
+		if (len >= buflen)
+			return -1;
+		return len;
+	}
+
+	if (capa->enc & WPA_DRIVER_CAPA_ENC_CCMP) {
+		ret = os_snprintf(pos, end - pos, "%sCCMP", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->enc & WPA_DRIVER_CAPA_ENC_GCMP) {
+		ret = os_snprintf(pos, end - pos, "%sGCMP", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->enc & WPA_DRIVER_CAPA_ENC_TKIP) {
+		ret = os_snprintf(pos, end - pos, "%sTKIP", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP104) {
+		ret = os_snprintf(pos, end - pos, "%sWEP104",
+				  first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->enc & WPA_DRIVER_CAPA_ENC_WEP40) {
+		ret = os_snprintf(pos, end - pos, "%sWEP40", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	return pos - buf;
+}
+
+
+static int ctrl_iface_get_capability_key_mgmt(int res, char *strict,
+					      struct wpa_driver_capa *capa,
+					      char *buf, size_t buflen)
+{
+	int ret;
+	char *pos, *end;
+	size_t len;
+
+	pos = buf;
+	end = pos + buflen;
+
+	if (res < 0) {
+		if (strict)
+			return 0;
+		len = os_strlcpy(buf, "WPA-PSK WPA-EAP IEEE8021X WPA-NONE "
+				 "NONE", buflen);
+		if (len >= buflen)
+			return -1;
+		return len;
+	}
+
+	ret = os_snprintf(pos, end - pos, "NONE IEEE8021X");
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2)) {
+		ret = os_snprintf(pos, end - pos, " WPA-EAP");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+		ret = os_snprintf(pos, end - pos, " WPA-PSK");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (capa->key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE) {
+		ret = os_snprintf(pos, end - pos, " WPA-NONE");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	return pos - buf;
+}
+
+
+static int ctrl_iface_get_capability_proto(int res, char *strict,
+					   struct wpa_driver_capa *capa,
+					   char *buf, size_t buflen)
+{
+	int ret, first = 1;
+	char *pos, *end;
+	size_t len;
+
+	pos = buf;
+	end = pos + buflen;
+
+	if (res < 0) {
+		if (strict)
+			return 0;
+		len = os_strlcpy(buf, "RSN WPA", buflen);
+		if (len >= buflen)
+			return -1;
+		return len;
+	}
+
+	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+			      WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+		ret = os_snprintf(pos, end - pos, "%sRSN", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->key_mgmt & (WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+			      WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK)) {
+		ret = os_snprintf(pos, end - pos, "%sWPA", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	return pos - buf;
+}
+
+
+static int ctrl_iface_get_capability_auth_alg(int res, char *strict,
+					      struct wpa_driver_capa *capa,
+					      char *buf, size_t buflen)
+{
+	int ret, first = 1;
+	char *pos, *end;
+	size_t len;
+
+	pos = buf;
+	end = pos + buflen;
+
+	if (res < 0) {
+		if (strict)
+			return 0;
+		len = os_strlcpy(buf, "OPEN SHARED LEAP", buflen);
+		if (len >= buflen)
+			return -1;
+		return len;
+	}
+
+	if (capa->auth & (WPA_DRIVER_AUTH_OPEN)) {
+		ret = os_snprintf(pos, end - pos, "%sOPEN", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->auth & (WPA_DRIVER_AUTH_SHARED)) {
+		ret = os_snprintf(pos, end - pos, "%sSHARED",
+				  first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	if (capa->auth & (WPA_DRIVER_AUTH_LEAP)) {
+		ret = os_snprintf(pos, end - pos, "%sLEAP", first ? "" : " ");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		first = 0;
+	}
+
+	return pos - buf;
+}
+
+
+static int ctrl_iface_get_capability_channels(struct wpa_supplicant *wpa_s,
+					      char *buf, size_t buflen)
+{
+	struct hostapd_channel_data *chnl;
+	int ret, i, j;
+	char *pos, *end, *hmode;
+
+	pos = buf;
+	end = pos + buflen;
+
+	for (j = 0; j < wpa_s->hw.num_modes; j++) {
+		switch (wpa_s->hw.modes[j].mode) {
+		case HOSTAPD_MODE_IEEE80211B:
+			hmode = "B";
+			break;
+		case HOSTAPD_MODE_IEEE80211G:
+			hmode = "G";
+			break;
+		case HOSTAPD_MODE_IEEE80211A:
+			hmode = "A";
+			break;
+		case HOSTAPD_MODE_IEEE80211AD:
+			hmode = "AD";
+			break;
+		default:
+			continue;
+		}
+		ret = os_snprintf(pos, end - pos, "Mode[%s] Channels:", hmode);
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+		chnl = wpa_s->hw.modes[j].channels;
+		for (i = 0; i < wpa_s->hw.modes[j].num_channels; i++) {
+			if (chnl[i].flag & HOSTAPD_CHAN_DISABLED)
+				continue;
+			ret = os_snprintf(pos, end - pos, " %d", chnl[i].chan);
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_get_capability(
+	struct wpa_supplicant *wpa_s, const char *_field, char *buf,
+	size_t buflen)
+{
+	struct wpa_driver_capa capa;
+	int res;
+	char *strict;
+	char field[30];
+	size_t len;
+
+	/* Determine whether or not strict checking was requested */
+	len = os_strlcpy(field, _field, sizeof(field));
+	if (len >= sizeof(field))
+		return -1;
+	strict = os_strchr(field, ' ');
+	if (strict != NULL) {
+		*strict++ = '\0';
+		if (os_strcmp(strict, "strict") != 0)
+			return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: GET_CAPABILITY '%s' %s",
+		field, strict ? strict : "");
+
+	if (os_strcmp(field, "eap") == 0) {
+		return eap_get_names(buf, buflen);
+	}
+
+	res = wpa_drv_get_capa(wpa_s, &capa);
+
+	if (os_strcmp(field, "pairwise") == 0)
+		return ctrl_iface_get_capability_pairwise(res, strict, &capa,
+							  buf, buflen);
+
+	if (os_strcmp(field, "group") == 0)
+		return ctrl_iface_get_capability_group(res, strict, &capa,
+						       buf, buflen);
+
+	if (os_strcmp(field, "key_mgmt") == 0)
+		return ctrl_iface_get_capability_key_mgmt(res, strict, &capa,
+							  buf, buflen);
+
+	if (os_strcmp(field, "proto") == 0)
+		return ctrl_iface_get_capability_proto(res, strict, &capa,
+						       buf, buflen);
+
+	if (os_strcmp(field, "auth_alg") == 0)
+		return ctrl_iface_get_capability_auth_alg(res, strict, &capa,
+							  buf, buflen);
+
+	if (os_strcmp(field, "channels") == 0)
+		return ctrl_iface_get_capability_channels(wpa_s, buf, buflen);
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown GET_CAPABILITY field '%s'",
+		   field);
+
+	return -1;
+}
+
+
+#ifdef CONFIG_INTERWORKING
+static char * anqp_add_hex(char *pos, char *end, const char *title,
+			   struct wpabuf *data)
+{
+	char *start = pos;
+	size_t i;
+	int ret;
+	const u8 *d;
+
+	if (data == NULL)
+		return start;
+
+	ret = os_snprintf(pos, end - pos, "%s=", title);
+	if (ret < 0 || ret >= end - pos)
+		return start;
+	pos += ret;
+
+	d = wpabuf_head_u8(data);
+	for (i = 0; i < wpabuf_len(data); i++) {
+		ret = os_snprintf(pos, end - pos, "%02x", *d++);
+		if (ret < 0 || ret >= end - pos)
+			return start;
+		pos += ret;
+	}
+
+	ret = os_snprintf(pos, end - pos, "\n");
+	if (ret < 0 || ret >= end - pos)
+		return start;
+	pos += ret;
+
+	return pos;
+}
+#endif /* CONFIG_INTERWORKING */
+
+
+static int print_bss_info(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+			  unsigned long mask, char *buf, size_t buflen)
+{
+	size_t i;
+	int ret;
+	char *pos, *end;
+	const u8 *ie, *ie2;
+
+	pos = buf;
+	end = buf + buflen;
+
+	if (mask & WPA_BSS_MASK_ID) {
+		ret = os_snprintf(pos, end - pos, "id=%u\n", bss->id);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_BSSID) {
+		ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n",
+				  MAC2STR(bss->bssid));
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_FREQ) {
+		ret = os_snprintf(pos, end - pos, "freq=%d\n", bss->freq);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_BEACON_INT) {
+		ret = os_snprintf(pos, end - pos, "beacon_int=%d\n",
+				  bss->beacon_int);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_CAPABILITIES) {
+		ret = os_snprintf(pos, end - pos, "capabilities=0x%04x\n",
+				  bss->caps);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_QUAL) {
+		ret = os_snprintf(pos, end - pos, "qual=%d\n", bss->qual);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_NOISE) {
+		ret = os_snprintf(pos, end - pos, "noise=%d\n", bss->noise);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_LEVEL) {
+		ret = os_snprintf(pos, end - pos, "level=%d\n", bss->level);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_TSF) {
+		ret = os_snprintf(pos, end - pos, "tsf=%016llu\n",
+				  (unsigned long long) bss->tsf);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_AGE) {
+		struct os_time now;
+
+		os_get_time(&now);
+		ret = os_snprintf(pos, end - pos, "age=%d\n",
+				  (int) (now.sec - bss->last_update.sec));
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_IE) {
+		ret = os_snprintf(pos, end - pos, "ie=");
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+
+		ie = (const u8 *) (bss + 1);
+		for (i = 0; i < bss->ie_len; i++) {
+			ret = os_snprintf(pos, end - pos, "%02x", *ie++);
+			if (ret < 0 || ret >= end - pos)
+				return 0;
+			pos += ret;
+		}
+
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_FLAGS) {
+		ret = os_snprintf(pos, end - pos, "flags=");
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+
+		ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+		if (ie)
+			pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie,
+						    2 + ie[1]);
+		ie2 = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+		if (ie2)
+			pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2,
+						    2 + ie2[1]);
+		pos = wpa_supplicant_wps_ie_txt(wpa_s, pos, end, bss);
+		if (!ie && !ie2 && bss->caps & IEEE80211_CAP_PRIVACY) {
+			ret = os_snprintf(pos, end - pos, "[WEP]");
+			if (ret < 0 || ret >= end - pos)
+				return 0;
+			pos += ret;
+		}
+		if (bss->caps & IEEE80211_CAP_IBSS) {
+			ret = os_snprintf(pos, end - pos, "[IBSS]");
+			if (ret < 0 || ret >= end - pos)
+				return 0;
+			pos += ret;
+		}
+		if (bss->caps & IEEE80211_CAP_ESS) {
+			ret = os_snprintf(pos, end - pos, "[ESS]");
+			if (ret < 0 || ret >= end - pos)
+				return 0;
+			pos += ret;
+		}
+		if (wpa_bss_get_vendor_ie(bss, P2P_IE_VENDOR_TYPE)) {
+			ret = os_snprintf(pos, end - pos, "[P2P]");
+			if (ret < 0 || ret >= end - pos)
+				return 0;
+			pos += ret;
+		}
+#ifdef CONFIG_HS20
+		if (wpa_bss_get_vendor_ie(bss, HS20_IE_VENDOR_TYPE)) {
+			ret = os_snprintf(pos, end - pos, "[HS20]");
+			if (ret < 0 || ret >= end - pos)
+				return -1;
+			pos += ret;
+		}
+#endif /* CONFIG_HS20 */
+
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+	if (mask & WPA_BSS_MASK_SSID) {
+		ret = os_snprintf(pos, end - pos, "ssid=%s\n",
+				  wpa_ssid_txt(bss->ssid, bss->ssid_len));
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+
+#ifdef CONFIG_WPS
+	if (mask & WPA_BSS_MASK_WPS_SCAN) {
+		ie = (const u8 *) (bss + 1);
+		ret = wpas_wps_scan_result_text(ie, bss->ie_len, pos, end);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+	if (mask & WPA_BSS_MASK_P2P_SCAN) {
+		ie = (const u8 *) (bss + 1);
+		ret = wpas_p2p_scan_result_text(ie, bss->ie_len, pos, end);
+		if (ret < 0 || ret >= end - pos)
+			return 0;
+		pos += ret;
+	}
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WIFI_DISPLAY
+	if (mask & WPA_BSS_MASK_WIFI_DISPLAY) {
+		struct wpabuf *wfd;
+		ie = (const u8 *) (bss + 1);
+		wfd = ieee802_11_vendor_ie_concat(ie, bss->ie_len,
+						  WFD_IE_VENDOR_TYPE);
+		if (wfd) {
+			ret = os_snprintf(pos, end - pos, "wfd_subelems=");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+
+			pos += wpa_snprintf_hex(pos, end - pos,
+						wpabuf_head(wfd),
+						wpabuf_len(wfd));
+			wpabuf_free(wfd);
+
+			ret = os_snprintf(pos, end - pos, "\n");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+	}
+#endif /* CONFIG_WIFI_DISPLAY */
+
+#ifdef CONFIG_INTERWORKING
+	if ((mask & WPA_BSS_MASK_INTERNETW) && bss->anqp) {
+		struct wpa_bss_anqp *anqp = bss->anqp;
+		pos = anqp_add_hex(pos, end, "anqp_venue_name",
+				   anqp->venue_name);
+		pos = anqp_add_hex(pos, end, "anqp_network_auth_type",
+				   anqp->network_auth_type);
+		pos = anqp_add_hex(pos, end, "anqp_roaming_consortium",
+				   anqp->roaming_consortium);
+		pos = anqp_add_hex(pos, end, "anqp_ip_addr_type_availability",
+				   anqp->ip_addr_type_availability);
+		pos = anqp_add_hex(pos, end, "anqp_nai_realm",
+				   anqp->nai_realm);
+		pos = anqp_add_hex(pos, end, "anqp_3gpp", anqp->anqp_3gpp);
+		pos = anqp_add_hex(pos, end, "anqp_domain_name",
+				   anqp->domain_name);
+#ifdef CONFIG_HS20
+		pos = anqp_add_hex(pos, end, "hs20_operator_friendly_name",
+				   anqp->hs20_operator_friendly_name);
+		pos = anqp_add_hex(pos, end, "hs20_wan_metrics",
+				   anqp->hs20_wan_metrics);
+		pos = anqp_add_hex(pos, end, "hs20_connection_capability",
+				   anqp->hs20_connection_capability);
+#endif /* CONFIG_HS20 */
+	}
+#endif /* CONFIG_INTERWORKING */
+
+	return pos - buf;
+}
+
+
+static int wpa_supplicant_ctrl_iface_bss(struct wpa_supplicant *wpa_s,
+					 const char *cmd, char *buf,
+					 size_t buflen)
+{
+	u8 bssid[ETH_ALEN];
+	size_t i;
+	struct wpa_bss *bss;
+	struct wpa_bss *bsslast = NULL;
+	struct dl_list *next;
+	int ret = 0;
+	int len;
+	char *ctmp;
+	unsigned long mask = WPA_BSS_MASK_ALL;
+
+	if (os_strncmp(cmd, "RANGE=", 6) == 0) {
+		if (os_strncmp(cmd + 6, "ALL", 3) == 0) {
+			bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss,
+					    list_id);
+			bsslast = dl_list_last(&wpa_s->bss_id, struct wpa_bss,
+					       list_id);
+		} else { /* N1-N2 */
+			unsigned int id1, id2;
+
+			if ((ctmp = os_strchr(cmd + 6, '-')) == NULL) {
+				wpa_printf(MSG_INFO, "Wrong BSS range "
+					   "format");
+				return 0;
+			}
+
+			id1 = atoi(cmd + 6);
+			bss = wpa_bss_get_id(wpa_s, id1);
+			id2 = atoi(ctmp + 1);
+			if (id2 == 0)
+				bsslast = dl_list_last(&wpa_s->bss_id,
+						       struct wpa_bss,
+						       list_id);
+			else {
+				bsslast = wpa_bss_get_id(wpa_s, id2);
+				if (bsslast == NULL && bss && id2 > id1) {
+					struct wpa_bss *tmp = bss;
+					for (;;) {
+						next = tmp->list_id.next;
+						if (next == &wpa_s->bss_id)
+							break;
+						tmp = dl_list_entry(
+							next, struct wpa_bss,
+							list_id);
+						if (tmp->id > id2)
+							break;
+						bsslast = tmp;
+					}
+				}
+			}
+		}
+	} else if (os_strcmp(cmd, "FIRST") == 0)
+		bss = dl_list_first(&wpa_s->bss_id, struct wpa_bss, list_id);
+	else if (os_strncmp(cmd, "ID-", 3) == 0) {
+		i = atoi(cmd + 3);
+		bss = wpa_bss_get_id(wpa_s, i);
+	} else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
+		i = atoi(cmd + 5);
+		bss = wpa_bss_get_id(wpa_s, i);
+		if (bss) {
+			next = bss->list_id.next;
+			if (next == &wpa_s->bss_id)
+				bss = NULL;
+			else
+				bss = dl_list_entry(next, struct wpa_bss,
+						    list_id);
+		}
+#ifdef CONFIG_P2P
+	} else if (os_strncmp(cmd, "p2p_dev_addr=", 13) == 0) {
+		if (hwaddr_aton(cmd + 13, bssid) == 0)
+			bss = wpa_bss_get_p2p_dev_addr(wpa_s, bssid);
+		else
+			bss = NULL;
+#endif /* CONFIG_P2P */
+	} else if (hwaddr_aton(cmd, bssid) == 0)
+		bss = wpa_bss_get_bssid(wpa_s, bssid);
+	else {
+		struct wpa_bss *tmp;
+		i = atoi(cmd);
+		bss = NULL;
+		dl_list_for_each(tmp, &wpa_s->bss_id, struct wpa_bss, list_id)
+		{
+			if (i-- == 0) {
+				bss = tmp;
+				break;
+			}
+		}
+	}
+
+	if ((ctmp = os_strstr(cmd, "MASK=")) != NULL) {
+		mask = strtoul(ctmp + 5, NULL, 0x10);
+		if (mask == 0)
+			mask = WPA_BSS_MASK_ALL;
+	}
+
+	if (bss == NULL)
+		return 0;
+
+	if (bsslast == NULL)
+		bsslast = bss;
+	do {
+		len = print_bss_info(wpa_s, bss, mask, buf, buflen);
+		ret += len;
+		buf += len;
+		buflen -= len;
+		if (bss == bsslast)
+			break;
+		next = bss->list_id.next;
+		if (next == &wpa_s->bss_id)
+			break;
+		bss = dl_list_entry(next, struct wpa_bss, list_id);
+	} while (bss && len);
+
+	return ret;
+}
+
+
+static int wpa_supplicant_ctrl_iface_ap_scan(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int ap_scan = atoi(cmd);
+	return wpa_supplicant_set_ap_scan(wpa_s, ap_scan);
+}
+
+
+static int wpa_supplicant_ctrl_iface_scan_interval(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int scan_int = atoi(cmd);
+	return wpa_supplicant_set_scan_interval(wpa_s, scan_int);
+}
+
+
+static int wpa_supplicant_ctrl_iface_bss_expire_age(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int expire_age = atoi(cmd);
+	return wpa_supplicant_set_bss_expiration_age(wpa_s, expire_age);
+}
+
+
+static int wpa_supplicant_ctrl_iface_bss_expire_count(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int expire_count = atoi(cmd);
+	return wpa_supplicant_set_bss_expiration_count(wpa_s, expire_count);
+}
+
+
+static int wpa_supplicant_ctrl_iface_bss_flush(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int flush_age = atoi(cmd);
+
+	if (flush_age == 0)
+		wpa_bss_flush(wpa_s);
+	else
+		wpa_bss_flush_by_age(wpa_s, flush_age);
+	return 0;
+}
+
+
+static void wpa_supplicant_ctrl_iface_drop_sa(struct wpa_supplicant *wpa_s)
+{
+	wpa_printf(MSG_DEBUG, "Dropping SA without deauthentication");
+	/* MLME-DELETEKEYS.request */
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
+#ifdef CONFIG_IEEE80211W
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
+#endif /* CONFIG_IEEE80211W */
+
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, wpa_s->bssid, 0, 0, NULL, 0, NULL,
+			0);
+	/* MLME-SETPROTECTION.request(None) */
+	wpa_drv_mlme_setprotection(wpa_s, wpa_s->bssid,
+				   MLME_SETPROTECTION_PROTECT_TYPE_NONE,
+				   MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
+	wpa_sm_drop_sa(wpa_s->wpa);
+}
+
+
+static int wpa_supplicant_ctrl_iface_roam(struct wpa_supplicant *wpa_s,
+					  char *addr)
+{
+#ifdef CONFIG_NO_SCAN_PROCESSING
+	return -1;
+#else /* CONFIG_NO_SCAN_PROCESSING */
+	u8 bssid[ETH_ALEN];
+	struct wpa_bss *bss;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	if (hwaddr_aton(addr, bssid)) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: invalid "
+			   "address '%s'", addr);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM " MACSTR, MAC2STR(bssid));
+
+	bss = wpa_bss_get_bssid(wpa_s, bssid);
+	if (!bss) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: Target AP not found "
+			   "from BSS table");
+		return -1;
+	}
+
+	/*
+	 * TODO: Find best network configuration block from configuration to
+	 * allow roaming to other networks
+	 */
+
+	if (!ssid) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE ROAM: No network "
+			   "configuration known for the target AP");
+		return -1;
+	}
+
+	wpa_s->reassociate = 1;
+	wpa_supplicant_connect(wpa_s, bss, ssid);
+
+	return 0;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+}
+
+
+#ifdef CONFIG_P2P
+static int p2p_ctrl_find(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	unsigned int timeout = atoi(cmd);
+	enum p2p_discovery_type type = P2P_FIND_START_WITH_FULL;
+	u8 dev_id[ETH_ALEN], *_dev_id = NULL;
+	char *pos;
+	unsigned int search_delay;
+
+	if (os_strstr(cmd, "type=social"))
+		type = P2P_FIND_ONLY_SOCIAL;
+	else if (os_strstr(cmd, "type=progressive"))
+		type = P2P_FIND_PROGRESSIVE;
+
+	pos = os_strstr(cmd, "dev_id=");
+	if (pos) {
+		pos += 7;
+		if (hwaddr_aton(pos, dev_id))
+			return -1;
+		_dev_id = dev_id;
+	}
+
+	pos = os_strstr(cmd, "delay=");
+	if (pos) {
+		pos += 6;
+		search_delay = atoi(pos);
+	} else
+		search_delay = wpas_p2p_search_delay(wpa_s);
+
+	return wpas_p2p_find(wpa_s, timeout, type, 0, NULL, _dev_id,
+			     search_delay);
+}
+
+
+static int p2p_ctrl_connect(struct wpa_supplicant *wpa_s, char *cmd,
+			    char *buf, size_t buflen)
+{
+	u8 addr[ETH_ALEN];
+	char *pos, *pos2;
+	char *pin = NULL;
+	enum p2p_wps_method wps_method;
+	int new_pin;
+	int ret;
+	int persistent_group, persistent_id = -1;
+	int join;
+	int auth;
+	int automatic;
+	int go_intent = -1;
+	int freq = 0;
+	int pd;
+	int ht40;
+
+	/* <addr> <"pbc" | "pin" | PIN> [label|display|keypad]
+	 * [persistent|persistent=<network id>]
+	 * [join] [auth] [go_intent=<0..15>] [freq=<in MHz>] [provdisc]
+	 * [ht40] */
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+
+	pos = cmd + 17;
+	if (*pos != ' ')
+		return -1;
+	pos++;
+
+	persistent_group = os_strstr(pos, " persistent") != NULL;
+	pos2 = os_strstr(pos, " persistent=");
+	if (pos2) {
+		struct wpa_ssid *ssid;
+		persistent_id = atoi(pos2 + 12);
+		ssid = wpa_config_get_network(wpa_s->conf, persistent_id);
+		if (ssid == NULL || ssid->disabled != 2 ||
+		    ssid->mode != WPAS_MODE_P2P_GO) {
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find "
+				   "SSID id=%d for persistent P2P group (GO)",
+				   persistent_id);
+			return -1;
+		}
+	}
+	join = os_strstr(pos, " join") != NULL;
+	auth = os_strstr(pos, " auth") != NULL;
+	automatic = os_strstr(pos, " auto") != NULL;
+	pd = os_strstr(pos, " provdisc") != NULL;
+	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+
+	pos2 = os_strstr(pos, " go_intent=");
+	if (pos2) {
+		pos2 += 11;
+		go_intent = atoi(pos2);
+		if (go_intent < 0 || go_intent > 15)
+			return -1;
+	}
+
+	pos2 = os_strstr(pos, " freq=");
+	if (pos2) {
+		pos2 += 6;
+		freq = atoi(pos2);
+		if (freq <= 0)
+			return -1;
+	}
+
+	if (os_strncmp(pos, "pin", 3) == 0) {
+		/* Request random PIN (to be displayed) and enable the PIN */
+		wps_method = WPS_PIN_DISPLAY;
+	} else if (os_strncmp(pos, "pbc", 3) == 0) {
+		wps_method = WPS_PBC;
+	} else {
+		pin = pos;
+		pos = os_strchr(pin, ' ');
+		wps_method = WPS_PIN_KEYPAD;
+		if (pos) {
+			*pos++ = '\0';
+			if (os_strncmp(pos, "display", 7) == 0)
+				wps_method = WPS_PIN_DISPLAY;
+		}
+		if (!wps_pin_str_valid(pin)) {
+			os_memcpy(buf, "FAIL-INVALID-PIN\n", 17);
+			return 17;
+		}
+	}
+
+	new_pin = wpas_p2p_connect(wpa_s, addr, pin, wps_method,
+				   persistent_group, automatic, join,
+				   auth, go_intent, freq, persistent_id, pd,
+				   ht40);
+	if (new_pin == -2) {
+		os_memcpy(buf, "FAIL-CHANNEL-UNAVAILABLE\n", 25);
+		return 25;
+	}
+	if (new_pin == -3) {
+		os_memcpy(buf, "FAIL-CHANNEL-UNSUPPORTED\n", 25);
+		return 25;
+	}
+	if (new_pin < 0)
+		return -1;
+	if (wps_method == WPS_PIN_DISPLAY && pin == NULL) {
+		ret = os_snprintf(buf, buflen, "%08d", new_pin);
+		if (ret < 0 || (size_t) ret >= buflen)
+			return -1;
+		return ret;
+	}
+
+	os_memcpy(buf, "OK\n", 3);
+	return 3;
+}
+
+
+static int p2p_ctrl_listen(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	unsigned int timeout = atoi(cmd);
+	return wpas_p2p_listen(wpa_s, timeout);
+}
+
+
+static int p2p_ctrl_prov_disc(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 addr[ETH_ALEN];
+	char *pos;
+	enum wpas_p2p_prov_disc_use use = WPAS_P2P_PD_FOR_GO_NEG;
+
+	/* <addr> <config method> [join|auto] */
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+
+	pos = cmd + 17;
+	if (*pos != ' ')
+		return -1;
+	pos++;
+
+	if (os_strstr(pos, " join") != NULL)
+		use = WPAS_P2P_PD_FOR_JOIN;
+	else if (os_strstr(pos, " auto") != NULL)
+		use = WPAS_P2P_PD_AUTO;
+
+	return wpas_p2p_prov_disc(wpa_s, addr, pos, use);
+}
+
+
+static int p2p_get_passphrase(struct wpa_supplicant *wpa_s, char *buf,
+			      size_t buflen)
+{
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	if (ssid == NULL || ssid->mode != WPAS_MODE_P2P_GO ||
+	    ssid->passphrase == NULL)
+		return -1;
+
+	os_strlcpy(buf, ssid->passphrase, buflen);
+	return os_strlen(buf);
+}
+
+
+static int p2p_ctrl_serv_disc_req(struct wpa_supplicant *wpa_s, char *cmd,
+				  char *buf, size_t buflen)
+{
+	u64 ref;
+	int res;
+	u8 dst_buf[ETH_ALEN], *dst;
+	struct wpabuf *tlvs;
+	char *pos;
+	size_t len;
+
+	if (hwaddr_aton(cmd, dst_buf))
+		return -1;
+	dst = dst_buf;
+	if (dst[0] == 0 && dst[1] == 0 && dst[2] == 0 &&
+	    dst[3] == 0 && dst[4] == 0 && dst[5] == 0)
+		dst = NULL;
+	pos = cmd + 17;
+	if (*pos != ' ')
+		return -1;
+	pos++;
+
+	if (os_strncmp(pos, "upnp ", 5) == 0) {
+		u8 version;
+		pos += 5;
+		if (hexstr2bin(pos, &version, 1) < 0)
+			return -1;
+		pos += 2;
+		if (*pos != ' ')
+			return -1;
+		pos++;
+		ref = wpas_p2p_sd_request_upnp(wpa_s, dst, version, pos);
+#ifdef CONFIG_WIFI_DISPLAY
+	} else if (os_strncmp(pos, "wifi-display ", 13) == 0) {
+		ref = wpas_p2p_sd_request_wifi_display(wpa_s, dst, pos + 13);
+#endif /* CONFIG_WIFI_DISPLAY */
+	} else {
+		len = os_strlen(pos);
+		if (len & 1)
+			return -1;
+		len /= 2;
+		tlvs = wpabuf_alloc(len);
+		if (tlvs == NULL)
+			return -1;
+		if (hexstr2bin(pos, wpabuf_put(tlvs, len), len) < 0) {
+			wpabuf_free(tlvs);
+			return -1;
+		}
+
+		ref = wpas_p2p_sd_request(wpa_s, dst, tlvs);
+		wpabuf_free(tlvs);
+	}
+	if (ref == 0)
+		return -1;
+	res = os_snprintf(buf, buflen, "%llx", (long long unsigned) ref);
+	if (res < 0 || (unsigned) res >= buflen)
+		return -1;
+	return res;
+}
+
+
+static int p2p_ctrl_serv_disc_cancel_req(struct wpa_supplicant *wpa_s,
+					 char *cmd)
+{
+	long long unsigned val;
+	u64 req;
+	if (sscanf(cmd, "%llx", &val) != 1)
+		return -1;
+	req = val;
+	return wpas_p2p_sd_cancel_request(wpa_s, req);
+}
+
+
+static int p2p_ctrl_serv_disc_resp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int freq;
+	u8 dst[ETH_ALEN];
+	u8 dialog_token;
+	struct wpabuf *resp_tlvs;
+	char *pos, *pos2;
+	size_t len;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+	freq = atoi(cmd);
+	if (freq == 0)
+		return -1;
+
+	if (hwaddr_aton(pos, dst))
+		return -1;
+	pos += 17;
+	if (*pos != ' ')
+		return -1;
+	pos++;
+
+	pos2 = os_strchr(pos, ' ');
+	if (pos2 == NULL)
+		return -1;
+	*pos2++ = '\0';
+	dialog_token = atoi(pos);
+
+	len = os_strlen(pos2);
+	if (len & 1)
+		return -1;
+	len /= 2;
+	resp_tlvs = wpabuf_alloc(len);
+	if (resp_tlvs == NULL)
+		return -1;
+	if (hexstr2bin(pos2, wpabuf_put(resp_tlvs, len), len) < 0) {
+		wpabuf_free(resp_tlvs);
+		return -1;
+	}
+
+	wpas_p2p_sd_response(wpa_s, freq, dst, dialog_token, resp_tlvs);
+	wpabuf_free(resp_tlvs);
+	return 0;
+}
+
+
+static int p2p_ctrl_serv_disc_external(struct wpa_supplicant *wpa_s,
+				       char *cmd)
+{
+	if (os_strcmp(cmd, "0") && os_strcmp(cmd, "1"))
+		return -1;
+	wpa_s->p2p_sd_over_ctrl_iface = atoi(cmd);
+	return 0;
+}
+
+
+static int p2p_ctrl_service_add_bonjour(struct wpa_supplicant *wpa_s,
+					char *cmd)
+{
+	char *pos;
+	size_t len;
+	struct wpabuf *query, *resp;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	len = os_strlen(cmd);
+	if (len & 1)
+		return -1;
+	len /= 2;
+	query = wpabuf_alloc(len);
+	if (query == NULL)
+		return -1;
+	if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
+		wpabuf_free(query);
+		return -1;
+	}
+
+	len = os_strlen(pos);
+	if (len & 1) {
+		wpabuf_free(query);
+		return -1;
+	}
+	len /= 2;
+	resp = wpabuf_alloc(len);
+	if (resp == NULL) {
+		wpabuf_free(query);
+		return -1;
+	}
+	if (hexstr2bin(pos, wpabuf_put(resp, len), len) < 0) {
+		wpabuf_free(query);
+		wpabuf_free(resp);
+		return -1;
+	}
+
+	if (wpas_p2p_service_add_bonjour(wpa_s, query, resp) < 0) {
+		wpabuf_free(query);
+		wpabuf_free(resp);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int p2p_ctrl_service_add_upnp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos;
+	u8 version;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	if (hexstr2bin(cmd, &version, 1) < 0)
+		return -1;
+
+	return wpas_p2p_service_add_upnp(wpa_s, version, pos);
+}
+
+
+static int p2p_ctrl_service_add(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	if (os_strcmp(cmd, "bonjour") == 0)
+		return p2p_ctrl_service_add_bonjour(wpa_s, pos);
+	if (os_strcmp(cmd, "upnp") == 0)
+		return p2p_ctrl_service_add_upnp(wpa_s, pos);
+	wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
+	return -1;
+}
+
+
+static int p2p_ctrl_service_del_bonjour(struct wpa_supplicant *wpa_s,
+					char *cmd)
+{
+	size_t len;
+	struct wpabuf *query;
+	int ret;
+
+	len = os_strlen(cmd);
+	if (len & 1)
+		return -1;
+	len /= 2;
+	query = wpabuf_alloc(len);
+	if (query == NULL)
+		return -1;
+	if (hexstr2bin(cmd, wpabuf_put(query, len), len) < 0) {
+		wpabuf_free(query);
+		return -1;
+	}
+
+	ret = wpas_p2p_service_del_bonjour(wpa_s, query);
+	wpabuf_free(query);
+	return ret;
+}
+
+
+static int p2p_ctrl_service_del_upnp(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos;
+	u8 version;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	if (hexstr2bin(cmd, &version, 1) < 0)
+		return -1;
+
+	return wpas_p2p_service_del_upnp(wpa_s, version, pos);
+}
+
+
+static int p2p_ctrl_service_del(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos;
+
+	pos = os_strchr(cmd, ' ');
+	if (pos == NULL)
+		return -1;
+	*pos++ = '\0';
+
+	if (os_strcmp(cmd, "bonjour") == 0)
+		return p2p_ctrl_service_del_bonjour(wpa_s, pos);
+	if (os_strcmp(cmd, "upnp") == 0)
+		return p2p_ctrl_service_del_upnp(wpa_s, pos);
+	wpa_printf(MSG_DEBUG, "Unknown service '%s'", cmd);
+	return -1;
+}
+
+
+static int p2p_ctrl_reject(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 addr[ETH_ALEN];
+
+	/* <addr> */
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+
+	return wpas_p2p_reject(wpa_s, addr);
+}
+
+
+static int p2p_ctrl_invite_persistent(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos;
+	int id;
+	struct wpa_ssid *ssid;
+	u8 *_peer = NULL, peer[ETH_ALEN];
+	int freq = 0;
+	int ht40;
+
+	id = atoi(cmd);
+	pos = os_strstr(cmd, " peer=");
+	if (pos) {
+		pos += 6;
+		if (hwaddr_aton(pos, peer))
+			return -1;
+		_peer = peer;
+	}
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL || ssid->disabled != 2) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
+			   "for persistent P2P group",
+			   id);
+		return -1;
+	}
+
+	pos = os_strstr(cmd, " freq=");
+	if (pos) {
+		pos += 6;
+		freq = atoi(pos);
+		if (freq <= 0)
+			return -1;
+	}
+
+	ht40 = (os_strstr(cmd, " ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+
+	return wpas_p2p_invite(wpa_s, _peer, ssid, NULL, freq, ht40);
+}
+
+
+static int p2p_ctrl_invite_group(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos;
+	u8 peer[ETH_ALEN], go_dev_addr[ETH_ALEN], *go_dev = NULL;
+
+	pos = os_strstr(cmd, " peer=");
+	if (!pos)
+		return -1;
+
+	*pos = '\0';
+	pos += 6;
+	if (hwaddr_aton(pos, peer)) {
+		wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'", pos);
+		return -1;
+	}
+
+	pos = os_strstr(pos, " go_dev_addr=");
+	if (pos) {
+		pos += 13;
+		if (hwaddr_aton(pos, go_dev_addr)) {
+			wpa_printf(MSG_DEBUG, "P2P: Invalid MAC address '%s'",
+				   pos);
+			return -1;
+		}
+		go_dev = go_dev_addr;
+	}
+
+	return wpas_p2p_invite_group(wpa_s, cmd, peer, go_dev);
+}
+
+
+static int p2p_ctrl_invite(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	if (os_strncmp(cmd, "persistent=", 11) == 0)
+		return p2p_ctrl_invite_persistent(wpa_s, cmd + 11);
+	if (os_strncmp(cmd, "group=", 6) == 0)
+		return p2p_ctrl_invite_group(wpa_s, cmd + 6);
+
+	return -1;
+}
+
+
+static int p2p_ctrl_group_add_persistent(struct wpa_supplicant *wpa_s,
+					 char *cmd, int freq, int ht40)
+{
+	int id;
+	struct wpa_ssid *ssid;
+
+	id = atoi(cmd);
+	ssid = wpa_config_get_network(wpa_s->conf, id);
+	if (ssid == NULL || ssid->disabled != 2) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Could not find SSID id=%d "
+			   "for persistent P2P group",
+			   id);
+		return -1;
+	}
+
+	return wpas_p2p_group_add_persistent(wpa_s, ssid, 0, freq, ht40);
+}
+
+
+static int p2p_ctrl_group_add(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int freq = 0, ht40;
+	char *pos;
+
+	pos = os_strstr(cmd, "freq=");
+	if (pos)
+		freq = atoi(pos + 5);
+
+	ht40 = (os_strstr(cmd, "ht40") != NULL) || wpa_s->conf->p2p_go_ht40;
+
+	if (os_strncmp(cmd, "persistent=", 11) == 0)
+		return p2p_ctrl_group_add_persistent(wpa_s, cmd + 11, freq,
+						     ht40);
+	if (os_strcmp(cmd, "persistent") == 0 ||
+	    os_strncmp(cmd, "persistent ", 11) == 0)
+		return wpas_p2p_group_add(wpa_s, 1, freq, ht40);
+	if (os_strncmp(cmd, "freq=", 5) == 0)
+		return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+	if (ht40)
+		return wpas_p2p_group_add(wpa_s, 0, freq, ht40);
+
+	wpa_printf(MSG_DEBUG, "CTRL: Invalid P2P_GROUP_ADD parameters '%s'",
+		   cmd);
+	return -1;
+}
+
+
+static int p2p_ctrl_peer(struct wpa_supplicant *wpa_s, char *cmd,
+			 char *buf, size_t buflen)
+{
+	u8 addr[ETH_ALEN], *addr_ptr;
+	int next, res;
+	const struct p2p_peer_info *info;
+	char *pos, *end;
+	char devtype[WPS_DEV_TYPE_BUFSIZE];
+	struct wpa_ssid *ssid;
+	size_t i;
+
+	if (!wpa_s->global->p2p)
+		return -1;
+
+	if (os_strcmp(cmd, "FIRST") == 0) {
+		addr_ptr = NULL;
+		next = 0;
+	} else if (os_strncmp(cmd, "NEXT-", 5) == 0) {
+		if (hwaddr_aton(cmd + 5, addr) < 0)
+			return -1;
+		addr_ptr = addr;
+		next = 1;
+	} else {
+		if (hwaddr_aton(cmd, addr) < 0)
+			return -1;
+		addr_ptr = addr;
+		next = 0;
+	}
+
+	info = p2p_get_peer_info(wpa_s->global->p2p, addr_ptr, next);
+	if (info == NULL)
+		return -1;
+
+	pos = buf;
+	end = buf + buflen;
+
+	res = os_snprintf(pos, end - pos, MACSTR "\n"
+			  "pri_dev_type=%s\n"
+			  "device_name=%s\n"
+			  "manufacturer=%s\n"
+			  "model_name=%s\n"
+			  "model_number=%s\n"
+			  "serial_number=%s\n"
+			  "config_methods=0x%x\n"
+			  "dev_capab=0x%x\n"
+			  "group_capab=0x%x\n"
+			  "level=%d\n",
+			  MAC2STR(info->p2p_device_addr),
+			  wps_dev_type_bin2str(info->pri_dev_type,
+					       devtype, sizeof(devtype)),
+			  info->device_name,
+			  info->manufacturer,
+			  info->model_name,
+			  info->model_number,
+			  info->serial_number,
+			  info->config_methods,
+			  info->dev_capab,
+			  info->group_capab,
+			  info->level);
+	if (res < 0 || res >= end - pos)
+		return pos - buf;
+	pos += res;
+
+	for (i = 0; i < info->wps_sec_dev_type_list_len / WPS_DEV_TYPE_LEN; i++)
+	{
+		const u8 *t;
+		t = &info->wps_sec_dev_type_list[i * WPS_DEV_TYPE_LEN];
+		res = os_snprintf(pos, end - pos, "sec_dev_type=%s\n",
+				  wps_dev_type_bin2str(t, devtype,
+						       sizeof(devtype)));
+		if (res < 0 || res >= end - pos)
+			return pos - buf;
+		pos += res;
+	}
+
+	ssid = wpas_p2p_get_persistent(wpa_s, info->p2p_device_addr, NULL, 0);
+	if (ssid) {
+		res = os_snprintf(pos, end - pos, "persistent=%d\n", ssid->id);
+		if (res < 0 || res >= end - pos)
+			return pos - buf;
+		pos += res;
+	}
+
+	res = p2p_get_peer_info_txt(info, pos, end - pos);
+	if (res < 0)
+		return pos - buf;
+	pos += res;
+
+	return pos - buf;
+}
+
+
+static int p2p_ctrl_disallow_freq(struct wpa_supplicant *wpa_s,
+				  const char *param)
+{
+	struct wpa_freq_range *freq = NULL, *n;
+	unsigned int count = 0, i;
+	const char *pos, *pos2, *pos3;
+
+	if (wpa_s->global->p2p == NULL)
+		return -1;
+
+	/*
+	 * param includes comma separated frequency range.
+	 * For example: 2412-2432,2462,5000-6000
+	 */
+	pos = param;
+	while (pos && pos[0]) {
+		n = os_realloc_array(freq, count + 1,
+				     sizeof(struct wpa_freq_range));
+		if (n == NULL) {
+			os_free(freq);
+			return -1;
+		}
+		freq = n;
+		freq[count].min = atoi(pos);
+		pos2 = os_strchr(pos, '-');
+		pos3 = os_strchr(pos, ',');
+		if (pos2 && (!pos3 || pos2 < pos3)) {
+			pos2++;
+			freq[count].max = atoi(pos2);
+		} else
+			freq[count].max = freq[count].min;
+		pos = pos3;
+		if (pos)
+			pos++;
+		count++;
+	}
+
+	for (i = 0; i < count; i++) {
+		wpa_printf(MSG_DEBUG, "P2P: Disallowed frequency range %u-%u",
+			   freq[i].min, freq[i].max);
+	}
+
+	os_free(wpa_s->global->p2p_disallow_freq);
+	wpa_s->global->p2p_disallow_freq = freq;
+	wpa_s->global->num_p2p_disallow_freq = count;
+	wpas_p2p_update_channel_list(wpa_s);
+	return 0;
+}
+
+
+static int p2p_ctrl_set(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *param;
+
+	if (wpa_s->global->p2p == NULL)
+		return -1;
+
+	param = os_strchr(cmd, ' ');
+	if (param == NULL)
+		return -1;
+	*param++ = '\0';
+
+	if (os_strcmp(cmd, "discoverability") == 0) {
+		p2p_set_client_discoverability(wpa_s->global->p2p,
+					       atoi(param));
+		return 0;
+	}
+
+	if (os_strcmp(cmd, "managed") == 0) {
+		p2p_set_managed_oper(wpa_s->global->p2p, atoi(param));
+		return 0;
+	}
+
+	if (os_strcmp(cmd, "listen_channel") == 0) {
+		return p2p_set_listen_channel(wpa_s->global->p2p, 81,
+					      atoi(param));
+	}
+
+	if (os_strcmp(cmd, "ssid_postfix") == 0) {
+		return p2p_set_ssid_postfix(wpa_s->global->p2p, (u8 *) param,
+					    os_strlen(param));
+	}
+
+	if (os_strcmp(cmd, "noa") == 0) {
+		char *pos;
+		int count, start, duration;
+		/* GO NoA parameters: count,start_offset(ms),duration(ms) */
+		count = atoi(param);
+		pos = os_strchr(param, ',');
+		if (pos == NULL)
+			return -1;
+		pos++;
+		start = atoi(pos);
+		pos = os_strchr(pos, ',');
+		if (pos == NULL)
+			return -1;
+		pos++;
+		duration = atoi(pos);
+		if (count < 0 || count > 255 || start < 0 || duration < 0)
+			return -1;
+		if (count == 0 && duration > 0)
+			return -1;
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: P2P_SET GO NoA: count=%d "
+			   "start=%d duration=%d", count, start, duration);
+		return wpas_p2p_set_noa(wpa_s, count, start, duration);
+	}
+
+	if (os_strcmp(cmd, "ps") == 0)
+		return wpa_drv_set_p2p_powersave(wpa_s, atoi(param), -1, -1);
+
+	if (os_strcmp(cmd, "oppps") == 0)
+		return wpa_drv_set_p2p_powersave(wpa_s, -1, atoi(param), -1);
+
+	if (os_strcmp(cmd, "ctwindow") == 0)
+		return wpa_drv_set_p2p_powersave(wpa_s, -1, -1, atoi(param));
+
+	if (os_strcmp(cmd, "disabled") == 0) {
+		wpa_s->global->p2p_disabled = atoi(param);
+		wpa_printf(MSG_DEBUG, "P2P functionality %s",
+			   wpa_s->global->p2p_disabled ?
+			   "disabled" : "enabled");
+		if (wpa_s->global->p2p_disabled) {
+			wpas_p2p_stop_find(wpa_s);
+			os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+			p2p_flush(wpa_s->global->p2p);
+		}
+		return 0;
+	}
+
+	if (os_strcmp(cmd, "conc_pref") == 0) {
+		if (os_strcmp(param, "sta") == 0)
+			wpa_s->global->conc_pref = WPA_CONC_PREF_STA;
+		else if (os_strcmp(param, "p2p") == 0)
+			wpa_s->global->conc_pref = WPA_CONC_PREF_P2P;
+		else {
+			wpa_printf(MSG_INFO, "Invalid conc_pref value");
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "Single channel concurrency preference: "
+			   "%s", param);
+		return 0;
+	}
+
+	if (os_strcmp(cmd, "force_long_sd") == 0) {
+		wpa_s->force_long_sd = atoi(param);
+		return 0;
+	}
+
+	if (os_strcmp(cmd, "peer_filter") == 0) {
+		u8 addr[ETH_ALEN];
+		if (hwaddr_aton(param, addr))
+			return -1;
+		p2p_set_peer_filter(wpa_s->global->p2p, addr);
+		return 0;
+	}
+
+	if (os_strcmp(cmd, "cross_connect") == 0)
+		return wpas_p2p_set_cross_connect(wpa_s, atoi(param));
+
+	if (os_strcmp(cmd, "go_apsd") == 0) {
+		if (os_strcmp(param, "disable") == 0)
+			wpa_s->set_ap_uapsd = 0;
+		else {
+			wpa_s->set_ap_uapsd = 1;
+			wpa_s->ap_uapsd = atoi(param);
+		}
+		return 0;
+	}
+
+	if (os_strcmp(cmd, "client_apsd") == 0) {
+		if (os_strcmp(param, "disable") == 0)
+			wpa_s->set_sta_uapsd = 0;
+		else {
+			int be, bk, vi, vo;
+			char *pos;
+			/* format: BE,BK,VI,VO;max SP Length */
+			be = atoi(param);
+			pos = os_strchr(param, ',');
+			if (pos == NULL)
+				return -1;
+			pos++;
+			bk = atoi(pos);
+			pos = os_strchr(pos, ',');
+			if (pos == NULL)
+				return -1;
+			pos++;
+			vi = atoi(pos);
+			pos = os_strchr(pos, ',');
+			if (pos == NULL)
+				return -1;
+			pos++;
+			vo = atoi(pos);
+			/* ignore max SP Length for now */
+
+			wpa_s->set_sta_uapsd = 1;
+			wpa_s->sta_uapsd = 0;
+			if (be)
+				wpa_s->sta_uapsd |= BIT(0);
+			if (bk)
+				wpa_s->sta_uapsd |= BIT(1);
+			if (vi)
+				wpa_s->sta_uapsd |= BIT(2);
+			if (vo)
+				wpa_s->sta_uapsd |= BIT(3);
+		}
+		return 0;
+	}
+
+	if (os_strcmp(cmd, "disallow_freq") == 0)
+		return p2p_ctrl_disallow_freq(wpa_s, param);
+
+	if (os_strcmp(cmd, "disc_int") == 0) {
+		int min_disc_int, max_disc_int, max_disc_tu;
+		char *pos;
+
+		pos = param;
+
+		min_disc_int = atoi(pos);
+		pos = os_strchr(pos, ' ');
+		if (pos == NULL)
+			return -1;
+		*pos++ = '\0';
+
+		max_disc_int = atoi(pos);
+		pos = os_strchr(pos, ' ');
+		if (pos == NULL)
+			return -1;
+		*pos++ = '\0';
+
+		max_disc_tu = atoi(pos);
+
+		return p2p_set_disc_int(wpa_s->global->p2p, min_disc_int,
+					max_disc_int, max_disc_tu);
+	}
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown P2P_SET field value '%s'",
+		   cmd);
+
+	return -1;
+}
+
+
+static int p2p_ctrl_presence_req(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos, *pos2;
+	unsigned int dur1 = 0, int1 = 0, dur2 = 0, int2 = 0;
+
+	if (cmd[0]) {
+		pos = os_strchr(cmd, ' ');
+		if (pos == NULL)
+			return -1;
+		*pos++ = '\0';
+		dur1 = atoi(cmd);
+
+		pos2 = os_strchr(pos, ' ');
+		if (pos2)
+			*pos2++ = '\0';
+		int1 = atoi(pos);
+	} else
+		pos2 = NULL;
+
+	if (pos2) {
+		pos = os_strchr(pos2, ' ');
+		if (pos == NULL)
+			return -1;
+		*pos++ = '\0';
+		dur2 = atoi(pos2);
+		int2 = atoi(pos);
+	}
+
+	return wpas_p2p_presence_req(wpa_s, dur1, int1, dur2, int2);
+}
+
+
+static int p2p_ctrl_ext_listen(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	char *pos;
+	unsigned int period = 0, interval = 0;
+
+	if (cmd[0]) {
+		pos = os_strchr(cmd, ' ');
+		if (pos == NULL)
+			return -1;
+		*pos++ = '\0';
+		period = atoi(cmd);
+		interval = atoi(pos);
+	}
+
+	return wpas_p2p_ext_listen(wpa_s, period, interval);
+}
+
+#endif /* CONFIG_P2P */
+
+
+#ifdef CONFIG_INTERWORKING
+static int ctrl_interworking_connect(struct wpa_supplicant *wpa_s, char *dst)
+{
+	u8 bssid[ETH_ALEN];
+	struct wpa_bss *bss;
+
+	if (hwaddr_aton(dst, bssid)) {
+		wpa_printf(MSG_DEBUG, "Invalid BSSID '%s'", dst);
+		return -1;
+	}
+
+	bss = wpa_bss_get_bssid(wpa_s, bssid);
+	if (bss == NULL) {
+		wpa_printf(MSG_DEBUG, "Could not find BSS " MACSTR,
+			   MAC2STR(bssid));
+		return -1;
+	}
+
+	return interworking_connect(wpa_s, bss);
+}
+
+
+static int get_anqp(struct wpa_supplicant *wpa_s, char *dst)
+{
+	u8 dst_addr[ETH_ALEN];
+	int used;
+	char *pos;
+#define MAX_ANQP_INFO_ID 100
+	u16 id[MAX_ANQP_INFO_ID];
+	size_t num_id = 0;
+
+	used = hwaddr_aton2(dst, dst_addr);
+	if (used < 0)
+		return -1;
+	pos = dst + used;
+	while (num_id < MAX_ANQP_INFO_ID) {
+		id[num_id] = atoi(pos);
+		if (id[num_id])
+			num_id++;
+		pos = os_strchr(pos + 1, ',');
+		if (pos == NULL)
+			break;
+		pos++;
+	}
+
+	if (num_id == 0)
+		return -1;
+
+	return anqp_send_req(wpa_s, dst_addr, id, num_id);
+}
+
+
+static int gas_request(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	u8 dst_addr[ETH_ALEN];
+	struct wpabuf *advproto, *query = NULL;
+	int used, ret = -1;
+	char *pos, *end;
+	size_t len;
+
+	used = hwaddr_aton2(cmd, dst_addr);
+	if (used < 0)
+		return -1;
+
+	pos = cmd + used;
+	while (*pos == ' ')
+		pos++;
+
+	/* Advertisement Protocol ID */
+	end = os_strchr(pos, ' ');
+	if (end)
+		len = end - pos;
+	else
+		len = os_strlen(pos);
+	if (len & 0x01)
+		return -1;
+	len /= 2;
+	if (len == 0)
+		return -1;
+	advproto = wpabuf_alloc(len);
+	if (advproto == NULL)
+		return -1;
+	if (hexstr2bin(pos, wpabuf_put(advproto, len), len) < 0)
+		goto fail;
+
+	if (end) {
+		/* Optional Query Request */
+		pos = end + 1;
+		while (*pos == ' ')
+			pos++;
+
+		len = os_strlen(pos);
+		if (len) {
+			if (len & 0x01)
+				goto fail;
+			len /= 2;
+			if (len == 0)
+				goto fail;
+			query = wpabuf_alloc(len);
+			if (query == NULL)
+				goto fail;
+			if (hexstr2bin(pos, wpabuf_put(query, len), len) < 0)
+				goto fail;
+		}
+	}
+
+	ret = gas_send_request(wpa_s, dst_addr, advproto, query);
+
+fail:
+	wpabuf_free(advproto);
+	wpabuf_free(query);
+
+	return ret;
+}
+
+
+static int gas_response_get(struct wpa_supplicant *wpa_s, char *cmd, char *buf,
+			    size_t buflen)
+{
+	u8 addr[ETH_ALEN];
+	int dialog_token;
+	int used;
+	char *pos;
+	size_t resp_len, start, requested_len;
+
+	if (!wpa_s->last_gas_resp)
+		return -1;
+
+	used = hwaddr_aton2(cmd, addr);
+	if (used < 0)
+		return -1;
+
+	pos = cmd + used;
+	while (*pos == ' ')
+		pos++;
+	dialog_token = atoi(pos);
+
+	if (os_memcmp(addr, wpa_s->last_gas_addr, ETH_ALEN) != 0 ||
+	    dialog_token != wpa_s->last_gas_dialog_token)
+		return -1;
+
+	resp_len = wpabuf_len(wpa_s->last_gas_resp);
+	start = 0;
+	requested_len = resp_len;
+
+	pos = os_strchr(pos, ' ');
+	if (pos) {
+		start = atoi(pos);
+		if (start > resp_len)
+			return os_snprintf(buf, buflen, "FAIL-Invalid range");
+		pos = os_strchr(pos, ',');
+		if (pos == NULL)
+			return -1;
+		pos++;
+		requested_len = atoi(pos);
+		if (start + requested_len > resp_len)
+			return os_snprintf(buf, buflen, "FAIL-Invalid range");
+	}
+
+	if (requested_len * 2 + 1 > buflen)
+		return os_snprintf(buf, buflen, "FAIL-Too long response");
+
+	return wpa_snprintf_hex(buf, buflen,
+				wpabuf_head_u8(wpa_s->last_gas_resp) + start,
+				requested_len);
+}
+#endif /* CONFIG_INTERWORKING */
+
+
+#ifdef CONFIG_HS20
+
+static int get_hs20_anqp(struct wpa_supplicant *wpa_s, char *dst)
+{
+	u8 dst_addr[ETH_ALEN];
+	int used;
+	char *pos;
+	u32 subtypes = 0;
+
+	used = hwaddr_aton2(dst, dst_addr);
+	if (used < 0)
+		return -1;
+	pos = dst + used;
+	for (;;) {
+		int num = atoi(pos);
+		if (num <= 0 || num > 31)
+			return -1;
+		subtypes |= BIT(num);
+		pos = os_strchr(pos + 1, ',');
+		if (pos == NULL)
+			break;
+		pos++;
+	}
+
+	if (subtypes == 0)
+		return -1;
+
+	return hs20_anqp_send_req(wpa_s, dst_addr, subtypes, NULL, 0);
+}
+
+
+static int hs20_nai_home_realm_list(struct wpa_supplicant *wpa_s,
+				    const u8 *addr, const char *realm)
+{
+	u8 *buf;
+	size_t rlen, len;
+	int ret;
+
+	rlen = os_strlen(realm);
+	len = 3 + rlen;
+	buf = os_malloc(len);
+	if (buf == NULL)
+		return -1;
+	buf[0] = 1; /* NAI Home Realm Count */
+	buf[1] = 0; /* Formatted in accordance with RFC 4282 */
+	buf[2] = rlen;
+	os_memcpy(buf + 3, realm, rlen);
+
+	ret = hs20_anqp_send_req(wpa_s, addr,
+				 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
+				 buf, len);
+
+	os_free(buf);
+
+	return ret;
+}
+
+
+static int hs20_get_nai_home_realm_list(struct wpa_supplicant *wpa_s,
+					char *dst)
+{
+	struct wpa_cred *cred = wpa_s->conf->cred;
+	u8 dst_addr[ETH_ALEN];
+	int used;
+	u8 *buf;
+	size_t len;
+	int ret;
+
+	used = hwaddr_aton2(dst, dst_addr);
+	if (used < 0)
+		return -1;
+
+	while (dst[used] == ' ')
+		used++;
+	if (os_strncmp(dst + used, "realm=", 6) == 0)
+		return hs20_nai_home_realm_list(wpa_s, dst_addr,
+						dst + used + 6);
+
+	len = os_strlen(dst + used);
+
+	if (len == 0 && cred && cred->realm)
+		return hs20_nai_home_realm_list(wpa_s, dst_addr, cred->realm);
+
+	if (len % 1)
+		return -1;
+	len /= 2;
+	buf = os_malloc(len);
+	if (buf == NULL)
+		return -1;
+	if (hexstr2bin(dst + used, buf, len) < 0) {
+		os_free(buf);
+		return -1;
+	}
+
+	ret = hs20_anqp_send_req(wpa_s, dst_addr,
+				 BIT(HS20_STYPE_NAI_HOME_REALM_QUERY),
+				 buf, len);
+	os_free(buf);
+
+	return ret;
+}
+
+#endif /* CONFIG_HS20 */
+
+
+static int wpa_supplicant_ctrl_iface_sta_autoconnect(
+	struct wpa_supplicant *wpa_s, char *cmd)
+{
+	wpa_s->auto_reconnect_disabled = atoi(cmd) == 0 ? 1 : 0;
+	return 0;
+}
+
+
+#ifdef CONFIG_AUTOSCAN
+
+static int wpa_supplicant_ctrl_iface_autoscan(struct wpa_supplicant *wpa_s,
+					      char *cmd)
+{
+	enum wpa_states state = wpa_s->wpa_state;
+	char *new_params = NULL;
+
+	if (os_strlen(cmd) > 0) {
+		new_params = os_strdup(cmd);
+		if (new_params == NULL)
+			return -1;
+	}
+
+	os_free(wpa_s->conf->autoscan);
+	wpa_s->conf->autoscan = new_params;
+
+	if (wpa_s->conf->autoscan == NULL)
+		autoscan_deinit(wpa_s);
+	else if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+		autoscan_init(wpa_s, 1);
+	else if (state == WPA_SCANNING)
+		wpa_supplicant_reinit_autoscan(wpa_s);
+
+	return 0;
+}
+
+#endif /* CONFIG_AUTOSCAN */
+
+
+#ifdef CONFIG_WNM
+
+static int wpas_ctrl_iface_wnm_sleep(struct wpa_supplicant *wpa_s, char *cmd)
+{
+	int enter;
+	int intval = 0;
+	char *pos;
+	int ret;
+	struct wpabuf *tfs_req = NULL;
+
+	if (os_strncmp(cmd, "enter", 5) == 0)
+		enter = 1;
+	else if (os_strncmp(cmd, "exit", 4) == 0)
+		enter = 0;
+	else
+		return -1;
+
+	pos = os_strstr(cmd, " interval=");
+	if (pos)
+		intval = atoi(pos + 10);
+
+	pos = os_strstr(cmd, " tfs_req=");
+	if (pos) {
+		char *end;
+		size_t len;
+		pos += 9;
+		end = os_strchr(pos, ' ');
+		if (end)
+			len = end - pos;
+		else
+			len = os_strlen(pos);
+		if (len & 1)
+			return -1;
+		len /= 2;
+		tfs_req = wpabuf_alloc(len);
+		if (tfs_req == NULL)
+			return -1;
+		if (hexstr2bin(pos, wpabuf_put(tfs_req, len), len) < 0) {
+			wpabuf_free(tfs_req);
+			return -1;
+		}
+	}
+
+	ret = ieee802_11_send_wnmsleep_req(wpa_s, enter ? WNM_SLEEP_MODE_ENTER :
+					   WNM_SLEEP_MODE_EXIT, intval,
+					   tfs_req);
+	wpabuf_free(tfs_req);
+
+	return ret;
+}
+
+#endif /* CONFIG_WNM */
+
+
+static int wpa_supplicant_signal_poll(struct wpa_supplicant *wpa_s, char *buf,
+				      size_t buflen)
+{
+	struct wpa_signal_info si;
+	int ret;
+
+	ret = wpa_drv_signal_poll(wpa_s, &si);
+	if (ret)
+		return -1;
+
+	ret = os_snprintf(buf, buflen, "RSSI=%d\nLINKSPEED=%d\n"
+			  "NOISE=%d\nFREQUENCY=%u\n",
+			  si.current_signal, si.current_txrate / 1000,
+			  si.current_noise, si.frequency);
+	if (ret < 0 || (unsigned int) ret > buflen)
+		return -1;
+	return ret;
+}
+
+
+static int wpa_supplicant_pktcnt_poll(struct wpa_supplicant *wpa_s, char *buf,
+				      size_t buflen)
+{
+	struct hostap_sta_driver_data sta;
+	int ret;
+
+	ret = wpa_drv_pktcnt_poll(wpa_s, &sta);
+	if (ret)
+		return -1;
+
+	ret = os_snprintf(buf, buflen, "TXGOOD=%lu\nTXBAD=%lu\nRXGOOD=%lu\n",
+			  sta.tx_packets, sta.tx_retry_failed, sta.rx_packets);
+	if (ret < 0 || (size_t) ret > buflen)
+		return -1;
+	return ret;
+}
+
+
+char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
+					 char *buf, size_t *resp_len)
+{
+	char *reply;
+	const int reply_size = 4096;
+	int ctrl_rsp = 0;
+	int reply_len;
+
+	if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0 ||
+	    os_strncmp(buf, "SET_NETWORK ", 12) == 0 ||
+	    os_strncmp(buf, "WPS_NFC_TAG_READ", 16) == 0 ||
+	    os_strncmp(buf, "NFC_RX_HANDOVER_SEL", 19) == 0) {
+		wpa_hexdump_ascii_key(MSG_DEBUG, "RX ctrl_iface",
+				      (const u8 *) buf, os_strlen(buf));
+	} else {
+		int level = MSG_DEBUG;
+		if (os_strcmp(buf, "PING") == 0)
+			level = MSG_EXCESSIVE;
+		wpa_hexdump_ascii(level, "RX ctrl_iface",
+				  (const u8 *) buf, os_strlen(buf));
+		wpa_dbg(wpa_s, level, "Control interface command '%s'", buf);
+	}
+
+	reply = os_malloc(reply_size);
+	if (reply == NULL) {
+		*resp_len = 1;
+		return NULL;
+	}
+
+	os_memcpy(reply, "OK\n", 3);
+	reply_len = 3;
+
+	if (os_strcmp(buf, "PING") == 0) {
+		os_memcpy(reply, "PONG\n", 5);
+		reply_len = 5;
+	} else if (os_strcmp(buf, "IFNAME") == 0) {
+		reply_len = os_strlen(wpa_s->ifname);
+		os_memcpy(reply, wpa_s->ifname, reply_len);
+	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
+		if (wpa_debug_reopen_file() < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "NOTE ", 5) == 0) {
+		wpa_printf(MSG_INFO, "NOTE: %s", buf + 5);
+	} else if (os_strcmp(buf, "MIB") == 0) {
+		reply_len = wpa_sm_get_mib(wpa_s->wpa, reply, reply_size);
+		if (reply_len >= 0) {
+			int res;
+			res = eapol_sm_get_mib(wpa_s->eapol, reply + reply_len,
+					       reply_size - reply_len);
+			if (res < 0)
+				reply_len = -1;
+			else
+				reply_len += res;
+		}
+	} else if (os_strncmp(buf, "STATUS", 6) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_status(
+			wpa_s, buf + 6, reply, reply_size);
+	} else if (os_strcmp(buf, "PMKSA") == 0) {
+		reply_len = wpa_sm_pmksa_cache_list(wpa_s->wpa, reply,
+						    reply_size);
+	} else if (os_strncmp(buf, "SET ", 4) == 0) {
+		if (wpa_supplicant_ctrl_iface_set(wpa_s, buf + 4))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "GET ", 4) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_get(wpa_s, buf + 4,
+							  reply, reply_size);
+	} else if (os_strcmp(buf, "LOGON") == 0) {
+		eapol_sm_notify_logoff(wpa_s->eapol, FALSE);
+	} else if (os_strcmp(buf, "LOGOFF") == 0) {
+		eapol_sm_notify_logoff(wpa_s->eapol, TRUE);
+	} else if (os_strcmp(buf, "REASSOCIATE") == 0) {
+		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+			reply_len = -1;
+		else
+			wpas_request_connection(wpa_s);
+	} else if (os_strcmp(buf, "RECONNECT") == 0) {
+		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+			reply_len = -1;
+		else if (wpa_s->disconnected)
+			wpas_request_connection(wpa_s);
+#ifdef IEEE8021X_EAPOL
+	} else if (os_strncmp(buf, "PREAUTH ", 8) == 0) {
+		if (wpa_supplicant_ctrl_iface_preauth(wpa_s, buf + 8))
+			reply_len = -1;
+#endif /* IEEE8021X_EAPOL */
+#ifdef CONFIG_PEERKEY
+	} else if (os_strncmp(buf, "STKSTART ", 9) == 0) {
+		if (wpa_supplicant_ctrl_iface_stkstart(wpa_s, buf + 9))
+			reply_len = -1;
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211R
+	} else if (os_strncmp(buf, "FT_DS ", 6) == 0) {
+		if (wpa_supplicant_ctrl_iface_ft_ds(wpa_s, buf + 6))
+			reply_len = -1;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_WPS
+	} else if (os_strcmp(buf, "WPS_PBC") == 0) {
+		int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, NULL);
+		if (res == -2) {
+			os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
+			reply_len = 17;
+		} else if (res)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_PBC ", 8) == 0) {
+		int res = wpa_supplicant_ctrl_iface_wps_pbc(wpa_s, buf + 8);
+		if (res == -2) {
+			os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
+			reply_len = 17;
+		} else if (res)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_wps_pin(wpa_s, buf + 8,
+							      reply,
+							      reply_size);
+	} else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_wps_check_pin(
+			wpa_s, buf + 14, reply, reply_size);
+	} else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
+		if (wpas_wps_cancel(wpa_s))
+			reply_len = -1;
+#ifdef CONFIG_WPS_NFC
+	} else if (os_strcmp(buf, "WPS_NFC") == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, NULL))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_NFC ", 8) == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_nfc(wpa_s, buf + 8))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_wps_nfc_token(
+			wpa_s, buf + 14, reply, reply_size);
+	} else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_nfc_tag_read(wpa_s,
+							       buf + 17))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "NFC_GET_HANDOVER_REQ ", 21) == 0) {
+		reply_len = wpas_ctrl_nfc_get_handover_req(
+			wpa_s, buf + 21, reply, reply_size);
+	} else if (os_strncmp(buf, "NFC_GET_HANDOVER_SEL ", 21) == 0) {
+		reply_len = wpas_ctrl_nfc_get_handover_sel(
+			wpa_s, buf + 21, reply, reply_size);
+	} else if (os_strncmp(buf, "NFC_RX_HANDOVER_REQ ", 20) == 0) {
+		reply_len = wpas_ctrl_nfc_rx_handover_req(
+			wpa_s, buf + 20, reply, reply_size);
+	} else if (os_strncmp(buf, "NFC_RX_HANDOVER_SEL ", 20) == 0) {
+		if (wpas_ctrl_nfc_rx_handover_sel(wpa_s, buf + 20))
+			reply_len = -1;
+#endif /* CONFIG_WPS_NFC */
+	} else if (os_strncmp(buf, "WPS_REG ", 8) == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_reg(wpa_s, buf + 8))
+			reply_len = -1;
+#ifdef CONFIG_AP
+	} else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_wps_ap_pin(
+			wpa_s, buf + 11, reply, reply_size);
+#endif /* CONFIG_AP */
+#ifdef CONFIG_WPS_ER
+	} else if (os_strcmp(buf, "WPS_ER_START") == 0) {
+		if (wpas_wps_er_start(wpa_s, NULL))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_ER_START ", 13) == 0) {
+		if (wpas_wps_er_start(wpa_s, buf + 13))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "WPS_ER_STOP") == 0) {
+		if (wpas_wps_er_stop(wpa_s))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_ER_PIN ", 11) == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_er_pin(wpa_s, buf + 11))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_ER_PBC ", 11) == 0) {
+		int ret = wpas_wps_er_pbc(wpa_s, buf + 11);
+		if (ret == -2) {
+			os_memcpy(reply, "FAIL-PBC-OVERLAP\n", 17);
+			reply_len = 17;
+		} else if (ret == -3) {
+			os_memcpy(reply, "FAIL-UNKNOWN-UUID\n", 18);
+			reply_len = 18;
+		} else if (ret == -4) {
+			os_memcpy(reply, "FAIL-NO-AP-SETTINGS\n", 20);
+			reply_len = 20;
+		} else if (ret)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_ER_LEARN ", 13) == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_er_learn(wpa_s, buf + 13))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_ER_SET_CONFIG ", 18) == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_er_set_config(wpa_s,
+								buf + 18))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_ER_CONFIG ", 14) == 0) {
+		if (wpa_supplicant_ctrl_iface_wps_er_config(wpa_s, buf + 14))
+			reply_len = -1;
+#ifdef CONFIG_WPS_NFC
+	} else if (os_strncmp(buf, "WPS_ER_NFC_CONFIG_TOKEN ", 24) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_wps_er_nfc_config_token(
+			wpa_s, buf + 24, reply, reply_size);
+#endif /* CONFIG_WPS_NFC */
+#endif /* CONFIG_WPS_ER */
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_IBSS_RSN
+	} else if (os_strncmp(buf, "IBSS_RSN ", 9) == 0) {
+		if (wpa_supplicant_ctrl_iface_ibss_rsn(wpa_s, buf + 9))
+			reply_len = -1;
+#endif /* CONFIG_IBSS_RSN */
+#ifdef CONFIG_P2P
+	} else if (os_strncmp(buf, "P2P_FIND ", 9) == 0) {
+		if (p2p_ctrl_find(wpa_s, buf + 9))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_FIND") == 0) {
+		if (p2p_ctrl_find(wpa_s, ""))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_STOP_FIND") == 0) {
+		wpas_p2p_stop_find(wpa_s);
+	} else if (os_strncmp(buf, "P2P_CONNECT ", 12) == 0) {
+		reply_len = p2p_ctrl_connect(wpa_s, buf + 12, reply,
+					     reply_size);
+	} else if (os_strncmp(buf, "P2P_LISTEN ", 11) == 0) {
+		if (p2p_ctrl_listen(wpa_s, buf + 11))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_LISTEN") == 0) {
+		if (p2p_ctrl_listen(wpa_s, ""))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_GROUP_REMOVE ", 17) == 0) {
+		if (wpas_p2p_group_remove(wpa_s, buf + 17))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_GROUP_ADD") == 0) {
+		if (wpas_p2p_group_add(wpa_s, 0, 0, 0))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_GROUP_ADD ", 14) == 0) {
+		if (p2p_ctrl_group_add(wpa_s, buf + 14))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_PROV_DISC ", 14) == 0) {
+		if (p2p_ctrl_prov_disc(wpa_s, buf + 14))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_GET_PASSPHRASE") == 0) {
+		reply_len = p2p_get_passphrase(wpa_s, reply, reply_size);
+	} else if (os_strncmp(buf, "P2P_SERV_DISC_REQ ", 18) == 0) {
+		reply_len = p2p_ctrl_serv_disc_req(wpa_s, buf + 18, reply,
+						   reply_size);
+	} else if (os_strncmp(buf, "P2P_SERV_DISC_CANCEL_REQ ", 25) == 0) {
+		if (p2p_ctrl_serv_disc_cancel_req(wpa_s, buf + 25) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_SERV_DISC_RESP ", 19) == 0) {
+		if (p2p_ctrl_serv_disc_resp(wpa_s, buf + 19) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_SERVICE_UPDATE") == 0) {
+		wpas_p2p_sd_service_update(wpa_s);
+	} else if (os_strncmp(buf, "P2P_SERV_DISC_EXTERNAL ", 23) == 0) {
+		if (p2p_ctrl_serv_disc_external(wpa_s, buf + 23) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_SERVICE_FLUSH") == 0) {
+		wpas_p2p_service_flush(wpa_s);
+	} else if (os_strncmp(buf, "P2P_SERVICE_ADD ", 16) == 0) {
+		if (p2p_ctrl_service_add(wpa_s, buf + 16) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_SERVICE_DEL ", 16) == 0) {
+		if (p2p_ctrl_service_del(wpa_s, buf + 16) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_REJECT ", 11) == 0) {
+		if (p2p_ctrl_reject(wpa_s, buf + 11) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_INVITE ", 11) == 0) {
+		if (p2p_ctrl_invite(wpa_s, buf + 11) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_PEER ", 9) == 0) {
+		reply_len = p2p_ctrl_peer(wpa_s, buf + 9, reply,
+					      reply_size);
+	} else if (os_strncmp(buf, "P2P_SET ", 8) == 0) {
+		if (p2p_ctrl_set(wpa_s, buf + 8) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_FLUSH") == 0) {
+		os_memset(wpa_s->p2p_auth_invite, 0, ETH_ALEN);
+		wpa_s->force_long_sd = 0;
+		if (wpa_s->global->p2p)
+			p2p_flush(wpa_s->global->p2p);
+	} else if (os_strncmp(buf, "P2P_UNAUTHORIZE ", 16) == 0) {
+		if (wpas_p2p_unauthorize(wpa_s, buf + 16) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_CANCEL") == 0) {
+		if (wpas_p2p_cancel(wpa_s))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_PRESENCE_REQ ", 17) == 0) {
+		if (p2p_ctrl_presence_req(wpa_s, buf + 17) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_PRESENCE_REQ") == 0) {
+		if (p2p_ctrl_presence_req(wpa_s, "") < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "P2P_EXT_LISTEN ", 15) == 0) {
+		if (p2p_ctrl_ext_listen(wpa_s, buf + 15) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "P2P_EXT_LISTEN") == 0) {
+		if (p2p_ctrl_ext_listen(wpa_s, "") < 0)
+			reply_len = -1;
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_WIFI_DISPLAY
+	} else if (os_strncmp(buf, "WFD_SUBELEM_SET ", 16) == 0) {
+		if (wifi_display_subelem_set(wpa_s->global, buf + 16) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WFD_SUBELEM_GET ", 16) == 0) {
+		reply_len = wifi_display_subelem_get(wpa_s->global, buf + 16,
+						     reply, reply_size);
+#endif /* CONFIG_WIFI_DISPLAY */
+#ifdef CONFIG_INTERWORKING
+	} else if (os_strcmp(buf, "FETCH_ANQP") == 0) {
+		if (interworking_fetch_anqp(wpa_s) < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "STOP_FETCH_ANQP") == 0) {
+		interworking_stop_fetch_anqp(wpa_s);
+	} else if (os_strncmp(buf, "INTERWORKING_SELECT", 19) == 0) {
+		if (interworking_select(wpa_s, os_strstr(buf + 19, "auto") !=
+					NULL) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "INTERWORKING_CONNECT ", 21) == 0) {
+		if (ctrl_interworking_connect(wpa_s, buf + 21) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "ANQP_GET ", 9) == 0) {
+		if (get_anqp(wpa_s, buf + 9) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "GAS_REQUEST ", 12) == 0) {
+		if (gas_request(wpa_s, buf + 12) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "GAS_RESPONSE_GET ", 17) == 0) {
+		reply_len = gas_response_get(wpa_s, buf + 17, reply,
+					     reply_size);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_HS20
+	} else if (os_strncmp(buf, "HS20_ANQP_GET ", 14) == 0) {
+		if (get_hs20_anqp(wpa_s, buf + 14) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "HS20_GET_NAI_HOME_REALM_LIST ", 29) == 0) {
+		if (hs20_get_nai_home_realm_list(wpa_s, buf + 29) < 0)
+			reply_len = -1;
+#endif /* CONFIG_HS20 */
+	} else if (os_strncmp(buf, WPA_CTRL_RSP, os_strlen(WPA_CTRL_RSP)) == 0)
+	{
+		if (wpa_supplicant_ctrl_iface_ctrl_rsp(
+			    wpa_s, buf + os_strlen(WPA_CTRL_RSP)))
+			reply_len = -1;
+		else
+			ctrl_rsp = 1;
+	} else if (os_strcmp(buf, "RECONFIGURE") == 0) {
+		if (wpa_supplicant_reload_configuration(wpa_s))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "TERMINATE") == 0) {
+		wpa_supplicant_terminate_proc(wpa_s->global);
+	} else if (os_strncmp(buf, "BSSID ", 6) == 0) {
+		if (wpa_supplicant_ctrl_iface_bssid(wpa_s, buf + 6))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "BLACKLIST", 9) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_blacklist(
+			wpa_s, buf + 9, reply, reply_size);
+	} else if (os_strncmp(buf, "LOG_LEVEL", 9) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_log_level(
+			wpa_s, buf + 9, reply, reply_size);
+	} else if (os_strcmp(buf, "LIST_NETWORKS") == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_list_networks(
+			wpa_s, reply, reply_size);
+	} else if (os_strcmp(buf, "DISCONNECT") == 0) {
+#ifdef CONFIG_SME
+		wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+		wpa_s->reassociate = 0;
+		wpa_s->disconnected = 1;
+		wpa_supplicant_cancel_sched_scan(wpa_s);
+		wpa_supplicant_cancel_scan(wpa_s);
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+	} else if (os_strcmp(buf, "SCAN") == 0) {
+		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+			reply_len = -1;
+		else {
+			if (!wpa_s->sched_scanning && !wpa_s->scanning &&
+			    ((wpa_s->wpa_state <= WPA_SCANNING) ||
+			     (wpa_s->wpa_state == WPA_COMPLETED))) {
+				wpa_s->normal_scans = 0;
+				wpa_s->scan_req = MANUAL_SCAN_REQ;
+				wpa_supplicant_req_scan(wpa_s, 0, 0);
+			} else if (wpa_s->sched_scanning) {
+				wpa_printf(MSG_DEBUG, "Stop ongoing "
+					   "sched_scan to allow requested "
+					   "full scan to proceed");
+				wpa_supplicant_cancel_sched_scan(wpa_s);
+				wpa_s->scan_req = MANUAL_SCAN_REQ;
+				wpa_supplicant_req_scan(wpa_s, 0, 0);
+			} else {
+				wpa_printf(MSG_DEBUG, "Ongoing scan action - "
+					   "reject new request");
+				reply_len = os_snprintf(reply, reply_size,
+							"FAIL-BUSY\n");
+			}
+		}
+	} else if (os_strcmp(buf, "SCAN_RESULTS") == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_scan_results(
+			wpa_s, reply, reply_size);
+	} else if (os_strncmp(buf, "SELECT_NETWORK ", 15) == 0) {
+		if (wpa_supplicant_ctrl_iface_select_network(wpa_s, buf + 15))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "ENABLE_NETWORK ", 15) == 0) {
+		if (wpa_supplicant_ctrl_iface_enable_network(wpa_s, buf + 15))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DISABLE_NETWORK ", 16) == 0) {
+		if (wpa_supplicant_ctrl_iface_disable_network(wpa_s, buf + 16))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "ADD_NETWORK") == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_add_network(
+			wpa_s, reply, reply_size);
+	} else if (os_strncmp(buf, "REMOVE_NETWORK ", 15) == 0) {
+		if (wpa_supplicant_ctrl_iface_remove_network(wpa_s, buf + 15))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "SET_NETWORK ", 12) == 0) {
+		if (wpa_supplicant_ctrl_iface_set_network(wpa_s, buf + 12))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "GET_NETWORK ", 12) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_get_network(
+			wpa_s, buf + 12, reply, reply_size);
+	} else if (os_strcmp(buf, "LIST_CREDS") == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_list_creds(
+			wpa_s, reply, reply_size);
+	} else if (os_strcmp(buf, "ADD_CRED") == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_add_cred(
+			wpa_s, reply, reply_size);
+	} else if (os_strncmp(buf, "REMOVE_CRED ", 12) == 0) {
+		if (wpa_supplicant_ctrl_iface_remove_cred(wpa_s, buf + 12))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "SET_CRED ", 9) == 0) {
+		if (wpa_supplicant_ctrl_iface_set_cred(wpa_s, buf + 9))
+			reply_len = -1;
+#ifndef CONFIG_NO_CONFIG_WRITE
+	} else if (os_strcmp(buf, "SAVE_CONFIG") == 0) {
+		if (wpa_supplicant_ctrl_iface_save_config(wpa_s))
+			reply_len = -1;
+#endif /* CONFIG_NO_CONFIG_WRITE */
+	} else if (os_strncmp(buf, "GET_CAPABILITY ", 15) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_get_capability(
+			wpa_s, buf + 15, reply, reply_size);
+	} else if (os_strncmp(buf, "AP_SCAN ", 8) == 0) {
+		if (wpa_supplicant_ctrl_iface_ap_scan(wpa_s, buf + 8))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "SCAN_INTERVAL ", 14) == 0) {
+		if (wpa_supplicant_ctrl_iface_scan_interval(wpa_s, buf + 14))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
+		reply_len = wpa_supplicant_global_iface_list(
+			wpa_s->global, reply, reply_size);
+	} else if (os_strcmp(buf, "INTERFACES") == 0) {
+		reply_len = wpa_supplicant_global_iface_interfaces(
+			wpa_s->global, reply, reply_size);
+	} else if (os_strncmp(buf, "BSS ", 4) == 0) {
+		reply_len = wpa_supplicant_ctrl_iface_bss(
+			wpa_s, buf + 4, reply, reply_size);
+#ifdef CONFIG_AP
+	} else if (os_strcmp(buf, "STA-FIRST") == 0) {
+		reply_len = ap_ctrl_iface_sta_first(wpa_s, reply, reply_size);
+	} else if (os_strncmp(buf, "STA ", 4) == 0) {
+		reply_len = ap_ctrl_iface_sta(wpa_s, buf + 4, reply,
+					      reply_size);
+	} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
+		reply_len = ap_ctrl_iface_sta_next(wpa_s, buf + 9, reply,
+						   reply_size);
+	} else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
+		if (ap_ctrl_iface_sta_deauthenticate(wpa_s, buf + 15))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
+		if (ap_ctrl_iface_sta_disassociate(wpa_s, buf + 13))
+			reply_len = -1;
+#endif /* CONFIG_AP */
+	} else if (os_strcmp(buf, "SUSPEND") == 0) {
+		wpas_notify_suspend(wpa_s->global);
+	} else if (os_strcmp(buf, "RESUME") == 0) {
+		wpas_notify_resume(wpa_s->global);
+	} else if (os_strcmp(buf, "DROP_SA") == 0) {
+		wpa_supplicant_ctrl_iface_drop_sa(wpa_s);
+	} else if (os_strncmp(buf, "ROAM ", 5) == 0) {
+		if (wpa_supplicant_ctrl_iface_roam(wpa_s, buf + 5))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "STA_AUTOCONNECT ", 16) == 0) {
+		if (wpa_supplicant_ctrl_iface_sta_autoconnect(wpa_s, buf + 16))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "BSS_EXPIRE_AGE ", 15) == 0) {
+		if (wpa_supplicant_ctrl_iface_bss_expire_age(wpa_s, buf + 15))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "BSS_EXPIRE_COUNT ", 17) == 0) {
+		if (wpa_supplicant_ctrl_iface_bss_expire_count(wpa_s,
+							       buf + 17))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "BSS_FLUSH ", 10) == 0) {
+		if (wpa_supplicant_ctrl_iface_bss_flush(wpa_s, buf + 10))
+			reply_len = -1;
+#ifdef CONFIG_TDLS
+	} else if (os_strncmp(buf, "TDLS_DISCOVER ", 14) == 0) {
+		if (wpa_supplicant_ctrl_iface_tdls_discover(wpa_s, buf + 14))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "TDLS_SETUP ", 11) == 0) {
+		if (wpa_supplicant_ctrl_iface_tdls_setup(wpa_s, buf + 11))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "TDLS_TEARDOWN ", 14) == 0) {
+		if (wpa_supplicant_ctrl_iface_tdls_teardown(wpa_s, buf + 14))
+			reply_len = -1;
+#endif /* CONFIG_TDLS */
+	} else if (os_strncmp(buf, "SIGNAL_POLL", 11) == 0) {
+		reply_len = wpa_supplicant_signal_poll(wpa_s, reply,
+						       reply_size);
+	} else if (os_strncmp(buf, "PKTCNT_POLL", 11) == 0) {
+		reply_len = wpa_supplicant_pktcnt_poll(wpa_s, reply,
+						       reply_size);
+#ifdef CONFIG_AUTOSCAN
+	} else if (os_strncmp(buf, "AUTOSCAN ", 9) == 0) {
+		if (wpa_supplicant_ctrl_iface_autoscan(wpa_s, buf + 9))
+			reply_len = -1;
+#endif /* CONFIG_AUTOSCAN */
+	} else if (os_strcmp(buf, "REAUTHENTICATE") == 0) {
+		pmksa_cache_clear_current(wpa_s->wpa);
+		eapol_sm_request_reauth(wpa_s->eapol);
+#ifdef CONFIG_WNM
+	} else if (os_strncmp(buf, "WNM_SLEEP ", 10) == 0) {
+		if (wpas_ctrl_iface_wnm_sleep(wpa_s, buf + 10))
+			reply_len = -1;
+#endif /* CONFIG_WNM */
+	} else {
+		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
+		reply_len = 16;
+	}
+
+	if (reply_len < 0) {
+		os_memcpy(reply, "FAIL\n", 5);
+		reply_len = 5;
+	}
+
+	if (ctrl_rsp)
+		eapol_sm_notify_ctrl_response(wpa_s->eapol);
+
+	*resp_len = reply_len;
+	return reply;
+}
+
+
+static int wpa_supplicant_global_iface_add(struct wpa_global *global,
+					   char *cmd)
+{
+	struct wpa_interface iface;
+	char *pos;
+
+	/*
+	 * <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB<driver_param>
+	 * TAB<bridge_ifname>
+	 */
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_ADD '%s'", cmd);
+
+	os_memset(&iface, 0, sizeof(iface));
+
+	do {
+		iface.ifname = pos = cmd;
+		pos = os_strchr(pos, '\t');
+		if (pos)
+			*pos++ = '\0';
+		if (iface.ifname[0] == '\0')
+			return -1;
+		if (pos == NULL)
+			break;
+
+		iface.confname = pos;
+		pos = os_strchr(pos, '\t');
+		if (pos)
+			*pos++ = '\0';
+		if (iface.confname[0] == '\0')
+			iface.confname = NULL;
+		if (pos == NULL)
+			break;
+
+		iface.driver = pos;
+		pos = os_strchr(pos, '\t');
+		if (pos)
+			*pos++ = '\0';
+		if (iface.driver[0] == '\0')
+			iface.driver = NULL;
+		if (pos == NULL)
+			break;
+
+		iface.ctrl_interface = pos;
+		pos = os_strchr(pos, '\t');
+		if (pos)
+			*pos++ = '\0';
+		if (iface.ctrl_interface[0] == '\0')
+			iface.ctrl_interface = NULL;
+		if (pos == NULL)
+			break;
+
+		iface.driver_param = pos;
+		pos = os_strchr(pos, '\t');
+		if (pos)
+			*pos++ = '\0';
+		if (iface.driver_param[0] == '\0')
+			iface.driver_param = NULL;
+		if (pos == NULL)
+			break;
+
+		iface.bridge_ifname = pos;
+		pos = os_strchr(pos, '\t');
+		if (pos)
+			*pos++ = '\0';
+		if (iface.bridge_ifname[0] == '\0')
+			iface.bridge_ifname = NULL;
+		if (pos == NULL)
+			break;
+	} while (0);
+
+	if (wpa_supplicant_get_iface(global, iface.ifname))
+		return -1;
+
+	return wpa_supplicant_add_iface(global, &iface) ? 0 : -1;
+}
+
+
+static int wpa_supplicant_global_iface_remove(struct wpa_global *global,
+					      char *cmd)
+{
+	struct wpa_supplicant *wpa_s;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE GLOBAL INTERFACE_REMOVE '%s'", cmd);
+
+	wpa_s = wpa_supplicant_get_iface(global, cmd);
+	if (wpa_s == NULL)
+		return -1;
+	return wpa_supplicant_remove_iface(global, wpa_s, 0);
+}
+
+
+static void wpa_free_iface_info(struct wpa_interface_info *iface)
+{
+	struct wpa_interface_info *prev;
+
+	while (iface) {
+		prev = iface;
+		iface = iface->next;
+
+		os_free(prev->ifname);
+		os_free(prev->desc);
+		os_free(prev);
+	}
+}
+
+
+static int wpa_supplicant_global_iface_list(struct wpa_global *global,
+					    char *buf, int len)
+{
+	int i, res;
+	struct wpa_interface_info *iface = NULL, *last = NULL, *tmp;
+	char *pos, *end;
+
+	for (i = 0; wpa_drivers[i]; i++) {
+		struct wpa_driver_ops *drv = wpa_drivers[i];
+		if (drv->get_interfaces == NULL)
+			continue;
+		tmp = drv->get_interfaces(global->drv_priv[i]);
+		if (tmp == NULL)
+			continue;
+
+		if (last == NULL)
+			iface = last = tmp;
+		else
+			last->next = tmp;
+		while (last->next)
+			last = last->next;
+	}
+
+	pos = buf;
+	end = buf + len;
+	for (tmp = iface; tmp; tmp = tmp->next) {
+		res = os_snprintf(pos, end - pos, "%s\t%s\t%s\n",
+				  tmp->drv_name, tmp->ifname,
+				  tmp->desc ? tmp->desc : "");
+		if (res < 0 || res >= end - pos) {
+			*pos = '\0';
+			break;
+		}
+		pos += res;
+	}
+
+	wpa_free_iface_info(iface);
+
+	return pos - buf;
+}
+
+
+static int wpa_supplicant_global_iface_interfaces(struct wpa_global *global,
+						  char *buf, int len)
+{
+	int res;
+	char *pos, *end;
+	struct wpa_supplicant *wpa_s;
+
+	wpa_s = global->ifaces;
+	pos = buf;
+	end = buf + len;
+
+	while (wpa_s) {
+		res = os_snprintf(pos, end - pos, "%s\n", wpa_s->ifname);
+		if (res < 0 || res >= end - pos) {
+			*pos = '\0';
+			break;
+		}
+		pos += res;
+		wpa_s = wpa_s->next;
+	}
+	return pos - buf;
+}
+
+
+char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
+						char *buf, size_t *resp_len)
+{
+	char *reply;
+	const int reply_size = 2048;
+	int reply_len;
+	int level = MSG_DEBUG;
+
+	if (os_strcmp(buf, "PING") == 0)
+		level = MSG_EXCESSIVE;
+	wpa_hexdump_ascii(level, "RX global ctrl_iface",
+			  (const u8 *) buf, os_strlen(buf));
+
+	reply = os_malloc(reply_size);
+	if (reply == NULL) {
+		*resp_len = 1;
+		return NULL;
+	}
+
+	os_memcpy(reply, "OK\n", 3);
+	reply_len = 3;
+
+	if (os_strcmp(buf, "PING") == 0) {
+		os_memcpy(reply, "PONG\n", 5);
+		reply_len = 5;
+	} else if (os_strncmp(buf, "INTERFACE_ADD ", 14) == 0) {
+		if (wpa_supplicant_global_iface_add(global, buf + 14))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "INTERFACE_REMOVE ", 17) == 0) {
+		if (wpa_supplicant_global_iface_remove(global, buf + 17))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "INTERFACE_LIST") == 0) {
+		reply_len = wpa_supplicant_global_iface_list(
+			global, reply, reply_size);
+	} else if (os_strcmp(buf, "INTERFACES") == 0) {
+		reply_len = wpa_supplicant_global_iface_interfaces(
+			global, reply, reply_size);
+	} else if (os_strcmp(buf, "TERMINATE") == 0) {
+		wpa_supplicant_terminate_proc(global);
+	} else if (os_strcmp(buf, "SUSPEND") == 0) {
+		wpas_notify_suspend(global);
+	} else if (os_strcmp(buf, "RESUME") == 0) {
+		wpas_notify_resume(global);
+	} else {
+		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
+		reply_len = 16;
+	}
+
+	if (reply_len < 0) {
+		os_memcpy(reply, "FAIL\n", 5);
+		reply_len = 5;
+	}
+
+	*resp_len = reply_len;
+	return reply;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/ctrl_iface.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,153 @@
+/*
+ * WPA Supplicant / UNIX domain socket -based control interface
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CTRL_IFACE_H
+#define CTRL_IFACE_H
+
+#ifdef CONFIG_CTRL_IFACE
+
+/* Shared functions from ctrl_iface.c; to be called by ctrl_iface backends */
+
+/**
+ * wpa_supplicant_ctrl_iface_process - Process ctrl_iface command
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @buf: Received command buffer (nul terminated string)
+ * @resp_len: Variable to be set to the response length
+ * Returns: Response (*resp_len bytes) or %NULL on failure
+ *
+ * Control interface backends call this function when receiving a message that
+ * they do not process internally, i.e., anything else than ATTACH, DETACH,
+ * and LEVEL. The return response value is then sent to the external program
+ * that sent the command. Caller is responsible for freeing the buffer after
+ * this. If %NULL is returned, *resp_len can be set to two special values:
+ * 1 = send "FAIL\n" response, 2 = send "OK\n" response. If *resp_len has any
+ * other value, no response is sent.
+ */
+char * wpa_supplicant_ctrl_iface_process(struct wpa_supplicant *wpa_s,
+					 char *buf, size_t *resp_len);
+
+/**
+ * wpa_supplicant_ctrl_iface_process - Process global ctrl_iface command
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @buf: Received command buffer (nul terminated string)
+ * @resp_len: Variable to be set to the response length
+ * Returns: Response (*resp_len bytes) or %NULL on failure
+ *
+ * Control interface backends call this function when receiving a message from
+ * the global ctrl_iface connection. The return response value is then sent to
+ * the external program that sent the command. Caller is responsible for
+ * freeing the buffer after this. If %NULL is returned, *resp_len can be set to
+ * two special values: 1 = send "FAIL\n" response, 2 = send "OK\n" response. If
+ * *resp_len has any other value, no response is sent.
+ */
+char * wpa_supplicant_global_ctrl_iface_process(struct wpa_global *global,
+						char *buf, size_t *resp_len);
+
+
+/* Functions that each ctrl_iface backend must implement */
+
+/**
+ * wpa_supplicant_ctrl_iface_init - Initialize control interface
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: Pointer to private data on success, %NULL on failure
+ *
+ * Initialize the control interface and start receiving commands from external
+ * programs.
+ *
+ * Required to be implemented in each control interface backend.
+ */
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s);
+
+/**
+ * wpa_supplicant_ctrl_iface_deinit - Deinitialize control interface
+ * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
+ *
+ * Deinitialize the control interface that was initialized with
+ * wpa_supplicant_ctrl_iface_init().
+ *
+ * Required to be implemented in each control interface backend.
+ */
+void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv);
+
+/**
+ * wpa_supplicant_ctrl_iface_wait - Wait for ctrl_iface monitor
+ * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
+ *
+ * Wait until the first message from an external program using the control
+ * interface is received. This function can be used to delay normal startup
+ * processing to allow control interface programs to attach with
+ * %wpa_supplicant before normal operations are started.
+ *
+ * Required to be implemented in each control interface backend.
+ */
+void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv);
+
+/**
+ * wpa_supplicant_global_ctrl_iface_init - Initialize global control interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * Returns: Pointer to private data on success, %NULL on failure
+ *
+ * Initialize the global control interface and start receiving commands from
+ * external programs.
+ *
+ * Required to be implemented in each control interface backend.
+ */
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global);
+
+/**
+ * wpa_supplicant_global_ctrl_iface_deinit - Deinitialize global ctrl interface
+ * @priv: Pointer to private data from wpa_supplicant_global_ctrl_iface_init()
+ *
+ * Deinitialize the global control interface that was initialized with
+ * wpa_supplicant_global_ctrl_iface_init().
+ *
+ * Required to be implemented in each control interface backend.
+ */
+void wpa_supplicant_global_ctrl_iface_deinit(
+	struct ctrl_iface_global_priv *priv);
+
+#else /* CONFIG_CTRL_IFACE */
+
+static inline struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+	return (void *) -1;
+}
+
+static inline void
+wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+{
+}
+
+static inline void
+wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv, int level,
+			       char *buf, size_t len)
+{
+}
+
+static inline void
+wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
+{
+}
+
+static inline struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+	return (void *) 1;
+}
+
+static inline void
+wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
+{
+}
+
+#endif /* CONFIG_CTRL_IFACE */
+
+#endif /* CTRL_IFACE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/ctrl_iface_unix.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,762 @@
+/*
+ * WPA Supplicant / UNIX domain socket -based control interface
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <grp.h>
+#include <stddef.h>
+#include <unistd.h>
+#include <fcntl.h>
+#ifdef ANDROID
+#include <cutils/sockets.h>
+#endif /* ANDROID */
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/list.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "ctrl_iface.h"
+
+/* Per-interface ctrl_iface */
+
+/**
+ * struct wpa_ctrl_dst - Internal data structure of control interface monitors
+ *
+ * This structure is used to store information about registered control
+ * interface monitors into struct wpa_supplicant. This data is private to
+ * ctrl_iface_unix.c and should not be touched directly from other files.
+ */
+struct wpa_ctrl_dst {
+	struct dl_list list;
+	struct sockaddr_un addr;
+	socklen_t addrlen;
+	int debug_level;
+	int errors;
+};
+
+
+struct ctrl_iface_priv {
+	struct wpa_supplicant *wpa_s;
+	int sock;
+	struct dl_list ctrl_dst;
+};
+
+
+static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+					   int level, const char *buf,
+					   size_t len);
+
+
+static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
+					    struct sockaddr_un *from,
+					    socklen_t fromlen)
+{
+	struct wpa_ctrl_dst *dst;
+
+	dst = os_zalloc(sizeof(*dst));
+	if (dst == NULL)
+		return -1;
+	os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
+	dst->addrlen = fromlen;
+	dst->debug_level = MSG_INFO;
+	dl_list_add(&priv->ctrl_dst, &dst->list);
+	wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
+		    (u8 *) from->sun_path,
+		    fromlen - offsetof(struct sockaddr_un, sun_path));
+	return 0;
+}
+
+
+static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
+					    struct sockaddr_un *from,
+					    socklen_t fromlen)
+{
+	struct wpa_ctrl_dst *dst;
+
+	dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) {
+		if (fromlen == dst->addrlen &&
+		    os_memcmp(from->sun_path, dst->addr.sun_path,
+			      fromlen - offsetof(struct sockaddr_un, sun_path))
+		    == 0) {
+			dl_list_del(&dst->list);
+			os_free(dst);
+			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
+				    (u8 *) from->sun_path,
+				    fromlen -
+				    offsetof(struct sockaddr_un, sun_path));
+			return 0;
+		}
+	}
+	return -1;
+}
+
+
+static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
+					   struct sockaddr_un *from,
+					   socklen_t fromlen,
+					   char *level)
+{
+	struct wpa_ctrl_dst *dst;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
+
+	dl_list_for_each(dst, &priv->ctrl_dst, struct wpa_ctrl_dst, list) {
+		if (fromlen == dst->addrlen &&
+		    os_memcmp(from->sun_path, dst->addr.sun_path,
+			      fromlen - offsetof(struct sockaddr_un, sun_path))
+		    == 0) {
+			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
+				    "level", (u8 *) from->sun_path,
+				    fromlen -
+				    offsetof(struct sockaddr_un, sun_path));
+			dst->debug_level = atoi(level);
+			return 0;
+		}
+	}
+
+	return -1;
+}
+
+
+static void wpa_supplicant_ctrl_iface_receive(int sock, void *eloop_ctx,
+					      void *sock_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct ctrl_iface_priv *priv = sock_ctx;
+	char buf[4096];
+	int res;
+	struct sockaddr_un from;
+	socklen_t fromlen = sizeof(from);
+	char *reply = NULL;
+	size_t reply_len = 0;
+	int new_attached = 0;
+
+	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+		       (struct sockaddr *) &from, &fromlen);
+	if (res < 0) {
+		perror("recvfrom(ctrl_iface)");
+		return;
+	}
+	buf[res] = '\0';
+
+	if (os_strcmp(buf, "ATTACH") == 0) {
+		if (wpa_supplicant_ctrl_iface_attach(priv, &from, fromlen))
+			reply_len = 1;
+		else {
+			new_attached = 1;
+			reply_len = 2;
+		}
+	} else if (os_strcmp(buf, "DETACH") == 0) {
+		if (wpa_supplicant_ctrl_iface_detach(priv, &from, fromlen))
+			reply_len = 1;
+		else
+			reply_len = 2;
+	} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
+		if (wpa_supplicant_ctrl_iface_level(priv, &from, fromlen,
+						    buf + 6))
+			reply_len = 1;
+		else
+			reply_len = 2;
+	} else {
+		reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
+							  &reply_len);
+	}
+
+	if (reply) {
+		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+		       fromlen);
+		os_free(reply);
+	} else if (reply_len == 1) {
+		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+		       fromlen);
+	} else if (reply_len == 2) {
+		sendto(sock, "OK\n", 3, 0, (struct sockaddr *) &from,
+		       fromlen);
+	}
+
+	if (new_attached)
+		eapol_sm_notify_ctrl_attached(wpa_s->eapol);
+}
+
+
+static char * wpa_supplicant_ctrl_iface_path(struct wpa_supplicant *wpa_s)
+{
+	char *buf;
+	size_t len;
+	char *pbuf, *dir = NULL, *gid_str = NULL;
+	int res;
+
+	if (wpa_s->conf->ctrl_interface == NULL)
+		return NULL;
+
+	pbuf = os_strdup(wpa_s->conf->ctrl_interface);
+	if (pbuf == NULL)
+		return NULL;
+	if (os_strncmp(pbuf, "DIR=", 4) == 0) {
+		dir = pbuf + 4;
+		gid_str = os_strstr(dir, " GROUP=");
+		if (gid_str) {
+			*gid_str = '\0';
+			gid_str += 7;
+		}
+	} else
+		dir = pbuf;
+
+	len = os_strlen(dir) + os_strlen(wpa_s->ifname) + 2;
+	buf = os_malloc(len);
+	if (buf == NULL) {
+		os_free(pbuf);
+		return NULL;
+	}
+
+	res = os_snprintf(buf, len, "%s/%s", dir, wpa_s->ifname);
+	if (res < 0 || (size_t) res >= len) {
+		os_free(pbuf);
+		os_free(buf);
+		return NULL;
+	}
+#ifdef __CYGWIN__
+	{
+		/* Windows/WinPcap uses interface names that are not suitable
+		 * as a file name - convert invalid chars to underscores */
+		char *pos = buf;
+		while (*pos) {
+			if (*pos == '\\')
+				*pos = '_';
+			pos++;
+		}
+	}
+#endif /* __CYGWIN__ */
+	os_free(pbuf);
+	return buf;
+}
+
+
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+					     const char *txt, size_t len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
+		return;
+	wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
+}
+
+
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+	struct ctrl_iface_priv *priv;
+	struct sockaddr_un addr;
+	char *fname = NULL;
+	gid_t gid = 0;
+	int gid_set = 0;
+	char *buf, *dir = NULL, *gid_str = NULL;
+	struct group *grp;
+	char *endp;
+	int flags;
+
+	priv = os_zalloc(sizeof(*priv));
+	if (priv == NULL)
+		return NULL;
+	dl_list_init(&priv->ctrl_dst);
+	priv->wpa_s = wpa_s;
+	priv->sock = -1;
+
+	if (wpa_s->conf->ctrl_interface == NULL)
+		return priv;
+
+	buf = os_strdup(wpa_s->conf->ctrl_interface);
+	if (buf == NULL)
+		goto fail;
+#ifdef ANDROID
+	os_snprintf(addr.sun_path, sizeof(addr.sun_path), "wpa_%s",
+		    wpa_s->conf->ctrl_interface);
+	priv->sock = android_get_control_socket(addr.sun_path);
+	if (priv->sock >= 0)
+		goto havesock;
+#endif /* ANDROID */
+	if (os_strncmp(buf, "DIR=", 4) == 0) {
+		dir = buf + 4;
+		gid_str = os_strstr(dir, " GROUP=");
+		if (gid_str) {
+			*gid_str = '\0';
+			gid_str += 7;
+		}
+	} else {
+		dir = buf;
+		gid_str = wpa_s->conf->ctrl_interface_group;
+	}
+
+	if (mkdir(dir, S_IRWXU | S_IRWXG) < 0) {
+		if (errno == EEXIST) {
+			wpa_printf(MSG_DEBUG, "Using existing control "
+				   "interface directory.");
+		} else {
+			perror("mkdir[ctrl_interface]");
+			goto fail;
+		}
+	}
+
+#ifdef ANDROID
+	/*
+	 * wpa_supplicant is started from /init.*.rc on Android and that seems
+	 * to be using umask 0077 which would leave the control interface
+	 * directory without group access. This breaks things since Wi-Fi
+	 * framework assumes that this directory can be accessed by other
+	 * applications in the wifi group. Fix this by adding group access even
+	 * if umask value would prevent this.
+	 */
+	if (chmod(dir, S_IRWXU | S_IRWXG) < 0) {
+		wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
+			   strerror(errno));
+		/* Try to continue anyway */
+	}
+#endif /* ANDROID */
+
+	if (gid_str) {
+		grp = getgrnam(gid_str);
+		if (grp) {
+			gid = grp->gr_gid;
+			gid_set = 1;
+			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
+				   " (from group name '%s')",
+				   (int) gid, gid_str);
+		} else {
+			/* Group name not found - try to parse this as gid */
+			gid = strtol(gid_str, &endp, 10);
+			if (*gid_str == '\0' || *endp != '\0') {
+				wpa_printf(MSG_ERROR, "CTRL: Invalid group "
+					   "'%s'", gid_str);
+				goto fail;
+			}
+			gid_set = 1;
+			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+				   (int) gid);
+		}
+	}
+
+	if (gid_set && chown(dir, -1, gid) < 0) {
+		perror("chown[ctrl_interface]");
+		goto fail;
+	}
+
+	/* Make sure the group can enter and read the directory */
+	if (gid_set &&
+	    chmod(dir, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | S_IXGRP) < 0) {
+		wpa_printf(MSG_ERROR, "CTRL: chmod[ctrl_interface]: %s",
+			   strerror(errno));
+		goto fail;
+	}
+
+	if (os_strlen(dir) + 1 + os_strlen(wpa_s->ifname) >=
+	    sizeof(addr.sun_path)) {
+		wpa_printf(MSG_ERROR, "ctrl_iface path limit exceeded");
+		goto fail;
+	}
+
+	priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (priv->sock < 0) {
+		perror("socket(PF_UNIX)");
+		goto fail;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+	addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
+	addr.sun_family = AF_UNIX;
+	fname = wpa_supplicant_ctrl_iface_path(wpa_s);
+	if (fname == NULL)
+		goto fail;
+	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
+	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
+			   strerror(errno));
+		if (connect(priv->sock, (struct sockaddr *) &addr,
+			    sizeof(addr)) < 0) {
+			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
+				   " allow connections - assuming it was left"
+				   "over from forced program termination");
+			if (unlink(fname) < 0) {
+				perror("unlink[ctrl_iface]");
+				wpa_printf(MSG_ERROR, "Could not unlink "
+					   "existing ctrl_iface socket '%s'",
+					   fname);
+				goto fail;
+			}
+			if (bind(priv->sock, (struct sockaddr *) &addr,
+				 sizeof(addr)) < 0) {
+				perror("supp-ctrl-iface-init: bind(PF_UNIX)");
+				goto fail;
+			}
+			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+				   "ctrl_iface socket '%s'", fname);
+		} else {
+			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
+				   "be in use - cannot override it");
+			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+				   "not used anymore", fname);
+			os_free(fname);
+			fname = NULL;
+			goto fail;
+		}
+	}
+
+	if (gid_set && chown(fname, -1, gid) < 0) {
+		perror("chown[ctrl_interface/ifname]");
+		goto fail;
+	}
+
+	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+		perror("chmod[ctrl_interface/ifname]");
+		goto fail;
+	}
+	os_free(fname);
+
+#ifdef ANDROID
+havesock:
+#endif /* ANDROID */
+
+	/*
+	 * Make socket non-blocking so that we don't hang forever if
+	 * target dies unexpectedly.
+	 */
+	flags = fcntl(priv->sock, F_GETFL);
+	if (flags >= 0) {
+		flags |= O_NONBLOCK;
+		if (fcntl(priv->sock, F_SETFL, flags) < 0) {
+			perror("fcntl(ctrl, O_NONBLOCK)");
+			/* Not fatal, continue on.*/
+		}
+	}
+
+	eloop_register_read_sock(priv->sock, wpa_supplicant_ctrl_iface_receive,
+				 wpa_s, priv);
+	wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
+
+	os_free(buf);
+	return priv;
+
+fail:
+	if (priv->sock >= 0)
+		close(priv->sock);
+	os_free(priv);
+	if (fname) {
+		unlink(fname);
+		os_free(fname);
+	}
+	os_free(buf);
+	return NULL;
+}
+
+
+void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+{
+	struct wpa_ctrl_dst *dst, *prev;
+
+	if (priv->sock > -1) {
+		char *fname;
+		char *buf, *dir = NULL, *gid_str = NULL;
+		eloop_unregister_read_sock(priv->sock);
+		if (!dl_list_empty(&priv->ctrl_dst)) {
+			/*
+			 * Wait a second before closing the control socket if
+			 * there are any attached monitors in order to allow
+			 * them to receive any pending messages.
+			 */
+			wpa_printf(MSG_DEBUG, "CTRL_IFACE wait for attached "
+				   "monitors to receive messages");
+			os_sleep(1, 0);
+		}
+		close(priv->sock);
+		priv->sock = -1;
+		fname = wpa_supplicant_ctrl_iface_path(priv->wpa_s);
+		if (fname) {
+			unlink(fname);
+			os_free(fname);
+		}
+
+		buf = os_strdup(priv->wpa_s->conf->ctrl_interface);
+		if (buf == NULL)
+			goto free_dst;
+		if (os_strncmp(buf, "DIR=", 4) == 0) {
+			dir = buf + 4;
+			gid_str = os_strstr(dir, " GROUP=");
+			if (gid_str) {
+				*gid_str = '\0';
+				gid_str += 7;
+			}
+		} else
+			dir = buf;
+
+		if (rmdir(dir) < 0) {
+			if (errno == ENOTEMPTY) {
+				wpa_printf(MSG_DEBUG, "Control interface "
+					   "directory not empty - leaving it "
+					   "behind");
+			} else {
+				perror("rmdir[ctrl_interface]");
+			}
+		}
+		os_free(buf);
+	}
+
+free_dst:
+	dl_list_for_each_safe(dst, prev, &priv->ctrl_dst, struct wpa_ctrl_dst,
+			      list)
+		os_free(dst);
+	os_free(priv);
+}
+
+
+/**
+ * wpa_supplicant_ctrl_iface_send - Send a control interface packet to monitors
+ * @priv: Pointer to private data from wpa_supplicant_ctrl_iface_init()
+ * @level: Priority level of the message
+ * @buf: Message data
+ * @len: Message length
+ *
+ * Send a packet to all monitor programs attached to the control interface.
+ */
+static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+					   int level, const char *buf,
+					   size_t len)
+{
+	struct wpa_ctrl_dst *dst, *next;
+	char levelstr[10];
+	int idx, res;
+	struct msghdr msg;
+	struct iovec io[2];
+
+	if (priv->sock < 0 || dl_list_empty(&priv->ctrl_dst))
+		return;
+
+	res = os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+	if (res < 0 || (size_t) res >= sizeof(levelstr))
+		return;
+	io[0].iov_base = levelstr;
+	io[0].iov_len = os_strlen(levelstr);
+	io[1].iov_base = (char *) buf;
+	io[1].iov_len = len;
+	os_memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = io;
+	msg.msg_iovlen = 2;
+
+	idx = 0;
+	dl_list_for_each_safe(dst, next, &priv->ctrl_dst, struct wpa_ctrl_dst,
+			      list) {
+		if (level >= dst->debug_level) {
+			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
+				    (u8 *) dst->addr.sun_path, dst->addrlen -
+				    offsetof(struct sockaddr_un, sun_path));
+			msg.msg_name = (void *) &dst->addr;
+			msg.msg_namelen = dst->addrlen;
+			if (sendmsg(priv->sock, &msg, 0) < 0) {
+				int _errno = errno;
+				wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
+					   "%d - %s",
+					   idx, errno, strerror(errno));
+				dst->errors++;
+				if (dst->errors > 1000 ||
+				    (_errno != ENOBUFS && dst->errors > 10) ||
+				    _errno == ENOENT) {
+					wpa_supplicant_ctrl_iface_detach(
+						priv, &dst->addr,
+						dst->addrlen);
+				}
+			} else
+				dst->errors = 0;
+		}
+		idx++;
+	}
+}
+
+
+void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
+{
+	char buf[256];
+	int res;
+	struct sockaddr_un from;
+	socklen_t fromlen = sizeof(from);
+
+	for (;;) {
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor to "
+			   "attach", priv->wpa_s->ifname);
+		eloop_wait_for_read_sock(priv->sock);
+
+		res = recvfrom(priv->sock, buf, sizeof(buf) - 1, 0,
+			       (struct sockaddr *) &from, &fromlen);
+		if (res < 0) {
+			perror("recvfrom(ctrl_iface)");
+			continue;
+		}
+		buf[res] = '\0';
+
+		if (os_strcmp(buf, "ATTACH") == 0) {
+			/* handle ATTACH signal of first monitor interface */
+			if (!wpa_supplicant_ctrl_iface_attach(priv, &from,
+							      fromlen)) {
+				sendto(priv->sock, "OK\n", 3, 0,
+				       (struct sockaddr *) &from, fromlen);
+				/* OK to continue */
+				return;
+			} else {
+				sendto(priv->sock, "FAIL\n", 5, 0,
+				       (struct sockaddr *) &from, fromlen);
+			}
+		} else {
+			/* return FAIL for all other signals */
+			sendto(priv->sock, "FAIL\n", 5, 0,
+			       (struct sockaddr *) &from, fromlen);
+		}
+	}
+}
+
+
+/* Global ctrl_iface */
+
+struct ctrl_iface_global_priv {
+	struct wpa_global *global;
+	int sock;
+};
+
+
+static void wpa_supplicant_global_ctrl_iface_receive(int sock, void *eloop_ctx,
+						     void *sock_ctx)
+{
+	struct wpa_global *global = eloop_ctx;
+	char buf[256];
+	int res;
+	struct sockaddr_un from;
+	socklen_t fromlen = sizeof(from);
+	char *reply;
+	size_t reply_len;
+
+	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+		       (struct sockaddr *) &from, &fromlen);
+	if (res < 0) {
+		perror("recvfrom(ctrl_iface)");
+		return;
+	}
+	buf[res] = '\0';
+
+	reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
+							 &reply_len);
+
+	if (reply) {
+		sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from,
+		       fromlen);
+		os_free(reply);
+	} else if (reply_len) {
+		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+		       fromlen);
+	}
+}
+
+
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+	struct ctrl_iface_global_priv *priv;
+	struct sockaddr_un addr;
+
+	priv = os_zalloc(sizeof(*priv));
+	if (priv == NULL)
+		return NULL;
+	priv->global = global;
+	priv->sock = -1;
+
+	if (global->params.ctrl_interface == NULL)
+		return priv;
+
+#ifdef ANDROID
+	priv->sock = android_get_control_socket(global->params.ctrl_interface);
+	if (priv->sock >= 0)
+		goto havesock;
+#endif /* ANDROID */
+
+	wpa_printf(MSG_DEBUG, "Global control interface '%s'",
+		   global->params.ctrl_interface);
+
+	priv->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (priv->sock < 0) {
+		perror("socket(PF_UNIX)");
+		goto fail;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+	addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
+	addr.sun_family = AF_UNIX;
+	os_strlcpy(addr.sun_path, global->params.ctrl_interface,
+		   sizeof(addr.sun_path));
+	if (bind(priv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("supp-global-ctrl-iface-init (will try fixup): "
+		       "bind(PF_UNIX)");
+		if (connect(priv->sock, (struct sockaddr *) &addr,
+			    sizeof(addr)) < 0) {
+			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
+				   " allow connections - assuming it was left"
+				   "over from forced program termination");
+			if (unlink(global->params.ctrl_interface) < 0) {
+				perror("unlink[ctrl_iface]");
+				wpa_printf(MSG_ERROR, "Could not unlink "
+					   "existing ctrl_iface socket '%s'",
+					   global->params.ctrl_interface);
+				goto fail;
+			}
+			if (bind(priv->sock, (struct sockaddr *) &addr,
+				 sizeof(addr)) < 0) {
+				perror("supp-glb-iface-init: bind(PF_UNIX)");
+				goto fail;
+			}
+			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+				   "ctrl_iface socket '%s'",
+				   global->params.ctrl_interface);
+		} else {
+			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
+				   "be in use - cannot override it");
+			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+				   "not used anymore",
+				   global->params.ctrl_interface);
+			goto fail;
+		}
+	}
+
+#ifdef ANDROID
+havesock:
+#endif /* ANDROID */
+	eloop_register_read_sock(priv->sock,
+				 wpa_supplicant_global_ctrl_iface_receive,
+				 global, NULL);
+
+	return priv;
+
+fail:
+	if (priv->sock >= 0)
+		close(priv->sock);
+	os_free(priv);
+	return NULL;
+}
+
+
+void
+wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
+{
+	if (priv->sock >= 0) {
+		eloop_unregister_read_sock(priv->sock);
+		close(priv->sock);
+	}
+	if (priv->global->params.ctrl_interface)
+		unlink(priv->global->params.ctrl_interface);
+	os_free(priv);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/dbus/dbus_common.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,20 @@
+/*
+ * wpa_supplicant D-Bus control interface - common definitions
+ * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
+ * Copyright (c) 2009, Witold Sowa <witold.sowa@gmail.com>
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DBUS_COMMON_H
+#define DBUS_COMMON_H
+
+struct wpas_dbus_priv;
+struct wpa_global;
+
+struct wpas_dbus_priv * wpas_dbus_init(struct wpa_global *global);
+void wpas_dbus_deinit(struct wpas_dbus_priv *priv);
+
+#endif /* DBUS_COMMON_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/dbus/dbus_new.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,498 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
+ * Copyright (c) 2009-2010, Witold Sowa <witold.sowa@gmail.com>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CTRL_IFACE_DBUS_NEW_H
+#define CTRL_IFACE_DBUS_NEW_H
+
+#include "common/defs.h"
+#include "p2p/p2p.h"
+
+struct wpa_global;
+struct wpa_supplicant;
+struct wpa_ssid;
+struct wps_event_m2d;
+struct wps_event_fail;
+struct wps_credential;
+
+enum wpas_dbus_prop {
+	WPAS_DBUS_PROP_AP_SCAN,
+	WPAS_DBUS_PROP_SCANNING,
+	WPAS_DBUS_PROP_STATE,
+	WPAS_DBUS_PROP_CURRENT_BSS,
+	WPAS_DBUS_PROP_CURRENT_NETWORK,
+	WPAS_DBUS_PROP_CURRENT_AUTH_MODE,
+	WPAS_DBUS_PROP_BSSS,
+	WPAS_DBUS_PROP_DISCONNECT_REASON,
+};
+
+enum wpas_dbus_bss_prop {
+	WPAS_DBUS_BSS_PROP_SIGNAL,
+	WPAS_DBUS_BSS_PROP_FREQ,
+	WPAS_DBUS_BSS_PROP_MODE,
+	WPAS_DBUS_BSS_PROP_PRIVACY,
+	WPAS_DBUS_BSS_PROP_RATES,
+	WPAS_DBUS_BSS_PROP_WPA,
+	WPAS_DBUS_BSS_PROP_RSN,
+	WPAS_DBUS_BSS_PROP_WPS,
+	WPAS_DBUS_BSS_PROP_IES,
+};
+
+#define WPAS_DBUS_OBJECT_PATH_MAX 150
+
+#define WPAS_DBUS_NEW_SERVICE		"fi.w1.wpa_supplicant1"
+#define WPAS_DBUS_NEW_PATH		"/fi/w1/wpa_supplicant1"
+#define WPAS_DBUS_NEW_INTERFACE		"fi.w1.wpa_supplicant1"
+
+#define WPAS_DBUS_NEW_PATH_INTERFACES	WPAS_DBUS_NEW_PATH "/Interfaces"
+#define WPAS_DBUS_NEW_IFACE_INTERFACE	WPAS_DBUS_NEW_INTERFACE ".Interface"
+#define WPAS_DBUS_NEW_IFACE_WPS WPAS_DBUS_NEW_IFACE_INTERFACE ".WPS"
+
+#define WPAS_DBUS_NEW_NETWORKS_PART "Networks"
+#define WPAS_DBUS_NEW_IFACE_NETWORK WPAS_DBUS_NEW_INTERFACE ".Network"
+
+#define WPAS_DBUS_NEW_BSSIDS_PART "BSSs"
+#define WPAS_DBUS_NEW_IFACE_BSS	WPAS_DBUS_NEW_INTERFACE ".BSS"
+
+#define WPAS_DBUS_NEW_IFACE_P2PDEVICE	\
+		WPAS_DBUS_NEW_IFACE_INTERFACE ".P2PDevice"
+
+/*
+ * Groups correspond to P2P groups where this device is a GO (owner)
+ */
+#define WPAS_DBUS_NEW_P2P_GROUPS_PART	"Groups"
+#define	WPAS_DBUS_NEW_IFACE_P2P_GROUP WPAS_DBUS_NEW_INTERFACE ".Group"
+
+/*
+ * Different dbus object for persistent groups so they do not get confused
+ * with regular (configured) network objects.
+ */
+#define WPAS_DBUS_NEW_PERSISTENT_GROUPS_PART "PersistentGroups"
+#define WPAS_DBUS_NEW_IFACE_PERSISTENT_GROUP \
+	WPAS_DBUS_NEW_INTERFACE ".PersistentGroup"
+
+#define WPAS_DBUS_NEW_P2P_PEERS_PART	"Peers"
+#define	WPAS_DBUS_NEW_IFACE_P2P_PEER WPAS_DBUS_NEW_INTERFACE ".Peer"
+
+#define WPAS_DBUS_NEW_P2P_GROUPMEMBERS_PART	"Members"
+#define	WPAS_DBUS_NEW_IFACE_P2P_GROUPMEMBER \
+	WPAS_DBUS_NEW_INTERFACE ".GroupMember"
+
+/* Errors */
+#define WPAS_DBUS_ERROR_UNKNOWN_ERROR \
+	WPAS_DBUS_NEW_INTERFACE ".UnknownError"
+#define WPAS_DBUS_ERROR_INVALID_ARGS \
+	WPAS_DBUS_NEW_INTERFACE ".InvalidArgs"
+
+#define WPAS_DBUS_ERROR_IFACE_EXISTS \
+	WPAS_DBUS_NEW_INTERFACE ".InterfaceExists"
+#define WPAS_DBUS_ERROR_IFACE_UNKNOWN \
+	WPAS_DBUS_NEW_INTERFACE ".InterfaceUnknown"
+
+#define WPAS_DBUS_ERROR_NOT_CONNECTED \
+	WPAS_DBUS_NEW_INTERFACE ".NotConnected"
+#define WPAS_DBUS_ERROR_NETWORK_UNKNOWN \
+	WPAS_DBUS_NEW_INTERFACE ".NetworkUnknown"
+
+#define WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNAVAILABLE \
+	WPAS_DBUS_NEW_INTERFACE ".ConnectChannelUnavailable"
+#define WPAS_DBUS_ERROR_CONNECT_CHANNEL_UNSUPPORTED \
+	WPAS_DBUS_NEW_INTERFACE ".ConnectChannelUnsupported"
+#define WPAS_DBUS_ERROR_CONNECT_UNSPECIFIED_ERROR \
+	WPAS_DBUS_NEW_INTERFACE ".ConnectUnspecifiedError"
+
+#define WPAS_DBUS_ERROR_BLOB_EXISTS \
+	WPAS_DBUS_NEW_INTERFACE ".BlobExists"
+#define WPAS_DBUS_ERROR_BLOB_UNKNOWN \
+	WPAS_DBUS_NEW_INTERFACE ".BlobUnknown"
+
+#define WPAS_DBUS_ERROR_SUBSCRIPTION_IN_USE \
+	WPAS_DBUS_NEW_INTERFACE ".SubscriptionInUse"
+#define WPAS_DBUS_ERROR_NO_SUBSCRIPTION \
+	WPAS_DBUS_NEW_INTERFACE ".NoSubscription"
+#define WPAS_DBUS_ERROR_SUBSCRIPTION_EPERM \
+	WPAS_DBUS_NEW_INTERFACE ".SubscriptionNotYou"
+
+
+void wpas_dbus_subscribe_noc(struct wpas_dbus_priv *priv);
+void wpas_dbus_unsubscribe_noc(struct wpas_dbus_priv *priv);
+
+
+#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
+
+int wpas_dbus_ctrl_iface_init(struct wpas_dbus_priv *priv);
+void wpas_dbus_ctrl_iface_deinit(struct wpas_dbus_priv *iface);
+
+int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s);
+int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s);
+void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
+				   enum wpas_dbus_prop property);
+void wpas_dbus_bss_signal_prop_changed(struct wpa_supplicant *wpa_s,
+				       enum wpas_dbus_bss_prop property,
+				       unsigned int id);
+void wpas_dbus_signal_network_enabled_changed(struct wpa_supplicant *wpa_s,
+					      struct wpa_ssid *ssid);
+void wpas_dbus_signal_network_selected(struct wpa_supplicant *wpa_s, int id);
+void wpas_dbus_signal_network_request(struct wpa_supplicant *wpa_s,
+				      struct wpa_ssid *ssid,
+				      enum wpa_ctrl_req_type rtype,
+				      const char *default_text);
+void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s, int success);
+void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
+			       const struct wps_credential *cred);
+void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s,
+				    struct wps_event_m2d *m2d);
+void wpas_dbus_signal_wps_event_fail(struct wpa_supplicant *wpa_s,
+				     struct wps_event_fail *fail);
+void wpas_dbus_signal_wps_event_success(struct wpa_supplicant *wpa_s);
+int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
+			       struct wpa_ssid *ssid);
+int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s, int nid);
+int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s,
+			     u8 bssid[ETH_ALEN], unsigned int id);
+int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
+			   u8 bssid[ETH_ALEN], unsigned int id);
+void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
+				 const char *name);
+void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s,
+				   const char *name);
+void wpas_dbus_signal_debug_level_changed(struct wpa_global *global);
+void wpas_dbus_signal_debug_timestamp_changed(struct wpa_global *global);
+void wpas_dbus_signal_debug_show_keys_changed(struct wpa_global *global);
+
+int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s, const u8 *dev_addr);
+void wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+					   const u8 *dev_addr);
+int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+				  const u8 *dev_addr);
+void wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+					   const u8 *dev_addr);
+void wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+					const char *role);
+void wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+					      const u8 *dev_addr, int request,
+					      enum p2p_prov_disc_status status,
+					      u16 config_methods,
+					      unsigned int generated_pin);
+void wpas_dbus_signal_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+				     const u8 *src, u16 dev_passwd_id);
+void wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+					const struct wpa_ssid *ssid,
+					int client, int network_id);
+void wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+				  struct wpa_ssid *ssid);
+void wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
+				      struct p2p_go_neg_results *res);
+void wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+				    const struct wpa_ssid *ssid);
+int wpas_dbus_register_persistent_group(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid);
+int wpas_dbus_unregister_persistent_group(struct wpa_supplicant *wpa_s,
+					  int nid);
+void wpas_dbus_signal_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+					    int status, const u8 *bssid);
+void wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+					const u8 *p2p_if_addr);
+void wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+					  const u8 *p2p_if_addr);
+void wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+					    const u8 *member);
+void wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s,
+				     int freq, const u8 *sa, u8 dialog_token,
+				     u16 update_indic, const u8 *tlvs,
+				     size_t tlvs_len);
+void wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+				      const u8 *sa, u16 update_indic,
+				      const u8 *tlvs, size_t tlvs_len);
+void wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+				const u8 *member);
+void wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+				     struct wps_event_fail *fail);
+void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
+				    int depth, const char *subject,
+				    const char *cert_hash,
+				    const struct wpabuf *cert);
+void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
+			   const u8 *addr, const u8 *dst, const u8 *bssid,
+			   const u8 *ie, size_t ie_len, u32 ssi_signal);
+void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
+				 const char *status, const char *parameter);
+
+#else /* CONFIG_CTRL_IFACE_DBUS_NEW */
+
+static inline int wpas_dbus_register_interface(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline int wpas_dbus_unregister_interface(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+#define wpas_dbus_signal_state_changed(w, n, o) do { } while (0)
+
+static inline void wpas_dbus_signal_prop_changed(struct wpa_supplicant *wpa_s,
+						 enum wpas_dbus_prop property)
+{
+}
+
+static inline void wpas_dbus_bss_signal_prop_changed(
+	struct wpa_supplicant *wpa_s, enum wpas_dbus_bss_prop property,
+	unsigned int id)
+{
+}
+
+static inline void wpas_dbus_signal_network_enabled_changed(
+	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+}
+
+static inline void wpas_dbus_signal_network_selected(
+	struct wpa_supplicant *wpa_s, int id)
+{
+}
+
+static inline void wpas_dbus_signal_network_request(
+	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+	enum wpa_ctrl_req_type rtype, const char *default_txt)
+{
+}
+
+static inline void wpas_dbus_signal_scan_done(struct wpa_supplicant *wpa_s,
+					      int success)
+{
+}
+
+static inline void wpas_dbus_signal_wps_cred(struct wpa_supplicant *wpa_s,
+					     const struct wps_credential *cred)
+{
+}
+
+static inline void wpas_dbus_signal_wps_event_m2d(struct wpa_supplicant *wpa_s,
+						  struct wps_event_m2d *m2d)
+{
+}
+
+static inline void wpas_dbus_signal_wps_event_fail(
+	struct wpa_supplicant *wpa_s, struct wps_event_fail *fail)
+{
+}
+
+static inline void wpas_dbus_signal_wps_event_success(
+	struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int wpas_dbus_register_network(struct wpa_supplicant *wpa_s,
+					     struct wpa_ssid *ssid)
+{
+	return 0;
+}
+
+static inline int wpas_dbus_unregister_network(struct wpa_supplicant *wpa_s,
+					       int nid)
+{
+	return 0;
+}
+
+static inline int wpas_dbus_unregister_bss(struct wpa_supplicant *wpa_s,
+					   u8 bssid[ETH_ALEN], unsigned int id)
+{
+	return 0;
+}
+
+static inline int wpas_dbus_register_bss(struct wpa_supplicant *wpa_s,
+					 u8 bssid[ETH_ALEN], unsigned int id)
+{
+	return 0;
+}
+
+static inline void wpas_dbus_signal_blob_added(struct wpa_supplicant *wpa_s,
+					       const char *name)
+{
+}
+
+static inline void wpas_dbus_signal_blob_removed(struct wpa_supplicant *wpa_s,
+						 const char *name)
+{
+}
+
+static inline void wpas_dbus_signal_debug_level_changed(
+	struct wpa_global *global)
+{
+}
+
+static inline void wpas_dbus_signal_debug_timestamp_changed(
+	struct wpa_global *global)
+{
+}
+
+static inline void wpas_dbus_signal_debug_show_keys_changed(
+	struct wpa_global *global)
+{
+}
+
+static inline int wpas_dbus_register_peer(struct wpa_supplicant *wpa_s,
+					  const u8 *dev_addr)
+{
+	return 0;
+}
+
+static inline int wpas_dbus_unregister_peer(struct wpa_supplicant *wpa_s,
+					    const u8 *dev_addr)
+{
+	return 0;
+}
+
+static inline void
+wpas_dbus_signal_p2p_group_removed(struct wpa_supplicant *wpa_s,
+				   const char *role)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+					 const u8 *dev_addr, int request,
+					 enum p2p_prov_disc_status status,
+					 u16 config_methods,
+					 unsigned int generated_pin)
+{
+}
+
+static inline void wpas_dbus_signal_p2p_go_neg_req(
+				struct wpa_supplicant *wpa_s,
+				const u8 *src,
+				u16 dev_passwd_id)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_group_started(struct wpa_supplicant *wpa_s,
+				   const struct wpa_ssid *ssid,
+				   int client, int network_id)
+{
+}
+
+static inline void
+wpas_dbus_register_p2p_group(struct wpa_supplicant *wpa_s,
+			     struct wpa_ssid *ssid)
+{
+}
+
+static inline int wpas_dbus_register_persistent_group(
+	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+	return 0;
+}
+
+static inline int wpas_dbus_unregister_persistent_group(
+	struct wpa_supplicant *wpa_s, int nid)
+{
+	return 0;
+}
+
+static inline void
+wpas_dbus_signal_p2p_go_neg_resp(struct wpa_supplicant *wpa_s,
+				 struct p2p_go_neg_results *res)
+{
+}
+
+static inline void
+wpas_dbus_unregister_p2p_group(struct wpa_supplicant *wpa_s,
+			       const struct wpa_ssid *ssid)
+{
+}
+
+static inline void wpas_dbus_signal_p2p_invitation_result(
+				struct wpa_supplicant *wpa_s, int status,
+				const u8 *bssid)
+{
+}
+
+static inline void
+wpas_dbus_register_p2p_groupmember(struct wpa_supplicant *wpa_s,
+				   const u8 *p2p_if_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_sd_request(struct wpa_supplicant *wpa_s, int freq,
+				const u8 *sa, u8 dialog_token, u16 update_indic,
+				const u8 *tlvs, size_t tlvs_len)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_sd_response(struct wpa_supplicant *wpa_s,
+				 const u8 *sa, u16 update_indic,
+				 const u8 *tlvs, size_t tlvs_len)
+{
+}
+
+static inline void
+wpas_dbus_unregister_p2p_groupmember(struct wpa_supplicant *wpa_s,
+				     const u8 *p2p_if_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_peer_joined(struct wpa_supplicant *wpa_s,
+				 const u8 *member)
+{
+}
+
+static inline void
+wpas_dbus_signal_peer_device_found(struct wpa_supplicant *wpa_s,
+				   const u8 *dev_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_peer_device_lost(struct wpa_supplicant *wpa_s,
+				  const u8 *dev_addr)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_peer_disconnected(struct wpa_supplicant *wpa_s,
+				       const u8 *member)
+{
+}
+
+static inline void
+wpas_dbus_signal_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+				struct wps_event_fail *fail)
+{
+}
+
+static inline void wpas_dbus_signal_certification(struct wpa_supplicant *wpa_s,
+						  int depth,
+						  const char *subject,
+						  const char *cert_hash,
+						  const struct wpabuf *cert)
+{
+}
+
+static inline void wpas_dbus_signal_preq(struct wpa_supplicant *wpa_s,
+					 const u8 *addr, const u8 *dst,
+					 const u8 *bssid,
+					 const u8 *ie, size_t ie_len,
+					 u32 ssi_signal)
+{
+}
+
+static inline void wpas_dbus_signal_eap_status(struct wpa_supplicant *wpa_s,
+					       const char *status,
+					       const char *parameter)
+{
+}
+
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+
+#endif /* CTRL_IFACE_DBUS_H_NEW */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/dbus/dbus_old.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,137 @@
+/*
+ * WPA Supplicant / dbus-based control interface
+ * Copyright (c) 2006, Dan Williams <dcbw@redhat.com> and Red Hat, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CTRL_IFACE_DBUS_H
+#define CTRL_IFACE_DBUS_H
+
+struct wps_credential;
+
+#ifdef CONFIG_CTRL_IFACE_DBUS
+
+#define WPAS_DBUS_OBJECT_PATH_MAX 150
+
+#define WPAS_DBUS_SERVICE	"fi.epitest.hostap.WPASupplicant"
+#define WPAS_DBUS_PATH		"/fi/epitest/hostap/WPASupplicant"
+#define WPAS_DBUS_INTERFACE	"fi.epitest.hostap.WPASupplicant"
+
+#define WPAS_DBUS_PATH_INTERFACES	WPAS_DBUS_PATH "/Interfaces"
+#define WPAS_DBUS_IFACE_INTERFACE	WPAS_DBUS_INTERFACE ".Interface"
+
+#define WPAS_DBUS_NETWORKS_PART "Networks"
+#define WPAS_DBUS_IFACE_NETWORK	WPAS_DBUS_INTERFACE ".Network"
+
+#define WPAS_DBUS_BSSIDS_PART	"BSSIDs"
+#define WPAS_DBUS_IFACE_BSSID	WPAS_DBUS_INTERFACE ".BSSID"
+
+
+/* Errors */
+#define WPAS_ERROR_INVALID_NETWORK \
+	WPAS_DBUS_IFACE_INTERFACE ".InvalidNetwork"
+#define WPAS_ERROR_INVALID_BSSID \
+	WPAS_DBUS_IFACE_INTERFACE ".InvalidBSSID"
+
+#define WPAS_ERROR_INVALID_OPTS \
+	WPAS_DBUS_INTERFACE ".InvalidOptions"
+#define WPAS_ERROR_INVALID_IFACE \
+	WPAS_DBUS_INTERFACE ".InvalidInterface"
+
+#define WPAS_ERROR_ADD_ERROR \
+	WPAS_DBUS_INTERFACE ".AddError"
+#define WPAS_ERROR_EXISTS_ERROR \
+	WPAS_DBUS_INTERFACE ".ExistsError"
+#define WPAS_ERROR_REMOVE_ERROR \
+	WPAS_DBUS_INTERFACE ".RemoveError"
+
+#define WPAS_ERROR_SCAN_ERROR \
+	WPAS_DBUS_IFACE_INTERFACE ".ScanError"
+#define WPAS_ERROR_ADD_NETWORK_ERROR \
+	WPAS_DBUS_IFACE_INTERFACE ".AddNetworkError"
+#define WPAS_ERROR_INTERNAL_ERROR \
+	WPAS_DBUS_IFACE_INTERFACE ".InternalError"
+#define WPAS_ERROR_REMOVE_NETWORK_ERROR \
+	WPAS_DBUS_IFACE_INTERFACE ".RemoveNetworkError"
+
+#define WPAS_ERROR_WPS_PBC_ERROR \
+	WPAS_DBUS_IFACE_INTERFACE ".WpsPbcError"
+#define WPAS_ERROR_WPS_PIN_ERROR \
+	WPAS_DBUS_IFACE_INTERFACE ".WpsPinError"
+#define WPAS_ERROR_WPS_REG_ERROR \
+	WPAS_DBUS_IFACE_INTERFACE ".WpsRegError"
+
+#define WPAS_DBUS_BSSID_FORMAT "%02x%02x%02x%02x%02x%02x"
+
+struct wpa_global;
+struct wpa_supplicant;
+
+int wpa_supplicant_dbus_ctrl_iface_init(struct wpas_dbus_priv *iface);
+void wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
+					     enum wpa_states new_state,
+					     enum wpa_states old_state);
+void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
+					 const struct wps_credential *cred);
+void wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
+					      int depth, const char *subject,
+					      const char *cert_hash,
+					      const struct wpabuf *cert);
+
+char * wpas_dbus_decompose_object_path(const char *path, char **network,
+                                       char **bssid);
+
+int wpas_dbus_register_iface(struct wpa_supplicant *wpa_s);
+int wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s);
+
+
+/* Methods internal to the dbus control interface */
+struct wpa_supplicant * wpa_supplicant_get_iface_by_dbus_path(
+	struct wpa_global *global, const char *path);
+
+#else /* CONFIG_CTRL_IFACE_DBUS */
+
+static inline void
+wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void
+wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
+{
+}
+
+#define wpa_supplicant_dbus_notify_state_change(w,n,o) do { } while (0)
+
+static inline void
+wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
+				    const struct wps_credential *cred)
+{
+}
+
+static inline void
+wpa_supplicant_dbus_notify_certification(struct wpa_supplicant *wpa_s,
+					      int depth, const char *subject,
+					      const char *cert_hash,
+					      const struct wpabuf *cert)
+{
+}
+
+static inline int
+wpas_dbus_register_iface(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline int
+wpas_dbus_unregister_iface(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+#endif /* CONFIG_CTRL_IFACE_DBUS */
+
+#endif /* CTRL_IFACE_DBUS_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/driver_i.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,692 @@
+/*
+ * wpa_supplicant - Internal driver interface wrappers
+ * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DRIVER_I_H
+#define DRIVER_I_H
+
+#include "drivers/driver.h"
+
+/* driver_ops */
+static inline void * wpa_drv_init(struct wpa_supplicant *wpa_s,
+				  const char *ifname)
+{
+	if (wpa_s->driver->init2)
+		return wpa_s->driver->init2(wpa_s, ifname,
+					    wpa_s->global_drv_priv);
+	if (wpa_s->driver->init) {
+		return wpa_s->driver->init(wpa_s, ifname);
+	}
+	return NULL;
+}
+
+static inline void wpa_drv_deinit(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->deinit)
+		wpa_s->driver->deinit(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_set_param(struct wpa_supplicant *wpa_s,
+				    const char *param)
+{
+	if (wpa_s->driver->set_param)
+		return wpa_s->driver->set_param(wpa_s->drv_priv, param);
+	return 0;
+}
+
+static inline int wpa_drv_set_countermeasures(struct wpa_supplicant *wpa_s,
+					      int enabled)
+{
+	if (wpa_s->driver->set_countermeasures) {
+		return wpa_s->driver->set_countermeasures(wpa_s->drv_priv,
+							  enabled);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_authenticate(struct wpa_supplicant *wpa_s,
+				       struct wpa_driver_auth_params *params)
+{
+	if (wpa_s->driver->authenticate)
+		return wpa_s->driver->authenticate(wpa_s->drv_priv, params);
+	return -1;
+}
+
+static inline int wpa_drv_associate(struct wpa_supplicant *wpa_s,
+				    struct wpa_driver_associate_params *params)
+{
+	if (wpa_s->driver->associate) {
+		return wpa_s->driver->associate(wpa_s->drv_priv, params);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_scan(struct wpa_supplicant *wpa_s,
+			       struct wpa_driver_scan_params *params)
+{
+	if (wpa_s->driver->scan2)
+		return wpa_s->driver->scan2(wpa_s->drv_priv, params);
+	return -1;
+}
+
+static inline int wpa_drv_sched_scan(struct wpa_supplicant *wpa_s,
+				     struct wpa_driver_scan_params *params,
+				     u32 interval)
+{
+	if (wpa_s->driver->sched_scan)
+		return wpa_s->driver->sched_scan(wpa_s->drv_priv,
+						 params, interval);
+	return -1;
+}
+
+static inline int wpa_drv_stop_sched_scan(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->stop_sched_scan)
+		return wpa_s->driver->stop_sched_scan(wpa_s->drv_priv);
+	return -1;
+}
+
+static inline struct wpa_scan_results * wpa_drv_get_scan_results2(
+	struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->get_scan_results2)
+		return wpa_s->driver->get_scan_results2(wpa_s->drv_priv);
+	return NULL;
+}
+
+static inline int wpa_drv_get_bssid(struct wpa_supplicant *wpa_s, u8 *bssid)
+{
+	if (wpa_s->driver->get_bssid) {
+		return wpa_s->driver->get_bssid(wpa_s->drv_priv, bssid);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_get_ssid(struct wpa_supplicant *wpa_s, u8 *ssid)
+{
+	if (wpa_s->driver->get_ssid) {
+		return wpa_s->driver->get_ssid(wpa_s->drv_priv, ssid);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_set_key(struct wpa_supplicant *wpa_s,
+				  enum wpa_alg alg, const u8 *addr,
+				  int key_idx, int set_tx,
+				   const u8 *seq, size_t seq_len,
+				   const u8 *key, size_t key_len)
+{
+	if (wpa_s->driver->set_key) {
+		wpa_s->keys_cleared = 0;
+		return wpa_s->driver->set_key(wpa_s->ifname, wpa_s->drv_priv,
+					      alg, addr, key_idx, set_tx,
+					      seq, seq_len, key, key_len);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_deauthenticate(struct wpa_supplicant *wpa_s,
+					 const u8 *addr, int reason_code)
+{
+	if (wpa_s->driver->deauthenticate) {
+		return wpa_s->driver->deauthenticate(wpa_s->drv_priv, addr,
+						     reason_code);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_add_pmkid(struct wpa_supplicant *wpa_s,
+				    const u8 *bssid, const u8 *pmkid)
+{
+	if (wpa_s->driver->add_pmkid) {
+		return wpa_s->driver->add_pmkid(wpa_s->drv_priv, bssid, pmkid);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_remove_pmkid(struct wpa_supplicant *wpa_s,
+				       const u8 *bssid, const u8 *pmkid)
+{
+	if (wpa_s->driver->remove_pmkid) {
+		return wpa_s->driver->remove_pmkid(wpa_s->drv_priv, bssid,
+						   pmkid);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_flush_pmkid(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->flush_pmkid) {
+		return wpa_s->driver->flush_pmkid(wpa_s->drv_priv);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_get_capa(struct wpa_supplicant *wpa_s,
+				   struct wpa_driver_capa *capa)
+{
+	if (wpa_s->driver->get_capa) {
+		return wpa_s->driver->get_capa(wpa_s->drv_priv, capa);
+	}
+	return -1;
+}
+
+static inline void wpa_drv_poll(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->poll) {
+		wpa_s->driver->poll(wpa_s->drv_priv);
+	}
+}
+
+static inline const char * wpa_drv_get_ifname(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->get_ifname) {
+		return wpa_s->driver->get_ifname(wpa_s->drv_priv);
+	}
+	return NULL;
+}
+
+static inline const u8 * wpa_drv_get_mac_addr(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->get_mac_addr) {
+		return wpa_s->driver->get_mac_addr(wpa_s->drv_priv);
+	}
+	return NULL;
+}
+
+static inline int wpa_drv_send_eapol(struct wpa_supplicant *wpa_s,
+				     const u8 *dst, u16 proto,
+				     const u8 *data, size_t data_len)
+{
+	if (wpa_s->driver->send_eapol)
+		return wpa_s->driver->send_eapol(wpa_s->drv_priv, dst, proto,
+						 data, data_len);
+	return -1;
+}
+
+static inline int wpa_drv_set_operstate(struct wpa_supplicant *wpa_s,
+					int state)
+{
+	if (wpa_s->driver->set_operstate)
+		return wpa_s->driver->set_operstate(wpa_s->drv_priv, state);
+	return 0;
+}
+
+static inline int wpa_drv_mlme_setprotection(struct wpa_supplicant *wpa_s,
+					     const u8 *addr, int protect_type,
+					     int key_type)
+{
+	if (wpa_s->driver->mlme_setprotection)
+		return wpa_s->driver->mlme_setprotection(wpa_s->drv_priv, addr,
+							 protect_type,
+							 key_type);
+	return 0;
+}
+
+static inline struct hostapd_hw_modes *
+wpa_drv_get_hw_feature_data(struct wpa_supplicant *wpa_s, u16 *num_modes,
+			    u16 *flags)
+{
+	if (wpa_s->driver->get_hw_feature_data)
+		return wpa_s->driver->get_hw_feature_data(wpa_s->drv_priv,
+							  num_modes, flags);
+	return NULL;
+}
+
+static inline int wpa_drv_set_country(struct wpa_supplicant *wpa_s,
+				      const char *alpha2)
+{
+	if (wpa_s->driver->set_country)
+		return wpa_s->driver->set_country(wpa_s->drv_priv, alpha2);
+	return 0;
+}
+
+static inline int wpa_drv_send_mlme(struct wpa_supplicant *wpa_s,
+				    const u8 *data, size_t data_len, int noack)
+{
+	if (wpa_s->driver->send_mlme)
+		return wpa_s->driver->send_mlme(wpa_s->drv_priv,
+						data, data_len, noack);
+	return -1;
+}
+
+static inline int wpa_drv_update_ft_ies(struct wpa_supplicant *wpa_s,
+					const u8 *md,
+					const u8 *ies, size_t ies_len)
+{
+	if (wpa_s->driver->update_ft_ies)
+		return wpa_s->driver->update_ft_ies(wpa_s->drv_priv, md,
+						    ies, ies_len);
+	return -1;
+}
+
+static inline int wpa_drv_send_ft_action(struct wpa_supplicant *wpa_s,
+					 u8 action, const u8 *target_ap,
+					 const u8 *ies, size_t ies_len)
+{
+	if (wpa_s->driver->send_ft_action)
+		return wpa_s->driver->send_ft_action(wpa_s->drv_priv, action,
+						     target_ap, ies, ies_len);
+	return -1;
+}
+
+static inline int wpa_drv_set_ap(struct wpa_supplicant *wpa_s,
+				 struct wpa_driver_ap_params *params)
+{
+	if (wpa_s->driver->set_ap)
+		return wpa_s->driver->set_ap(wpa_s->drv_priv, params);
+	return -1;
+}
+
+static inline int wpa_drv_sta_add(struct wpa_supplicant *wpa_s,
+				  struct hostapd_sta_add_params *params)
+{
+	if (wpa_s->driver->sta_add)
+		return wpa_s->driver->sta_add(wpa_s->drv_priv, params);
+	return -1;
+}
+
+static inline int wpa_drv_sta_remove(struct wpa_supplicant *wpa_s,
+				     const u8 *addr)
+{
+	if (wpa_s->driver->sta_remove)
+		return wpa_s->driver->sta_remove(wpa_s->drv_priv, addr);
+	return -1;
+}
+
+static inline int wpa_drv_hapd_send_eapol(struct wpa_supplicant *wpa_s,
+					  const u8 *addr, const u8 *data,
+					  size_t data_len, int encrypt,
+					  const u8 *own_addr, u32 flags)
+{
+	if (wpa_s->driver->hapd_send_eapol)
+		return wpa_s->driver->hapd_send_eapol(wpa_s->drv_priv, addr,
+						      data, data_len, encrypt,
+						      own_addr, flags);
+	return -1;
+}
+
+static inline int wpa_drv_sta_set_flags(struct wpa_supplicant *wpa_s,
+					const u8 *addr, int total_flags,
+					int flags_or, int flags_and)
+{
+	if (wpa_s->driver->sta_set_flags)
+		return wpa_s->driver->sta_set_flags(wpa_s->drv_priv, addr,
+						    total_flags, flags_or,
+						    flags_and);
+	return -1;
+}
+
+static inline int wpa_drv_set_supp_port(struct wpa_supplicant *wpa_s,
+					int authorized)
+{
+	if (wpa_s->driver->set_supp_port) {
+		return wpa_s->driver->set_supp_port(wpa_s->drv_priv,
+						    authorized);
+	}
+	return 0;
+}
+
+static inline int wpa_drv_send_action(struct wpa_supplicant *wpa_s,
+				      unsigned int freq,
+				      unsigned int wait,
+				      const u8 *dst, const u8 *src,
+				      const u8 *bssid,
+				      const u8 *data, size_t data_len,
+				      int no_cck)
+{
+	if (wpa_s->driver->send_action)
+		return wpa_s->driver->send_action(wpa_s->drv_priv, freq,
+						  wait, dst, src, bssid,
+						  data, data_len, no_cck);
+	return -1;
+}
+
+static inline void wpa_drv_send_action_cancel_wait(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->send_action_cancel_wait)
+		wpa_s->driver->send_action_cancel_wait(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_set_freq(struct wpa_supplicant *wpa_s,
+				   struct hostapd_freq_params *freq)
+{
+	if (wpa_s->driver->set_freq)
+		return wpa_s->driver->set_freq(wpa_s->drv_priv, freq);
+	return -1;
+}
+
+static inline int wpa_drv_if_add(struct wpa_supplicant *wpa_s,
+				 enum wpa_driver_if_type type,
+				 const char *ifname, const u8 *addr,
+				 void *bss_ctx, char *force_ifname,
+				 u8 *if_addr, const char *bridge)
+{
+	if (wpa_s->driver->if_add)
+		return wpa_s->driver->if_add(wpa_s->drv_priv, type, ifname,
+					     addr, bss_ctx, NULL, force_ifname,
+					     if_addr, bridge);
+	return -1;
+}
+
+static inline int wpa_drv_if_remove(struct wpa_supplicant *wpa_s,
+				    enum wpa_driver_if_type type,
+				    const char *ifname)
+{
+	if (wpa_s->driver->if_remove)
+		return wpa_s->driver->if_remove(wpa_s->drv_priv, type, ifname);
+	return -1;
+}
+
+static inline int wpa_drv_remain_on_channel(struct wpa_supplicant *wpa_s,
+					    unsigned int freq,
+					    unsigned int duration)
+{
+	if (wpa_s->driver->remain_on_channel)
+		return wpa_s->driver->remain_on_channel(wpa_s->drv_priv, freq,
+							duration);
+	return -1;
+}
+
+static inline int wpa_drv_cancel_remain_on_channel(
+	struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->cancel_remain_on_channel)
+		return wpa_s->driver->cancel_remain_on_channel(
+			wpa_s->drv_priv);
+	return -1;
+}
+
+static inline int wpa_drv_probe_req_report(struct wpa_supplicant *wpa_s,
+					   int report)
+{
+	if (wpa_s->driver->probe_req_report)
+		return wpa_s->driver->probe_req_report(wpa_s->drv_priv,
+						       report);
+	return -1;
+}
+
+static inline int wpa_drv_deinit_ap(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->deinit_ap)
+		return wpa_s->driver->deinit_ap(wpa_s->drv_priv);
+	return 0;
+}
+
+static inline int wpa_drv_deinit_p2p_cli(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->deinit_p2p_cli)
+		return wpa_s->driver->deinit_p2p_cli(wpa_s->drv_priv);
+	return 0;
+}
+
+static inline void wpa_drv_suspend(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->suspend)
+		wpa_s->driver->suspend(wpa_s->drv_priv);
+}
+
+static inline void wpa_drv_resume(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->resume)
+		wpa_s->driver->resume(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_signal_monitor(struct wpa_supplicant *wpa_s,
+					 int threshold, int hysteresis)
+{
+	if (wpa_s->driver->signal_monitor)
+		return wpa_s->driver->signal_monitor(wpa_s->drv_priv,
+						     threshold, hysteresis);
+	return -1;
+}
+
+static inline int wpa_drv_signal_poll(struct wpa_supplicant *wpa_s,
+				      struct wpa_signal_info *si)
+{
+	if (wpa_s->driver->signal_poll)
+		return wpa_s->driver->signal_poll(wpa_s->drv_priv, si);
+	return -1;
+}
+
+static inline int wpa_drv_pktcnt_poll(struct wpa_supplicant *wpa_s,
+				      struct hostap_sta_driver_data *sta)
+{
+	if (wpa_s->driver->read_sta_data)
+		return wpa_s->driver->read_sta_data(wpa_s->drv_priv, sta,
+						    wpa_s->bssid);
+	return -1;
+}
+
+static inline int wpa_drv_set_ap_wps_ie(struct wpa_supplicant *wpa_s,
+					const struct wpabuf *beacon,
+					const struct wpabuf *proberesp,
+					const struct wpabuf *assocresp)
+{
+	if (!wpa_s->driver->set_ap_wps_ie)
+		return -1;
+	return wpa_s->driver->set_ap_wps_ie(wpa_s->drv_priv, beacon,
+					    proberesp, assocresp);
+}
+
+static inline int wpa_drv_shared_freq(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->driver->shared_freq)
+		return -1;
+	return wpa_s->driver->shared_freq(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_get_noa(struct wpa_supplicant *wpa_s,
+				  u8 *buf, size_t buf_len)
+{
+	if (!wpa_s->driver->get_noa)
+		return -1;
+	return wpa_s->driver->get_noa(wpa_s->drv_priv, buf, buf_len);
+}
+
+static inline int wpa_drv_set_p2p_powersave(struct wpa_supplicant *wpa_s,
+					    int legacy_ps, int opp_ps,
+					    int ctwindow)
+{
+	if (!wpa_s->driver->set_p2p_powersave)
+		return -1;
+	return wpa_s->driver->set_p2p_powersave(wpa_s->drv_priv, legacy_ps,
+						opp_ps, ctwindow);
+}
+
+static inline int wpa_drv_ampdu(struct wpa_supplicant *wpa_s, int ampdu)
+{
+	if (!wpa_s->driver->ampdu)
+		return -1;
+	return wpa_s->driver->ampdu(wpa_s->drv_priv, ampdu);
+}
+
+static inline int wpa_drv_p2p_find(struct wpa_supplicant *wpa_s,
+				   unsigned int timeout, int type)
+{
+	if (!wpa_s->driver->p2p_find)
+		return -1;
+	return wpa_s->driver->p2p_find(wpa_s->drv_priv, timeout, type);
+}
+
+static inline int wpa_drv_p2p_stop_find(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->driver->p2p_stop_find)
+		return -1;
+	return wpa_s->driver->p2p_stop_find(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_p2p_listen(struct wpa_supplicant *wpa_s,
+				     unsigned int timeout)
+{
+	if (!wpa_s->driver->p2p_listen)
+		return -1;
+	return wpa_s->driver->p2p_listen(wpa_s->drv_priv, timeout);
+}
+
+static inline int wpa_drv_p2p_connect(struct wpa_supplicant *wpa_s,
+				      const u8 *peer_addr, int wps_method,
+				      int go_intent,
+				      const u8 *own_interface_addr,
+				      unsigned int force_freq,
+				      int persistent_group)
+{
+	if (!wpa_s->driver->p2p_connect)
+		return -1;
+	return wpa_s->driver->p2p_connect(wpa_s->drv_priv, peer_addr,
+					  wps_method, go_intent,
+					  own_interface_addr, force_freq,
+					  persistent_group);
+}
+
+static inline int wpa_drv_wps_success_cb(struct wpa_supplicant *wpa_s,
+					 const u8 *peer_addr)
+{
+	if (!wpa_s->driver->wps_success_cb)
+		return -1;
+	return wpa_s->driver->wps_success_cb(wpa_s->drv_priv, peer_addr);
+}
+
+static inline int
+wpa_drv_p2p_group_formation_failed(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->driver->p2p_group_formation_failed)
+		return -1;
+	return wpa_s->driver->p2p_group_formation_failed(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_p2p_set_params(struct wpa_supplicant *wpa_s,
+					 const struct p2p_params *params)
+{
+	if (!wpa_s->driver->p2p_set_params)
+		return -1;
+	return wpa_s->driver->p2p_set_params(wpa_s->drv_priv, params);
+}
+
+static inline int wpa_drv_p2p_prov_disc_req(struct wpa_supplicant *wpa_s,
+					    const u8 *peer_addr,
+					    u16 config_methods, int join)
+{
+	if (!wpa_s->driver->p2p_prov_disc_req)
+		return -1;
+	return wpa_s->driver->p2p_prov_disc_req(wpa_s->drv_priv, peer_addr,
+						config_methods, join);
+}
+
+static inline u64 wpa_drv_p2p_sd_request(struct wpa_supplicant *wpa_s,
+					 const u8 *dst,
+					 const struct wpabuf *tlvs)
+{
+	if (!wpa_s->driver->p2p_sd_request)
+		return 0;
+	return wpa_s->driver->p2p_sd_request(wpa_s->drv_priv, dst, tlvs);
+}
+
+static inline int wpa_drv_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s,
+						u64 req)
+{
+	if (!wpa_s->driver->p2p_sd_cancel_request)
+		return -1;
+	return wpa_s->driver->p2p_sd_cancel_request(wpa_s->drv_priv, req);
+}
+
+static inline int wpa_drv_p2p_sd_response(struct wpa_supplicant *wpa_s,
+					  int freq, const u8 *dst,
+					  u8 dialog_token,
+					  const struct wpabuf *resp_tlvs)
+{
+	if (!wpa_s->driver->p2p_sd_response)
+		return -1;
+	return wpa_s->driver->p2p_sd_response(wpa_s->drv_priv, freq, dst,
+					      dialog_token, resp_tlvs);
+}
+
+static inline int wpa_drv_p2p_service_update(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->driver->p2p_service_update)
+		return -1;
+	return wpa_s->driver->p2p_service_update(wpa_s->drv_priv);
+}
+
+static inline int wpa_drv_p2p_reject(struct wpa_supplicant *wpa_s,
+				     const u8 *addr)
+{
+	if (!wpa_s->driver->p2p_reject)
+		return -1;
+	return wpa_s->driver->p2p_reject(wpa_s->drv_priv, addr);
+}
+
+static inline int wpa_drv_p2p_invite(struct wpa_supplicant *wpa_s,
+				     const u8 *peer, int role, const u8 *bssid,
+				     const u8 *ssid, size_t ssid_len,
+				     const u8 *go_dev_addr,
+				     int persistent_group)
+{
+	if (!wpa_s->driver->p2p_invite)
+		return -1;
+	return wpa_s->driver->p2p_invite(wpa_s->drv_priv, peer, role, bssid,
+					 ssid, ssid_len, go_dev_addr,
+					 persistent_group);
+}
+
+static inline int wpa_drv_send_tdls_mgmt(struct wpa_supplicant *wpa_s,
+					 const u8 *dst, u8 action_code,
+					 u8 dialog_token, u16 status_code,
+					 const u8 *buf, size_t len)
+{
+	if (wpa_s->driver->send_tdls_mgmt) {
+		return wpa_s->driver->send_tdls_mgmt(wpa_s->drv_priv, dst,
+						     action_code, dialog_token,
+						     status_code, buf, len);
+	}
+	return -1;
+}
+
+static inline int wpa_drv_tdls_oper(struct wpa_supplicant *wpa_s,
+				    enum tdls_oper oper, const u8 *peer)
+{
+	if (!wpa_s->driver->tdls_oper)
+		return -1;
+	return wpa_s->driver->tdls_oper(wpa_s->drv_priv, oper, peer);
+}
+
+static inline void wpa_drv_set_rekey_info(struct wpa_supplicant *wpa_s,
+					  const u8 *kek, const u8 *kck,
+					  const u8 *replay_ctr)
+{
+	if (!wpa_s->driver->set_rekey_info)
+		return;
+	wpa_s->driver->set_rekey_info(wpa_s->drv_priv, kek, kck, replay_ctr);
+}
+
+static inline int wpa_drv_radio_disable(struct wpa_supplicant *wpa_s,
+					int disabled)
+{
+	if (!wpa_s->driver->radio_disable)
+		return -1;
+	return wpa_s->driver->radio_disable(wpa_s->drv_priv, disabled);
+}
+
+static inline int wpa_drv_switch_channel(struct wpa_supplicant *wpa_s,
+					 unsigned int freq)
+{
+	if (!wpa_s->driver->switch_channel)
+		return -1;
+	return wpa_s->driver->switch_channel(wpa_s->drv_priv, freq);
+}
+
+static inline int wpa_drv_wnm_oper(struct wpa_supplicant *wpa_s,
+				   enum wnm_oper oper, const u8 *peer,
+				   u8 *buf, u16 *buf_len)
+{
+	if (!wpa_s->driver->wnm_oper)
+		return -1;
+	return wpa_s->driver->wnm_oper(wpa_s->drv_priv, oper, peer, buf,
+				       buf_len);
+}
+
+#endif /* DRIVER_I_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/eap_register.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,249 @@
+/*
+ * EAP method registration
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_peer/eap_methods.h"
+#include "eap_server/eap_methods.h"
+#include "wpa_supplicant_i.h"
+
+
+/**
+ * eap_register_methods - Register statically linked EAP methods
+ * Returns: 0 on success, -1 or -2 on failure
+ *
+ * This function is called at program initialization to register all EAP
+ * methods that were linked in statically.
+ */
+int eap_register_methods(void)
+{
+	int ret = 0;
+
+#ifdef EAP_MD5
+	if (ret == 0)
+		ret = eap_peer_md5_register();
+#endif /* EAP_MD5 */
+
+#ifdef EAP_TLS
+	if (ret == 0)
+		ret = eap_peer_tls_register();
+#endif /* EAP_TLS */
+
+#ifdef EAP_UNAUTH_TLS
+	if (ret == 0)
+		ret = eap_peer_unauth_tls_register();
+#endif /* EAP_UNAUTH_TLS */
+
+#ifdef EAP_MSCHAPv2
+	if (ret == 0)
+		ret = eap_peer_mschapv2_register();
+#endif /* EAP_MSCHAPv2 */
+
+#ifdef EAP_PEAP
+	if (ret == 0)
+		ret = eap_peer_peap_register();
+#endif /* EAP_PEAP */
+
+#ifdef EAP_TTLS
+	if (ret == 0)
+		ret = eap_peer_ttls_register();
+#endif /* EAP_TTLS */
+
+#ifdef EAP_GTC
+	if (ret == 0)
+		ret = eap_peer_gtc_register();
+#endif /* EAP_GTC */
+
+#ifdef EAP_OTP
+	if (ret == 0)
+		ret = eap_peer_otp_register();
+#endif /* EAP_OTP */
+
+#ifdef EAP_SIM
+	if (ret == 0)
+		ret = eap_peer_sim_register();
+#endif /* EAP_SIM */
+
+#ifdef EAP_LEAP
+	if (ret == 0)
+		ret = eap_peer_leap_register();
+#endif /* EAP_LEAP */
+
+#ifdef EAP_PSK
+	if (ret == 0)
+		ret = eap_peer_psk_register();
+#endif /* EAP_PSK */
+
+#ifdef EAP_AKA
+	if (ret == 0)
+		ret = eap_peer_aka_register();
+#endif /* EAP_AKA */
+
+#ifdef EAP_AKA_PRIME
+	if (ret == 0)
+		ret = eap_peer_aka_prime_register();
+#endif /* EAP_AKA_PRIME */
+
+#ifdef EAP_FAST
+	if (ret == 0)
+		ret = eap_peer_fast_register();
+#endif /* EAP_FAST */
+
+#ifdef EAP_PAX
+	if (ret == 0)
+		ret = eap_peer_pax_register();
+#endif /* EAP_PAX */
+
+#ifdef EAP_SAKE
+	if (ret == 0)
+		ret = eap_peer_sake_register();
+#endif /* EAP_SAKE */
+
+#ifdef EAP_GPSK
+	if (ret == 0)
+		ret = eap_peer_gpsk_register();
+#endif /* EAP_GPSK */
+
+#ifdef EAP_WSC
+	if (ret == 0)
+		ret = eap_peer_wsc_register();
+#endif /* EAP_WSC */
+
+#ifdef EAP_IKEV2
+	if (ret == 0)
+		ret = eap_peer_ikev2_register();
+#endif /* EAP_IKEV2 */
+
+#ifdef EAP_VENDOR_TEST
+	if (ret == 0)
+		ret = eap_peer_vendor_test_register();
+#endif /* EAP_VENDOR_TEST */
+
+#ifdef EAP_TNC
+	if (ret == 0)
+		ret = eap_peer_tnc_register();
+#endif /* EAP_TNC */
+
+#ifdef EAP_PWD
+	if (ret == 0)
+		ret = eap_peer_pwd_register();
+#endif /* EAP_PWD */
+
+#ifdef EAP_SERVER_IDENTITY
+	if (ret == 0)
+		ret = eap_server_identity_register();
+#endif /* EAP_SERVER_IDENTITY */
+
+#ifdef EAP_SERVER_MD5
+	if (ret == 0)
+		ret = eap_server_md5_register();
+#endif /* EAP_SERVER_MD5 */
+
+#ifdef EAP_SERVER_TLS
+	if (ret == 0)
+		ret = eap_server_tls_register();
+#endif /* EAP_SERVER_TLS */
+
+#ifdef EAP_SERVER_UNAUTH_TLS
+	if (ret == 0)
+		ret = eap_server_unauth_tls_register();
+#endif /* EAP_SERVER_UNAUTH_TLS */
+
+#ifdef EAP_SERVER_MSCHAPV2
+	if (ret == 0)
+		ret = eap_server_mschapv2_register();
+#endif /* EAP_SERVER_MSCHAPV2 */
+
+#ifdef EAP_SERVER_PEAP
+	if (ret == 0)
+		ret = eap_server_peap_register();
+#endif /* EAP_SERVER_PEAP */
+
+#ifdef EAP_SERVER_TLV
+	if (ret == 0)
+		ret = eap_server_tlv_register();
+#endif /* EAP_SERVER_TLV */
+
+#ifdef EAP_SERVER_GTC
+	if (ret == 0)
+		ret = eap_server_gtc_register();
+#endif /* EAP_SERVER_GTC */
+
+#ifdef EAP_SERVER_TTLS
+	if (ret == 0)
+		ret = eap_server_ttls_register();
+#endif /* EAP_SERVER_TTLS */
+
+#ifdef EAP_SERVER_SIM
+	if (ret == 0)
+		ret = eap_server_sim_register();
+#endif /* EAP_SERVER_SIM */
+
+#ifdef EAP_SERVER_AKA
+	if (ret == 0)
+		ret = eap_server_aka_register();
+#endif /* EAP_SERVER_AKA */
+
+#ifdef EAP_SERVER_AKA_PRIME
+	if (ret == 0)
+		ret = eap_server_aka_prime_register();
+#endif /* EAP_SERVER_AKA_PRIME */
+
+#ifdef EAP_SERVER_PAX
+	if (ret == 0)
+		ret = eap_server_pax_register();
+#endif /* EAP_SERVER_PAX */
+
+#ifdef EAP_SERVER_PSK
+	if (ret == 0)
+		ret = eap_server_psk_register();
+#endif /* EAP_SERVER_PSK */
+
+#ifdef EAP_SERVER_SAKE
+	if (ret == 0)
+		ret = eap_server_sake_register();
+#endif /* EAP_SERVER_SAKE */
+
+#ifdef EAP_SERVER_GPSK
+	if (ret == 0)
+		ret = eap_server_gpsk_register();
+#endif /* EAP_SERVER_GPSK */
+
+#ifdef EAP_SERVER_VENDOR_TEST
+	if (ret == 0)
+		ret = eap_server_vendor_test_register();
+#endif /* EAP_SERVER_VENDOR_TEST */
+
+#ifdef EAP_SERVER_FAST
+	if (ret == 0)
+		ret = eap_server_fast_register();
+#endif /* EAP_SERVER_FAST */
+
+#ifdef EAP_SERVER_WSC
+	if (ret == 0)
+		ret = eap_server_wsc_register();
+#endif /* EAP_SERVER_WSC */
+
+#ifdef EAP_SERVER_IKEV2
+	if (ret == 0)
+		ret = eap_server_ikev2_register();
+#endif /* EAP_SERVER_IKEV2 */
+
+#ifdef EAP_SERVER_TNC
+	if (ret == 0)
+		ret = eap_server_tnc_register();
+#endif /* EAP_SERVER_TNC */
+
+#ifdef EAP_SERVER_PWD
+	if (ret == 0)
+		ret = eap_server_pwd_register();
+#endif /* EAP_SERVER_PWD */
+
+	return ret;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/events.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,2941 @@
+/*
+ * WPA Supplicant - Driver event processing
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
+#include "eloop.h"
+#include "config.h"
+#include "l2_packet/l2_packet.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "pcsc_funcs.h"
+#include "rsn_supp/preauth.h"
+#include "rsn_supp/pmksa_cache.h"
+#include "common/wpa_ctrl.h"
+#include "eap_peer/eap.h"
+#include "ap/hostapd.h"
+#include "p2p/p2p.h"
+#include "wnm_sta.h"
+#include "notify.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "crypto/random.h"
+#include "blacklist.h"
+#include "wpas_glue.h"
+#include "wps_supplicant.h"
+#include "ibss_rsn.h"
+#include "sme.h"
+#include "gas_query.h"
+#include "p2p_supplicant.h"
+#include "bgscan.h"
+#include "autoscan.h"
+#include "ap.h"
+#include "bss.h"
+#include "scan.h"
+#include "offchannel.h"
+#include "interworking.h"
+
+
+static int wpas_temp_disabled(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid)
+{
+	struct os_time now;
+
+	if (ssid == NULL || ssid->disabled_until.sec == 0)
+		return 0;
+
+	os_get_time(&now);
+	if (ssid->disabled_until.sec > now.sec)
+		return ssid->disabled_until.sec - now.sec;
+
+	wpas_clear_temp_disabled(wpa_s, ssid, 0);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_select_config(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid, *old_ssid;
+	int res;
+
+	if (wpa_s->conf->ap_scan == 1 && wpa_s->current_ssid)
+		return 0;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Select network based on association "
+		"information");
+	ssid = wpa_supplicant_get_ssid(wpa_s);
+	if (ssid == NULL) {
+		wpa_msg(wpa_s, MSG_INFO,
+			"No network configuration found for the current AP");
+		return -1;
+	}
+
+	if (wpas_network_disabled(wpa_s, ssid)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is disabled");
+		return -1;
+	}
+
+	if (disallowed_bssid(wpa_s, wpa_s->bssid) ||
+	    disallowed_ssid(wpa_s, ssid->ssid, ssid->ssid_len)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS is disallowed");
+		return -1;
+	}
+
+	res = wpas_temp_disabled(wpa_s, ssid);
+	if (res > 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is temporarily "
+			"disabled for %d second(s)", res);
+		return -1;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Network configuration found for the "
+		"current AP");
+	if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
+		u8 wpa_ie[80];
+		size_t wpa_ie_len = sizeof(wpa_ie);
+		wpa_supplicant_set_suites(wpa_s, NULL, ssid,
+					  wpa_ie, &wpa_ie_len);
+	} else {
+		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+	}
+
+	if (wpa_s->current_ssid && wpa_s->current_ssid != ssid)
+		eapol_sm_invalidate_cached_session(wpa_s->eapol);
+	old_ssid = wpa_s->current_ssid;
+	wpa_s->current_ssid = ssid;
+	wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
+	wpa_supplicant_initiate_eapol(wpa_s);
+	if (old_ssid != wpa_s->current_ssid)
+		wpas_notify_network_changed(wpa_s);
+
+	return 0;
+}
+
+
+void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	if (wpa_s->countermeasures) {
+		wpa_s->countermeasures = 0;
+		wpa_drv_set_countermeasures(wpa_s, 0);
+		wpa_msg(wpa_s, MSG_INFO, "WPA: TKIP countermeasures stopped");
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+	}
+}
+
+
+void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
+{
+	int bssid_changed;
+
+	wnm_bss_keep_alive_deinit(wpa_s);
+
+#ifdef CONFIG_IBSS_RSN
+	ibss_rsn_deinit(wpa_s->ibss_rsn);
+	wpa_s->ibss_rsn = NULL;
+#endif /* CONFIG_IBSS_RSN */
+
+#ifdef CONFIG_AP
+	wpa_supplicant_ap_deinit(wpa_s);
+#endif /* CONFIG_AP */
+
+	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+		return;
+
+	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+	bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
+	os_memset(wpa_s->bssid, 0, ETH_ALEN);
+	os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+#ifdef CONFIG_SME
+	wpa_s->sme.prev_bssid_set = 0;
+#endif /* CONFIG_SME */
+#ifdef CONFIG_P2P
+	os_memset(wpa_s->go_dev_addr, 0, ETH_ALEN);
+#endif /* CONFIG_P2P */
+	wpa_s->current_bss = NULL;
+	wpa_s->assoc_freq = 0;
+#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_SME
+	if (wpa_s->sme.ft_ies)
+		sme_update_ft_ies(wpa_s, NULL, NULL, 0);
+#endif /* CONFIG_SME */
+#endif /* CONFIG_IEEE80211R */
+
+	if (bssid_changed)
+		wpas_notify_bssid_changed(wpa_s);
+
+	eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
+	eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
+		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+	wpa_s->ap_ies_from_associnfo = 0;
+	wpa_s->current_ssid = NULL;
+	wpa_s->key_mgmt = 0;
+}
+
+
+static void wpa_find_assoc_pmkid(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ie_data ie;
+	int pmksa_set = -1;
+	size_t i;
+
+	if (wpa_sm_parse_own_wpa_ie(wpa_s->wpa, &ie) < 0 ||
+	    ie.pmkid == NULL)
+		return;
+
+	for (i = 0; i < ie.num_pmkid; i++) {
+		pmksa_set = pmksa_cache_set_current(wpa_s->wpa,
+						    ie.pmkid + i * PMKID_LEN,
+						    NULL, NULL, 0);
+		if (pmksa_set == 0) {
+			eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+			break;
+		}
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "RSN: PMKID from assoc IE %sfound from "
+		"PMKSA cache", pmksa_set == 0 ? "" : "not ");
+}
+
+
+static void wpa_supplicant_event_pmkid_candidate(struct wpa_supplicant *wpa_s,
+						 union wpa_event_data *data)
+{
+	if (data == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: No data in PMKID candidate "
+			"event");
+		return;
+	}
+	wpa_dbg(wpa_s, MSG_DEBUG, "RSN: PMKID candidate event - bssid=" MACSTR
+		" index=%d preauth=%d",
+		MAC2STR(data->pmkid_candidate.bssid),
+		data->pmkid_candidate.index,
+		data->pmkid_candidate.preauth);
+
+	pmksa_candidate_add(wpa_s->wpa, data->pmkid_candidate.bssid,
+			    data->pmkid_candidate.index,
+			    data->pmkid_candidate.preauth);
+}
+
+
+static int wpa_supplicant_dynamic_keys(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
+		return 0;
+
+#ifdef IEEE8021X_EAPOL
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+	    wpa_s->current_ssid &&
+	    !(wpa_s->current_ssid->eapol_flags &
+	      (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
+	       EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) {
+		/* IEEE 802.1X, but not using dynamic WEP keys (i.e., either
+		 * plaintext or static WEP keys). */
+		return 0;
+	}
+#endif /* IEEE8021X_EAPOL */
+
+	return 1;
+}
+
+
+/**
+ * wpa_supplicant_scard_init - Initialize SIM/USIM access with PC/SC
+ * @wpa_s: pointer to wpa_supplicant data
+ * @ssid: Configuration data for the network
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called when starting authentication with a network that is
+ * configured to use PC/SC for SIM/USIM access (EAP-SIM or EAP-AKA).
+ */
+int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid)
+{
+#ifdef IEEE8021X_EAPOL
+#ifdef PCSC_FUNCS
+	int aka = 0, sim = 0, type;
+
+	if (ssid->eap.pcsc == NULL || wpa_s->scard != NULL)
+		return 0;
+
+	if (ssid->eap.eap_methods == NULL) {
+		sim = 1;
+		aka = 1;
+	} else {
+		struct eap_method_type *eap = ssid->eap.eap_methods;
+		while (eap->vendor != EAP_VENDOR_IETF ||
+		       eap->method != EAP_TYPE_NONE) {
+			if (eap->vendor == EAP_VENDOR_IETF) {
+				if (eap->method == EAP_TYPE_SIM)
+					sim = 1;
+				else if (eap->method == EAP_TYPE_AKA ||
+					 eap->method == EAP_TYPE_AKA_PRIME)
+					aka = 1;
+			}
+			eap++;
+		}
+	}
+
+	if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_SIM) == NULL)
+		sim = 0;
+	if (eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_AKA) == NULL &&
+	    eap_peer_get_eap_method(EAP_VENDOR_IETF, EAP_TYPE_AKA_PRIME) ==
+	    NULL)
+		aka = 0;
+
+	if (!sim && !aka) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is configured to "
+			"use SIM, but neither EAP-SIM nor EAP-AKA are "
+			"enabled");
+		return 0;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Selected network is configured to use SIM "
+		"(sim=%d aka=%d) - initialize PCSC", sim, aka);
+	if (sim && aka)
+		type = SCARD_TRY_BOTH;
+	else if (aka)
+		type = SCARD_USIM_ONLY;
+	else
+		type = SCARD_GSM_SIM_ONLY;
+
+	wpa_s->scard = scard_init(type, NULL);
+	if (wpa_s->scard == NULL) {
+		wpa_msg(wpa_s, MSG_WARNING, "Failed to initialize SIM "
+			"(pcsc-lite)");
+		return -1;
+	}
+	wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
+	eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
+#endif /* PCSC_FUNCS */
+#endif /* IEEE8021X_EAPOL */
+
+	return 0;
+}
+
+
+#ifndef CONFIG_NO_SCAN_PROCESSING
+static int wpa_supplicant_match_privacy(struct wpa_bss *bss,
+					struct wpa_ssid *ssid)
+{
+	int i, privacy = 0;
+
+	if (ssid->mixed_cell)
+		return 1;
+
+#ifdef CONFIG_WPS
+	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
+		return 1;
+#endif /* CONFIG_WPS */
+
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		if (ssid->wep_key_len[i]) {
+			privacy = 1;
+			break;
+		}
+	}
+#ifdef IEEE8021X_EAPOL
+	if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
+	    ssid->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
+				 EAPOL_FLAG_REQUIRE_KEY_BROADCAST))
+		privacy = 1;
+#endif /* IEEE8021X_EAPOL */
+
+	if (wpa_key_mgmt_wpa(ssid->key_mgmt))
+		privacy = 1;
+
+	if (bss->caps & IEEE80211_CAP_PRIVACY)
+		return privacy;
+	return !privacy;
+}
+
+
+static int wpa_supplicant_ssid_bss_match(struct wpa_supplicant *wpa_s,
+					 struct wpa_ssid *ssid,
+					 struct wpa_bss *bss)
+{
+	struct wpa_ie_data ie;
+	int proto_match = 0;
+	const u8 *rsn_ie, *wpa_ie;
+	int ret;
+	int wep_ok;
+
+	ret = wpas_wps_ssid_bss_match(wpa_s, ssid, bss);
+	if (ret >= 0)
+		return ret;
+
+	/* Allow TSN if local configuration accepts WEP use without WPA/WPA2 */
+	wep_ok = !wpa_key_mgmt_wpa(ssid->key_mgmt) &&
+		(((ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
+		  ssid->wep_key_len[ssid->wep_tx_keyidx] > 0) ||
+		 (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA));
+
+	rsn_ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+	while ((ssid->proto & WPA_PROTO_RSN) && rsn_ie) {
+		proto_match++;
+
+		if (wpa_parse_wpa_ie(rsn_ie, 2 + rsn_ie[1], &ie)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - parse "
+				"failed");
+			break;
+		}
+
+		if (wep_ok &&
+		    (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
+		{
+			wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on TSN "
+				"in RSN IE");
+			return 1;
+		}
+
+		if (!(ie.proto & ssid->proto)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - proto "
+				"mismatch");
+			break;
+		}
+
+		if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - PTK "
+				"cipher mismatch");
+			break;
+		}
+
+		if (!(ie.group_cipher & ssid->group_cipher)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - GTK "
+				"cipher mismatch");
+			break;
+		}
+
+		if (!(ie.key_mgmt & ssid->key_mgmt)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - key mgmt "
+				"mismatch");
+			break;
+		}
+
+#ifdef CONFIG_IEEE80211W
+		if (!(ie.capabilities & WPA_CAPABILITY_MFPC) &&
+		    (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+		     wpa_s->conf->pmf : ssid->ieee80211w) ==
+		    MGMT_FRAME_PROTECTION_REQUIRED) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip RSN IE - no mgmt "
+				"frame protection");
+			break;
+		}
+#endif /* CONFIG_IEEE80211W */
+
+		wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on RSN IE");
+		return 1;
+	}
+
+	wpa_ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+	while ((ssid->proto & WPA_PROTO_WPA) && wpa_ie) {
+		proto_match++;
+
+		if (wpa_parse_wpa_ie(wpa_ie, 2 + wpa_ie[1], &ie)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - parse "
+				"failed");
+			break;
+		}
+
+		if (wep_ok &&
+		    (ie.group_cipher & (WPA_CIPHER_WEP40 | WPA_CIPHER_WEP104)))
+		{
+			wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on TSN "
+				"in WPA IE");
+			return 1;
+		}
+
+		if (!(ie.proto & ssid->proto)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - proto "
+				"mismatch");
+			break;
+		}
+
+		if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - PTK "
+				"cipher mismatch");
+			break;
+		}
+
+		if (!(ie.group_cipher & ssid->group_cipher)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - GTK "
+				"cipher mismatch");
+			break;
+		}
+
+		if (!(ie.key_mgmt & ssid->key_mgmt)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip WPA IE - key mgmt "
+				"mismatch");
+			break;
+		}
+
+		wpa_dbg(wpa_s, MSG_DEBUG, "   selected based on WPA IE");
+		return 1;
+	}
+
+	if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && !wpa_ie &&
+	    !rsn_ie) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "   allow for non-WPA IEEE 802.1X");
+		return 1;
+	}
+
+	if ((ssid->proto & (WPA_PROTO_WPA | WPA_PROTO_RSN)) &&
+	    wpa_key_mgmt_wpa(ssid->key_mgmt) && proto_match == 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "   skip - no WPA/RSN proto match");
+		return 0;
+	}
+
+	if (!wpa_key_mgmt_wpa(ssid->key_mgmt)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "   allow in non-WPA/WPA2");
+		return 1;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "   reject due to mismatch with "
+		"WPA/WPA2");
+
+	return 0;
+}
+
+
+static int freq_allowed(int *freqs, int freq)
+{
+	int i;
+
+	if (freqs == NULL)
+		return 1;
+
+	for (i = 0; freqs[i]; i++)
+		if (freqs[i] == freq)
+			return 1;
+	return 0;
+}
+
+
+static int ht_supported(const struct hostapd_hw_modes *mode)
+{
+	if (!(mode->flags & HOSTAPD_MODE_FLAG_HT_INFO_KNOWN)) {
+		/*
+		 * The driver did not indicate whether it supports HT. Assume
+		 * it does to avoid connection issues.
+		 */
+		return 1;
+	}
+
+	/*
+	 * IEEE Std 802.11n-2009 20.1.1:
+	 * An HT non-AP STA shall support all EQM rates for one spatial stream.
+	 */
+	return mode->mcs_set[0] == 0xff;
+}
+
+
+static int rate_match(struct wpa_supplicant *wpa_s, struct wpa_bss *bss)
+{
+	const struct hostapd_hw_modes *mode = NULL, *modes;
+	const u8 scan_ie[2] = { WLAN_EID_SUPP_RATES, WLAN_EID_EXT_SUPP_RATES };
+	const u8 *rate_ie;
+	int i, j, k;
+
+	if (bss->freq == 0)
+		return 1; /* Cannot do matching without knowing band */
+
+	modes = wpa_s->hw.modes;
+	if (modes == NULL) {
+		/*
+		 * The driver does not provide any additional information
+		 * about the utilized hardware, so allow the connection attempt
+		 * to continue.
+		 */
+		return 1;
+	}
+
+	for (i = 0; i < wpa_s->hw.num_modes; i++) {
+		for (j = 0; j < modes[i].num_channels; j++) {
+			int freq = modes[i].channels[j].freq;
+			if (freq == bss->freq) {
+				if (mode &&
+				    mode->mode == HOSTAPD_MODE_IEEE80211G)
+					break; /* do not allow 802.11b replace
+						* 802.11g */
+				mode = &modes[i];
+				break;
+			}
+		}
+	}
+
+	if (mode == NULL)
+		return 0;
+
+	for (i = 0; i < (int) sizeof(scan_ie); i++) {
+		rate_ie = wpa_bss_get_ie(bss, scan_ie[i]);
+		if (rate_ie == NULL)
+			continue;
+
+		for (j = 2; j < rate_ie[1] + 2; j++) {
+			int flagged = !!(rate_ie[j] & 0x80);
+			int r = (rate_ie[j] & 0x7f) * 5;
+
+			/*
+			 * IEEE Std 802.11n-2009 7.3.2.2:
+			 * The new BSS Membership selector value is encoded
+			 * like a legacy basic rate, but it is not a rate and
+			 * only indicates if the BSS members are required to
+			 * support the mandatory features of Clause 20 [HT PHY]
+			 * in order to join the BSS.
+			 */
+			if (flagged && ((rate_ie[j] & 0x7f) ==
+					BSS_MEMBERSHIP_SELECTOR_HT_PHY)) {
+				if (!ht_supported(mode)) {
+					wpa_dbg(wpa_s, MSG_DEBUG,
+						"   hardware does not support "
+						"HT PHY");
+					return 0;
+				}
+				continue;
+			}
+
+			if (!flagged)
+				continue;
+
+			/* check for legacy basic rates */
+			for (k = 0; k < mode->num_rates; k++) {
+				if (mode->rates[k] == r)
+					break;
+			}
+			if (k == mode->num_rates) {
+				/*
+				 * IEEE Std 802.11-2007 7.3.2.2 demands that in
+				 * order to join a BSS all required rates
+				 * have to be supported by the hardware.
+				 */
+				wpa_dbg(wpa_s, MSG_DEBUG, "   hardware does "
+					"not support required rate %d.%d Mbps",
+					r / 10, r % 10);
+				return 0;
+			}
+		}
+	}
+
+	return 1;
+}
+
+
+static struct wpa_ssid * wpa_scan_res_match(struct wpa_supplicant *wpa_s,
+					    int i, struct wpa_bss *bss,
+					    struct wpa_ssid *group)
+{
+	u8 wpa_ie_len, rsn_ie_len;
+	int wpa;
+	struct wpa_blacklist *e;
+	const u8 *ie;
+	struct wpa_ssid *ssid;
+
+	ie = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+	wpa_ie_len = ie ? ie[1] : 0;
+
+	ie = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+	rsn_ie_len = ie ? ie[1] : 0;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
+		"wpa_ie_len=%u rsn_ie_len=%u caps=0x%x level=%d%s",
+		i, MAC2STR(bss->bssid), wpa_ssid_txt(bss->ssid, bss->ssid_len),
+		wpa_ie_len, rsn_ie_len, bss->caps, bss->level,
+		wpa_bss_get_vendor_ie(bss, WPS_IE_VENDOR_TYPE) ? " wps" : "");
+
+	e = wpa_blacklist_get(wpa_s, bss->bssid);
+	if (e) {
+		int limit = 1;
+		if (wpa_supplicant_enabled_networks(wpa_s) == 1) {
+			/*
+			 * When only a single network is enabled, we can
+			 * trigger blacklisting on the first failure. This
+			 * should not be done with multiple enabled networks to
+			 * avoid getting forced to move into a worse ESS on
+			 * single error if there are no other BSSes of the
+			 * current ESS.
+			 */
+			limit = 0;
+		}
+		if (e->count > limit) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - blacklisted "
+				"(count=%d limit=%d)", e->count, limit);
+			return NULL;
+		}
+	}
+
+	if (bss->ssid_len == 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID not known");
+		return NULL;
+	}
+
+	if (disallowed_bssid(wpa_s, bss->bssid)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "   skip - BSSID disallowed");
+		return NULL;
+	}
+
+	if (disallowed_ssid(wpa_s, bss->ssid, bss->ssid_len)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID disallowed");
+		return NULL;
+	}
+
+	wpa = wpa_ie_len > 0 || rsn_ie_len > 0;
+
+	for (ssid = group; ssid; ssid = ssid->pnext) {
+		int check_ssid = wpa ? 1 : (ssid->ssid_len != 0);
+		int res;
+
+		if (wpas_network_disabled(wpa_s, ssid)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - disabled");
+			continue;
+		}
+
+		res = wpas_temp_disabled(wpa_s, ssid);
+		if (res > 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - disabled "
+				"temporarily for %d second(s)", res);
+			continue;
+		}
+
+#ifdef CONFIG_WPS
+		if ((ssid->key_mgmt & WPA_KEY_MGMT_WPS) && e && e->count > 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - blacklisted "
+				"(WPS)");
+			continue;
+		}
+
+		if (wpa && ssid->ssid_len == 0 &&
+		    wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
+			check_ssid = 0;
+
+		if (!wpa && (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+			/* Only allow wildcard SSID match if an AP
+			 * advertises active WPS operation that matches
+			 * with our mode. */
+			check_ssid = 1;
+			if (ssid->ssid_len == 0 &&
+			    wpas_wps_ssid_wildcard_ok(wpa_s, ssid, bss))
+				check_ssid = 0;
+		}
+#endif /* CONFIG_WPS */
+
+		if (ssid->bssid_set && ssid->ssid_len == 0 &&
+		    os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) == 0)
+			check_ssid = 0;
+
+		if (check_ssid &&
+		    (bss->ssid_len != ssid->ssid_len ||
+		     os_memcmp(bss->ssid, ssid->ssid, bss->ssid_len) != 0)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - SSID mismatch");
+			continue;
+		}
+
+		if (ssid->bssid_set &&
+		    os_memcmp(bss->bssid, ssid->bssid, ETH_ALEN) != 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - BSSID mismatch");
+			continue;
+		}
+
+		if (!wpa_supplicant_ssid_bss_match(wpa_s, ssid, bss))
+			continue;
+
+		if (!wpa &&
+		    !(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
+		    !(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
+		    !(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - non-WPA network "
+				"not allowed");
+			continue;
+		}
+
+		if (!wpa_supplicant_match_privacy(bss, ssid)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - privacy "
+				"mismatch");
+			continue;
+		}
+
+		if (bss->caps & IEEE80211_CAP_IBSS) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - IBSS (adhoc) "
+				"network");
+			continue;
+		}
+
+		if (!freq_allowed(ssid->freq_list, bss->freq)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - frequency not "
+				"allowed");
+			continue;
+		}
+
+		if (!rate_match(wpa_s, bss)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "   skip - rate sets do "
+				"not match");
+			continue;
+		}
+
+#ifdef CONFIG_P2P
+		/*
+		 * TODO: skip the AP if its P2P IE has Group Formation
+		 * bit set in the P2P Group Capability Bitmap and we
+		 * are not in Group Formation with that device.
+		 */
+#endif /* CONFIG_P2P */
+
+		/* Matching configuration found */
+		return ssid;
+	}
+
+	/* No matching configuration found */
+	return NULL;
+}
+
+
+static struct wpa_bss *
+wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s,
+			  struct wpa_ssid *group,
+			  struct wpa_ssid **selected_ssid)
+{
+	unsigned int i;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Selecting BSS from priority group %d",
+		group->priority);
+
+	for (i = 0; i < wpa_s->last_scan_res_used; i++) {
+		struct wpa_bss *bss = wpa_s->last_scan_res[i];
+		*selected_ssid = wpa_scan_res_match(wpa_s, i, bss, group);
+		if (!*selected_ssid)
+			continue;
+		wpa_dbg(wpa_s, MSG_DEBUG, "   selected BSS " MACSTR
+			" ssid='%s'",
+			MAC2STR(bss->bssid),
+			wpa_ssid_txt(bss->ssid, bss->ssid_len));
+		return bss;
+	}
+
+	return NULL;
+}
+
+
+static struct wpa_bss *
+wpa_supplicant_pick_network(struct wpa_supplicant *wpa_s,
+			    struct wpa_ssid **selected_ssid)
+{
+	struct wpa_bss *selected = NULL;
+	int prio;
+
+	if (wpa_s->last_scan_res == NULL ||
+	    wpa_s->last_scan_res_used == 0)
+		return NULL; /* no scan results from last update */
+
+	while (selected == NULL) {
+		for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
+			selected = wpa_supplicant_select_bss(
+				wpa_s, wpa_s->conf->pssid[prio],
+				selected_ssid);
+			if (selected)
+				break;
+		}
+
+		if (selected == NULL && wpa_s->blacklist &&
+		    !wpa_s->countermeasures) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "No APs found - clear "
+				"blacklist and try again");
+			wpa_blacklist_clear(wpa_s);
+			wpa_s->blacklist_cleared++;
+		} else if (selected == NULL)
+			break;
+	}
+
+	return selected;
+}
+
+
+static void wpa_supplicant_req_new_scan(struct wpa_supplicant *wpa_s,
+					int timeout_sec, int timeout_usec)
+{
+	if (!wpa_supplicant_enabled_networks(wpa_s)) {
+		/*
+		 * No networks are enabled; short-circuit request so
+		 * we don't wait timeout seconds before transitioning
+		 * to INACTIVE state.
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG, "Short-circuit new scan request "
+			"since there are no enabled networks");
+		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
+#ifdef CONFIG_P2P
+		wpa_s->sta_scan_pending = 0;
+#endif /* CONFIG_P2P */
+		return;
+	}
+
+	wpa_s->scan_for_connection = 1;
+	wpa_supplicant_req_scan(wpa_s, timeout_sec, timeout_usec);
+}
+
+
+int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
+			   struct wpa_bss *selected,
+			   struct wpa_ssid *ssid)
+{
+	if (wpas_wps_scan_pbc_overlap(wpa_s, selected, ssid)) {
+		wpa_msg(wpa_s, MSG_INFO, WPS_EVENT_OVERLAP
+			"PBC session overlap");
+#ifdef CONFIG_P2P
+		if (wpas_p2p_notif_pbc_overlap(wpa_s) == 1)
+			return -1;
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WPS
+		wpas_wps_cancel(wpa_s);
+#endif /* CONFIG_WPS */
+		return -1;
+	}
+
+	/*
+	 * Do not trigger new association unless the BSSID has changed or if
+	 * reassociation is requested. If we are in process of associating with
+	 * the selected BSSID, do not trigger new attempt.
+	 */
+	if (wpa_s->reassociate ||
+	    (os_memcmp(selected->bssid, wpa_s->bssid, ETH_ALEN) != 0 &&
+	     ((wpa_s->wpa_state != WPA_ASSOCIATING &&
+	       wpa_s->wpa_state != WPA_AUTHENTICATING) ||
+	      os_memcmp(selected->bssid, wpa_s->pending_bssid, ETH_ALEN) !=
+	      0))) {
+		if (wpa_supplicant_scard_init(wpa_s, ssid)) {
+			wpa_supplicant_req_new_scan(wpa_s, 10, 0);
+			return 0;
+		}
+		wpa_msg(wpa_s, MSG_DEBUG, "Request association: "
+			"reassociate: %d  selected: "MACSTR "  bssid: " MACSTR
+			"  pending: " MACSTR "  wpa_state: %s",
+			wpa_s->reassociate, MAC2STR(selected->bssid),
+			MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
+			wpa_supplicant_state_txt(wpa_s->wpa_state));
+		wpa_supplicant_associate(wpa_s, selected, ssid);
+	} else {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with the "
+			"selected AP");
+	}
+
+	return 0;
+}
+
+
+static struct wpa_ssid *
+wpa_supplicant_pick_new_network(struct wpa_supplicant *wpa_s)
+{
+	int prio;
+	struct wpa_ssid *ssid;
+
+	for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
+		for (ssid = wpa_s->conf->pssid[prio]; ssid; ssid = ssid->pnext)
+		{
+			if (wpas_network_disabled(wpa_s, ssid))
+				continue;
+			if (ssid->mode == IEEE80211_MODE_IBSS ||
+			    ssid->mode == IEEE80211_MODE_AP)
+				return ssid;
+		}
+	}
+	return NULL;
+}
+
+
+/* TODO: move the rsn_preauth_scan_result*() to be called from notify.c based
+ * on BSS added and BSS changed events */
+static void wpa_supplicant_rsn_preauth_scan_results(
+	struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss;
+
+	if (rsn_preauth_scan_results(wpa_s->wpa) < 0)
+		return;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		const u8 *ssid, *rsn;
+
+		ssid = wpa_bss_get_ie(bss, WLAN_EID_SSID);
+		if (ssid == NULL)
+			continue;
+
+		rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+		if (rsn == NULL)
+			continue;
+
+		rsn_preauth_scan_result(wpa_s->wpa, bss->bssid, ssid, rsn);
+	}
+
+}
+
+
+static int wpa_supplicant_need_to_roam(struct wpa_supplicant *wpa_s,
+				       struct wpa_bss *selected,
+				       struct wpa_ssid *ssid)
+{
+	struct wpa_bss *current_bss = NULL;
+	int min_diff;
+
+	if (wpa_s->reassociate)
+		return 1; /* explicit request to reassociate */
+	if (wpa_s->wpa_state < WPA_ASSOCIATED)
+		return 1; /* we are not associated; continue */
+	if (wpa_s->current_ssid == NULL)
+		return 1; /* unknown current SSID */
+	if (wpa_s->current_ssid != ssid)
+		return 1; /* different network block */
+
+	if (wpas_driver_bss_selection(wpa_s))
+		return 0; /* Driver-based roaming */
+
+	if (wpa_s->current_ssid->ssid)
+		current_bss = wpa_bss_get(wpa_s, wpa_s->bssid,
+					  wpa_s->current_ssid->ssid,
+					  wpa_s->current_ssid->ssid_len);
+	if (!current_bss)
+		current_bss = wpa_bss_get_bssid(wpa_s, wpa_s->bssid);
+
+	if (!current_bss)
+		return 1; /* current BSS not seen in scan results */
+
+	if (current_bss == selected)
+		return 0;
+
+	if (selected->last_update_idx > current_bss->last_update_idx)
+		return 1; /* current BSS not seen in the last scan */
+
+#ifndef CONFIG_NO_ROAMING
+	wpa_dbg(wpa_s, MSG_DEBUG, "Considering within-ESS reassociation");
+	wpa_dbg(wpa_s, MSG_DEBUG, "Current BSS: " MACSTR " level=%d",
+		MAC2STR(current_bss->bssid), current_bss->level);
+	wpa_dbg(wpa_s, MSG_DEBUG, "Selected BSS: " MACSTR " level=%d",
+		MAC2STR(selected->bssid), selected->level);
+
+	if (wpa_s->current_ssid->bssid_set &&
+	    os_memcmp(selected->bssid, wpa_s->current_ssid->bssid, ETH_ALEN) ==
+	    0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Allow reassociation - selected BSS "
+			"has preferred BSSID");
+		return 1;
+	}
+
+	if (current_bss->level < 0 && current_bss->level > selected->level) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - Current BSS has better "
+			"signal level");
+		return 0;
+	}
+
+	min_diff = 2;
+	if (current_bss->level < 0) {
+		if (current_bss->level < -85)
+			min_diff = 1;
+		else if (current_bss->level < -80)
+			min_diff = 2;
+		else if (current_bss->level < -75)
+			min_diff = 3;
+		else if (current_bss->level < -70)
+			min_diff = 4;
+		else
+			min_diff = 5;
+	}
+	if (abs(current_bss->level - selected->level) < min_diff) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Skip roam - too small difference "
+			"in signal level");
+		return 0;
+	}
+
+	return 1;
+#else /* CONFIG_NO_ROAMING */
+	return 0;
+#endif /* CONFIG_NO_ROAMING */
+}
+
+
+/* Return != 0 if no scan results could be fetched or if scan results should not
+ * be shared with other virtual interfaces. */
+static int _wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
+					      union wpa_event_data *data)
+{
+	struct wpa_scan_results *scan_res;
+	int ap = 0;
+#ifndef CONFIG_NO_RANDOM_POOL
+	size_t i, num;
+#endif /* CONFIG_NO_RANDOM_POOL */
+
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface)
+		ap = 1;
+#endif /* CONFIG_AP */
+
+	wpa_supplicant_notify_scanning(wpa_s, 0);
+
+#ifdef CONFIG_P2P
+	if (wpa_s->global->p2p_cb_on_scan_complete &&
+	    !wpa_s->global->p2p_disabled &&
+	    wpa_s->global->p2p != NULL && !wpa_s->sta_scan_pending &&
+	    !wpa_s->scan_res_handler) {
+		wpa_s->global->p2p_cb_on_scan_complete = 0;
+		if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+				"stopped scan processing");
+			wpa_s->sta_scan_pending = 1;
+			wpa_supplicant_req_scan(wpa_s, 5, 0);
+			return -1;
+		}
+	}
+	wpa_s->sta_scan_pending = 0;
+#endif /* CONFIG_P2P */
+
+	scan_res = wpa_supplicant_get_scan_results(wpa_s,
+						   data ? &data->scan_info :
+						   NULL, 1);
+	if (scan_res == NULL) {
+		if (wpa_s->conf->ap_scan == 2 || ap)
+			return -1;
+		wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results - try "
+			"scanning again");
+		wpa_supplicant_req_new_scan(wpa_s, 1, 0);
+		return -1;
+	}
+
+#ifndef CONFIG_NO_RANDOM_POOL
+	num = scan_res->num;
+	if (num > 10)
+		num = 10;
+	for (i = 0; i < num; i++) {
+		u8 buf[5];
+		struct wpa_scan_res *res = scan_res->res[i];
+		buf[0] = res->bssid[5];
+		buf[1] = res->qual & 0xff;
+		buf[2] = res->noise & 0xff;
+		buf[3] = res->level & 0xff;
+		buf[4] = res->tsf & 0xff;
+		random_add_randomness(buf, sizeof(buf));
+	}
+#endif /* CONFIG_NO_RANDOM_POOL */
+
+	if (wpa_s->scan_res_handler) {
+		void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
+					 struct wpa_scan_results *scan_res);
+
+		scan_res_handler = wpa_s->scan_res_handler;
+		wpa_s->scan_res_handler = NULL;
+		scan_res_handler(wpa_s, scan_res);
+
+		wpa_scan_results_free(scan_res);
+		return -2;
+	}
+
+	if (ap) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Ignore scan results in AP mode");
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface->scan_cb)
+			wpa_s->ap_iface->scan_cb(wpa_s->ap_iface);
+#endif /* CONFIG_AP */
+		wpa_scan_results_free(scan_res);
+		return 0;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "New scan results available");
+	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+	wpas_notify_scan_results(wpa_s);
+
+	wpas_notify_scan_done(wpa_s, 1);
+
+	if (sme_proc_obss_scan(wpa_s) > 0) {
+		wpa_scan_results_free(scan_res);
+		return 0;
+	}
+
+	if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s))) {
+		wpa_scan_results_free(scan_res);
+		return 0;
+	}
+
+	if (autoscan_notify_scan(wpa_s, scan_res)) {
+		wpa_scan_results_free(scan_res);
+		return 0;
+	}
+
+	if (wpa_s->disconnected) {
+		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+		wpa_scan_results_free(scan_res);
+		return 0;
+	}
+
+	if (!wpas_driver_bss_selection(wpa_s) &&
+	    bgscan_notify_scan(wpa_s, scan_res) == 1) {
+		wpa_scan_results_free(scan_res);
+		return 0;
+	}
+
+	wpas_wps_update_ap_info(wpa_s, scan_res);
+
+	wpa_scan_results_free(scan_res);
+
+	return wpas_select_network_from_last_scan(wpa_s);
+}
+
+
+int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *selected;
+	struct wpa_ssid *ssid = NULL;
+
+	selected = wpa_supplicant_pick_network(wpa_s, &ssid);
+
+	if (selected) {
+		int skip;
+		skip = !wpa_supplicant_need_to_roam(wpa_s, selected, ssid);
+		if (skip) {
+			wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+			return 0;
+		}
+
+		if (wpa_supplicant_connect(wpa_s, selected, ssid) < 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Connect failed");
+			return -1;
+		}
+		wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+		/*
+		 * Do not notify other virtual radios of scan results since we do not
+		 * want them to start other associations at the same time.
+		 */
+		return 1;
+	} else {
+		wpa_dbg(wpa_s, MSG_DEBUG, "No suitable network found");
+		ssid = wpa_supplicant_pick_new_network(wpa_s);
+		if (ssid) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Setup a new network");
+			wpa_supplicant_associate(wpa_s, NULL, ssid);
+			wpa_supplicant_rsn_preauth_scan_results(wpa_s);
+		} else {
+			int timeout_sec = wpa_s->scan_interval;
+			int timeout_usec = 0;
+#ifdef CONFIG_P2P
+			if (wpas_p2p_scan_no_go_seen(wpa_s) == 1)
+				return 0;
+
+			if (wpa_s->p2p_in_provisioning) {
+				/*
+				 * Use shorter wait during P2P Provisioning
+				 * state to speed up group formation.
+				 */
+				timeout_sec = 0;
+				timeout_usec = 250000;
+				wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
+							    timeout_usec);
+				return 0;
+			}
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+			if (wpa_s->conf->auto_interworking &&
+			    wpa_s->conf->interworking &&
+			    wpa_s->conf->cred) {
+				wpa_dbg(wpa_s, MSG_DEBUG, "Interworking: "
+					"start ANQP fetch since no matching "
+					"networks found");
+				wpa_s->network_select = 1;
+				wpa_s->auto_network_select = 1;
+				interworking_start_fetch_anqp(wpa_s);
+				return 1;
+			}
+#endif /* CONFIG_INTERWORKING */
+			if (wpa_supplicant_req_sched_scan(wpa_s))
+				wpa_supplicant_req_new_scan(wpa_s, timeout_sec,
+							    timeout_usec);
+		}
+	}
+	return 0;
+}
+
+
+static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s,
+					      union wpa_event_data *data)
+{
+	const char *rn, *rn2;
+	struct wpa_supplicant *ifs;
+
+	if (_wpa_supplicant_event_scan_results(wpa_s, data) != 0) {
+		/*
+		 * If no scan results could be fetched, then no need to
+		 * notify those interfaces that did not actually request
+		 * this scan. Similarly, if scan results started a new operation on this
+		 * interface, do not notify other interfaces to avoid concurrent
+		 * operations during a connection attempt.
+		 */
+		return;
+	}
+
+	/*
+	 * Check other interfaces to see if they have the same radio-name. If
+	 * so, they get updated with this same scan info.
+	 */
+	if (!wpa_s->driver->get_radio_name)
+		return;
+
+	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+	if (rn == NULL || rn[0] == '\0')
+		return;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Checking for other virtual interfaces "
+		"sharing same radio (%s) in event_scan_results", rn);
+
+	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+		if (ifs == wpa_s || !ifs->driver->get_radio_name)
+			continue;
+
+		rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
+		if (rn2 && os_strcmp(rn, rn2) == 0) {
+			wpa_printf(MSG_DEBUG, "%s: Updating scan results from "
+				   "sibling", ifs->ifname);
+			_wpa_supplicant_event_scan_results(ifs, data);
+		}
+	}
+}
+
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+
+
+#ifdef CONFIG_WNM
+
+static void wnm_bss_keep_alive(void *eloop_ctx, void *sock_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	if (wpa_s->wpa_state < WPA_ASSOCIATED)
+		return;
+
+	if (!wpa_s->no_keep_alive) {
+		wpa_printf(MSG_DEBUG, "WNM: Send keep-alive to AP " MACSTR,
+			   MAC2STR(wpa_s->bssid));
+		/* TODO: could skip this if normal data traffic has been sent */
+		/* TODO: Consider using some more appropriate data frame for
+		 * this */
+		if (wpa_s->l2)
+			l2_packet_send(wpa_s->l2, wpa_s->bssid, 0x0800,
+				       (u8 *) "", 0);
+	}
+
+#ifdef CONFIG_SME
+	if (wpa_s->sme.bss_max_idle_period) {
+		unsigned int msec;
+		msec = wpa_s->sme.bss_max_idle_period * 1024; /* times 1000 */
+		if (msec > 100)
+			msec -= 100;
+		eloop_register_timeout(msec / 1000, msec % 1000 * 1000,
+				       wnm_bss_keep_alive, wpa_s, NULL);
+	}
+#endif /* CONFIG_SME */
+}
+
+
+static void wnm_process_assoc_resp(struct wpa_supplicant *wpa_s,
+				   const u8 *ies, size_t ies_len)
+{
+	struct ieee802_11_elems elems;
+
+	if (ies == NULL)
+		return;
+
+	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed)
+		return;
+
+#ifdef CONFIG_SME
+	if (elems.bss_max_idle_period) {
+		unsigned int msec;
+		wpa_s->sme.bss_max_idle_period =
+			WPA_GET_LE16(elems.bss_max_idle_period);
+		wpa_printf(MSG_DEBUG, "WNM: BSS Max Idle Period: %u (* 1000 "
+			   "TU)%s", wpa_s->sme.bss_max_idle_period,
+			   (elems.bss_max_idle_period[2] & 0x01) ?
+			   " (protected keep-live required)" : "");
+		if (wpa_s->sme.bss_max_idle_period == 0)
+			wpa_s->sme.bss_max_idle_period = 1;
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) {
+			eloop_cancel_timeout(wnm_bss_keep_alive, wpa_s, NULL);
+			 /* msec times 1000 */
+			msec = wpa_s->sme.bss_max_idle_period * 1024;
+			if (msec > 100)
+				msec -= 100;
+			eloop_register_timeout(msec / 1000, msec % 1000 * 1000,
+					       wnm_bss_keep_alive, wpa_s,
+					       NULL);
+		}
+	}
+#endif /* CONFIG_SME */
+}
+
+#endif /* CONFIG_WNM */
+
+
+void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WNM
+	eloop_cancel_timeout(wnm_bss_keep_alive, wpa_s, NULL);
+#endif /* CONFIG_WNM */
+}
+
+
+static int wpa_supplicant_event_associnfo(struct wpa_supplicant *wpa_s,
+					  union wpa_event_data *data)
+{
+	int l, len, found = 0, wpa_found, rsn_found;
+	const u8 *p;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Association info event");
+	if (data->assoc_info.req_ies)
+		wpa_hexdump(MSG_DEBUG, "req_ies", data->assoc_info.req_ies,
+			    data->assoc_info.req_ies_len);
+	if (data->assoc_info.resp_ies) {
+		wpa_hexdump(MSG_DEBUG, "resp_ies", data->assoc_info.resp_ies,
+			    data->assoc_info.resp_ies_len);
+#ifdef CONFIG_TDLS
+		wpa_tdls_assoc_resp_ies(wpa_s->wpa, data->assoc_info.resp_ies,
+					data->assoc_info.resp_ies_len);
+#endif /* CONFIG_TDLS */
+#ifdef CONFIG_WNM
+		wnm_process_assoc_resp(wpa_s, data->assoc_info.resp_ies,
+				       data->assoc_info.resp_ies_len);
+#endif /* CONFIG_WNM */
+	}
+	if (data->assoc_info.beacon_ies)
+		wpa_hexdump(MSG_DEBUG, "beacon_ies",
+			    data->assoc_info.beacon_ies,
+			    data->assoc_info.beacon_ies_len);
+	if (data->assoc_info.freq)
+		wpa_dbg(wpa_s, MSG_DEBUG, "freq=%u MHz",
+			data->assoc_info.freq);
+
+	p = data->assoc_info.req_ies;
+	l = data->assoc_info.req_ies_len;
+
+	/* Go through the IEs and make a copy of the WPA/RSN IE, if present. */
+	while (p && l >= 2) {
+		len = p[1] + 2;
+		if (len > l) {
+			wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info",
+				    p, l);
+			break;
+		}
+		if ((p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+		     (os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0)) ||
+		    (p[0] == WLAN_EID_RSN && p[1] >= 2)) {
+			if (wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, p, len))
+				break;
+			found = 1;
+			wpa_find_assoc_pmkid(wpa_s);
+			break;
+		}
+		l -= len;
+		p += len;
+	}
+	if (!found && data->assoc_info.req_ies)
+		wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+
+#ifdef CONFIG_IEEE80211R
+#ifdef CONFIG_SME
+	if (wpa_s->sme.auth_alg == WPA_AUTH_ALG_FT) {
+		u8 bssid[ETH_ALEN];
+		if (wpa_drv_get_bssid(wpa_s, bssid) < 0 ||
+		    wpa_ft_validate_reassoc_resp(wpa_s->wpa,
+						 data->assoc_info.resp_ies,
+						 data->assoc_info.resp_ies_len,
+						 bssid) < 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "FT: Validation of "
+				"Reassociation Response failed");
+			wpa_supplicant_deauthenticate(
+				wpa_s, WLAN_REASON_INVALID_IE);
+			return -1;
+		}
+	}
+
+	p = data->assoc_info.resp_ies;
+	l = data->assoc_info.resp_ies_len;
+
+#ifdef CONFIG_WPS_STRICT
+	if (p && wpa_s->current_ssid &&
+	    wpa_s->current_ssid->key_mgmt == WPA_KEY_MGMT_WPS) {
+		struct wpabuf *wps;
+		wps = ieee802_11_vendor_ie_concat(p, l, WPS_IE_VENDOR_TYPE);
+		if (wps == NULL) {
+			wpa_msg(wpa_s, MSG_INFO, "WPS-STRICT: AP did not "
+				"include WPS IE in (Re)Association Response");
+			return -1;
+		}
+
+		if (wps_validate_assoc_resp(wps) < 0) {
+			wpabuf_free(wps);
+			wpa_supplicant_deauthenticate(
+				wpa_s, WLAN_REASON_INVALID_IE);
+			return -1;
+		}
+		wpabuf_free(wps);
+	}
+#endif /* CONFIG_WPS_STRICT */
+
+	/* Go through the IEs and make a copy of the MDIE, if present. */
+	while (p && l >= 2) {
+		len = p[1] + 2;
+		if (len > l) {
+			wpa_hexdump(MSG_DEBUG, "Truncated IE in assoc_info",
+				    p, l);
+			break;
+		}
+		if (p[0] == WLAN_EID_MOBILITY_DOMAIN &&
+		    p[1] >= MOBILITY_DOMAIN_ID_LEN) {
+			wpa_s->sme.ft_used = 1;
+			os_memcpy(wpa_s->sme.mobility_domain, p + 2,
+				  MOBILITY_DOMAIN_ID_LEN);
+			break;
+		}
+		l -= len;
+		p += len;
+	}
+#endif /* CONFIG_SME */
+
+	wpa_sm_set_ft_params(wpa_s->wpa, data->assoc_info.resp_ies,
+			     data->assoc_info.resp_ies_len);
+#endif /* CONFIG_IEEE80211R */
+
+	/* WPA/RSN IE from Beacon/ProbeResp */
+	p = data->assoc_info.beacon_ies;
+	l = data->assoc_info.beacon_ies_len;
+
+	/* Go through the IEs and make a copy of the WPA/RSN IEs, if present.
+	 */
+	wpa_found = rsn_found = 0;
+	while (p && l >= 2) {
+		len = p[1] + 2;
+		if (len > l) {
+			wpa_hexdump(MSG_DEBUG, "Truncated IE in beacon_ies",
+				    p, l);
+			break;
+		}
+		if (!wpa_found &&
+		    p[0] == WLAN_EID_VENDOR_SPECIFIC && p[1] >= 6 &&
+		    os_memcmp(&p[2], "\x00\x50\xF2\x01\x01\x00", 6) == 0) {
+			wpa_found = 1;
+			wpa_sm_set_ap_wpa_ie(wpa_s->wpa, p, len);
+		}
+
+		if (!rsn_found &&
+		    p[0] == WLAN_EID_RSN && p[1] >= 2) {
+			rsn_found = 1;
+			wpa_sm_set_ap_rsn_ie(wpa_s->wpa, p, len);
+		}
+
+		l -= len;
+		p += len;
+	}
+
+	if (!wpa_found && data->assoc_info.beacon_ies)
+		wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
+	if (!rsn_found && data->assoc_info.beacon_ies)
+		wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+	if (wpa_found || rsn_found)
+		wpa_s->ap_ies_from_associnfo = 1;
+
+	if (wpa_s->assoc_freq && data->assoc_info.freq &&
+	    wpa_s->assoc_freq != data->assoc_info.freq) {
+		wpa_printf(MSG_DEBUG, "Operating frequency changed from "
+			   "%u to %u MHz",
+			   wpa_s->assoc_freq, data->assoc_info.freq);
+		wpa_supplicant_update_scan_results(wpa_s);
+	}
+
+	wpa_s->assoc_freq = data->assoc_info.freq;
+
+	return 0;
+}
+
+
+static struct wpa_bss * wpa_supplicant_get_new_bss(
+	struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	struct wpa_bss *bss = NULL;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+	if (ssid->ssid_len > 0)
+		bss = wpa_bss_get(wpa_s, bssid, ssid->ssid, ssid->ssid_len);
+	if (!bss)
+		bss = wpa_bss_get_bssid(wpa_s, bssid);
+
+	return bss;
+}
+
+
+static int wpa_supplicant_assoc_update_ie(struct wpa_supplicant *wpa_s)
+{
+	const u8 *bss_wpa = NULL, *bss_rsn = NULL;
+
+	if (!wpa_s->current_bss || !wpa_s->current_ssid)
+		return -1;
+
+	if (!wpa_key_mgmt_wpa_any(wpa_s->current_ssid->key_mgmt))
+		return 0;
+
+	bss_wpa = wpa_bss_get_vendor_ie(wpa_s->current_bss,
+					WPA_IE_VENDOR_TYPE);
+	bss_rsn = wpa_bss_get_ie(wpa_s->current_bss, WLAN_EID_RSN);
+
+	if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
+				 bss_wpa ? 2 + bss_wpa[1] : 0) ||
+	    wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
+				 bss_rsn ? 2 + bss_rsn[1] : 0))
+		return -1;
+
+	return 0;
+}
+
+
+static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
+				       union wpa_event_data *data)
+{
+	u8 bssid[ETH_ALEN];
+	int ft_completed;
+	struct wpa_driver_capa capa;
+
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface) {
+		hostapd_notif_assoc(wpa_s->ap_iface->bss[0],
+				    data->assoc_info.addr,
+				    data->assoc_info.req_ies,
+				    data->assoc_info.req_ies_len,
+				    data->assoc_info.reassoc);
+		return;
+	}
+#endif /* CONFIG_AP */
+
+	ft_completed = wpa_ft_is_completed(wpa_s->wpa);
+	if (data && wpa_supplicant_event_associnfo(wpa_s, data) < 0)
+		return;
+
+	if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+		wpa_dbg(wpa_s, MSG_ERROR, "Failed to get BSSID");
+		wpa_supplicant_deauthenticate(
+			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+		return;
+	}
+
+	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATED);
+	if (os_memcmp(bssid, wpa_s->bssid, ETH_ALEN) != 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Associated to a new BSS: BSSID="
+			MACSTR, MAC2STR(bssid));
+		random_add_randomness(bssid, ETH_ALEN);
+		os_memcpy(wpa_s->bssid, bssid, ETH_ALEN);
+		os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+		wpas_notify_bssid_changed(wpa_s);
+
+		if (wpa_supplicant_dynamic_keys(wpa_s) && !ft_completed) {
+			wpa_clear_keys(wpa_s, bssid);
+		}
+		if (wpa_supplicant_select_config(wpa_s) < 0) {
+			wpa_supplicant_deauthenticate(
+				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+			return;
+		}
+		if (wpa_s->current_ssid) {
+			struct wpa_bss *bss = NULL;
+
+			bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
+			if (!bss) {
+				wpa_supplicant_update_scan_results(wpa_s);
+
+				/* Get the BSS from the new scan results */
+				bss = wpa_supplicant_get_new_bss(wpa_s, bssid);
+			}
+
+			if (bss)
+				wpa_s->current_bss = bss;
+		}
+
+		if (wpa_s->conf->ap_scan == 1 &&
+		    wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION) {
+			if (wpa_supplicant_assoc_update_ie(wpa_s) < 0)
+				wpa_msg(wpa_s, MSG_WARNING,
+					"WPA/RSN IEs not updated");
+		}
+	}
+
+#ifdef CONFIG_SME
+	os_memcpy(wpa_s->sme.prev_bssid, bssid, ETH_ALEN);
+	wpa_s->sme.prev_bssid_set = 1;
+#endif /* CONFIG_SME */
+
+	wpa_msg(wpa_s, MSG_INFO, "Associated with " MACSTR, MAC2STR(bssid));
+	if (wpa_s->current_ssid) {
+		/* When using scanning (ap_scan=1), SIM PC/SC interface can be
+		 * initialized before association, but for other modes,
+		 * initialize PC/SC here, if the current configuration needs
+		 * smartcard or SIM/USIM. */
+		wpa_supplicant_scard_init(wpa_s, wpa_s->current_ssid);
+	}
+	wpa_sm_notify_assoc(wpa_s->wpa, bssid);
+	if (wpa_s->l2)
+		l2_packet_notify_auth_start(wpa_s->l2);
+
+	/*
+	 * Set portEnabled first to FALSE in order to get EAP state machine out
+	 * of the SUCCESS state and eapSuccess cleared. Without this, EAPOL PAE
+	 * state machine may transit to AUTHENTICATING state based on obsolete
+	 * eapSuccess and then trigger BE_AUTH to SUCCESS and PAE to
+	 * AUTHENTICATED without ever giving chance to EAP state machine to
+	 * reset the state.
+	 */
+	if (!ft_completed) {
+		eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
+		eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+	}
+	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) || ft_completed)
+		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+	/* 802.1X::portControl = Auto */
+	eapol_sm_notify_portEnabled(wpa_s->eapol, TRUE);
+	wpa_s->eapol_received = 0;
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE ||
+	    (wpa_s->current_ssid &&
+	     wpa_s->current_ssid->mode == IEEE80211_MODE_IBSS)) {
+		wpa_supplicant_cancel_auth_timeout(wpa_s);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+	} else if (!ft_completed) {
+		/* Timeout for receiving the first EAPOL packet */
+		wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
+	}
+	wpa_supplicant_cancel_scan(wpa_s);
+
+	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+	    wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+		/*
+		 * We are done; the driver will take care of RSN 4-way
+		 * handshake.
+		 */
+		wpa_supplicant_cancel_auth_timeout(wpa_s);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+		eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+	} else if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+		   wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
+		/*
+		 * The driver will take care of RSN 4-way handshake, so we need
+		 * to allow EAPOL supplicant to complete its work without
+		 * waiting for WPA supplicant.
+		 */
+		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+	} else if (ft_completed) {
+		/*
+		 * FT protocol completed - make sure EAPOL state machine ends
+		 * up in authenticated.
+		 */
+		wpa_supplicant_cancel_auth_timeout(wpa_s);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+		eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+	}
+
+	wpa_s->last_eapol_matches_bssid = 0;
+
+	if (wpa_s->pending_eapol_rx) {
+		struct os_time now, age;
+		os_get_time(&now);
+		os_time_sub(&now, &wpa_s->pending_eapol_rx_time, &age);
+		if (age.sec == 0 && age.usec < 100000 &&
+		    os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) ==
+		    0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Process pending EAPOL "
+				"frame that was received just before "
+				"association notification");
+			wpa_supplicant_rx_eapol(
+				wpa_s, wpa_s->pending_eapol_rx_src,
+				wpabuf_head(wpa_s->pending_eapol_rx),
+				wpabuf_len(wpa_s->pending_eapol_rx));
+		}
+		wpabuf_free(wpa_s->pending_eapol_rx);
+		wpa_s->pending_eapol_rx = NULL;
+	}
+
+	if ((wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
+	     wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) &&
+	    wpa_s->current_ssid && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
+	    capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE) {
+		/* Set static WEP keys again */
+		wpa_set_wep_keys(wpa_s, wpa_s->current_ssid);
+	}
+
+#ifdef CONFIG_IBSS_RSN
+	if (wpa_s->current_ssid &&
+	    wpa_s->current_ssid->mode == WPAS_MODE_IBSS &&
+	    wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
+	    wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE &&
+	    wpa_s->ibss_rsn == NULL) {
+		wpa_s->ibss_rsn = ibss_rsn_init(wpa_s);
+		if (!wpa_s->ibss_rsn) {
+			wpa_msg(wpa_s, MSG_INFO, "Failed to init IBSS RSN");
+			wpa_supplicant_deauthenticate(
+				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+			return;
+		}
+
+		ibss_rsn_set_psk(wpa_s->ibss_rsn, wpa_s->current_ssid->psk);
+	}
+#endif /* CONFIG_IBSS_RSN */
+
+	wpas_wps_notify_assoc(wpa_s, bssid);
+}
+
+
+static int disconnect_reason_recoverable(u16 reason_code)
+{
+	return reason_code == WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY ||
+		reason_code == WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA ||
+		reason_code == WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA;
+}
+
+
+static void wpa_supplicant_event_disassoc(struct wpa_supplicant *wpa_s,
+					  u16 reason_code,
+					  int locally_generated)
+{
+	const u8 *bssid;
+
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
+		/*
+		 * At least Host AP driver and a Prism3 card seemed to be
+		 * generating streams of disconnected events when configuring
+		 * IBSS for WPA-None. Ignore them for now.
+		 */
+		return;
+	}
+
+	bssid = wpa_s->bssid;
+	if (is_zero_ether_addr(bssid))
+		bssid = wpa_s->pending_bssid;
+
+	if (!is_zero_ether_addr(bssid) ||
+	    wpa_s->wpa_state >= WPA_AUTHENTICATING) {
+		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_DISCONNECTED "bssid=" MACSTR
+			" reason=%d%s",
+			MAC2STR(bssid), reason_code,
+			locally_generated ? " locally_generated=1" : "");
+	}
+}
+
+
+static int could_be_psk_mismatch(struct wpa_supplicant *wpa_s, u16 reason_code,
+				 int locally_generated)
+{
+	if (wpa_s->wpa_state != WPA_4WAY_HANDSHAKE ||
+	    !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt))
+		return 0; /* Not in 4-way handshake with PSK */
+
+	/*
+	 * It looks like connection was lost while trying to go through PSK
+	 * 4-way handshake. Filter out known disconnection cases that are caused
+	 * by something else than PSK mismatch to avoid confusing reports.
+	 */
+
+	if (locally_generated) {
+		if (reason_code == WLAN_REASON_IE_IN_4WAY_DIFFERS)
+			return 0;
+	}
+
+	return 1;
+}
+
+
+static void wpa_supplicant_event_disassoc_finish(struct wpa_supplicant *wpa_s,
+						 u16 reason_code,
+						 int locally_generated)
+{
+	const u8 *bssid;
+	int authenticating;
+	u8 prev_pending_bssid[ETH_ALEN];
+	struct wpa_bss *fast_reconnect = NULL;
+	struct wpa_ssid *fast_reconnect_ssid = NULL;
+	struct wpa_ssid *last_ssid;
+
+	authenticating = wpa_s->wpa_state == WPA_AUTHENTICATING;
+	os_memcpy(prev_pending_bssid, wpa_s->pending_bssid, ETH_ALEN);
+
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
+		/*
+		 * At least Host AP driver and a Prism3 card seemed to be
+		 * generating streams of disconnected events when configuring
+		 * IBSS for WPA-None. Ignore them for now.
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - ignore in "
+			"IBSS/WPA-None mode");
+		return;
+	}
+
+	if (could_be_psk_mismatch(wpa_s, reason_code, locally_generated)) {
+		wpa_msg(wpa_s, MSG_INFO, "WPA: 4-Way Handshake failed - "
+			"pre-shared key may be incorrect");
+		wpas_auth_failed(wpa_s);
+	}
+	if (!wpa_s->auto_reconnect_disabled ||
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect enabled: try to "
+			"reconnect (wps=%d wpa_state=%d)",
+			wpa_s->key_mgmt == WPA_KEY_MGMT_WPS,
+			wpa_s->wpa_state);
+		if (wpa_s->wpa_state == WPA_COMPLETED &&
+		    wpa_s->current_ssid &&
+		    wpa_s->current_ssid->mode == WPAS_MODE_INFRA &&
+		    !locally_generated &&
+		    disconnect_reason_recoverable(reason_code)) {
+			/*
+			 * It looks like the AP has dropped association with
+			 * us, but could allow us to get back in. Try to
+			 * reconnect to the same BSS without full scan to save
+			 * time for some common cases.
+			 */
+			fast_reconnect = wpa_s->current_bss;
+			fast_reconnect_ssid = wpa_s->current_ssid;
+		} else if (wpa_s->wpa_state >= WPA_ASSOCIATING)
+			wpa_supplicant_req_scan(wpa_s, 0, 100000);
+		else
+			wpa_dbg(wpa_s, MSG_DEBUG, "Do not request new "
+				"immediate scan");
+	} else {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Auto connect disabled: do not "
+			"try to re-connect");
+		wpa_s->reassociate = 0;
+		wpa_s->disconnected = 1;
+		wpa_supplicant_cancel_sched_scan(wpa_s);
+	}
+	bssid = wpa_s->bssid;
+	if (is_zero_ether_addr(bssid))
+		bssid = wpa_s->pending_bssid;
+	if (wpa_s->wpa_state >= WPA_AUTHENTICATING)
+		wpas_connection_failed(wpa_s, bssid);
+	wpa_sm_notify_disassoc(wpa_s->wpa);
+	if (locally_generated)
+		wpa_s->disconnect_reason = -reason_code;
+	else
+		wpa_s->disconnect_reason = reason_code;
+	wpas_notify_disconnect_reason(wpa_s);
+	if (wpa_supplicant_dynamic_keys(wpa_s)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Disconnect event - remove keys");
+		wpa_s->keys_cleared = 0;
+		wpa_clear_keys(wpa_s, wpa_s->bssid);
+	}
+	last_ssid = wpa_s->current_ssid;
+	wpa_supplicant_mark_disassoc(wpa_s);
+
+	if (authenticating && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)) {
+		sme_disassoc_while_authenticating(wpa_s, prev_pending_bssid);
+		wpa_s->current_ssid = last_ssid;
+	}
+
+	if (fast_reconnect) {
+#ifndef CONFIG_NO_SCAN_PROCESSING
+		wpa_dbg(wpa_s, MSG_DEBUG, "Try to reconnect to the same BSS");
+		if (wpa_supplicant_connect(wpa_s, fast_reconnect,
+					   fast_reconnect_ssid) < 0) {
+			/* Recover through full scan */
+			wpa_supplicant_req_scan(wpa_s, 0, 100000);
+		}
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+	}
+}
+
+
+#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	if (!wpa_s->pending_mic_error_report)
+		return;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Sending pending MIC error report");
+	wpa_sm_key_request(wpa_s->wpa, 1, wpa_s->pending_mic_error_pairwise);
+	wpa_s->pending_mic_error_report = 0;
+}
+#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
+
+
+static void
+wpa_supplicant_event_michael_mic_failure(struct wpa_supplicant *wpa_s,
+					 union wpa_event_data *data)
+{
+	int pairwise;
+	struct os_time t;
+
+	wpa_msg(wpa_s, MSG_WARNING, "Michael MIC failure detected");
+	pairwise = (data && data->michael_mic_failure.unicast);
+	os_get_time(&t);
+	if ((wpa_s->last_michael_mic_error &&
+	     t.sec - wpa_s->last_michael_mic_error <= 60) ||
+	    wpa_s->pending_mic_error_report) {
+		if (wpa_s->pending_mic_error_report) {
+			/*
+			 * Send the pending MIC error report immediately since
+			 * we are going to start countermeasures and AP better
+			 * do the same.
+			 */
+			wpa_sm_key_request(wpa_s->wpa, 1,
+					   wpa_s->pending_mic_error_pairwise);
+		}
+
+		/* Send the new MIC error report immediately since we are going
+		 * to start countermeasures and AP better do the same.
+		 */
+		wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
+
+		/* initialize countermeasures */
+		wpa_s->countermeasures = 1;
+
+		wpa_blacklist_add(wpa_s, wpa_s->bssid);
+
+		wpa_msg(wpa_s, MSG_WARNING, "TKIP countermeasures started");
+
+		/*
+		 * Need to wait for completion of request frame. We do not get
+		 * any callback for the message completion, so just wait a
+		 * short while and hope for the best. */
+		os_sleep(0, 10000);
+
+		wpa_drv_set_countermeasures(wpa_s, 1);
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_MICHAEL_MIC_FAILURE);
+		eloop_cancel_timeout(wpa_supplicant_stop_countermeasures,
+				     wpa_s, NULL);
+		eloop_register_timeout(60, 0,
+				       wpa_supplicant_stop_countermeasures,
+				       wpa_s, NULL);
+		/* TODO: mark the AP rejected for 60 second. STA is
+		 * allowed to associate with another AP.. */
+	} else {
+#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+		if (wpa_s->mic_errors_seen) {
+			/*
+			 * Reduce the effectiveness of Michael MIC error
+			 * reports as a means for attacking against TKIP if
+			 * more than one MIC failure is noticed with the same
+			 * PTK. We delay the transmission of the reports by a
+			 * random time between 0 and 60 seconds in order to
+			 * force the attacker wait 60 seconds before getting
+			 * the information on whether a frame resulted in a MIC
+			 * failure.
+			 */
+			u8 rval[4];
+			int sec;
+
+			if (os_get_random(rval, sizeof(rval)) < 0)
+				sec = os_random() % 60;
+			else
+				sec = WPA_GET_BE32(rval) % 60;
+			wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Delay MIC error "
+				"report %d seconds", sec);
+			wpa_s->pending_mic_error_report = 1;
+			wpa_s->pending_mic_error_pairwise = pairwise;
+			eloop_cancel_timeout(
+				wpa_supplicant_delayed_mic_error_report,
+				wpa_s, NULL);
+			eloop_register_timeout(
+				sec, os_random() % 1000000,
+				wpa_supplicant_delayed_mic_error_report,
+				wpa_s, NULL);
+		} else {
+			wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
+		}
+#else /* CONFIG_DELAYED_MIC_ERROR_REPORT */
+		wpa_sm_key_request(wpa_s->wpa, 1, pairwise);
+#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
+	}
+	wpa_s->last_michael_mic_error = t.sec;
+	wpa_s->mic_errors_seen++;
+}
+
+
+#ifdef CONFIG_TERMINATE_ONLASTIF
+static int any_interfaces(struct wpa_supplicant *head)
+{
+	struct wpa_supplicant *wpa_s;
+
+	for (wpa_s = head; wpa_s != NULL; wpa_s = wpa_s->next)
+		if (!wpa_s->interface_removed)
+			return 1;
+	return 0;
+}
+#endif /* CONFIG_TERMINATE_ONLASTIF */
+
+
+static void
+wpa_supplicant_event_interface_status(struct wpa_supplicant *wpa_s,
+				      union wpa_event_data *data)
+{
+	if (os_strcmp(wpa_s->ifname, data->interface_status.ifname) != 0)
+		return;
+
+	switch (data->interface_status.ievent) {
+	case EVENT_INTERFACE_ADDED:
+		if (!wpa_s->interface_removed)
+			break;
+		wpa_s->interface_removed = 0;
+		wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was added");
+		if (wpa_supplicant_driver_init(wpa_s) < 0) {
+			wpa_msg(wpa_s, MSG_INFO, "Failed to initialize the "
+				"driver after interface was added");
+		}
+		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+		break;
+	case EVENT_INTERFACE_REMOVED:
+		wpa_dbg(wpa_s, MSG_DEBUG, "Configured interface was removed");
+		wpa_s->interface_removed = 1;
+		wpa_supplicant_mark_disassoc(wpa_s);
+		wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
+		l2_packet_deinit(wpa_s->l2);
+		wpa_s->l2 = NULL;
+#ifdef CONFIG_IBSS_RSN
+		ibss_rsn_deinit(wpa_s->ibss_rsn);
+		wpa_s->ibss_rsn = NULL;
+#endif /* CONFIG_IBSS_RSN */
+#ifdef CONFIG_TERMINATE_ONLASTIF
+		/* check if last interface */
+		if (!any_interfaces(wpa_s->global->ifaces))
+			eloop_terminate();
+#endif /* CONFIG_TERMINATE_ONLASTIF */
+		break;
+	}
+}
+
+
+#ifdef CONFIG_PEERKEY
+static void
+wpa_supplicant_event_stkstart(struct wpa_supplicant *wpa_s,
+			      union wpa_event_data *data)
+{
+	if (data == NULL)
+		return;
+	wpa_sm_stkstart(wpa_s->wpa, data->stkstart.peer);
+}
+#endif /* CONFIG_PEERKEY */
+
+
+#ifdef CONFIG_TDLS
+static void wpa_supplicant_event_tdls(struct wpa_supplicant *wpa_s,
+				      union wpa_event_data *data)
+{
+	if (data == NULL)
+		return;
+	switch (data->tdls.oper) {
+	case TDLS_REQUEST_SETUP:
+		wpa_tdls_start(wpa_s->wpa, data->tdls.peer);
+		break;
+	case TDLS_REQUEST_TEARDOWN:
+		wpa_tdls_send_teardown(wpa_s->wpa, data->tdls.peer,
+				       data->tdls.reason_code);
+		break;
+	}
+}
+#endif /* CONFIG_TDLS */
+
+
+#ifdef CONFIG_WNM
+static void wpa_supplicant_event_wnm(struct wpa_supplicant *wpa_s,
+				     union wpa_event_data *data)
+{
+	if (data == NULL)
+		return;
+	switch (data->wnm.oper) {
+	case WNM_OPER_SLEEP:
+		wpa_printf(MSG_DEBUG, "Start sending WNM-Sleep Request "
+			   "(action=%d, intval=%d)",
+			   data->wnm.sleep_action, data->wnm.sleep_intval);
+		ieee802_11_send_wnmsleep_req(wpa_s, data->wnm.sleep_action,
+					     data->wnm.sleep_intval, NULL);
+		break;
+	}
+}
+#endif /* CONFIG_WNM */
+
+
+#ifdef CONFIG_IEEE80211R
+static void
+wpa_supplicant_event_ft_response(struct wpa_supplicant *wpa_s,
+				 union wpa_event_data *data)
+{
+	if (data == NULL)
+		return;
+
+	if (wpa_ft_process_response(wpa_s->wpa, data->ft_ies.ies,
+				    data->ft_ies.ies_len,
+				    data->ft_ies.ft_action,
+				    data->ft_ies.target_ap,
+				    data->ft_ies.ric_ies,
+				    data->ft_ies.ric_ies_len) < 0) {
+		/* TODO: prevent MLME/driver from trying to associate? */
+	}
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+#ifdef CONFIG_IBSS_RSN
+static void wpa_supplicant_event_ibss_rsn_start(struct wpa_supplicant *wpa_s,
+						union wpa_event_data *data)
+{
+	struct wpa_ssid *ssid;
+	if (wpa_s->wpa_state < WPA_ASSOCIATED)
+		return;
+	if (data == NULL)
+		return;
+	ssid = wpa_s->current_ssid;
+	if (ssid == NULL)
+		return;
+	if (ssid->mode != WPAS_MODE_IBSS || !wpa_key_mgmt_wpa(ssid->key_mgmt))
+		return;
+
+	ibss_rsn_start(wpa_s->ibss_rsn, data->ibss_rsn_start.peer);
+}
+#endif /* CONFIG_IBSS_RSN */
+
+
+#ifdef CONFIG_IEEE80211R
+static void ft_rx_action(struct wpa_supplicant *wpa_s, const u8 *data,
+			 size_t len)
+{
+	const u8 *sta_addr, *target_ap_addr;
+	u16 status;
+
+	wpa_hexdump(MSG_MSGDUMP, "FT: RX Action", data, len);
+	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME))
+		return; /* only SME case supported for now */
+	if (len < 1 + 2 * ETH_ALEN + 2)
+		return;
+	if (data[0] != 2)
+		return; /* Only FT Action Response is supported for now */
+	sta_addr = data + 1;
+	target_ap_addr = data + 1 + ETH_ALEN;
+	status = WPA_GET_LE16(data + 1 + 2 * ETH_ALEN);
+	wpa_dbg(wpa_s, MSG_DEBUG, "FT: Received FT Action Response: STA "
+		MACSTR " TargetAP " MACSTR " status %u",
+		MAC2STR(sta_addr), MAC2STR(target_ap_addr), status);
+
+	if (os_memcmp(sta_addr, wpa_s->own_addr, ETH_ALEN) != 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "FT: Foreign STA Address " MACSTR
+			" in FT Action Response", MAC2STR(sta_addr));
+		return;
+	}
+
+	if (status) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "FT: FT Action Response indicates "
+			"failure (status code %d)", status);
+		/* TODO: report error to FT code(?) */
+		return;
+	}
+
+	if (wpa_ft_process_response(wpa_s->wpa, data + 1 + 2 * ETH_ALEN + 2,
+				    len - (1 + 2 * ETH_ALEN + 2), 1,
+				    target_ap_addr, NULL, 0) < 0)
+		return;
+
+#ifdef CONFIG_SME
+	{
+		struct wpa_bss *bss;
+		bss = wpa_bss_get_bssid(wpa_s, target_ap_addr);
+		if (bss)
+			wpa_s->sme.freq = bss->freq;
+		wpa_s->sme.auth_alg = WPA_AUTH_ALG_FT;
+		sme_associate(wpa_s, WPAS_MODE_INFRA, target_ap_addr,
+			      WLAN_AUTH_FT);
+	}
+#endif /* CONFIG_SME */
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+static void wpa_supplicant_event_unprot_deauth(struct wpa_supplicant *wpa_s,
+					       struct unprot_deauth *e)
+{
+#ifdef CONFIG_IEEE80211W
+	wpa_printf(MSG_DEBUG, "Unprotected Deauthentication frame "
+		   "dropped: " MACSTR " -> " MACSTR
+		   " (reason code %u)",
+		   MAC2STR(e->sa), MAC2STR(e->da), e->reason_code);
+	sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code);
+#endif /* CONFIG_IEEE80211W */
+}
+
+
+static void wpa_supplicant_event_unprot_disassoc(struct wpa_supplicant *wpa_s,
+						 struct unprot_disassoc *e)
+{
+#ifdef CONFIG_IEEE80211W
+	wpa_printf(MSG_DEBUG, "Unprotected Disassociation frame "
+		   "dropped: " MACSTR " -> " MACSTR
+		   " (reason code %u)",
+		   MAC2STR(e->sa), MAC2STR(e->da), e->reason_code);
+	sme_event_unprot_disconnect(wpa_s, e->sa, e->da, e->reason_code);
+#endif /* CONFIG_IEEE80211W */
+}
+
+
+void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
+			  union wpa_event_data *data)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	u16 reason_code = 0;
+	int locally_generated = 0;
+
+	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED &&
+	    event != EVENT_INTERFACE_ENABLED &&
+	    event != EVENT_INTERFACE_STATUS &&
+	    event != EVENT_SCHED_SCAN_STOPPED) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Ignore event %s (%d) while interface is disabled",
+			event_to_string(event), event);
+		return;
+	}
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+{
+	int level = MSG_DEBUG;
+
+	if (event == EVENT_RX_MGMT && data->rx_mgmt.frame_len >= 24) {
+		const struct ieee80211_hdr *hdr;
+		u16 fc;
+		hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
+		fc = le_to_host16(hdr->frame_control);
+		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
+			level = MSG_EXCESSIVE;
+	}
+
+	wpa_dbg(wpa_s, level, "Event %s (%d) received",
+		event_to_string(event), event);
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+	switch (event) {
+	case EVENT_AUTH:
+		sme_event_auth(wpa_s, data);
+		break;
+	case EVENT_ASSOC:
+		wpa_supplicant_event_assoc(wpa_s, data);
+		break;
+	case EVENT_DISASSOC:
+		wpa_dbg(wpa_s, MSG_DEBUG, "Disassociation notification");
+		if (data) {
+			wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s",
+				data->disassoc_info.reason_code,
+				data->disassoc_info.locally_generated ?
+				" (locally generated)" : "");
+			if (data->disassoc_info.addr)
+				wpa_dbg(wpa_s, MSG_DEBUG, " * address " MACSTR,
+					MAC2STR(data->disassoc_info.addr));
+		}
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface && data && data->disassoc_info.addr) {
+			hostapd_notif_disassoc(wpa_s->ap_iface->bss[0],
+					       data->disassoc_info.addr);
+			break;
+		}
+		if (wpa_s->ap_iface) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Ignore disassoc event in "
+				"AP mode");
+			break;
+		}
+#endif /* CONFIG_AP */
+		if (data) {
+			reason_code = data->disassoc_info.reason_code;
+			locally_generated =
+				data->disassoc_info.locally_generated;
+			wpa_hexdump(MSG_DEBUG, "Disassociation frame IE(s)",
+				    data->disassoc_info.ie,
+				    data->disassoc_info.ie_len);
+#ifdef CONFIG_P2P
+			wpas_p2p_disassoc_notif(
+				wpa_s, data->disassoc_info.addr, reason_code,
+				data->disassoc_info.ie,
+				data->disassoc_info.ie_len,
+				locally_generated);
+#endif /* CONFIG_P2P */
+		}
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+			sme_event_disassoc(wpa_s, data);
+		/* fall through */
+	case EVENT_DEAUTH:
+		if (event == EVENT_DEAUTH) {
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"Deauthentication notification");
+			if (data) {
+				reason_code = data->deauth_info.reason_code;
+				locally_generated =
+					data->deauth_info.locally_generated;
+				wpa_dbg(wpa_s, MSG_DEBUG, " * reason %u%s",
+					data->deauth_info.reason_code,
+					data->deauth_info.locally_generated ?
+					" (locally generated)" : "");
+				if (data->deauth_info.addr) {
+					wpa_dbg(wpa_s, MSG_DEBUG, " * address "
+						MACSTR,
+						MAC2STR(data->deauth_info.
+							addr));
+				}
+				wpa_hexdump(MSG_DEBUG,
+					    "Deauthentication frame IE(s)",
+					    data->deauth_info.ie,
+					    data->deauth_info.ie_len);
+			}
+		}
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface && data && data->deauth_info.addr) {
+			hostapd_notif_disassoc(wpa_s->ap_iface->bss[0],
+					       data->deauth_info.addr);
+			break;
+		}
+		if (wpa_s->ap_iface) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Ignore deauth event in "
+				"AP mode");
+			break;
+		}
+#endif /* CONFIG_AP */
+		wpa_supplicant_event_disassoc(wpa_s, reason_code,
+					      locally_generated);
+		if (reason_code == WLAN_REASON_IEEE_802_1X_AUTH_FAILED ||
+		    ((wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+		      (wpa_s->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)) &&
+		     eapol_sm_failed(wpa_s->eapol)))
+			wpas_auth_failed(wpa_s);
+#ifdef CONFIG_P2P
+		if (event == EVENT_DEAUTH && data) {
+			if (wpas_p2p_deauth_notif(wpa_s,
+						  data->deauth_info.addr,
+						  reason_code,
+						  data->deauth_info.ie,
+						  data->deauth_info.ie_len,
+						  locally_generated) > 0) {
+				/*
+				 * The interface was removed, so cannot
+				 * continue processing any additional
+				 * operations after this.
+				 */
+				break;
+			}
+		}
+#endif /* CONFIG_P2P */
+		wpa_supplicant_event_disassoc_finish(wpa_s, reason_code,
+						     locally_generated);
+		break;
+	case EVENT_MICHAEL_MIC_FAILURE:
+		wpa_supplicant_event_michael_mic_failure(wpa_s, data);
+		break;
+#ifndef CONFIG_NO_SCAN_PROCESSING
+	case EVENT_SCAN_RESULTS:
+		wpa_supplicant_event_scan_results(wpa_s, data);
+#ifdef CONFIG_P2P
+	if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+	    wpa_s->global->p2p != NULL &&
+	    wpa_s->wpa_state != WPA_AUTHENTICATING &&
+	    wpa_s->wpa_state != WPA_ASSOCIATING) {
+		wpa_s->global->p2p_cb_on_scan_complete = 0;
+		if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+				"continued after scan result processing");
+		}
+	}
+#endif /* CONFIG_P2P */
+		break;
+#endif /* CONFIG_NO_SCAN_PROCESSING */
+	case EVENT_ASSOCINFO:
+		wpa_supplicant_event_associnfo(wpa_s, data);
+		break;
+	case EVENT_INTERFACE_STATUS:
+		wpa_supplicant_event_interface_status(wpa_s, data);
+		break;
+	case EVENT_PMKID_CANDIDATE:
+		wpa_supplicant_event_pmkid_candidate(wpa_s, data);
+		break;
+#ifdef CONFIG_PEERKEY
+	case EVENT_STKSTART:
+		wpa_supplicant_event_stkstart(wpa_s, data);
+		break;
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_TDLS
+	case EVENT_TDLS:
+		wpa_supplicant_event_tdls(wpa_s, data);
+		break;
+#endif /* CONFIG_TDLS */
+#ifdef CONFIG_WNM
+	case EVENT_WNM:
+		wpa_supplicant_event_wnm(wpa_s, data);
+		break;
+#endif /* CONFIG_WNM */
+#ifdef CONFIG_IEEE80211R
+	case EVENT_FT_RESPONSE:
+		wpa_supplicant_event_ft_response(wpa_s, data);
+		break;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IBSS_RSN
+	case EVENT_IBSS_RSN_START:
+		wpa_supplicant_event_ibss_rsn_start(wpa_s, data);
+		break;
+#endif /* CONFIG_IBSS_RSN */
+	case EVENT_ASSOC_REJECT:
+		if (data->assoc_reject.bssid)
+			wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
+				"bssid=" MACSTR	" status_code=%u",
+				MAC2STR(data->assoc_reject.bssid),
+				data->assoc_reject.status_code);
+		else
+			wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_ASSOC_REJECT
+				"status_code=%u",
+				data->assoc_reject.status_code);
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+			sme_event_assoc_reject(wpa_s, data);
+		else {
+			const u8 *bssid = data->assoc_reject.bssid;
+			if (bssid == NULL || is_zero_ether_addr(bssid))
+				bssid = wpa_s->pending_bssid;
+			wpas_connection_failed(wpa_s, bssid);
+			wpa_supplicant_mark_disassoc(wpa_s);
+		}
+		break;
+	case EVENT_AUTH_TIMED_OUT:
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+			sme_event_auth_timed_out(wpa_s, data);
+		break;
+	case EVENT_ASSOC_TIMED_OUT:
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+			sme_event_assoc_timed_out(wpa_s, data);
+		break;
+	case EVENT_TX_STATUS:
+		wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS dst=" MACSTR
+			" type=%d stype=%d",
+			MAC2STR(data->tx_status.dst),
+			data->tx_status.type, data->tx_status.stype);
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface == NULL) {
+#ifdef CONFIG_OFFCHANNEL
+			if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
+			    data->tx_status.stype == WLAN_FC_STYPE_ACTION)
+				offchannel_send_action_tx_status(
+					wpa_s, data->tx_status.dst,
+					data->tx_status.data,
+					data->tx_status.data_len,
+					data->tx_status.ack ?
+					OFFCHANNEL_SEND_ACTION_SUCCESS :
+					OFFCHANNEL_SEND_ACTION_NO_ACK);
+#endif /* CONFIG_OFFCHANNEL */
+			break;
+		}
+#endif /* CONFIG_AP */
+#ifdef CONFIG_OFFCHANNEL
+		wpa_dbg(wpa_s, MSG_DEBUG, "EVENT_TX_STATUS pending_dst="
+			MACSTR, MAC2STR(wpa_s->parent->pending_action_dst));
+		/*
+		 * Catch TX status events for Action frames we sent via group
+		 * interface in GO mode.
+		 */
+		if (data->tx_status.type == WLAN_FC_TYPE_MGMT &&
+		    data->tx_status.stype == WLAN_FC_STYPE_ACTION &&
+		    os_memcmp(wpa_s->parent->pending_action_dst,
+			      data->tx_status.dst, ETH_ALEN) == 0) {
+			offchannel_send_action_tx_status(
+				wpa_s->parent, data->tx_status.dst,
+				data->tx_status.data,
+				data->tx_status.data_len,
+				data->tx_status.ack ?
+				OFFCHANNEL_SEND_ACTION_SUCCESS :
+				OFFCHANNEL_SEND_ACTION_NO_ACK);
+			break;
+		}
+#endif /* CONFIG_OFFCHANNEL */
+#ifdef CONFIG_AP
+		switch (data->tx_status.type) {
+		case WLAN_FC_TYPE_MGMT:
+			ap_mgmt_tx_cb(wpa_s, data->tx_status.data,
+				      data->tx_status.data_len,
+				      data->tx_status.stype,
+				      data->tx_status.ack);
+			break;
+		case WLAN_FC_TYPE_DATA:
+			ap_tx_status(wpa_s, data->tx_status.dst,
+				     data->tx_status.data,
+				     data->tx_status.data_len,
+				     data->tx_status.ack);
+			break;
+		}
+#endif /* CONFIG_AP */
+		break;
+#ifdef CONFIG_AP
+	case EVENT_EAPOL_TX_STATUS:
+		ap_eapol_tx_status(wpa_s, data->eapol_tx_status.dst,
+				   data->eapol_tx_status.data,
+				   data->eapol_tx_status.data_len,
+				   data->eapol_tx_status.ack);
+		break;
+	case EVENT_DRIVER_CLIENT_POLL_OK:
+		ap_client_poll_ok(wpa_s, data->client_poll.addr);
+		break;
+	case EVENT_RX_FROM_UNKNOWN:
+		if (wpa_s->ap_iface == NULL)
+			break;
+		ap_rx_from_unknown_sta(wpa_s, data->rx_from_unknown.addr,
+				       data->rx_from_unknown.wds);
+		break;
+	case EVENT_CH_SWITCH:
+		if (!data)
+			break;
+		if (!wpa_s->ap_iface) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "AP: Ignore channel switch "
+				"event in non-AP mode");
+			break;
+		}
+
+#ifdef CONFIG_AP
+		wpas_ap_ch_switch(wpa_s, data->ch_switch.freq,
+				  data->ch_switch.ht_enabled,
+				  data->ch_switch.ch_offset);
+#endif /* CONFIG_AP */
+		break;
+	case EVENT_RX_MGMT: {
+		u16 fc, stype;
+		const struct ieee80211_mgmt *mgmt;
+
+		mgmt = (const struct ieee80211_mgmt *)
+			data->rx_mgmt.frame;
+		fc = le_to_host16(mgmt->frame_control);
+		stype = WLAN_FC_GET_STYPE(fc);
+
+		if (wpa_s->ap_iface == NULL) {
+#ifdef CONFIG_P2P
+			if (stype == WLAN_FC_STYPE_PROBE_REQ &&
+			    data->rx_mgmt.frame_len > 24) {
+				const u8 *src = mgmt->sa;
+				const u8 *ie = mgmt->u.probe_req.variable;
+				size_t ie_len = data->rx_mgmt.frame_len -
+					(mgmt->u.probe_req.variable -
+					 data->rx_mgmt.frame);
+				wpas_p2p_probe_req_rx(
+					wpa_s, src, mgmt->da,
+					mgmt->bssid, ie, ie_len,
+					data->rx_mgmt.ssi_signal);
+				break;
+			}
+#endif /* CONFIG_P2P */
+			wpa_dbg(wpa_s, MSG_DEBUG, "AP: ignore received "
+				"management frame in non-AP mode");
+			break;
+		}
+
+		if (stype == WLAN_FC_STYPE_PROBE_REQ &&
+		    data->rx_mgmt.frame_len > 24) {
+			const u8 *ie = mgmt->u.probe_req.variable;
+			size_t ie_len = data->rx_mgmt.frame_len -
+				(mgmt->u.probe_req.variable -
+				 data->rx_mgmt.frame);
+
+			wpas_notify_preq(wpa_s, mgmt->sa, mgmt->da,
+					 mgmt->bssid, ie, ie_len,
+					 data->rx_mgmt.ssi_signal);
+		}
+
+		ap_mgmt_rx(wpa_s, &data->rx_mgmt);
+		break;
+		}
+#endif /* CONFIG_AP */
+	case EVENT_RX_ACTION:
+		wpa_dbg(wpa_s, MSG_DEBUG, "Received Action frame: SA=" MACSTR
+			" Category=%u DataLen=%d freq=%d MHz",
+			MAC2STR(data->rx_action.sa),
+			data->rx_action.category, (int) data->rx_action.len,
+			data->rx_action.freq);
+#ifdef CONFIG_IEEE80211R
+		if (data->rx_action.category == WLAN_ACTION_FT) {
+			ft_rx_action(wpa_s, data->rx_action.data,
+				     data->rx_action.len);
+			break;
+		}
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+#ifdef CONFIG_SME
+		if (data->rx_action.category == WLAN_ACTION_SA_QUERY) {
+			sme_sa_query_rx(wpa_s, data->rx_action.sa,
+					data->rx_action.data,
+					data->rx_action.len);
+			break;
+		}
+#endif /* CONFIG_SME */
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WNM
+		if (data->rx_action.category == WLAN_ACTION_WNM) {
+			ieee802_11_rx_wnm_action(wpa_s, &data->rx_action);
+			break;
+		}
+#endif /* CONFIG_WNM */
+#ifdef CONFIG_GAS
+		if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
+		    gas_query_rx(wpa_s->gas, data->rx_action.da,
+				 data->rx_action.sa, data->rx_action.bssid,
+				 data->rx_action.data, data->rx_action.len,
+				 data->rx_action.freq) == 0)
+			break;
+#endif /* CONFIG_GAS */
+#ifdef CONFIG_TDLS
+		if (data->rx_action.category == WLAN_ACTION_PUBLIC &&
+		    data->rx_action.len >= 4 &&
+		    data->rx_action.data[0] == WLAN_TDLS_DISCOVERY_RESPONSE) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "TDLS: Received Discovery "
+				"Response from " MACSTR,
+				MAC2STR(data->rx_action.sa));
+			break;
+		}
+#endif /* CONFIG_TDLS */
+#ifdef CONFIG_P2P
+		wpas_p2p_rx_action(wpa_s, data->rx_action.da,
+				   data->rx_action.sa,
+				   data->rx_action.bssid,
+				   data->rx_action.category,
+				   data->rx_action.data,
+				   data->rx_action.len, data->rx_action.freq);
+#endif /* CONFIG_P2P */
+		break;
+	case EVENT_RX_PROBE_REQ:
+		if (data->rx_probe_req.sa == NULL ||
+		    data->rx_probe_req.ie == NULL)
+			break;
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface) {
+			hostapd_probe_req_rx(wpa_s->ap_iface->bss[0],
+					     data->rx_probe_req.sa,
+					     data->rx_probe_req.da,
+					     data->rx_probe_req.bssid,
+					     data->rx_probe_req.ie,
+					     data->rx_probe_req.ie_len,
+					     data->rx_probe_req.ssi_signal);
+			break;
+		}
+#endif /* CONFIG_AP */
+#ifdef CONFIG_P2P
+		wpas_p2p_probe_req_rx(wpa_s, data->rx_probe_req.sa,
+				      data->rx_probe_req.da,
+				      data->rx_probe_req.bssid,
+				      data->rx_probe_req.ie,
+				      data->rx_probe_req.ie_len,
+				      data->rx_probe_req.ssi_signal);
+#endif /* CONFIG_P2P */
+		break;
+	case EVENT_REMAIN_ON_CHANNEL:
+#ifdef CONFIG_OFFCHANNEL
+		offchannel_remain_on_channel_cb(
+			wpa_s, data->remain_on_channel.freq,
+			data->remain_on_channel.duration);
+#endif /* CONFIG_OFFCHANNEL */
+#ifdef CONFIG_P2P
+		wpas_p2p_remain_on_channel_cb(
+			wpa_s, data->remain_on_channel.freq,
+			data->remain_on_channel.duration);
+#endif /* CONFIG_P2P */
+		break;
+	case EVENT_CANCEL_REMAIN_ON_CHANNEL:
+#ifdef CONFIG_OFFCHANNEL
+		offchannel_cancel_remain_on_channel_cb(
+			wpa_s, data->remain_on_channel.freq);
+#endif /* CONFIG_OFFCHANNEL */
+#ifdef CONFIG_P2P
+		wpas_p2p_cancel_remain_on_channel_cb(
+			wpa_s, data->remain_on_channel.freq);
+#endif /* CONFIG_P2P */
+		break;
+#ifdef CONFIG_P2P
+	case EVENT_P2P_DEV_FOUND: {
+		struct p2p_peer_info peer_info;
+
+		os_memset(&peer_info, 0, sizeof(peer_info));
+		if (data->p2p_dev_found.dev_addr)
+			os_memcpy(peer_info.p2p_device_addr,
+				  data->p2p_dev_found.dev_addr, ETH_ALEN);
+		if (data->p2p_dev_found.pri_dev_type)
+			os_memcpy(peer_info.pri_dev_type,
+				  data->p2p_dev_found.pri_dev_type,
+				  sizeof(peer_info.pri_dev_type));
+		if (data->p2p_dev_found.dev_name)
+			os_strlcpy(peer_info.device_name,
+				   data->p2p_dev_found.dev_name,
+				   sizeof(peer_info.device_name));
+		peer_info.config_methods = data->p2p_dev_found.config_methods;
+		peer_info.dev_capab = data->p2p_dev_found.dev_capab;
+		peer_info.group_capab = data->p2p_dev_found.group_capab;
+
+		/*
+		 * FIX: new_device=1 is not necessarily correct. We should
+		 * maintain a P2P peer database in wpa_supplicant and update
+		 * this information based on whether the peer is truly new.
+		 */
+		wpas_dev_found(wpa_s, data->p2p_dev_found.addr, &peer_info, 1);
+		break;
+		}
+	case EVENT_P2P_GO_NEG_REQ_RX:
+		wpas_go_neg_req_rx(wpa_s, data->p2p_go_neg_req_rx.src,
+				   data->p2p_go_neg_req_rx.dev_passwd_id);
+		break;
+	case EVENT_P2P_GO_NEG_COMPLETED:
+		wpas_go_neg_completed(wpa_s, data->p2p_go_neg_completed.res);
+		break;
+	case EVENT_P2P_PROV_DISC_REQUEST:
+		wpas_prov_disc_req(wpa_s, data->p2p_prov_disc_req.peer,
+				   data->p2p_prov_disc_req.config_methods,
+				   data->p2p_prov_disc_req.dev_addr,
+				   data->p2p_prov_disc_req.pri_dev_type,
+				   data->p2p_prov_disc_req.dev_name,
+				   data->p2p_prov_disc_req.supp_config_methods,
+				   data->p2p_prov_disc_req.dev_capab,
+				   data->p2p_prov_disc_req.group_capab,
+				   NULL, 0);
+		break;
+	case EVENT_P2P_PROV_DISC_RESPONSE:
+		wpas_prov_disc_resp(wpa_s, data->p2p_prov_disc_resp.peer,
+				    data->p2p_prov_disc_resp.config_methods);
+		break;
+	case EVENT_P2P_SD_REQUEST:
+		wpas_sd_request(wpa_s, data->p2p_sd_req.freq,
+				data->p2p_sd_req.sa,
+				data->p2p_sd_req.dialog_token,
+				data->p2p_sd_req.update_indic,
+				data->p2p_sd_req.tlvs,
+				data->p2p_sd_req.tlvs_len);
+		break;
+	case EVENT_P2P_SD_RESPONSE:
+		wpas_sd_response(wpa_s, data->p2p_sd_resp.sa,
+				 data->p2p_sd_resp.update_indic,
+				 data->p2p_sd_resp.tlvs,
+				 data->p2p_sd_resp.tlvs_len);
+		break;
+#endif /* CONFIG_P2P */
+	case EVENT_EAPOL_RX:
+		wpa_supplicant_rx_eapol(wpa_s, data->eapol_rx.src,
+					data->eapol_rx.data,
+					data->eapol_rx.data_len);
+		break;
+	case EVENT_SIGNAL_CHANGE:
+		bgscan_notify_signal_change(
+			wpa_s, data->signal_change.above_threshold,
+			data->signal_change.current_signal,
+			data->signal_change.current_noise,
+			data->signal_change.current_txrate);
+		break;
+	case EVENT_INTERFACE_ENABLED:
+		wpa_dbg(wpa_s, MSG_DEBUG, "Interface was enabled");
+		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+			wpa_supplicant_update_mac_addr(wpa_s);
+#ifdef CONFIG_AP
+			if (!wpa_s->ap_iface) {
+				wpa_supplicant_set_state(wpa_s,
+							 WPA_DISCONNECTED);
+				wpa_supplicant_req_scan(wpa_s, 0, 0);
+			} else
+				wpa_supplicant_set_state(wpa_s,
+							 WPA_COMPLETED);
+#else /* CONFIG_AP */
+			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+			wpa_supplicant_req_scan(wpa_s, 0, 0);
+#endif /* CONFIG_AP */
+		}
+		break;
+	case EVENT_INTERFACE_DISABLED:
+		wpa_dbg(wpa_s, MSG_DEBUG, "Interface was disabled");
+		wpa_supplicant_mark_disassoc(wpa_s);
+		wpa_supplicant_set_state(wpa_s, WPA_INTERFACE_DISABLED);
+		break;
+	case EVENT_CHANNEL_LIST_CHANGED:
+		if (wpa_s->drv_priv == NULL)
+			break; /* Ignore event during drv initialization */
+
+		free_hw_features(wpa_s);
+		wpa_s->hw.modes = wpa_drv_get_hw_feature_data(
+			wpa_s, &wpa_s->hw.num_modes, &wpa_s->hw.flags);
+
+#ifdef CONFIG_P2P
+		wpas_p2p_update_channel_list(wpa_s);
+#endif /* CONFIG_P2P */
+		break;
+	case EVENT_INTERFACE_UNAVAILABLE:
+#ifdef CONFIG_P2P
+		wpas_p2p_interface_unavailable(wpa_s);
+#endif /* CONFIG_P2P */
+		break;
+	case EVENT_BEST_CHANNEL:
+		wpa_dbg(wpa_s, MSG_DEBUG, "Best channel event received "
+			"(%d %d %d)",
+			data->best_chan.freq_24, data->best_chan.freq_5,
+			data->best_chan.freq_overall);
+		wpa_s->best_24_freq = data->best_chan.freq_24;
+		wpa_s->best_5_freq = data->best_chan.freq_5;
+		wpa_s->best_overall_freq = data->best_chan.freq_overall;
+#ifdef CONFIG_P2P
+		wpas_p2p_update_best_channels(wpa_s, data->best_chan.freq_24,
+					      data->best_chan.freq_5,
+					      data->best_chan.freq_overall);
+#endif /* CONFIG_P2P */
+		break;
+	case EVENT_UNPROT_DEAUTH:
+		wpa_supplicant_event_unprot_deauth(wpa_s,
+						   &data->unprot_deauth);
+		break;
+	case EVENT_UNPROT_DISASSOC:
+		wpa_supplicant_event_unprot_disassoc(wpa_s,
+						     &data->unprot_disassoc);
+		break;
+	case EVENT_STATION_LOW_ACK:
+#ifdef CONFIG_AP
+		if (wpa_s->ap_iface && data)
+			hostapd_event_sta_low_ack(wpa_s->ap_iface->bss[0],
+						  data->low_ack.addr);
+#endif /* CONFIG_AP */
+#ifdef CONFIG_TDLS
+		if (data)
+			wpa_tdls_disable_link(wpa_s->wpa, data->low_ack.addr);
+#endif /* CONFIG_TDLS */
+		break;
+	case EVENT_IBSS_PEER_LOST:
+#ifdef CONFIG_IBSS_RSN
+		ibss_rsn_stop(wpa_s->ibss_rsn, data->ibss_peer_lost.peer);
+#endif /* CONFIG_IBSS_RSN */
+		break;
+	case EVENT_DRIVER_GTK_REKEY:
+		if (os_memcmp(data->driver_gtk_rekey.bssid,
+			      wpa_s->bssid, ETH_ALEN))
+			break;
+		if (!wpa_s->wpa)
+			break;
+		wpa_sm_update_replay_ctr(wpa_s->wpa,
+					 data->driver_gtk_rekey.replay_ctr);
+		break;
+	case EVENT_SCHED_SCAN_STOPPED:
+		wpa_s->sched_scanning = 0;
+		wpa_supplicant_notify_scanning(wpa_s, 0);
+
+		if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED)
+			break;
+
+		/*
+		 * If we timed out, start a new sched scan to continue
+		 * searching for more SSIDs.
+		 */
+		if (wpa_s->sched_scan_timed_out)
+			wpa_supplicant_req_sched_scan(wpa_s);
+		break;
+	case EVENT_WPS_BUTTON_PUSHED:
+#ifdef CONFIG_WPS
+		wpas_wps_start_pbc(wpa_s, NULL, 0);
+#endif /* CONFIG_WPS */
+		break;
+	default:
+		wpa_msg(wpa_s, MSG_INFO, "Unknown event %d", event);
+		break;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/gas_query.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,58 @@
+/*
+ * Generic advertisement service (GAS) query
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef GAS_QUERY_H
+#define GAS_QUERY_H
+
+struct gas_query;
+
+#ifdef CONFIG_GAS
+
+struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s);
+void gas_query_deinit(struct gas_query *gas);
+int gas_query_rx(struct gas_query *gas, const u8 *da, const u8 *sa,
+		 const u8 *bssid, const u8 *data, size_t len, int freq);
+
+/**
+ * enum gas_query_result - GAS query result
+ */
+enum gas_query_result {
+	GAS_QUERY_SUCCESS,
+	GAS_QUERY_FAILURE,
+	GAS_QUERY_TIMEOUT,
+	GAS_QUERY_PEER_ERROR,
+	GAS_QUERY_INTERNAL_ERROR,
+	GAS_QUERY_CANCELLED,
+	GAS_QUERY_DELETED_AT_DEINIT
+};
+
+int gas_query_req(struct gas_query *gas, const u8 *dst, int freq,
+		  struct wpabuf *req,
+		  void (*cb)(void *ctx, const u8 *dst, u8 dialog_token,
+			     enum gas_query_result result,
+			     const struct wpabuf *adv_proto,
+			     const struct wpabuf *resp, u16 status_code),
+		  void *ctx);
+void gas_query_cancel(struct gas_query *gas, const u8 *dst, u8 dialog_token);
+
+#else /* CONFIG_GAS */
+
+static inline struct gas_query * gas_query_init(struct wpa_supplicant *wpa_s)
+{
+	return (void *) 1;
+}
+
+static inline void gas_query_deinit(struct gas_query *gas)
+{
+}
+
+#endif /* CONFIG_GAS */
+
+
+#endif /* GAS_QUERY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/hs20_supplicant.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,20 @@
+/*
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HS20_SUPPLICANT_H
+#define HS20_SUPPLICANT_H
+
+void wpas_hs20_add_indication(struct wpabuf *buf);
+
+int hs20_anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst, u32 stypes,
+		       const u8 *payload, size_t payload_len);
+struct wpabuf * hs20_build_anqp_req(u32 stypes, const u8 *payload,
+				    size_t payload_len);
+void hs20_parse_rx_hs20_anqp_resp(struct wpa_supplicant *wpa_s,
+				  const u8 *sa, const u8 *data, size_t slen);
+
+#endif /* HS20_SUPPLICANT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/ibss_rsn.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,44 @@
+/*
+ * wpa_supplicant - IBSS RSN
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IBSS_RSN_H
+#define IBSS_RSN_H
+
+struct ibss_rsn;
+
+struct ibss_rsn_peer {
+	struct ibss_rsn_peer *next;
+	struct ibss_rsn *ibss_rsn;
+
+	u8 addr[ETH_ALEN];
+
+	struct wpa_sm *supp;
+	enum wpa_states supp_state;
+	u8 supp_ie[80];
+	size_t supp_ie_len;
+
+	struct wpa_state_machine *auth;
+};
+
+struct ibss_rsn {
+	struct wpa_supplicant *wpa_s;
+	struct wpa_authenticator *auth_group;
+	struct ibss_rsn_peer *peers;
+	u8 psk[PMK_LEN];
+};
+
+
+struct ibss_rsn * ibss_rsn_init(struct wpa_supplicant *wpa_s);
+void ibss_rsn_deinit(struct ibss_rsn *ibss_rsn);
+int ibss_rsn_start(struct ibss_rsn *ibss_rsn, const u8 *addr);
+void ibss_rsn_stop(struct ibss_rsn *ibss_rsn, const u8 *peermac);
+int ibss_rsn_rx_eapol(struct ibss_rsn *ibss_rsn, const u8 *src_addr,
+		      const u8 *buf, size_t len);
+void ibss_rsn_set_psk(struct ibss_rsn *ibss_rsn, const u8 *psk);
+
+#endif /* IBSS_RSN_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/interworking.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,32 @@
+/*
+ * Interworking (IEEE 802.11u)
+ * Copyright (c) 2011-2012, Qualcomm Atheros
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef INTERWORKING_H
+#define INTERWORKING_H
+
+enum gas_query_result;
+
+int anqp_send_req(struct wpa_supplicant *wpa_s, const u8 *dst,
+		  u16 info_ids[], size_t num_ids);
+void anqp_resp_cb(void *ctx, const u8 *dst, u8 dialog_token,
+		  enum gas_query_result result,
+		  const struct wpabuf *adv_proto,
+		  const struct wpabuf *resp, u16 status_code);
+int gas_send_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+		     const struct wpabuf *adv_proto,
+		     const struct wpabuf *query);
+int interworking_fetch_anqp(struct wpa_supplicant *wpa_s);
+void interworking_stop_fetch_anqp(struct wpa_supplicant *wpa_s);
+int interworking_select(struct wpa_supplicant *wpa_s, int auto_select);
+int interworking_connect(struct wpa_supplicant *wpa_s, struct wpa_bss *bss);
+void interworking_start_fetch_anqp(struct wpa_supplicant *wpa_s);
+int interworking_home_sp_cred(struct wpa_supplicant *wpa_s,
+			      struct wpa_cred *cred,
+			      struct wpabuf *domain_names);
+
+#endif /* INTERWORKING_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/main.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,309 @@
+/*
+ * WPA Supplicant / main() function for UNIX like OSes and MinGW
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#ifdef __linux__
+#include <fcntl.h>
+#endif /* __linux__ */
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+
+extern struct wpa_driver_ops *wpa_drivers[];
+
+
+static void usage(void)
+{
+	int i;
+	printf("%s\n\n%s\n"
+	       "usage:\n"
+	       "  wpa_supplicant [-BddhKLqqstuvW] [-P<pid file>] "
+	       "[-g<global ctrl>] \\\n"
+	       "        -i<ifname> -c<config file> [-C<ctrl>] [-D<driver>] "
+	       "[-p<driver_param>] \\\n"
+	       "        [-b<br_ifname>] [-f<debug file>] [-e<entropy file>] "
+	       "\\\n"
+	       "        [-o<override driver>] [-O<override ctrl>] \\\n"
+	       "        [-N -i<ifname> -c<conf> [-C<ctrl>] "
+	       "[-D<driver>] \\\n"
+	       "        [-p<driver_param>] [-b<br_ifname>] ...]\n"
+	       "\n"
+	       "drivers:\n",
+	       wpa_supplicant_version, wpa_supplicant_license);
+
+	for (i = 0; wpa_drivers[i]; i++) {
+		printf("  %s = %s\n",
+		       wpa_drivers[i]->name,
+		       wpa_drivers[i]->desc);
+	}
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	printf("options:\n"
+	       "  -b = optional bridge interface name\n"
+	       "  -B = run daemon in the background\n"
+	       "  -c = Configuration file\n"
+	       "  -C = ctrl_interface parameter (only used if -c is not)\n"
+	       "  -i = interface name\n"
+	       "  -d = increase debugging verbosity (-dd even more)\n"
+	       "  -D = driver name (can be multiple drivers: nl80211,wext)\n"
+	       "  -e = entropy file\n");
+#ifdef CONFIG_DEBUG_FILE
+	printf("  -f = log output to debug file instead of stdout\n");
+#endif /* CONFIG_DEBUG_FILE */
+	printf("  -g = global ctrl_interface\n"
+	       "  -K = include keys (passwords, etc.) in debug output\n");
+#ifdef CONFIG_DEBUG_SYSLOG
+	printf("  -s = log output to syslog instead of stdout\n");
+#endif /* CONFIG_DEBUG_SYSLOG */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+	printf("  -T = record to Linux tracing in addition to logging\n");
+	printf("       (records all messages regardless of debug verbosity)\n");
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+	printf("  -t = include timestamp in debug messages\n"
+	       "  -h = show this help text\n"
+	       "  -L = show license (BSD)\n"
+	       "  -o = override driver parameter for new interfaces\n"
+	       "  -O = override ctrl_interface parameter for new interfaces\n"
+	       "  -p = driver parameters\n"
+	       "  -P = PID file\n"
+	       "  -q = decrease debugging verbosity (-qq even less)\n");
+#ifdef CONFIG_DBUS
+	printf("  -u = enable DBus control interface\n");
+#endif /* CONFIG_DBUS */
+	printf("  -v = show version\n"
+	       "  -W = wait for a control interface monitor before starting\n"
+	       "  -N = start describing new interface\n");
+
+	printf("example:\n"
+	       "  wpa_supplicant -D%s -iwlan0 -c/etc/wpa_supplicant.conf\n",
+	       wpa_drivers[i] ? wpa_drivers[i]->name : "wext");
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+static void license(void)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	printf("%s\n\n%s%s%s%s%s\n",
+	       wpa_supplicant_version,
+	       wpa_supplicant_full_license1,
+	       wpa_supplicant_full_license2,
+	       wpa_supplicant_full_license3,
+	       wpa_supplicant_full_license4,
+	       wpa_supplicant_full_license5);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+static void wpa_supplicant_fd_workaround(int start)
+{
+#ifdef __linux__
+	static int fd[3] = { -1, -1, -1 };
+	int i;
+	/* When started from pcmcia-cs scripts, wpa_supplicant might start with
+	 * fd 0, 1, and 2 closed. This will cause some issues because many
+	 * places in wpa_supplicant are still printing out to stdout. As a
+	 * workaround, make sure that fd's 0, 1, and 2 are not used for other
+	 * sockets. */
+	if (start) {
+		for (i = 0; i < 3; i++) {
+			fd[i] = open("/dev/null", O_RDWR);
+			if (fd[i] > 2) {
+				close(fd[i]);
+				fd[i] = -1;
+				break;
+			}
+		}
+	} else {
+		for (i = 0; i < 3; i++) {
+			if (fd[i] >= 0) {
+				close(fd[i]);
+				fd[i] = -1;
+			}
+		}
+	}
+#endif /* __linux__ */
+}
+
+
+int main(int argc, char *argv[])
+{
+	int c, i;
+	struct wpa_interface *ifaces, *iface;
+	int iface_count, exitcode = -1;
+	struct wpa_params params;
+	struct wpa_global *global;
+
+	if (os_program_init())
+		return -1;
+
+	os_memset(&params, 0, sizeof(params));
+	params.wpa_debug_level = MSG_INFO;
+
+	iface = ifaces = os_zalloc(sizeof(struct wpa_interface));
+	if (ifaces == NULL)
+		return -1;
+	iface_count = 1;
+
+	wpa_supplicant_fd_workaround(1);
+
+	for (;;) {
+		c = getopt(argc, argv,
+			   "b:Bc:C:D:de:f:g:hi:KLNo:O:p:P:qsTtuvW");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'b':
+			iface->bridge_ifname = optarg;
+			break;
+		case 'B':
+			params.daemonize++;
+			break;
+		case 'c':
+			iface->confname = optarg;
+			break;
+		case 'C':
+			iface->ctrl_interface = optarg;
+			break;
+		case 'D':
+			iface->driver = optarg;
+			break;
+		case 'd':
+#ifdef CONFIG_NO_STDOUT_DEBUG
+			printf("Debugging disabled with "
+			       "CONFIG_NO_STDOUT_DEBUG=y build time "
+			       "option.\n");
+			goto out;
+#else /* CONFIG_NO_STDOUT_DEBUG */
+			params.wpa_debug_level--;
+			break;
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+		case 'e':
+			params.entropy_file = optarg;
+			break;
+#ifdef CONFIG_DEBUG_FILE
+		case 'f':
+			params.wpa_debug_file_path = optarg;
+			break;
+#endif /* CONFIG_DEBUG_FILE */
+		case 'g':
+			params.ctrl_interface = optarg;
+			break;
+		case 'h':
+			usage();
+			exitcode = 0;
+			goto out;
+		case 'i':
+			iface->ifname = optarg;
+			break;
+		case 'K':
+			params.wpa_debug_show_keys++;
+			break;
+		case 'L':
+			license();
+			exitcode = 0;
+			goto out;
+		case 'o':
+			params.override_driver = optarg;
+			break;
+		case 'O':
+			params.override_ctrl_interface = optarg;
+			break;
+		case 'p':
+			iface->driver_param = optarg;
+			break;
+		case 'P':
+			os_free(params.pid_file);
+			params.pid_file = os_rel2abs_path(optarg);
+			break;
+		case 'q':
+			params.wpa_debug_level++;
+			break;
+#ifdef CONFIG_DEBUG_SYSLOG
+		case 's':
+			params.wpa_debug_syslog++;
+			break;
+#endif /* CONFIG_DEBUG_SYSLOG */
+#ifdef CONFIG_DEBUG_LINUX_TRACING
+		case 'T':
+			params.wpa_debug_tracing++;
+			break;
+#endif /* CONFIG_DEBUG_LINUX_TRACING */
+		case 't':
+			params.wpa_debug_timestamp++;
+			break;
+#ifdef CONFIG_DBUS
+		case 'u':
+			params.dbus_ctrl_interface = 1;
+			break;
+#endif /* CONFIG_DBUS */
+		case 'v':
+			printf("%s\n", wpa_supplicant_version);
+			exitcode = 0;
+			goto out;
+		case 'W':
+			params.wait_for_monitor++;
+			break;
+		case 'N':
+			iface_count++;
+			iface = os_realloc_array(ifaces, iface_count,
+						 sizeof(struct wpa_interface));
+			if (iface == NULL)
+				goto out;
+			ifaces = iface;
+			iface = &ifaces[iface_count - 1]; 
+			os_memset(iface, 0, sizeof(*iface));
+			break;
+		default:
+			usage();
+			exitcode = 0;
+			goto out;
+		}
+	}
+
+	exitcode = 0;
+	global = wpa_supplicant_init(&params);
+	if (global == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to initialize wpa_supplicant");
+		exitcode = -1;
+		goto out;
+	} else {
+		wpa_printf(MSG_INFO, "Successfully initialized "
+			   "wpa_supplicant");
+	}
+
+	for (i = 0; exitcode == 0 && i < iface_count; i++) {
+		if ((ifaces[i].confname == NULL &&
+		     ifaces[i].ctrl_interface == NULL) ||
+		    ifaces[i].ifname == NULL) {
+			if (iface_count == 1 && (params.ctrl_interface ||
+						 params.dbus_ctrl_interface))
+				break;
+			usage();
+			exitcode = -1;
+			break;
+		}
+		if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
+			exitcode = -1;
+	}
+
+	if (exitcode == 0)
+		exitcode = wpa_supplicant_run(global);
+
+	wpa_supplicant_deinit(global);
+
+out:
+	wpa_supplicant_fd_workaround(0);
+	os_free(ifaces);
+	os_free(params.pid_file);
+
+	os_program_deinit();
+
+	return exitcode;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/notify.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,630 @@
+/*
+ * wpa_supplicant - Event notifications
+ * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/wpa_ctrl.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "wps_supplicant.h"
+#include "dbus/dbus_common.h"
+#include "dbus/dbus_old.h"
+#include "dbus/dbus_new.h"
+#include "rsn_supp/wpa.h"
+#include "driver_i.h"
+#include "scan.h"
+#include "p2p_supplicant.h"
+#include "sme.h"
+#include "notify.h"
+
+int wpas_notify_supplicant_initialized(struct wpa_global *global)
+{
+#ifdef CONFIG_DBUS
+	if (global->params.dbus_ctrl_interface) {
+		global->dbus = wpas_dbus_init(global);
+		if (global->dbus == NULL)
+			return -1;
+	}
+#endif /* CONFIG_DBUS */
+
+	return 0;
+}
+
+
+void wpas_notify_supplicant_deinitialized(struct wpa_global *global)
+{
+#ifdef CONFIG_DBUS
+	if (global->dbus)
+		wpas_dbus_deinit(global->dbus);
+#endif /* CONFIG_DBUS */
+}
+
+
+int wpas_notify_iface_added(struct wpa_supplicant *wpa_s)
+{
+	if (wpas_dbus_register_iface(wpa_s))
+		return -1;
+
+	if (wpas_dbus_register_interface(wpa_s))
+		return -1;
+
+	return 0;
+}
+
+
+void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s)
+{
+	/* unregister interface in old DBus ctrl iface */
+	wpas_dbus_unregister_iface(wpa_s);
+
+	/* unregister interface in new DBus ctrl iface */
+	wpas_dbus_unregister_interface(wpa_s);
+}
+
+
+void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
+			       enum wpa_states new_state,
+			       enum wpa_states old_state)
+{
+	/* notify the old DBus API */
+	wpa_supplicant_dbus_notify_state_change(wpa_s, new_state,
+						old_state);
+
+	/* notify the new DBus API */
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_STATE);
+
+#ifdef CONFIG_P2P
+	if (new_state == WPA_COMPLETED)
+		wpas_p2p_notif_connected(wpa_s);
+	else if (old_state >= WPA_ASSOCIATED && new_state < WPA_ASSOCIATED)
+		wpas_p2p_notif_disconnected(wpa_s);
+#endif /* CONFIG_P2P */
+
+	sme_state_changed(wpa_s);
+
+#ifdef ANDROID
+	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_STATE_CHANGE
+		     "id=%d state=%d BSSID=" MACSTR,
+		     wpa_s->current_ssid ? wpa_s->current_ssid->id : -1,
+		     new_state, MAC2STR(wpa_s->pending_bssid));
+#endif /* ANDROID */
+}
+
+
+void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s)
+{
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_DISCONNECT_REASON);
+}
+
+
+void wpas_notify_network_changed(struct wpa_supplicant *wpa_s)
+{
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_NETWORK);
+}
+
+
+void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s)
+{
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_AP_SCAN);
+}
+
+
+void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s)
+{
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_BSS);
+}
+
+
+void wpas_notify_auth_changed(struct wpa_supplicant *wpa_s)
+{
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_CURRENT_AUTH_MODE);
+}
+
+
+void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s,
+					 struct wpa_ssid *ssid)
+{
+	wpas_dbus_signal_network_enabled_changed(wpa_s, ssid);
+}
+
+
+void wpas_notify_network_selected(struct wpa_supplicant *wpa_s,
+				  struct wpa_ssid *ssid)
+{
+	wpas_dbus_signal_network_selected(wpa_s, ssid->id);
+}
+
+
+void wpas_notify_network_request(struct wpa_supplicant *wpa_s,
+				 struct wpa_ssid *ssid,
+				 enum wpa_ctrl_req_type rtype,
+				 const char *default_txt)
+{
+	wpas_dbus_signal_network_request(wpa_s, ssid, rtype, default_txt);
+}
+
+
+void wpas_notify_scanning(struct wpa_supplicant *wpa_s)
+{
+	/* notify the old DBus API */
+	wpa_supplicant_dbus_notify_scanning(wpa_s);
+
+	/* notify the new DBus API */
+	wpas_dbus_signal_prop_changed(wpa_s, WPAS_DBUS_PROP_SCANNING);
+}
+
+
+void wpas_notify_scan_done(struct wpa_supplicant *wpa_s, int success)
+{
+	wpas_dbus_signal_scan_done(wpa_s, success);
+}
+
+
+void wpas_notify_scan_results(struct wpa_supplicant *wpa_s)
+{
+	/* notify the old DBus API */
+	wpa_supplicant_dbus_notify_scan_results(wpa_s);
+
+	wpas_wps_notify_scan_results(wpa_s);
+}
+
+
+void wpas_notify_wps_credential(struct wpa_supplicant *wpa_s,
+				const struct wps_credential *cred)
+{
+#ifdef CONFIG_WPS
+	/* notify the old DBus API */
+	wpa_supplicant_dbus_notify_wps_cred(wpa_s, cred);
+	/* notify the new DBus API */
+	wpas_dbus_signal_wps_cred(wpa_s, cred);
+#endif /* CONFIG_WPS */
+}
+
+
+void wpas_notify_wps_event_m2d(struct wpa_supplicant *wpa_s,
+			       struct wps_event_m2d *m2d)
+{
+#ifdef CONFIG_WPS
+	wpas_dbus_signal_wps_event_m2d(wpa_s, m2d);
+#endif /* CONFIG_WPS */
+}
+
+
+void wpas_notify_wps_event_fail(struct wpa_supplicant *wpa_s,
+				struct wps_event_fail *fail)
+{
+#ifdef CONFIG_WPS
+	wpas_dbus_signal_wps_event_fail(wpa_s, fail);
+#endif /* CONFIG_WPS */
+}
+
+
+void wpas_notify_wps_event_success(struct wpa_supplicant *wpa_s)
+{
+#ifdef CONFIG_WPS
+	wpas_dbus_signal_wps_event_success(wpa_s);
+#endif /* CONFIG_WPS */
+}
+
+
+void wpas_notify_network_added(struct wpa_supplicant *wpa_s,
+			       struct wpa_ssid *ssid)
+{
+	/*
+	 * Networks objects created during any P2P activities should not be
+	 * exposed out. They might/will confuse certain non-P2P aware
+	 * applications since these network objects won't behave like
+	 * regular ones.
+	 */
+	if (wpa_s->global->p2p_group_formation != wpa_s)
+		wpas_dbus_register_network(wpa_s, ssid);
+}
+
+
+void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_P2P
+	wpas_dbus_register_persistent_group(wpa_s, ssid);
+#endif /* CONFIG_P2P */
+}
+
+
+void wpas_notify_persistent_group_removed(struct wpa_supplicant *wpa_s,
+					  struct wpa_ssid *ssid)
+{
+#ifdef CONFIG_P2P
+	wpas_dbus_unregister_persistent_group(wpa_s, ssid->id);
+#endif /* CONFIG_P2P */
+}
+
+
+void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
+				 struct wpa_ssid *ssid)
+{
+	if (wpa_s->wpa)
+		wpa_sm_pmksa_cache_flush(wpa_s->wpa, ssid);
+	if (wpa_s->global->p2p_group_formation != wpa_s)
+		wpas_dbus_unregister_network(wpa_s, ssid->id);
+#ifdef CONFIG_P2P
+	wpas_p2p_network_removed(wpa_s, ssid);
+#endif /* CONFIG_P2P */
+}
+
+
+void wpas_notify_bss_added(struct wpa_supplicant *wpa_s,
+			   u8 bssid[], unsigned int id)
+{
+	wpas_dbus_register_bss(wpa_s, bssid, id);
+	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_BSS_ADDED "%u " MACSTR,
+		     id, MAC2STR(bssid));
+}
+
+
+void wpas_notify_bss_removed(struct wpa_supplicant *wpa_s,
+			     u8 bssid[], unsigned int id)
+{
+	wpas_dbus_unregister_bss(wpa_s, bssid, id);
+	wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_BSS_REMOVED "%u " MACSTR,
+		     id, MAC2STR(bssid));
+}
+
+
+void wpas_notify_bss_freq_changed(struct wpa_supplicant *wpa_s,
+				  unsigned int id)
+{
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_FREQ, id);
+}
+
+
+void wpas_notify_bss_signal_changed(struct wpa_supplicant *wpa_s,
+				    unsigned int id)
+{
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_SIGNAL,
+					  id);
+}
+
+
+void wpas_notify_bss_privacy_changed(struct wpa_supplicant *wpa_s,
+				     unsigned int id)
+{
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_PRIVACY,
+					  id);
+}
+
+
+void wpas_notify_bss_mode_changed(struct wpa_supplicant *wpa_s,
+				  unsigned int id)
+{
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_MODE, id);
+}
+
+
+void wpas_notify_bss_wpaie_changed(struct wpa_supplicant *wpa_s,
+				   unsigned int id)
+{
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPA, id);
+}
+
+
+void wpas_notify_bss_rsnie_changed(struct wpa_supplicant *wpa_s,
+				   unsigned int id)
+{
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_RSN, id);
+}
+
+
+void wpas_notify_bss_wps_changed(struct wpa_supplicant *wpa_s,
+				 unsigned int id)
+{
+#ifdef CONFIG_WPS
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_WPS, id);
+#endif /* CONFIG_WPS */
+}
+
+
+void wpas_notify_bss_ies_changed(struct wpa_supplicant *wpa_s,
+				   unsigned int id)
+{
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_IES, id);
+}
+
+
+void wpas_notify_bss_rates_changed(struct wpa_supplicant *wpa_s,
+				   unsigned int id)
+{
+	wpas_dbus_bss_signal_prop_changed(wpa_s, WPAS_DBUS_BSS_PROP_RATES, id);
+}
+
+
+void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name)
+{
+	wpas_dbus_signal_blob_added(wpa_s, name);
+}
+
+
+void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name)
+{
+	wpas_dbus_signal_blob_removed(wpa_s, name);
+}
+
+
+void wpas_notify_debug_level_changed(struct wpa_global *global)
+{
+	wpas_dbus_signal_debug_level_changed(global);
+}
+
+
+void wpas_notify_debug_timestamp_changed(struct wpa_global *global)
+{
+	wpas_dbus_signal_debug_timestamp_changed(global);
+}
+
+
+void wpas_notify_debug_show_keys_changed(struct wpa_global *global)
+{
+	wpas_dbus_signal_debug_show_keys_changed(global);
+}
+
+
+void wpas_notify_suspend(struct wpa_global *global)
+{
+	struct wpa_supplicant *wpa_s;
+
+	os_get_time(&global->suspend_time);
+	wpa_printf(MSG_DEBUG, "System suspend notification");
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
+		wpa_drv_suspend(wpa_s);
+}
+
+
+void wpas_notify_resume(struct wpa_global *global)
+{
+	struct os_time now;
+	int slept;
+	struct wpa_supplicant *wpa_s;
+
+	if (global->suspend_time.sec == 0)
+		slept = -1;
+	else {
+		os_get_time(&now);
+		slept = now.sec - global->suspend_time.sec;
+	}
+	wpa_printf(MSG_DEBUG, "System resume notification (slept %d seconds)",
+		   slept);
+
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		wpa_drv_resume(wpa_s);
+		if (wpa_s->wpa_state == WPA_DISCONNECTED)
+			wpa_supplicant_req_scan(wpa_s, 0, 100000);
+	}
+}
+
+
+#ifdef CONFIG_P2P
+
+void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s,
+				  const u8 *dev_addr, int new_device)
+{
+	if (new_device) {
+		/* Create the new peer object */
+		wpas_dbus_register_peer(wpa_s, dev_addr);
+	}
+
+	/* Notify a new peer has been detected*/
+	wpas_dbus_signal_peer_device_found(wpa_s, dev_addr);
+}
+
+
+void wpas_notify_p2p_device_lost(struct wpa_supplicant *wpa_s,
+				 const u8 *dev_addr)
+{
+	wpas_dbus_unregister_peer(wpa_s, dev_addr);
+
+	/* Create signal on interface object*/
+	wpas_dbus_signal_peer_device_lost(wpa_s, dev_addr);
+}
+
+
+void wpas_notify_p2p_group_removed(struct wpa_supplicant *wpa_s,
+				   const struct wpa_ssid *ssid,
+				   const char *role)
+{
+	wpas_dbus_unregister_p2p_group(wpa_s, ssid);
+
+	wpas_dbus_signal_p2p_group_removed(wpa_s, role);
+}
+
+
+void wpas_notify_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+				const u8 *src, u16 dev_passwd_id)
+{
+	wpas_dbus_signal_p2p_go_neg_req(wpa_s, src, dev_passwd_id);
+}
+
+
+void wpas_notify_p2p_go_neg_completed(struct wpa_supplicant *wpa_s,
+				      struct p2p_go_neg_results *res)
+{
+	wpas_dbus_signal_p2p_go_neg_resp(wpa_s, res);
+}
+
+
+void wpas_notify_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+				       int status, const u8 *bssid)
+{
+	wpas_dbus_signal_p2p_invitation_result(wpa_s, status, bssid);
+}
+
+
+void wpas_notify_p2p_sd_request(struct wpa_supplicant *wpa_s,
+				int freq, const u8 *sa, u8 dialog_token,
+				u16 update_indic, const u8 *tlvs,
+				size_t tlvs_len)
+{
+	wpas_dbus_signal_p2p_sd_request(wpa_s, freq, sa, dialog_token,
+					update_indic, tlvs, tlvs_len);
+}
+
+
+void wpas_notify_p2p_sd_response(struct wpa_supplicant *wpa_s,
+				 const u8 *sa, u16 update_indic,
+				 const u8 *tlvs, size_t tlvs_len)
+{
+	wpas_dbus_signal_p2p_sd_response(wpa_s, sa, update_indic,
+					 tlvs, tlvs_len);
+}
+
+
+/**
+ * wpas_notify_p2p_provision_discovery - Notification of provision discovery
+ * @dev_addr: Who sent the request or responded to our request.
+ * @request: Will be 1 if request, 0 for response.
+ * @status: Valid only in case of response (0 in case of success)
+ * @config_methods: WPS config methods
+ * @generated_pin: PIN to be displayed in case of WPS_CONFIG_DISPLAY method
+ *
+ * This can be used to notify:
+ * - Requests or responses
+ * - Various config methods
+ * - Failure condition in case of response
+ */
+void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+					 const u8 *dev_addr, int request,
+					 enum p2p_prov_disc_status status,
+					 u16 config_methods,
+					 unsigned int generated_pin)
+{
+	wpas_dbus_signal_p2p_provision_discovery(wpa_s, dev_addr, request,
+						 status, config_methods,
+						 generated_pin);
+}
+
+
+void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid, int network_id,
+				   int client)
+{
+	/* Notify a group has been started */
+	wpas_dbus_register_p2p_group(wpa_s, ssid);
+
+	wpas_dbus_signal_p2p_group_started(wpa_s, ssid, client, network_id);
+}
+
+
+void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+				struct wps_event_fail *fail)
+{
+	wpas_dbus_signal_p2p_wps_failed(wpa_s, fail);
+}
+
+#endif /* CONFIG_P2P */
+
+
+static void wpas_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
+					  const u8 *sta,
+					  const u8 *p2p_dev_addr)
+{
+#ifdef CONFIG_P2P
+	wpas_p2p_notify_ap_sta_authorized(wpa_s, p2p_dev_addr);
+
+	/*
+	 * Register a group member object corresponding to this peer and
+	 * emit a PeerJoined signal. This will check if it really is a
+	 * P2P group.
+	 */
+	wpas_dbus_register_p2p_groupmember(wpa_s, sta);
+
+	/*
+	 * Create 'peer-joined' signal on group object -- will also
+	 * check P2P itself.
+	 */
+	wpas_dbus_signal_p2p_peer_joined(wpa_s, sta);
+#endif /* CONFIG_P2P */
+}
+
+
+static void wpas_notify_ap_sta_deauthorized(struct wpa_supplicant *wpa_s,
+					    const u8 *sta)
+{
+#ifdef CONFIG_P2P
+	/*
+	 * Unregister a group member object corresponding to this peer
+	 * if this is a P2P group.
+	 */
+	wpas_dbus_unregister_p2p_groupmember(wpa_s, sta);
+
+	/*
+	 * Create 'peer-disconnected' signal on group object if this
+	 * is a P2P group.
+	 */
+	wpas_dbus_signal_p2p_peer_disconnected(wpa_s, sta);
+#endif /* CONFIG_P2P */
+}
+
+
+void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s,
+				const u8 *mac_addr, int authorized,
+				const u8 *p2p_dev_addr)
+{
+	if (authorized)
+		wpas_notify_ap_sta_authorized(wpa_s, mac_addr, p2p_dev_addr);
+	else
+		wpas_notify_ap_sta_deauthorized(wpa_s, mac_addr);
+}
+
+
+void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
+			       const char *subject, const char *cert_hash,
+			       const struct wpabuf *cert)
+{
+	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_EAP_PEER_CERT
+		"depth=%d subject='%s'%s%s",
+		depth, subject,
+		cert_hash ? " hash=" : "",
+		cert_hash ? cert_hash : "");
+
+	if (cert) {
+		char *cert_hex;
+		size_t len = wpabuf_len(cert) * 2 + 1;
+		cert_hex = os_malloc(len);
+		if (cert_hex) {
+			wpa_snprintf_hex(cert_hex, len, wpabuf_head(cert),
+					 wpabuf_len(cert));
+			wpa_msg_ctrl(wpa_s, MSG_INFO,
+				     WPA_EVENT_EAP_PEER_CERT
+				     "depth=%d subject='%s' cert=%s",
+				     depth, subject, cert_hex);
+			os_free(cert_hex);
+		}
+	}
+
+	/* notify the old DBus API */
+	wpa_supplicant_dbus_notify_certification(wpa_s, depth, subject,
+						 cert_hash, cert);
+	/* notify the new DBus API */
+	wpas_dbus_signal_certification(wpa_s, depth, subject, cert_hash, cert);
+}
+
+
+void wpas_notify_preq(struct wpa_supplicant *wpa_s,
+		      const u8 *addr, const u8 *dst, const u8 *bssid,
+		      const u8 *ie, size_t ie_len, u32 ssi_signal)
+{
+#ifdef CONFIG_AP
+	wpas_dbus_signal_preq(wpa_s, addr, dst, bssid, ie, ie_len, ssi_signal);
+#endif /* CONFIG_AP */
+}
+
+
+void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
+			    const char *parameter)
+{
+	wpas_dbus_signal_eap_status(wpa_s, status, parameter);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/notify.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,131 @@
+/*
+ * wpa_supplicant - Event notifications
+ * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef NOTIFY_H
+#define NOTIFY_H
+
+#include "p2p/p2p.h"
+
+struct wps_credential;
+struct wps_event_m2d;
+struct wps_event_fail;
+
+int wpas_notify_supplicant_initialized(struct wpa_global *global);
+void wpas_notify_supplicant_deinitialized(struct wpa_global *global);
+int wpas_notify_iface_added(struct wpa_supplicant *wpa_s);
+void wpas_notify_iface_removed(struct wpa_supplicant *wpa_s);
+void wpas_notify_state_changed(struct wpa_supplicant *wpa_s,
+			       enum wpa_states new_state,
+			       enum wpa_states old_state);
+void wpas_notify_disconnect_reason(struct wpa_supplicant *wpa_s);
+void wpas_notify_network_changed(struct wpa_supplicant *wpa_s);
+void wpas_notify_ap_scan_changed(struct wpa_supplicant *wpa_s);
+void wpas_notify_bssid_changed(struct wpa_supplicant *wpa_s);
+void wpas_notify_auth_changed(struct wpa_supplicant *wpa_s);
+void wpas_notify_network_enabled_changed(struct wpa_supplicant *wpa_s,
+					 struct wpa_ssid *ssid);
+void wpas_notify_network_selected(struct wpa_supplicant *wpa_s,
+				  struct wpa_ssid *ssid);
+void wpas_notify_network_request(struct wpa_supplicant *wpa_s,
+				 struct wpa_ssid *ssid,
+				 enum wpa_ctrl_req_type rtype,
+				 const char *default_txt);
+void wpas_notify_scanning(struct wpa_supplicant *wpa_s);
+void wpas_notify_scan_done(struct wpa_supplicant *wpa_s, int success);
+void wpas_notify_scan_results(struct wpa_supplicant *wpa_s);
+void wpas_notify_wps_credential(struct wpa_supplicant *wpa_s,
+				const struct wps_credential *cred);
+void wpas_notify_wps_event_m2d(struct wpa_supplicant *wpa_s,
+			       struct wps_event_m2d *m2d);
+void wpas_notify_wps_event_fail(struct wpa_supplicant *wpa_s,
+				struct wps_event_fail *fail);
+void wpas_notify_wps_event_success(struct wpa_supplicant *wpa_s);
+void wpas_notify_network_added(struct wpa_supplicant *wpa_s,
+			       struct wpa_ssid *ssid);
+void wpas_notify_network_removed(struct wpa_supplicant *wpa_s,
+				 struct wpa_ssid *ssid);
+void wpas_notify_bss_added(struct wpa_supplicant *wpa_s, u8 bssid[],
+			   unsigned int id);
+void wpas_notify_bss_removed(struct wpa_supplicant *wpa_s, u8 bssid[],
+			     unsigned int id);
+void wpas_notify_bss_freq_changed(struct wpa_supplicant *wpa_s,
+				  unsigned int id);
+void wpas_notify_bss_signal_changed(struct wpa_supplicant *wpa_s,
+				    unsigned int id);
+void wpas_notify_bss_privacy_changed(struct wpa_supplicant *wpa_s,
+				     unsigned int id);
+void wpas_notify_bss_mode_changed(struct wpa_supplicant *wpa_s,
+				  unsigned int id);
+void wpas_notify_bss_wpaie_changed(struct wpa_supplicant *wpa_s,
+				   unsigned int id);
+void wpas_notify_bss_rsnie_changed(struct wpa_supplicant *wpa_s,
+				   unsigned int id);
+void wpas_notify_bss_wps_changed(struct wpa_supplicant *wpa_s,
+				 unsigned int id);
+void wpas_notify_bss_ies_changed(struct wpa_supplicant *wpa_s,
+				 unsigned int id);
+void wpas_notify_bss_rates_changed(struct wpa_supplicant *wpa_s,
+				   unsigned int id);
+void wpas_notify_blob_added(struct wpa_supplicant *wpa_s, const char *name);
+void wpas_notify_blob_removed(struct wpa_supplicant *wpa_s, const char *name);
+
+void wpas_notify_debug_level_changed(struct wpa_global *global);
+void wpas_notify_debug_timestamp_changed(struct wpa_global *global);
+void wpas_notify_debug_show_keys_changed(struct wpa_global *global);
+void wpas_notify_suspend(struct wpa_global *global);
+void wpas_notify_resume(struct wpa_global *global);
+
+void wpas_notify_sta_authorized(struct wpa_supplicant *wpa_s,
+				const u8 *mac_addr, int authorized,
+				const u8 *p2p_dev_addr);
+void wpas_notify_p2p_device_found(struct wpa_supplicant *wpa_s,
+				  const u8 *dev_addr, int new_device);
+void wpas_notify_p2p_device_lost(struct wpa_supplicant *wpa_s,
+				 const u8 *dev_addr);
+void wpas_notify_p2p_group_removed(struct wpa_supplicant *wpa_s,
+				   const struct wpa_ssid *ssid,
+				   const char *role);
+void wpas_notify_p2p_go_neg_req(struct wpa_supplicant *wpa_s,
+				const u8 *src, u16 dev_passwd_id);
+void wpas_notify_p2p_go_neg_completed(struct wpa_supplicant *wpa_s,
+				      struct p2p_go_neg_results *res);
+void wpas_notify_p2p_invitation_result(struct wpa_supplicant *wpa_s,
+				       int status, const u8 *bssid);
+void wpas_notify_p2p_sd_request(struct wpa_supplicant *wpa_s,
+				int freq, const u8 *sa, u8 dialog_token,
+				u16 update_indic, const u8 *tlvs,
+				size_t tlvs_len);
+void wpas_notify_p2p_sd_response(struct wpa_supplicant *wpa_s,
+				 const u8 *sa, u16 update_indic,
+				 const u8 *tlvs, size_t tlvs_len);
+void wpas_notify_p2p_provision_discovery(struct wpa_supplicant *wpa_s,
+					 const u8 *dev_addr, int request,
+					 enum p2p_prov_disc_status status,
+					 u16 config_methods,
+					 unsigned int generated_pin);
+void wpas_notify_p2p_group_started(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid, int network_id,
+				   int client);
+void wpas_notify_persistent_group_added(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid);
+void wpas_notify_persistent_group_removed(struct wpa_supplicant *wpa_s,
+					  struct wpa_ssid *ssid);
+
+void wpas_notify_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+				struct wps_event_fail *fail);
+
+void wpas_notify_certification(struct wpa_supplicant *wpa_s, int depth,
+			       const char *subject, const char *cert_hash,
+			       const struct wpabuf *cert);
+void wpas_notify_preq(struct wpa_supplicant *wpa_s,
+		      const u8 *addr, const u8 *dst, const u8 *bssid,
+		      const u8 *ie, size_t ie_len, u32 ssi_signal);
+void wpas_notify_eap_status(struct wpa_supplicant *wpa_s, const char *status,
+			    const char *parameter);
+
+#endif /* NOTIFY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/offchannel.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,35 @@
+/*
+ * wpa_supplicant - Off-channel Action frame TX/RX
+ * Copyright (c) 2009-2010, Atheros Communications
+ * Copyright (c) 2011, Qualcomm Atheros
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef OFFCHANNEL_H
+#define OFFCHANNEL_H
+
+int offchannel_send_action(struct wpa_supplicant *wpa_s, unsigned int freq,
+			   const u8 *dst, const u8 *src, const u8 *bssid,
+			   const u8 *buf, size_t len, unsigned int wait_time,
+			   void (*tx_cb)(struct wpa_supplicant *wpa_s,
+					 unsigned int freq, const u8 *dst,
+					 const u8 *src, const u8 *bssid,
+					 const u8 *data, size_t data_len,
+					 enum offchannel_send_action_result
+					 result),
+			   int no_cck);
+void offchannel_send_action_done(struct wpa_supplicant *wpa_s);
+void offchannel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+				     unsigned int freq, unsigned int duration);
+void offchannel_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+					    unsigned int freq);
+void offchannel_deinit(struct wpa_supplicant *wpa_s);
+void offchannel_send_action_tx_status(
+	struct wpa_supplicant *wpa_s, const u8 *dst, const u8 *data,
+	size_t data_len, enum offchannel_send_action_result result);
+const void * offchannel_pending_action_tx(struct wpa_supplicant *wpa_s);
+void offchannel_clear_pending_action_tx(struct wpa_supplicant *wpa_s);
+
+#endif /* OFFCHANNEL_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/p2p_supplicant.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,151 @@
+/*
+ * wpa_supplicant - P2P
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef P2P_SUPPLICANT_H
+#define P2P_SUPPLICANT_H
+
+enum p2p_wps_method;
+struct p2p_go_neg_results;
+enum p2p_send_action_result;
+struct p2p_peer_info;
+
+int wpas_p2p_init(struct wpa_global *global, struct wpa_supplicant *wpa_s);
+void wpas_p2p_deinit(struct wpa_supplicant *wpa_s);
+void wpas_p2p_deinit_global(struct wpa_global *global);
+int wpas_p2p_connect(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+		     const char *pin, enum p2p_wps_method wps_method,
+		     int persistent_group, int auto_join, int join,
+		     int auth, int go_intent, int freq, int persistent_id,
+		     int pd, int ht40);
+void wpas_p2p_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+				   unsigned int freq, unsigned int duration);
+void wpas_p2p_cancel_remain_on_channel_cb(struct wpa_supplicant *wpa_s,
+					  unsigned int freq);
+int wpas_p2p_group_remove(struct wpa_supplicant *wpa_s, const char *ifname);
+int wpas_p2p_group_add(struct wpa_supplicant *wpa_s, int persistent_group,
+		       int freq, int ht40);
+int wpas_p2p_group_add_persistent(struct wpa_supplicant *wpa_s,
+				  struct wpa_ssid *ssid, int addr_allocated,
+				  int freq, int ht40);
+struct p2p_group * wpas_p2p_group_init(struct wpa_supplicant *wpa_s,
+				       struct wpa_ssid *ssid);
+void wpas_p2p_wps_success(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+			  int registrar);
+enum wpas_p2p_prov_disc_use {
+	WPAS_P2P_PD_FOR_GO_NEG,
+	WPAS_P2P_PD_FOR_JOIN,
+	WPAS_P2P_PD_AUTO
+};
+int wpas_p2p_prov_disc(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+		       const char *config_method,
+		       enum wpas_p2p_prov_disc_use use);
+void wpas_send_action_tx_status(struct wpa_supplicant *wpa_s, const u8 *dst,
+				const u8 *data, size_t data_len,
+				enum p2p_send_action_result result);
+int wpas_p2p_scan_result_text(const u8 *ies, size_t ies_len, char *buf,
+			      char *end);
+enum p2p_discovery_type;
+int wpas_p2p_find(struct wpa_supplicant *wpa_s, unsigned int timeout,
+		  enum p2p_discovery_type type,
+		  unsigned int num_req_dev_types, const u8 *req_dev_types,
+		  const u8 *dev_id, unsigned int search_delay);
+void wpas_p2p_stop_find(struct wpa_supplicant *wpa_s);
+int wpas_p2p_listen(struct wpa_supplicant *wpa_s, unsigned int timeout);
+int wpas_p2p_assoc_req_ie(struct wpa_supplicant *wpa_s, struct wpa_bss *bss,
+			  u8 *buf, size_t len, int p2p_group);
+int wpas_p2p_probe_req_rx(struct wpa_supplicant *wpa_s, const u8 *addr,
+			  const u8 *dst, const u8 *bssid,
+			  const u8 *ie, size_t ie_len,
+			  int ssi_signal);
+void wpas_p2p_rx_action(struct wpa_supplicant *wpa_s, const u8 *da,
+			const u8 *sa, const u8 *bssid,
+			u8 category, const u8 *data, size_t len, int freq);
+void wpas_p2p_scan_ie(struct wpa_supplicant *wpa_s, struct wpabuf *ies);
+void wpas_p2p_group_deinit(struct wpa_supplicant *wpa_s);
+void wpas_dev_found(void *ctx, const u8 *addr,
+		    const struct p2p_peer_info *info,
+		    int new_device);
+void wpas_go_neg_completed(void *ctx, struct p2p_go_neg_results *res);
+void wpas_go_neg_req_rx(void *ctx, const u8 *src, u16 dev_passwd_id);
+void wpas_prov_disc_req(void *ctx, const u8 *peer, u16 config_methods,
+			const u8 *dev_addr, const u8 *pri_dev_type,
+			const char *dev_name, u16 supp_config_methods,
+			u8 dev_capab, u8 group_capab, const u8 *group_id,
+			size_t group_id_len);
+void wpas_prov_disc_resp(void *ctx, const u8 *peer, u16 config_methods);
+void wpas_sd_request(void *ctx, int freq, const u8 *sa, u8 dialog_token,
+		     u16 update_indic, const u8 *tlvs, size_t tlvs_len);
+void wpas_sd_response(void *ctx, const u8 *sa, u16 update_indic,
+		      const u8 *tlvs, size_t tlvs_len);
+u64 wpas_p2p_sd_request(struct wpa_supplicant *wpa_s, const u8 *dst,
+			const struct wpabuf *tlvs);
+u64 wpas_p2p_sd_request_upnp(struct wpa_supplicant *wpa_s, const u8 *dst,
+			     u8 version, const char *query);
+u64 wpas_p2p_sd_request_wifi_display(struct wpa_supplicant *wpa_s,
+				     const u8 *dst, const char *role);
+int wpas_p2p_sd_cancel_request(struct wpa_supplicant *wpa_s, u64 req);
+void wpas_p2p_sd_response(struct wpa_supplicant *wpa_s, int freq,
+			  const u8 *dst, u8 dialog_token,
+			  const struct wpabuf *resp_tlvs);
+void wpas_p2p_sd_service_update(struct wpa_supplicant *wpa_s);
+void wpas_p2p_service_flush(struct wpa_supplicant *wpa_s);
+int wpas_p2p_service_add_bonjour(struct wpa_supplicant *wpa_s,
+				 struct wpabuf *query, struct wpabuf *resp);
+int wpas_p2p_service_del_bonjour(struct wpa_supplicant *wpa_s,
+				 const struct wpabuf *query);
+int wpas_p2p_service_add_upnp(struct wpa_supplicant *wpa_s, u8 version,
+			      const char *service);
+int wpas_p2p_service_del_upnp(struct wpa_supplicant *wpa_s, u8 version,
+			      const char *service);
+int wpas_p2p_reject(struct wpa_supplicant *wpa_s, const u8 *addr);
+int wpas_p2p_invite(struct wpa_supplicant *wpa_s, const u8 *peer_addr,
+		    struct wpa_ssid *ssid, const u8 *go_dev_addr, int freq,
+		    int ht40);
+int wpas_p2p_invite_group(struct wpa_supplicant *wpa_s, const char *ifname,
+			  const u8 *peer_addr, const u8 *go_dev_addr);
+void wpas_p2p_completed(struct wpa_supplicant *wpa_s);
+int wpas_p2p_presence_req(struct wpa_supplicant *wpa_s, u32 duration1,
+			  u32 interval1, u32 duration2, u32 interval2);
+int wpas_p2p_ext_listen(struct wpa_supplicant *wpa_s, unsigned int period,
+			unsigned int interval);
+int wpas_p2p_deauth_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			  u16 reason_code, const u8 *ie, size_t ie_len,
+			  int locally_generated);
+void wpas_p2p_disassoc_notif(struct wpa_supplicant *wpa_s, const u8 *bssid,
+			     u16 reason_code, const u8 *ie, size_t ie_len,
+			     int locally_generated);
+void wpas_p2p_update_config(struct wpa_supplicant *wpa_s);
+int wpas_p2p_set_noa(struct wpa_supplicant *wpa_s, u8 count, int start,
+		     int duration);
+int wpas_p2p_set_cross_connect(struct wpa_supplicant *wpa_s, int enabled);
+void wpas_p2p_notif_connected(struct wpa_supplicant *wpa_s);
+void wpas_p2p_notif_disconnected(struct wpa_supplicant *wpa_s);
+int wpas_p2p_notif_pbc_overlap(struct wpa_supplicant *wpa_s);
+void wpas_p2p_update_channel_list(struct wpa_supplicant *wpa_s);
+int wpas_p2p_cancel(struct wpa_supplicant *wpa_s);
+void wpas_p2p_interface_unavailable(struct wpa_supplicant *wpa_s);
+void wpas_p2p_update_best_channels(struct wpa_supplicant *wpa_s,
+				   int freq_24, int freq_5, int freq_overall);
+int wpas_p2p_unauthorize(struct wpa_supplicant *wpa_s, const char *addr);
+int wpas_p2p_disconnect(struct wpa_supplicant *wpa_s);
+void wpas_p2p_wps_failed(struct wpa_supplicant *wpa_s,
+			 struct wps_event_fail *fail);
+int wpas_p2p_in_progress(struct wpa_supplicant *wpa_s);
+void wpas_p2p_network_removed(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid);
+struct wpa_ssid * wpas_p2p_get_persistent(struct wpa_supplicant *wpa_s,
+					  const u8 *addr, const u8 *ssid,
+					  size_t ssid_len);
+void wpas_p2p_notify_ap_sta_authorized(struct wpa_supplicant *wpa_s,
+				       const u8 *addr);
+int wpas_p2p_scan_no_go_seen(struct wpa_supplicant *wpa_s);
+int wpas_p2p_get_ht40_mode(struct wpa_supplicant *wpa_s,
+			   struct hostapd_hw_modes *mode, u8 channel);
+unsigned int wpas_p2p_search_delay(struct wpa_supplicant *wpa_s);
+
+#endif /* P2P_SUPPLICANT_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/scan.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,1561 @@
+/*
+ * WPA Supplicant - Scanning
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "config.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "wps_supplicant.h"
+#include "p2p_supplicant.h"
+#include "p2p/p2p.h"
+#include "hs20_supplicant.h"
+#include "notify.h"
+#include "bss.h"
+#include "scan.h"
+
+
+static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid;
+	union wpa_event_data data;
+
+	ssid = wpa_supplicant_get_ssid(wpa_s);
+	if (ssid == NULL)
+		return;
+
+	if (wpa_s->current_ssid == NULL) {
+		wpa_s->current_ssid = ssid;
+		if (wpa_s->current_ssid != NULL)
+			wpas_notify_network_changed(wpa_s);
+	}
+	wpa_supplicant_initiate_eapol(wpa_s);
+	wpa_dbg(wpa_s, MSG_DEBUG, "Already associated with a configured "
+		"network - generating associated event");
+	os_memset(&data, 0, sizeof(data));
+	wpa_supplicant_event(wpa_s, EVENT_ASSOC, &data);
+}
+
+
+#ifdef CONFIG_WPS
+static int wpas_wps_in_use(struct wpa_supplicant *wpa_s,
+			   enum wps_request_type *req_type)
+{
+	struct wpa_ssid *ssid;
+	int wps = 0;
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (!(ssid->key_mgmt & WPA_KEY_MGMT_WPS))
+			continue;
+
+		wps = 1;
+		*req_type = wpas_wps_get_req_type(ssid);
+		if (!ssid->eap.phase1)
+			continue;
+
+		if (os_strstr(ssid->eap.phase1, "pbc=1"))
+			return 2;
+	}
+
+#ifdef CONFIG_P2P
+	if (!wpa_s->global->p2p_disabled && wpa_s->global->p2p &&
+	    !wpa_s->conf->p2p_disabled) {
+		wpa_s->wps->dev.p2p = 1;
+		if (!wps) {
+			wps = 1;
+			*req_type = WPS_REQ_ENROLLEE_INFO;
+		}
+	}
+#endif /* CONFIG_P2P */
+
+	return wps;
+}
+#endif /* CONFIG_WPS */
+
+
+/**
+ * wpa_supplicant_enabled_networks - Check whether there are enabled networks
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 if no networks are enabled, >0 if networks are enabled
+ *
+ * This function is used to figure out whether any networks (or Interworking
+ * with enabled credentials and auto_interworking) are present in the current
+ * configuration.
+ */
+int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid = wpa_s->conf->ssid;
+	int count = 0, disabled = 0;
+	while (ssid) {
+		if (!wpas_network_disabled(wpa_s, ssid))
+			count++;
+		else
+			disabled++;
+		ssid = ssid->next;
+	}
+	if (wpa_s->conf->cred && wpa_s->conf->interworking &&
+	    wpa_s->conf->auto_interworking)
+		count++;
+	if (count == 0 && disabled > 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks (%d disabled "
+			"networks)", disabled);
+	}
+	return count;
+}
+
+
+static void wpa_supplicant_assoc_try(struct wpa_supplicant *wpa_s,
+				     struct wpa_ssid *ssid)
+{
+	while (ssid) {
+		if (!wpas_network_disabled(wpa_s, ssid))
+			break;
+		ssid = ssid->next;
+	}
+
+	/* ap_scan=2 mode - try to associate with each SSID. */
+	if (ssid == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "wpa_supplicant_assoc_try: Reached "
+			"end of scan list - go back to beginning");
+		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+		return;
+	}
+	if (ssid->next) {
+		/* Continue from the next SSID on the next attempt. */
+		wpa_s->prev_scan_ssid = ssid;
+	} else {
+		/* Start from the beginning of the SSID list. */
+		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
+	}
+	wpa_supplicant_associate(wpa_s, NULL, ssid);
+}
+
+
+static int int_array_len(const int *a)
+{
+	int i;
+	for (i = 0; a && a[i]; i++)
+		;
+	return i;
+}
+
+
+static void int_array_concat(int **res, const int *a)
+{
+	int reslen, alen, i;
+	int *n;
+
+	reslen = int_array_len(*res);
+	alen = int_array_len(a);
+
+	n = os_realloc_array(*res, reslen + alen + 1, sizeof(int));
+	if (n == NULL) {
+		os_free(*res);
+		*res = NULL;
+		return;
+	}
+	for (i = 0; i <= alen; i++)
+		n[reslen + i] = a[i];
+	*res = n;
+}
+
+
+static int freq_cmp(const void *a, const void *b)
+{
+	int _a = *(int *) a;
+	int _b = *(int *) b;
+
+	if (_a == 0)
+		return 1;
+	if (_b == 0)
+		return -1;
+	return _a - _b;
+}
+
+
+static void int_array_sort_unique(int *a)
+{
+	int alen;
+	int i, j;
+
+	if (a == NULL)
+		return;
+
+	alen = int_array_len(a);
+	qsort(a, alen, sizeof(int), freq_cmp);
+
+	i = 0;
+	j = 1;
+	while (a[i] && a[j]) {
+		if (a[i] == a[j]) {
+			j++;
+			continue;
+		}
+		a[++i] = a[j++];
+	}
+	if (a[i])
+		i++;
+	a[i] = 0;
+}
+
+
+/**
+ * wpa_supplicant_trigger_scan - Request driver to start a scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @params: Scan parameters
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
+				struct wpa_driver_scan_params *params)
+{
+	int ret;
+
+	wpa_supplicant_notify_scanning(wpa_s, 1);
+
+	ret = wpa_drv_scan(wpa_s, params);
+	if (ret) {
+		wpa_supplicant_notify_scanning(wpa_s, 0);
+		wpas_notify_scan_done(wpa_s, 0);
+	} else {
+		wpa_s->scan_runs++;
+		wpa_s->normal_scans++;
+	}
+
+	return ret;
+}
+
+
+static void
+wpa_supplicant_delayed_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Starting delayed sched scan");
+
+	if (wpa_supplicant_req_sched_scan(wpa_s))
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
+
+
+static void
+wpa_supplicant_sched_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Sched scan timeout - stopping it");
+
+	wpa_s->sched_scan_timed_out = 1;
+	wpa_supplicant_cancel_sched_scan(wpa_s);
+}
+
+
+static int
+wpa_supplicant_start_sched_scan(struct wpa_supplicant *wpa_s,
+				struct wpa_driver_scan_params *params,
+				int interval)
+{
+	int ret;
+
+	wpa_supplicant_notify_scanning(wpa_s, 1);
+	ret = wpa_drv_sched_scan(wpa_s, params, interval * 1000);
+	if (ret)
+		wpa_supplicant_notify_scanning(wpa_s, 0);
+	else
+		wpa_s->sched_scanning = 1;
+
+	return ret;
+}
+
+
+static int wpa_supplicant_stop_sched_scan(struct wpa_supplicant *wpa_s)
+{
+	int ret;
+
+	ret = wpa_drv_stop_sched_scan(wpa_s);
+	if (ret) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "stopping sched_scan failed!");
+		/* TODO: what to do if stopping fails? */
+		return -1;
+	}
+
+	return ret;
+}
+
+
+static struct wpa_driver_scan_filter *
+wpa_supplicant_build_filter_ssids(struct wpa_config *conf, size_t *num_ssids)
+{
+	struct wpa_driver_scan_filter *ssids;
+	struct wpa_ssid *ssid;
+	size_t count;
+
+	*num_ssids = 0;
+	if (!conf->filter_ssids)
+		return NULL;
+
+	for (count = 0, ssid = conf->ssid; ssid; ssid = ssid->next) {
+		if (ssid->ssid && ssid->ssid_len)
+			count++;
+	}
+	if (count == 0)
+		return NULL;
+	ssids = os_zalloc(count * sizeof(struct wpa_driver_scan_filter));
+	if (ssids == NULL)
+		return NULL;
+
+	for (ssid = conf->ssid; ssid; ssid = ssid->next) {
+		if (!ssid->ssid || !ssid->ssid_len)
+			continue;
+		os_memcpy(ssids[*num_ssids].ssid, ssid->ssid, ssid->ssid_len);
+		ssids[*num_ssids].ssid_len = ssid->ssid_len;
+		(*num_ssids)++;
+	}
+
+	return ssids;
+}
+
+
+static void wpa_supplicant_optimize_freqs(
+	struct wpa_supplicant *wpa_s, struct wpa_driver_scan_params *params)
+{
+#ifdef CONFIG_P2P
+	if (params->freqs == NULL && wpa_s->p2p_in_provisioning &&
+	    wpa_s->go_params) {
+		/* Optimize provisioning state scan based on GO information */
+		if (wpa_s->p2p_in_provisioning < 5 &&
+		    wpa_s->go_params->freq > 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only GO "
+				"preferred frequency %d MHz",
+				wpa_s->go_params->freq);
+			params->freqs = os_zalloc(2 * sizeof(int));
+			if (params->freqs)
+				params->freqs[0] = wpa_s->go_params->freq;
+		} else if (wpa_s->p2p_in_provisioning < 8 &&
+			   wpa_s->go_params->freq_list[0]) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only common "
+				"channels");
+			int_array_concat(&params->freqs,
+					 wpa_s->go_params->freq_list);
+			if (params->freqs)
+				int_array_sort_unique(params->freqs);
+		}
+		wpa_s->p2p_in_provisioning++;
+	}
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_WPS
+	if (params->freqs == NULL && wpa_s->after_wps && wpa_s->wps_freq) {
+		/*
+		 * Optimize post-provisioning scan based on channel used
+		 * during provisioning.
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz "
+			"that was used during provisioning", wpa_s->wps_freq);
+		params->freqs = os_zalloc(2 * sizeof(int));
+		if (params->freqs)
+			params->freqs[0] = wpa_s->wps_freq;
+		wpa_s->after_wps--;
+	}
+
+	if (params->freqs == NULL && wpa_s->known_wps_freq && wpa_s->wps_freq)
+	{
+		/* Optimize provisioning scan based on already known channel */
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Scan only frequency %u MHz",
+			wpa_s->wps_freq);
+		params->freqs = os_zalloc(2 * sizeof(int));
+		if (params->freqs)
+			params->freqs[0] = wpa_s->wps_freq;
+		wpa_s->known_wps_freq = 0; /* only do this once */
+	}
+#endif /* CONFIG_WPS */
+}
+
+
+#ifdef CONFIG_INTERWORKING
+static void wpas_add_interworking_elements(struct wpa_supplicant *wpa_s,
+					   struct wpabuf *buf)
+{
+	if (wpa_s->conf->interworking == 0)
+		return;
+
+	wpabuf_put_u8(buf, WLAN_EID_EXT_CAPAB);
+	wpabuf_put_u8(buf, 4);
+	wpabuf_put_u8(buf, 0x00);
+	wpabuf_put_u8(buf, 0x00);
+	wpabuf_put_u8(buf, 0x00);
+	wpabuf_put_u8(buf, 0x80); /* Bit 31 - Interworking */
+
+	wpabuf_put_u8(buf, WLAN_EID_INTERWORKING);
+	wpabuf_put_u8(buf, is_zero_ether_addr(wpa_s->conf->hessid) ? 1 :
+		      1 + ETH_ALEN);
+	wpabuf_put_u8(buf, wpa_s->conf->access_network_type);
+	/* No Venue Info */
+	if (!is_zero_ether_addr(wpa_s->conf->hessid))
+		wpabuf_put_data(buf, wpa_s->conf->hessid, ETH_ALEN);
+}
+#endif /* CONFIG_INTERWORKING */
+
+
+static struct wpabuf * wpa_supplicant_extra_ies(struct wpa_supplicant *wpa_s)
+{
+	struct wpabuf *extra_ie = NULL;
+#ifdef CONFIG_WPS
+	int wps = 0;
+	enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_INTERWORKING
+	if (wpa_s->conf->interworking &&
+	    wpabuf_resize(&extra_ie, 100) == 0)
+		wpas_add_interworking_elements(wpa_s, extra_ie);
+#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_WPS
+	wps = wpas_wps_in_use(wpa_s, &req_type);
+
+	if (wps) {
+		struct wpabuf *wps_ie;
+		wps_ie = wps_build_probe_req_ie(wps == 2 ? DEV_PW_PUSHBUTTON :
+						DEV_PW_DEFAULT,
+						&wpa_s->wps->dev,
+						wpa_s->wps->uuid, req_type,
+						0, NULL);
+		if (wps_ie) {
+			if (wpabuf_resize(&extra_ie, wpabuf_len(wps_ie)) == 0)
+				wpabuf_put_buf(extra_ie, wps_ie);
+			wpabuf_free(wps_ie);
+		}
+	}
+
+#ifdef CONFIG_P2P
+	if (wps) {
+		size_t ielen = p2p_scan_ie_buf_len(wpa_s->global->p2p);
+		if (wpabuf_resize(&extra_ie, ielen) == 0)
+			wpas_p2p_scan_ie(wpa_s, extra_ie);
+	}
+#endif /* CONFIG_P2P */
+
+#endif /* CONFIG_WPS */
+
+	return extra_ie;
+}
+
+
+#ifdef CONFIG_P2P
+
+/*
+ * Check whether there are any enabled networks or credentials that could be
+ * used for a non-P2P connection.
+ */
+static int non_p2p_network_enabled(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid;
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (wpas_network_disabled(wpa_s, ssid))
+			continue;
+		if (!ssid->p2p_group)
+			return 1;
+	}
+
+	if (wpa_s->conf->cred && wpa_s->conf->interworking &&
+	    wpa_s->conf->auto_interworking)
+		return 1;
+
+	return 0;
+}
+
+
+/*
+ * Find the operating frequency of any other virtual interface that is using
+ * the same radio concurrently.
+ */
+static int shared_vif_oper_freq(struct wpa_supplicant *wpa_s)
+{
+	const char *rn, *rn2;
+	struct wpa_supplicant *ifs;
+	u8 bssid[ETH_ALEN];
+
+	if (!wpa_s->driver->get_radio_name)
+		return -1;
+
+	rn = wpa_s->driver->get_radio_name(wpa_s->drv_priv);
+	if (rn == NULL || rn[0] == '\0')
+		return -1;
+
+	for (ifs = wpa_s->global->ifaces; ifs; ifs = ifs->next) {
+		if (ifs == wpa_s || !ifs->driver->get_radio_name)
+			continue;
+
+		rn2 = ifs->driver->get_radio_name(ifs->drv_priv);
+		if (!rn2 || os_strcmp(rn, rn2) != 0)
+			continue;
+
+		if (ifs->current_ssid == NULL || ifs->assoc_freq == 0)
+			continue;
+
+		if (ifs->current_ssid->mode == WPAS_MODE_AP ||
+		    ifs->current_ssid->mode == WPAS_MODE_P2P_GO)
+			return ifs->current_ssid->frequency;
+		if (wpa_drv_get_bssid(ifs, bssid) == 0)
+			return ifs->assoc_freq;
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_P2P */
+
+
+static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	struct wpa_ssid *ssid;
+	enum scan_req_type scan_req = NORMAL_SCAN_REQ;
+	int ret;
+	struct wpabuf *extra_ie = NULL;
+	struct wpa_driver_scan_params params;
+	struct wpa_driver_scan_params *scan_params;
+	size_t max_ssids;
+	enum wpa_states prev_state;
+
+	if (wpa_s->wpa_state == WPA_INTERFACE_DISABLED) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Skip scan - interface disabled");
+		return;
+	}
+
+	if (wpa_s->disconnected && wpa_s->scan_req == NORMAL_SCAN_REQ) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Disconnected - do not scan");
+		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+		return;
+	}
+
+	if (!wpa_supplicant_enabled_networks(wpa_s) &&
+	    wpa_s->scan_req == NORMAL_SCAN_REQ) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "No enabled networks - do not scan");
+		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
+#ifdef CONFIG_P2P
+		wpa_s->sta_scan_pending = 0;
+#endif /* CONFIG_P2P */
+		return;
+	}
+
+	if (wpa_s->conf->ap_scan != 0 &&
+	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Using wired authentication - "
+			"overriding ap_scan configuration");
+		wpa_s->conf->ap_scan = 0;
+		wpas_notify_ap_scan_changed(wpa_s);
+	}
+
+	if (wpa_s->conf->ap_scan == 0) {
+		wpa_supplicant_gen_assoc_event(wpa_s);
+		return;
+	}
+
+#ifdef CONFIG_P2P
+	if (wpas_p2p_in_progress(wpa_s)) {
+		if (wpa_s->sta_scan_pending &&
+		    wpas_p2p_in_progress(wpa_s) == 2 &&
+		    wpa_s->global->p2p_cb_on_scan_complete) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Process pending station "
+				"mode scan during P2P search");
+		} else {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Delay station mode scan "
+				"while P2P operation is in progress");
+			wpa_s->sta_scan_pending = 1;
+			wpa_supplicant_req_scan(wpa_s, 5, 0);
+			return;
+		}
+	}
+#endif /* CONFIG_P2P */
+
+	if (wpa_s->conf->ap_scan == 2)
+		max_ssids = 1;
+	else {
+		max_ssids = wpa_s->max_scan_ssids;
+		if (max_ssids > WPAS_MAX_SCAN_SSIDS)
+			max_ssids = WPAS_MAX_SCAN_SSIDS;
+	}
+
+	scan_req = wpa_s->scan_req;
+	wpa_s->scan_req = NORMAL_SCAN_REQ;
+
+	os_memset(&params, 0, sizeof(params));
+
+	prev_state = wpa_s->wpa_state;
+	if (wpa_s->wpa_state == WPA_DISCONNECTED ||
+	    wpa_s->wpa_state == WPA_INACTIVE)
+		wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
+
+	/*
+	 * If autoscan has set its own scanning parameters
+	 */
+	if (wpa_s->autoscan_params != NULL) {
+		scan_params = wpa_s->autoscan_params;
+		goto scan;
+	}
+
+	if (scan_req != MANUAL_SCAN_REQ && wpa_s->connect_without_scan) {
+		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+			if (ssid == wpa_s->connect_without_scan)
+				break;
+		}
+		wpa_s->connect_without_scan = NULL;
+		if (ssid) {
+			wpa_printf(MSG_DEBUG, "Start a pre-selected network "
+				   "without scan step");
+			wpa_supplicant_associate(wpa_s, NULL, ssid);
+			return;
+		}
+	}
+
+#ifdef CONFIG_P2P
+	if ((wpa_s->p2p_in_provisioning || wpa_s->show_group_started) &&
+	    wpa_s->go_params) {
+		wpa_printf(MSG_DEBUG, "P2P: Use specific SSID for scan during "
+			   "P2P group formation");
+		params.ssids[0].ssid = wpa_s->go_params->ssid;
+		params.ssids[0].ssid_len = wpa_s->go_params->ssid_len;
+		params.num_ssids = 1;
+		goto ssid_list_set;
+	}
+#endif /* CONFIG_P2P */
+
+	/* Find the starting point from which to continue scanning */
+	ssid = wpa_s->conf->ssid;
+	if (wpa_s->prev_scan_ssid != WILDCARD_SSID_SCAN) {
+		while (ssid) {
+			if (ssid == wpa_s->prev_scan_ssid) {
+				ssid = ssid->next;
+				break;
+			}
+			ssid = ssid->next;
+		}
+	}
+
+	if (scan_req != MANUAL_SCAN_REQ && wpa_s->conf->ap_scan == 2) {
+		wpa_s->connect_without_scan = NULL;
+		wpa_s->prev_scan_wildcard = 0;
+		wpa_supplicant_assoc_try(wpa_s, ssid);
+		return;
+	} else if (wpa_s->conf->ap_scan == 2) {
+		/*
+		 * User-initiated scan request in ap_scan == 2; scan with
+		 * wildcard SSID.
+		 */
+		ssid = NULL;
+	} else {
+		struct wpa_ssid *start = ssid, *tssid;
+		int freqs_set = 0;
+		if (ssid == NULL && max_ssids > 1)
+			ssid = wpa_s->conf->ssid;
+		while (ssid) {
+			if (!wpas_network_disabled(wpa_s, ssid) &&
+			    ssid->scan_ssid) {
+				wpa_hexdump_ascii(MSG_DEBUG, "Scan SSID",
+						  ssid->ssid, ssid->ssid_len);
+				params.ssids[params.num_ssids].ssid =
+					ssid->ssid;
+				params.ssids[params.num_ssids].ssid_len =
+					ssid->ssid_len;
+				params.num_ssids++;
+				if (params.num_ssids + 1 >= max_ssids)
+					break;
+			}
+			ssid = ssid->next;
+			if (ssid == start)
+				break;
+			if (ssid == NULL && max_ssids > 1 &&
+			    start != wpa_s->conf->ssid)
+				ssid = wpa_s->conf->ssid;
+		}
+
+		for (tssid = wpa_s->conf->ssid; tssid; tssid = tssid->next) {
+			if (wpas_network_disabled(wpa_s, tssid))
+				continue;
+			if ((params.freqs || !freqs_set) && tssid->scan_freq) {
+				int_array_concat(&params.freqs,
+						 tssid->scan_freq);
+			} else {
+				os_free(params.freqs);
+				params.freqs = NULL;
+			}
+			freqs_set = 1;
+		}
+		int_array_sort_unique(params.freqs);
+	}
+
+	if (ssid && max_ssids == 1) {
+		/*
+		 * If the driver is limited to 1 SSID at a time interleave
+		 * wildcard SSID scans with specific SSID scans to avoid
+		 * waiting a long time for a wildcard scan.
+		 */
+		if (!wpa_s->prev_scan_wildcard) {
+			params.ssids[0].ssid = NULL;
+			params.ssids[0].ssid_len = 0;
+			wpa_s->prev_scan_wildcard = 1;
+			wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for "
+				"wildcard SSID (Interleave with specific)");
+		} else {
+			wpa_s->prev_scan_ssid = ssid;
+			wpa_s->prev_scan_wildcard = 0;
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"Starting AP scan for specific SSID: %s",
+				wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+		}
+	} else if (ssid) {
+		/* max_ssids > 1 */
+
+		wpa_s->prev_scan_ssid = ssid;
+		wpa_dbg(wpa_s, MSG_DEBUG, "Include wildcard SSID in "
+			"the scan request");
+		params.num_ssids++;
+	} else {
+		wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
+		params.num_ssids++;
+		wpa_dbg(wpa_s, MSG_DEBUG, "Starting AP scan for wildcard "
+			"SSID");
+	}
+#ifdef CONFIG_P2P
+ssid_list_set:
+#endif /* CONFIG_P2P */
+
+	wpa_supplicant_optimize_freqs(wpa_s, &params);
+	extra_ie = wpa_supplicant_extra_ies(wpa_s);
+
+#ifdef CONFIG_HS20
+	if (wpa_s->conf->hs20 && wpabuf_resize(&extra_ie, 6) == 0)
+		wpas_hs20_add_indication(extra_ie);
+#endif /* CONFIG_HS20 */
+
+	if (params.freqs == NULL && wpa_s->next_scan_freqs) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Optimize scan based on previously "
+			"generated frequency list");
+		params.freqs = wpa_s->next_scan_freqs;
+	} else
+		os_free(wpa_s->next_scan_freqs);
+	wpa_s->next_scan_freqs = NULL;
+
+	params.filter_ssids = wpa_supplicant_build_filter_ssids(
+		wpa_s->conf, &params.num_filter_ssids);
+	if (extra_ie) {
+		params.extra_ies = wpabuf_head(extra_ie);
+		params.extra_ies_len = wpabuf_len(extra_ie);
+	}
+
+#ifdef CONFIG_P2P
+	if (wpa_s->p2p_in_provisioning ||
+	    (wpa_s->show_group_started && wpa_s->go_params)) {
+		/*
+		 * The interface may not yet be in P2P mode, so we have to
+		 * explicitly request P2P probe to disable CCK rates.
+		 */
+		params.p2p_probe = 1;
+	}
+#endif /* CONFIG_P2P */
+
+	scan_params = &params;
+
+scan:
+#ifdef CONFIG_P2P
+	/*
+	 * If the driver does not support multi-channel concurrency and a
+	 * virtual interface that shares the same radio with the wpa_s interface
+	 * is operating there may not be need to scan other channels apart from
+	 * the current operating channel on the other virtual interface. Filter
+	 * out other channels in case we are trying to find a connection for a
+	 * station interface when we are not configured to prefer station
+	 * connection and a concurrent operation is already in process.
+	 */
+	if (wpa_s->scan_for_connection && scan_req == NORMAL_SCAN_REQ &&
+	    !scan_params->freqs && !params.freqs &&
+	    wpas_is_p2p_prioritized(wpa_s) &&
+	    !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT) &&
+	    wpa_s->p2p_group_interface == NOT_P2P_GROUP_INTERFACE &&
+	    non_p2p_network_enabled(wpa_s)) {
+		int freq = shared_vif_oper_freq(wpa_s);
+		if (freq > 0) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Scan only the current "
+				"operating channel (%d MHz) since driver does "
+				"not support multi-channel concurrency", freq);
+			params.freqs = os_zalloc(sizeof(int) * 2);
+			if (params.freqs)
+				params.freqs[0] = freq;
+			scan_params->freqs = params.freqs;
+		}
+	}
+#endif /* CONFIG_P2P */
+
+	ret = wpa_supplicant_trigger_scan(wpa_s, scan_params);
+
+	wpabuf_free(extra_ie);
+	os_free(params.freqs);
+	os_free(params.filter_ssids);
+
+	if (ret) {
+		wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate AP scan");
+		if (prev_state != wpa_s->wpa_state)
+			wpa_supplicant_set_state(wpa_s, prev_state);
+		/* Restore scan_req since we will try to scan again */
+		wpa_s->scan_req = scan_req;
+		wpa_supplicant_req_scan(wpa_s, 1, 0);
+	} else {
+		wpa_s->scan_for_connection = 0;
+	}
+}
+
+
+/**
+ * wpa_supplicant_req_scan - Schedule a scan for neighboring access points
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @sec: Number of seconds after which to scan
+ * @usec: Number of microseconds after which to scan
+ *
+ * This function is used to schedule a scan for neighboring access points after
+ * the specified time.
+ */
+void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
+{
+	/* If there's at least one network that should be specifically scanned
+	 * then don't cancel the scan and reschedule.  Some drivers do
+	 * background scanning which generates frequent scan results, and that
+	 * causes the specific SSID scan to get continually pushed back and
+	 * never happen, which causes hidden APs to never get probe-scanned.
+	 */
+	if (eloop_is_timeout_registered(wpa_supplicant_scan, wpa_s, NULL) &&
+	    wpa_s->conf->ap_scan == 1) {
+		struct wpa_ssid *ssid = wpa_s->conf->ssid;
+
+		while (ssid) {
+			if (!wpas_network_disabled(wpa_s, ssid) &&
+			    ssid->scan_ssid)
+				break;
+			ssid = ssid->next;
+		}
+		if (ssid) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Not rescheduling scan to "
+			        "ensure that specific SSID scans occur");
+			return;
+		}
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Setting scan request: %d sec %d usec",
+		sec, usec);
+	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
+	eloop_register_timeout(sec, usec, wpa_supplicant_scan, wpa_s, NULL);
+}
+
+
+/**
+ * wpa_supplicant_delayed_sched_scan - Request a delayed scheduled scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @sec: Number of seconds after which to scan
+ * @usec: Number of microseconds after which to scan
+ * Returns: 0 on success or -1 otherwise
+ *
+ * This function is used to schedule periodic scans for neighboring
+ * access points after the specified time.
+ */
+int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
+				      int sec, int usec)
+{
+	if (!wpa_s->sched_scan_supported)
+		return -1;
+
+	eloop_register_timeout(sec, usec,
+			       wpa_supplicant_delayed_sched_scan_timeout,
+			       wpa_s, NULL);
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_req_sched_scan - Start a periodic scheduled scan
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 is sched_scan was started or -1 otherwise
+ *
+ * This function is used to schedule periodic scans for neighboring
+ * access points repeating the scan continuously.
+ */
+int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_driver_scan_params params;
+	struct wpa_driver_scan_params *scan_params;
+	enum wpa_states prev_state;
+	struct wpa_ssid *ssid = NULL;
+	struct wpabuf *extra_ie = NULL;
+	int ret;
+	unsigned int max_sched_scan_ssids;
+	int wildcard = 0;
+	int need_ssids;
+
+	if (!wpa_s->sched_scan_supported)
+		return -1;
+
+	if (wpa_s->max_sched_scan_ssids > WPAS_MAX_SCAN_SSIDS)
+		max_sched_scan_ssids = WPAS_MAX_SCAN_SSIDS;
+	else
+		max_sched_scan_ssids = wpa_s->max_sched_scan_ssids;
+	if (max_sched_scan_ssids < 1 || wpa_s->conf->disable_scan_offload)
+		return -1;
+
+	if (wpa_s->sched_scanning) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Already sched scanning");
+		return 0;
+	}
+
+	need_ssids = 0;
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next) {
+		if (!wpas_network_disabled(wpa_s, ssid) && !ssid->scan_ssid) {
+			/* Use wildcard SSID to find this network */
+			wildcard = 1;
+		} else if (!wpas_network_disabled(wpa_s, ssid) &&
+			   ssid->ssid_len)
+			need_ssids++;
+
+#ifdef CONFIG_WPS
+		if (!wpas_network_disabled(wpa_s, ssid) &&
+		    ssid->key_mgmt == WPA_KEY_MGMT_WPS) {
+			/*
+			 * Normal scan is more reliable and faster for WPS
+			 * operations and since these are for short periods of
+			 * time, the benefit of trying to use sched_scan would
+			 * be limited.
+			 */
+			wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of "
+				"sched_scan for WPS");
+			return -1;
+		}
+#endif /* CONFIG_WPS */
+	}
+	if (wildcard)
+		need_ssids++;
+
+	if (wpa_s->normal_scans < 3 &&
+	    (need_ssids <= wpa_s->max_scan_ssids ||
+	     wpa_s->max_scan_ssids >= (int) max_sched_scan_ssids)) {
+		/*
+		 * When normal scan can speed up operations, use that for the
+		 * first operations before starting the sched_scan to allow
+		 * user space sleep more. We do this only if the normal scan
+		 * has functionality that is suitable for this or if the
+		 * sched_scan does not have better support for multiple SSIDs.
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG, "Use normal scan instead of "
+			"sched_scan for initial scans (normal_scans=%d)",
+			wpa_s->normal_scans);
+		return -1;
+	}
+
+	os_memset(&params, 0, sizeof(params));
+
+	/* If we can't allocate space for the filters, we just don't filter */
+	params.filter_ssids = os_zalloc(wpa_s->max_match_sets *
+					sizeof(struct wpa_driver_scan_filter));
+
+	prev_state = wpa_s->wpa_state;
+	if (wpa_s->wpa_state == WPA_DISCONNECTED ||
+	    wpa_s->wpa_state == WPA_INACTIVE)
+		wpa_supplicant_set_state(wpa_s, WPA_SCANNING);
+
+	if (wpa_s->autoscan_params != NULL) {
+		scan_params = wpa_s->autoscan_params;
+		goto scan;
+	}
+
+	/* Find the starting point from which to continue scanning */
+	ssid = wpa_s->conf->ssid;
+	if (wpa_s->prev_sched_ssid) {
+		while (ssid) {
+			if (ssid == wpa_s->prev_sched_ssid) {
+				ssid = ssid->next;
+				break;
+			}
+			ssid = ssid->next;
+		}
+	}
+
+	if (!ssid || !wpa_s->prev_sched_ssid) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Beginning of SSID list");
+
+		if (wpa_s->sched_scan_interval == 0)
+			wpa_s->sched_scan_interval = 10;
+		wpa_s->sched_scan_timeout = max_sched_scan_ssids * 2;
+		wpa_s->first_sched_scan = 1;
+		ssid = wpa_s->conf->ssid;
+		wpa_s->prev_sched_ssid = ssid;
+	}
+
+	if (wildcard) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Add wildcard SSID to sched_scan");
+		params.num_ssids++;
+	}
+
+	while (ssid) {
+		if (wpas_network_disabled(wpa_s, ssid))
+			goto next;
+
+		if (params.num_filter_ssids < wpa_s->max_match_sets &&
+		    params.filter_ssids && ssid->ssid && ssid->ssid_len) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "add to filter ssid: %s",
+				wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+			os_memcpy(params.filter_ssids[params.num_filter_ssids].ssid,
+				  ssid->ssid, ssid->ssid_len);
+			params.filter_ssids[params.num_filter_ssids].ssid_len =
+				ssid->ssid_len;
+			params.num_filter_ssids++;
+		} else if (params.filter_ssids && ssid->ssid && ssid->ssid_len)
+		{
+			wpa_dbg(wpa_s, MSG_DEBUG, "Not enough room for SSID "
+				"filter for sched_scan - drop filter");
+			os_free(params.filter_ssids);
+			params.filter_ssids = NULL;
+			params.num_filter_ssids = 0;
+		}
+
+		if (ssid->scan_ssid && ssid->ssid && ssid->ssid_len) {
+			if (params.num_ssids == max_sched_scan_ssids)
+				break; /* only room for broadcast SSID */
+			wpa_dbg(wpa_s, MSG_DEBUG,
+				"add to active scan ssid: %s",
+				wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+			params.ssids[params.num_ssids].ssid =
+				ssid->ssid;
+			params.ssids[params.num_ssids].ssid_len =
+				ssid->ssid_len;
+			params.num_ssids++;
+			if (params.num_ssids >= max_sched_scan_ssids) {
+				wpa_s->prev_sched_ssid = ssid;
+				do {
+					ssid = ssid->next;
+				} while (ssid &&
+					 (wpas_network_disabled(wpa_s, ssid) ||
+					  !ssid->scan_ssid));
+				break;
+			}
+		}
+
+	next:
+		wpa_s->prev_sched_ssid = ssid;
+		ssid = ssid->next;
+	}
+
+	if (params.num_filter_ssids == 0) {
+		os_free(params.filter_ssids);
+		params.filter_ssids = NULL;
+	}
+
+	extra_ie = wpa_supplicant_extra_ies(wpa_s);
+	if (extra_ie) {
+		params.extra_ies = wpabuf_head(extra_ie);
+		params.extra_ies_len = wpabuf_len(extra_ie);
+	}
+
+	scan_params = &params;
+
+scan:
+	if (ssid || !wpa_s->first_sched_scan) {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Starting sched scan: interval %d timeout %d",
+			wpa_s->sched_scan_interval, wpa_s->sched_scan_timeout);
+	} else {
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"Starting sched scan: interval %d (no timeout)",
+			wpa_s->sched_scan_interval);
+	}
+
+	ret = wpa_supplicant_start_sched_scan(wpa_s, scan_params,
+					      wpa_s->sched_scan_interval);
+	wpabuf_free(extra_ie);
+	os_free(params.filter_ssids);
+	if (ret) {
+		wpa_msg(wpa_s, MSG_WARNING, "Failed to initiate sched scan");
+		if (prev_state != wpa_s->wpa_state)
+			wpa_supplicant_set_state(wpa_s, prev_state);
+		return ret;
+	}
+
+	/* If we have more SSIDs to scan, add a timeout so we scan them too */
+	if (ssid || !wpa_s->first_sched_scan) {
+		wpa_s->sched_scan_timed_out = 0;
+		eloop_register_timeout(wpa_s->sched_scan_timeout, 0,
+				       wpa_supplicant_sched_scan_timeout,
+				       wpa_s, NULL);
+		wpa_s->first_sched_scan = 0;
+		wpa_s->sched_scan_timeout /= 2;
+		wpa_s->sched_scan_interval *= 2;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_cancel_scan - Cancel a scheduled scan request
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to cancel a scan request scheduled with
+ * wpa_supplicant_req_scan().
+ */
+void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
+{
+	wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling scan request");
+	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
+}
+
+
+/**
+ * wpa_supplicant_cancel_sched_scan - Stop running scheduled scans
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to stop a periodic scheduled scan.
+ */
+void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s)
+{
+	if (!wpa_s->sched_scanning)
+		return;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling sched scan");
+	eloop_cancel_timeout(wpa_supplicant_sched_scan_timeout, wpa_s, NULL);
+	wpa_supplicant_stop_sched_scan(wpa_s);
+}
+
+
+/**
+ * wpa_supplicant_notify_scanning - Indicate possible scan state change
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @scanning: Whether scanning is currently in progress
+ *
+ * This function is to generate scanning notifycations. It is called whenever
+ * there may have been a change in scanning (scan started, completed, stopped).
+ * wpas_notify_scanning() is called whenever the scanning state changed from the
+ * previously notified state.
+ */
+void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
+				    int scanning)
+{
+	if (wpa_s->scanning != scanning) {
+		wpa_s->scanning = scanning;
+		wpas_notify_scanning(wpa_s);
+	}
+}
+
+
+static int wpa_scan_get_max_rate(const struct wpa_scan_res *res)
+{
+	int rate = 0;
+	const u8 *ie;
+	int i;
+
+	ie = wpa_scan_get_ie(res, WLAN_EID_SUPP_RATES);
+	for (i = 0; ie && i < ie[1]; i++) {
+		if ((ie[i + 2] & 0x7f) > rate)
+			rate = ie[i + 2] & 0x7f;
+	}
+
+	ie = wpa_scan_get_ie(res, WLAN_EID_EXT_SUPP_RATES);
+	for (i = 0; ie && i < ie[1]; i++) {
+		if ((ie[i + 2] & 0x7f) > rate)
+			rate = ie[i + 2] & 0x7f;
+	}
+
+	return rate;
+}
+
+
+/**
+ * wpa_scan_get_ie - Fetch a specified information element from a scan result
+ * @res: Scan result entry
+ * @ie: Information element identitifier (WLAN_EID_*)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the scan
+ * result.
+ */
+const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie)
+{
+	const u8 *end, *pos;
+
+	pos = (const u8 *) (res + 1);
+	end = pos + res->ie_len;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == ie)
+			return pos;
+		pos += 2 + pos[1];
+	}
+
+	return NULL;
+}
+
+
+/**
+ * wpa_scan_get_vendor_ie - Fetch vendor information element from a scan result
+ * @res: Scan result entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element (id field) or %NULL if not found
+ *
+ * This function returns the first matching information element in the scan
+ * result.
+ */
+const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
+				  u32 vendor_type)
+{
+	const u8 *end, *pos;
+
+	pos = (const u8 *) (res + 1);
+	end = pos + res->ie_len;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			return pos;
+		pos += 2 + pos[1];
+	}
+
+	return NULL;
+}
+
+
+/**
+ * wpa_scan_get_vendor_ie_multi - Fetch vendor IE data from a scan result
+ * @res: Scan result entry
+ * @vendor_type: Vendor type (four octets starting the IE payload)
+ * Returns: Pointer to the information element payload or %NULL if not found
+ *
+ * This function returns concatenated payload of possibly fragmented vendor
+ * specific information elements in the scan result. The caller is responsible
+ * for freeing the returned buffer.
+ */
+struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
+					     u32 vendor_type)
+{
+	struct wpabuf *buf;
+	const u8 *end, *pos;
+
+	buf = wpabuf_alloc(res->ie_len);
+	if (buf == NULL)
+		return NULL;
+
+	pos = (const u8 *) (res + 1);
+	end = pos + res->ie_len;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			wpabuf_put_data(buf, pos + 2 + 4, pos[1] - 4);
+		pos += 2 + pos[1];
+	}
+
+	if (wpabuf_len(buf) == 0) {
+		wpabuf_free(buf);
+		buf = NULL;
+	}
+
+	return buf;
+}
+
+
+/*
+ * Channels with a great SNR can operate at full rate. What is a great SNR?
+ * This doc https://supportforums.cisco.com/docs/DOC-12954 says, "the general
+ * rule of thumb is that any SNR above 20 is good." This one
+ * http://www.cisco.com/en/US/tech/tk722/tk809/technologies_q_and_a_item09186a00805e9a96.shtml#qa23
+ * recommends 25 as a minimum SNR for 54 Mbps data rate. 30 is chosen here as a
+ * conservative value.
+ */
+#define GREAT_SNR 30
+
+/* Compare function for sorting scan results. Return >0 if @b is considered
+ * better. */
+static int wpa_scan_result_compar(const void *a, const void *b)
+{
+#define IS_5GHZ(n) (n > 4000)
+#define MIN(a,b) a < b ? a : b
+	struct wpa_scan_res **_wa = (void *) a;
+	struct wpa_scan_res **_wb = (void *) b;
+	struct wpa_scan_res *wa = *_wa;
+	struct wpa_scan_res *wb = *_wb;
+	int wpa_a, wpa_b, maxrate_a, maxrate_b;
+	int snr_a, snr_b;
+
+	/* WPA/WPA2 support preferred */
+	wpa_a = wpa_scan_get_vendor_ie(wa, WPA_IE_VENDOR_TYPE) != NULL ||
+		wpa_scan_get_ie(wa, WLAN_EID_RSN) != NULL;
+	wpa_b = wpa_scan_get_vendor_ie(wb, WPA_IE_VENDOR_TYPE) != NULL ||
+		wpa_scan_get_ie(wb, WLAN_EID_RSN) != NULL;
+
+	if (wpa_b && !wpa_a)
+		return 1;
+	if (!wpa_b && wpa_a)
+		return -1;
+
+	/* privacy support preferred */
+	if ((wa->caps & IEEE80211_CAP_PRIVACY) == 0 &&
+	    (wb->caps & IEEE80211_CAP_PRIVACY))
+		return 1;
+	if ((wa->caps & IEEE80211_CAP_PRIVACY) &&
+	    (wb->caps & IEEE80211_CAP_PRIVACY) == 0)
+		return -1;
+
+	if ((wa->flags & wb->flags & WPA_SCAN_LEVEL_DBM) &&
+	    !((wa->flags | wb->flags) & WPA_SCAN_NOISE_INVALID)) {
+		snr_a = MIN(wa->level - wa->noise, GREAT_SNR);
+		snr_b = MIN(wb->level - wb->noise, GREAT_SNR);
+	} else {
+		/* Not suitable information to calculate SNR, so use level */
+		snr_a = wa->level;
+		snr_b = wb->level;
+	}
+
+	/* best/max rate preferred if SNR close enough */
+        if ((snr_a && snr_b && abs(snr_b - snr_a) < 5) ||
+	    (wa->qual && wb->qual && abs(wb->qual - wa->qual) < 10)) {
+		maxrate_a = wpa_scan_get_max_rate(wa);
+		maxrate_b = wpa_scan_get_max_rate(wb);
+		if (maxrate_a != maxrate_b)
+			return maxrate_b - maxrate_a;
+		if (IS_5GHZ(wa->freq) ^ IS_5GHZ(wb->freq))
+			return IS_5GHZ(wa->freq) ? -1 : 1;
+	}
+
+	/* use freq for channel preference */
+
+	/* all things being equal, use SNR; if SNRs are
+	 * identical, use quality values since some drivers may only report
+	 * that value and leave the signal level zero */
+	if (snr_b == snr_a)
+		return wb->qual - wa->qual;
+	return snr_b - snr_a;
+#undef MIN
+#undef IS_5GHZ
+}
+
+
+#ifdef CONFIG_WPS
+/* Compare function for sorting scan results when searching a WPS AP for
+ * provisioning. Return >0 if @b is considered better. */
+static int wpa_scan_result_wps_compar(const void *a, const void *b)
+{
+	struct wpa_scan_res **_wa = (void *) a;
+	struct wpa_scan_res **_wb = (void *) b;
+	struct wpa_scan_res *wa = *_wa;
+	struct wpa_scan_res *wb = *_wb;
+	int uses_wps_a, uses_wps_b;
+	struct wpabuf *wps_a, *wps_b;
+	int res;
+
+	/* Optimization - check WPS IE existence before allocated memory and
+	 * doing full reassembly. */
+	uses_wps_a = wpa_scan_get_vendor_ie(wa, WPS_IE_VENDOR_TYPE) != NULL;
+	uses_wps_b = wpa_scan_get_vendor_ie(wb, WPS_IE_VENDOR_TYPE) != NULL;
+	if (uses_wps_a && !uses_wps_b)
+		return -1;
+	if (!uses_wps_a && uses_wps_b)
+		return 1;
+
+	if (uses_wps_a && uses_wps_b) {
+		wps_a = wpa_scan_get_vendor_ie_multi(wa, WPS_IE_VENDOR_TYPE);
+		wps_b = wpa_scan_get_vendor_ie_multi(wb, WPS_IE_VENDOR_TYPE);
+		res = wps_ap_priority_compar(wps_a, wps_b);
+		wpabuf_free(wps_a);
+		wpabuf_free(wps_b);
+		if (res)
+			return res;
+	}
+
+	/*
+	 * Do not use current AP security policy as a sorting criteria during
+	 * WPS provisioning step since the AP may get reconfigured at the
+	 * completion of provisioning.
+	 */
+
+	/* all things being equal, use signal level; if signal levels are
+	 * identical, use quality values since some drivers may only report
+	 * that value and leave the signal level zero */
+	if (wb->level == wa->level)
+		return wb->qual - wa->qual;
+	return wb->level - wa->level;
+}
+#endif /* CONFIG_WPS */
+
+
+static void dump_scan_res(struct wpa_scan_results *scan_res)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	size_t i;
+
+	if (scan_res->res == NULL || scan_res->num == 0)
+		return;
+
+	wpa_printf(MSG_EXCESSIVE, "Sorted scan results");
+
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *r = scan_res->res[i];
+		u8 *pos;
+		if ((r->flags & (WPA_SCAN_LEVEL_DBM | WPA_SCAN_NOISE_INVALID))
+		    == WPA_SCAN_LEVEL_DBM) {
+			int snr = r->level - r->noise;
+			wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
+				   "noise=%d level=%d snr=%d%s flags=0x%x",
+				   MAC2STR(r->bssid), r->freq, r->qual,
+				   r->noise, r->level, snr,
+				   snr >= GREAT_SNR ? "*" : "", r->flags);
+		} else {
+			wpa_printf(MSG_EXCESSIVE, MACSTR " freq=%d qual=%d "
+				   "noise=%d level=%d flags=0x%x",
+				   MAC2STR(r->bssid), r->freq, r->qual,
+				   r->noise, r->level, r->flags);
+		}
+		pos = (u8 *) (r + 1);
+		if (r->ie_len)
+			wpa_hexdump(MSG_EXCESSIVE, "IEs", pos, r->ie_len);
+		pos += r->ie_len;
+		if (r->beacon_ie_len)
+			wpa_hexdump(MSG_EXCESSIVE, "Beacon IEs",
+				    pos, r->beacon_ie_len);
+	}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+/**
+ * wpa_supplicant_filter_bssid_match - Is the specified BSSID allowed
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bssid: BSSID to check
+ * Returns: 0 if the BSSID is filtered or 1 if not
+ *
+ * This function is used to filter out specific BSSIDs from scan reslts mainly
+ * for testing purposes (SET bssid_filter ctrl_iface command).
+ */
+int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
+				      const u8 *bssid)
+{
+	size_t i;
+
+	if (wpa_s->bssid_filter == NULL)
+		return 1;
+
+	for (i = 0; i < wpa_s->bssid_filter_count; i++) {
+		if (os_memcmp(wpa_s->bssid_filter + i * ETH_ALEN, bssid,
+			      ETH_ALEN) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+static void filter_scan_res(struct wpa_supplicant *wpa_s,
+			    struct wpa_scan_results *res)
+{
+	size_t i, j;
+
+	if (wpa_s->bssid_filter == NULL)
+		return;
+
+	for (i = 0, j = 0; i < res->num; i++) {
+		if (wpa_supplicant_filter_bssid_match(wpa_s,
+						      res->res[i]->bssid)) {
+			res->res[j++] = res->res[i];
+		} else {
+			os_free(res->res[i]);
+			res->res[i] = NULL;
+		}
+	}
+
+	if (res->num != j) {
+		wpa_printf(MSG_DEBUG, "Filtered out %d scan results",
+			   (int) (res->num - j));
+		res->num = j;
+	}
+}
+
+
+/**
+ * wpa_supplicant_get_scan_results - Get scan results
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @info: Information about what was scanned or %NULL if not available
+ * @new_scan: Whether a new scan was performed
+ * Returns: Scan results, %NULL on failure
+ *
+ * This function request the current scan results from the driver and updates
+ * the local BSS list wpa_s->bss. The caller is responsible for freeing the
+ * results with wpa_scan_results_free().
+ */
+struct wpa_scan_results *
+wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
+				struct scan_info *info, int new_scan)
+{
+	struct wpa_scan_results *scan_res;
+	size_t i;
+	int (*compar)(const void *, const void *) = wpa_scan_result_compar;
+
+	scan_res = wpa_drv_get_scan_results2(wpa_s);
+	if (scan_res == NULL) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Failed to get scan results");
+		return NULL;
+	}
+	filter_scan_res(wpa_s, scan_res);
+
+#ifdef CONFIG_WPS
+	if (wpas_wps_in_progress(wpa_s)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPS: Order scan results with WPS "
+			"provisioning rules");
+		compar = wpa_scan_result_wps_compar;
+	}
+#endif /* CONFIG_WPS */
+
+	qsort(scan_res->res, scan_res->num, sizeof(struct wpa_scan_res *),
+	      compar);
+	dump_scan_res(scan_res);
+
+	wpa_bss_update_start(wpa_s);
+	for (i = 0; i < scan_res->num; i++)
+		wpa_bss_update_scan_res(wpa_s, scan_res->res[i]);
+	wpa_bss_update_end(wpa_s, info, new_scan);
+
+	return scan_res;
+}
+
+
+/**
+ * wpa_supplicant_update_scan_results - Update scan results from the driver
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function updates the BSS table within wpa_supplicant based on the
+ * currently available scan results from the driver without requesting a new
+ * scan. This is used in cases where the driver indicates an association
+ * (including roaming within ESS) and wpa_supplicant does not yet have the
+ * needed information to complete the connection (e.g., to perform validation
+ * steps in 4-way handshake).
+ */
+int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_scan_results *scan_res;
+	scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL, 0);
+	if (scan_res == NULL)
+		return -1;
+	wpa_scan_results_free(scan_res);
+
+	return 0;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/scan.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,36 @@
+/*
+ * WPA Supplicant - Scanning
+ * Copyright (c) 2003-2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SCAN_H
+#define SCAN_H
+
+int wpa_supplicant_enabled_networks(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
+int wpa_supplicant_delayed_sched_scan(struct wpa_supplicant *wpa_s,
+				      int sec, int usec);
+int wpa_supplicant_req_sched_scan(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_cancel_sched_scan(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
+				    int scanning);
+struct wpa_driver_scan_params;
+int wpa_supplicant_trigger_scan(struct wpa_supplicant *wpa_s,
+				struct wpa_driver_scan_params *params);
+struct wpa_scan_results *
+wpa_supplicant_get_scan_results(struct wpa_supplicant *wpa_s,
+				struct scan_info *info, int new_scan);
+int wpa_supplicant_update_scan_results(struct wpa_supplicant *wpa_s);
+const u8 * wpa_scan_get_ie(const struct wpa_scan_res *res, u8 ie);
+const u8 * wpa_scan_get_vendor_ie(const struct wpa_scan_res *res,
+				  u32 vendor_type);
+struct wpabuf * wpa_scan_get_vendor_ie_multi(const struct wpa_scan_res *res,
+					     u32 vendor_type);
+int wpa_supplicant_filter_bssid_match(struct wpa_supplicant *wpa_s,
+				      const u8 *bssid);
+
+#endif /* SCAN_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/sme.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,113 @@
+/*
+ * wpa_supplicant - SME
+ * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SME_H
+#define SME_H
+
+#ifdef CONFIG_SME
+
+void sme_authenticate(struct wpa_supplicant *wpa_s,
+		      struct wpa_bss *bss, struct wpa_ssid *ssid);
+void sme_associate(struct wpa_supplicant *wpa_s, enum wpas_mode mode,
+		   const u8 *bssid, u16 auth_type);
+void sme_event_auth(struct wpa_supplicant *wpa_s, union wpa_event_data *data);
+int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
+		      const u8 *ies, size_t ies_len);
+void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
+			    union wpa_event_data *data);
+void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
+			      union wpa_event_data *data);
+void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
+			       union wpa_event_data *data);
+void sme_event_disassoc(struct wpa_supplicant *wpa_s,
+			union wpa_event_data *data);
+void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s, const u8 *sa,
+				 const u8 *da, u16 reason_code);
+void sme_sa_query_rx(struct wpa_supplicant *wpa_s, const u8 *sa,
+		     const u8 *data, size_t len);
+void sme_state_changed(struct wpa_supplicant *wpa_s);
+void sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
+				       const u8 *prev_pending_bssid);
+void sme_deinit(struct wpa_supplicant *wpa_s);
+
+int sme_proc_obss_scan(struct wpa_supplicant *wpa_s);
+void sme_sched_obss_scan(struct wpa_supplicant *wpa_s, int enable);
+
+#else /* CONFIG_SME */
+
+static inline void sme_authenticate(struct wpa_supplicant *wpa_s,
+				    struct wpa_bss *bss,
+				    struct wpa_ssid *ssid)
+{
+}
+
+static inline void sme_event_auth(struct wpa_supplicant *wpa_s,
+				  union wpa_event_data *data)
+{
+}
+
+static inline int sme_update_ft_ies(struct wpa_supplicant *wpa_s, const u8 *md,
+				    const u8 *ies, size_t ies_len)
+{
+	return -1;
+}
+
+
+static inline void sme_event_assoc_reject(struct wpa_supplicant *wpa_s,
+					  union wpa_event_data *data)
+{
+}
+
+static inline void sme_event_auth_timed_out(struct wpa_supplicant *wpa_s,
+					    union wpa_event_data *data)
+{
+}
+
+static inline void sme_event_assoc_timed_out(struct wpa_supplicant *wpa_s,
+					     union wpa_event_data *data)
+{
+}
+
+static inline void sme_event_disassoc(struct wpa_supplicant *wpa_s,
+				      union wpa_event_data *data)
+{
+}
+
+static inline void sme_event_unprot_disconnect(struct wpa_supplicant *wpa_s,
+					       const u8 *sa, const u8 *da,
+					       u16 reason_code)
+{
+}
+
+static inline void sme_state_changed(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void
+sme_disassoc_while_authenticating(struct wpa_supplicant *wpa_s,
+				  const u8 *prev_pending_bssid)
+{
+}
+
+static inline void sme_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int sme_proc_obss_scan(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline void sme_sched_obss_scan(struct wpa_supplicant *wpa_s,
+				       int enable)
+{
+}
+
+#endif /* CONFIG_SME */
+
+#endif /* SME_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/wifi_display.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,20 @@
+/*
+ * wpa_supplicant - Wi-Fi Display
+ * Copyright (c) 2011, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WIFI_DISPLAY_H
+#define WIFI_DISPLAY_H
+
+int wifi_display_init(struct wpa_global *global);
+void wifi_display_deinit(struct wpa_global *global);
+void wifi_display_enable(struct wpa_global *global, int enabled);
+int wifi_display_subelem_set(struct wpa_global *global, char *cmd);
+int wifi_display_subelem_get(struct wpa_global *global, char *cmd,
+			     char *buf, size_t buflen);
+
+#endif /* WIFI_DISPLAY_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/wnm_sta.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,21 @@
+/*
+ * IEEE 802.11v WNM related functions and structures
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WNM_STA_H
+#define WNM_STA_H
+
+struct rx_action;
+struct wpa_supplicant;
+
+int ieee802_11_send_wnmsleep_req(struct wpa_supplicant *wpa_s,
+				 u8 action, u16 intval, struct wpabuf *tfs_req);
+
+void ieee802_11_rx_wnm_action(struct wpa_supplicant *wpa_s,
+			      struct rx_action *action);
+
+#endif /* WNM_STA_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/wpa_supplicant.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,3796 @@
+/*
+ * WPA Supplicant
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file implements functions for registering and unregistering
+ * %wpa_supplicant interfaces. In addition, this file contains number of
+ * functions for managing network connections.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/random.h"
+#include "crypto/sha1.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "eap_peer/eap.h"
+#include "eap_server/eap_methods.h"
+#include "rsn_supp/wpa.h"
+#include "eloop.h"
+#include "config.h"
+#include "utils/ext_password.h"
+#include "l2_packet/l2_packet.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "ctrl_iface.h"
+#include "pcsc_funcs.h"
+#include "common/version.h"
+#include "rsn_supp/preauth.h"
+#include "rsn_supp/pmksa_cache.h"
+#include "common/wpa_ctrl.h"
+#include "common/ieee802_11_defs.h"
+#include "p2p/p2p.h"
+#include "blacklist.h"
+#include "wpas_glue.h"
+#include "wps_supplicant.h"
+#include "ibss_rsn.h"
+#include "sme.h"
+#include "gas_query.h"
+#include "ap.h"
+#include "p2p_supplicant.h"
+#include "wifi_display.h"
+#include "notify.h"
+#include "bgscan.h"
+#include "autoscan.h"
+#include "bss.h"
+#include "scan.h"
+#include "offchannel.h"
+#include "hs20_supplicant.h"
+
+const char *wpa_supplicant_version =
+"wpa_supplicant v" VERSION_STR "\n"
+"Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi> and contributors";
+
+const char *wpa_supplicant_license =
+"This software may be distributed under the terms of the BSD license.\n"
+"See README for more details.\n"
+#ifdef EAP_TLS_OPENSSL
+"\nThis product includes software developed by the OpenSSL Project\n"
+"for use in the OpenSSL Toolkit (http://www.openssl.org/)\n"
+#endif /* EAP_TLS_OPENSSL */
+;
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+/* Long text divided into parts in order to fit in C89 strings size limits. */
+const char *wpa_supplicant_full_license1 =
+"";
+const char *wpa_supplicant_full_license2 =
+"This software may be distributed under the terms of the BSD license.\n"
+"\n"
+"Redistribution and use in source and binary forms, with or without\n"
+"modification, are permitted provided that the following conditions are\n"
+"met:\n"
+"\n";
+const char *wpa_supplicant_full_license3 =
+"1. Redistributions of source code must retain the above copyright\n"
+"   notice, this list of conditions and the following disclaimer.\n"
+"\n"
+"2. Redistributions in binary form must reproduce the above copyright\n"
+"   notice, this list of conditions and the following disclaimer in the\n"
+"   documentation and/or other materials provided with the distribution.\n"
+"\n";
+const char *wpa_supplicant_full_license4 =
+"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
+"   names of its contributors may be used to endorse or promote products\n"
+"   derived from this software without specific prior written permission.\n"
+"\n"
+"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
+"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
+"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
+"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n";
+const char *wpa_supplicant_full_license5 =
+"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
+"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
+"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
+"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
+"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
+"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
+"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
+"\n";
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+extern int wpa_debug_timestamp;
+extern struct wpa_driver_ops *wpa_drivers[];
+
+/* Configure default/group WEP keys for static WEP */
+int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+	int i, set = 0;
+
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		if (ssid->wep_key_len[i] == 0)
+			continue;
+
+		set = 1;
+		wpa_drv_set_key(wpa_s, WPA_ALG_WEP, NULL,
+				i, i == ssid->wep_tx_keyidx, NULL, 0,
+				ssid->wep_key[i], ssid->wep_key_len[i]);
+	}
+
+	return set;
+}
+
+
+static int wpa_supplicant_set_wpa_none_key(struct wpa_supplicant *wpa_s,
+					   struct wpa_ssid *ssid)
+{
+	u8 key[32];
+	size_t keylen;
+	enum wpa_alg alg;
+	u8 seq[6] = { 0 };
+
+	/* IBSS/WPA-None uses only one key (Group) for both receiving and
+	 * sending unicast and multicast packets. */
+
+	if (ssid->mode != WPAS_MODE_IBSS) {
+		wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid mode %d (not "
+			"IBSS/ad-hoc) for WPA-None", ssid->mode);
+		return -1;
+	}
+
+	if (!ssid->psk_set) {
+		wpa_msg(wpa_s, MSG_INFO, "WPA: No PSK configured for "
+			"WPA-None");
+		return -1;
+	}
+
+	switch (wpa_s->group_cipher) {
+	case WPA_CIPHER_CCMP:
+		os_memcpy(key, ssid->psk, 16);
+		keylen = 16;
+		alg = WPA_ALG_CCMP;
+		break;
+	case WPA_CIPHER_GCMP:
+		os_memcpy(key, ssid->psk, 16);
+		keylen = 16;
+		alg = WPA_ALG_GCMP;
+		break;
+	case WPA_CIPHER_TKIP:
+		/* WPA-None uses the same Michael MIC key for both TX and RX */
+		os_memcpy(key, ssid->psk, 16 + 8);
+		os_memcpy(key + 16 + 8, ssid->psk + 16, 8);
+		keylen = 32;
+		alg = WPA_ALG_TKIP;
+		break;
+	default:
+		wpa_msg(wpa_s, MSG_INFO, "WPA: Invalid group cipher %d for "
+			"WPA-None", wpa_s->group_cipher);
+		return -1;
+	}
+
+	/* TODO: should actually remember the previously used seq#, both for TX
+	 * and RX from each STA.. */
+
+	return wpa_drv_set_key(wpa_s, alg, NULL, 0, 1, seq, 6, key, keylen);
+}
+
+
+static void wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_supplicant *wpa_s = eloop_ctx;
+	const u8 *bssid = wpa_s->bssid;
+	if (is_zero_ether_addr(bssid))
+		bssid = wpa_s->pending_bssid;
+	wpa_msg(wpa_s, MSG_INFO, "Authentication with " MACSTR " timed out.",
+		MAC2STR(bssid));
+	wpa_blacklist_add(wpa_s, bssid);
+	wpa_sm_notify_disassoc(wpa_s->wpa);
+	wpa_supplicant_deauthenticate(wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+	wpa_s->reassociate = 1;
+
+	/*
+	 * If we timed out, the AP or the local radio may be busy.
+	 * So, wait a second until scanning again.
+	 */
+	wpa_supplicant_req_scan(wpa_s, 1, 0);
+
+#ifdef CONFIG_P2P
+	if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+	    wpa_s->global->p2p != NULL) {
+		wpa_s->global->p2p_cb_on_scan_complete = 0;
+		if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+				"continued after timed out authentication");
+		}
+	}
+#endif /* CONFIG_P2P */
+}
+
+
+/**
+ * wpa_supplicant_req_auth_timeout - Schedule a timeout for authentication
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @sec: Number of seconds after which to time out authentication
+ * @usec: Number of microseconds after which to time out authentication
+ *
+ * This function is used to schedule a timeout for the current authentication
+ * attempt.
+ */
+void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
+				     int sec, int usec)
+{
+	if (wpa_s->conf && wpa_s->conf->ap_scan == 0 &&
+	    (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
+		return;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Setting authentication timeout: %d sec "
+		"%d usec", sec, usec);
+	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+	eloop_register_timeout(sec, usec, wpa_supplicant_timeout, wpa_s, NULL);
+}
+
+
+/**
+ * wpa_supplicant_cancel_auth_timeout - Cancel authentication timeout
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to cancel authentication timeout scheduled with
+ * wpa_supplicant_req_auth_timeout() and it is called when authentication has
+ * been completed.
+ */
+void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
+{
+	wpa_dbg(wpa_s, MSG_DEBUG, "Cancelling authentication timeout");
+	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+	wpa_blacklist_del(wpa_s, wpa_s->bssid);
+}
+
+
+/**
+ * wpa_supplicant_initiate_eapol - Configure EAPOL state machine
+ * @wpa_s: Pointer to wpa_supplicant data
+ *
+ * This function is used to configure EAPOL state machine based on the selected
+ * authentication mode.
+ */
+void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s)
+{
+#ifdef IEEE8021X_EAPOL
+	struct eapol_config eapol_conf;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+
+#ifdef CONFIG_IBSS_RSN
+	if (ssid->mode == WPAS_MODE_IBSS &&
+	    wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
+	    wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
+		/*
+		 * RSN IBSS authentication is per-STA and we can disable the
+		 * per-BSSID EAPOL authentication.
+		 */
+		eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
+		eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
+		eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
+		return;
+	}
+#endif /* CONFIG_IBSS_RSN */
+
+	eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+	eapol_sm_notify_eap_fail(wpa_s->eapol, FALSE);
+
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE)
+		eapol_sm_notify_portControl(wpa_s->eapol, ForceAuthorized);
+	else
+		eapol_sm_notify_portControl(wpa_s->eapol, Auto);
+
+	os_memset(&eapol_conf, 0, sizeof(eapol_conf));
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		eapol_conf.accept_802_1x_keys = 1;
+		eapol_conf.required_keys = 0;
+		if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_UNICAST) {
+			eapol_conf.required_keys |= EAPOL_REQUIRE_KEY_UNICAST;
+		}
+		if (ssid->eapol_flags & EAPOL_FLAG_REQUIRE_KEY_BROADCAST) {
+			eapol_conf.required_keys |=
+				EAPOL_REQUIRE_KEY_BROADCAST;
+		}
+
+		if (wpa_s->conf && (wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED))
+			eapol_conf.required_keys = 0;
+	}
+	if (wpa_s->conf)
+		eapol_conf.fast_reauth = wpa_s->conf->fast_reauth;
+	eapol_conf.workaround = ssid->eap_workaround;
+	eapol_conf.eap_disabled =
+		!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) &&
+		wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA &&
+		wpa_s->key_mgmt != WPA_KEY_MGMT_WPS;
+	eapol_sm_notify_config(wpa_s->eapol, &ssid->eap, &eapol_conf);
+#endif /* IEEE8021X_EAPOL */
+}
+
+
+/**
+ * wpa_supplicant_set_non_wpa_policy - Set WPA parameters to non-WPA mode
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @ssid: Configuration data for the network
+ *
+ * This function is used to configure WPA state machine and related parameters
+ * to a mode where WPA is not enabled. This is called as part of the
+ * authentication configuration when the selected network does not use WPA.
+ */
+void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
+				       struct wpa_ssid *ssid)
+{
+	int i;
+
+	if (ssid->key_mgmt & WPA_KEY_MGMT_WPS)
+		wpa_s->key_mgmt = WPA_KEY_MGMT_WPS;
+	else if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA)
+		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_NO_WPA;
+	else
+		wpa_s->key_mgmt = WPA_KEY_MGMT_NONE;
+	wpa_sm_set_ap_wpa_ie(wpa_s->wpa, NULL, 0);
+	wpa_sm_set_ap_rsn_ie(wpa_s->wpa, NULL, 0);
+	wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+	wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
+	wpa_s->group_cipher = WPA_CIPHER_NONE;
+	wpa_s->mgmt_group_cipher = 0;
+
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		if (ssid->wep_key_len[i] > 5) {
+			wpa_s->pairwise_cipher = WPA_CIPHER_WEP104;
+			wpa_s->group_cipher = WPA_CIPHER_WEP104;
+			break;
+		} else if (ssid->wep_key_len[i] > 0) {
+			wpa_s->pairwise_cipher = WPA_CIPHER_WEP40;
+			wpa_s->group_cipher = WPA_CIPHER_WEP40;
+			break;
+		}
+	}
+
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED, 0);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
+			 wpa_s->pairwise_cipher);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
+#ifdef CONFIG_IEEE80211W
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
+			 wpa_s->mgmt_group_cipher);
+#endif /* CONFIG_IEEE80211W */
+
+	pmksa_cache_clear_current(wpa_s->wpa);
+}
+
+
+void free_hw_features(struct wpa_supplicant *wpa_s)
+{
+	int i;
+	if (wpa_s->hw.modes == NULL)
+		return;
+
+	for (i = 0; i < wpa_s->hw.num_modes; i++) {
+		os_free(wpa_s->hw.modes[i].channels);
+		os_free(wpa_s->hw.modes[i].rates);
+	}
+
+	os_free(wpa_s->hw.modes);
+	wpa_s->hw.modes = NULL;
+}
+
+
+static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
+{
+	bgscan_deinit(wpa_s);
+	autoscan_deinit(wpa_s);
+	scard_deinit(wpa_s->scard);
+	wpa_s->scard = NULL;
+	wpa_sm_set_scard_ctx(wpa_s->wpa, NULL);
+	eapol_sm_register_scard_ctx(wpa_s->eapol, NULL);
+	l2_packet_deinit(wpa_s->l2);
+	wpa_s->l2 = NULL;
+	if (wpa_s->l2_br) {
+		l2_packet_deinit(wpa_s->l2_br);
+		wpa_s->l2_br = NULL;
+	}
+
+	if (wpa_s->conf != NULL) {
+		struct wpa_ssid *ssid;
+		for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+			wpas_notify_network_removed(wpa_s, ssid);
+	}
+
+	os_free(wpa_s->confname);
+	wpa_s->confname = NULL;
+
+	wpa_sm_set_eapol(wpa_s->wpa, NULL);
+	eapol_sm_deinit(wpa_s->eapol);
+	wpa_s->eapol = NULL;
+
+	rsn_preauth_deinit(wpa_s->wpa);
+
+#ifdef CONFIG_TDLS
+	wpa_tdls_deinit(wpa_s->wpa);
+#endif /* CONFIG_TDLS */
+
+	pmksa_candidate_free(wpa_s->wpa);
+	wpa_sm_deinit(wpa_s->wpa);
+	wpa_s->wpa = NULL;
+	wpa_blacklist_clear(wpa_s);
+
+	wpa_bss_deinit(wpa_s);
+
+	wpa_supplicant_cancel_scan(wpa_s);
+	wpa_supplicant_cancel_auth_timeout(wpa_s);
+	eloop_cancel_timeout(wpa_supplicant_stop_countermeasures, wpa_s, NULL);
+#ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+	eloop_cancel_timeout(wpa_supplicant_delayed_mic_error_report,
+			     wpa_s, NULL);
+#endif /* CONFIG_DELAYED_MIC_ERROR_REPORT */
+
+	wpas_wps_deinit(wpa_s);
+
+	wpabuf_free(wpa_s->pending_eapol_rx);
+	wpa_s->pending_eapol_rx = NULL;
+
+#ifdef CONFIG_IBSS_RSN
+	ibss_rsn_deinit(wpa_s->ibss_rsn);
+	wpa_s->ibss_rsn = NULL;
+#endif /* CONFIG_IBSS_RSN */
+
+	sme_deinit(wpa_s);
+
+#ifdef CONFIG_AP
+	wpa_supplicant_ap_deinit(wpa_s);
+#endif /* CONFIG_AP */
+
+#ifdef CONFIG_P2P
+	wpas_p2p_deinit(wpa_s);
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_OFFCHANNEL
+	offchannel_deinit(wpa_s);
+#endif /* CONFIG_OFFCHANNEL */
+
+	wpa_supplicant_cancel_sched_scan(wpa_s);
+
+	os_free(wpa_s->next_scan_freqs);
+	wpa_s->next_scan_freqs = NULL;
+
+	gas_query_deinit(wpa_s->gas);
+	wpa_s->gas = NULL;
+
+	free_hw_features(wpa_s);
+
+	os_free(wpa_s->bssid_filter);
+	wpa_s->bssid_filter = NULL;
+
+	os_free(wpa_s->disallow_aps_bssid);
+	wpa_s->disallow_aps_bssid = NULL;
+	os_free(wpa_s->disallow_aps_ssid);
+	wpa_s->disallow_aps_ssid = NULL;
+
+	wnm_bss_keep_alive_deinit(wpa_s);
+
+	ext_password_deinit(wpa_s->ext_pw);
+	wpa_s->ext_pw = NULL;
+
+	wpabuf_free(wpa_s->last_gas_resp);
+
+	os_free(wpa_s->last_scan_res);
+	wpa_s->last_scan_res = NULL;
+}
+
+
+/**
+ * wpa_clear_keys - Clear keys configured for the driver
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @addr: Previously used BSSID or %NULL if not available
+ *
+ * This function clears the encryption keys that has been previously configured
+ * for the driver.
+ */
+void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
+{
+	if (wpa_s->keys_cleared) {
+		/* Some drivers (e.g., ndiswrapper & NDIS drivers) seem to have
+		 * timing issues with keys being cleared just before new keys
+		 * are set or just after association or something similar. This
+		 * shows up in group key handshake failing often because of the
+		 * client not receiving the first encrypted packets correctly.
+		 * Skipping some of the extra key clearing steps seems to help
+		 * in completing group key handshake more reliably. */
+		wpa_dbg(wpa_s, MSG_DEBUG, "No keys have been configured - "
+			"skip key clearing");
+		return;
+	}
+
+	/* MLME-DELETEKEYS.request */
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 0, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 1, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 2, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 3, 0, NULL, 0, NULL, 0);
+#ifdef CONFIG_IEEE80211W
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 4, 0, NULL, 0, NULL, 0);
+	wpa_drv_set_key(wpa_s, WPA_ALG_NONE, NULL, 5, 0, NULL, 0, NULL, 0);
+#endif /* CONFIG_IEEE80211W */
+	if (addr) {
+		wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
+				0);
+		/* MLME-SETPROTECTION.request(None) */
+		wpa_drv_mlme_setprotection(
+			wpa_s, addr,
+			MLME_SETPROTECTION_PROTECT_TYPE_NONE,
+			MLME_SETPROTECTION_KEY_TYPE_PAIRWISE);
+	}
+	wpa_s->keys_cleared = 1;
+}
+
+
+/**
+ * wpa_supplicant_state_txt - Get the connection state name as a text string
+ * @state: State (wpa_state; WPA_*)
+ * Returns: The state name as a printable text string
+ */
+const char * wpa_supplicant_state_txt(enum wpa_states state)
+{
+	switch (state) {
+	case WPA_DISCONNECTED:
+		return "DISCONNECTED";
+	case WPA_INACTIVE:
+		return "INACTIVE";
+	case WPA_INTERFACE_DISABLED:
+		return "INTERFACE_DISABLED";
+	case WPA_SCANNING:
+		return "SCANNING";
+	case WPA_AUTHENTICATING:
+		return "AUTHENTICATING";
+	case WPA_ASSOCIATING:
+		return "ASSOCIATING";
+	case WPA_ASSOCIATED:
+		return "ASSOCIATED";
+	case WPA_4WAY_HANDSHAKE:
+		return "4WAY_HANDSHAKE";
+	case WPA_GROUP_HANDSHAKE:
+		return "GROUP_HANDSHAKE";
+	case WPA_COMPLETED:
+		return "COMPLETED";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+#ifdef CONFIG_BGSCAN
+
+static void wpa_supplicant_start_bgscan(struct wpa_supplicant *wpa_s)
+{
+	if (wpas_driver_bss_selection(wpa_s))
+		return;
+	if (wpa_s->current_ssid == wpa_s->bgscan_ssid)
+		return;
+
+	bgscan_deinit(wpa_s);
+	if (wpa_s->current_ssid && wpa_s->current_ssid->bgscan) {
+		if (bgscan_init(wpa_s, wpa_s->current_ssid)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
+				"bgscan");
+			/*
+			 * Live without bgscan; it is only used as a roaming
+			 * optimization, so the initial connection is not
+			 * affected.
+			 */
+		} else {
+			struct wpa_scan_results *scan_res;
+			wpa_s->bgscan_ssid = wpa_s->current_ssid;
+			scan_res = wpa_supplicant_get_scan_results(wpa_s, NULL,
+								   0);
+			if (scan_res) {
+				bgscan_notify_scan(wpa_s, scan_res);
+				wpa_scan_results_free(scan_res);
+			}
+		}
+	} else
+		wpa_s->bgscan_ssid = NULL;
+}
+
+
+static void wpa_supplicant_stop_bgscan(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->bgscan_ssid != NULL) {
+		bgscan_deinit(wpa_s);
+		wpa_s->bgscan_ssid = NULL;
+	}
+}
+
+#endif /* CONFIG_BGSCAN */
+
+
+static void wpa_supplicant_start_autoscan(struct wpa_supplicant *wpa_s)
+{
+	if (autoscan_init(wpa_s, 0))
+		wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize autoscan");
+}
+
+
+static void wpa_supplicant_stop_autoscan(struct wpa_supplicant *wpa_s)
+{
+	autoscan_deinit(wpa_s);
+}
+
+
+void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->wpa_state == WPA_DISCONNECTED ||
+	    wpa_s->wpa_state == WPA_SCANNING) {
+		autoscan_deinit(wpa_s);
+		wpa_supplicant_start_autoscan(wpa_s);
+	}
+}
+
+
+/**
+ * wpa_supplicant_set_state - Set current connection state
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @state: The new connection state
+ *
+ * This function is called whenever the connection state changes, e.g.,
+ * association is completed for WPA/WPA2 4-Way Handshake is started.
+ */
+void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
+			      enum wpa_states state)
+{
+	enum wpa_states old_state = wpa_s->wpa_state;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "State: %s -> %s",
+		wpa_supplicant_state_txt(wpa_s->wpa_state),
+		wpa_supplicant_state_txt(state));
+
+	if (state != WPA_SCANNING)
+		wpa_supplicant_notify_scanning(wpa_s, 0);
+
+	if (state == WPA_COMPLETED && wpa_s->new_connection) {
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+		struct wpa_ssid *ssid = wpa_s->current_ssid;
+		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_CONNECTED "- Connection to "
+			MACSTR " completed [id=%d id_str=%s]",
+			MAC2STR(wpa_s->bssid),
+			ssid ? ssid->id : -1,
+			ssid && ssid->id_str ? ssid->id_str : "");
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+		wpas_clear_temp_disabled(wpa_s, ssid, 1);
+		wpa_s->extra_blacklist_count = 0;
+		wpa_s->new_connection = 0;
+		wpa_drv_set_operstate(wpa_s, 1);
+#ifndef IEEE8021X_EAPOL
+		wpa_drv_set_supp_port(wpa_s, 1);
+#endif /* IEEE8021X_EAPOL */
+		wpa_s->after_wps = 0;
+#ifdef CONFIG_P2P
+		wpas_p2p_completed(wpa_s);
+#endif /* CONFIG_P2P */
+
+		sme_sched_obss_scan(wpa_s, 1);
+	} else if (state == WPA_DISCONNECTED || state == WPA_ASSOCIATING ||
+		   state == WPA_ASSOCIATED) {
+		wpa_s->new_connection = 1;
+		wpa_drv_set_operstate(wpa_s, 0);
+#ifndef IEEE8021X_EAPOL
+		wpa_drv_set_supp_port(wpa_s, 0);
+#endif /* IEEE8021X_EAPOL */
+		sme_sched_obss_scan(wpa_s, 0);
+	}
+	wpa_s->wpa_state = state;
+
+#ifdef CONFIG_BGSCAN
+	if (state == WPA_COMPLETED)
+		wpa_supplicant_start_bgscan(wpa_s);
+	else
+		wpa_supplicant_stop_bgscan(wpa_s);
+#endif /* CONFIG_BGSCAN */
+
+	if (state == WPA_AUTHENTICATING)
+		wpa_supplicant_stop_autoscan(wpa_s);
+
+	if (state == WPA_DISCONNECTED || state == WPA_INACTIVE)
+		wpa_supplicant_start_autoscan(wpa_s);
+
+	if (wpa_s->wpa_state != old_state) {
+		wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
+
+		if (wpa_s->wpa_state == WPA_COMPLETED ||
+		    old_state == WPA_COMPLETED)
+			wpas_notify_auth_changed(wpa_s);
+	}
+}
+
+
+void wpa_supplicant_terminate_proc(struct wpa_global *global)
+{
+	int pending = 0;
+#ifdef CONFIG_WPS
+	struct wpa_supplicant *wpa_s = global->ifaces;
+	while (wpa_s) {
+		if (wpas_wps_terminate_pending(wpa_s) == 1)
+			pending = 1;
+		wpa_s = wpa_s->next;
+	}
+#endif /* CONFIG_WPS */
+	if (pending)
+		return;
+	eloop_terminate();
+}
+
+
+static void wpa_supplicant_terminate(int sig, void *signal_ctx)
+{
+	struct wpa_global *global = signal_ctx;
+	wpa_supplicant_terminate_proc(global);
+}
+
+
+void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s)
+{
+	enum wpa_states old_state = wpa_s->wpa_state;
+
+	wpa_s->pairwise_cipher = 0;
+	wpa_s->group_cipher = 0;
+	wpa_s->mgmt_group_cipher = 0;
+	wpa_s->key_mgmt = 0;
+	if (wpa_s->wpa_state != WPA_INTERFACE_DISABLED)
+		wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+
+	if (wpa_s->wpa_state != old_state)
+		wpas_notify_state_changed(wpa_s, wpa_s->wpa_state, old_state);
+}
+
+
+/**
+ * wpa_supplicant_reload_configuration - Reload configuration data
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success or -1 if configuration parsing failed
+ *
+ * This function can be used to request that the configuration data is reloaded
+ * (e.g., after configuration file change). This function is reloading
+ * configuration only for one interface, so this may need to be called multiple
+ * times if %wpa_supplicant is controlling multiple interfaces and all
+ * interfaces need reconfiguration.
+ */
+int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_config *conf;
+	int reconf_ctrl;
+	int old_ap_scan;
+
+	if (wpa_s->confname == NULL)
+		return -1;
+	conf = wpa_config_read(wpa_s->confname);
+	if (conf == NULL) {
+		wpa_msg(wpa_s, MSG_ERROR, "Failed to parse the configuration "
+			"file '%s' - exiting", wpa_s->confname);
+		return -1;
+	}
+	conf->changed_parameters = (unsigned int) -1;
+
+	reconf_ctrl = !!conf->ctrl_interface != !!wpa_s->conf->ctrl_interface
+		|| (conf->ctrl_interface && wpa_s->conf->ctrl_interface &&
+		    os_strcmp(conf->ctrl_interface,
+			      wpa_s->conf->ctrl_interface) != 0);
+
+	if (reconf_ctrl && wpa_s->ctrl_iface) {
+		wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+		wpa_s->ctrl_iface = NULL;
+	}
+
+	eapol_sm_invalidate_cached_session(wpa_s->eapol);
+	if (wpa_s->current_ssid) {
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+	}
+
+	/*
+	 * TODO: should notify EAPOL SM about changes in opensc_engine_path,
+	 * pkcs11_engine_path, pkcs11_module_path.
+	 */
+	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt)) {
+		/*
+		 * Clear forced success to clear EAP state for next
+		 * authentication.
+		 */
+		eapol_sm_notify_eap_success(wpa_s->eapol, FALSE);
+	}
+	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+	wpa_sm_set_config(wpa_s->wpa, NULL);
+	wpa_sm_pmksa_cache_flush(wpa_s->wpa, NULL);
+	wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
+	rsn_preauth_deinit(wpa_s->wpa);
+
+	old_ap_scan = wpa_s->conf->ap_scan;
+	wpa_config_free(wpa_s->conf);
+	wpa_s->conf = conf;
+	if (old_ap_scan != wpa_s->conf->ap_scan)
+		wpas_notify_ap_scan_changed(wpa_s);
+
+	if (reconf_ctrl)
+		wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
+
+	wpa_supplicant_update_config(wpa_s);
+
+	wpa_supplicant_clear_status(wpa_s);
+	if (wpa_supplicant_enabled_networks(wpa_s)) {
+		wpa_s->reassociate = 1;
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+	}
+	wpa_dbg(wpa_s, MSG_DEBUG, "Reconfiguration completed");
+	return 0;
+}
+
+
+static void wpa_supplicant_reconfig(int sig, void *signal_ctx)
+{
+	struct wpa_global *global = signal_ctx;
+	struct wpa_supplicant *wpa_s;
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Signal %d received - reconfiguring",
+			sig);
+		if (wpa_supplicant_reload_configuration(wpa_s) < 0) {
+			wpa_supplicant_terminate_proc(global);
+		}
+	}
+}
+
+
+enum wpa_cipher cipher_suite2driver(int cipher)
+{
+	switch (cipher) {
+	case WPA_CIPHER_NONE:
+		return CIPHER_NONE;
+	case WPA_CIPHER_WEP40:
+		return CIPHER_WEP40;
+	case WPA_CIPHER_WEP104:
+		return CIPHER_WEP104;
+	case WPA_CIPHER_CCMP:
+		return CIPHER_CCMP;
+	case WPA_CIPHER_GCMP:
+		return CIPHER_GCMP;
+	case WPA_CIPHER_TKIP:
+	default:
+		return CIPHER_TKIP;
+	}
+}
+
+
+enum wpa_key_mgmt key_mgmt2driver(int key_mgmt)
+{
+	switch (key_mgmt) {
+	case WPA_KEY_MGMT_NONE:
+		return KEY_MGMT_NONE;
+	case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
+		return KEY_MGMT_802_1X_NO_WPA;
+	case WPA_KEY_MGMT_IEEE8021X:
+		return KEY_MGMT_802_1X;
+	case WPA_KEY_MGMT_WPA_NONE:
+		return KEY_MGMT_WPA_NONE;
+	case WPA_KEY_MGMT_FT_IEEE8021X:
+		return KEY_MGMT_FT_802_1X;
+	case WPA_KEY_MGMT_FT_PSK:
+		return KEY_MGMT_FT_PSK;
+	case WPA_KEY_MGMT_IEEE8021X_SHA256:
+		return KEY_MGMT_802_1X_SHA256;
+	case WPA_KEY_MGMT_PSK_SHA256:
+		return KEY_MGMT_PSK_SHA256;
+	case WPA_KEY_MGMT_WPS:
+		return KEY_MGMT_WPS;
+	case WPA_KEY_MGMT_PSK:
+	default:
+		return KEY_MGMT_PSK;
+	}
+}
+
+
+static int wpa_supplicant_suites_from_ai(struct wpa_supplicant *wpa_s,
+					 struct wpa_ssid *ssid,
+					 struct wpa_ie_data *ie)
+{
+	int ret = wpa_sm_parse_own_wpa_ie(wpa_s->wpa, ie);
+	if (ret) {
+		if (ret == -2) {
+			wpa_msg(wpa_s, MSG_INFO, "WPA: Failed to parse WPA IE "
+				"from association info");
+		}
+		return -1;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Using WPA IE from AssocReq to set "
+		"cipher suites");
+	if (!(ie->group_cipher & ssid->group_cipher)) {
+		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled group "
+			"cipher 0x%x (mask 0x%x) - reject",
+			ie->group_cipher, ssid->group_cipher);
+		return -1;
+	}
+	if (!(ie->pairwise_cipher & ssid->pairwise_cipher)) {
+		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled pairwise "
+			"cipher 0x%x (mask 0x%x) - reject",
+			ie->pairwise_cipher, ssid->pairwise_cipher);
+		return -1;
+	}
+	if (!(ie->key_mgmt & ssid->key_mgmt)) {
+		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver used disabled key "
+			"management 0x%x (mask 0x%x) - reject",
+			ie->key_mgmt, ssid->key_mgmt);
+		return -1;
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (!(ie->capabilities & WPA_CAPABILITY_MFPC) &&
+	    (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+	     wpa_s->conf->pmf : ssid->ieee80211w) ==
+	    MGMT_FRAME_PROTECTION_REQUIRED) {
+		wpa_msg(wpa_s, MSG_INFO, "WPA: Driver associated with an AP "
+			"that does not support management frame protection - "
+			"reject");
+		return -1;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_set_suites - Set authentication and encryption parameters
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bss: Scan results for the selected BSS, or %NULL if not available
+ * @ssid: Configuration data for the selected network
+ * @wpa_ie: Buffer for the WPA/RSN IE
+ * @wpa_ie_len: Maximum wpa_ie buffer size on input. This is changed to be the
+ * used buffer length in case the functions returns success.
+ * Returns: 0 on success or -1 on failure
+ *
+ * This function is used to configure authentication and encryption parameters
+ * based on the network configuration and scan result for the selected BSS (if
+ * available).
+ */
+int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
+			      struct wpa_bss *bss, struct wpa_ssid *ssid,
+			      u8 *wpa_ie, size_t *wpa_ie_len)
+{
+	struct wpa_ie_data ie;
+	int sel, proto;
+	const u8 *bss_wpa, *bss_rsn;
+
+	if (bss) {
+		bss_wpa = wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+		bss_rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+	} else
+		bss_wpa = bss_rsn = NULL;
+
+	if (bss_rsn && (ssid->proto & WPA_PROTO_RSN) &&
+	    wpa_parse_wpa_ie(bss_rsn, 2 + bss_rsn[1], &ie) == 0 &&
+	    (ie.group_cipher & ssid->group_cipher) &&
+	    (ie.pairwise_cipher & ssid->pairwise_cipher) &&
+	    (ie.key_mgmt & ssid->key_mgmt)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
+		proto = WPA_PROTO_RSN;
+	} else if (bss_wpa && (ssid->proto & WPA_PROTO_WPA) &&
+		   wpa_parse_wpa_ie(bss_wpa, 2 +bss_wpa[1], &ie) == 0 &&
+		   (ie.group_cipher & ssid->group_cipher) &&
+		   (ie.pairwise_cipher & ssid->pairwise_cipher) &&
+		   (ie.key_mgmt & ssid->key_mgmt)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
+		proto = WPA_PROTO_WPA;
+	} else if (bss) {
+		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select WPA/RSN");
+		return -1;
+	} else {
+		if (ssid->proto & WPA_PROTO_RSN)
+			proto = WPA_PROTO_RSN;
+		else
+			proto = WPA_PROTO_WPA;
+		if (wpa_supplicant_suites_from_ai(wpa_s, ssid, &ie) < 0) {
+			os_memset(&ie, 0, sizeof(ie));
+			ie.group_cipher = ssid->group_cipher;
+			ie.pairwise_cipher = ssid->pairwise_cipher;
+			ie.key_mgmt = ssid->key_mgmt;
+#ifdef CONFIG_IEEE80211W
+			ie.mgmt_group_cipher =
+				ssid->ieee80211w != NO_MGMT_FRAME_PROTECTION ?
+				WPA_CIPHER_AES_128_CMAC : 0;
+#endif /* CONFIG_IEEE80211W */
+			wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Set cipher suites "
+				"based on configuration");
+		} else
+			proto = ie.proto;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected cipher suites: group %d "
+		"pairwise %d key_mgmt %d proto %d",
+		ie.group_cipher, ie.pairwise_cipher, ie.key_mgmt, proto);
+#ifdef CONFIG_IEEE80211W
+	if (ssid->ieee80211w) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected mgmt group cipher %d",
+			ie.mgmt_group_cipher);
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	wpa_s->wpa_proto = proto;
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PROTO, proto);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_RSN_ENABLED,
+			 !!(ssid->proto & WPA_PROTO_RSN));
+
+	if (bss || !wpa_s->ap_ies_from_associnfo) {
+		if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, bss_wpa,
+					 bss_wpa ? 2 + bss_wpa[1] : 0) ||
+		    wpa_sm_set_ap_rsn_ie(wpa_s->wpa, bss_rsn,
+					 bss_rsn ? 2 + bss_rsn[1] : 0))
+			return -1;
+	}
+
+	sel = ie.group_cipher & ssid->group_cipher;
+	if (sel & WPA_CIPHER_CCMP) {
+		wpa_s->group_cipher = WPA_CIPHER_CCMP;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK CCMP");
+	} else if (sel & WPA_CIPHER_GCMP) {
+		wpa_s->group_cipher = WPA_CIPHER_GCMP;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK GCMP");
+	} else if (sel & WPA_CIPHER_TKIP) {
+		wpa_s->group_cipher = WPA_CIPHER_TKIP;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK TKIP");
+	} else if (sel & WPA_CIPHER_WEP104) {
+		wpa_s->group_cipher = WPA_CIPHER_WEP104;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP104");
+	} else if (sel & WPA_CIPHER_WEP40) {
+		wpa_s->group_cipher = WPA_CIPHER_WEP40;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using GTK WEP40");
+	} else {
+		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select group "
+			"cipher");
+		return -1;
+	}
+
+	sel = ie.pairwise_cipher & ssid->pairwise_cipher;
+	if (sel & WPA_CIPHER_CCMP) {
+		wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK CCMP");
+	} else if (sel & WPA_CIPHER_GCMP) {
+		wpa_s->pairwise_cipher = WPA_CIPHER_GCMP;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK GCMP");
+	} else if (sel & WPA_CIPHER_TKIP) {
+		wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK TKIP");
+	} else if (sel & WPA_CIPHER_NONE) {
+		wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using PTK NONE");
+	} else {
+		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select pairwise "
+			"cipher");
+		return -1;
+	}
+
+	sel = ie.key_mgmt & ssid->key_mgmt;
+#ifdef CONFIG_SAE
+	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_SAE))
+		sel &= ~(WPA_KEY_MGMT_SAE | WPA_KEY_MGMT_FT_SAE);
+#endif /* CONFIG_SAE */
+	if (0) {
+#ifdef CONFIG_IEEE80211R
+	} else if (sel & WPA_KEY_MGMT_FT_IEEE8021X) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/802.1X");
+	} else if (sel & WPA_KEY_MGMT_FT_PSK) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_PSK;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT FT/PSK");
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+	} else if (sel & WPA_KEY_MGMT_SAE) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_SAE;
+		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT SAE");
+	} else if (sel & WPA_KEY_MGMT_FT_SAE) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_FT_SAE;
+		wpa_dbg(wpa_s, MSG_DEBUG, "RSN: using KEY_MGMT FT/SAE");
+#endif /* CONFIG_SAE */
+#ifdef CONFIG_IEEE80211W
+	} else if (sel & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"WPA: using KEY_MGMT 802.1X with SHA256");
+	} else if (sel & WPA_KEY_MGMT_PSK_SHA256) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
+		wpa_dbg(wpa_s, MSG_DEBUG,
+			"WPA: using KEY_MGMT PSK with SHA256");
+#endif /* CONFIG_IEEE80211W */
+	} else if (sel & WPA_KEY_MGMT_IEEE8021X) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT 802.1X");
+	} else if (sel & WPA_KEY_MGMT_PSK) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-PSK");
+	} else if (sel & WPA_KEY_MGMT_WPA_NONE) {
+		wpa_s->key_mgmt = WPA_KEY_MGMT_WPA_NONE;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using KEY_MGMT WPA-NONE");
+	} else {
+		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to select "
+			"authenticated key management type");
+		return -1;
+	}
+
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_KEY_MGMT, wpa_s->key_mgmt);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_PAIRWISE,
+			 wpa_s->pairwise_cipher);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_GROUP, wpa_s->group_cipher);
+
+#ifdef CONFIG_IEEE80211W
+	sel = ie.mgmt_group_cipher;
+	if ((ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+	     wpa_s->conf->pmf : ssid->ieee80211w) == NO_MGMT_FRAME_PROTECTION ||
+	    !(ie.capabilities & WPA_CAPABILITY_MFPC))
+		sel = 0;
+	if (sel & WPA_CIPHER_AES_128_CMAC) {
+		wpa_s->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: using MGMT group cipher "
+			"AES-128-CMAC");
+	} else {
+		wpa_s->mgmt_group_cipher = 0;
+		wpa_dbg(wpa_s, MSG_DEBUG, "WPA: not using MGMT group cipher");
+	}
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MGMT_GROUP,
+			 wpa_s->mgmt_group_cipher);
+	wpa_sm_set_param(wpa_s->wpa, WPA_PARAM_MFP,
+			 (ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+			  wpa_s->conf->pmf : ssid->ieee80211w));
+#endif /* CONFIG_IEEE80211W */
+
+	if (wpa_sm_set_assoc_wpa_ie_default(wpa_s->wpa, wpa_ie, wpa_ie_len)) {
+		wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to generate WPA IE");
+		return -1;
+	}
+
+	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt)) {
+		wpa_sm_set_pmk(wpa_s->wpa, ssid->psk, PMK_LEN);
+#ifndef CONFIG_NO_PBKDF2
+		if (bss && ssid->bssid_set && ssid->ssid_len == 0 &&
+		    ssid->passphrase) {
+			u8 psk[PMK_LEN];
+		        pbkdf2_sha1(ssid->passphrase, bss->ssid, bss->ssid_len,
+				    4096, psk, PMK_LEN);
+		        wpa_hexdump_key(MSG_MSGDUMP, "PSK (from passphrase)",
+					psk, PMK_LEN);
+			wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+		}
+#endif /* CONFIG_NO_PBKDF2 */
+#ifdef CONFIG_EXT_PASSWORD
+		if (ssid->ext_psk) {
+			struct wpabuf *pw = ext_password_get(wpa_s->ext_pw,
+							     ssid->ext_psk);
+			char pw_str[64 + 1];
+			u8 psk[PMK_LEN];
+
+			if (pw == NULL) {
+				wpa_msg(wpa_s, MSG_INFO, "EXT PW: No PSK "
+					"found from external storage");
+				return -1;
+			}
+
+			if (wpabuf_len(pw) < 8 || wpabuf_len(pw) > 64) {
+				wpa_msg(wpa_s, MSG_INFO, "EXT PW: Unexpected "
+					"PSK length %d in external storage",
+					(int) wpabuf_len(pw));
+				ext_password_free(pw);
+				return -1;
+			}
+
+			os_memcpy(pw_str, wpabuf_head(pw), wpabuf_len(pw));
+			pw_str[wpabuf_len(pw)] = '\0';
+
+#ifndef CONFIG_NO_PBKDF2
+			if (wpabuf_len(pw) >= 8 && wpabuf_len(pw) < 64 && bss)
+			{
+				pbkdf2_sha1(pw_str, bss->ssid, bss->ssid_len,
+					    4096, psk, PMK_LEN);
+				os_memset(pw_str, 0, sizeof(pw_str));
+				wpa_hexdump_key(MSG_MSGDUMP, "PSK (from "
+						"external passphrase)",
+						psk, PMK_LEN);
+				wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+			} else
+#endif /* CONFIG_NO_PBKDF2 */
+			if (wpabuf_len(pw) == 2 * PMK_LEN) {
+				if (hexstr2bin(pw_str, psk, PMK_LEN) < 0) {
+					wpa_msg(wpa_s, MSG_INFO, "EXT PW: "
+						"Invalid PSK hex string");
+					os_memset(pw_str, 0, sizeof(pw_str));
+					ext_password_free(pw);
+					return -1;
+				}
+				wpa_sm_set_pmk(wpa_s->wpa, psk, PMK_LEN);
+			} else {
+				wpa_msg(wpa_s, MSG_INFO, "EXT PW: No suitable "
+					"PSK available");
+				os_memset(pw_str, 0, sizeof(pw_str));
+				ext_password_free(pw);
+				return -1;
+			}
+
+			os_memset(pw_str, 0, sizeof(pw_str));
+			ext_password_free(pw);
+		}
+#endif /* CONFIG_EXT_PASSWORD */
+	} else
+		wpa_sm_set_pmk_from_pmksa(wpa_s->wpa);
+
+	return 0;
+}
+
+
+int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf)
+{
+	u32 ext_capab = 0;
+	u8 *pos = buf;
+
+#ifdef CONFIG_INTERWORKING
+	if (wpa_s->conf->interworking)
+		ext_capab |= BIT(31); /* Interworking */
+#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_WNM
+	ext_capab |= BIT(17); /* WNM-Sleep Mode */
+	ext_capab |= BIT(19); /* BSS Transition */
+#endif /* CONFIG_WNM */
+
+	if (!ext_capab)
+		return 0;
+
+	*pos++ = WLAN_EID_EXT_CAPAB;
+	*pos++ = 4;
+	WPA_PUT_LE32(pos, ext_capab);
+	pos += 4;
+
+	return pos - buf;
+}
+
+
+/**
+ * wpa_supplicant_associate - Request association
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @bss: Scan results for the selected BSS, or %NULL if not available
+ * @ssid: Configuration data for the selected network
+ *
+ * This function is used to request %wpa_supplicant to associate with a BSS.
+ */
+void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
+			      struct wpa_bss *bss, struct wpa_ssid *ssid)
+{
+	u8 wpa_ie[200];
+	size_t wpa_ie_len;
+	int use_crypt, ret, i, bssid_changed;
+	int algs = WPA_AUTH_ALG_OPEN;
+	enum wpa_cipher cipher_pairwise, cipher_group;
+	struct wpa_driver_associate_params params;
+	int wep_keys_set = 0;
+	struct wpa_driver_capa capa;
+	int assoc_failed = 0;
+	struct wpa_ssid *old_ssid;
+	u8 ext_capab[10];
+	int ext_capab_len;
+#ifdef CONFIG_HT_OVERRIDES
+	struct ieee80211_ht_capabilities htcaps;
+	struct ieee80211_ht_capabilities htcaps_mask;
+#endif /* CONFIG_HT_OVERRIDES */
+
+#ifdef CONFIG_IBSS_RSN
+	ibss_rsn_deinit(wpa_s->ibss_rsn);
+	wpa_s->ibss_rsn = NULL;
+#endif /* CONFIG_IBSS_RSN */
+
+	if (ssid->mode == WPAS_MODE_AP || ssid->mode == WPAS_MODE_P2P_GO ||
+	    ssid->mode == WPAS_MODE_P2P_GROUP_FORMATION) {
+#ifdef CONFIG_AP
+		if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_AP)) {
+			wpa_msg(wpa_s, MSG_INFO, "Driver does not support AP "
+				"mode");
+			return;
+		}
+		if (wpa_supplicant_create_ap(wpa_s, ssid) < 0) {
+			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+			return;
+		}
+		wpa_s->current_bss = bss;
+#else /* CONFIG_AP */
+		wpa_msg(wpa_s, MSG_ERROR, "AP mode support not included in "
+			"the build");
+#endif /* CONFIG_AP */
+		return;
+	}
+
+#ifdef CONFIG_TDLS
+	if (bss)
+		wpa_tdls_ap_ies(wpa_s->wpa, (const u8 *) (bss + 1),
+				bss->ie_len);
+#endif /* CONFIG_TDLS */
+
+	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME) &&
+	    ssid->mode == IEEE80211_MODE_INFRA) {
+		sme_authenticate(wpa_s, bss, ssid);
+		return;
+	}
+
+	os_memset(&params, 0, sizeof(params));
+	wpa_s->reassociate = 0;
+	if (bss && !wpas_driver_bss_selection(wpa_s)) {
+#ifdef CONFIG_IEEE80211R
+		const u8 *ie, *md = NULL;
+#endif /* CONFIG_IEEE80211R */
+		wpa_msg(wpa_s, MSG_INFO, "Trying to associate with " MACSTR
+			" (SSID='%s' freq=%d MHz)", MAC2STR(bss->bssid),
+			wpa_ssid_txt(bss->ssid, bss->ssid_len), bss->freq);
+		bssid_changed = !is_zero_ether_addr(wpa_s->bssid);
+		os_memset(wpa_s->bssid, 0, ETH_ALEN);
+		os_memcpy(wpa_s->pending_bssid, bss->bssid, ETH_ALEN);
+		if (bssid_changed)
+			wpas_notify_bssid_changed(wpa_s);
+#ifdef CONFIG_IEEE80211R
+		ie = wpa_bss_get_ie(bss, WLAN_EID_MOBILITY_DOMAIN);
+		if (ie && ie[1] >= MOBILITY_DOMAIN_ID_LEN)
+			md = ie + 2;
+		wpa_sm_set_ft_params(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0);
+		if (md) {
+			/* Prepare for the next transition */
+			wpa_ft_prepare_auth_request(wpa_s->wpa, ie);
+		}
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_WPS
+	} else if ((ssid->ssid == NULL || ssid->ssid_len == 0) &&
+		   wpa_s->conf->ap_scan == 2 &&
+		   (ssid->key_mgmt & WPA_KEY_MGMT_WPS)) {
+		/* Use ap_scan==1 style network selection to find the network
+		 */
+		wpa_s->scan_req = MANUAL_SCAN_REQ;
+		wpa_s->reassociate = 1;
+		wpa_supplicant_req_scan(wpa_s, 0, 0);
+		return;
+#endif /* CONFIG_WPS */
+	} else {
+		wpa_msg(wpa_s, MSG_INFO, "Trying to associate with SSID '%s'",
+			wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+		os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+	}
+	wpa_supplicant_cancel_sched_scan(wpa_s);
+	wpa_supplicant_cancel_scan(wpa_s);
+
+	/* Starting new association, so clear the possibly used WPA IE from the
+	 * previous association. */
+	wpa_sm_set_assoc_wpa_ie(wpa_s->wpa, NULL, 0);
+
+#ifdef IEEE8021X_EAPOL
+	if (ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		if (ssid->leap) {
+			if (ssid->non_leap == 0)
+				algs = WPA_AUTH_ALG_LEAP;
+			else
+				algs |= WPA_AUTH_ALG_LEAP;
+		}
+	}
+#endif /* IEEE8021X_EAPOL */
+	wpa_dbg(wpa_s, MSG_DEBUG, "Automatic auth_alg selection: 0x%x", algs);
+	if (ssid->auth_alg) {
+		algs = ssid->auth_alg;
+		wpa_dbg(wpa_s, MSG_DEBUG, "Overriding auth_alg selection: "
+			"0x%x", algs);
+	}
+
+	if (bss && (wpa_bss_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE) ||
+		    wpa_bss_get_ie(bss, WLAN_EID_RSN)) &&
+	    wpa_key_mgmt_wpa(ssid->key_mgmt)) {
+		int try_opportunistic;
+		try_opportunistic = (ssid->proactive_key_caching < 0 ?
+				     wpa_s->conf->okc :
+				     ssid->proactive_key_caching) &&
+			(ssid->proto & WPA_PROTO_RSN);
+		if (pmksa_cache_set_current(wpa_s->wpa, NULL, bss->bssid,
+					    wpa_s->current_ssid,
+					    try_opportunistic) == 0)
+			eapol_sm_notify_pmkid_attempt(wpa_s->eapol, 1);
+		wpa_ie_len = sizeof(wpa_ie);
+		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
+					      wpa_ie, &wpa_ie_len)) {
+			wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
+				"key management and encryption suites");
+			return;
+		}
+	} else if ((ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA) && bss &&
+		   wpa_key_mgmt_wpa_ieee8021x(ssid->key_mgmt)) {
+		/*
+		 * Both WPA and non-WPA IEEE 802.1X enabled in configuration -
+		 * use non-WPA since the scan results did not indicate that the
+		 * AP is using WPA or WPA2.
+		 */
+		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+		wpa_ie_len = 0;
+		wpa_s->wpa_proto = 0;
+	} else if (wpa_key_mgmt_wpa_any(ssid->key_mgmt)) {
+		wpa_ie_len = sizeof(wpa_ie);
+		if (wpa_supplicant_set_suites(wpa_s, NULL, ssid,
+					      wpa_ie, &wpa_ie_len)) {
+			wpa_msg(wpa_s, MSG_WARNING, "WPA: Failed to set WPA "
+				"key management and encryption suites (no "
+				"scan results)");
+			return;
+		}
+#ifdef CONFIG_WPS
+	} else if (ssid->key_mgmt & WPA_KEY_MGMT_WPS) {
+		struct wpabuf *wps_ie;
+		wps_ie = wps_build_assoc_req_ie(wpas_wps_get_req_type(ssid));
+		if (wps_ie && wpabuf_len(wps_ie) <= sizeof(wpa_ie)) {
+			wpa_ie_len = wpabuf_len(wps_ie);
+			os_memcpy(wpa_ie, wpabuf_head(wps_ie), wpa_ie_len);
+		} else
+			wpa_ie_len = 0;
+		wpabuf_free(wps_ie);
+		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+		if (!bss || (bss->caps & IEEE80211_CAP_PRIVACY))
+			params.wps = WPS_MODE_PRIVACY;
+		else
+			params.wps = WPS_MODE_OPEN;
+		wpa_s->wpa_proto = 0;
+#endif /* CONFIG_WPS */
+	} else {
+		wpa_supplicant_set_non_wpa_policy(wpa_s, ssid);
+		wpa_ie_len = 0;
+		wpa_s->wpa_proto = 0;
+	}
+
+#ifdef CONFIG_P2P
+	if (wpa_s->global->p2p) {
+		u8 *pos;
+		size_t len;
+		int res;
+		pos = wpa_ie + wpa_ie_len;
+		len = sizeof(wpa_ie) - wpa_ie_len;
+		res = wpas_p2p_assoc_req_ie(wpa_s, bss, pos, len,
+					    ssid->p2p_group);
+		if (res >= 0)
+			wpa_ie_len += res;
+	}
+
+	wpa_s->cross_connect_disallowed = 0;
+	if (bss) {
+		struct wpabuf *p2p;
+		p2p = wpa_bss_get_vendor_ie_multi(bss, P2P_IE_VENDOR_TYPE);
+		if (p2p) {
+			wpa_s->cross_connect_disallowed =
+				p2p_get_cross_connect_disallowed(p2p);
+			wpabuf_free(p2p);
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: WLAN AP %s cross "
+				"connection",
+				wpa_s->cross_connect_disallowed ?
+				"disallows" : "allows");
+		}
+	}
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_HS20
+	if (wpa_s->conf->hs20) {
+		struct wpabuf *hs20;
+		hs20 = wpabuf_alloc(20);
+		if (hs20) {
+			wpas_hs20_add_indication(hs20);
+			os_memcpy(wpa_ie + wpa_ie_len, wpabuf_head(hs20),
+				  wpabuf_len(hs20));
+			wpa_ie_len += wpabuf_len(hs20);
+			wpabuf_free(hs20);
+		}
+	}
+#endif /* CONFIG_HS20 */
+
+	ext_capab_len = wpas_build_ext_capab(wpa_s, ext_capab);
+	if (ext_capab_len > 0) {
+		u8 *pos = wpa_ie;
+		if (wpa_ie_len > 0 && pos[0] == WLAN_EID_RSN)
+			pos += 2 + pos[1];
+		os_memmove(pos + ext_capab_len, pos,
+			   wpa_ie_len - (pos - wpa_ie));
+		wpa_ie_len += ext_capab_len;
+		os_memcpy(pos, ext_capab, ext_capab_len);
+	}
+
+	wpa_clear_keys(wpa_s, bss ? bss->bssid : NULL);
+	use_crypt = 1;
+	cipher_pairwise = cipher_suite2driver(wpa_s->pairwise_cipher);
+	cipher_group = cipher_suite2driver(wpa_s->group_cipher);
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE ||
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE)
+			use_crypt = 0;
+		if (wpa_set_wep_keys(wpa_s, ssid)) {
+			use_crypt = 1;
+			wep_keys_set = 1;
+		}
+	}
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPS)
+		use_crypt = 0;
+
+#ifdef IEEE8021X_EAPOL
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		if ((ssid->eapol_flags &
+		     (EAPOL_FLAG_REQUIRE_KEY_UNICAST |
+		      EAPOL_FLAG_REQUIRE_KEY_BROADCAST)) == 0 &&
+		    !wep_keys_set) {
+			use_crypt = 0;
+		} else {
+			/* Assume that dynamic WEP-104 keys will be used and
+			 * set cipher suites in order for drivers to expect
+			 * encryption. */
+			cipher_pairwise = cipher_group = CIPHER_WEP104;
+		}
+	}
+#endif /* IEEE8021X_EAPOL */
+
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
+		/* Set the key before (and later after) association */
+		wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
+	}
+
+	wpa_supplicant_set_state(wpa_s, WPA_ASSOCIATING);
+	if (bss) {
+		params.ssid = bss->ssid;
+		params.ssid_len = bss->ssid_len;
+		if (!wpas_driver_bss_selection(wpa_s) || ssid->bssid_set) {
+			wpa_printf(MSG_DEBUG, "Limit connection to BSSID "
+				   MACSTR " freq=%u MHz based on scan results "
+				   "(bssid_set=%d)",
+				   MAC2STR(bss->bssid), bss->freq,
+				   ssid->bssid_set);
+			params.bssid = bss->bssid;
+			params.freq = bss->freq;
+		}
+	} else {
+		params.ssid = ssid->ssid;
+		params.ssid_len = ssid->ssid_len;
+	}
+
+	if (ssid->mode == WPAS_MODE_IBSS && ssid->bssid_set &&
+	    wpa_s->conf->ap_scan == 2) {
+		params.bssid = ssid->bssid;
+		params.fixed_bssid = 1;
+	}
+
+	if (ssid->mode == WPAS_MODE_IBSS && ssid->frequency > 0 &&
+	    params.freq == 0)
+		params.freq = ssid->frequency; /* Initial channel for IBSS */
+	params.wpa_ie = wpa_ie;
+	params.wpa_ie_len = wpa_ie_len;
+	params.pairwise_suite = cipher_pairwise;
+	params.group_suite = cipher_group;
+	params.key_mgmt_suite = key_mgmt2driver(wpa_s->key_mgmt);
+	params.wpa_proto = wpa_s->wpa_proto;
+	params.auth_alg = algs;
+	params.mode = ssid->mode;
+	params.bg_scan_period = ssid->bg_scan_period;
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		if (ssid->wep_key_len[i])
+			params.wep_key[i] = ssid->wep_key[i];
+		params.wep_key_len[i] = ssid->wep_key_len[i];
+	}
+	params.wep_tx_keyidx = ssid->wep_tx_keyidx;
+
+	if ((wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) &&
+	    (params.key_mgmt_suite == KEY_MGMT_PSK ||
+	     params.key_mgmt_suite == KEY_MGMT_FT_PSK)) {
+		params.passphrase = ssid->passphrase;
+		if (ssid->psk_set)
+			params.psk = ssid->psk;
+	}
+
+	params.drop_unencrypted = use_crypt;
+
+#ifdef CONFIG_IEEE80211W
+	params.mgmt_frame_protection =
+		ssid->ieee80211w == MGMT_FRAME_PROTECTION_DEFAULT ?
+		wpa_s->conf->pmf : ssid->ieee80211w;
+	if (params.mgmt_frame_protection != NO_MGMT_FRAME_PROTECTION && bss) {
+		const u8 *rsn = wpa_bss_get_ie(bss, WLAN_EID_RSN);
+		struct wpa_ie_data ie;
+		if (rsn && wpa_parse_wpa_ie(rsn, 2 + rsn[1], &ie) == 0 &&
+		    ie.capabilities &
+		    (WPA_CAPABILITY_MFPC | WPA_CAPABILITY_MFPR)) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "WPA: Selected AP supports "
+				"MFP: require MFP");
+			params.mgmt_frame_protection =
+				MGMT_FRAME_PROTECTION_REQUIRED;
+		}
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	params.p2p = ssid->p2p_group;
+
+	if (wpa_s->parent->set_sta_uapsd)
+		params.uapsd = wpa_s->parent->sta_uapsd;
+	else
+		params.uapsd = -1;
+
+#ifdef CONFIG_HT_OVERRIDES
+	os_memset(&htcaps, 0, sizeof(htcaps));
+	os_memset(&htcaps_mask, 0, sizeof(htcaps_mask));
+	params.htcaps = (u8 *) &htcaps;
+	params.htcaps_mask = (u8 *) &htcaps_mask;
+	wpa_supplicant_apply_ht_overrides(wpa_s, ssid, &params);
+#endif /* CONFIG_HT_OVERRIDES */
+
+	ret = wpa_drv_associate(wpa_s, &params);
+	if (ret < 0) {
+		wpa_msg(wpa_s, MSG_INFO, "Association request to the driver "
+			"failed");
+		if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SANE_ERROR_CODES) {
+			/*
+			 * The driver is known to mean what is saying, so we
+			 * can stop right here; the association will not
+			 * succeed.
+			 */
+			wpas_connection_failed(wpa_s, wpa_s->pending_bssid);
+			wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+			os_memset(wpa_s->pending_bssid, 0, ETH_ALEN);
+			return;
+		}
+		/* try to continue anyway; new association will be tried again
+		 * after timeout */
+		assoc_failed = 1;
+	}
+
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_WPA_NONE) {
+		/* Set the key after the association just in case association
+		 * cleared the previously configured key. */
+		wpa_supplicant_set_wpa_none_key(wpa_s, ssid);
+		/* No need to timeout authentication since there is no key
+		 * management. */
+		wpa_supplicant_cancel_auth_timeout(wpa_s);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+#ifdef CONFIG_IBSS_RSN
+	} else if (ssid->mode == WPAS_MODE_IBSS &&
+		   wpa_s->key_mgmt != WPA_KEY_MGMT_NONE &&
+		   wpa_s->key_mgmt != WPA_KEY_MGMT_WPA_NONE) {
+		/*
+		 * RSN IBSS authentication is per-STA and we can disable the
+		 * per-BSSID authentication.
+		 */
+		wpa_supplicant_cancel_auth_timeout(wpa_s);
+#endif /* CONFIG_IBSS_RSN */
+	} else {
+		/* Timeout for IEEE 802.11 authentication and association */
+		int timeout = 60;
+
+		if (assoc_failed) {
+			/* give IBSS a bit more time */
+			timeout = ssid->mode == WPAS_MODE_IBSS ? 10 : 5;
+		} else if (wpa_s->conf->ap_scan == 1) {
+			/* give IBSS a bit more time */
+			timeout = ssid->mode == WPAS_MODE_IBSS ? 20 : 10;
+		}
+		wpa_supplicant_req_auth_timeout(wpa_s, timeout, 0);
+	}
+
+	if (wep_keys_set && wpa_drv_get_capa(wpa_s, &capa) == 0 &&
+	    capa.flags & WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC) {
+		/* Set static WEP keys again */
+		wpa_set_wep_keys(wpa_s, ssid);
+	}
+
+	if (wpa_s->current_ssid && wpa_s->current_ssid != ssid) {
+		/*
+		 * Do not allow EAP session resumption between different
+		 * network configurations.
+		 */
+		eapol_sm_invalidate_cached_session(wpa_s->eapol);
+	}
+	old_ssid = wpa_s->current_ssid;
+	wpa_s->current_ssid = ssid;
+	wpa_s->current_bss = bss;
+	wpa_supplicant_rsn_supp_set_config(wpa_s, wpa_s->current_ssid);
+	wpa_supplicant_initiate_eapol(wpa_s);
+	if (old_ssid != wpa_s->current_ssid)
+		wpas_notify_network_changed(wpa_s);
+}
+
+
+static void wpa_supplicant_clear_connection(struct wpa_supplicant *wpa_s,
+					    const u8 *addr)
+{
+	struct wpa_ssid *old_ssid;
+
+	wpa_clear_keys(wpa_s, addr);
+	old_ssid = wpa_s->current_ssid;
+	wpa_supplicant_mark_disassoc(wpa_s);
+	wpa_sm_set_config(wpa_s->wpa, NULL);
+	eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
+	if (old_ssid != wpa_s->current_ssid)
+		wpas_notify_network_changed(wpa_s);
+	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+}
+
+
+/**
+ * wpa_supplicant_deauthenticate - Deauthenticate the current connection
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @reason_code: IEEE 802.11 reason code for the deauthenticate frame
+ *
+ * This function is used to request %wpa_supplicant to deauthenticate from the
+ * current AP.
+ */
+void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
+				   int reason_code)
+{
+	u8 *addr = NULL;
+	union wpa_event_data event;
+	int zero_addr = 0;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Request to deauthenticate - bssid=" MACSTR
+		" pending_bssid=" MACSTR " reason=%d state=%s",
+		MAC2STR(wpa_s->bssid), MAC2STR(wpa_s->pending_bssid),
+		reason_code, wpa_supplicant_state_txt(wpa_s->wpa_state));
+
+	if (!is_zero_ether_addr(wpa_s->bssid))
+		addr = wpa_s->bssid;
+	else if (!is_zero_ether_addr(wpa_s->pending_bssid) &&
+		 (wpa_s->wpa_state == WPA_AUTHENTICATING ||
+		  wpa_s->wpa_state == WPA_ASSOCIATING))
+		addr = wpa_s->pending_bssid;
+	else if (wpa_s->wpa_state == WPA_ASSOCIATING) {
+		/*
+		 * When using driver-based BSS selection, we may not know the
+		 * BSSID with which we are currently trying to associate. We
+		 * need to notify the driver of this disconnection even in such
+		 * a case, so use the all zeros address here.
+		 */
+		addr = wpa_s->bssid;
+		zero_addr = 1;
+	}
+
+	if (addr) {
+		wpa_drv_deauthenticate(wpa_s, addr, reason_code);
+		os_memset(&event, 0, sizeof(event));
+		event.deauth_info.reason_code = (u16) reason_code;
+		event.deauth_info.locally_generated = 1;
+		wpa_supplicant_event(wpa_s, EVENT_DEAUTH, &event);
+		if (zero_addr)
+			addr = NULL;
+	}
+
+	wpa_supplicant_clear_connection(wpa_s, addr);
+}
+
+
+/**
+ * wpa_supplicant_enable_network - Mark a configured network as enabled
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network or %NULL
+ *
+ * Enables the specified network or all networks if no network specified.
+ */
+void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid)
+{
+	struct wpa_ssid *other_ssid;
+	int was_disabled;
+
+	if (ssid == NULL) {
+		for (other_ssid = wpa_s->conf->ssid; other_ssid;
+		     other_ssid = other_ssid->next) {
+			if (other_ssid->disabled == 2)
+				continue; /* do not change persistent P2P group
+					   * data */
+			if (other_ssid == wpa_s->current_ssid &&
+			    other_ssid->disabled)
+				wpa_s->reassociate = 1;
+
+			was_disabled = other_ssid->disabled;
+
+			other_ssid->disabled = 0;
+			if (was_disabled)
+				wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
+
+			if (was_disabled != other_ssid->disabled)
+				wpas_notify_network_enabled_changed(
+					wpa_s, other_ssid);
+		}
+		if (wpa_s->reassociate)
+			wpa_supplicant_req_scan(wpa_s, 0, 0);
+	} else if (ssid->disabled && ssid->disabled != 2) {
+		if (wpa_s->current_ssid == NULL) {
+			/*
+			 * Try to reassociate since there is no current
+			 * configuration and a new network was made available.
+			 */
+			wpa_s->reassociate = 1;
+			wpa_supplicant_req_scan(wpa_s, 0, 0);
+		}
+
+		was_disabled = ssid->disabled;
+
+		ssid->disabled = 0;
+		wpas_clear_temp_disabled(wpa_s, ssid, 1);
+
+		if (was_disabled != ssid->disabled)
+			wpas_notify_network_enabled_changed(wpa_s, ssid);
+	}
+}
+
+
+/**
+ * wpa_supplicant_disable_network - Mark a configured network as disabled
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network or %NULL
+ *
+ * Disables the specified network or all networks if no network specified.
+ */
+void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
+				    struct wpa_ssid *ssid)
+{
+	struct wpa_ssid *other_ssid;
+	int was_disabled;
+
+	if (ssid == NULL) {
+		for (other_ssid = wpa_s->conf->ssid; other_ssid;
+		     other_ssid = other_ssid->next) {
+			was_disabled = other_ssid->disabled;
+			if (was_disabled == 2)
+				continue; /* do not change persistent P2P group
+					   * data */
+
+			other_ssid->disabled = 1;
+
+			if (was_disabled != other_ssid->disabled)
+				wpas_notify_network_enabled_changed(
+					wpa_s, other_ssid);
+		}
+		if (wpa_s->current_ssid)
+			wpa_supplicant_deauthenticate(
+				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+	} else if (ssid->disabled != 2) {
+		if (ssid == wpa_s->current_ssid)
+			wpa_supplicant_deauthenticate(
+				wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+
+		was_disabled = ssid->disabled;
+
+		ssid->disabled = 1;
+
+		if (was_disabled != ssid->disabled)
+			wpas_notify_network_enabled_changed(wpa_s, ssid);
+	}
+}
+
+
+/**
+ * wpa_supplicant_select_network - Attempt association with a network
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ssid: wpa_ssid structure for a configured network or %NULL for any network
+ */
+void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid)
+{
+
+	struct wpa_ssid *other_ssid;
+	int disconnected = 0;
+
+	if (ssid && ssid != wpa_s->current_ssid && wpa_s->current_ssid) {
+		wpa_supplicant_deauthenticate(
+			wpa_s, WLAN_REASON_DEAUTH_LEAVING);
+		disconnected = 1;
+	}
+
+	if (ssid)
+		wpas_clear_temp_disabled(wpa_s, ssid, 1);
+
+	/*
+	 * Mark all other networks disabled or mark all networks enabled if no
+	 * network specified.
+	 */
+	for (other_ssid = wpa_s->conf->ssid; other_ssid;
+	     other_ssid = other_ssid->next) {
+		int was_disabled = other_ssid->disabled;
+		if (was_disabled == 2)
+			continue; /* do not change persistent P2P group data */
+
+		other_ssid->disabled = ssid ? (ssid->id != other_ssid->id) : 0;
+		if (was_disabled && !other_ssid->disabled)
+			wpas_clear_temp_disabled(wpa_s, other_ssid, 0);
+
+		if (was_disabled != other_ssid->disabled)
+			wpas_notify_network_enabled_changed(wpa_s, other_ssid);
+	}
+
+	if (ssid && ssid == wpa_s->current_ssid && wpa_s->current_ssid) {
+		/* We are already associated with the selected network */
+		wpa_printf(MSG_DEBUG, "Already associated with the "
+			   "selected network - do nothing");
+		return;
+	}
+
+	if (ssid)
+		wpa_s->current_ssid = ssid;
+	wpa_s->connect_without_scan = NULL;
+	wpa_s->disconnected = 0;
+	wpa_s->reassociate = 1;
+	wpa_supplicant_req_scan(wpa_s, 0, disconnected ? 100000 : 0);
+
+	if (ssid)
+		wpas_notify_network_selected(wpa_s, ssid);
+}
+
+
+/**
+ * wpa_supplicant_set_ap_scan - Set AP scan mode for interface
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @ap_scan: AP scan mode
+ * Returns: 0 if succeed or -1 if ap_scan has an invalid value
+ *
+ */
+int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s, int ap_scan)
+{
+
+	int old_ap_scan;
+
+	if (ap_scan < 0 || ap_scan > 2)
+		return -1;
+
+#ifdef ANDROID
+	if (ap_scan == 2 && ap_scan != wpa_s->conf->ap_scan &&
+	    wpa_s->wpa_state >= WPA_ASSOCIATING &&
+	    wpa_s->wpa_state < WPA_COMPLETED) {
+		wpa_printf(MSG_ERROR, "ap_scan = %d (%d) rejected while "
+			   "associating", wpa_s->conf->ap_scan, ap_scan);
+		return 0;
+	}
+#endif /* ANDROID */
+
+	old_ap_scan = wpa_s->conf->ap_scan;
+	wpa_s->conf->ap_scan = ap_scan;
+
+	if (old_ap_scan != wpa_s->conf->ap_scan)
+		wpas_notify_ap_scan_changed(wpa_s);
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_set_bss_expiration_age - Set BSS entry expiration age
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @expire_age: Expiration age in seconds
+ * Returns: 0 if succeed or -1 if expire_age has an invalid value
+ *
+ */
+int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s,
+					  unsigned int bss_expire_age)
+{
+	if (bss_expire_age < 10) {
+		wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration age %u",
+			bss_expire_age);
+		return -1;
+	}
+	wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration age: %d sec",
+		bss_expire_age);
+	wpa_s->conf->bss_expiration_age = bss_expire_age;
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_set_bss_expiration_count - Set BSS entry expiration scan count
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @expire_count: number of scans after which an unseen BSS is reclaimed
+ * Returns: 0 if succeed or -1 if expire_count has an invalid value
+ *
+ */
+int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
+					    unsigned int bss_expire_count)
+{
+	if (bss_expire_count < 1) {
+		wpa_msg(wpa_s, MSG_ERROR, "Invalid bss expiration count %u",
+			bss_expire_count);
+		return -1;
+	}
+	wpa_msg(wpa_s, MSG_DEBUG, "Setting bss expiration scan count: %u",
+		bss_expire_count);
+	wpa_s->conf->bss_expiration_scan_count = bss_expire_count;
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_set_scan_interval - Set scan interval
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * @scan_interval: scan interval in seconds
+ * Returns: 0 if succeed or -1 if scan_interval has an invalid value
+ *
+ */
+int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
+				     int scan_interval)
+{
+	if (scan_interval < 0) {
+		wpa_msg(wpa_s, MSG_ERROR, "Invalid scan interval %d",
+			scan_interval);
+		return -1;
+	}
+	wpa_msg(wpa_s, MSG_DEBUG, "Setting scan interval: %d sec",
+		scan_interval);
+	wpa_s->scan_interval = scan_interval;
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_set_debug_params - Set global debug params
+ * @global: wpa_global structure
+ * @debug_level: debug level
+ * @debug_timestamp: determines if show timestamp in debug data
+ * @debug_show_keys: determines if show keys in debug data
+ * Returns: 0 if succeed or -1 if debug_level has wrong value
+ */
+int wpa_supplicant_set_debug_params(struct wpa_global *global, int debug_level,
+				    int debug_timestamp, int debug_show_keys)
+{
+
+	int old_level, old_timestamp, old_show_keys;
+
+	/* check for allowed debuglevels */
+	if (debug_level != MSG_EXCESSIVE &&
+	    debug_level != MSG_MSGDUMP &&
+	    debug_level != MSG_DEBUG &&
+	    debug_level != MSG_INFO &&
+	    debug_level != MSG_WARNING &&
+	    debug_level != MSG_ERROR)
+		return -1;
+
+	old_level = wpa_debug_level;
+	old_timestamp = wpa_debug_timestamp;
+	old_show_keys = wpa_debug_show_keys;
+
+	wpa_debug_level = debug_level;
+	wpa_debug_timestamp = debug_timestamp ? 1 : 0;
+	wpa_debug_show_keys = debug_show_keys ? 1 : 0;
+
+	if (wpa_debug_level != old_level)
+		wpas_notify_debug_level_changed(global);
+	if (wpa_debug_timestamp != old_timestamp)
+		wpas_notify_debug_timestamp_changed(global);
+	if (wpa_debug_show_keys != old_show_keys)
+		wpas_notify_debug_show_keys_changed(global);
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_get_ssid - Get a pointer to the current network structure
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: A pointer to the current network structure or %NULL on failure
+ */
+struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *entry;
+	u8 ssid[MAX_SSID_LEN];
+	int res;
+	size_t ssid_len;
+	u8 bssid[ETH_ALEN];
+	int wired;
+
+	res = wpa_drv_get_ssid(wpa_s, ssid);
+	if (res < 0) {
+		wpa_msg(wpa_s, MSG_WARNING, "Could not read SSID from "
+			"driver");
+		return NULL;
+	}
+	ssid_len = res;
+
+	if (wpa_drv_get_bssid(wpa_s, bssid) < 0) {
+		wpa_msg(wpa_s, MSG_WARNING, "Could not read BSSID from "
+			"driver");
+		return NULL;
+	}
+
+	wired = wpa_s->conf->ap_scan == 0 &&
+		(wpa_s->drv_flags & WPA_DRIVER_FLAGS_WIRED);
+
+	entry = wpa_s->conf->ssid;
+	while (entry) {
+		if (!wpas_network_disabled(wpa_s, entry) &&
+		    ((ssid_len == entry->ssid_len &&
+		      os_memcmp(ssid, entry->ssid, ssid_len) == 0) || wired) &&
+		    (!entry->bssid_set ||
+		     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
+			return entry;
+#ifdef CONFIG_WPS
+		if (!wpas_network_disabled(wpa_s, entry) &&
+		    (entry->key_mgmt & WPA_KEY_MGMT_WPS) &&
+		    (entry->ssid == NULL || entry->ssid_len == 0) &&
+		    (!entry->bssid_set ||
+		     os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0))
+			return entry;
+#endif /* CONFIG_WPS */
+
+		if (!wpas_network_disabled(wpa_s, entry) && entry->bssid_set &&
+		    entry->ssid_len == 0 &&
+		    os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)
+			return entry;
+
+		entry = entry->next;
+	}
+
+	return NULL;
+}
+
+
+static int select_driver(struct wpa_supplicant *wpa_s, int i)
+{
+	struct wpa_global *global = wpa_s->global;
+
+	if (wpa_drivers[i]->global_init && global->drv_priv[i] == NULL) {
+		global->drv_priv[i] = wpa_drivers[i]->global_init();
+		if (global->drv_priv[i] == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to initialize driver "
+				   "'%s'", wpa_drivers[i]->name);
+			return -1;
+		}
+	}
+
+	wpa_s->driver = wpa_drivers[i];
+	wpa_s->global_drv_priv = global->drv_priv[i];
+
+	return 0;
+}
+
+
+static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
+				     const char *name)
+{
+	int i;
+	size_t len;
+	const char *pos, *driver = name;
+
+	if (wpa_s == NULL)
+		return -1;
+
+	if (wpa_drivers[0] == NULL) {
+		wpa_msg(wpa_s, MSG_ERROR, "No driver interfaces build into "
+			"wpa_supplicant");
+		return -1;
+	}
+
+	if (name == NULL) {
+		/* default to first driver in the list */
+		return select_driver(wpa_s, 0);
+	}
+
+	do {
+		pos = os_strchr(driver, ',');
+		if (pos)
+			len = pos - driver;
+		else
+			len = os_strlen(driver);
+
+		for (i = 0; wpa_drivers[i]; i++) {
+			if (os_strlen(wpa_drivers[i]->name) == len &&
+			    os_strncmp(driver, wpa_drivers[i]->name, len) ==
+			    0) {
+				/* First driver that succeeds wins */
+				if (select_driver(wpa_s, i) == 0)
+					return 0;
+			}
+		}
+
+		driver = pos + 1;
+	} while (pos);
+
+	wpa_msg(wpa_s, MSG_ERROR, "Unsupported driver '%s'", name);
+	return -1;
+}
+
+
+/**
+ * wpa_supplicant_rx_eapol - Deliver a received EAPOL frame to wpa_supplicant
+ * @ctx: Context pointer (wpa_s); this is the ctx variable registered
+ *	with struct wpa_driver_ops::init()
+ * @src_addr: Source address of the EAPOL frame
+ * @buf: EAPOL data starting from the EAPOL header (i.e., no Ethernet header)
+ * @len: Length of the EAPOL data
+ *
+ * This function is called for each received EAPOL frame. Most driver
+ * interfaces rely on more generic OS mechanism for receiving frames through
+ * l2_packet, but if such a mechanism is not available, the driver wrapper may
+ * take care of received EAPOL frames and deliver them to the core supplicant
+ * code by calling this function.
+ */
+void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
+			     const u8 *buf, size_t len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
+	wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
+
+	if (wpa_s->wpa_state < WPA_ASSOCIATED ||
+	    (wpa_s->last_eapol_matches_bssid &&
+#ifdef CONFIG_AP
+	     !wpa_s->ap_iface &&
+#endif /* CONFIG_AP */
+	     os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) != 0)) {
+		/*
+		 * There is possible race condition between receiving the
+		 * association event and the EAPOL frame since they are coming
+		 * through different paths from the driver. In order to avoid
+		 * issues in trying to process the EAPOL frame before receiving
+		 * association information, lets queue it for processing until
+		 * the association event is received. This may also be needed in
+		 * driver-based roaming case, so also use src_addr != BSSID as a
+		 * trigger if we have previously confirmed that the
+		 * Authenticator uses BSSID as the src_addr (which is not the
+		 * case with wired IEEE 802.1X).
+		 */
+		wpa_dbg(wpa_s, MSG_DEBUG, "Not associated - Delay processing "
+			"of received EAPOL frame (state=%s bssid=" MACSTR ")",
+			wpa_supplicant_state_txt(wpa_s->wpa_state),
+			MAC2STR(wpa_s->bssid));
+		wpabuf_free(wpa_s->pending_eapol_rx);
+		wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
+		if (wpa_s->pending_eapol_rx) {
+			os_get_time(&wpa_s->pending_eapol_rx_time);
+			os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
+				  ETH_ALEN);
+		}
+		return;
+	}
+
+	wpa_s->last_eapol_matches_bssid =
+		os_memcmp(src_addr, wpa_s->bssid, ETH_ALEN) == 0;
+
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface) {
+		wpa_supplicant_ap_rx_eapol(wpa_s, src_addr, buf, len);
+		return;
+	}
+#endif /* CONFIG_AP */
+
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Ignored received EAPOL frame since "
+			"no key management is configured");
+		return;
+	}
+
+	if (wpa_s->eapol_received == 0 &&
+	    (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE) ||
+	     !wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
+	     wpa_s->wpa_state != WPA_COMPLETED) &&
+	    (wpa_s->current_ssid == NULL ||
+	     wpa_s->current_ssid->mode != IEEE80211_MODE_IBSS)) {
+		/* Timeout for completing IEEE 802.1X and WPA authentication */
+		wpa_supplicant_req_auth_timeout(
+			wpa_s,
+			(wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) ||
+			 wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA ||
+			 wpa_s->key_mgmt == WPA_KEY_MGMT_WPS) ?
+			70 : 10, 0);
+	}
+	wpa_s->eapol_received++;
+
+	if (wpa_s->countermeasures) {
+		wpa_msg(wpa_s, MSG_INFO, "WPA: Countermeasures - dropped "
+			"EAPOL packet");
+		return;
+	}
+
+#ifdef CONFIG_IBSS_RSN
+	if (wpa_s->current_ssid &&
+	    wpa_s->current_ssid->mode == WPAS_MODE_IBSS) {
+		ibss_rsn_rx_eapol(wpa_s->ibss_rsn, src_addr, buf, len);
+		return;
+	}
+#endif /* CONFIG_IBSS_RSN */
+
+	/* Source address of the incoming EAPOL frame could be compared to the
+	 * current BSSID. However, it is possible that a centralized
+	 * Authenticator could be using another MAC address than the BSSID of
+	 * an AP, so just allow any address to be used for now. The replies are
+	 * still sent to the current BSSID (if available), though. */
+
+	os_memcpy(wpa_s->last_eapol_src, src_addr, ETH_ALEN);
+	if (!wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) &&
+	    eapol_sm_rx_eapol(wpa_s->eapol, src_addr, buf, len) > 0)
+		return;
+	wpa_drv_poll(wpa_s);
+	if (!(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+		wpa_sm_rx_eapol(wpa_s->wpa, src_addr, buf, len);
+	else if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
+		/*
+		 * Set portValid = TRUE here since we are going to skip 4-way
+		 * handshake processing which would normally set portValid. We
+		 * need this to allow the EAPOL state machines to be completed
+		 * without going through EAPOL-Key handshake.
+		 */
+		eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
+	}
+}
+
+
+int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->driver->send_eapol) {
+		const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
+		if (addr)
+			os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
+	} else if (!(wpa_s->drv_flags &
+		     WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE)) {
+		l2_packet_deinit(wpa_s->l2);
+		wpa_s->l2 = l2_packet_init(wpa_s->ifname,
+					   wpa_drv_get_mac_addr(wpa_s),
+					   ETH_P_EAPOL,
+					   wpa_supplicant_rx_eapol, wpa_s, 0);
+		if (wpa_s->l2 == NULL)
+			return -1;
+	} else {
+		const u8 *addr = wpa_drv_get_mac_addr(wpa_s);
+		if (addr)
+			os_memcpy(wpa_s->own_addr, addr, ETH_ALEN);
+	}
+
+	if (wpa_s->l2 && l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
+		wpa_msg(wpa_s, MSG_ERROR, "Failed to get own L2 address");
+		return -1;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Own MAC address: " MACSTR,
+		MAC2STR(wpa_s->own_addr));
+	wpa_sm_set_own_addr(wpa_s->wpa, wpa_s->own_addr);
+
+	return 0;
+}
+
+
+static void wpa_supplicant_rx_eapol_bridge(void *ctx, const u8 *src_addr,
+					   const u8 *buf, size_t len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	const struct l2_ethhdr *eth;
+
+	if (len < sizeof(*eth))
+		return;
+	eth = (const struct l2_ethhdr *) buf;
+
+	if (os_memcmp(eth->h_dest, wpa_s->own_addr, ETH_ALEN) != 0 &&
+	    !(eth->h_dest[0] & 0x01)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
+			" (bridge - not for this interface - ignore)",
+			MAC2STR(src_addr), MAC2STR(eth->h_dest));
+		return;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "RX EAPOL from " MACSTR " to " MACSTR
+		" (bridge)", MAC2STR(src_addr), MAC2STR(eth->h_dest));
+	wpa_supplicant_rx_eapol(wpa_s, src_addr, buf + sizeof(*eth),
+				len - sizeof(*eth));
+}
+
+
+/**
+ * wpa_supplicant_driver_init - Initialize driver interface parameters
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called to initialize driver interface parameters.
+ * wpa_drv_init() must have been called before this function to initialize the
+ * driver interface.
+ */
+int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s)
+{
+	static int interface_count = 0;
+
+	if (wpa_supplicant_update_mac_addr(wpa_s) < 0)
+		return -1;
+
+	if (wpa_s->bridge_ifname[0]) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Receiving packets from bridge "
+			"interface '%s'", wpa_s->bridge_ifname);
+		wpa_s->l2_br = l2_packet_init(wpa_s->bridge_ifname,
+					      wpa_s->own_addr,
+					      ETH_P_EAPOL,
+					      wpa_supplicant_rx_eapol_bridge,
+					      wpa_s, 1);
+		if (wpa_s->l2_br == NULL) {
+			wpa_msg(wpa_s, MSG_ERROR, "Failed to open l2_packet "
+				"connection for the bridge interface '%s'",
+				wpa_s->bridge_ifname);
+			return -1;
+		}
+	}
+
+	wpa_clear_keys(wpa_s, NULL);
+
+	/* Make sure that TKIP countermeasures are not left enabled (could
+	 * happen if wpa_supplicant is killed during countermeasures. */
+	wpa_drv_set_countermeasures(wpa_s, 0);
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "RSN: flushing PMKID list in the driver");
+	wpa_drv_flush_pmkid(wpa_s);
+
+	wpa_s->prev_scan_ssid = WILDCARD_SSID_SCAN;
+	wpa_s->prev_scan_wildcard = 0;
+
+	if (wpa_supplicant_enabled_networks(wpa_s)) {
+		if (wpa_supplicant_delayed_sched_scan(wpa_s, interface_count,
+						      100000))
+			wpa_supplicant_req_scan(wpa_s, interface_count,
+						100000);
+		interface_count++;
+	} else
+		wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_daemon(const char *pid_file)
+{
+	wpa_printf(MSG_DEBUG, "Daemonize..");
+	return os_daemonize(pid_file);
+}
+
+
+static struct wpa_supplicant * wpa_supplicant_alloc(void)
+{
+	struct wpa_supplicant *wpa_s;
+
+	wpa_s = os_zalloc(sizeof(*wpa_s));
+	if (wpa_s == NULL)
+		return NULL;
+	wpa_s->scan_req = INITIAL_SCAN_REQ;
+	wpa_s->scan_interval = 5;
+	wpa_s->new_connection = 1;
+	wpa_s->parent = wpa_s;
+	wpa_s->sched_scanning = 0;
+
+	return wpa_s;
+}
+
+
+#ifdef CONFIG_HT_OVERRIDES
+
+static int wpa_set_htcap_mcs(struct wpa_supplicant *wpa_s,
+			     struct ieee80211_ht_capabilities *htcaps,
+			     struct ieee80211_ht_capabilities *htcaps_mask,
+			     const char *ht_mcs)
+{
+	/* parse ht_mcs into hex array */
+	int i;
+	const char *tmp = ht_mcs;
+	char *end = NULL;
+
+	/* If ht_mcs is null, do not set anything */
+	if (!ht_mcs)
+		return 0;
+
+	/* This is what we are setting in the kernel */
+	os_memset(&htcaps->supported_mcs_set, 0, IEEE80211_HT_MCS_MASK_LEN);
+
+	wpa_msg(wpa_s, MSG_DEBUG, "set_htcap, ht_mcs -:%s:-", ht_mcs);
+
+	for (i = 0; i < IEEE80211_HT_MCS_MASK_LEN; i++) {
+		errno = 0;
+		long v = strtol(tmp, &end, 16);
+		if (errno == 0) {
+			wpa_msg(wpa_s, MSG_DEBUG,
+				"htcap value[%i]: %ld end: %p  tmp: %p",
+				i, v, end, tmp);
+			if (end == tmp)
+				break;
+
+			htcaps->supported_mcs_set[i] = v;
+			tmp = end;
+		} else {
+			wpa_msg(wpa_s, MSG_ERROR,
+				"Failed to parse ht-mcs: %s, error: %s\n",
+				ht_mcs, strerror(errno));
+			return -1;
+		}
+	}
+
+	/*
+	 * If we were able to parse any values, then set mask for the MCS set.
+	 */
+	if (i) {
+		os_memset(&htcaps_mask->supported_mcs_set, 0xff,
+			  IEEE80211_HT_MCS_MASK_LEN - 1);
+		/* skip the 3 reserved bits */
+		htcaps_mask->supported_mcs_set[IEEE80211_HT_MCS_MASK_LEN - 1] =
+			0x1f;
+	}
+
+	return 0;
+}
+
+
+static int wpa_disable_max_amsdu(struct wpa_supplicant *wpa_s,
+				 struct ieee80211_ht_capabilities *htcaps,
+				 struct ieee80211_ht_capabilities *htcaps_mask,
+				 int disabled)
+{
+	u16 msk;
+
+	wpa_msg(wpa_s, MSG_DEBUG, "set_disable_max_amsdu: %d", disabled);
+
+	if (disabled == -1)
+		return 0;
+
+	msk = host_to_le16(HT_CAP_INFO_MAX_AMSDU_SIZE);
+	htcaps_mask->ht_capabilities_info |= msk;
+	if (disabled)
+		htcaps->ht_capabilities_info &= msk;
+	else
+		htcaps->ht_capabilities_info |= msk;
+
+	return 0;
+}
+
+
+static int wpa_set_ampdu_factor(struct wpa_supplicant *wpa_s,
+				struct ieee80211_ht_capabilities *htcaps,
+				struct ieee80211_ht_capabilities *htcaps_mask,
+				int factor)
+{
+	wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_factor: %d", factor);
+
+	if (factor == -1)
+		return 0;
+
+	if (factor < 0 || factor > 3) {
+		wpa_msg(wpa_s, MSG_ERROR, "ampdu_factor: %d out of range. "
+			"Must be 0-3 or -1", factor);
+		return -EINVAL;
+	}
+
+	htcaps_mask->a_mpdu_params |= 0x3; /* 2 bits for factor */
+	htcaps->a_mpdu_params &= ~0x3;
+	htcaps->a_mpdu_params |= factor & 0x3;
+
+	return 0;
+}
+
+
+static int wpa_set_ampdu_density(struct wpa_supplicant *wpa_s,
+				 struct ieee80211_ht_capabilities *htcaps,
+				 struct ieee80211_ht_capabilities *htcaps_mask,
+				 int density)
+{
+	wpa_msg(wpa_s, MSG_DEBUG, "set_ampdu_density: %d", density);
+
+	if (density == -1)
+		return 0;
+
+	if (density < 0 || density > 7) {
+		wpa_msg(wpa_s, MSG_ERROR,
+			"ampdu_density: %d out of range. Must be 0-7 or -1.",
+			density);
+		return -EINVAL;
+	}
+
+	htcaps_mask->a_mpdu_params |= 0x1C;
+	htcaps->a_mpdu_params &= ~(0x1C);
+	htcaps->a_mpdu_params |= (density << 2) & 0x1C;
+
+	return 0;
+}
+
+
+static int wpa_set_disable_ht40(struct wpa_supplicant *wpa_s,
+				struct ieee80211_ht_capabilities *htcaps,
+				struct ieee80211_ht_capabilities *htcaps_mask,
+				int disabled)
+{
+	/* Masking these out disables HT40 */
+	u16 msk = host_to_le16(HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET |
+			       HT_CAP_INFO_SHORT_GI40MHZ);
+
+	wpa_msg(wpa_s, MSG_DEBUG, "set_disable_ht40: %d", disabled);
+
+	if (disabled)
+		htcaps->ht_capabilities_info &= ~msk;
+	else
+		htcaps->ht_capabilities_info |= msk;
+
+	htcaps_mask->ht_capabilities_info |= msk;
+
+	return 0;
+}
+
+
+static int wpa_set_disable_sgi(struct wpa_supplicant *wpa_s,
+			       struct ieee80211_ht_capabilities *htcaps,
+			       struct ieee80211_ht_capabilities *htcaps_mask,
+			       int disabled)
+{
+	/* Masking these out disables SGI */
+	u16 msk = host_to_le16(HT_CAP_INFO_SHORT_GI20MHZ |
+			       HT_CAP_INFO_SHORT_GI40MHZ);
+
+	wpa_msg(wpa_s, MSG_DEBUG, "set_disable_sgi: %d", disabled);
+
+	if (disabled)
+		htcaps->ht_capabilities_info &= ~msk;
+	else
+		htcaps->ht_capabilities_info |= msk;
+
+	htcaps_mask->ht_capabilities_info |= msk;
+
+	return 0;
+}
+
+
+void wpa_supplicant_apply_ht_overrides(
+	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+	struct wpa_driver_associate_params *params)
+{
+	struct ieee80211_ht_capabilities *htcaps;
+	struct ieee80211_ht_capabilities *htcaps_mask;
+
+	if (!ssid)
+		return;
+
+	params->disable_ht = ssid->disable_ht;
+	if (!params->htcaps || !params->htcaps_mask)
+		return;
+
+	htcaps = (struct ieee80211_ht_capabilities *) params->htcaps;
+	htcaps_mask = (struct ieee80211_ht_capabilities *) params->htcaps_mask;
+	wpa_set_htcap_mcs(wpa_s, htcaps, htcaps_mask, ssid->ht_mcs);
+	wpa_disable_max_amsdu(wpa_s, htcaps, htcaps_mask,
+			      ssid->disable_max_amsdu);
+	wpa_set_ampdu_factor(wpa_s, htcaps, htcaps_mask, ssid->ampdu_factor);
+	wpa_set_ampdu_density(wpa_s, htcaps, htcaps_mask, ssid->ampdu_density);
+	wpa_set_disable_ht40(wpa_s, htcaps, htcaps_mask, ssid->disable_ht40);
+	wpa_set_disable_sgi(wpa_s, htcaps, htcaps_mask, ssid->disable_sgi);
+}
+
+#endif /* CONFIG_HT_OVERRIDES */
+
+
+static int pcsc_reader_init(struct wpa_supplicant *wpa_s)
+{
+#ifdef PCSC_FUNCS
+	size_t len;
+
+	if (!wpa_s->conf->pcsc_reader)
+		return 0;
+
+	wpa_s->scard = scard_init(SCARD_TRY_BOTH, wpa_s->conf->pcsc_reader);
+	if (!wpa_s->scard)
+		return 1;
+
+	if (wpa_s->conf->pcsc_pin &&
+	    scard_set_pin(wpa_s->scard, wpa_s->conf->pcsc_pin) < 0) {
+		scard_deinit(wpa_s->scard);
+		wpa_s->scard = NULL;
+		wpa_msg(wpa_s, MSG_ERROR, "PC/SC PIN validation failed");
+		return -1;
+	}
+
+	len = sizeof(wpa_s->imsi) - 1;
+	if (scard_get_imsi(wpa_s->scard, wpa_s->imsi, &len)) {
+		scard_deinit(wpa_s->scard);
+		wpa_s->scard = NULL;
+		wpa_msg(wpa_s, MSG_ERROR, "Could not read IMSI");
+		return -1;
+	}
+	wpa_s->imsi[len] = '\0';
+
+	wpa_s->mnc_len = scard_get_mnc_len(wpa_s->scard);
+
+	wpa_printf(MSG_DEBUG, "SCARD: IMSI %s (MNC length %d)",
+		   wpa_s->imsi, wpa_s->mnc_len);
+
+	wpa_sm_set_scard_ctx(wpa_s->wpa, wpa_s->scard);
+	eapol_sm_register_scard_ctx(wpa_s->eapol, wpa_s->scard);
+#endif /* PCSC_FUNCS */
+
+	return 0;
+}
+
+
+int wpas_init_ext_pw(struct wpa_supplicant *wpa_s)
+{
+	char *val, *pos;
+
+	ext_password_deinit(wpa_s->ext_pw);
+	wpa_s->ext_pw = NULL;
+	eapol_sm_set_ext_pw_ctx(wpa_s->eapol, NULL);
+
+	if (!wpa_s->conf->ext_password_backend)
+		return 0;
+
+	val = os_strdup(wpa_s->conf->ext_password_backend);
+	if (val == NULL)
+		return -1;
+	pos = os_strchr(val, ':');
+	if (pos)
+		*pos++ = '\0';
+
+	wpa_printf(MSG_DEBUG, "EXT PW: Initialize backend '%s'", val);
+
+	wpa_s->ext_pw = ext_password_init(val, pos);
+	os_free(val);
+	if (wpa_s->ext_pw == NULL) {
+		wpa_printf(MSG_DEBUG, "EXT PW: Failed to initialize backend");
+		return -1;
+	}
+	eapol_sm_set_ext_pw_ctx(wpa_s->eapol, wpa_s->ext_pw);
+
+	return 0;
+}
+
+
+static int wpa_supplicant_init_iface(struct wpa_supplicant *wpa_s,
+				     struct wpa_interface *iface)
+{
+	const char *ifname, *driver;
+	struct wpa_driver_capa capa;
+
+	wpa_printf(MSG_DEBUG, "Initializing interface '%s' conf '%s' driver "
+		   "'%s' ctrl_interface '%s' bridge '%s'", iface->ifname,
+		   iface->confname ? iface->confname : "N/A",
+		   iface->driver ? iface->driver : "default",
+		   iface->ctrl_interface ? iface->ctrl_interface : "N/A",
+		   iface->bridge_ifname ? iface->bridge_ifname : "N/A");
+
+	if (iface->confname) {
+#ifdef CONFIG_BACKEND_FILE
+		wpa_s->confname = os_rel2abs_path(iface->confname);
+		if (wpa_s->confname == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to get absolute path "
+				   "for configuration file '%s'.",
+				   iface->confname);
+			return -1;
+		}
+		wpa_printf(MSG_DEBUG, "Configuration file '%s' -> '%s'",
+			   iface->confname, wpa_s->confname);
+#else /* CONFIG_BACKEND_FILE */
+		wpa_s->confname = os_strdup(iface->confname);
+#endif /* CONFIG_BACKEND_FILE */
+		wpa_s->conf = wpa_config_read(wpa_s->confname);
+		if (wpa_s->conf == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to read or parse "
+				   "configuration '%s'.", wpa_s->confname);
+			return -1;
+		}
+
+		/*
+		 * Override ctrl_interface and driver_param if set on command
+		 * line.
+		 */
+		if (iface->ctrl_interface) {
+			os_free(wpa_s->conf->ctrl_interface);
+			wpa_s->conf->ctrl_interface =
+				os_strdup(iface->ctrl_interface);
+		}
+
+		if (iface->driver_param) {
+			os_free(wpa_s->conf->driver_param);
+			wpa_s->conf->driver_param =
+				os_strdup(iface->driver_param);
+		}
+	} else
+		wpa_s->conf = wpa_config_alloc_empty(iface->ctrl_interface,
+						     iface->driver_param);
+
+	if (wpa_s->conf == NULL) {
+		wpa_printf(MSG_ERROR, "\nNo configuration found.");
+		return -1;
+	}
+
+	if (iface->ifname == NULL) {
+		wpa_printf(MSG_ERROR, "\nInterface name is required.");
+		return -1;
+	}
+	if (os_strlen(iface->ifname) >= sizeof(wpa_s->ifname)) {
+		wpa_printf(MSG_ERROR, "\nToo long interface name '%s'.",
+			   iface->ifname);
+		return -1;
+	}
+	os_strlcpy(wpa_s->ifname, iface->ifname, sizeof(wpa_s->ifname));
+
+	if (iface->bridge_ifname) {
+		if (os_strlen(iface->bridge_ifname) >=
+		    sizeof(wpa_s->bridge_ifname)) {
+			wpa_printf(MSG_ERROR, "\nToo long bridge interface "
+				   "name '%s'.", iface->bridge_ifname);
+			return -1;
+		}
+		os_strlcpy(wpa_s->bridge_ifname, iface->bridge_ifname,
+			   sizeof(wpa_s->bridge_ifname));
+	}
+
+	/* RSNA Supplicant Key Management - INITIALIZE */
+	eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
+	eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
+
+	/* Initialize driver interface and register driver event handler before
+	 * L2 receive handler so that association events are processed before
+	 * EAPOL-Key packets if both become available for the same select()
+	 * call. */
+	driver = iface->driver;
+next_driver:
+	if (wpa_supplicant_set_driver(wpa_s, driver) < 0)
+		return -1;
+
+	wpa_s->drv_priv = wpa_drv_init(wpa_s, wpa_s->ifname);
+	if (wpa_s->drv_priv == NULL) {
+		const char *pos;
+		pos = driver ? os_strchr(driver, ',') : NULL;
+		if (pos) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Failed to initialize "
+				"driver interface - try next driver wrapper");
+			driver = pos + 1;
+			goto next_driver;
+		}
+		wpa_msg(wpa_s, MSG_ERROR, "Failed to initialize driver "
+			"interface");
+		return -1;
+	}
+	if (wpa_drv_set_param(wpa_s, wpa_s->conf->driver_param) < 0) {
+		wpa_msg(wpa_s, MSG_ERROR, "Driver interface rejected "
+			"driver_param '%s'", wpa_s->conf->driver_param);
+		return -1;
+	}
+
+	ifname = wpa_drv_get_ifname(wpa_s);
+	if (ifname && os_strcmp(ifname, wpa_s->ifname) != 0) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Driver interface replaced "
+			"interface name with '%s'", ifname);
+		os_strlcpy(wpa_s->ifname, ifname, sizeof(wpa_s->ifname));
+	}
+
+	if (wpa_supplicant_init_wpa(wpa_s) < 0)
+		return -1;
+
+	wpa_sm_set_ifname(wpa_s->wpa, wpa_s->ifname,
+			  wpa_s->bridge_ifname[0] ? wpa_s->bridge_ifname :
+			  NULL);
+	wpa_sm_set_fast_reauth(wpa_s->wpa, wpa_s->conf->fast_reauth);
+
+	if (wpa_s->conf->dot11RSNAConfigPMKLifetime &&
+	    wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_LIFETIME,
+			     wpa_s->conf->dot11RSNAConfigPMKLifetime)) {
+		wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
+			"dot11RSNAConfigPMKLifetime");
+		return -1;
+	}
+
+	if (wpa_s->conf->dot11RSNAConfigPMKReauthThreshold &&
+	    wpa_sm_set_param(wpa_s->wpa, RSNA_PMK_REAUTH_THRESHOLD,
+			     wpa_s->conf->dot11RSNAConfigPMKReauthThreshold)) {
+		wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
+			"dot11RSNAConfigPMKReauthThreshold");
+		return -1;
+	}
+
+	if (wpa_s->conf->dot11RSNAConfigSATimeout &&
+	    wpa_sm_set_param(wpa_s->wpa, RSNA_SA_TIMEOUT,
+			     wpa_s->conf->dot11RSNAConfigSATimeout)) {
+		wpa_msg(wpa_s, MSG_ERROR, "Invalid WPA parameter value for "
+			"dot11RSNAConfigSATimeout");
+		return -1;
+	}
+
+	wpa_s->hw.modes = wpa_drv_get_hw_feature_data(wpa_s,
+						      &wpa_s->hw.num_modes,
+						      &wpa_s->hw.flags);
+
+	if (wpa_drv_get_capa(wpa_s, &capa) == 0) {
+		wpa_s->drv_capa_known = 1;
+		wpa_s->drv_flags = capa.flags;
+		wpa_s->drv_enc = capa.enc;
+		wpa_s->probe_resp_offloads = capa.probe_resp_offloads;
+		wpa_s->max_scan_ssids = capa.max_scan_ssids;
+		wpa_s->max_sched_scan_ssids = capa.max_sched_scan_ssids;
+		wpa_s->sched_scan_supported = capa.sched_scan_supported;
+		wpa_s->max_match_sets = capa.max_match_sets;
+		wpa_s->max_remain_on_chan = capa.max_remain_on_chan;
+		wpa_s->max_stations = capa.max_stations;
+	}
+	if (wpa_s->max_remain_on_chan == 0)
+		wpa_s->max_remain_on_chan = 1000;
+
+	if (wpa_supplicant_driver_init(wpa_s) < 0)
+		return -1;
+
+#ifdef CONFIG_TDLS
+	if (wpa_tdls_init(wpa_s->wpa))
+		return -1;
+#endif /* CONFIG_TDLS */
+
+	if (wpa_s->conf->country[0] && wpa_s->conf->country[1] &&
+	    wpa_drv_set_country(wpa_s, wpa_s->conf->country)) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "Failed to set country");
+		return -1;
+	}
+
+	if (wpas_wps_init(wpa_s))
+		return -1;
+
+	if (wpa_supplicant_init_eapol(wpa_s) < 0)
+		return -1;
+	wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
+
+	wpa_s->ctrl_iface = wpa_supplicant_ctrl_iface_init(wpa_s);
+	if (wpa_s->ctrl_iface == NULL) {
+		wpa_printf(MSG_ERROR,
+			   "Failed to initialize control interface '%s'.\n"
+			   "You may have another wpa_supplicant process "
+			   "already running or the file was\n"
+			   "left by an unclean termination of wpa_supplicant "
+			   "in which case you will need\n"
+			   "to manually remove this file before starting "
+			   "wpa_supplicant again.\n",
+			   wpa_s->conf->ctrl_interface);
+		return -1;
+	}
+
+	wpa_s->gas = gas_query_init(wpa_s);
+	if (wpa_s->gas == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to initialize GAS query");
+		return -1;
+	}
+
+#ifdef CONFIG_P2P
+	if (wpas_p2p_init(wpa_s->global, wpa_s) < 0) {
+		wpa_msg(wpa_s, MSG_ERROR, "Failed to init P2P");
+		return -1;
+	}
+#endif /* CONFIG_P2P */
+
+	if (wpa_bss_init(wpa_s) < 0)
+		return -1;
+
+	if (pcsc_reader_init(wpa_s) < 0)
+		return -1;
+
+	if (wpas_init_ext_pw(wpa_s) < 0)
+		return -1;
+
+	return 0;
+}
+
+
+static void wpa_supplicant_deinit_iface(struct wpa_supplicant *wpa_s,
+					int notify, int terminate)
+{
+	if (wpa_s->drv_priv) {
+		wpa_supplicant_deauthenticate(wpa_s,
+					      WLAN_REASON_DEAUTH_LEAVING);
+
+		wpa_drv_set_countermeasures(wpa_s, 0);
+		wpa_clear_keys(wpa_s, NULL);
+	}
+
+	wpa_supplicant_cleanup(wpa_s);
+
+#ifdef CONFIG_P2P
+	if (wpa_s == wpa_s->global->p2p_init_wpa_s && wpa_s->global->p2p) {
+		wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Disable P2P since removing "
+			"the management interface is being removed");
+		wpas_p2p_deinit_global(wpa_s->global);
+	}
+#endif /* CONFIG_P2P */
+
+	if (wpa_s->drv_priv)
+		wpa_drv_deinit(wpa_s);
+
+	if (notify)
+		wpas_notify_iface_removed(wpa_s);
+
+	if (terminate)
+		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TERMINATING);
+
+	if (wpa_s->ctrl_iface) {
+		wpa_supplicant_ctrl_iface_deinit(wpa_s->ctrl_iface);
+		wpa_s->ctrl_iface = NULL;
+	}
+
+	if (wpa_s->conf != NULL) {
+		wpa_config_free(wpa_s->conf);
+		wpa_s->conf = NULL;
+	}
+}
+
+
+/**
+ * wpa_supplicant_add_iface - Add a new network interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @iface: Interface configuration options
+ * Returns: Pointer to the created interface or %NULL on failure
+ *
+ * This function is used to add new network interfaces for %wpa_supplicant.
+ * This can be called before wpa_supplicant_run() to add interfaces before the
+ * main event loop has been started. In addition, new interfaces can be added
+ * dynamically while %wpa_supplicant is already running. This could happen,
+ * e.g., when a hotplug network adapter is inserted.
+ */
+struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
+						 struct wpa_interface *iface)
+{
+	struct wpa_supplicant *wpa_s;
+	struct wpa_interface t_iface;
+	struct wpa_ssid *ssid;
+
+	if (global == NULL || iface == NULL)
+		return NULL;
+
+	wpa_s = wpa_supplicant_alloc();
+	if (wpa_s == NULL)
+		return NULL;
+
+	wpa_s->global = global;
+
+	t_iface = *iface;
+	if (global->params.override_driver) {
+		wpa_printf(MSG_DEBUG, "Override interface parameter: driver "
+			   "('%s' -> '%s')",
+			   iface->driver, global->params.override_driver);
+		t_iface.driver = global->params.override_driver;
+	}
+	if (global->params.override_ctrl_interface) {
+		wpa_printf(MSG_DEBUG, "Override interface parameter: "
+			   "ctrl_interface ('%s' -> '%s')",
+			   iface->ctrl_interface,
+			   global->params.override_ctrl_interface);
+		t_iface.ctrl_interface =
+			global->params.override_ctrl_interface;
+	}
+	if (wpa_supplicant_init_iface(wpa_s, &t_iface)) {
+		wpa_printf(MSG_DEBUG, "Failed to add interface %s",
+			   iface->ifname);
+		wpa_supplicant_deinit_iface(wpa_s, 0, 0);
+		os_free(wpa_s);
+		return NULL;
+	}
+
+	/* Notify the control interfaces about new iface */
+	if (wpas_notify_iface_added(wpa_s)) {
+		wpa_supplicant_deinit_iface(wpa_s, 1, 0);
+		os_free(wpa_s);
+		return NULL;
+	}
+
+	for (ssid = wpa_s->conf->ssid; ssid; ssid = ssid->next)
+		wpas_notify_network_added(wpa_s, ssid);
+
+	wpa_s->next = global->ifaces;
+	global->ifaces = wpa_s;
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Added interface %s", wpa_s->ifname);
+	wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+
+	return wpa_s;
+}
+
+
+/**
+ * wpa_supplicant_remove_iface - Remove a network interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @wpa_s: Pointer to the network interface to be removed
+ * Returns: 0 if interface was removed, -1 if interface was not found
+ *
+ * This function can be used to dynamically remove network interfaces from
+ * %wpa_supplicant, e.g., when a hotplug network adapter is ejected. In
+ * addition, this function is used to remove all remaining interfaces when
+ * %wpa_supplicant is terminated.
+ */
+int wpa_supplicant_remove_iface(struct wpa_global *global,
+				struct wpa_supplicant *wpa_s,
+				int terminate)
+{
+	struct wpa_supplicant *prev;
+
+	/* Remove interface from the global list of interfaces */
+	prev = global->ifaces;
+	if (prev == wpa_s) {
+		global->ifaces = wpa_s->next;
+	} else {
+		while (prev && prev->next != wpa_s)
+			prev = prev->next;
+		if (prev == NULL)
+			return -1;
+		prev->next = wpa_s->next;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Removing interface %s", wpa_s->ifname);
+
+	if (global->p2p_group_formation == wpa_s)
+		global->p2p_group_formation = NULL;
+	wpa_supplicant_deinit_iface(wpa_s, 1, terminate);
+	os_free(wpa_s);
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_get_eap_mode - Get the current EAP mode
+ * @wpa_s: Pointer to the network interface
+ * Returns: Pointer to the eap mode or the string "UNKNOWN" if not found
+ */
+const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s)
+{
+	const char *eapol_method;
+
+        if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt) == 0 &&
+            wpa_s->key_mgmt != WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		return "NO-EAP";
+	}
+
+	eapol_method = eapol_sm_get_method_name(wpa_s->eapol);
+	if (eapol_method == NULL)
+		return "UNKNOWN-EAP";
+
+	return eapol_method;
+}
+
+
+/**
+ * wpa_supplicant_get_iface - Get a new network interface
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * @ifname: Interface name
+ * Returns: Pointer to the interface or %NULL if not found
+ */
+struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
+						 const char *ifname)
+{
+	struct wpa_supplicant *wpa_s;
+
+	for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next) {
+		if (os_strcmp(wpa_s->ifname, ifname) == 0)
+			return wpa_s;
+	}
+	return NULL;
+}
+
+
+#ifndef CONFIG_NO_WPA_MSG
+static const char * wpa_supplicant_msg_ifname_cb(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_s == NULL)
+		return NULL;
+	return wpa_s->ifname;
+}
+#endif /* CONFIG_NO_WPA_MSG */
+
+
+/**
+ * wpa_supplicant_init - Initialize %wpa_supplicant
+ * @params: Parameters for %wpa_supplicant
+ * Returns: Pointer to global %wpa_supplicant data, or %NULL on failure
+ *
+ * This function is used to initialize %wpa_supplicant. After successful
+ * initialization, the returned data pointer can be used to add and remove
+ * network interfaces, and eventually, to deinitialize %wpa_supplicant.
+ */
+struct wpa_global * wpa_supplicant_init(struct wpa_params *params)
+{
+	struct wpa_global *global;
+	int ret, i;
+
+	if (params == NULL)
+		return NULL;
+
+#ifdef CONFIG_DRIVER_NDIS
+	{
+		void driver_ndis_init_ops(void);
+		driver_ndis_init_ops();
+	}
+#endif /* CONFIG_DRIVER_NDIS */
+
+#ifndef CONFIG_NO_WPA_MSG
+	wpa_msg_register_ifname_cb(wpa_supplicant_msg_ifname_cb);
+#endif /* CONFIG_NO_WPA_MSG */
+
+	wpa_debug_open_file(params->wpa_debug_file_path);
+	if (params->wpa_debug_syslog)
+		wpa_debug_open_syslog();
+	if (params->wpa_debug_tracing) {
+		ret = wpa_debug_open_linux_tracing();
+		if (ret) {
+			wpa_printf(MSG_ERROR,
+				   "Failed to enable trace logging");
+			return NULL;
+		}
+	}
+
+	ret = eap_register_methods();
+	if (ret) {
+		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
+		if (ret == -2)
+			wpa_printf(MSG_ERROR, "Two or more EAP methods used "
+				   "the same EAP type.");
+		return NULL;
+	}
+
+	global = os_zalloc(sizeof(*global));
+	if (global == NULL)
+		return NULL;
+	dl_list_init(&global->p2p_srv_bonjour);
+	dl_list_init(&global->p2p_srv_upnp);
+	global->params.daemonize = params->daemonize;
+	global->params.wait_for_monitor = params->wait_for_monitor;
+	global->params.dbus_ctrl_interface = params->dbus_ctrl_interface;
+	if (params->pid_file)
+		global->params.pid_file = os_strdup(params->pid_file);
+	if (params->ctrl_interface)
+		global->params.ctrl_interface =
+			os_strdup(params->ctrl_interface);
+	if (params->override_driver)
+		global->params.override_driver =
+			os_strdup(params->override_driver);
+	if (params->override_ctrl_interface)
+		global->params.override_ctrl_interface =
+			os_strdup(params->override_ctrl_interface);
+	wpa_debug_level = global->params.wpa_debug_level =
+		params->wpa_debug_level;
+	wpa_debug_show_keys = global->params.wpa_debug_show_keys =
+		params->wpa_debug_show_keys;
+	wpa_debug_timestamp = global->params.wpa_debug_timestamp =
+		params->wpa_debug_timestamp;
+
+	wpa_printf(MSG_DEBUG, "wpa_supplicant v" VERSION_STR);
+
+	if (eloop_init()) {
+		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+		wpa_supplicant_deinit(global);
+		return NULL;
+	}
+
+	random_init(params->entropy_file);
+
+	global->ctrl_iface = wpa_supplicant_global_ctrl_iface_init(global);
+	if (global->ctrl_iface == NULL) {
+		wpa_supplicant_deinit(global);
+		return NULL;
+	}
+
+	if (wpas_notify_supplicant_initialized(global)) {
+		wpa_supplicant_deinit(global);
+		return NULL;
+	}
+
+	for (i = 0; wpa_drivers[i]; i++)
+		global->drv_count++;
+	if (global->drv_count == 0) {
+		wpa_printf(MSG_ERROR, "No drivers enabled");
+		wpa_supplicant_deinit(global);
+		return NULL;
+	}
+	global->drv_priv = os_zalloc(global->drv_count * sizeof(void *));
+	if (global->drv_priv == NULL) {
+		wpa_supplicant_deinit(global);
+		return NULL;
+	}
+
+#ifdef CONFIG_WIFI_DISPLAY
+	if (wifi_display_init(global) < 0) {
+		wpa_printf(MSG_ERROR, "Failed to initialize Wi-Fi Display");
+		wpa_supplicant_deinit(global);
+		return NULL;
+	}
+#endif /* CONFIG_WIFI_DISPLAY */
+
+	return global;
+}
+
+
+/**
+ * wpa_supplicant_run - Run the %wpa_supplicant main event loop
+ * @global: Pointer to global data from wpa_supplicant_init()
+ * Returns: 0 after successful event loop run, -1 on failure
+ *
+ * This function starts the main event loop and continues running as long as
+ * there are any remaining events. In most cases, this function is running as
+ * long as the %wpa_supplicant process in still in use.
+ */
+int wpa_supplicant_run(struct wpa_global *global)
+{
+	struct wpa_supplicant *wpa_s;
+
+	if (global->params.daemonize &&
+	    wpa_supplicant_daemon(global->params.pid_file))
+		return -1;
+
+	if (global->params.wait_for_monitor) {
+		for (wpa_s = global->ifaces; wpa_s; wpa_s = wpa_s->next)
+			if (wpa_s->ctrl_iface)
+				wpa_supplicant_ctrl_iface_wait(
+					wpa_s->ctrl_iface);
+	}
+
+	eloop_register_signal_terminate(wpa_supplicant_terminate, global);
+	eloop_register_signal_reconfig(wpa_supplicant_reconfig, global);
+
+	eloop_run();
+
+	return 0;
+}
+
+
+/**
+ * wpa_supplicant_deinit - Deinitialize %wpa_supplicant
+ * @global: Pointer to global data from wpa_supplicant_init()
+ *
+ * This function is called to deinitialize %wpa_supplicant and to free all
+ * allocated resources. Remaining network interfaces will also be removed.
+ */
+void wpa_supplicant_deinit(struct wpa_global *global)
+{
+	int i;
+
+	if (global == NULL)
+		return;
+
+#ifdef CONFIG_WIFI_DISPLAY
+	wifi_display_deinit(global);
+#endif /* CONFIG_WIFI_DISPLAY */
+#ifdef CONFIG_P2P
+	wpas_p2p_deinit_global(global);
+#endif /* CONFIG_P2P */
+
+	while (global->ifaces)
+		wpa_supplicant_remove_iface(global, global->ifaces, 1);
+
+	if (global->ctrl_iface)
+		wpa_supplicant_global_ctrl_iface_deinit(global->ctrl_iface);
+
+	wpas_notify_supplicant_deinitialized(global);
+
+	eap_peer_unregister_methods();
+#ifdef CONFIG_AP
+	eap_server_unregister_methods();
+#endif /* CONFIG_AP */
+
+	for (i = 0; wpa_drivers[i] && global->drv_priv; i++) {
+		if (!global->drv_priv[i])
+			continue;
+		wpa_drivers[i]->global_deinit(global->drv_priv[i]);
+	}
+	os_free(global->drv_priv);
+
+	random_deinit();
+
+	eloop_destroy();
+
+	if (global->params.pid_file) {
+		os_daemonize_terminate(global->params.pid_file);
+		os_free(global->params.pid_file);
+	}
+	os_free(global->params.ctrl_interface);
+	os_free(global->params.override_driver);
+	os_free(global->params.override_ctrl_interface);
+
+	os_free(global->p2p_disallow_freq);
+
+	os_free(global);
+	wpa_debug_close_syslog();
+	wpa_debug_close_file();
+	wpa_debug_close_linux_tracing();
+}
+
+
+void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s)
+{
+	if ((wpa_s->conf->changed_parameters & CFG_CHANGED_COUNTRY) &&
+	    wpa_s->conf->country[0] && wpa_s->conf->country[1]) {
+		char country[3];
+		country[0] = wpa_s->conf->country[0];
+		country[1] = wpa_s->conf->country[1];
+		country[2] = '\0';
+		if (wpa_drv_set_country(wpa_s, country) < 0) {
+			wpa_printf(MSG_ERROR, "Failed to set country code "
+				   "'%s'", country);
+		}
+	}
+
+	if (wpa_s->conf->changed_parameters & CFG_CHANGED_EXT_PW_BACKEND)
+		wpas_init_ext_pw(wpa_s);
+
+#ifdef CONFIG_WPS
+	wpas_wps_update_config(wpa_s);
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+	wpas_p2p_update_config(wpa_s);
+#endif /* CONFIG_P2P */
+
+	wpa_s->conf->changed_parameters = 0;
+}
+
+
+static void add_freq(int *freqs, int *num_freqs, int freq)
+{
+	int i;
+
+	for (i = 0; i < *num_freqs; i++) {
+		if (freqs[i] == freq)
+			return;
+	}
+
+	freqs[*num_freqs] = freq;
+	(*num_freqs)++;
+}
+
+
+static int * get_bss_freqs_in_ess(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_bss *bss, *cbss;
+	const int max_freqs = 10;
+	int *freqs;
+	int num_freqs = 0;
+
+	freqs = os_zalloc(sizeof(int) * (max_freqs + 1));
+	if (freqs == NULL)
+		return NULL;
+
+	cbss = wpa_s->current_bss;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (bss == cbss)
+			continue;
+		if (bss->ssid_len == cbss->ssid_len &&
+		    os_memcmp(bss->ssid, cbss->ssid, bss->ssid_len) == 0 &&
+		    wpa_blacklist_get(wpa_s, bss->bssid) == NULL) {
+			add_freq(freqs, &num_freqs, bss->freq);
+			if (num_freqs == max_freqs)
+				break;
+		}
+	}
+
+	if (num_freqs == 0) {
+		os_free(freqs);
+		freqs = NULL;
+	}
+
+	return freqs;
+}
+
+
+void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	int timeout;
+	int count;
+	int *freqs = NULL;
+
+	/*
+	 * Remove possible authentication timeout since the connection failed.
+	 */
+	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
+
+	/*
+	 * Add the failed BSSID into the blacklist and speed up next scan
+	 * attempt if there could be other APs that could accept association.
+	 * The current blacklist count indicates how many times we have tried
+	 * connecting to this AP and multiple attempts mean that other APs are
+	 * either not available or has already been tried, so that we can start
+	 * increasing the delay here to avoid constant scanning.
+	 */
+	count = wpa_blacklist_add(wpa_s, bssid);
+	if (count == 1 && wpa_s->current_bss) {
+		/*
+		 * This BSS was not in the blacklist before. If there is
+		 * another BSS available for the same ESS, we should try that
+		 * next. Otherwise, we may as well try this one once more
+		 * before allowing other, likely worse, ESSes to be considered.
+		 */
+		freqs = get_bss_freqs_in_ess(wpa_s);
+		if (freqs) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "Another BSS in this ESS "
+				"has been seen; try it next");
+			wpa_blacklist_add(wpa_s, bssid);
+			/*
+			 * On the next scan, go through only the known channels
+			 * used in this ESS based on previous scans to speed up
+			 * common load balancing use case.
+			 */
+			os_free(wpa_s->next_scan_freqs);
+			wpa_s->next_scan_freqs = freqs;
+		}
+	}
+
+	/*
+	 * Add previous failure count in case the temporary blacklist was
+	 * cleared due to no other BSSes being available.
+	 */
+	count += wpa_s->extra_blacklist_count;
+
+	switch (count) {
+	case 1:
+		timeout = 100;
+		break;
+	case 2:
+		timeout = 500;
+		break;
+	case 3:
+		timeout = 1000;
+		break;
+	case 4:
+		timeout = 5000;
+		break;
+	default:
+		timeout = 10000;
+		break;
+	}
+
+	wpa_dbg(wpa_s, MSG_DEBUG, "Blacklist count %d --> request scan in %d "
+		"ms", count, timeout);
+
+	/*
+	 * TODO: if more than one possible AP is available in scan results,
+	 * could try the other ones before requesting a new scan.
+	 */
+	wpa_supplicant_req_scan(wpa_s, timeout / 1000,
+				1000 * (timeout % 1000));
+
+#ifdef CONFIG_P2P
+	if (wpa_s->global->p2p_cb_on_scan_complete && !wpa_s->global->p2p_disabled &&
+	    wpa_s->global->p2p != NULL) {
+		wpa_s->global->p2p_cb_on_scan_complete = 0;
+		if (p2p_other_scan_completed(wpa_s->global->p2p) == 1) {
+			wpa_dbg(wpa_s, MSG_DEBUG, "P2P: Pending P2P operation "
+				"continued after failed association");
+		}
+	}
+#endif /* CONFIG_P2P */
+}
+
+
+int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s)
+{
+	return wpa_s->conf->ap_scan == 2 ||
+		(wpa_s->drv_flags & WPA_DRIVER_FLAGS_BSS_SELECTION);
+}
+
+
+#if defined(CONFIG_CTRL_IFACE) || defined(CONFIG_CTRL_IFACE_DBUS_NEW)
+int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
+					      struct wpa_ssid *ssid,
+					      const char *field,
+					      const char *value)
+{
+#ifdef IEEE8021X_EAPOL
+	struct eap_peer_config *eap = &ssid->eap;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: response handle field=%s", field);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "CTRL_IFACE: response value",
+			      (const u8 *) value, os_strlen(value));
+
+	switch (wpa_supplicant_ctrl_req_from_string(field)) {
+	case WPA_CTRL_REQ_EAP_IDENTITY:
+		os_free(eap->identity);
+		eap->identity = (u8 *) os_strdup(value);
+		eap->identity_len = os_strlen(value);
+		eap->pending_req_identity = 0;
+		if (ssid == wpa_s->current_ssid)
+			wpa_s->reassociate = 1;
+		break;
+	case WPA_CTRL_REQ_EAP_PASSWORD:
+		os_free(eap->password);
+		eap->password = (u8 *) os_strdup(value);
+		eap->password_len = os_strlen(value);
+		eap->pending_req_password = 0;
+		if (ssid == wpa_s->current_ssid)
+			wpa_s->reassociate = 1;
+		break;
+	case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
+		os_free(eap->new_password);
+		eap->new_password = (u8 *) os_strdup(value);
+		eap->new_password_len = os_strlen(value);
+		eap->pending_req_new_password = 0;
+		if (ssid == wpa_s->current_ssid)
+			wpa_s->reassociate = 1;
+		break;
+	case WPA_CTRL_REQ_EAP_PIN:
+		os_free(eap->pin);
+		eap->pin = os_strdup(value);
+		eap->pending_req_pin = 0;
+		if (ssid == wpa_s->current_ssid)
+			wpa_s->reassociate = 1;
+		break;
+	case WPA_CTRL_REQ_EAP_OTP:
+		os_free(eap->otp);
+		eap->otp = (u8 *) os_strdup(value);
+		eap->otp_len = os_strlen(value);
+		os_free(eap->pending_req_otp);
+		eap->pending_req_otp = NULL;
+		eap->pending_req_otp_len = 0;
+		break;
+	case WPA_CTRL_REQ_EAP_PASSPHRASE:
+		os_free(eap->private_key_passwd);
+		eap->private_key_passwd = (u8 *) os_strdup(value);
+		eap->pending_req_passphrase = 0;
+		if (ssid == wpa_s->current_ssid)
+			wpa_s->reassociate = 1;
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "CTRL_IFACE: Unknown field '%s'", field);
+		return -1;
+	}
+
+	return 0;
+#else /* IEEE8021X_EAPOL */
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE: IEEE 802.1X not included");
+	return -1;
+#endif /* IEEE8021X_EAPOL */
+}
+#endif /* CONFIG_CTRL_IFACE || CONFIG_CTRL_IFACE_DBUS_NEW */
+
+
+int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid)
+{
+	int i;
+	unsigned int drv_enc;
+
+	if (ssid == NULL)
+		return 1;
+
+	if (ssid->disabled)
+		return 1;
+
+	if (wpa_s && wpa_s->drv_capa_known)
+		drv_enc = wpa_s->drv_enc;
+	else
+		drv_enc = (unsigned int) -1;
+
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		size_t len = ssid->wep_key_len[i];
+		if (len == 0)
+			continue;
+		if (len == 5 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP40))
+			continue;
+		if (len == 13 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP104))
+			continue;
+		if (len == 16 && (drv_enc & WPA_DRIVER_CAPA_ENC_WEP128))
+			continue;
+		return 1; /* invalid WEP key */
+	}
+
+	if (wpa_key_mgmt_wpa_psk(ssid->key_mgmt) && !ssid->psk_set &&
+	    !ssid->ext_psk)
+		return 1;
+
+	return 0;
+}
+
+
+int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s)
+{
+	if (wpa_s->global->conc_pref == WPA_CONC_PREF_P2P)
+		return 1;
+	if (wpa_s->global->conc_pref == WPA_CONC_PREF_STA)
+		return 0;
+	return -1;
+}
+
+
+void wpas_auth_failed(struct wpa_supplicant *wpa_s)
+{
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	int dur;
+	struct os_time now;
+
+	if (ssid == NULL) {
+		wpa_printf(MSG_DEBUG, "Authentication failure but no known "
+			   "SSID block");
+		return;
+	}
+
+	if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
+		return;
+
+	ssid->auth_failures++;
+	if (ssid->auth_failures > 50)
+		dur = 300;
+	else if (ssid->auth_failures > 20)
+		dur = 120;
+	else if (ssid->auth_failures > 10)
+		dur = 60;
+	else if (ssid->auth_failures > 5)
+		dur = 30;
+	else if (ssid->auth_failures > 1)
+		dur = 20;
+	else
+		dur = 10;
+
+	os_get_time(&now);
+	if (now.sec + dur <= ssid->disabled_until.sec)
+		return;
+
+	ssid->disabled_until.sec = now.sec + dur;
+
+	wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_TEMP_DISABLED
+		"id=%d ssid=\"%s\" auth_failures=%u duration=%d",
+		ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len),
+		ssid->auth_failures, dur);
+}
+
+
+void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid, int clear_failures)
+{
+	if (ssid == NULL)
+		return;
+
+	if (ssid->disabled_until.sec) {
+		wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_REENABLED
+			"id=%d ssid=\"%s\"",
+			ssid->id, wpa_ssid_txt(ssid->ssid, ssid->ssid_len));
+	}
+	ssid->disabled_until.sec = 0;
+	ssid->disabled_until.usec = 0;
+	if (clear_failures)
+		ssid->auth_failures = 0;
+}
+
+
+int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid)
+{
+	size_t i;
+
+	if (wpa_s->disallow_aps_bssid == NULL)
+		return 0;
+
+	for (i = 0; i < wpa_s->disallow_aps_bssid_count; i++) {
+		if (os_memcmp(wpa_s->disallow_aps_bssid + i * ETH_ALEN,
+			      bssid, ETH_ALEN) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
+		    size_t ssid_len)
+{
+	size_t i;
+
+	if (wpa_s->disallow_aps_ssid == NULL || ssid == NULL)
+		return 0;
+
+	for (i = 0; i < wpa_s->disallow_aps_ssid_count; i++) {
+		struct wpa_ssid_value *s = &wpa_s->disallow_aps_ssid[i];
+		if (ssid_len == s->ssid_len &&
+		    os_memcmp(ssid, s->ssid, ssid_len) == 0)
+			return 1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpas_request_connection - Request a new connection
+ * @wpa_s: Pointer to the network interface
+ *
+ * This function is used to request a new connection to be found. It will mark
+ * the interface to allow reassociation and request a new scan to find a
+ * suitable network to connect to.
+ */
+void wpas_request_connection(struct wpa_supplicant *wpa_s)
+{
+	wpa_s->normal_scans = 0;
+	wpa_supplicant_reinit_autoscan(wpa_s);
+	wpa_s->extra_blacklist_count = 0;
+	wpa_s->disconnected = 0;
+	wpa_s->reassociate = 1;
+	wpa_supplicant_req_scan(wpa_s, 0, 0);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/wpa_supplicant_i.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,808 @@
+/*
+ * wpa_supplicant - Internal definitions
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_SUPPLICANT_I_H
+#define WPA_SUPPLICANT_I_H
+
+#include "utils/list.h"
+#include "common/defs.h"
+#include "config_ssid.h"
+
+extern const char *wpa_supplicant_version;
+extern const char *wpa_supplicant_license;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+extern const char *wpa_supplicant_full_license1;
+extern const char *wpa_supplicant_full_license2;
+extern const char *wpa_supplicant_full_license3;
+extern const char *wpa_supplicant_full_license4;
+extern const char *wpa_supplicant_full_license5;
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+struct wpa_sm;
+struct wpa_supplicant;
+struct ibss_rsn;
+struct scan_info;
+struct wpa_bss;
+struct wpa_scan_results;
+struct hostapd_hw_modes;
+struct wpa_driver_associate_params;
+
+/*
+ * Forward declarations of private structures used within the ctrl_iface
+ * backends. Other parts of wpa_supplicant do not have access to data stored in
+ * these structures.
+ */
+struct ctrl_iface_priv;
+struct ctrl_iface_global_priv;
+struct wpas_dbus_priv;
+
+/**
+ * struct wpa_interface - Parameters for wpa_supplicant_add_iface()
+ */
+struct wpa_interface {
+	/**
+	 * confname - Configuration name (file or profile) name
+	 *
+	 * This can also be %NULL when a configuration file is not used. In
+	 * that case, ctrl_interface must be set to allow the interface to be
+	 * configured.
+	 */
+	const char *confname;
+
+	/**
+	 * ctrl_interface - Control interface parameter
+	 *
+	 * If a configuration file is not used, this variable can be used to
+	 * set the ctrl_interface parameter that would have otherwise been read
+	 * from the configuration file. If both confname and ctrl_interface are
+	 * set, ctrl_interface is used to override the value from configuration
+	 * file.
+	 */
+	const char *ctrl_interface;
+
+	/**
+	 * driver - Driver interface name, or %NULL to use the default driver
+	 */
+	const char *driver;
+
+	/**
+	 * driver_param - Driver interface parameters
+	 *
+	 * If a configuration file is not used, this variable can be used to
+	 * set the driver_param parameters that would have otherwise been read
+	 * from the configuration file. If both confname and driver_param are
+	 * set, driver_param is used to override the value from configuration
+	 * file.
+	 */
+	const char *driver_param;
+
+	/**
+	 * ifname - Interface name
+	 */
+	const char *ifname;
+
+	/**
+	 * bridge_ifname - Optional bridge interface name
+	 *
+	 * If the driver interface (ifname) is included in a Linux bridge
+	 * device, the bridge interface may need to be used for receiving EAPOL
+	 * frames. This can be enabled by setting this variable to enable
+	 * receiving of EAPOL frames from an additional interface.
+	 */
+	const char *bridge_ifname;
+};
+
+/**
+ * struct wpa_params - Parameters for wpa_supplicant_init()
+ */
+struct wpa_params {
+	/**
+	 * daemonize - Run %wpa_supplicant in the background
+	 */
+	int daemonize;
+
+	/**
+	 * wait_for_monitor - Wait for a monitor program before starting
+	 */
+	int wait_for_monitor;
+
+	/**
+	 * pid_file - Path to a PID (process ID) file
+	 *
+	 * If this and daemonize are set, process ID of the background process
+	 * will be written to the specified file.
+	 */
+	char *pid_file;
+
+	/**
+	 * wpa_debug_level - Debugging verbosity level (e.g., MSG_INFO)
+	 */
+	int wpa_debug_level;
+
+	/**
+	 * wpa_debug_show_keys - Whether keying material is included in debug
+	 *
+	 * This parameter can be used to allow keying material to be included
+	 * in debug messages. This is a security risk and this option should
+	 * not be enabled in normal configuration. If needed during
+	 * development or while troubleshooting, this option can provide more
+	 * details for figuring out what is happening.
+	 */
+	int wpa_debug_show_keys;
+
+	/**
+	 * wpa_debug_timestamp - Whether to include timestamp in debug messages
+	 */
+	int wpa_debug_timestamp;
+
+	/**
+	 * ctrl_interface - Global ctrl_iface path/parameter
+	 */
+	char *ctrl_interface;
+
+	/**
+	 * dbus_ctrl_interface - Enable the DBus control interface
+	 */
+	int dbus_ctrl_interface;
+
+	/**
+	 * wpa_debug_file_path - Path of debug file or %NULL to use stdout
+	 */
+	const char *wpa_debug_file_path;
+
+	/**
+	 * wpa_debug_syslog - Enable log output through syslog
+	 */
+	int wpa_debug_syslog;
+
+	/**
+	 * wpa_debug_tracing - Enable log output through Linux tracing
+	 */
+	int wpa_debug_tracing;
+
+	/**
+	 * override_driver - Optional driver parameter override
+	 *
+	 * This parameter can be used to override the driver parameter in
+	 * dynamic interface addition to force a specific driver wrapper to be
+	 * used instead.
+	 */
+	char *override_driver;
+
+	/**
+	 * override_ctrl_interface - Optional ctrl_interface override
+	 *
+	 * This parameter can be used to override the ctrl_interface parameter
+	 * in dynamic interface addition to force a control interface to be
+	 * created.
+	 */
+	char *override_ctrl_interface;
+
+	/**
+	 * entropy_file - Optional entropy file
+	 *
+	 * This parameter can be used to configure wpa_supplicant to maintain
+	 * its internal entropy store over restarts.
+	 */
+	char *entropy_file;
+};
+
+struct p2p_srv_bonjour {
+	struct dl_list list;
+	struct wpabuf *query;
+	struct wpabuf *resp;
+};
+
+struct p2p_srv_upnp {
+	struct dl_list list;
+	u8 version;
+	char *service;
+};
+
+struct wpa_freq_range {
+	unsigned int min;
+	unsigned int max;
+};
+
+
+/**
+ * struct wpa_global - Internal, global data for all %wpa_supplicant interfaces
+ *
+ * This structure is initialized by calling wpa_supplicant_init() when starting
+ * %wpa_supplicant.
+ */
+struct wpa_global {
+	struct wpa_supplicant *ifaces;
+	struct wpa_params params;
+	struct ctrl_iface_global_priv *ctrl_iface;
+	struct wpas_dbus_priv *dbus;
+	void **drv_priv;
+	size_t drv_count;
+	struct os_time suspend_time;
+	struct p2p_data *p2p;
+	struct wpa_supplicant *p2p_init_wpa_s;
+	struct wpa_supplicant *p2p_group_formation;
+	u8 p2p_dev_addr[ETH_ALEN];
+	struct dl_list p2p_srv_bonjour; /* struct p2p_srv_bonjour */
+	struct dl_list p2p_srv_upnp; /* struct p2p_srv_upnp */
+	int p2p_disabled;
+	int cross_connection;
+	struct wpa_freq_range *p2p_disallow_freq;
+	unsigned int num_p2p_disallow_freq;
+	enum wpa_conc_pref {
+		WPA_CONC_PREF_NOT_SET,
+		WPA_CONC_PREF_STA,
+		WPA_CONC_PREF_P2P
+	} conc_pref;
+	unsigned int p2p_cb_on_scan_complete:1;
+
+#ifdef CONFIG_WIFI_DISPLAY
+	int wifi_display;
+#define MAX_WFD_SUBELEMS 10
+	struct wpabuf *wfd_subelem[MAX_WFD_SUBELEMS];
+#endif /* CONFIG_WIFI_DISPLAY */
+};
+
+
+/**
+ * offchannel_send_action_result - Result of offchannel send Action frame
+ */
+enum offchannel_send_action_result {
+	OFFCHANNEL_SEND_ACTION_SUCCESS /**< Frame was send and acknowledged */,
+	OFFCHANNEL_SEND_ACTION_NO_ACK /**< Frame was sent, but not acknowledged
+				       */,
+	OFFCHANNEL_SEND_ACTION_FAILED /**< Frame was not sent due to a failure
+				       */
+};
+
+struct wps_ap_info {
+	u8 bssid[ETH_ALEN];
+	enum wps_ap_info_type {
+		WPS_AP_NOT_SEL_REG,
+		WPS_AP_SEL_REG,
+		WPS_AP_SEL_REG_OUR
+	} type;
+	unsigned int tries;
+	struct os_time last_attempt;
+};
+
+struct wpa_ssid_value {
+	u8 ssid[32];
+	size_t ssid_len;
+};
+
+/**
+ * struct wpa_supplicant - Internal data for wpa_supplicant interface
+ *
+ * This structure contains the internal data for core wpa_supplicant code. This
+ * should be only used directly from the core code. However, a pointer to this
+ * data is used from other files as an arbitrary context pointer in calls to
+ * core functions.
+ */
+struct wpa_supplicant {
+	struct wpa_global *global;
+	struct wpa_supplicant *parent;
+	struct wpa_supplicant *next;
+	struct l2_packet_data *l2;
+	struct l2_packet_data *l2_br;
+	unsigned char own_addr[ETH_ALEN];
+	char ifname[100];
+#ifdef CONFIG_CTRL_IFACE_DBUS
+	char *dbus_path;
+#endif /* CONFIG_CTRL_IFACE_DBUS */
+#ifdef CONFIG_CTRL_IFACE_DBUS_NEW
+	char *dbus_new_path;
+	char *dbus_groupobj_path;
+#ifdef CONFIG_AP
+	char *preq_notify_peer;
+#endif /* CONFIG_AP */
+#endif /* CONFIG_CTRL_IFACE_DBUS_NEW */
+	char bridge_ifname[16];
+
+	char *confname;
+	struct wpa_config *conf;
+	int countermeasures;
+	os_time_t last_michael_mic_error;
+	u8 bssid[ETH_ALEN];
+	u8 pending_bssid[ETH_ALEN]; /* If wpa_state == WPA_ASSOCIATING, this
+				     * field contains the target BSSID. */
+	int reassociate; /* reassociation requested */
+	int disconnected; /* all connections disabled; i.e., do no reassociate
+			   * before this has been cleared */
+	struct wpa_ssid *current_ssid;
+	struct wpa_bss *current_bss;
+	int ap_ies_from_associnfo;
+	unsigned int assoc_freq;
+
+	/* Selected configuration (based on Beacon/ProbeResp WPA IE) */
+	int pairwise_cipher;
+	int group_cipher;
+	int key_mgmt;
+	int wpa_proto;
+	int mgmt_group_cipher;
+
+	void *drv_priv; /* private data used by driver_ops */
+	void *global_drv_priv;
+
+	u8 *bssid_filter;
+	size_t bssid_filter_count;
+
+	u8 *disallow_aps_bssid;
+	size_t disallow_aps_bssid_count;
+	struct wpa_ssid_value *disallow_aps_ssid;
+	size_t disallow_aps_ssid_count;
+
+	/* previous scan was wildcard when interleaving between
+	 * wildcard scans and specific SSID scan when max_ssids=1 */
+	int prev_scan_wildcard;
+	struct wpa_ssid *prev_scan_ssid; /* previously scanned SSID;
+					  * NULL = not yet initialized (start
+					  * with wildcard SSID)
+					  * WILDCARD_SSID_SCAN = wildcard
+					  * SSID was used in the previous scan
+					  */
+#define WILDCARD_SSID_SCAN ((struct wpa_ssid *) 1)
+
+	struct wpa_ssid *prev_sched_ssid; /* last SSID used in sched scan */
+	int sched_scan_timeout;
+	int sched_scan_interval;
+	int first_sched_scan;
+	int sched_scan_timed_out;
+
+	void (*scan_res_handler)(struct wpa_supplicant *wpa_s,
+				 struct wpa_scan_results *scan_res);
+	struct dl_list bss; /* struct wpa_bss::list */
+	struct dl_list bss_id; /* struct wpa_bss::list_id */
+	size_t num_bss;
+	unsigned int bss_update_idx;
+	unsigned int bss_next_id;
+
+	 /*
+	  * Pointers to BSS entries in the order they were in the last scan
+	  * results.
+	  */
+	struct wpa_bss **last_scan_res;
+	unsigned int last_scan_res_used;
+	unsigned int last_scan_res_size;
+	int last_scan_full;
+	struct os_time last_scan;
+
+	struct wpa_driver_ops *driver;
+	int interface_removed; /* whether the network interface has been
+				* removed */
+	struct wpa_sm *wpa;
+	struct eapol_sm *eapol;
+
+	struct ctrl_iface_priv *ctrl_iface;
+
+	enum wpa_states wpa_state;
+	int scanning;
+	int sched_scanning;
+	int new_connection;
+
+	int eapol_received; /* number of EAPOL packets received after the
+			     * previous association event */
+
+	struct scard_data *scard;
+#ifdef PCSC_FUNCS
+	char imsi[20];
+	int mnc_len;
+#endif /* PCSC_FUNCS */
+
+	unsigned char last_eapol_src[ETH_ALEN];
+
+	int keys_cleared;
+
+	struct wpa_blacklist *blacklist;
+
+	/**
+	 * extra_blacklist_count - Sum of blacklist counts after last connection
+	 *
+	 * This variable is used to maintain a count of temporary blacklisting
+	 * failures (maximum number for any BSS) over blacklist clear
+	 * operations. This is needed for figuring out whether there has been
+	 * failures prior to the last blacklist clear operation which happens
+	 * whenever no other not-blacklisted BSS candidates are available. This
+	 * gets cleared whenever a connection has been established successfully.
+	 */
+	int extra_blacklist_count;
+
+	/**
+	 * scan_req - Type of the scan request
+	 */
+	enum scan_req_type {
+		/**
+		 * NORMAL_SCAN_REQ - Normal scan request
+		 *
+		 * This is used for scans initiated by wpa_supplicant to find an
+		 * AP for a connection.
+		 */
+		NORMAL_SCAN_REQ,
+
+		/**
+		 * INITIAL_SCAN_REQ - Initial scan request
+		 *
+		 * This is used for the first scan on an interface to force at
+		 * least one scan to be run even if the configuration does not
+		 * include any enabled networks.
+		 */
+		INITIAL_SCAN_REQ,
+
+		/**
+		 * MANUAL_SCAN_REQ - Manual scan request
+		 *
+		 * This is used for scans where the user request a scan or
+		 * a specific wpa_supplicant operation (e.g., WPS) requires scan
+		 * to be run.
+		 */
+		MANUAL_SCAN_REQ
+	} scan_req;
+	int scan_runs; /* number of scan runs since WPS was started */
+	int *next_scan_freqs;
+	int scan_interval; /* time in sec between scans to find suitable AP */
+	int normal_scans; /* normal scans run before sched_scan */
+	int scan_for_connection; /* whether the scan request was triggered for
+				  * finding a connection */
+
+	unsigned int drv_flags;
+	unsigned int drv_enc;
+
+	/*
+	 * A bitmap of supported protocols for probe response offload. See
+	 * struct wpa_driver_capa in driver.h
+	 */
+	unsigned int probe_resp_offloads;
+
+	int max_scan_ssids;
+	int max_sched_scan_ssids;
+	int sched_scan_supported;
+	unsigned int max_match_sets;
+	unsigned int max_remain_on_chan;
+	unsigned int max_stations;
+
+	int pending_mic_error_report;
+	int pending_mic_error_pairwise;
+	int mic_errors_seen; /* Michael MIC errors with the current PTK */
+
+	struct wps_context *wps;
+	int wps_success; /* WPS success event received */
+	struct wps_er *wps_er;
+	int blacklist_cleared;
+
+	struct wpabuf *pending_eapol_rx;
+	struct os_time pending_eapol_rx_time;
+	u8 pending_eapol_rx_src[ETH_ALEN];
+	unsigned int last_eapol_matches_bssid:1;
+
+	struct ibss_rsn *ibss_rsn;
+
+	int set_sta_uapsd;
+	int sta_uapsd;
+	int set_ap_uapsd;
+	int ap_uapsd;
+
+#ifdef CONFIG_SME
+	struct {
+		u8 ssid[32];
+		size_t ssid_len;
+		int freq;
+		u8 assoc_req_ie[200];
+		size_t assoc_req_ie_len;
+		int mfp;
+		int ft_used;
+		u8 mobility_domain[2];
+		u8 *ft_ies;
+		size_t ft_ies_len;
+		u8 prev_bssid[ETH_ALEN];
+		int prev_bssid_set;
+		int auth_alg;
+		int proto;
+
+		int sa_query_count; /* number of pending SA Query requests;
+				     * 0 = no SA Query in progress */
+		int sa_query_timed_out;
+		u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
+					* sa_query_count octets of pending
+					* SA Query transaction identifiers */
+		struct os_time sa_query_start;
+		u8 sched_obss_scan;
+		u16 obss_scan_int;
+		u16 bss_max_idle_period;
+		enum {
+			SME_SAE_INIT,
+			SME_SAE_COMMIT,
+			SME_SAE_CONFIRM
+		} sae_state;
+		u16 sae_send_confirm;
+	} sme;
+#endif /* CONFIG_SME */
+
+#ifdef CONFIG_AP
+	struct hostapd_iface *ap_iface;
+	void (*ap_configured_cb)(void *ctx, void *data);
+	void *ap_configured_cb_ctx;
+	void *ap_configured_cb_data;
+#endif /* CONFIG_AP */
+
+	unsigned int off_channel_freq;
+	struct wpabuf *pending_action_tx;
+	u8 pending_action_src[ETH_ALEN];
+	u8 pending_action_dst[ETH_ALEN];
+	u8 pending_action_bssid[ETH_ALEN];
+	unsigned int pending_action_freq;
+	int pending_action_no_cck;
+	int pending_action_without_roc;
+	void (*pending_action_tx_status_cb)(struct wpa_supplicant *wpa_s,
+					    unsigned int freq, const u8 *dst,
+					    const u8 *src, const u8 *bssid,
+					    const u8 *data, size_t data_len,
+					    enum offchannel_send_action_result
+					    result);
+	unsigned int roc_waiting_drv_freq;
+	int action_tx_wait_time;
+
+#ifdef CONFIG_P2P
+	struct p2p_go_neg_results *go_params;
+	int create_p2p_iface;
+	u8 pending_interface_addr[ETH_ALEN];
+	char pending_interface_name[100];
+	int pending_interface_type;
+	int p2p_group_idx;
+	unsigned int pending_listen_freq;
+	unsigned int pending_listen_duration;
+	enum {
+		NOT_P2P_GROUP_INTERFACE,
+		P2P_GROUP_INTERFACE_PENDING,
+		P2P_GROUP_INTERFACE_GO,
+		P2P_GROUP_INTERFACE_CLIENT
+	} p2p_group_interface;
+	struct p2p_group *p2p_group;
+	int p2p_long_listen; /* remaining time in long Listen state in ms */
+	char p2p_pin[10];
+	int p2p_wps_method;
+	u8 p2p_auth_invite[ETH_ALEN];
+	int p2p_sd_over_ctrl_iface;
+	int p2p_in_provisioning;
+	int pending_invite_ssid_id;
+	int show_group_started;
+	u8 go_dev_addr[ETH_ALEN];
+	int pending_pd_before_join;
+	u8 pending_join_iface_addr[ETH_ALEN];
+	u8 pending_join_dev_addr[ETH_ALEN];
+	int pending_join_wps_method;
+	int p2p_join_scan_count;
+	int auto_pd_scan_retry;
+	int force_long_sd;
+	u16 pending_pd_config_methods;
+	enum {
+		NORMAL_PD, AUTO_PD_GO_NEG, AUTO_PD_JOIN
+	} pending_pd_use;
+
+	/*
+	 * Whether cross connection is disallowed by the AP to which this
+	 * interface is associated (only valid if there is an association).
+	 */
+	int cross_connect_disallowed;
+
+	/*
+	 * Whether this P2P group is configured to use cross connection (only
+	 * valid if this is P2P GO interface). The actual cross connect packet
+	 * forwarding may not be configured depending on the uplink status.
+	 */
+	int cross_connect_enabled;
+
+	/* Whether cross connection forwarding is in use at the moment. */
+	int cross_connect_in_use;
+
+	/*
+	 * Uplink interface name for cross connection
+	 */
+	char cross_connect_uplink[100];
+
+	unsigned int sta_scan_pending:1;
+	unsigned int p2p_auto_join:1;
+	unsigned int p2p_auto_pd:1;
+	unsigned int p2p_persistent_group:1;
+	unsigned int p2p_fallback_to_go_neg:1;
+	unsigned int p2p_pd_before_go_neg:1;
+	unsigned int p2p_go_ht40:1;
+	unsigned int user_initiated_pd:1;
+	int p2p_persistent_go_freq;
+	int p2p_persistent_id;
+	int p2p_go_intent;
+	int p2p_connect_freq;
+	struct os_time p2p_auto_started;
+#endif /* CONFIG_P2P */
+
+	struct wpa_ssid *bgscan_ssid;
+	const struct bgscan_ops *bgscan;
+	void *bgscan_priv;
+
+	const struct autoscan_ops *autoscan;
+	struct wpa_driver_scan_params *autoscan_params;
+	void *autoscan_priv;
+
+	struct wpa_ssid *connect_without_scan;
+
+	struct wps_ap_info *wps_ap;
+	size_t num_wps_ap;
+	int wps_ap_iter;
+
+	int after_wps;
+	int known_wps_freq;
+	unsigned int wps_freq;
+	u16 wps_ap_channel;
+	int wps_fragment_size;
+	int auto_reconnect_disabled;
+
+	 /* Channel preferences for AP/P2P GO use */
+	int best_24_freq;
+	int best_5_freq;
+	int best_overall_freq;
+
+	struct gas_query *gas;
+
+#ifdef CONFIG_INTERWORKING
+	unsigned int fetch_anqp_in_progress:1;
+	unsigned int network_select:1;
+	unsigned int auto_select:1;
+	unsigned int auto_network_select:1;
+	unsigned int fetch_all_anqp:1;
+#endif /* CONFIG_INTERWORKING */
+	unsigned int drv_capa_known;
+
+	struct {
+		struct hostapd_hw_modes *modes;
+		u16 num_modes;
+		u16 flags;
+	} hw;
+
+	int pno;
+
+	/* WLAN_REASON_* reason codes. Negative if locally generated. */
+	int disconnect_reason;
+
+	struct ext_password_data *ext_pw;
+
+	struct wpabuf *last_gas_resp;
+	u8 last_gas_addr[ETH_ALEN];
+	u8 last_gas_dialog_token;
+
+	unsigned int no_keep_alive:1;
+};
+
+
+/* wpa_supplicant.c */
+void wpa_supplicant_apply_ht_overrides(
+	struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid,
+	struct wpa_driver_associate_params *params);
+
+int wpa_set_wep_keys(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+
+int wpa_supplicant_reload_configuration(struct wpa_supplicant *wpa_s);
+
+const char * wpa_supplicant_state_txt(enum wpa_states state);
+int wpa_supplicant_update_mac_addr(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_driver_init(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
+			      struct wpa_bss *bss, struct wpa_ssid *ssid,
+			      u8 *wpa_ie, size_t *wpa_ie_len);
+void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
+			      struct wpa_bss *bss,
+			      struct wpa_ssid *ssid);
+void wpa_supplicant_set_non_wpa_policy(struct wpa_supplicant *wpa_s,
+				       struct wpa_ssid *ssid);
+void wpa_supplicant_initiate_eapol(struct wpa_supplicant *wpa_s);
+void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr);
+void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
+				     int sec, int usec);
+void wpa_supplicant_reinit_autoscan(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s,
+			      enum wpa_states state);
+struct wpa_ssid * wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s);
+const char * wpa_supplicant_get_eap_mode(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
+				   int reason_code);
+
+void wpa_supplicant_enable_network(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid);
+void wpa_supplicant_disable_network(struct wpa_supplicant *wpa_s,
+				    struct wpa_ssid *ssid);
+void wpa_supplicant_select_network(struct wpa_supplicant *wpa_s,
+				   struct wpa_ssid *ssid);
+int wpa_supplicant_set_ap_scan(struct wpa_supplicant *wpa_s,
+			       int ap_scan);
+int wpa_supplicant_set_bss_expiration_age(struct wpa_supplicant *wpa_s,
+					  unsigned int expire_age);
+int wpa_supplicant_set_bss_expiration_count(struct wpa_supplicant *wpa_s,
+					    unsigned int expire_count);
+int wpa_supplicant_set_scan_interval(struct wpa_supplicant *wpa_s,
+				     int scan_interval);
+int wpa_supplicant_set_debug_params(struct wpa_global *global,
+				    int debug_level, int debug_timestamp,
+				    int debug_show_keys);
+void free_hw_features(struct wpa_supplicant *wpa_s);
+
+void wpa_show_license(void);
+
+struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
+						 struct wpa_interface *iface);
+int wpa_supplicant_remove_iface(struct wpa_global *global,
+				struct wpa_supplicant *wpa_s,
+				int terminate);
+struct wpa_supplicant * wpa_supplicant_get_iface(struct wpa_global *global,
+						 const char *ifname);
+struct wpa_global * wpa_supplicant_init(struct wpa_params *params);
+int wpa_supplicant_run(struct wpa_global *global);
+void wpa_supplicant_deinit(struct wpa_global *global);
+
+int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid);
+void wpa_supplicant_terminate_proc(struct wpa_global *global);
+void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
+			     const u8 *buf, size_t len);
+enum wpa_key_mgmt key_mgmt2driver(int key_mgmt);
+enum wpa_cipher cipher_suite2driver(int cipher);
+void wpa_supplicant_update_config(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_clear_status(struct wpa_supplicant *wpa_s);
+void wpas_connection_failed(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpas_driver_bss_selection(struct wpa_supplicant *wpa_s);
+int wpas_is_p2p_prioritized(struct wpa_supplicant *wpa_s);
+void wpas_auth_failed(struct wpa_supplicant *wpa_s);
+void wpas_clear_temp_disabled(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid, int clear_failures);
+int disallowed_bssid(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int disallowed_ssid(struct wpa_supplicant *wpa_s, const u8 *ssid,
+		    size_t ssid_len);
+void wpas_request_connection(struct wpa_supplicant *wpa_s);
+int wpas_build_ext_capab(struct wpa_supplicant *wpa_s, u8 *buf);
+
+/**
+ * wpa_supplicant_ctrl_iface_ctrl_rsp_handle - Handle a control response
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @ssid: Pointer to the network block the reply is for
+ * @field: field the response is a reply for
+ * @value: value (ie, password, etc) for @field
+ * Returns: 0 on success, non-zero on error
+ *
+ * Helper function to handle replies to control interface requests.
+ */
+int wpa_supplicant_ctrl_iface_ctrl_rsp_handle(struct wpa_supplicant *wpa_s,
+					      struct wpa_ssid *ssid,
+					      const char *field,
+					      const char *value);
+
+/* events.c */
+void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_connect(struct wpa_supplicant *wpa_s,
+			   struct wpa_bss *selected,
+			   struct wpa_ssid *ssid);
+void wpa_supplicant_stop_countermeasures(void *eloop_ctx, void *sock_ctx);
+void wpa_supplicant_delayed_mic_error_report(void *eloop_ctx, void *sock_ctx);
+void wnm_bss_keep_alive_deinit(struct wpa_supplicant *wpa_s);
+int wpas_select_network_from_last_scan(struct wpa_supplicant *wpa_s);
+
+/* eap_register.c */
+int eap_register_methods(void);
+
+/**
+ * Utility method to tell if a given network is a persistent group
+ * @ssid: Network object
+ * Returns: 1 if network is a persistent group, 0 otherwise
+ */
+static inline int network_is_persistent_group(struct wpa_ssid *ssid)
+{
+	return ((ssid->disabled == 2) || ssid->p2p_persistent_group);
+}
+
+int wpas_network_disabled(struct wpa_supplicant *wpa_s, struct wpa_ssid *ssid);
+
+int wpas_init_ext_pw(struct wpa_supplicant *wpa_s);
+
+#endif /* WPA_SUPPLICANT_I_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/wpas_glue.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,895 @@
+/*
+ * WPA Supplicant - Glue code to setup EAPOL and RSN modules
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "rsn_supp/wpa.h"
+#include "eloop.h"
+#include "config.h"
+#include "l2_packet/l2_packet.h"
+#include "common/wpa_common.h"
+#include "wpa_supplicant_i.h"
+#include "driver_i.h"
+#include "rsn_supp/pmksa_cache.h"
+#include "sme.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "wpas_glue.h"
+#include "wps_supplicant.h"
+#include "bss.h"
+#include "scan.h"
+#include "notify.h"
+
+
+#ifndef CONFIG_NO_CONFIG_BLOBS
+#if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA)
+static void wpa_supplicant_set_config_blob(void *ctx,
+					   struct wpa_config_blob *blob)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	wpa_config_set_blob(wpa_s->conf, blob);
+	if (wpa_s->conf->update_config) {
+		int ret = wpa_config_write(wpa_s->confname, wpa_s->conf);
+		if (ret) {
+			wpa_printf(MSG_DEBUG, "Failed to update config after "
+				   "blob set");
+		}
+	}
+}
+
+
+static const struct wpa_config_blob *
+wpa_supplicant_get_config_blob(void *ctx, const char *name)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	return wpa_config_get_blob(wpa_s->conf, name);
+}
+#endif /* defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA) */
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+
+
+#if defined(IEEE8021X_EAPOL) || !defined(CONFIG_NO_WPA)
+static u8 * wpa_alloc_eapol(const struct wpa_supplicant *wpa_s, u8 type,
+			    const void *data, u16 data_len,
+			    size_t *msg_len, void **data_pos)
+{
+	struct ieee802_1x_hdr *hdr;
+
+	*msg_len = sizeof(*hdr) + data_len;
+	hdr = os_malloc(*msg_len);
+	if (hdr == NULL)
+		return NULL;
+
+	hdr->version = wpa_s->conf->eapol_version;
+	hdr->type = type;
+	hdr->length = host_to_be16(data_len);
+
+	if (data)
+		os_memcpy(hdr + 1, data, data_len);
+	else
+		os_memset(hdr + 1, 0, data_len);
+
+	if (data_pos)
+		*data_pos = hdr + 1;
+
+	return (u8 *) hdr;
+}
+
+
+/**
+ * wpa_ether_send - Send Ethernet frame
+ * @wpa_s: Pointer to wpa_supplicant data
+ * @dest: Destination MAC address
+ * @proto: Ethertype in host byte order
+ * @buf: Frame payload starting from IEEE 802.1X header
+ * @len: Frame payload length
+ * Returns: >=0 on success, <0 on failure
+ */
+static int wpa_ether_send(struct wpa_supplicant *wpa_s, const u8 *dest,
+			  u16 proto, const u8 *buf, size_t len)
+{
+	if (wpa_s->l2) {
+		return l2_packet_send(wpa_s->l2, dest, proto, buf, len);
+	}
+
+	return wpa_drv_send_eapol(wpa_s, dest, proto, buf, len);
+}
+#endif /* IEEE8021X_EAPOL || !CONFIG_NO_WPA */
+
+
+#ifdef IEEE8021X_EAPOL
+
+/**
+ * wpa_supplicant_eapol_send - Send IEEE 802.1X EAPOL packet to Authenticator
+ * @ctx: Pointer to wpa_supplicant data (wpa_s)
+ * @type: IEEE 802.1X packet type (IEEE802_1X_TYPE_*)
+ * @buf: EAPOL payload (after IEEE 802.1X header)
+ * @len: EAPOL payload length
+ * Returns: >=0 on success, <0 on failure
+ *
+ * This function adds Ethernet and IEEE 802.1X header and sends the EAPOL frame
+ * to the current Authenticator.
+ */
+static int wpa_supplicant_eapol_send(void *ctx, int type, const u8 *buf,
+				     size_t len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	u8 *msg, *dst, bssid[ETH_ALEN];
+	size_t msglen;
+	int res;
+
+	/* TODO: could add l2_packet_sendmsg that allows fragments to avoid
+	 * extra copy here */
+
+	if (wpa_key_mgmt_wpa_psk(wpa_s->key_mgmt) ||
+	    wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
+		/* Current SSID is not using IEEE 802.1X/EAP, so drop possible
+		 * EAPOL frames (mainly, EAPOL-Start) from EAPOL state
+		 * machines. */
+		wpa_printf(MSG_DEBUG, "WPA: drop TX EAPOL in non-IEEE 802.1X "
+			   "mode (type=%d len=%lu)", type,
+			   (unsigned long) len);
+		return -1;
+	}
+
+	if (pmksa_cache_get_current(wpa_s->wpa) &&
+	    type == IEEE802_1X_TYPE_EAPOL_START) {
+		/* Trying to use PMKSA caching - do not send EAPOL-Start frames
+		 * since they will trigger full EAPOL authentication. */
+		wpa_printf(MSG_DEBUG, "RSN: PMKSA caching - do not send "
+			   "EAPOL-Start");
+		return -1;
+	}
+
+	if (is_zero_ether_addr(wpa_s->bssid)) {
+		wpa_printf(MSG_DEBUG, "BSSID not set when trying to send an "
+			   "EAPOL frame");
+		if (wpa_drv_get_bssid(wpa_s, bssid) == 0 &&
+		    !is_zero_ether_addr(bssid)) {
+			dst = bssid;
+			wpa_printf(MSG_DEBUG, "Using current BSSID " MACSTR
+				   " from the driver as the EAPOL destination",
+				   MAC2STR(dst));
+		} else {
+			dst = wpa_s->last_eapol_src;
+			wpa_printf(MSG_DEBUG, "Using the source address of the"
+				   " last received EAPOL frame " MACSTR " as "
+				   "the EAPOL destination",
+				   MAC2STR(dst));
+		}
+	} else {
+		/* BSSID was already set (from (Re)Assoc event, so use it as
+		 * the EAPOL destination. */
+		dst = wpa_s->bssid;
+	}
+
+	msg = wpa_alloc_eapol(wpa_s, type, buf, len, &msglen, NULL);
+	if (msg == NULL)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "TX EAPOL: dst=" MACSTR, MAC2STR(dst));
+	wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", msg, msglen);
+	res = wpa_ether_send(wpa_s, dst, ETH_P_EAPOL, msg, msglen);
+	os_free(msg);
+	return res;
+}
+
+
+/**
+ * wpa_eapol_set_wep_key - set WEP key for the driver
+ * @ctx: Pointer to wpa_supplicant data (wpa_s)
+ * @unicast: 1 = individual unicast key, 0 = broadcast key
+ * @keyidx: WEP key index (0..3)
+ * @key: Pointer to key data
+ * @keylen: Key length in bytes
+ * Returns: 0 on success or < 0 on error.
+ */
+static int wpa_eapol_set_wep_key(void *ctx, int unicast, int keyidx,
+				 const u8 *key, size_t keylen)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+		int cipher = (keylen == 5) ? WPA_CIPHER_WEP40 :
+			WPA_CIPHER_WEP104;
+		if (unicast)
+			wpa_s->pairwise_cipher = cipher;
+		else
+			wpa_s->group_cipher = cipher;
+	}
+	return wpa_drv_set_key(wpa_s, WPA_ALG_WEP,
+			       unicast ? wpa_s->bssid : NULL,
+			       keyidx, unicast, NULL, 0, key, keylen);
+}
+
+
+static void wpa_supplicant_aborted_cached(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	wpa_sm_aborted_cached(wpa_s->wpa);
+}
+
+
+static void wpa_supplicant_eapol_cb(struct eapol_sm *eapol, int success,
+				    void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	int res, pmk_len;
+	u8 pmk[PMK_LEN];
+
+	wpa_printf(MSG_DEBUG, "EAPOL authentication completed %ssuccessfully",
+		   success ? "" : "un");
+
+	if (wpas_wps_eapol_cb(wpa_s) > 0)
+		return;
+
+	if (!success) {
+		/*
+		 * Make sure we do not get stuck here waiting for long EAPOL
+		 * timeout if the AP does not disconnect in case of
+		 * authentication failure.
+		 */
+		wpa_supplicant_req_auth_timeout(wpa_s, 2, 0);
+	}
+
+	if (!success || !(wpa_s->drv_flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+		return;
+
+	if (!wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt))
+		return;
+
+	wpa_printf(MSG_DEBUG, "Configure PMK for driver-based RSN 4-way "
+		   "handshake");
+
+	pmk_len = PMK_LEN;
+	if (wpa_key_mgmt_ft(wpa_s->key_mgmt)) {
+#ifdef CONFIG_IEEE80211R
+		u8 buf[2 * PMK_LEN];
+		wpa_printf(MSG_DEBUG, "RSN: Use FT XXKey as PMK for "
+			   "driver-based 4-way hs and FT");
+		res = eapol_sm_get_key(eapol, buf, 2 * PMK_LEN);
+		if (res == 0) {
+			os_memcpy(pmk, buf + PMK_LEN, PMK_LEN);
+			os_memset(buf, 0, sizeof(buf));
+		}
+#else /* CONFIG_IEEE80211R */
+		res = -1;
+#endif /* CONFIG_IEEE80211R */
+	} else {
+		res = eapol_sm_get_key(eapol, pmk, PMK_LEN);
+		if (res) {
+			/*
+			 * EAP-LEAP is an exception from other EAP methods: it
+			 * uses only 16-byte PMK.
+			 */
+			res = eapol_sm_get_key(eapol, pmk, 16);
+			pmk_len = 16;
+		}
+	}
+
+	if (res) {
+		wpa_printf(MSG_DEBUG, "Failed to get PMK from EAPOL state "
+			   "machines");
+		return;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "RSN: Configure PMK for driver-based 4-way "
+			"handshake", pmk, pmk_len);
+
+	if (wpa_drv_set_key(wpa_s, WPA_ALG_PMK, NULL, 0, 0, NULL, 0, pmk,
+			    pmk_len)) {
+		wpa_printf(MSG_DEBUG, "Failed to set PMK to the driver");
+	}
+
+	wpa_supplicant_cancel_scan(wpa_s);
+	wpa_supplicant_cancel_auth_timeout(wpa_s);
+	wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+
+}
+
+
+static void wpa_supplicant_notify_eapol_done(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	wpa_msg(wpa_s, MSG_DEBUG, "WPA: EAPOL processing complete");
+	if (wpa_key_mgmt_wpa_ieee8021x(wpa_s->key_mgmt)) {
+		wpa_supplicant_set_state(wpa_s, WPA_4WAY_HANDSHAKE);
+	} else {
+		wpa_supplicant_cancel_auth_timeout(wpa_s);
+		wpa_supplicant_set_state(wpa_s, WPA_COMPLETED);
+	}
+}
+
+#endif /* IEEE8021X_EAPOL */
+
+
+#ifndef CONFIG_NO_WPA
+
+static int wpa_get_beacon_ie(struct wpa_supplicant *wpa_s)
+{
+	int ret = 0;
+	struct wpa_bss *curr = NULL, *bss;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	const u8 *ie;
+
+	dl_list_for_each(bss, &wpa_s->bss, struct wpa_bss, list) {
+		if (os_memcmp(bss->bssid, wpa_s->bssid, ETH_ALEN) != 0)
+			continue;
+		if (ssid == NULL ||
+		    ((bss->ssid_len == ssid->ssid_len &&
+		      os_memcmp(bss->ssid, ssid->ssid, ssid->ssid_len) == 0) ||
+		     ssid->ssid_len == 0)) {
+			curr = bss;
+			break;
+		}
+	}
+
+	if (curr) {
+		ie = wpa_bss_get_vendor_ie(curr, WPA_IE_VENDOR_TYPE);
+		if (wpa_sm_set_ap_wpa_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
+			ret = -1;
+
+		ie = wpa_bss_get_ie(curr, WLAN_EID_RSN);
+		if (wpa_sm_set_ap_rsn_ie(wpa_s->wpa, ie, ie ? 2 + ie[1] : 0))
+			ret = -1;
+	} else {
+		ret = -1;
+	}
+
+	return ret;
+}
+
+
+static int wpa_supplicant_get_beacon_ie(void *ctx)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_get_beacon_ie(wpa_s) == 0) {
+		return 0;
+	}
+
+	/* No WPA/RSN IE found in the cached scan results. Try to get updated
+	 * scan results from the driver. */
+	if (wpa_supplicant_update_scan_results(wpa_s) < 0)
+		return -1;
+
+	return wpa_get_beacon_ie(wpa_s);
+}
+
+
+static u8 * _wpa_alloc_eapol(void *wpa_s, u8 type,
+			     const void *data, u16 data_len,
+			     size_t *msg_len, void **data_pos)
+{
+	return wpa_alloc_eapol(wpa_s, type, data, data_len, msg_len, data_pos);
+}
+
+
+static int _wpa_ether_send(void *wpa_s, const u8 *dest, u16 proto,
+			   const u8 *buf, size_t len)
+{
+	return wpa_ether_send(wpa_s, dest, proto, buf, len);
+}
+
+
+static void _wpa_supplicant_cancel_auth_timeout(void *wpa_s)
+{
+	wpa_supplicant_cancel_auth_timeout(wpa_s);
+}
+
+
+static void _wpa_supplicant_set_state(void *wpa_s, enum wpa_states state)
+{
+	wpa_supplicant_set_state(wpa_s, state);
+}
+
+
+/**
+ * wpa_supplicant_get_state - Get the connection state
+ * @wpa_s: Pointer to wpa_supplicant data
+ * Returns: The current connection state (WPA_*)
+ */
+static enum wpa_states wpa_supplicant_get_state(struct wpa_supplicant *wpa_s)
+{
+	return wpa_s->wpa_state;
+}
+
+
+static enum wpa_states _wpa_supplicant_get_state(void *wpa_s)
+{
+	return wpa_supplicant_get_state(wpa_s);
+}
+
+
+static void _wpa_supplicant_deauthenticate(void *wpa_s, int reason_code)
+{
+	wpa_supplicant_deauthenticate(wpa_s, reason_code);
+	/* Schedule a scan to make sure we continue looking for networks */
+	wpa_supplicant_req_scan(wpa_s, 5, 0);
+}
+
+
+static void * wpa_supplicant_get_network_ctx(void *wpa_s)
+{
+	return wpa_supplicant_get_ssid(wpa_s);
+}
+
+
+static int wpa_supplicant_get_bssid(void *ctx, u8 *bssid)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	return wpa_drv_get_bssid(wpa_s, bssid);
+}
+
+
+static int wpa_supplicant_set_key(void *_wpa_s, enum wpa_alg alg,
+				  const u8 *addr, int key_idx, int set_tx,
+				  const u8 *seq, size_t seq_len,
+				  const u8 *key, size_t key_len)
+{
+	struct wpa_supplicant *wpa_s = _wpa_s;
+	if (alg == WPA_ALG_TKIP && key_idx == 0 && key_len == 32) {
+		/* Clear the MIC error counter when setting a new PTK. */
+		wpa_s->mic_errors_seen = 0;
+	}
+	return wpa_drv_set_key(wpa_s, alg, addr, key_idx, set_tx, seq, seq_len,
+			       key, key_len);
+}
+
+
+static int wpa_supplicant_mlme_setprotection(void *wpa_s, const u8 *addr,
+					     int protection_type,
+					     int key_type)
+{
+	return wpa_drv_mlme_setprotection(wpa_s, addr, protection_type,
+					  key_type);
+}
+
+
+static int wpa_supplicant_add_pmkid(void *wpa_s,
+				    const u8 *bssid, const u8 *pmkid)
+{
+	return wpa_drv_add_pmkid(wpa_s, bssid, pmkid);
+}
+
+
+static int wpa_supplicant_remove_pmkid(void *wpa_s,
+				       const u8 *bssid, const u8 *pmkid)
+{
+	return wpa_drv_remove_pmkid(wpa_s, bssid, pmkid);
+}
+
+
+#ifdef CONFIG_IEEE80211R
+static int wpa_supplicant_update_ft_ies(void *ctx, const u8 *md,
+					const u8 *ies, size_t ies_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_SME)
+		return sme_update_ft_ies(wpa_s, md, ies, ies_len);
+	return wpa_drv_update_ft_ies(wpa_s, md, ies, ies_len);
+}
+
+
+static int wpa_supplicant_send_ft_action(void *ctx, u8 action,
+					 const u8 *target_ap,
+					 const u8 *ies, size_t ies_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	return wpa_drv_send_ft_action(wpa_s, action, target_ap, ies, ies_len);
+}
+
+
+static int wpa_supplicant_mark_authenticated(void *ctx, const u8 *target_ap)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct wpa_driver_auth_params params;
+	struct wpa_bss *bss;
+
+	bss = wpa_bss_get_bssid(wpa_s, target_ap);
+	if (bss == NULL)
+		return -1;
+
+	os_memset(&params, 0, sizeof(params));
+	params.bssid = target_ap;
+	params.freq = bss->freq;
+	params.ssid = bss->ssid;
+	params.ssid_len = bss->ssid_len;
+	params.auth_alg = WPA_AUTH_ALG_FT;
+	params.local_state_change = 1;
+	return wpa_drv_authenticate(wpa_s, &params);
+}
+#endif /* CONFIG_IEEE80211R */
+
+#endif /* CONFIG_NO_WPA */
+
+
+#ifdef CONFIG_TDLS
+
+static int wpa_supplicant_tdls_get_capa(void *ctx, int *tdls_supported,
+					int *tdls_ext_setup)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	*tdls_supported = 0;
+	*tdls_ext_setup = 0;
+
+	if (!wpa_s->drv_capa_known)
+		return -1;
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_SUPPORT)
+		*tdls_supported = 1;
+
+	if (wpa_s->drv_flags & WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP)
+		*tdls_ext_setup = 1;
+
+	return 0;
+}
+
+
+static int wpa_supplicant_send_tdls_mgmt(void *ctx, const u8 *dst,
+					 u8 action_code, u8 dialog_token,
+					 u16 status_code, const u8 *buf,
+					 size_t len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	return wpa_drv_send_tdls_mgmt(wpa_s, dst, action_code, dialog_token,
+				      status_code, buf, len);
+}
+
+
+static int wpa_supplicant_tdls_oper(void *ctx, int oper, const u8 *peer)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	return wpa_drv_tdls_oper(wpa_s, oper, peer);
+}
+
+
+static int wpa_supplicant_tdls_peer_addset(
+	void *ctx, const u8 *peer, int add, u16 capability,
+	const u8 *supp_rates, size_t supp_rates_len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct hostapd_sta_add_params params;
+
+	params.addr = peer;
+	params.aid = 1;
+	params.capability = capability;
+	params.flags = WPA_STA_TDLS_PEER | WPA_STA_AUTHORIZED;
+	params.ht_capabilities = NULL;
+	params.listen_interval = 0;
+	params.supp_rates = supp_rates;
+	params.supp_rates_len = supp_rates_len;
+	params.set = !add;
+
+	return wpa_drv_sta_add(wpa_s, &params);
+}
+
+#endif /* CONFIG_TDLS */
+
+
+enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field)
+{
+	if (os_strcmp(field, "IDENTITY") == 0)
+		return WPA_CTRL_REQ_EAP_IDENTITY;
+	else if (os_strcmp(field, "PASSWORD") == 0)
+		return WPA_CTRL_REQ_EAP_PASSWORD;
+	else if (os_strcmp(field, "NEW_PASSWORD") == 0)
+		return WPA_CTRL_REQ_EAP_NEW_PASSWORD;
+	else if (os_strcmp(field, "PIN") == 0)
+		return WPA_CTRL_REQ_EAP_PIN;
+	else if (os_strcmp(field, "OTP") == 0)
+		return WPA_CTRL_REQ_EAP_OTP;
+	else if (os_strcmp(field, "PASSPHRASE") == 0)
+		return WPA_CTRL_REQ_EAP_PASSPHRASE;
+	return WPA_CTRL_REQ_UNKNOWN;
+}
+
+
+const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
+					       const char *default_txt,
+					       const char **txt)
+{
+	const char *ret = NULL;
+
+	*txt = default_txt;
+
+	switch (field) {
+	case WPA_CTRL_REQ_EAP_IDENTITY:
+		*txt = "Identity";
+		ret = "IDENTITY";
+		break;
+	case WPA_CTRL_REQ_EAP_PASSWORD:
+		*txt = "Password";
+		ret = "PASSWORD";
+		break;
+	case WPA_CTRL_REQ_EAP_NEW_PASSWORD:
+		*txt = "New Password";
+		ret = "NEW_PASSWORD";
+		break;
+	case WPA_CTRL_REQ_EAP_PIN:
+		*txt = "PIN";
+		ret = "PIN";
+		break;
+	case WPA_CTRL_REQ_EAP_OTP:
+		ret = "OTP";
+		break;
+	case WPA_CTRL_REQ_EAP_PASSPHRASE:
+		*txt = "Private key passphrase";
+		ret = "PASSPHRASE";
+		break;
+	default:
+		break;
+	}
+
+	/* txt needs to be something */
+	if (*txt == NULL) {
+		wpa_printf(MSG_WARNING, "No message for request %d", field);
+		ret = NULL;
+	}
+
+	return ret;
+}
+
+#ifdef IEEE8021X_EAPOL
+#if defined(CONFIG_CTRL_IFACE) || !defined(CONFIG_NO_STDOUT_DEBUG)
+static void wpa_supplicant_eap_param_needed(void *ctx,
+					    enum wpa_ctrl_req_type field,
+					    const char *default_txt)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	struct wpa_ssid *ssid = wpa_s->current_ssid;
+	const char *field_name, *txt = NULL;
+	char *buf;
+	size_t buflen;
+	int len;
+
+	if (ssid == NULL)
+		return;
+
+	wpas_notify_network_request(wpa_s, ssid, field, default_txt);
+
+	field_name = wpa_supplicant_ctrl_req_to_string(field, default_txt,
+						       &txt);
+	if (field_name == NULL) {
+		wpa_printf(MSG_WARNING, "Unhandled EAP param %d needed",
+			   field);
+		return;
+	}
+
+	buflen = 100 + os_strlen(txt) + ssid->ssid_len;
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return;
+	len = os_snprintf(buf, buflen,
+			  WPA_CTRL_REQ "%s-%d:%s needed for SSID ",
+			  field_name, ssid->id, txt);
+	if (len < 0 || (size_t) len >= buflen) {
+		os_free(buf);
+		return;
+	}
+	if (ssid->ssid && buflen > len + ssid->ssid_len) {
+		os_memcpy(buf + len, ssid->ssid, ssid->ssid_len);
+		len += ssid->ssid_len;
+		buf[len] = '\0';
+	}
+	buf[buflen - 1] = '\0';
+	wpa_msg(wpa_s, MSG_INFO, "%s", buf);
+	os_free(buf);
+}
+#else /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+#define wpa_supplicant_eap_param_needed NULL
+#endif /* CONFIG_CTRL_IFACE || !CONFIG_NO_STDOUT_DEBUG */
+
+
+static void wpa_supplicant_port_cb(void *ctx, int authorized)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+#ifdef CONFIG_AP
+	if (wpa_s->ap_iface) {
+		wpa_printf(MSG_DEBUG, "AP mode active - skip EAPOL Supplicant "
+			   "port status: %s",
+			   authorized ? "Authorized" : "Unauthorized");
+		return;
+	}
+#endif /* CONFIG_AP */
+	wpa_printf(MSG_DEBUG, "EAPOL: Supplicant port status: %s",
+		   authorized ? "Authorized" : "Unauthorized");
+	wpa_drv_set_supp_port(wpa_s, authorized);
+}
+
+
+static void wpa_supplicant_cert_cb(void *ctx, int depth, const char *subject,
+				   const char *cert_hash,
+				   const struct wpabuf *cert)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpas_notify_certification(wpa_s, depth, subject, cert_hash, cert);
+}
+
+
+static void wpa_supplicant_status_cb(void *ctx, const char *status,
+				     const char *parameter)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpas_notify_eap_status(wpa_s, status, parameter);
+}
+
+
+static void wpa_supplicant_set_anon_id(void *ctx, const u8 *id, size_t len)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+	char *str;
+	int res;
+
+	wpa_hexdump_ascii(MSG_DEBUG, "EAP method updated anonymous_identity",
+			  id, len);
+
+	if (wpa_s->current_ssid == NULL)
+		return;
+
+	if (id == NULL) {
+		if (wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+				   "NULL", 0) < 0)
+			return;
+	} else {
+		str = os_malloc(len * 2 + 1);
+		if (str == NULL)
+			return;
+		wpa_snprintf_hex(str, len * 2 + 1, id, len);
+		res = wpa_config_set(wpa_s->current_ssid, "anonymous_identity",
+				     str, 0);
+		os_free(str);
+		if (res < 0)
+			return;
+	}
+
+	if (wpa_s->conf->update_config) {
+		res = wpa_config_write(wpa_s->confname, wpa_s->conf);
+		if (res) {
+			wpa_printf(MSG_DEBUG, "Failed to update config after "
+				   "anonymous_id update");
+		}
+	}
+}
+#endif /* IEEE8021X_EAPOL */
+
+
+int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s)
+{
+#ifdef IEEE8021X_EAPOL
+	struct eapol_ctx *ctx;
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to allocate EAPOL context.");
+		return -1;
+	}
+
+	ctx->ctx = wpa_s;
+	ctx->msg_ctx = wpa_s;
+	ctx->eapol_send_ctx = wpa_s;
+	ctx->preauth = 0;
+	ctx->eapol_done_cb = wpa_supplicant_notify_eapol_done;
+	ctx->eapol_send = wpa_supplicant_eapol_send;
+	ctx->set_wep_key = wpa_eapol_set_wep_key;
+	ctx->set_config_blob = wpa_supplicant_set_config_blob;
+	ctx->get_config_blob = wpa_supplicant_get_config_blob;
+	ctx->aborted_cached = wpa_supplicant_aborted_cached;
+	ctx->opensc_engine_path = wpa_s->conf->opensc_engine_path;
+	ctx->pkcs11_engine_path = wpa_s->conf->pkcs11_engine_path;
+	ctx->pkcs11_module_path = wpa_s->conf->pkcs11_module_path;
+	ctx->wps = wpa_s->wps;
+	ctx->eap_param_needed = wpa_supplicant_eap_param_needed;
+	ctx->port_cb = wpa_supplicant_port_cb;
+	ctx->cb = wpa_supplicant_eapol_cb;
+	ctx->cert_cb = wpa_supplicant_cert_cb;
+	ctx->status_cb = wpa_supplicant_status_cb;
+	ctx->set_anon_id = wpa_supplicant_set_anon_id;
+	ctx->cb_ctx = wpa_s;
+	wpa_s->eapol = eapol_sm_init(ctx);
+	if (wpa_s->eapol == NULL) {
+		os_free(ctx);
+		wpa_printf(MSG_ERROR, "Failed to initialize EAPOL state "
+			   "machines.");
+		return -1;
+	}
+#endif /* IEEE8021X_EAPOL */
+
+	return 0;
+}
+
+
+#ifndef CONFIG_NO_WPA
+static void wpa_supplicant_set_rekey_offload(void *ctx, const u8 *kek,
+					     const u8 *kck,
+					     const u8 *replay_ctr)
+{
+	struct wpa_supplicant *wpa_s = ctx;
+
+	wpa_drv_set_rekey_info(wpa_s, kek, kck, replay_ctr);
+}
+#endif /* CONFIG_NO_WPA */
+
+
+int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s)
+{
+#ifndef CONFIG_NO_WPA
+	struct wpa_sm_ctx *ctx;
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to allocate WPA context.");
+		return -1;
+	}
+
+	ctx->ctx = wpa_s;
+	ctx->msg_ctx = wpa_s;
+	ctx->set_state = _wpa_supplicant_set_state;
+	ctx->get_state = _wpa_supplicant_get_state;
+	ctx->deauthenticate = _wpa_supplicant_deauthenticate;
+	ctx->set_key = wpa_supplicant_set_key;
+	ctx->get_network_ctx = wpa_supplicant_get_network_ctx;
+	ctx->get_bssid = wpa_supplicant_get_bssid;
+	ctx->ether_send = _wpa_ether_send;
+	ctx->get_beacon_ie = wpa_supplicant_get_beacon_ie;
+	ctx->alloc_eapol = _wpa_alloc_eapol;
+	ctx->cancel_auth_timeout = _wpa_supplicant_cancel_auth_timeout;
+	ctx->add_pmkid = wpa_supplicant_add_pmkid;
+	ctx->remove_pmkid = wpa_supplicant_remove_pmkid;
+#ifndef CONFIG_NO_CONFIG_BLOBS
+	ctx->set_config_blob = wpa_supplicant_set_config_blob;
+	ctx->get_config_blob = wpa_supplicant_get_config_blob;
+#endif /* CONFIG_NO_CONFIG_BLOBS */
+	ctx->mlme_setprotection = wpa_supplicant_mlme_setprotection;
+#ifdef CONFIG_IEEE80211R
+	ctx->update_ft_ies = wpa_supplicant_update_ft_ies;
+	ctx->send_ft_action = wpa_supplicant_send_ft_action;
+	ctx->mark_authenticated = wpa_supplicant_mark_authenticated;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_TDLS
+	ctx->tdls_get_capa = wpa_supplicant_tdls_get_capa;
+	ctx->send_tdls_mgmt = wpa_supplicant_send_tdls_mgmt;
+	ctx->tdls_oper = wpa_supplicant_tdls_oper;
+	ctx->tdls_peer_addset = wpa_supplicant_tdls_peer_addset;
+#endif /* CONFIG_TDLS */
+	ctx->set_rekey_offload = wpa_supplicant_set_rekey_offload;
+
+	wpa_s->wpa = wpa_sm_init(ctx);
+	if (wpa_s->wpa == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
+			   "machine");
+		return -1;
+	}
+#endif /* CONFIG_NO_WPA */
+
+	return 0;
+}
+
+
+void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid)
+{
+	struct rsn_supp_config conf;
+	if (ssid) {
+		os_memset(&conf, 0, sizeof(conf));
+		conf.network_ctx = ssid;
+		conf.peerkey_enabled = ssid->peerkey;
+		conf.allowed_pairwise_cipher = ssid->pairwise_cipher;
+#ifdef IEEE8021X_EAPOL
+		conf.proactive_key_caching = ssid->proactive_key_caching < 0 ?
+			wpa_s->conf->okc : ssid->proactive_key_caching;
+		conf.eap_workaround = ssid->eap_workaround;
+		conf.eap_conf_ctx = &ssid->eap;
+#endif /* IEEE8021X_EAPOL */
+		conf.ssid = ssid->ssid;
+		conf.ssid_len = ssid->ssid_len;
+		conf.wpa_ptk_rekey = ssid->wpa_ptk_rekey;
+	}
+	wpa_sm_set_config(wpa_s->wpa, ssid ? &conf : NULL);
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/wpas_glue.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,25 @@
+/*
+ * WPA Supplicant - Glue code to setup EAPOL and RSN modules
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPAS_GLUE_H
+#define WPAS_GLUE_H
+
+enum wpa_ctrl_req_type;
+
+int wpa_supplicant_init_eapol(struct wpa_supplicant *wpa_s);
+int wpa_supplicant_init_wpa(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_rsn_supp_set_config(struct wpa_supplicant *wpa_s,
+					struct wpa_ssid *ssid);
+
+const char * wpa_supplicant_ctrl_req_to_string(enum wpa_ctrl_req_type field,
+					       const char *default_txt,
+					       const char **txt);
+
+enum wpa_ctrl_req_type wpa_supplicant_ctrl_req_from_string(const char *field);
+
+#endif /* WPAS_GLUE_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/wpa_supplicant/wps_supplicant.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,142 @@
+/*
+ * wpa_supplicant / WPS integration
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPS_SUPPLICANT_H
+#define WPS_SUPPLICANT_H
+
+struct wpa_scan_results;
+
+#ifdef CONFIG_WPS
+
+#include "wps/wps.h"
+#include "wps/wps_defs.h"
+
+struct wpa_bss;
+
+struct wps_new_ap_settings {
+	const char *ssid_hex;
+	const char *auth;
+	const char *encr;
+	const char *key_hex;
+};
+
+int wpas_wps_init(struct wpa_supplicant *wpa_s);
+void wpas_wps_deinit(struct wpa_supplicant *wpa_s);
+int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s);
+enum wps_request_type wpas_wps_get_req_type(struct wpa_ssid *ssid);
+int wpas_wps_start_pbc(struct wpa_supplicant *wpa_s, const u8 *bssid,
+		       int p2p_group);
+int wpas_wps_start_pin(struct wpa_supplicant *wpa_s, const u8 *bssid,
+		       const char *pin, int p2p_group, u16 dev_pw_id);
+int wpas_wps_cancel(struct wpa_supplicant *wpa_s);
+int wpas_wps_start_reg(struct wpa_supplicant *wpa_s, const u8 *bssid,
+		       const char *pin, struct wps_new_ap_settings *settings);
+int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
+			    struct wpa_ssid *ssid, struct wpa_bss *bss);
+int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
+			      struct wpa_ssid *ssid, struct wpa_bss *bss);
+int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
+			      struct wpa_bss *selected, struct wpa_ssid *ssid);
+void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s);
+int wpas_wps_searching(struct wpa_supplicant *wpa_s);
+int wpas_wps_scan_result_text(const u8 *ies, size_t ies_len, char *pos,
+			      char *end);
+int wpas_wps_er_start(struct wpa_supplicant *wpa_s, const char *filter);
+int wpas_wps_er_stop(struct wpa_supplicant *wpa_s);
+int wpas_wps_er_add_pin(struct wpa_supplicant *wpa_s, const u8 *addr,
+			const char *uuid, const char *pin);
+int wpas_wps_er_pbc(struct wpa_supplicant *wpa_s, const char *uuid);
+int wpas_wps_er_learn(struct wpa_supplicant *wpa_s, const char *uuid,
+		      const char *pin);
+int wpas_wps_er_set_config(struct wpa_supplicant *wpa_s, const char *uuid,
+			   int id);
+int wpas_wps_er_config(struct wpa_supplicant *wpa_s, const char *uuid,
+		       const char *pin, struct wps_new_ap_settings *settings);
+struct wpabuf * wpas_wps_er_nfc_config_token(struct wpa_supplicant *wpa_s,
+					     int ndef, const char *uuid);
+int wpas_wps_terminate_pending(struct wpa_supplicant *wpa_s);
+int wpas_wps_in_progress(struct wpa_supplicant *wpa_s);
+void wpas_wps_update_config(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_wps_nfc_token(struct wpa_supplicant *wpa_s, int ndef);
+int wpas_wps_start_nfc(struct wpa_supplicant *wpa_s, const u8 *bssid);
+int wpas_wps_nfc_tag_read(struct wpa_supplicant *wpa_s,
+			  const struct wpabuf *data);
+struct wpabuf * wpas_wps_nfc_handover_req(struct wpa_supplicant *wpa_s);
+struct wpabuf * wpas_wps_nfc_handover_sel(struct wpa_supplicant *wpa_s);
+int wpas_wps_nfc_rx_handover_req(struct wpa_supplicant *wpa_s,
+				 const struct wpabuf *data);
+int wpas_wps_nfc_rx_handover_sel(struct wpa_supplicant *wpa_s,
+				 const struct wpabuf *data);
+void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
+			     struct wpa_scan_results *scan_res);
+void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s, const u8 *bssid);
+
+#else /* CONFIG_WPS */
+
+static inline int wpas_wps_init(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline void wpas_wps_deinit(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline u8 wpas_wps_get_req_type(struct wpa_ssid *ssid)
+{
+	return 0;
+}
+
+static inline int wpas_wps_ssid_bss_match(struct wpa_supplicant *wpa_s,
+					  struct wpa_ssid *ssid,
+					  struct wpa_bss *bss)
+{
+	return -1;
+}
+
+static inline int wpas_wps_ssid_wildcard_ok(struct wpa_supplicant *wpa_s,
+					    struct wpa_ssid *ssid,
+					    struct wpa_bss *bss)
+{
+	return 0;
+}
+
+static inline int wpas_wps_scan_pbc_overlap(struct wpa_supplicant *wpa_s,
+					    struct wpa_bss *selected,
+					    struct wpa_ssid *ssid)
+{
+	return 0;
+}
+
+static inline void wpas_wps_notify_scan_results(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline int wpas_wps_searching(struct wpa_supplicant *wpa_s)
+{
+	return 0;
+}
+
+static inline void wpas_wps_update_ap_info(struct wpa_supplicant *wpa_s,
+					   struct wpa_scan_results *scan_res)
+{
+}
+
+static inline void wpas_wps_notify_assoc(struct wpa_supplicant *wpa_s,
+					 const u8 *bssid)
+{
+}
+
+#endif /* CONFIG_WPS */
+
+#endif /* WPS_SUPPLICANT_H */
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/Makefile	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,59 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-PROG =		wpad
-MANIFEST =	wpa.xml
-OBJS =		wpa_supplicant.o wpa.o wpa_enc.o eloop.o \
-		driver_wifi.o l2_packet.o
-SRCS = 		$(OBJS:%.o=%.c)
-
-include	../../../Makefile.cmd
-
-ROOTMANIFESTDIR = $(ROOTSVCNETWORK)
-
-LDLIBS    += 	-ldladm -ldlpi
-all install := LDLIBS += -lcrypto
-
-LINTFLAGS += 	-u
-
-.KEEP_STATE:
-
-all:		$(PROG)
-
-$(PROG):	$(OBJS)
-		$(LINK.c) $(OBJS) -o $@ $(LDLIBS)
-		$(POST_PROCESS)
-
-include ../Makefile.lib
-
-install:	all $(ROOTLIBINETPROG) $(ROOTMANIFEST)
-
-check:		$(CHKMANIFEST)
-
-clean:
-		$(RM) $(OBJS)
-
-lint:		lint_SRCS
-
-include ../../../Makefile.targ
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/README	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,772 +0,0 @@
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-WPA Supplicant
-==============
-
-Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
-All Rights Reserved.
-
-Sun elects to license this software under the BSD license.
-
-
-License
--------
-
-BSD license:
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-1. Redistributions of source code must retain the above copyright
-   notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
-   notice, this list of conditions and the following disclaimer in the
-   documentation and/or other materials provided with the distribution.
-
-3. Neither the name(s) of the above-listed copyright holder(s) nor the
-   names of its contributors may be used to endorse or promote products
-   derived from this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-
-
-Features
---------
-
-Supported WPA/IEEE 802.11i features:
-- WPA-PSK ("WPA-Personal")
-- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise")
-  Following authentication methods are supported with an integrate IEEE 802.1X
-  Supplicant:
-  * EAP-TLS
-  * EAP-PEAP/MSCHAPv2 (both PEAPv0 and PEAPv1)
-  * EAP-PEAP/TLS (both PEAPv0 and PEAPv1)
-  * EAP-PEAP/GTC (both PEAPv0 and PEAPv1)
-  * EAP-PEAP/OTP (both PEAPv0 and PEAPv1)
-  * EAP-PEAP/MD5-Challenge (both PEAPv0 and PEAPv1)
-  * EAP-TTLS/EAP-MD5-Challenge
-  * EAP-TTLS/EAP-GTC
-  * EAP-TTLS/EAP-OTP
-  * EAP-TTLS/EAP-MSCHAPv2
-  * EAP-TTLS/EAP-TLS
-  * EAP-TTLS/MSCHAPv2
-  * EAP-TTLS/MSCHAP
-  * EAP-TTLS/PAP
-  * EAP-TTLS/CHAP
-  * EAP-SIM
-  * LEAP (note: only with WEP keys, i.e., not for WPA; in addition, LEAP
-	requires special support from the driver for IEEE 802.11
-	authentication)
-  (following methods are supported, but since they do not generate keying
-   material, they cannot be used with WPA or IEEE 802.1X WEP keying)
-  * EAP-MD5-Challenge 
-  * EAP-MSCHAPv2
-  * EAP-GTC
-  * EAP-OTP
-  Alternatively, an external program, e.g., Xsupplicant, can be used for EAP
-  authentication.
-- key management for CCMP, TKIP, WEP104, WEP40
-- RSN/WPA2 (IEEE 802.11i)
-  * pre-authentication
-  * PMKSA caching
-
-
-
-Requirements
-------------
-
-Current hardware/software requirements:
-- Linux kernel 2.4.x or 2.6.x
-- Linux Wireless Extensions v15 or newer
-- drivers:
-	Host AP driver for Prism2/2.5/3 (development snapshot/v0.2.x)
-	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 Makefile
-	to use correct path for madwifi driver root directory
-	(CFLAGS += -I../madwifi/wpa line in Makefile).
-
-	ATMEL AT76C5XXx driver for USB and PCMCIA cards
-	(http://atmelwlandriver.sourceforge.net/).
-
-	Linux ndiswrapper (http://ndiswrapper.sourceforge.net/) with
-	Windows NDIS driver.
-
-	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.
-
-wpa_supplicant was designed to be portable for different drivers and
-operating systems. Hopefully, support for more wlan cards will be
-added in the future. See developer.txt for more information about the
-design of wpa_supplicant and porting to other drivers. One main goal
-is to add full WPA/WPA2 support to Linux wireless extensions to allow
-new drivers to be supported without having to implement new
-driver-specific interface code in wpa_supplicant.
-
-Optional libraries for layer2 packet processing:
-- libpcap (tested with 0.7.2, most relatively recent versions assumed to work,
-	this is likely to be available with most distributions,
-	http://tcpdump.org/)
-- libdnet (tested with v1.4, most versions assumed to work,
-	http://libdnet.sourceforge.net/)
-
-These libraries are _not_ used in the default build. Instead, internal
-Linux specific implementation is used. libpcap/libdnet are more
-portable and they can be used by modifying Makefile (define
-USE_DNET_PCAP and link with these libraries).
-
-
-Optional libraries for EAP-TLS, EAP-PEAP, and EAP-TTLS:
-- openssl (tested with 0.9.7c and 0.9.7d, assumed to work with most
-  relatively recent versions; this is likely to be available with most
-  distributions, http://www.openssl.org/)
-
-This library is only needed when EAP-TLS, EAP-PEAP, or EAP-TTLS
-support is enabled. WPA-PSK mode does not require this or EAPOL/EAP
-implementation. A configuration file, .config, for compilation is
-needed to enable IEEE 802.1X/EAPOL and EAP methods. Note that EAP-MD5,
-EAP-GTC, EAP-OTP, and EAP-MSCHAPV2 cannot be used alone with WPA, so
-they should only be enabled if testing the EAPOL/EAP state
-machines. However, there can be used as inner authentication
-algorithms with EAP-PEAP and EAP-TTLS.
-
-See Building and installing section below for more detailed
-information about the wpa_supplicant build time configuration.
-
-
-
-WPA
----
-
-The original security mechanism of IEEE 802.11 standard was not
-designed to be strong and has 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 choice have proved 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, key 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.
-Certification for WPA2 is likely to start during the second half of
-2004.
-
-
-
-wpa_supplicant
---------------
-
-wpa_supplicant is an implementation of the WPA Supplicant component,
-i.e., the part that runs in the client stations. It implements WPA key
-negotiation with a WPA Authenticator and EAP authentication with
-Authentication Server. In addition, it controls the roaming and IEEE
-802.11 authentication/association of the wlan driver.
-
-wpa_supplicant is designed to be a "daemon" program that runs in the
-background and acts as the backend component controlling the wireless
-connection. wpa_supplicant supports separate frontend programs and an
-example text-based frontend, wpa_cli, is included with wpa_supplicant.
-
-Following steps are used when associating with an AP using WPA:
-
-- wpa_supplicant requests the kernel driver to scan neighboring BSSes
-- wpa_supplicant selects a BSS based on its configuration
-- wpa_supplicant requests the kernel driver to associate with the chosen
-  BSS
-- If WPA-EAP: integrated IEEE 802.1X Supplicant or external Xsupplicant
-  completes EAP authentication with the authentication server (proxied
-  by the Authenticator in the AP)
-- If WPA-EAP: master key is received from the IEEE 802.1X Supplicant
-- If WPA-PSK: wpa_supplicant uses PSK as the master session key
-- wpa_supplicant completes WPA 4-Way Handshake and Group Key Handshake
-  with the Authenticator (AP)
-- wpa_supplicant configures encryption keys for unicast and broadcast
-- normal data packets can be transmitted and received
-
-
-
-Building and installing
------------------------
-
-In order to be able to build wpa_supplicant, you will first need to
-select which parts of it will be included. This is done by creating a
-build time configuration file, .config, in the wpa_supplicant root
-directory. Configuration options are text lines using following
-format: CONFIG_<option>=y. Lines starting with # are considered
-comments and are ignored.
-
-The build time configuration can be used to select only the needed
-features and limit the binary size and requirements for external
-libraries. The main configuration parts are the selection of which
-driver interfaces (e.g., hostap, madwifi, ..) and which authentication
-methods (e.g., EAP-TLS, EAP-PEAP, ..) are included.
-
-Following build time configuration options are used to control IEEE
-802.1X/EAPOL and EAP state machines and all EAP methods. Including
-TLS, PEAP, or TTLS will require linking wpa_supplicant with openssl
-library for TLS implementation.
-
-CONFIG_IEEE8021X_EAPOL=y
-CONFIG_EAP_MD5=y
-CONFIG_MSCHAPV2=y
-CONFIG_EAP_TLS=y
-CONFIG_EAP_PEAP=y
-CONFIG_EAP_TTLS=y
-CONFIG_EAP_GTC=y
-CONFIG_EAP_OTP=y
-CONFIG_EAP_SIM=y
-CONFIG_EAP_LEAP=y
-
-Following option can be used to include GSM SIM/USIM interface for GSM
-authentication algorithm (for EAP-SIM). This requires pcsc-lite
-(http://www.linuxnet.com/) for smart card access.
-
-CONFIG_PCSC=y
-
-Following options can be added to .config to select which driver
-interfaces are included. Prism54.org driver is not yet complete and
-Hermes driver interface needs to be downloaded from Agere (see above).
-Most Linux driver need to include CONFIG_WIRELESS_EXTENSION.
-
-CONFIG_WIRELESS_EXTENSION=y
-CONFIG_DRIVER_HOSTAP=y
-CONFIG_DRIVER_PRISM54=y
-CONFIG_DRIVER_HERMES=y
-CONFIG_DRIVER_MADWIFI=y
-CONFIG_DRIVER_ATMEL=y
-CONFIG_DRIVER_WEXT=y
-CONFIG_DRIVER_NDISWRAPPER=y
-
-Following example includes all features and driver interfaces that are
-included in the wpa_supplicant package:
-
-CONFIG_DRIVER_HOSTAP=y
-CONFIG_DRIVER_PRISM54=y
-CONFIG_DRIVER_HERMES=y
-CONFIG_DRIVER_MADWIFI=y
-CONFIG_DRIVER_ATMEL=y
-CONFIG_DRIVER_WEXT=y
-CONFIG_DRIVER_NDISWRAPPER=y
-CONFIG_WIRELESS_EXTENSION=y
-CONFIG_IEEE8021X_EAPOL=y
-CONFIG_EAP_MD5=y
-CONFIG_MSCHAPV2=y
-CONFIG_EAP_TLS=y
-CONFIG_EAP_PEAP=y
-CONFIG_EAP_TTLS=y
-CONFIG_EAP_GTC=y
-CONFIG_EAP_OTP=y
-CONFIG_EAP_SIM=y
-CONFIG_EAP_LEAP=y
-CONFIG_PCSC=y
-
-EAP-PEAP and EAP-TTLS will automatically include configured EAP
-methods (MD5, OTP, GTC, MSCHAPV2) for inner authentication selection.
-
-
-After you have created a configuration file, you can build
-wpa_supplicant and wpa_cli with 'make' command. You may then install
-the binaries to a suitable system directory, e.g., /usr/local/bin.
-
-Example commands:
-
-# build wpa_supplicant and wpa_cli
-make
-# install binaries (this may need root privileges)
-cp wpa_cli wpa_supplicant /usr/local/bin
-
-
-You will need to make a configuration file, e.g.,
-/etc/wpa_supplicant.conf, with network configuration for the networks
-you are going to use. Configuration file section below includes
-explanation fo the configuration file format and includes various
-examples. Once the configuration is ready, you can test whether the
-configuration work by first running wpa_supplicant with following
-command to start it on foreground with debugging enabled:
-
-wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -d
-
-Assuming everything goes fine, you can start using following command
-to start wpa_supplicant on background without debugging:
-
-wpa_supplicant -iwlan0 -c/etc/wpa_supplicant.conf -B
-
-Please note that if you included more than one driver interface in the
-build time configuration (.config), you may need to specify which
-interface to use by including -D<driver name> option on the command
-line. See following section for more details on command line options
-for wpa_supplicant.
-
-
-
-Command line options
---------------------
-
-usage:
-  wpa_supplicant [-BddehLqqvw] -i<ifname> -c<config file> [-D<driver>]
-
-options:
-  -B = run daemon in the background
-  -d = increase debugging verbosity (-dd even more)
-  -e = use external IEEE 802.1X Supplicant (e.g., xsupplicant)
-       (this disables the internal Supplicant)
-  -h = show this help text
-  -L = show license (GPL and BSD)
-  -q = decrease debugging verbosity (-qq even less)
-  -v = show version
-  -w = wait for interface to be added, if needed
-
-drivers:
-  hostap = Host AP driver (Intersil Prism2/2.5/3) [default]
-	(this can also be used with Linuxant DriverLoader)
-  prism54 = Prism54.org driver (Intersil Prism GT/Duette/Indigo)
-	not yet fully implemented
-  hermes = Agere Systems Inc. driver (Hermes-I/Hermes-II)
-  madwifi = MADWIFI 802.11 support (Atheros, etc.)
-  atmel = ATMEL AT76C5XXx (USB, PCMCIA)
-  wext = Linux wireless extensions (generic)
-  ndiswrapper = Linux ndiswrapper
-
-In most common cases, wpa_supplicant is started with
-
-wpa_supplicant -Bw -c/etc/wpa_supplicant.conf -iwlan0
-
-This makes the process fork into background and wait for the wlan0
-interface if it is not available at startup time.
-
-
-
-Configuration file
-------------------
-
-wpa_supplicant is configured using a text file that lists all accepted
-networks and security policies, including pre-shared keys. See
-example configuration file, wpa_supplicant.conf, for detailed
-information about the configuration format and supported fields.
-
-Changes to configuration file can be reloaded be sending SIGHUP signal
-to wpa_supplicant ('killall -HUP wpa_supplicant'). Similarily,
-reloading can be triggered with 'wpa_cli reconfigure' command.
-
-Configuration file can include one or more network blocks, e.g., one
-for each used SSID. wpa_supplicant will automatically select the best
-betwork based on the order of network blocks in the configuration
-file, network security level (WPA/WPA2 is prefered), and signal
-strength.
-
-Example configuration files for some common configurations:
-
-1) WPA-Personal (PSK) as home network and WPA-Enterprise with EAP-TLS as work
-   network
-
-# allow frontend (e.g., wpa_cli) to be used by all users in 'wheel' group
-ctrl_interface=/var/run/wpa_supplicant
-ctrl_interface_group=wheel
-#
-# home network; allow all valid ciphers
-network={
-	ssid="home"
-	scan_ssid=1
-	key_mgmt=WPA-PSK
-	psk="very secret passphrase"
-}
-#
-# work network; use EAP-TLS with WPA; allow only CCMP and TKIP ciphers
-network={
-	ssid="work"
-	scan_ssid=1
-	key_mgmt=WPA-EAP
-	pairwise=CCMP TKIP
-	group=CCMP TKIP
-	eap=TLS
-	identity="user@example.com"
-	ca_cert="/etc/cert/ca.pem"
-	client_cert="/etc/cert/user.pem"
-	private_key="/etc/cert/user.prv"
-	private_key_passwd="password"
-}
-
-
-2) WPA-RADIUS/EAP-PEAP/MSCHAPv2 with RADIUS servers that use old peaplabel
-   (e.g., Funk Odyssey and SBR, Meetinghouse Aegis, Interlink RAD-Series)
-
-ctrl_interface=/var/run/wpa_supplicant
-ctrl_interface_group=wheel
-network={
-	ssid="example"
-	scan_ssid=1
-	key_mgmt=WPA-EAP
-	eap=PEAP
-	identity="user@example.com"
-	password="foobar"
-	ca_cert="/etc/cert/ca.pem"
-	phase1="peaplabel=0"
-	phase2="auth=MSCHAPV2"
-}
-
-
-3) EAP-TTLS/EAP-MD5-Challenge configuration with anonymous identity for the
-   unencrypted use. Real identity is sent only within an encrypted TLS tunnel.
-
-ctrl_interface=/var/run/wpa_supplicant
-ctrl_interface_group=wheel
-network={
-	ssid="example"
-	scan_ssid=1
-	key_mgmt=WPA-EAP
-	eap=TTLS
-	identity="user@example.com"
-	anonymous_identity="anonymous@example.com"
-	password="foobar"
-	ca_cert="/etc/cert/ca.pem"
-	phase2="auth=MD5"
-}
-
-
-4) IEEE 802.1X (i.e., no WPA) with dynamic WEP keys (require both unicast and
-   broadcast); use EAP-TLS for authentication
-
-ctrl_interface=/var/run/wpa_supplicant
-ctrl_interface_group=wheel
-network={
-	ssid="1x-test"
-	scan_ssid=1
-	key_mgmt=IEEE8021X
-	eap=TLS
-	identity="user@example.com"
-	ca_cert="/etc/cert/ca.pem"
-	client_cert="/etc/cert/user.pem"
-	private_key="/etc/cert/user.prv"
-	private_key_passwd="password"
-	eapol_flags=3
-}
-
-
-5) Catch all example that allows more or less all configuration modes. The
-   configuration options are used based on what security policy is used in the
-   selected SSID. This is mostly for testing and is not recommended for normal
-   use.
-
-ctrl_interface=/var/run/wpa_supplicant
-ctrl_interface_group=wheel
-network={
-	ssid="example"
-	scan_ssid=1
-	key_mgmt=WPA-EAP WPA-PSK IEEE8021X NONE
-	pairwise=CCMP TKIP
-	group=CCMP TKIP WEP104 WEP40
-	psk="very secret passphrase"
-	eap=TTLS PEAP TLS
-	identity="user@example.com"
-	password="foobar"
-	ca_cert="/etc/cert/ca.pem"
-	client_cert="/etc/cert/user.pem"
-	private_key="/etc/cert/user.prv"
-	private_key_passwd="password"
-	phase1="peaplabel=0"
-	ca_cert2="/etc/cert/ca2.pem"
-	client_cert2="/etc/cer/user.pem"
-	private_key2="/etc/cer/user.prv"
-	private_key2_passwd="password"
-}
-
-
-
-Certificates
-------------
-
-Some EAP authentication methods require use of certificates. EAP-TLS
-uses both server side and client certificates whereas EAP-PEAP and
-EAP-TTLS only require the server side certificate. When client
-certificate is used, a matching private key file has to also be
-included in configuration. If the private key uses a passphrase, this
-has to be configured in wpa_supplicant.conf ("private_key_passwd").
-
-wpa_supplicant supports X.509 certificates in PEM and DER
-formats. User certificate and private key can be included in the same
-file.
-
-If the user certificate and private key is received in PKCS#12/PFX
-format, they need to be converted to suitable PEM/DER format for
-wpa_supplicant. This can be done, e.g., with following commands:
-
-# convert client certificate and private key to PEM format
-openssl pkcs12 -in example.pfx -out user.pem -clcerts
-# convert CA certificate (if included in PFX file) to PEM format
-openssl pkcs12 -in example.pfx -out ca.pem -cacerts -nokeys
-
-
-
-wpa_cli
--------
-
-wpa_cli is a text-based frontend program for interacting with
-wpa_supplicant. It is used to query current status, change
-configuration, trigger events, and request interactive user input.
-
-wpa_cli can show the current authentication status, selected security
-mode, dot11 and dot1x MIBs, etc. In addition, it can configuring some
-variables like EAPOL state machine parameters and trigger events like
-reassociation and IEEE 802.1X logoff/logon. wpa_cli provides a user
-interface to request authentication information, like username and
-password, if these are not included in the configuration. This can be
-used to implement, e.g., one-time-passwords or generic token card
-authentication where the authentication is based on a
-challenge-response that uses an external device for generating the
-response.
-
-The control interface of wpa_supplicant can be configured to allow
-non-root user access (ctrl_interface_group in the configuration
-file). This makes it possible to run wpa_cli with a normal user
-account.
-
-wpa_cli supports two modes: interactive and command line. Both modes
-share the same command set and the main difference is in interactive
-mode providing access to unsolicited messages (event messages,
-username/password requests).
-
-Interactive mode is started when wpa_cli is executed without including
-the command as a command line parameter. Commands are then entered on
-the wpa_cli prompt. In command line mode, the same commands are
-entered as command line arguments for wpa_cli.
-
-
-Interactive authentication parameters request
-
-When wpa_supplicant need authentication parameters, like username and
-password, which are not present in the configuration file, it sends a
-request message to all attached frontend programs, e.g., wpa_cli in
-interactive mode. wpa_cli shows these requests with
-"CTRL-REQ-<type>-<id>:<text>" prefix. <type> is IDENTITY, PASSWORD, or
-OTP (one-time-password). <id> is a unique identifier for the current
-network. <text> is description of the request. In case of OTP request,
-it includes the challenge from the authentication server.
-
-The reply to these requests can be given with 'identity', 'password',
-and 'otp' commands. <id> needs to be copied from the the matching
-request. 'password' and 'otp' commands can be used regardless of
-whether the request was for PASSWORD or OTP. The main difference
-between these two commands is that values given with 'password' are
-remembered as long as wpa_supplicant is running whereas values given
-with 'otp' are used only once and then forgotten, i.e., wpa_supplicant
-will ask frontend for a new value for every use. This can be used to
-implement one-time-password lists and generic token card -based
-authentication.
-
-Example request for password and a matching reply:
-
-CTRL-REQ-PASSWORD-1:Password needed for SSID foobar
-> password 1 mysecretpassword
-
-Example request for generic token card challenge-response:
-
-CTRL-REQ-OTP-2:Challenge 1235663 needed for SSID foobar
-> otp 2 9876
-
-
-wpa_cli commands
-
-  status = get current WPA/EAPOL/EAP status
-  mib = get MIB variables (dot1x, dot11)
-  help = show this usage help
-  interface [ifname] = show interfaces/select interface
-  level <debug level> = change debug level
-  license = show full wpa_cli license
-  logoff = IEEE 802.1X EAPOL state machine logoff
-  logon = IEEE 802.1X EAPOL state machine logon
-  set = set variables (shows list of variables when run without arguments)
-  pmksa = show PMKSA cache
-  reassociate = force reassociation
-  reconfigure = force wpa_supplicant to re-read its configuration file
-  preauthenticate <BSSID> = force preauthentication
-  identity <network id> <identity> = configure identity for an SSID
-  password <network id> <password> = configure password for an SSID
-  otp <network id> <password> = configure one-time-password for an SSID
-  quit = exit wpa_cli
-
-
-
-Integrating with pcmcia-cs/cardmgr scripts
-------------------------------------------
-
-wpa_supplicant needs to be running when using a wireless network with
-WPA. It can be started either from system startup scripts or from
-pcmcia-cs/cardmgr scripts (when using PC Cards). WPA handshake must be
-completed before data frames can be exchanged, so wpa_supplicant
-should be started before DHCP client.
-
-Command line option '-w' can be used if wpa_supplicant is started
-before the wireless LAN interface is present (e.g., before inserting
-the PC Card) or is not yet up.
-
-For example, following small changes to pcmcia-cs scripts can be used
-to enable WPA support:
-
-Add MODE="Managed" and WPA="y" to the network scheme in
-/etc/pcmcia/wireless.opts.
-
-Add the following block to the end of 'start' action handler in
-/etc/pcmcia/wireless:
-
-    if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
-	/usr/local/bin/wpa_supplicant -Bw -c/etc/wpa_supplicant.conf \
-		-i$DEVICE
-    fi
-
-Add the following block to the end of 'stop' action handler (may need
-to be separated from other actions) in /etc/pcmcia/wireless:
-
-    if [ "$WPA" = "y" -a -x /usr/local/bin/wpa_supplicant ]; then
-	killall wpa_supplicant
-    fi
-
-This will make cardmgr start wpa_supplicant when the card is plugged
-in. wpa_supplicant will wait until the interface is set up--either
-when a static IP address is configured or when DHCP client is
-started--and will then negotiate keys with the AP.
-
-
-
-Optional integration with Xsupplicant
--------------------------------------
-
-wpa_supplicant has an integrated IEEE 802.1X Supplicant that supports
-most commonly used EAP methods. In addition, wpa_supplicant has an
-experimental interface for integrating it with Xsupplicant
-(http://www.open1x.org/) for the WPA with EAP authentication.
-
-Xsupplicant needs to be modified to send master session key to
-wpa_supplicant after successful EAP authentication. The included patch
-(xsupplicant.patch) shows the changes needed. This was merged into
-xsupplicant CVS on February 6, 2004, so any snapshot after that should
-have the needed functionality already included.
-
-When using WPA-EAP, both wpa_supplicant and Xsupplicant must be
-configured with the network security policy. See Xsupplicant documents
-for information about its configuration. Please also note, that a new
-command line option -W (enable WPA; added by xsupplicant.patch) must
-be used when starting xsupplicant.
-
-Example configuration for xsupplicant:
-
-network_list = all
-default_netname = jkm
-
-jkm
-{
-	type = wireless
-	allow_types = eap_peap
-	identity = <BEGIN_ID>jkm<END_ID>
-	eap-peap {
-		random_file = /dev/urandom
-		root_cert = /home/jkm/CA.pem
-		chunk_size = 1398
-		allow_types = eap_mschapv2
-		eap-mschapv2 {
-			username = <BEGIN_UNAME>jkm<END_UNAME>
-			password = <BEGIN_PASS>jkm<END_PASS>
-		}
-	}
-}
-
-
-Example configuration for wpa_supplicant:
-
-network={
-	ssid="jkm"
-	key_mgmt=WPA-EAP
-}
-
-
-Both wpa_supplicant and xsupplicant need to be started. Please remember
-to add '-W' option for xsupplicant in order to provide keying material
-for wpa_supplicant and '-e' option for wpa_supplicant to disable internal
-IEEE 802.1X implementation.
-
-wpa_supplicant -iwlan0 -cwpa_supplicant.conf -e
-xsupplicant -iwlan0 -cxsupplicant.conf -W
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/THIRDPARTYLICENSE	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,46 +0,0 @@
-WPA Supplicant
-==============
-
-Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
-All Rights Reserved.
-
-Sun elects to license this software under the BSD license.
-
-
-License
--------
-
-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.
-
-/*
- * Copyright (c) 2004, Sam Leffler <sam@errno.com>
- * Sun elects to license this software under the BSD license.
- * See README for more details.
- */
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/THIRDPARTYLICENSE.descrip	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-PORTIONS OF WPA FUNCTIONALITY
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/driver.h	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,44 +0,0 @@
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
- * Sun elects to license this software under the BSD license.
- * See README for more details.
- */
-#ifndef __DRIVER_H
-#define	__DRIVER_H
-
-#include <libdlwlan.h>
-#include <libdllink.h>
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
-typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
-	CIPHER_WEP104 } wpa_cipher;
-typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE } wpa_key_mgmt;
-
-struct wpa_driver_ops {
-	int (*get_bssid)(dladm_handle_t, datalink_id_t, char *);
-	int (*get_ssid)(dladm_handle_t, datalink_id_t, char *);
-	int (*set_wpa)(dladm_handle_t, datalink_id_t, boolean_t);
-	int (*set_key)(dladm_handle_t, datalink_id_t, wpa_alg, uint8_t *,
-	    int, boolean_t, uint8_t *, uint32_t, uint8_t *, uint32_t);
-	int (*scan)(dladm_handle_t, datalink_id_t);
-	int (*get_scan_results)(dladm_handle_t, datalink_id_t,
-	    dladm_wlan_ess_t *, uint32_t);
-	int (*disassociate)(dladm_handle_t, datalink_id_t, int);
-	int (*associate)(dladm_handle_t, datalink_id_t, const char *, uint8_t *,
-	    uint32_t);
-};
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __DRIVER_H */
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/driver_wifi.c	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,375 +0,0 @@
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 2004, Sam Leffler <sam@errno.com>
- * Sun elects to license this software under the BSD license.
- * See README for more details.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stropts.h>
-#include <string.h>
-#include <stddef.h>
-
-#include "wpa_impl.h"
-#include "driver.h"
-
-#define	WPA_STATUS(status)	(status == DLADM_STATUS_OK? 0 : -1)
-
-/*
- * get_bssid - get the current BSSID
- * @linkid: linkid of the given interface
- * @bssid: buffer for BSSID (IEEE80211_ADDR_LEN = 6 bytes)
- *
- * Returns: 0 on success, -1 on failure
- *
- * Query kernel driver for the current BSSID and copy it to @bssid.
- * Setting @bssid to 00:00:00:00:00:00 is recommended if the STA is not
- * associated.
- */
-int
-wpa_driver_wifi_get_bssid(dladm_handle_t handle, datalink_id_t linkid,
-    char *bssid)
-{
-	dladm_status_t status;
-	dladm_wlan_linkattr_t attr;
-	dladm_wlan_attr_t *wl_attrp;
-
-	status = dladm_wlan_get_linkattr(handle, linkid, &attr);
-	if (status != DLADM_STATUS_OK)
-		return (-1);
-
-	wl_attrp = &attr.la_wlan_attr;
-	if ((attr.la_valid & DLADM_WLAN_LINKATTR_WLAN) == 0 ||
-	    (wl_attrp->wa_valid & DLADM_WLAN_ATTR_BSSID) == 0)
-		return (-1);
-
-	(void) memcpy(bssid, wl_attrp->wa_bssid.wb_bytes, DLADM_WLAN_BSSID_LEN);
-
-	wpa_printf(MSG_DEBUG, "wpa_driver_wifi_get_bssid: " MACSTR,
-	    MAC2STR((unsigned char *)bssid));
-
-	return (WPA_STATUS(status));
-}
-
-/*
- * get_ssid - get the current SSID
- * @linkid: linkid of the given interface
- * @ssid: buffer for SSID (at least 32 bytes)
- *
- * Returns: length of the SSID on success, -1 on failure
- *
- * Query kernel driver for the current SSID and copy it to @ssid.
- * Returning zero is recommended if the STA is not associated.
- */
-int
-wpa_driver_wifi_get_ssid(dladm_handle_t handle, datalink_id_t linkid,
-    char *ssid)
-{
-	int ret;
-	dladm_status_t status;
-	dladm_wlan_linkattr_t attr;
-	dladm_wlan_attr_t *wl_attrp;
-
-	status = dladm_wlan_get_linkattr(handle, linkid, &attr);
-	if (status != DLADM_STATUS_OK)
-		return (-1);
-
-	wl_attrp = &attr.la_wlan_attr;
-	if ((attr.la_valid & DLADM_WLAN_LINKATTR_WLAN) == 0 ||
-	    (wl_attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0)
-		return (-1);
-
-	(void) memcpy(ssid, wl_attrp->wa_essid.we_bytes, MAX_ESSID_LENGTH);
-	ret = strlen(ssid);
-
-	wpa_printf(MSG_DEBUG, "wpa_driver_wifi_get_ssid: ssid=%s len=%d",
-	    ssid, ret);
-
-	return (ret);
-}
-
-static int
-wpa_driver_wifi_set_wpa_ie(dladm_handle_t handle, datalink_id_t linkid,
-    uint8_t *wpa_ie, uint32_t wpa_ie_len)
-{
-	dladm_status_t status;
-
-	wpa_printf(MSG_DEBUG, "%s", "wpa_driver_wifi_set_wpa_ie");
-	status = dladm_wlan_wpa_set_ie(handle, linkid, wpa_ie, wpa_ie_len);
-
-	return (WPA_STATUS(status));
-}
-
-/*
- * set_wpa - enable/disable WPA support
- * @linkid: linkid of the given interface
- * @enabled: 1 = enable, 0 = disable
- *
- * Returns: 0 on success, -1 on failure
- *
- * Configure the kernel driver to enable/disable WPA support. This may
- * be empty function, if WPA support is always enabled. Common
- * configuration items are WPA IE (clearing it when WPA support is
- * disabled), Privacy flag for capability field, roaming mode (need to
- * allow wpa_supplicant to control roaming).
- */
-static int
-wpa_driver_wifi_set_wpa(dladm_handle_t handle, datalink_id_t linkid,
-    boolean_t enabled)
-{
-	dladm_status_t status;
-
-	wpa_printf(MSG_DEBUG, "wpa_driver_wifi_set_wpa: enable=%d", enabled);
-
-	if (!enabled && wpa_driver_wifi_set_wpa_ie(handle, linkid, NULL, 0) < 0)
-		return (-1);
-
-	status = dladm_wlan_wpa_set_wpa(handle, linkid, enabled);
-
-	return (WPA_STATUS(status));
-}
-
-static int
-wpa_driver_wifi_del_key(dladm_handle_t handle, datalink_id_t linkid,
-    int key_idx, unsigned char *addr)
-{
-	dladm_status_t status;
-	dladm_wlan_bssid_t bss;
-
-	wpa_printf(MSG_DEBUG, "%s: id=%d", "wpa_driver_wifi_del_key",
-	    key_idx);
-
-	(void) memcpy(bss.wb_bytes, addr, DLADM_WLAN_BSSID_LEN);
-	status = dladm_wlan_wpa_del_key(handle, linkid, key_idx, &bss);
-
-	return (WPA_STATUS(status));
-}
-
-/*
- * set_key - configure encryption key
- * @linkid: linkid of the given interface
- * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
- *	%WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key.
- * @addr: address of the peer STA or ff:ff:ff:ff:ff:ff for
- *	broadcast/default keys
- * @key_idx: key index (0..3), always 0 for unicast keys
- * @set_tx: configure this key as the default Tx key (only used when
- *	driver does not support separate unicast/individual key
- * @seq: sequence number/packet number, @seq_len octets, the next
- *	packet number to be used for in replay protection; configured
- *	for Rx keys (in most cases, this is only used with broadcast
- *	keys and set to zero for unicast keys)
- * @seq_len: length of the @seq, depends on the algorithm:
- *	TKIP: 6 octets, CCMP: 6 octets
- * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
- *	8-byte Rx Mic Key
- * @key_len: length of the key buffer in octets (WEP: 5 or 13,
- *	TKIP: 32, CCMP: 16)
- *
- * Returns: 0 on success, -1 on failure
- *
- * Configure the given key for the kernel driver. If the driver
- * supports separate individual keys (4 default keys + 1 individual),
- * @addr can be used to determine whether the key is default or
- * individual. If only 4 keys are supported, the default key with key
- * index 0 is used as the individual key. STA must be configured to use
- * it as the default Tx key (@set_tx is set) and accept Rx for all the
- * key indexes. In most cases, WPA uses only key indexes 1 and 2 for
- * broadcast keys, so key index 0 is available for this kind of
- * configuration.
- */
-static int
-wpa_driver_wifi_set_key(dladm_handle_t handle, datalink_id_t linkid,
-    wpa_alg alg, unsigned char *addr, int key_idx, boolean_t set_tx,
-    uint8_t *seq, uint32_t seq_len, uint8_t *key, uint32_t key_len)
-{
-	char *alg_name;
-	dladm_wlan_cipher_t cipher;
-	dladm_wlan_bssid_t bss;
-	dladm_status_t status;
-
-	wpa_printf(MSG_DEBUG, "%s", "wpa_driver_wifi_set_key");
-	if (alg == WPA_ALG_NONE)
-		return (wpa_driver_wifi_del_key(handle, linkid, key_idx, addr));
-
-	switch (alg) {
-	case WPA_ALG_WEP:
-		alg_name = "WEP";
-		cipher = DLADM_WLAN_CIPHER_WEP;
-		break;
-	case WPA_ALG_TKIP:
-		alg_name = "TKIP";
-		cipher = DLADM_WLAN_CIPHER_TKIP;
-		break;
-	case WPA_ALG_CCMP:
-		alg_name = "CCMP";
-		cipher = DLADM_WLAN_CIPHER_AES_CCM;
-		break;
-	default:
-		wpa_printf(MSG_DEBUG, "wpa_driver_wifi_set_key:"
-		    " unknown/unsupported algorithm %d", alg);
-		return (-1);
-	}
-
-	wpa_printf(MSG_DEBUG, "wpa_driver_wifi_set_key: alg=%s key_idx=%d"
-	    " set_tx=%d seq_len=%d seq=%d key_len=%d",
-	    alg_name, key_idx, set_tx,
-	    seq_len, *(uint64_t *)(uintptr_t)seq, key_len);
-
-	if (seq_len > sizeof (uint64_t)) {
-		wpa_printf(MSG_DEBUG, "wpa_driver_wifi_set_key:"
-		    " seq_len %d too big", seq_len);
-		return (-1);
-	}
-	(void) memcpy(bss.wb_bytes, addr, DLADM_WLAN_BSSID_LEN);
-
-	status = dladm_wlan_wpa_set_key(handle, linkid, cipher, &bss, set_tx,
-	    *(uint64_t *)(uintptr_t)seq, key_idx, key, key_len);
-
-	return (WPA_STATUS(status));
-}
-
-/*
- * disassociate - request driver to disassociate
- * @linkid: linkid of the given interface
- * @reason_code: 16-bit reason code to be sent in the disassociation
- * frame
- *
- * Return: 0 on success, -1 on failure
- */
-static int
-wpa_driver_wifi_disassociate(dladm_handle_t handle, datalink_id_t linkid,
-    int reason_code)
-{
-	dladm_status_t status;
-
-	wpa_printf(MSG_DEBUG, "wpa_driver_wifi_disassociate");
-
-	status = dladm_wlan_wpa_set_mlme(handle, linkid,
-	    DLADM_WLAN_MLME_DISASSOC, reason_code, NULL);
-
-	return (WPA_STATUS(status));
-}
-
-/*
- * associate - request driver to associate
- * @linkid: linkid of the given interface
- * @bssid: BSSID of the selected AP
- * @wpa_ie: WPA information element to be included in (Re)Association
- *	Request (including information element id and length). Use of
- *	this WPA IE is optional. If the driver generates the WPA IE, it
- *	can use @pairwise_suite, @group_suite, and @key_mgmt_suite
- *	to select proper algorithms. In this case, the driver has to
- *	notify wpa_supplicant about the used WPA IE by generating an
- *	event that the interface code will convert into EVENT_ASSOCINFO
- *	data (see wpa_supplicant.h). When using WPA2/IEEE 802.11i,
- *	@wpa_ie is used for RSN IE instead. The driver can determine
- *	which version is used by looking at the first byte of the IE
- *	(0xdd for WPA, 0x30 for WPA2/RSN).
- * @wpa_ie_len: length of the @wpa_ie
- *
- * Return: 0 on success, -1 on failure
- */
-static int
-wpa_driver_wifi_associate(dladm_handle_t handle, datalink_id_t linkid,
-    const char *bssid, uint8_t *wpa_ie, uint32_t wpa_ie_len)
-{
-	dladm_status_t status;
-	dladm_wlan_bssid_t bss;
-
-	wpa_printf(MSG_DEBUG, "wpa_driver_wifi_associate : "
-	    MACSTR, MAC2STR(bssid));
-
-	/*
-	 * 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.
-	 */
-	if (wpa_driver_wifi_set_wpa_ie(handle, linkid, wpa_ie, wpa_ie_len) < 0)
-		return (-1);
-
-	(void) memcpy(bss.wb_bytes, bssid, DLADM_WLAN_BSSID_LEN);
-	status = dladm_wlan_wpa_set_mlme(handle, linkid, DLADM_WLAN_MLME_ASSOC,
-	    0, &bss);
-
-	return (WPA_STATUS(status));
-}
-
-/*
- * scan - request the driver to initiate scan
- * @linkid: linkid of the given interface
- *
- * Return: 0 on success, -1 on failure
- *
- * Once the scan results are ready, the driver should report scan
- * results event for wpa_supplicant which will eventually request the
- * results with wpa_driver_get_scan_results().
- */
-static int
-wpa_driver_wifi_scan(dladm_handle_t handle, datalink_id_t linkid)
-{
-	dladm_status_t status;
-
-	wpa_printf(MSG_DEBUG, "%s", "wpa_driver_wifi_scan");
-	/*
-	 * We force the state to INIT before calling ieee80211_new_state
-	 * to get ieee80211_begin_scan called.  We really want to scan w/o
-	 * altering the current state but that's not possible right now.
-	 */
-	(void) wpa_driver_wifi_disassociate(handle, linkid,
-	    DLADM_WLAN_REASON_DISASSOC_LEAVING);
-
-	status = dladm_wlan_scan(handle, linkid, NULL, NULL);
-
-	wpa_printf(MSG_DEBUG, "%s: return", "wpa_driver_wifi_scan");
-	return (WPA_STATUS(status));
-}
-
-/*
- * get_scan_results - fetch the latest scan results
- * @linkid: linkid of the given interface
- * @results: pointer to buffer for scan results
- * @max_size: maximum number of entries (buffer size)
- *
- * Return: number of scan result entries used on success, -1 on failure
- *
- * If scan results include more than @max_size BSSes, @max_size will be
- * returned and the remaining entries will not be included in the
- * buffer.
- */
-int
-wpa_driver_wifi_get_scan_results(dladm_handle_t handle, datalink_id_t linkid,
-    dladm_wlan_ess_t *results, uint32_t max_size)
-{
-	uint_t ret;
-
-	wpa_printf(MSG_DEBUG, "%s: max size=%d\n",
-	    "wpa_driver_wifi_get_scan_results", max_size);
-
-	if (dladm_wlan_wpa_get_sr(handle, linkid, results, max_size, &ret)
-	    != DLADM_STATUS_OK) {
-		return (-1);
-	}
-
-	return (ret);
-}
-
-struct wpa_driver_ops wpa_driver_wifi_ops = {
-	wpa_driver_wifi_get_bssid,
-	wpa_driver_wifi_get_ssid,
-	wpa_driver_wifi_set_wpa,
-	wpa_driver_wifi_set_key,
-	wpa_driver_wifi_scan,
-	wpa_driver_wifi_get_scan_results,
-	wpa_driver_wifi_disassociate,
-	wpa_driver_wifi_associate
-};
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/eloop.c	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,321 +0,0 @@
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
- * Sun elects to license this software under the BSD license.
- * See README for more details.
- */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <unistd.h>
-#include <errno.h>
-#include <signal.h>
-#include <poll.h>
-
-#include "eloop.h"
-
-static struct eloop_data eloop;
-/*
- * Initialize global event loop data - must be called before any other eloop_*
- * function. user_data is a pointer to global data structure and will be passed
- * as eloop_ctx to signal handlers.
- */
-void
-eloop_init(void *user_data)
-{
-	(void) memset(&eloop, 0, sizeof (eloop));
-	eloop.user_data = user_data;
-}
-
-/*
- * Register handler for read event
- */
-int
-eloop_register_read_sock(int sock,
-    void (*handler)(int sock, void *eloop_ctx,
-    void *sock_ctx), void *eloop_data, void *user_data)
-{
-	struct eloop_sock *tmp;
-
-	tmp = (struct eloop_sock *)realloc(eloop.readers,
-	    (eloop.reader_count + 1) * sizeof (struct eloop_sock));
-	if (tmp == NULL)
-		return (-1);
-
-	tmp[eloop.reader_count].sock = sock;
-	tmp[eloop.reader_count].eloop_data = eloop_data;
-	tmp[eloop.reader_count].user_data = user_data;
-	tmp[eloop.reader_count].handler = handler;
-	eloop.reader_count++;
-	eloop.readers = tmp;
-	if (sock > eloop.max_sock)
-		eloop.max_sock = sock;
-
-	return (0);
-}
-
-void
-eloop_unregister_read_sock(int sock)
-{
-	int i;
-
-	if (eloop.readers == NULL || eloop.reader_count == 0)
-		return;
-
-	for (i = 0; i < eloop.reader_count; i++) {
-		if (eloop.readers[i].sock == sock)
-			break;
-	}
-	if (i == eloop.reader_count)
-		return;
-	if (i != eloop.reader_count - 1) {
-		(void) memmove(&eloop.readers[i], &eloop.readers[i + 1],
-		    (eloop.reader_count - i - 1) *
-		    sizeof (struct eloop_sock));
-	}
-	eloop.reader_count--;
-}
-
-/*
- * Register timeout routines
- */
-int
-eloop_register_timeout(unsigned int secs, unsigned int usecs,
-    void (*handler)(void *eloop_ctx, void *timeout_ctx),
-    void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *timeout, *tmp, *prev;
-
-	timeout = (struct eloop_timeout *)malloc(sizeof (*timeout));
-	if (timeout == NULL)
-		return (-1);
-	(void) gettimeofday(&timeout->time, NULL);
-	timeout->time.tv_sec += secs;
-	timeout->time.tv_usec += usecs;
-	while (timeout->time.tv_usec >= 1000000) {
-		timeout->time.tv_sec++;
-		timeout->time.tv_usec -= 1000000;
-	}
-	timeout->eloop_data = eloop_data;
-	timeout->user_data = user_data;
-	timeout->handler = handler;
-	timeout->next = NULL;
-
-	if (eloop.timeout == NULL) {
-		eloop.timeout = timeout;
-		return (0);
-	}
-
-	prev = NULL;
-	tmp = eloop.timeout;
-	while (tmp != NULL) {
-		if (timercmp(&timeout->time, &tmp->time, < /* */))
-			break;
-		prev = tmp;
-		tmp = tmp->next;
-	}
-
-	if (prev == NULL) {
-		timeout->next = eloop.timeout;
-		eloop.timeout = timeout;
-	} else {
-		timeout->next = prev->next;
-		prev->next = timeout;
-	}
-
-	return (0);
-}
-
-/*
- * Cancel timeouts matching <handler,eloop_data,user_data>.
- * ELOOP_ALL_CTX can be used as a wildcard for cancelling all timeouts
- * regardless of eloop_data/user_data.
- */
-void
-eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
-    void *eloop_data, void *user_data)
-{
-	struct eloop_timeout *timeout, *prev, *next;
-
-	prev = NULL;
-	timeout = eloop.timeout;
-	while (timeout != NULL) {
-		next = timeout->next;
-
-		if (timeout->handler == handler &&
-		    (timeout->eloop_data == eloop_data ||
-		    eloop_data == ELOOP_ALL_CTX) &&
-		    (timeout->user_data == user_data ||
-		    user_data == ELOOP_ALL_CTX)) {
-			if (prev == NULL)
-				eloop.timeout = next;
-			else
-				prev->next = next;
-			free(timeout);
-		} else
-			prev = timeout;
-
-		timeout = next;
-	}
-}
-
-static void eloop_handle_signal(int sig)
-{
-	int i;
-
-	eloop.signaled++;
-	for (i = 0; i < eloop.signal_count; i++) {
-		if (eloop.signals[i].sig == sig) {
-			eloop.signals[i].signaled++;
-			break;
-		}
-	}
-}
-
-static void eloop_process_pending_signals(void)
-{
-	int i;
-
-	if (eloop.signaled == 0)
-		return;
-	eloop.signaled = 0;
-
-	for (i = 0; i < eloop.signal_count; i++) {
-		if (eloop.signals[i].signaled) {
-			eloop.signals[i].signaled = 0;
-			eloop.signals[i].handler(eloop.signals[i].sig,
-			    eloop.user_data, eloop.signals[i].user_data);
-		}
-	}
-}
-
-/*
- * Register handler for signal.
- * Note: signals are 'global' events and there is no local eloop_data pointer
- * like with other handlers. The (global) pointer given to eloop_init() will be
- * used as eloop_ctx for signal handlers.
- */
-int
-eloop_register_signal(int sig,
-    void (*handler)(int sig, void *eloop_ctx, void *signal_ctx),
-    void *user_data)
-{
-	struct eloop_signal *tmp;
-
-	tmp = (struct eloop_signal *)
-	    realloc(eloop.signals,
-	    (eloop.signal_count + 1) *
-	    sizeof (struct eloop_signal));
-	if (tmp == NULL)
-		return (-1);
-
-	tmp[eloop.signal_count].sig = sig;
-	tmp[eloop.signal_count].user_data = user_data;
-	tmp[eloop.signal_count].handler = handler;
-	tmp[eloop.signal_count].signaled = 0;
-	eloop.signal_count++;
-	eloop.signals = tmp;
-	(void) signal(sig, eloop_handle_signal);
-
-	return (0);
-}
-
-/*
- * Start event loop and continue running as long as there are any registered
- * event handlers.
- */
-void
-eloop_run(void)
-{
-	struct pollfd pfds[MAX_POLLFDS];	/* array of polled fd */
-	int i, res;
-	int default_t, t;
-	struct timeval tv, now;
-
-	default_t = 5 * 1000;	/* 5 seconds */
-	while (!eloop.terminate &&
-	    (eloop.timeout || eloop.reader_count > 0)) {
-		if (eloop.timeout) {
-			(void) gettimeofday(&now, NULL);
-			if (timercmp(&now, &eloop.timeout->time, < /* */))
-				timersub(&eloop.timeout->time, &now, &tv);
-			else
-				tv.tv_sec = tv.tv_usec = 0;
-		}
-
-		t = (eloop.timeout == NULL ?
-		    default_t : (tv.tv_sec * 1000 + tv.tv_usec / 1000));
-		for (i = 0; i < eloop.reader_count; i++) {
-			pfds[i].fd = eloop.readers[i].sock;
-			pfds[i].events = POLLIN | POLLPRI;
-		}
-		res = poll(pfds, eloop.reader_count, t);
-		if (res < 0 && errno != EINTR)
-			return;
-
-		eloop_process_pending_signals();
-
-		/* check if some registered timeouts have occurred */
-		if (eloop.timeout) {
-			struct eloop_timeout *tmp;
-
-			(void) gettimeofday(&now, NULL);
-			if (!timercmp(&now, &eloop.timeout->time, < /* */)) {
-				tmp = eloop.timeout;
-				eloop.timeout = eloop.timeout->next;
-				tmp->handler(tmp->eloop_data, tmp->user_data);
-				free(tmp);
-			}
-
-		}
-
-		if (res <= 0)
-			continue;
-
-		for (i = 0; i < eloop.reader_count; i++) {
-			if (pfds[i].revents) {
-				eloop.readers[i].handler(
-				    eloop.readers[i].sock,
-				    eloop.readers[i].eloop_data,
-				    eloop.readers[i].user_data);
-			}
-		}
-	}
-}
-
-/*
- * Terminate event loop even if there are registered events.
- */
-void
-eloop_terminate(void)
-{
-	eloop.terminate = 1;
-}
-
-
-/*
- * Free any reserved resources. After calling eloop_destoy(), other eloop_*
- * functions must not be called before re-running eloop_init().
- */
-void
-eloop_destroy(void)
-{
-	struct eloop_timeout *timeout, *prev;
-
-	timeout = eloop.timeout;
-	while (timeout != NULL) {
-		prev = timeout;
-		timeout = timeout->next;
-		free(prev);
-	}
-	free(eloop.readers);
-	free(eloop.signals);
-}
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/eloop.h	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,82 +0,0 @@
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
- * Sun elects to license this software under the BSD license.
- * See README for more details.
- */
-#ifndef __ELOOP_H
-#define	__ELOOP_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-/* Magic number for eloop_cancel_timeout() */
-#define	ELOOP_ALL_CTX		(void *) -1
-#define	MAX_POLLFDS		32
-
-struct eloop_sock {
-	int sock;
-	void *eloop_data;
-	void *user_data;
-	void (*handler)(int, void *, void *);
-};
-
-struct eloop_timeout {
-	struct timeval time;
-	void *eloop_data;
-	void *user_data;
-	void (*handler)(void *, void *);
-	struct eloop_timeout *next;
-};
-
-struct eloop_signal {
-	int sig;
-	void *user_data;
-	void (*handler)(int, void *, void *);
-	int signaled;
-};
-
-struct eloop_data {
-	void *user_data;
-
-	int max_sock, reader_count;
-	struct eloop_sock *readers;
-
-	struct eloop_timeout *timeout;
-
-	int signal_count;
-	struct eloop_signal *signals;
-	int signaled;
-
-	int terminate;
-};
-
-void eloop_init(void *);
-
-int eloop_register_read_sock(int,
-	void (*handler)(int, void *, void *), void *, void *);
-
-void eloop_unregister_read_sock(int);
-
-int eloop_register_timeout(unsigned int, unsigned int,
-	void (*handler)(void *, void *), void *, void *);
-
-void eloop_cancel_timeout(void (*handler)(void *, void *), void *, void *);
-int eloop_register_signal(int, void (*handler)(int, void *, void *), void *);
-
-void eloop_run(void);
-void eloop_terminate(void);
-void eloop_destroy(void);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __ELOOP_H */
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/l2_packet.c	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,162 +0,0 @@
-/*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
- * Sun elects to license this software under the BSD license.
- * See README for more details.
- */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <libdlpi.h>
-#include <sys/ethernet.h>
-#include <netinet/in.h>
-
-#include "wpa_impl.h"
-#include "eloop.h"
-#include "l2_packet.h"
-
-static int
-link_init(struct l2_packet_data *l2)
-{
-	int retval;
-	uint8_t paddr[DLPI_PHYSADDR_MAX];
-	size_t paddrlen = sizeof (paddr);
-
-	retval = dlpi_bind(l2->dh, DLPI_ANY_SAP, NULL);
-	if (retval != DLPI_SUCCESS) {
-		wpa_printf(MSG_ERROR, "cannot bind on %s: %s",
-		    l2->ifname, dlpi_strerror(retval));
-		return (-1);
-	}
-
-	retval = dlpi_promiscon(l2->dh, DL_PROMISC_SAP);
-	if (retval != DLPI_SUCCESS) {
-		wpa_printf(MSG_ERROR, "cannot enable promiscous"
-		    " mode (SAP) on %s: %s",
-		    l2->ifname, dlpi_strerror(retval));
-		return (-1);
-	}
-
-	retval = dlpi_get_physaddr(l2->dh, DL_CURR_PHYS_ADDR, paddr, &paddrlen);
-	if (retval != DLPI_SUCCESS) {
-		wpa_printf(MSG_ERROR, "cannot get physical address for %s: %s",
-		    l2->ifname, dlpi_strerror(retval));
-		return (-1);
-	}
-	if (paddrlen != sizeof (l2->own_addr)) {
-		wpa_printf(MSG_ERROR, "physical address for %s is not %d bytes",
-		    l2->ifname, sizeof (l2->own_addr));
-		return (-1);
-	}
-	(void) memcpy(l2->own_addr, paddr, sizeof (l2->own_addr));
-
-	return (0);
-}
-
-/*
- * layer2 packet handling.
- */
-int
-l2_packet_get_own_addr(struct l2_packet_data *l2, uint8_t *addr)
-{
-	(void) memcpy(addr, l2->own_addr, sizeof (l2->own_addr));
-	return (0);
-}
-
-int
-l2_packet_send(struct l2_packet_data *l2, uint8_t *buf, size_t buflen)
-{
-	int retval;
-
-	retval = dlpi_send(l2->dh, NULL, 0, buf, buflen, NULL);
-	if (retval != DLPI_SUCCESS) {
-		wpa_printf(MSG_ERROR, "l2_packet_send: cannot send "
-		    "message on %s: %s", l2->ifname, dlpi_strerror(retval));
-		return (-1);
-	}
-	return (0);
-}
-
-/* ARGSUSED */
-static void
-l2_packet_receive(int fd, void *eloop_ctx, void *sock_ctx)
-{
-	struct l2_packet_data *l2 = eloop_ctx;
-	uint64_t buf[IEEE80211_MTU_MAX / sizeof (uint64_t)];
-	size_t buflen = sizeof (buf);
-	struct l2_ethhdr *ethhdr;
-	int retval;
-
-	retval = dlpi_recv(l2->dh, NULL, NULL, buf, &buflen, 0, NULL);
-	if (retval != DLPI_SUCCESS) {
-		wpa_printf(MSG_ERROR, "l2_packet_receive: cannot receive "
-		    "message on %s: %s", l2->ifname, dlpi_strerror(retval));
-		return;
-	}
-
-	ethhdr = (struct l2_ethhdr *)buf;
-	if (buflen < sizeof (*ethhdr) ||
-	    (ntohs(ethhdr->h_proto) != ETHERTYPE_EAPOL &&
-	    ntohs(ethhdr->h_proto) != ETHERTYPE_RSN_PREAUTH))
-		return;
-
-	l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source,
-	    (unsigned char *)(ethhdr + 1), buflen - sizeof (*ethhdr));
-}
-
-/* ARGSUSED */
-struct l2_packet_data *
-l2_packet_init(const char *ifname, unsigned short protocol,
-	void (*rx_callback)(void *, unsigned char *, unsigned char *, size_t),
-	void *rx_callback_ctx)
-{
-	int retval;
-	struct l2_packet_data *l2;
-
-	l2 = calloc(1, sizeof (struct l2_packet_data));
-	if (l2 == NULL)
-		return (NULL);
-
-	(void) strlcpy(l2->ifname, ifname, sizeof (l2->ifname));
-	l2->rx_callback = rx_callback;
-	l2->rx_callback_ctx = rx_callback_ctx;
-
-	retval = dlpi_open(l2->ifname, &l2->dh, DLPI_RAW);
-	if (retval != DLPI_SUCCESS) {
-		wpa_printf(MSG_ERROR, "unable to open DLPI link %s: %s",
-		    l2->ifname, dlpi_strerror(retval));
-		free(l2);
-		return (NULL);
-	}
-
-	/* NOTE: link_init() sets l2->own_addr */
-	if (link_init(l2) < 0) {
-		dlpi_close(l2->dh);
-		free(l2);
-		return (NULL);
-	}
-
-	(void) eloop_register_read_sock(dlpi_fd(l2->dh), l2_packet_receive, l2,
-	    NULL);
-
-	return (l2);
-}
-
-void
-l2_packet_deinit(struct l2_packet_data *l2)
-{
-	if (l2 == NULL)
-		return;
-
-	eloop_unregister_read_sock(dlpi_fd(l2->dh));
-	dlpi_close(l2->dh);
-	free(l2);
-}
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/l2_packet.h	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,57 +0,0 @@
-/*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
- * Sun elects to license this software under the BSD license.
- * See README for more details.
- */
-#ifndef __L2_PACKET_H
-#define	__L2_PACKET_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-#include <sys/types.h>
-#include <net/if.h>
-#include <libdlpi.h>
-
-#define	IEEE80211_MTU_MAX	2304
-
-struct l2_packet_data {
-	dlpi_handle_t	dh;	/* dlpi handle for EAPOL frames */
-	char		ifname[DLPI_LINKNAME_MAX];
-	uint8_t		own_addr[IEEE80211_ADDR_LEN];
-	void		(*rx_callback)(void *, unsigned char *,
-	    unsigned char *, size_t);
-	void		*rx_callback_ctx;
-};
-
-#pragma pack(1)
-struct l2_ethhdr {
-	uint8_t h_dest[IEEE80211_ADDR_LEN];
-	uint8_t h_source[IEEE80211_ADDR_LEN];
-	uint16_t h_proto;
-};
-#pragma pack()
-
-struct l2_packet_data *l2_packet_init(
-	const char *, unsigned short,
-	void (*rx_callback)(void *, unsigned char *,
-			    unsigned char *, size_t),
-	void *);
-void l2_packet_deinit(struct l2_packet_data *);
-
-int l2_packet_get_own_addr(struct l2_packet_data *, uint8_t *);
-int l2_packet_send(struct l2_packet_data *, uint8_t *, size_t);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __L2_PACKET_H */
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa.c	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1793 +0,0 @@
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
- * Sun elects to license this software under the BSD license.
- * See README for more details.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <netinet/in.h>
-#include <sys/ethernet.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include "wpa_impl.h"
-#include "wpa_enc.h"
-#include "driver.h"
-#include "eloop.h"
-#include "l2_packet.h"
-
-static void pmksa_cache_set_expiration(struct wpa_supplicant *);
-
-/*
- * IEEE 802.11i/D3.0
- */
-static const int WPA_SELECTOR_LEN = 4;
-static const uint8_t WPA_OUI_AND_TYPE[] = { 0x00, 0x50, 0xf2, 1 };
-static const uint8_t
-WPA_AUTH_KEY_MGMT_UNSPEC_802_1X[] 		= { 0x00, 0x50, 0xf2, 1 };
-static const uint8_t
-WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X[] 		= { 0x00, 0x50, 0xf2, 2 };
-static const uint8_t WPA_CIPHER_SUITE_NONE[]	= { 0x00, 0x50, 0xf2, 0 };
-static const uint8_t WPA_CIPHER_SUITE_WEP40[]	= { 0x00, 0x50, 0xf2, 1 };
-static const uint8_t WPA_CIPHER_SUITE_TKIP[]	= { 0x00, 0x50, 0xf2, 2 };
-static const uint8_t WPA_CIPHER_SUITE_CCMP[]	= { 0x00, 0x50, 0xf2, 4 };
-static const uint8_t WPA_CIPHER_SUITE_WEP104[]	= { 0x00, 0x50, 0xf2, 5 };
-
-/*
- * WPA IE version 1
- * 00-50-f2:1 (OUI:OUI type)
- * 0x01 0x00 (version; little endian)
- * (all following fields are optional:)
- * Group Suite Selector (4 octets) (default: TKIP)
- * Pairwise Suite Count (2 octets, little endian) (default: 1)
- * Pairwise Suite List (4 * n octets) (default: TKIP)
- * Authenticated Key Management Suite Count (2 octets, little endian)
- * (default: 1)
- * Authenticated Key Management Suite List (4 * n octets)
- * (default: unspec 802.1x)
- * WPA Capabilities (2 octets, little endian) (default: 0)
- */
-#pragma pack(1)
-struct wpa_ie_hdr {
-	uint8_t		elem_id;
-	uint8_t		len;
-	uint8_t		oui[3];
-	uint8_t		oui_type;
-	uint16_t	version;
-};
-#pragma pack()
-
-/*
- * IEEE 802.11i/D9.0
- */
-static const int RSN_SELECTOR_LEN = 4;
-static const uint16_t RSN_VERSION = 1;
-static const uint8_t
-RSN_AUTH_KEY_MGMT_UNSPEC_802_1X[]		= { 0x00, 0x0f, 0xac, 1 };
-static const uint8_t
-RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X[]		= { 0x00, 0x0f, 0xac, 2 };
-static const uint8_t RSN_CIPHER_SUITE_NONE[]	= { 0x00, 0x0f, 0xac, 0 };
-static const uint8_t RSN_CIPHER_SUITE_WEP40[]	= { 0x00, 0x0f, 0xac, 1 };
-static const uint8_t RSN_CIPHER_SUITE_TKIP[]	= { 0x00, 0x0f, 0xac, 2 };
-static const uint8_t RSN_CIPHER_SUITE_CCMP[]	= { 0x00, 0x0f, 0xac, 4 };
-static const uint8_t RSN_CIPHER_SUITE_WEP104[]	= { 0x00, 0x0f, 0xac, 5 };
-
-/*
- * EAPOL-Key Key Data Encapsulation
- * GroupKey and STAKey require encryption, otherwise, encryption is optional.
- */
-static const uint8_t RSN_KEY_DATA_GROUPKEY[]	= { 0x00, 0x0f, 0xac, 1 };
-static const uint8_t RSN_KEY_DATA_PMKID[]	= { 0x00, 0x0f, 0xac, 4 };
-
-/*
- * 1/4: PMKID
- * 2/4: RSN IE
- * 3/4: one or two RSN IEs + GTK IE (encrypted)
- * 4/4: empty
- * 1/2: GTK IE (encrypted)
- * 2/2: empty
- */
-
-/*
- * RSN IE version 1
- * 0x01 0x00 (version; little endian)
- * (all following fields are optional:)
- * Group Suite Selector (4 octets) (default: CCMP)
- * Pairwise Suite Count (2 octets, little endian) (default: 1)
- * Pairwise Suite List (4 * n octets) (default: CCMP)
- * Authenticated Key Management Suite Count (2 octets, little endian)
- *    (default: 1)
- * Authenticated Key Management Suite List (4 * n octets)
- *    (default: unspec 802.1x)
- * RSN Capabilities (2 octets, little endian) (default: 0)
- * PMKID Count (2 octets) (default: 0)
- * PMKID List (16 * n octets)
- */
-#pragma pack(1)
-struct rsn_ie_hdr {
-	uint8_t		elem_id; /* WLAN_EID_RSN */
-	uint8_t		len;
-	uint16_t	version;
-};
-#pragma pack()
-
-static int
-random_get_pseudo_bytes(uint8_t *ptr, size_t len)
-{
-	int fd;
-	size_t resid = len;
-	size_t bytes;
-
-	fd = open("/dev/urandom", O_RDONLY);
-	if (fd == -1) {
-		wpa_printf(MSG_ERROR, "Could not open /dev/urandom.\n");
-		return (-1);
-	}
-
-	while (resid != 0) {
-		bytes = read(fd, ptr, resid);
-		ptr += bytes;
-		resid -= bytes;
-	}
-
-	(void) close(fd);
-
-	return (0);
-}
-
-static void
-inc_byte_array(uint8_t *counter, size_t len)
-{
-	int pos = len - 1;
-	while (pos >= 0) {
-		counter[pos]++;
-		if (counter[pos] != 0)
-			break;
-		pos--;
-	}
-}
-
-static int
-wpa_selector_to_bitfield(uint8_t *s)
-{
-	if (memcmp(s, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN) == 0)
-		return (WPA_CIPHER_NONE);
-	if (memcmp(s, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN) == 0)
-		return (WPA_CIPHER_WEP40);
-	if (memcmp(s, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN) == 0)
-		return (WPA_CIPHER_TKIP);
-	if (memcmp(s, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN) == 0)
-		return (WPA_CIPHER_CCMP);
-	if (memcmp(s, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN) == 0)
-		return (WPA_CIPHER_WEP104);
-	return (0);
-}
-
-static int
-wpa_key_mgmt_to_bitfield(uint8_t *s)
-{
-	if (memcmp(s, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X, WPA_SELECTOR_LEN) == 0)
-		return (WPA_KEY_MGMT_IEEE8021X);
-	if (memcmp(s, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X, WPA_SELECTOR_LEN) ==
-	    0)
-		return (WPA_KEY_MGMT_PSK);
-	return (0);
-}
-
-static int
-rsn_selector_to_bitfield(uint8_t *s)
-{
-	if (memcmp(s, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN) == 0)
-		return (WPA_CIPHER_NONE);
-	if (memcmp(s, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN) == 0)
-		return (WPA_CIPHER_WEP40);
-	if (memcmp(s, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN) == 0)
-		return (WPA_CIPHER_TKIP);
-	if (memcmp(s, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN) == 0)
-		return (WPA_CIPHER_CCMP);
-	if (memcmp(s, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN) == 0)
-		return (WPA_CIPHER_WEP104);
-	return (0);
-}
-
-static int
-rsn_key_mgmt_to_bitfield(uint8_t *s)
-{
-	if (memcmp(s, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X, RSN_SELECTOR_LEN) == 0)
-		return (WPA_KEY_MGMT_IEEE8021X);
-	if (memcmp(s, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X, RSN_SELECTOR_LEN) ==
-	    0)
-		return (WPA_KEY_MGMT_PSK);
-	return (0);
-}
-
-static void
-pmksa_cache_free_entry(struct wpa_supplicant *wpa_s,
-	struct rsn_pmksa_cache *entry)
-{
-	wpa_s->pmksa_count--;
-	if (wpa_s->cur_pmksa == entry) {
-		wpa_printf(MSG_DEBUG, "RSN: removed current PMKSA entry");
-		wpa_s->cur_pmksa = NULL;
-	}
-	free(entry);
-}
-
-/* ARGSUSED */
-static void
-pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-	time_t now;
-
-	(void) time(&now);
-	while (wpa_s->pmksa && wpa_s->pmksa->expiration <= now) {
-		struct rsn_pmksa_cache *entry = wpa_s->pmksa;
-		wpa_s->pmksa = entry->next;
-		wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
-		    MACSTR, MAC2STR(entry->aa));
-		pmksa_cache_free_entry(wpa_s, entry);
-	}
-
-	pmksa_cache_set_expiration(wpa_s);
-}
-
-static void
-pmksa_cache_set_expiration(struct wpa_supplicant *wpa_s)
-{
-	int sec;
-	eloop_cancel_timeout(pmksa_cache_expire, wpa_s, NULL);
-	if (wpa_s->pmksa == NULL)
-		return;
-	sec = wpa_s->pmksa->expiration - time(NULL);
-	if (sec < 0)
-		sec = 0;
-	(void) eloop_register_timeout(sec + 1, 0, pmksa_cache_expire,
-	    wpa_s, NULL);
-}
-
-void
-pmksa_cache_free(struct wpa_supplicant *wpa_s)
-{
-	struct rsn_pmksa_cache *entry, *prev;
-
-	entry = wpa_s->pmksa;
-	wpa_s->pmksa = NULL;
-	while (entry) {
-		prev = entry;
-		entry = entry->next;
-		free(prev);
-	}
-	pmksa_cache_set_expiration(wpa_s);
-	wpa_s->cur_pmksa = NULL;
-}
-
-struct rsn_pmksa_cache *
-pmksa_cache_get(struct wpa_supplicant *wpa_s,
-		uint8_t *aa, uint8_t *pmkid)
-{
-	struct rsn_pmksa_cache *entry = wpa_s->pmksa;
-	while (entry) {
-		if ((aa == NULL ||
-		    memcmp(entry->aa, aa, IEEE80211_ADDR_LEN) == 0) &&
-		    (pmkid == NULL ||
-		    memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
-			return (entry);
-		entry = entry->next;
-	}
-	return (NULL);
-}
-
-int
-pmksa_cache_list(struct wpa_supplicant *wpa_s, char *buf, size_t len)
-{
-	int i, j;
-	char *pos = buf;
-	struct rsn_pmksa_cache *entry;
-	time_t now;
-
-	(void) time(&now);
-	pos += snprintf(pos, buf + len - pos,
-	    "Index / AA / PMKID / expiration (in seconds)\n");
-	i = 0;
-	entry = wpa_s->pmksa;
-	while (entry) {
-		i++;
-		pos += snprintf(pos, buf + len - pos, "%d " MACSTR " ",
-		    i, MAC2STR(entry->aa));
-		for (j = 0; j < PMKID_LEN; j++)
-			pos += snprintf(pos, buf + len - pos, "%02x",
-			    entry->pmkid[j]);
-		pos += snprintf(pos, buf + len - pos, " %d\n",
-		    (int)(entry->expiration - now));
-		entry = entry->next;
-	}
-	return (pos - buf);
-}
-
-void
-pmksa_candidate_free(struct wpa_supplicant *wpa_s)
-{
-	struct rsn_pmksa_candidate *entry, *prev;
-
-	entry = wpa_s->pmksa_candidates;
-	wpa_s->pmksa_candidates = NULL;
-	while (entry) {
-		prev = entry;
-		entry = entry->next;
-		free(prev);
-	}
-}
-
-/* ARGSUSED */
-static int
-wpa_parse_wpa_ie_wpa(struct wpa_supplicant *wpa_s, uint8_t *wpa_ie,
-    size_t wpa_ie_len, struct wpa_ie_data *data)
-{
-	struct wpa_ie_hdr *hdr;
-	uint8_t *pos;
-	int left;
-	int i, count;
-
-	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;
-
-	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 %u",
-		    "wpa_parse_wpa_ie_wpa", wpa_ie_len);
-		return (-1);
-	}
-
-	hdr = (struct wpa_ie_hdr *)wpa_ie;
-
-	if (hdr->elem_id != GENERIC_INFO_ELEM ||
-	    hdr->len != wpa_ie_len - 2 ||
-	    memcmp(&hdr->oui, WPA_OUI_AND_TYPE, WPA_SELECTOR_LEN) != 0 ||
-	    LE_16(hdr->version) != WPA_VERSION) {
-		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
-		    "wpa_parse_wpa_ie_wpa");
-		return (-1);
-	}
-
-	pos = (uint8_t *)(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",
-		    "wpa_parse_wpa_ie_wpa", left);
-		return (-1);
-	}
-
-	if (left >= 2) {
-		data->pairwise_cipher = 0;
-		count = pos[0] | (pos[1] << 8);
-		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",
-			    "wpa_parse_wpa_ie_wpa", 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)",
-		    "wpa_parse_wpa_ie_wpa");
-		return (-1);
-	}
-
-	if (left >= 2) {
-		data->key_mgmt = 0;
-		count = pos[0] | (pos[1] << 8);
-		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",
-			    "wpa_parse_wpa_ie_wpa", 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)",
-		    "wpa_parse_wpa_ie_wpa");
-		return (-1);
-	}
-
-	if (left >= 2) {
-		data->capabilities = pos[0] | (pos[1] << 8);
-		pos += 2;
-		left -= 2;
-	}
-
-	if (left > 0) {
-		wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes",
-		    "wpa_parse_wpa_ie_wpa", left);
-		return (-1);
-	}
-
-	return (0);
-}
-
-/* ARGSUSED */
-static int
-wpa_parse_wpa_ie_rsn(struct wpa_supplicant *wpa_s, uint8_t *rsn_ie,
-    size_t rsn_ie_len, struct wpa_ie_data *data)
-{
-	struct rsn_ie_hdr *hdr;
-	uint8_t *pos;
-	int left;
-	int i, count;
-
-	data->proto = WPA_PROTO_RSN;
-	data->pairwise_cipher = WPA_CIPHER_CCMP;
-	data->group_cipher = WPA_CIPHER_CCMP;
-	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
-	data->capabilities = 0;
-
-	if (rsn_ie_len == 0) {
-		/* No RSN IE - fail silently */
-		return (-1);
-	}
-
-	if (rsn_ie_len < sizeof (struct rsn_ie_hdr)) {
-		wpa_printf(MSG_DEBUG, "%s: ie len too short %u",
-		    "wpa_parse_wpa_ie_rsn", rsn_ie_len);
-		return (-1);
-	}
-
-	hdr = (struct rsn_ie_hdr *)rsn_ie;
-
-	if (hdr->elem_id != RSN_INFO_ELEM ||
-	    hdr->len != rsn_ie_len - 2 ||
-	    LE_16(hdr->version) != RSN_VERSION) {
-		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
-		    "wpa_parse_wpa_ie_rsn");
-		return (-1);
-	}
-
-	pos = (uint8_t *)(hdr + 1);
-	left = rsn_ie_len - sizeof (*hdr);
-
-	if (left >= RSN_SELECTOR_LEN) {
-		data->group_cipher = rsn_selector_to_bitfield(pos);
-		pos += RSN_SELECTOR_LEN;
-		left -= RSN_SELECTOR_LEN;
-	} else if (left > 0) {
-		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
-		    "wpa_parse_wpa_ie_rsn", left);
-		return (-1);
-	}
-
-	if (left >= 2) {
-		data->pairwise_cipher = 0;
-		count = pos[0] | (pos[1] << 8);
-		pos += 2;
-		left -= 2;
-		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
-			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
-			    "count %u left %u",
-			    "wpa_parse_wpa_ie_rsn", count, left);
-			return (-1);
-		}
-		for (i = 0; i < count; i++) {
-			data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
-			pos += RSN_SELECTOR_LEN;
-			left -= RSN_SELECTOR_LEN;
-		}
-	} else if (left == 1) {
-		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
-		    "wpa_parse_wpa_ie_rsn");
-		return (-1);
-	}
-
-	if (left >= 2) {
-		data->key_mgmt = 0;
-		count = pos[0] | (pos[1] << 8);
-		pos += 2;
-		left -= 2;
-		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
-			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
-			    "count %u left %u",
-			    "wpa_parse_wpa_ie_rsn", count, left);
-			return (-1);
-		}
-		for (i = 0; i < count; i++) {
-			data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
-			pos += RSN_SELECTOR_LEN;
-			left -= RSN_SELECTOR_LEN;
-		}
-	} else if (left == 1) {
-		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
-		    "wpa_parse_wpa_ie_rsn");
-		return (-1);
-	}
-
-	if (left >= 2) {
-		data->capabilities = pos[0] | (pos[1] << 8);
-		pos += 2;
-		left -= 2;
-	}
-
-	if (left > 0) {
-		/*
-		 * RSN IE could include PMKID data, but Authenticator should
-		 * never include it, so no need to parse it in the Supplicant.
-		 */
-		wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
-		    "wpa_parse_wpa_ie_rsn", left);
-	}
-
-	return (0);
-}
-
-int
-wpa_parse_wpa_ie(struct wpa_supplicant *wpa_s, uint8_t *wpa_ie,
-    size_t wpa_ie_len, struct wpa_ie_data *data)
-{
-	if (wpa_ie_len >= 1 && wpa_ie[0] == RSN_INFO_ELEM)
-		return (wpa_parse_wpa_ie_rsn(wpa_s, wpa_ie, wpa_ie_len, data));
-	else
-		return (wpa_parse_wpa_ie_wpa(wpa_s, wpa_ie, wpa_ie_len, data));
-}
-
-static int
-wpa_gen_wpa_ie_wpa(struct wpa_supplicant *wpa_s, uint8_t *wpa_ie)
-{
-	uint8_t *pos;
-	struct wpa_ie_hdr *hdr;
-
-	hdr = (struct wpa_ie_hdr *)wpa_ie;
-	hdr->elem_id = GENERIC_INFO_ELEM;
-	(void) memcpy(&hdr->oui, WPA_OUI_AND_TYPE, WPA_SELECTOR_LEN);
-	hdr->version = LE_16(WPA_VERSION);
-	pos = (uint8_t *)(hdr + 1);
-
-	if (wpa_s->group_cipher == WPA_CIPHER_CCMP) {
-		(void) memcpy(pos, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN);
-	} else if (wpa_s->group_cipher == WPA_CIPHER_TKIP) {
-		(void) memcpy(pos, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN);
-	} else if (wpa_s->group_cipher == WPA_CIPHER_WEP104) {
-		(void) memcpy(pos, WPA_CIPHER_SUITE_WEP104, WPA_SELECTOR_LEN);
-	} else if (wpa_s->group_cipher == WPA_CIPHER_WEP40) {
-		(void) memcpy(pos, WPA_CIPHER_SUITE_WEP40, WPA_SELECTOR_LEN);
-	} else {
-		wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
-		    wpa_s->group_cipher);
-		return (-1);
-	}
-	pos += WPA_SELECTOR_LEN;
-
-	*pos++ = 1;
-	*pos++ = 0;
-	if (wpa_s->pairwise_cipher == WPA_CIPHER_CCMP) {
-		(void) memcpy(pos, WPA_CIPHER_SUITE_CCMP, WPA_SELECTOR_LEN);
-	} else if (wpa_s->pairwise_cipher == WPA_CIPHER_TKIP) {
-		(void) memcpy(pos, WPA_CIPHER_SUITE_TKIP, WPA_SELECTOR_LEN);
-	} else if (wpa_s->pairwise_cipher == WPA_CIPHER_NONE) {
-		(void) memcpy(pos, WPA_CIPHER_SUITE_NONE, WPA_SELECTOR_LEN);
-	} else {
-		wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
-		    wpa_s->pairwise_cipher);
-		return (-1);
-	}
-	pos += WPA_SELECTOR_LEN;
-
-	*pos++ = 1;
-	*pos++ = 0;
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
-		(void) memcpy(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X,
-		    WPA_SELECTOR_LEN);
-	} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK) {
-		(void) memcpy(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X,
-		    WPA_SELECTOR_LEN);
-	} else {
-		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
-		    wpa_s->key_mgmt);
-		return (-1);
-	}
-	pos += WPA_SELECTOR_LEN;
-
-	/*
-	 * WPA Capabilities; use defaults, so no need to include it
-	 */
-	hdr->len = (pos - wpa_ie) - 2;
-
-	return (pos - wpa_ie);
-}
-
-static int
-wpa_gen_wpa_ie_rsn(struct wpa_supplicant *wpa_s, uint8_t *rsn_ie)
-{
-	uint8_t *pos;
-	struct rsn_ie_hdr *hdr;
-
-	hdr = (struct rsn_ie_hdr *)rsn_ie;
-	hdr->elem_id = RSN_INFO_ELEM;
-	hdr->version = LE_16(RSN_VERSION);
-	pos = (uint8_t *)(hdr + 1);
-
-	if (wpa_s->group_cipher == WPA_CIPHER_CCMP) {
-		(void) memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN);
-	} else if (wpa_s->group_cipher == WPA_CIPHER_TKIP) {
-		(void) memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN);
-	} else if (wpa_s->group_cipher == WPA_CIPHER_WEP104) {
-		(void) memcpy(pos, RSN_CIPHER_SUITE_WEP104, RSN_SELECTOR_LEN);
-	} else if (wpa_s->group_cipher == WPA_CIPHER_WEP40) {
-		(void) memcpy(pos, RSN_CIPHER_SUITE_WEP40, RSN_SELECTOR_LEN);
-	} else {
-		wpa_printf(MSG_WARNING, "Invalid group cipher (%d).",
-		    wpa_s->group_cipher);
-		return (-1);
-	}
-	pos += RSN_SELECTOR_LEN;
-
-	*pos++ = 1;
-	*pos++ = 0;
-	if (wpa_s->pairwise_cipher == WPA_CIPHER_CCMP) {
-		(void) memcpy(pos, RSN_CIPHER_SUITE_CCMP, RSN_SELECTOR_LEN);
-	} else if (wpa_s->pairwise_cipher == WPA_CIPHER_TKIP) {
-		(void) memcpy(pos, RSN_CIPHER_SUITE_TKIP, RSN_SELECTOR_LEN);
-	} else if (wpa_s->pairwise_cipher == WPA_CIPHER_NONE) {
-		(void) memcpy(pos, RSN_CIPHER_SUITE_NONE, RSN_SELECTOR_LEN);
-	} else {
-		wpa_printf(MSG_WARNING, "Invalid pairwise cipher (%d).",
-		    wpa_s->pairwise_cipher);
-		return (-1);
-	}
-	pos += RSN_SELECTOR_LEN;
-
-	*pos++ = 1;
-	*pos++ = 0;
-	if (wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X) {
-		(void) memcpy(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X,
-		    RSN_SELECTOR_LEN);
-	} else if (wpa_s->key_mgmt == WPA_KEY_MGMT_PSK) {
-		(void) memcpy(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X,
-		    RSN_SELECTOR_LEN);
-	} else {
-		wpa_printf(MSG_WARNING, "Invalid key management type (%d).",
-		    wpa_s->key_mgmt);
-		return (-1);
-	}
-	pos += RSN_SELECTOR_LEN;
-
-	/* RSN Capabilities */
-	*pos++ = 0;
-	*pos++ = 0;
-
-	if (wpa_s->cur_pmksa) {
-		/* PMKID Count (2 octets, little endian) */
-		*pos++ = 1;
-		*pos++ = 0;
-		/* PMKID */
-		(void) memcpy(pos, wpa_s->cur_pmksa->pmkid, PMKID_LEN);
-		pos += PMKID_LEN;
-	}
-
-	hdr->len = (pos - rsn_ie) - 2;
-
-	return (pos - rsn_ie);
-}
-
-int
-wpa_gen_wpa_ie(struct wpa_supplicant *wpa_s, uint8_t *wpa_ie)
-{
-	if (wpa_s->proto == WPA_PROTO_RSN)
-		return (wpa_gen_wpa_ie_rsn(wpa_s, wpa_ie));
-	else
-		return (wpa_gen_wpa_ie_wpa(wpa_s, wpa_ie));
-}
-
-static void
-wpa_pmk_to_ptk(uint8_t *pmk, uint8_t *addr1, uint8_t *addr2,
-    uint8_t *nonce1, uint8_t *nonce2, uint8_t *ptk, size_t ptk_len)
-{
-	uint8_t data[2 * IEEE80211_ADDR_LEN + 2 * WPA_PMK_LEN];
-
-	/*
-	 * PTK = PRF-X(PMK, "Pairwise key expansion",
-	 * 	Min(AA, SA) || Max(AA, SA) ||
-	 * 	Min(ANonce, SNonce) || Max(ANonce, SNonce))
-	 */
-
-	if (memcmp(addr1, addr2, IEEE80211_ADDR_LEN) < 0) {
-		(void) memcpy(data, addr1, IEEE80211_ADDR_LEN);
-		(void) memcpy(data + IEEE80211_ADDR_LEN, addr2,
-		    IEEE80211_ADDR_LEN);
-	} else {
-		(void) memcpy(data, addr2, IEEE80211_ADDR_LEN);
-		(void) memcpy(data + IEEE80211_ADDR_LEN, addr1,
-		    IEEE80211_ADDR_LEN);
-	}
-
-	if (memcmp(nonce1, nonce2, WPA_PMK_LEN) < 0) {
-		(void) memcpy(data + 2 * IEEE80211_ADDR_LEN, nonce1,
-		    WPA_PMK_LEN);
-		(void) memcpy(data + 2 * IEEE80211_ADDR_LEN + WPA_PMK_LEN,
-		    nonce2, WPA_PMK_LEN);
-	} else {
-		(void) memcpy(data + 2 * IEEE80211_ADDR_LEN, nonce2,
-		    WPA_PMK_LEN);
-		(void) memcpy(data + 2 * IEEE80211_ADDR_LEN + WPA_PMK_LEN,
-		    nonce1, WPA_PMK_LEN);
-	}
-
-	sha1_prf(pmk, WPA_PMK_LEN, "Pairwise key expansion", data,
-	    sizeof (data), ptk, ptk_len);
-
-	wpa_hexdump(MSG_DEBUG, "WPA: PMK", pmk, WPA_PMK_LEN);
-	wpa_hexdump(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
-}
-
-struct wpa_ssid *
-wpa_supplicant_get_ssid(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_ssid *entry;
-	uint8_t ssid[MAX_ESSID_LENGTH];
-	int ssid_len;
-	uint8_t bssid[IEEE80211_ADDR_LEN];
-
-	(void) memset(ssid, 0, MAX_ESSID_LENGTH);
-	ssid_len = wpa_s->driver->get_ssid(wpa_s->handle, wpa_s->linkid,
-	    (char *)ssid);
-	if (ssid_len < 0) {
-		wpa_printf(MSG_WARNING, "Could not read SSID from driver.");
-		return (NULL);
-	}
-
-	if (wpa_s->driver->get_bssid(wpa_s->handle, wpa_s->linkid,
-	    (char *)bssid) < 0) {
-		wpa_printf(MSG_WARNING, "Could not read BSSID from driver.");
-		return (NULL);
-	}
-
-	entry = wpa_s->conf->ssid;
-	wpa_printf(MSG_DEBUG, "entry len=%d ssid=%s,"
-	    " driver len=%d ssid=%s",
-	    entry->ssid_len, entry->ssid, ssid_len, ssid);
-
-	if (ssid_len == entry->ssid_len &&
-	    memcmp(ssid, entry->ssid, ssid_len) == 0 &&
-	    (!entry->bssid_set ||
-	    memcmp(bssid, entry->bssid, IEEE80211_ADDR_LEN) == 0))
-		return (entry);
-
-	return (NULL);
-}
-
-static void
-wpa_eapol_key_mic(uint8_t *key, int ver, uint8_t *buf, size_t len, uint8_t *mic)
-{
-	if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
-		hmac_md5(key, 16, buf, len, mic);
-	} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
-		uint8_t hash[SHA1_MAC_LEN];
-		hmac_sha1(key, 16, buf, len, hash);
-		(void) memcpy(mic, hash, MD5_MAC_LEN);
-	}
-}
-
-void
-wpa_supplicant_key_request(struct wpa_supplicant *wpa_s,
-	int error, int pairwise)
-{
-	int rlen;
-	struct ieee802_1x_hdr *hdr;
-	struct wpa_eapol_key *reply;
-	unsigned char *rbuf;
-	struct l2_ethhdr *ethhdr;
-	int key_info, ver;
-	uint8_t bssid[IEEE80211_ADDR_LEN];
-
-	if (wpa_s->pairwise_cipher == WPA_CIPHER_CCMP)
-		ver = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
-	else
-		ver = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
-
-	if (wpa_s->driver->get_bssid(wpa_s->handle, wpa_s->linkid,
-	    (char *)bssid) < 0) {
-		wpa_printf(MSG_WARNING, "Failed to read BSSID for EAPOL-Key "
-		    "request");
-		return;
-	}
-
-	rlen = sizeof (*ethhdr) + sizeof (*hdr) + sizeof (*reply);
-	rbuf = malloc(rlen);
-	if (rbuf == NULL)
-		return;
-
-	(void) memset(rbuf, 0, rlen);
-	ethhdr = (struct l2_ethhdr *)rbuf;
-	(void) memcpy(ethhdr->h_dest, bssid, IEEE80211_ADDR_LEN);
-	(void) memcpy(ethhdr->h_source, wpa_s->own_addr, IEEE80211_ADDR_LEN);
-	ethhdr->h_proto = htons(ETHERTYPE_EAPOL);
-
-	hdr = (struct ieee802_1x_hdr *)(ethhdr + 1);
-	hdr->version = wpa_s->conf->eapol_version;
-	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
-	hdr->length = htons(sizeof (*reply));
-
-	reply = (struct wpa_eapol_key *)(hdr + 1);
-	reply->type = wpa_s->proto == WPA_PROTO_RSN ?
-	    EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
-	key_info = WPA_KEY_INFO_REQUEST | ver;
-	if (wpa_s->ptk_set)
-		key_info |= WPA_KEY_INFO_MIC;
-	if (error)
-		key_info |= WPA_KEY_INFO_ERROR;
-	if (pairwise)
-		key_info |= WPA_KEY_INFO_KEY_TYPE;
-	reply->key_info = BE_16(key_info);
-	reply->key_length = 0;
-	(void) memcpy(reply->replay_counter, wpa_s->request_counter,
-	    WPA_REPLAY_COUNTER_LEN);
-	inc_byte_array(wpa_s->request_counter, WPA_REPLAY_COUNTER_LEN);
-
-	reply->key_data_length = BE_16(0);
-
-	if (key_info & WPA_KEY_INFO_MIC) {
-		wpa_eapol_key_mic(wpa_s->ptk.mic_key, ver, (uint8_t *)hdr,
-		    rlen - sizeof (*ethhdr), reply->key_mic);
-	}
-
-	wpa_printf(MSG_INFO, "WPA: Sending EAPOL-Key Request (error=%d "
-	    "pairwise=%d ptk_set=%d len=%d)",
-	    error, pairwise, wpa_s->ptk_set, rlen);
-	wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key Request", rbuf, rlen);
-	(void) l2_packet_send(wpa_s->l2, rbuf, rlen);
-	free(rbuf);
-}
-
-static void
-wpa_supplicant_process_1_of_4(struct wpa_supplicant *wpa_s,
-    unsigned char *src_addr, struct wpa_eapol_key *key, int ver)
-{
-	int rlen;
-	struct ieee802_1x_hdr *hdr;
-	struct wpa_eapol_key *reply;
-	unsigned char *rbuf;
-	struct l2_ethhdr *ethhdr;
-	struct wpa_ssid *ssid;
-	struct wpa_ptk *ptk;
-	uint8_t buf[8], wpa_ie_buf[80], *wpa_ie, *pmkid = NULL;
-	int wpa_ie_len;
-
-	wpa_s->wpa_state = WPA_4WAY_HANDSHAKE;
-	wpa_printf(MSG_DEBUG, "WPA: RX message 1 of 4-Way Handshake from "
-	    MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
-
-	ssid = wpa_supplicant_get_ssid(wpa_s);
-	if (ssid == NULL) {
-		wpa_printf(MSG_WARNING,
-		    "WPA: No SSID info found (msg 1 of 4).");
-		return;
-	}
-
-	if (wpa_s->proto == WPA_PROTO_RSN) {
-		/* RSN: msg 1/4 should contain PMKID for the selected PMK */
-		uint8_t *pos = (uint8_t *)(key + 1);
-		uint8_t *end = pos + BE_16(key->key_data_length);
-
-		wpa_hexdump(MSG_DEBUG, "RSN: msg 1/4 key data",
-		    pos, BE_16(key->key_data_length));
-
-		while (pos + 1 < end) {
-			if (pos + 2 + pos[1] > end) {
-				wpa_printf(MSG_DEBUG, "RSN: key data "
-				    "underflow (ie=%d len=%d)",
-				    pos[0], pos[1]);
-				break;
-			}
-			if (pos[0] == GENERIC_INFO_ELEM &&
-			    pos + 1 + RSN_SELECTOR_LEN < end &&
-			    pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
-			    memcmp(pos + 2, RSN_KEY_DATA_PMKID,
-			    RSN_SELECTOR_LEN) == 0) {
-				pmkid = pos + 2 + RSN_SELECTOR_LEN;
-				wpa_hexdump(MSG_DEBUG, "RSN: PMKID from "
-				    "Authenticator", pmkid, PMKID_LEN);
-				break;
-			} else if (pos[0] == GENERIC_INFO_ELEM && pos[1] == 0)
-				break;
-			pos += 2 + pos[1];
-		}
-	}
-
-	wpa_ie = wpa_ie_buf;
-	wpa_ie_len = wpa_gen_wpa_ie(wpa_s, wpa_ie);
-	if (wpa_ie_len < 0) {
-		wpa_printf(MSG_WARNING, "WPA: Failed to generate "
-		    "WPA IE (for msg 2 of 4).");
-		return;
-	}
-	wpa_hexdump(MSG_DEBUG, "WPA: WPA IE for msg 2/4", wpa_ie, wpa_ie_len);
-
-	rlen = sizeof (*ethhdr) + sizeof (*hdr) + sizeof (*reply) + wpa_ie_len;
-	rbuf = malloc(rlen);
-	if (rbuf == NULL)
-		return;
-
-	(void) memset(rbuf, 0, rlen);
-	ethhdr = (struct l2_ethhdr *)rbuf;
-	(void) memcpy(ethhdr->h_dest, src_addr, IEEE80211_ADDR_LEN);
-	(void) memcpy(ethhdr->h_source, wpa_s->own_addr, IEEE80211_ADDR_LEN);
-	ethhdr->h_proto = htons(ETHERTYPE_EAPOL);
-
-	hdr = (struct ieee802_1x_hdr *)(ethhdr + 1);
-	hdr->version = wpa_s->conf->eapol_version;
-	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
-	hdr->length = htons(sizeof (*reply) + wpa_ie_len);
-
-	reply = (struct wpa_eapol_key *)(hdr + 1);
-	reply->type = wpa_s->proto == WPA_PROTO_RSN ?
-	    EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
-	reply->key_info = BE_16(ver | WPA_KEY_INFO_KEY_TYPE | WPA_KEY_INFO_MIC);
-	reply->key_length = key->key_length;
-	(void) memcpy(reply->replay_counter, key->replay_counter,
-	    WPA_REPLAY_COUNTER_LEN);
-
-	reply->key_data_length = BE_16(wpa_ie_len);
-	(void) memcpy(reply + 1, wpa_ie, wpa_ie_len);
-
-	if (wpa_s->renew_snonce) {
-		if (random_get_pseudo_bytes(wpa_s->snonce, WPA_NONCE_LEN)) {
-			wpa_printf(MSG_WARNING, "WPA: Failed to get "
-			    "random data for SNonce");
-			free(rbuf);
-			return;
-		}
-
-		wpa_s->renew_snonce = 0;
-		wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce",
-		    wpa_s->snonce, WPA_NONCE_LEN);
-	}
-	(void) memcpy(reply->key_nonce, wpa_s->snonce, WPA_NONCE_LEN);
-	ptk = &wpa_s->tptk;
-	(void) memcpy(wpa_s->anonce, key->key_nonce, WPA_NONCE_LEN);
-
-	wpa_pmk_to_ptk(wpa_s->pmk, wpa_s->own_addr, src_addr,
-	    wpa_s->snonce, key->key_nonce, (uint8_t *)ptk, sizeof (*ptk));
-
-	/*
-	 * Supplicant: swap tx/rx Mic keys
-	 */
-	(void) memcpy(buf, ptk->u.auth.tx_mic_key, 8);
-	(void) memcpy(ptk->u.auth.tx_mic_key, ptk->u.auth.rx_mic_key, 8);
-	(void) memcpy(ptk->u.auth.rx_mic_key, buf, 8);
-	wpa_s->tptk_set = 1;
-	wpa_eapol_key_mic(wpa_s->tptk.mic_key, ver, (uint8_t *)hdr,
-	    rlen - sizeof (*ethhdr), reply->key_mic);
-	wpa_hexdump(MSG_DEBUG, "WPA: EAPOL-Key MIC", reply->key_mic, 16);
-
-	wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 2/4");
-	wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key 2/4", rbuf, rlen);
-	(void) l2_packet_send(wpa_s->l2, rbuf, rlen);
-
-	free(rbuf);
-}
-
-static void
-wpa_supplicant_process_3_of_4_gtk(struct wpa_supplicant *wpa_s,
-    unsigned char *src_addr, struct wpa_eapol_key *key,
-    uint8_t *gtk, int gtk_len)
-{
-	int keyidx, tx, key_rsc_len = 0, alg;
-
-	wpa_hexdump(MSG_DEBUG,
-	    "WPA: received GTK in pairwise handshake", gtk, gtk_len);
-
-	keyidx = gtk[0] & 0x3;
-	tx = !!(gtk[0] & BIT(2));
-	if (tx && wpa_s->pairwise_cipher != WPA_CIPHER_NONE) {
-		/*
-		 * Ignore Tx bit in GTK IE if a pairwise key is used.
-		 * One AP seemed to set this bit (incorrectly, since Tx
-		 * is only when doing Group Key only APs) and without
-		 * this workaround, the data connection does not work
-		 * because wpa_supplicant configured non-zero keyidx to
-		 * be used for unicast.
-		 */
-		wpa_printf(MSG_INFO, "RSN: Tx bit set for GTK IE, but "
-		    "pairwise keys are used - ignore Tx bit");
-		tx = 0;
-	}
-
-	gtk += 2;
-	gtk_len -= 2;
-	wpa_hexdump(MSG_DEBUG, "WPA: Group Key", gtk, gtk_len);
-
-	switch (wpa_s->group_cipher) {
-	case WPA_CIPHER_CCMP:
-		if (gtk_len != 16) {
-			wpa_printf(MSG_WARNING, "WPA: Unsupported CCMP"
-			    " Group Cipher key length %d.", gtk_len);
-			return;
-		}
-		key_rsc_len = 6;
-		alg = WPA_ALG_CCMP;
-		break;
-	case WPA_CIPHER_TKIP:
-		if (gtk_len != 32) {
-			wpa_printf(MSG_WARNING, "WPA: Unsupported TKIP"
-			    " Group Cipher key length %d.", gtk_len);
-			return;
-		}
-		key_rsc_len = 6;
-		alg = WPA_ALG_TKIP;
-		break;
-	case WPA_CIPHER_WEP104:
-		if (gtk_len != 13) {
-			wpa_printf(MSG_WARNING, "WPA: Unsupported "
-			    "WEP104 Group Cipher key length " "%d.", gtk_len);
-			return;
-		}
-		alg = WPA_ALG_WEP;
-		break;
-	case WPA_CIPHER_WEP40:
-		if (gtk_len != 5) {
-			wpa_printf(MSG_WARNING, "WPA: Unsupported "
-			    "WEP40 Group Cipher key length %d.", gtk_len);
-			return;
-		}
-		alg = WPA_ALG_WEP;
-		break;
-	default:
-		wpa_printf(MSG_WARNING, "WPA: Unsupport Group Cipher "
-		    "%d", wpa_s->group_cipher);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "WPA: Installing GTK to the driver "
-	    "(keyidx=%d tx=%d).", keyidx, tx);
-	wpa_hexdump(MSG_DEBUG, "WPA: RSC", key->key_rsc, key_rsc_len);
-	if (wpa_s->group_cipher == WPA_CIPHER_TKIP) {
-		uint8_t tmpbuf[8];
-		/*
-		 * Swap Tx/Rx keys for Michael MIC
-		 */
-		(void) memcpy(tmpbuf, gtk + 16, 8);
-		(void) memcpy(gtk + 16, gtk + 24, 8);
-		(void) memcpy(gtk + 24, tmpbuf, 8);
-	}
-	if (wpa_s->pairwise_cipher == WPA_CIPHER_NONE) {
-		if (wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, alg,
-		    (uint8_t *)"\xff\xff\xff\xff\xff\xff",
-		    keyidx, 1, key->key_rsc,
-		    key_rsc_len, gtk, gtk_len) < 0)
-			wpa_printf(MSG_WARNING, "WPA: Failed to set "
-			    "GTK to the driver (Group only).");
-	} else if (wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, alg,
-	    (uint8_t *)"\xff\xff\xff\xff\xff\xff", keyidx, tx,
-	    key->key_rsc, key_rsc_len, gtk, gtk_len) < 0) {
-		wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to "
-		    "the driver.");
-	}
-
-	wpa_printf(MSG_INFO, "WPA: Key negotiation completed with "
-	    MACSTR, MAC2STR(src_addr));
-	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
-	wpa_supplicant_cancel_auth_timeout(wpa_s);
-	wpa_s->wpa_state = WPA_COMPLETED;
-}
-
-static void
-wpa_supplicant_process_3_of_4(struct wpa_supplicant *wpa_s,
-    unsigned char *src_addr, struct wpa_eapol_key *key,
-    int extra_len, int ver)
-{
-	int rlen;
-	struct ieee802_1x_hdr *hdr;
-	struct wpa_eapol_key *reply;
-	unsigned char *rbuf;
-	struct l2_ethhdr *ethhdr;
-	int key_info, ie_len = 0, keylen, gtk_len = 0;
-	uint8_t *ie = NULL, *gtk = NULL, *key_rsc;
-	uint8_t null_rsc[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
-
-	wpa_s->wpa_state = WPA_4WAY_HANDSHAKE;
-	wpa_printf(MSG_DEBUG, "WPA: RX message 3 of 4-Way Handshake from "
-	    MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
-
-	key_info = BE_16(key->key_info);
-
-	if (wpa_s->proto == WPA_PROTO_RSN) {
-		uint8_t *pos = (uint8_t *)(key + 1);
-		uint8_t *end = pos + BE_16(key->key_data_length);
-		while (pos + 1 < end) {
-			if (pos + 2 + pos[1] > end) {
-				wpa_printf(MSG_DEBUG, "RSN: key data "
-				    "underflow (ie=%d len=%d)",
-				    pos[0], pos[1]);
-				break;
-			}
-			if (*pos == RSN_INFO_ELEM) {
-				ie = pos;
-				ie_len = pos[1] + 2;
-			} else if (pos[0] == GENERIC_INFO_ELEM &&
-			    pos + 1 + RSN_SELECTOR_LEN < end &&
-			    pos[1] > RSN_SELECTOR_LEN + 2 &&
-			    memcmp(pos + 2, RSN_KEY_DATA_GROUPKEY,
-			    RSN_SELECTOR_LEN) == 0) {
-				if (!(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
-					wpa_printf(MSG_WARNING, "WPA: GTK IE "
-					    "in unencrypted key data");
-					return;
-				}
-				gtk = pos + 2 + RSN_SELECTOR_LEN;
-				gtk_len = pos[1] - RSN_SELECTOR_LEN;
-			} else if (pos[0] == GENERIC_INFO_ELEM && pos[1] == 0)
-				break;
-
-			pos += 2 + pos[1];
-		}
-	} else {
-		ie = (uint8_t *)(key + 1);
-		ie_len = BE_16(key->key_data_length);
-		if (ie_len > extra_len) {
-			wpa_printf(MSG_INFO, "WPA: Truncated EAPOL-Key packet:"
-			    " ie_len=%d > extra_len=%d",
-			    ie_len, extra_len);
-			return;
-		}
-	}
-
-	if (wpa_s->ap_wpa_ie &&
-	    (wpa_s->ap_wpa_ie_len != ie_len ||
-	    memcmp(wpa_s->ap_wpa_ie, ie, ie_len) != 0)) {
-		wpa_printf(MSG_WARNING, "WPA: WPA IE in 3/4 msg does not match"
-		    " with WPA IE in Beacon/ProbeResp (src=" MACSTR ")",
-		    MAC2STR(src_addr));
-		wpa_hexdump(MSG_INFO, "WPA: WPA IE in Beacon/ProbeResp",
-		    wpa_s->ap_wpa_ie, wpa_s->ap_wpa_ie_len);
-		wpa_hexdump(MSG_INFO, "WPA: WPA IE in 3/4 msg", ie, ie_len);
-		wpa_supplicant_disassociate(wpa_s, REASON_IE_IN_4WAY_DIFFERS);
-		wpa_supplicant_req_scan(wpa_s, 0, 0);
-		return;
-	}
-
-	if (memcmp(wpa_s->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(src_addr));
-		return;
-	}
-
-	keylen = BE_16(key->key_length);
-	switch (wpa_s->pairwise_cipher) {
-	case WPA_CIPHER_CCMP:
-		if (keylen != 16) {
-			wpa_printf(MSG_WARNING, "WPA: Invalid CCMP key length "
-			    "%d (src=" MACSTR ")",
-			    keylen, MAC2STR(src_addr));
-			return;
-		}
-		break;
-	case WPA_CIPHER_TKIP:
-		if (keylen != 32) {
-			wpa_printf(MSG_WARNING, "WPA: Invalid TKIP key length "
-			    "%d (src=" MACSTR ")",
-			    keylen, MAC2STR(src_addr));
-			return;
-		}
-		break;
-	}
-
-	rlen = sizeof (*ethhdr) + sizeof (*hdr) + sizeof (*reply);
-	rbuf = malloc(rlen);
-	if (rbuf == NULL)
-		return;
-
-	(void) memset(rbuf, 0, rlen);
-	ethhdr = (struct l2_ethhdr *)rbuf;
-	(void) memcpy(ethhdr->h_dest, src_addr, IEEE80211_ADDR_LEN);
-	(void) memcpy(ethhdr->h_source, wpa_s->own_addr, IEEE80211_ADDR_LEN);
-	ethhdr->h_proto = htons(ETHERTYPE_EAPOL);
-
-	hdr = (struct ieee802_1x_hdr *)(ethhdr + 1);
-	hdr->version = wpa_s->conf->eapol_version;
-	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
-	hdr->length = htons(sizeof (*reply));
-
-	reply = (struct wpa_eapol_key *)(hdr + 1);
-	reply->type = wpa_s->proto == WPA_PROTO_RSN ?
-	    EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
-	reply->key_info = BE_16(ver | WPA_KEY_INFO_KEY_TYPE |
-	    WPA_KEY_INFO_MIC | (key_info & WPA_KEY_INFO_SECURE));
-	reply->key_length = key->key_length;
-	(void) memcpy(reply->replay_counter, key->replay_counter,
-	    WPA_REPLAY_COUNTER_LEN);
-
-	reply->key_data_length = BE_16(0);
-
-	(void) memcpy(reply->key_nonce, wpa_s->snonce, WPA_NONCE_LEN);
-	wpa_eapol_key_mic(wpa_s->ptk.mic_key, ver, (uint8_t *)hdr,
-	    rlen - sizeof (*ethhdr), reply->key_mic);
-
-	wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 4/4");
-	wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key 4/4", rbuf, rlen);
-	(void) l2_packet_send(wpa_s->l2, rbuf, rlen);
-
-	free(rbuf);
-
-	/*
-	 * SNonce was successfully used in msg 3/4, so mark it to be renewed
-	 * for the next 4-Way Handshake. If msg 3 is received again, the old
-	 * SNonce will still be used to avoid changing PTK.
-	 */
-	wpa_s->renew_snonce = 1;
-
-	if (key_info & WPA_KEY_INFO_INSTALL) {
-		int alg, keylen, rsclen;
-		wpa_printf(MSG_DEBUG, "WPA: Installing PTK to the driver.");
-		switch (wpa_s->pairwise_cipher) {
-		case WPA_CIPHER_CCMP:
-			alg = WPA_ALG_CCMP;
-			keylen = 16;
-			rsclen = 6;
-			break;
-		case WPA_CIPHER_TKIP:
-			alg = WPA_ALG_TKIP;
-			keylen = 32;
-			rsclen = 6;
-			break;
-		case WPA_CIPHER_NONE:
-			wpa_printf(MSG_DEBUG, "WPA: Pairwise Cipher Suite: "
-			    "NONE - do not use pairwise keys");
-			return;
-		default:
-			wpa_printf(MSG_WARNING, "WPA: Unsupported pairwise "
-			    "cipher %d", wpa_s->pairwise_cipher);
-			return;
-		}
-		if (wpa_s->proto == WPA_PROTO_RSN) {
-			key_rsc = null_rsc;
-		} else {
-			key_rsc = key->key_rsc;
-			wpa_hexdump(MSG_DEBUG, "WPA: RSC", key_rsc, rsclen);
-		}
-
-		if (wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, alg,
-		    src_addr, 0, 1, key_rsc, rsclen,
-		    (uint8_t *)&wpa_s->ptk.tk1, keylen) < 0) {
-			wpa_printf(MSG_WARNING, "WPA: Failed to set PTK to the"
-			    " driver.");
-		}
-	}
-
-	wpa_printf(MSG_DEBUG, "%s: key_info=%x gtk=%p\n",
-	    "wpa_supplicant_process_3_of_4", key_info, gtk);
-	wpa_s->wpa_state = WPA_GROUP_HANDSHAKE;
-
-	if (gtk)
-		wpa_supplicant_process_3_of_4_gtk(wpa_s,
-		    src_addr, key, gtk, gtk_len);
-}
-
-static void
-wpa_supplicant_process_1_of_2(struct wpa_supplicant *wpa_s,
-    unsigned char *src_addr, struct wpa_eapol_key *key,
-    int extra_len, int ver)
-{
-	int rlen;
-	struct ieee802_1x_hdr *hdr;
-	struct wpa_eapol_key *reply;
-	unsigned char *rbuf;
-	struct l2_ethhdr *ethhdr;
-	int key_info, keylen, keydatalen, maxkeylen, keyidx, key_rsc_len = 0;
-	int alg, tx;
-	uint8_t ek[32], tmpbuf[8], gtk[32];
-	uint8_t *gtk_ie = NULL;
-	size_t gtk_ie_len = 0;
-
-	wpa_s->wpa_state = WPA_GROUP_HANDSHAKE;
-	wpa_printf(MSG_DEBUG, "WPA: RX message 1 of Group Key Handshake from "
-	    MACSTR " (ver=%d)", MAC2STR(src_addr), ver);
-
-	key_info = BE_16(key->key_info);
-	keydatalen = BE_16(key->key_data_length);
-
-	if (wpa_s->proto == WPA_PROTO_RSN) {
-		uint8_t *pos = (uint8_t *)(key + 1);
-		uint8_t *end = pos + keydatalen;
-		while (pos + 1 < end) {
-			if (pos + 2 + pos[1] > end) {
-				wpa_printf(MSG_DEBUG, "RSN: key data "
-				    "underflow (ie=%d len=%d)",
-				    pos[0], pos[1]);
-				break;
-			}
-			if (pos[0] == GENERIC_INFO_ELEM &&
-			    pos + 1 + RSN_SELECTOR_LEN < end &&
-			    pos[1] > RSN_SELECTOR_LEN + 2 &&
-			    memcmp(pos + 2, RSN_KEY_DATA_GROUPKEY,
-			    RSN_SELECTOR_LEN) == 0) {
-				if (!(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
-					wpa_printf(MSG_WARNING, "WPA: GTK IE "
-					    "in unencrypted key data");
-					return;
-				}
-				gtk_ie = pos + 2 + RSN_SELECTOR_LEN;
-				gtk_ie_len = pos[1] - RSN_SELECTOR_LEN;
-				break;
-			} else if (pos[0] == GENERIC_INFO_ELEM && pos[1] == 0) {
-				break;
-			}
-
-			pos += 2 + pos[1];
-		}
-
-		if (gtk_ie == NULL) {
-			wpa_printf(MSG_INFO, "WPA: No GTK IE in Group Key "
-			    "message 1/2");
-			return;
-		}
-		maxkeylen = keylen = gtk_ie_len - 2;
-	} else {
-		keylen = BE_16(key->key_length);
-		maxkeylen = keydatalen;
-		if (keydatalen > extra_len) {
-			wpa_printf(MSG_INFO, "WPA: Truncated EAPOL-Key packet:"
-			    " key_data_length=%d > extra_len=%d",
-			    keydatalen, extra_len);
-			return;
-		}
-		if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES)
-			maxkeylen -= 8;
-	}
-
-	switch (wpa_s->group_cipher) {
-	case WPA_CIPHER_CCMP:
-		if (keylen != 16 || maxkeylen < 16) {
-			wpa_printf(MSG_WARNING, "WPA: Unsupported CCMP Group "
-			    "Cipher key length %d (%d).", keylen, maxkeylen);
-			return;
-		}
-		key_rsc_len = 6;
-		alg = WPA_ALG_CCMP;
-		break;
-	case WPA_CIPHER_TKIP:
-		if (keylen != 32 || maxkeylen < 32) {
-			wpa_printf(MSG_WARNING, "WPA: Unsupported TKIP Group "
-			    "Cipher key length %d (%d).", keylen, maxkeylen);
-			return;
-		}
-		key_rsc_len = 6; /* key->key_data; */
-		alg = WPA_ALG_TKIP;
-		break;
-	case WPA_CIPHER_WEP104:
-		if (keylen != 13 || maxkeylen < 13) {
-			wpa_printf(MSG_WARNING, "WPA: Unsupported WEP104 Group"
-			    " Cipher key length %d (%d).", keylen, maxkeylen);
-			return;
-		}
-		alg = WPA_ALG_WEP;
-		break;
-	case WPA_CIPHER_WEP40:
-		if (keylen != 5 || maxkeylen < 5) {
-			wpa_printf(MSG_WARNING, "WPA: Unsupported WEP40 Group "
-			    "Cipher key length %d (%d).", keylen, maxkeylen);
-			return;
-		}
-		alg = WPA_ALG_WEP;
-		break;
-	default:
-		wpa_printf(MSG_WARNING, "WPA: Unsupport Group Cipher %d",
-		    wpa_s->group_cipher);
-		return;
-	}
-
-	if (wpa_s->proto == WPA_PROTO_RSN) {
-		wpa_hexdump(MSG_DEBUG,
-		    "WPA: received GTK in group key handshake",
-		    gtk_ie, gtk_ie_len);
-		keyidx = gtk_ie[0] & 0x3;
-		tx = !!(gtk_ie[0] & BIT(2));
-		if (gtk_ie_len - 2 > sizeof (gtk)) {
-			wpa_printf(MSG_INFO, "WPA: Too long GTK in GTK IE "
-			    "(len=%d)", gtk_ie_len - 2);
-			return;
-		}
-		(void) memcpy(gtk, gtk_ie + 2, gtk_ie_len - 2);
-	} else {
-		keyidx = (key_info & WPA_KEY_INFO_KEY_INDEX_MASK) >>
-		    WPA_KEY_INFO_KEY_INDEX_SHIFT;
-		if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
-			(void) memcpy(ek, key->key_iv, 16);
-			(void) memcpy(ek + 16, wpa_s->ptk.encr_key, 16);
-			rc4_skip(ek, 32, 256, (uint8_t *)(key + 1), keydatalen);
-			(void) memcpy(gtk, key + 1, keylen);
-		} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
-			if (keydatalen % 8) {
-				wpa_printf(MSG_WARNING, "WPA: Unsupported "
-				    "AES-WRAP len %d", keydatalen);
-				return;
-			}
-			if (aes_unwrap(wpa_s->ptk.encr_key, maxkeylen / 8,
-			    (uint8_t *)(key + 1), gtk)) {
-				wpa_printf(MSG_WARNING, "WPA: AES unwrap "
-				    "failed - could not decrypt GTK");
-				return;
-			}
-		}
-		tx = !!(key_info & WPA_KEY_INFO_TXRX);
-		if (tx && wpa_s->pairwise_cipher != WPA_CIPHER_NONE) {
-			/*
-			 * Ignore Tx bit in Group Key message if a pairwise key
-			 * is used. Some APs seem to setting this bit
-			 * (incorrectly, since Tx is only when doing Group Key
-			 * only APs) and without this workaround, the data
-			 * connection does not work because wpa_supplicant
-			 * configured non-zero keyidx to be used for unicast.
-			 */
-			wpa_printf(MSG_INFO, "WPA: Tx bit set for GTK, but "
-			    "pairwise keys are used - ignore Tx bit");
-			tx = 0;
-		}
-	}
-	wpa_hexdump(MSG_DEBUG, "WPA: Group Key", gtk, keylen);
-	wpa_printf(MSG_DEBUG, "WPA: Installing GTK to the driver (keyidx=%d "
-	    "tx=%d).", keyidx, tx);
-	wpa_hexdump(MSG_DEBUG, "WPA: RSC", key->key_rsc, key_rsc_len);
-	if (wpa_s->group_cipher == WPA_CIPHER_TKIP) {
-		/*
-		 * Swap Tx/Rx keys for Michael MIC
-		 */
-		(void) memcpy(tmpbuf, gtk + 16, 8);
-		(void) memcpy(gtk + 16, gtk + 24, 8);
-		(void) memcpy(gtk + 24, tmpbuf, 8);
-	}
-	if (wpa_s->pairwise_cipher == WPA_CIPHER_NONE) {
-		if (wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, alg,
-		    (uint8_t *)"\xff\xff\xff\xff\xff\xff",
-		    keyidx, 1, key->key_rsc,
-		    key_rsc_len, gtk, keylen) < 0)
-			wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the"
-			    " driver (Group only).");
-	} else if (wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, alg,
-	    (uint8_t *)"\xff\xff\xff\xff\xff\xff",
-	    keyidx, tx,
-	    key->key_rsc, key_rsc_len,
-	    gtk, keylen) < 0) {
-		wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to the "
-		    "driver.");
-	}
-
-	rlen = sizeof (*ethhdr) + sizeof (*hdr) + sizeof (*reply);
-	rbuf = malloc(rlen);
-	if (rbuf == NULL)
-		return;
-
-	(void) memset(rbuf, 0, rlen);
-	ethhdr = (struct l2_ethhdr *)rbuf;
-	(void) memcpy(ethhdr->h_dest, src_addr, IEEE80211_ADDR_LEN);
-	(void) memcpy(ethhdr->h_source, wpa_s->own_addr, IEEE80211_ADDR_LEN);
-	ethhdr->h_proto = htons(ETHERTYPE_EAPOL);
-
-	hdr = (struct ieee802_1x_hdr *)(ethhdr + 1);
-	hdr->version = wpa_s->conf->eapol_version;
-	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
-	hdr->length = htons(sizeof (*reply));
-
-	reply = (struct wpa_eapol_key *)(hdr + 1);
-	reply->type = wpa_s->proto == WPA_PROTO_RSN ?
-	    EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
-	reply->key_info =
-	    BE_16(ver | WPA_KEY_INFO_MIC | WPA_KEY_INFO_SECURE |
-	    (key_info & WPA_KEY_INFO_KEY_INDEX_MASK));
-	reply->key_length = key->key_length;
-	(void) memcpy(reply->replay_counter, key->replay_counter,
-	    WPA_REPLAY_COUNTER_LEN);
-
-	reply->key_data_length = BE_16(0);
-
-	wpa_eapol_key_mic(wpa_s->ptk.mic_key, ver, (uint8_t *)hdr,
-	    rlen - sizeof (*ethhdr), reply->key_mic);
-
-	wpa_printf(MSG_DEBUG, "WPA: Sending EAPOL-Key 2/2");
-	wpa_hexdump(MSG_MSGDUMP, "WPA: TX EAPOL-Key 2/2", rbuf, rlen);
-	(void) l2_packet_send(wpa_s->l2, rbuf, rlen);
-	free(rbuf);
-
-	wpa_printf(MSG_INFO, "WPA: Key negotiation completed with " MACSTR,
-	    MAC2STR(src_addr));
-	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
-	wpa_supplicant_cancel_auth_timeout(wpa_s);
-	wpa_s->wpa_state = WPA_COMPLETED;
-	wpa_printf(MSG_INFO, "-----------------------------------\n");
-}
-
-static int
-wpa_supplicant_verify_eapol_key_mic(struct wpa_supplicant *wpa_s,
-    struct wpa_eapol_key *key, int ver, uint8_t *buf, size_t len)
-{
-	uint8_t mic[16];
-	int ok = 0;
-
-	(void) memcpy(mic, key->key_mic, 16);
-	if (wpa_s->tptk_set) {
-		(void) memset(key->key_mic, 0, 16);
-		wpa_eapol_key_mic(wpa_s->tptk.mic_key, ver, buf, len,
-		    key->key_mic);
-		if (memcmp(mic, key->key_mic, 16) != 0) {
-			wpa_printf(MSG_WARNING, "WPA: Invalid EAPOL-Key MIC "
-			    "when using TPTK - ignoring TPTK");
-		} else {
-			ok = 1;
-			wpa_s->tptk_set = 0;
-			wpa_s->ptk_set = 1;
-			(void) memcpy(&wpa_s->ptk, &wpa_s->tptk,
-			    sizeof (wpa_s->ptk));
-		}
-	}
-
-	if (!ok && wpa_s->ptk_set) {
-		(void) memset(key->key_mic, 0, 16);
-		wpa_eapol_key_mic(wpa_s->ptk.mic_key, ver, buf, len,
-		    key->key_mic);
-		if (memcmp(mic, key->key_mic, 16) != 0) {
-			wpa_printf(MSG_WARNING, "WPA: Invalid EAPOL-Key MIC "
-			    "- dropping packet");
-			return (-1);
-		}
-		ok = 1;
-	}
-
-	if (!ok) {
-		wpa_printf(MSG_WARNING, "WPA: Could not verify EAPOL-Key MIC "
-		    "- dropping packet");
-		return (-1);
-	}
-
-	(void) memcpy(wpa_s->rx_replay_counter, key->replay_counter,
-	    WPA_REPLAY_COUNTER_LEN);
-	wpa_s->rx_replay_counter_set = 1;
-
-	return (0);
-}
-
-/* Decrypt RSN EAPOL-Key key data (RC4 or AES-WRAP) */
-static int
-wpa_supplicant_decrypt_key_data(struct wpa_supplicant *wpa_s,
-	struct wpa_eapol_key *key, int ver)
-{
-	int keydatalen = BE_16(key->key_data_length);
-
-	wpa_hexdump(MSG_DEBUG, "RSN: encrypted key data",
-	    (uint8_t *)(key + 1), keydatalen);
-	if (!wpa_s->ptk_set) {
-		wpa_printf(MSG_WARNING, "WPA: PTK not available, "
-		    "cannot decrypt EAPOL-Key key data.");
-		return (-1);
-	}
-
-	/*
-	 * Decrypt key data here so that this operation does not need
-	 * to be implemented separately for each message type.
-	 */
-	if (ver == WPA_KEY_INFO_TYPE_HMAC_MD5_RC4) {
-		uint8_t ek[32];
-		(void) memcpy(ek, key->key_iv, 16);
-		(void) memcpy(ek + 16, wpa_s->ptk.encr_key, 16);
-		rc4_skip(ek, 32, 256, (uint8_t *)(key + 1), keydatalen);
-	} else if (ver == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
-		uint8_t *buf;
-		if (keydatalen % 8) {
-			wpa_printf(MSG_WARNING, "WPA: Unsupported "
-			    "AES-WRAP len %d", keydatalen);
-			return (-1);
-		}
-		keydatalen -= 8; /* AES-WRAP adds 8 bytes */
-		buf = malloc(keydatalen);
-		if (buf == NULL) {
-			wpa_printf(MSG_WARNING, "WPA: No memory for "
-			    "AES-UNWRAP buffer");
-			return (-1);
-		}
-		if (aes_unwrap(wpa_s->ptk.encr_key, keydatalen / 8,
-		    (uint8_t *)(key + 1), buf)) {
-			free(buf);
-			wpa_printf(MSG_WARNING, "WPA: AES unwrap failed - "
-			    "could not decrypt EAPOL-Key key data");
-			return (-1);
-		}
-		(void) memcpy(key + 1, buf, keydatalen);
-		free(buf);
-		key->key_data_length = BE_16(keydatalen);
-	}
-	wpa_hexdump(MSG_DEBUG, "WPA: decrypted EAPOL-Key key data",
-	    (uint8_t *)(key + 1), keydatalen);
-
-	return (0);
-}
-
-static void
-wpa_sm_rx_eapol(struct wpa_supplicant *wpa_s,
-    unsigned char *src_addr, unsigned char *buf, size_t len)
-{
-	size_t plen, data_len, extra_len;
-	struct ieee802_1x_hdr *hdr;
-	struct wpa_eapol_key *key;
-	int key_info, ver;
-
-	wpa_printf(MSG_DEBUG, "WPA: EAPOL frame len %u\n ", len);
-
-	hdr = (struct ieee802_1x_hdr *)buf;
-	key = (struct wpa_eapol_key *)(hdr + 1);
-	wpa_printf(MSG_DEBUG, "hdr_len=%u, key_len=%u",
-	    sizeof (*hdr), sizeof (*key));
-	if (len < sizeof (*hdr) + sizeof (*key)) {
-		wpa_printf(MSG_DEBUG, "WPA: EAPOL frame too short, len %u, "
-		    "expecting at least %u",
-		    len, sizeof (*hdr) + sizeof (*key));
-		return;
-	}
-	plen = ntohs(hdr->length);
-	data_len = plen + sizeof (*hdr);
-	wpa_printf(MSG_DEBUG, "IEEE 802.1X RX: version=%d type=%d length=%d",
-	    hdr->version, hdr->type, plen);
-
-	if (hdr->type != IEEE802_1X_TYPE_EAPOL_KEY) {
-		wpa_printf(MSG_DEBUG, "WPA: EAPOL frame (type %u) discarded, "
-		    "not a Key frame", hdr->type);
-		return;
-	}
-	if (plen > len - sizeof (*hdr) || plen < sizeof (*key)) {
-		wpa_printf(MSG_DEBUG, "WPA: EAPOL frame payload size %u "
-		    "invalid (frame size %u)", plen, len);
-		return;
-	}
-
-	wpa_printf(MSG_DEBUG, "  EAPOL-Key type=%d", key->type);
-	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);
-		return;
-	}
-
-	wpa_hexdump(MSG_MSGDUMP, "WPA: RX EAPOL-Key", buf, len);
-	if (data_len < len) {
-		wpa_printf(MSG_DEBUG, "WPA: ignoring %d bytes after the IEEE "
-		    "802.1X data", len - data_len);
-	}
-	key_info = BE_16(key->key_info);
-	ver = key_info & WPA_KEY_INFO_TYPE_MASK;
-	if (ver != WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 &&
-	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
-		wpa_printf(MSG_INFO, "WPA: Unsupported EAPOL-Key descriptor "
-		    "version %d.", ver);
-		return;
-	}
-
-	if (wpa_s->pairwise_cipher == WPA_CIPHER_CCMP &&
-	    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
-		wpa_printf(MSG_INFO, "WPA: CCMP is used, but EAPOL-Key "
-		    "descriptor version (%d) is not 2.", ver);
-		if (wpa_s->group_cipher != WPA_CIPHER_CCMP &&
-		    !(key_info & WPA_KEY_INFO_KEY_TYPE)) {
-			/*
-			 * Earlier versions of IEEE 802.11i did not explicitly
-			 * require version 2 descriptor for all EAPOL-Key
-			 * packets, so allow group keys to use version 1 if
-			 * CCMP is not used for them.
-			 */
-			wpa_printf(MSG_INFO, "WPA: Backwards compatibility: "
-			    "allow invalid version for non-CCMP group keys");
-		} else
-			return;
-	}
-
-	if (wpa_s->rx_replay_counter_set &&
-	    memcmp(key->replay_counter, wpa_s->rx_replay_counter,
-	    WPA_REPLAY_COUNTER_LEN) <= 0) {
-		wpa_printf(MSG_WARNING, "WPA: EAPOL-Key Replay Counter did not"
-		    " increase - dropping packet");
-		return;
-	}
-
-	if (!(key_info & WPA_KEY_INFO_ACK)) {
-		wpa_printf(MSG_INFO, "WPA: No Ack bit in key_info");
-		return;
-	}
-
-	if (key_info & WPA_KEY_INFO_REQUEST) {
-		wpa_printf(MSG_INFO, "WPA: EAPOL-Key with Request bit - "
-		    "dropped");
-		return;
-	}
-
-	if ((key_info & WPA_KEY_INFO_MIC) &&
-	    wpa_supplicant_verify_eapol_key_mic(wpa_s, key, ver, buf,
-	    data_len)) {
-		return;
-	}
-
-	extra_len = data_len - sizeof (*hdr) - sizeof (*key);
-
-	if (wpa_s->proto == WPA_PROTO_RSN &&
-	    (key_info & WPA_KEY_INFO_ENCR_KEY_DATA) &&
-	    wpa_supplicant_decrypt_key_data(wpa_s, key, ver))
-		return;
-
-	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");
-			return;
-		}
-		if (key_info & WPA_KEY_INFO_MIC) {
-			/* 3/4 4-Way Handshake */
-			wpa_supplicant_process_3_of_4(wpa_s, src_addr, key,
-			    extra_len, ver);
-		} else {
-			/* 1/4 4-Way Handshake */
-			wpa_supplicant_process_1_of_4(wpa_s, src_addr, key,
-			    ver);
-		}
-	} else {
-		if (key_info & WPA_KEY_INFO_MIC) {
-			/* 1/2 Group Key Handshake */
-			wpa_supplicant_process_1_of_2(wpa_s, src_addr, key,
-			    extra_len, ver);
-		} else {
-			wpa_printf(MSG_WARNING, "WPA: EAPOL-Key (Group) "
-			    "without Mic bit - dropped");
-		}
-	}
-}
-
-void
-wpa_supplicant_rx_eapol(void *ctx, unsigned char *src_addr,
-    unsigned char *buf, size_t len)
-{
-	struct wpa_supplicant *wpa_s = ctx;
-
-	wpa_printf(MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
-	wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
-
-	if (wpa_s->eapol_received == 0) {
-		/* Timeout for completing IEEE 802.1X and WPA authentication */
-		wpa_supplicant_req_auth_timeout(
-		    wpa_s, wpa_s->key_mgmt == WPA_KEY_MGMT_IEEE8021X ?
-		    70 : 10, 0);
-	}
-	wpa_s->eapol_received++;
-
-	/*
-	 * Source address of the incoming EAPOL frame could be compared to the
-	 * current BSSID. However, it is possible that a centralized
-	 * Authenticator could be using another MAC address than the BSSID of
-	 * an AP, so just allow any address to be used for now. The replies are
-	 * still sent to the current BSSID (if available), though.
-	 */
-	wpa_sm_rx_eapol(wpa_s, src_addr, buf, len);
-}
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa.xml	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,95 +0,0 @@
-<?xml version="1.0"?>
-<!DOCTYPE service_bundle SYSTEM "/usr/share/lib/xml/dtd/service_bundle.dtd.1">
-<!--
-	Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
-	Use is subject to license terms.
-
- CDDL HEADER START
-
- The contents of this file are subject to the terms of the
- Common Development and Distribution License (the "License").
- You may not use this file except in compliance with the License.
-
- You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- or http://www.opensolaris.org/os/licensing.
- See the License for the specific language governing permissions
- and limitations under the License.
-
- When distributing Covered Code, include this CDDL HEADER in each
- file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- If applicable, add the following below this CDDL HEADER, with the
- fields enclosed by brackets "[]" replaced with your own identifying
- information: Portions Copyright [yyyy] [name of copyright owner]
-
- CDDL HEADER END
-
-	ident	"%Z%%M%	%I%	%E% SMI"
-
-	NOTE:  This service manifest is not editable; its contents will
-	be overwritten by package or patch operations, including
-	operating system upgrade.  Make customizations in a different
-	file.
--->
-
-<service_bundle type='manifest' name='SUNWsupr:wpad'>
-
-<service
-	name='network/wpa'
-	type='service'
-	version='1'>
-
-	<!--
-	    The wpa service will use the crypto framework of
-	    PKCS #11 when we come to the enterprise mode.
-	-->
-	<dependency
-	    name='cryptosvc'
-	    grouping='require_all'
-	    restart_on='none'
-	    type='service'>
-		<service_fmri value='svc:/system/cryptosvc' />
-	</dependency>
-
-	<exec_method
-		type='method'
-		name='start'
-		exec='/usr/lib/inet/wpad'
-		timeout_seconds='60' >
-		<method_context>
-			<method_credential
-				user='root'
-				group='root'
-				limit_privileges=':default'
-				privileges='basic,sys_net_config,net_rawaccess'
-			/>
-		</method_context>
-	</exec_method>
-
-	<exec_method
-		type='method'
-		name='stop'
-		exec=':kill'
-		timeout_seconds='60' />
-
-        <property_group name='general' type='framework'>
-                <!-- to start stop wpad -->
-                <propval name='action_authorization' type='astring'
-                        value='solaris.smf.manage.wpa' />
-        </property_group>
-
-	<stability value='Unstable' />
-
-	<template>
-		<common_name>
-			<loctext xml:lang='C'>
-			Wireless WPA Supplicant
-			</loctext>
-		</common_name>
-		<documentation>
-			<manpage title='wpad' section='1M'
-			    manpath='/usr/share/man' />
-		</documentation>
-	</template>
-</service>
-
-</service_bundle>
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_enc.c	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,270 +0,0 @@
-/*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
- * Sun elects to license this software under the BSD license.
- * See README for more details.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <strings.h>
-#include <sys/types.h>
-
-#include <openssl/aes.h>
-#include <openssl/hmac.h>
-#include <openssl/rc4.h>
-
-#include "wpa_enc.h"
-
-/*
- * @kek: key encryption key (KEK)
- * @n: length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
- * @plain: plaintext key to be wrapped, n * 64 bit
- * @cipher: wrapped key, (n + 1) * 64 bit
- */
-void
-aes_wrap(uint8_t *kek, int n, uint8_t *plain, uint8_t *cipher)
-{
-	uint8_t *a, *r, b[16];
-	int i, j;
-	AES_KEY key;
-
-	a = cipher;
-	r = cipher + 8;
-
-	/* 1) Initialize variables. */
-	(void) memset(a, 0xa6, 8);
-	(void) memcpy(r, plain, 8 * n);
-
-	(void) AES_set_encrypt_key(kek, 128, &key);
-
-	/*
-	 * 2) Calculate intermediate values.
-	 * For j = 0 to 5
-	 * 	For i=1 to n
-	 * 		B = AES(K, A | R[i])
-	 * 		A = MSB(64, B) ^ t where t = (n*j)+i
-	 * 		R[i] = LSB(64, B)
-	 */
-	for (j = 0; j <= 5; j++) {
-		r = cipher + 8;
-		for (i = 1; i <= n; i++) {
-			(void) memcpy(b, a, 8);
-			(void) memcpy(b + 8, r, 8);
-			AES_encrypt(b, b, &key);
-			(void) memcpy(a, b, 8);
-			a[7] ^= n * j + i;
-			(void) memcpy(r, b + 8, 8);
-			r += 8;
-		}
-	}
-
-	/*
-	 * 3) Output the results.
-	 *
-	 * These are already in @cipher due to the location of temporary
-	 * variables.
-	 */
-}
-
-/*
- * @kek: key encryption key (KEK)
- * @n: length of the wrapped key in 64-bit units; e.g., 2 = 128-bit = 16 bytes
- * @cipher: wrapped key to be unwrapped, (n + 1) * 64 bit
- * @plain: plaintext key, n * 64 bit
- */
-int
-aes_unwrap(uint8_t *kek, int n, uint8_t *cipher, uint8_t *plain)
-{
-	uint8_t a[8], *r, b[16];
-	int i, j;
-	AES_KEY key;
-
-	/* 1) Initialize variables. */
-	(void) memcpy(a, cipher, 8);
-	r = plain;
-	(void) memcpy(r, cipher + 8, 8 * n);
-
-	(void) AES_set_decrypt_key(kek, 128, &key);
-
-	/*
-	 * 2) Compute intermediate values.
-	 * For j = 5 to 0
-	 * 	For i = n to 1
-	 * 		B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i
-	 * 		A = MSB(64, B)
-	 * 		R[i] = LSB(64, B)
-	 */
-	for (j = 5; j >= 0; j--) {
-		r = plain + (n - 1) * 8;
-		for (i = n; i >= 1; i--) {
-			(void) memcpy(b, a, 8);
-			b[7] ^= n * j + i;
-
-			(void) memcpy(b + 8, r, 8);
-			AES_decrypt(b, b, &key);
-			(void) memcpy(a, b, 8);
-			(void) memcpy(r, b + 8, 8);
-			r -= 8;
-		}
-	}
-
-	/*
-	 * 3) Output results.
-	 *
-	 * These are already in @plain due to the location of temporary
-	 * variables. Just verify that the IV matches with the expected value.
-	 */
-	for (i = 0; i < 8; i++) {
-		if (a[i] != 0xa6) {
-			return (-1);
-		}
-	}
-
-	return (0);
-}
-
-/* RFC 2104 */
-void
-hmac_sha1(unsigned char *key, unsigned int key_len,
-    unsigned char *data, unsigned int data_len, unsigned char *mac)
-{
-	unsigned int mac_len = 0;
-	(void) HMAC(EVP_sha1(), key, key_len, data, data_len, mac, &mac_len);
-}
-
-
-void
-hmac_sha1_vector(unsigned char *key, unsigned int key_len, size_t num_elem,
-    unsigned char *addr[], unsigned int *len, unsigned char *mac)
-{
-	unsigned char *buf, *ptr;
-	int i, buf_len;
-
-	buf_len = 0;
-	for (i = 0; i < num_elem; i ++)
-		buf_len += len[i];
-
-	buf = malloc(buf_len);
-	ptr = buf;
-
-	for (i = 0; i < num_elem; i ++) {
-		(void) memcpy(ptr, addr[i], len[i]);
-		ptr += len[i];
-	}
-
-	hmac_sha1(key, key_len, buf, buf_len, mac);
-
-	free(buf);
-}
-
-
-void
-sha1_prf(unsigned char *key, unsigned int key_len,
-    char *label, unsigned char *data, unsigned int data_len,
-    unsigned char *buf, size_t buf_len)
-{
-	uint8_t zero = 0, counter = 0;
-	size_t pos, plen;
-	uint8_t hash[SHA1_MAC_LEN];
-	size_t label_len = strlen(label);
-
-	unsigned char *addr[4];
-	unsigned int len[4];
-
-	addr[0] = (uint8_t *)label;
-	len[0] = label_len;
-	addr[1] = &zero;
-	len[1] = 1;
-	addr[2] = data;
-	len[2] = data_len;
-	addr[3] = &counter;
-	len[3] = 1;
-
-	pos = 0;
-	while (pos < buf_len) {
-		plen = buf_len - pos;
-		if (plen >= SHA1_MAC_LEN) {
-			hmac_sha1_vector(key, key_len, 4, addr, len, &buf[pos]);
-			pos += SHA1_MAC_LEN;
-		} else {
-			hmac_sha1_vector(key, key_len, 4, addr, len, hash);
-			(void) memcpy(&buf[pos], hash, plen);
-			break;
-		}
-		counter++;
-	}
-}
-
-void
-pbkdf2_sha1(char *passphrase, char *ssid, size_t ssid_len, int iterations,
-    unsigned char *buf, size_t buflen)
-{
-	(void) PKCS5_PBKDF2_HMAC_SHA1(passphrase, -1, (unsigned char *)ssid,
-	    ssid_len, iterations, buflen, buf);
-}
-
-void
-rc4_skip(uint8_t *key, size_t keylen, size_t skip,
-    uint8_t *data, size_t data_len)
-{
-	uint8_t *buf;
-	size_t buf_len;
-
-	buf_len = skip + data_len;
-	buf = malloc(buf_len);
-
-	bzero(buf, buf_len);
-	bcopy(data, buf + skip, data_len);
-
-	rc4(buf, buf_len, key, keylen);
-
-	bcopy(buf + skip, data, data_len);
-	free(buf);
-}
-
-void
-rc4(uint8_t *buf, size_t len, uint8_t *key, size_t key_len)
-{
-	RC4_KEY k;
-
-	RC4_set_key(&k, key_len, key);
-	RC4(&k, len, buf, buf);
-}
-
-void
-hmac_md5_vector(uint8_t *key, size_t key_len, size_t num_elem,
-    uint8_t *addr[], size_t *len, uint8_t *mac)
-{
-	unsigned char *buf, *ptr;
-	int i, buf_len;
-
-	buf_len = 0;
-	for (i = 0; i < num_elem; i ++)
-		buf_len += len[i];
-
-	buf = malloc(buf_len);
-	ptr = buf;
-
-	for (i = 0; i < num_elem; i ++) {
-		(void) memcpy(ptr, addr[i], len[i]);
-		ptr += len[i];
-	}
-
-	hmac_md5(key, key_len, buf, buf_len, mac);
-	free(buf);
-}
-
-/* RFC 2104 */
-void
-hmac_md5(uint8_t *key, size_t key_len, uint8_t *data,
-    size_t data_len, uint8_t *mac)
-{
-	unsigned int mac_len = 0;
-	(void) HMAC(EVP_md5(), key, key_len, data, data_len, mac, &mac_len);
-}
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_enc.h	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,51 +0,0 @@
-/*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
- * Sun elects to license this software under the BSD license.
- * See README for more details.
- */
-#ifndef __WPA_ENC_H
-#define	__WPA_ENC_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#include <openssl/sha.h>
-#include <openssl/md5.h>
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-#define	SHA1_MAC_LEN	SHA_DIGEST_LENGTH
-#define	MD5_MAC_LEN	MD5_DIGEST_LENGTH
-
-void aes_wrap(uint8_t *, int, uint8_t *, uint8_t *);
-int aes_unwrap(uint8_t *, int, uint8_t *, uint8_t *);
-
-void hmac_sha1_vector(unsigned char *, unsigned int,
-    size_t, unsigned char *[], unsigned int *, unsigned char *);
-
-void hmac_sha1(unsigned char *, unsigned int,
-    unsigned char *, unsigned int, unsigned char *);
-
-void sha1_prf(unsigned char *, unsigned int,
-    char *, unsigned char *, unsigned int, unsigned char *, size_t);
-
-void pbkdf2_sha1(char *, char *, size_t, int, unsigned char *, size_t);
-
-void rc4_skip(uint8_t *, size_t, size_t, uint8_t *, size_t);
-void rc4(uint8_t *, size_t, uint8_t *, size_t);
-
-void hmac_md5_vector(uint8_t *, size_t, size_t,
-    uint8_t *[], size_t *, uint8_t *);
-void hmac_md5(uint8_t *, size_t, uint8_t *, size_t, uint8_t *);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __WPA_ENC_H */
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_impl.h	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,297 +0,0 @@
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
- * Sun elects to license this software under the BSD license.
- * See README for more details.
- */
-#ifndef __WPA_IMPL_H
-#define	__WPA_IMPL_H
-
-#include <net/wpa.h>
-#include <libdladm.h>
-#include <libdllink.h>
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-#define	BIT(n)			(1 << (n))
-
-#define	WPA_CIPHER_NONE		BIT(0)
-#define	WPA_CIPHER_WEP40	BIT(1)
-#define	WPA_CIPHER_WEP104	BIT(2)
-#define	WPA_CIPHER_TKIP		BIT(3)
-#define	WPA_CIPHER_CCMP		BIT(4)
-
-#define	WPA_KEY_MGMT_IEEE8021X	BIT(0)
-#define	WPA_KEY_MGMT_PSK	BIT(1)
-#define	WPA_KEY_MGMT_NONE	BIT(2)
-#define	WPA_KEY_MGMT_IEEE8021X_NO_WPA	BIT(3)
-
-#define	WPA_PROTO_WPA		BIT(0)
-#define	WPA_PROTO_RSN		BIT(1)
-
-#pragma pack(1)
-struct ieee802_1x_hdr {
-	uint8_t		version;
-	uint8_t		type;
-	uint16_t	length;
-	/* followed by length octets of data */
-};
-#pragma pack()
-
-#define	EAPOL_VERSION	2
-
-enum {	IEEE802_1X_TYPE_EAP_PACKET	= 0,
-	IEEE802_1X_TYPE_EAPOL_START	= 1,
-	IEEE802_1X_TYPE_EAPOL_LOGOFF	= 2,
-	IEEE802_1X_TYPE_EAPOL_KEY	= 3,
-	IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT	= 4
-};
-
-enum {	EAPOL_KEY_TYPE_RC4 = 1,
-	EAPOL_KEY_TYPE_RSN = 2,
-	EAPOL_KEY_TYPE_WPA = 254
-};
-
-#define	WPA_NONCE_LEN		32
-#define	WPA_REPLAY_COUNTER_LEN	8
-#define	MAX_PSK_LENGTH		64
-#define	WPA_PMK_LEN		32
-
-#pragma pack(1)
-struct wpa_eapol_key {
-	uint8_t		type;
-	uint16_t	key_info;
-	uint16_t	key_length;
-	uint8_t		replay_counter[WPA_REPLAY_COUNTER_LEN];
-	uint8_t		key_nonce[WPA_NONCE_LEN];
-	uint8_t		key_iv[16];
-	uint8_t		key_rsc[8];
-	uint8_t		key_id[8]; /* Reserved in IEEE 802.11i/RSN */
-	uint8_t		key_mic[16];
-	uint16_t	key_data_length;
-	/* followed by key_data_length bytes of key_data */
-};
-#pragma pack()
-
-#define	WPA_KEY_INFO_TYPE_MASK		(BIT(0) | BIT(1) | BIT(2))
-#define	WPA_KEY_INFO_TYPE_HMAC_MD5_RC4	BIT(0)
-#define	WPA_KEY_INFO_TYPE_HMAC_SHA1_AES	BIT(1)
-#define	WPA_KEY_INFO_KEY_TYPE		BIT(3) /* 1: Pairwise, 0: Group key */
-/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */
-#define	WPA_KEY_INFO_KEY_INDEX_MASK	(BIT(4) | BIT(5))
-#define	WPA_KEY_INFO_KEY_INDEX_SHIFT	4
-#define	WPA_KEY_INFO_INSTALL		BIT(6) /* pairwise */
-#define	WPA_KEY_INFO_TXRX		BIT(6) /* group */
-#define	WPA_KEY_INFO_ACK		BIT(7)
-#define	WPA_KEY_INFO_MIC		BIT(8)
-#define	WPA_KEY_INFO_SECURE		BIT(9)
-#define	WPA_KEY_INFO_ERROR		BIT(10)
-#define	WPA_KEY_INFO_REQUEST		BIT(11)
-#define	WPA_KEY_INFO_ENCR_KEY_DATA	BIT(12) /* IEEE 802.11i/RSN only */
-
-#define	WPA_CAPABILITY_PREAUTH		BIT(0)
-
-#define	GENERIC_INFO_ELEM		0xdd
-#define	RSN_INFO_ELEM			0x30
-
-#define	MAX_LOGBUF			4096
-#define	MAX_SCANRESULTS			64
-
-enum {
-	REASON_UNSPECIFIED			= 1,
-	REASON_DEAUTH_LEAVING			= 3,
-	REASON_INVALID_IE			= 13,
-	REASON_MICHAEL_MIC_FAILURE		= 14,
-	REASON_4WAY_HANDSHAKE_TIMEOUT		= 15,
-	REASON_GROUP_KEY_UPDATE_TIMEOUT		= 16,
-	REASON_IE_IN_4WAY_DIFFERS		= 17,
-	REASON_GROUP_CIPHER_NOT_VALID		= 18,
-	REASON_PAIRWISE_CIPHER_NOT_VALID	= 19,
-	REASON_AKMP_NOT_VALID			= 20,
-	REASON_UNSUPPORTED_RSN_IE_VERSION	= 21,
-	REASON_INVALID_RSN_IE_CAPAB		= 22,
-	REASON_IEEE_802_1X_AUTH_FAILED		= 23,
-	REASON_CIPHER_SUITE_REJECTED		= 24
-};
-
-/*
- * wpa_supplicant
- */
-#define	PMKID_LEN 			16
-#define	PMK_LEN				32
-
-#define	MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
-#define	MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
-
-struct rsn_pmksa_cache {
-	struct rsn_pmksa_cache	*next;
-	uint8_t			pmkid[PMKID_LEN];
-	uint8_t			pmk[PMK_LEN];
-	time_t			expiration;
-	int			akmp; /* WPA_KEY_MGMT_* */
-	uint8_t			aa[IEEE80211_ADDR_LEN];
-};
-
-struct rsn_pmksa_candidate {
-	struct rsn_pmksa_candidate *next;
-	uint8_t			bssid[IEEE80211_ADDR_LEN];
-};
-
-
-#pragma pack(1)
-struct wpa_ptk {
-	uint8_t mic_key[16]; /* EAPOL-Key MIC Key (MK) */
-	uint8_t encr_key[16]; /* EAPOL-Key Encryption Key (EK) */
-	uint8_t tk1[16]; /* Temporal Key 1 (TK1) */
-	union {
-		uint8_t tk2[16]; /* Temporal Key 2 (TK2) */
-		struct {
-			uint8_t tx_mic_key[8];
-			uint8_t rx_mic_key[8];
-		} auth;
-	} u;
-};
-#pragma pack()
-
-
-struct wpa_supplicant {
-	struct l2_packet_data	*l2;
-	unsigned char		own_addr[IEEE80211_ADDR_LEN];
-
-	/* The handle required for libdladm calls */
-	dladm_handle_t		handle;
-
-	datalink_id_t		linkid;
-	char			kname[DLADM_SECOBJ_NAME_MAX];
-
-	uint8_t			pmk[PMK_LEN];
-
-	uint8_t			snonce[WPA_NONCE_LEN];
-	uint8_t			anonce[WPA_NONCE_LEN];
-	/* ANonce from the last 1/4 msg */
-
-	struct wpa_ptk		ptk, tptk;
-	int			ptk_set, tptk_set;
-	int			renew_snonce;
-
-	struct wpa_config	*conf;
-
-	uint8_t			request_counter[WPA_REPLAY_COUNTER_LEN];
-	uint8_t			rx_replay_counter[WPA_REPLAY_COUNTER_LEN];
-	int			rx_replay_counter_set;
-
-	uint8_t			bssid[IEEE80211_ADDR_LEN];
-	int			reassociate; /* reassociation requested */
-
-	uint8_t			*ap_wpa_ie;
-	size_t			ap_wpa_ie_len;
-
-	/*
-	 * Selected configuration
-	 * based on Beacon/ProbeResp WPA IE
-	 */
-	int			proto;
-	int 			pairwise_cipher;
-	int 			group_cipher;
-	int			key_mgmt;
-
-	struct wpa_driver_ops	*driver;
-
-	enum {
-		WPA_DISCONNECTED,
-		WPA_SCANNING,
-		WPA_ASSOCIATING,
-		WPA_ASSOCIATED,
-		WPA_4WAY_HANDSHAKE,
-		WPA_GROUP_HANDSHAKE,
-		WPA_COMPLETED
-	} wpa_state;
-
-	struct rsn_pmksa_cache	*pmksa; /* PMKSA cache */
-	int	pmksa_count; /* number of entries in PMKSA cache */
-	struct rsn_pmksa_cache	*cur_pmksa; /* current PMKSA entry */
-	struct rsn_pmksa_candidate	*pmksa_candidates;
-
-	/*
-	 * number of EAPOL packets received after the
-	 * previous association event
-	 */
-	int			eapol_received;
-};
-
-struct wpa_ie_data {
-	int	proto;
-	int	pairwise_cipher;
-	int	group_cipher;
-	int	key_mgmt;
-	int	capabilities;
-};
-
-/* WPA configuration */
-struct wpa_ssid {
-	uint8_t	*ssid;
-	size_t	ssid_len;
-
-	uint8_t	bssid[IEEE80211_ADDR_LEN];
-	int	bssid_set;
-
-	uint8_t	psk[PMK_LEN];
-	int	psk_set;
-	char	*passphrase;
-
-	/* Bitfields of allowed Pairwise/Group Ciphers, WPA_CIPHER_* */
-	int	pairwise_cipher;
-	int	group_cipher;
-
-	int	key_mgmt;
-	int	proto; /* Bitfield of allowed protocols (WPA_PROTO_*) */
-};
-
-struct wpa_config {
-	struct wpa_ssid *ssid; /* global network list */
-	int eapol_version;
-	/* int ap_scan; */
-};
-
-struct wpa_config *wpa_config_read(void *);
-void wpa_config_free(struct wpa_config *);
-
-/*
- * 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 };
-
-void wpa_printf(int, char *, ...);
-void wpa_hexdump(int, const char *, const uint8_t *, size_t);
-
-void wpa_event_handler(void *, wpa_event_type);
-void wpa_supplicant_rx_eapol(void *, unsigned char *, unsigned char *, size_t);
-
-void wpa_supplicant_scan(void *, void *);
-void wpa_supplicant_req_scan(struct wpa_supplicant *, int, int);
-
-void wpa_supplicant_req_auth_timeout(struct wpa_supplicant *, int, int);
-void wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *);
-void wpa_supplicant_disassociate(struct wpa_supplicant *, int);
-
-void pmksa_cache_free(struct wpa_supplicant *);
-void pmksa_candidate_free(struct wpa_supplicant *);
-struct rsn_pmksa_cache *pmksa_cache_get(struct wpa_supplicant *,
-    uint8_t *, uint8_t *);
-
-int wpa_parse_wpa_ie(struct wpa_supplicant *, uint8_t *,
-	size_t, struct wpa_ie_data *);
-int wpa_gen_wpa_ie(struct wpa_supplicant *, uint8_t *);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __WPA_IMPL_H */
--- a/usr/src/cmd/cmd-inet/usr.lib/wpad/wpa_supplicant.c	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,937 +0,0 @@
-/*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 2003-2004, Jouni Malinen <jkmaline@cc.hut.fi>
- * Sun elects to license this software under the BSD license.
- * See README for more details.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
-#include <syslog.h>
-#include <sys/stat.h>
-#include <errno.h>
-#include <signal.h>
-#include <fcntl.h>
-#include <door.h>
-#include <libscf.h>
-#include <libdladm.h>
-#include <libdllink.h>
-#include <sys/ethernet.h>
-
-#include "wpa_impl.h"
-#include "wpa_enc.h"
-#include "driver.h"
-#include "eloop.h"
-#include "l2_packet.h"
-
-extern struct wpa_driver_ops wpa_driver_wifi_ops;
-int wpa_debug_level = MSG_ERROR;
-
-/*
- * wpa_printf - conditional printf
- * @level: priority level (MSG_*) of the message
- * @fmt: printf format string, followed by optional arguments
- *
- * This function is used to print conditional debugging and error messages. The
- * output may be directed to stdout, stderr, and/or syslog based on
- * configuration.
- */
-void
-wpa_printf(int level, char *fmt, ...)
-{
-	va_list ap;
-	char buffer[MAX_LOGBUF];
-
-	if (level < wpa_debug_level)
-		return;
-
-	va_start(ap, fmt);
-
-	/* LINTED E_SEC_PRINTF_VAR_FMT */
-	(void) vsnprintf(buffer, sizeof (buffer), fmt, ap);
-
-	va_end(ap);
-
-	syslog(LOG_NOTICE | LOG_DAEMON, "%s", buffer);
-}
-
-/*
- * wpa_hexdump - conditional hex dump
- * @level: priority level (MSG_*) of the message
- * @title: title of for the message
- * @buf: data buffer to be dumped
- * @len: length of the @buf
- *
- * This function is used to print conditional debugging and error messages. The
- * output may be directed to stdout, stderr, and/or syslog based on
- * configuration. The contents of @buf is printed out has hex dump.
- */
-void
-wpa_hexdump(int level, const char *title, const uint8_t *buf, size_t len)
-{
-	size_t i;
-	char buffer[MAX_LOGBUF], tmp[4];
-	int n;
-
-	if (level < wpa_debug_level)
-		return;
-
-	(void) snprintf(buffer, sizeof (buffer), "%s - hexdump(len=%d):",
-	    title, len);
-	n = strlen(buffer);
-
-	for (i = 0; i < len; i++) {
-		(void) sprintf(tmp, " %02x", buf[i]);
-
-		n += strlen(tmp);
-		if (n >= MAX_LOGBUF) break;
-
-		(void) strlcat(buffer, tmp, sizeof (buffer));
-	}
-
-	syslog(LOG_NOTICE | LOG_DAEMON, "%s", buffer);
-}
-
-static const char *
-wpa_ssid_txt(char *ssid, size_t ssid_len)
-{
-	static char ssid_txt[MAX_ESSID_LENGTH + 1];
-	char *pos;
-
-	if (ssid_len > MAX_ESSID_LENGTH)
-		ssid_len = MAX_ESSID_LENGTH;
-	(void) memcpy(ssid_txt, ssid, ssid_len);
-	ssid_txt[ssid_len] = '\0';
-	for (pos = ssid_txt; *pos != '\0'; pos ++) {
-		if ((uint8_t)*pos < 32 || (uint8_t)*pos >= 127)
-			*pos = '_';
-	}
-	return (ssid_txt);
-}
-
-/* ARGSUSED */
-void
-wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-	struct wpa_ssid *ssid;
-
-	if (wpa_s->conf == NULL)
-		return;
-
-	if (wpa_s->wpa_state == WPA_DISCONNECTED)
-		wpa_s->wpa_state = WPA_SCANNING;
-
-	ssid = wpa_s->conf->ssid;
-	wpa_printf(MSG_DEBUG, "Starting AP scan (%s SSID)",
-	    ssid ? "specific": "broadcast");
-
-	if (ssid) {
-		wpa_printf(MSG_DEBUG, "Scan SSID: %s", ssid->ssid);
-	}
-
-	if (wpa_s->driver->scan(wpa_s->handle, wpa_s->linkid)) {
-		wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
-	}
-}
-
-void
-wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec)
-{
-	wpa_printf(MSG_DEBUG, "Setting scan request: %d sec %d usec",
-	    sec, usec);
-	(void) eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
-	(void) eloop_register_timeout(sec, usec, wpa_supplicant_scan,
-	    wpa_s, NULL);
-}
-
-void
-wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
-{
-	wpa_printf(MSG_DEBUG, "Cancelling scan request");
-	eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
-}
-
-/* ARGSUSED */
-static void
-wpa_supplicant_timeout(void *eloop_ctx, void *timeout_ctx)
-{
-	struct wpa_supplicant *wpa_s = eloop_ctx;
-
-	wpa_printf(MSG_INFO, "Authentication with " MACSTR " timed out.",
-	    MAC2STR(wpa_s->bssid));
-
-	wpa_s->reassociate = 1;
-	wpa_supplicant_req_scan(wpa_s, 0, 0);
-}
-
-void
-wpa_supplicant_req_auth_timeout(struct wpa_supplicant *wpa_s,
-				int sec, int usec)
-{
-	wpa_printf(MSG_DEBUG, "Setting authentication timeout: %d sec "
-	    "%d usec", sec, usec);
-	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
-	(void) eloop_register_timeout(sec, usec, wpa_supplicant_timeout,
-	    wpa_s, NULL);
-}
-
-void
-wpa_supplicant_cancel_auth_timeout(struct wpa_supplicant *wpa_s)
-{
-	wpa_printf(MSG_DEBUG, "Cancelling authentication timeout");
-	eloop_cancel_timeout(wpa_supplicant_timeout, wpa_s, NULL);
-}
-
-static void
-wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
-{
-	l2_packet_deinit(wpa_s->l2);
-	wpa_s->l2 = NULL;
-
-	if (wpa_s->conf != NULL) {
-		wpa_config_free(wpa_s->conf);
-		wpa_s->conf = NULL;
-	}
-
-	dladm_close(wpa_s->handle);
-	free(wpa_s->ap_wpa_ie);
-	pmksa_candidate_free(wpa_s);
-	pmksa_cache_free(wpa_s);
-}
-
-static void
-wpa_clear_keys(struct wpa_supplicant *wpa_s, uint8_t *addr)
-{
-	wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, WPA_ALG_NONE,
-	    (uint8_t *)"\xff\xff\xff\xff\xff\xff", 0, 0, NULL, 0, NULL, 0);
-	wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, WPA_ALG_NONE,
-	    (uint8_t *)"\xff\xff\xff\xff\xff\xff", 1, 0, NULL, 0, NULL, 0);
-	wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, WPA_ALG_NONE,
-	    (uint8_t *)"\xff\xff\xff\xff\xff\xff", 2, 0, NULL, 0, NULL, 0);
-	wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid, WPA_ALG_NONE,
-	    (uint8_t *)"\xff\xff\xff\xff\xff\xff", 3, 0, NULL, 0, NULL, 0);
-	if (addr) {
-		wpa_s->driver->set_key(wpa_s->handle, wpa_s->linkid,
-		    WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL, 0);
-	}
-}
-
-static void
-wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s)
-{
-	wpa_s->wpa_state = WPA_DISCONNECTED;
-	(void) memset(wpa_s->bssid, 0, IEEE80211_ADDR_LEN);
-}
-
-static int
-wpa_supplicant_set_suites(struct wpa_supplicant *wpa_s,
-    dladm_wlan_ess_t *bss, struct wpa_ssid *ssid,
-    uint8_t *wpa_ie, int *wpa_ie_len)
-{
-	struct wpa_ie_data ie;
-	int sel, proto;
-	uint8_t *ap_ie;
-	size_t ap_ie_len;
-
-	/* RSN or WPA */
-	if (bss->we_wpa_ie_len && bss->we_wpa_ie[0] == RSN_INFO_ELEM &&
-	    (ssid->proto & WPA_PROTO_RSN)) {
-		wpa_printf(MSG_DEBUG, "RSN: using IEEE 802.11i/D9.0");
-		proto = WPA_PROTO_RSN;
-	} else {
-		wpa_printf(MSG_DEBUG, "WPA: using IEEE 802.11i/D3.0");
-		proto = WPA_PROTO_WPA;
-	}
-
-	ap_ie = bss->we_wpa_ie;
-	ap_ie_len = bss->we_wpa_ie_len;
-
-	if (wpa_parse_wpa_ie(wpa_s, ap_ie, ap_ie_len, &ie)) {
-		wpa_printf(MSG_WARNING, "WPA: Failed to parse WPA IE for "
-		    "the selected BSS.");
-		return (-1);
-	}
-
-	wpa_s->proto = proto;
-	free(wpa_s->ap_wpa_ie);
-	wpa_s->ap_wpa_ie = malloc(ap_ie_len);
-	(void) memcpy(wpa_s->ap_wpa_ie, ap_ie, ap_ie_len);
-	wpa_s->ap_wpa_ie_len = ap_ie_len;
-
-	sel = ie.group_cipher & ssid->group_cipher;
-	if (sel & WPA_CIPHER_CCMP) {
-		wpa_s->group_cipher = WPA_CIPHER_CCMP;
-	} else if (sel & WPA_CIPHER_TKIP) {
-		wpa_s->group_cipher = WPA_CIPHER_TKIP;
-	} else if (sel & WPA_CIPHER_WEP104) {
-		wpa_s->group_cipher = WPA_CIPHER_WEP104;
-	} else if (sel & WPA_CIPHER_WEP40) {
-		wpa_s->group_cipher = WPA_CIPHER_WEP40;
-	} else {
-		wpa_printf(MSG_WARNING, "WPA: Failed to select group cipher.");
-		return (-1);
-	}
-
-	sel = ie.pairwise_cipher & ssid->pairwise_cipher;
-	if (sel & WPA_CIPHER_CCMP) {
-		wpa_s->pairwise_cipher = WPA_CIPHER_CCMP;
-	} else if (sel & WPA_CIPHER_TKIP) {
-		wpa_s->pairwise_cipher = WPA_CIPHER_TKIP;
-	} else if (sel & WPA_CIPHER_NONE) {
-		wpa_s->pairwise_cipher = WPA_CIPHER_NONE;
-	} else {
-		wpa_printf(MSG_WARNING, "WPA: Failed to select pairwise "
-		    "cipher.");
-		return (-1);
-	}
-
-	sel = ie.key_mgmt & ssid->key_mgmt;
-	if (sel & WPA_KEY_MGMT_IEEE8021X) {
-		wpa_s->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
-	} else if (sel & WPA_KEY_MGMT_PSK) {
-		wpa_s->key_mgmt = WPA_KEY_MGMT_PSK;
-	} else {
-		wpa_printf(MSG_WARNING, "WPA: Failed to select authenticated "
-		    "key management type.");
-		return (-1);
-	}
-
-	*wpa_ie_len = wpa_gen_wpa_ie(wpa_s, wpa_ie);
-	if (*wpa_ie_len < 0) {
-		wpa_printf(MSG_WARNING, "WPA: Failed to generate WPA IE.");
-		return (-1);
-	}
-	wpa_hexdump(MSG_DEBUG, "WPA: Own WPA IE", wpa_ie, *wpa_ie_len);
-
-	if (ssid->key_mgmt & WPA_KEY_MGMT_PSK)
-		(void) memcpy(wpa_s->pmk, ssid->psk, PMK_LEN);
-	else if (wpa_s->cur_pmksa)
-		(void) memcpy(wpa_s->pmk, wpa_s->cur_pmksa->pmk, PMK_LEN);
-	else {
-		(void) memset(wpa_s->pmk, 0, PMK_LEN);
-	}
-
-	return (0);
-}
-
-static void wpa_supplicant_associate(struct wpa_supplicant *wpa_s,
-    dladm_wlan_ess_t *bss, struct wpa_ssid *ssid)
-{
-	uint8_t wpa_ie[IEEE80211_MAX_OPT_IE];
-	int wpa_ie_len;
-
-	wpa_s->reassociate = 0;
-	wpa_printf(MSG_DEBUG, "Trying to associate with " MACSTR
-	    " (SSID='%s' freq=%d MHz)", MAC2STR(bss->we_bssid.wb_bytes),
-	    wpa_ssid_txt((char *)ssid->ssid, ssid->ssid_len), bss->we_freq);
-	wpa_supplicant_cancel_scan(wpa_s);
-
-	if (bss->we_wpa_ie_len &&
-	    (ssid->key_mgmt & (WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK))) {
-		wpa_s->cur_pmksa = pmksa_cache_get(wpa_s,
-		    bss->we_bssid.wb_bytes, NULL);
-		if (wpa_s->cur_pmksa) {
-			wpa_hexdump(MSG_DEBUG, "RSN: PMKID",
-			    wpa_s->cur_pmksa->pmkid, PMKID_LEN);
-		}
-		if (wpa_supplicant_set_suites(wpa_s, bss, ssid,
-		    wpa_ie, &wpa_ie_len)) {
-			wpa_printf(MSG_WARNING, "WPA: Failed to set WPA key "
-			    "management and encryption suites");
-			return;
-		}
-	} else {
-		wpa_ie_len = 0;
-	}
-
-	wpa_clear_keys(wpa_s, bss->we_bssid.wb_bytes);
-	wpa_s->wpa_state = WPA_ASSOCIATING;
-	wpa_s->driver->associate(wpa_s->handle, wpa_s->linkid,
-	    (const char *)bss->we_bssid.wb_bytes, wpa_ie, wpa_ie_len);
-
-	/* Timeout for IEEE 802.11 authentication and association */
-	wpa_supplicant_req_auth_timeout(wpa_s, 15, 0);
-}
-
-void
-wpa_supplicant_disassociate(struct wpa_supplicant *wpa_s, int reason_code)
-{
-	uint8_t *addr = NULL;
-	wpa_s->wpa_state = WPA_DISCONNECTED;
-	if (memcmp(wpa_s->bssid, "\x00\x00\x00\x00\x00\x00",
-	    IEEE80211_ADDR_LEN) != 0) {
-		wpa_s->driver->disassociate(wpa_s->handle, wpa_s->linkid,
-		    reason_code);
-		addr = wpa_s->bssid;
-	}
-	wpa_clear_keys(wpa_s, addr);
-}
-
-static dladm_wlan_ess_t *
-wpa_supplicant_select_bss(struct wpa_supplicant *wpa_s, struct wpa_ssid *group,
-    dladm_wlan_ess_t *results, int num, struct wpa_ssid **selected_ssid)
-{
-	struct wpa_ssid *ssid;
-	dladm_wlan_ess_t *bss, *selected = NULL;
-	int i;
-
-	struct wpa_ie_data ie;
-
-	wpa_printf(MSG_DEBUG, "Selecting BSS from scan results (%d)", num);
-
-	bss = NULL;
-	ssid = NULL;
-
-	/* try to find matched AP */
-	for (i = 0; i < num && !selected; i++) {
-		bss = &results[i];
-		wpa_printf(MSG_DEBUG, "%d: " MACSTR " ssid='%s' "
-		    "wpa_ie_len=%d",
-		    i, MAC2STR(bss->we_bssid.wb_bytes),
-		    wpa_ssid_txt(bss->we_ssid.we_bytes, bss->we_ssid_len),
-		    bss->we_wpa_ie_len);
-		if (bss->we_wpa_ie_len == 0) {
-			wpa_printf(MSG_DEBUG, "   skip - no WPA/RSN IE");
-		}
-
-		ssid = group;
-		if (bss->we_ssid_len != ssid->ssid_len ||
-		    memcmp(bss->we_ssid.we_bytes, ssid->ssid,
-		    bss->we_ssid_len) != 0) {
-			wpa_printf(MSG_DEBUG, "   skip - SSID mismatch");
-			continue;
-		}
-		if (!((ssid->proto & (WPA_PROTO_RSN | WPA_PROTO_WPA)) &&
-		    wpa_parse_wpa_ie(wpa_s, bss->we_wpa_ie,
-		    bss->we_wpa_ie_len, &ie) == 0)) {
-			wpa_printf(MSG_DEBUG, "   skip - "
-			    "could not parse WPA/RSN IE");
-			continue;
-		}
-		if (!(ie.proto & ssid->proto)) {
-			wpa_printf(MSG_DEBUG, "   skip - proto mismatch");
-			continue;
-		}
-		if (!(ie.pairwise_cipher & ssid->pairwise_cipher)) {
-			wpa_printf(MSG_DEBUG, "   skip - PTK cipher mismatch");
-			continue;
-		}
-		if (!(ie.group_cipher & ssid->group_cipher)) {
-			wpa_printf(MSG_DEBUG, "   skip - GTK cipher mismatch");
-			continue;
-		}
-		if (!(ie.key_mgmt & ssid->key_mgmt)) {
-			wpa_printf(MSG_DEBUG, "   skip - key mgmt mismatch");
-			continue;
-		}
-
-		selected = bss;
-		*selected_ssid = ssid;
-		wpa_printf(MSG_DEBUG, "   selected");
-	}
-
-	return (selected);
-}
-
-
-static void
-wpa_supplicant_scan_results(struct wpa_supplicant *wpa_s)
-{
-	dladm_wlan_ess_t results[MAX_SCANRESULTS];
-	int num;
-	dladm_wlan_ess_t *selected = NULL;
-	struct wpa_ssid *ssid;
-
-	(void) memset(results, 0, sizeof (dladm_wlan_ess_t) * MAX_SCANRESULTS);
-	num = wpa_s->driver->get_scan_results(wpa_s->handle, wpa_s->linkid,
-	    results, MAX_SCANRESULTS);
-	wpa_printf(MSG_DEBUG, "Scan results: %d", num);
-	if (num < 0)
-		return;
-	if (num > MAX_SCANRESULTS) {
-		wpa_printf(MSG_INFO, "Not enough room for all APs (%d < %d)",
-		    num, MAX_SCANRESULTS);
-		num = MAX_SCANRESULTS;
-	}
-
-	selected = wpa_supplicant_select_bss(wpa_s,
-	    wpa_s->conf->ssid, results, num, &ssid);
-
-	if (selected) {
-		if (wpa_s->reassociate ||
-		    memcmp(selected->we_bssid.wb_bytes, wpa_s->bssid,
-		    IEEE80211_ADDR_LEN) != 0) {
-			wpa_supplicant_associate(wpa_s, selected, ssid);
-		} else {
-			wpa_printf(MSG_DEBUG, "Already associated with the "
-			    "selected AP.");
-		}
-	} else {
-		wpa_printf(MSG_DEBUG, "No suitable AP found.");
-		wpa_supplicant_req_scan(wpa_s, 5, 0);	/* wait 5 seconds */
-	}
-}
-
-/*
- * wpa_event_handler - report a driver event for wpa_supplicant
- * @wpa_s: pointer to wpa_supplicant data; this is the @ctx variable registered
- *	with wpa_driver_events_init()
- * @event: event type (defined above)
- *
- * Driver wrapper code should call this function whenever an event is received
- * from the driver.
- */
-void
-wpa_event_handler(void *cookie, wpa_event_type event)
-{
-	struct wpa_supplicant *wpa_s = cookie;
-
-	switch (event) {
-	case EVENT_ASSOC:
-		wpa_printf(MSG_DEBUG, "\nAssociation event\n");
-		/* async event */
-		if (wpa_s->wpa_state < WPA_ASSOCIATED) {
-			wpa_s->wpa_state = WPA_ASSOCIATED;
-			if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
-				wpa_supplicant_cancel_auth_timeout(wpa_s);
-			} else {
-				/* Timeout for receiving first EAPOL packet */
-				wpa_supplicant_req_auth_timeout(wpa_s, 10, 0);
-			}
-		}
-		break;
-	case EVENT_DISASSOC:
-		if (wpa_s->wpa_state >= WPA_ASSOCIATED)
-			wpa_supplicant_req_scan(wpa_s, 0, 100000);
-		wpa_supplicant_mark_disassoc(wpa_s);
-		wpa_printf(MSG_DEBUG, "Disconnect event - remove keys");
-		if (wpa_s->key_mgmt != WPA_KEY_MGMT_NONE)
-			wpa_clear_keys(wpa_s, wpa_s->bssid);
-		break;
-	case EVENT_SCAN_RESULTS:
-		wpa_supplicant_scan_results(wpa_s);
-		/* reset vars */
-		(void) memset(wpa_s->rx_replay_counter, 0,
-		    WPA_REPLAY_COUNTER_LEN);
-		wpa_s->rx_replay_counter_set = 0;
-		wpa_s->renew_snonce = 1;
-		wpa_s->eapol_received = 0;
-		break;
-	default:
-		wpa_printf(MSG_INFO, "Unknown event %d", event);
-		break;
-	}
-}
-
-/* ARGSUSED */
-static void
-wpa_supplicant_terminate(int sig, void *eloop_ctx, void *signal_ctx)
-{
-	wpa_printf(MSG_INFO, "Signal %d received - terminating", sig);
-	eloop_terminate();
-}
-
-static int
-wpa_supplicant_driver_init(const char *link, struct wpa_supplicant *wpa_s)
-{
-	wpa_s->l2 = l2_packet_init(link, ETHERTYPE_EAPOL,
-	    wpa_supplicant_rx_eapol, wpa_s);
-	if (wpa_s->l2 == NULL)
-		return (-1);
-
-	if (l2_packet_get_own_addr(wpa_s->l2, wpa_s->own_addr)) {
-		(void) fprintf(stderr, "Failed to get own L2 address\n");
-		return (-1);
-	}
-
-	if (wpa_s->driver->set_wpa(wpa_s->handle, wpa_s->linkid, 1) < 0) {
-		wpa_printf(MSG_ERROR, "Failed to enable WPA in the driver.");
-		return (-1);
-	}
-
-	wpa_clear_keys(wpa_s, NULL);
-	wpa_supplicant_req_scan(wpa_s, 0, 100000);
-
-	return (0);
-}
-
-static int door_id = -1;
-
-/* ARGSUSED */
-static void
-event_handler(void *cookie, char *argp, size_t asize,
-    door_desc_t *dp, uint_t n_desc)
-{
-	wpa_event_type event;
-
-	/* LINTED E_BAD_PTR_CAST_ALIGN */
-	event = ((wl_events_t *)argp)->event;
-	wpa_event_handler(cookie, event);
-
-	(void) door_return(NULL, 0, NULL, 0);
-}
-
-/*
- * Create the driver to wpad door
- */
-int
-wpa_supplicant_door_setup(void *cookie, char *doorname)
-{
-	struct stat stbuf;
-	int error = 0;
-
-	wpa_printf(MSG_DEBUG, "wpa_supplicant_door_setup(%s)", doorname);
-	/*
-	 * Create the door
-	 */
-	door_id = door_create(event_handler, cookie,
-	    DOOR_UNREF | DOOR_REFUSE_DESC | DOOR_NO_CANCEL);
-
-	if (door_id < 0) {
-		error = -1;
-		goto out;
-	}
-
-	if (stat(doorname, &stbuf) < 0) {
-		int newfd;
-		if ((newfd = creat(doorname, 0666)) < 0) {
-			(void) door_revoke(door_id);
-			door_id = -1;
-			error = -1;
-
-			goto out;
-		}
-		(void) close(newfd);
-	}
-
-	if (fattach(door_id, doorname) < 0) {
-		if ((errno != EBUSY) || (fdetach(doorname) < 0) ||
-		    (fattach(door_id, doorname) < 0)) {
-			(void) door_revoke(door_id);
-			door_id = -1;
-			error = -1;
-
-			goto out;
-		}
-	}
-
-out:
-	return (error);
-}
-
-void
-wpa_supplicant_door_destroy(char *doorname)
-{
-	wpa_printf(MSG_DEBUG, "wpa_supplicant_door_destroy(%s)\n", doorname);
-
-	if (door_id == -1)
-		return;
-
-	if (door_revoke(door_id) == -1) {
-		wpa_printf(MSG_ERROR, "failed to door_revoke(%d) %s, exiting.",
-		    door_id, strerror(errno));
-	}
-
-	if (fdetach(doorname) == -1) {
-		wpa_printf(MSG_ERROR, "failed to fdetach %s: %s, exiting.",
-		    doorname, strerror(errno));
-	}
-
-	(void) close(door_id);
-}
-
-static int
-wpa_config_parse_ssid(struct wpa_ssid *ssid, int line, const char *value)
-{
-	free(ssid->ssid);
-
-	ssid->ssid = (uint8_t *)strdup(value);
-	ssid->ssid_len = strlen(value);
-
-	if (ssid->ssid == NULL) {
-		wpa_printf(MSG_ERROR, "Invalid SSID '%s'.", line, value);
-		return (-1);
-	}
-	if (ssid->ssid_len > MAX_ESSID_LENGTH) {
-		free(ssid->ssid);
-		wpa_printf(MSG_ERROR, "Too long SSID '%s'.", line, value);
-		return (-1);
-	}
-	wpa_printf(MSG_MSGDUMP, "SSID: %s", ssid->ssid);
-	return (0);
-}
-
-static struct wpa_ssid *
-wpa_config_read_network(struct wpa_supplicant *wpa_s)
-{
-	struct wpa_ssid *ssid;
-	char buf[MAX_ESSID_LENGTH + 1];
-	dladm_secobj_class_t cl;
-	uint8_t psk[MAX_PSK_LENGTH + 1];
-	uint_t key_len;
-
-	wpa_printf(MSG_MSGDUMP, "Start of a new network configration");
-
-	ssid = (struct wpa_ssid *)malloc(sizeof (*ssid));
-	if (ssid == NULL)
-		return (NULL);
-	(void) memset(ssid, 0, sizeof (*ssid));
-
-	/*
-	 * Set default supported values
-	 */
-	ssid->proto = WPA_PROTO_WPA | WPA_PROTO_RSN;
-	ssid->pairwise_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP;
-	ssid->group_cipher = WPA_CIPHER_CCMP | WPA_CIPHER_TKIP |
-	    WPA_CIPHER_WEP104 | WPA_CIPHER_WEP40;
-	ssid->key_mgmt = WPA_KEY_MGMT_PSK; /* | WPA_KEY_MGMT_IEEE8021X; */
-
-	(void) memset(buf, 0, MAX_ESSID_LENGTH + 1);
-	wpa_s->driver->get_ssid(wpa_s->handle, wpa_s->linkid, (char *)buf);
-
-	(void) wpa_config_parse_ssid(ssid, 0, buf);
-
-	key_len = sizeof (psk);
-	(void) dladm_get_secobj(wpa_s->handle, (const char *)wpa_s->kname, &cl,
-	    psk, &key_len, DLADM_OPT_ACTIVE);
-	psk[key_len] = '\0';
-	ssid->passphrase = strdup((const char *)psk);
-
-	if (ssid->passphrase) {
-		pbkdf2_sha1(ssid->passphrase, (char *)ssid->ssid,
-		    ssid->ssid_len, 4096, ssid->psk, PMK_LEN);
-		wpa_hexdump(MSG_MSGDUMP, "PSK (from passphrase)",
-		    ssid->psk, PMK_LEN);
-		ssid->psk_set = 1;
-	}
-
-	if ((ssid->key_mgmt & WPA_KEY_MGMT_PSK) && !ssid->psk_set) {
-		wpa_printf(MSG_ERROR, "WPA-PSK accepted for key "
-		    "management, but no PSK configured.");
-		free(ssid);
-		ssid = NULL;
-	}
-
-	return (ssid);
-}
-
-struct wpa_config *
-wpa_config_read(void *arg)
-{
-	struct wpa_ssid *ssid;
-	struct wpa_config *config;
-	struct wpa_supplicant *wpa_s = arg;
-
-	config = malloc(sizeof (*config));
-	if (config == NULL)
-		return (NULL);
-	(void) memset(config, 0, sizeof (*config));
-	config->eapol_version = 1;	/* fixed value */
-
-	wpa_printf(MSG_DEBUG, "Reading configuration parameters from driver\n");
-
-	ssid = wpa_config_read_network(wpa_s);
-	if (ssid == NULL) {
-		wpa_config_free(config);
-		config = NULL;
-	} else {
-		config->ssid = ssid;
-	}
-
-	return (config);
-}
-
-void
-wpa_config_free(struct wpa_config *config)
-{
-	struct wpa_ssid *ssid = config->ssid;
-
-	if (ssid != NULL) {
-		free(ssid->ssid);
-		free(ssid->passphrase);
-		free(ssid);
-	}
-	free(config);
-}
-
-/*
- * make sure wpad is running under SMF context.
- */
-static boolean_t
-is_smf_context(void)
-{
-	char *fmri;
-
-	return (((fmri = getenv("SMF_FMRI")) != NULL) &&
-	    (strstr(fmri, SERVICE_NAME) != NULL));
-}
-
-int
-main(int argc, char *argv[])
-{
-	struct wpa_supplicant wpa_s;
-	char *link = NULL;
-	char *key = NULL;
-	dlpi_handle_t dh = NULL;
-	datalink_id_t linkid;
-	dladm_phys_attr_t dpa;
-	int c;
-	int exitcode;
-	char door_file[MAXPATHLEN];
-	dladm_handle_t handle;
-
-	if (!is_smf_context()) {
-		(void) fprintf(stderr,
-		    "wpad is an smf(5) managed service and cannot be run from "
-		    "the command line; please use dladm(1M).\n");
-		return (SMF_EXIT_ERR_NOSMF);
-	}
-
-	for (;;) {
-		c = getopt(argc, argv, "i:k:");
-		if (c < 0)
-			break;
-		switch (c) {
-		case 'i':
-			link = optarg;
-			break;
-		case 'k':
-			key = optarg;
-			break;
-		default:
-			return (SMF_EXIT_ERR_CONFIG);
-		}
-	}
-
-	/*
-	 * key name is required to retrieve PSK value through libwdladm APIs.
-	 * key is saved by dladm command by keyname
-	 * see dladm.
-	 */
-	if ((link == NULL) || (key == NULL)) {
-		wpa_printf(MSG_ERROR, "\nLink & key is required.");
-		return (-1);
-	}
-
-	if ((strlen(key) >= sizeof (wpa_s.kname)))  {
-		wpa_printf(MSG_ERROR, "Too long key name '%s'.", key);
-		return (-1);
-	}
-
-	if (daemon(0, 0))
-		return (-1);
-
-	/*
-	 * Hold this link open to prevent a link renaming operation.
-	 */
-	if (dlpi_open(link, &dh, 0) != DLPI_SUCCESS) {
-		wpa_printf(MSG_ERROR, "Failed to open link '%s'.", link);
-		return (-1);
-	}
-
-	/* This handle is stored in wpa_s when that struct is filled. */
-	if (dladm_open(&handle) != DLADM_STATUS_OK) {
-		wpa_printf(MSG_ERROR, "Failed to open dladm handle");
-		dlpi_close(dh);
-		return (-1);
-	}
-
-	if (dladm_name2info(handle, link, &linkid, NULL, NULL, NULL) !=
-	    DLADM_STATUS_OK) {
-		wpa_printf(MSG_ERROR, "Invalid link name '%s'.", link);
-		dladm_close(handle);
-		dlpi_close(dh);
-		return (-1);
-	}
-
-	/*
-	 * Get the device name of the link, which will be used as the door
-	 * file name used to communicate with the driver. Note that different
-	 * links use different doors.
-	 */
-	if (dladm_phys_info(handle, linkid, &dpa, DLADM_OPT_ACTIVE) !=
-	    DLADM_STATUS_OK) {
-		wpa_printf(MSG_ERROR,
-		    "Failed to get device name of link '%s'.", link);
-		dladm_close(handle);
-		dlpi_close(dh);
-		return (-1);
-	}
-	(void) snprintf(door_file, MAXPATHLEN, "%s_%s", WPA_DOOR, dpa.dp_dev);
-
-	(void) memset(&wpa_s, 0, sizeof (wpa_s));
-	wpa_s.driver = &wpa_driver_wifi_ops;
-	wpa_s.handle = handle;
-	wpa_s.linkid = linkid;
-	(void) strlcpy(wpa_s.kname, key, sizeof (wpa_s.kname));
-	eloop_init(&wpa_s);
-
-	/*
-	 * Setup default WPA/WPA2 configuration
-	 * get ESSID and PSK value
-	 */
-	wpa_s.conf = wpa_config_read(&wpa_s);
-	if (wpa_s.conf == NULL || wpa_s.conf->ssid == NULL) {
-		wpa_printf(MSG_ERROR, "\nNo networks (SSID) configured.\n");
-		exitcode = -1;
-		goto cleanup;
-	}
-
-	exitcode = 0;
-
-	/*
-	 * Setup door file to communicate with driver
-	 */
-	if (wpa_supplicant_door_setup(&wpa_s, door_file) != 0) {
-		wpa_printf(MSG_ERROR, "Failed to setup door(%s)", door_file);
-		exitcode = -1;
-		goto cleanup;
-	}
-
-	wpa_s.renew_snonce = 1;
-	if (wpa_supplicant_driver_init(link, &wpa_s) < 0) {
-		exitcode = -1;
-		goto cleanup;
-	}
-
-	/*
-	 * This link is hold again in wpa_supplicant_driver_init(), so that
-	 * we release the first reference.
-	 */
-	dlpi_close(dh);
-	dh = NULL;
-
-	wpa_printf(MSG_DEBUG, "=> eloop_run");
-
-	(void) eloop_register_signal(SIGINT, wpa_supplicant_terminate, NULL);
-	(void) eloop_register_signal(SIGTERM, wpa_supplicant_terminate, NULL);
-	(void) eloop_register_signal(SIGKILL, wpa_supplicant_terminate, NULL);
-
-	eloop_run();
-
-	wpa_printf(MSG_DEBUG, "<= eloop_run()");
-	wpa_supplicant_disassociate(&wpa_s, REASON_DEAUTH_LEAVING);
-
-	if (wpa_s.driver->set_wpa(wpa_s.handle, wpa_s.linkid, 0) < 0) {
-		wpa_printf(MSG_ERROR, "Failed to disable WPA in the driver.\n");
-	}
-
-cleanup:
-	wpa_supplicant_door_destroy(door_file);
-	/* The libdladm handle is closed in the following method */
-	wpa_supplicant_cleanup(&wpa_s);
-	eloop_destroy();
-
-	if (dh != NULL)
-		dlpi_close(dh);
-
-	return (exitcode);
-}
--- a/usr/src/cmd/cmd-inet/usr.sbin/Makefile	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/usr.sbin/Makefile	Wed May 29 08:31:24 2013 +0200
@@ -68,11 +68,11 @@
 SUBDIRS=	bootconfchk htable ifconfig ilbadm in.ftpd in.rdisc in.routed \
 		in.talkd inetadm inetconv ipadm ipmpstat ipqosconf ipsecutils \
 		kssl/kssladm kssl/ksslcfg nwamadm nwamcfg ping routeadm \
-		snoop sppptun traceroute wificonfig
+		snoop sppptun traceroute
 
 MSGSUBDIRS=	bootconfchk htable ifconfig ilbadm in.ftpd in.routed in.talkd \
 		inetadm inetconv ipadm ipmpstat ipqosconf ipsecutils \
-		kssl/ksslcfg nwamadm nwamcfg routeadm sppptun snoop wificonfig
+		kssl/ksslcfg nwamadm nwamcfg routeadm sppptun snoop
 
 # As programs get lint-clean, add them here and to the 'lint' target.
 # Eventually this hack should go away, and all in PROG should be
@@ -86,8 +86,7 @@
 # for the lint rule.
 LINTSUBDIRS=	bootconfchk ilbadm in.rdisc in.routed in.talkd inetadm \
 		inetconv ipmpstat ipqosconf ipsecutils kssl/kssladm \
-		kssl/ksslcfg nwamadm nwamcfg ping routeadm sppptun traceroute \
-		wificonfig
+		kssl/ksslcfg nwamadm nwamcfg ping routeadm sppptun traceroute
 # And as programs are verified not to attempt to write into constants,
 # -xstrconst should be used to ensure they stay that way.
 CONSTCLEAN=
--- a/usr/src/cmd/cmd-inet/usr.sbin/nwamadm/Makefile	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/usr.sbin/nwamadm/Makefile	Wed May 29 08:31:24 2013 +0200
@@ -31,7 +31,7 @@
 include ../../../Makefile.cmd
 
 XGETFLAGS +=	-a -x $(PROG).xcl
-LDLIBS +=	-linetutil -lnsl -lnwam -lumem -lscf
+LDLIBS +=	-linetutil -lnsl -ldladm -lnwam -lumem -lscf
 
 CERRWARN += -_gcc=-Wno-switch
 CERRWARN += -_gcc=-Wno-uninitialized
--- a/usr/src/cmd/cmd-inet/usr.sbin/nwamadm/nwamadm.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/usr.sbin/nwamadm/nwamadm.c	Wed May 29 08:31:24 2013 +0200
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 /*
@@ -72,15 +73,14 @@
 #define	CMD_DISABLE	2
 #define	CMD_LIST	3
 #define	CMD_SHOW_EVENTS	4
-#define	CMD_SCAN_WIFI	5
-#define	CMD_SELECT_WIFI	6
+#define	CMD_SELECT_WIFI	5
 
 #define	CMD_MIN		CMD_HELP
 #define	CMD_MAX		CMD_SELECT_WIFI
 
 /* functions to call */
 static cmd_func_t help_func, enable_func, disable_func, list_func;
-static cmd_func_t show_events_func, scan_wifi_func, select_wifi_func;
+static cmd_func_t show_events_func, select_wifi_func;
 static ofmt_cb_t print_list_cb;
 
 /* table of commands and usage */
@@ -100,12 +100,9 @@
 	{ CMD_SHOW_EVENTS,	"show-events",	show_events_func,
 	    "show-events",
 	    "Display all events.",			B_TRUE		},
-	{ CMD_SCAN_WIFI,	"scan-wifi",	scan_wifi_func,
-	    "scan-wifi <link-name>",
-	    "Request a WiFi scan for the selected link.", B_TRUE	},
 	{ CMD_SELECT_WIFI,	"select-wifi",	select_wifi_func,
 	    "select-wifi <link-name>",
-	    "Make a WLAN selection from the last WiFi scan.", B_TRUE	}
+	    "Make a WLAN selection from WiFi scan results", B_TRUE	}
 };
 
 /* Structure for "nwamadm list" output */
@@ -1017,8 +1014,6 @@
 	const char *action = NULL;
 	char *state = NULL;
 	boolean_t display = B_TRUE;
-	int i;
-	nwam_wlan_t *wlans;
 
 	(void) strlcpy(description, "-", sizeof (description));
 
@@ -1057,28 +1052,19 @@
 	case NWAM_EVENT_TYPE_WLAN_SCAN_REPORT:
 		(void) printf("%-*s \n", EVENT_WIDTH,
 		    nwam_event_type_to_string(event->nwe_type));
-		wlans = event->nwe_data.nwe_wlan_info.nwe_wlans;
-		for (i = 0;
-		    i < event->nwe_data.nwe_wlan_info.nwe_num_wlans;
-		    i++) {
-			(void) snprintf(description, DESCRIPTION_WIDTH,
-			    "%d: %c%c ESSID %s BSSID %s", i + 1,
-			    wlans[i].nww_selected ? 'S' : '-',
-			    wlans[i].nww_connected ? 'C' : '-',
-			    wlans[i].nww_essid, wlans[i].nww_bssid);
-			(void) printf("%-*s %-*s\n", EVENT_WIDTH, "-",
-			    DESCRIPTION_WIDTH, description);
-		}
+		(void) printf("Found %u  Scan Results for link %s",
+		    event->nwe_data.nwe_wlan_info.nwe_scanres_num,
+		    event->nwe_data.nwe_wlan_info.nwe_name);
 		display = B_FALSE;
 		break;
 
-	case NWAM_EVENT_TYPE_WLAN_NEED_CHOICE:
+	case NWAM_EVENT_TYPE_WLAN_ASSOCIATION_REPORT:
 		(void) printf("%-*s \n", EVENT_WIDTH,
 		    nwam_event_type_to_string(event->nwe_type));
 		display = B_FALSE;
 		break;
 
-	case NWAM_EVENT_TYPE_WLAN_NEED_KEY:
+	case NWAM_EVENT_TYPE_WLAN_WRONG_KEY:
 		(void) printf("%-*s \n", EVENT_WIDTH,
 		    nwam_event_type_to_string(event->nwe_type));
 		display = B_FALSE;
@@ -1087,10 +1073,17 @@
 	case NWAM_EVENT_TYPE_WLAN_CONNECTION_REPORT:
 		(void) snprintf(description, DESCRIPTION_WIDTH,
 		    gettext("connect to WLAN ESSID %s, BSSID %s %s"),
-		    event->nwe_data.nwe_wlan_info.nwe_wlans[0].nww_essid,
-		    event->nwe_data.nwe_wlan_info.nwe_wlans[0].nww_bssid,
-		    event->nwe_data.nwe_wlan_info.nwe_connected ?
-		    "succeeded" : "failed");
+		    event->nwe_data.nwe_wlan_info.nwe_wlan.nww_essid,
+		    event->nwe_data.nwe_wlan_info.nwe_wlan.nww_bssid,
+		    "succeeded");
+		break;
+
+	case NWAM_EVENT_TYPE_WLAN_DISASSOCIATION_REPORT:
+		(void) snprintf(description, DESCRIPTION_WIDTH,
+		    gettext("disconnected from WLAN ESSID %s, BSSID %s %s"),
+		    event->nwe_data.nwe_wlan_info.nwe_wlan.nww_essid,
+		    event->nwe_data.nwe_wlan_info.nwe_wlan.nww_bssid,
+		    "failed");
 		break;
 
 	case NWAM_EVENT_TYPE_INFO:
@@ -1202,179 +1195,338 @@
 	die_nwamerr(err, "event handling stopped");
 }
 
-/* May need to convert case-insensitive link name match to case-sensitive one */
-static nwam_error_t
-name_to_linkname(char *name, char **linknamep)
+static void
+prompt_sec_policy(dladm_wlan_secmode_t security_mode, dladm_wlan_key_t *key,
+    dladm_wlan_eap_t *eap_data)
 {
-	nwam_error_t err;
-	nwam_ncp_handle_t ncph = NULL;
-	nwam_ncu_handle_t ncuh = NULL;
+	uint_t k;
+
+	if (security_mode == DLADM_WLAN_SECMODE_EAP) {
+		char eap_input[PATH_MAX];
+		char mode[3];
+		char *user_prompt[] = {
+			"EAP Identity [mandatory]",
+			"EAP Anonymous Identity [optional]"
+		};
+		char *filename_prompt[] = {
+			"CA Certificate [optional]",
+			"EAP-TLS Private Key Filename [mandatory] \n",
+			"EAP-TLS Client Certificate [optional if pk12 file was "
+			"used for Private Key]"
+		};
+
+		/* ask eap mode */
+		do {
+			char eap_str[8];
+			for (k = DLADM_SECOBJ_CLASS_TLS;
+			    dladm_valid_secobjclass(k); k++)
+				(void) printf("\n %d: %s", k - 2,
+				    dladm_secobjclass2str(k, eap_str));
+			(void) printf(gettext("\nEnter EAP mode: "));
+			(void) fgets(mode, 2, stdin);
+			(void) fflush(stdin);
+			key->wk_class = atoi(mode) + 2;
+		} while (key->wk_class != DLADM_SECOBJ_CLASS_TLS &&
+		    key->wk_class != DLADM_SECOBJ_CLASS_TTLS &&
+		    key->wk_class != DLADM_SECOBJ_CLASS_PEAP);
+
+		/* user */
+		k = 0;
+		do {
+			(void) memset(eap_input, 0, sizeof (eap_input));
+			(void) printf(gettext("\nEnter %s : "), user_prompt[k]);
+			(void) fgets(eap_input, sizeof (eap_input), stdin);
+			(void) fflush(stdin);
+		} while (eap_input[0] == '\n' ||
+		    dladm_str2identity(eap_input, eap_data->eap_user));
+		eap_data->eap_valid |= DLADM_EAP_ATTR_USER;
 
-	if ((ncph = determine_active_ncp()) == NULL)
-		return (NWAM_ENTITY_NOT_FOUND);
+		/* anon */
+		k++;
+		do {
+			(void) memset(eap_input, 0, sizeof (eap_input));
+			(void) printf(gettext("\nEnter %s : "), user_prompt[k]);
+			(void) fgets(eap_input, sizeof (eap_input), stdin);
+			(void) fflush(stdin);
+		} while (dladm_str2identity(eap_input, eap_data->eap_anon) &&
+		    eap_input[0] != '\n');
+		if (eap_input[0] != '\n')
+			eap_data->eap_valid |= DLADM_EAP_ATTR_ANON;
+
+		/* ca cert */
+		k = 0;
+		do {
+			(void) memset(eap_input, 0, sizeof (eap_input));
+			(void) printf(gettext("\nEnter %s : "),
+			    filename_prompt[k]);
+			(void) fgets(eap_input, sizeof (eap_input), stdin);
+			(void) fflush(stdin);
+		} while (dladm_str2crtname(eap_input, eap_data->eap_ca_cert) &&
+		    eap_input[0] != '\n');
+		if (eap_input[0] != '\n')
+			eap_data->eap_valid |= DLADM_EAP_ATTR_CACERT;
 
-	err = nwam_ncu_read(ncph, name, NWAM_NCU_TYPE_LINK, 0, &ncuh);
-	if (err == NWAM_SUCCESS)
-		err = nwam_ncu_get_name(ncuh, linknamep);
+		if (key->wk_class == DLADM_SECOBJ_CLASS_TLS) {
+			/* priv key */
+			k++;
+			do {
+				(void) memset(eap_input, 0, sizeof (eap_input));
+				(void) printf(gettext("\nEnter %s: "),
+				    filename_prompt[k]);
+				(void) fgets(eap_input, sizeof (eap_input),
+				    stdin);
+				(void) fflush(stdin);
+			} while (dladm_str2crtname(eap_input,
+			    eap_data->eap_priv));
+			eap_data->eap_valid |= DLADM_EAP_ATTR_PRIV;
 
-	nwam_ncp_free(ncph);
-	nwam_ncu_free(ncuh);
-	return (err);
+			(void) fflush(stdin);
+			/* cli cert */
+			k++;
+			do {
+				(void) memset(eap_input, 0, sizeof (eap_input));
+				(void) printf(gettext("\nEnter %s: "),
+				    filename_prompt[k]);
+				(void) fgets(eap_input, sizeof (eap_input),
+				    stdin);
+				(void) fflush(stdin);
+			} while (dladm_str2crtname(eap_input,
+			    eap_data->eap_cli_cert) && eap_input[0] != '\n');
+			if (eap_input[0] != '\n')
+				eap_data->eap_valid |= DLADM_EAP_ATTR_CLICERT;
+		}
+	} else
+		key->wk_class = (dladm_secobj_class_t)security_mode;
+
+	while (dladm_secobj_prompt(key, NULL) != DLADM_STATUS_OK) {}
+
+	/* TODO: PKCS11 keystore: if true, import the certificates here */
 }
 
-static void
-scan_wifi_func(int argc, char *argv[])
+static ofmt_field_t scanres_common_fields[] = {
+{ "    WlanID",	11, 0,	NULL},
+{ "BSSID",	19, 1,	NULL},
+{ "CHAN",	5,  2,	NULL},
+{ "STRENGTH",	9,  3,	NULL},
+{ "SPEED",	6,  4,	NULL},
+{ "ESSID",	32, 5,	NULL},
+{ "SECMODE",	1,  6,	NULL},
+{ NULL,		0,  0,	NULL}};
+
+static char *scanres_select_fields =
+	"    WlanID,bssid,chan,strength,speed,essid,secmode";
+
+static boolean_t
+do_print_nww_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
 {
-	nwam_error_t err;
-	char *linkname = NULL;
-
-	if (argc != 1)
-		die_usage(CMD_SCAN_WIFI);
+	nwam_wlan_t	*attrp = ofarg->ofmt_cbarg;
 
-	if ((err = name_to_linkname(argv[0], &linkname)) != NWAM_SUCCESS)
-		die_nwamerr(err, "scan request failed for %s", argv[0]);
-
-	err = nwam_wlan_scan(linkname);
+	switch (ofarg->ofmt_id) {
+	case 0:
+		if (attrp->nww_wlanid)
+			(void) snprintf(buf, bufsize, "%u)  {%u}",
+			    attrp->nww_scanid + 1, attrp->nww_wlanid);
+		else
+			(void) snprintf(buf, bufsize, "%u)  NONE",
+			    attrp->nww_scanid + 1);
+		break;
+	case 5:
+		(void) memcpy(buf, attrp->nww_essid, DLADM_WLAN_MAX_ESSID_LEN);
+		break;
+	case 1:
+		(void) dladm_wlan_bssid2str(attrp->nww_bssid, buf);
+		break;
+	case 3:
+		(void) dladm_wlan_strength2str(attrp->nww_strength, buf);
+		break;
+	case 6:
+		(void) strlcpy(buf, attrp->nww_ietxt,
+		    sizeof (attrp->nww_ietxt));
+		break;
+	case 4:
+		(void) dladm_wlan_rate2str(attrp->nww_rate, buf);
+		break;
+	case 2:
+		(void) dladm_wlan_freq2channel(attrp->nww_freq, buf);
+		break;
+	default:
+		break;
+	}
 
-	if (err != NWAM_SUCCESS)
-		die_nwamerr(err, "scan request failed for %s", linkname);
-
-	free(linkname);
+	return (B_TRUE);
 }
 
 static void
 select_wifi_func(int argc, char *argv[])
 {
 	nwam_error_t err;
-	char *linkname = NULL;
-	uint_t i, choice, num_wlans = 0;
-	uint32_t security_mode;
-	boolean_t have_key = B_FALSE;
+	nwam_event_t event;
+
+	uint_t i = 0, choice = 0, num_wlans = 0;
+
 	nwam_wlan_t *wlans = NULL;
-	char choicestr[NWAM_MAX_VALUE_LEN];
-	char modestr[NWAM_MAX_VALUE_LEN];
-	char essid[NWAM_MAX_VALUE_LEN];
-	char bssid[NWAM_MAX_VALUE_LEN];
+	nwam_wlan_t *mywlan = NULL;
+	dladm_wlan_eap_t *eap_data = NULL;
+	dladm_wlan_key_t *key = NULL;
+
+	char selection[3]; /* max num is "64" */
+
+	ofmt_status_t		oferr;
+	ofmt_field_t		*template, *of;
+	ofmt_handle_t		ofmt;
 
 	if (argc != 1)
 		die_usage(CMD_SELECT_WIFI);
 
-	if ((err = name_to_linkname(argv[0], &linkname)) != NWAM_SUCCESS) {
-		die_nwamerr(err, "could not retrieve scan results for %s",
-		    argv[0]);
+	if ((err = nwam_wlan_scan(argv[0])) != NWAM_SUCCESS)
+		die_nwamerr(err, "Scan request failed for %s", argv[0]);
+	else
+		(void) printf("Scanning on link %s ...\n", argv[0]);
+
+	if ((err = nwam_events_init()) != NWAM_SUCCESS)
+		die_nwamerr(err, "Could not bind to receive events");
+
+	for (;;) {
+		if ((err = nwam_event_wait(&event)) == NWAM_SUCCESS &&
+		    event->nwe_type == NWAM_EVENT_TYPE_WLAN_SCAN_REPORT) {
+			nwam_event_free(event);
+			break;
+		} else if (err == NWAM_SUCCESS) {
+			nwam_event_free(event);
+		} else {
+			die_nwamerr(err, "Event handling stopped");
+		}
 	}
-	err = nwam_wlan_get_scan_results(linkname, &num_wlans, &wlans);
+	nwam_events_fini();
 
-	if (err != NWAM_SUCCESS) {
-		die_nwamerr(err, "could not retrieve scan results for %s",
-		    linkname);
+	if ((err = nwam_wlan_get_scan_results(argv[0], &num_wlans, &wlans)) !=
+	    NWAM_SUCCESS) {
+		die_nwamerr(err, "Could not retrieve scan results for %s",
+		    argv[0]);
+	} else if (num_wlans == 0) {
+		(void) printf("No wireless networks found during last scan(%s)",
+		    argv[0]);
+	} else {
+		template = scanres_common_fields;
+		for (of = template; of->of_name != NULL; of++) {
+			if (of->of_cb == NULL)
+				of->of_cb = do_print_nww_attr_cb;
+		}
+
+		oferr = ofmt_open(scanres_select_fields, template, 0, 0, &ofmt);
+		if (oferr != OFMT_SUCCESS) {
+			char buf[DLADM_STRSIZE];
+			free(wlans);
+			die("Internal Error %s", ofmt_strerror(ofmt, oferr,
+			    buf, sizeof (buf)));
+		}
 	}
-	bssid[0] = '\0';
+	(void) printf("\n");
+	for (i = 0; i < num_wlans; i++)
+		ofmt_print(ofmt, &wlans[i]);
+	ofmt_close(ofmt);
+
+	(void) printf(gettext("\n%d)  Specify a different AP\n"), i + 1);
+	(void) printf(gettext("\nChoose WLAN to connect to [1-%d]: "), i + 1);
 
 	/* Loop until valid selection made */
 	for (;;) {
-		(void) printf("\n");
-		/* Display WLAN choices for user to select from */
-		for (i = 0; i < num_wlans; i++) {
-			(void) printf("%d: ESSID %s BSSID %s\n",
-			    i + 1, wlans[i].nww_essid, wlans[i].nww_bssid);
-		}
-		(void) printf(gettext("%d: Other\n"), i + 1);
-
-		(void) printf(gettext("\nChoose WLAN to connect to [1-%d]: "),
-		    i + 1);
-
-		if (fgets(choicestr, sizeof (choicestr), stdin) != NULL &&
-		    (choice = atoi(choicestr)) >= 1 && choice <= (i + 1))
+		if (fgets(selection, 3, stdin) != NULL &&
+		    (choice = atoi(selection)) >= 1 && choice > 0 &&
+		    choice <= (i + 1))
 			break;
 	}
 
-	if (choice == i + 1 || wlans[choice - 1].nww_essid[0] == '\0') {
-		nwam_known_wlan_handle_t kwh = NULL;
-		nwam_value_t keynameval = NULL;
-
-		/* If "Other" or a hidden WLAN is selected, ask for ESSID */
-		do {
-			(void) printf(gettext("\nEnter WLAN name: "));
-			while (fgets(essid, sizeof (essid), stdin) == NULL) {}
-			essid[strlen(essid) - 1] = '\0';
-		} while (strspn(essid, " \t") == strlen(essid));
+	if (choice != i + 1) {
+		mywlan = &wlans[choice - 1];
+	} else {
+		mywlan = calloc(1, sizeof (nwam_wlan_t));
+		if (mywlan == NULL) {
+			free(wlans);
+			die("Out of Memory");
+		}
+	}
 
-		/* If "Other" was selected, secmode must be specified. */
-		if (choice == i + 1) {
-			for (;;) {
-				(void) printf(gettext("1: None\n"));
-				(void) printf(gettext("2: WEP\n"));
-				(void) printf(gettext("3: WPA\n"));
-				(void) printf(gettext("Enter security mode: "));
-				if (fgets(modestr, sizeof (choicestr), stdin)
-				    != NULL &&
-				    (security_mode = atoi(modestr)) >= 1 &&
-				    security_mode <= 3)
-					break;
-			}
-		} else {
-			security_mode = wlans[choice - 1].nww_security_mode;
-			have_key = wlans[choice - 1].nww_have_key;
-		}
-
-		/*
-		 * We have to determine if we have a key for this ESSID from
-		 * the known WLAN list, since we cannot determine this from
-		 * the scan results.
-		 */
-		if (nwam_known_wlan_read(essid, 0, &kwh) == NWAM_SUCCESS &&
-		    nwam_known_wlan_get_prop_value(kwh,
-		    NWAM_KNOWN_WLAN_PROP_KEYNAME, &keynameval) == NWAM_SUCCESS)
-			have_key = B_TRUE;
-		else
-			have_key = B_FALSE;
-
-		nwam_value_free(keynameval);
-		nwam_known_wlan_free(kwh);
-	} else {
-		(void) strlcpy(essid, wlans[choice - 1].nww_essid,
-		    sizeof (essid));
-		(void) strlcpy(bssid, wlans[choice - 1].nww_bssid,
-		    sizeof (bssid));
-		security_mode = wlans[choice - 1].nww_security_mode;
-		have_key = wlans[choice - 1].nww_have_key;
+	/*
+	 * If "Other" or a hidden WLAN is selected, ask for ESSID
+	 * In this case we won't search if this ESSID is a known wlan
+	 * To perform this search we require bssid
+	 */
+	if (mywlan->nww_esslen == 0) {
+		char tmpess[DLADM_WLAN_MAX_ESSID_LEN+1];
+		do {
+			(void) memset(tmpess, 0, sizeof (tmpess));
+			(void) printf(gettext("\nEnter Wlan SSID (max 32 chars)"
+			    ": "));
+			while (fgets(tmpess, sizeof (tmpess), stdin) == NULL) {}
+		} while (strspn(tmpess, " \n\t") ==
+		    strnlen(tmpess, DLADM_WLAN_MAX_ESSID_LEN));
+		mywlan->nww_esslen = strnlen(tmpess, DLADM_WLAN_MAX_ESSID_LEN);
+		mywlan->nww_esslen--;
+		(void) memcpy(mywlan->nww_essid, tmpess, mywlan->nww_esslen);
 	}
 
-	if (security_mode != DLADM_WLAN_SECMODE_NONE && !have_key) {
-		uint_t keyslot = 1;
-		char key[NWAM_MAX_VALUE_LEN];
-		char slotstr[NWAM_MAX_VALUE_LEN];
+	/* "Other" was selected - Get Secmode */
+	if (choice == i + 1) {
+		for (;;) {
+			uint_t j;
+			char secmode_name[8];
+			for (j = DLADM_WLAN_SECMODE_NONE;
+			    j <= DLADM_WLAN_SECMODE_EAP; j++)
+				(void) printf("\n%d: %s", j,
+				    dladm_wlan_secmode2str(j, secmode_name));
+			(void) printf(gettext("\nEnter security mode: "));
+			if (fgets(selection, 2, stdin) != NULL &&
+			    (mywlan->nww_security_mode = atoi(selection)) &&
+			    mywlan->nww_security_mode <= DLADM_WLAN_SECMODE_EAP)
+				break;
+		}
+	}
 
-		do {
-			(void) printf(gettext("\nEnter WLAN key for "
-			    "ESSID %s: "), essid);
-			while (fgets(key, sizeof (key), stdin) == NULL) {}
-			key[strlen(key) - 1] = '\0';
-		} while (strspn(key, " \t") == strlen(key));
+	/* It is not a known wlan */
+	if (mywlan->nww_wlanid == 0 &&
+	    mywlan->nww_security_mode != DLADM_WLAN_SECMODE_NONE) {
+		key = calloc(1, sizeof (dladm_wlan_key_t));
+
+		if (mywlan->nww_security_mode == DLADM_WLAN_SECMODE_EAP)
+			eap_data = calloc(1, sizeof (dladm_wlan_eap_t));
+		prompt_sec_policy(mywlan->nww_security_mode, key, eap_data);
+	}
 
-		if (security_mode == DLADM_WLAN_SECMODE_WEP) {
-			for (;;) {
-				(void) printf(
-				    gettext("\nEnter key slot [1-4]: "));
-				if (fgets(slotstr, sizeof (slotstr), stdin)
-				    != NULL && (keyslot = atoi(slotstr)) >= 1 &&
-				    keyslot <= 4)
-					break;
-			}
-		}
+	(void) printf(gettext("\nConnecting link %s ...\n"), argv[0]);
+	err = nwam_wlan_select(argv[0], mywlan, key, eap_data);
+	if (err != NWAM_SUCCESS)
+		(void) printf(gettext("\nCould not select WLAN %s [%s]\n"),
+		    mywlan->nww_essid, nwam_strerror(err));
+	if (choice == i + 1)
+		free(mywlan);
+	if (wlans != NULL)
+		free(wlans);
+	if (key != NULL)
+		free(key);
+	if (eap_data != NULL)
+		free(eap_data);
+
+	if ((err = nwam_events_init()) != NWAM_SUCCESS)
+		die_nwamerr(err, "Could not bind to receive events");
 
-		err = nwam_wlan_set_key(linkname, essid, bssid, security_mode,
-		    keyslot, key);
-		if (err != NWAM_SUCCESS)
-			die_nwamerr(err, "could not set WiFi key");
+	for (;;) {
+		if ((err = nwam_event_wait(&event)) == NWAM_SUCCESS &&
+		    (event->nwe_type ==
+		    NWAM_EVENT_TYPE_WLAN_CONNECTION_REPORT ||
+		    event->nwe_type ==
+		    NWAM_EVENT_TYPE_WLAN_DISASSOCIATION_REPORT ||
+		    event->nwe_type == NWAM_EVENT_TYPE_WLAN_WRONG_KEY)) {
+			nwam_event_free(event);
+			break;
+		} else if (err == NWAM_SUCCESS) {
+			nwam_event_free(event);
+		} else {
+			die_nwamerr(err, "Event handling stopped");
+		}
 	}
-	err = nwam_wlan_select(linkname, essid, bssid[0] != '\0' ? bssid : NULL,
-	    security_mode, B_TRUE);
-	if (err != NWAM_SUCCESS)
-		die_nwamerr(err, "could not select WLAN %s", essid);
-	free(wlans);
-	free(linkname);
+
+	nwam_events_fini();
 }
 
 int
--- a/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/Makefile	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/Makefile	Wed May 29 08:31:24 2013 +0200
@@ -32,7 +32,7 @@
 
 XGETFLAGS +=	-a -x $(PROG).xcl
 LFLAGS =	-t
-LDLIBS +=	-ll -ltecla -lnwam -lumem
+LDLIBS +=	-ll -ltecla -ldladm -lnwam -lumem
 YFLAGS +=	-d -b nwamcfg_grammar
 CLEANFILES +=	nwamcfg_lex.c nwamcfg_grammar.tab.c nwamcfg_grammar.tab.h
 
@@ -44,7 +44,7 @@
 
 .KEEP_STATE:
 
-all: $(PROG) 
+all: $(PROG)
 
 $(PROG): $(OBJS)
 	$(LINK.c) $(OBJS) -o $@ $(LDLIBS)
--- a/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg.c	Wed May 29 08:31:24 2013 +0200
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 /*
@@ -194,11 +195,16 @@
 	NWAM_LOC_PROP_IPPOOL_CONFIG_FILE,
 	NWAM_LOC_PROP_IKE_CONFIG_FILE,
 	NWAM_LOC_PROP_IPSECPOLICY_CONFIG_FILE,
-	NWAM_KNOWN_WLAN_PROP_BSSIDS,
-	NWAM_KNOWN_WLAN_PROP_PRIORITY,
+	NWAM_KNOWN_WLAN_PROP_SSID,
+	NWAM_KNOWN_WLAN_PROP_BSSID,
 	NWAM_KNOWN_WLAN_PROP_KEYNAME,
-	NWAM_KNOWN_WLAN_PROP_KEYSLOT,
-	NWAM_KNOWN_WLAN_PROP_SECURITY_MODE
+	NWAM_KNOWN_WLAN_PROP_PRIORITY,
+	NWAM_KNOWN_WLAN_PROP_DISABLED,
+	NWAM_KNOWN_WLAN_PROP_EAP_USER,
+	NWAM_KNOWN_WLAN_PROP_EAP_ANON,
+	NWAM_KNOWN_WLAN_PROP_CA_CERT,
+	NWAM_KNOWN_WLAN_PROP_PRIV,
+	NWAM_KNOWN_WLAN_PROP_CLI_CERT
 };
 
 /* properties table: maps PT_* constants to property names */
@@ -268,11 +274,16 @@
 
 /* Known WLAN properties table */
 static prop_table_entry_t wlan_prop_table[] = {
-	{ PT_WLAN_BSSIDS, 	NWAM_KNOWN_WLAN_PROP_BSSIDS },
-	{ PT_WLAN_PRIORITY, 	NWAM_KNOWN_WLAN_PROP_PRIORITY },
+	{ PT_WLAN_SSID, 	NWAM_KNOWN_WLAN_PROP_SSID },
+	{ PT_WLAN_BSSID, 	NWAM_KNOWN_WLAN_PROP_BSSID },
 	{ PT_WLAN_KEYNAME, 	NWAM_KNOWN_WLAN_PROP_KEYNAME },
-	{ PT_WLAN_KEYSLOT, 	NWAM_KNOWN_WLAN_PROP_KEYSLOT },
-	{ PT_WLAN_SECURITY_MODE, NWAM_KNOWN_WLAN_PROP_SECURITY_MODE },
+	{ PT_WLAN_PRIORITY, 	NWAM_KNOWN_WLAN_PROP_PRIORITY },
+	{ PT_WLAN_DISABLED, 	NWAM_KNOWN_WLAN_PROP_DISABLED },
+	{ PT_WLAN_EAP_USER, 	NWAM_KNOWN_WLAN_PROP_EAP_USER },
+	{ PT_WLAN_EAP_ANON, 	NWAM_KNOWN_WLAN_PROP_EAP_ANON },
+	{ PT_WLAN_CA_CERT, 	NWAM_KNOWN_WLAN_PROP_CA_CERT },
+	{ PT_WLAN_PRIV, 	NWAM_KNOWN_WLAN_PROP_PRIV },
+	{ PT_WLAN_CLI_CERT, 	NWAM_KNOWN_WLAN_PROP_CLI_CERT },
 	{ 0, NULL }
 };
 
@@ -1169,7 +1180,7 @@
 		ret = nwam_loc_commit(loc_h, 0);
 		break;
 	case NWAM_OBJECT_TYPE_KNOWN_WLAN:
-		ret = nwam_known_wlan_commit(wlan_h, 0);
+		ret = nwam_known_wlan_commit(wlan_h);
 		break;
 	}
 
@@ -1356,11 +1367,16 @@
 			    ncu_class, &ncu_h);
 		}
 
+		if (cmd->cmd_res1_type == RT1_WLAN && ret == NWAM_INVALID_ARG) {
+			nerr("Invalid known wlan name: "
+			    "Only positive decimal numbers are valid");
+			goto done;
+		}
+
 		if (ret != NWAM_SUCCESS) {
 			nwamerr(ret, "Create error");
 			goto done;
 		}
-
 	} else {
 		/* template given */
 		/* argv[0] is -t, argv[1] is old name, argv[2] is new name */
@@ -1553,7 +1569,7 @@
 	if (ret != NWAM_SUCCESS)
 		goto done;
 
-	ret = nwam_walk_known_wlans(destroy_wlan_callback, NULL, 0, NULL);
+	ret = nwam_walk_known_wlans(destroy_wlan_callback, NULL, NULL);
 	if (ret != NWAM_SUCCESS)
 		goto done;
 
@@ -2253,7 +2269,19 @@
 
 /* Rules for Known WLANs */
 static prop_display_entry_t wlan_prop_display_entry_table[] = {
-	/* no rules for WLANs */
+	{ NWAM_KNOWN_WLAN_PROP_EAP_USER, NWAM_KNOWN_WLAN_PROP_KEYNAME,
+	    { DLADM_SECOBJ_CLASS_TLS, DLADM_SECOBJ_CLASS_TTLS,
+	    DLADM_SECOBJ_CLASS_PEAP, -1 } },
+	{ NWAM_KNOWN_WLAN_PROP_EAP_ANON, NWAM_KNOWN_WLAN_PROP_KEYNAME,
+	    { DLADM_SECOBJ_CLASS_TLS, DLADM_SECOBJ_CLASS_TTLS,
+	    DLADM_SECOBJ_CLASS_PEAP, -1 } },
+	{ NWAM_KNOWN_WLAN_PROP_CA_CERT, NWAM_KNOWN_WLAN_PROP_KEYNAME,
+	    { DLADM_SECOBJ_CLASS_TLS, DLADM_SECOBJ_CLASS_TTLS,
+	    DLADM_SECOBJ_CLASS_PEAP, -1 } },
+	{ NWAM_KNOWN_WLAN_PROP_PRIV, NWAM_KNOWN_WLAN_PROP_KEYNAME,
+	    { DLADM_SECOBJ_CLASS_TLS, -1 } },
+	{ NWAM_KNOWN_WLAN_PROP_CLI_CERT, NWAM_KNOWN_WLAN_PROP_PRIV,
+	    { NWAM_SUCCESS, -1 } },
 	{ NULL, NULL, { -1 } }
 };
 
@@ -2329,7 +2357,9 @@
 			    display_list[i].pde_checkname, &prop_val);
 			break;
 		case NWAM_OBJECT_TYPE_KNOWN_WLAN:
-			return (B_TRUE);
+			ret = nwam_known_wlan_get_prop_value(wlan_h,
+			    display_list[i].pde_checkname, &prop_val);
+			break;
 		}
 		if (ret != NWAM_SUCCESS)
 			continue;
@@ -2380,6 +2410,57 @@
 					goto next_rule;
 				}
 			}
+		} else if (object_type == NWAM_OBJECT_TYPE_KNOWN_WLAN &&
+		    strcmp(prop, NWAM_KNOWN_WLAN_PROP_CLI_CERT) == 0 &&
+		    prop_type == NWAM_VALUE_TYPE_STRING) {
+			/*
+			 * TODO:
+			 * When PKCS#11 certificates by reference are supported
+			 * check if private key is a .pk12 file so that this
+			 * property is skipped.
+			 */
+			show_prop = B_TRUE;
+			goto next_rule;
+		} else if (object_type == NWAM_OBJECT_TYPE_KNOWN_WLAN &&
+		    strcmp(prop, NWAM_KNOWN_WLAN_PROP_KEYNAME) == 0 &&
+		    prop_type == NWAM_VALUE_TYPE_STRING) {
+			dladm_handle_t adm_handle;
+			secobj_class_info_t key_if;
+			char *keyname = NULL;
+			if (nwam_value_get_string(prop_val, &keyname) !=
+			    NWAM_SUCCESS) {
+				nwam_value_free(prop_val);
+				continue;
+			}
+			if (dladm_open(&adm_handle) != DLADM_STATUS_OK) {
+				nwam_value_free(prop_val);
+				continue;
+			}
+
+			key_if.sc_name = keyname;
+			key_if.sc_dladmclass = 0;
+			if (dladm_walk_secobj(adm_handle, &key_if,
+			    find_matching_secobj,
+			    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST)) {
+				dladm_close(adm_handle);
+				nwam_value_free(prop_val);
+				continue;
+			}
+			dladm_close(adm_handle);
+
+			if (key_if.sc_dladmclass == 0) {
+				nwam_value_free(prop_val);
+				continue;
+			}
+
+			for (k = 0; display_list[i].pde_checkvals[k] != -1;
+			    k++) {
+				if (key_if.sc_dladmclass ==
+				    display_list[i].pde_checkvals[k]) {
+					show_prop = B_TRUE;
+					goto next_rule;
+				}
+			}
 		}
 
 next_rule:
@@ -2464,7 +2545,7 @@
 		ret = nwam_enm_prop_multivalued(prop, &multi);
 		break;
 	case NWAM_OBJECT_TYPE_KNOWN_WLAN:
-		ret = nwam_known_wlan_prop_multivalued(prop, &multi);
+		ret = NWAM_INVALID_ARG;
 		break;
 	}
 
@@ -2546,6 +2627,7 @@
 		nerr("Set error: property '%s' is read-only", prop);
 		return;
 	}
+
 	if (!show_prop_test(object_type, prop, prop_table, checked, 0)) {
 		if (interactive_mode) {
 			(void) printf(gettext("setting property '%s' "
@@ -3186,8 +3268,7 @@
 			    cmd->cmd_argv[0], all_props, NULL, -1);
 		} else {
 			ret = nwam_walk_known_wlans(list_wlan_callback,
-			    &list_msg, NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER,
-			    NULL);
+			    &list_msg, NULL);
 		}
 		if (ret != NWAM_SUCCESS)
 			goto done;
@@ -3707,7 +3788,7 @@
 		if (name == NULL) {
 			/* export all WLANs */
 			ret = nwam_walk_known_wlans(export_wlan_callback, of,
-			    NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER, NULL);
+			    NULL);
 		} else {
 			if (wlan_h == NULL) {
 				ret = nwam_known_wlan_read(name, 0,
@@ -4059,6 +4140,7 @@
 			(void) putchar(')');
 			nwam_value_free(vals);
 		}
+
 		/* print choices, won't print anything if there aren't any */
 		print_all_prop_choices(object_type, props[i]);
 		(void) printf("> ");
--- a/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg.h	Wed May 29 08:31:24 2013 +0200
@@ -22,6 +22,7 @@
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #ifndef _NWAMCFG_H
@@ -128,17 +129,22 @@
 #define	PT_LOC_IPPOOL_CONFIG	37
 #define	PT_LOC_IKE_CONFIG	38
 #define	PT_LOC_IPSECPOL_CONFIG	39
-#define	PT_WLAN_BSSIDS		40
-#define	PT_WLAN_PRIORITY	41
+#define	PT_WLAN_SSID		40
+#define	PT_WLAN_BSSID		41
 #define	PT_WLAN_KEYNAME		42
-#define	PT_WLAN_KEYSLOT		43
-#define	PT_WLAN_SECURITY_MODE	44
+#define	PT_WLAN_PRIORITY	43
+#define	PT_WLAN_DISABLED	44
+#define	PT_WLAN_EAP_USER	45
+#define	PT_WLAN_EAP_ANON	46
+#define	PT_WLAN_CA_CERT		47
+#define	PT_WLAN_PRIV		48
+#define	PT_WLAN_CLI_CERT	49
 /*
  * If any new PT_ are defined here, make sure it is added in the same
  * order into the pt_types array in nwamcfg.c
  */
 #define	PT_MIN			PT_UNKNOWN
-#define	PT_MAX			PT_WLAN_SECURITY_MODE
+#define	PT_MAX			PT_WLAN_CLI_CERT
 
 #define	MAX_SUBCMD_ARGS	3
 
--- a/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg_grammar.y	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg_grammar.y	Wed May 29 08:31:24 2013 +0200
@@ -66,7 +66,7 @@
 %token LOC_DEFAULT_DOMAIN LOC_NFSV4_DOMAIN
 %token LOC_IPF_CONFIG LOC_IPF_V6_CONFIG
 %token LOC_IPNAT_CONFIG LOC_IPPOOL_CONFIG LOC_IKE_CONFIG LOC_IPSECPOL_CONFIG
-%token WLAN_BSSIDS WLAN_PRIORITY WLAN_KEYNAME WLAN_KEYSLOT WLAN_SECURITY_MODE
+%token WLAN_SSID WLAN_BSSID WLAN_KEYNAME WLAN_PRIORITY WLAN_DISABLED WLAN_EAP_USER WLAN_EAP_ANON WLAN_CA_CERT WLAN_PRIV WLAN_CLI_CERT
 
 %type <strval> TOKEN EQUAL OPTION
 %type <ival> resource1_type LOC NCP ENM WLAN
@@ -85,7 +85,7 @@
     LOC_DEFAULT_DOMAIN LOC_NFSV4_DOMAIN
     LOC_IPF_CONFIG LOC_IPF_V6_CONFIG
     LOC_IPNAT_CONFIG LOC_IPPOOL_CONFIG LOC_IKE_CONFIG LOC_IPSECPOL_CONFIG
-    WLAN_BSSIDS WLAN_PRIORITY WLAN_KEYNAME WLAN_KEYSLOT WLAN_SECURITY_MODE
+    WLAN_SSID WLAN_BSSID WLAN_KEYNAME WLAN_PRIORITY WLAN_DISABLED WLAN_EAP_USER WLAN_EAP_ANON WLAN_CA_CERT WLAN_PRIV WLAN_CLI_CERT
 %type <cmd> command
 %type <cmd> cancel_command CANCEL
 %type <cmd> clear_command CLEAR
@@ -178,7 +178,7 @@
 	{
 		properr($2);
 		YYERROR;
-	}		
+	}
 	|	CLEAR property_type
 	{
 		/* clear prop */
@@ -238,7 +238,7 @@
 	}
 	|	CREATE resource2_type ncu_class_type TOKEN
 	{
-		/* create ncu ip/phys test */	  
+		/* create ncu ip/phys test */
 		if (($$ = alloc_cmd()) == NULL)
 			YYERROR;
 		cmd = $$;
@@ -268,7 +268,7 @@
 	}
 	|	CREATE OPTION TOKEN resource2_type ncu_class_type TOKEN
 	{
-		/* create -t old ncu ip/phys test */	  
+		/* create -t old ncu ip/phys test */
 		if (($$ = alloc_cmd()) == NULL)
 			YYERROR;
 		cmd = $$;
@@ -534,7 +534,7 @@
 	{
 		properr($2);
 		YYERROR;
-	}		
+	}
 	|	GET property_type
 	{
 		/* get prop */
@@ -895,10 +895,14 @@
 	|	LOC_IPPOOL_CONFIG	{ $$ = PT_LOC_IPPOOL_CONFIG; }
 	|	LOC_IKE_CONFIG		{ $$ = PT_LOC_IKE_CONFIG; }
 	|	LOC_IPSECPOL_CONFIG	{ $$ = PT_LOC_IPSECPOL_CONFIG; }
-	|	WLAN_BSSIDS		{ $$ = PT_WLAN_BSSIDS; }
-	|	WLAN_PRIORITY		{ $$ = PT_WLAN_PRIORITY; }
+	|	WLAN_SSID		{ $$ = PT_WLAN_SSID; }
+	|	WLAN_BSSID		{ $$ = PT_WLAN_BSSID; }
 	|	WLAN_KEYNAME		{ $$ = PT_WLAN_KEYNAME; }
-	|	WLAN_KEYSLOT		{ $$ = PT_WLAN_KEYSLOT; }
-	|	WLAN_SECURITY_MODE	{ $$ = PT_WLAN_SECURITY_MODE; }
-
+	|	WLAN_PRIORITY		{ $$ = PT_WLAN_PRIORITY; }
+	|	WLAN_DISABLED		{ $$ = PT_WLAN_DISABLED; }
+	|	WLAN_EAP_USER		{ $$ = PT_WLAN_EAP_USER; }
+	|	WLAN_EAP_ANON		{ $$ = PT_WLAN_EAP_ANON; }
+	|	WLAN_CA_CERT		{ $$ = PT_WLAN_CA_CERT; }
+	|	WLAN_PRIV		{ $$ = PT_WLAN_PRIV; }
+	|	WLAN_CLI_CERT		{ $$ = PT_WLAN_CLI_CERT; }
 %%
--- a/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg_lex.l	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/cmd-inet/usr.sbin/nwamcfg/nwamcfg_lex.l	Wed May 29 08:31:24 2013 +0200
@@ -207,17 +207,22 @@
 <TSTATE>ike-config-file			{ return LOC_IKE_CONFIG; }
 <TSTATE>ipsecpolicy-config-file		{ return LOC_IPSECPOL_CONFIG; }
 
-<TSTATE>bssids		{ return WLAN_BSSIDS; }
-<TSTATE>priority	{ return WLAN_PRIORITY; }
-<TSTATE>keyname		{ return WLAN_KEYNAME; }
-<TSTATE>keyslot		{ return WLAN_KEYSLOT; }
-<TSTATE>security-mode	{ return WLAN_SECURITY_MODE; }
+<TSTATE>ssid			{ return WLAN_SSID; }
+<TSTATE>bssid			{ return WLAN_BSSID; }
+<TSTATE>keyname			{ return WLAN_KEYNAME; }
+<TSTATE>priority		{ return WLAN_PRIORITY; }
+<TSTATE>disabled		{ return WLAN_DISABLED; }
+<TSTATE>identity		{ return WLAN_EAP_USER; }
+<TSTATE>anonymous-identity	{ return WLAN_EAP_ANON; }
+<TSTATE>ca_cert			{ return WLAN_CA_CERT; }
+<TSTATE>private_key		{ return WLAN_PRIV; }
+<TSTATE>client_cert		{ return WLAN_CLI_CERT; }
 
 <TSTATE>=		{ return EQUAL; }
 
 <TSTATE>\-[adftV] {	/* matches options */
 			yylval.strval = safe_strdup(yytext);
-			return OPTION; 
+			return OPTION;
 		}
 
 <TSTATE>[^ \t\n\";=\[\]\(\)]+	{	/* matches non-quoted values */
--- a/usr/src/cmd/cmd-inet/usr.sbin/wificonfig/Makefile	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,64 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License, Version 1.0 only
-# (the "License").  You may not use this file except in compliance
-# with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-#
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-PROG=		wificonfig	
-OBJS=		wificonfig.o
-SRCS=		$(OBJS:%.o=%.c)
-
-include		../../../Makefile.cmd
-
-LDLIBS +=	-lsecdb
-
-$(ROOTSBIN)/wificonfig := FILEMODE = 04755
-ROOTUSRSBINLINKS = $(ROOTUSRSBIN)/$(PROG)
-CERRWARN += -_gcc=-Wno-char-subscripts
-CERRWARN += -_gcc=-Wno-parentheses
-
-.KEEP_STATE:
-
-all:	$(PROG)
-
-_msg:	$(POFILE)
-
-CPPFLAGS	+= -I$(SRC)/uts/common
-
-SECLEVEL	= standard
-
-$(PROG):	$(OBJS)
-	$(LINK.c) $(OBJS) -o $@ $(LDLIBS)
-	$(POST_PROCESS)
-
-install: all $(ROOTSBINPROG) $(ROOTUSRSBINLINKS)
-
-$(ROOTUSRSBINLINKS):
-	-$(RM) $@; $(SYMLINK) ../../sbin/$(PROG) $@
-
-clean:
-	$(RM) $(OBJS)
-
-lint:	lint_SRCS
-
-include		../../../Makefile.targ
--- a/usr/src/cmd/cmd-inet/usr.sbin/wificonfig/wificonfig.c	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4928 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stddef.h>
-#include <errno.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <net/if.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/ipc.h>
-#include <sys/ddi.h>
-#include <stropts.h>
-#include <assert.h>
-#include <termios.h>
-#include <time.h>
-#include <string.h>
-#include <strings.h>
-#include <auth_attr.h>
-#include <auth_list.h>
-#include <libdevinfo.h>
-#include <secdb.h>
-#include <priv.h>
-#include <pwd.h>
-#include <umem.h>
-#include <locale.h>
-#include <libintl.h>
-#include <dirent.h>
-#include <inet/wifi_ioctl.h>
-
-/*
- * Debug information
- */
-#ifdef	DEBUG
-int wifi_debug = 0;
-void wifi_dbgprintf(char *fmt, ...);
-#define	PRTDBG(msg) if (wifi_debug > 1) wifi_dbgprintf msg
-#else /* DEBUG */
-#define	PRTDBG(msg)
-#endif /* DEBUG */
-
-#define	MAX_HISTORY_NUM			10
-#define	MAX_PREFERENCE_NUM		10
-#define	MAX_SCANBUF_LEN			256
-#define	MAX_CONFIG_FILE_LENGTH		256
-#define	MAX_LOADPF_LENGTH		256
-#define	LOADPROFILE_TIMEOUT		10
-#define	RECORD_ADD		0
-#define	RECORD_DEL		1
-/*
- * Wificonfig exit status
- */
-#define	WIFI_EXIT_DEF		0
-#define	WIFI_FATAL_ERR		1
-#define	WIFI_IMPROPER_USE	2
-#define	WIFI_MINOR_ERR		3
-
-#define	WIFI_LOCKF "/var/run/lockf_wifi"
-
-typedef enum {
-	PREFERENCE,
-	HISTORY,
-	ACTIVEP,
-	PROFILE,
-	OTHER
-} list_type_t;
-
-#define	WIFI_PREFER	"{preference}"
-#define	WIFI_HISTORY	"{history}"
-#define	WIFI_ACTIVEP	"{active_profile}"
-
-typedef enum {
-	LINKSTATUS = 0,
-	BSSID,
-	ESSID,
-	BSSTYPE,
-	CREATEIBSS,
-	CHANNEL,
-	RATES,
-	POWERMODE,
-	AUTHMODE,
-	ENCRYPTION,
-	WEPKEYID,
-	WEPKEY,
-	SIGNAL,
-	RADIOON,
-	WLANLIST,
-	CONFIG_ITEM_END /* 15 */
-} config_item_t;
-typedef struct ae {
-	struct ae *ae_next;
-	char *ae_arg;
-}ae_t;
-typedef struct aelist {
-	int ael_argc;
-	ae_t *ael_head, *ael_tail;
-	list_type_t type;
-}aelist_t;
-typedef struct section {
-	struct section *section_next;
-	aelist_t *list;
-	char *section_id;
-}section_t;
-
-/*
- * config_file_t is an abstract of configration file,
- * either/etc/inet/wifi/wifi.<interface> or /etc/inet/secret/
- * wifi/wifiwepkey.<interface>
- */
-typedef struct config_file {
-	int section_argc;
-	section_t *section_head, *section_tail;
-}config_file_t;
-
-static config_file_t *gp_config_file = NULL;
-static config_file_t *gp_wepkey_file = NULL;
-static char *p_file_wifi = "/etc/inet/wifi";
-static char *p_file_wifiwepkey = "/etc/inet/secret/wifiwepkey";
-
-typedef enum {
-	AUTH_WEP = 0,
-	AUTH_OTHER = 1
-} wifi_auth_t;
-
-static char *p_auth_string[] = {
-	WIFI_WEP_AUTH,
-	WIFI_CONFIG_AUTH
-};
-
-/*
- * gbuf: is a global buf, which is used to communicate between the user and
- * the driver
- */
-static wldp_t *gbuf = NULL;
-static char *gExecName = NULL;
-
-static void print_error(uint32_t);
-static void *safe_malloc(size_t);
-static void *safe_calloc(size_t, size_t);
-static char *safe_strdup(const char *s1);
-static void safe_snprintf(char *s, size_t n,
-    const char *format, ...);
-static void safe_fclose(FILE *stream);
-static void new_ae(aelist_t *ael, const char *arg);
-static aelist_t *new_ael(list_type_t type);
-static config_file_t *new_config_file();
-static void new_section(config_file_t *p_config_file, aelist_t *p_list,
-	const char *section_id);
-static void destroy_config(config_file_t *p_config_file);
-static config_file_t *parse_file(const char *pfile);
-static char **aeltoargv(aelist_t *ael, int *ael_num);
-static boolean_t fprint_config_file(config_file_t *p_config_file,
-	const char *file_name);
-static char *append_pa(const char *arg);
-static section_t *find_section(config_file_t *p_config_file,
-	const char *section_id);
-static ae_t *find_ae(aelist_t *plist, const char *arg);
-static void update_aelist(aelist_t *plist, const char *arg);
-static const char *get_value(const char *arg);
-static char *find_active_profile(int);
-static const char *essid_of_profile(const char *profile);
-static boolean_t search_interface(char *interface);
-static int open_dev(char *devname);
-static boolean_t call_ioctl(int, int, uint32_t, uint32_t);
-static boolean_t del_prefer(config_file_t *p_config_file, const char *prefer,
-    boolean_t rflag);
-static boolean_t del_section(config_file_t *p_config_file, char *section_id);
-static boolean_t set_prefer(config_file_t *p_config_file, const char *prefer,
-	int rank);
-static void add_to_history(config_file_t *p_config_file,
-    int argc, char **argv);
-static boolean_t check_authority(wifi_auth_t type);
-static void heuristic_load(int fd, uint32_t ess_num, wl_ess_conf_t **);
-static char *select_profile(int fd, int readonly, int timeout);
-static char *construct_format(uint32_t nt);
-static void print_gbuf(config_item_t index);
-static boolean_t items_in_profile(aelist_t *, aelist_t *, int, char **);
-static char *get_commit_key(int, int, char **);
-static void print_wepkey_info(const char *id, const char *wepkeyn);
-static void  do_print_usage();
-static boolean_t do_print_support_params(int fd);
-static boolean_t do_autoconf(int fd, int argc, char **argv);
-static boolean_t do_startconf(int fd, int argc, char **argv);
-static boolean_t do_loadpf(int fd, int argc, char **argv);
-static boolean_t do_disconnect(int fd, int argc, char **argv);
-static boolean_t do_printpf(int fd, int argc, char **argv);
-static boolean_t do_restoredef(int fd, int argc, char **argv);
-static boolean_t do_history(int fd, int argc, char **argv);
-static boolean_t do_deletepf(int fd, int argc, char **argv);
-static boolean_t do_wepkey(int fd, int argc, char **argv);
-static boolean_t do_setprefer(int fd, int argc, char **arg);
-static boolean_t do_rmprefer(int fd, int argc, char **argv);
-static boolean_t do_lsprefer(int fd, int argc, char **argv);
-static boolean_t do_wlanlist(int fd, int argc, char **argv);
-static boolean_t do_showstatus(int fd, int argc, char **argv);
-static boolean_t do_getprofparam(int fd, int argc, char **argv);
-static boolean_t do_setprofparam(int fd, int argc, char **argv);
-static boolean_t do_setprofwepkey(int fd, int argc, char **argv);
-static boolean_t is_rates_support(int fd, int num, uint8_t *rates);
-static boolean_t do_set_bsstype(int fd, const char *arg);
-static boolean_t do_set_essid(int fd, const char *arg);
-static boolean_t do_set_powermode(int fd, const char *arg);
-static boolean_t do_set_rates(int fd, const char *arg);
-static boolean_t do_set_channel(int fd, const char *arg);
-static boolean_t do_set_createibss(int fd, const char *arg);
-static boolean_t do_set_radioon(int fd, const char *arg);
-static boolean_t do_set_wepkeyid(int fd, const char *arg);
-static boolean_t do_set_encryption(int fd, const char *arg);
-static boolean_t do_set_authmode(int fd, const char *arg);
-static boolean_t do_set_wepkey(int fd, const char *pbuf);
-static boolean_t do_get_createibss(int fd);
-static boolean_t do_get_bsstype(int fd);
-static boolean_t do_get_essid(int fd);
-static boolean_t do_get_bssid(int fd);
-static boolean_t do_get_radioon(int fd);
-static boolean_t do_get_signal(int fd);
-static boolean_t do_get_wepkeyid(int fd);
-static boolean_t do_get_encryption(int fd);
-static boolean_t do_get_authmode(int fd);
-static boolean_t do_get_powermode(int fd);
-static boolean_t do_get_rates(int fd);
-static boolean_t do_get_wlanlist(int fd);
-static boolean_t do_get_linkstatus(int fd);
-static boolean_t do_get_channel(int fd);
-static boolean_t do_get(int fd, int argc, char **argv);
-static boolean_t do_set(int fd, int argc, char **argv);
-static boolean_t do_createprofile(int fd, int argc, char **argv);
-static boolean_t value_is_valid(config_item_t item, const char *value);
-
-typedef struct cmd_ops {
-	char cmd[32];
-	boolean_t (*p_do_func)(int fd, int argc, char **argv);
-	boolean_t b_auth;
-	boolean_t b_fileonly; /* operation only on the config file */
-	boolean_t b_readonly; /* only read from the card or config file */
-} cmd_ops_t;
-static cmd_ops_t do_func[] = {
-	{
-		"autoconf",
-		do_autoconf,
-		B_TRUE,
-		B_FALSE,
-		B_FALSE
-	},
-	{
-		"startconf",
-		do_startconf,
-		B_TRUE,
-		B_FALSE,
-		B_TRUE
-	},
-	{
-		"connect",
-		do_loadpf,
-		B_TRUE,
-		B_FALSE,
-		B_FALSE
-	},
-	{
-		"disconnect",
-		do_disconnect,
-		B_TRUE,
-		B_FALSE,
-		B_FALSE
-	},
-	{
-		"showprofile",
-		do_printpf,
-		B_FALSE,
-		B_TRUE,
-		B_TRUE
-	},
-	{
-		"deleteprofile",
-		do_deletepf,
-		B_TRUE,
-		B_TRUE,
-		B_FALSE
-	},
-	{
-		"history",
-		do_history,
-		B_FALSE,
-		B_TRUE,
-		B_TRUE
-	},
-	{
-		"listprefer",
-		do_lsprefer,
-		B_FALSE,
-		B_TRUE,
-		B_TRUE
-	},
-	{
-		"removeprefer",
-		do_rmprefer,
-		B_TRUE,
-		B_TRUE,
-		B_FALSE
-	},
-	{
-		"setprefer",
-		do_setprefer,
-		B_TRUE,
-		B_TRUE,
-		B_FALSE
-	},
-	{
-		"setwepkey",
-		do_wepkey,
-		B_TRUE,
-		B_FALSE,
-		B_FALSE
-	},
-	{
-		"restoredef",
-		do_restoredef,
-		B_TRUE,
-		B_FALSE,
-		B_FALSE
-	},
-	{
-		"getparam",
-		do_get,
-		B_FALSE,
-		B_FALSE,
-		B_TRUE
-	},
-	{
-		"setparam",
-		do_set,
-		B_TRUE,
-		B_FALSE,
-		B_FALSE
-	},
-	{
-		"createprofile",
-		do_createprofile,
-		B_TRUE,
-		B_TRUE,
-		B_FALSE
-	},
-	{
-		"scan",
-		do_wlanlist,
-		B_FALSE,
-		B_FALSE,
-		B_FALSE
-	},
-	{
-		"showstatus",
-		do_showstatus,
-		B_FALSE,
-		B_FALSE,
-		B_TRUE
-	},
-	{
-		"setprofileparam",
-		do_setprofparam,
-		B_TRUE,
-		B_TRUE,
-		B_FALSE
-	},
-	{
-		"getprofileparam",
-		do_getprofparam,
-		B_FALSE,
-		B_TRUE,
-		B_TRUE
-	},
-	{
-		"setprofilewepkey",
-		do_setprofwepkey,
-		B_TRUE,
-		B_TRUE,
-		B_FALSE
-	}
-};
-
-
-typedef enum {RW, RO, WO} rw_property_t;
-typedef struct gs_ops {
-	config_item_t index;
-	char cmd[32];
-	boolean_t (*p_do_get_func)(int fd);
-	boolean_t (*p_do_set_func)(int fd, const char *arg);
-	rw_property_t rw;
-} gs_ops_t;
-static gs_ops_t do_gs_func[] = {
-	{LINKSTATUS, "linkstatus", NULL, NULL, RO},
-	{BSSID, "bssid", do_get_bssid, NULL, RO},
-	{ESSID, "essid", do_get_essid, do_set_essid, RW},
-	{BSSTYPE, "bsstype", do_get_bsstype, do_set_bsstype, RW},
-	{CREATEIBSS, "createibss", do_get_createibss, do_set_createibss, RW},
-	{CHANNEL, "channel", do_get_channel, do_set_channel, RW},
-	{RATES, "rates", do_get_rates, do_set_rates, RW},
-	{POWERMODE, "powermode", do_get_powermode, do_set_powermode, RW},
-	{AUTHMODE, "authmode", do_get_authmode, do_set_authmode, RW},
-	{ENCRYPTION, "encryption", do_get_encryption, do_set_encryption, RW},
-	{WEPKEYID, "wepkeyindex", do_get_wepkeyid, do_set_wepkeyid, RW},
-	{WEPKEY, "wepkey|1-4", NULL, do_set_wepkey, WO},
-	{SIGNAL, "signal", do_get_signal, NULL, RO},
-	{RADIOON, "radio",	do_get_radioon, do_set_radioon, RW},
-};
-
-#define	N_FUNC		sizeof (do_func) / sizeof (cmd_ops_t)
-#define	N_GS_FUNC 	sizeof (do_gs_func) / sizeof (gs_ops_t)
-
-/*
- * valid rate value
- */
-typedef	struct wifi_rates_tab {
-	char *rates_s;
-	uint8_t rates_i;
-	uint8_t rates_reserve0;
-	uint8_t rates_reserve1;
-	uint8_t rates_reserve2;
-} wifi_rates_tab_t;
-
-/*
- * the rates value is in increments of 500kb/s.
- * according to the 802.11 a/b/g specs(IEEE):
- * 802.11b(IEEE Std 802.11b-1999) page35, rates should be:
- *	X02, X04, X0b, X16
- * 802.11a(IEEE Std 802.11a-1999) page47, rates should be:
- *	6,9,12,18,24,36,48,54 Mb/s
- * 802.11g(IEEE Std 802.11g-2003) page44, rates should be:
- *	1,2,5.5,11,6,9,12,18,22,24,33,36,48,54 Mb/s
- */
-#define	WIFI_RATES_NUM	14
-static wifi_rates_tab_t wifi_rates_s[WIFI_RATES_NUM] = {
-	{"1",	WL_RATE_1M,	0,	0,	0},
-	{"2",	WL_RATE_2M,	0,	0,	0},
-	{"5.5",	WL_RATE_5_5M,	0,	0,	0},
-	{"6",	WL_RATE_6M,	0,	0,	0},
-	{"9",	WL_RATE_9M,	0,	0,	0},
-	{"11",	WL_RATE_11M,	0,	0,	0},
-	{"12",	WL_RATE_12M,	0,	0,	0},
-	{"18",	WL_RATE_18M,	0,	0,	0},
-	{"22",	WL_RATE_22M,	0,	0,	0},
-	{"24",	WL_RATE_24M,	0,	0,	0},
-	{"33",	WL_RATE_33M,	0,	0,	0},
-	{"36",	WL_RATE_36M,	0,	0,	0},
-	{"48",	WL_RATE_48M,	0,	0,	0},
-	{"54",	WL_RATE_54M,	0,	0,	0}
-};
-/* print the error message on why set or get ioctl command failed. */
-static void
-print_error(uint32_t errorno)
-{
-	char *buf;
-
-	switch (errorno) {
-	case WL_SUCCESS:
-		buf = gettext("command succeeded");
-		break;
-	case WL_NOTSUPPORTED:
-	case WL_LACK_FEATURE:
-	case WL_HW_ERROR:
-	case WL_ACCESS_DENIED:
-		buf = strerror(errorno);
-		break;
-	case WL_READONLY:
-		buf = gettext("parameter read-only");
-		break;
-	case WL_WRITEONLY:
-		buf = gettext("parameter write-only");
-		break;
-	case WL_NOAP:
-		buf = gettext("no access point available");
-		break;
-	default:
-		buf = gettext("unknown error");
-		break;
-	}
-	(void) fprintf(stderr, "%s\n", buf);
-}
-
-static void *
-safe_malloc(size_t size)
-{
-	void *buf;
-
-	buf = malloc(size);
-	if (buf == NULL) {
-		(void) fprintf(stderr, gettext("%s: malloc: %s\n"),
-		    gExecName, strerror(errno));
-		exit(WIFI_FATAL_ERR);
-	}
-	return (buf);
-}
-
-static void *
-safe_calloc(size_t nelem, size_t elsize)
-{
-	void *buf;
-
-	buf = calloc(nelem, elsize);
-	if (buf == NULL) {
-		(void) fprintf(stderr, gettext("%s: calloc: %s\n"),
-		    gExecName, strerror(errno));
-		exit(WIFI_FATAL_ERR);
-	}
-	return (buf);
-}
-
-static char *
-safe_strdup(const char *s1)
-{
-	char *p;
-
-	p = strdup(s1);
-	if (p == NULL) {
-		(void) fprintf(stderr, gettext("%s: strdup: %s\n"),
-		    gExecName, strerror(errno));
-		exit(WIFI_FATAL_ERR);
-	}
-	return (p);
-}
-
-static void
-safe_snprintf(char *s, size_t n,  const  char  *format, ...)
-{
-	int len;
-	va_list ap;
-	va_start(ap, format);
-
-	len = vsnprintf(s, n, format, ap);
-	if ((len <= 0) || (len > n - 1)) {
-		(void) fprintf(stderr,
-		    gettext("%s: snprintf: %s\n"),
-		    gExecName, strerror(errno));
-		exit(WIFI_FATAL_ERR);
-	}
-	va_end(ap);
-}
-
-static void
-safe_fclose(FILE *stream)
-{
-	int err;
-
-	err = fclose(stream);
-	if (err == EOF) {
-		(void) fprintf(stderr, gettext("%s: fclose: %s\n"),
-		    gExecName, strerror(errno));
-		exit(WIFI_FATAL_ERR);
-	}
-}
-/*
- * new_ae: Add an element with content pointed by arg to the list *ael.
- */
-static void
-new_ae(aelist_t *ael, const char *arg)
-{
-	ae_t *pae = NULL;
-
-	PRTDBG(("new_ae(0x%x, \"%s\")\n", ael, arg));
-	assert((ael != NULL) && (arg != NULL));
-
-	pae = safe_calloc(sizeof (*pae), 1);
-	pae->ae_arg = safe_strdup(arg);
-	pae->ae_next = NULL;
-
-	if (ael->ael_tail == NULL) {
-		ael->ael_head = pae;
-	} else {
-		ael->ael_tail->ae_next = pae;
-	}
-	ael->ael_tail = pae;
-	ael->ael_argc++;
-}
-/*
- * new_ael:  Create a new aelist with list_type "type"
- * and return the list pointer.
- */
-static aelist_t *
-new_ael(list_type_t type)
-{
-	aelist_t *plist;
-
-	plist = safe_calloc(sizeof (*plist), 1);
-	plist->type = type;
-	plist->ael_argc = 0;
-	plist->ael_head = plist->ael_tail = NULL;
-
-	PRTDBG(("new_ael(%d) = 0x%x\n", type, plist));
-	return (plist);
-}
-
-/*
- * new_config_file: Creates a new config_file_t struct which is counterpart of
- * of the configration file, and return the pointer.
- */
-static config_file_t *
-new_config_file()
-{
-	config_file_t *p_config_file;
-
-	p_config_file = safe_calloc(sizeof (config_file_t), 1);
-	p_config_file->section_argc = 0;
-	p_config_file->section_head = p_config_file->section_tail = NULL;
-
-	PRTDBG(("new_config_file() = 0x%x\n", p_config_file));
-	return (p_config_file);
-}
-
-/*
- * new_section: Add a list pointed by "p_list", with identity "section_id" to
- * the config_file_t struct pointed by "p_config_file"
- */
-static void
-new_section(config_file_t *p_config_file, aelist_t *p_list,
-    const char *section_id)
-{
-	section_t *p_section = NULL;
-
-	PRTDBG(("new_section(0x%x, 0x%x, \"%s\")\n", p_config_file, p_list,
-	    section_id));
-	assert((p_config_file != NULL) && (p_list != NULL) &&
-	    (section_id != NULL));
-
-	p_section = safe_calloc(sizeof (*p_section), 1);
-	p_section->list = p_list;
-	p_section->section_next = NULL;
-	p_section->section_id = safe_strdup(section_id);
-
-	if (p_config_file->section_tail == NULL) {
-		p_config_file->section_head = p_section;
-	} else {
-		p_config_file->section_tail->section_next = p_section;
-	}
-	p_config_file->section_tail = p_section;
-	p_config_file->section_argc++;
-}
-
-/*
- * destroy_config:Destroy the config_file struct
- */
-static void
-destroy_config(config_file_t *p_config_file)
-{
-	section_t *p_section = NULL;
-	aelist_t *p_list = NULL;
-	ae_t *pae = NULL;
-
-	PRTDBG(("destory_config(0x%x)\n", p_config_file));
-	assert(p_config_file != NULL);
-
-	p_section = p_config_file->section_head;
-	while (p_section != NULL) {
-		p_list = p_section->list;
-		if (p_list != NULL) {
-			pae = p_list->ael_head;
-			while (pae != NULL) {
-				if (pae->ae_arg != NULL)
-					free(pae->ae_arg);
-				pae->ae_arg = NULL;
-				pae = pae->ae_next;
-				free(p_list->ael_head);
-				p_list->ael_head = pae;
-			}
-			free(p_list);
-			p_list = NULL;
-		}
-		if (p_section->section_id != NULL)
-			free(p_section->section_id);
-		p_section->section_id = NULL;
-		p_section = p_section->section_next;
-		free(p_config_file->section_head);
-		p_config_file->section_head = p_section;
-	}
-	free(p_config_file);
-	p_config_file = NULL;
-}
-
-/*
- * parse_file: Parse each section of the configration file
- * and construct the config_file_t structure.
- * Example:
- * A config file has contents below:
- *
- * {preferrence}
- * essid=ap7-3
- * essid=linksys
- *
- * {history}
- * essid=ap7-3
- * essid=ap7-2
- *
- * [ap7-3]
- * essid=ap7-3
- * wepkeyid=3
- * channel=11
- * rates=1,2
- *
- * [linksys]
- * essid=linksys
- * createibss=BSS
- * authmode=OPENSYSTEM
- * wepkeyid=1
- *
- * then its config_file_t structure will be:
- *
- *                        config_file_t
- *                       |~~~~~~~~~~~~~~~~~~~~~~~~~~|
- *                       |      section_argc=5      |
- *                       |~~~~~~~~~~~~T~~~~~~~~~~~~~|
- *                      /|   *head    |    *tail    |\
- *                     / ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ \
- *                    /                                \
- *                   /	                                \
- *                  /                                    \
- *                 /                                      \
- *                /                                        \
- *  section_t    V           section_t                      V section_t
- * |~~~~~~~~~~~~~~~|~~|     |~~~~~~~~~~~~~~~|~~|      |~~~~~~~~~~~~~~|~~|
- * |"{preferrence}"|  |     |  "{history}"  |  |      | "[linksys]"  |  |
- * |~~~~~~~~~~~~~~~| -+---->|~~~~~~~~~~~~~~~| -+->..->|~~~~~~~~~~~~~~| -+->NULL
- * |    *list      |  |     |    *list      |  |      |    *list     |  |
- * ~~T~~~~~~~~~~~~~~~~~     ~~~T~~~~~~~~~~~~~~~~      ~~~T~~~~~~~~~~~~~~~
- *   |                         |                         |
- *   |                         |                         |
- *   V aelist_t                V aelist_t                V aelist_t
- * |~~~~~~~~~~~~~|          |~~~~~~~~~~~~~|           |~~~~~~~~~~~~~|
- * |  argc=2     |          |  argc=3     |           |  argc=4     |
- * |~~~~~~~~~~~~~|          |~~~~~~~~~~~~~|           |~~~~~~~~~~~~~|
- * |PREFFERRENCE |          |   HISTORY   |           |   PROFILE   |
- * |~~~~~~T~~~~~~|          |~~~~~~T~~~~~~|           |~~~~~~T~~~~~~|
- * |*head |*tail |\         |*head |*tail |\          |*head |*tail |
- * ~~T~~~~~~~~~~~~ \        ~~T~~~~~~~~~~~~ \        /~~~~~~~~~~~~~~~\
- *   |              \         V              V      /                 \
- *   |               \        ...            ...   /                   \
- *   V ae_t           V  ae_t             ae_t    V           ae_t      V
- * |~~~~~~~~~T~~|  |~~~~~~~~~T~~|       |~~~~~~~~~T~~|      |~~~~~~~~~T~~|
- * |"essid=  | -+->|"essid=  | -+->NULL |"essid=  | -+->..->|"wepkeyid| -+->NULL
- * | ap7-3"  |  |  | linksys"|  |       | linksys"|  |      | =1"     |  |
- * ~~~~~~~~~~~~~~  ~~~~~~~~~~~~~~       ~~~~~~~~~~~~~~      ~~~~~~~~~~~~~~
- *
- */
-
-static config_file_t *
-parse_file(const char *pfile)
-{
-	FILE *file = NULL;
-	int fd = 0;
-	char buf_line[256];
-	config_file_t *p_config_file;
-	list_type_t cur_list = OTHER;
-	aelist_t *prefer_list = NULL;
-	aelist_t *history_list = NULL;
-	aelist_t *profile_list = NULL;
-	aelist_t *activep_list = NULL;
-
-	assert(pfile != NULL);
-	/*
-	 * The files /etc/inet/wifi and /etc/inet/secret/wifiwepkey should
-	 * be opened with "r" attribute. If these two files do not exist,
-	 * create them here.
-	 */
-	file = fopen(pfile, "r");
-
-	if (file == NULL) {
-		fd = open(pfile, O_CREAT|O_EXCL|O_RDWR, 0600);
-		if (fd < 0) {
-			(void) fprintf(stderr, gettext("%s: failed to open %s"
-			    "\n"), gExecName, pfile);
-			goto error1;
-		}
-		file = fdopen(fd, "w");
-		(void) chmod(pfile, S_IRUSR);
-	}
-
-	p_config_file = new_config_file();
-
-	while (fgets(buf_line, sizeof (buf_line), file) != NULL) {
-		if ((buf_line[0] == '\n') || (buf_line[0] == ' '))
-			continue;
-		/* replace the old '\n' to '\0' */
-		buf_line[strlen(buf_line) - 1] = '\0';
-		if (strstr(buf_line, WIFI_PREFER) == buf_line) {
-			if (prefer_list == NULL) {
-				cur_list = PREFERENCE;
-				prefer_list = new_ael(PREFERENCE);
-				new_section(p_config_file, prefer_list,
-				    WIFI_PREFER);
-			} else {
-				(void) fprintf(stderr, gettext("%s: "
-				    "%s : duplicated %s section\n"),
-				    gExecName, pfile, WIFI_PREFER);
-				goto error;
-			}
-		} else if (strstr(buf_line, WIFI_HISTORY) == buf_line) {
-			if (history_list == NULL) {
-				cur_list = HISTORY;
-				history_list = new_ael(HISTORY);
-				new_section(p_config_file, history_list,
-				    WIFI_HISTORY);
-			} else {
-				(void) fprintf(stderr, gettext("%s: "
-				    "%s : duplicated %s section\n"),
-				    gExecName, pfile, WIFI_HISTORY);
-				goto error;
-			}
-		} else if (strstr(buf_line, WIFI_ACTIVEP) == buf_line) {
-			if (activep_list == NULL) {
-				cur_list = ACTIVEP;
-				activep_list = new_ael(ACTIVEP);
-				new_section(p_config_file, activep_list,
-				    WIFI_ACTIVEP);
-			} else {
-				(void) fprintf(stderr, gettext("%s: "
-				    "%s : duplicated %s section\n"),
-				    gExecName, pfile, WIFI_ACTIVEP);
-				goto error;
-			}
-		} else if ((strchr(buf_line, '[') == buf_line) &&
-		    (buf_line[strlen(buf_line) - 1] == ']')) {
-			cur_list = PROFILE;
-			profile_list = new_ael(PROFILE);
-			new_section(p_config_file, profile_list,
-			    buf_line);
-		} else {
-			switch (cur_list) {
-			case PREFERENCE:
-				if (prefer_list->ael_argc <=
-				    MAX_PREFERENCE_NUM)
-					new_ae(prefer_list, buf_line);
-				break;
-			case HISTORY:
-				if (history_list->ael_argc <=
-				    MAX_HISTORY_NUM)
-					new_ae(history_list, buf_line);
-				break;
-			case ACTIVEP:
-				if ((activep_list->ael_argc <= 1) &&
-				    (strpbrk(buf_line, "=") != NULL))
-					new_ae(activep_list, buf_line);
-				break;
-			case PROFILE:
-				if (strpbrk(buf_line, "=") != NULL)
-					new_ae(profile_list, buf_line);
-				break;
-			default:
-				(void) fprintf(stderr,
-				    gettext("%s: %s: file format error\n"),
-				    gExecName, pfile);
-				goto error;
-			}
-		}
-	}
-	PRTDBG(("parse_file(\"%s\")=0x%x\n", pfile, p_config_file));
-	(void) fclose(file);
-	return (p_config_file);
-error:
-	destroy_config(p_config_file);
-	(void) fclose(file);
-error1:
-	return (NULL);
-}
-/*
- * construct an argument vector from an aelist
- */
-static char **
-aeltoargv(aelist_t *ael, int *ael_num)
-{
-	ae_t *ae = NULL;
-	char **argv = NULL;
-	int argc = 0;
-
-	PRTDBG(("aeltoargv(%x)\n", ael));
-	assert(ael != NULL);
-
-	argv = safe_calloc(sizeof (*argv), ael->ael_argc);
-
-	for (argc = 0, ae = ael->ael_head; ae; ae = ae->ae_next) {
-		/* skip bssid since it can not be set */
-		if (strncmp(ae->ae_arg, "bssid=", strlen("bssid=")) == 0)
-			continue;
-		argv[argc] = safe_strdup(ae->ae_arg);
-		argc++;
-		if (ae == ael->ael_tail)
-			break;
-	}
-
-	PRTDBG(("aeltoargv(0x%x) = 0x%x\n\n", ael, argv));
-	*ael_num = argc;
-	return (argv);
-}
-
-/*
- * archived contents into a file
- */
-static boolean_t
-fprint_config_file(config_file_t *p_config_file, const char *file_name)
-{
-	FILE *file = NULL;
-	int fd = 0;
-	int len;
-	section_t *p_section = NULL;
-	aelist_t *p_list = NULL;
-	ae_t *pae = NULL;
-	char temp_file[256];
-	struct stat buf;
-
-	PRTDBG(("fprint_config_file(0x%x, \"%s\")\n", p_config_file,
-	    file_name));
-	assert((p_config_file != NULL)&&(strcmp(file_name, "") != 0));
-
-	safe_snprintf(temp_file, sizeof (temp_file),
-	    "%s.tmp", file_name);
-	fd = open(temp_file, O_CREAT|O_WRONLY|O_TRUNC, 0600);
-	if (fd < 0) {
-		(void) fprintf(stderr, gettext("%s: failed to open %s\n"),
-		    gExecName, temp_file);
-		return (B_FALSE);
-	}
-	file = fdopen(fd, "w");
-
-	p_section = p_config_file->section_head;
-	while (p_section != NULL) {
-		p_list = p_section->list;
-		if (p_list != NULL) {
-			PRTDBG(("fprint_config_file: section_id=%s\n",
-			    p_section->section_id));
-			len = fprintf(file, "\n%s\n", p_section->section_id);
-			if (len < 0) {
-				(void) fprintf(stderr, gettext("%s: "
-				    "failed to update %s: %s\n"),
-				    gExecName, file_name, strerror(errno));
-				safe_fclose(file);
-				return (B_FALSE);
-			}
-			pae = p_list->ael_head;
-			while (pae != NULL) {
-				if (pae->ae_arg != NULL) {
-					len = fprintf(file, "%s\n",
-					    pae->ae_arg);
-					if (len < 0) {
-						(void) fprintf(stderr,
-						    gettext("%s: failed to "
-						    "update %s: %s\n"),
-						    gExecName, file_name,
-						    strerror(errno));
-						safe_fclose(file);
-						return (B_FALSE);
-					}
-				}
-				pae = pae->ae_next;
-			}
-		}
-		p_section = p_section->section_next;
-	}
-	safe_fclose(file);
-	/*
-	 * The attribute of the file /etc/inet/wifi and
-	 * /etc/inet/security/wifiwepkey should be retained.
-	 * if those file do not exist, set default file mode.
-	 */
-	if (stat(file_name, &buf) != 0) {
-		if (errno == ENOENT) {
-			buf.st_mode = 0600;
-		} else {
-			(void) fprintf(stderr, gettext("%s: failed to get "
-			    "file %s stat: %s\n"),
-			    gExecName, file_name, strerror(errno));
-			return (B_FALSE);
-		}
-	}
-	if (rename(temp_file, file_name) != 0) {
-		(void) fprintf(stderr, gettext("%s: failed to update %s: %s"
-		    "\n"), gExecName, file_name, strerror(errno));
-		return (B_FALSE);
-	}
-	(void) chmod(file_name, buf.st_mode);
-	return (B_TRUE);
-}
-/*
- * append_pa: Each section holds a section_id which identifies a section
- * a profile uses its essid appending "[]" to denote its section_id.
- * note: new memory is allocated, remember to free.
- */
-static char *
-append_pa(const char *arg)
-{
-	char *pbuf = NULL;
-	int len;
-
-	assert(arg != NULL);
-
-	len = strlen(arg) + 3;
-	pbuf = safe_malloc(len);
-	safe_snprintf(pbuf, len, "[%s]", arg);
-	PRTDBG(("append_pa(\"%s\") = \"%s\"\n", arg, pbuf));
-	return (pbuf);
-}
-/*
- * find a section by section_id from p_config_file,
- * return the section pointer.
- */
-static section_t *
-find_section(config_file_t *p_config_file, const char *section_id)
-{
-	section_t *p_section = NULL;
-
-	PRTDBG(("find_section(0x%x, \"%s\")\n", p_config_file, section_id));
-	assert((section_id != NULL)&&(p_config_file != NULL));
-
-	p_section = p_config_file->section_head;
-
-	while (p_section != NULL) {
-		if ((p_section->section_id != NULL) &&
-		    (strcmp(p_section->section_id, section_id) == 0))
-			return (p_section);
-		p_section = p_section->section_next;
-	}
-	return (NULL);
-}
-
-/*
- * get_value: Get rid of "parameter=" from a "parameter=value", for example:
- * when we read an line from file, we gets "essid=ap7-2", this function
- * returns the pointer to string "ap7-2";
- */
-
-static const char *
-get_value(const char *arg)
-{
-	char *p;
-	assert(arg != NULL);
-
-	p = strchr(arg, '=');
-	PRTDBG(("get_value(\"%s\") = \"%s\"\n", arg, p + 1));
-	if (p != NULL)
-		return (p + 1);
-	else
-		return (NULL);
-}
-
-/*
- * search /dev/wifi to see which interface is available
- */
-static boolean_t
-search_interface(char *interface)
-{
-	DIR *dirp;
-	struct dirent *dp;
-	char buf[256];
-	int fd;
-
-	PRTDBG(("search interface\n"));
-	assert(interface != NULL);
-
-	/*
-	 * Try to return the first found wifi interface.
-	 * If no wifi interface is available, return B_FALSE
-	 */
-
-	if ((dirp = opendir("/dev/wifi")) == NULL) {
-		PRTDBG(("failed to open '/dev/wifi'\n"));
-		return (B_FALSE);
-	}
-	while ((dp = readdir(dirp)) != NULL) {
-		if (strcmp(dp->d_name, ".") == 0 ||
-		    strcmp(dp->d_name, "..") == 0)
-			continue;
-		if (dp->d_name[strlen(dp->d_name) - 1] < '0' ||
-		    dp->d_name[strlen(dp->d_name) - 1] > '9')
-			continue;
-		safe_snprintf(buf, sizeof (buf), "%s%s",
-		    "/dev/wifi/", dp->d_name);
-		fd = open(buf, O_RDWR);
-		if (fd == -1) {
-			PRTDBG(("interface %s doesn't exist\n", dp->d_name));
-			continue;
-		} else {
-			PRTDBG(("interface %s is the first found interface\n",
-			    dp->d_name));
-			(void) strlcpy(interface, buf, LIFNAMSIZ);
-			(void) close(fd);
-			(void) closedir(dirp);
-			return (B_TRUE);
-		}
-	}
-
-	PRTDBG(("failed to find available wireless interface\n"));
-	(void) closedir(dirp);
-	return (B_FALSE);
-
-}
-/*
- * open_dev: Open the driver.
- * if the 'devname' has format like 'ath0', we should add the path to that
- * device(/dev/ath0) and open it; if the 'devname' has format like
- * '/dev/wifi/ath0', we open it directly.
- */
-static int
-open_dev(char *devname)
-{
-	int fd;
-	int len;
-	char *pbuf = NULL;
-
-	PRTDBG(("open_dev(\"%s\")\n", devname));
-	assert(devname != NULL);
-	/*
-	 * If the devname is got from the user input, we
-	 * add '/dev/' to that relative devname. If it
-	 * is got from the 'search interface', it is an
-	 * absolute path.
-	 */
-	if (strncmp(devname, "/dev/wifi/", strlen("/dev/wifi/")) == 0) {
-		pbuf = safe_strdup(devname);
-	} else {
-		len = strlen(devname) + strlen("/dev/") + 1;
-		pbuf = safe_malloc(len);
-		safe_snprintf(pbuf, len, "/dev/%s", devname);
-	}
-	fd = open(pbuf, O_RDWR);
-	free(pbuf);
-
-	if (fd == -1) {
-		(void) fprintf(stderr, gettext("%s: failed to open '%s': %s"
-		    "\n"), gExecName, devname, strerror(errno));
-		return (-1);
-	}
-	if (!isastream(fd)) {
-		(void) fprintf(stderr, gettext("%s: %s is "
-		    "not a stream device\n"),
-		    gExecName, devname);
-		(void) close(fd);
-		return (-1);
-	}
-	return (fd);
-}
-/*
- * call_ioctl: Fill strioctl structure and issue an ioctl system call
- */
-static boolean_t
-call_ioctl(int fd, int cmd, uint32_t params, uint32_t buf_len)
-{
-	struct strioctl stri;
-
-	PRTDBG(("call_ioctl_gs(%d, 0x%x, 0x%x, 0x%x)\n",
-	    fd, cmd, params, buf_len));
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		(void) memset(gbuf, 0, MAX_BUF_LEN);
-		stri.ic_len = MAX_BUF_LEN;
-		break;
-	case WLAN_SET_PARAM:
-		gbuf->wldp_length = buf_len + WIFI_BUF_OFFSET;
-		stri.ic_len = gbuf->wldp_length;
-		break;
-	case WLAN_COMMAND:
-		gbuf->wldp_length = sizeof (wldp_t);
-		stri.ic_len = gbuf->wldp_length;
-		break;
-	default:
-		(void) fprintf(stderr, gettext("%s: ioctl : "
-		    "unsupported ioctl command\n"), gExecName);
-		return (B_FALSE);
-	}
-	gbuf->wldp_type = NET_802_11;
-	gbuf->wldp_id = params;
-
-	stri.ic_cmd = cmd;
-	stri.ic_timout = 0;
-	stri.ic_dp = (char *)gbuf;
-
-	if (ioctl(fd, I_STR, &stri) == -1) {
-		gbuf->wldp_result = 0xffff;
-		return (B_FALSE);
-	}
-	if (cmd == WLAN_COMMAND) {
-		return (B_TRUE);
-	} else {
-		return (gbuf->wldp_result != WL_SUCCESS ?
-		    B_FALSE:B_TRUE);
-	}
-}
-
-/*
- * del_prefer: Delete an item from the {preferrence} list, the idea is
- * simply free the ae_t element, and set ae_arg to NULL, then when archive
- * the config_file_t struct to the file, it will be delete.
- * The last flag is used to identify whether this function is invoked due to
- * the 'removeprefer' subcommand or due to 'deleteprofile' subcommand.
- */
-static boolean_t
-del_prefer(config_file_t *p_config_file, const char *prefer, boolean_t rflag)
-{
-	section_t *p_section = NULL;
-	aelist_t *plist = NULL;
-	ae_t *pae = NULL;
-	int i = 0, position = 0;
-	int number;
-	ae_t *prm_ae = NULL;
-
-	PRTDBG(("del_prefer(0x%x, \"%s\")\n", p_config_file, prefer));
-	assert((prefer != NULL)&&(p_config_file != NULL));
-
-	p_section = find_section(p_config_file, WIFI_PREFER);
-	if (p_section != NULL)
-		plist = p_section->list;
-
-	if ((p_section == NULL) || (plist == NULL))
-		return (B_FALSE);
-
-	number = plist->ael_argc;
-	pae = plist->ael_head;
-	prm_ae = plist->ael_head;
-	while (pae != NULL) {
-		if (strcmp(prefer, pae->ae_arg) == 0) {
-			free(pae->ae_arg);
-			pae->ae_arg = NULL; /* mark */
-			if (!position) {
-				plist->ael_head = pae->ae_next;
-				if (pae->ae_next == NULL)
-					plist->ael_tail = NULL;
-			} else {
-				for (i = 0; i < position - 1; i++)
-					prm_ae = prm_ae->ae_next;
-				prm_ae->ae_next = pae->ae_next;
-				if (pae->ae_next == NULL)
-					plist->ael_tail = prm_ae;
-			}
-			free(pae);
-			pae = NULL;
-			plist->ael_argc--;
-			break;
-		}
-		position++;
-		pae = pae->ae_next;
-	}
-	if ((number == plist->ael_argc) && (rflag == B_TRUE)) {
-		(void) fprintf(stderr, gettext("%s: removeprefer : "
-		    "no such profile: '%s' in the preference list\n"),
-		    gExecName, prefer);
-		return (B_FALSE);
-	}
-	return (B_TRUE);
-}
-
-/*
- * del_section: Delete an section from p_config_file, the idea is
- * simply free the aelist_t struct and set it to NULL, when archiving
- * config_file_t struct to the file, we will find section list is NULL,
- * and will not write it to file, so it will be deleted.
- */
-static boolean_t
-del_section(config_file_t *p_config_file, char *section_id)
-{
-	section_t *p_section = NULL;
-	section_t *prm_section = NULL;
-	aelist_t *plist = NULL;
-	ae_t *pae = NULL;
-	int i = 0, position = 0;
-
-	PRTDBG(("del_section(0x%x, \"%s\")\n", p_config_file, section_id));
-	PRTDBG(("del_section: %d section(s) in config file\n",
-	    p_config_file->section_argc));
-	assert((section_id != NULL)&&(p_config_file != NULL));
-
-	if (find_section(p_config_file, section_id) == NULL) {
-		return (B_FALSE);
-	}
-	p_section = p_config_file->section_head;
-	prm_section = p_config_file->section_head;
-	while (p_section != NULL) {
-		if (p_section->section_id != NULL) {
-			if (strcmp(p_section->section_id, section_id) == 0) {
-				plist = p_section->list;
-				pae = plist->ael_head;
-				while (pae != NULL) {
-					free(pae->ae_arg);
-					pae->ae_arg = NULL;
-					pae = pae->ae_next;
-					free(plist->ael_head);
-					plist->ael_head = pae;
-				}
-				free(plist);
-				p_section->list = NULL;
-				free(p_section->section_id);
-				p_section->section_id = NULL;
-
-				if (!position) {
-					p_config_file->section_head =
-					    p_section->section_next;
-					if (p_section->section_next == NULL)
-						p_config_file->section_tail =
-						    NULL;
-				} else {
-					for (i = 0; i < position - 1; i++) {
-						prm_section =
-						    prm_section->section_next;
-					}
-					prm_section->section_next =
-					    p_section->section_next;
-					if (p_section->section_next == NULL)
-						p_config_file->section_tail =
-						    prm_section;
-				}
-				free(p_section);
-				p_config_file->section_argc--;
-				break;
-			}
-			position++;
-		}
-		p_section = p_section->section_next;
-	}
-	return (B_TRUE);
-}
-
-/*
- * set_prefer: Reorder the preferrence list.
- */
-static boolean_t
-set_prefer(config_file_t *p_config_file, const char *prefer, int rank)
-{
-	char *pbuf = NULL;
-	aelist_t *plist = NULL;
-	section_t *p_section = NULL;
-	ae_t *pae = NULL;
-	int i = 0, position = 0;
-	ae_t *pae_move = NULL;
-
-	assert(prefer != NULL);
-	PRTDBG(("set_prefer(0x%x, \"%s\", %d)\n", p_config_file, prefer, rank));
-
-	pbuf = append_pa(prefer);
-	if (find_section(p_config_file, pbuf) == NULL) {
-		(void) fprintf(stderr, gettext("%s: setprefer: "
-		    "no such profile: '%s'\n"),
-		    gExecName, prefer);
-		free(pbuf);
-		return (B_FALSE);
-	}
-	free(pbuf);
-
-	p_section = find_section(p_config_file, WIFI_PREFER);
-
-	if (p_section == NULL) {
-		plist = new_ael(PREFERENCE);
-		new_section(p_config_file, plist, WIFI_PREFER);
-		new_ae(plist, prefer);
-		return (B_TRUE);
-	} else {
-		plist = p_section->list;
-	}
-
-	pae = plist->ael_head;
-	pae_move = plist->ael_head;
-	while (pae != NULL) {
-		if (strcmp(prefer, pae->ae_arg) == 0) {
-			free(pae->ae_arg);
-			pae->ae_arg = NULL;
-			if (!position) {
-				plist->ael_head = pae->ae_next;
-				if (pae->ae_next == NULL)
-					plist->ael_tail = NULL;
-			} else {
-				for (i = 0; i < position - 1; i++)
-					pae_move = pae_move->ae_next;
-				pae_move->ae_next = pae->ae_next;
-				if (pae->ae_next == NULL)
-					plist->ael_tail = pae_move;
-			}
-			free(pae);
-			plist->ael_argc--;
-			break;
-		}
-		position++;
-		pae = pae->ae_next;
-	}
-	PRTDBG(("set_prefer: %d Profiles in prefer list\n", plist->ael_argc));
-	if (rank > plist->ael_argc) {
-		new_ae(plist, prefer);
-	} else if (rank <= 1) {
-		pae = safe_calloc(sizeof (ae_t), 1);
-		pae->ae_arg = safe_strdup(prefer);
-		pae->ae_next = plist->ael_head;
-		plist->ael_head = pae;
-		plist->ael_argc++;
-	} else {
-		pae_move = plist->ael_head;
-		for (i = 1; i < rank-1; i++) {
-			pae_move = pae_move->ae_next;
-		}
-		pae = safe_calloc(sizeof (ae_t), 1);
-		pae->ae_arg = safe_strdup(prefer);
-		pae->ae_next = pae_move->ae_next;
-		pae_move->ae_next = pae;
-		plist->ael_argc++;
-	}
-	/*
-	 * If number of prefer list items is larger than the MAX_PREFERENCE_NUM
-	 * delete those items whose No is larger than MAX_PREFERENCE_NUM.
-	 */
-	if (plist->ael_argc > MAX_PREFERENCE_NUM) {
-		pae = plist->ael_head;
-		while (pae->ae_next != plist->ael_tail)
-			pae = pae->ae_next;
-		free(plist->ael_tail->ae_arg);
-		plist->ael_tail->ae_arg = NULL;
-		free(plist->ael_tail);
-		plist->ael_tail = pae;
-		plist->ael_tail->ae_next = NULL;
-		plist->ael_argc--;
-	}
-	PRTDBG(("set_prefer: %d Profiles in prefer list\n", plist->ael_argc));
-	return (B_TRUE);
-}
-/*
- * add_to_history: Save the scanlist argv into history section
- */
-static void
-add_to_history(config_file_t *p_config_file, int argc, char **argv)
-{
-	int i = 0, j = 0, pos = 0;
-	aelist_t *plist = NULL;
-	section_t *p_section = NULL;
-	ae_t *pae = NULL;
-	ae_t *pae_m = NULL;
-	char item[256];
-	time_t cltime;
-
-	PRTDBG(("add_to_history(0x%x, %d, 0x%x)\n", p_config_file, argc, argv));
-	assert(p_config_file != NULL);
-
-	p_section = find_section(p_config_file, WIFI_HISTORY);
-
-	if (p_section == NULL) {
-		plist = new_ael(HISTORY);
-		new_section(p_config_file, plist, WIFI_HISTORY);
-	} else {
-		plist = p_section->list;
-	}
-
-	if (plist != NULL) {
-		for (i = 0; i < argc; i++) {
-			if (!strlen(argv[i]))
-				continue;
-			pos = 0;
-			pae = plist->ael_head;
-			pae_m = plist->ael_head;
-			/*
-			 * add time stamp to the history record
-			 */
-			cltime = time(&cltime);
-			(void) snprintf(item, sizeof (item), "%s%c%ld",
-			    argv[i], ',', cltime);
-			while (pae != NULL) {
-				if (strncmp(item, pae->ae_arg,
-				    strlen(argv[i])) == 0) {
-					free(pae->ae_arg);
-					pae->ae_arg = NULL;
-					if (!pos) {
-						plist->ael_head = pae->ae_next;
-						if (pae->ae_next == NULL)
-							plist->ael_tail = NULL;
-					} else {
-						for (j = 0; j < pos - 1; j++)
-							pae_m = pae_m->ae_next;
-						pae_m->ae_next = pae->ae_next;
-						if (pae->ae_next == NULL)
-							plist->ael_tail = pae_m;
-					}
-					free(pae);
-					plist->ael_argc--;
-					break;
-				}
-				pos++;
-				pae = pae->ae_next;
-			}
-			new_ae(plist, item);
-		}
-
-		if (plist->ael_argc > MAX_HISTORY_NUM) {
-			for (i = 0; i < plist->ael_argc - MAX_HISTORY_NUM;
-			    i++) {
-				pae = plist->ael_head;
-				free(pae->ae_arg);
-				plist->ael_head = pae->ae_next;
-				free(pae);
-			}
-			plist->ael_argc = MAX_HISTORY_NUM;
-		}
-	}
-}
-
-static void
-do_print_usage()
-{
-	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
-	    " autoconf [wait={n|forever}]\n"), gExecName);
-	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
-	    " connect profile [wait={n|forever}]\n"), gExecName);
-	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
-	    " connect essid [wait={n|forever}]\n"), gExecName);
-	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
-	    " disconnect\n"), gExecName);
-	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
-	    " getparam [parameter [...]]\n"), gExecName);
-	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
-	    " setparam [parameter=value [...]]\n"), gExecName);
-	(void) fprintf(stderr, gettext(
-	    "\tparameters:\n"
-	    "\t\tbssid\t\t - read only: 6 byte mac address of "
-	    "base station\n"
-	    "\t\tessid\t\t - name of the network, a string of up "
-	    "to 32 chars\n"
-	    "\t\tbsstype\t\t - bss(ap, infrastructure), ibss(ad-hoc)"
-	    " or auto\n"
-	    "\t\tcreateibss\t - flag to identify whether a ibss is to be\n"
-	    "\t\t\t\t   created when the network to connect is\n"
-	    "\t\t\t\t   not available, yes or no\n"
-	    "\t\tchannel\t\t - channel(used only when creating an ibss)\n"
-	    "\t\t\t\t   valid value:\n"
-	    "\t\t\t\t\t 802.11a: 0-99\n"
-	    "\t\t\t\t\t 802.11b: 1-14\n"
-	    "\t\t\t\t\t 802.11g: 1-14\n"
-	    "\t\trates\t\t - set of rates, seperated by ',' valid rates:\n"
-	    "\t\t\t\t   1,2,5.5,6,9,11,12,18,22,24,33,36,48 and 54\n"
-	    "\t\tpowermode\t - off, mps or fast\n"
-	    "\t\tauthmode\t - opensystem or shared_key\n"
-	    "\t\tencryption\t - none or wep\n"
-	    "\t\twepkey|1-4\t - write only:\n"
-	    "\t\t\t\t   5 chars or 10 hex digits for 40bit wepkey;\n"
-	    "\t\t\t\t   13 chars or 26 hex digits for 128bit wepkey\n"
-	    "\t\twepkeyindex\t - an integer within the range 1-4\n"
-	    "\t\tsignal\t\t - read only: signal strength from 0 to 15\n"
-	    "\t\tradio\t\t - on or off\n"));
-	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
-	    " restoredef\n"), gExecName);
-	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
-	    " scan\n"), gExecName);
-	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
-	    " showstatus\n"), gExecName);
-	(void) fprintf(stderr, gettext("\t%s [-R root_path][-i interface]"
-	    " setwepkey 1|2|3|4\n"), gExecName);
-
-	(void) fprintf(stderr, "\n");
-
-	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
-	    " createprofile profile parameter=value [...]\n"), gExecName);
-	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
-	    " deleteprofile profile1 [profile2 [...]]\n"), gExecName);
-	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
-	    " showprofile profile1 [profile2 [...]]\n"), gExecName);
-	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
-	    " setprofilewepkey profile 1|2|3|4\n"), gExecName);
-	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
-	    " getprofileparam profile [parameter [...]]\n"), gExecName);
-	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
-	    " setprofileparam profile [parameter=value [...]]\n"), gExecName);
-
-	(void) fprintf(stderr, "\n");
-
-	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
-	    " history\n"), gExecName);
-	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
-	    " listprefer\n"), gExecName);
-	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
-	    " removeprefer profile\n"), gExecName);
-	(void) fprintf(stderr, gettext("\t%s [-R root_path]"
-	    " setprefer profile [n]\n"), gExecName);
-}
-
-/*
- * do_print_support_params: Query interface which cmd is supported
- */
-static boolean_t
-do_print_support_params(int fd)
-{
-	int i = 0, n = 0;
-
-	PRTDBG(("do_print_support_params(\"%d\")\n", fd));
-	assert(fd != -1);
-
-	(void) printf(gettext("\t  parameter\tproperty\n"));
-	for (i = 0; i < N_GS_FUNC; i++) {
-		gbuf->wldp_result = WL_LACK_FEATURE;
-		if ((do_gs_func[i].p_do_get_func != NULL) &&
-		    (do_gs_func[i].p_do_get_func(fd) != B_TRUE)) {
-				continue;
-		}
-		if (gbuf->wldp_result == WL_SUCCESS) {
-			(void) printf("\t%11s", do_gs_func[i].cmd);
-			if (do_gs_func[i].rw == RO)
-				(void) printf(gettext("\tread only\n"));
-			else
-				(void) printf(gettext("\tread/write\n"));
-			n++;
-		}
-	}
-
-	return (n ? B_TRUE : B_FALSE);
-}
-
-/*
- * check_authority: Check if command is permitted.
- */
-static boolean_t
-check_authority(wifi_auth_t type)
-{
-	struct passwd *pw = NULL;
-
-	PRTDBG(("check_authority()\n"));
-
-	pw = getpwuid(getuid());
-	if (pw == NULL)
-		return (B_FALSE);
-	if (chkauthattr(p_auth_string[type], pw->pw_name) == 0) {
-		if (type == AUTH_WEP)
-			(void) fprintf(stderr, gettext("%s: "
-			    "privilege '%s' is required for setting "
-			    "wepkey.\n"), gExecName, WIFI_WEP_AUTH);
-		else
-			(void) fprintf(stderr, gettext("%s: "
-			    "privilege '%s' is required.\n"),
-			    gExecName, WIFI_CONFIG_AUTH);
-		return (B_FALSE);
-	} else {
-		return (B_TRUE);
-	}
-}
-
-/*
- * construct the 'history' and 'scan' output format
- * memory allocated. need to free after the function is invoked.
- */
-static char *
-construct_format(uint32_t nt)
-{
-	char *format;
-	int len = 0, i;
-
-#define	FORMAT_LEN 256
-	assert((nt >= 1) && (nt <= 4));
-	format = safe_malloc(FORMAT_LEN);
-
-	for (i = 0; i < nt; i++)
-		len += snprintf(format + len, FORMAT_LEN - len, "\t");
-	if ((len <= 0) || (len > FORMAT_LEN - 1)) {
-		return ("\t\t\t\t");
-	}
-	return (format);
-}
-
-/*
- * find the essid of the named profile.
- * gp_config_file is golable, so the return is gloable too.
- */
-static const char *
-essid_of_profile(const char *profile)
-{
-	section_t *p_section = NULL;
-	aelist_t *plist = NULL;
-	ae_t *pae = NULL;
-	char *pbuf;
-
-	PRTDBG(("essid_of_profile: profile = %s\n", profile));
-	pbuf = append_pa(profile);
-	p_section = find_section(gp_config_file, pbuf);
-	free(pbuf);
-
-	if (p_section == NULL) {
-		return (NULL);
-	} else {
-		plist = p_section->list;
-	}
-	pae = plist->ael_head;
-	while (pae != NULL) {
-		if (strncmp(pae->ae_arg, "essid=", strlen("essid=")) == 0) {
-			PRTDBG(("essid_of_profile: essid = %s\n",
-			    pae->ae_arg));
-			return (get_value(pae->ae_arg));
-		}
-		pae = pae->ae_next;
-	}
-	return (NULL);
-}
-
-/*
- * If we don't know which profile is our favorate in 'autoconf',
- * we select the wifi network based on the following heuristic
- * 1. the network without wep.
- * 2. the network with the strongst signal.
- * 3. the network with the faster speed(not implemented since signal affects
- * the speed in some degree).
- */
-static void
-heuristic_load(int fd, uint32_t ess_num, wl_ess_conf_t **p_ess_conf)
-{
-	int i = 0;
-	char *flag = NULL;
-	int have_nowep_wlan = 0;
-	wl_rssi_t maxsignal = 0;
-	char essid[34];
-	int timeout = LOADPROFILE_TIMEOUT;
-
-	PRTDBG(("heuristic_load: enter\n"));
-	(void) call_ioctl(fd, WLAN_COMMAND, WL_LOAD_DEFAULTS, 0);
-	flag = calloc(sizeof (char), ess_num);
-	for (i = 0; i < ess_num; i++) { /* extract none-wep network */
-		if (p_ess_conf[i]->wl_ess_conf_wepenabled == B_FALSE) {
-			flag[i] = 1;
-			have_nowep_wlan = 1;
-		}
-	}
-	/*
-	 * if all the wlans are weped, we select the one with strongest signal
-	 * in all of them, otherwise we just select in the none weped ones.
-	 */
-	if (!have_nowep_wlan)
-		(void) memset(flag, 1, ess_num);
-	for (i = 0; i < ess_num; i++) { /* extract the strongest signal ones */
-		if (flag[i] == 1) {
-			if (p_ess_conf[i]->wl_ess_conf_sl > maxsignal) {
-				maxsignal = p_ess_conf[i]->wl_ess_conf_sl;
-				(void) memset(flag, 0, i);
-			} else if (p_ess_conf[i]->wl_ess_conf_sl == maxsignal)
-				continue;
-			else
-				flag[i] = 0;
-		}
-	}
-	for (i = 0; i < ess_num; i++) {
-		if (flag[i] == 1)
-			break;
-	}
-	free(flag);
-	PRTDBG(("heuristic_load: %s is selected\n",
-	    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid));
-	/* select one in all the networks which meet the preceding stardands */
-	if (i == ess_num)
-		(void) do_set_essid(fd, "");
-	else
-		(void) do_set_essid(fd,
-		    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid);
-
-	if ((ess_num == 0) || (do_get_essid(fd) == B_FALSE)) {
-		(void) fprintf(stderr, gettext("%s: autoconf:"
-		    " failed to connect to any essid\n"),
-		    gExecName);
-		exit(WIFI_MINOR_ERR);
-	}
-	(void) strlcpy(essid, ((wl_essid_t *)(gbuf->wldp_buf))->wl_essid_essid,
-	    sizeof (essid));
-	(void) printf(gettext("%s: autoconf: essid '%s' is selected%s\n"),
-	    gExecName, essid,
-	    have_nowep_wlan ? "" : ": this is a WEPed "
-	    "access point");
-
-	if (!have_nowep_wlan)
-		exit(WIFI_FATAL_ERR);
-
-	while (timeout > 0) {
-		if ((do_get_linkstatus(fd) == B_TRUE) &&
-		    (*(wl_linkstatus_t *)(gbuf->wldp_buf) == WL_CONNECTED)) {
-			(void) printf(gettext("%s: connecting to "
-			    "essid '%s'\n"), gExecName, essid);
-			return;
-		}
-		(void) sleep(1);
-		timeout--;
-	}
-	(void) fprintf(stderr, gettext("%s: failed to connect to "
-	    "essid '%s'\n"), gExecName, essid);
-	exit(WIFI_FATAL_ERR);
-}
-
-/*
- * Called in autoconf and startconf to find which 'profile' is selected.
- * The process is: check profile names in the prefer list item by item,
- * if the essid of the profile is in the scan list, then it is the wanted.
- * readonly: 1 for startconf
- *           0 for autoconf
- * for autoconf, the scan result will be recorded in the history list.
- */
-static char *
-select_profile(int fd, int readonly, int timeout)
-{
-	uint32_t ess_num = 0;
-	int nprefer = 1;
-	char **ess_argv;
-	char **hisess_argv;
-	wl_ess_conf_t **p_ess_conf;
-	section_t *p_section = NULL;
-	aelist_t *plist = NULL;
-	ae_t *pae = NULL;
-	int i;
-	const char *parg;
-	char *selected = NULL;
-	boolean_t flag = B_FALSE;
-
-	if ((call_ioctl(fd, WLAN_COMMAND, WL_SCAN, 0) == B_FALSE) ||
-	    (do_get_wlanlist(fd) == B_FALSE)) {
-		(void) fprintf(stderr, gettext("%s: "
-		    "autoconf : failed to scan\n"), gExecName);
-		exit(WIFI_FATAL_ERR);
-	}
-	ess_num = ((wl_ess_list_t *)(gbuf->wldp_buf))->wl_ess_list_num;
-	ess_argv = safe_calloc(sizeof (char *), ess_num);
-	hisess_argv = safe_calloc(sizeof (char *), ess_num);
-	p_ess_conf = safe_calloc(sizeof (wl_ess_list_t *), ess_num);
-	for (i = 0; i < ess_num; i++) {
-		p_ess_conf[i] = ((wl_ess_list_t *)gbuf->wldp_buf)
-		    ->wl_ess_list_ess + i;
-		ess_argv[i] = safe_malloc(MAX_SCANBUF_LEN);
-		if (readonly == 0) {
-			hisess_argv[i] = safe_malloc(MAX_SCANBUF_LEN);
-			(void) snprintf(hisess_argv[i], MAX_SCANBUF_LEN,
-			    "%s%c%02x:%02x:%02x:%02x:%02x:%02x%c%s",
-			    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid,
-			    ',',
-			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[0]),
-			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[1]),
-			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[2]),
-			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[3]),
-			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[4]),
-			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[5]), ',',
-			    (p_ess_conf[i]->wl_ess_conf_wepenabled == B_TRUE
-			    ?  "wep":"none"));
-		}
-		(void) snprintf(ess_argv[i], MAX_SCANBUF_LEN, "%s",
-		    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid);
-	}
-	if (readonly == 0) {
-		add_to_history(gp_config_file, ess_num, hisess_argv);
-		for (i = 0; i < ess_num; i++) {
-			free(hisess_argv[i]);
-		}
-		free(hisess_argv);
-	}
-
-	p_section = find_section(gp_config_file, WIFI_PREFER);
-	if (p_section == NULL) {
-		if (ess_num > 0) {
-			heuristic_load(fd, ess_num, p_ess_conf);
-			exit(WIFI_EXIT_DEF);
-		}
-		goto done;
-	}
-	plist = p_section->list;
-	assert(plist != NULL);
-	if (plist != NULL) {
-		nprefer = plist->ael_argc;
-		if (nprefer == 0) {
-			if (ess_num > 0) {
-				heuristic_load(fd, ess_num, p_ess_conf);
-				exit(WIFI_EXIT_DEF);
-			}
-			goto done;
-		}
-	}
-	pae = plist->ael_head;
-	while ((pae != NULL) && (flag != B_TRUE)) {
-		parg = essid_of_profile(pae->ae_arg);
-		if (parg != NULL) {
-			for (i = 0; i < ess_num; i++) {
-				if (strcmp(parg, ess_argv[i]) == 0) {
-					selected = pae->ae_arg;
-					flag = B_TRUE;
-					break;
-				}
-			}
-		}
-		pae = pae->ae_next;
-	}
-done:
-	if ((selected == NULL) && (timeout == 0)) {
-		heuristic_load(fd, ess_num, p_ess_conf);
-	}
-	for (i = 0; i < ess_num; i++) {
-		free(ess_argv[i]);
-	}
-	free(ess_argv);
-	free(p_ess_conf);
-	return (selected);
-}
-
-static boolean_t
-is_waittime_valid(char *pbuf)
-{
-	int i;
-
-	i = atoi(pbuf);
-	if (i == -1)
-		return (B_TRUE);
-	for (i = 0; i < strlen(pbuf); i++) {
-		if (isdigit(pbuf[i]) == 0) {
-			return (B_FALSE);
-		}
-	}
-	return (B_TRUE);
-}
-/*
- * do_autoconf: First scan the wlanlist, and select one essid from scan result
- * by the order in {preferrence} list. If no match, then heuristic_load;
- */
-/*ARGSUSED*/
-static boolean_t
-do_autoconf(int fd, int argc, char **argv)
-{
-	const char *selected = NULL;
-	int timeout = LOADPROFILE_TIMEOUT, forever = 0, len = 0;
-	char *pequal, *param;
-	char **ld_argv = NULL;
-	boolean_t ret = B_TRUE;
-
-	PRTDBG(("do_autoconf(%d, 0x%x)\n", argc, argv));
-	assert(fd > 0);
-	if (argc > 0) {
-		param = safe_strdup(argv[0]);
-		pequal = strchr(param, '=');
-		if (pequal != NULL) {
-			*pequal++ = '\0';
-		} else {
-			do_print_usage();
-			exit(WIFI_IMPROPER_USE);
-		}
-		if (strcmp(param, "wait") != 0) {
-			do_print_usage();
-			exit(WIFI_IMPROPER_USE);
-		} else {
-			if (strcmp(pequal, "forever") == 0) {
-				forever = 1;
-			} else {
-				if (is_waittime_valid(pequal) == B_FALSE) {
-					(void) fprintf(stderr, gettext("%s: "
-					    "invalid value %s for 'wait'\n"),
-					    gExecName, pequal);
-					exit(WIFI_FATAL_ERR);
-				}
-				if (sscanf(pequal, "%d", &timeout) != 1) {
-					do_print_usage();
-					exit(WIFI_IMPROPER_USE);
-				}
-				if (timeout == -1) {
-					forever = 1;
-				}
-			}
-		}
-		free(param);
-		if (argc > 1) {
-			(void) fprintf(stderr, gettext("%s: trailing "
-			    "useless tokens after '%s'\n"),
-			    gExecName, argv[0]);
-		}
-	}
-
-	while ((forever == 1) || (timeout > 0)) {
-		timeout--;
-		selected = select_profile(fd, 0, max(timeout, forever));
-		if (selected != NULL)
-			break;
-		(void) sleep(1);
-	}
-	if (selected == NULL) {
-		return (B_TRUE);
-	}
-	(void) printf(gettext("%s: autoconf: profile [%s]"
-	    " is selected\n"), gExecName, selected);
-	ld_argv = safe_calloc(sizeof (char *), argc+1);
-	ld_argv[0] = safe_strdup(selected);
-	if (argc > 0) {
-		len = max(strlen(argv[0]), strlen("wait=forever"));
-		ld_argv[1] = safe_malloc(len);
-		safe_snprintf(ld_argv[1], len + 1, forever == 1 ?
-		    "wait=forever" : "wait=%d", timeout);
-	}
-	ret = do_loadpf(fd, argc+1, ld_argv);
-	free(ld_argv[0]);
-	if (argc > 0) {
-		free(ld_argv[1]);
-	}
-	free(ld_argv);
-	return (ret);
-}
-
-/*
- * do_startconf: almost the same as the do_autoconf, except that doesn't
- * write file.
- */
-/*ARGSUSED*/
-static boolean_t
-do_startconf(int fd, int argc, char **argv)
-{
-	int i = 0, ael_num = 0;
-	section_t *p_section = NULL;
-	section_t *p_wep_section = NULL;
-	aelist_t *plist = NULL;
-	const char *selected = NULL;
-	ae_t *pae = NULL;
-	char *pbuf = NULL;
-	char **argvnew = NULL;
-
-	PRTDBG(("do_startconf(%d, 0x%x)\n", argc, argv));
-	assert(fd > 0);
-
-	selected = select_profile(fd, 1, 0);
-	if (selected == NULL) {
-		return (B_TRUE);
-	}
-
-	(void) call_ioctl(fd, WLAN_COMMAND, WL_LOAD_DEFAULTS, 0);
-
-	pbuf = append_pa(selected);
-	p_wep_section = find_section(gp_wepkey_file, pbuf);
-	p_section = find_section(gp_config_file, pbuf);
-	free(pbuf);
-
-	if (p_wep_section != NULL) {
-		plist = p_wep_section->list;
-		pae = plist->ael_head;
-		while (pae != NULL) {
-			if (pae->ae_arg != NULL)
-				(void) do_set_wepkey(fd, pae->ae_arg);
-			pae = pae->ae_next;
-		}
-	}
-
-	if (p_section != NULL) {
-		plist = p_section->list;
-		if (plist->ael_argc == 0) {
-			return (B_TRUE);
-		}
-		argvnew = aeltoargv(plist, &ael_num);
-		(void) do_set(fd, ael_num, argvnew);
-
-		for (i = 0; i < ael_num; i++)
-			free(argvnew[i]);
-		free(argvnew);
-	}
-	return (B_TRUE);
-}
-
-static char *
-find_active_profile(int fd)
-{
-	section_t *p_section = NULL, *activep_section = NULL;
-	aelist_t *plist = NULL;
-	ae_t *pae = NULL;
-	const char *pessid = NULL, *pbssid = NULL;
-	char essid[34], bssid[32];
-	const char *activeprofile = NULL;
-
-	PRTDBG(("find_active_profile: %d\n", fd));
-	if (do_get_essid(fd) == B_FALSE) {
-		return (NULL);
-	}
-	(void) strlcpy(essid, ((wl_essid_t *)(gbuf->wldp_buf))->wl_essid_essid,
-	    sizeof (essid));
-	if (do_get_bssid(fd) == B_FALSE) {
-		return (NULL);
-	}
-	safe_snprintf(bssid, sizeof (bssid), "%02x:%02x:%02x:%02x:%02x:%02x",
-	    ((uint8_t *)gbuf->wldp_buf)[0],
-	    ((uint8_t *)gbuf->wldp_buf)[1],
-	    ((uint8_t *)gbuf->wldp_buf)[2],
-	    ((uint8_t *)gbuf->wldp_buf)[3],
-	    ((uint8_t *)gbuf->wldp_buf)[4],
-	    ((uint8_t *)gbuf->wldp_buf)[5]);
-	activep_section = find_section(gp_config_file, WIFI_ACTIVEP);
-	if (activep_section == NULL)
-		return (NULL);
-	activeprofile = get_value(activep_section->list->
-	    ael_head->ae_arg);
-	if (activeprofile == NULL)
-		return (NULL);
-	p_section = gp_config_file->section_head;
-	while (p_section != NULL) {
-		if (((plist = p_section->list) != NULL) &&
-		    (plist->type == PROFILE) &&
-		    (strcmp(p_section->section_id, activeprofile) == 0)) {
-			pae = plist->ael_head;
-			while (pae != NULL) {
-				if (strncmp(pae->ae_arg, "essid=",
-				    strlen("essid=")) == 0) {
-					pessid = get_value(pae->ae_arg);
-				}
-				if (strncmp(pae->ae_arg, "bssid=",
-				    strlen("bssid=")) == 0) {
-					pbssid = get_value(pae->ae_arg);
-				}
-				pae = pae->ae_next;
-			}
-			if (pessid && pbssid &&
-			    (strcmp(essid, pessid) == 0) &&
-			    (strcmp(bssid, pbssid) == 0)) {
-				return (p_section->section_id);
-			}
-		}
-		p_section = p_section->section_next;
-	}
-	return (NULL);
-}
-
-static void
-record_active_profile(char *pname, int action)
-{
-	section_t *p_section = NULL;
-	aelist_t *plist = NULL;
-	char pbuf[256];
-
-	p_section = find_section(gp_config_file, WIFI_ACTIVEP);
-	if (p_section == NULL) {
-		plist = new_ael(ACTIVEP);
-		new_section(gp_config_file, plist, WIFI_ACTIVEP);
-	} else {
-		plist = p_section->list;
-	}
-
-	if (action == RECORD_ADD) {
-		assert(pname != NULL);
-		safe_snprintf(pbuf, sizeof (pbuf), "activep=%s", pname);
-		update_aelist(plist, pbuf);
-	} else if (action == RECORD_DEL) {
-		assert(pname == NULL);
-		update_aelist(plist, "activep= ");
-	}
-}
-
-/*
- * do_loadpf: load a profile, set related parameters both in wifi
- * and in wifiwepkey, if network name is not exist in the
- * configration files, then we clean all parameters and set essid only
- */
-static boolean_t
-do_loadpf(int fd, int argc, char ** argv)
-{
-	int i = 0, ael_num = 0;
-	int timeout = LOADPROFILE_TIMEOUT, forever = 0;
-	section_t *p_section = NULL;
-	section_t *p_wep_section = NULL;
-	aelist_t *plist = NULL;
-	ae_t *pae = NULL;
-	char *pbuf = NULL;
-	char **argvnew = NULL;
-	char *connect;
-	char *pequal, *param;
-
-	PRTDBG(("do_loadpf(%d, %x)\n", argc, argv));
-	assert(fd > 0);
-	if (argc == 0) {
-		(void) fprintf(stderr, gettext("%s: connect: "
-		    "profile name missing\n"), gExecName);
-		return (B_FALSE);
-	}
-	if (argc > 1) {
-		param = safe_strdup(argv[1]);
-		pequal = strchr(param, '=');
-		if (pequal != NULL) {
-			*pequal++ = '\0';
-		} else {
-			do_print_usage();
-			exit(WIFI_IMPROPER_USE);
-		}
-		if (strcmp(param, "wait") != 0) {
-			do_print_usage();
-			exit(WIFI_IMPROPER_USE);
-		} else {
-			if (strcmp(pequal, "forever") == 0) {
-				forever = 1;
-			} else {
-				if (is_waittime_valid(pequal) == B_FALSE) {
-					(void) fprintf(stderr, gettext("%s: "
-					    "invalid value %s for 'wait'\n"),
-					    gExecName, pequal);
-					exit(WIFI_FATAL_ERR);
-				}
-				if (sscanf(pequal, "%d", &timeout) != 1) {
-					do_print_usage();
-					exit(WIFI_IMPROPER_USE);
-				}
-				if (timeout == -1) {
-					forever = 1;
-				}
-			}
-		}
-		free(param);
-		if (argc > 2) {
-			(void) fprintf(stderr, gettext("%s: trailing "
-			    "useless tokens after '%s'\n"),
-			    gExecName, argv[1]);
-		}
-	}
-	(void) call_ioctl(fd, WLAN_COMMAND, WL_LOAD_DEFAULTS, 0);
-
-	pbuf = append_pa(argv[0]);
-	p_wep_section = find_section(gp_wepkey_file, pbuf);
-	p_section = find_section(gp_config_file, pbuf);
-
-	if (p_wep_section != NULL) {
-		(void) set_prefer(gp_config_file, argv[0], 1);
-		plist = p_wep_section->list;
-		pae = plist->ael_head;
-		while (pae != NULL) {
-			if (pae->ae_arg != NULL) {
-				(void) do_set_wepkey(fd, pae->ae_arg);
-			}
-			pae = pae->ae_next;
-		}
-	}
-
-	if (p_section != NULL) {
-		connect = "profile";
-
-		(void) set_prefer(gp_config_file, argv[0], 1);
-		plist = p_section->list;
-		if (plist->ael_argc == 0) {
-			free(pbuf);
-			return (B_TRUE);
-		}
-		argvnew = aeltoargv(plist, &ael_num);
-		/*
-		 * if there is no 'essid' item in argvnew, the profile
-		 * name(argv[0]) is treated as essid.
-		 */
-		for (i = 0; i < ael_num; i++) {
-			if (strncmp(argvnew[i], "essid=", strlen("essid="))
-			    == 0)
-				break;
-		}
-		if (i == ael_num)
-			(void) do_set_essid(fd, argv[0]);
-
-		(void) do_set(fd, ael_num, argvnew);
-
-		for (i = 0; i < ael_num; i++)
-			free(argvnew[i]);
-		free(argvnew);
-
-		/*
-		 * set flag in {active_profile} so that showprofile knows
-		 * which profile is active when more than one profiles are
-		 * created for the same WLAN.
-		 */
-		record_active_profile(pbuf, RECORD_ADD);
-	} else {
-		(void) do_set_essid(fd, argv[0]);
-		connect = "essid";
-	}
-
-	while ((forever == 1) || (timeout > 0)) {
-		if ((do_get_linkstatus(fd) == B_TRUE) &&
-		    (*(wl_linkstatus_t *)(gbuf->wldp_buf) == WL_CONNECTED)) {
-			section_t *p_section = NULL;
-			aelist_t *plist = NULL;
-			char bssid[32];
-			/* record bssid in the profile */
-			if (do_get_bssid(fd) == B_FALSE) {
-				free(pbuf);
-				return (B_TRUE);
-			}
-			safe_snprintf(bssid, sizeof (bssid),
-			    "bssid=%02x:%02x:%02x:%02x:%02x:%02x",
-			    ((uint8_t *)gbuf->wldp_buf)[0],
-			    ((uint8_t *)gbuf->wldp_buf)[1],
-			    ((uint8_t *)gbuf->wldp_buf)[2],
-			    ((uint8_t *)gbuf->wldp_buf)[3],
-			    ((uint8_t *)gbuf->wldp_buf)[4],
-			    ((uint8_t *)gbuf->wldp_buf)[5]);
-
-			p_section = find_section(gp_config_file, pbuf);
-			if (p_section != NULL) {
-				plist = p_section->list;
-				update_aelist(plist, bssid);
-			}
-			free(pbuf);
-			(void) printf(gettext("%s: connecting to "
-			    "%s '%s'\n"), gExecName, connect, argv[0]);
-			return (B_TRUE);
-		}
-		(void) sleep(1);
-		timeout--;
-		PRTDBG(("connect counting:......%d\n", timeout));
-	}
-	(void) fprintf(stderr, gettext("%s: failed to connect to "
-	    "%s '%s'\n"), gExecName, connect, argv[0]);
-	free(pbuf);
-	return (B_FALSE);
-}
-
-/*
- * if wepkey is set in the profile, display wepkey|n=*****
- * when showprofile and getprofilewepkey.
- * if wepkeyn is NULL, all the wepkeys will be display,
- * otherwise, just display the matching one.
- */
-static void
-print_wepkey_info(const char *id, const char *wepkeyn)
-{
-	char *pequal, *param;
-	section_t *p_section = NULL;
-	aelist_t *plist = NULL;
-	ae_t *pae = NULL;
-
-	p_section = find_section(gp_wepkey_file, id);
-	if (p_section != NULL) {
-		plist = p_section->list;
-		pae = plist->ael_head;
-		while (pae != NULL) {
-			if (pae->ae_arg != NULL) {
-				param = safe_strdup(pae->ae_arg);
-				pequal = strchr(param, '=');
-				if (pequal == NULL)
-					return;
-				*pequal = '\0';
-				if (wepkeyn != NULL) {
-					if (strcmp(wepkeyn, param) == 0)
-						(void) printf("\t%s=*****\n",
-						    param);
-					free(param);
-					return;
-				} else {
-					(void) printf("\t%s=*****\n", param);
-					free(param);
-				}
-			}
-			pae = pae->ae_next;
-		}
-	}
-}
-
-/*
- * do_printpf: print each parameters of the profile, if no network name
- * assigned, then print all profile saved in configration file.
- */
-/*ARGSUSED*/
-static boolean_t
-do_printpf(int fd, int argc, char ** argv)
-{
-	section_t *p_section = NULL;
-	aelist_t *plist = NULL;
-	ae_t *pae = NULL;
-	char *pbuf = NULL;
-	int i;
-
-	PRTDBG(("do_printpf(%d, %x)\n", argc, argv));
-
-	/*
-	 * if no profile name is inputted, all the profiles will be displayed.
-	 */
-	if (argc == 0) {
-		p_section = gp_config_file->section_head;
-		while (p_section != NULL) {
-			plist = p_section->list;
-			if (plist->type == PROFILE) {
-				(void) printf("%s\n", p_section->section_id);
-				pae = plist->ael_head;
-				while (pae != NULL) {
-					if (pae->ae_arg != NULL) {
-						(void) printf("\t%s\n",
-						    pae->ae_arg);
-					}
-					pae = pae->ae_next;
-				}
-				/*
-				 * identify whether wepkey is set
-				 * in the profile
-				 */
-				print_wepkey_info(p_section->section_id, NULL);
-			}
-			p_section = p_section->section_next;
-		}
-		return (B_TRUE);
-	}
-
-	for (i = 0; i < argc; i++) {
-		pbuf =	append_pa(argv[i]);
-		p_section = find_section(gp_config_file, pbuf);
-		free(pbuf);
-		if (p_section != NULL)	{
-			(void) printf("%s\n", p_section->section_id);
-			plist = p_section->list;
-			if (plist != NULL) {
-				pae = plist->ael_head;
-				while (pae != NULL) {
-					if (pae->ae_arg != NULL) {
-						(void) printf("\t%s\n",
-						    pae->ae_arg);
-					}
-					pae = pae->ae_next;
-				}
-				/*
-				 * identify whether wepkey is set
-				 * in the profile
-				 */
-				print_wepkey_info(p_section->section_id, NULL);
-			}
-		} else {
-			(void) fprintf(stderr,
-			    gettext("%s: showprofile : "
-			    "no such profile: '%s'\n"),
-			    gExecName, argv[i]);
-			return (B_FALSE);
-		}
-	}
-	return (B_TRUE);
-}
-/*
- * find_ae: Find an ae by its contents, return its pointer.
- */
-static ae_t *
-find_ae(aelist_t *plist, const char *arg)
-{
-	char *param = NULL;
-	char *pnext = NULL;
-	ae_t *pae = NULL;
-
-	if ((arg == NULL) || (plist == NULL)) {
-		PRTDBG(("find_ae: arg= NULL or plist=NULL\n"));
-		return (NULL);
-	}
-	PRTDBG(("find_ae(0x%x, \"%s\")\n", plist, arg));
-	param = safe_strdup(arg);
-	pnext = strchr(param, '=');
-	if (pnext != NULL) {
-		*pnext = '\0';
-	} else {
-		PRTDBG(("find_ae: param = \"%s\"\n", param));
-		free(param);
-		return (NULL);
-	}
-
-	pae = plist->ael_head;
-	while (pae != NULL) {
-		if ((pae->ae_arg != NULL) &&
-		    (strncmp(pae->ae_arg, param, strlen(param)) == 0)) {
-			PRTDBG(("find_ae: param = \"%s\"\n", param));
-			free(param);
-			return (pae);
-		}
-		pae = pae->ae_next;
-	}
-	free(param);
-	return (NULL);
-}
-
-/*
- * update_aelist: Update an aelist by arg, for example:
- * there are an item with content"essid=ap7-2",
- * update_aelist(0x..., "essid=myssid2") will update it as "essid=myssid2"
- */
-static void
-update_aelist(aelist_t *plist, const char *arg)
-{
-	ae_t *pae = NULL;
-
-	assert((arg != NULL)&&(plist != NULL));
-	PRTDBG(("update_aelist(0x%x, \"%s\")\n", plist, arg));
-	pae = find_ae(plist, arg);
-	if (pae == NULL) {
-		new_ae(plist, arg);
-	} else {
-		free(pae->ae_arg);
-		pae->ae_arg = safe_strdup(arg);
-	}
-}
-
-/*
- * do_deletepf: delete a profile in configration files.
- */
-/*ARGSUSED*/
-static boolean_t
-do_deletepf(int fd, int argc, char **argv)
-{
-	int i = 0;
-	char *section_id;
-	char *prefer;
-	section_t *p_section = NULL, *p_sectionbak = NULL;
-	aelist_t *plist = NULL;
-
-	PRTDBG(("do_deletepf(%d, \"%s\")\n", argc, argv));
-	if (argc <= 0) {
-		do_print_usage();
-		exit(WIFI_IMPROPER_USE);
-	}
-
-	/*
-	 * if a "all" is inputted, all the profiles will be deleted.
-	 */
-	if (strcasecmp(argv[0], "all") == 0) {
-		p_section = gp_config_file->section_head;
-		while ((p_section != NULL) &&
-		    ((plist = p_section->list) != NULL)) {
-			if (plist->type == PROFILE) {
-				p_sectionbak = p_section->section_next;
-				section_id = safe_strdup(p_section->section_id);
-				(void) del_section(gp_config_file, section_id);
-				(void) del_section(gp_wepkey_file, section_id);
-				/*
-				 * remove the '[]' of the [section_id]
-				 */
-				prefer = section_id + 1;
-				*(prefer + strlen(section_id) - 2) = '\0';
-				(void) del_prefer(gp_config_file, prefer,
-				    B_FALSE);
-				free(section_id);
-				p_section = p_sectionbak;
-					continue;
-			}
-			p_section = p_section->section_next;
-		}
-		return (B_TRUE);
-	}
-	if (gp_config_file != NULL) {
-		for (i = 0; i < argc; i++) {
-			section_id = append_pa(argv[i]);
-			if (del_section(gp_config_file, section_id)
-			    == B_FALSE) {
-				if (del_section(gp_wepkey_file, section_id)
-				    == B_TRUE) {
-					(void) del_prefer(gp_config_file,
-					    argv[i], B_FALSE);
-					free(section_id);
-					return (B_TRUE);
-				} else {
-					(void) fprintf(stderr,
-					    gettext("%s: deleteprofile"
-					    ": no such profile: '%s'\n"),
-					    gExecName, argv[i]);
-					free(section_id);
-					return (B_FALSE);
-				}
-			}
-			(void) del_prefer(gp_config_file, argv[i], B_FALSE);
-			(void) del_section(gp_wepkey_file, section_id);
-			free(section_id);
-		}
-	}
-	return (B_TRUE);
-}
-
-/*
- * do_history: Print the list in {history} section.
- */
-/*ARGSUSED*/
-static boolean_t
-do_history(int fd, int argc, char **argv)
-{
-	section_t *p_section = NULL;
-	aelist_t *plist = NULL;
-	ae_t *pae = NULL;
-	char *param, *param_bak, *pcomma;
-	uint32_t maxessidlen = 0, ulen;
-	char format[256], *ntstr;
-	uint32_t nt = 0, cnt = 0;
-	int len;
-	time_t cltime;
-
-	PRTDBG(("do_history(%d, 0x%x)\n", argc, argv));
-	if (argc > 0) {
-		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
-		    "after 'history'\n"), gExecName);
-	}
-	p_section = find_section(gp_config_file, WIFI_HISTORY);
-	if (p_section == NULL) {
-		PRTDBG(("no history section\n"));
-		return (B_FALSE);
-	}
-	plist = p_section->list;
-
-	/*
-	 * If history section is empty, directly return.
-	 */
-	if (plist == NULL)
-		return (B_TRUE);
-	/*
-	 * construct the output format in terms of the
-	 * maxmium essid length
-	 */
-	pae = NULL;
-	pae = plist->ael_head;
-	while (pae != NULL) {
-		if (pae->ae_arg != NULL) {
-			param = safe_strdup(pae->ae_arg);
-			pcomma = strchr(param, ',');
-			if (pcomma == NULL) {
-				(void) fprintf(stderr,
-				    gettext("%s: history : "
-				    "data format error\n"),
-				    gExecName);
-				free(param);
-				return (B_FALSE);
-			}
-			*pcomma = '\0';
-			ulen = strlen(param);
-			maxessidlen = (maxessidlen > ulen
-			    ? maxessidlen:ulen);
-			free(param);
-		}
-		pae = pae->ae_next;
-	}
-	if ((nt = (maxessidlen / 8 + 1)) > 4)
-		nt = 4;
-	len = snprintf(format, sizeof (format), gettext("essid"));
-	ntstr = construct_format(nt);
-	assert((ntstr != NULL) && (strlen(ntstr) <= 4));
-	len += snprintf(format + len, sizeof (format) - len, "%s", ntstr);
-	len += snprintf(format + len, sizeof (format) - len,
-	    gettext("bssid\t\t  encryption\tlast seen\n"));
-
-	if ((len <= 0) || (len > sizeof (format) - 1)) {
-		(void) printf(gettext("essid\t\t\t\tbssid\t\t  encryption"
-		    "\tlast seen\n"));
-	} else {
-		(void) printf("%s", format);
-	}
-	/*
-	 * output the contents of the history section.
-	 */
-	pae = plist->ael_head;
-	while (pae != NULL) {
-		if (pae->ae_arg != NULL) {
-			param = safe_strdup(pae->ae_arg);
-			param_bak = param;
-			if ((pcomma = strchr(param, ',')) != NULL) {
-				*pcomma = '\0';
-				cnt = nt - (min((strlen(param)/8 + 1), 4) - 1);
-				ntstr = construct_format(cnt);
-				assert(ntstr != NULL);
-				/* display essid */
-				(void) printf("%s%s", param, ntstr);
-				free(ntstr);
-			}
-			param = pcomma + 1;
-			if ((pcomma = strchr(param, ',')) != NULL) {
-				*pcomma = '\0';
-				/* display bssid */
-				(void) printf("%s ", param);
-			}
-			param = pcomma + 1;
-			if ((pcomma = strchr(param, ',')) != NULL) {
-				*pcomma = '\0';
-				/* display wep */
-				(void) printf("%s\t\t", param);
-			}
-			param = pcomma + 1;
-			/* display time stamp */
-			cltime = (time_t)atol(param);
-			(void) printf("%s", ctime(&cltime));
-			free(param_bak);
-		}
-		pae = pae->ae_next;
-	}
-
-	return (B_TRUE);
-}
-
-/*
- * do_lsprefer: Print the list in {preferrence} section
- */
-/*ARGSUSED*/
-static boolean_t
-do_lsprefer(int fd, int argc, char **argv)
-{
-	int i = 0;
-	section_t *p_section = NULL;
-	aelist_t *plist = NULL;
-	ae_t *pae = NULL;
-	char *pbuf;
-
-	PRTDBG(("do_lsprefer(%d, 0x%x)\n", argc, argv));
-	if (argc > 0) {
-		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
-		    "after 'listprefer'\n"), gExecName);
-	}
-	p_section = find_section(gp_config_file, WIFI_PREFER);
-	if (p_section != NULL) {
-		plist = p_section->list;
-		if (plist != NULL) {
-			pae = NULL;
-			pae = plist->ael_head;
-			while (pae != NULL) {
-				if (pae->ae_arg != NULL) {
-					pbuf = append_pa(pae->ae_arg);
-					(void) printf("%d\t%s\n", ++i, pbuf);
-				}
-				pae = pae->ae_next;
-			}
-		}
-		return (B_TRUE);
-	} else {
-		PRTDBG(("no preference section\n"));
-		return (B_FALSE);
-	}
-}
-
-/*
- * do_rmprefer: Remove an item in {preferrence} list
- */
-/*ARGSUSED*/
-static boolean_t
-do_rmprefer(int fd, int argc, char **argv)
-{
-	int i = 0;
-	section_t *p_section = NULL;
-	aelist_t *plist = NULL;
-	ae_t *pae = NULL;
-
-	PRTDBG(("do_rmprefer(%d, 0x%x)\n", argc, argv));
-	if (argc <= 0) {
-		do_print_usage();
-		exit(WIFI_IMPROPER_USE);
-	}
-
-	/*
-	 * if a "all" is inputted, all the items in the preference
-	 * list will be deleted.
-	 */
-	if (strcasecmp(argv[0], "all") == 0) {
-		p_section = find_section(gp_config_file, WIFI_PREFER);
-		if (p_section != NULL)
-			plist = p_section->list;
-
-		if ((p_section == NULL) || (plist == NULL))
-			return (B_FALSE);
-		pae = plist->ael_head;
-		while (pae != NULL) {
-			free(pae);
-			pae = pae->ae_next;
-		}
-		plist->ael_head = plist->ael_tail = NULL;
-		plist->ael_argc = 0;
-	} else if (gp_config_file != NULL) {
-		for (i = 0; i < argc; i++) {
-			if (del_prefer(gp_config_file, argv[i], B_TRUE)
-			    == B_FALSE) {
-				return (B_FALSE);
-			}
-		}
-	}
-	return (B_TRUE);
-}
-
-static boolean_t
-is_prefer_rank_valid(const char *pbuf)
-{
-	int i;
-	boolean_t ret = B_FALSE;
-
-	for (i = 0; i < strlen(pbuf); i++) {
-		if (isdigit(pbuf[i]) == 0) {
-			ret = B_FALSE;
-			goto exit0;
-		}
-	}
-	i = atoi(pbuf);
-	if ((i >= 1) && (i <= MAX_PREFERENCE_NUM))
-		ret = B_TRUE;
-exit0:
-	return (ret);
-}
-
-/*
- * do_setprefer: Set network preferrence
- */
-/*ARGSUSED*/
-static boolean_t
-do_setprefer(int fd, int argc, char **argv)
-{
-	int rank = 0;
-
-	PRTDBG(("do_setprefer(%d, 0x%x)\n", argc, argv));
-	if (argc <= 0) {
-		do_print_usage();
-		exit(WIFI_IMPROPER_USE);
-	}
-	if (argc == 1) {
-		rank = 1;
-	} else {
-		if (is_prefer_rank_valid(argv[1]) == B_FALSE) {
-			(void) fprintf(stderr, gettext("%s: preference rank "
-			    "should be an integer within 1-10\n"), gExecName);
-			return (B_FALSE);
-		}
-		rank = atoi(argv[1]);
-	}
-	return (set_prefer(gp_config_file, argv[0], rank));
-}
-
-static boolean_t
-is_wepkeyindex_valid(const char *pbuf)
-{
-	int i;
-	boolean_t ret = B_FALSE;
-
-	for (i = 0; i < strlen(pbuf); i++) {
-		if (isdigit(pbuf[i]) == 0) {
-			ret = B_FALSE;
-			goto exit0;
-		}
-	}
-	i = atoi(pbuf);
-	if ((i >= 1) && (i <= MAX_NWEPKEYS))
-		ret = B_TRUE;
-exit0:
-	return (ret);
-}
-
-static boolean_t
-is_channel_valid(const char *pbuf)
-{
-	int i;
-	boolean_t ret = B_FALSE;
-
-	for (i = 0; i < strlen(pbuf); i++) {
-		if (isdigit(pbuf[i]) == 0) {
-			ret = B_FALSE;
-			goto exit0;
-		}
-	}
-	i = atoi(pbuf);
-	if ((i >= 0) && (i <= MAX_CHANNEL_NUM))
-		ret = B_TRUE;
-exit0:
-	return (ret);
-}
-
-static boolean_t
-is_wepkey_valid(const char *pbuf, uint32_t length)
-{
-	int i;
-	boolean_t ret = B_FALSE;
-
-	switch (length) {
-	case 10:
-	case 26:
-		for (i = 0; i < length; i++) {
-			if (isxdigit(pbuf[i]) == 0) {
-				ret = B_FALSE;
-				goto exit0;
-			}
-		}
-		ret = B_TRUE;
-		break;
-	case 5:
-	case 13:
-		ret = B_TRUE;
-		break;
-	default:
-		ret = B_FALSE;
-		break;
-	}
-exit0:
-	if (ret == B_FALSE) {
-		(void) fprintf(stderr, gettext("%s: "
-		    "wepkey should be:\n"
-		    "\t 40bits: 5 char or 10 hex digits.\n"
-		    "\t 128bits: 13 char or 26 hex digits.\n"),
-		    gExecName);
-	}
-	return (ret);
-}
-
-/*
- * get_valid_wepkey: get an valid wepkey from stdin
- */
-static char *
-get_valid_wepkey()
-{
-	int i = 0;
-	char *buf = NULL;
-	uint8_t length = 0;
-	struct termios stored_settings;
-	struct termios new_settings;
-
-	PRTDBG(("get_valid_wepkey()\n"));
-	buf = safe_calloc(sizeof (char), MAX_KEY_LENGTH + 2);
-	/*
-	 * Because we need to get single char from terminal, so we need to
-	 * disable canonical mode and set buffer size to 1 tyte. And because
-	 * wepkey should not be see by others, so we disable echo too.
-	 */
-	(void) fflush(stdin);
-	(void) tcgetattr(0, &stored_settings);
-	new_settings = stored_settings;
-	new_settings.c_lflag &= (~ICANON);
-	new_settings.c_lflag &= (~ECHO);
-	new_settings.c_cc[VTIME] = 0;
-	new_settings.c_cc[VMIN] = 1;
-	/* Set new terminal attributes */
-	(void) tcsetattr(0, TCSANOW, &new_settings);
-	while (((buf[i++] = getchar()) != '\n') && (i < MAX_KEY_LENGTH + 1)) {
-		(void) putchar('*');
-	}
-	(void) putchar('\n');
-	/* Restore terminal attributes */
-	(void) tcsetattr(0, TCSANOW, &stored_settings);
-	(void) fflush(stdin);
-
-	if (buf[--i] != '\n') {
-		(void) fprintf(stderr, gettext("%s: wepkey length "
-		    "exceeds 26 hex digits\n"), gExecName);
-		free(buf);
-		return (NULL);
-	}
-	/* Replace last char '\n' with '\0' */
-	buf[i] = '\0';
-	length = (uint8_t)i;
-	return ((is_wepkey_valid(buf, length) == B_TRUE)?
-	    buf : NULL);
-}
-
-/*
- * do_set_wepkey: Set parameters in wepkey, and call ioctl
- */
-static boolean_t
-do_set_wepkey(int fd, const char *pbuf)
-{
-	int id = 0;
-	char i = 0;
-	uint8_t len = 0;
-	uint8_t length;
-	const char *wepkey = NULL;
-	char key[MAX_KEY_LENGTH] = {0};
-	unsigned int keytmp;
-	wl_wep_key_tab_t wepkey_tab;
-
-	PRTDBG(("do_set_wepkey(%d, \"%s\")\n", fd, pbuf));
-	if (!check_authority(AUTH_WEP)) {
-		exit(WIFI_FATAL_ERR);
-	}
-	id = pbuf[strlen("wepkeyn") - 1] - '0';
-	wepkey = get_value(pbuf);
-	length = strlen(wepkey);
-	switch (length) {
-	case 10:
-	case 26:
-		for (i = 0; i < length / 2; i++) {
-			(void) sscanf(wepkey + i * 2, "%2x", &keytmp);
-			key[i] = (char)keytmp;
-		}
-		len = length / 2;
-		break;
-	case 5:
-	case 13:
-		(void) strlcpy(key, wepkey, MAX_KEY_LENGTH);
-		len = length;
-		break;
-	default:
-		PRTDBG(("do_set_wepkey: error pbuf size\n"));
-		(void) fprintf(stderr, gettext("%s: "
-		    "wepkey should be:\n"
-		    "\t 40bits: 5 char or 10 hex digits.\n"
-		    "\t 128bits: 13 char or 26 hex digits.\n"),
-		    gExecName);
-		exit(WIFI_FATAL_ERR);
-	}
-
-	(void) memset(wepkey_tab, 0, sizeof (wepkey_tab));
-	for (i = 0; i < MAX_NWEPKEYS; i++) {
-		wepkey_tab[i].wl_wep_operation = WL_NUL;
-	}
-
-	if (id > 0 && id <= MAX_NWEPKEYS) {
-		wepkey_tab[id-1].wl_wep_operation = WL_ADD;
-		wepkey_tab[id-1].wl_wep_length = len;
-		(void) memcpy(wepkey_tab[id-1].wl_wep_key, key, len);
-	} else {
-		(void) fprintf(stderr, gettext("%s: wepkeyindex "
-		    "should be an integer within the range 1-4\n"), gExecName);
-		exit(WIFI_FATAL_ERR);
-	}
-	(void) memmove(gbuf->wldp_buf, &wepkey_tab, sizeof (wl_wep_key_tab_t));
-	return (call_ioctl(fd, WLAN_SET_PARAM, WL_WEP_KEY_TAB,
-	    sizeof (wl_wep_key_tab_t)));
-}
-
-/*
- * get the committed wepkey. the return form is like wepkey1=*****;
- */
-/*ARGSUSED*/
-static char *
-get_commit_key(int fd, int argc, char **argv)
-{
-	int key;
-	int len;
-	char *wepkey = NULL;
-	char *wepkey_confirm = NULL;
-	char *pbuf = NULL;
-
-	key = atoi(argv[0]);
-	if (key <= 0 || key > MAX_NWEPKEYS) {
-		(void) fprintf(stderr, gettext("%s: wepkeyindex "
-		    "should be an integer within the range 1-4\n"), gExecName);
-		goto exit0;
-	}
-	(void) printf(gettext("input wepkey%d:"), key);
-	wepkey = get_valid_wepkey();
-	if (wepkey == NULL) {
-		goto exit0;
-	}
-	(void) printf(gettext("confirm wepkey%d:"), key);
-	wepkey_confirm = get_valid_wepkey();
-	if (wepkey_confirm == NULL) {
-		free(wepkey);
-		goto exit0;
-	}
-	if (strcmp(wepkey, wepkey_confirm) != 0) {
-		free(wepkey);
-		free(wepkey_confirm);
-		(void) fprintf(stderr,
-		    gettext("%s: wepkey: "
-		    "two inputs are not identical\n"), gExecName);
-		goto exit0;
-	}
-	free(wepkey_confirm); /* wepkey_confirm is no longer used */
-
-	len = MAX_KEY_LENGTH + strlen("wepkey1=\n") + 1;
-	pbuf = safe_malloc(len);
-	safe_snprintf(pbuf, len, "%s%d=%s", "wepkey", key, wepkey);
-
-	free(wepkey); /* wepkey is no longer used */
-	return (pbuf);
-exit0:
-	return (NULL);
-}
-
-/*
- * do_wepkey: Get input from user, call do_set_wepkey
- */
-/*ARGSUSED*/
-static boolean_t
-do_wepkey(int fd, int argc, char **argv)
-{
-	char *pbuf;
-
-	PRTDBG(("do_wepkey(%d, 0x%x)\n", argc, argv));
-	assert(fd > 0);
-	if (argc <= 0) {
-		do_print_usage();
-		exit(WIFI_IMPROPER_USE);
-	}
-	if (argc > 1) {
-		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
-		    "after 'setwepkey'\n"), gExecName);
-	}
-	pbuf = get_commit_key(fd, argc, argv);
-	if ((pbuf != NULL) && (do_set_wepkey(fd, pbuf) == B_TRUE)) {
-		free(pbuf);
-		return (B_TRUE);
-	}
-	free(pbuf);
-	return (B_FALSE);
-}
-
-/*ARGSUSED*/
-static boolean_t
-do_setprofwepkey(int fd, int argc, char **argv)
-{
-	char *pbuf;
-	char *section_id = NULL;
-	section_t *p_section = NULL;
-	aelist_t *plist = NULL;
-
-	PRTDBG(("do_setprofwepkey(%d, 0x%x)\n", argc, argv));
-	if (argc < 2) {
-		do_print_usage();
-		exit(WIFI_IMPROPER_USE);
-	}
-	if (argc > 2) {
-		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
-		    "after 'setprofwepkey'\n"), gExecName);
-	}
-
-	section_id = append_pa(argv[0]);
-	p_section = find_section(gp_wepkey_file, section_id);
-	free(section_id);
-	if (p_section == NULL) {
-		(void) fprintf(stderr, gettext("%s: "
-		    "no such profile: '%s'\n"),
-		    gExecName, argv[0]);
-		return (B_FALSE);
-	}
-
-	argc--;
-	argv++;
-	pbuf = get_commit_key(fd, argc, argv);
-	if (pbuf == NULL)
-		return (B_FALSE);
-	plist = p_section->list;
-	update_aelist(plist, pbuf);
-
-	return (B_TRUE);
-}
-
-/*
- * do_wlanlist: Scan for wlanlist
- */
-/*ARGSUSED*/
-static boolean_t
-do_wlanlist(int fd, int argc, char **argv)
-{
-	PRTDBG(("do_wlanlist(%d, 0x%x)\n", argc, argv));
-	assert(fd > 0);
-	if (argc > 0) {
-		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
-		    "after 'scan'\n"), gExecName);
-	}
-	if (call_ioctl(fd, WLAN_COMMAND, WL_SCAN, 0) == B_FALSE) {
-		(void) fprintf(stderr, gettext("%s: failed to scan\n"),
-		    gExecName);
-		return (B_FALSE);
-	}
-	if (do_get_wlanlist(fd) == B_TRUE) {
-		print_gbuf(WLANLIST);
-	}
-	return (B_TRUE);
-}
-
-/*
- * do_showstatus: show the basic status of the interface, including
- * linkstauts, essid, encryption and signal strength.
- */
-/*ARGSUSED*/
-static boolean_t
-do_showstatus(int fd, int argc, char **argv)
-{
-	wl_rssi_t signal;
-	char *active_profile = NULL;
-
-	PRTDBG(("do_showstatus(%d, 0x%x)\n", argc, argv));
-	assert(fd > 0);
-
-	if (argc > 0) {
-		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
-		    "after 'showstatus'\n"), gExecName);
-	}
-	if (do_get_linkstatus(fd) == B_TRUE) {
-		print_gbuf(LINKSTATUS);
-		if (*(wl_linkstatus_t *)(gbuf->wldp_buf) == WL_NOTCONNECTED) {
-			return (B_TRUE);
-		}
-	}
-	active_profile = find_active_profile(fd);
-	(void) printf("\tactive profile: %s\n",
-	    active_profile ? active_profile : "none");
-	if (do_get_essid(fd) == B_TRUE) {
-		print_gbuf(ESSID);
-	}
-	if (do_get_bssid(fd) == B_TRUE) {
-		print_gbuf(BSSID);
-	}
-	if (do_get_encryption(fd) == B_TRUE) {
-		print_gbuf(ENCRYPTION);
-	}
-	if (do_get_signal(fd) == B_TRUE) {
-		signal = *(wl_rssi_t *)(gbuf->wldp_buf);
-		if (signal < 4) {
-			(void) printf("\tsignal strength: weak(%d)\n",
-			    signal);
-		} else if ((signal >= 4) && (signal <= 11)) {
-			(void) printf("\tsignal strength: medium(%d)\n",
-			    signal);
-		} else {
-			(void) printf("\tsignal strength: strong(%d)\n",
-			    signal);
-		}
-	}
-
-	return (B_TRUE);
-}
-
-
-/*
- * do_restoredef: Ask driver for loading default parameters
- */
-/*ARGSUSED*/
-static boolean_t
-do_restoredef(int fd, int argc, char **argv)
-{
-	PRTDBG(("do_restoredef(%d, 0x%x)\n", argc, argv));
-	assert(fd > 0);
-
-	if (argc > 0) {
-		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
-		    "after 'restoredef'\n"), gExecName);
-	}
-	record_active_profile(NULL, RECORD_DEL);
-	if (call_ioctl(fd, WLAN_COMMAND, WL_LOAD_DEFAULTS, 0) == B_FALSE) {
-		return (B_FALSE);
-	} else {
-		return (B_TRUE);
-	}
-}
-
-/*
- * do_disconnect: disconnect from the current connectted network
- */
-/*ARGSUSED*/
-static boolean_t
-do_disconnect(int fd, int argc, char **argv)
-{
-	PRTDBG(("do_disconnect(%d, 0x%x)\n", argc, argv));
-	assert(fd > 0);
-
-	if (argc > 0) {
-		(void) fprintf(stderr, gettext("%s: trailing useless tokens "
-		    "after 'disconnect'\n"), gExecName);
-	}
-	record_active_profile(NULL, RECORD_DEL);
-	if (call_ioctl(fd, WLAN_COMMAND, WL_DISASSOCIATE, 0) == B_FALSE) {
-		return (B_FALSE);
-	} else {
-		return (B_TRUE);
-	}
-}
-
-static boolean_t
-do_set_essid(int fd, const char *arg)
-{
-	wl_essid_t essid;
-
-	PRTDBG(("do_set_essid(%d, \"%s\")\n", fd, arg));
-
-	/*
-	 * a trick here: clean the active_profile flag
-	 * in section{active_profile}
-	 */
-	record_active_profile(NULL, RECORD_DEL);
-
-	(void) memset(&essid, 0x0, sizeof (essid));
-
-	if (arg == NULL || strcmp(arg, "") == 0) {
-		essid.wl_essid_length = 0;
-		essid.wl_essid_essid[0] = '\0';
-	} else {
-		essid.wl_essid_length = strlen(arg);
-		if (essid.wl_essid_length > MAX_ESSID_LENGTH - 1) {
-			(void) fprintf(stderr, gettext("%s: "
-			    "essid exceeds 32 bytes\n"), gExecName);
-			exit(WIFI_FATAL_ERR);
-		}
-		(void) strcpy(essid.wl_essid_essid, arg);
-	}
-	(void) memmove(gbuf->wldp_buf, &essid, sizeof (wl_essid_t));
-	return (call_ioctl(fd, WLAN_SET_PARAM, WL_ESSID, sizeof (wl_essid_t)));
-}
-
-static boolean_t
-do_set_bsstype(int fd, const char *arg)
-{
-	wl_bss_type_t bsstype;
-
-	assert(arg != NULL);
-
-	PRTDBG(("do_set_bsstype(%d, \"%s\")\n", fd, arg));
-
-	(void) memset(&bsstype, 0xff, sizeof (bsstype));
-
-	if ((strcasecmp(arg, "BSS") == 0) ||
-	    (strcasecmp(arg, "AP") == 0) ||
-	    (strcasecmp(arg, "INFRASTRUCTURE") == 0)) {
-		bsstype = WL_BSS_BSS;
-	} else if ((strcasecmp(arg, "IBSS") == 0) ||
-	    (strcasecmp(arg, "AD-HOC") == 0)) {
-		bsstype = WL_BSS_IBSS;
-	} else if (strcasecmp(arg, "AUTO") == 0) {
-		bsstype = WL_BSS_ANY;
-	} else {
-		(void) fprintf(stderr, gettext("%s: bsstype: "
-		    "bss(ap,infrastructure) ibss(ad-hoc) or auto\n"),
-		    gExecName);
-		exit(WIFI_FATAL_ERR);
-	}
-
-	(void) memmove(gbuf->wldp_buf, &bsstype, sizeof (wl_bss_type_t));
-	return (call_ioctl(fd, WLAN_SET_PARAM, WL_BSS_TYPE,
-	    sizeof (wl_bss_type_t)));
-}
-
-static boolean_t
-do_set_createibss(int fd, const char *arg)
-{
-	wl_create_ibss_t create_ibss;
-
-	assert(arg != NULL);
-
-	PRTDBG(("do_set_createibss(%d, \"%s\")\n", fd, arg));
-
-	(void) memset(&create_ibss, 0x0, sizeof (create_ibss));
-
-	if (strcasecmp(arg, "YES") == 0) {
-		create_ibss = B_TRUE;
-	} else if (strcasecmp(arg, "NO") == 0) {
-		create_ibss = B_FALSE;
-	} else {
-		(void) fprintf(stderr, gettext("%s: "
-		    "createibss: yes or no\n"), gExecName);
-		exit(WIFI_FATAL_ERR);
-	}
-
-	(void) memmove(gbuf->wldp_buf, &create_ibss,
-	    sizeof (wl_create_ibss_t));
-	return (call_ioctl(fd, WLAN_SET_PARAM, WL_CREATE_IBSS,
-	    sizeof (wl_create_ibss_t)));
-}
-
-static boolean_t
-do_set_channel(int fd, const char *arg)
-{
-	wl_phy_conf_t phy_conf;
-
-	assert(arg != NULL);
-	PRTDBG(("do_set_channel(%d, \"%s\")\n", fd, arg));
-
-	(void) memset(&phy_conf, 0xff, sizeof (phy_conf));
-
-	if (is_channel_valid(arg) == B_FALSE) {
-		(void) fprintf(stderr, gettext("%s: channel No. "
-		    "should be:\n"
-		    "\t802.11a: 0-99\n"
-		    "\t802.11b: 1-14\n"
-		    "\t802.11g: 1-14\n"), gExecName);
-		exit(WIFI_FATAL_ERR);
-	}
-	phy_conf.wl_phy_dsss_conf.wl_dsss_channel = atoi(arg);
-	PRTDBG(("channel=%d\n", phy_conf.wl_phy_dsss_conf.wl_dsss_channel));
-
-	(void) memmove(gbuf->wldp_buf, &phy_conf, sizeof (wl_phy_conf_t));
-	return (call_ioctl(fd, WLAN_SET_PARAM, WL_PHY_CONFIG,
-	    sizeof (wl_phy_conf_t)));
-}
-/*
- * is_rates_support: Querying driver about supported rates.
- */
-static boolean_t
-is_rates_support(int fd, int num, uint8_t *rates)
-{
-	int rates_num = 0;
-	int i = 0, j = 0;
-	uint8_t value = 0;
-
-	assert((rates != NULL)&&(num != 0));
-	PRTDBG(("is_rates_support(%d, %d, 0x%x)\n", fd, num, rates));
-
-	if (call_ioctl(fd, WLAN_GET_PARAM, WL_SUPPORTED_RATES, 0)
-	    == B_TRUE) {
-		rates_num = ((wl_rates_t *)(gbuf->wldp_buf))->wl_rates_num;
-
-		for (i = 0; i < num; i++) {
-			PRTDBG(("rates[%d] = %d\n", i, rates[i]));
-			for (j = 0; j < rates_num; j++) {
-				value = ((wl_rates_t *)gbuf->wldp_buf)
-				    ->wl_rates_rates[j];
-				PRTDBG(("supported rates[%d]=%d\n", j, value));
-				if (value == rates[i]) {
-					break;
-				}
-			}
-			if (j == rates_num) {
-				if (rates[i] == 11) {
-					(void) fprintf(stderr,
-					    gettext("%s: "
-					    "rate 5.5M is not supported\n"),
-					    gExecName);
-				} else {
-					(void) fprintf(stderr,
-					    gettext("%s: "
-					    "rate %dM is not supported\n"),
-					    gExecName, rates[i]/2);
-				}
-				return (B_FALSE);
-			}
-		}
-		return (B_TRUE);
-	}
-	return (B_FALSE);
-}
-
-/*
- *
- */
-static uint8_t
-rates_convert(const char *rates)
-{
-	int i;
-	uint8_t ret;
-
-	for (i = 0; i < WIFI_RATES_NUM; i++) {
-		if (strcmp(rates, wifi_rates_s[i].rates_s) == 0) {
-			ret = wifi_rates_s[i].rates_i;
-			break;
-		}
-	}
-	if (i == WIFI_RATES_NUM) {
-		(void) fprintf(stderr, gettext("%s: "
-		    "invalid rates '%s'\n"), gExecName, rates);
-		exit(WIFI_FATAL_ERR);
-	}
-	return (ret);
-}
-
-/*
- * get_rates: convert string value arg into uint8_t array,
- * array length will be save into *len[i].
- * for example:
- * arg = "1,2,5.5,11"
- * then after call, rates[] = {2,4,11,22} will be returned.
- * and *len will equal to 4
- */
-static uint8_t *
-get_rates(const char *arg, uint32_t *len)
-{
-	int i = 1, j = 0;
-	uint8_t *rates = NULL;
-	char *pnext = NULL;
-	char *token;
-	char *pstart;
-	char *pstart_bak;
-
-	assert(arg != NULL);
-
-	if (strlen(arg) == 0) {
-		PRTDBG(("get_rates: empty rates string\n"));
-		return (NULL);
-	}
-	PRTDBG(("get_rates(\"%s\", 0x%x)\n", arg, len));
-	pstart = safe_strdup(arg);
-	pstart_bak = pstart;
-	while ((pnext = strchr(pstart, ',')) != NULL) {
-		pstart = pnext + 1;
-		i++;
-	}
-	*len = i;
-	rates = safe_calloc(sizeof (uint8_t), i);
-
-	pstart = pstart_bak;
-	if ((token = strtok(pstart, ",")) != NULL) {
-		PRTDBG(("rates[0]: %s\n", token));
-		rates[0] = rates_convert(token);
-		i = 1;
-		while ((token = strtok(NULL, ",")) != NULL) {
-			PRTDBG(("rates[%d]: %s\n", i, token));
-			rates[i++] = rates_convert(token);
-		}
-	}
-	free(pstart_bak);
-	for (i = 0; i < *len; i++) {
-		for (j = 0; j < i; j++)
-			if (rates[j] == rates[i]) {
-				(void) fprintf(stderr,
-				    gettext("%s: rates duplicated\n"),
-				    gExecName);
-				free(rates);
-				return (NULL);
-			}
-	}
-
-	return (rates);
-}
-
-static boolean_t
-do_set_rates(int fd, const char *arg)
-{
-	int i = 0;
-	uint32_t num = 0;
-	uint8_t *rates;
-
-	assert(arg != NULL);
-
-	PRTDBG(("do_set_rates(%d, \"%s\")\n", fd, arg));
-
-	rates = get_rates(arg, &num);
-	if ((rates == NULL) ||
-	    is_rates_support(fd, num, rates) == B_FALSE) {
-		exit(WIFI_FATAL_ERR);
-	}
-
-	((wl_rates_t *)(gbuf->wldp_buf))->wl_rates_num = num;
-	for (i = 0; i < num; i++) {
-		((wl_rates_t *)gbuf->wldp_buf)->wl_rates_rates[i]
-		    = rates[i];
-	}
-	free(rates);
-	return (call_ioctl(fd, WLAN_SET_PARAM, WL_DESIRED_RATES,
-	    offsetof(wl_rates_t, wl_rates_rates) +
-	    num*sizeof (char)));
-}
-
-static boolean_t
-do_set_powermode(int fd, const char *arg)
-{
-	wl_ps_mode_t ps_mode;
-
-	assert(arg != NULL);
-
-	PRTDBG(("do_set_powermode(%d, \"%s\")\n", fd, arg));
-
-	(void) memset(&ps_mode, 0xff, sizeof (ps_mode));
-
-	if ((strcasecmp(arg, "OFF") == 0) ||
-	    (strcasecmp(arg, "MPS") == 0) ||
-	    (strcasecmp(arg, "FAST") == 0)) {
-		switch (arg[0]) {
-		case 'O':
-		case 'o':
-			ps_mode.wl_ps_mode = WL_PM_AM;
-			break;
-		case 'M':
-		case 'm':
-			ps_mode.wl_ps_mode = WL_PM_MPS;
-			break;
-		case 'F':
-		case 'f':
-			ps_mode.wl_ps_mode = WL_PM_FAST;
-			break;
-		default:
-			break;
-		}
-	} else {
-		(void) fprintf(stderr,
-		    gettext("%s: powermode: off mps or fast\n"), gExecName);
-		exit(WIFI_FATAL_ERR);
-	}
-
-	(void) memmove(gbuf->wldp_buf, &ps_mode, sizeof (wl_ps_mode_t));
-	return (call_ioctl(fd, WLAN_SET_PARAM, WL_POWER_MODE,
-	    sizeof (wl_ps_mode_t)));
-}
-
-static boolean_t
-do_set_authmode(int fd, const char *arg)
-{
-	wl_authmode_t auth_mode;
-
-	assert(arg != NULL);
-	PRTDBG(("do_set_authmode(%d, \"%s\")\n", fd, arg));
-
-	(void) memset(&auth_mode, 0xff, sizeof (auth_mode));
-	/* Mark */
-	if (strcasecmp(arg, "OPENSYSTEM") == 0) {
-		auth_mode = WL_OPENSYSTEM;
-	} else if (strcasecmp(arg, "SHARED_KEY") == 0) {
-		auth_mode = WL_SHAREDKEY;
-	} else {
-		(void) fprintf(stderr,
-		    gettext("%s: authmode: "
-		    "opensystem or shared_key\n"), gExecName);
-		exit(WIFI_FATAL_ERR);
-	}
-
-	(void) memmove(gbuf->wldp_buf, &auth_mode, sizeof (wl_authmode_t));
-	return (call_ioctl(fd, WLAN_SET_PARAM, WL_AUTH_MODE,
-	    sizeof (wl_authmode_t)));
-}
-
-static boolean_t
-do_set_encryption(int fd, const char *arg)
-{
-	wl_encryption_t encryption;
-
-	assert(arg != NULL);
-	PRTDBG(("do_set_encryption(%d, \"%s\")\n", fd, arg));
-
-	(void) memset(&encryption, 0xff, sizeof (encryption));
-
-	if (strcasecmp(arg, "NONE") == 0) {
-		encryption = WL_NOENCRYPTION;
-	} else if (strcasecmp(arg, "WEP") == 0) {
-		encryption = WL_ENC_WEP;
-	} else {
-		(void) fprintf(stderr, gettext("%s: encryption: "
-		    "none or wep\n"), gExecName);
-		exit(WIFI_FATAL_ERR);
-	}
-
-	(void) memmove(gbuf->wldp_buf, &encryption, sizeof (wl_encryption_t));
-	return (call_ioctl(fd, WLAN_SET_PARAM, WL_ENCRYPTION,
-	    sizeof (wl_encryption_t)));
-}
-
-static boolean_t
-do_set_wepkeyid(int fd, const char *arg)
-{
-	wl_wep_key_id_t wep_key_id;
-
-	assert(arg != NULL);
-	PRTDBG(("do_set_wepkeyid(%d, \"%s\")\n", fd, arg));
-
-	(void) memset(&wep_key_id, 0xff, sizeof (wep_key_id));
-	if (is_wepkeyindex_valid(arg) == B_FALSE) {
-		(void) fprintf(stderr, gettext("%s: wepkeyindex "
-		    "should be an integer within the range 1-4\n"), gExecName);
-		exit(WIFI_FATAL_ERR);
-	}
-	wep_key_id = atoi(arg) - 1;
-
-	(void) memmove(gbuf->wldp_buf, &wep_key_id, sizeof (wl_wep_key_id_t));
-	return (call_ioctl(fd, WLAN_SET_PARAM, WL_WEP_KEY_ID,
-	    sizeof (wl_wep_key_id_t)));
-}
-
-static boolean_t
-do_set_radioon(int fd, const char *arg)
-{
-	wl_radio_t radio;
-
-	assert(arg != NULL);
-	PRTDBG(("do_set_radioon(%d, \"%s\")\n", fd, arg));
-
-	(void) memset(&radio, 0xff, sizeof (radio));
-
-	if (strcasecmp(arg, "ON") == 0) {
-		radio = B_TRUE;
-	} else if (strcasecmp(arg, "OFF") == 0) {
-		radio = B_FALSE;
-	} else {
-		(void) fprintf(stderr,
-		    gettext("%s: radio : on or off\n"), gExecName);
-		exit(WIFI_FATAL_ERR);
-	}
-
-	(void) memmove(gbuf->wldp_buf, &radio, sizeof (wl_radio_t));
-	return (call_ioctl(fd, WLAN_SET_PARAM, WL_RADIO, sizeof (wl_radio_t)));
-}
-/*
- * print_gbuf: After each ioctl system call, gbuf will contain result, gbuf
- * contents's format varies from each kind of ioctl system call.
- */
-static void
-print_gbuf(config_item_t index)
-{
-	int i = 0, j = 0;
-	uint32_t ess_num;
-	char **ess_argv;
-	uint32_t rates_num;
-	uint32_t subtype;
-	wl_bss_type_t bsstype;
-	wl_create_ibss_t createibss;
-	wl_ps_mode_t *ps_mode;
-	wl_authmode_t authmode;
-	wl_encryption_t encryption;
-	wl_wep_key_id_t wepkeyid;
-	wl_rssi_t signal;
-	wl_radio_t radioon;
-	wl_ess_conf_t **p_ess_conf;
-	wl_linkstatus_t linkstatus;
-	char format[256], *ntstr;
-	uint32_t maxessidlen = 0, nt = 0, cnt = 0;
-	int len;
-	uint8_t bssid[6];
-
-	PRTDBG(("print_gbuf(%d)\n", index));
-	assert(gbuf->wldp_length < MAX_BUF_LEN);
-
-	switch (index) {
-	case BSSID:
-		(void) printf("\tbssid: ");
-		(void) memset(bssid, 0, sizeof (bssid));
-		if (memcmp((uint8_t *)gbuf->wldp_buf, bssid, sizeof (bssid))
-		    == 0) {
-			(void) printf("none\n");
-			break;
-		}
-		(void) memset(bssid, 0xff, sizeof (bssid));
-		if (memcmp((uint8_t *)gbuf->wldp_buf, bssid, sizeof (bssid))
-		    == 0) {
-			(void) printf("none\n");
-			break;
-		}
-		for (i = 0; i < 5; i++)
-			(void) printf("%02x:", ((uint8_t *)gbuf->wldp_buf)[i]);
-		(void) printf("%02x\n", ((uint8_t *)gbuf->wldp_buf)[i]);
-		break;
-	case ESSID:
-		(void) printf("\tessid: %s\n", ((wl_essid_t *)(gbuf->wldp_buf))
-		    ->wl_essid_essid);
-		break;
-	case BSSTYPE:
-		bsstype = *(wl_bss_type_t *)(gbuf->wldp_buf);
-		switch (bsstype) {
-		case WL_BSS_BSS:
-			(void) printf("\tbsstype: bss(ap, infrastructure)\n");
-			break;
-		case WL_BSS_IBSS:
-			(void) printf("\tbsstype: ibss(ad-hoc)\n");
-			break;
-		case WL_BSS_ANY:
-			(void) printf("\tbsstype: auto\n");
-			break;
-		default:
-			(void) fprintf(stderr,
-			    gettext("%s: "
-			    "invalid bsstype value\n"), gExecName);
-		}
-		break;
-	case CREATEIBSS:
-		createibss = *(wl_create_ibss_t *)(gbuf->wldp_buf);
-		switch (createibss) {
-		case B_TRUE:
-			(void) printf("\tcreateibss: yes\n");
-			break;
-		case B_FALSE:
-			(void) printf("\tcreateibss: no\n");
-			break;
-		default:
-			(void) fprintf(stderr,
-			    gettext("%s: "
-			    "invalid createibss value\n"), gExecName);
-		}
-		break;
-	case CHANNEL:
-		subtype = ((wl_fhss_t *)(gbuf->wldp_buf))->wl_fhss_subtype;
-		switch (subtype) {
-		case WL_FHSS:
-		case WL_DSSS:
-		case WL_IRBASE:
-		case WL_HRDS:
-		case WL_ERP:
-			(void) printf("\tchannel: %d\n", ((wl_fhss_t *)
-			    (gbuf->wldp_buf))->wl_fhss_channel);
-			break;
-		case WL_OFDM:
-			(void) printf("\tchannel: %d\n", ((wl_ofdm_t *)
-			    (gbuf->wldp_buf))
-			    ->wl_ofdm_frequency);
-			break;
-		default:
-			(void) fprintf(stderr, gettext("%s: "
-			    "invalid subtype\n"), gExecName);
-			break;
-		}
-		break;
-	case RATES:
-		rates_num = ((wl_rates_t *)(gbuf->wldp_buf))->wl_rates_num;
-		(void) printf("\trates: ");
-		for (i = 0; i < rates_num; i++) {
-			char rate;
-			rate = ((wl_rates_t *)gbuf->wldp_buf)
-			    ->wl_rates_rates[i];
-			if (rate == WL_RATE_5_5M)
-				(void) printf("5.5");
-			else
-				(void) printf("%d", (uint8_t)(rate / 2));
-
-			if (i == (rates_num - 1))
-				(void) printf("\n");
-			else
-				(void) printf(",");
-		}
-		break;
-	case POWERMODE:
-		ps_mode = (wl_ps_mode_t *)(gbuf->wldp_buf);
-		switch (ps_mode->wl_ps_mode) {
-		case WL_PM_AM:
-			(void) printf("\tpowermode: off\n");
-			break;
-		case WL_PM_MPS:
-			(void) printf("\tpowermode: mps\n");
-			break;
-		case WL_PM_FAST:
-			(void) printf("\tpowermode: fast\n");
-			break;
-		default:
-			(void) fprintf(stderr,
-			    gettext("%s: "
-			    "invalid powermode value\n"), gExecName);
-			break;
-		}
-		break;
-	case AUTHMODE:
-		authmode = *(wl_authmode_t *)(gbuf->wldp_buf);
-		switch (authmode) {
-		case WL_OPENSYSTEM:
-			(void) printf("\tauthmode: opensystem\n");
-			break;
-		case WL_SHAREDKEY:
-			(void) printf("\tauthmode: shared_key\n");
-			break;
-		default:
-			(void) fprintf(stderr,
-			    gettext("%s: "
-			    "invalid authmode value\n"), gExecName);
-			break;
-		}
-		break;
-	case ENCRYPTION:
-		encryption = *(wl_encryption_t *)(gbuf->wldp_buf);
-		switch (encryption) {
-		case WL_NOENCRYPTION:
-			(void) printf("\tencryption: none\n");
-			break;
-		case WL_ENC_WEP:
-			(void) printf("\tencryption: wep\n");
-			break;
-		default:
-			(void) fprintf(stderr,
-			    gettext("%s: "
-			    "invalid encryption value\n"), gExecName);
-			break;
-		}
-		break;
-	case WEPKEYID:
-		wepkeyid = *(wl_wep_key_id_t *)(gbuf->wldp_buf);
-		(void) printf("\twepkeyindex: %d\n", wepkeyid + 1);
-		break;
-	case SIGNAL:
-		signal = *(wl_rssi_t *)(gbuf->wldp_buf);
-		(void) printf("\tsignal: %d\n", signal);
-		break;
-	case RADIOON:
-		radioon = *(wl_radio_t *)(gbuf->wldp_buf);
-		switch (radioon) {
-		case B_TRUE:
-			(void) printf("\tradio: on\n");
-			break;
-		case B_FALSE:
-			(void) printf("\tradio: off\n");
-			break;
-		default: /* Mark */
-			(void) fprintf(stderr,
-			    gettext("%s: "
-			    "invalid radioon value\n"), gExecName);
-		}
-		break;
-	case LINKSTATUS:
-		linkstatus = *(wl_linkstatus_t *)(gbuf->wldp_buf);
-		switch (linkstatus) {
-		case WL_CONNECTED:
-			(void) printf("\tlinkstatus: connected\n");
-			break;
-		case WL_NOTCONNECTED:
-			(void) printf("\tlinkstatus: not connected\n");
-			break;
-		default: /* Mark */
-			(void) fprintf(stderr,
-			    gettext("%s: "
-			    "invalid linkstatus value\n"), gExecName);
-		}
-		break;
-	case WLANLIST:
-		ess_num = ((wl_ess_list_t *)(gbuf->wldp_buf))->wl_ess_list_num;
-		ess_argv = safe_calloc(sizeof (char *), ess_num);
-		p_ess_conf = safe_calloc(sizeof (wl_ess_conf_t *), ess_num);
-		for (i = 0; i < ess_num; i++) {
-			p_ess_conf[i] = ((wl_ess_list_t *)gbuf->wldp_buf)
-			    ->wl_ess_list_ess + i;
-			maxessidlen = (maxessidlen >
-			    strlen(p_ess_conf[i]
-			    ->wl_ess_conf_essid.wl_essid_essid) ?
-			    maxessidlen :
-			    strlen(p_ess_conf[i]
-			    ->wl_ess_conf_essid.wl_essid_essid));
-		}
-		/*
-		 * construct the output format.
-		 */
-		if ((nt = (maxessidlen / 8 + 1)) > 4)
-			nt = 4;
-		len = snprintf(format, sizeof (format), gettext("essid"));
-		ntstr = construct_format(nt);
-		assert(ntstr != NULL);
-		len += snprintf(format + len, sizeof (format) - len, "%s",
-		    ntstr);
-		len += snprintf(format + len, sizeof (format) - len,
-		    gettext("bssid\t\t  type\t\tencryption\tsignallevel\n"));
-
-		if ((len <= 0) || (len > sizeof (format) - 1)) {
-			(void) printf("essid\t\t\t\tbssid\t\t  type\t\t"
-			    "encryption\tsignallevel\n");
-		} else {
-			(void) printf("%s", format);
-		}
-
-		for (i = 0; i < ess_num; i++) {
-			ess_argv[i] = safe_malloc(MAX_SCANBUF_LEN);
-			safe_snprintf(ess_argv[i], MAX_SCANBUF_LEN,
-			    "%s%c%02x:%02x:%02x:%02x:%02x:%02x%c%s",
-			    p_ess_conf[i]->wl_ess_conf_essid.wl_essid_essid,
-			    ',',
-			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[0]),
-			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[1]),
-			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[2]),
-			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[3]),
-			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[4]),
-			    (uint8_t)(p_ess_conf[i]->wl_ess_conf_bssid[5]), ',',
-			    (p_ess_conf[i]->wl_ess_conf_wepenabled ==
-			    B_TRUE ? "wep":"none"));
-			len = strlen(p_ess_conf[i]->wl_ess_conf_essid.
-			    wl_essid_essid);
-			cnt = nt - (min(len /8 + 1, 4) - 1);
-			ntstr = construct_format(cnt);
-			assert(ntstr != NULL);
-			(void) printf("%s%s", p_ess_conf[i]->wl_ess_conf_essid.
-			    wl_essid_essid, ntstr);
-			free(ntstr);
-			for (j = 0; j < 5; j++) {
-				(void) printf("%02x:", (uint8_t)(p_ess_conf[i]
-				    ->wl_ess_conf_bssid[j]));
-			}
-			(void) printf("%02x ", (uint8_t)(p_ess_conf[i]
-			    ->wl_ess_conf_bssid[j]));
-
-			if (p_ess_conf[i]->wl_ess_conf_bsstype ==
-			    WL_BSS_BSS)
-				(void) printf("access point");
-			else
-				(void) printf("ad-hoc");
-			if (p_ess_conf[i]->wl_ess_conf_wepenabled ==
-			    WL_ENC_WEP)
-				(void) printf("\twep\t");
-			else
-				(void) printf("\tnone\t");
-			(void) printf("\t%d\n", p_ess_conf[i]->wl_ess_conf_sl);
-		}
-		add_to_history(gp_config_file, ess_num, ess_argv);
-		free(p_ess_conf);
-		for (i = 0; i < ess_num; i++) {
-			free(ess_argv[i]);
-		}
-		free(ess_argv);
-		break;
-	default:
-		(void) fprintf(stderr, gettext("%s: "
-		    "invalid parameter type\n"), gExecName);
-		break;
-	}
-}
-/*
- * do_get_xxx: will send ioctl to driver, then the driver will fill gbuf
- * with related value. gbuf has a format of wldp_t structure.
- */
-static boolean_t
-do_get_bssid(int fd)
-{
-	PRTDBG(("do_get_bssid(%d)\n", fd));
-	return (call_ioctl(fd, WLAN_GET_PARAM, WL_BSSID, 0));
-}
-
-static boolean_t
-do_get_essid(int fd)
-{
-	PRTDBG(("do_get_essid(%d)\n", fd));
-	return (call_ioctl(fd, WLAN_GET_PARAM, WL_ESSID, 0));
-}
-
-static boolean_t
-do_get_bsstype(int fd)
-{
-	PRTDBG(("do_get_bsstype(%d)\n", fd));
-	return (call_ioctl(fd, WLAN_GET_PARAM, WL_BSS_TYPE, 0));
-}
-
-static boolean_t
-do_get_createibss(int fd)
-{
-	PRTDBG(("do_get_createibss(%d)\n", fd));
-	return (call_ioctl(fd, WLAN_GET_PARAM, WL_CREATE_IBSS, 0));
-}
-
-static boolean_t
-do_get_channel(int fd)
-{
-	PRTDBG(("do_get_channel(%d)\n", fd));
-	return (call_ioctl(fd, WLAN_GET_PARAM, WL_PHY_CONFIG, 0));
-}
-
-static boolean_t
-do_get_wlanlist(int fd)
-{
-	PRTDBG(("do_get_wlanlist(%d)\n", fd));
-	return (call_ioctl(fd, WLAN_GET_PARAM, WL_ESS_LIST, 0));
-}
-
-static boolean_t
-do_get_linkstatus(int fd)
-{
-	PRTDBG(("do_get_linkstauts(%d)\n", fd));
-	return (call_ioctl(fd, WLAN_GET_PARAM, WL_LINKSTATUS, 0));
-}
-
-static boolean_t
-do_get_rates(int fd)
-{
-	PRTDBG(("do_get_rates(%d)\n", fd));
-	return (call_ioctl(fd, WLAN_GET_PARAM, WL_DESIRED_RATES, 0));
-}
-
-static boolean_t
-do_get_powermode(int fd)
-{
-	PRTDBG(("do_get_powermode(%d)\n", fd));
-	return (call_ioctl(fd, WLAN_GET_PARAM, WL_POWER_MODE, 0));
-}
-
-static boolean_t
-do_get_authmode(int fd)
-{
-	PRTDBG(("do_get_authmode(%d)\n", fd));
-	return (call_ioctl(fd, WLAN_GET_PARAM, WL_AUTH_MODE, 0));
-}
-
-static boolean_t
-do_get_encryption(int fd)
-{
-	PRTDBG(("do_get_encryption(%d)\n", fd));
-	return (call_ioctl(fd, WLAN_GET_PARAM, WL_ENCRYPTION, 0));
-}
-
-static boolean_t
-do_get_wepkeyid(int fd)
-{
-	PRTDBG(("do_get_wepkeyid(%d)\n", fd));
-	return (call_ioctl(fd, WLAN_GET_PARAM, WL_WEP_KEY_ID, 0));
-}
-static boolean_t
-do_get_signal(int fd)
-{
-	PRTDBG(("do_get_signal(%d)\n", fd));
-	return (call_ioctl(fd, WLAN_GET_PARAM, WL_RSSI, 0));
-}
-
-static boolean_t
-do_get_radioon(int fd)
-{
-	PRTDBG(("do_get_radioon(%d)\n", fd));
-	return (call_ioctl(fd, WLAN_GET_PARAM, WL_RADIO, 0));
-}
-
-/*
- * param has two kinds of forms:
- * 'wepkeyn=*****' (when equalflag == B_TRUE),
- * 'wepkeyn' (when equalflag == B_FALSE)
- */
-static boolean_t
-param_is_wepkey(char *param, boolean_t equalflag)
-{
-	if ((equalflag == B_FALSE) &&
-	    (strcmp(param, "wepkey1") == 0) ||
-	    (strcmp(param, "wepkey2") == 0) ||
-	    (strcmp(param, "wepkey3") == 0) ||
-	    (strcmp(param, "wepkey4") == 0))
-		return (B_TRUE);
-	else if ((equalflag == B_TRUE) &&
-	    (strncmp(param, "wepkey1=", strlen("wepkey1="))) == 0 ||
-	    (strncmp(param, "wepkey2=", strlen("wepkey2="))) == 0 ||
-	    (strncmp(param, "wepkey3=", strlen("wepkey3="))) == 0 ||
-	    (strncmp(param, "wepkey4=", strlen("wepkey4="))) == 0)
-		return (B_TRUE);
-	else
-		return (B_FALSE);
-}
-
-/*
- * update/add items in the profile
- */
-static boolean_t
-items_in_profile(aelist_t *cplist, aelist_t *wplist, int argc, char **argv)
-{
-	int i = 0, j = 0;
-	char *param;
-	char *pequal;
-	const char *wepkey;
-
-	for (i = 0; i < argc; i++) {
-		if (param_is_wepkey(argv[i], B_TRUE) == B_TRUE) {
-			wepkey = get_value(argv[i]);
-			if (value_is_valid(WEPKEY, wepkey) == B_FALSE) {
-				(void) fprintf(stderr, gettext("%s: "
-				    "invalid value '%s' for parameter "
-				    "'wepkey'\n"), gExecName, wepkey);
-				return (B_FALSE);
-			}
-			update_aelist(wplist, argv[i]);
-			continue;
-		}
-		param = safe_strdup(argv[i]);
-		pequal = strchr(param, '=');
-		if (pequal == NULL) {
-			(void) fprintf(stderr, gettext("%s: "
-			    "invalid argument '%s', use "
-			    "parameter=value'\n"),
-			    gExecName, argv[i]);
-			free(param);
-			return (B_FALSE);
-		}
-
-		*pequal++ = '\0';
-		for (j = 0; j < N_GS_FUNC; j++) {
-			if (strcmp(param, do_gs_func[j].cmd) == 0) {
-				break;
-			}
-		}
-		if (j == N_GS_FUNC) {
-			(void) fprintf(stderr, gettext("%s: "
-			    "unrecognized parameter '%s'\n"),
-			    gExecName, param);
-			free(param);
-			return (B_FALSE);
-		}
-		if (value_is_valid(do_gs_func[j].index, pequal) ==
-		    B_FALSE) {
-			(void) fprintf(stderr, gettext("%s: "
-			    "invalid value '%s' for parameter '%s'\n"),
-			    gExecName, pequal, param);
-			return (B_FALSE);
-		}
-		free(param);
-		update_aelist(cplist, argv[i]);
-	}
-	return (B_TRUE);
-}
-
-/*
- * do_createprofile: Called when create a profile off-line.
- */
-/*ARGSUSED*/
-static boolean_t
-do_createprofile(int fd, int argc, char **argv)
-{
-	int i = 0;
-	char *pbuf = NULL;
-	char *pfbuf = NULL;
-	const char *profilename;
-	aelist_t *plist_config = NULL, *plist_wepkey = NULL;
-
-	PRTDBG(("do_createprofile(%d, 0x%x)\n", argc, argv));
-	if (argc <= 0) {
-		do_print_usage();
-		exit(WIFI_IMPROPER_USE);
-	}
-	/*
-	 * When creating a profile, if the profile name is not specified,
-	 * the essid is selected as the profile name. the paramters are
-	 * saved into the section.
-	 */
-	if (strchr(argv[0], '=') == NULL) {
-		pfbuf = safe_strdup(argv[0]);
-		argc--;
-		argv++;
-	}
-	for (i = 0; i < argc; i++) {
-		if (strncmp(argv[i], "essid=", strlen("essid=")) == 0) {
-			break;
-		}
-	}
-	if (i == argc) {
-		(void) fprintf(stderr,
-		    gettext("%s: "
-		    "essid required when creating profile\n"),
-		    gExecName);
-		goto exit0;
-	}
-	profilename = (pfbuf ? pfbuf : get_value(argv[i]));
-	if (strlen(profilename) == 0) {
-		(void) fprintf(stderr,
-		    gettext("%s: "
-		    "non-empty essid required\n"),
-		    gExecName);
-		goto exit0;
-	}
-	/*
-	 * 'all', '{preference}', '{history}', '{active_profile}'
-	 * and any string with '[' as start and ']' as end should
-	 * not be a profile name
-	 */
-	if ((strcasecmp(profilename, "all") == 0) ||
-	    (strcmp(profilename, WIFI_HISTORY) == 0) ||
-	    (strcmp(profilename, WIFI_PREFER) == 0) ||
-	    (strcmp(profilename, WIFI_ACTIVEP) == 0) ||
-	    ((profilename[0] == '[') &&
-	    (profilename[strlen(profilename) - 1] == ']'))) {
-		(void) fprintf(stderr, gettext("%s: "
-		    "'%s' is an invalid profile name\n"),
-		    gExecName, profilename);
-		goto exit0;
-	}
-	pbuf = append_pa(profilename);
-
-	PRTDBG(("do_createprofile: profile_name = %s\n", pbuf));
-	if ((find_section(gp_config_file, pbuf) != NULL) ||
-	    find_section(gp_wepkey_file, pbuf) != NULL) {
-		(void) fprintf(stderr,
-		    gettext("%s: "
-		    "profile '%s' already exists\n"),
-		    gExecName, profilename);
-		goto exit1;
-	}
-	/*
-	 * Save each parameters in the profile.
-	 */
-	plist_config = new_ael(PROFILE);
-	new_section(gp_config_file, plist_config, pbuf);
-	plist_wepkey = new_ael(PROFILE);
-	new_section(gp_wepkey_file, plist_wepkey, pbuf);
-	free(pfbuf);
-	free(pbuf);
-	return (items_in_profile(plist_config, plist_wepkey,
-	    argc, argv));
-exit1:
-	free(pbuf);
-exit0:
-	free(pfbuf);
-	return (B_FALSE);
-}
-
-/*ARGSUSED*/
-static boolean_t
-do_setprofparam(int fd, int argc, char **argv)
-{
-	char *pbuf = NULL;
-	section_t *psection_config = NULL, *psection_wep = NULL;
-	aelist_t *plist_config = NULL, *plist_wepkey = NULL;
-
-	PRTDBG(("do_setprofparam(%d, 0x%x)\n", argc, argv));
-	if (argc < 1) {
-		do_print_usage();
-		exit(WIFI_IMPROPER_USE);
-	}
-	pbuf = append_pa(argv[0]);
-
-	psection_config = find_section(gp_config_file, pbuf);
-	psection_wep = find_section(gp_wepkey_file, pbuf);
-	if ((psection_config == NULL) || (psection_wep == NULL)) {
-		(void) fprintf(stderr, gettext("%s: "
-		    "profile '%s' doesn't exist\n"),
-		    gExecName, argv[0]);
-		free(pbuf);
-		return (B_FALSE);
-	}
-	free(pbuf);
-	/*
-	 * modify each parameters in the profile.
-	 */
-	plist_config = psection_config->list;
-	plist_wepkey = psection_wep->list;
-	argc--;
-	argv++;
-	return (items_in_profile(plist_config, plist_wepkey,
-	    argc, argv));
-}
-
-/*ARGSUSED*/
-static boolean_t
-do_getprofparam(int fd, int argc, char **argv)
-{
-	int i = 0, j = 0;
-	int flag;
-	boolean_t ret = B_TRUE;
-	section_t *p_section = NULL;
-	aelist_t *plist = NULL;
-	ae_t *pae = NULL;
-	char *pbuf = NULL;
-
-	PRTDBG(("do_getprofparam(%d, 0x%x)\n", argc, argv));
-	if (argc < 1) {
-		do_print_usage();
-		exit(WIFI_IMPROPER_USE);
-	}
-	pbuf = append_pa(argv[0]);
-	p_section = find_section(gp_config_file, pbuf);
-	if (p_section == NULL) {
-		(void) fprintf(stderr, gettext("%s: "
-		    "profile '%s' doesn't exist\n"),
-		    gExecName, argv[0]);
-		ret = B_FALSE;
-		goto exit0;
-	}
-	argc--;
-	argv++;
-
-	plist = p_section->list;
-	assert(plist != NULL);
-	/*
-	 * If no specific parameter typed, we print out all parameters
-	 */
-	if (argc == 0) {
-		pae = plist->ael_head;
-		while (pae != NULL) {
-			if (pae->ae_arg != NULL) {
-				(void) printf("\t%s\n", pae->ae_arg);
-			}
-			pae = pae->ae_next;
-		}
-		print_wepkey_info(p_section->section_id, NULL);
-		ret = B_TRUE;
-		goto exit0;
-	}
-
-	/*
-	 * Match function with do_gs_func[] table, and print its result
-	 */
-	for (i = 0; i < argc; i++) {
-		flag = 0;
-		for (j = 0; j < N_GS_FUNC; j++) {
-			if (strcmp(argv[i], do_gs_func[j].cmd) == 0) {
-				break;
-			}
-			if (param_is_wepkey(argv[i], B_FALSE) == B_TRUE) {
-				j = WEPKEY;
-				print_wepkey_info(p_section->section_id,
-				    argv[i]);
-				flag++;
-				break;
-			}
-		}
-		if (j == N_GS_FUNC) {
-			(void) fprintf(stderr,
-			    gettext("wificonifg: unrecognized parameter: "
-			    "%s\n"), argv[i]);
-			ret = B_FALSE;
-			goto exit0;
-		}
-
-		pae = plist->ael_head;
-		while ((pae != NULL) && (!flag)) {
-			if ((pae->ae_arg != NULL) &&
-			    (strncmp(pae->ae_arg, argv[i],
-			    strlen(argv[i])) == 0)) {
-				(void) printf("\t%s\n", pae->ae_arg);
-				flag++;
-			}
-			pae = pae->ae_next;
-		}
-		if (!flag) {
-			(void) fprintf(stderr, gettext("%s: "
-			    "parameter '%s' has not been set in profile %s\n"),
-			    gExecName, argv[i], pbuf);
-			ret = B_FALSE;
-			goto exit0;
-		}
-	}
-exit0:
-	free(pbuf);
-	return (ret);
-}
-
-/*
- * Verify whether the value in the parameter=value pair is valid or not.
- * For the channel, since we donot know what kind of wifi card(a,b,or g)
- * is in the system, so we just leave to verify the validity of the value
- * when the value is set to the card.
- * The same goes for the rates.
- */
-static boolean_t
-value_is_valid(config_item_t item, const char *value)
-{
-	uint32_t num = 0;
-	uint8_t *rates;
-	boolean_t ret;
-
-	assert(value != NULL);
-	switch (item) {
-	case ESSID:
-		if (strlen(value) > 32)
-			ret = B_FALSE;
-		else
-			ret = B_TRUE;
-		break;
-	case BSSTYPE:
-		if ((strcasecmp(value, "bss") == 0) ||
-		    (strcasecmp(value, "ap") == 0) ||
-		    (strcasecmp(value, "infrastructure") == 0) ||
-		    (strcasecmp(value, "ibss") == 0) ||
-		    (strcasecmp(value, "ad-hoc") == 0) ||
-		    (strcasecmp(value, "auto") == 0))
-			ret = B_TRUE;
-		else
-			ret = B_FALSE;
-		break;
-	case CREATEIBSS:
-		if ((strcasecmp(value, "yes") == 0) ||
-		    (strcasecmp(value, "no") == 0))
-			ret = B_TRUE;
-		else
-			ret = B_FALSE;
-		break;
-	case AUTHMODE:
-		if ((strcasecmp(value, "opensystem") == 0) ||
-		    (strcasecmp(value, "shared_key") == 0))
-			ret = B_TRUE;
-		else
-			ret = B_FALSE;
-		break;
-	case POWERMODE:
-		if ((strcasecmp(value, "off") == 0) ||
-		    (strcasecmp(value, "mps") == 0) ||
-		    (strcasecmp(value, "fast") == 0))
-			ret = B_TRUE;
-		else
-			ret = B_FALSE;
-		break;
-	case ENCRYPTION:
-		if ((strcasecmp(value, "wep") == 0) ||
-		    (strcasecmp(value, "none") == 0))
-			ret = B_TRUE;
-		else
-			ret = B_FALSE;
-		break;
-	case RADIOON:
-		if ((strcasecmp(value, "on") == 0) ||
-		    (strcasecmp(value, "off") == 0))
-			ret = B_TRUE;
-		else
-			ret = B_FALSE;
-		break;
-	case WEPKEYID:
-		ret = is_wepkeyindex_valid(value);
-		break;
-	case WEPKEY:
-		ret = is_wepkey_valid(value, strlen(value));
-		break;
-	case CHANNEL:
-		ret = is_channel_valid(value);
-		break;
-	case RATES:
-		rates = get_rates(value, &num);
-		if (rates == NULL) {
-			ret = B_FALSE;
-		} else {
-			free(rates);
-			ret = B_TRUE;
-		}
-		break;
-	default:
-		ret = B_FALSE;
-		break;
-	}
-
-	return (ret);
-}
-
-/*
- * do_set: Called when set a parameter, the format should be
- * parameter=value.
- */
-static boolean_t
-do_set(int fd, int argc, char **argv)
-{
-	int i = 0, j = 0;
-	char *param;
-	char *pequal;
-	char *value;
-	boolean_t ret;
-
-	PRTDBG(("do_set(%d, 0x%x)\n", argc, argv));
-	assert(fd > 0);
-	if (argc <= 0) {
-		(void) do_print_support_params(fd);
-		ret = B_FALSE;
-		goto exit0;
-	}
-	/*
-	 * Set each parameters, if one failed, others behind it will
-	 * not be set
-	 */
-	for (i = 0; i < argc; i++) {
-		/*
-		 * Separate param and its value, if the user types "param=",
-		 * then value will be set to "";if the user types "param",
-		 * it is an error.
-		 */
-		param = safe_strdup(argv[i]);
-		pequal = strchr(param, '=');
-		value = NULL;
-		if (pequal != NULL) {
-			*pequal = '\0';
-			value = pequal + 1;
-		} else {
-			(void) fprintf(stderr,
-			    gettext("%s: invalid setparam argument "
-			    "'%s', use 'parameter=value'\n"),
-			    gExecName, argv[i]);
-			free(param);
-			ret = B_FALSE;
-			goto exit0;
-		}
-		PRTDBG(("do_set: param = \"%s\", value = \"%s\"\n",
-		    param, value));
-		for (j = 0; j < N_GS_FUNC; j++) {
-			/*
-			 * Match each parameters with do_gs_func table,
-			 */
-			if (strcmp(param, do_gs_func[j].cmd) == 0)
-				break;
-			if (param_is_wepkey(param, B_FALSE) == B_TRUE) {
-				value = argv[i];
-				j = WEPKEY;
-				break;
-			}
-		}
-		if (j == N_GS_FUNC) {
-			(void) fprintf(stderr,
-			    gettext("%s: unrecognized parameter: "
-			    "%s\n"), gExecName, param);
-			free(param);
-			ret  = B_FALSE;
-			goto exit0;
-		}
-
-		if (do_gs_func[j].p_do_set_func == NULL) {
-			(void) fprintf(stderr,
-			    gettext("%s: parameter '%s' is read-only\n"),
-			    gExecName, do_gs_func[j].cmd);
-			free(param);
-			ret = B_FALSE;
-			goto exit0;
-		}
-		if (do_gs_func[j].p_do_set_func(fd, value)
-		    == B_TRUE) {
-			ret = B_TRUE;
-		} else {
-			if (gbuf->wldp_result != WL_SUCCESS) {
-				(void) fprintf(stderr,
-				    gettext("%s: "
-				    "failed to set '%s' for "),
-				    gExecName, param);
-				print_error(gbuf->wldp_result);
-			}
-			free(param);
-			ret = B_FALSE;
-			goto exit0;
-		}
-		free(param);
-	}
-exit0:
-	return (ret);
-}
-
-static boolean_t
-do_get(int fd, int argc, char **argv)
-{
-	int i = 0, j = 0, n = 0;
-	boolean_t ret = B_TRUE;
-
-	PRTDBG(("do_get(%d, 0x%x)\n", argc, argv));
-	assert(fd > 0);
-	/*
-	 * If no specific parameter typed, we print out all parameters
-	 */
-	if (argc <= 0) {
-		for (i = 0; i < N_GS_FUNC; i++) {
-			if ((do_gs_func[i].p_do_get_func != NULL) &&
-			    (do_gs_func[i].p_do_get_func(fd)
-			    == B_TRUE)) {
-				print_gbuf(do_gs_func[i].index);
-				n++;
-			}
-		}
-		ret = n ? B_TRUE:B_FALSE;
-		goto exit0;
-	}
-	/*
-	 * Match function with do_gs_func[] table, and print its result
-	 */
-	for (i = 0; i < argc; i++) {
-		for (j = 0; j < N_GS_FUNC; j++) {
-			if (strcmp(argv[i], do_gs_func[j].cmd) == 0) {
-				break;
-			}
-			if (param_is_wepkey(argv[i], B_FALSE) == B_TRUE) {
-				j = WEPKEY;
-				break;
-			}
-		}
-		if (j == N_GS_FUNC) {
-			(void) fprintf(stderr,
-			    gettext("wificonifg: unrecognized parameter: "
-			    "%s\n"), argv[i]);
-			ret = B_FALSE;
-			goto exit0;
-		}
-		if (do_gs_func[j].p_do_get_func == NULL) {
-			(void) fprintf(stderr,
-			    gettext("%s: parameter '%s' is write-only\n"),
-			    gExecName, do_gs_func[j].cmd);
-			ret = B_FALSE;
-			goto exit0;
-		}
-		if (do_gs_func[j].p_do_get_func(fd) == B_TRUE) {
-			print_gbuf(do_gs_func[j].index);
-			ret = B_TRUE;
-		} else {
-			(void) fprintf(stderr,
-			    gettext("%s: "
-			    "failed to read parameter '%s' : "),
-			    gExecName, argv[i]);
-			print_error(gbuf->wldp_result);
-			ret = B_FALSE;
-		}
-	}
-exit0:
-	return (ret);
-}
-
-/*
- * Only one wificonfig is running at one time.
- * The following wificonfig which tries to be run will return error,
- * and the pid of the process will own the filelock will be printed out.
- */
-static pid_t
-enter_wifi_lock(int *fd)
-{
-	int fd0 = -1;
-	struct flock lock;
-
-	fd0 = open(WIFI_LOCKF, O_CREAT|O_WRONLY, 0600);
-	if (fd0 < 0) {
-		(void) fprintf(stderr, gettext("%s: failed to open lockfile"
-		    " '"WIFI_LOCKF"': %s\n"), gExecName, strerror(errno));
-		exit(WIFI_FATAL_ERR);
-	}
-
-	*fd = fd0;
-	lock.l_type = F_WRLCK;
-	lock.l_whence = SEEK_SET;
-	lock.l_start = 0;
-	lock.l_len = 0;
-
-	if ((fcntl(fd0, F_SETLK, &lock) == -1) &&
-	    (errno == EAGAIN || errno == EDEADLK)) {
-		if (fcntl(fd0, F_GETLK, &lock) == -1) {
-			(void) fprintf(stderr,
-			    gettext("%s: enter_filelock"));
-			exit(WIFI_FATAL_ERR);
-		}
-		(void) fprintf(stderr, gettext("%s:"
-		    "enter_filelock:filelock is owned "
-		    "by 'process %d'\n"), gExecName, lock.l_pid);
-		return (lock.l_pid);
-	}
-
-	return (getpid());
-}
-
-static void
-exit_wifi_lock(int fd)
-{
-	struct flock lock;
-
-	lock.l_type = F_UNLCK;
-	lock.l_whence = SEEK_SET;
-	lock.l_start = 0;
-	lock.l_len = 0;
-	if (fcntl(fd, F_SETLK, &lock) == -1) {
-		(void) fprintf(stderr, gettext("%s: failed to"
-		    " exit_filelock: %s\n"),
-		    gExecName, strerror(errno));
-	}
-	(void) close(fd);
-}
-
-int
-main(int argc, char **argv)
-{
-	int i, ret;
-	int fddev = -1;
-	int c, iflag = 0, rflag = 0, fileonly = 0, readonly = 0;
-	int fd;
-	char *iname = NULL;
-	char *path = NULL;
-	extern char *optarg;
-	extern int optind;
-	char interface[LIFNAMSIZ];
-	char file_wifi[MAX_CONFIG_FILE_LENGTH];
-	char file_wifiwepkey[MAX_CONFIG_FILE_LENGTH];
-	priv_set_t *ppriv;
-	wifi_auth_t autht;
-
-	PRTDBG(("main(%d, 0x%x)\n", argc, argv));
-	PRTDBG(("uid=%d\n", getuid()));
-	PRTDBG(("euid=%d\n", geteuid()));
-
-#ifdef DEBUG
-	if (wifi_debug == 1) { /* for debuf purpose only */
-		(void) printf("Press RETURN to continue...\n");
-		(void) getchar();
-	}
-#endif
-	ret = WIFI_EXIT_DEF;
-
-	(void) setlocale(LC_ALL, "");
-	(void) textdomain(TEXT_DOMAIN);
-
-	gExecName = argv[0];
-
-	gbuf = safe_malloc(MAX_BUF_LEN);
-
-	if ((ppriv = priv_str_to_set("basic", ",", NULL)) == NULL) {
-		PRTDBG(("main: priviledge init error\n"));
-		(void) fprintf(stderr, gettext("%s: "
-		    "set priviledge to 'basic' error\n"),
-		    gExecName);
-		ret = WIFI_FATAL_ERR;
-		goto exit0;
-	}
-	(void) priv_addset(ppriv, PRIV_NET_RAWACCESS);
-	(void) priv_addset(ppriv, PRIV_SYS_NET_CONFIG);
-	if (setppriv(PRIV_SET, PRIV_PERMITTED, ppriv) == -1) {
-		(void) fprintf(stderr, gettext("%s: "
-		    "set permitted priviledge: %s\n"),
-		    gExecName, strerror(errno));
-		ret = WIFI_FATAL_ERR;
-		goto exit0;
-	}
-	if (setppriv(PRIV_SET, PRIV_LIMIT, ppriv) == -1) {
-		(void) fprintf(stderr, gettext("%s: "
-		    "set limit priviledge: %s\n"),
-		    gExecName, strerror(errno));
-		ret = WIFI_FATAL_ERR;
-		goto exit0;
-	}
-	if (setppriv(PRIV_SET, PRIV_INHERITABLE, ppriv) == -1) {
-		(void) fprintf(stderr, gettext("%s: "
-		    "set inherit priviledge: %s\n"),
-		    gExecName, strerror(errno));
-		ret = WIFI_FATAL_ERR;
-		goto exit0;
-	}
-	if (setppriv(PRIV_SET, PRIV_EFFECTIVE, ppriv) == -1) {
-		(void) fprintf(stderr, gettext("%s: "
-		    "set effective priviledge: %s\n"),
-		    gExecName, strerror(errno));
-		ret = WIFI_FATAL_ERR;
-		goto exit0;
-	}
-	priv_freeset(ppriv);
-
-	for (i = 0; i < argc; i++) {
-		PRTDBG(("%d\t\t\"%s\"\n", i, argv[i]));
-	}
-
-	while ((c = getopt(argc, argv, "i:R:")) != EOF) {
-		switch (c) {
-		case 'i':
-			if (iflag) {
-				do_print_usage();
-				ret = WIFI_IMPROPER_USE;
-				goto exit0;
-			}
-			iflag = 1;
-			iname = optarg;
-			break;
-		case 'R':
-			if (rflag) {
-				do_print_usage();
-				ret = WIFI_IMPROPER_USE;
-				goto exit0;
-			}
-			rflag = 1;
-			path = optarg;
-			break;
-		case '?':
-		default:
-			do_print_usage();
-			ret = WIFI_IMPROPER_USE;
-			goto exit0;
-		}
-	}
-	argc -= optind;
-	argv +=	optind;
-
-	if (argc <= 0) {
-		if (iname) {
-			if ((fddev = open_dev(iname)) == -1) {
-				ret = WIFI_FATAL_ERR;
-				goto exit0;
-			}
-			if (do_print_support_params(fddev) ==
-			    B_TRUE)
-				ret = WIFI_EXIT_DEF;
-			else
-				ret = WIFI_FATAL_ERR;
-			goto exit1;
-		} else {
-			do_print_usage();
-			ret = WIFI_IMPROPER_USE;
-			goto exit0;
-		}
-	}
-
-	for (i = 0; i < N_FUNC; i++) {
-		if (strcmp(argv[0], do_func[i].cmd) == 0) {
-			autht = ((strcmp(argv[0], "setwepkey") == 0) ||
-			    (strcmp(argv[0], "setprofwepkey") == 0)) ?
-			    AUTH_WEP:AUTH_OTHER;
-			if (do_func[i].b_auth &&
-			    !check_authority(autht)) {
-				ret = WIFI_FATAL_ERR;
-				goto exit0;
-			}
-			if (do_func[i].b_fileonly)
-				fileonly++;
-			if (do_func[i].b_readonly)
-				readonly++;
-			break;
-		}
-	}
-	if (i == N_FUNC) {
-		(void) fprintf(stderr, gettext("%s: unrecognized "
-		    "subcommand: %s\n"), gExecName, argv[0]);
-		do_print_usage();
-		ret = WIFI_IMPROPER_USE;
-		goto exit0;
-	}
-	if ((fileonly) && (iname)) {
-		do_print_usage();
-		ret = WIFI_IMPROPER_USE;
-		goto exit0;
-	}
-	if ((!fileonly) && (!iname)) {
-		if (search_interface(interface) != B_TRUE) {
-			(void) fprintf(stderr, gettext("%s: "
-			    "failed to find the default wifi interface;"
-			    " -i option should be used to specify the "
-			    "wifi interface\n"), gExecName);
-			ret = WIFI_FATAL_ERR;
-			goto exit0;
-		}
-		iname = interface;
-	}
-	if (iname) {
-		if ((fddev = open_dev(iname)) == -1) {
-			ret = WIFI_FATAL_ERR;
-			goto exit0;
-		}
-	}
-	if (rflag) {
-		safe_snprintf(file_wifi, sizeof (file_wifi),
-		    "%s%s", path, p_file_wifi);
-		safe_snprintf(file_wifiwepkey, sizeof (file_wifiwepkey),
-		    "%s%s", path, p_file_wifiwepkey);
-	} else {
-		safe_snprintf(file_wifi, sizeof (file_wifi),
-		    "%s", p_file_wifi);
-		safe_snprintf(file_wifiwepkey, sizeof (file_wifiwepkey),
-		    "%s", p_file_wifiwepkey);
-	}
-	/*
-	 * There is an occasion when more than one wificonfig processes
-	 * which attempt to write the <wifi> and <wifiwepkey> files are
-	 * running. We must be able to avoid this.
-	 * We use file lock here to implement this.
-	 */
-	if ((!readonly) && (enter_wifi_lock(&fd) != getpid())) {
-		ret = WIFI_FATAL_ERR;
-		goto exit1;
-	}
-	gp_config_file = parse_file(file_wifi);
-	if (gp_config_file == NULL) {
-		ret = WIFI_FATAL_ERR;
-		goto exit2;
-	}
-
-	gp_wepkey_file = parse_file(file_wifiwepkey);
-	if (gp_wepkey_file == NULL) {
-		destroy_config(gp_config_file);
-		ret = WIFI_FATAL_ERR;
-		goto exit2;
-	}
-	if (do_func[i].p_do_func(fddev, argc-1, argv+1)
-	    == B_TRUE) {
-		/*
-		 * can not write file when startconfing
-		 * during boot
-		 */
-		if (do_func[i].b_readonly)
-			ret = WIFI_EXIT_DEF;
-		else if ((fprint_config_file(gp_config_file,
-		    file_wifi) != B_TRUE) ||
-		    (fprint_config_file(gp_wepkey_file,
-		    file_wifiwepkey) != B_TRUE))
-			ret = WIFI_FATAL_ERR;
-		else
-			ret = WIFI_EXIT_DEF;
-	} else {
-		PRTDBG(("Command %s failed\n", argv[0]));
-		ret = WIFI_FATAL_ERR;
-	}
-	destroy_config(gp_wepkey_file);
-	destroy_config(gp_config_file);
-exit2:
-	if (!readonly)
-		exit_wifi_lock(fd);
-exit1:
-	if (iname)
-		(void) close(fddev);
-exit0:
-	free(gbuf);
-	return (ret);
-}
-
-#ifdef DEBUG
-static void
-wifi_dbgprintf(char *fmt, ...)
-{
-	va_list ap;
-	va_start(ap, fmt);
-	(void) vfprintf(stdout, fmt, ap);
-	va_end(ap);
-}
-#endif
--- a/usr/src/cmd/dladm/dladm.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/dladm/dladm.c	Wed May 29 08:31:24 2013 +0200
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #include <stdio.h>
@@ -40,7 +41,6 @@
 #include <unistd.h>
 #include <priv.h>
 #include <limits.h>
-#include <termios.h>
 #include <pwd.h>
 #include <auth_attr.h>
 #include <auth_list.h>
@@ -51,6 +51,7 @@
 #include <libdllink.h>
 #include <libdlstat.h>
 #include <libdlaggr.h>
+#include <secobj.h>
 #include <libdlwlan.h>
 #include <libdlvlan.h>
 #include <libdlvnic.h>
@@ -84,13 +85,6 @@
 #define	SMF_DLADM_UPGRADE_MSG		" # added by dladm(1M)"
 #define	DLADM_DEFAULT_COL	80
 
-/*
- * used by the wifi show-* commands to set up ofmt_field_t structures.
- */
-#define	WIFI_CMD_SCAN		0x00000001
-#define	WIFI_CMD_SHOW		0x00000002
-#define	WIFI_CMD_ALL		(WIFI_CMD_SCAN | WIFI_CMD_SHOW)
-
 /* No larger than pktsum_t */
 typedef struct brsum_s {
 	uint64_t	drops;
@@ -191,7 +185,6 @@
 static ofmt_cb_t print_lacp_cb, print_phys_one_mac_cb;
 static ofmt_cb_t print_xaggr_cb, print_aggr_stats_cb;
 static ofmt_cb_t print_phys_one_hwgrp_cb, print_wlan_attr_cb;
-static ofmt_cb_t print_wifi_status_cb, print_link_attr_cb;
 static void dladm_ofmt_check(ofmt_status_t, boolean_t, ofmt_handle_t);
 
 typedef void cmdfunc_t(int, char **, const char *);
@@ -202,7 +195,7 @@
 static cmdfunc_t do_scan_wifi, do_connect_wifi, do_disconnect_wifi;
 static cmdfunc_t do_show_linkprop, do_set_linkprop, do_reset_linkprop;
 static cmdfunc_t do_create_secobj, do_delete_secobj, do_show_secobj;
-static cmdfunc_t do_init_linkprop, do_init_secobj;
+static cmdfunc_t do_init_linkprop;
 static cmdfunc_t do_create_vlan, do_delete_vlan, do_up_vlan, do_show_vlan;
 static cmdfunc_t do_rename_link, do_delete_phys, do_init_phys;
 static cmdfunc_t do_show_linkmap;
@@ -288,17 +281,19 @@
 	    "[<link>]\n"						},
 	{ "up-aggr",		do_up_aggr,	NULL			},
 	{ "scan-wifi",		do_scan_wifi,
-	    "    scan-wifi        [-p] [-o <field>,...] [<link>]"	},
+	    "    scan-wifi        <link>"	},
 	{ "connect-wifi",	do_connect_wifi,
-	    "    connect-wifi     [-e <essid>] [-i <bssid>] [-k <key>,...] "
-	    "[-s wep|wpa]\n"
-	    "\t\t     [-a open|shared] [-b bss|ibss] [-c] [-m a|b|g] "
-	    "[-T <time>]\n"
-	    "\t\t     [<link>]"						},
+	    "    connect-wifi\t[-e <essid>] [-k <secobj_name>,...]\n"
+	    "\t\t\t[-b <bssid>] [-i ESS|IBSS]\n"
+	    "\t\t\t[-U <identity>] [-N <anon_identity>]\n"
+	    "\t\t\t[-A <CA_Cert_filename>)]\n"
+	    "\t\t\t[-C <Client_Cert_filename>]\n"
+	    "\t\t\t[-K <Private_Key_filename>]\n"
+	    "\t\t\t[<link>]"						},
 	{ "disconnect-wifi",	do_disconnect_wifi,
 	    "    disconnect-wifi  [-a] [<link>]"			},
 	{ "show-wifi",		do_show_wifi,
-	    "    show-wifi        [-p] [-o <field>,...] [<link>]\n"	},
+	    "    show-wifi        [<link>]\n"	},
 	{ "set-linkprop",	do_set_linkprop,
 	    "    set-linkprop     [-t] -p <prop>=<value>[,...] <name>"	},
 	{ "reset-linkprop",	do_reset_linkprop,
@@ -309,13 +304,13 @@
 	{ "show-ether",		do_show_ether,
 	    "    show-ether       [-px][-o <field>,...] <link>\n"	},
 	{ "create-secobj",	do_create_secobj,
-	    "    create-secobj    [-t] [-f <file>] -c <class> <secobj>"	},
+	    "    create-secobj    [-t] -c <class> <secobj>\n"
+	    "\t\t     [-R <root-dir>] [-f <file>]"			},
 	{ "delete-secobj",	do_delete_secobj,
-	    "    delete-secobj    [-t] <secobj>[,...]"			},
+	    "    delete-secobj    [-t] [-R <root-dir>] <secobj>[,...]"	},
 	{ "show-secobj",	do_show_secobj,
-	    "    show-secobj      [-pP] [-o <field>,...] [<secobj>,...]\n" },
+	    "    show-secobj      [-t] [-p] [-o <field>,...] [<secobj>,...]\n"},
 	{ "init-linkprop",	do_init_linkprop,	NULL		},
-	{ "init-secobj",	do_init_secobj,		NULL		},
 	{ "create-vlan", 	do_create_vlan,
 	    "    create-vlan      [-ft] -l <link> -v <vid> [link]"	},
 	{ "delete-vlan", 	do_delete_vlan,
@@ -481,13 +476,14 @@
 	{"parseable",	no_argument,		0, 'p'  },
 	{"output",	required_argument,	0, 'o'  },
 	{"essid",	required_argument,	0, 'e'  },
-	{"bsstype",	required_argument,	0, 'b'  },
-	{"mode",	required_argument,	0, 'm'  },
+	{"bssid",	required_argument,	0, 'b'  },
+	{"bsstype",	required_argument,	0, 'i'  },
 	{"key",		required_argument,	0, 'k'  },
-	{"sec",		required_argument,	0, 's'  },
-	{"auth",	required_argument,	0, 'a'  },
-	{"create-ibss",	required_argument,	0, 'c'  },
-	{"timeout",	required_argument,	0, 'T'  },
+	{"username",	required_argument,	0, 'U'  },
+	{"anonymous",	required_argument,	0, 'N'  },
+	{"authority",	required_argument,	0, 'A'  },
+	{"cli_cert",	required_argument,	0, 'C'  },
+	{"priv_key",	required_argument,	0, 'K'  },
 	{"all-links",	no_argument,		0, 'a'  },
 	{"temporary",	no_argument,		0, 't'  },
 	{"root-dir",	required_argument,	0, 'R'  },
@@ -657,6 +653,19 @@
 	pktsum_t	*link_s_psum;
 } link_args_t;
 
+
+static ofmt_field_t scanres_common_fields[] = {
+{ "BSSID",	19, DLADM_WLAN_ATTR_BSSID,	NULL},
+{ "CHAN",	5,  DLADM_WLAN_ATTR_CHANNEL,	NULL},
+{ "STRENGTH",	9,  DLADM_WLAN_ATTR_STRENGTH,	NULL},
+{ "SPEED",	6,  DLADM_WLAN_ATTR_RATES,	NULL},
+{ "ESSID",	32, DLADM_WLAN_ATTR_ESSID,	NULL},
+{ "SECMODE",	1,  DLADM_WLAN_ATTR_IEDETAIL,	NULL},
+{ NULL,		0,  0,				NULL}};
+
+static const char *scanres_print_fields =
+	"bssid,chan,strength,speed,essid,secmode";
+
 /*
  * buffer used by print functions for show-{link,phys,vlan} commands.
  */
@@ -895,39 +904,10 @@
 ;
 
 /*
- * structures common to 'dladm scan-wifi' and 'dladm show-wifi'
- * callback will be determined in parse_wifi_fields.
+ * global variable for 'dladm scan-wifi' and 'dladm connect-wifi'
+ * signal handler
  */
-static ofmt_field_t wifi_common_fields[] = {
-{ "LINK",	11, 0,				NULL},
-{ "ESSID",	20, DLADM_WLAN_ATTR_ESSID,	NULL},
-{ "BSSID",	18, DLADM_WLAN_ATTR_BSSID,	NULL},
-{ "IBSSID",	18, DLADM_WLAN_ATTR_BSSID,	NULL},
-{ "MODE",	7,  DLADM_WLAN_ATTR_MODE,	NULL},
-{ "SPEED",	7,  DLADM_WLAN_ATTR_SPEED,	NULL},
-{ "BSSTYPE",	9,  DLADM_WLAN_ATTR_BSSTYPE,	NULL},
-{ "SEC",	7,  DLADM_WLAN_ATTR_SECMODE,	NULL},
-{ "STRENGTH",	11, DLADM_WLAN_ATTR_STRENGTH,	NULL},
-{ NULL,		0,  0,				NULL}};
-
-/*
- * the 'show-wifi' command supports all the fields in wifi_common_fields
- * plus the AUTH and STATUS fields.
- */
-static ofmt_field_t wifi_show_fields[A_CNT(wifi_common_fields) + 2] = {
-{ "AUTH",	9,  DLADM_WLAN_ATTR_AUTH,	NULL},
-{ "STATUS",	18, DLADM_WLAN_LINKATTR_STATUS,	print_wifi_status_cb},
-/* copy wifi_common_fields here */
-};
-
-static char *all_scan_wifi_fields =
-	"link,essid,bssid,sec,strength,mode,speed,bsstype";
-static char *all_show_wifi_fields =
-	"link,status,essid,sec,strength,mode,speed,auth,bssid,bsstype";
-static char *def_scan_wifi_fields =
-	"link,essid,bssid,sec,strength,mode,speed";
-static char *def_show_wifi_fields =
-	"link,status,essid,sec,strength,mode,speed";
+static datalink_id_t	sigh_linkid;
 
 /*
  * structures for 'dladm show-linkprop'
@@ -984,9 +964,9 @@
  * structures for 'dladm show-secobj'
  */
 typedef struct secobj_fields_buf_s {
-	char			ss_obj_name[DLADM_SECOBJ_VAL_MAX];
+	char			ss_obj_name[DLADM_SECOBJ_NAME_MAX];
 	char			ss_class[20];
-	char			ss_val[30];
+	char			ss_val[DLADM_SECOBJ_VAL_MAX];
 } secobj_fields_buf_t;
 
 static const ofmt_field_t secobj_fields[] = {
@@ -1425,7 +1405,6 @@
 { NULL,		0, 0, NULL}};
 
 static char *progname;
-static sig_atomic_t signalled;
 
 /*
  * Handle to libdladm.  Opened in main() before the sub-command
@@ -2912,6 +2891,8 @@
 	pktsum_t		stats, diff_stats;
 	dladm_phys_attr_t	dpa;
 	link_args_t		largs;
+	uint32_t		media;
+	struct wpa_ctrl		*ctrl_conn = NULL;
 
 	if (state->ls_firstonly) {
 		if (state->ls_donefirst)
@@ -2921,10 +2902,9 @@
 		bzero(&state->ls_prevstats, sizeof (state->ls_prevstats));
 	}
 
-	if (dladm_datalink_id2info(dh, linkid, NULL, &class, NULL, link,
-	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK) {
+	if (dladm_datalink_id2info(dh, linkid, NULL, &class, &media, link,
+	    DLPI_LINKNAME_MAX) != DLADM_STATUS_OK)
 		return (DLADM_WALK_CONTINUE);
-	}
 
 	if (class == DATALINK_CLASS_PHYS) {
 		if (dladm_phys_info(dh, linkid, &dpa, DLADM_OPT_ACTIVE) !=
@@ -2935,6 +2915,16 @@
 			get_mac_stats(dpa.dp_dev, &stats);
 		else
 			get_link_stats(link, &stats);
+
+		if (media == DL_WIFI && !state->ls_firstonly) {
+			dladm_status_t status;
+			status = dladm_wlan_validate(dh, linkid, &ctrl_conn,
+			    NULL);
+			if (status != DLADM_STATUS_OK) {
+				wpa_ctrl_close(ctrl_conn);
+				ctrl_conn = NULL;
+			}
+		}
 	} else {
 		get_link_stats(link, &stats);
 	}
@@ -2944,6 +2934,12 @@
 	largs.link_s_psum = &diff_stats;
 	ofmt_print(state->ls_ofmt, &largs);
 
+	if (ctrl_conn != NULL) {
+		char *mib_cmd[] = {"MIB"};
+		(void) wpa_request(ctrl_conn, 1, mib_cmd);
+		wpa_ctrl_close(ctrl_conn);
+	}
+
 	state->ls_prevstats = stats;
 	return (DLADM_WALK_CONTINUE);
 }
@@ -5905,101 +5901,38 @@
 	return (dladm_linkduplex2str(linkduplex, buf));
 }
 
-static int
-parse_wifi_fields(char *str, ofmt_handle_t *ofmt, uint_t cmdtype,
-    boolean_t parsable)
-{
-	ofmt_field_t	*template, *of;
-	ofmt_cb_t	*fn;
-	ofmt_status_t	oferr;
-
-	if (cmdtype == WIFI_CMD_SCAN) {
-		template = wifi_common_fields;
-		if (str == NULL)
-			str = def_scan_wifi_fields;
-		if (strcasecmp(str, "all") == 0)
-			str = all_scan_wifi_fields;
-		fn = print_wlan_attr_cb;
-	} else if (cmdtype == WIFI_CMD_SHOW) {
-		bcopy(wifi_common_fields, &wifi_show_fields[2],
-		    sizeof (wifi_common_fields));
-		template = wifi_show_fields;
-		if (str == NULL)
-			str = def_show_wifi_fields;
-		if (strcasecmp(str, "all") == 0)
-			str = all_show_wifi_fields;
-		fn = print_link_attr_cb;
-	} else {
-		return (-1);
-	}
-
-	for (of = template; of->of_name != NULL; of++) {
-		if (of->of_cb == NULL)
-			of->of_cb = fn;
-	}
-
-	oferr = ofmt_open(str, template, (parsable ? OFMT_PARSABLE : 0),
-	    0, ofmt);
-	dladm_ofmt_check(oferr, parsable, *ofmt);
-	return (0);
-}
-
-typedef struct print_wifi_state {
-	char		*ws_link;
-	boolean_t	ws_parsable;
-	boolean_t	ws_header;
-	ofmt_handle_t	ws_ofmt;
-} print_wifi_state_t;
-
-typedef struct  wlan_scan_args_s {
-	print_wifi_state_t	*ws_state;
-	void			*ws_attr;
-} wlan_scan_args_t;
-
 static boolean_t
+/* LINTED E_FUNC_ARG_UNUSED */
 print_wlan_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
 {
-	wlan_scan_args_t	*w = ofarg->ofmt_cbarg;
-	print_wifi_state_t	*statep = w->ws_state;
-	dladm_wlan_attr_t	*attrp = w->ws_attr;
-	char			tmpbuf[DLADM_STRSIZE];
-
-	if (ofarg->ofmt_id == 0) {
-		(void) strlcpy(buf, (char *)statep->ws_link, bufsize);
-		return (B_TRUE);
-	}
+	dladm_wlan_attr_t *attrp = ofarg->ofmt_cbarg;
 
 	if ((ofarg->ofmt_id & attrp->wa_valid) == 0)
 		return (B_TRUE);
 
 	switch (ofarg->ofmt_id) {
 	case DLADM_WLAN_ATTR_ESSID:
-		(void) dladm_wlan_essid2str(&attrp->wa_essid, tmpbuf);
+		(void) memcpy(buf, attrp->wa_essid.we_bytes,
+		    DLADM_WLAN_MAX_ESSID_LEN);
 		break;
 	case DLADM_WLAN_ATTR_BSSID:
-		(void) dladm_wlan_bssid2str(&attrp->wa_bssid, tmpbuf);
-		break;
-	case DLADM_WLAN_ATTR_SECMODE:
-		(void) dladm_wlan_secmode2str(&attrp->wa_secmode, tmpbuf);
+		(void) dladm_wlan_bssid2str(attrp->wa_bssid.wb_bytes, buf);
 		break;
 	case DLADM_WLAN_ATTR_STRENGTH:
-		(void) dladm_wlan_strength2str(&attrp->wa_strength, tmpbuf);
+		(void) dladm_wlan_strength2str(attrp->wa_strength, buf);
 		break;
-	case DLADM_WLAN_ATTR_MODE:
-		(void) dladm_wlan_mode2str(&attrp->wa_mode, tmpbuf);
-		break;
-	case DLADM_WLAN_ATTR_SPEED:
-		(void) dladm_wlan_speed2str(&attrp->wa_speed, tmpbuf);
-		(void) strlcat(tmpbuf, "Mb", sizeof (tmpbuf));
+	case DLADM_WLAN_ATTR_IEDETAIL:
+		(void) strlcpy(buf, attrp->wa_ietxt, sizeof (attrp->wa_ietxt));
 		break;
-	case DLADM_WLAN_ATTR_AUTH:
-		(void) dladm_wlan_auth2str(&attrp->wa_auth, tmpbuf);
+	case DLADM_WLAN_ATTR_RATES:
+		(void) dladm_wlan_rate2str(attrp->wa_rates.wr_rates[0], buf);
 		break;
-	case DLADM_WLAN_ATTR_BSSTYPE:
-		(void) dladm_wlan_bsstype2str(&attrp->wa_bsstype, tmpbuf);
+	case DLADM_WLAN_ATTR_CHANNEL:
+		(void) dladm_wlan_freq2channel(attrp->wa_freq, buf);
 		break;
-	}
-	(void) strlcpy(buf, tmpbuf, bufsize);
+	default:
+		break;
+	}
 
 	return (B_TRUE);
 }
@@ -6007,165 +5940,166 @@
 static boolean_t
 print_scan_results(void *arg, dladm_wlan_attr_t *attrp)
 {
-	print_wifi_state_t	*statep = arg;
-	wlan_scan_args_t	warg;
-
-	bzero(&warg, sizeof (warg));
-	warg.ws_state = statep;
-	warg.ws_attr = attrp;
-	ofmt_print(statep->ws_ofmt, &warg);
+	ofmt_print(arg, attrp);
 	return (B_TRUE);
 }
 
+static void
+/* LINTED E_FUNC_ARG_UNUSED */
+stop_wpa_s(int sig)
+{
+	(void) dladm_wlan_disconnect(handle, sigh_linkid);
+	die("Operation Interrupted\n");
+}
+
+static void
+do_scan_wifi(int argc, char **argv, const char *use)
+{
+	int			option;
+	dladm_status_t		status;
+	datalink_id_t 		linkid;
+
+	ofmt_status_t		oferr;
+	ofmt_field_t		*template, *of;
+	ofmt_handle_t		ofmt;
+
+	opterr = 0;
+	while ((option = getopt_long(argc, argv, "", wifi_longopts, NULL)) !=
+	    -1) {
+		switch (option) {
+		default:
+			die_opterr(optopt, option, use);
+			break;
+		}
+	}
+
+	if (optind == (argc - 1)) {
+		if ((status = dladm_name2info(handle, argv[optind], &linkid,
+		    NULL, NULL, NULL)) != DLADM_STATUS_OK)
+			die_dlerr(status, "link %s is not valid", argv[optind]);
+	} else if (optind != argc) {
+		usage();
+	} else {
+		die("Missing linkname argument");
+	}
+
+	sigh_linkid = linkid;
+
+	if (sigset(SIGINT, stop_wpa_s) == SIG_ERR)
+		die("Sigset error");
+
+	(void) printf(gettext("Scanning on link %s ...\n"), argv[optind]);
+	if ((status = dladm_wlan_scan(handle, linkid)) != DLADM_STATUS_OK)
+		die_dlerr(status, "scan-wifi command failed");
+
+	template = scanres_common_fields;
+	for (of = template; of->of_name != NULL; of++) {
+		if (of->of_cb == NULL)
+			of->of_cb = print_wlan_attr_cb;
+	}
+
+	oferr = ofmt_open(scanres_print_fields, template, 0, 0, &ofmt);
+	dladm_ofmt_check(oferr, B_FALSE, ofmt);
+
+	if ((status = dladm_wlan_parse_esslist(handle, linkid, ofmt,
+	    &print_scan_results)) != DLADM_STATUS_OK) {
+		ofmt_close(ofmt);
+		if (status == DLADM_STATUS_NOTFOUND)
+			die("No wireless networks found");
+		else
+			die_dlerr(status, "scan-wifi command failed");
+	}
+	ofmt_close(ofmt);
+}
+
 static int
-scan_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
-{
-	print_wifi_state_t	*statep = arg;
-	dladm_status_t		status;
-	char			link[MAXLINKNAMELEN];
-
-	if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link,
-	    sizeof (link))) != DLADM_STATUS_OK) {
+/* LINTED E_FUNC_ARG_UNUSED */
+show_wifi(dladm_handle_t dh, datalink_id_t linkid, void* arg)
+{
+	dladm_wlan_linkattr_t  	attr;
+	struct wpa_ctrl		*ctrl_conn = NULL;
+	char			linkname[MAXLINKNAMELEN];
+
+	int 	i;
+	char 	statbuf[16];
+	char	*status_req[] = {"STATUS VERBOSE"};
+
+	(void) memset(linkname, 0, sizeof (linkname));
+
+	if (dladm_wlan_validate(dh, linkid, &ctrl_conn, linkname))
 		return (DLADM_WALK_CONTINUE);
-	}
-
-	statep->ws_link = link;
-	status = dladm_wlan_scan(dh, linkid, statep, print_scan_results);
-	if (status != DLADM_STATUS_OK)
-		die_dlerr(status, "cannot scan link '%s'", statep->ws_link);
-
-	return (DLADM_WALK_CONTINUE);
-}
-
-static boolean_t
-print_wifi_status_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
-{
-	static char		tmpbuf[DLADM_STRSIZE];
-	wlan_scan_args_t	*w = ofarg->ofmt_cbarg;
-	dladm_wlan_linkattr_t	*attrp = w->ws_attr;
-
-	if ((ofarg->ofmt_id & attrp->la_valid) != 0) {
-		(void) dladm_wlan_linkstatus2str(&attrp->la_status, tmpbuf);
-		(void) strlcpy(buf, tmpbuf, bufsize);
-	}
-	return (B_TRUE);
-}
-
-static boolean_t
-print_link_attr_cb(ofmt_arg_t *ofarg, char *buf, uint_t bufsize)
-{
-	wlan_scan_args_t	*w = ofarg->ofmt_cbarg, w1;
-	print_wifi_state_t	*statep = w->ws_state;
-	dladm_wlan_linkattr_t	*attrp = w->ws_attr;
-
-	bzero(&w1, sizeof (w1));
-	w1.ws_state = statep;
-	w1.ws_attr = &attrp->la_wlan_attr;
-	ofarg->ofmt_cbarg = &w1;
-	return (print_wlan_attr_cb(ofarg, buf, bufsize));
-}
-
-static int
-show_wifi(dladm_handle_t dh, datalink_id_t linkid, void *arg)
-{
-	print_wifi_state_t	*statep = arg;
-	dladm_wlan_linkattr_t	attr;
-	dladm_status_t		status;
-	char			link[MAXLINKNAMELEN];
-	wlan_scan_args_t	warg;
-
-	if ((status = dladm_datalink_id2info(dh, linkid, NULL, NULL, NULL, link,
-	    sizeof (link))) != DLADM_STATUS_OK) {
-		return (DLADM_WALK_CONTINUE);
-	}
-
-	/* dladm_wlan_get_linkattr() memsets attr with 0 */
-	status = dladm_wlan_get_linkattr(dh, linkid, &attr);
-	if (status != DLADM_STATUS_OK)
-		die_dlerr(status, "cannot get link attributes for %s", link);
-
-	statep->ws_link = link;
-
-	bzero(&warg, sizeof (warg));
-	warg.ws_state = statep;
-	warg.ws_attr = &attr;
-	ofmt_print(statep->ws_ofmt, &warg);
+
+	(void) memset(&attr, 0, sizeof (attr));
+	if (dladm_wlan_get_linkattr(dh, linkid, &attr))
+		goto end;
+
+	(void) printf(gettext("Wifi Link %s \nStatus: %s\n"), linkname,
+	    dladm_wlan_linkstatus2str(attr.la_connected, statbuf));
+
+	if (!attr.la_connected)
+		goto end;
+
+	(void) memset(statbuf, 0, sizeof (statbuf));
+	(void) printf(gettext("Signal Strength: %s\n"),
+	    dladm_wlan_strength2str(attr.la_wlan_attr.wa_strength, statbuf));
+
+	(void) printf(gettext("Link Speed Rates: "));
+	for (i = 0; i < attr.la_wlan_attr.wa_rates.wr_cnt; i++) {
+		(void) memset(statbuf, 0, sizeof (statbuf));
+		(void) printf("%s ",
+		    dladm_wlan_rate2str(attr.la_wlan_attr.wa_rates.wr_rates[i],
+		    statbuf));
+	}
+
+	(void) memset(statbuf, 0, sizeof (statbuf));
+	(void) printf(gettext("\n802.11 Mode: \"%s\"\n"),
+	    dladm_wlan_mode2str(attr.la_wlan_attr.wa_mode, statbuf));
+
+	(void) memset(statbuf, 0, sizeof (statbuf));
+	(void) printf(gettext("802.11 Channel: \"%s\"\n"),
+	    dladm_wlan_freq2channel(attr.la_wlan_attr.wa_freq, statbuf));
+
+end:
+	(void) wpa_request(ctrl_conn, 1, status_req);
+	wpa_ctrl_close(ctrl_conn);
 	return (DLADM_WALK_CONTINUE);
 }
 
 static void
-do_display_wifi(int argc, char **argv, int cmd, const char *use)
+do_show_wifi(int argc, char **argv, const char *use)
 {
 	int			option;
-	char			*fields_str = NULL;
-	int		(*callback)(dladm_handle_t, datalink_id_t, void *);
-	print_wifi_state_t	state;
-	datalink_id_t		linkid = DATALINK_ALL_LINKID;
 	dladm_status_t		status;
 
-	if (cmd == WIFI_CMD_SCAN)
-		callback = scan_wifi;
-	else if (cmd == WIFI_CMD_SHOW)
-		callback = show_wifi;
-	else
-		return;
-
-	state.ws_parsable = B_FALSE;
-	state.ws_header = B_TRUE;
 	opterr = 0;
-	while ((option = getopt_long(argc, argv, ":o:p",
+	while ((option = getopt_long(argc, argv, "",
 	    wifi_longopts, NULL)) != -1) {
 		switch (option) {
-		case 'o':
-			fields_str = optarg;
-			break;
-		case 'p':
-			state.ws_parsable = B_TRUE;
-			break;
 		default:
 			die_opterr(optopt, option, use);
-		}
-	}
-
-	if (state.ws_parsable && fields_str == NULL)
-		die("-p requires -o");
-
-	if (state.ws_parsable && strcasecmp(fields_str, "all") == 0)
-		die("\"-o all\" is invalid with -p");
+			break;
+		}
+	}
 
 	if (optind == (argc - 1)) {
-		if ((status = dladm_name2info(handle, argv[optind], &linkid,
-		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
+		datalink_id_t linkid;
+		uint32_t media;
+		status = dladm_name2info(handle, argv[optind], &linkid,
+		    NULL, NULL, &media);
+		if (status != DLADM_STATUS_OK || media != DL_WIFI)
 			die_dlerr(status, "link %s is not valid", argv[optind]);
-		}
+		status = show_wifi(handle, linkid, NULL);
+		if (status != DLADM_WALK_CONTINUE)
+			die_dlerr(status, "show-wifi command failed");
 	} else if (optind != argc) {
 		usage();
-	}
-
-	if (parse_wifi_fields(fields_str, &state.ws_ofmt, cmd,
-	    state.ws_parsable) < 0)
-		die("invalid field(s) specified");
-
-	if (linkid == DATALINK_ALL_LINKID) {
-		(void) dladm_walk_datalink_id(callback, handle, &state,
+	} else {
+		status = dladm_walk_datalink_id(&show_wifi, handle, NULL,
 		    DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET,
 		    DL_WIFI, DLADM_OPT_ACTIVE);
-	} else {
-		(void) (*callback)(handle, linkid, &state);
-	}
-	ofmt_close(state.ws_ofmt);
-}
-
-static void
-do_scan_wifi(int argc, char **argv, const char *use)
-{
-	do_display_wifi(argc, argv, WIFI_CMD_SCAN, use);
-}
-
-static void
-do_show_wifi(int argc, char **argv, const char *use)
-{
-	do_display_wifi(argc, argv, WIFI_CMD_SHOW, use);
+		if (status != DLADM_STATUS_OK)
+			die_dlerr(status, "show-wifi command failed");
+	}
 }
 
 typedef struct wlan_count_attr {
@@ -6185,159 +6119,149 @@
 	return (DLADM_WALK_CONTINUE);
 }
 
-static int
-parse_wlan_keys(char *str, dladm_wlan_key_t **keys, uint_t *key_countp)
-{
-	uint_t			i;
-	dladm_wlan_key_t	*wk;
-	int			nfields = 1;
-	char			*field, *token, *lasts = NULL, c;
-
-	token = str;
-	while ((c = *token++) != NULL) {
-		if (c == ',')
-			nfields++;
-	}
-	token = strdup(str);
+static uint_t
+parse_wlan_keys(char *str, dladm_wlan_key_t *key, char *crtpw1)
+{
+	char		*token = NULL;
+	uint_t		keysnum = 0;
+
+	if (key == NULL || str == NULL || crtpw1 == NULL)
+		return (0);
+
+	token = strtok(str, ",");
 	if (token == NULL)
-		return (-1);
-
-	wk = malloc(nfields * sizeof (dladm_wlan_key_t));
-	if (wk == NULL)
-		goto fail;
-
-	token = str;
-	for (i = 0; i < nfields; i++) {
-		char			*s;
-		dladm_secobj_class_t	class;
-		dladm_status_t		status;
-
-		field = strtok_r(token, ",", &lasts);
-		token = NULL;
-
-		(void) strlcpy(wk[i].wk_name, field,
-		    DLADM_WLAN_MAX_KEYNAME_LEN);
-
-		wk[i].wk_idx = 1;
-		if ((s = strrchr(wk[i].wk_name, ':')) != NULL) {
-			if (s[1] == '\0' || s[2] != '\0' || !isdigit(s[1]))
-				goto fail;
-
-			wk[i].wk_idx = (uint_t)(s[1] - '0');
-			*s = '\0';
-		}
-		wk[i].wk_len = DLADM_WLAN_MAX_KEY_LEN;
-
-		status = dladm_get_secobj(handle, wk[i].wk_name, &class,
-		    wk[i].wk_val, &wk[i].wk_len, 0);
-		if (status != DLADM_STATUS_OK) {
-			if (status == DLADM_STATUS_NOTFOUND) {
-				status = dladm_get_secobj(handle, wk[i].wk_name,
-				    &class, wk[i].wk_val, &wk[i].wk_len,
-				    DLADM_OPT_PERSIST);
-			}
-			if (status != DLADM_STATUS_OK)
-				goto fail;
-		}
-		wk[i].wk_class = class;
-	}
-	*keys = wk;
-	*key_countp = i;
-	free(token);
-	return (0);
-fail:
-	free(wk);
-	free(token);
-	return (-1);
+		return (0);
+
+	(void) strlcpy(key->wk_name, token, DLADM_SECOBJ_NAME_MAX);
+
+	if (dladm_get_secobj(handle, key, DLADM_OPT_ACTIVE|DLADM_OPT_PERSIST))
+		return (0);
+
+	keysnum++;
+
+	token = strtok(NULL, ",");
+	if (token != NULL) {
+		secobj_class_info_t exists1;
+		exists1.sc_name = token;
+		exists1.sc_dladmclass = 0;
+		if (dladm_walk_secobj(handle, &exists1, find_matching_secobj,
+		    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST))
+			return (keysnum);
+		if (exists1.sc_dladmclass == DLADM_SECOBJ_CLASS_TLS) {
+			(void) strlcpy(crtpw1, token, DLADM_SECOBJ_NAME_MAX);
+			keysnum++;
+		}
+	}
+
+	return (keysnum);
 }
 
 static void
 do_connect_wifi(int argc, char **argv, const char *use)
 {
-	int			option;
-	dladm_wlan_attr_t	attr, *attrp;
 	dladm_status_t		status = DLADM_STATUS_OK;
-	int			timeout = DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT;
 	datalink_id_t		linkid = DATALINK_ALL_LINKID;
-	dladm_wlan_key_t	*keys = NULL;
-	uint_t			key_count = 0;
-	uint_t			flags = 0;
-	dladm_wlan_secmode_t	keysecmode = DLADM_WLAN_SECMODE_NONE;
-	char			buf[DLADM_STRSIZE];
+	int			option;
+	uint_t			keynum = 0;
+	dladm_wlan_attr_t	attr, *attrp;
+	dladm_wlan_eap_t	eap_attr, *eap_attrp;
+	dladm_wlan_key_t	key;
+	char 			crtpw[DLADM_SECOBJ_NAME_MAX];
+	int			rc;
 
 	opterr = 0;
 	(void) memset(&attr, 0, sizeof (attr));
-	while ((option = getopt_long(argc, argv, ":e:i:a:m:b:s:k:T:c",
-	    wifi_longopts, NULL)) != -1) {
+	(void) memset(&eap_attr, 0, sizeof (eap_attr));
+	(void) memset(&key, 0, sizeof (key));
+	(void) memset(crtpw, 0, sizeof (crtpw));
+
+	/* TODO: when adhoc mode is supported add channel option */
+
+	while ((option = getopt_long(argc, argv,
+	    ":e:b:i:k:U:N:A:D:C:K:", wifi_longopts, NULL)) != -1) {
 		switch (option) {
 		case 'e':
-			status = dladm_wlan_str2essid(optarg, &attr.wa_essid);
-			if (status != DLADM_STATUS_OK)
+			/* essid */
+			rc = strlcpy((char *)attr.wa_essid.we_bytes, optarg,
+			    DLADM_WLAN_MAX_ESSID_LEN + 1);
+			if (rc < 1 || rc > DLADM_WLAN_MAX_ESSID_LEN)
 				die("invalid ESSID '%s'", optarg);
-
+			if ((attr.wa_essid.we_length =
+			    strnlen((char *)attr.wa_essid.we_bytes,
+			    DLADM_WLAN_MAX_ESSID_LEN + 1)) ==
+			    DLADM_WLAN_MAX_ESSID_LEN + 1)
+				die("invalid ESSID '%s'", optarg);
 			attr.wa_valid |= DLADM_WLAN_ATTR_ESSID;
-			/*
-			 * Try to connect without doing a scan.
-			 */
-			flags |= DLADM_WLAN_CONNECT_NOSCAN;
-			break;
-		case 'i':
-			status = dladm_wlan_str2bssid(optarg, &attr.wa_bssid);
+			break;
+		case 'b':
+			/* bssid */
+			status = dladm_wlan_str2bssid(optarg,
+			    attr.wa_bssid.wb_bytes);
 			if (status != DLADM_STATUS_OK)
 				die("invalid BSSID %s", optarg);
 
 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSID;
 			break;
-		case 'a':
-			status = dladm_wlan_str2auth(optarg, &attr.wa_auth);
-			if (status != DLADM_STATUS_OK)
-				die("invalid authentication mode '%s'", optarg);
-
-			attr.wa_valid |= DLADM_WLAN_ATTR_AUTH;
-			break;
-		case 'm':
-			status = dladm_wlan_str2mode(optarg, &attr.wa_mode);
-			if (status != DLADM_STATUS_OK)
-				die("invalid mode '%s'", optarg);
-
-			attr.wa_valid |= DLADM_WLAN_ATTR_MODE;
-			break;
-		case 'b':
+		case 'i':
+			/* bss/ibss */
 			if ((status = dladm_wlan_str2bsstype(optarg,
-			    &attr.wa_bsstype)) != DLADM_STATUS_OK) {
+			    &attr.wa_bsstype)) != DLADM_STATUS_OK)
 				die("invalid bsstype '%s'", optarg);
-			}
 
 			attr.wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
 			break;
-		case 's':
-			if ((status = dladm_wlan_str2secmode(optarg,
-			    &attr.wa_secmode)) != DLADM_STATUS_OK) {
-				die("invalid security mode '%s'", optarg);
-			}
+		case 'k':
+			/* secobj selection */
+			keynum = parse_wlan_keys(optarg, &key, crtpw);
+			if (!(keynum))
+				die("invalid key '%s'", optarg);
+
+			if (key.wk_class == DLADM_SECOBJ_CLASS_WEP)
+				attr.wa_secmode = DLADM_WLAN_SECMODE_WEP;
+			else if (key.wk_class == DLADM_SECOBJ_CLASS_PSK)
+				attr.wa_secmode = DLADM_WLAN_SECMODE_PSK;
+			else
+				attr.wa_secmode = DLADM_WLAN_SECMODE_EAP;
 
 			attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
 			break;
-		case 'k':
-			if (parse_wlan_keys(optarg, &keys, &key_count) < 0)
-				die("invalid key(s) '%s'", optarg);
-
-			if (keys[0].wk_class == DLADM_SECOBJ_CLASS_WEP)
-				keysecmode = DLADM_WLAN_SECMODE_WEP;
-			else
-				keysecmode = DLADM_WLAN_SECMODE_WPA;
-			break;
-		case 'T':
-			if (strcasecmp(optarg, "forever") == 0) {
-				timeout = -1;
-				break;
-			}
-			if (!str2int(optarg, &timeout) || timeout < 0)
-				die("invalid timeout value '%s'", optarg);
-			break;
-		case 'c':
-			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
-			flags |= DLADM_WLAN_CONNECT_CREATEIBSS;
+		case 'U':
+			/* eap user identity */
+			status = dladm_str2identity(optarg, eap_attr.eap_user);
+			if (status != DLADM_STATUS_OK)
+				die("invalid user identity '%s'", optarg);
+			eap_attr.eap_valid |= DLADM_EAP_ATTR_USER;
+			break;
+		case 'N':
+			/*
+			 * eap anonymous identity
+			 * currently only for eap-ttls
+			 */
+			status = dladm_str2identity(optarg, eap_attr.eap_anon);
+			if (status != DLADM_STATUS_OK)
+				die("invalid anonymous identity '%s'", optarg);
+			eap_attr.eap_valid |= DLADM_EAP_ATTR_ANON;
+			break;
+		case 'A':
+			/* certifice authority filename */
+			if (dladm_str2crtname(optarg,
+			    eap_attr.eap_ca_cert))
+				die("invalid filename for '%s'", optarg);
+			eap_attr.eap_valid |= DLADM_EAP_ATTR_CACERT;
+			break;
+		case 'C':
+			/* client cert filename */
+			if (dladm_str2crtname(optarg,
+			    eap_attr.eap_cli_cert))
+				die("invalid filename for '%s'", optarg);
+			eap_attr.eap_valid |= DLADM_EAP_ATTR_CLICERT;
+			break;
+		case 'K':
+			/* client private key filename */
+			if (dladm_str2crtname(optarg,
+			    eap_attr.eap_priv))
+				die("invalid filename for '%s'", optarg);
+			eap_attr.eap_valid |= DLADM_EAP_ATTR_PRIV;
 			break;
 		default:
 			die_opterr(optopt, option, use);
@@ -6345,19 +6269,6 @@
 		}
 	}
 
-	if (keysecmode == DLADM_WLAN_SECMODE_NONE) {
-		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) {
-			die("key required for security mode '%s'",
-			    dladm_wlan_secmode2str(&attr.wa_secmode, buf));
-		}
-	} else {
-		if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
-		    attr.wa_secmode != keysecmode)
-			die("incompatible -s and -k options");
-		attr.wa_valid |= DLADM_WLAN_ATTR_SECMODE;
-		attr.wa_secmode = keysecmode;
-	}
-
 	if (optind == (argc - 1)) {
 		if ((status = dladm_name2info(handle, argv[optind], &linkid,
 		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
@@ -6375,37 +6286,98 @@
 		(void) dladm_walk_datalink_id(do_count_wlan, handle, &wcattr,
 		    DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET,
 		    DL_WIFI, DLADM_OPT_ACTIVE);
-		if (wcattr.wc_count == 0) {
+		if (wcattr.wc_count == 0)
 			die("no wifi links are available");
-		} else if (wcattr.wc_count > 1) {
+		else if (wcattr.wc_count > 1)
 			die("link name is required when more than one wifi "
 			    "link is available");
-		}
 		linkid = wcattr.wc_linkid;
 	}
+
+	if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) &&
+	    !(attr.wa_valid & DLADM_WLAN_ATTR_ESSID))
+		die("ESSID is mandatory for non-plaintext networks");
+
+	if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) &&
+	    key.wk_class == DLADM_SECOBJ_CLASS_TLS) {
+		if (!(eap_attr.eap_valid & DLADM_EAP_ATTR_USER))
+			die("provide username (-U) for EAP-TLS");
+		if (!(eap_attr.eap_valid & DLADM_EAP_ATTR_PRIV))
+			die("client private key required for EAP-TLS");
+		if (key.wk_engine) {
+			status = dladm_eap_import(handle, eap_attr.eap_priv,
+			    key.wk_name, key.wk_name, key.wk_class);
+			if (status)
+				die_dlerr(status, "Failed to Import Key/Cert");
+
+			if (keynum > 1 &&
+			    (eap_attr.eap_valid & DLADM_EAP_ATTR_CLICERT)) {
+				status = dladm_eap_import(handle,
+				    eap_attr.eap_cli_cert, key.wk_name,
+				    crtpw, key.wk_class);
+				keynum--;
+			}
+			if (status)
+				die_dlerr(status, "Failed to Import Key/Cert");
+		}
+	} else if ((attr.wa_valid & DLADM_WLAN_ATTR_SECMODE) &&
+	    (key.wk_class == DLADM_SECOBJ_CLASS_TTLS ||
+	    key.wk_class == DLADM_SECOBJ_CLASS_PEAP)) {
+		if (!(eap_attr.eap_valid & DLADM_EAP_ATTR_USER) &&
+		    !(eap_attr.eap_valid & DLADM_EAP_ATTR_ANON))
+			die("provide username (-U) or anonymous identity (-N)"
+			" for EAP-TTLS or EAP-PEAP");
+	}
+
+	if (attr.wa_valid & DLADM_WLAN_ATTR_BSSTYPE) {
+		if (attr.wa_secmode != DLADM_WLAN_SECMODE_NONE &&
+		    attr.wa_secmode != DLADM_WLAN_SECMODE_PSK)
+			die("ibss type supports only PSK or NONE security");
+	}
+
+	if ((key.wk_engine) && attr.wa_secmode != DLADM_WLAN_SECMODE_EAP)
+		die("PKCS#11 keystores can be used only in WPA-EAP mode");
+
 	attrp = (attr.wa_valid == 0) ? NULL : &attr;
-again:
-	if ((status = dladm_wlan_connect(handle, linkid, attrp, timeout, keys,
-	    key_count, flags)) != DLADM_STATUS_OK) {
-		if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0) {
-			/*
-			 * Try again with scanning and filtering.
-			 */
-			flags &= ~DLADM_WLAN_CONNECT_NOSCAN;
-			goto again;
-		}
-
-		if (status == DLADM_STATUS_NOTFOUND) {
-			if (attr.wa_valid == 0) {
-				die("no wifi networks are available");
-			} else {
-				die("no wifi networks with the specified "
-				    "criteria are available");
-			}
-		}
-		die_dlerr(status, "cannot connect");
-	}
-	free(keys);
+	eap_attrp = (eap_attr.eap_valid == 0) ? NULL : &eap_attr;
+
+	sigh_linkid = linkid;
+
+	if (sigset(SIGINT, stop_wpa_s) == SIG_ERR)
+		die("Sigset error");
+
+	if ((status = dladm_wlan_connect(handle, linkid, attrp, &key,
+	    eap_attrp)) != DLADM_STATUS_OK) {
+		switch (status) {
+		/*
+		 * we assume wifi params the user had passed are coherent
+		 * with the last scan results. The user will simply get a
+		 * timeout if a matching AP with the specified essid/bssid/sec
+		 * is not found.
+		 * This is not the case in nwam, where the user selects the
+		 * target AP from scan results list
+		 */
+		case DLADM_STATUS_ISCONN:
+			die("wifi link already connected, disconnect first");
+			break;
+		case DLADM_STATUS_BADVAL:
+			die("bad input parameters value");
+			break;
+		case DLADM_STATUS_TIMEDOUT:
+			die_dlerr(status, "connection timeout");
+			break;
+		case DLADM_STATUS_DENIED:
+			die("svc:/network/wpa_supplicant is not enabled "
+			    "or dladm failed to bind to its control interface");
+			break;
+		case DLADM_STATUS_IOERR:
+			die("Cannot initialize Driver Interface");
+			break;
+		default:
+			die_dlerr(status, "cannot connect");
+			break;
+		}
+	}
 }
 
 /* ARGSUSED */
@@ -6415,7 +6387,7 @@
 	dladm_status_t	status;
 
 	status = dladm_wlan_disconnect(dh, linkid);
-	if (status != DLADM_STATUS_OK)
+	if (status != DLADM_STATUS_OK && status != DLADM_STATUS_LINKINVAL)
 		warn_dlerr(status, "cannot disconnect link");
 
 	return (DLADM_WALK_CONTINUE);
@@ -6425,9 +6397,9 @@
 do_disconnect_wifi(int argc, char **argv, const char *use)
 {
 	int			option;
-	datalink_id_t		linkid = DATALINK_ALL_LINKID;
+	datalink_id_t		linkid;
 	boolean_t		all_links = B_FALSE;
-	dladm_status_t		status;
+	dladm_status_t		status = DLADM_STATUS_OK;
 	wlan_count_attr_t	wcattr;
 
 	opterr = 0;
@@ -6436,6 +6408,7 @@
 		switch (option) {
 		case 'a':
 			all_links = B_TRUE;
+			linkid = DATALINK_ALL_LINKID;
 			break;
 		default:
 			die_opterr(optopt, option, use);
@@ -6443,17 +6416,14 @@
 		}
 	}
 
-	if (optind == (argc - 1)) {
-		if ((status = dladm_name2info(handle, argv[optind], &linkid,
-		    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
-			die_dlerr(status, "link %s is not valid", argv[optind]);
-		}
-	} else if (optind != argc) {
-		usage();
-	}
-
-	if (linkid == DATALINK_ALL_LINKID) {
-		if (!all_links) {
+	if (!all_links) {
+		if (optind == (argc - 1)) {
+			if ((status = dladm_name2info(handle, argv[optind], &linkid,
+			    NULL, NULL, NULL)) != DLADM_STATUS_OK) {
+				die_dlerr(status, "link %s is not valid", argv[optind]);
+			}
+			status = dladm_wlan_disconnect(handle, linkid);
+		} else if (argc == 0) {
 			wcattr.wc_linkid = linkid;
 			wcattr.wc_count = 0;
 			(void) dladm_walk_datalink_id(do_count_wlan, handle,
@@ -6467,15 +6437,16 @@
 				    "one wifi link is available");
 			}
 			linkid = wcattr.wc_linkid;
-		} else {
-			(void) dladm_walk_datalink_id(do_all_disconnect_wifi,
-			    handle, NULL,
-			    DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET,
-			    DL_WIFI, DLADM_OPT_ACTIVE);
-			return;
-		}
-	}
-	status = dladm_wlan_disconnect(handle, linkid);
+		} else if (optind != argc) {
+			usage();
+		}
+	} else {
+		(void) dladm_walk_datalink_id(do_all_disconnect_wifi, handle,
+		    NULL, DATALINK_CLASS_PHYS | DATALINK_CLASS_SIMNET, DL_WIFI,
+		    DLADM_OPT_ACTIVE);
+		return;
+	}
+
 	if (status != DLADM_STATUS_OK)
 		die_dlerr(status, "cannot disconnect");
 }
@@ -7035,146 +7006,6 @@
 	set_linkprop(argc, argv, B_TRUE, use);
 }
 
-static int
-convert_secobj(char *buf, uint_t len, uint8_t *obj_val, uint_t *obj_lenp,
-    dladm_secobj_class_t class)
-{
-	int error = 0;
-
-	if (class == DLADM_SECOBJ_CLASS_WPA) {
-		if (len < 8 || len > 63)
-			return (EINVAL);
-		(void) memcpy(obj_val, buf, len);
-		*obj_lenp = len;
-		return (error);
-	}
-
-	if (class == DLADM_SECOBJ_CLASS_WEP) {
-		switch (len) {
-		case 5:			/* ASCII key sizes */
-		case 13:
-			(void) memcpy(obj_val, buf, len);
-			*obj_lenp = len;
-			break;
-		case 10:		/* Hex key sizes, not preceded by 0x */
-		case 26:
-			error = hexascii_to_octet(buf, len, obj_val, obj_lenp);
-			break;
-		case 12:		/* Hex key sizes, preceded by 0x */
-		case 28:
-			if (strncmp(buf, "0x", 2) != 0)
-				return (EINVAL);
-			error = hexascii_to_octet(buf + 2, len - 2,
-			    obj_val, obj_lenp);
-			break;
-		default:
-			return (EINVAL);
-		}
-		return (error);
-	}
-
-	return (ENOENT);
-}
-
-static void
-defersig(int sig)
-{
-	signalled = sig;
-}
-
-static int
-get_secobj_from_tty(uint_t try, const char *objname, char *buf)
-{
-	uint_t		len = 0;
-	int		c;
-	struct termios	stored, current;
-	void		(*sigfunc)(int);
-
-	/*
-	 * Turn off echo -- but before we do so, defer SIGINT handling
-	 * so that a ^C doesn't leave the terminal corrupted.
-	 */
-	sigfunc = signal(SIGINT, defersig);
-	(void) fflush(stdin);
-	(void) tcgetattr(0, &stored);
-	current = stored;
-	current.c_lflag &= ~(ICANON|ECHO);
-	current.c_cc[VTIME] = 0;
-	current.c_cc[VMIN] = 1;
-	(void) tcsetattr(0, TCSANOW, &current);
-again:
-	if (try == 1)
-		(void) printf(gettext("provide value for '%s': "), objname);
-	else
-		(void) printf(gettext("confirm value for '%s': "), objname);
-
-	(void) fflush(stdout);
-	while (signalled == 0) {
-		c = getchar();
-		if (c == '\n' || c == '\r') {
-			if (len != 0)
-				break;
-			(void) putchar('\n');
-			goto again;
-		}
-
-		buf[len++] = c;
-		if (len >= DLADM_SECOBJ_VAL_MAX - 1)
-			break;
-		(void) putchar('*');
-	}
-
-	(void) putchar('\n');
-	(void) fflush(stdin);
-
-	/*
-	 * Restore terminal setting and handle deferred signals.
-	 */
-	(void) tcsetattr(0, TCSANOW, &stored);
-
-	(void) signal(SIGINT, sigfunc);
-	if (signalled != 0)
-		(void) kill(getpid(), signalled);
-
-	return (len);
-}
-
-static int
-get_secobj_val(char *obj_name, uint8_t *obj_val, uint_t *obj_lenp,
-    dladm_secobj_class_t class, FILE *filep)
-{
-	int		rval;
-	uint_t		len, len2;
-	char		buf[DLADM_SECOBJ_VAL_MAX], buf2[DLADM_SECOBJ_VAL_MAX];
-
-	if (filep == NULL) {
-		len = get_secobj_from_tty(1, obj_name, buf);
-		rval = convert_secobj(buf, len, obj_val, obj_lenp, class);
-		if (rval == 0) {
-			len2 = get_secobj_from_tty(2, obj_name, buf2);
-			if (len != len2 || memcmp(buf, buf2, len) != 0)
-				rval = ENOTSUP;
-		}
-		return (rval);
-	} else {
-		for (;;) {
-			if (fgets(buf, sizeof (buf), filep) == NULL)
-				break;
-			if (isspace(buf[0]))
-				continue;
-
-			len = strlen(buf);
-			if (buf[len - 1] == '\n') {
-				buf[len - 1] = '\0';
-				len--;
-			}
-			break;
-		}
-		(void) fclose(filep);
-	}
-	return (convert_secobj(buf, len, obj_val, obj_lenp, class));
-}
-
 static boolean_t
 check_auth(const char *auth)
 {
@@ -7240,19 +7071,16 @@
 static void
 do_create_secobj(int argc, char **argv, const char *use)
 {
-	int			option, rval;
+	int			option;
 	FILE			*filep = NULL;
-	char			*obj_name = NULL;
-	char			*class_name = NULL;
-	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
-	uint_t			obj_len;
 	boolean_t		success, temp = B_FALSE;
-	dladm_status_t		status;
-	dladm_secobj_class_t	class = -1;
+	dladm_status_t		status = DLADM_STATUS_OK;
+	dladm_wlan_key_t	key_data;
 	uid_t			euid;
+	char			classtmp[DLADM_STRSIZE];
 
 	opterr = 0;
-	(void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX);
+	(void) memset(&key_data, 0, sizeof (dladm_wlan_key_t));
 	while ((option = getopt_long(argc, argv, ":f:c:R:t",
 	    wifi_longopts, NULL)) != -1) {
 		switch (option) {
@@ -7267,11 +7095,12 @@
 			(void) seteuid(euid);
 			break;
 		case 'c':
-			class_name = optarg;
-			status = dladm_str2secobjclass(optarg, &class);
+			status = dladm_str2secobjclass(optarg,
+			    &key_data.wk_class);
 			if (status != DLADM_STATUS_OK) {
 				die("invalid secure object class '%s', "
-				    "valid values are: wep, wpa", optarg);
+				    "valid values are: [wep|psk|eap-tls|"
+				    "eap-ttls|peap]", optarg);
 			}
 			break;
 		case 't':
@@ -7291,57 +7120,38 @@
 	}
 
 	if (optind == (argc - 1))
-		obj_name = argv[optind];
+		(void) strlcpy(key_data.wk_name, argv[optind],
+		    DLADM_SECOBJ_VAL_MAX);
 	else if (optind != argc)
 		usage();
 
-	if (class == -1)
+	if (key_data.wk_class == 0)
 		die("secure object class required");
 
-	if (obj_name == NULL)
+	if (key_data.wk_name[0] == '\0')
 		die("secure object name required");
 
-	if (!dladm_valid_secobj_name(obj_name))
-		die("invalid secure object name '%s'", obj_name);
+	if (!dladm_valid_secobj_name(key_data.wk_name))
+		die("invalid secure object name '%s'", key_data.wk_name);
 
 	success = check_auth(LINK_SEC_AUTH);
-	audit_secobj(LINK_SEC_AUTH, class_name, obj_name, success, B_TRUE);
+	(void) memset(classtmp, 0, sizeof (classtmp));
+	(void) dladm_secobjclass2str(key_data.wk_class, classtmp);
+	audit_secobj(LINK_SEC_AUTH, classtmp, key_data.wk_name, success,
+	    B_TRUE);
 	if (!success)
 		die("authorization '%s' is required", LINK_SEC_AUTH);
 
-	rval = get_secobj_val(obj_name, obj_val, &obj_len, class, filep);
-	if (rval != 0) {
-		switch (rval) {
-		case ENOENT:
-			die("invalid secure object class");
-			break;
-		case EINVAL:
-			die("invalid secure object value");
-			break;
-		case ENOTSUP:
-			die("verification failed");
-			break;
-		default:
-			die("invalid secure object: %s", strerror(rval));
-			break;
-		}
-	}
-
-	status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len,
-	    DLADM_OPT_CREATE | DLADM_OPT_ACTIVE);
-	if (status != DLADM_STATUS_OK) {
-		die_dlerr(status, "could not create secure object '%s'",
-		    obj_name);
-	}
-	if (temp)
-		return;
-
-	status = dladm_set_secobj(handle, obj_name, class, obj_val, obj_len,
-	    DLADM_OPT_PERSIST);
-	if (status != DLADM_STATUS_OK) {
-		warn_dlerr(status, "could not persistently create secure "
-		    "object '%s'", obj_name);
-	}
+	status = dladm_secobj_prompt(&key_data, filep);
+	if (status != DLADM_STATUS_OK)
+		die("invalid secure object: %s", key_data.wk_name);
+
+	status = dladm_set_secobj(handle, &key_data, temp ?
+	    (DLADM_OPT_CREATE | DLADM_OPT_ACTIVE) :
+	    (DLADM_OPT_CREATE | DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST));
+	if (status != DLADM_STATUS_OK)
+		die_dlerr(status, "could not create secure object %s",
+		    key_data.wk_name);
 }
 
 static void
@@ -7350,12 +7160,11 @@
 	int		i, option;
 	boolean_t	temp = B_FALSE;
 	boolean_t	success;
-	dladm_status_t	status, pstatus;
+	dladm_status_t	status = DLADM_STATUS_OK;
 	int		nfields = 1;
 	char		*field, *token, *lasts = NULL, c;
 
 	opterr = 0;
-	status = pstatus = DLADM_STATUS_OK;
 	while ((option = getopt_long(argc, argv, ":R:t",
 	    wifi_longopts, NULL)) != -1) {
 		switch (option) {
@@ -7396,72 +7205,62 @@
 
 		field = strtok_r(token, ",", &lasts);
 		token = NULL;
-		status = dladm_unset_secobj(handle, field, DLADM_OPT_ACTIVE);
-		if (!temp) {
-			pstatus = dladm_unset_secobj(handle, field,
-			    DLADM_OPT_PERSIST);
-		} else {
-			pstatus = DLADM_STATUS_OK;
-		}
-
-		if (status != DLADM_STATUS_OK) {
-			warn_dlerr(status, "could not delete secure object "
-			    "'%s'", field);
-		}
-		if (pstatus != DLADM_STATUS_OK) {
-			warn_dlerr(pstatus, "could not persistently delete "
-			    "secure object '%s'", field);
-		}
-	}
+		if ((status = dladm_unset_secobj(handle, field,
+		    DLADM_OPT_ACTIVE)) != DLADM_STATUS_OK)
+			warn_dlerr(status, "could not find or delete "
+			    "temporary secure object '%s'", field);
+		if (!temp && (status = dladm_unset_secobj(handle, field,
+		    DLADM_OPT_PERSIST)) != DLADM_STATUS_OK)
+			warn_dlerr(status, "could not find or delete "
+			    "persistent secure object '%s'", field);
+	}
+
 	free(token);
 
-	if (status != DLADM_STATUS_OK || pstatus != DLADM_STATUS_OK) {
+	if (status != DLADM_STATUS_OK) {
 		dladm_close(handle);
 		exit(EXIT_FAILURE);
 	}
 }
 
 typedef struct show_secobj_state {
-	boolean_t	ss_persist;
+	boolean_t	ss_temp;
 	boolean_t	ss_parsable;
 	boolean_t	ss_header;
 	ofmt_handle_t	ss_ofmt;
 } show_secobj_state_t;
 
-
 static boolean_t
-show_secobj(dladm_handle_t dh, void *arg, const char *obj_name)
-{
-	uint_t			obj_len = DLADM_SECOBJ_VAL_MAX;
-	uint8_t			obj_val[DLADM_SECOBJ_VAL_MAX];
-	char			buf[DLADM_STRSIZE];
+show_secobj(dladm_handle_t dh, void *arg, const char *obj_name,
+/* LINTED E_FUNC_ARG_UNUSED */
+    dladm_secobj_class_t not_used)
+{
 	uint_t			flags = 0;
-	dladm_secobj_class_t	class;
 	show_secobj_state_t	*statep = arg;
 	dladm_status_t		status;
+
+	dladm_wlan_key_t	keyd;
 	secobj_fields_buf_t	sbuf;
 
 	bzero(&sbuf, sizeof (secobj_fields_buf_t));
-	if (statep->ss_persist)
+	bzero(&keyd, sizeof (dladm_wlan_key_t));
+
+	if (statep->ss_temp) {
+		flags |= DLADM_OPT_ACTIVE;
+	} else {
 		flags |= DLADM_OPT_PERSIST;
-
-	status = dladm_get_secobj(dh, obj_name, &class, obj_val, &obj_len,
-	    flags);
-	if (status != DLADM_STATUS_OK)
+	}
+
+	(void) memcpy(keyd.wk_name, obj_name, DLADM_SECOBJ_NAME_MAX);
+
+	if ((status = dladm_get_secobj(dh, &keyd, flags)) != DLADM_STATUS_OK)
 		die_dlerr(status, "cannot get secure object '%s'", obj_name);
 
-	(void) snprintf(sbuf.ss_obj_name, sizeof (sbuf.ss_obj_name),
-	    obj_name);
-	(void) dladm_secobjclass2str(class, buf);
-	(void) snprintf(sbuf.ss_class, sizeof (sbuf.ss_class), "%s", buf);
-	if (getuid() == 0) {
-		char	val[DLADM_SECOBJ_VAL_MAX * 2];
-		uint_t	len = sizeof (val);
-
-		if (octet_to_hexascii(obj_val, obj_len, val, &len) == 0)
-			(void) snprintf(sbuf.ss_val,
-			    sizeof (sbuf.ss_val), "%s", val);
-	}
+	(void) memcpy(sbuf.ss_obj_name, obj_name, DLADM_SECOBJ_NAME_MAX);
+	(void) dladm_secobjclass2str(keyd.wk_class, sbuf.ss_class);
+	if (getuid() == 0)
+		(void) memcpy(sbuf.ss_val, keyd.wk_val, DLADM_SECOBJ_VAL_MAX);
+
 	ofmt_print(statep->ss_ofmt, &sbuf);
 	return (B_TRUE);
 }
@@ -7474,7 +7273,7 @@
 	dladm_status_t		status;
 	boolean_t		o_arg = B_FALSE;
 	uint_t			i;
-	uint_t			flags;
+	uint_t			flags = 0;
 	char			*fields_str = NULL;
 	char			*def_fields = "object,class";
 	char			*all_fields = "object,class,value";
@@ -7487,17 +7286,17 @@
 	bzero(&state, sizeof (state));
 	state.ss_parsable = B_FALSE;
 	fields_str = def_fields;
-	state.ss_persist = B_FALSE;
+	state.ss_temp = B_FALSE;
 	state.ss_parsable = B_FALSE;
 	state.ss_header = B_TRUE;
-	while ((option = getopt_long(argc, argv, ":pPo:",
+	while ((option = getopt_long(argc, argv, ":pto:R:",
 	    wifi_longopts, NULL)) != -1) {
 		switch (option) {
 		case 'p':
 			state.ss_parsable = B_TRUE;
 			break;
-		case 'P':
-			state.ss_persist = B_TRUE;
+		case 't':
+			state.ss_temp = B_TRUE;
 			break;
 		case 'o':
 			o_arg = B_TRUE;
@@ -7506,6 +7305,13 @@
 			else
 				fields_str = optarg;
 			break;
+		case 'R':
+			status = dladm_set_rootdir(optarg);
+			if (status != DLADM_STATUS_OK) {
+				die_dlerr(status, "invalid directory "
+				    "specified");
+			}
+			break;
 		default:
 			die_opterr(optopt, option, use);
 			break;
@@ -7524,7 +7330,7 @@
 	dladm_ofmt_check(oferr, state.ss_parsable, ofmt);
 	state.ss_ofmt = ofmt;
 
-	flags = state.ss_persist ? DLADM_OPT_PERSIST : 0;
+	flags = state.ss_temp ? DLADM_OPT_ACTIVE : DLADM_OPT_PERSIST;
 
 	if (optind == (argc - 1)) {
 		uint_t obj_fields = 1;
@@ -7542,7 +7348,7 @@
 		for (i = 0; i < obj_fields; i++) {
 			field = strtok_r(token, ",", &lasts);
 			token = NULL;
-			if (!show_secobj(handle, &state, field))
+			if (!show_secobj(handle, &state, field, 0))
 				break;
 		}
 		free(token);
@@ -7553,9 +7359,10 @@
 
 	status = dladm_walk_secobj(handle, &state, show_secobj, flags);
 
+	ofmt_close(ofmt);
+
 	if (status != DLADM_STATUS_OK)
 		die_dlerr(status, "show-secobj");
-	ofmt_close(ofmt);
 }
 
 /*ARGSUSED*/
@@ -7710,17 +7517,6 @@
 	return (DLADM_WALK_CONTINUE);
 }
 
-/* ARGSUSED */
-static void
-do_init_secobj(int argc, char **argv, const char *use)
-{
-	dladm_status_t	status;
-
-	status = dladm_init_secobj(handle);
-	if (status != DLADM_STATUS_OK)
-		die_dlerr(status, "secure object initialization failed");
-}
-
 enum bridge_func {
 	brCreate, brAdd, brModify
 };
--- a/usr/src/cmd/svc/milestone/net-nwam	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/svc/milestone/net-nwam	Wed May 29 08:31:24 2013 +0200
@@ -165,7 +165,7 @@
 	# Copy /etc/nsswitch.conf file
 	copy_to_legacy_loc /etc/nsswitch.conf
 	NAMESERVICES_CONFIG_FILE="$VOL_LEGACY_PATH/nsswitch.conf"
-	
+
 	# Gather DNS info from resolv.conf if present.
 	if [ -f /etc/resolv.conf ]; then
 		NAMESERVICES="dns,"
@@ -238,7 +238,7 @@
 	# Retrieve NFSv4 domain from SMF.
 	if service_is_enabled $NFS_MAPID_FMRI; then
 		NFS_DOMAIN=`get_smf_prop NFS_MAPID_FMRI \
-		    nfs-props/nfsmapid_domain`    
+		    nfs-props/nfsmapid_domain`
 		write_loc_prop "nfsv4-domain" \
 		    $NFS_DOMAIN $CREATE_LOC_LEGACY_FILE
 	fi
@@ -313,7 +313,7 @@
 	if [ -n "$IPNAT_CONFIG_FILE" -a -f "$IPNAT_CONFIG_FILE" ]; then
 		write_loc_prop "ipnat-config-file" $IPNAT_CONFIG_FILE \
 		    $CREATE_LOC_LEGACY_FILE
-	fi   
+	fi
 	if [ -n "$IPPOOL_CONFIG_FILE" -a -f "$IPPOOL_CONFIG_FILE" ]; then
 		write_loc_prop "ippool-config-file" $IPPOOL_CONFIG_FILE \
 		    $CREATE_LOC_LEGACY_FILE
@@ -504,7 +504,7 @@
 	# The real daemon is not started in a shared stack zone. But we need to
 	# create a dummy background process to preserve contract lifetime.
 	smf_configure_ip
-	if [ $? = "1" ] ; then 
+	if [ $? = "1" ] ; then
 		$RM -f $VOL_NWAM_PATH/nwam_blocked
 		$MKFIFO $VOL_NWAM_PATH/nwam_blocked
 		($CAT <$VOL_NWAM_PATH/nwam_blocked >/dev/null) &
@@ -553,8 +553,6 @@
 
 		# Bring up simnet instances
 		/sbin/dladm up-simnet
-		# Initialize security objects.
-		/sbin/dladm init-secobj
 
 		#
 		# Initialize VNICs, VLANs and flows.  Though they are brought
@@ -588,7 +586,7 @@
 'stop')
 	# We need to make the dummy process we created above stop.
 	smf_configure_ip
-	if [ $? = "1" ] ; then 
+	if [ $? = "1" ] ; then
 		echo "stop" > $VOL_NWAM_PATH/nwam_blocked
 		exit $SMF_EXIT_OK
 	fi
@@ -604,7 +602,7 @@
 		exit $SMF_EXIT_OK
 	fi
 	revert_to_legacy_loc
-	# remove the location property group 
+	# remove the location property group
 	$SVCCFG -s $NET_LOC_FMRI delpg location
 	;;
 
@@ -614,7 +612,7 @@
 	# network/physical:nwam will be disabled.
 	# There are various other parts of the system (nscd, nfs) that
 	# depend on continuing to have a working network.  For this
-	# reason we don't change the network configuration immediately.	
+	# reason we don't change the network configuration immediately.
 	#
 	# Disable network/physical temporarily and make sure that will
 	# be enabled on reboot.
@@ -622,7 +620,7 @@
 	$SVCCFG -s $NET_PHYS_FMRI setprop general/enabled=true
 
 	# If nwam is online then make sure that it's temporarily enabled.
-	nwam_online=`$SVCPROP -t -p restarter/state $NET_NWAM_FMRI`	
+	nwam_online=`$SVCPROP -t -p restarter/state $NET_NWAM_FMRI`
 	if [ $? -eq 0 ]; then
 		set -- $nwam_online
 		[ $3 = "online" ] && $SVCADM enable -st $NET_NWAM_FMRI
--- a/usr/src/cmd/svc/milestone/net-physical	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/svc/milestone/net-physical	Wed May 29 08:31:24 2013 +0200
@@ -259,17 +259,6 @@
 	[ -n "$inet_failed" ] && warn_failed_ifs "plumb IPv4" "$inet_failed"
 fi
 
-# Run autoconf to connect to a WLAN if the interface is a wireless one
-if [ -x /sbin/wificonfig -a -n "$inet_plumbed" ]; then
-	set -- $inet_plumbed
-	while [ $# -gt 0 ]; do
-			if [ -r /dev/wifi/$1 ]; then
-				/sbin/wificonfig -i $1 startconf >/dev/null
-			fi
-		shift
-	done
-fi
-
 #
 # Step through the IPv6 interface list and plumb every interface.
 # Generate list of plumbed and failed IPv6 interfaces.  Each plumbed
--- a/usr/src/cmd/svc/milestone/network-physical.xml	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/cmd/svc/milestone/network-physical.xml	Wed May 29 08:31:24 2013 +0200
@@ -93,6 +93,20 @@
 
 	<instance name='nwam' enabled='false'>
 
+	<!--
+		wpa_supplicant just opens global control interface and waits for
+		wpa_ctrl to add an interface (could be wired OR wireless)
+	-->
+	<!--
+	<dependency
+		name='wpa_supplicant'
+		grouping='require_all'
+		restart_on='none'
+		type='service'>
+		<service_fmri value='svc:/network/wpa_supplicant' />
+	</dependency>
+	-->
+
 	<exec_method
 		type='method'
 		name='start'
@@ -137,13 +151,9 @@
 	<property_group name='nwamd' type='application'>
 		<stability value='Unstable' />
 		<propval name='debug' type='boolean' value='false' />
-		<propval name='autoconf' type='boolean' value='false' />
 		<propval name='ncu_wait_time' type='count' value='60' />
 		<propval name='condition_check_interval' type='count'
 			value='120' />
-		<propval name='scan_interval' type='count' value='120' />
-		<propval name='scan_level' type='astring' value='weak' />
-		<propval name='strict_bssid' type='boolean' value='false' />
 		<propval name='active_ncp' type='astring' value='Automatic' />
 		<propval name='value_authorization' type='astring'
 			value='solaris.smf.value.nwam' />
--- a/usr/src/lib/libdladm/Makefile	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libdladm/Makefile	Wed May 29 08:31:24 2013 +0200
@@ -20,12 +20,13 @@
 #
 #
 # Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
 #
 #
 
 include $(SRC)/lib/Makefile.lib
 
-HDRS =		libdladm.h libdladm_impl.h libdllink.h libdlaggr.h	\
+HDRS =		libdladm.h libdladm_impl.h libdllink.h libdlaggr.h secobj.h \
 		libdlwlan.h libdlwlan_impl.h libdlvnic.h libdlvlan.h	\
 		libdlmgmt.h libdlflow.h libdlflow_impl.h libdlstat.h	\
 		libdlether.h libdlsim.h libdlbridge.h libdliptun.h	\
@@ -37,10 +38,10 @@
 $(BUILD64)SUBDIRS += $(MACH64)
 
 POFILE =	libdladm.po
-MSGFILES =	common/libdladm.c common/linkprop.c common/secobj.c	\
-		common/libdllink.c common/libdlaggr.c	\
-		common/libdlwlan.c common/libdlvnic.c	\
-		common/libdlvlan.c common/libdlmgmt.c	\
+MSGFILES =	common/libdladm.c common/linkprop.c common/libdllink.c \
+		common/libdlaggr.c common/secobj.c common/eap_pk11.c \
+		common/wpa_ie.c common/wpa_ctrl.c common/libdlwlan.c \
+		common/libdlvnic.c common/libdlvlan.c common/libdlmgmt.c \
 		common/flowattr.c common/flowprop.c	\
 		common/propfuncs.c common/libdlflow.c	\
 		common/libdlstat.c common/flowattr.c	\
--- a/usr/src/lib/libdladm/Makefile.com	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libdladm/Makefile.com	Wed May 29 08:31:24 2013 +0200
@@ -20,32 +20,42 @@
 #
 #
 # Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
 #
 
 LIBRARY = libdladm.a
 VERS    = .1
-OBJECTS = libdladm.o secobj.o linkprop.o libdllink.o libdlaggr.o \
-	libdlwlan.o libdlvnic.o libdlmgmt.o libdlvlan.o	libdlib.o\
-	flowattr.o flowprop.o propfuncs.o libdlflow.o libdlstat.o \
+OBJECTS = libdladm.o linkprop.o libdllink.o libdlaggr.o secobj.o eap_pk11.o \
+	wpa_ie.o wpa_ctrl.o libdlwlan.o libdlvnic.o libdlmgmt.o libdlvlan.o \
+	libdlib.o flowattr.o flowprop.o propfuncs.o libdlflow.o libdlstat.o \
 	usage.o libdlether.o libdlsim.o libdlbridge.o libdliptun.o
 
 include ../../Makefile.lib
 
+include	../Makefile.wpactrl
+
 # install this library in the root filesystem
 include ../../Makefile.rootfs
 
 LIBS =		$(DYNLIB) $(LINTLIB)
 LDLIBS +=	-ldevinfo -lc -linetutil -lsocket -lscf -lrcm -lnvpair \
-		-lexacct -lnsl -lkstat -lcurses -lpool
+		-lexacct -lnsl -lkstat -lcurses -lpool -lkmf -lcryptoutil
 
 SRCDIR =	../common
 $(LINTLIB) :=	SRCS = $(SRCDIR)/$(LINTSRC)
 
+# skip wpa_ctrl.c and wpa_ie.c
+lintcheck :=	SRCS = ../common/libdladm.c ../common/linkprop.c \
+	../common/libdllink.c ../common/libdlaggr.c ../common/secobj.c \
+	../common/eap_pk11.c  ../common/libdlwlan.c ../common/libdlvnic.c \
+	../common/libdlmgmt.c ../common/libdlvlan.c  ../common/libdlib.c \
+	../common/flowattr.c ../common/flowprop.c ../common/propfuncs.c \
+	../common/libdlflow.c ../common/libdlstat.c  ../common/usage.c \
+	../common/libdlether.c ../common/libdlsim.c ../common/libdlbridge.c \
+	../common/libdliptun.c
+
 CFLAGS +=	$(CCVERBOSE)
-CERRWARN +=	-_gcc=-Wno-parentheses
-CERRWARN +=	-_gcc=-Wno-switch
-CERRWARN +=	-_gcc=-Wno-unused-label
-CERRWARN +=	-_gcc=-Wno-uninitialized
+CERRWARN +=     -_gcc=-Wno-uninitialized
 CPPFLAGS +=	-I$(SRCDIR) -D_REENTRANT
 
 .KEEP_STATE:
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libdladm/Makefile.wpactrl	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,22 @@
+#
+# This file and its contents are supplied under the terms of the
+# Common Development and Distribution License ("CDDL"), version 1.0.
+# You may only use this file in accordance with the terms of version
+# 1.0 of the CDDL.
+#
+# A full copy of the text of the CDDL should have accompanied this
+# source.  A copy of the CDDL is also available via the Internet at
+# http://www.illumos.org/license/CDDL.
+#
+
+#
+# Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
+#
+
+WPASPATH=	$(SRC)/cmd/cmd-inet/usr.lib/wpa_supplicant
+
+WPAINC= 	-I$(WPASPATH)/src/common -I$(WPASPATH)/src/utils
+
+include $(WPASPATH)/wpa_supplicant/Makefile.cflags
+
+pics/wpa_ctrl.o := CPPFLAGS += -xc99=%all $(WPAFLAGS) $(WPAINC)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libdladm/common/eap_pk11.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,790 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy is of the CDDL is also available via the Internet
+ * at http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2012 Enrico Papi <enricop@computer.org>.  All rights reserved.
+ */
+
+/*
+ * PKCS#11 keystore keys/certificates import support routines.
+ * Required for using OpenSSL ENGINE when connecting to EAP-TLS protected
+ * network with wpa_supplicant.
+ *
+ * The code is based on 'pktool'
+ */
+
+#include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <cryptoutil.h>
+#include <kmfapi.h>
+#include <secobj.h>
+
+#define	PRINT_PIN_FILE	"#!/bin/sh\n/usr/gnu/bin/echo -n "
+#define	EMPTYSTRING(s)	(s == NULL || !strlen(s))
+
+static KMF_RETURN
+select_token_pk11(void *kmfhandle, int readonly)
+{
+	KMF_ATTRIBUTE attlist[10];
+	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
+	KMF_RETURN rv;
+
+	kmf_set_attr_at_index(attlist, 0, KMF_KEYSTORE_TYPE_ATTR, &kstype,
+	    sizeof (kstype));
+
+	kmf_set_attr_at_index(attlist, 1, KMF_TOKEN_LABEL_ATTR,
+	    SOFT_TOKEN_LABEL, strlen(SOFT_TOKEN_LABEL));
+
+	kmf_set_attr_at_index(attlist, 2, KMF_READONLY_ATTR, &readonly,
+	    sizeof (readonly));
+
+	rv = kmf_configure_keystore(kmfhandle, 3, attlist);
+	if (rv == KMF_ERR_TOKEN_SELECTED)
+		rv = KMF_OK;
+	return (rv);
+}
+
+static int
+setpin_pkcs11(KMF_HANDLE_T handle, char *new_pin, uint32_t new_pin_len)
+{
+	ulong_t		slot_id;
+	int		rv;
+	KMF_CREDENTIAL	newcred = {NULL, 0};
+	KMF_CREDENTIAL	oldcred = {NULL, 0};
+	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
+	KMF_ATTRIBUTE	attrlist[6];
+	char 		*token_spec = SOFT_TOKEN_LABEL ":" SOFT_MANUFACTURER_ID;
+
+	rv = kmf_pk11_token_lookup(NULL, token_spec, &slot_id);
+	if (rv != KMF_OK)
+		return (-1);
+
+	if ((oldcred.cred = strdup(SOFT_DEFAULT_PIN)) == NULL)
+		return (-1);
+	oldcred.credlen = strlen(SOFT_DEFAULT_PIN);
+
+	kmf_set_attr_at_index(attrlist, 0, KMF_KEYSTORE_TYPE_ATTR,
+	    &kstype, sizeof (kstype));
+
+	kmf_set_attr_at_index(attrlist, 1, KMF_TOKEN_LABEL_ATTR,
+	    SOFT_TOKEN_LABEL, strlen(SOFT_TOKEN_LABEL));
+
+	kmf_set_attr_at_index(attrlist, 2, KMF_CREDENTIAL_ATTR, &oldcred,
+	    sizeof (oldcred));
+
+	kmf_set_attr_at_index(attrlist, 3, KMF_SLOT_ID_ATTR, &slot_id,
+	    sizeof (slot_id));
+
+	newcred.cred = new_pin;
+	newcred.credlen = new_pin_len;
+	kmf_set_attr_at_index(attrlist, 4, KMF_NEWPIN_ATTR, &newcred,
+	    sizeof (newcred));
+
+	rv = kmf_set_token_pin(handle, 5, attrlist);
+
+	/* Clean up. */
+	if (oldcred.cred != NULL)
+		free(oldcred.cred);
+
+	return (rv);
+}
+
+static KMF_RETURN
+destroy_keys(void *handle, KMF_ATTRIBUTE *attrlist, int numattr)
+{
+	int i;
+	KMF_RETURN rv;
+	uint32_t *numkeys;
+	KMF_KEY_HANDLE *keys;
+	int del_num = 0;
+	KMF_ATTRIBUTE delete_attlist[16];
+	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
+	boolean_t destroy = B_TRUE;
+	KMF_CREDENTIAL cred;
+
+	kmf_set_attr_at_index(delete_attlist, del_num,
+	    KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
+	del_num++;
+
+	kmf_set_attr_at_index(delete_attlist, del_num,
+	    KMF_DESTROY_BOOL_ATTR, &destroy, sizeof (boolean_t));
+	del_num++;
+
+	rv = kmf_get_attr(KMF_CREDENTIAL_ATTR, attrlist, numattr, &cred, NULL);
+	if (rv == KMF_OK) {
+		if (cred.credlen > 0) {
+			kmf_set_attr_at_index(delete_attlist, del_num,
+			    KMF_CREDENTIAL_ATTR, &cred,
+			    sizeof (KMF_CREDENTIAL));
+			del_num++;
+		}
+	}
+
+	numkeys = kmf_get_attr_ptr(KMF_COUNT_ATTR, attrlist, numattr);
+	if (numkeys == NULL)
+		return (KMF_ERR_KEY_NOT_FOUND);
+
+	keys = kmf_get_attr_ptr(KMF_KEY_HANDLE_ATTR, attrlist, numattr);
+	if (keys == NULL)
+		return (KMF_ERR_KEY_NOT_FOUND);
+
+	for (i = 0; rv == KMF_OK && i < *numkeys; i++) {
+		int num = del_num;
+
+		kmf_set_attr_at_index(delete_attlist, num,
+		    KMF_KEY_HANDLE_ATTR, &keys[i], sizeof (KMF_KEY_HANDLE));
+		num++;
+
+		rv = kmf_delete_key_from_keystore(handle, num, delete_attlist);
+	}
+	return (rv);
+}
+
+static KMF_RETURN
+delete_keys(KMF_HANDLE_T kmfhandle, KMF_ATTRIBUTE *attlist, int numattr,
+    int *keysdeleted)
+{
+	KMF_RETURN rv;
+	uint32_t numkeys;
+	int num = numattr;
+
+	*keysdeleted = 0;
+	numkeys = 0;
+
+	kmf_set_attr_at_index(attlist, num, KMF_COUNT_ATTR, &numkeys,
+	    sizeof (uint32_t));
+	num++;
+
+	rv = kmf_find_key(kmfhandle, num, attlist);
+
+	if (rv == KMF_OK && numkeys > 0) {
+		KMF_KEY_HANDLE *keys;
+		keys = (KMF_KEY_HANDLE *)malloc(numkeys *
+		    sizeof (KMF_KEY_HANDLE));
+		if (keys == NULL)
+			return (KMF_ERR_MEMORY);
+		(void) memset(keys, 0, numkeys *sizeof (KMF_KEY_HANDLE));
+
+		kmf_set_attr_at_index(attlist, num, KMF_KEY_HANDLE_ATTR, keys,
+		    sizeof (KMF_KEY_HANDLE));
+
+		rv = kmf_find_key(kmfhandle, num, attlist);
+		if (rv == KMF_OK)
+			rv = destroy_keys(kmfhandle, attlist, num);
+
+		free(keys);
+	}
+
+	*keysdeleted = numkeys;
+	return (rv);
+}
+
+static KMF_RETURN
+delete_pk11_keys(KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *tokencred,
+    char *objlabel)
+{
+	KMF_RETURN rv = KMF_OK;
+	int nk;
+	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
+	int numattr = 0;
+	KMF_ATTRIBUTE attrlist[16];
+	/* User is supposed to import only private keys */
+	KMF_KEY_CLASS keyclass = KMF_ASYM_PRI;
+	boolean_t token_bool = B_TRUE;
+	boolean_t private = B_TRUE;
+	/*
+	 * Symmetric keys and RSA/DSA private keys are always
+	 * created with the "CKA_PRIVATE" field == TRUE, so
+	 * make sure we search for them with it also set.
+	 */
+
+	rv = select_token_pk11(kmfhandle, FALSE);
+	if (rv != KMF_OK) {
+		return (rv);
+	}
+
+	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
+	    &kstype, sizeof (kstype));
+	numattr++;
+
+	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR, objlabel,
+	    strlen(objlabel));
+	numattr++;
+
+	if (tokencred != NULL && tokencred->credlen > 0) {
+		kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR,
+		    tokencred, sizeof (KMF_CREDENTIAL));
+		numattr++;
+	}
+
+	kmf_set_attr_at_index(attrlist, numattr, KMF_PRIVATE_BOOL_ATTR,
+	    &private, sizeof (private));
+	numattr++;
+
+	kmf_set_attr_at_index(attrlist, numattr, KMF_TOKEN_BOOL_ATTR,
+	    &token_bool, sizeof (token_bool));
+	numattr++;
+
+	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR,
+	    &keyclass, sizeof (keyclass));
+	numattr++;
+
+	rv = delete_keys(kmfhandle, attrlist, numattr, &nk);
+
+	if (rv == KMF_OK && nk == 0)
+		rv = KMF_ERR_KEY_NOT_FOUND;
+
+	return (rv);
+}
+
+static KMF_RETURN
+delete_certs(KMF_HANDLE_T kmfhandle, KMF_ATTRIBUTE *attlist, const int numattr)
+{
+	KMF_RETURN rv;
+	uint32_t numcerts = 0;
+	int num = numattr;
+
+	kmf_set_attr_at_index(attlist, num, KMF_COUNT_ATTR, &numcerts,
+	    sizeof (uint32_t));
+	num++;
+
+	rv = kmf_find_cert(kmfhandle, num, attlist);
+	if (rv == KMF_OK && numcerts > 0) {
+		/*
+		 * Use numattr because delete cert does not require
+		 * KMF_COUNT_ATTR attribute.
+		 */
+		rv = kmf_delete_cert_from_keystore(kmfhandle, numattr, attlist);
+	}
+
+	return (rv);
+}
+
+static KMF_RETURN
+delete_pk11_certs(KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *tokencred,
+    char *objlabel)
+{
+	KMF_RETURN kmfrv;
+	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
+	int numattr = 0;
+	KMF_ATTRIBUTE attrlist[16];
+
+	kmfrv = select_token_pk11(kmfhandle, FALSE);
+
+	if (kmfrv != KMF_OK) {
+		return (kmfrv);
+	}
+
+	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
+	    &kstype, sizeof (kstype));
+	numattr++;
+
+	if (tokencred != NULL && tokencred->credlen > 0) {
+		kmf_set_attr_at_index(attrlist, numattr, KMF_CREDENTIAL_ATTR,
+		    tokencred, sizeof (KMF_CREDENTIAL));
+		numattr++;
+	}
+
+	kmf_set_attr_at_index(attrlist, numattr, KMF_CERT_LABEL_ATTR, objlabel,
+	    strlen(objlabel));
+	numattr++;
+
+	kmfrv = delete_certs(kmfhandle, attrlist, numattr);
+
+	return (kmfrv);
+}
+
+/*
+ * Delete token objects.
+ */
+dladm_status_t
+dladm_eap_delete(char *label, dladm_secobj_class_t obj_type)
+{
+	struct stat	statbuf;
+	KMF_HANDLE_T	kmfhandle;
+	KMF_CREDENTIAL	tokencred = {NULL, 0};
+
+	KMF_RETURN	keyrv = KMF_ERR_KEY_NOT_FOUND;
+	KMF_RETURN	certrv = KMF_ERR_KEY_NOT_FOUND;
+	dladm_status_t  status = DLADM_STATUS_OK;
+
+	if (obj_type == 0)
+		return (DLADM_STATUS_BADARG);
+
+	if (label == NULL)
+		return (DLADM_STATUS_BADARG);
+
+	if (stat(PIN_FILE, &statbuf) < 0)
+		return (DLADM_STATUS_BADVAL);
+
+	/* GET PIN */
+	if (S_ISREG(statbuf.st_mode)) {
+		char random_pin[DLADM_SECOBJ_VAL_MAX];
+		FILE *fp;
+		if ((fp = fopen(PIN_FILE, "r")) == NULL)
+			return (DLADM_STATUS_FAILED);
+		if ((fscanf(fp, PRINT_PIN_FILE "%255s\n", random_pin)) == EOF)
+			return (DLADM_STATUS_FAILED);
+		if (fclose(fp))
+			return (DLADM_STATUS_FAILED);
+		tokencred.credlen = strnlen(random_pin, DLADM_SECOBJ_VAL_MAX);
+		tokencred.cred = strndup(random_pin, tokencred.credlen);
+		if (tokencred.cred == NULL)
+			return (DLADM_STATUS_FAILED);
+	} else
+		return (DLADM_STATUS_FAILED);
+
+	if (setenv("METASLOT_ENABLED", "false", 1) < 0)
+		return (DLADM_STATUS_FAILED);
+	if (setenv("SOFTTOKEN_DIR", "/etc/dladm", 1) < 0)
+		return (DLADM_STATUS_FAILED);
+
+	if ((kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK)
+		return (DLADM_STATUS_FAILED);
+
+	if (obj_type == DLADM_SECOBJ_CLASS_TLS)
+		keyrv = delete_pk11_keys(kmfhandle, &tokencred, label);
+
+	certrv = delete_pk11_certs(kmfhandle, &tokencred, label);
+
+	/*
+	 * Logic here:
+	 *    If searching for more than just one class of object (key or cert)
+	 *    and only 1 of the classes was not found, it is not an error.
+	 *    If searching for just one class of object, that failure should
+	 *    be reported.
+	 *
+	 *    Any error other than "KMF_ERR_[key/cert]_NOT_FOUND" should
+	 *    be reported either way.
+	 */
+	if (keyrv != KMF_ERR_KEY_NOT_FOUND && keyrv != KMF_OK)
+		status = DLADM_STATUS_FAILED;
+	else if (certrv != KMF_OK && certrv != KMF_ERR_CERT_NOT_FOUND)
+		status = DLADM_STATUS_FAILED;
+
+	/*
+	 * If nothing was found, return error.
+	 */
+	if (keyrv == KMF_ERR_KEY_NOT_FOUND && certrv == KMF_ERR_CERT_NOT_FOUND)
+		status = DLADM_STATUS_NOTFOUND;
+
+	(void) kmf_finalize(kmfhandle);
+	free(tokencred.cred);
+	return (status);
+}
+
+static KMF_RETURN
+import_cert_pk11(KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *tokencred,
+    char *filename, char *label)
+{
+	KMF_RETURN rv;
+	KMF_ATTRIBUTE attrlist[32];
+	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
+	int i = 0;
+
+	rv = select_token_pk11(kmfhandle, FALSE);
+
+	if (rv != KMF_OK)
+		return (rv);
+
+	kmf_set_attr_at_index(attrlist, i,
+	    KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (KMF_KEYSTORE_TYPE));
+	i++;
+
+	kmf_set_attr_at_index(attrlist, i, KMF_CERT_FILENAME_ATTR,
+	    filename, strlen(filename));
+	i++;
+
+	kmf_set_attr_at_index(attrlist, i, KMF_CERT_LABEL_ATTR,
+	    label, strlen(label));
+	i++;
+
+	kmf_set_attr_at_index(attrlist, i, KMF_CREDENTIAL_ATTR, &tokencred,
+	    sizeof (KMF_CREDENTIAL));
+	i++;
+
+	rv = kmf_import_cert(kmfhandle, i, attrlist);
+
+	return (rv);
+}
+
+#define	NEW_ATTRLIST(a, n) \
+{ \
+	a = (KMF_ATTRIBUTE *)malloc(n * sizeof (KMF_ATTRIBUTE)); \
+	if (a == NULL) { \
+		rv = KMF_ERR_MEMORY; \
+		goto end; \
+	} \
+	(void) memset(a, 0, n * sizeof (KMF_ATTRIBUTE));  \
+}
+
+static KMF_RETURN
+import_pk12_pk11(KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *p12cred,
+    KMF_CREDENTIAL *tokencred, char *filename, char *label)
+{
+	KMF_RETURN rv;
+	KMF_X509_DER_CERT *certs;
+	KMF_RAW_KEY_DATA *keys;
+	int ncerts = 0;
+	int nkeys = 0;
+	int i;
+	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
+	KMF_ATTRIBUTE *attrlist;
+	int numattr = 0;
+
+	rv = select_token_pk11(kmfhandle, FALSE);
+
+	if (rv != KMF_OK)
+		return (rv);
+
+	rv = kmf_import_objects(kmfhandle, filename, p12cred, &certs,
+	    &ncerts, &keys, &nkeys);
+
+	if (rv == KMF_OK) {
+		NEW_ATTRLIST(attrlist, (3 + (2 * nkeys)));
+
+		kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
+		    &kstype, sizeof (kstype));
+		numattr++;
+
+		kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR,
+		    label, strlen(label));
+			numattr++;
+
+		if (tokencred != NULL && tokencred->credlen > 0) {
+			kmf_set_attr_at_index(attrlist, numattr,
+			    KMF_CREDENTIAL_ATTR, tokencred,
+			    sizeof (KMF_CREDENTIAL));
+			numattr++;
+		}
+
+		/* The order of certificates and keys should match */
+		for (i = 0; i < nkeys; i++) {
+			int num = numattr;
+
+			if (i < ncerts) {
+				kmf_set_attr_at_index(attrlist, num,
+				    KMF_CERT_DATA_ATTR, &certs[i].certificate,
+				    sizeof (KMF_DATA));
+				num++;
+			}
+
+			kmf_set_attr_at_index(attrlist, num,
+			    KMF_RAW_KEY_ATTR, &keys[i],
+			    sizeof (KMF_RAW_KEY_DATA));
+			num++;
+
+			rv = kmf_store_key(kmfhandle, num, attrlist);
+
+		}
+		free(attrlist);
+	}
+
+	if (rv == KMF_OK) {
+		numattr = 0;
+		NEW_ATTRLIST(attrlist, (1 + (2 * ncerts)));
+
+		kmf_set_attr_at_index(attrlist, numattr,
+		    KMF_KEYSTORE_TYPE_ATTR, &kstype, sizeof (kstype));
+		numattr++;
+
+		for (i = 0; rv == KMF_OK && i < ncerts; i++) {
+			int num = numattr;
+			if (certs[i].kmf_private.label != NULL) {
+				kmf_set_attr_at_index(attrlist, num,
+				    KMF_CERT_LABEL_ATTR,
+				    certs[i].kmf_private.label,
+				    strlen(certs[i].kmf_private.label));
+				num++;
+			} else if (i == 0 && label != NULL) {
+				kmf_set_attr_at_index(attrlist, num,
+				    KMF_CERT_LABEL_ATTR, label, strlen(label));
+				num++;
+			}
+
+			kmf_set_attr_at_index(attrlist, num,
+			    KMF_CERT_DATA_ATTR, &certs[i].certificate,
+			    sizeof (KMF_DATA));
+			num++;
+
+			rv = kmf_store_cert(kmfhandle, num, attrlist);
+		}
+		free(attrlist);
+	}
+
+end:
+	/*
+	 * Cleanup memory.
+	 */
+	if (certs) {
+		for (i = 0; i < ncerts; i++)
+			kmf_free_kmf_cert(kmfhandle, &certs[i]);
+		free(certs);
+	}
+	if (keys) {
+		for (i = 0; i < nkeys; i++)
+			kmf_free_raw_key(&keys[i]);
+		free(keys);
+	}
+
+	return (rv);
+}
+
+/*ARGSUSED*/
+static KMF_RETURN
+import_keys_pk11(KMF_HANDLE_T kmfhandle, KMF_CREDENTIAL *cred,
+    char *filename, char *label)
+{
+	KMF_RETURN rv;
+	KMF_ATTRIBUTE attrlist[16];
+	int numattr = 0;
+	KMF_KEY_HANDLE key;
+	KMF_RAW_KEY_DATA rawkey;
+	KMF_KEY_CLASS class = KMF_ASYM_PRI;
+	int numkeys = 1;
+	KMF_KEYSTORE_TYPE kstype = KMF_KEYSTORE_PK11TOKEN;
+
+	rv = select_token_pk11(kmfhandle, FALSE);
+
+	if (rv != KMF_OK)
+		return (rv);
+	/*
+	 * First, set up to read the keyfile using the FILE plugin
+	 * mechanisms.
+	 */
+	kmf_set_attr_at_index(attrlist, numattr, KMF_COUNT_ATTR,
+	    &numkeys, sizeof (numkeys));
+	numattr++;
+
+	kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_HANDLE_ATTR,
+	    &key, sizeof (key));
+	numattr++;
+
+	kmf_set_attr_at_index(attrlist, numattr, KMF_RAW_KEY_ATTR,
+	    &rawkey, sizeof (rawkey));
+	numattr++;
+
+	kmf_set_attr_at_index(attrlist, numattr, KMF_KEYCLASS_ATTR,
+	    &class, sizeof (class));
+	numattr++;
+
+	kmf_set_attr_at_index(attrlist, numattr, KMF_KEY_FILENAME_ATTR,
+	    filename, strlen(filename));
+	numattr++;
+
+	rv = kmf_find_key(kmfhandle, numattr, attrlist);
+	if (rv == KMF_OK) {
+		numattr = 0;
+
+		kmf_set_attr_at_index(attrlist, numattr, KMF_KEYSTORE_TYPE_ATTR,
+		    &kstype, sizeof (kstype));
+		numattr++;
+
+		if (cred != NULL && cred->credlen > 0) {
+			kmf_set_attr_at_index(attrlist, numattr,
+			    KMF_CREDENTIAL_ATTR, cred, sizeof (KMF_CREDENTIAL));
+			numattr++;
+		}
+
+		kmf_set_attr_at_index(attrlist, numattr, KMF_KEYLABEL_ATTR,
+		    label, strlen(label));
+		numattr++;
+
+		kmf_set_attr_at_index(attrlist, numattr,
+		    KMF_RAW_KEY_ATTR, &rawkey, sizeof (rawkey));
+		numattr++;
+
+		rv = kmf_store_key(kmfhandle, numattr, attrlist);
+		if (rv == KMF_OK)
+			(void) printf("Importing %d keys\n", numkeys);
+
+		kmf_free_kmf_key(kmfhandle, &key);
+		kmf_free_raw_key(&rawkey);
+	} else {
+		/* to be removed */
+		(void) printf("Failed importing key from %s\n", filename);
+	}
+	return (rv);
+}
+
+/*
+ * Import objects from into KMF repositories.
+ */
+dladm_status_t
+dladm_eap_import(dladm_handle_t handle, char *filename, char *label,
+    const char *secobjname, const dladm_secobj_class_t obj_type)
+{
+	struct	stat		statbuf;
+	dladm_status_t		status = DLADM_STATUS_OK;
+	KMF_ENCODE_FORMAT	kfmt = 0;
+	KMF_RETURN		rv;
+	KMF_CREDENTIAL		filecred = { NULL, 0 };
+	KMF_CREDENTIAL		tokencred = { NULL, 0 };
+	KMF_HANDLE_T		kmfhandle;
+	char 			random_bytes[DLADM_SECOBJ_VAL_MAX];
+	int			len;
+
+	/* Filename arg is required. */
+	if (EMPTYSTRING(filename))
+		return (DLADM_STATUS_BADARG);
+
+	/* Label arg is required. */
+	if (EMPTYSTRING(label))
+		return (DLADM_STATUS_BADARG);
+
+	if (obj_type == 0)
+		return (DLADM_STATUS_BADARG);
+
+	len = strnlen(filename, FILENAME_MAX);
+	if (filename[0] == '"' && filename[len - 1] == '"') {
+		filename[len - 1] = '\0';
+		filename++;
+	}
+
+	switch (kmf_get_file_format(filename, &kfmt)) {
+		case KMF_OK:
+			break;
+		case KMF_ERR_BAD_PARAMETER:
+			return (DLADM_STATUS_BADARG);
+		case KMF_ERR_OPEN_FILE:
+			return (DLADM_STATUS_NOTFOUND);
+		case KMF_ERR_ENCODING:
+			return (DLADM_STATUS_NOTSUP);
+		default:
+			return (DLADM_STATUS_FAILED);
+	}
+
+	/*
+	 * Get Token PIN. Initialize if it is not set
+	 */
+	if (stat(PIN_FILE, &statbuf) < 0) {
+		int i, fd;
+		mode_t mode = S_IRUSR | S_IXUSR;
+		if (pkcs11_get_random(random_bytes, DLADM_SECOBJ_VAL_MAX) != 0)
+			return (DLADM_STATUS_FAILED);
+		for (i = 0; i < DLADM_SECOBJ_VAL_MAX; i++) {
+			if (isalnum(random_bytes[i])) {
+				random_bytes[tokencred.credlen] =
+				    random_bytes[i];
+				tokencred.credlen++;
+			}
+		}
+		if ((fd = creat(PIN_FILE, mode)) == -1)
+			return (DLADM_STATUS_FAILED);
+		if (write(fd, PRINT_PIN_FILE, strlen(PRINT_PIN_FILE)) !=
+		    strlen(PRINT_PIN_FILE))
+			return (DLADM_STATUS_FAILED);
+		if (write(fd, random_bytes, tokencred.credlen) !=
+		    tokencred.credlen)
+			return (DLADM_STATUS_FAILED);
+		if (write(fd, "\n", 1) != 1)
+			return (DLADM_STATUS_FAILED);
+		if (close(fd))
+			return (DLADM_STATUS_FAILED);
+		tokencred.cred = &random_bytes[0];
+	} else if (S_ISREG(statbuf.st_mode)) {
+		FILE *fp;
+		if ((fp = fopen(PIN_FILE, "r")) == NULL)
+			return (DLADM_STATUS_FAILED);
+		if ((fscanf(fp, PRINT_PIN_FILE "%255s\n", random_bytes)) == EOF)
+			return (DLADM_STATUS_FAILED);
+		if (fclose(fp))
+			return (DLADM_STATUS_FAILED);
+		tokencred.credlen = strnlen(random_bytes, DLADM_SECOBJ_VAL_MAX);
+		tokencred.cred = &random_bytes[0];
+	} else
+		return (DLADM_STATUS_FAILED);
+
+	if (setenv("METASLOT_ENABLED", "false", 1) < 0)
+		return (DLADM_STATUS_FAILED);
+	if (setenv("SOFTTOKEN_DIR", "/etc/dladm", 1) < 0)
+		return (DLADM_STATUS_FAILED);
+
+	/* Retrieve temporary secobj value, containg private key passphrase */
+	if (!(EMPTYSTRING(secobjname))) {
+		dladm_wlan_key_t keydata;
+		(void) strlcpy(keydata.wk_name, secobjname,
+		    DLADM_SECOBJ_NAME_MAX);
+		status = dladm_get_secobj(handle, &keydata,
+		    DLADM_OPT_ACTIVE | DLADM_OPT_PERSIST);
+		if (status != DLADM_STATUS_OK) {
+			if (status == DLADM_STATUS_NOTFOUND)
+				return (DLADM_STATUS_BADARG);
+			else
+				return (DLADM_STATUS_FAILED);
+		}
+		filecred.cred = malloc(keydata.wk_len);
+		if (filecred.cred == NULL)
+			return (DLADM_STATUS_FAILED);
+		(void) memcpy(filecred.cred, keydata.wk_val, keydata.wk_len);
+		filecred.credlen = keydata.wk_len;
+	}
+
+	if ((rv = kmf_initialize(&kmfhandle, NULL, NULL)) != KMF_OK)
+		/* "Error initializing KMF" */
+		return (DLADM_STATUS_FAILED);
+
+	/*
+	 * this means that we have just generated the new PIN and we have to
+	 * overwrite the default PIN value
+	 */
+	if (!(S_ISREG(statbuf.st_mode)) && tokencred.cred != NULL &&
+	    tokencred.credlen != 0) {
+		rv = setpin_pkcs11(kmfhandle, tokencred.cred,
+		    tokencred.credlen);
+		if (rv == KMF_ERR_AUTH_FAILED)
+			/* Incorrect passphrase */
+			status = DLADM_STATUS_BADVAL;
+		else if (rv)
+			/* Failed to change passphrase */
+			status = (DLADM_STATUS_FAILED);
+	} else
+		status = (DLADM_STATUS_FAILED);
+
+	if (status != DLADM_STATUS_OK) {
+		(void) kmf_finalize(kmfhandle);
+		if (filecred.cred != NULL)
+			free(filecred.cred);
+	}
+
+	if (kfmt == KMF_FORMAT_PKCS12 && obj_type == DLADM_SECOBJ_CLASS_TLS) {
+		rv = import_pk12_pk11(kmfhandle, &filecred, &tokencred,
+		    filename, label);
+	} else if (kfmt == KMF_FORMAT_PEM_KEYPAIR &&
+	    obj_type == DLADM_SECOBJ_CLASS_TLS) {
+		rv = import_keys_pk11(kmfhandle, &tokencred, filename, label);
+	} else if (kfmt == KMF_FORMAT_ASN1 || kfmt == KMF_FORMAT_PEM) {
+		if (kmf_is_cert_file(kmfhandle, filename, &kfmt) !=
+		    KMF_OK && obj_type == DLADM_SECOBJ_CLASS_TLS) {
+			rv = import_keys_pk11(kmfhandle, &tokencred, filename,
+			    label);
+		} else if (kfmt == KMF_FORMAT_ASN1 || kfmt == KMF_FORMAT_PEM) {
+			rv = import_cert_pk11(kmfhandle, &tokencred, filename,
+			    label);
+		} else
+			status = DLADM_STATUS_BADVAL;
+	} else
+		status = DLADM_STATUS_BADARG;
+
+	if (rv != KMF_OK)
+		/* "Error importing objects" */
+		status = DLADM_STATUS_FAILED;
+
+	(void) kmf_finalize(kmfhandle);
+
+	if (filecred.cred != NULL)
+		free(filecred.cred);
+
+	return (status);
+}
--- a/usr/src/lib/libdladm/common/flowprop.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libdladm/common/flowprop.c	Wed May 29 08:31:24 2013 +0200
@@ -484,7 +484,7 @@
 i_dladm_flow_proplist_extract_one(dladm_arg_list_t *proplist,
     const char *name, void *arg)
 {
-	dladm_status_t		status;
+	dladm_status_t		status = DLADM_STATUS_OK;
 	dladm_arg_info_t	*aip = NULL;
 	int			i, j;
 
--- a/usr/src/lib/libdladm/common/libdladm.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libdladm/common/libdladm.c	Wed May 29 08:31:24 2013 +0200
@@ -1107,7 +1107,7 @@
 				if (*endp++ != '-')
 					return (DLADM_STATUS_BADRANGE);
 				ur->mpur_max = strtol(endp, &endp, 10);
-				if (endp != NULL && *endp != '\0' ||
+				if ((endp != NULL && *endp != '\0') ||
 				    ur->mpur_max < ur->mpur_min)
 					return (DLADM_STATUS_BADRANGE);
 			}
--- a/usr/src/lib/libdladm/common/libdliptun.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libdladm/common/libdliptun.c	Wed May 29 08:31:24 2013 +0200
@@ -122,6 +122,8 @@
 		case IPTUN_TYPE_IPV6:
 			hints.ai_family = AF_INET6;
 			break;
+		default:
+			break;
 		}
 	}
 
--- a/usr/src/lib/libdladm/common/libdllink.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libdladm/common/libdllink.h	Wed May 29 08:31:24 2013 +0200
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #ifndef _LIBDLLINK_H
@@ -62,18 +63,6 @@
 	DLADM_PROP_VAL_PERSISTENT
 } dladm_prop_type_t;
 
-/*
- * Maximum size of secobj value. Note that it should not be greater than
- * DLD_SECOBJ_VAL_MAX.
- */
-#define	DLADM_SECOBJ_VAL_MAX	256
-
-/*
- * Maximum size of secobj name. Note that it should not be greater than
- * DLD_SECOBJ_NAME_MAX.
- */
-#define	DLADM_SECOBJ_NAME_MAX	32
-
 #define	DLADM_MAX_PROP_VALCNT	32
 /*
  * Size of prop_val buffer passed to pd_get function must be at
@@ -81,10 +70,6 @@
  */
 #define	DLADM_PROP_VAL_MAX	128
 
-#define		DLADM_SECOBJ_CLASS_WEP	0
-#define		DLADM_SECOBJ_CLASS_WPA	1
-typedef int	dladm_secobj_class_t;
-
 typedef int (dladm_walkcb_t)(const char *, void *);
 
 /* possible flags for ma_flags below */
@@ -136,28 +121,10 @@
 extern boolean_t	dladm_attr_is_linkprop(const char *name);
 extern dladm_status_t	dladm_linkprop_is_set(dladm_handle_t, datalink_id_t,
 			    dladm_prop_type_t, const char *, boolean_t *);
-
-extern dladm_status_t	dladm_set_secobj(dladm_handle_t, const char *,
-			    dladm_secobj_class_t, uint8_t *, uint_t, uint_t);
-extern dladm_status_t	dladm_get_secobj(dladm_handle_t, const char *,
-			    dladm_secobj_class_t *, uint8_t *, uint_t *,
-			    uint_t);
-extern dladm_status_t	dladm_unset_secobj(dladm_handle_t, const char *,
-			    uint_t);
-extern dladm_status_t	dladm_walk_secobj(dladm_handle_t, void *,
-			    boolean_t (*)(dladm_handle_t, void *, const char *),
-			    uint_t);
-
+extern dladm_status_t	dladm_init_linkprop(dladm_handle_t, datalink_id_t,
+			    boolean_t);
 extern const char	*dladm_linkstate2str(link_state_t, char *);
 extern const char	*dladm_linkduplex2str(link_duplex_t, char *);
-extern const char	*dladm_secobjclass2str(dladm_secobj_class_t, char *);
-extern dladm_status_t	dladm_str2secobjclass(const char *,
-			    dladm_secobj_class_t *);
-
-extern dladm_status_t	dladm_init_linkprop(dladm_handle_t, datalink_id_t,
-			    boolean_t);
-extern dladm_status_t	dladm_init_secobj(dladm_handle_t);
-extern boolean_t	dladm_valid_secobj_name(const char *);
 
 extern dladm_status_t	dladm_create_datalink_id(dladm_handle_t, const char *,
 			    datalink_class_t, uint_t, uint32_t,
--- a/usr/src/lib/libdladm/common/libdlstat.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libdladm/common/libdlstat.c	Wed May 29 08:31:24 2013 +0200
@@ -1449,7 +1449,7 @@
 
 		prev = curr;
 	}
-done:
+
 	(void) kstat_close(kcp);
 	return (head);
 }
@@ -1558,7 +1558,7 @@
 static void *
 i_dlstat_rx_local_retrieve_stat(kstat_ctl_t *kcp, kstat_t *ksp, int i)
 {
-	rx_lane_stat_entry_t	*local_stat_entry;
+	rx_lane_stat_entry_t	*local_stat_entry = NULL;
 	rx_lane_stat_entry_t	*rx_lane_stat_entry;
 
 	rx_lane_stat_entry = calloc(1, sizeof (rx_lane_stat_entry_t));
@@ -2580,7 +2580,7 @@
 dlstat_aggr_total_stats(dladm_stat_chain_t *head)
 {
 	dladm_stat_chain_t	*curr;
-	dladm_stat_chain_t	*total_head;
+	dladm_stat_chain_t	*total_head = NULL;
 	aggr_port_stat_entry_t	*total_stats;
 
 	total_stats = calloc(1, sizeof (aggr_port_stat_entry_t));
@@ -2655,8 +2655,10 @@
 	uint_t			instance;
 	aggr_port_stat_entry_t	*aggr_port_stat_entry = NULL;
 
-	if (dladm_parselink(portname, module, &instance) != DLADM_STATUS_OK)
-		goto done;
+	if (dladm_parselink(portname, module, &instance) != DLADM_STATUS_OK) {
+		warn("dladm_parselink operation failed");
+		return (NULL);
+	}
 
 	if ((kcp = kstat_open()) == NULL) {
 		warn("kstat open operation failed");
@@ -2938,7 +2940,7 @@
 
 		nvstat_prev = nvstat_curr;
 	}
-done:
+
 	return (nvstat_head);
 }
 
--- a/usr/src/lib/libdladm/common/libdlvnic.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libdladm/common/libdlvnic.c	Wed May 29 08:31:24 2013 +0200
@@ -144,6 +144,9 @@
 		bcopy(ioc.vc_mac_addr, attr->va_mac_addr, MAXMACADDRLEN);
 		attr->va_mac_len = ioc.vc_mac_len;
 		break;
+	default:
+		status = DLADM_STATUS_FAILED;
+		break;
 	}
 	return (status);
 }
--- a/usr/src/lib/libdladm/common/libdlwlan.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libdladm/common/libdlwlan.c	Wed May 29 08:31:24 2013 +0200
@@ -21,104 +21,61 @@
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
-#include <libintl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
 #include <stddef.h>
-#include <string.h>
+#include <errno.h>
 #include <stropts.h>
-#include <libdevinfo.h>
-#include <net/if.h>
-#include <net/if_dl.h>
-#include <net/if_types.h>
-#include <libdlpi.h>
+#include <string.h>
+#include <unistd.h>
+#include <libscf.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <secobj.h>
+#include <wpa_defs.h>
 #include <libdllink.h>
-#include <libscf.h>
 #include <libdlwlan.h>
 #include <libdladm_impl.h>
 #include <libdlwlan_impl.h>
-#include <net/wpa.h>
-
-static dladm_status_t	wpa_instance_create(dladm_handle_t, datalink_id_t,
-			    void *);
-static dladm_status_t	wpa_instance_delete(dladm_handle_t, datalink_id_t);
+#include <sys/net80211_crypto.h>
+#include <libnwam.h>
 
-static dladm_status_t 	do_get_bsstype(dladm_handle_t, datalink_id_t, void *,
-			    int);
-static dladm_status_t 	do_get_essid(dladm_handle_t, datalink_id_t, void *,
-			    int);
-static dladm_status_t 	do_get_bssid(dladm_handle_t, datalink_id_t, void *,
-			    int);
+static dladm_status_t	wpa_instance_create(struct wpa_ctrl *, char *);
+static dladm_status_t	wpa_instance_delete(struct wpa_ctrl *, char *);
+static dladm_status_t	wpa_network_config(struct wpa_ctrl *,
+    dladm_wlan_attr_t *attrp, const dladm_wlan_key_t *key,
+    dladm_wlan_eap_t *identity);
+
 static dladm_status_t 	do_get_signal(dladm_handle_t, datalink_id_t, void *,
-			    int);
-static dladm_status_t 	do_get_encryption(dladm_handle_t, datalink_id_t, void *,
-			    int);
-static dladm_status_t 	do_get_authmode(dladm_handle_t, datalink_id_t, void *,
-			    int);
-static dladm_status_t 	do_get_linkstatus(dladm_handle_t, datalink_id_t, void *,
-			    int);
-static dladm_status_t	do_get_esslist(dladm_handle_t, datalink_id_t, void  *,
-			    int);
-static dladm_status_t 	do_get_rate(dladm_handle_t, datalink_id_t, void *, int);
-static dladm_status_t	do_get_mode(dladm_handle_t, datalink_id_t, void *, int);
-static dladm_status_t	do_get_capability(dladm_handle_t, datalink_id_t, void *,
-			    int);
-static dladm_status_t	do_get_wpamode(dladm_handle_t, datalink_id_t, void *,
-			    int);
+			    size_t);
+static dladm_status_t 	do_get_rate(dladm_handle_t, datalink_id_t, void *,
+			    size_t);
+static dladm_status_t	do_get_mode(dladm_handle_t, datalink_id_t, void *,
+			    size_t);
+static dladm_status_t	do_set_wep(dladm_handle_t, datalink_id_t);
 
-static dladm_status_t	do_set_bsstype(dladm_handle_t, datalink_id_t,
-			    dladm_wlan_bsstype_t *);
-static dladm_status_t	do_set_authmode(dladm_handle_t, datalink_id_t,
-			    dladm_wlan_auth_t *);
-static dladm_status_t	do_set_encryption(dladm_handle_t, datalink_id_t,
-			    dladm_wlan_secmode_t *);
-static dladm_status_t	do_set_essid(dladm_handle_t, datalink_id_t,
-			    dladm_wlan_essid_t *);
-static dladm_status_t	do_set_createibss(dladm_handle_t, datalink_id_t,
-			    boolean_t *);
-static dladm_status_t	do_set_key(dladm_handle_t, datalink_id_t,
-			    dladm_wlan_key_t *, uint_t);
-static dladm_status_t	do_set_channel(dladm_handle_t, datalink_id_t,
-			    dladm_wlan_channel_t *);
-
-static dladm_status_t	do_scan(dladm_handle_t, datalink_id_t, void *, int);
-static dladm_status_t	do_connect(dladm_handle_t, datalink_id_t, void *, int,
-			    dladm_wlan_attr_t *, boolean_t, void *, uint_t,
-			    int);
-static dladm_status_t	do_disconnect(dladm_handle_t, datalink_id_t, void *,
-			    int);
-static boolean_t	find_val_by_name(const char *, val_desc_t *,
+static boolean_t	find_val_by_name(const char *, const val_desc_t *,
 			    uint_t, uint_t *);
-static boolean_t	find_name_by_val(uint_t, val_desc_t *, uint_t, char **);
+static boolean_t	find_name_by_val(uint_t, const val_desc_t *, uint_t,
+			    char **);
 static void		generate_essid(dladm_wlan_essid_t *);
 
 static dladm_status_t	dladm_wlan_wlresult2status(wldp_t *);
-static dladm_status_t	dladm_wlan_validate(dladm_handle_t, datalink_id_t);
 
-static val_desc_t	linkstatus_vals[] = {
-	{ "disconnected", DLADM_WLAN_LINK_DISCONNECTED	},
-	{ "connected",    DLADM_WLAN_LINK_CONNECTED	}
+static const val_desc_t	linkstatus_vals[] = {
+	{ "disconnected", B_FALSE	},
+	{ "connected",    B_TRUE	}
 };
 
-static val_desc_t 	secmode_vals[] = {
-	{ "none",	DLADM_WLAN_SECMODE_NONE		},
-	{ "wep",	DLADM_WLAN_SECMODE_WEP		},
-	{ "wpa",	DLADM_WLAN_SECMODE_WPA		}
+static const val_desc_t 	secmode_vals[] = {
+	{ "none",	DLADM_WLAN_SECMODE_NONE	},
+	{ "wep",	DLADM_WLAN_SECMODE_WEP	},
+	{ "wpa-psk",	DLADM_WLAN_SECMODE_PSK	},
+	{ "wpa-eap",	DLADM_WLAN_SECMODE_EAP	}
 };
 
-static val_desc_t 	strength_vals[] = {
-	{ "very weak",	DLADM_WLAN_STRENGTH_VERY_WEAK	},
-	{ "weak",	DLADM_WLAN_STRENGTH_WEAK	},
-	{ "good",	DLADM_WLAN_STRENGTH_GOOD	},
-	{ "very good",	DLADM_WLAN_STRENGTH_VERY_GOOD	},
-	{ "excellent",	DLADM_WLAN_STRENGTH_EXCELLENT	}
-};
-
-static val_desc_t	mode_vals[] = {
+static const val_desc_t	mode_vals[] = {
 	{ "a",		DLADM_WLAN_MODE_80211A		},
 	{ "b",		DLADM_WLAN_MODE_80211B		},
 	{ "g",		DLADM_WLAN_MODE_80211G		},
@@ -126,19 +83,17 @@
 	{ "n",		DLADM_WLAN_MODE_80211AN		}
 };
 
-static val_desc_t	auth_vals[] = {
-	{ "open",	DLADM_WLAN_AUTH_OPEN		},
-	{ "shared",	DLADM_WLAN_AUTH_SHARED		}
+/* capital chars */
+static const val_desc_t auth_vals[] = {
+	{ "OPEN",	WPA_AUTH_ALG_OPEN		},
+	{ "SHARED",	WPA_AUTH_ALG_SHARED		}
 };
 
-static val_desc_t	bsstype_vals[] = {
-	{ "bss",	DLADM_WLAN_BSSTYPE_BSS		},
-	{ "ibss",	DLADM_WLAN_BSSTYPE_IBSS		},
-	{ "any",	DLADM_WLAN_BSSTYPE_ANY		}
+static const val_desc_t bsstype_vals[] = {
+	{ "ESS",	IEEE80211_MODE_INFRA		},
+	{ "IBSS",	IEEE80211_MODE_IBSS		}
 };
 
-#define	WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
-
 static dladm_status_t
 dladm_wlan_wlresult2status(wldp_t *gbuf)
 {
@@ -184,7 +139,7 @@
 }
 
 boolean_t
-i_dladm_wlan_convert_chan(wl_phy_conf_t *phyp, uint32_t *channelp)
+i_dladm_wlan_convert_chan(wl_phy_conf_t *phyp, uint16_t *channelp)
 {
 	wl_fhss_t *wlfp = &phyp->wl_phy_fhss_conf;
 	wl_ofdm_t *wlop = &phyp->wl_phy_ofdm_conf;
@@ -195,10 +150,10 @@
 	case WL_IRBASE:
 	case WL_HRDS:
 	case WL_ERP:
-		*channelp = wlfp->wl_fhss_channel;
+		*channelp = wlfp->wl_fhss_frequency;
 		break;
 	case WL_OFDM:
-		*channelp = DLADM_WLAN_OFDM2CHAN(wlop->wl_ofdm_frequency);
+		*channelp = wlop->wl_ofdm_frequency;
 		break;
 	default:
 		return (B_FALSE);
@@ -206,489 +161,318 @@
 	return (B_TRUE);
 }
 
-#define	IEEE80211_RATE	0x7f
 static void
 fill_wlan_attr(wl_ess_conf_t *wlp, dladm_wlan_attr_t *attrp)
 {
-	int		i;
-
-	(void) memset(attrp, 0, sizeof (*attrp));
+	int i;
+	int keymgmt = -1;
 
-	(void) snprintf(attrp->wa_essid.we_bytes, DLADM_WLAN_MAX_ESSID_LEN,
-	    "%s", wlp->wl_ess_conf_essid.wl_essid_essid);
-	attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID;
+	/*
+	 * Note: SSID is an array of octets, i.e.,
+	 * it is not NULL terminated and can, at least in theory,
+	 * contain control characters (including NULL) and as such,
+	 * should be processed as binary data, not a printable string.
+	 */
+	if (wlp->wl_ess_conf_essid.wl_essid_length != 0) {
+		attrp->wa_essid.we_length =
+		    wlp->wl_ess_conf_essid.wl_essid_length;
+		(void) memcpy(attrp->wa_essid.we_bytes,
+		    wlp->wl_ess_conf_essid.wl_essid_essid,
+		    attrp->wa_essid.we_length);
+		attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID;
+	}
 
-	(void) memcpy(attrp->wa_bssid.wb_bytes, wlp->wl_ess_conf_bssid,
-	    DLADM_WLAN_BSSID_LEN);
+	(void) memcpy(attrp->wa_bssid.wb_bytes,
+	    wlp->wl_ess_conf_bssid.wl_bssid_bssid, DLADM_WLAN_BSSID_LEN);
 	attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID;
 
-	attrp->wa_secmode = (wlp->wl_ess_conf_wepenabled ==
-	    WL_ENC_WEP ? DLADM_WLAN_SECMODE_WEP : DLADM_WLAN_SECMODE_NONE);
-	if (wlp->wl_ess_conf_reserved[0] > 0)
-		attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA;
-	attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE;
+	/*
+	 * Open/Shared is simply not present in the AP's beacon.  It is a
+	 * deficiency of WEP, which WPA fixed by only allowing open
+	 * authentication for WPA connections. There is simply no way to tell
+	 * whether an AP is using shared auth or open system auth because a WEP
+	 * AP never broadcasts that information.
+	 * [net80211 sets it to 1 (OPEN) by default for scanned nodes]
+	 *
+	 * If wpa_ie is not present and IEEE80211_CAP_PRIVACY is on => WEP
+	 * If wpa_ie is not present and IEEE80211_CAP_PRIVACY is off => NONE
+	 */
+	if (wpa_supplicant_capsie2txt(wlp->wl_ess_conf_caps,
+	    wlp->wl_ess_conf_wpa_ie.wpa_ie, wlp->wl_ess_conf_wpa_ie.wpa_ie_len,
+	    attrp->wa_ietxt, sizeof (attrp->wa_ietxt), &keymgmt) == 0)
+		attrp->wa_valid |= DLADM_WLAN_ATTR_IEDETAIL;
 
-	attrp->wa_bsstype = (wlp->wl_ess_conf_bsstype == WL_BSS_BSS ?
-	    DLADM_WLAN_BSSTYPE_BSS : DLADM_WLAN_BSSTYPE_IBSS);
-	attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
-
-	attrp->wa_auth = (wlp->wl_ess_conf_authmode == 0 ?
-	    DLADM_WLAN_AUTH_OPEN : DLADM_WLAN_AUTH_SHARED);
+	if (wlp->wl_ess_conf_wpa_ie.wpa_ie_len == 0) {
+		if (wlp->wl_ess_conf_caps & IEEE80211_CAP_PRIVACY) {
+			attrp->wa_auth = WPA_AUTH_ALG_SHARED;
+			attrp->wa_secmode = DLADM_WLAN_SECMODE_WEP;
+		} else {
+			attrp->wa_auth = WPA_AUTH_ALG_OPEN;
+			attrp->wa_secmode = DLADM_WLAN_SECMODE_NONE;
+		}
+		attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE;
+	} else if (keymgmt != -1) {
+		/*
+		 * check wpa_ie.c defines
+		 */
+		attrp->wa_auth = WPA_AUTH_ALG_OPEN;
+		if (keymgmt == WPA_KEY_MGMT_IEEE8021X) {
+			attrp->wa_secmode = DLADM_WLAN_SECMODE_EAP;
+			attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE;
+		} else if (keymgmt == WPA_KEY_MGMT_PSK) {
+			attrp->wa_secmode = DLADM_WLAN_SECMODE_PSK;
+			attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE;
+		}
+	}
 	attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
 
-	attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(wlp->wl_ess_conf_sl);
+	/* caps values are not mutually-exclusive here */
+	if (wlp->wl_ess_conf_caps & IEEE80211_CAP_IBSS)
+		attrp->wa_bsstype = IEEE80211_MODE_IBSS;
+	if (wlp->wl_ess_conf_caps & IEEE80211_CAP_ESS)
+		attrp->wa_bsstype = IEEE80211_MODE_INFRA;
+	attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
+
+	/* signal strength (0->127) */
+	attrp->wa_strength = wlp->wl_ess_conf_sl;
 	attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH;
 
-	attrp->wa_mode = do_convert_mode((wl_phy_conf_t *)&wlp->wl_phy_conf);
+	/* speed rates */
+	for (i = 0; i < wlp->wl_ess_conf_rates.wl_rates_num; i++)
+		attrp->wa_rates.wr_rates[i] =
+		    wlp->wl_ess_conf_rates.wl_rates_rates[i];
+	attrp->wa_rates.wr_cnt = wlp->wl_ess_conf_rates.wl_rates_num;
+	attrp->wa_valid |= DLADM_WLAN_ATTR_RATES;
+
+	/* 802.11 mode + frequency */
+	attrp->wa_mode = do_convert_mode(&wlp->wl_ess_conf_phys);
 	attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
 
-	for (i = 0; i < MAX_SCAN_SUPPORT_RATES; i++) {
-		wlp->wl_supported_rates[i] &= IEEE80211_RATE;
-		if (wlp->wl_supported_rates[i] > attrp->wa_speed)
-			attrp->wa_speed = wlp->wl_supported_rates[i];
-	}
-	if (attrp->wa_speed > 0)
-		attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED;
-
-	if (i_dladm_wlan_convert_chan((wl_phy_conf_t *)&wlp->wl_phy_conf,
-	    &attrp->wa_channel))
+	if (i_dladm_wlan_convert_chan(&wlp->wl_ess_conf_phys, &attrp->wa_freq))
 		attrp->wa_valid |= DLADM_WLAN_ATTR_CHANNEL;
 }
 
 dladm_status_t
-dladm_wlan_scan(dladm_handle_t handle, datalink_id_t linkid, void *arg,
-    boolean_t (*func)(void *, dladm_wlan_attr_t *))
+dladm_wlan_scan(dladm_handle_t handle, datalink_id_t linkid)
 {
-	int			i;
-	uint32_t		count;
-	wl_ess_conf_t		*wlp;
-	wl_ess_list_t		*wls = NULL;
-	char 			buf[WLDP_BUFSIZE];
-	wl_linkstatus_t		wl_status;
-	dladm_wlan_attr_t	wlattr;
-	dladm_status_t		status;
+	struct wpa_ctrl *ctrl_conn = NULL;
+	char *cmd_scan[] = {"SCAN"};
+
+	dladm_status_t	status;
+
+	if ((status = dladm_wlan_validate(handle, linkid, &ctrl_conn, NULL)) !=
+	    DLADM_STATUS_OK)
+		return (status);
 
-	if ((status = dladm_wlan_validate(handle, linkid)) != DLADM_STATUS_OK)
-		goto done;
-
-	status = do_get_linkstatus(handle, linkid, &wl_status,
-	    sizeof (wl_status));
-	if (status != DLADM_STATUS_OK)
-		goto done;
+	/*
+	 * using wpa ctrl_if to request scan we can wait for
+	 * WPA_EVENT_SCAN_RESULTS before processing scan results
+	 */
+	if (wpa_request(ctrl_conn, 1, cmd_scan)) {
+		wpa_ctrl_close(ctrl_conn);
+		return (DLADM_STATUS_FAILED);
+	}
 
-	if ((status = do_scan(handle, linkid, buf, sizeof (buf))) !=
-	    DLADM_STATUS_OK)
-		goto done;
-
-	if (func == NULL) {
-		status = DLADM_STATUS_OK;
-		goto done;
+	if (wpa_ctrl_attach(ctrl_conn)) {
+		wpa_ctrl_close(ctrl_conn);
+		return (DLADM_STATUS_IOERR);
 	}
 
-	wls = malloc(WLDP_BUFSIZE);
-	if (wls == NULL) {
-		status = DLADM_STATUS_NOMEM;
-		goto done;
-	}
+	do {
+		char *ev_id = NULL;
+		char *ev_extra = NULL;
+
+		status = DLADM_STATUS_NOTFOUND;
 
-	if ((status = do_get_esslist(handle, linkid, wls, WLDP_BUFSIZE))
-	    != DLADM_STATUS_OK)
-		goto done;
-
-	wlp = wls->wl_ess_list_ess;
-	count = wls->wl_ess_list_num;
+		if (wpa_ctrl_pending(ctrl_conn) < 0) {
+			status = DLADM_STATUS_IOERR;
+			break;
+		} else if (wpa_ctrl_pending(ctrl_conn) == 0) {
+			continue;
+		}
 
-	for (i = 0; i < count; i++, wlp++) {
-		fill_wlan_attr(wlp, &wlattr);
-		if (!func(arg, &wlattr))
-			break;
-	}
+		if (!wpa_get_event(ctrl_conn, &ev_id, &ev_extra))
+			continue;
+
+		if (strcmp(ev_id, WPA_EVENT_SCAN_RESULTS) == 0)
+			status = DLADM_STATUS_OK;
 
-	if (wl_status != WL_CONNECTED) {
-		status = do_get_linkstatus(handle, linkid, &wl_status,
-		    sizeof (&wl_status));
-		if (status != DLADM_STATUS_OK)
-			goto done;
-		if (wl_status == WL_CONNECTED)
-			(void) do_disconnect(handle, linkid, buf, sizeof (buf));
-	}
+		free(ev_id);
+		free(ev_extra);
+	} while (status != DLADM_STATUS_OK);
 
-	status = DLADM_STATUS_OK;
-done:
-	free(wls);
+	(void) wpa_ctrl_detach(ctrl_conn);
+
+	wpa_ctrl_close(ctrl_conn);
+
 	return (status);
 }
 
-/*
- * Structures used in building the list of eligible WLANs to connect to.
- * Specifically, `connect_state' has the WLAN attributes that must be matched
- * (in `cs_attr') and a growing list of WLANs that matched those attributes
- * chained through `cs_list'.  Each element in the list is of type `attr_node'
- * and has the matching WLAN's attributes and a pointer to the next element.
- * For convenience, `cs_count' tracks the number of elements in the list.
- */
-typedef struct attr_node {
-	dladm_wlan_attr_t	an_attr;
-	struct attr_node	*an_next;
-} attr_node_t;
-
-typedef struct connect_state {
-	dladm_wlan_attr_t	*cs_attr;
-	uint_t			cs_count;
-	attr_node_t		*cs_list;
-} connect_state_t;
-
-/*
- * Compare two sets of WLAN attributes.  For now, we only consider strength
- * and speed (in that order), which matches the documented default policy for
- * dladm_wlan_connect().
- */
-static int
-attr_compare(const void *p1, const void *p2)
+dladm_status_t
+dladm_wlan_parse_esslist(dladm_handle_t handle, datalink_id_t linkid, void *arg,
+    boolean_t (*func)(void *, dladm_wlan_attr_t *))
 {
-	dladm_wlan_attr_t *attrp1, *attrp2;
-
-	attrp1 = (*(dladm_wlan_attr_t **)p1);
-	attrp2 = (*(dladm_wlan_attr_t **)p2);
-
-	if (attrp1->wa_strength < attrp2->wa_strength)
-		return (1);
-
-	if (attrp1->wa_strength > attrp2->wa_strength)
-		return (-1);
-
-	return (attrp2->wa_speed - attrp1->wa_speed);
-}
+	int			i;
+	wl_ess_conf_t		*wlp;
+	wl_ess_list_t		*wls;
+	dladm_wlan_attr_t 	*wlattr;
+	dladm_status_t		status;
 
-/*
- * Callback function used by dladm_wlan_connect() to filter out unwanted
- * WLANs when scanning for available WLANs.  Always returns B_TRUE to
- * continue the scan.
- */
-static boolean_t
-connect_cb(void *arg, dladm_wlan_attr_t *attrp)
-{
-	attr_node_t		*nodep;
-	dladm_wlan_attr_t	*fattrp;
-	connect_state_t		*statep = (connect_state_t *)arg;
-
-	fattrp = statep->cs_attr;
-	if (fattrp == NULL)
-		goto append;
-
-	if ((fattrp->wa_valid & attrp->wa_valid) != fattrp->wa_valid)
-		return (B_TRUE);
-
-	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0 &&
-	    strncmp(fattrp->wa_essid.we_bytes, attrp->wa_essid.we_bytes,
-	    DLADM_WLAN_MAX_ESSID_LEN) != 0)
-		return (B_TRUE);
+	if (func == NULL)
+		return (DLADM_STATUS_BADARG);
 
-	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0 &&
-	    fattrp->wa_secmode != attrp->wa_secmode)
-		return (B_TRUE);
-
-	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0 &&
-	    fattrp->wa_mode != attrp->wa_mode)
-		return (B_TRUE);
-
-	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_STRENGTH) != 0 &&
-	    fattrp->wa_strength != attrp->wa_strength)
-		return (B_TRUE);
-
-	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_SPEED) != 0 &&
-	    fattrp->wa_speed != attrp->wa_speed)
-		return (B_TRUE);
-
-	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) {
-		attrp->wa_auth = fattrp->wa_auth;
-		attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
-	}
-
-	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 &&
-	    fattrp->wa_bsstype != attrp->wa_bsstype)
-		return (B_TRUE);
+	if ((status = dladm_wlan_validate(handle, linkid, NULL, NULL)) !=
+	    DLADM_STATUS_OK)
+		return (status);
 
-	if ((fattrp->wa_valid & DLADM_WLAN_ATTR_BSSID) != 0 &&
-	    memcmp(fattrp->wa_bssid.wb_bytes, attrp->wa_bssid.wb_bytes,
-	    DLADM_WLAN_BSSID_LEN) != 0)
-		return (B_TRUE);
-append:
-	nodep = malloc(sizeof (attr_node_t));
-	if (nodep == NULL)
-		return (B_TRUE);
-
-	(void) memcpy(&nodep->an_attr, attrp, sizeof (dladm_wlan_attr_t));
-	nodep->an_next = statep->cs_list;
-	statep->cs_list = nodep;
-	statep->cs_count++;
-
-	return (B_TRUE);
-}
-
-#define	IEEE80211_C_WPA		0x01800000
-
-static dladm_status_t
-do_connect(dladm_handle_t handle, datalink_id_t linkid, void *buf, int bufsize,
-    dladm_wlan_attr_t *attrp, boolean_t create_ibss, void *keys,
-    uint_t key_count, int timeout)
-{
-	dladm_wlan_secmode_t	secmode;
-	dladm_wlan_auth_t	authmode;
-	dladm_wlan_bsstype_t	bsstype;
-	dladm_wlan_essid_t	essid;
-	boolean_t		essid_valid = B_FALSE;
-	dladm_status_t		status;
-	dladm_wlan_channel_t	channel;
-	hrtime_t		start;
-	wl_capability_t		*caps;
-	wl_linkstatus_t		wl_status;
-
-	if ((attrp->wa_valid & DLADM_WLAN_ATTR_CHANNEL) != 0) {
-		channel = attrp->wa_channel;
-		status = do_set_channel(handle, linkid, &channel);
-		if (status != DLADM_STATUS_OK)
-			goto fail;
-	}
-
-	secmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) != 0) ?
-	    attrp->wa_secmode : DLADM_WLAN_SECMODE_NONE;
-
-	if ((status = do_set_encryption(handle, linkid, &secmode)) !=
-	    DLADM_STATUS_OK)
-		goto fail;
+	/*
+	 * WLDP_BUFSIZE can contain more than 2800 wl_ess_conf_t.
+	 * We should initially use a smaller buffer. We start with 25.
+	 */
+	wls = calloc(25, sizeof (wl_ess_conf_t));
+	if (wls == NULL)
+		return (DLADM_STATUS_NOMEM);
 
-	authmode = ((attrp->wa_valid & DLADM_WLAN_ATTR_AUTH) != 0) ?
-	    attrp->wa_auth : DLADM_WLAN_AUTH_OPEN;
-
-	if ((status = do_set_authmode(handle, linkid, &authmode)) !=
-	    DLADM_STATUS_OK)
-		goto fail;
-
-	bsstype = ((attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0) ?
-	    attrp->wa_bsstype : DLADM_WLAN_BSSTYPE_BSS;
-
-	if ((status = do_set_bsstype(handle, linkid, &bsstype)) !=
-	    DLADM_STATUS_OK)
-		goto fail;
-
-	if (secmode == DLADM_WLAN_SECMODE_WEP) {
-		if (keys == NULL || key_count == 0 ||
-		    key_count > MAX_NWEPKEYS) {
-			status = DLADM_STATUS_BADARG;
-			goto fail;
-		}
-		status = do_set_key(handle, linkid, keys, key_count);
-		if (status != DLADM_STATUS_OK)
-			goto fail;
-	} else if (secmode == DLADM_WLAN_SECMODE_WPA) {
-		if (keys == NULL || key_count == 0 ||
-		    key_count > MAX_NWEPKEYS) {
-			status = DLADM_STATUS_BADARG;
-			goto fail;
-		}
-		status = do_get_capability(handle, linkid, buf, bufsize);
-		if (status != DLADM_STATUS_OK)
-			goto fail;
-		caps = (wl_capability_t *)buf;
-		if ((caps->caps & IEEE80211_C_WPA) == 0)
-			return (DLADM_STATUS_NOTSUP);
-	}
-
-	if (create_ibss) {
-		status = do_set_channel(handle, linkid, &channel);
-		if (status != DLADM_STATUS_OK)
-			goto fail;
-
-		status = do_set_createibss(handle, linkid, &create_ibss);
-		if (status != DLADM_STATUS_OK)
-			goto fail;
-
-		if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0) {
-			generate_essid(&essid);
-			essid_valid = B_TRUE;
+	if ((status = dladm_wlan_get_esslist(handle, linkid, wls,
+	    sizeof (wl_ess_conf_t) * 25)) != DLADM_STATUS_OK) {
+		if (status == DLADM_STATUS_TOOSMALL) {
+			wls = realloc(wls, WLDP_BUFSIZE);
+			if (wls == NULL) {
+				free(wls);
+				return (DLADM_STATUS_NOMEM);
+			}
+			(void) memset(wls, 0, WLDP_BUFSIZE);
+			if ((status = dladm_wlan_get_esslist(handle, linkid,
+			    wls, WLDP_BUFSIZE)) != DLADM_STATUS_OK) {
+				free(wls);
+				return (status);
+			}
+		} else {
+			free(wls);
+			return (status);
 		}
 	}
 
-	if ((attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) != 0) {
-		essid = attrp->wa_essid;
-		essid_valid = B_TRUE;
-	}
-
-	if (!essid_valid) {
-		status = DLADM_STATUS_FAILED;
-		goto fail;
+	if (wls->wl_ess_list_num == 0) {
+		free(wls);
+		return (DLADM_STATUS_NOTFOUND);
 	}
 
-	if ((status = do_set_essid(handle, linkid, &essid)) != DLADM_STATUS_OK)
-		goto fail;
-
-	/*
-	 * Because wpa daemon needs getting essid from driver,
-	 * we need call do_set_essid() first, then call wpa_instance_create().
-	 */
-	if (secmode == DLADM_WLAN_SECMODE_WPA && keys != NULL)
-		(void) wpa_instance_create(handle, linkid, keys);
+	wlattr = malloc(sizeof (dladm_wlan_attr_t));
+	if (wlattr == NULL) {
+		free(wls);
+		return (DLADM_STATUS_NOMEM);
+	}
 
-	start = gethrtime();
-	for (;;) {
-		status = do_get_linkstatus(handle, linkid, &wl_status,
-		    sizeof (wl_status));
-		if (status != DLADM_STATUS_OK)
-			goto fail;
-
-		if (wl_status == WL_CONNECTED)
+	wlp = wls->wl_ess_list_ess;
+	for (i = 0; i < wls->wl_ess_list_num; i++, wlp++) {
+		(void) memset(wlattr, 0, sizeof (dladm_wlan_attr_t));
+		fill_wlan_attr(wlp, wlattr);
+		if (!func(arg, wlattr))
 			break;
-
-		(void) poll(NULL, 0, DLADM_WLAN_CONNECT_POLLRATE);
-		if ((timeout >= 0) && (gethrtime() - start) /
-		    NANOSEC >= timeout) {
-			status = DLADM_STATUS_TIMEDOUT;
-			goto fail;
-		}
 	}
-	status = DLADM_STATUS_OK;
-fail:
+	free(wlattr);
+	free(wls);
 	return (status);
 }
 
 dladm_status_t
 dladm_wlan_connect(dladm_handle_t handle, datalink_id_t linkid,
-    dladm_wlan_attr_t *attrp, int timeout, void *keys, uint_t key_count,
-    uint_t flags)
+    dladm_wlan_attr_t *attrp, const void *key, void *eap_attr)
 {
-	int			i;
-	char 			buf[WLDP_BUFSIZE];
-	connect_state_t		state = {0, NULL, NULL};
-	attr_node_t		*nodep = NULL;
-	boolean_t		create_ibss, set_authmode;
-	dladm_wlan_attr_t	**wl_list = NULL;
-	dladm_status_t		status;
-	wl_linkstatus_t		wl_status;
+	struct wpa_ctrl *ctrlif = NULL;
+	dladm_status_t status;
 
-	if ((status = dladm_wlan_validate(handle, linkid)) != DLADM_STATUS_OK)
+	if ((status = dladm_wlan_validate(handle, linkid, &ctrlif, NULL)) !=
+	    DLADM_STATUS_OK)
 		return (status);
 
-	if ((status = do_get_linkstatus(handle, linkid, &wl_status,
-	    sizeof (wl_status))) != DLADM_STATUS_OK)
-		goto done;
-
-	if (wl_status == WL_CONNECTED) {
-		status = DLADM_STATUS_ISCONN;
-		goto done;
-	}
-
-	set_authmode = ((attrp != NULL) &&
-	    (attrp->wa_valid & DLADM_WLAN_ATTR_MODE) != 0);
-	create_ibss = ((flags & DLADM_WLAN_CONNECT_CREATEIBSS) != 0 &&
-	    attrp != NULL &&
-	    (attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) != 0 &&
-	    attrp->wa_bsstype == DLADM_WLAN_BSSTYPE_IBSS);
-
-	if ((flags & DLADM_WLAN_CONNECT_NOSCAN) != 0 ||
-	    (create_ibss && attrp != NULL &&
-	    (attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) == 0)) {
-		status = do_connect(handle, linkid, buf, sizeof (buf), attrp,
-		    create_ibss, keys, key_count, timeout);
-		goto done;
+	status = wpa_network_config(ctrlif, attrp, key, eap_attr);
+	if (status != DLADM_STATUS_OK) {
+		wpa_ctrl_close(ctrlif);
+		return (status);
 	}
 
-	state.cs_attr = attrp;
-	state.cs_list = NULL;
-	state.cs_count = 0;
+	if (isatty(fileno(stdout))) {
+		if (wpa_ctrl_attach(ctrlif)) {
+			wpa_ctrl_close(ctrlif);
+			return (DLADM_STATUS_IOERR);
+		}
 
-	status = dladm_wlan_scan(handle, linkid, &state, connect_cb);
-	if (status != DLADM_STATUS_OK)
-		goto done;
+		do {
+			char *ev_id = NULL;
+			char *ev_extra = NULL;
 
-	if (state.cs_count == 0) {
-		if (!create_ibss) {
 			status = DLADM_STATUS_NOTFOUND;
-			goto done;
-		}
-		status = do_connect(handle, linkid, buf, sizeof (buf),
-		    attrp, create_ibss, keys, key_count, timeout);
-		goto done;
-	}
+
+			if (wpa_ctrl_pending(ctrlif) < 0) {
+				status = DLADM_STATUS_IOERR;
+				break;
+			} else if (wpa_ctrl_pending(ctrlif) == 0) {
+				continue;
+			}
+
+			if (!wpa_get_event(ctrlif, &ev_id, &ev_extra))
+				continue;
 
-	wl_list = malloc(state.cs_count * sizeof (dladm_wlan_attr_t *));
-	if (wl_list == NULL) {
-		status = DLADM_STATUS_NOMEM;
-		goto done;
+			if (strcmp(ev_id, WPA_EVENT_CONNECTED) == 0 ||
+			    strcmp(ev_id, WPA_EVENT_DISCONNECTED) == 0 ||
+			    strcmp(ev_id, WPA_EVENT_ASSOC_REJECT) == 0 ||
+			    strcmp(ev_id, WPA_EVENT_TERMINATING) == 0 ||
+			    strcmp(ev_id, WPA_EVENT_EAP_FAILURE) == 0 ||
+			    strcmp(ev_id, WPA_EVENT_EAP_TLS_CERT_ERROR) == 0)
+				status = DLADM_STATUS_OK;
+
+			if (strcmp(ev_id, WPA_EVENT_SCAN_RESULTS) != 0 &&
+			    strcmp(ev_id, WPA_EVENT_BSS_ADDED) != 0)
+				(void) printf("%s\n%s\n", ev_id, ev_extra);
+
+			free(ev_id);
+			if (ev_extra != NULL)
+				free(ev_extra);
+		} while (status != DLADM_STATUS_OK);
+
+		(void) wpa_ctrl_detach(ctrlif);
 	}
 
-	nodep = state.cs_list;
-	for (i = 0; i < state.cs_count; i++) {
-		wl_list[i] = &nodep->an_attr;
-		nodep = nodep->an_next;
-	}
-	qsort(wl_list, state.cs_count, sizeof (dladm_wlan_attr_t *),
-	    attr_compare);
-
-	for (i = 0; i < state.cs_count; i++) {
-		dladm_wlan_attr_t	*ap = wl_list[i];
-
-		status = do_connect(handle, linkid, buf, sizeof (buf),
-		    ap, create_ibss, keys, key_count, timeout);
-		if (status == DLADM_STATUS_OK)
-			break;
+	wpa_ctrl_close(ctrlif);
 
-		if (!set_authmode) {
-			ap->wa_auth = DLADM_WLAN_AUTH_SHARED;
-			ap->wa_valid |= DLADM_WLAN_ATTR_AUTH;
-			status = do_connect(handle, linkid, buf, sizeof (buf),
-			    ap, create_ibss, keys, key_count, timeout);
-			if (status == DLADM_STATUS_OK)
-				break;
-		}
-	}
-done:
-	if ((status != DLADM_STATUS_OK) && (status != DLADM_STATUS_ISCONN))
-		(void) do_disconnect(handle, linkid, buf, sizeof (buf));
-
-	while (state.cs_list != NULL) {
-		nodep = state.cs_list;
-		state.cs_list = nodep->an_next;
-		free(nodep);
-	}
-	free(wl_list);
 	return (status);
 }
 
 dladm_status_t
 dladm_wlan_disconnect(dladm_handle_t handle, datalink_id_t linkid)
 {
-	char		buf[WLDP_BUFSIZE];
 	dladm_status_t	status;
 	wl_linkstatus_t	wl_status;
+	char linkname[MAXLINKNAMELEN];
 
-	if ((status = dladm_wlan_validate(handle, linkid)) != DLADM_STATUS_OK)
+	if ((status = dladm_wlan_validate(handle, linkid, NULL, linkname)) !=
+	    DLADM_STATUS_OK)
+		return (status);
+
+	if ((status = dladm_wlan_get_linkstatus(handle, linkid, &wl_status,
+	    sizeof (wl_status))) != DLADM_STATUS_OK)
 		return (status);
 
-	if ((status = do_get_linkstatus(handle, linkid, &wl_status,
-	    sizeof (wl_status))) != DLADM_STATUS_OK)
-		goto done;
+	if (wl_status) {
+		/* associated */
+		struct wpa_ctrl *ctrl_conn = NULL;
 
-	if (wl_status != WL_CONNECTED) {
-		status = DLADM_STATUS_NOTCONN;
-		goto done;
+		if ((status = dladm_wlan_validate(handle, linkid, &ctrl_conn,
+		    NULL)) == DLADM_STATUS_OK) {
+			if ((status = wpa_instance_delete(ctrl_conn,
+			    linkname)) == DLADM_STATUS_OK)
+				return (status);
+		}
+
+		/* force disassociation in case something has failed */
+		status = dladm_wlan_cmd(linkname, WL_DISASSOCIATE);
+	} else {
+		/* not associated */
+		(void) wpa_instance_delete(NULL, linkname);
 	}
 
-	if ((status = do_disconnect(handle, linkid, buf, sizeof (buf)))
-	    != DLADM_STATUS_OK)
-		goto done;
-
-	if ((status = do_get_linkstatus(handle, linkid, &wl_status,
-	    sizeof (wl_status))) != DLADM_STATUS_OK)
-		goto done;
-
-	if (wl_status == WL_CONNECTED) {
-		status = DLADM_STATUS_FAILED;
-		goto done;
-	}
-
-	status = DLADM_STATUS_OK;
-done:
 	return (status);
 }
 
@@ -696,185 +480,168 @@
 dladm_wlan_get_linkattr(dladm_handle_t handle, datalink_id_t linkid,
     dladm_wlan_linkattr_t *attrp)
 {
-	wl_rssi_t		signal;
-	wl_bss_type_t		bsstype;
-	wl_authmode_t		authmode;
-	wl_encryption_t		encryption;
-	wl_rates_t		*ratesp = NULL;
-	dladm_wlan_attr_t	*wl_attrp;
+	wl_ess_conf_t		confd;
 	dladm_status_t		status;
-	char			buf[WLDP_BUFSIZE];
-	wl_essid_t		wls;
-	wl_phy_conf_t		wl_phy_conf;
-	wl_linkstatus_t		wl_status;
 
 	if (attrp == NULL)
 		return (DLADM_STATUS_BADARG);
 
-	if ((status = dladm_wlan_validate(handle, linkid)) != DLADM_STATUS_OK)
-		goto done;
-
-	(void) memset(attrp, 0, sizeof (*attrp));
-	wl_attrp = &attrp->la_wlan_attr;
-
-	if ((status = do_get_linkstatus(handle, linkid, &wl_status,
-	    sizeof (wl_status))) != DLADM_STATUS_OK)
-		goto done;
-
-	attrp->la_valid |= DLADM_WLAN_LINKATTR_STATUS;
-	if (wl_status != WL_CONNECTED)
-		attrp->la_status = DLADM_WLAN_LINK_DISCONNECTED;
-	else
-		attrp->la_status = DLADM_WLAN_LINK_CONNECTED;
-
-	if ((status = do_get_essid(handle, linkid, &wls, sizeof (wls)))
+	/* link status */
+	if ((status = dladm_wlan_get_linkstatus(handle, linkid,
+	    &attrp->la_connected, sizeof (attrp->la_connected)))
 	    != DLADM_STATUS_OK)
-		goto done;
-
-	(void) strlcpy(wl_attrp->wa_essid.we_bytes, wls.wl_essid_essid,
-	    DLADM_WLAN_MAX_ESSID_LEN);
-
-	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID;
-
-	if ((status = do_get_bssid(handle, linkid, buf, sizeof (buf)))
-	    != DLADM_STATUS_OK)
-		goto done;
-
-	(void) memcpy(wl_attrp->wa_bssid.wb_bytes, buf, DLADM_WLAN_BSSID_LEN);
-
-	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSID;
+		return (status);
 
-	if (attrp->la_status == DLADM_WLAN_LINK_DISCONNECTED) {
-		attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN;
-		status = DLADM_STATUS_OK;
-		goto done;
-	}
-
-	if ((status = do_get_encryption(handle, linkid, &encryption,
-	    sizeof (encryption))) != DLADM_STATUS_OK)
-		goto done;
-
-	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SECMODE;
+	if (!attrp->la_connected)
+		return (DLADM_STATUS_OK);
 
-	switch (encryption) {
-	case WL_NOENCRYPTION:
-		wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_NONE;
-		break;
-	case WL_ENC_WEP:
-		wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WEP;
-		break;
-	case WL_ENC_WPA:
-		wl_attrp->wa_secmode = DLADM_WLAN_SECMODE_WPA;
-		break;
-	default:
-		wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_SECMODE;
-		break;
-	}
-
-	if ((status = do_get_signal(handle, linkid, &signal, sizeof (signal)))
-	    != DLADM_STATUS_OK)
-		goto done;
-
-	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_STRENGTH;
-	wl_attrp->wa_strength = DLADM_WLAN_SIGNAL2STRENGTH(signal);
+	(void) memset(&confd, 0, sizeof (confd));
 
-	ratesp = malloc(WLDP_BUFSIZE);
-	if (ratesp == NULL) {
-		status = DLADM_STATUS_NOMEM;
-		goto done;
-	}
-
-	if ((status = do_get_rate(handle, linkid, ratesp, WLDP_BUFSIZE))
-	    != DLADM_STATUS_OK)
-		goto done;
-
-	if (ratesp->wl_rates_num > 0) {
-		uint_t	i, r = 0;
-
-		for (i = 0; i < ratesp->wl_rates_num; i++) {
-			if (ratesp->wl_rates_rates[i] > r)
-				r = ratesp->wl_rates_rates[i];
-		}
-		wl_attrp->wa_speed = r;
-		wl_attrp->wa_valid |= DLADM_WLAN_ATTR_SPEED;
-	}
-
-	if ((status = do_get_authmode(handle, linkid, &authmode,
-	    sizeof (authmode))) != DLADM_STATUS_OK)
-		goto done;
-
-	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_AUTH;
+	/* signal level */
+	if (do_get_signal(handle, linkid, &confd.wl_ess_conf_sl,
+	    sizeof (wl_rssi_t)))
+		return (status);
 
-	switch (authmode) {
-	case WL_OPENSYSTEM:
-		wl_attrp->wa_auth = DLADM_WLAN_AUTH_OPEN;
-		break;
-	case WL_SHAREDKEY:
-		wl_attrp->wa_auth = DLADM_WLAN_AUTH_SHARED;
-		break;
-	default:
-		wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_AUTH;
-		break;
-	}
-
-	if ((status = do_get_bsstype(handle, linkid, &bsstype,
-	    sizeof (bsstype))) != DLADM_STATUS_OK)
-		goto done;
-
-	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_BSSTYPE;
+	/* speed */
+	if (do_get_rate(handle, linkid, &confd.wl_ess_conf_rates,
+	    sizeof (wl_rates_t)))
+		return (status);
 
-	switch (bsstype) {
-	case WL_BSS_BSS:
-		wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_BSS;
-		break;
-	case WL_BSS_IBSS:
-		wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_IBSS;
-		break;
-	case WL_BSS_ANY:
-		wl_attrp->wa_bsstype = DLADM_WLAN_BSSTYPE_ANY;
-		break;
-	default:
-		wl_attrp->wa_valid &= ~DLADM_WLAN_ATTR_BSSTYPE;
-		break;
-	}
+	/* 802.11 mode + freq */
+	if ((status = do_get_mode(handle, linkid, &confd.wl_ess_conf_phys,
+	    sizeof (wl_phy_conf_t))) != DLADM_STATUS_OK)
+		return (status);
 
-	if ((status = do_get_mode(handle, linkid, &wl_phy_conf,
-	    sizeof (wl_phy_conf))) != DLADM_STATUS_OK)
-		goto done;
+	fill_wlan_attr(&confd, &attrp->la_wlan_attr);
 
-	wl_attrp->wa_mode = do_convert_mode(&wl_phy_conf);
-	wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
-	if (wl_attrp->wa_mode != DLADM_WLAN_MODE_NONE)
-		wl_attrp->wa_valid |= DLADM_WLAN_ATTR_MODE;
-
-	attrp->la_valid |= DLADM_WLAN_LINKATTR_WLAN;
-	status = DLADM_STATUS_OK;
-
-done:
-	free(ratesp);
 	return (status);
 }
 
+#define	WPA_SUPPLICANT_SVC	"svc:/network/wpa_supplicant:default"
+#define	CTRL_IFACE_GLOBAL 	"/var/run/wpa_supplicant-global"
+
 /*
  * Check to see if the link is wireless.
+ * If caller passes ctrl_conn, check wpa_s ctrl interface too.
  */
-static dladm_status_t
-dladm_wlan_validate(dladm_handle_t handle, datalink_id_t linkid)
+dladm_status_t
+dladm_wlan_validate(dladm_handle_t handle, datalink_id_t linkid,
+    struct wpa_ctrl **ctrl_conn, char *linkname)
 {
+	dladm_status_t	status = DLADM_STATUS_OK;
+
+	uint32_t	flags;
 	uint32_t	media;
-	dladm_status_t	status;
+	char 		ifname[MAXLINKNAMELEN];
+	char		ctrlif[DLADM_STRSIZE];
+
+	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
+	    &media, ifname, MAXLINKNAMELEN)) != DLADM_STATUS_OK)
+		return (status);
+
+	if (media != DL_WIFI || !(flags & DLADM_OPT_ACTIVE))
+		return (DLADM_STATUS_LINKINVAL);
+	if (linkname != NULL)
+		(void) strlcpy(linkname, ifname, MAXLINKNAMELEN);
+	if (ctrl_conn == NULL)
+		return (status);
+	if (wpa_get_ctrlname(ifname, ctrlif) == NULL)
+		return (DLADM_STATUS_FAILED);
+
+	/* Loops until wpa_s ctrl socket accepts commands */
+	for (;;) {
+		struct wpa_ctrl	*global_conn = NULL;
+		struct stat statbf;
+		char *ping[] = {"PING"};
+		char *state = NULL;
+
+		/*
+		 * ctrl_open tries to unlink its argument if it already exists.
+		 * It could be an inactive socket left by improper termination.
+		 */
+		if ((*ctrl_conn = wpa_ctrl_open(ctrlif)) == NULL &&
+		    stat(CTRL_IFACE_GLOBAL, &statbf) == 0 &&
+		    S_ISSOCK(statbf.st_mode) &&
+		    (global_conn = wpa_ctrl_open(CTRL_IFACE_GLOBAL)) != NULL) {
+
+			status = wpa_instance_create(global_conn, ifname);
+			if (status == DLADM_STATUS_OK &&
+			    (*ctrl_conn = wpa_ctrl_open(ctrlif)) != NULL) {
+				char *no_auto_connect[] =
+				    {"DISABLE_NETWORK", "all"};
+				char *no_auto_reconnect[] =
+				    {"STA_AUTOCONNECT", "0"};
+				(void) wpa_request(*ctrl_conn, 2,
+				    no_auto_connect);
+				(void) wpa_request(*ctrl_conn, 2,
+				    no_auto_reconnect);
+			}
+		}
 
-	status = dladm_datalink_id2info(handle, linkid, NULL, NULL, &media,
-	    NULL, 0);
-	if (status == DLADM_STATUS_OK) {
-		if (media != DL_WIFI)
-			status = DLADM_STATUS_LINKINVAL;
+		if (*ctrl_conn != NULL &&
+		    wpa_request(*ctrl_conn, 1, ping) == 0) {
+			wpa_ctrl_close(global_conn);
+			return (DLADM_STATUS_OK);
+		}
+
+		if ((state = smf_get_state(WPA_SUPPLICANT_SVC)) == NULL) {
+			if (isatty(fileno(stdout)))
+				(void) printf("Install 'wpa_supplicant' "
+				    "package!\n");
+			return (DLADM_STATUS_NOTFOUND);
+		}
+
+		if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 &&
+		    *ctrl_conn != NULL) {
+			(void) wpa_instance_delete(*ctrl_conn, ifname);
+			*ctrl_conn = NULL;
+			wpa_ctrl_close(global_conn);
+			(void) unlink(ctrlif);
+		} else if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 &&
+		    global_conn != NULL) {
+			char *term[] = {"TERMINATE"};
+			struct timespec ts;
+			/* safest way to kill wpa_s process. smf will restart */
+			(void) wpa_request(global_conn, 1, term);
+
+			wpa_ctrl_close(global_conn);
+			*ctrl_conn = NULL;
+			(void) unlink(ctrlif);
+
+			ts.tv_sec = 0;
+			ts.tv_nsec = 10000000;
+			(void) nanosleep(&ts, NULL);
+		} else if (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 &&
+		    global_conn == NULL) {
+			if (smf_restart_instance(WPA_SUPPLICANT_SVC) == -1)
+				return (DLADM_STATUS_FAILED);
+		} else if (strcmp(state, SCF_STATE_STRING_DISABLED) == 0) {
+			if (smf_enable_instance(WPA_SUPPLICANT_SVC,
+			    SMF_TEMPORARY) == -1)
+				return (DLADM_STATUS_FAILED);
+		} else if (strcmp(state, SCF_STATE_STRING_MAINT) == 0 ||
+		    strcmp(state, SCF_STATE_STRING_DEGRADED) == 0) {
+			if (smf_disable_instance(WPA_SUPPLICANT_SVC,
+			    SMF_TEMPORARY) == -1)
+				return (DLADM_STATUS_FAILED);
+		} else if (strcmp(state, SCF_STATE_STRING_UNINIT) == 0 ||
+		    strcmp(state, SCF_STATE_STRING_OFFLINE) == 0) {
+			/* Loop until it's ready after waiting 10msec */
+			struct timespec ts;
+			ts.tv_sec = 0;
+			ts.tv_nsec = 10000000;
+			(void) nanosleep(&ts, NULL);
+		} else {
+			free(state);
+			return (DLADM_STATUS_FAILED);
+		}
+		free(state);
 	}
-	return (status);
 }
 
 static boolean_t
-find_val_by_name(const char *str, val_desc_t *vdp, uint_t cnt, uint_t *valp)
+find_val_by_name(const char *str, const val_desc_t *vdp, uint_t cnt,
+    uint_t *valp)
 {
 	int	i;
 
@@ -888,7 +655,7 @@
 }
 
 static boolean_t
-find_name_by_val(uint_t val, val_desc_t *vdp, uint_t cnt, char **strp)
+find_name_by_val(uint_t val, const val_desc_t *vdp, uint_t cnt, char **strp)
 {
 	int	i;
 
@@ -901,22 +668,21 @@
 	return (B_FALSE);
 }
 
-const char *
-dladm_wlan_essid2str(dladm_wlan_essid_t *essid, char *buf)
-{
-	(void) snprintf(buf, DLADM_STRSIZE, "%s", essid->we_bytes);
-	return (buf);
-}
+/* data to string */
+
+#define	MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define	MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
 
 const char *
-dladm_wlan_bssid2str(dladm_wlan_bssid_t *bssid, char *buf)
+dladm_wlan_bssid2str(const uint8_t *bssid_bytes, char *bssid_str)
 {
-	return (_link_ntoa(bssid->wb_bytes, buf, DLADM_WLAN_BSSID_LEN,
-	    IFT_OTHER));
+	(void) snprintf(bssid_str, 3 * DLADM_WLAN_BSSID_LEN, MACSTR,
+	    MAC2STR(bssid_bytes));
+	return (bssid_str);
 }
 
 static const char *
-dladm_wlan_val2str(uint_t val, val_desc_t *vdp, uint_t cnt, char *buf)
+dladm_wlan_val2str(uint_t val, const val_desc_t *vdp, uint_t cnt, char *buf)
 {
 	char	*s;
 
@@ -928,71 +694,111 @@
 }
 
 const char *
-dladm_wlan_secmode2str(dladm_wlan_secmode_t *secmode, char *buf)
+dladm_wlan_secmode2str(dladm_wlan_secmode_t secmode, char *buf)
 {
-	return (dladm_wlan_val2str((uint_t)*secmode, secmode_vals,
-	    VALCNT(secmode_vals), buf));
+	return (dladm_wlan_val2str(secmode, secmode_vals, VALCNT(secmode_vals),
+	    buf));
+}
+
+const char *
+dladm_wlan_strength2str(const uint8_t strength, char *buf)
+{
+	(void) snprintf(buf, DLADM_STRSIZE, "%u/127", strength);
+	return (buf);
 }
 
 const char *
-dladm_wlan_strength2str(dladm_wlan_strength_t *strength, char *buf)
+dladm_wlan_mode2str(dladm_wlan_mode_t mode, char *buf)
 {
-	return (dladm_wlan_val2str((uint_t)*strength, strength_vals,
-	    VALCNT(strength_vals), buf));
+	return (dladm_wlan_val2str(mode, mode_vals, VALCNT(mode_vals), buf));
 }
 
+/*
+ * Logic Here:
+ *
+ * WL_RATE_1M 2
+ * WL_RATE_2M 4
+ * WL_RATE_5_5M 11
+ * WL_RATE_6M 12
+ * WL_RATE_9M 18
+ * WL_RATE_11M 22
+ * WL_RATE_12M 24
+ * WL_RATE_18M 36
+ * WL_RATE_22M 44
+ * WL_RATE_24M 48
+ * WL_RATE_33M 66
+ * WL_RATE_36M 72
+ * WL_RATE_48M 96
+ * WL_RATE_54M 108
+ *
+ */
+#define	IEEE80211_RATE	0x7f
+
 const char *
-dladm_wlan_mode2str(dladm_wlan_mode_t *mode, char *buf)
+dladm_wlan_rate2str(const uint8_t rate, char *buf)
 {
-	return (dladm_wlan_val2str((uint_t)*mode, mode_vals,
-	    VALCNT(mode_vals), buf));
-}
-
-const char *
-dladm_wlan_speed2str(dladm_wlan_speed_t *speed, char *buf)
-{
-	(void) snprintf(buf, DLADM_STRSIZE, "%.*f", *speed % 2,
-	    (float)(*speed) / 2);
+	(void) snprintf(buf, DLADM_STRSIZE, "%uMb",
+	    (rate & IEEE80211_RATE) / 2);
 	return (buf);
 }
 
 const char *
-dladm_wlan_auth2str(dladm_wlan_auth_t *auth, char *buf)
+dladm_wlan_auth2str(const uint8_t auth, char *buf)
 {
-	return (dladm_wlan_val2str((uint_t)*auth, auth_vals,
-	    VALCNT(auth_vals), buf));
+	return (dladm_wlan_val2str(auth, auth_vals, VALCNT(auth_vals), buf));
 }
 
+/*
+ * Convert MHz frequency to IEEE channel number.
+ */
 const char *
-dladm_wlan_bsstype2str(dladm_wlan_bsstype_t *bsstype, char *buf)
+dladm_wlan_freq2channel(const uint16_t freq, char *buf)
 {
-	return (dladm_wlan_val2str((uint_t)*bsstype, bsstype_vals,
-	    VALCNT(bsstype_vals), buf));
+	int channel;
+	if (freq == 2484) {
+		channel = 14;
+	} else if (freq < 2484) {
+		channel = ((int)freq - 2407) / 5;
+	} else if (freq < 5000) {
+		if (freq > 4900)
+			channel = (freq - 4000) / 5;
+		else
+			channel = 15 + ((freq - 2512) / 20);
+	} else
+		channel = (freq - 5000) / 5;
+	(void) sprintf(buf, "%d", channel);
+	if (channel > 0)
+		return (buf);
+	else
+		return (NULL);
 }
 
 const char *
-dladm_wlan_linkstatus2str(dladm_wlan_linkstatus_t *linkstatus, char *buf)
+dladm_wlan_bsstype2str(const uint8_t bsstype, char *buf)
 {
-	return (dladm_wlan_val2str((uint_t)*linkstatus, linkstatus_vals,
+	return (dladm_wlan_val2str(bsstype, bsstype_vals, VALCNT(bsstype_vals),
+	    buf));
+}
+
+const char *
+dladm_wlan_linkstatus2str(uint_t linkstatus, char *buf)
+{
+	return (dladm_wlan_val2str(linkstatus, linkstatus_vals,
 	    VALCNT(linkstatus_vals), buf));
 }
 
-dladm_status_t
-dladm_wlan_str2essid(const char *str, dladm_wlan_essid_t *essid)
-{
-	if (str[0] == '\0' || strlen(str) > DLADM_WLAN_MAX_ESSID_LEN - 1)
-		return (DLADM_STATUS_BADARG);
 
-	(void) strlcpy(essid->we_bytes, str, DLADM_WLAN_MAX_ESSID_LEN);
-	return (DLADM_STATUS_OK);
-}
+/* string to data */
 
 dladm_status_t
-dladm_wlan_str2bssid(const char *str, dladm_wlan_bssid_t *bssid)
+dladm_wlan_str2bssid(const char *str, uint8_t *bssid)
 {
-	int	len;
+	int	len = 0;
 	uchar_t	*buf;
 
+	if (str == NULL || bssid == NULL)
+		return (DLADM_STATUS_BADARG);
+
 	buf = _link_aton(str, &len);
 	if (buf == NULL)
 		return (DLADM_STATUS_BADARG);
@@ -1002,7 +808,7 @@
 		return (DLADM_STATUS_BADARG);
 	}
 
-	(void) memcpy(bssid->wb_bytes, buf, len);
+	(void) memcpy(bssid, buf, len);
 	free(buf);
 	return (DLADM_STATUS_OK);
 }
@@ -1020,18 +826,6 @@
 }
 
 dladm_status_t
-dladm_wlan_str2strength(const char *str, dladm_wlan_strength_t *strength)
-{
-	uint_t	val;
-
-	if (!find_val_by_name(str, strength_vals, VALCNT(strength_vals), &val))
-		return (DLADM_STATUS_BADARG);
-
-	*strength = (dladm_wlan_strength_t)val;
-	return (DLADM_STATUS_OK);
-}
-
-dladm_status_t
 dladm_wlan_str2mode(const char *str, dladm_wlan_mode_t *mode)
 {
 	uint_t	val;
@@ -1044,89 +838,61 @@
 }
 
 dladm_status_t
-dladm_wlan_str2speed(const char *str, dladm_wlan_speed_t *speed)
-{
-	*speed = (dladm_wlan_speed_t)(atof(str) * 2);
-	return (DLADM_STATUS_OK);
-}
-
-dladm_status_t
-dladm_wlan_str2auth(const char *str, dladm_wlan_auth_t *auth)
-{
-	uint_t	val;
-
-	if (!find_val_by_name(str, auth_vals, VALCNT(auth_vals), &val))
-		return (DLADM_STATUS_BADARG);
-
-	*auth = (dladm_wlan_auth_t)val;
-	return (DLADM_STATUS_OK);
-}
-
-dladm_status_t
-dladm_wlan_str2bsstype(const char *str, dladm_wlan_bsstype_t *bsstype)
+dladm_wlan_str2bsstype(const char *str, uint8_t *bsstype)
 {
 	uint_t	val;
 
 	if (!find_val_by_name(str, bsstype_vals, VALCNT(bsstype_vals), &val))
 		return (DLADM_STATUS_BADARG);
 
-	*bsstype = (dladm_wlan_bsstype_t)val;
-	return (DLADM_STATUS_OK);
-}
-
-dladm_status_t
-dladm_wlan_str2linkstatus(const char *str, dladm_wlan_linkstatus_t *linkstatus)
-{
-	uint_t	val;
-
-	if (!find_val_by_name(str, linkstatus_vals,
-	    VALCNT(linkstatus_vals), &val)) {
-		return (DLADM_STATUS_BADARG);
-	}
-
-	*linkstatus = (dladm_wlan_linkstatus_t)val;
+	*bsstype = val;
 	return (DLADM_STATUS_OK);
 }
 
+/* legacy ioctl for WL_SCAN and WL_DISASSOCIATE */
+
 dladm_status_t
-i_dladm_wlan_legacy_ioctl(dladm_handle_t handle, datalink_id_t linkid,
-    wldp_t *gbuf, uint_t id, size_t len, uint_t cmd, size_t cmdlen)
+dladm_wlan_cmd(const char *ifname, uint_t id)
 {
-	char			linkname[MAXPATHLEN];
 	int			fd, rc;
-	struct	strioctl	stri;
-	uint32_t		flags;
-	dladm_status_t		status;
-	uint32_t		media;
-	char			link[MAXLINKNAMELEN];
+	struct strioctl		stri;
+	dladm_status_t		status = DLADM_STATUS_OK;
+	wldp_t			*gbuf;
+	char			linkpath[MAXLINKNAMELEN*2];
 
-	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
-	    &media, link, MAXLINKNAMELEN)) != DLADM_STATUS_OK) {
-		return (status);
-	}
-
-	if (media != DL_WIFI)
+	if (ifname == NULL || id == 0 || ifname[0] == '\0')
 		return (DLADM_STATUS_BADARG);
 
-	if (!(flags & DLADM_OPT_ACTIVE))
-		return (DLADM_STATUS_TEMPONLY);
+	if ((gbuf = malloc(sizeof (wldp_t))) == NULL)
+		return (DLADM_STATUS_NOMEM);
 
+	if (memset(gbuf, 0, sizeof (wldp_t)) == NULL) {
+		free(gbuf);
+		return (DLADM_STATUS_BADVALCNT);
+	}
+	(void) memset(linkpath, 0, sizeof (linkpath));
 	/*
 	 * dlpi_open() is not used here because libdlpi depends on libdladm,
 	 * and we do not want to introduce recursive dependencies.
 	 */
-	(void) snprintf(linkname, MAXPATHLEN, "/dev/net/%s", link);
-	if ((fd = open(linkname, O_RDWR)) < 0)
+	rc = snprintf(linkpath, sizeof (linkpath), "/dev/net/%s", ifname);
+	if (rc < 1 || rc >= sizeof (linkpath)) {
+		free(gbuf);
+		return (DLADM_STATUS_FAILED);
+	}
+	if ((fd = open(linkpath, O_RDWR)) < 0) {
+		free(gbuf);
 		return (dladm_errno2status(errno));
+	}
 
-	gbuf->wldp_type = NET_802_11;
+	gbuf->wldp_type = 80211;
 	gbuf->wldp_id	= id;
-	gbuf->wldp_length = len;
+	gbuf->wldp_length = sizeof (uint32_t);
 
 	stri.ic_timout	= 0;
 	stri.ic_dp	= (char *)gbuf;
-	stri.ic_cmd	= cmd;
-	stri.ic_len	= cmdlen;
+	stri.ic_cmd	= WLAN_COMMAND;
+	stri.ic_len	= sizeof (wldp_t);
 
 	if ((rc = ioctl(fd, I_STR, &stri)) != 0) {
 		if (rc > 0) {
@@ -1143,230 +909,178 @@
 			status = dladm_errno2status(errno);
 		}
 	}
+
 	(void) close(fd);
-	return (status);
-}
-
-static dladm_status_t
-do_cmd_ioctl(dladm_handle_t handle, datalink_id_t linkid, void *buf,
-    int buflen, uint_t cmd)
-{
-	wldp_t *gbuf;
-	dladm_status_t status = DLADM_STATUS_OK;
-
-	if ((gbuf = malloc(MAX_BUF_LEN)) == NULL)
-		return (DLADM_STATUS_NOMEM);
-
-	(void) memset(gbuf, 0, MAX_BUF_LEN);
-	status = i_dladm_wlan_legacy_ioctl(handle, linkid, gbuf, cmd,
-	    WLDP_BUFSIZE, WLAN_COMMAND, sizeof (wldp_t));
-	(void) memcpy(buf, gbuf->wldp_buf, buflen);
 	free(gbuf);
 	return (status);
 }
 
-static dladm_status_t
-do_scan(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
-{
-	return (do_cmd_ioctl(handle, linkid, buf, buflen, WL_SCAN));
-}
-
-static dladm_status_t
-do_disconnect(dladm_handle_t handle, datalink_id_t linkid, void *buf,
-    int buflen)
-{
-	if (do_get_wpamode(handle, linkid, buf, buflen) == 0 &&
-	    ((wl_wpa_t *)(buf))->wpa_flag > 0)
-		(void) wpa_instance_delete(handle, linkid);
-
-	return (do_cmd_ioctl(handle, linkid, buf, buflen, WL_DISASSOCIATE));
-}
-
-static dladm_status_t
-do_get_esslist(dladm_handle_t handle, datalink_id_t linkid, void *buf,
-    int buflen)
+/* GET */
+dladm_status_t
+dladm_wlan_get_esslist(dladm_handle_t handle, datalink_id_t linkid, void *buf,
+    size_t buflen)
 {
 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_ESS_LIST,
 	    buflen, B_FALSE));
 }
 
-static dladm_status_t
-do_get_bssid(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
+dladm_status_t
+dladm_wlan_get_bssid(dladm_handle_t handle, datalink_id_t linkid,
+    uint8_t *sta_bssid)
 {
-	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_BSSID,
-	    buflen, B_FALSE));
+	wl_bssid_t ieee_bssid;
+	dladm_status_t status;
+
+	status = i_dladm_wlan_param(handle, linkid, &ieee_bssid,
+	    MAC_PROP_WL_BSSID, sizeof (ieee_bssid), B_FALSE);
+
+	if (status == DLADM_STATUS_OK)
+		(void) memcpy(sta_bssid, ieee_bssid.wl_bssid_bssid,
+		    DLADM_WLAN_BSSID_LEN);
+	return (status);
 }
 
-static dladm_status_t
-do_get_essid(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
+dladm_status_t
+dladm_wlan_get_essid(dladm_handle_t handle, datalink_id_t linkid,
+    uint8_t *sta_essid, uint8_t *sta_essid_len)
 {
-	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_ESSID,
-	    buflen, B_FALSE));
+	wl_essid_t ieee_essid;
+	dladm_status_t status;
+
+	status = i_dladm_wlan_param(handle, linkid, &ieee_essid,
+	    MAC_PROP_WL_ESSID, sizeof (ieee_essid), B_FALSE);
+
+	if (status == DLADM_STATUS_OK) {
+		(void) memset(sta_essid, 0, DLADM_WLAN_MAX_ESSID_LEN);
+		(void) memcpy(sta_essid, ieee_essid.wl_essid_essid,
+		    ieee_essid.wl_essid_length);
+		*sta_essid_len = ieee_essid.wl_essid_length;
+	}
+	return (status);
 }
 
-static dladm_status_t
-do_get_bsstype(dladm_handle_t handle, datalink_id_t linkid, void *buf,
-    int buflen)
-{
-	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_BSSTYPE,
-	    buflen, B_FALSE));
-}
-
-static dladm_status_t
-do_get_linkstatus(dladm_handle_t handle, datalink_id_t linkid, void *buf,
-    int buflen)
+dladm_status_t
+dladm_wlan_get_linkstatus(dladm_handle_t handle, datalink_id_t linkid,
+    void *buf, size_t buflen)
 {
 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_LINKSTATUS,
 	    buflen, B_FALSE));
 }
 
 static dladm_status_t
-do_get_rate(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
+do_get_rate(dladm_handle_t handle, datalink_id_t linkid, void *buf,
+    size_t buflen)
 {
 	return (i_dladm_wlan_param(handle, linkid, buf,
 	    MAC_PROP_WL_DESIRED_RATES, buflen, B_FALSE));
 }
 
 static dladm_status_t
-do_get_authmode(dladm_handle_t handle, datalink_id_t linkid, void *buf,
-    int buflen)
-{
-	return (i_dladm_wlan_param(handle, linkid, buf,
-	    MAC_PROP_WL_AUTH_MODE, buflen, B_FALSE));
-}
-
-static dladm_status_t
-do_get_encryption(dladm_handle_t handle, datalink_id_t linkid, void *buf,
-    int buflen)
-{
-	return (i_dladm_wlan_param(handle, linkid, buf,
-	    MAC_PROP_WL_ENCRYPTION, buflen, B_FALSE));
-}
-
-static dladm_status_t
 do_get_signal(dladm_handle_t handle, datalink_id_t linkid, void *buf,
-    int buflen)
+    size_t buflen)
 {
 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_RSSI,
 	    buflen, B_FALSE));
 }
 
 static dladm_status_t
-do_get_mode(dladm_handle_t handle, datalink_id_t linkid, void *buf, int buflen)
+do_get_mode(dladm_handle_t handle, datalink_id_t linkid, void *buf,
+    size_t buflen)
 {
 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_PHY_CONFIG,
 	    buflen, B_FALSE));
 }
 
-static dladm_status_t
-do_set_bsstype(dladm_handle_t handle, datalink_id_t linkid,
-    dladm_wlan_bsstype_t *bsstype)
+/* SET */
+dladm_status_t
+dladm_wlan_set_bsstype(dladm_handle_t handle, datalink_id_t linkid,
+    uint8_t bsstype)
 {
-	wl_bss_type_t	ibsstype;
+	wl_bss_type_t ibsstype = bsstype;
 
-	switch (*bsstype) {
-	case DLADM_WLAN_BSSTYPE_BSS:
-		ibsstype = WL_BSS_BSS;
-		break;
-	case DLADM_WLAN_BSSTYPE_IBSS:
-		ibsstype = WL_BSS_IBSS;
-		break;
-	default:
-		ibsstype = WL_BSS_ANY;
-		break;
-	}
 	return (i_dladm_wlan_param(handle, linkid, &ibsstype,
 	    MAC_PROP_WL_BSSTYPE, sizeof (ibsstype), B_TRUE));
 }
 
-static dladm_status_t
-do_set_authmode(dladm_handle_t handle, datalink_id_t linkid,
-    dladm_wlan_auth_t *auth)
+dladm_status_t
+dladm_wlan_set_authmode(dladm_handle_t handle, datalink_id_t linkid,
+    uint8_t authalg)
 {
-	wl_authmode_t	auth_mode;
+	wl_authmode_t auth_mode = authalg;
 
-	switch (*auth) {
-	case DLADM_WLAN_AUTH_OPEN:
-		auth_mode = WL_OPENSYSTEM;
-		break;
-	case DLADM_WLAN_AUTH_SHARED:
-		auth_mode = WL_SHAREDKEY;
-		break;
-	default:
-		return (DLADM_STATUS_NOTSUP);
-	}
 	return (i_dladm_wlan_param(handle, linkid, &auth_mode,
 	    MAC_PROP_WL_AUTH_MODE, sizeof (auth_mode), B_TRUE));
 }
 
 static dladm_status_t
-do_set_encryption(dladm_handle_t handle, datalink_id_t linkid,
-    dladm_wlan_secmode_t *secmode)
+do_set_wep(dladm_handle_t handle, datalink_id_t linkid)
 {
-	wl_encryption_t	encryption;
+	wl_encryption_t	encryption = WL_ENC_WEP;
 
-	switch (*secmode) {
-	case DLADM_WLAN_SECMODE_NONE:
-		encryption = WL_NOENCRYPTION;
-		break;
-	case DLADM_WLAN_SECMODE_WEP:
-		encryption = WL_ENC_WEP;
-		break;
-	case DLADM_WLAN_SECMODE_WPA:
-		return (0);
-	default:
-		return (DLADM_STATUS_NOTSUP);
-	}
 	return (i_dladm_wlan_param(handle, linkid, &encryption,
 	    MAC_PROP_WL_ENCRYPTION, sizeof (encryption), B_TRUE));
 }
 
+#define	DLADM_WLAN_WEPKEY64_LEN		5	/* per WEP spec */
+#define	DLADM_WLAN_WEPKEY128_LEN	13	/* per WEP spec */
+
 static dladm_status_t
-do_set_key(dladm_handle_t handle, datalink_id_t linkid, dladm_wlan_key_t *keys,
-    uint_t key_count)
+do_set_static_wep(dladm_handle_t handle, datalink_id_t linkid,
+    const uint8_t *wep_key, size_t wep_key_len, int wep_tx_keyidx)
 {
 	int			i;
-	wl_wep_key_t		*wkp;
+	dladm_status_t		status;
 	wl_wep_key_tab_t	wepkey_tab;
-	dladm_wlan_key_t	*kp;
 
-	if (key_count == 0 || key_count > MAX_NWEPKEYS || keys == NULL)
+	if ((status = do_set_wep(handle, linkid)) != DLADM_STATUS_OK)
+		return (status);
+
+	if (wep_key_len == 0 || wep_key == NULL)
 		return (DLADM_STATUS_BADARG);
 
 	(void) memset(wepkey_tab, 0, sizeof (wepkey_tab));
-	for (i = 0; i < MAX_NWEPKEYS; i++)
+	for (i = 0; i < IEEE80211_KEY_MAX; i++)
 		wepkey_tab[i].wl_wep_operation = WL_NUL;
 
-	for (i = 0; i < key_count; i++) {
-		kp = &keys[i];
-		if (kp->wk_idx == 0 || kp->wk_idx > MAX_NWEPKEYS)
-			return (DLADM_STATUS_BADARG);
-		if (kp->wk_len != DLADM_WLAN_WEPKEY64_LEN &&
-		    kp->wk_len != DLADM_WLAN_WEPKEY128_LEN)
-			return (DLADM_STATUS_BADARG);
-
-		wkp = &wepkey_tab[kp->wk_idx - 1];
-		wkp->wl_wep_operation = WL_ADD;
-		wkp->wl_wep_length = kp->wk_len;
-		(void) memcpy(wkp->wl_wep_key, kp->wk_val, kp->wk_len);
-	}
+	if (wep_tx_keyidx == 0 || wep_tx_keyidx > IEEE80211_KEY_MAX)
+		return (DLADM_STATUS_BADARG);
+	if (wep_key_len != DLADM_WLAN_WEPKEY64_LEN &&
+	    wep_key_len != DLADM_WLAN_WEPKEY128_LEN)
+		return (DLADM_STATUS_BADARG);
+	wepkey_tab[wep_tx_keyidx - 1].wl_wep_operation = WL_ADD;
+	wepkey_tab[wep_tx_keyidx - 1].wl_wep_length = wep_key_len;
+	(void) memcpy(wepkey_tab[wep_tx_keyidx - 1].wl_wep_keyval, wep_key,
+	    wep_key_len);
 
 	return (i_dladm_wlan_param(handle, linkid, &wepkey_tab,
 	    MAC_PROP_WL_KEY_TAB, sizeof (wepkey_tab), B_TRUE));
 }
 
-static dladm_status_t
-do_set_essid(dladm_handle_t handle, datalink_id_t linkid,
-    dladm_wlan_essid_t *essid)
+static void
+generate_essid(dladm_wlan_essid_t *essid)
+{
+	char ssid_temp[DLADM_WLAN_MAX_ESSID_LEN];
+
+	srandom(gethrtime());
+	(void) snprintf(ssid_temp, DLADM_WLAN_MAX_ESSID_LEN, "illumos-%s",
+	    random());
+	/* truncate final ESSID */
+	(void) memcpy(essid->we_bytes, ssid_temp, DLADM_WLAN_MAX_ESSID_LEN / 2);
+	essid->we_length = DLADM_WLAN_MAX_ESSID_LEN / 2;
+}
+
+dladm_status_t
+dladm_wlan_set_essid(dladm_handle_t handle, datalink_id_t linkid,
+    const uint8_t *essid, uint8_t essid_len)
 {
 	wl_essid_t	iessid;
 
-	(void) memset(&iessid, 0, sizeof (essid));
+	(void) memset(&iessid, 0, sizeof (iessid));
 
-	if (essid != NULL && essid->we_bytes[0] != '\0') {
-		iessid.wl_essid_length = strlen(essid->we_bytes);
-		(void) strlcpy(iessid.wl_essid_essid, essid->we_bytes,
-		    sizeof (iessid.wl_essid_essid));
+	if (essid != NULL && essid_len != 0) {
+		iessid.wl_essid_length = essid_len;
+		(void) memcpy(iessid.wl_essid_essid, essid,
+		    iessid.wl_essid_length);
 	} else {
 		return (DLADM_STATUS_BADARG);
 	}
@@ -1374,606 +1088,811 @@
 	    sizeof (iessid), B_TRUE));
 }
 
-static dladm_status_t
-do_set_channel(dladm_handle_t handle, datalink_id_t linkid,
-    dladm_wlan_channel_t *channel)
+dladm_status_t
+dladm_wlan_set_bssid(dladm_handle_t handle, datalink_id_t linkid,
+    const uint8_t *bssid)
+{
+	wl_bssid_t	ibssid;
+
+	if (bssid != NULL) {
+		(void) memcpy(ibssid.wl_bssid_bssid, bssid,
+		    DLADM_WLAN_BSSID_LEN);
+	} else {
+		return (DLADM_STATUS_BADARG);
+	}
+	return (i_dladm_wlan_param(handle, linkid, &ibssid, MAC_PROP_WL_BSSID,
+	    sizeof (ibssid), B_TRUE));
+}
+
+/*
+ * this is actually used only in wpa_s driver interface when setting IBSS
+ * mode channel. The user provides a channel number in this case and not
+ * a frequency value
+ */
+dladm_status_t
+dladm_wlan_set_channel(dladm_handle_t handle, datalink_id_t linkid,
+    uint16_t channel)
 {
 	wl_phy_conf_t phy_conf;
 
-	if (*channel > MAX_CHANNEL_NUM)
-		return (DLADM_STATUS_BADVAL);
-
 	(void) memset(&phy_conf, 0xff, sizeof (phy_conf));
-	phy_conf.wl_phy_dsss_conf.wl_dsss_channel = *channel;
+	phy_conf.wl_phy_ofdm_conf.wl_ofdm_frequency = channel;
 
 	return (i_dladm_wlan_param(handle, linkid, &phy_conf,
 	    MAC_PROP_WL_PHY_CONFIG, sizeof (phy_conf), B_TRUE));
 }
 
-static dladm_status_t
-do_set_createibss(dladm_handle_t handle, datalink_id_t linkid,
-    boolean_t *create_ibss)
+dladm_status_t
+dladm_wlan_createibss(dladm_handle_t handle, datalink_id_t linkid)
 {
-	wl_create_ibss_t cr = (wl_create_ibss_t)(*create_ibss);
+	wl_create_ibss_t cr = B_TRUE;
 
 	return (i_dladm_wlan_param(handle, linkid, &cr, MAC_PROP_WL_CREATE_IBSS,
 	    sizeof (cr), B_TRUE));
 }
 
-static void
-generate_essid(dladm_wlan_essid_t *essid)
-{
-	srandom(gethrtime());
-	(void) snprintf(essid->we_bytes, DLADM_WLAN_MAX_ESSID_LEN, "%d",
-	    random());
-}
-
-static dladm_status_t
-do_get_capability(dladm_handle_t handle, datalink_id_t linkid, void *buf,
-    int buflen)
+dladm_status_t
+dladm_wlan_get_capability(dladm_handle_t handle, datalink_id_t linkid,
+    void *buf, size_t buflen)
 {
 	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_CAPABILITY,
 	    buflen, B_FALSE));
 }
 
-static dladm_status_t
-do_get_wpamode(dladm_handle_t handle, datalink_id_t linkid, void *buf,
-    int buflen)
-{
-	return (i_dladm_wlan_param(handle, linkid, buf, MAC_PROP_WL_WPA, buflen,
-	    B_FALSE));
-}
+/* WPA support routines */
 
 dladm_status_t
-dladm_wlan_wpa_get_sr(dladm_handle_t handle, datalink_id_t linkid,
-    dladm_wlan_ess_t *sr, uint_t escnt, uint_t *estot)
+dladm_wlan_get_wpa_ie(dladm_handle_t handle, datalink_id_t linkid, void *buf,
+    size_t buflen)
 {
-	int		i, n;
-	wl_wpa_ess_t	*es;
+	wl_wpa_ie_t ie;
 	dladm_status_t	status;
 
-	es = malloc(WLDP_BUFSIZE);
-	if (es == NULL)
-		return (DLADM_STATUS_NOMEM);
-
-	status = i_dladm_wlan_param(handle, linkid, es, MAC_PROP_WL_SCANRESULTS,
-	    WLDP_BUFSIZE, B_FALSE);
+	(void) memset(&ie, 0, sizeof(wl_wpa_ie_t));
 
-	if (status == DLADM_STATUS_OK) {
-		n = (es->count > escnt) ? escnt : es->count;
-		for (i = 0; i < n; i ++) {
-			(void) memcpy(sr[i].we_bssid.wb_bytes, es->ess[i].bssid,
-			    DLADM_WLAN_BSSID_LEN);
-			sr[i].we_ssid_len = es->ess[i].ssid_len;
-			(void) memcpy(sr[i].we_ssid.we_bytes, es->ess[i].ssid,
-			    es->ess[i].ssid_len);
-			sr[i].we_wpa_ie_len = es->ess[i].wpa_ie_len;
-			(void) memcpy(sr[i].we_wpa_ie, es->ess[i].wpa_ie,
-			    es->ess[i].wpa_ie_len);
-			sr[i].we_freq = es->ess[i].freq;
-		}
-		*estot = n;
-	}
+	status = i_dladm_wlan_param(handle, linkid, &ie, MAC_PROP_WL_OPTIE,
+	    sizeof (wl_wpa_ie_t), B_FALSE);
+	if (status != DLADM_STATUS_OK)
+		return (status);
 
-	free(es);
+	if (buflen >= sizeof (wl_wpa_ie_t))
+		(void) memcpy(buf, &ie, sizeof (wl_wpa_ie_t));
+	else
+		return (DLADM_STATUS_BADARG);
+
 	return (status);
 }
 
 dladm_status_t
-dladm_wlan_wpa_set_ie(dladm_handle_t handle, datalink_id_t linkid,
-    uint8_t *wpa_ie, uint_t wpa_ie_len)
+dladm_wlan_set_wpa_ie(dladm_handle_t handle, datalink_id_t linkid,
+    const uint8_t *wpa_ie, size_t wpa_ie_len)
 {
 	wl_wpa_ie_t *ie;
-	uint_t len;
 	dladm_status_t	status;
 
-	if (wpa_ie_len > DLADM_WLAN_MAX_WPA_IE_LEN)
+	if (wpa_ie_len > IEEE80211_MAX_WPA_IE)
 		return (DLADM_STATUS_BADARG);
-	len = sizeof (wl_wpa_ie_t) + wpa_ie_len;
-	ie = malloc(len);
+	ie = malloc(sizeof (wl_wpa_ie_t));
 	if (ie == NULL)
 		return (DLADM_STATUS_NOMEM);
 
-	(void) memset(ie, 0, len);
+	(void) memset(ie, 0, sizeof (wl_wpa_ie_t));
 	ie->wpa_ie_len = wpa_ie_len;
 	(void) memcpy(ie->wpa_ie, wpa_ie, wpa_ie_len);
 
-	status = i_dladm_wlan_param(handle, linkid, ie, MAC_PROP_WL_SETOPTIE,
-	    len, B_TRUE);
+	status = i_dladm_wlan_param(handle, linkid, ie, MAC_PROP_WL_OPTIE,
+	    sizeof (wl_wpa_ie_t), B_TRUE);
 	free(ie);
 
 	return (status);
 }
 
 dladm_status_t
-dladm_wlan_wpa_set_wpa(dladm_handle_t handle, datalink_id_t linkid,
-    boolean_t flag)
+dladm_wlan_set_wpa(dladm_handle_t handle, datalink_id_t linkid)
 {
-	wl_wpa_t	wpa;
+	wl_wpa_t wpa = B_TRUE;
 
-	wpa.wpa_flag = flag;
 	return (i_dladm_wlan_param(handle, linkid, &wpa, MAC_PROP_WL_WPA,
 	    sizeof (wpa), B_TRUE));
 }
 
 dladm_status_t
-dladm_wlan_wpa_del_key(dladm_handle_t handle, datalink_id_t linkid,
-    uint_t key_idx, const dladm_wlan_bssid_t *addr)
+dladm_wlan_set_counterm(dladm_handle_t handle, datalink_id_t linkid,
+    boolean_t flag)
 {
-	wl_del_key_t	wk;
+	boolean_t counterm = flag;
+
+	return (i_dladm_wlan_param(handle, linkid, &counterm,
+	    MAC_PROP_WL_COUNTERM, sizeof (wl_counterm_t), B_TRUE));
+}
+
+/*
+ * set_key - Configure encryption key
+ * @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 (BSSID of the current AP when setting
+ *	pairwise key in station mode), ff:ff:ff:ff:ff:ff for
+ *	broadcast keys, %NULL for default keys that are used both for
+ *	broadcast and unicast; when clearing keys, %NULL is used to
+ *	indicate that both the broadcast-only and default key of the
+ *	specified key index is to be cleared
+ * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for
+ *	IGTK
+ * @set_tx: configure this key as the default Tx key (only used when
+ *	driver does not support separate unicast/individual key
+ * @seq: sequence number/packet number, seq_len octets, the next
+ *	packet number to be used for in replay protection; configured
+ *	for Rx keys (in most cases, this is only used with broadcast
+ *	keys and set to zero for unicast keys); %NULL if not set
+ * @seq_len: length of the seq, depends on the algorithm:
+ *	TKIP: 6 octets, CCMP: 6 octets, IGTK: 6 octets
+ * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
+ *	8-byte Rx Mic Key
+ * @key_len: length of the key buffer in octets (WEP: 5 or 13,
+ *	TKIP: 32, CCMP: 16, IGTK: 16)
+ *
+ * Returns: 0 on success, -1 on failure
+ *
+ * Configure the given key for the kernel driver. If the driver
+ * supports separate individual keys (4 default keys + 1 individual),
+ * addr can be used to determine whether the key is default or
+ * individual. If only 4 keys are supported, the default key with key
+ * index 0 is used as the individual key. STA must be configured to use
+ * it as the default Tx key (set_tx is set) and accept Rx for all the
+ * key indexes. In most cases, WPA uses only key indexes 1 and 2 for
+ * broadcast keys, so key index 0 is available for this kind of
+ * configuration.
+ *
+ * Please note that TKIP keys include separate TX and RX MIC keys and
+ * some drivers may expect them in different order than wpa_supplicant
+ * is using. If the TX/RX keys are swapped, all TKIP encrypted packets
+ * will 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.
+ *
+ * Check also bsd_set_key.c in driver_bsd.c in wpa_s tree
+ */
+dladm_status_t
+dladm_wlan_set_key(dladm_handle_t handle, datalink_id_t linkid,
+    uint_t alg, const uint8_t *addr, int key_idx, int set_tx,
+    const uint8_t *seq, size_t seq_len, const uint8_t *key, size_t key_len)
+{
+	wl_key_t	wks;
+	wl_del_key_t	wkd;
+
+	(void) memset(&wks, 0, sizeof (wl_key_t));
 
-	wk.idk_keyix = key_idx;
-	if (addr != NULL)
-		(void) memcpy((char *)wk.idk_macaddr, addr->wb_bytes,
-		    DLADM_WLAN_BSSID_LEN);
+	switch (alg) {
+	case WPA_ALG_NONE:
+		(void) memset(&wkd, 0, sizeof (wl_del_key_t));
+		wkd.idk_keyix = key_idx;
+		if (addr != NULL)
+			(void) memcpy(wkd.idk_macaddr, addr,
+			    DLADM_WLAN_BSSID_LEN);
+		return (i_dladm_wlan_param(handle, linkid, &wkd,
+		    MAC_PROP_WL_DELKEY, sizeof (wkd), B_TRUE));
+	case WPA_ALG_TKIP:
+		wks.ik_type = IEEE80211_CIPHER_TKIP;
+		break;
+	case WPA_ALG_CCMP:
+		wks.ik_type = IEEE80211_CIPHER_AES_CCM;
+		break;
+	case WPA_ALG_WEP:
+		return (do_set_static_wep(handle, linkid, key, key_len,
+		    key_idx));
+	case WPA_ALG_IGTK:
+	case WPA_ALG_PMK:
+	default:
+		return (DLADM_STATUS_NOTSUP);
+	}
+
+	/* keylen + keydata */
+	if (key_len > sizeof (wks.ik_keydata) || key == NULL)
+		return (DLADM_STATUS_BADARG);
+
+	wks.ik_keylen = key_len;
+	(void) memcpy(wks.ik_keydata, key, key_len);
 
-	return (i_dladm_wlan_param(handle, linkid, &wk, MAC_PROP_WL_DELKEY,
-	    sizeof (wk), B_TRUE));
+	/* rx seq */
+	if (seq != NULL) {
+		if (seq_len > sizeof (wks.ik_keyrsc))
+			return (DLADM_STATUS_BADARG);
+#ifdef _BIG_ENDIAN
+		/*
+		 * 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;
+			uint8_t *keyrsc = (uint8_t *)&wks.ik_keyrsc;
+			for (i = 0; i < seq_len; i++)
+				keyrsc[sizeof (wks.ik_keyrsc) - i - 1] = seq[i];
+		}
+#else /* _BIG_ENDIAN */
+		(void) memcpy(&wks.ik_keyrsc, seq, seq_len);
+#endif /* _BIG_ENDIAN */
+	}
+
+	/* flags */
+	wks.ik_flags = IEEE80211_KEY_RECV;
+
+	/* tx key */
+	if (set_tx)
+		wks.ik_flags |= IEEE80211_KEY_XMIT;
+
+	/* key_idx */
+	if (key_idx > sizeof (wks.ik_keyix))
+		return (DLADM_STATUS_BADARG);
+
+	wks.ik_keyix = key_idx;
+
+	if (addr == NULL) {
+		(void) memset(wks.ik_macaddr, 0xff, DLADM_WLAN_BSSID_LEN);
+	} else {
+		/*
+		 * Deduce whether group/global or unicast key by checking
+		 * the address (yech).  Note also that we can only mark global
+		 * keys default; doing this for a unicast key is an error.
+		 */
+		if ((addr[0] & addr[1] & addr[2] & addr[3] & addr[4] & addr[5])
+		    == 0xff) {
+			wks.ik_flags |= IEEE80211_KEY_GROUP;
+			wks.ik_keyix = key_idx;
+			(void) memset(wks.ik_macaddr, 0xff,
+			    DLADM_WLAN_BSSID_LEN);
+		} else {
+			(void) memcpy(wks.ik_macaddr, addr,
+			    DLADM_WLAN_BSSID_LEN);
+			if (key_idx == 0) {
+				wks.ik_keyix = IEEE80211_KEYIX_NONE;
+				wks.ik_flags |= IEEE80211_KEY_DEFAULT;
+			} else
+				wks.ik_keyix = key_idx;
+		}
+	}
+
+	return (i_dladm_wlan_param(handle, linkid, &wks, MAC_PROP_WL_KEY,
+	    sizeof (wks), B_TRUE));
 }
 
 dladm_status_t
-dladm_wlan_wpa_set_key(dladm_handle_t handle, datalink_id_t linkid,
-    dladm_wlan_cipher_t cipher, const dladm_wlan_bssid_t *addr,
-    boolean_t set_tx, uint64_t seq, uint_t key_idx, uint8_t *key,
-    uint_t key_len)
-{
-	wl_key_t	wk;
-
-	(void) memset(&wk, 0, sizeof (wl_key_t));
-	switch (cipher) {
-	case DLADM_WLAN_CIPHER_WEP:
-		wk.ik_type = IEEE80211_CIPHER_WEP;
-		break;
-	case DLADM_WLAN_CIPHER_TKIP:
-		wk.ik_type = IEEE80211_CIPHER_TKIP;
-		break;
-	case DLADM_WLAN_CIPHER_AES_OCB:
-		wk.ik_type = IEEE80211_CIPHER_AES_OCB;
-		break;
-	case DLADM_WLAN_CIPHER_AES_CCM:
-		wk.ik_type = IEEE80211_CIPHER_AES_CCM;
-		break;
-	case DLADM_WLAN_CIPHER_CKIP:
-		wk.ik_type = IEEE80211_CIPHER_CKIP;
-		break;
-	case DLADM_WLAN_CIPHER_NONE:
-		wk.ik_type = IEEE80211_CIPHER_NONE;
-		break;
-	default:
-		return (DLADM_STATUS_BADARG);
-	}
-	wk.ik_flags = IEEE80211_KEY_RECV;
-	if (set_tx) {
-		wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
-		(void) memcpy(wk.ik_macaddr, addr->wb_bytes,
-		    DLADM_WLAN_BSSID_LEN);
-	} else
-		(void) memset(wk.ik_macaddr, 0, DLADM_WLAN_BSSID_LEN);
-	wk.ik_keyix = key_idx;
-	wk.ik_keylen = key_len;
-	(void) memcpy(&wk.ik_keyrsc, &seq, 6);	/* only use 48-bit of seq */
-	(void) memcpy(wk.ik_keydata, key, key_len);
-
-	return (i_dladm_wlan_param(handle, linkid, &wk, MAC_PROP_WL_KEY,
-	    sizeof (wk), B_TRUE));
-}
-
-dladm_status_t
-dladm_wlan_wpa_set_mlme(dladm_handle_t handle, datalink_id_t linkid,
-    dladm_wlan_mlme_op_t op, dladm_wlan_reason_t reason,
-    dladm_wlan_bssid_t *bssid)
+dladm_wlan_set_mlme(dladm_handle_t handle, datalink_id_t linkid,
+    boolean_t op, int reason, const uint8_t *bssid)
 {
 	wl_mlme_t mlme;
 
+	if (bssid == NULL)
+		return (DLADM_STATUS_BADARG);
+
 	(void) memset(&mlme, 0, sizeof (wl_mlme_t));
-	switch (op) {
-	case DLADM_WLAN_MLME_ASSOC:
-		mlme.im_op = IEEE80211_MLME_ASSOC;
-		break;
-	case DLADM_WLAN_MLME_DISASSOC:
-		mlme.im_op = IEEE80211_MLME_DISASSOC;
-		break;
-	default:
-		return (DLADM_STATUS_BADARG);
-	}
+
+	mlme.im_op = op ? IEEE80211_MLME_ASSOC : IEEE80211_MLME_DISASSOC;
 	mlme.im_reason = reason;
-	if (bssid != NULL)
-		(void) memcpy(mlme.im_macaddr, bssid->wb_bytes,
-		    DLADM_WLAN_BSSID_LEN);
+	(void) memcpy(mlme.im_macaddr, bssid, DLADM_WLAN_BSSID_LEN);
 
 	return (i_dladm_wlan_param(handle, linkid, &mlme, MAC_PROP_WL_MLME,
 	    sizeof (mlme), B_TRUE));
 }
 
 /*
- * routines of create instance
+ * Opens a control interface connection to wpa_supplicant
+ * global interface ctrl_path, /var/run/wpa_supplicant-global. This path
+ * is configured in network/wpa_supplicant service manifest.
+ * network/wpa_supplicant service must be running.
  */
-static scf_propertygroup_t *
-add_property_group_to_instance(scf_handle_t *handle, scf_instance_t *instance,
-    const char *pg_name, const char *pg_type)
-{
-	scf_propertygroup_t *pg;
-
-	pg = scf_pg_create(handle);
-	if (pg == NULL)
-		return (NULL);
-
-	if (scf_instance_add_pg(instance, pg_name, pg_type, 0, pg) != 0) {
-		scf_pg_destroy(pg);
-		return (NULL);
-	}
-
-	return (pg);
-}
-
 static dladm_status_t
-add_new_property(scf_handle_t *handle, const char *prop_name,
-    scf_type_t type, const char *val, scf_transaction_t *tx)
+wpa_instance_create(struct wpa_ctrl *ctrl_global, char *ifname)
 {
-	scf_value_t *value = NULL;
-	scf_transaction_entry_t *entry = NULL;
+	int res;
+	boolean_t nwam;
 
-	entry = scf_entry_create(handle);
-	if (entry == NULL)
-		goto out;
+	char interface_add[DLADM_STRSIZE];
+	char *interface_add_cmd[1];
+	char *state;
+
+	if (ctrl_global == NULL || ifname == NULL)
+		return (DLADM_STATUS_BADARG);
+
+	interface_add_cmd[0] = interface_add;
 
-	value = scf_value_create(handle);
-	if (value == NULL)
-		goto out;
+	state = smf_get_state(NWAM_FMRI);
+	nwam = (strcmp(state, SCF_STATE_STRING_DISABLED) != 0);
+	free(state);
 
-	if (scf_transaction_property_new(tx, entry, prop_name, type) != 0)
-		goto out;
+	res = snprintf(interface_add, sizeof (interface_add),
+	    "INTERFACE_ADD %s\t%s\t%s\t%s",
+	    ifname, nwam ? ifname : "", "solaris", CTRL_IFACE_DIR);
 
-	if (scf_value_set_from_string(value, type, val) != 0)
-		goto out;
+	if (res <= 0 || res >= sizeof (interface_add))
+		return (DLADM_STATUS_FAILED);
 
-	if (scf_entry_add_value(entry, value) != 0)
-		goto out;
+	/* wpa_s now executes synchronously wpa_driver_solaris_init */
+	if (wpa_request(ctrl_global, 1, interface_add_cmd))
+		return (DLADM_STATUS_IOERR);
 
 	return (DLADM_STATUS_OK);
-
-out:
-	if (value != NULL)
-		scf_value_destroy(value);
-	if (entry != NULL)
-		scf_entry_destroy(entry);
-
-	return (DLADM_STATUS_FAILED);
 }
 
 static dladm_status_t
-add_pg_method(scf_handle_t *handle, scf_instance_t *instance,
-    const char *pg_name, const char *flags)
+wpa_instance_delete(struct wpa_ctrl *ctrl_conn, char *ifname)
 {
-	int			rv, size;
-	dladm_status_t		status = DLADM_STATUS_FAILED;
-	char			*command = NULL;
-	scf_transaction_t	*tran = NULL;
-	scf_propertygroup_t	*pg;
+	dladm_status_t status = DLADM_STATUS_OK;
+	struct stat statbuf;
 
-	pg = add_property_group_to_instance(handle, instance,
-	    pg_name, SCF_GROUP_METHOD);
-	if (pg == NULL)
-		goto out;
-
-	tran = scf_transaction_create(handle);
-	if (tran == NULL)
-		goto out;
-
-	size = strlen(SVC_METHOD) + strlen("  ") + strlen(flags) + 1;
-	command = malloc(size);
-	if (command == NULL) {
-		status = DLADM_STATUS_NOMEM;
-		goto out;
+	if (ifname == NULL || ifname[0] == '\0') {
+		if (ctrl_conn != NULL)
+			wpa_ctrl_close(ctrl_conn);
+		return (DLADM_STATUS_BADARG);
 	}
-	(void) snprintf(command, size, "%s %s", SVC_METHOD, flags);
 
-	do {
-		if (scf_transaction_start(tran, pg) != 0)
-			goto out;
-
-		if (add_new_property(handle, SCF_PROPERTY_EXEC,
-		    SCF_TYPE_ASTRING, command, tran) != DLADM_STATUS_OK) {
-			goto out;
-		}
-
-		rv = scf_transaction_commit(tran);
-		switch (rv) {
-		case 1:
-			status = DLADM_STATUS_OK;
-			goto out;
-		case 0:
-			scf_transaction_destroy_children(tran);
-			if (scf_pg_update(pg) == -1) {
-				goto out;
-			}
-			break;
-		case -1:
-		default:
-			goto out;
-		}
-	} while (rv == 0);
-
-out:
-	if (tran != NULL) {
-		scf_transaction_destroy_children(tran);
-		scf_transaction_destroy(tran);
+	if (ctrl_conn != NULL) {
+		char *disable_network[] = {"DISABLE_NETWORK", "all"};
+		char *remove_network[] = {"REMOVE_NETWORK", "0"};
+		/*
+		 * disable network causes driver to send disassoc frame
+		 * and to load default values
+		 */
+		if (wpa_request(ctrl_conn, 2, disable_network))
+			status = DLADM_STATUS_IOERR;
+		(void) wpa_request(ctrl_conn, 2, remove_network);
+		wpa_ctrl_close(ctrl_conn);
 	}
 
-	if (pg != NULL)
-		scf_pg_destroy(pg);
-
-	if (command != NULL)
-		free(command);
-
-	return (status);
-}
-
-static dladm_status_t
-do_create_instance(scf_handle_t *handle, scf_service_t *svc,
-    const char *instance_name, const char *command)
-{
-	dladm_status_t status = DLADM_STATUS_FAILED;
-	char *buf;
-	ssize_t max_fmri_len;
-	scf_instance_t *instance;
+	if (stat(CTRL_IFACE_GLOBAL, &statbuf) == 0 &&
+	    S_ISSOCK(statbuf.st_mode)) {
 
-	instance = scf_instance_create(handle);
-	if (instance == NULL)
-		goto out;
+		struct wpa_ctrl *ctrl_global = NULL;
+		char *state = smf_get_state(NWAM_FMRI);
 
-	if (scf_service_add_instance(svc, instance_name, instance) != 0) {
-		if (scf_error() == SCF_ERROR_EXISTS)
-			/* Let the caller deal with the duplicate instance */
-			status = DLADM_STATUS_EXIST;
-		goto out;
-	}
-
-	if (add_pg_method(handle, instance, "start",
-	    command) != DLADM_STATUS_OK) {
-		goto out;
-	}
-
-	/* enabling the instance */
-	max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
-	if ((buf = malloc(max_fmri_len + 1)) == NULL)
-		goto out;
+		if (state != NULL && strcmp(state,
+		    SCF_STATE_STRING_DISABLED) == 0 &&
+		    (ctrl_global = wpa_ctrl_open(CTRL_IFACE_GLOBAL)) != NULL) {
 
-	if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
-		if ((smf_disable_instance(buf, 0) != 0) ||
-		    (smf_enable_instance(buf, SMF_TEMPORARY) != 0)) {
-			goto out;
+			char *interface_remove[] = {"INTERFACE_REMOVE", NULL};
+			if (ctrl_conn != NULL) {
+				/*
+				 * This prevents disassoc event from being
+				 * received when interface is being removed
+				 */
+				struct timespec ts;
+				ts.tv_sec = 0;
+				ts.tv_nsec = 100000000;
+				(void) nanosleep(&ts, NULL);
+			}
+			/*
+			 * remove wpa_s instance interface and
+			 * deinit device driver interface
+			 */
+			interface_remove[1] = ifname;
+			if (wpa_request(ctrl_global, 2, interface_remove))
+				status = DLADM_STATUS_IOERR;
+			wpa_ctrl_close(ctrl_global);
 		}
-		status = DLADM_STATUS_OK;
-	}
-
-out:
-	if (instance != NULL)
-		scf_instance_destroy(instance);
-	return (status);
-}
-
-static dladm_status_t
-create_instance(const char *instance_name, const char *command)
-{
-	dladm_status_t status = DLADM_STATUS_FAILED;
-	scf_service_t *svc = NULL;
-	scf_handle_t *handle = NULL;
-
-	handle = scf_handle_create(SCF_VERSION);
-	if (handle == NULL)
-		goto out;
-
-	if (scf_handle_bind(handle) == -1)
-		goto out;
-
-	if ((svc = scf_service_create(handle)) == NULL)
-		goto out;
-
-	if (scf_handle_decode_fmri(handle, SERVICE_NAME, NULL, svc,
-	    NULL, NULL, NULL, SCF_DECODE_FMRI_EXACT) != 0)
-		goto out;
-
-	status = do_create_instance(handle, svc, instance_name, command);
-
-out:
-	if (svc != NULL)
-		scf_service_destroy(svc);
-
-	if (handle != NULL) {
-		(void) scf_handle_unbind(handle);
-		scf_handle_destroy(handle);
+		if (state != NULL)
+			free(state);
+		if (ctrl_global == NULL)
+			status = DLADM_STATUS_DENIED;
+	} else {
+		status = DLADM_STATUS_DENIED;
 	}
 
 	return (status);
 }
 
-/*
- * routines of delete instance
- */
-#define	DEFAULT_TIMEOUT	60000000
-#define	INIT_WAIT_USECS	50000
-
-static void
-wait_until_disabled(scf_handle_t *handle, char *fmri)
+static dladm_status_t wpa_network_config(struct wpa_ctrl *ctrl_conn,
+    dladm_wlan_attr_t *attrp, const dladm_wlan_key_t *key,
+    dladm_wlan_eap_t *eapp)
 {
-	char		*state;
-	useconds_t	max;
-	useconds_t	usecs;
-	uint64_t	*cp = NULL;
-	scf_simple_prop_t *sp = NULL;
-
-	max = DEFAULT_TIMEOUT;
+	int i = 0;
+	dladm_status_t status = DLADM_STATUS_OK;
 
-	if (((sp = scf_simple_prop_get(handle, fmri, "stop",
-	    SCF_PROPERTY_TIMEOUT)) != NULL) &&
-	    ((cp = scf_simple_prop_next_count(sp)) != NULL) && (*cp != 0))
-		max = (*cp) * 1000000;	/* convert to usecs */
-
-	if (sp != NULL)
-		scf_simple_prop_free(sp);
+	char *set_network[] = {"SET_NETWORK", "0", NULL, NULL};
+	char *common_props[] = {"mode", "auth_alg", "key_mgmt"};
+	char *common_vals[] = {"0", "OPEN", "NONE"};
 
-	for (usecs = INIT_WAIT_USECS; max > 0; max -= usecs) {
-		/* incremental wait */
-		usecs *= 2;
-		usecs = (usecs > max) ? max : usecs;
-
-		(void) usleep(usecs);
+	char *add_network[] = {"ADD_NETWORK"};
+	char *remove_network[] = {"REMOVE_NETWORK", "0"};
 
-		/* Check state after the wait */
-		if ((state = smf_get_state(fmri)) != NULL) {
-			if (strcmp(state, "disabled") == 0)
-				return;
-		}
-	}
-}
+	if (ctrl_conn == NULL)
+		return (DLADM_STATUS_BADARG);
+
+	(void) wpa_request(ctrl_conn, 2, remove_network);
 
-static dladm_status_t
-delete_instance(const char *instance_name)
-{
-	dladm_status_t	status = DLADM_STATUS_FAILED;
-	char		*buf;
-	ssize_t		max_fmri_len;
-	scf_scope_t	*scope = NULL;
-	scf_service_t	*svc = NULL;
-	scf_handle_t	*handle = NULL;
-	scf_instance_t	*instance;
+	/* add empty wifi network block */
+	if (wpa_request(ctrl_conn, 1, add_network))
+		status = DLADM_STATUS_BADVAL;
 
-	handle = scf_handle_create(SCF_VERSION);
-	if (handle == NULL)
-		goto out;
+	/* attrp can be NULL */
+	if (attrp == NULL)
+		goto enable;
 
-	if (scf_handle_bind(handle) == -1)
-		goto out;
-
-	if ((scope = scf_scope_create(handle)) == NULL)
-		goto out;
+	if ((attrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) &&
+	    attrp->wa_secmode != DLADM_WLAN_SECMODE_NONE && key == NULL)
+		status = DLADM_STATUS_BADVAL;
 
-	if ((svc = scf_service_create(handle)) == NULL)
-		goto out;
-
-	if (scf_handle_get_scope(handle, SCF_SCOPE_LOCAL, scope) == -1)
-		goto out;
-
-	if (scf_scope_get_service(scope, SERVICE_NAME, svc) < 0)
-		goto out;
+	if ((attrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) &&
+	    attrp->wa_secmode == DLADM_WLAN_SECMODE_EAP && eapp == NULL)
+		status = DLADM_STATUS_BADVAL;
 
-	instance = scf_instance_create(handle);
-	if (instance == NULL)
-		goto out;
-
-	if (scf_service_get_instance(svc, instance_name, instance) != 0) {
-		scf_error_t scf_errnum = scf_error();
-
-		if (scf_errnum == SCF_ERROR_NOT_FOUND)
-			status = DLADM_STATUS_OK;
-
-		scf_instance_destroy(instance);
-		goto out;
+	/* bssid */
+	/* we always set bssid if present */
+	if (attrp->wa_valid & DLADM_WLAN_ATTR_BSSID) {
+		char ap_bssid[DLADM_WLAN_BSSID_LEN * 3];
+		char *cmd_bssid[] = { "bssid", "0", NULL };
+		cmd_bssid[2] = ap_bssid;
+		(void) dladm_wlan_bssid2str(attrp->wa_bssid.wb_bytes, ap_bssid);
+		if (wpa_request(ctrl_conn, 3, cmd_bssid))
+			status = DLADM_STATUS_BADVAL;
 	}
 
-	max_fmri_len = scf_limit(SCF_LIMIT_MAX_FMRI_LENGTH);
-	if ((buf = malloc(max_fmri_len + 1)) == NULL) {
-		scf_instance_destroy(instance);
-		goto out;
-	}
-
-	if (scf_instance_to_fmri(instance, buf, max_fmri_len + 1) > 0) {
-		char *state;
-
-		state = smf_get_state(buf);
-		if (state && (strcmp(state, SCF_STATE_STRING_ONLINE) == 0 ||
-		    strcmp(state, SCF_STATE_STRING_DEGRADED) == 0)) {
-			if (smf_disable_instance(buf, 0) == 0) {
-				/*
-				 * Wait for some time till timeout to avoid
-				 * a race with scf_instance_delete() below.
-				 */
-				wait_until_disabled(handle, buf);
+	/* Ad-Hoc */
+	if ((attrp->wa_valid & DLADM_WLAN_ATTR_BSSTYPE) &&
+	    (attrp->wa_bsstype == IEEE80211_MODE_IBSS)) {
+		/*
+		 * TODO:
+		 * add frequency to dladm connect-wifi
+		 * when adhoc mode is supported
+		 */
+		set_network[2] = "frequency";
+		set_network[3] = "1";
+		common_vals[0] = "1";
+		if (wpa_request(ctrl_conn, 4, set_network))
+			status = DLADM_STATUS_BADVAL;
+		if ((!(attrp->wa_valid & DLADM_WLAN_ATTR_ESSID))) {
+			generate_essid(&attrp->wa_essid);
+			attrp->wa_valid |= DLADM_WLAN_ATTR_ESSID;
+		}
+		if (attrp->wa_secmode == DLADM_WLAN_SECMODE_PSK)  {
+			char *secure_ibss_props[] = {"proto", "pairwise",
+			    "group"};
+			char *secure_ibss_vals[] = {"WPA", "NONE", "TKIP"};
+			common_vals[2] = "WPA-NONE";
+			/*
+			 * wpa_supplicant.conf specify this is the only
+			 * supported configuration mode if cleartext is not used
+			 *
+			 * TODO:
+			 * when adhoc mode is supported we should check that
+			 * the net80211 or the device driver supports this
+			 * security mode
+			 */
+			for (i = 0; i < 3; i++) {
+				set_network[2] = secure_ibss_props[i];
+				set_network[3] = secure_ibss_vals[i];
+				if (wpa_request(ctrl_conn, 4, set_network))
+					status = DLADM_STATUS_BADVAL;
 			}
 		}
 	}
 
-	if (scf_instance_delete(instance) != 0) {
-		scf_instance_destroy(instance);
-		goto out;
+	/* Essid */
+	if (attrp->wa_valid & DLADM_WLAN_ATTR_ESSID) {
+		set_network[2] = "ssid";
+		/* ssid string needs to be quoted */
+		if (asprintf(&set_network[3], "\"%s\"",
+		    attrp->wa_essid.we_bytes) == -1)
+			status = DLADM_STATUS_BADVAL;
+		if (wpa_request(ctrl_conn, 4, set_network))
+			status = DLADM_STATUS_BADVAL;
+		/* required for nwam connection report */
+		set_network[2] = "id_str";
+		if (wpa_request(ctrl_conn, 4, set_network))
+			status = DLADM_STATUS_BADVAL;
+		free(set_network[3]);
+	} else {
+		/* Essid is mandatory for non-plaintext APs */
+		if (!(attrp->wa_valid & DLADM_WLAN_ATTR_SECMODE) ||
+		    attrp->wa_secmode == DLADM_WLAN_SECMODE_NONE)
+			goto enable;
 	}
 
-	scf_instance_destroy(instance);
-
-	status = DLADM_STATUS_OK;
+	switch (attrp->wa_secmode) {
+	case DLADM_WLAN_SECMODE_WEP:
+		common_vals[1] = "SHARED";
+		if (asprintf(&set_network[2], "wep_key%c", key->wk_idx) == -1)
+			status = DLADM_STATUS_BADVAL;
+		set_network[3] = (char *)key->wk_val;
+		if (wpa_request(ctrl_conn, 4, set_network))
+			status = DLADM_STATUS_BADVAL;
+		free(set_network[2]);
+		set_network[2] = "wep_tx_keyidx";
+		if (asprintf(&set_network[3], "%c", key->wk_idx) == -1)
+			status = DLADM_STATUS_BADVAL;
+		if (wpa_request(ctrl_conn, 4, set_network))
+			status = DLADM_STATUS_BADVAL;
+		free(set_network[3]);
+		break;
+	case DLADM_WLAN_SECMODE_PSK:
+		common_vals[2] = "WPA-PSK";
+		set_network[2] = "psk";
+		set_network[3] = (char *)key->wk_val;
+		if (wpa_request(ctrl_conn, 4, set_network))
+			status = DLADM_STATUS_BADVAL;
+		break;
+	case DLADM_WLAN_SECMODE_EAP:
+	/*
+	 * TODO: when we add PCKS#11 cert. reference support
+	 * move to a separate function  and fix checks for each eap_valid flags
+	 */
+		{
+		int eap_param = 2;
+		char *eap_props[] = {"eap", "identity", "ca_path", "ca_cert"};
+		char *eap_vals[] = {NULL, NULL, "\"/etc/certs/CA\"", NULL };
 
-out:
-	if (svc != NULL)
-		scf_service_destroy(svc);
+		eap_vals[1] = eapp->eap_user;
+		eap_vals[3] = eapp->eap_ca_cert;
+
+		if (eapp->eap_valid & DLADM_EAP_ATTR_CACERT)
+			eap_param += 2;
+
+		common_vals[2] = "WPA-EAP";
+
+		/* < TLS > */
+		if (key->wk_class == DLADM_SECOBJ_CLASS_TLS) {
+			int clicrt = (eapp->eap_valid & DLADM_EAP_ATTR_CLICERT)
+			    ? 4 : 3;
+			char *tls_props[] = {"engine", NULL, NULL,
+			    "client_cert"};
+			char *tls_vals[] = {"0", NULL, NULL, NULL};
 
-	if (scope != NULL)
-		scf_scope_destroy(scope);
+			tls_vals[3] = eapp->eap_cli_cert;
+			eap_vals[0] = "TLS";
+			/*
+			 * FIX ME when we can retrieve crt using engine
+			 * the "client_cert" string in tls_props must be
+			 * replaced with "cert_id"
+			 * The same is for ca_cert -> "ca_cert_id"
+			 * Both values are the key_data->wk_name string
+			 */
+			if (key->wk_engine) {
+				tls_props[1] = "engine_id";
+				tls_props[2] = "key_id";
+				tls_vals[0] = "1";
+				tls_vals[1] = "\"pkcs11\"";
+				if (asprintf(&tls_vals[2],
+				    "\"pkcs11:object=%s;passphrasedialog=exec:"
+				    "%s\"", key->wk_name, PIN_FILE) <= 0)
+					status = DLADM_STATUS_BADVAL;
+			} else {
+				tls_props[1] = "private_key";
+				tls_props[2] = "private_key_passwd";
+				tls_vals[1] = eapp->eap_priv;
+				tls_vals[2] = (char *)key->wk_val;
+			}
+			for (i = 0; i < clicrt; i++) {
+				set_network[2] = tls_props[i];
+				set_network[3] = tls_vals[i];
+				if (wpa_request(ctrl_conn, 4, set_network))
+					status = DLADM_STATUS_BADVAL;
+			}
+			if (key->wk_engine)
+				free(tls_vals[2]);
+		} else {
+			char *tunnel_props[] = {"password", "phase2",
+			    "anonymous_identity"};
+			char *tunnel_vals[3] = {NULL, NULL, NULL};
+			char inauthtyp[DLADM_STRSIZE];
+			int f = (eapp->eap_valid & DLADM_EAP_ATTR_ANON) ? 3 : 2;
+
+			tunnel_vals[0] = (char *)key->wk_val;
+			tunnel_vals[1] = inauthtyp;
+			tunnel_vals[2] = eapp->eap_anon;
+
+			(void) memset(inauthtyp, 0, sizeof (inauthtyp));
 
-	if (handle != NULL) {
-		(void) scf_handle_unbind(handle);
-		scf_handle_destroy(handle);
+			if (key->wk_class == DLADM_SECOBJ_CLASS_TTLS) {
+				if (dladm_p2ttls_2_str(key->wk_p2mask,
+				    inauthtyp, B_FALSE) < 1)
+					status = DLADM_STATUS_BADVAL;
+				eap_vals[0] = "TTLS";
+			} else if (key->wk_class == DLADM_SECOBJ_CLASS_PEAP) {
+				if (dladm_p2peap_2_str(key->wk_p2mask,
+				    inauthtyp, B_FALSE) < 1)
+					status = DLADM_STATUS_BADVAL;
+				eap_vals[0] = "PEAP";
+			}
+			for (i = 0; i < f; i++) {
+				set_network[2] = tunnel_props[i];
+				set_network[3] = tunnel_vals[i];
+				if (wpa_request(ctrl_conn, 4, set_network))
+					status = DLADM_STATUS_BADVAL;
+			}
+		}
+		for (i = 0; i < eap_param; i++) {
+			set_network[2] = eap_props[i];
+			set_network[3] = eap_vals[i];
+			if (wpa_request(ctrl_conn, 4, set_network))
+				status = DLADM_STATUS_BADVAL;
+		}
+		}
+		break;
+	case DLADM_WLAN_SECMODE_NONE:
+		break;
+	default:
+		status = DLADM_STATUS_BADVAL;
+		break;
 	}
 
+enable:
+	for (i = 0; i < 3; i++) {
+		set_network[2] = common_props[i];
+		set_network[3] = common_vals[i];
+		if (wpa_request(ctrl_conn, 4, set_network))
+			status = DLADM_STATUS_BADVAL;
+	}
+
+	/* disable other networks and enable network with id 0 */
+	if (status == DLADM_STATUS_OK) {
+		char *select_network[] = {"SELECT_NETWORK", "0"};
+		if (wpa_request(ctrl_conn, 2, select_network))
+			status = DLADM_STATUS_BADVAL;
+	} else {
+		(void) wpa_request(ctrl_conn, 2, remove_network);
+	}
+
+	/*
+	 * the wpa_s driver interface starts interacting with net80211 module
+	 * and requests a network scan
+	 */
+
 	return (status);
 }
 
-static dladm_status_t
-wpa_instance_create(dladm_handle_t handle, datalink_id_t linkid, void *key)
+boolean_t
+wpa_get_event(struct wpa_ctrl *ctrlif, char **ev_type, char **ev_info)
 {
-	dladm_status_t	status = DLADM_STATUS_FAILED;
-	char		*command = NULL;
-	char		*wk_name = ((dladm_wlan_key_t *)key)->wk_name;
-	int		size;
-	char		instance_name[MAXLINKNAMELEN];
+	char evdata[DLADM_STRSIZE];
+	size_t evlen = sizeof (evdata) - 1;
+	size_t evtype_len;
+	char *pos = evdata, *pos2;
 
-	/*
-	 * Use the link name as the instance name of the network/wpad service.
-	 */
-	status = dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL,
-	    instance_name, sizeof (instance_name));
-	if (status != DLADM_STATUS_OK)
-		goto out;
+	if (ctrlif == NULL || *ev_type != NULL || *ev_info != NULL)
+		return (B_FALSE);
+
+	(void) memset(evdata, 0, sizeof (evdata));
 
-	size = strlen(instance_name) + strlen(" -i  -k ") + strlen(wk_name) + 1;
-	command = malloc(size);
-	if (command == NULL) {
-		status = DLADM_STATUS_NOMEM;
-		goto out;
-	}
-	(void) snprintf(command, size, "-i %s -k %s", instance_name, wk_name);
+	if (wpa_ctrl_recv(ctrlif, evdata, &evlen))
+		return (B_FALSE);
+
+	if (evlen >= sizeof (evdata))
+		return (B_FALSE);
+
+	evdata[evlen] = '\0';
 
-	status = create_instance(instance_name, command);
-	if (status == DLADM_STATUS_EXIST) {
-		/*
-		 * Delete the existing instance and create a new instance
-		 * with the supplied arguments.
-		 */
-		if ((status = delete_instance(instance_name)) ==
-		    DLADM_STATUS_OK) {
-			status = create_instance(instance_name, command);
-		}
+	if (*pos == '<') {
+		/* skip priority */
+		pos++;
+		pos = memchr(pos, '>', evlen);
+		if (pos)
+			pos++;
+		else
+			return (B_FALSE);
 	}
 
-out:
-	if (command != NULL)
-		free(command);
+	if (evlen < 14 || strncmp(pos, "CTRL-EVENT-", 11) != 0)
+		return (B_FALSE);
+
+	pos2 = memchr(pos, ' ', evlen - (pos - evdata));
+	if (pos2)
+		pos2++;
+	else
+		return (B_FALSE);
+
+
+	evtype_len = pos2 - pos;
+
+	*ev_type = strndup(pos, evtype_len);
+	if (*ev_type == NULL)
+		return (B_FALSE);
+
+	if (*pos2 != '\0')
+		*ev_info = strndup(pos2, evlen - evtype_len - (pos - evdata));
+
+	return (B_TRUE);
+}
 
-	return (status);
+char *
+wpa_get_ctrlname(const char *ifname, char *ctrl_path)
+{
+	int flen, namelen, res;
+
+	if (ctrl_path == NULL || ifname == NULL)
+		return (NULL);
+
+	namelen = strnlen(ifname, MAXLINELEN);
+	if (namelen <= 0 || namelen >= MAXLINELEN)
+		return (NULL);
+
+	flen = strlen(CTRL_IFACE_DIR) + namelen + 2;
+
+	res = snprintf(ctrl_path, flen, "%s/%s", CTRL_IFACE_DIR, ifname);
+	if (res <= 0 || res >= flen)
+		return (NULL);
+
+	return (ctrl_path);
+}
+
+/*
+ * msg_cb can be used to register a callback function that will be called for
+ * unsolicited messages received while waiting for the command response.
+ */
+static void
+wpa_msg_cb(char *msg, size_t len)
+{
+	if (isatty(fileno(stdout)) && len != 0)
+		(void) printf("%s", msg);
 }
 
-static dladm_status_t
-wpa_instance_delete(dladm_handle_t handle, datalink_id_t linkid)
+static int
+wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, size_t cmdlen)
 {
-	char	instance_name[MAXLINKNAMELEN];
+	char *replybuf;
+	size_t len;
+	int ret;
+	boolean_t verbose;
+
+	/* with these two commands we need to print reply msg to stdout */
+	verbose = (strncmp(cmd, "STATUS VERBOSE", cmdlen) == 0 ||
+	    strncmp(cmd, "MIB", cmdlen) == 0);
+
+	len = verbose ? 2047 : 31;
+
+	replybuf = calloc(1, len + 1);
+	if (replybuf == NULL)
+		return (-1);
+
+	ret = wpa_ctrl_request(ctrl, cmd, cmdlen, replybuf, &len, wpa_msg_cb);
+
+	/* remove verbose condition to enable debugging */
+	if (verbose && isatty(fileno(stdout)) && len != 0)
+		(void) printf("%s", replybuf);
+
+	free(replybuf);
+
+	return (ret);
+}
 
-	/*
-	 * Get the instance name of the network/wpad service (the same as
-	 * the link name).
-	 */
-	if (dladm_datalink_id2info(handle, linkid, NULL, NULL, NULL,
-	    instance_name, sizeof (instance_name)) != DLADM_STATUS_OK)
-		return (DLADM_STATUS_FAILED);
+int
+wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char *cmdbuf;
+	size_t cmdlen = 0;
+	size_t bufsize = 0;
+	int ret = 0;
+	int i;
+
+	if (ctrl == NULL || argc < 1 || argc > 4 || argv == NULL)
+		return (-1);
 
-	return (delete_instance(instance_name));
+	for (i = 0; i < argc; i++) {
+		size_t len;
+		if (argv[i] == NULL)
+			return (-1);
+		len = strnlen(argv[i], DLADM_STRSIZE);
+		if (len > 0 && len < DLADM_STRSIZE)
+			bufsize += len;
+		else
+			return (-1);
+	}
+
+	bufsize += 8;
+	cmdbuf = calloc(1, bufsize);
+	if (cmdbuf == NULL)
+		return (-1);
+
+	for (i = 0; i < argc; i++) {
+		cmdlen = strlcat(cmdbuf, argv[i], bufsize);
+		if (cmdlen == 0 && cmdlen >= bufsize) {
+			free(cmdbuf);
+			return (-1);
+		}
+		if (i < (argc - 1))
+			cmdbuf[cmdlen] = ' ';
+	}
+
+	ret = wpa_ctrl_command(ctrl, cmdbuf, cmdlen);
+	free(cmdbuf);
+	return (ret);
 }
--- a/usr/src/lib/libdladm/common/libdlwlan.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libdladm/common/libdlwlan.h	Wed May 29 08:31:24 2013 +0200
@@ -18,9 +18,11 @@
  *
  * CDDL HEADER END
  */
+
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #ifndef _LIBDLWLAN_H
@@ -31,81 +33,52 @@
  * administration.
  */
 
-#include <sys/types.h>
 #include <libdladm.h>
+#include <wpa_ctrl.h>
 
 /*
  * General libdlwlan definitions and functions.
  *
  * These interfaces are ON consolidation-private.
  * For documentation, refer to PSARC/2006/623.
+ *
  */
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
-#define	DLADM_WLAN_MAX_ESSID_LEN    (32 + 1)	/* per 802.11 spec */
-						/* max essid length is 32 */
-						/* one more for '\0' */
+#define	DLADM_WLAN_MAX_ESSID_LEN    	32	/* per 802.11 spec */
 #define	DLADM_WLAN_BSSID_LEN		6	/* per 802.11 spec */
-#define	DLADM_WLAN_WPA_KEY_LEN		32	/* per 802.11i spec */
-#define	DLADM_WLAN_MAX_WPA_IE_LEN	40	/* per 802.11i spec */
-
-#define	DLADM_WLAN_CONNECT_TIMEOUT_DEFAULT	10
-#define	DLADM_WLAN_CONNECT_CREATEIBSS		0x00000001
-#define	DLADM_WLAN_CONNECT_NOSCAN		0x00000002
-
-typedef struct dladm_wlan_essid {
-	char	we_bytes[DLADM_WLAN_MAX_ESSID_LEN];
-} dladm_wlan_essid_t;
-
-typedef struct dladm_wlan_bssid {
-	uint8_t	wb_bytes[DLADM_WLAN_BSSID_LEN];
-} dladm_wlan_bssid_t;
+#define	DLADM_WLAN_MAX_RATES_NUM	15	/* IEEE80211_RATE_MAXSIZE */
 
-typedef struct dladm_wlan_ess {
-	dladm_wlan_bssid_t	we_bssid;
-	dladm_wlan_essid_t	we_ssid;
-	uint_t			we_ssid_len;
-	uint8_t			we_wpa_ie[DLADM_WLAN_MAX_WPA_IE_LEN];
-	uint_t			we_wpa_ie_len;
-	int			we_freq;
-} dladm_wlan_ess_t;
+/*
+ * wa_valid is a bitfield used for indicating the validity of each attribute in
+ * the dladm_wlan_attr data struct
+ * wa_valid may have 0 or more of the following bits set:
+ */
+enum {
+	DLADM_WLAN_ATTR_ESSID = 0x00000001,
+	DLADM_WLAN_ATTR_BSSID = 0x00000002,
+	DLADM_WLAN_ATTR_SECMODE = 0x00000004,
+	DLADM_WLAN_ATTR_STRENGTH = 0x00000008,
+	DLADM_WLAN_ATTR_MODE = 0x00000010,
+	DLADM_WLAN_ATTR_RATES = 0x00000020,
+	DLADM_WLAN_ATTR_AUTH = 0x00000040,
+	DLADM_WLAN_ATTR_BSSTYPE = 0x00000080,
+	DLADM_WLAN_ATTR_CHANNEL = 0x00000100,
+	DLADM_WLAN_ATTR_IEDETAIL = 0x00000200
+};
 
+/* the type of key management used */
 typedef enum {
-	DLADM_WLAN_CIPHER_WEP		= 0,
-	DLADM_WLAN_CIPHER_TKIP,
-	DLADM_WLAN_CIPHER_AES_OCB,
-	DLADM_WLAN_CIPHER_AES_CCM,
-	DLADM_WLAN_CIPHER_CKIP,
-	DLADM_WLAN_CIPHER_NONE
-} dladm_wlan_cipher_t;
-
-typedef enum {
-	DLADM_WLAN_MLME_ASSOC		= 1,	/* associate station */
-	DLADM_WLAN_MLME_DISASSOC	= 2	/* disassociate station */
-} dladm_wlan_mlme_op_t;
-
-typedef enum {
-	DLADM_WLAN_REASON_UNSPECIFIED	= 1,
-	DLADM_WLAN_REASON_DISASSOC_LEAVING	= 5
-} dladm_wlan_reason_t;
-
-typedef enum {
-	DLADM_WLAN_SECMODE_NONE = 1,
+	DLADM_WLAN_SECMODE_NONE = 0,
 	DLADM_WLAN_SECMODE_WEP,
-	DLADM_WLAN_SECMODE_WPA
+	DLADM_WLAN_SECMODE_PSK,
+	DLADM_WLAN_SECMODE_EAP
 } dladm_wlan_secmode_t;
 
-typedef enum {
-	DLADM_WLAN_STRENGTH_VERY_WEAK = 1,
-	DLADM_WLAN_STRENGTH_WEAK,
-	DLADM_WLAN_STRENGTH_GOOD,
-	DLADM_WLAN_STRENGTH_VERY_GOOD,
-	DLADM_WLAN_STRENGTH_EXCELLENT
-} dladm_wlan_strength_t;
-
+/* 80211 mode, this is actually an informative field only */
 typedef enum {
 	DLADM_WLAN_MODE_NONE = 0,
 	DLADM_WLAN_MODE_80211A,
@@ -115,125 +88,126 @@
 	DLADM_WLAN_MODE_80211AN
 } dladm_wlan_mode_t;
 
-typedef enum {
-	DLADM_WLAN_AUTH_OPEN = 1,
-	DLADM_WLAN_AUTH_SHARED
-} dladm_wlan_auth_t;
+typedef struct dladm_wlan_essid {
+	uint8_t we_bytes[DLADM_WLAN_MAX_ESSID_LEN];
+	uint8_t we_length;
+} dladm_wlan_essid_t;
 
-typedef enum {
-	DLADM_WLAN_BSSTYPE_BSS = 1,
-	DLADM_WLAN_BSSTYPE_IBSS,
-	DLADM_WLAN_BSSTYPE_ANY
-} dladm_wlan_bsstype_t;
-
-typedef enum {
-	DLADM_WLAN_LINK_DISCONNECTED = 1,
-	DLADM_WLAN_LINK_CONNECTED
-} dladm_wlan_linkstatus_t;
-
-typedef uint32_t dladm_wlan_speed_t;
-typedef	uint32_t dladm_wlan_channel_t;
+typedef struct dladm_wlan_bssid {
+	uint8_t wb_bytes[DLADM_WLAN_BSSID_LEN];
+} dladm_wlan_bssid_t;
 
-enum {
-	DLADM_WLAN_ATTR_ESSID	= 0x00000001,
-	DLADM_WLAN_ATTR_BSSID	= 0x00000002,
-	DLADM_WLAN_ATTR_SECMODE	= 0x00000004,
-	DLADM_WLAN_ATTR_STRENGTH = 0x00000008,
-	DLADM_WLAN_ATTR_MODE	= 0x00000010,
-	DLADM_WLAN_ATTR_SPEED	= 0x00000020,
-	DLADM_WLAN_ATTR_AUTH	= 0x00000040,
-	DLADM_WLAN_ATTR_BSSTYPE	= 0x00000080,
-	DLADM_WLAN_ATTR_CHANNEL	= 0x00000100
-};
+/* link speed rates: wr_rates[0] should be the highest rate */
+typedef struct dladm_wlan_rates {
+	uint8_t	wr_rates[DLADM_WLAN_MAX_RATES_NUM]; /* 0->127 */
+	uint8_t	wr_cnt;
+} dladm_wlan_rates_t;
+
+
 typedef struct dladm_wlan_attr {
-	uint_t			wa_valid;
-	dladm_wlan_essid_t	wa_essid;
-	dladm_wlan_bssid_t	wa_bssid;
-	dladm_wlan_secmode_t	wa_secmode;
-	dladm_wlan_strength_t	wa_strength;
-	dladm_wlan_mode_t	wa_mode;
-	dladm_wlan_speed_t	wa_speed;
-	dladm_wlan_auth_t	wa_auth;
-	dladm_wlan_bsstype_t	wa_bsstype;
-	dladm_wlan_channel_t	wa_channel;
+	uint_t wa_valid;
+	dladm_wlan_essid_t wa_essid;
+	dladm_wlan_bssid_t wa_bssid;
+	uint8_t wa_auth; /* shared/open */
+	dladm_wlan_secmode_t wa_secmode;
+	dladm_wlan_mode_t wa_mode;
+	dladm_wlan_rates_t wa_rates;
+	uint16_t wa_freq; /* 80211 channel (value is in Mhz) */
+	uint8_t wa_strength; /* signal strength 0->127 */
+	uint8_t wa_bsstype; /* ibss/bss */
+	char wa_ietxt[48]; /* string with detailed information on wpaie props */
 } dladm_wlan_attr_t;
 
-enum {
-	DLADM_WLAN_LINKATTR_STATUS	= 0x00000001,
-	DLADM_WLAN_LINKATTR_WLAN	= 0x00000002
-};
 typedef struct dladm_wlan_linkattr {
-	uint_t			la_valid;
-	dladm_wlan_linkstatus_t	la_status;
-	dladm_wlan_attr_t	la_wlan_attr;
+	boolean_t la_connected;
+	dladm_wlan_attr_t la_wlan_attr;
 } dladm_wlan_linkattr_t;
 
-#define	DLADM_WLAN_WEPKEY64_LEN		5 	/* per WEP spec */
-#define	DLADM_WLAN_WEPKEY128_LEN	13 	/* per WEP spec */
-#define	DLADM_WLAN_MAX_KEY_LEN		64	/* per WEP/WPA spec */
-#define	DLADM_WLAN_MAX_WEPKEYS		4 	/* MAX_NWEPKEYS */
-#define	DLADM_WLAN_MAX_KEYNAME_LEN	64
-typedef struct dladm_wlan_key {
-	uint_t		wk_idx;
-	uint_t		wk_len;
-	uint8_t		wk_val[DLADM_WLAN_MAX_KEY_LEN];
-	char		wk_name[DLADM_WLAN_MAX_KEYNAME_LEN];
-	uint_t		wk_class;
-} dladm_wlan_key_t;
+/* check wpa_s status and retrieves a valid handler for its ctrl interface */
+extern dladm_status_t dladm_wlan_validate(dladm_handle_t, datalink_id_t,
+			    struct wpa_ctrl **, char *);
+/* start a network scan */
+extern dladm_status_t dladm_wlan_scan(dladm_handle_t, datalink_id_t);
+/* retrieve and parse scan results */
+extern dladm_status_t dladm_wlan_parse_esslist(dladm_handle_t, datalink_id_t,
+    void *, boolean_t (*)(void *, dladm_wlan_attr_t *));
+/* connection management */
+extern dladm_status_t dladm_wlan_connect(dladm_handle_t, datalink_id_t,
+    dladm_wlan_attr_t *, const void *, void *);
+extern dladm_status_t dladm_wlan_disconnect(dladm_handle_t, datalink_id_t);
+extern dladm_status_t dladm_wlan_cmd(const char *, uint_t);
+
+/* GET */
+extern dladm_status_t dladm_wlan_get_linkattr(dladm_handle_t, datalink_id_t,
+    dladm_wlan_linkattr_t *);
+extern dladm_status_t dladm_wlan_get_essid(dladm_handle_t, datalink_id_t,
+    uint8_t *, uint8_t *);
+extern dladm_status_t dladm_wlan_get_bssid(dladm_handle_t, datalink_id_t,
+    uint8_t *);
+extern dladm_status_t dladm_wlan_get_esslist(dladm_handle_t, datalink_id_t,
+    void *, size_t);
+extern dladm_status_t dladm_wlan_get_capability(dladm_handle_t, datalink_id_t,
+    void *, size_t);
+extern dladm_status_t dladm_wlan_get_linkstatus(dladm_handle_t, datalink_id_t,
+    void *, size_t);
+extern dladm_status_t dladm_wlan_get_wpa_ie(dladm_handle_t, datalink_id_t,
+    void *, size_t);
 
-extern dladm_status_t	dladm_wlan_scan(dladm_handle_t, datalink_id_t, void *,
-			    boolean_t (*)(void *, dladm_wlan_attr_t *));
-extern dladm_status_t	dladm_wlan_connect(dladm_handle_t, datalink_id_t,
-			    dladm_wlan_attr_t *, int, void *, uint_t, uint_t);
-extern dladm_status_t	dladm_wlan_disconnect(dladm_handle_t, datalink_id_t);
-extern dladm_status_t	dladm_wlan_get_linkattr(dladm_handle_t, datalink_id_t,
-			    dladm_wlan_linkattr_t *);
-/* WPA support routines */
-extern dladm_status_t	dladm_wlan_wpa_get_sr(dladm_handle_t, datalink_id_t,
-			    dladm_wlan_ess_t *, uint_t, uint_t *);
-extern dladm_status_t	dladm_wlan_wpa_set_ie(dladm_handle_t, datalink_id_t,
-			    uint8_t *, uint_t);
-extern dladm_status_t	dladm_wlan_wpa_set_wpa(dladm_handle_t, datalink_id_t,
-			    boolean_t);
-extern dladm_status_t	dladm_wlan_wpa_del_key(dladm_handle_t, datalink_id_t,
-			    uint_t, const dladm_wlan_bssid_t *);
-extern dladm_status_t	dladm_wlan_wpa_set_key(dladm_handle_t, datalink_id_t,
-			    dladm_wlan_cipher_t, const dladm_wlan_bssid_t *,
-			    boolean_t, uint64_t, uint_t, uint8_t *, uint_t);
-extern dladm_status_t	dladm_wlan_wpa_set_mlme(dladm_handle_t, datalink_id_t,
-			    dladm_wlan_mlme_op_t,
-			    dladm_wlan_reason_t, dladm_wlan_bssid_t *);
+/* SET - the main consumer is wpa_s driver interface */
+extern dladm_status_t dladm_wlan_set_bsstype(dladm_handle_t, datalink_id_t,
+    uint8_t);
+extern dladm_status_t dladm_wlan_set_authmode(dladm_handle_t, datalink_id_t,
+    uint8_t);
+extern dladm_status_t dladm_wlan_set_essid(dladm_handle_t, datalink_id_t,
+    const uint8_t *, uint8_t);
+extern dladm_status_t dladm_wlan_set_bssid(dladm_handle_t, datalink_id_t,
+    const uint8_t *);
+extern dladm_status_t dladm_wlan_set_counterm(dladm_handle_t, datalink_id_t,
+    boolean_t);
+extern dladm_status_t dladm_wlan_createibss(dladm_handle_t, datalink_id_t);
+/*
+ * this is actually used only in wpa_s driver interface when setting IBSS
+ * mode channel. The user provides a channel number in this case and not
+ * a frequency value
+ */
+extern dladm_status_t dladm_wlan_set_channel(dladm_handle_t, datalink_id_t,
+    uint16_t);
+extern dladm_status_t dladm_wlan_set_wpa_ie(dladm_handle_t, datalink_id_t,
+    const uint8_t *, size_t);
+extern dladm_status_t dladm_wlan_set_wpa(dladm_handle_t, datalink_id_t);
+/* same signature of the set_key function in wpa_s driver interface */
+extern dladm_status_t dladm_wlan_set_key(dladm_handle_t handle,
+    datalink_id_t linkid,
+    uint_t alg, const uint8_t *addr, int key_idx, int set_tx,
+    const uint8_t *seq, size_t seq_len,
+    const uint8_t *key, size_t key_len);
+extern dladm_status_t dladm_wlan_set_mlme(dladm_handle_t, datalink_id_t,
+    boolean_t, int, const uint8_t *);
 
-extern const char	*dladm_wlan_essid2str(dladm_wlan_essid_t *, char *);
-extern const char	*dladm_wlan_bssid2str(dladm_wlan_bssid_t *, char *);
-extern const char	*dladm_wlan_secmode2str(dladm_wlan_secmode_t *, char *);
-extern const char	*dladm_wlan_strength2str(dladm_wlan_strength_t *,
-			    char *);
-extern const char	*dladm_wlan_mode2str(dladm_wlan_mode_t *, char *);
-extern const char	*dladm_wlan_speed2str(dladm_wlan_speed_t *, char *);
-extern const char	*dladm_wlan_auth2str(dladm_wlan_auth_t *, char *);
-extern const char	*dladm_wlan_bsstype2str(dladm_wlan_bsstype_t *, char *);
-extern const char	*dladm_wlan_linkstatus2str(dladm_wlan_linkstatus_t *,
-			    char *);
+/* VAL2STR */
+extern const char *dladm_wlan_bssid2str(const uint8_t *, char *);
+extern const char *dladm_wlan_secmode2str(dladm_wlan_secmode_t, char *);
+extern const char *dladm_wlan_strength2str(const uint8_t, char *);
+extern const char *dladm_wlan_mode2str(dladm_wlan_mode_t, char *);
+extern const char *dladm_wlan_rate2str(const uint8_t, char *);
+extern const char *dladm_wlan_auth2str(const uint8_t, char *);
+extern const char *dladm_wlan_bsstype2str(const uint8_t, char *);
+extern const char *dladm_wlan_linkstatus2str(uint_t, char *);
+extern const char *dladm_wlan_freq2channel(const uint16_t, char *);
 
-extern dladm_status_t	dladm_wlan_str2essid(const char *,
-			    dladm_wlan_essid_t *);
-extern dladm_status_t	dladm_wlan_str2bssid(const char *,
-			    dladm_wlan_bssid_t *);
-extern dladm_status_t	dladm_wlan_str2secmode(const char *,
-			    dladm_wlan_secmode_t *);
-extern dladm_status_t	dladm_wlan_str2strength(const char *,
-			    dladm_wlan_strength_t *);
-extern dladm_status_t	dladm_wlan_str2mode(const char *,
-			    dladm_wlan_mode_t *);
-extern dladm_status_t	dladm_wlan_str2speed(const char *,
-			    dladm_wlan_speed_t *);
-extern dladm_status_t	dladm_wlan_str2auth(const char *,
-			    dladm_wlan_auth_t *);
-extern dladm_status_t	dladm_wlan_str2bsstype(const char *,
-			    dladm_wlan_bsstype_t *);
-extern dladm_status_t	dladm_wlan_str2linkstatus(const char *,
-			    dladm_wlan_linkstatus_t *);
+/* STR2VAL */
+extern dladm_status_t dladm_wlan_str2bssid(const char *, uint8_t *);
+extern dladm_status_t dladm_wlan_str2bsstype(const char *, uint8_t *);
+
+/* obtains the full path of the control socket of a given wpa_s instance */
+extern char *wpa_get_ctrlname(const char *, char *);
+/* for sending control requests to wpa_supplicant */
+extern int wpa_request(struct wpa_ctrl *, int, char *[]);
+/* listens on the control sockets for control events */
+extern boolean_t wpa_get_event(struct wpa_ctrl *, char **, char **);
+/* parses wpa informazion element */
+extern int wpa_supplicant_capsie2txt(const uint16_t ,
+    const uint8_t *, const uint8_t , char *, size_t , int *);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/lib/libdladm/common/libdlwlan_impl.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libdladm/common/libdlwlan_impl.h	Wed May 29 08:31:24 2013 +0200
@@ -21,12 +21,12 @@
 /*
  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #ifndef _LIBDLWLAN_IMPL_H
 #define	_LIBDLWLAN_IMPL_H
 
-#include <sys/types.h>
 #include <inet/wifi_ioctl.h>
 #include <sys/mac.h>
 
@@ -39,29 +39,18 @@
 #endif
 
 /*
- * Map a signal value from 0-15 into an enumerated strength.  Since there are
- * 5 strengths but 16 values, by convention the "middle" strength gets the
- * extra value.  Thus, the buckets are 0-2, 3-5, 6-9, 10-12, and 13-15.
+ * These settings are not supported by current device drivers:
+ *
+ * powermode: Specifies the power management mode of the WiFi link.
+ * Possible values are:
+ * 	off (disable power management),
+ * 	max (maximum power savings), and
+ * 	fast (performance sensitive power management).
+ * Default is off.
+ *
+ * radio: Specifies whether the radio is on or off;
+ * default is on.
  */
-#define	DLADM_WLAN_SIGNAL2STRENGTH(signal)			\
-	    (((signal) > 12 ? DLADM_WLAN_STRENGTH_EXCELLENT :	\
-	    ((signal) > 9 ? DLADM_WLAN_STRENGTH_VERY_GOOD : 	\
-	    ((signal) > 5 ? DLADM_WLAN_STRENGTH_GOOD :		\
-	    ((signal) > 2 ? DLADM_WLAN_STRENGTH_WEAK :		\
-	    DLADM_WLAN_STRENGTH_VERY_WEAK)))))
-
-/*
- * Convert between an OFDM MHz and a channel number.
- */
-#define	DLADM_WLAN_OFDM2CHAN(mhz)		(((mhz) - 5000) / 5)
-
-#define	DLADM_WLAN_CONNECT_POLLRATE		200 /* milliseconds */
-
-#define	DLADM_WLAN_MAX_RATES	4
-typedef struct dladm_wlan_rates {
-	uint8_t		wr_rates[DLADM_WLAN_MAX_RATES];
-	int		wr_cnt;
-} dladm_wlan_rates_t;
 
 typedef enum {
 	DLADM_WLAN_RADIO_ON = 1,
@@ -74,12 +63,9 @@
 	DLADM_WLAN_PM_FAST
 } dladm_wlan_powermode_t;
 
-extern	dladm_status_t i_dladm_wlan_legacy_ioctl(dladm_handle_t,
-			    datalink_id_t, wldp_t *, uint_t, size_t, uint_t,
-			    size_t);
 extern dladm_status_t	i_dladm_wlan_param(dladm_handle_t, datalink_id_t,
 			    void *, mac_prop_id_t, size_t, boolean_t);
-extern boolean_t	i_dladm_wlan_convert_chan(wl_phy_conf_t *, uint32_t *);
+extern boolean_t	i_dladm_wlan_convert_chan(wl_phy_conf_t *, uint16_t *);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/lib/libdladm/common/linkprop.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libdladm/common/linkprop.c	Wed May 29 08:31:24 2013 +0200
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #include <stdlib.h>
@@ -37,17 +38,15 @@
 #include <libdevinfo.h>
 #include <zone.h>
 #include <libdllink.h>
+#include <libdlwlan.h>
 #include <libdladm_impl.h>
 #include <libdlwlan_impl.h>
-#include <libdlwlan.h>
 #include <libdlvlan.h>
 #include <libdlvnic.h>
 #include <libdlib.h>
 #include <libintl.h>
 #include <dlfcn.h>
 #include <link.h>
-#include <inet/wifi_ioctl.h>
-#include <libdladm.h>
 #include <libdlstat.h>
 #include <sys/param.h>
 #include <sys/debug.h>
@@ -55,7 +54,6 @@
 #include <inttypes.h>
 #include <sys/ethernet.h>
 #include <inet/iptun.h>
-#include <net/wpa.h>
 #include <sys/sysmacros.h>
 #include <sys/vlan.h>
 #include <libdlbridge.h>
@@ -282,13 +280,13 @@
 
 	{ MAC_PROP_EN_10HDX_CAP, sizeof (uint8_t),	"en_10hdx_cap"},
 
-	{ MAC_PROP_WL_ESSID,	sizeof (wl_linkstatus_t), "essid"},
+	{ MAC_PROP_WL_ESSID,	sizeof (wl_essid_t), "essid"},
 
 	{ MAC_PROP_WL_BSSID,	sizeof (wl_bssid_t),	"bssid"},
 
 	{ MAC_PROP_WL_BSSTYPE,	sizeof (wl_bss_type_t),	"bsstype"},
 
-	{ MAC_PROP_WL_LINKSTATUS, sizeof (wl_linkstatus_t), "wl_linkstatus"},
+	{ MAC_PROP_WL_LINKSTATUS, sizeof (wl_linkstatus_t), "linkstatus"},
 
 	/* wl_rates_t has variable length */
 	{ MAC_PROP_WL_DESIRED_RATES, sizeof (wl_rates_t), "desired_rates"},
@@ -308,8 +306,7 @@
 
 	{ MAC_PROP_WL_WPA,	sizeof (wl_wpa_t),	"wpa"},
 
-	/*  wl_wpa_ess_t has variable length */
-	{ MAC_PROP_WL_SCANRESULTS, sizeof (wl_wpa_ess_t), "scan_results"},
+	{ MAC_PROP_WL_COUNTERM,	sizeof (wl_counterm_t),	"tkip countermeasures"},
 
 	{ MAC_PROP_WL_POWER_MODE, sizeof (wl_ps_mode_t), "powermode"},
 
@@ -322,7 +319,7 @@
 	{ MAC_PROP_WL_CREATE_IBSS, sizeof (wl_create_ibss_t), "createibss"},
 
 	/* wl_wpa_ie_t has variable length */
-	{ MAC_PROP_WL_SETOPTIE,	sizeof (wl_wpa_ie_t),	"set_ie"},
+	{ MAC_PROP_WL_OPTIE,	sizeof (wl_wpa_ie_t),	"set_ie"},
 
 	{ MAC_PROP_WL_DELKEY,	sizeof (wl_del_key_t),	"wpa_del_key"},
 
@@ -769,15 +766,6 @@
 static dladm_status_t	i_dladm_getset_defval(dladm_handle_t, prop_desc_t *,
 			    datalink_id_t, datalink_media_t, uint_t);
 
-/*
- * Unfortunately, MAX_SCAN_SUPPORT_RATES is too small to allow all
- * rates to be retrieved. However, we cannot increase it at this
- * time because it will break binary compatibility with unbundled
- * WiFi drivers and utilities. So for now we define an additional
- * constant, MAX_SUPPORT_RATES, to allow all rates to be retrieved.
- */
-#define	MAX_SUPPORT_RATES	64
-
 #define	AP_ANCHOR	"[anchor]"
 #define	AP_DELIMITER	'.'
 
@@ -1414,7 +1402,7 @@
 			return (dladm_errno2status(errno));
 		}
 
-		(void) strncpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
+		(void) strlcpy(*prop_val, zone_name, DLADM_PROP_VAL_MAX);
 	} else {
 		*prop_val[0] = '\0';
 	}
@@ -2582,7 +2570,7 @@
 	    ptr[strspn(ptr, "0123456789")] == '.') {
 		char	*cp;
 		ulong_t	duidtype;
-		ulong_t	subtype;
+		ulong_t	subtype = 0;
 		ulong_t	timestamp;
 		uchar_t	*lladdr;
 		int	addrlen;
@@ -2914,8 +2902,6 @@
 	return (DLADM_STATUS_OK);
 }
 
-#define	WLDP_BUFSIZE (MAX_BUF_LEN - WIFI_BUF_OFFSET)
-
 /* ARGSUSED */
 static dladm_status_t
 get_rate_common(dladm_handle_t handle, prop_desc_t *pdp,
@@ -3054,7 +3040,7 @@
     datalink_media_t media)
 {
 	int		i;
-	uint_t		modval_cnt = MAX_SUPPORT_RATES;
+	uint_t		modval_cnt = sizeof (uint8_t);
 	char		*buf, **modval;
 	dladm_status_t	status;
 	uint_t 		perm_flags;
@@ -3065,15 +3051,15 @@
 		return (DLADM_STATUS_BADVALCNT);
 
 	buf = malloc((sizeof (char *) + DLADM_STRSIZE) *
-	    MAX_SUPPORT_RATES);
+	    sizeof (uint8_t));
 	if (buf == NULL) {
 		status = DLADM_STATUS_NOMEM;
 		goto done;
 	}
 
 	modval = (char **)(void *)buf;
-	for (i = 0; i < MAX_SUPPORT_RATES; i++) {
-		modval[i] = buf + sizeof (char *) * MAX_SUPPORT_RATES +
+	for (i = 0; i < sizeof (uint8_t); i++) {
+		modval[i] = buf + sizeof (char *) * sizeof (uint8_t) +
 		    i * DLADM_STRSIZE;
 	}
 
@@ -3111,17 +3097,17 @@
     datalink_id_t linkid, char **prop_val, uint_t *val_cnt,
     datalink_media_t media, uint_t flags, uint_t *perm_flags)
 {
-	uint32_t	channel;
+	uint16_t	channel;
 	char		buf[WLDP_BUFSIZE];
 	dladm_status_t	status;
-	wl_phy_conf_t	wl_phy_conf;
+	wl_phy_conf_t	wl_phys_conf;
 
 	if ((status = get_phyconf(handle, linkid, buf, sizeof (buf)))
 	    != DLADM_STATUS_OK)
 		return (status);
 
-	(void) memcpy(&wl_phy_conf, buf, sizeof (wl_phy_conf));
-	if (!i_dladm_wlan_convert_chan(&wl_phy_conf, &channel))
+	(void) memcpy(&wl_phys_conf, buf, sizeof (wl_phys_conf));
+	if (!i_dladm_wlan_convert_chan(&wl_phys_conf, &channel))
 		return (DLADM_STATUS_NOTFOUND);
 
 	(void) snprintf(*prop_val, DLADM_STRSIZE, "%u", channel);
@@ -3479,6 +3465,7 @@
 	link_attr_t *p;
 
 	p = dladm_id2prop(propid);
+
 	valsize = MAX(p->pp_valsize, valsize);
 	return (i_dladm_buf_alloc_impl(valsize, linkid, p->pp_name, propid,
 	    flags, status));
@@ -3534,7 +3521,6 @@
 
 	status = i_dladm_macprop(handle, dip, B_TRUE);
 
-done:
 	free(dip);
 	return (status);
 }
@@ -4090,7 +4076,7 @@
     val_desc_t **vdpp, datalink_media_t media)
 {
 	char		*cp;
-	boolean_t	iscost;
+	boolean_t	iscost = B_FALSE;
 	uint_t		val_cnt = *val_cntp;
 	val_desc_t	*vdp = *vdpp;
 
@@ -4267,24 +4253,11 @@
 i_dladm_wlan_param(dladm_handle_t handle, datalink_id_t linkid, void *buf,
     mac_prop_id_t cmd, size_t len, boolean_t set)
 {
-	uint32_t		flags;
 	dladm_status_t		status;
-	uint32_t		media;
 	dld_ioc_macprop_t	*dip;
 	void			*dp;
 
-	if ((status = dladm_datalink_id2info(handle, linkid, &flags, NULL,
-	    &media, NULL, 0)) != DLADM_STATUS_OK) {
-		return (status);
-	}
-
-	if (media != DL_WIFI)
-		return (DLADM_STATUS_BADARG);
-
-	if (!(flags & DLADM_OPT_ACTIVE))
-		return (DLADM_STATUS_TEMPONLY);
-
-	if (len == (MAX_BUF_LEN - WIFI_BUF_OFFSET))
+	if (len == WLDP_BUFSIZE)
 		len = MAX_BUF_LEN - sizeof (dld_ioc_macprop_t) - 1;
 
 	dip = i_dladm_buf_alloc_by_id(len, linkid, cmd, 0, &status);
@@ -4369,7 +4342,7 @@
 i_dladm_link_proplist_extract_one(dladm_handle_t handle,
     dladm_arg_list_t *proplist, const char *name, uint_t flags, void *arg)
 {
-	dladm_status_t		status;
+	dladm_status_t		status = DLADM_STATUS_OK;
 	dladm_arg_info_t	*aip = NULL;
 	int			i, j;
 
--- a/usr/src/lib/libdladm/common/llib-ldladm	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libdladm/common/llib-ldladm	Wed May 29 08:31:24 2013 +0200
@@ -27,6 +27,7 @@
 
 #include <libdllink.h>
 #include <libdlaggr.h>
+#include <secobj.h>
 #include <libdlwlan.h>
 #include <libdlvnic.h>
 #include <libdlvlan.h>
--- a/usr/src/lib/libdladm/common/mapfile-vers	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libdladm/common/mapfile-vers	Wed May 29 08:31:24 2013 +0200
@@ -59,12 +59,6 @@
 	dladm_walk_linkprop;
 	dladm_attr_is_linkprop;
 	dladm_linkprop_is_set;
-	dladm_valid_secobj_name;
-	dladm_init_secobj;
-	dladm_get_secobj;
-	dladm_set_secobj;
-	dladm_unset_secobj;
-	dladm_walk_secobj;
 	dladm_str2interval;
 	dladm_bw2str;
 	dladm_str2bw;
@@ -89,26 +83,62 @@
 	dladm_key2linkid;
 	dladm_wlan_scan;
 	dladm_wlan_connect;
+	dladm_wlan_validate;
+	dladm_wlan_createibss;
 	dladm_wlan_disconnect;
+	dladm_wlan_parse_esslist;
+	dladm_wlan_cmd;
+	dladm_wlan_get_bssid;
+	dladm_wlan_get_capability;
+	dladm_wlan_get_essid;
+	dladm_wlan_get_esslist;
 	dladm_wlan_get_linkattr;
-	dladm_wlan_essid2str;
+	dladm_wlan_get_linkstatus;
+	dladm_wlan_get_wpa_ie;
+	dladm_wlan_set_authmode;
+	dladm_wlan_set_bssid;
+	dladm_wlan_set_bsstype;
+	dladm_wlan_set_channel;
+	dladm_wlan_set_essid;
+	dladm_wlan_set_wpa;
+	dladm_wlan_set_counterm;
+	dladm_wlan_set_wpa_ie;
+	dladm_wlan_set_key;
+	dladm_wlan_set_mlme;
 	dladm_wlan_bssid2str;
 	dladm_wlan_secmode2str;
 	dladm_wlan_strength2str;
 	dladm_wlan_mode2str;
-	dladm_wlan_speed2str;
+	dladm_wlan_rate2str;
 	dladm_wlan_auth2str;
 	dladm_wlan_bsstype2str;
 	dladm_wlan_linkstatus2str;
-	dladm_wlan_str2essid;
+	dladm_wlan_freq2channel;
 	dladm_wlan_str2bssid;
-	dladm_wlan_str2secmode;
-	dladm_wlan_str2strength;
-	dladm_wlan_str2mode;
-	dladm_wlan_str2speed;
-	dladm_wlan_str2auth;
 	dladm_wlan_str2bsstype;
-	dladm_wlan_str2linkstatus;
+	dladm_str2identity;
+	dladm_str2crtname;
+	dladm_p2peap_2_str;
+	dladm_p2ttls_2_str;
+	dladm_valid_secobj_name;
+	dladm_valid_secobjclass;
+	dladm_str2secobjval;
+	dladm_secobj_prompt;
+	dladm_get_secobj;
+	dladm_set_secobj;
+	dladm_unset_secobj;
+	dladm_walk_secobj;
+	find_matching_secobj;
+	wpa_request;
+	wpa_get_ctrlname;
+	wpa_get_event;
+	wpa_ctrl_attach;
+	wpa_ctrl_detach;
+	wpa_ctrl_pending;
+	wpa_ctrl_open;
+	wpa_ctrl_close;
+	dladm_eap_import;
+	dladm_eap_delete;
 	dladm_iptun_create;
 	dladm_iptun_delete;
 	dladm_iptun_modify;
@@ -145,12 +175,6 @@
 	dladm_get_conf_field;
 	dladm_set_conf_field;
 	dladm_unset_conf_field;
-	dladm_wlan_wpa_get_sr;
-	dladm_wlan_wpa_set_ie;
-	dladm_wlan_wpa_set_wpa;
-	dladm_wlan_wpa_del_key;
-	dladm_wlan_wpa_set_key;
-	dladm_wlan_wpa_set_mlme;
 	dladm_vnic_create;
 	dladm_vnic_delete;
 	dladm_vnic_info;
--- a/usr/src/lib/libdladm/common/secobj.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libdladm/common/secobj.c	Wed May 29 08:31:24 2013 +0200
@@ -21,60 +21,107 @@
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
+#include <strings.h>
+#include <ctype.h>
 #include <unistd.h>
-#include <stdlib.h>
-#include <strings.h>
+#include <stropts.h>
 #include <errno.h>
-#include <ctype.h>
-#include <fcntl.h>
 #include <sys/stat.h>
-#include <sys/dld.h>
+#include <libintl.h>
+#include <secobj.h>
+#include <netinet/inetutil.h>
 #include <sys/dld_ioc.h>
-#include <libinetutil.h>
-#include <libdllink.h>
 #include <libdladm_impl.h>
+#include <kmfapi.h>
 
-static dladm_status_t	i_dladm_set_secobj_db(dladm_handle_t, const char *,
-			    dladm_secobj_class_t, uint8_t *, uint_t);
-static dladm_status_t	i_dladm_get_secobj_db(dladm_handle_t, const char *,
-			    dladm_secobj_class_t *, uint8_t *, uint_t *);
+static dladm_status_t	i_dladm_set_secobj_db(dladm_handle_t,
+			    dladm_wlan_key_t *);
+static dladm_status_t	i_dladm_get_secobj_db(dladm_handle_t,
+			    dladm_wlan_key_t *);
 static dladm_status_t	i_dladm_unset_secobj_db(dladm_handle_t, const char *);
 static dladm_status_t	i_dladm_walk_secobj_db(dladm_handle_t, void *,
 			    boolean_t (*)(dladm_handle_t, void *,
-			    const char *));
+			    const char *, dladm_secobj_class_t));
+
+static const secobj_class_info_t secobj_class_table[] = {
+	{"wep",		DLADM_SECOBJ_CLASS_WEP},
+	{"psk", 	DLADM_SECOBJ_CLASS_PSK},
+	{"eap-tls",	DLADM_SECOBJ_CLASS_TLS},
+	{"eap-ttls",	DLADM_SECOBJ_CLASS_TTLS},
+	{"peap",	DLADM_SECOBJ_CLASS_PEAP}
+};
 
-typedef struct secobj_class_info {
-	const char		*sc_name;
-	dld_secobj_class_t	sc_dldclass;
-} secobj_class_info_t;
+static const val_desc_t p2ttls_vals[] = {
+	{ "pap",	DLADM_EAP_P2TTLS_PAP	},
+	{ "chap",	DLADM_EAP_P2TTLS_CHAP	},
+	{ "mschap",	DLADM_EAP_P2TTLS_MS	},
+	{ "mschapv2",	DLADM_EAP_P2TTLS_MSV2	},
+	{ "eap-md5",	DLADM_EAP_P2TTLS_EAPMD5	},
+	{ "eap-gtc",	DLADM_EAP_P2TTLS_EAPGTC	},
+	{ "eap-mschapv2", DLADM_EAP_P2TTLS_EAPMSV2}
+};
 
-static secobj_class_info_t secobj_class_table[] = {
-	{"wep",	DLD_SECOBJ_CLASS_WEP},
-	{"wpa",	DLD_SECOBJ_CLASS_WPA}
+static const val_desc_t p2peap_vals[] = {
+	{ "md5",	DLADM_WLAN_P2PEAP_MD5	},
+	{ "gtc",	DLADM_WLAN_P2PEAP_MSV2	},
+	{ "mschapv2",	DLADM_WLAN_P2PEAP_GTC	}
+/*	{ "tls",	DLADM_WLAN_P2PEAP_TLS	} unsupported config */
+};
+
+static const char *key_prompts[] = {
+	NULL,
+	"WEP Password (5/13 ASCII or 10/26 Hex characters)\n",
+	"WPA PSK (from 8, up to 63 ASCII chars or 64 Hex characters)\n",
+	"EAP Passphrase (up to 256 ASCII characters)\n",
+	"EAP Passphrase (up to 256 ASCII characters)\n",
+	"Private Key File Passphrase (up to 256 ASCII characters)\n",
 };
 
 #define	SECOBJ_MAXBUFSZ	65536
 #define	NSECOBJCLASS \
 	(sizeof (secobj_class_table) / sizeof (secobj_class_info_t))
 
-static boolean_t
-dladm_check_secobjclass(dladm_secobj_class_t class)
+boolean_t
+dladm_valid_secobjclass(dladm_secobj_class_t class)
+{
+	return (class > 0 && class <= NSECOBJCLASS);
+}
+
+boolean_t
+dladm_valid_secobj_name(const char *secobj_name)
 {
-	return (class >= 0 && class < NSECOBJCLASS);
+	const char *cp;
+	size_t len = strnlen(secobj_name, DLADM_SECOBJ_NAME_MAX);
+
+	if (len == DLADM_SECOBJ_NAME_MAX || len == 0)
+		return (B_FALSE);
+
+	/*
+	 * The legal characters in a secobj name are:
+	 * alphanumeric (a-z, A-Z, 0-9), '.', '_', '-', ':'
+	 */
+	for (cp = secobj_name; *cp != '\0'; cp++) {
+		if (!isalnum(*cp) && (*cp != ':') &&
+		    (*cp != '.') && (*cp != '_') && (*cp != '-'))
+			return (B_FALSE);
+	}
+
+	return (B_TRUE);
 }
 
 dladm_status_t
 dladm_str2secobjclass(const char *str, dladm_secobj_class_t *class)
 {
-	int			i;
-	secobj_class_info_t	*sp;
+	int i;
+	const secobj_class_info_t *sp;
 
 	for (i = 0; i < NSECOBJCLASS; i++) {
 		sp = &secobj_class_table[i];
 		if (strcasecmp(str, sp->sc_name) == 0) {
-			*class = i;
+			*class = i + 1;
 			return (DLADM_STATUS_OK);
 		}
 	}
@@ -86,166 +133,646 @@
 {
 	const char		*s;
 
-	if (!dladm_check_secobjclass(class))
+	if (!dladm_valid_secobjclass(class))
 		s = "";
 	else
-		s = secobj_class_table[class].sc_name;
+		s = secobj_class_table[class-1].sc_name;
 
-	(void) snprintf(buf, DLADM_STRSIZE, "%s", s);
+	(void) snprintf(buf, 10, "%s", s);
 	return (buf);
 }
 
-static boolean_t
-dladm_convert_secobjclass(dladm_secobj_class_t class,
-    dld_secobj_class_t *dldclass)
+dladm_status_t
+dladm_str2identity(char *input_str, char *eap_usern)
 {
-	if (!dladm_check_secobjclass(class))
-		return (B_FALSE);
+	int flen;
+	int i;
+	if (input_str == NULL || eap_usern == NULL || *eap_usern != '\0')
+		return (DLADM_STATUS_BADARG);
+
+	flen = strnlen(input_str, DLADM_STRSIZE - 2);
+	if (flen < 1 || flen == DLADM_STRSIZE - 2)
+		return (DLADM_STATUS_BADVAL);
+
+	if (input_str[flen - 1] == '\n') {
+		flen--;
+		if (flen == 0)
+			return (DLADM_STATUS_BADVAL);
+		input_str[flen] = '\0';
+	}
+
+	for (i = 0; i < flen; i++)
+		if (iscntrl(input_str[i]))
+			return (DLADM_STATUS_BADVAL);
+
+	eap_usern[0] = '"';
+	(void) memcpy(&eap_usern[1], input_str, flen);
+	eap_usern[flen + 1] = '"';
+	eap_usern[flen + 2] = '\0';
+	return (DLADM_STATUS_OK);
+}
+
+dladm_status_t
+dladm_str2crtname(char *option, char *eap_filename) {
+	struct stat stbuf;
+	int flen;
+	int i;
+	char str_tmp[PATH_MAX];
+	KMF_ENCODE_FORMAT kfmt = 0;
+
+	if (option == NULL || eap_filename == NULL || *eap_filename != '\0')
+		return (DLADM_STATUS_BADARG);
+
+	flen = strnlen(option, PATH_MAX);
+	if (flen < 1 || flen >= PATH_MAX)
+		return (DLADM_STATUS_BADVAL);
+
+	if (option[flen - 1] == '\n') {
+		flen--;
+		if (flen == 0)
+			return (DLADM_STATUS_BADVAL);
+		option[flen] = '\0';
+	}
+
+	for (i = 0; i < flen; i++)
+		if (iscntrl(option[i]))
+			return (DLADM_STATUS_BADVAL);
+
+	if (realpath(option, str_tmp) == NULL)
+		return (DLADM_STATUS_BADVAL);
+	if (stat(str_tmp, &stbuf) == -1)
+		return (DLADM_STATUS_BADVAL);
+	if (!(S_ISREG(stbuf.st_mode)))
+		return (DLADM_STATUS_BADVAL);
 
-	*dldclass = secobj_class_table[class].sc_dldclass;
-	return (B_TRUE);
+	switch (kmf_get_file_format(str_tmp, &kfmt)) {
+		case KMF_ERR_BAD_PARAMETER:
+			return (DLADM_STATUS_BADARG);
+		case KMF_ERR_OPEN_FILE:
+			return (DLADM_STATUS_NOTFOUND);
+		case KMF_OK:
+			if (kfmt == KMF_FORMAT_ASN1 || kfmt == KMF_FORMAT_PEM ||
+			    kfmt == KMF_FORMAT_PKCS12 ||
+			    kfmt == KMF_FORMAT_PEM_KEYPAIR)
+				break;
+		/* FALLTHROUGH */
+		case KMF_ERR_ENCODING:
+			return (DLADM_STATUS_NOTSUP);
+		default:
+			return (DLADM_STATUS_FAILED);
+	}
+
+	(void) snprintf(eap_filename, PATH_MAX, "\"%s\"", str_tmp);
+	return (DLADM_STATUS_OK);
+}
+
+static uint_t
+print_p2names_by_mask(uint8_t val, const val_desc_t *vdp, uint_t cnt,
+    char *buf, boolean_t namesonly)
+{
+	uint_t i = 0, len;
+	int j;
+
+	if (buf == NULL || buf[0] != '\0')
+		return (0);
+
+	buf[0] = '"';
+	for (j = 0; j < cnt; j++) {
+		if (val & vdp[j].vd_val) {
+			char value[DLADM_STRSIZE];
+			if (namesonly) {
+				(void) snprintf(value, DLADM_STRSIZE, "%s ",
+				    vdp[j].vd_name);
+			} else if (strncmp(vdp[j].vd_name, "eap-", 4) == 0) {
+				/* removes 'eap-' prefix */
+				(void) snprintf(value, DLADM_STRSIZE,
+				    "autheap=%s ", vdp[j].vd_name + 4);
+			} else {
+				(void) snprintf(value, DLADM_STRSIZE,
+				    "auth=%s ", vdp[j].vd_name);
+			}
+			(void) strlcat(buf, value, DLADM_STRSIZE);
+			i++;
+		}
+	}
+	len = strnlen(buf, DLADM_STRSIZE);
+	buf[len - 1] = '"';
+	buf[len] = '\0';
+
+	return (i);
+}
+
+uint_t
+dladm_p2peap_2_str(uint8_t mask, char *phase2str, boolean_t namesonly)
+{
+	return (print_p2names_by_mask(mask, p2peap_vals, VALCNT(p2peap_vals),
+	    phase2str, namesonly));
 }
 
-static boolean_t
-dladm_convert_dldsecobjclass(dld_secobj_class_t dldclass,
-    dladm_secobj_class_t *class)
+uint_t
+dladm_p2ttls_2_str(uint8_t mask, char *phase2str, boolean_t namesonly)
+{
+	return (print_p2names_by_mask(mask, p2ttls_vals, VALCNT(p2ttls_vals),
+	    phase2str, namesonly));
+}
+
+static uint_t
+set_mask_by_string(char *str, const val_desc_t *vdp, uint_t cnt,
+    uint8_t *valp)
 {
-	int			i;
-	secobj_class_info_t	*sp;
+	char *tokenp;
+	uint_t i = 0;
+	int j;
+
+	*valp = 0;
+
+	if ((tokenp = strtok(str, " \n\t")) == NULL)
+		return (0);
+
+	do {
+		for (j = 0; j < cnt; j++) {
+			if (strncasecmp(tokenp, vdp[j].vd_name,
+			    DLADM_STRSIZE) == 0) {
+				*valp |= vdp[j].vd_val;
+				i++;
+				break;
+			}
+		}
+	} while ((tokenp = strtok(NULL, " \n\t")) != NULL);
+
+	return (i);
+}
+
+uint_t
+dladm_str_2_p2peap(char *str, uint8_t *p2peap_mask)
+{
+	return (set_mask_by_string(str, p2peap_vals, VALCNT(p2peap_vals),
+	    p2peap_mask));
+}
+
+uint_t
+dladm_str_2_p2ttls(char *str, uint8_t *p2ttls_mask)
+{
+	return (set_mask_by_string(str, p2ttls_vals, VALCNT(p2ttls_vals),
+	    p2ttls_mask));
+}
+
+dladm_status_t
+dladm_str2secobjval(char *buf, uint8_t *obj_val, uint16_t *obj_lenp,
+    dladm_secobj_class_t class)
+{
+	int i;
+	uint16_t buf_len;
+
+	if (buf == NULL || obj_val == NULL || obj_lenp == NULL)
+		return (DLADM_STATUS_BADARG);
+
+	buf_len = strnlen(buf, DLADM_SECOBJ_VAL_MAX);
+	if (buf_len == DLADM_SECOBJ_VAL_MAX || buf_len == 0)
+		return (DLADM_STATUS_BADARG);
+
+	if (iscntrl(buf[buf_len - 1])) {
+		buf[buf_len - 1] = '\0';
+		buf_len--;
+	}
 
-	for (i = 0; i < NSECOBJCLASS; i++) {
-		sp = &secobj_class_table[i];
-		if (dldclass == sp->sc_dldclass) {
-			*class = i;
-			return (B_TRUE);
+	for (i = 0; i < buf_len; i++)
+		if (!(isprint(buf[i])))
+			return (DLADM_STATUS_BADVAL);
+
+	(void) memset(obj_val, 0, DLADM_SECOBJ_VAL_MAX);
+
+	if (class == DLADM_SECOBJ_CLASS_PSK) {
+		if (buf_len >= 8 && buf_len <= 63) {
+			*obj_val = '"';
+			(void) memcpy(obj_val + 1, buf, buf_len);
+			*(obj_val+buf_len + 1) = '"';
+			*obj_lenp = buf_len + 2;
+		} else if (buf_len == 64) {
+			for (i = 0; i < buf_len; i++)
+				if (!(isxdigit(buf[i])))
+					return (DLADM_STATUS_BADVAL);
+			(void) memcpy(obj_val, buf, buf_len);
+			*obj_lenp = buf_len;
+		} else
+			return (DLADM_STATUS_BADVALCNT);
+	} else if (class == DLADM_SECOBJ_CLASS_WEP) {
+		switch (buf_len) {
+		case 5:
+		case 13:
+			/* ASCII key sizes  */
+			*obj_val = '"';
+			(void) memcpy(obj_val + 1, buf, buf_len);
+			*(obj_val + buf_len + 1) = '"';
+			*obj_lenp = buf_len + 2;
+			break;
+
+		case 10:
+		case 26:
+			/* Hex key sizes, not preceded by 0x (64bit/128bit) */
+			for (i = 0; i < buf_len; i++)
+				if (!(isxdigit(buf[i])))
+					return (DLADM_STATUS_BADVAL);
+			(void) memcpy(obj_val, buf, buf_len);
+			*obj_lenp = buf_len;
+			break;
+
+		case 12:
+		case 28:
+			/* Hex key sizes, preceded by 0x (64bit/128bit) */
+			if (strncmp(buf, "0x", 2) != 0) {
+				return (DLADM_STATUS_BADVAL);
+			} else {
+				for (i = 2; i < buf_len; i++)
+					if (!(isxdigit(buf[i])))
+						return (DLADM_STATUS_BADVAL);
+			}
+			(void) memcpy(obj_val + 2, buf, buf_len - 2);
+			*obj_lenp = buf_len - 2;
+			break;
+		default:
+			return (DLADM_STATUS_BADVALCNT);
 		}
-	}
-	return (B_FALSE);
+	} else if (class == DLADM_SECOBJ_CLASS_TTLS ||
+	    class == DLADM_SECOBJ_CLASS_PEAP ||
+	    class == DLADM_SECOBJ_CLASS_TLS) {
+		/*
+		 * When using ENGINE, Private Key Password (eap-tls)
+		 * needs to be unquoted. This is done in eap_pk11.
+		 */
+		*obj_val = '"';
+		(void) memcpy(obj_val + 1, buf, buf_len);
+		*(obj_val + buf_len + 1) = '"';
+		*obj_lenp = buf_len + 2;
+	} else
+		return (DLADM_STATUS_NOTSUP);
+
+	return (DLADM_STATUS_OK);
 }
 
 dladm_status_t
-dladm_set_secobj(dladm_handle_t handle, const char *obj_name,
-    dladm_secobj_class_t class, uint8_t *obj_val, uint_t obj_len, uint_t flags)
+dladm_secobj_prompt(dladm_wlan_key_t *kdata, FILE *filep)
 {
-	dladm_status_t		status = DLADM_STATUS_OK;
-	dld_ioc_secobj_set_t	secobj_set;
-	dld_secobj_t		*objp;
-
-	if (!dladm_valid_secobj_name(obj_name))
-		return (DLADM_STATUS_BADARG);
-
-	if (!dladm_check_secobjclass(class) || flags == 0 ||
-	    obj_name == NULL || strlen(obj_name) > DLD_SECOBJ_NAME_MAX ||
-	    obj_val == NULL || obj_len == 0 || obj_len > DLD_SECOBJ_VAL_MAX)
-		return (DLADM_STATUS_BADARG);
+	dladm_status_t status = DLADM_STATUS_OK;
+	char tmpbuf[DLADM_STRSIZE];
 
-	if ((flags & DLADM_OPT_ACTIVE) == 0)
-		goto persist;
-
-	bzero(&secobj_set, sizeof (secobj_set));
-	objp = &secobj_set.ss_obj;
-	if (!dladm_convert_secobjclass(class, &objp->so_class))
-		return (DLADM_STATUS_BADARG);
+	switch (kdata->wk_class) {
+	case DLADM_SECOBJ_CLASS_PSK:
+		break;
+	case DLADM_SECOBJ_CLASS_WEP:
+		do {
+			tmpbuf[0] = '\0';
+			(void) printf(gettext("\nEnter WEP Key Slot [1-4]: "));
+			(void) fflush(stdin);
+			(void) fgets(tmpbuf, 2, stdin);
+		} while (tmpbuf[0] != '1' && tmpbuf[0] != '2' &&
+		    tmpbuf[0] != '3' && tmpbuf[0] != '4');
+		kdata->wk_idx = tmpbuf[0];
+		break;
+	case DLADM_SECOBJ_CLASS_TTLS:
+		do {
+			(void) memset(tmpbuf, 0, DLADM_STRSIZE);
+			(void) printf(gettext("\nEnter one or more "
+			    "space-separated inner authentication methods "
+			    "among these\n"));
+			(void) dladm_p2ttls_2_str(0xFF, tmpbuf, B_TRUE);
+			(void) printf("\n%s", tmpbuf);
+			(void) memset(tmpbuf, 0, DLADM_STRSIZE);
+			(void) printf(gettext("\n\nEnter EAP-TTLS Phase2 : "));
+			(void) fflush(stdin);
+			(void) fgets(tmpbuf, DLADM_STRSIZE, stdin);
+		} while (dladm_str_2_p2ttls(tmpbuf, &kdata->wk_p2mask) == 0);
+		break;
+	case DLADM_SECOBJ_CLASS_PEAP:
+		do {
+			(void) memset(tmpbuf, 0, DLADM_STRSIZE);
+			(void) printf(gettext("\nEnter one or more "
+			    "space-separated inner authentication methods "
+			    "among these\n"));
+			(void) dladm_p2peap_2_str(0xFF, tmpbuf, B_TRUE);
+			(void) printf("\n%s", tmpbuf);
+			(void) memset(tmpbuf, 0, DLADM_STRSIZE);
+			(void) printf(gettext("\n\nEnter EAP-PEAP Phase2 : "));
+			(void) fflush(stdin);
+			(void) fgets(tmpbuf, DLADM_STRSIZE, stdin);
+		} while (dladm_str_2_p2peap(tmpbuf, &kdata->wk_p2mask) == 0);
+		break;
+	case DLADM_SECOBJ_CLASS_TLS:
+		for (;;) {
+			tmpbuf[0] = '\0';
+			(void) printf(gettext("\nUse PKCS#11 keystore to manage"
+			    " EAP-TLS private key and client certificate? "
+			    "[y/n]:"));
+			(void) fflush(stdin);
+			(void) fgets(tmpbuf, 2, stdin);
+			if (tmpbuf[0] == 'y' || tmpbuf[0] == 'Y') {
+				(void) printf(gettext("\nPrivate key passphrase"
+				    " won't be stored permanently in secobj "
+				    "db\n"));
+				kdata->wk_engine = B_TRUE;
+				break;
+			} else if (tmpbuf[0] == 'n' || tmpbuf[0] == 'N') {
+				(void) printf(gettext("The private key "
+				    "passphrase will be stored permanently "
+				    "in secobj db\n"));
+				kdata->wk_engine = B_FALSE;
+				break;
+			}
+		}
+		break;
+	default:
+		return (DLADM_STATUS_NOTSUP);
+	}
 
-	(void) strlcpy(objp->so_name, obj_name, DLD_SECOBJ_NAME_MAX);
-	bcopy(obj_val, objp->so_val, obj_len);
-	objp->so_len = obj_len;
+	if (filep == NULL) {
+		char *buf = NULL;
+		uint8_t *buf2 = NULL;
+		uint16_t len = 0;
+
+		(void) memset(tmpbuf, 0, sizeof (tmpbuf));
+
+		(void) snprintf(tmpbuf, sizeof (tmpbuf), gettext("\nProvide "
+		    "value for %s\n  > "), key_prompts[kdata->wk_class]);
+
+		buf = getpassphrase(tmpbuf);
+		if (buf == NULL) {
+			status = DLADM_STATUS_FAILED;
+			goto err;
+		}
+
+		status = dladm_str2secobjval(buf, kdata->wk_val,
+		    &kdata->wk_len, kdata->wk_class);
+		if (status != DLADM_STATUS_OK)
+			goto err;
+
+		(void) snprintf(tmpbuf, sizeof (tmpbuf), gettext("\nConfirm "
+		    "value for %s\n  > "), key_prompts[kdata->wk_class]);
+
+		buf = getpassphrase(tmpbuf);
+		if (buf == NULL) {
+			status = DLADM_STATUS_FAILED;
+			goto err;
+		}
 
-	if ((flags & DLADM_OPT_CREATE) != 0)
-		secobj_set.ss_flags = DLD_SECOBJ_OPT_CREATE;
+		buf2 = malloc(DLADM_SECOBJ_VAL_MAX);
+		if (buf2 == NULL) {
+			status = DLADM_STATUS_FAILED;
+			goto err;
+		}
+
+		status = dladm_str2secobjval(buf, buf2, &len, kdata->wk_class);
+		if (status != DLADM_STATUS_OK)
+			goto err;
+
+		if (len != kdata->wk_len || memcmp(buf2, kdata->wk_val,
+		    kdata->wk_len) != 0)
+			status = DLADM_STATUS_BADPROP;
 
-	if (ioctl(dladm_dld_fd(handle), DLDIOC_SECOBJ_SET, &secobj_set) < 0)
-		status = dladm_errno2status(errno);
+		free(buf2);
+	} else {
+		char buf[DLADM_SECOBJ_VAL_MAX];
+		int len;
+
+		if (fgets(buf, sizeof (buf), filep) == NULL) {
+			(void) fclose(filep);
+			return (DLADM_STATUS_DENIED);
+		}
 
-	if (status != DLADM_STATUS_OK)
+		(void) fclose(filep);
+
+		len = strnlen(buf, DLADM_SECOBJ_VAL_MAX);
+		if ((len - 1) == '\n')
+			buf[len - 1] = '\0';
+		status = dladm_str2secobjval(buf, kdata->wk_val, &kdata->wk_len,
+		    kdata->wk_class);
+	}
+
+err:
+	if (!(isatty(fileno(stdout))))
 		return (status);
 
-persist:
-	if ((flags & DLADM_OPT_PERSIST) != 0) {
-		status = i_dladm_set_secobj_db(handle, obj_name, class,
-		    obj_val, obj_len);
+	switch (status) {
+		case DLADM_STATUS_BADVALCNT:
+			(void) printf(gettext("Invalid secure object "
+			    "length\n"));
+			break;
+		case DLADM_STATUS_TOOSMALL:
+			(void) printf(gettext("Zero-length secure object\n"));
+			break;
+		case DLADM_STATUS_NOTSUP:
+			(void) printf(gettext("Invalid secure object class\n"));
+			break;
+		case DLADM_STATUS_BADVAL:
+			(void) printf(gettext("Invalid secure object "
+			    "characters\n"));
+			break;
+		case DLADM_STATUS_BADPROP:
+			(void) printf(gettext("Verification failed. Secure "
+			    "objects do not match\n"));
+			break;
+		case DLADM_STATUS_OK:
+			break;
+		default:
+			break;
 	}
+
 	return (status);
 }
 
-dladm_status_t
-dladm_get_secobj(dladm_handle_t handle, const char *obj_name,
-    dladm_secobj_class_t *classp, uint8_t *obj_val, uint_t *obj_lenp,
-    uint_t flags)
+/*
+ * Walk security objects looking for one that matches the keyname.
+ * Store the keyclass if a match is found - we use the last match
+ * since it is the most recently updated.
+ */
+boolean_t
+/* LINTED E_FUNC_ARG_UNUSED */
+find_matching_secobj(dladm_handle_t dh, void *arg, const char *secobjname,
+    dladm_secobj_class_t secobjclass)
+{
+	secobj_class_info_t *winfo = arg;
+
+	if (strnlen(secobjname, DLADM_SECOBJ_NAME_MAX) ==
+	    strnlen(winfo->sc_name, DLADM_SECOBJ_NAME_MAX) &&
+	    strncmp(winfo->sc_name, secobjname, DLADM_SECOBJ_NAME_MAX) == 0) {
+		winfo->sc_dladmclass = secobjclass;
+		return (B_FALSE);
+	}
+	return (B_TRUE);
+}
+
+static void
+get_first_byte(dladm_wlan_key_t *data, uint8_t fbyte)
 {
-	dladm_status_t		status = DLADM_STATUS_OK;
-	dld_ioc_secobj_get_t	secobj_get;
-	dld_secobj_t		*objp;
+	switch (data->wk_class) {
+	case DLADM_SECOBJ_CLASS_WEP:
+		data->wk_idx = fbyte;
+		break;
+	case DLADM_SECOBJ_CLASS_PSK:
+		break;
+	case DLADM_SECOBJ_CLASS_TTLS:
+	case DLADM_SECOBJ_CLASS_PEAP:
+		data->wk_p2mask = fbyte;
+		break;
+	case DLADM_SECOBJ_CLASS_TLS:
+		data->wk_engine = (fbyte == 1) ? B_TRUE : B_FALSE;
+		break;
+	default:
+		break;
+	}
+}
 
-	if (obj_name == NULL || strlen(obj_name) > DLD_SECOBJ_NAME_MAX ||
-	    obj_val == NULL || obj_lenp == NULL || *obj_lenp == 0 ||
-	    *obj_lenp > DLD_SECOBJ_VAL_MAX)
+static void
+set_first_byte(dladm_wlan_key_t *data, uint8_t *fbyte)
+{
+	*fbyte = 0;
+	switch (data->wk_class) {
+	case DLADM_SECOBJ_CLASS_WEP:
+		*fbyte = data->wk_idx;
+		break;
+	case DLADM_SECOBJ_CLASS_PSK:
+		break;
+	case DLADM_SECOBJ_CLASS_TTLS:
+	case DLADM_SECOBJ_CLASS_PEAP:
+		*fbyte = data->wk_p2mask;
+		break;
+	case DLADM_SECOBJ_CLASS_TLS:
+		if (data->wk_engine)
+			*fbyte = 0x31;
+		break;
+	default:
+		break;
+	}
+}
+
+dladm_status_t
+dladm_set_secobj(dladm_handle_t handle, dladm_wlan_key_t *data, uint_t flags)
+{
+	secobj_class_info_t	key_if;
+
+	if (data == NULL || flags == 0 || data->wk_len == 0 ||
+	    !dladm_valid_secobj_name(data->wk_name) ||
+	    !dladm_valid_secobjclass(data->wk_class))
 		return (DLADM_STATUS_BADARG);
 
-	if ((flags & DLADM_OPT_PERSIST) != 0) {
-		return (i_dladm_get_secobj_db(handle, obj_name, classp,
-		    obj_val, obj_lenp));
+	/* check if this name has already been used */
+	key_if.sc_name = data->wk_name;
+	key_if.sc_dladmclass = 0;
+	if (dladm_walk_secobj(handle, &key_if, find_matching_secobj,
+	    DLADM_OPT_PERSIST | DLADM_OPT_ACTIVE))
+		return (DLADM_STATUS_FAILED);
+
+	if (dladm_valid_secobjclass(key_if.sc_dladmclass))
+		return (DLADM_STATUS_EXIST);
+
+	if (flags & DLADM_OPT_ACTIVE) {
+		dld_ioc_secobj_set_t	secobj_set;
+		dld_secobj_t		*objp;
+
+		bzero(&secobj_set, sizeof (secobj_set));
+		objp = &secobj_set.ss_obj;
+
+		set_first_byte(data, &objp->so_val[0]);
+
+		objp->so_class = (dld_secobj_class_t)data->wk_class;
+		(void) strlcpy(objp->so_name, data->wk_name,
+		    DLADM_SECOBJ_NAME_MAX);
+		bcopy(data->wk_val, &objp->so_val[1], data->wk_len);
+		objp->so_len = data->wk_len + 1;
+
+		if (flags & DLADM_OPT_CREATE)
+			secobj_set.ss_flags = DLD_SECOBJ_OPT_CREATE;
+
+		if (ioctl(dladm_dld_fd(handle),
+		    DLDIOC_SECOBJ_SET, &secobj_set) < 0)
+			return (dladm_errno2status(errno));
 	}
 
-	bzero(&secobj_get, sizeof (secobj_get));
-	objp = &secobj_get.sg_obj;
-	(void) strlcpy(objp->so_name, obj_name, DLD_SECOBJ_NAME_MAX);
+	if (flags & DLADM_OPT_PERSIST)
+		return (i_dladm_set_secobj_db(handle, data));
+
+	return (DLADM_STATUS_OK);
+}
 
-	secobj_get.sg_size = sizeof (secobj_get);
-	if (ioctl(dladm_dld_fd(handle), DLDIOC_SECOBJ_GET, &secobj_get) < 0)
-		status = dladm_errno2status(errno);
+dladm_status_t
+dladm_get_secobj(dladm_handle_t handle, dladm_wlan_key_t *data, uint_t flags)
+{
+	if (data == NULL || flags == 0 || data->wk_name[0] == '\0')
+		return (DLADM_STATUS_BADARG);
+
+	if (flags & DLADM_OPT_PERSIST) {
+		dladm_status_t status = i_dladm_get_secobj_db(handle, data);
+		if (status == DLADM_STATUS_OK ||
+		    status != DLADM_STATUS_NOTFOUND)
+			return (status);
+	}
 
-	if (objp->so_len > *obj_lenp)
-		return (DLADM_STATUS_TOOSMALL);
+	if (flags & DLADM_OPT_ACTIVE) {
+		dld_ioc_secobj_get_t	secobj_get;
+		dld_secobj_t		*objp;
+
+		bzero(&secobj_get, sizeof (secobj_get));
+		objp = &secobj_get.sg_obj;
+		(void) strlcpy(objp->so_name, data->wk_name,
+		    DLADM_SECOBJ_NAME_MAX);
+
+		secobj_get.sg_size = sizeof (secobj_get);
 
-	if (!dladm_convert_dldsecobjclass(objp->so_class, classp))
-		return (DLADM_STATUS_FAILED);
+		if (ioctl(dladm_dld_fd(handle),
+		    DLDIOC_SECOBJ_GET, &secobj_get) < 0)
+			return (dladm_errno2status(errno));
 
-	*obj_lenp = objp->so_len;
-	bcopy(objp->so_val, obj_val, *obj_lenp);
-	return (status);
+		data->wk_class = (dladm_secobj_class_t)objp->so_class;
+		get_first_byte(data, objp->so_val[0]);
+		data->wk_len = objp->so_len - 1;
+		bcopy(&objp->so_val[1], data->wk_val, data->wk_len);
+	}
+
+	return (DLADM_STATUS_OK);
 }
 
 dladm_status_t
 dladm_unset_secobj(dladm_handle_t handle, const char *obj_name, uint_t flags)
 {
-	dladm_status_t		status = DLADM_STATUS_OK;
-	dld_ioc_secobj_unset_t	secobj_unset;
-
-	if (obj_name == NULL || strlen(obj_name) > DLD_SECOBJ_NAME_MAX ||
+	if (obj_name == NULL || strlen(obj_name) >= DLADM_SECOBJ_NAME_MAX ||
 	    flags == 0)
 		return (DLADM_STATUS_BADARG);
 
-	if ((flags & DLADM_OPT_ACTIVE) == 0)
-		goto persist;
+	if (flags & DLADM_OPT_ACTIVE) {
+		dld_ioc_secobj_unset_t	secobj_unset;
+		bzero(&secobj_unset, sizeof (secobj_unset));
 
-	bzero(&secobj_unset, sizeof (secobj_unset));
-	(void) strlcpy(secobj_unset.su_name, obj_name, DLD_SECOBJ_NAME_MAX);
-
-	if (ioctl(dladm_dld_fd(handle), DLDIOC_SECOBJ_UNSET, &secobj_unset) < 0)
-		status = dladm_errno2status(errno);
+		(void) strlcpy(secobj_unset.su_name, obj_name,
+		    DLADM_SECOBJ_NAME_MAX);
 
-	if (status != DLADM_STATUS_OK)
-		return (status);
+		if (ioctl(dladm_dld_fd(handle), DLDIOC_SECOBJ_UNSET,
+		    &secobj_unset) < 0)
+			return (dladm_errno2status(errno));
+	}
 
-persist:
-	if ((flags & DLADM_OPT_PERSIST) != 0)
-		status = i_dladm_unset_secobj_db(handle, obj_name);
+	if (flags & DLADM_OPT_PERSIST)
+		return (i_dladm_unset_secobj_db(handle, obj_name));
 
-	return (status);
+	return (DLADM_STATUS_OK);
 }
 
 dladm_status_t
 dladm_walk_secobj(dladm_handle_t handle, void *arg,
-    boolean_t (*func)(dladm_handle_t, void *, const char *), uint_t flags)
+    boolean_t (*func)(dladm_handle_t, void *, const char *,
+    dladm_secobj_class_t), uint_t flags)
 {
 	dladm_status_t		status = DLADM_STATUS_OK;
 	dld_ioc_secobj_get_t	*secobj_getp;
 	dld_secobj_t		*objp;
 	size_t			secobj_bufsz;
 
-	if ((flags & DLADM_OPT_PERSIST) != 0)
-		return (i_dladm_walk_secobj_db(handle, arg, func));
+	if (flags == 0 || arg == NULL || func == NULL)
+		return (DLADM_STATUS_BADARG);
+
+	if (flags & DLADM_OPT_PERSIST)
+		status = i_dladm_walk_secobj_db(handle, arg, func);
+
+	if (status != DLADM_STATUS_OK || !(flags & DLADM_OPT_ACTIVE))
+		return (status);
 
 	/* Start with enough room for 10 objects, increase if necessary. */
 	secobj_bufsz = sizeof (*secobj_getp) + (10 * sizeof (*objp));
@@ -279,7 +806,8 @@
 
 	objp = (dld_secobj_t *)(secobj_getp + 1);
 	while (secobj_getp->sg_count > 0) {
-		if (!func(handle, arg, objp->so_name))
+		if (!func(handle, arg, objp->so_name,
+		    (dladm_secobj_class_t)objp->so_class))
 			goto done;
 		secobj_getp->sg_count--;
 		objp++;
@@ -290,17 +818,18 @@
 }
 
 /*
- * Data structures used for implementing persistent secure objects
+ * Private data structures used for persistent secure objects back-end
  */
 typedef struct secobj_info {
 	const char		*si_name;
-	dladm_secobj_class_t	*si_classp;
+	dladm_secobj_class_t	si_class;
 	uint8_t			*si_val;
-	uint_t			*si_lenp;
+	uint16_t		si_len;
 } secobj_info_t;
 
 typedef struct secobj_name {
 	char			*sn_name;
+	dladm_secobj_class_t    sn_class;
 	struct secobj_name	*sn_next;
 } secobj_name_t;
 
@@ -332,13 +861,16 @@
 
 	ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t", sip->si_name);
 	ptr += snprintf(ptr, BUFLEN(lim, ptr), "%s\t",
-	    dladm_secobjclass2str(*sip->si_classp, classbuf));
+	    dladm_secobjclass2str(sip->si_class, classbuf));
 
-	ptr += snprintf(ptr, BUFLEN(lim, ptr), "0x");
-	for (i = 0; i < *sip->si_lenp; i++) {
+	/* new syntax lines begin with 1x, old ones with 0x */
+	ptr += snprintf(ptr, BUFLEN(lim, ptr), "1x");
+
+	for (i = 0; i < sip->si_len; i++) {
 		ptr += snprintf(ptr, BUFLEN(lim, ptr), "%02x",
 		    sip->si_val[i] & 0xff);
 	}
+
 	if (ptr > lim) {
 		*statusp = DLADM_STATUS_TOOSMALL;
 		return (B_FALSE);
@@ -352,13 +884,9 @@
 process_secobj_get(dladm_handle_t handle, secobj_db_state_t *ssp, char *buf,
     secobj_info_t *sip, dladm_status_t *statusp)
 {
-	if (*sip->si_lenp > *ssp->ss_info.si_lenp) {
-		*statusp = DLADM_STATUS_TOOSMALL;
-		return (B_FALSE);
-	}
-	bcopy(sip->si_val, ssp->ss_info.si_val, *sip->si_lenp);
-	*ssp->ss_info.si_lenp = *sip->si_lenp;
-	*ssp->ss_info.si_classp = *sip->si_classp;
+	bcopy(sip->si_val, ssp->ss_info.si_val, sip->si_len);
+	ssp->ss_info.si_len = sip->si_len;
+	ssp->ss_info.si_class = sip->si_class;
 	return (B_FALSE);
 }
 
@@ -389,31 +917,24 @@
 		return (B_TRUE);
 	}
 
+	snp->sn_class = sip->si_class;
 	snp->sn_next = NULL;
 	*ssp->ss_namelist = snp;
 	ssp->ss_namelist = &snp->sn_next;
 	return (B_TRUE);
 }
 
-/* ARGSUSED */
-static boolean_t
-process_secobj_init(dladm_handle_t handle, secobj_db_state_t *ssp, char *buf,
-    secobj_info_t *sip, dladm_status_t *statusp)
-{
-	*statusp = dladm_set_secobj(handle, sip->si_name, *sip->si_classp,
-	    sip->si_val, *sip->si_lenp,
-	    DLADM_OPT_ACTIVE | DLADM_OPT_CREATE);
-	return (B_TRUE);
-}
-
 static int
 parse_secobj_val(char *buf, secobj_info_t *sip)
 {
-	if (strncmp(buf, "0x", 2) != 0)
-		return (EINVAL);
+	uint_t tlen = DLD_SECOBJ_VAL_MAX, ret = 0;
 
-	return (hexascii_to_octet(buf + 2, strlen(buf) - 2,
-	    sip->si_val, sip->si_lenp));
+	/* new syntax lines begin with 1x, old ones with 0x */
+	if (strncmp(buf, "1x", 2) != 0)
+		return (EINVAL);
+	ret = hexascii_to_octet(buf + 2, strlen(buf) - 2, sip->si_val, &tlen);
+	sip->si_len = tlen;
+	return (ret);
 }
 
 static boolean_t
@@ -421,9 +942,8 @@
     dladm_status_t *statusp)
 {
 	secobj_info_t		sinfo;
-	dladm_secobj_class_t	class;
-	uint8_t			val[DLADM_SECOBJ_VAL_MAX];
-	uint_t			vlen;
+	uint8_t			val[DLD_SECOBJ_VAL_MAX];
+
 	int			i, len, nlen;
 	char			*str, *lasts;
 
@@ -470,7 +990,7 @@
 	if ((str = strtok_r(str, " \n\t", &lasts)) == NULL)
 		goto fail;
 
-	*statusp = dladm_str2secobjclass(str, &class);
+	*statusp = dladm_str2secobjclass(str, &sinfo.si_class);
 	if (*statusp != DLADM_STATUS_OK)
 		goto fail;
 
@@ -480,10 +1000,7 @@
 	if ((str = strtok_r(NULL, " \n\t", &lasts)) == NULL)
 		goto fail;
 
-	vlen = DLADM_SECOBJ_VAL_MAX;
-	sinfo.si_classp = &class;
 	sinfo.si_val = val;
-	sinfo.si_lenp = &vlen;
 	if (parse_secobj_val(str, &sinfo) != 0)
 		goto fail;
 
@@ -505,6 +1022,7 @@
 	char			buf[MAXLINELEN];
 	boolean_t		cont = B_TRUE;
 
+	(void) memset(buf, 0, sizeof (buf));
 	/*
 	 * This loop processes each line of the configuration file.
 	 * buf can potentially be modified by process_secobj_line().
@@ -549,35 +1067,61 @@
 	process_secobj_db, (statep), (writeop)))
 
 static dladm_status_t
-i_dladm_set_secobj_db(dladm_handle_t handle, const char *obj_name,
-    dladm_secobj_class_t class, uint8_t *obj_val, uint_t obj_len)
+i_dladm_set_secobj_db(dladm_handle_t handle, dladm_wlan_key_t *keyp)
 {
 	secobj_db_state_t	state;
+	uint8_t 		tmpval[DLD_SECOBJ_VAL_MAX];
+
+	(void) memset(tmpval, 0, sizeof (tmpval));
+	set_first_byte(keyp, &tmpval[0]);
+	(void) memcpy(&tmpval[1], keyp->wk_val, keyp->wk_len);
+	keyp->wk_len += 1;
 
 	state.ss_op = process_secobj_set;
-	state.ss_info.si_name = obj_name;
-	state.ss_info.si_classp = &class;
-	state.ss_info.si_val = obj_val;
-	state.ss_info.si_lenp = &obj_len;
+	state.ss_info.si_name = keyp->wk_name;
+	state.ss_info.si_class = keyp->wk_class;
+	state.ss_info.si_val = tmpval;
+	state.ss_info.si_len = keyp->wk_len;
 	state.ss_namelist = NULL;
 
 	return (SECOBJ_RW_DB(handle, &state, B_TRUE));
 }
 
 static dladm_status_t
-i_dladm_get_secobj_db(dladm_handle_t handle, const char *obj_name,
-    dladm_secobj_class_t *classp, uint8_t *obj_val, uint_t *obj_lenp)
+i_dladm_get_secobj_db(dladm_handle_t handle, dladm_wlan_key_t *keyp)
 {
 	secobj_db_state_t	state;
+	dladm_status_t		status;
+	uint8_t 		tmpval[DLD_SECOBJ_VAL_MAX];
 
 	state.ss_op = process_secobj_get;
-	state.ss_info.si_name = obj_name;
-	state.ss_info.si_classp = classp;
-	state.ss_info.si_val = obj_val;
-	state.ss_info.si_lenp = obj_lenp;
+	state.ss_info.si_name = keyp->wk_name;
+	state.ss_info.si_val = tmpval;
 	state.ss_namelist = NULL;
 
-	return (SECOBJ_RW_DB(handle, &state, B_FALSE));
+	(void) memset(tmpval, 0, sizeof (tmpval));
+
+	status = SECOBJ_RW_DB(handle, &state, B_FALSE);
+	if (status == DLADM_STATUS_OK) {
+		keyp->wk_len = state.ss_info.si_len;
+		keyp->wk_class = state.ss_info.si_class;
+		get_first_byte(keyp, *state.ss_info.si_val);
+		keyp->wk_len--;
+		bcopy(state.ss_info.si_val + 1, keyp->wk_val, keyp->wk_len);
+		keyp->wk_val[keyp->wk_len] = 0;
+	} else if (status == DLADM_STATUS_NOTSUP) {
+		/* delete corrupted/old format entries */
+		state.ss_op = process_secobj_walk;
+		state.ss_info.si_name = NULL;
+		state.ss_info.si_class = 0;
+		state.ss_info.si_val = NULL;
+		state.ss_info.si_len = 0;
+		state.ss_namelist = NULL;
+		(void) SECOBJ_RW_DB(handle, &state, B_TRUE);
+		return (DLADM_STATUS_OK);
+	}
+
+	return (status);
 }
 
 static dladm_status_t
@@ -587,9 +1131,9 @@
 
 	state.ss_op = process_secobj_unset;
 	state.ss_info.si_name = obj_name;
-	state.ss_info.si_classp = NULL;
+	state.ss_info.si_class = 0;
 	state.ss_info.si_val = NULL;
-	state.ss_info.si_lenp = NULL;
+	state.ss_info.si_len = 0;
 	state.ss_namelist = NULL;
 
 	return (SECOBJ_RW_DB(handle, &state, B_TRUE));
@@ -597,7 +1141,8 @@
 
 static dladm_status_t
 i_dladm_walk_secobj_db(dladm_handle_t handle, void *arg,
-    boolean_t (*func)(dladm_handle_t, void *, const char *))
+    boolean_t (*func)(dladm_handle_t, void *, const char *,
+    dladm_secobj_class_t))
 {
 	secobj_db_state_t	state;
 	secobj_name_t		*snp = NULL, *fsnp;
@@ -606,59 +1151,25 @@
 
 	state.ss_op = process_secobj_walk;
 	state.ss_info.si_name = NULL;
-	state.ss_info.si_classp = NULL;
+	state.ss_info.si_class = 0;
 	state.ss_info.si_val = NULL;
-	state.ss_info.si_lenp = NULL;
+	state.ss_info.si_len = 0;
 	state.ss_namelist = &snp;
 
 	status = SECOBJ_RW_DB(handle, &state, B_FALSE);
-	if (status != DLADM_STATUS_OK)
-		return (status);
+	if (status == DLADM_STATUS_NOTSUP) {
+		/* delete corrupted/old format entries */
+		(void) SECOBJ_RW_DB(handle, &state, B_TRUE);
+		return (DLADM_STATUS_OK);
+	}
 
 	while (snp != NULL) {
 		fsnp = snp;
 		snp = snp->sn_next;
 		if (cont)
-			cont = func(handle, arg, fsnp->sn_name);
+			cont = func(handle, arg, fsnp->sn_name, fsnp->sn_class);
 		free(fsnp->sn_name);
 		free(fsnp);
 	}
 	return (status);
 }
-
-dladm_status_t
-dladm_init_secobj(dladm_handle_t handle)
-{
-	secobj_db_state_t	state;
-
-	state.ss_op = process_secobj_init;
-	state.ss_info.si_name = NULL;
-	state.ss_info.si_classp = NULL;
-	state.ss_info.si_val = NULL;
-	state.ss_info.si_lenp = NULL;
-	state.ss_namelist = NULL;
-
-	return (SECOBJ_RW_DB(handle, &state, B_FALSE));
-}
-
-boolean_t
-dladm_valid_secobj_name(const char *secobj_name)
-{
-	size_t len = strlen(secobj_name);
-	const char *cp;
-
-	if (len + 1 > DLADM_SECOBJ_NAME_MAX)
-		return (B_FALSE);
-
-	/*
-	 * The legal characters in a secobj name are:
-	 * alphanumeric (a-z, A-Z, 0-9), '.', '_', '-'.
-	 */
-	for (cp = secobj_name; *cp != '\0'; cp++) {
-		if (!isalnum(*cp) &&
-		    (*cp != '.') && (*cp != '_') && (*cp != '-'))
-			return (B_FALSE);
-	}
-
-	return (B_TRUE);
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libdladm/common/secobj.h	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,158 @@
+/*
+ * This file and its contents are supplied under the terms of the
+ * Common Development and Distribution License ("CDDL"), version 1.0.
+ * You may only use this file in accordance with the terms of version
+ * 1.0 of the CDDL.
+ *
+ * A full copy of the text of the CDDL should have accompanied this
+ * source.  A copy is of the CDDL is also available via the Internet
+ * at http://www.illumos.org/license/CDDL.
+ */
+
+/*
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
+ */
+
+/*
+ * Wifi Security Policy Defines
+ */
+
+#ifndef _SECOBJ_H
+#define	_SECOBJ_H
+
+#include <libdladm.h>
+#include <limits.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+/*
+ * Maximum size of secobj value. Note that it should not be greater than
+ * DLD_SECOBJ_VAL_MAX.
+ */
+#define	DLADM_SECOBJ_VAL_MAX	256
+
+/*
+ * Maximum size of secobj name. Note that it should not be greater than
+ * DLD_SECOBJ_NAME_MAX.
+ */
+#define	DLADM_SECOBJ_NAME_MAX	32
+
+#define	PIN_FILE	"/etc/dladm/eap_pin.sh"
+
+/* same as CONFIG_CTRL_IFACE_DIR in wpa_cli.c */
+#define	CTRL_IFACE_DIR	"/var/run/wpa_supplicant"
+
+/*
+ * Do not reorder these
+ */
+typedef enum {
+	DLADM_SECOBJ_CLASS_WEP = 1,
+	DLADM_SECOBJ_CLASS_PSK,
+	DLADM_SECOBJ_CLASS_TLS,
+	DLADM_SECOBJ_CLASS_TTLS,
+	DLADM_SECOBJ_CLASS_PEAP
+} dladm_secobj_class_t;
+
+typedef struct dladm_wlan_key {
+	dladm_secobj_class_t wk_class;
+	boolean_t wk_engine;
+	char wk_name[DLADM_SECOBJ_NAME_MAX];
+	uint8_t wk_val[DLADM_SECOBJ_VAL_MAX];
+	uint16_t wk_len;
+	uint8_t wk_p2mask;
+	char wk_idx;
+} dladm_wlan_key_t;
+
+typedef struct secobj_class_info {
+	const char		*sc_name;
+	dladm_secobj_class_t	sc_dladmclass;
+} secobj_class_info_t;
+
+/*
+ * Tunnel inner authentication
+ * only for eap-ttls eap-peap
+ */
+typedef enum {
+	DLADM_EAP_P2TTLS_PAP = 0x01,
+	DLADM_EAP_P2TTLS_CHAP = 0x02,
+	DLADM_EAP_P2TTLS_MS = 0x04,
+	DLADM_EAP_P2TTLS_MSV2 = 0x08,
+	DLADM_EAP_P2TTLS_EAPMD5 = 0x10,
+	DLADM_EAP_P2TTLS_EAPGTC = 0x20,
+	DLADM_EAP_P2TTLS_EAPMSV2 = 0x40
+} dladm_wlan_p2ttls_t;
+
+typedef enum {
+	DLADM_WLAN_P2PEAP_MD5 = 0x01,
+	DLADM_WLAN_P2PEAP_MSV2 = 0x02,
+	DLADM_WLAN_P2PEAP_GTC = 0x04
+/*	DLADM_WLAN_P2PEAP_TLS = 0x08 (unsupported configuration scheme) */
+} dladm_wlan_p2peap_t;
+
+enum {
+	DLADM_EAP_ATTR_USER = 0x01,
+	DLADM_EAP_ATTR_ANON = 0x02,
+	DLADM_EAP_ATTR_CACERT = 0x04,
+	DLADM_EAP_ATTR_CLICERT = 0x08,
+	DLADM_EAP_ATTR_PRIV = 0x10
+};
+
+typedef struct dladm_wlan_eap {
+	char eap_user[DLADM_STRSIZE]; /* email */
+	char eap_anon[DLADM_STRSIZE]; /* email */
+	char eap_ca_cert[PATH_MAX]; /*  filename */
+	char eap_cli_cert[PATH_MAX]; /* filename */
+	char eap_priv[PATH_MAX]; /* filename */
+	uint8_t eap_valid;
+} dladm_wlan_eap_t;
+
+/* class */
+extern const char	*dladm_secobjclass2str(dladm_secobj_class_t, char *);
+extern dladm_status_t	dladm_str2secobjclass(const char *,
+			    dladm_secobj_class_t *);
+extern boolean_t	dladm_valid_secobjclass(dladm_secobj_class_t class);
+
+/* keyname */
+extern boolean_t	dladm_valid_secobj_name(const char *);
+
+/* keyval */
+extern dladm_status_t	dladm_str2secobjval(char *buf, uint8_t *obj_val,
+			    uint16_t *obj_lenp, dladm_secobj_class_t class);
+extern dladm_status_t	dladm_secobj_prompt(dladm_wlan_key_t *kdata,
+			    FILE *filep);
+
+/* secobj */
+extern dladm_status_t	dladm_set_secobj(dladm_handle_t, dladm_wlan_key_t *,
+			    uint_t);
+extern dladm_status_t	dladm_get_secobj(dladm_handle_t, dladm_wlan_key_t *,
+			    uint_t);
+extern dladm_status_t	dladm_unset_secobj(dladm_handle_t, const char *,
+			    uint_t);
+extern dladm_status_t	dladm_walk_secobj(dladm_handle_t, void *,
+			    boolean_t (*)(dladm_handle_t, void *, const char *,
+			    dladm_secobj_class_t), uint_t);
+extern boolean_t	find_matching_secobj(dladm_handle_t, void *,
+			    const char *, dladm_secobj_class_t);
+
+/* eap */
+extern uint_t dladm_p2peap_2_str(uint8_t, char *, boolean_t);
+extern uint_t dladm_p2ttls_2_str(uint8_t, char *, boolean_t);
+extern uint_t dladm_str_2_p2peap(char *, uint8_t *);
+extern uint_t dladm_str_2_p2ttls(char *, uint8_t *);
+
+extern dladm_status_t dladm_str2crtname(char *option, char *eapst);
+extern dladm_status_t dladm_str2identity(char *, char *);
+
+
+/* pkcs11 routines */
+extern dladm_status_t   dladm_eap_import(dladm_handle_t, char *,
+			    char *, const char *, const dladm_secobj_class_t);
+extern dladm_status_t   dladm_eap_delete(char *, dladm_secobj_class_t);
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif	/* _SECOBJ_H */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libdladm/common/wpa_ctrl.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,551 @@
+/*
+ * wpa_supplicant/hostapd control interface library
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#ifdef CONFIG_CTRL_IFACE
+
+#ifdef CONFIG_CTRL_IFACE_UNIX
+#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"
+
+
+#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
+#define CTRL_IFACE_SOCKET
+#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
+
+
+/**
+ * struct wpa_ctrl - Internal structure for control interface library
+ *
+ * This structure is used by the wpa_supplicant/hostapd control interface
+ * library to store internal data. Programs using the library should not touch
+ * this data directly. They can only use the pointer to the data structure as
+ * an identifier for the control interface connection and use this as one of
+ * the arguments for most of the control interface library functions.
+ */
+struct wpa_ctrl {
+#ifdef CONFIG_CTRL_IFACE_UDP
+	int s;
+	struct sockaddr_in local;
+	struct sockaddr_in dest;
+	char *cookie;
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#ifdef CONFIG_CTRL_IFACE_UNIX
+	int s;
+	struct sockaddr_un local;
+	struct sockaddr_un dest;
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+	HANDLE pipe;
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+};
+
+
+#ifdef CONFIG_CTRL_IFACE_UNIX
+
+#ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
+#define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp"
+#endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */
+#ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
+#define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
+#endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */
+
+
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
+{
+	struct wpa_ctrl *ctrl;
+	static int counter = 0;
+	int ret;
+	size_t res;
+	int tries = 0;
+
+	ctrl = os_malloc(sizeof(*ctrl));
+	if (ctrl == NULL)
+		return NULL;
+	os_memset(ctrl, 0, sizeof(*ctrl));
+
+	ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (ctrl->s < 0) {
+		os_free(ctrl);
+		return NULL;
+	}
+
+	ctrl->local.sun_family = AF_UNIX;
+	counter++;
+try_again:
+	ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
+			  CONFIG_CTRL_IFACE_CLIENT_DIR "/"
+			  CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
+			  (int) getpid(), counter);
+	if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
+		close(ctrl->s);
+		os_free(ctrl);
+		return NULL;
+	}
+	tries++;
+	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
+		    sizeof(ctrl->local)) < 0) {
+		if (errno == EADDRINUSE && tries < 2) {
+			/*
+			 * getpid() returns unique identifier for this instance
+			 * of wpa_ctrl, so the existing socket file must have
+			 * been left by unclean termination of an earlier run.
+			 * Remove the file and try again.
+			 */
+			unlink(ctrl->local.sun_path);
+			goto try_again;
+		}
+		close(ctrl->s);
+		os_free(ctrl);
+		return NULL;
+	}
+
+#ifdef ANDROID
+	chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+	chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
+	/*
+	 * If the ctrl_path isn't an absolute pathname, assume that
+	 * it's the name of a socket in the Android reserved namespace.
+	 * Otherwise, it's a normal UNIX domain socket appearing in the
+	 * filesystem.
+	 */
+	if (ctrl_path != NULL && *ctrl_path != '/') {
+		char buf[21];
+		os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
+		if (socket_local_client_connect(
+			    ctrl->s, buf,
+			    ANDROID_SOCKET_NAMESPACE_RESERVED,
+			    SOCK_DGRAM) < 0) {
+			close(ctrl->s);
+			unlink(ctrl->local.sun_path);
+			os_free(ctrl);
+			return NULL;
+		}
+		return ctrl;
+	}
+#endif /* ANDROID */
+
+	ctrl->dest.sun_family = AF_UNIX;
+	res = strlcpy(ctrl->dest.sun_path, ctrl_path,
+			 sizeof(ctrl->dest.sun_path));
+	if (res >= sizeof(ctrl->dest.sun_path)) {
+		close(ctrl->s);
+		os_free(ctrl);
+		return NULL;
+	}
+	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
+		    sizeof(ctrl->dest)) < 0) {
+		close(ctrl->s);
+		unlink(ctrl->local.sun_path);
+		os_free(ctrl);
+		return NULL;
+	}
+
+	return ctrl;
+}
+
+
+void wpa_ctrl_close(struct wpa_ctrl *ctrl)
+{
+	if (ctrl == NULL)
+		return;
+	unlink(ctrl->local.sun_path);
+	if (ctrl->s >= 0)
+		close(ctrl->s);
+	os_free(ctrl);
+}
+
+
+#ifdef ANDROID
+/**
+ * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
+ * may be left over from clients that were previously connected to
+ * wpa_supplicant. This keeps these files from being orphaned in the
+ * event of crashes that prevented them from being removed as part
+ * of the normal orderly shutdown.
+ */
+void wpa_ctrl_cleanup(void)
+{
+	DIR *dir;
+	struct dirent entry;
+	struct dirent *result;
+	size_t dirnamelen;
+	int prefixlen = os_strlen(CONFIG_CTRL_IFACE_CLIENT_PREFIX);
+	size_t maxcopy;
+	char pathname[PATH_MAX];
+	char *namep;
+
+	if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL)
+		return;
+
+	dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/",
+					  CONFIG_CTRL_IFACE_CLIENT_DIR);
+	if (dirnamelen >= sizeof(pathname)) {
+		closedir(dir);
+		return;
+	}
+	namep = pathname + dirnamelen;
+	maxcopy = PATH_MAX - dirnamelen;
+	while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
+		if (os_strncmp(entry.d_name, CONFIG_CTRL_IFACE_CLIENT_PREFIX,
+			       prefixlen) == 0) {
+			if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
+				unlink(pathname);
+		}
+	}
+	closedir(dir);
+}
+#endif /* ANDROID */
+
+#else /* CONFIG_CTRL_IFACE_UNIX */
+
+#ifdef ANDROID
+void wpa_ctrl_cleanup(void)
+{
+}
+#endif /* ANDROID */
+
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
+{
+	struct wpa_ctrl *ctrl;
+	char buf[128];
+	size_t len;
+
+	ctrl = os_malloc(sizeof(*ctrl));
+	if (ctrl == NULL)
+		return NULL;
+	os_memset(ctrl, 0, sizeof(*ctrl));
+
+	ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
+	if (ctrl->s < 0) {
+		perror("socket");
+		os_free(ctrl);
+		return NULL;
+	}
+
+	ctrl->local.sin_family = AF_INET;
+	ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
+	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
+		 sizeof(ctrl->local)) < 0) {
+		close(ctrl->s);
+		os_free(ctrl);
+		return NULL;
+	}
+
+	ctrl->dest.sin_family = AF_INET;
+	ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
+	ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
+	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
+		    sizeof(ctrl->dest)) < 0) {
+		perror("connect");
+		close(ctrl->s);
+		os_free(ctrl);
+		return NULL;
+	}
+
+	len = sizeof(buf) - 1;
+	if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
+		buf[len] = '\0';
+		ctrl->cookie = os_strdup(buf);
+	}
+
+	return ctrl;
+}
+
+
+void wpa_ctrl_close(struct wpa_ctrl *ctrl)
+{
+	close(ctrl->s);
+	os_free(ctrl->cookie);
+	os_free(ctrl);
+}
+
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+
+#ifdef CTRL_IFACE_SOCKET
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+		     char *reply, size_t *reply_len,
+		     void (*msg_cb)(char *msg, size_t len))
+{
+	struct timeval tv;
+	int res;
+	fd_set rfds;
+	const char *_cmd;
+	char *cmd_buf = NULL;
+	size_t _cmd_len;
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+	if (ctrl->cookie) {
+		char *pos;
+		_cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
+		cmd_buf = os_malloc(_cmd_len);
+		if (cmd_buf == NULL)
+			return -1;
+		_cmd = cmd_buf;
+		pos = cmd_buf;
+		os_strlcpy(pos, ctrl->cookie, _cmd_len);
+		pos += os_strlen(ctrl->cookie);
+		*pos++ = ' ';
+		os_memcpy(pos, cmd, cmd_len);
+	} else
+#endif /* CONFIG_CTRL_IFACE_UDP */
+	{
+		_cmd = cmd;
+		_cmd_len = cmd_len;
+	}
+
+	if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
+		os_free(cmd_buf);
+		return -1;
+	}
+	os_free(cmd_buf);
+
+	for (;;) {
+		tv.tv_sec = 10;
+		tv.tv_usec = 0;
+		FD_ZERO(&rfds);
+		FD_SET(ctrl->s, &rfds);
+		res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+		if (res < 0)
+			return res;
+		if (FD_ISSET(ctrl->s, &rfds)) {
+			res = recv(ctrl->s, reply, *reply_len, 0);
+			if (res < 0)
+				return res;
+			if (res > 0 && reply[0] == '<') {
+				/* This is an unsolicited message from
+				 * wpa_supplicant, not the reply to the
+				 * request. Use msg_cb to report this to the
+				 * caller. */
+				if (msg_cb) {
+					/* Make sure the message is nul
+					 * terminated. */
+					if ((size_t) res == *reply_len)
+						res = (*reply_len) - 1;
+					reply[res] = '\0';
+					msg_cb(reply, res);
+				}
+				continue;
+			}
+			*reply_len = res;
+			break;
+		} else {
+			return -2;
+		}
+	}
+	return 0;
+}
+#endif /* CTRL_IFACE_SOCKET */
+
+
+static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
+{
+	char buf[10];
+	int ret;
+	size_t len = 10;
+
+	ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
+			       buf, &len, NULL);
+	if (ret < 0)
+		return ret;
+	if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
+		return 0;
+	return -1;
+}
+
+
+int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
+{
+	return wpa_ctrl_attach_helper(ctrl, 1);
+}
+
+
+int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
+{
+	return wpa_ctrl_attach_helper(ctrl, 0);
+}
+
+
+#ifdef CTRL_IFACE_SOCKET
+
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
+{
+	int res;
+
+	res = recv(ctrl->s, reply, *reply_len, 0);
+	if (res < 0)
+		return res;
+	*reply_len = res;
+	return 0;
+}
+
+
+int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
+{
+	struct timeval tv;
+	fd_set rfds;
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+	FD_ZERO(&rfds);
+	FD_SET(ctrl->s, &rfds);
+	select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+	return FD_ISSET(ctrl->s, &rfds);
+}
+
+
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
+{
+	return ctrl->s;
+}
+
+#endif /* CTRL_IFACE_SOCKET */
+
+
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+
+#ifndef WPA_SUPPLICANT_NAMED_PIPE
+#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
+#endif
+#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
+
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
+{
+	struct wpa_ctrl *ctrl;
+	DWORD mode;
+	TCHAR name[256];
+	int i, ret;
+
+	ctrl = os_malloc(sizeof(*ctrl));
+	if (ctrl == NULL)
+		return NULL;
+	os_memset(ctrl, 0, sizeof(*ctrl));
+
+#ifdef UNICODE
+	if (ctrl_path == NULL)
+		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
+	else
+		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
+				 ctrl_path);
+#else /* UNICODE */
+	if (ctrl_path == NULL)
+		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
+	else
+		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
+				  ctrl_path);
+#endif /* UNICODE */
+	if (ret < 0 || ret >= 256) {
+		os_free(ctrl);
+		return NULL;
+	}
+
+	for (i = 0; i < 10; i++) {
+		ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
+					NULL, OPEN_EXISTING, 0, NULL);
+		/*
+		 * Current named pipe server side in wpa_supplicant is
+		 * re-opening the pipe for new clients only after the previous
+		 * one is taken into use. This leaves a small window for race
+		 * conditions when two connections are being opened at almost
+		 * the same time. Retry if that was the case.
+		 */
+		if (ctrl->pipe != INVALID_HANDLE_VALUE ||
+		    GetLastError() != ERROR_PIPE_BUSY)
+			break;
+		WaitNamedPipe(name, 1000);
+	}
+	if (ctrl->pipe == INVALID_HANDLE_VALUE) {
+		os_free(ctrl);
+		return NULL;
+	}
+
+	mode = PIPE_READMODE_MESSAGE;
+	if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
+		CloseHandle(ctrl->pipe);
+		os_free(ctrl);
+		return NULL;
+	}
+
+	return ctrl;
+}
+
+
+void wpa_ctrl_close(struct wpa_ctrl *ctrl)
+{
+	CloseHandle(ctrl->pipe);
+	os_free(ctrl);
+}
+
+
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+		     char *reply, size_t *reply_len,
+		     void (*msg_cb)(char *msg, size_t len))
+{
+	DWORD written;
+	DWORD readlen = *reply_len;
+
+	if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
+		return -1;
+
+	if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
+		return -1;
+	*reply_len = readlen;
+
+	return 0;
+}
+
+
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
+{
+	DWORD len = *reply_len;
+	if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
+		return -1;
+	*reply_len = len;
+	return 0;
+}
+
+
+int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
+{
+	DWORD left;
+
+	if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
+		return -1;
+	return left ? 1 : 0;
+}
+
+
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
+{
+	return -1;
+}
+
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+
+#endif /* CONFIG_CTRL_IFACE */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/lib/libdladm/common/wpa_ie.c	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,598 @@
+/*
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ */
+
+/*
+ * wpa_supplicant routines and defines for parsing wpa Information Element
+ */
+
+#include <string.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <wpa_defs.h>
+#include <inet/wifi_ioctl.h>
+
+/* IEEE 802.11i */
+#define PMKID_LEN 16
+
+#define WPA_SELECTOR_LEN 4
+#define WPA_VERSION 1
+#define RSN_SELECTOR_LEN 4
+#define RSN_VERSION 1
+
+/* Information Element IDs */
+#define WLAN_EID_SSID 0
+#define WLAN_EID_RSN 48
+#define WLAN_EID_VENDOR_SPECIFIC 221
+
+#define WPA_GET_LE16(a) ((uint16_t) (((a)[1] << 8) | (a)[0]))
+#define WPA_GET_BE16(a) ((uint16_t) (((a)[0] << 8) | (a)[1]))
+#define WPA_PUT_BE16(a, val)                    \
+        do {                                    \
+                (a)[0] = ((uint16_t) (val)) >> 8;    \
+                (a)[1] = ((uint16_t) (val)) & 0xff;  \
+        } while (0)
+
+
+#define RSN_SELECTOR(a, b, c, d) \
+	((((uint32_t) (a)) << 24) | (((uint32_t) (b)) << 16) | (((uint32_t) (c)) << 8) | \
+	 (uint32_t) (d))
+
+#define WPA_AUTH_KEY_MGMT_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
+#define WPA_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
+#define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
+#define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
+#define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
+#define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
+#define WPA_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x50, 0xf2, 3)
+#define WPA_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x50, 0xf2, 4)
+#define WPA_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x50, 0xf2, 5)
+
+#define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
+#define RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
+
+#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)
+#define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
+#define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3
+#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
+#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
+#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
+
+#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
+
+#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((uint8_t *) (a), (val))
+#define RSN_SELECTOR_GET(a) WPA_GET_BE32((const uint8_t *) (a))
+
+#define RSN_NUM_REPLAY_COUNTERS_1 0
+#define RSN_NUM_REPLAY_COUNTERS_2 1
+#define RSN_NUM_REPLAY_COUNTERS_4 2
+#define RSN_NUM_REPLAY_COUNTERS_16 3
+
+/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */
+#define WPA_CAPABILITY_PREAUTH BIT(0)
+#define WPA_CAPABILITY_NO_PAIRWISE BIT(1)
+
+#define WPA_GET_BE32(a) ((((uint32_t) (a)[0]) << 24) | (((uint32_t) (a)[1]) << 16) | \
+			 (((uint32_t) (a)[2]) << 8) | ((uint32_t) (a)[3]))
+
+struct wpa_ie_data {
+	int proto;
+	int pairwise_cipher;
+	int group_cipher;
+	int key_mgmt;
+	int capabilities;
+	size_t num_pmkid;
+	const uint8_t *pmkid;
+	int mgmt_group_cipher;
+};
+
+#pragma pack(1)
+struct wpa_ie_hdr {
+	uint8_t elem_id;
+	uint8_t len;
+	uint8_t oui[4]; /* 24-bit OUI followed by 8-bit OUI type */
+	uint8_t version[2]; /* little endian */
+};
+#pragma pack()
+
+#pragma pack(1)
+struct rsn_ie_hdr {
+	uint8_t elem_id; /* WLAN_EID_RSN */
+	uint8_t len;
+	uint8_t version[2]; /* little endian */
+};
+#pragma pack()
+
+static int wpa_selector_to_bitfield(const uint8_t *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 uint8_t *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 rsn_key_mgmt_to_bitfield(const uint8_t *s)
+{
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
+		return WPA_KEY_MGMT_IEEE8021X;
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
+		return WPA_KEY_MGMT_PSK;
+	return 0;
+}
+
+static int rsn_selector_to_bitfield(const uint8_t *s)
+{
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
+		return WPA_CIPHER_NONE;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40)
+		return WPA_CIPHER_WEP40;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
+		return WPA_CIPHER_TKIP;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
+		return WPA_CIPHER_CCMP;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104)
+		return WPA_CIPHER_WEP104;
+	return 0;
+}
+
+static int wpa_parse_wpa_ie_wpa(const uint8_t *wpa_ie, size_t wpa_ie_len,
+    struct wpa_ie_data *data)
+{
+	const struct wpa_ie_hdr *hdr;
+	const uint8_t *pos;
+	int left;
+	int i, count;
+
+	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)) {
+		printf("wpa_parse_wpa_ie_wpa: ie len too short %lu",
+			   (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) {
+		printf("wpa_parse_wpa_ie_wpa: malformed ie or unknown version");
+		return -2;
+	}
+
+	pos = (const uint8_t *) (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) {
+		printf("wpa_parse_wpa_ie_wpa: ie length mismatch, %u too much",
+		    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) {
+			printf("wpa_parse_wpa_ie_wpa: ie count botch (pairwise)\
+			    , count %u left %u", 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) {
+		printf("wpa_parse_wpa_ie_wpa: ie too short (for key mgmt)");
+		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) {
+			printf("wpa_parse_wpa_ie_wpa: ie count botch (key mgmt)\
+			    , count %u left %u", 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) {
+		printf("wpa_parse_wpa_ie_wpa: ie too short (for capabilities)");
+		return -7;
+	}
+
+	if (left >= 2) {
+		data->capabilities = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+	}
+
+	if (left > 0) {
+		printf("wpa_parse_wpa_ie_wpa: ie has %u trailing bytes \
+		    - ignored", left);
+	}
+
+	return 0;
+}
+
+/**
+ * wpa_parse_wpa_ie_rsn - Parse RSN IE
+ * @rsn_ie: Buffer containing RSN IE
+ * @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
+ * @data: Pointer to structure that will be filled in with parsed data
+ * Returns: 0 on success, <0 on failure
+ */
+static int wpa_parse_wpa_ie_rsn(const uint8_t *rsn_ie, size_t rsn_ie_len,
+    struct wpa_ie_data *data)
+{
+	const struct rsn_ie_hdr *hdr;
+	const uint8_t *pos;
+	int left;
+	int i, count;
+
+	memset(data, 0, sizeof (*data));
+	data->proto = WPA_PROTO_RSN;
+	data->pairwise_cipher = WPA_CIPHER_CCMP;
+	data->group_cipher = WPA_CIPHER_CCMP;
+	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+	data->capabilities = 0;
+	data->pmkid = NULL;
+	data->num_pmkid = 0;
+	data->mgmt_group_cipher = 0;
+
+	if (rsn_ie_len == 0) {
+		/* No RSN IE - fail silently */
+		return -1;
+	}
+
+	if (rsn_ie_len < sizeof (struct rsn_ie_hdr)) {
+		printf("wpa_parse_wpa_ie_rsn: ie len too short %lu",
+		    (unsigned long) rsn_ie_len);
+		return -1;
+	}
+
+	hdr = (const struct rsn_ie_hdr *) rsn_ie;
+
+	if (hdr->elem_id != WLAN_EID_RSN ||
+	    hdr->len != rsn_ie_len - 2 ||
+	    WPA_GET_LE16(hdr->version) != RSN_VERSION) {
+		printf("wpa_parse_wpa_ie_rsn: malformed ie or unknown version");
+		return -2;
+	}
+
+	pos = (const uint8_t *) (hdr + 1);
+	left = rsn_ie_len - sizeof (*hdr);
+
+	if (left >= RSN_SELECTOR_LEN) {
+		data->group_cipher = rsn_selector_to_bitfield(pos);
+		pos += RSN_SELECTOR_LEN;
+		left -= RSN_SELECTOR_LEN;
+	} else if (left > 0) {
+		printf("wpa_parse_wpa_ie_rsn: ie length mismatch, %u too much",
+		    left);
+		return -3;
+	}
+
+	if (left >= 2) {
+		data->pairwise_cipher = 0;
+		count = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+			printf("wpa_parse_wpa_ie_rsn: ie count botch (pairwise)\
+			, count %u left %u", count, left);
+			return -4;
+		}
+		for (i = 0; i < count; i++) {
+			data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
+			pos += RSN_SELECTOR_LEN;
+			left -= RSN_SELECTOR_LEN;
+		}
+	} else if (left == 1) {
+		printf("wpa_parse_wpa_ie_rsn: ie too short (for key mgmt)");
+		return -5;
+	}
+
+	if (left >= 2) {
+		data->key_mgmt = 0;
+		count = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+			printf("wpa_parse_wpa_ie_rsn: ie count botch (key mgmt)\
+			, count %u left %u", count, left);
+			return -6;
+		}
+		for (i = 0; i < count; i++) {
+			data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
+			pos += RSN_SELECTOR_LEN;
+			left -= RSN_SELECTOR_LEN;
+		}
+	} else if (left == 1) {
+		printf("wpa_parse_wpa_ie_rsn: ie too short (for capabilities)");
+		return -7;
+	}
+
+	if (left >= 2) {
+		data->capabilities = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+	}
+
+	if (left >= 2) {
+		data->num_pmkid = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (left < (int) data->num_pmkid * PMKID_LEN) {
+			printf("wpa_parse_wpa_ie_rsn: PMKID underflow "
+				   "(num_pmkid=%lu left=%d)",
+				   (unsigned long) data->num_pmkid,
+				   left);
+			data->num_pmkid = 0;
+			return -9;
+		} else {
+			data->pmkid = pos;
+			pos += data->num_pmkid * PMKID_LEN;
+			left -= data->num_pmkid * PMKID_LEN;
+		}
+	}
+
+	if (left > 0)
+		printf("wpa_parse_wpa_ie_rsn: ie has %u trailing bytes \
+		- ignored", left);
+
+	return 0;
+}
+
+static int wpa_parse_wpa_ie(const uint8_t *wpa_ie, size_t wpa_ie_len,
+    struct wpa_ie_data *data)
+{
+        if (wpa_ie_len >= 1 && wpa_ie[0] == WLAN_EID_RSN)
+                return wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, data);
+        else
+                return wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, data);
+}
+
+static char * wpa_supplicant_cipher_txt(char *pos, char *end, int cipher)
+{
+	int first = 1, ret;
+	ret = snprintf(pos, end - pos, "-");
+	if (ret < 0 || ret >= end - pos)
+		return pos;
+	pos += ret;
+	if (cipher & WPA_CIPHER_NONE) {
+		ret = snprintf(pos, end - pos, "%sNONE", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (cipher & WPA_CIPHER_WEP40) {
+		ret = snprintf(pos, end - pos, "%sWEP40", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (cipher & WPA_CIPHER_WEP104) {
+		ret = snprintf(pos, end - pos, "%sWEP104",
+				  first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (cipher & WPA_CIPHER_TKIP) {
+		ret = snprintf(pos, end - pos, "%sTKIP", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (cipher & WPA_CIPHER_CCMP) {
+		ret = snprintf(pos, end - pos, "%sCCMP", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	return pos;
+}
+
+static char * wpa_supplicant_ie_txt(char *pos, char *end, const char *proto,
+    const uint8_t *ie, size_t ie_len, int *keymgmt)
+{
+	struct wpa_ie_data data;
+	int first, ret;
+
+	ret = snprintf(pos, end - pos, "[%s-", proto);
+	if (ret < 0 || ret >= end - pos)
+		return pos;
+	pos += ret;
+
+	if (wpa_parse_wpa_ie(ie, ie_len, &data) < 0) {
+		ret = snprintf(pos, end - pos, "?]");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		return pos;
+	}
+
+	*keymgmt = data.key_mgmt;
+
+	first = 1;
+	if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+		ret = snprintf(pos, end - pos, "%sEAP", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (data.key_mgmt & WPA_KEY_MGMT_PSK) {
+		ret = snprintf(pos, end - pos, "%sPSK", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+	if (data.key_mgmt & WPA_KEY_MGMT_WPA_NONE) {
+		ret = snprintf(pos, end - pos, "%sNone", first ? "" : "+");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+		first = 0;
+	}
+
+	pos = wpa_supplicant_cipher_txt(pos, end, data.pairwise_cipher);
+
+	if (data.capabilities & WPA_CAPABILITY_PREAUTH) {
+		ret = snprintf(pos, end - pos, "-preauth");
+		if (ret < 0 || ret >= end - pos)
+			return pos;
+		pos += ret;
+	}
+
+	ret = snprintf(pos, end - pos, "]");
+	if (ret < 0 || ret >= end - pos)
+		return pos;
+	pos += ret;
+
+	return pos;
+}
+
+static const uint8_t * wpa_bss_get_vendor_ie(const uint8_t *wpaie,
+    const uint8_t wpaielen, uint32_t vendor_type)
+{
+	const uint8_t *end, *pos;
+
+	pos = wpaie;
+	end = pos + wpaielen;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    vendor_type == WPA_GET_BE32(&pos[2]))
+			return pos;
+		pos += 2 + pos[1];
+	}
+
+	return NULL;
+}
+
+static const uint8_t * wpa_bss_get_ie(const uint8_t *wpaie,
+    const uint8_t wpaielen, uint8_t ie)
+{
+	const uint8_t *end, *pos;
+
+	pos = wpaie;
+	end = pos + wpaielen;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == ie)
+			return pos;
+		pos += 2 + pos[1];
+	}
+
+	return NULL;
+}
+
+#define WPA_IE_VENDOR_TYPE 0x0050f201
+
+int wpa_supplicant_capsie2txt(const uint16_t nodecaps, const uint8_t *wpaie,
+    const uint8_t wpaielen, char *buf, size_t buflen, int *keymgmt)
+{
+	char *pos, *end;
+	int ret;
+	const uint8_t *ie, *ie2;
+
+	pos = buf;
+	end = buf + buflen;
+
+	ie = wpa_bss_get_vendor_ie(wpaie, wpaielen, WPA_IE_VENDOR_TYPE);
+	if (ie)
+		pos = wpa_supplicant_ie_txt(pos, end, "WPA", ie, 2 + ie[1],
+		    keymgmt);
+	ie2 = wpa_bss_get_ie(wpaie, wpaielen, WLAN_EID_RSN);
+	if (ie2)
+		pos = wpa_supplicant_ie_txt(pos, end, "WPA2", ie2, 2 + ie2[1],
+		    keymgmt);
+	if (!ie && !ie2 && nodecaps & IEEE80211_CAP_PRIVACY) {
+		ret = snprintf(pos, end - pos, "[WEP]");
+		if (ret < 0 || ret >= end - pos)
+			return -1;
+		pos += ret;
+	}
+	if (nodecaps & IEEE80211_CAP_IBSS) {
+		ret = snprintf(pos, end - pos, "[IBSS]");
+		if (ret < 0 || ret >= end - pos)
+			return -1;
+		pos += ret;
+	}
+	if (nodecaps & IEEE80211_CAP_ESS) {
+		ret = snprintf(pos, end - pos, "[ESS]");
+		if (ret < 0 || ret >= end - pos)
+			return -1;
+		pos += ret;
+	}
+
+	return 0;
+}
--- a/usr/src/lib/libnwam/Makefile.com	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libnwam/Makefile.com	Wed May 29 08:31:24 2013 +0200
@@ -51,9 +51,6 @@
 CFLAGS +=       $(CCVERBOSE)
 CPPFLAGS +=	-I$(SRCDIR) -D_REENTRANT
 
-CERRWARN +=	-_gcc=-Wno-switch
-CERRWARN +=	-_gcc=-Wno-uninitialized
-
 .KEEP_STATE:
 
 all:	$(LIBS)
--- a/usr/src/lib/libnwam/common/libnwam.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libnwam/common/libnwam.h	Wed May 29 08:31:24 2013 +0200
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 /*
@@ -39,6 +40,7 @@
 #include <inet/ip6.h>
 #include <sys/types.h>
 #include <sys/socket.h>
+#include <secobj.h>
 
 /*
  * Note - several interface functions below are not utilized in ON, but are
@@ -94,11 +96,6 @@
 				NWAM_FLAG_ACTIVATION_MODE_CONDITIONAL_ANY |\
 				NWAM_FLAG_ACTIVATION_MODE_CONDITIONAL_ALL)
 
-/* Walk known WLANs in order of priority (lowest first) */
-#define	NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER	0x000010000ULL << 32
-/* Do not perform priority collision checking for known WLANs */
-#define	NWAM_FLAG_KNOWN_WLAN_NO_COLLISION_CHECK		0x000020000ULL << 32
-
 /* nwam return codes */
 typedef enum {
 	NWAM_SUCCESS,			/* No error occured */
@@ -233,11 +230,9 @@
 	NWAM_AUX_STATE_METHOD_RUNNING,
 	NWAM_AUX_STATE_INVALID_CONFIG,
 	NWAM_AUX_STATE_ACTIVE,
-	/* Link-specific auxiliary states */
-	NWAM_AUX_STATE_LINK_WIFI_SCANNING,
-	NWAM_AUX_STATE_LINK_WIFI_NEED_SELECTION,
-	NWAM_AUX_STATE_LINK_WIFI_NEED_KEY,
-	NWAM_AUX_STATE_LINK_WIFI_CONNECTING,
+	/* Wifi Link-specific auxiliary states */
+	NWAM_AUX_STATE_LINK_WIFI_ASSOCIATED,
+	NWAM_AUX_STATE_LINK_WIFI_CONNECTED,
 	/* IP interface-specific auxiliary states */
 	NWAM_AUX_STATE_IF_WAITING_FOR_ADDR,
 	NWAM_AUX_STATE_IF_DHCP_TIMED_OUT,
@@ -284,9 +279,7 @@
 	NWAM_CONDITION_OBJECT_TYPE_LOC,
 	NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS,
 	NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN,
-	NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN,
-	NWAM_CONDITION_OBJECT_TYPE_ESSID,
-	NWAM_CONDITION_OBJECT_TYPE_BSSID
+	NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN
 } nwam_condition_object_type_t;
 
 /*
@@ -476,12 +469,18 @@
 
 typedef struct nwam_handle *nwam_known_wlan_handle_t;
 
-#define	NWAM_KNOWN_WLAN_PROP_BSSIDS		"bssids"
-#define	NWAM_KNOWN_WLAN_PROP_PRIORITY		"priority"
-#define	NWAM_KNOWN_WLAN_PROP_KEYNAME		"keyname"
-#define	NWAM_KNOWN_WLAN_PROP_KEYSLOT		"keyslot"
-#define	NWAM_KNOWN_WLAN_PROP_SECURITY_MODE	"security-mode"
-
+#define	NWAM_KNOWN_WLAN_PROP_SSID	"ssid"
+#define	NWAM_KNOWN_WLAN_PROP_BSSID	"bssid"
+#define	NWAM_KNOWN_WLAN_PROP_KEYNAME	"keyname"
+#define	NWAM_KNOWN_WLAN_PROP_PRIORITY	"priority"
+#define	NWAM_KNOWN_WLAN_PROP_DISABLED	"disabled"
+/* eap */
+#define	NWAM_KNOWN_WLAN_PROP_EAP_USER	"identity"
+#define	NWAM_KNOWN_WLAN_PROP_EAP_ANON	"anonymous_identity"
+#define	NWAM_KNOWN_WLAN_PROP_CA_CERT	"ca_cert"
+/* tls */
+#define	NWAM_KNOWN_WLAN_PROP_PRIV	"private_key"
+#define	NWAM_KNOWN_WLAN_PROP_CLI_CERT	"client_cert"
 /*
  * Location Functions
  */
@@ -816,7 +815,7 @@
     nwam_known_wlan_handle_t *);
 
 /* Commit known WLAN changes to persistent storage */
-extern nwam_error_t nwam_known_wlan_commit(nwam_known_wlan_handle_t, uint64_t);
+extern nwam_error_t nwam_known_wlan_commit(nwam_known_wlan_handle_t);
 
 /* Validate known WLAN content */
 extern nwam_error_t nwam_known_wlan_validate(nwam_known_wlan_handle_t,
@@ -824,7 +823,7 @@
 
 /* Walk known WLANs */
 extern nwam_error_t nwam_walk_known_wlans
-	(int(*)(nwam_known_wlan_handle_t, void *), void *, uint64_t, int *);
+	(int(*)(nwam_known_wlan_handle_t, void *), void *, int *);
 
 /* get/set known WLAN name */
 extern nwam_error_t nwam_known_wlan_get_name(nwam_known_wlan_handle_t, char **);
@@ -850,6 +849,7 @@
 /* Retrieve data type */
 extern nwam_error_t nwam_known_wlan_get_prop_type(const char *,
     nwam_value_type_t *);
+
 /* Retrieve prop description */
 extern nwam_error_t nwam_known_wlan_get_prop_description(const char *,
     const char **);
@@ -858,56 +858,36 @@
 extern nwam_error_t nwam_known_wlan_get_default_proplist(const char ***,
     uint_t *);
 
-/* Whether the property is multi-valued or not */
-extern nwam_error_t nwam_known_wlan_prop_multivalued(const char *, boolean_t *);
-
-/* Add a bssid to the known WLANs */
-extern nwam_error_t nwam_known_wlan_add_to_known_wlans(const char *,
-    const char *, uint32_t, uint_t, const char *);
-
-/* Remove a bssid from known WLANs */
+/* Remove from known WLANs */
 extern nwam_error_t nwam_known_wlan_remove_from_known_wlans(const char *,
     const char *, const char *);
 
-/*
- * nwam_wlan_t is used for scan/need choice/need key events and by
- * nwam_wlan_get_scan_results().  The following fields are valid:
- *
- * - for scan and need choice event, ESSID, BSSID, signal strength, security
- * mode, speed, channel, bsstype, key index, and if we already have a key
- * (have_key), if the WLAN is the current selection (selected) and
- * if the current WLAN is connected (connected).
- * - for need key events, ESSID, security mode, have_key, selected and connected
- * values are set.  The rest of the fields are not set since multiple WLANs
- * may match the ESSID and have different speeds, channels etc.  If an
- * ESSID/BSSID selection is specified, the BSSID will be set also.
- *
- */
 typedef struct {
-	char nww_essid[NWAM_MAX_NAME_LEN];
-	char nww_bssid[NWAM_MAX_NAME_LEN];
-	char nww_signal_strength[NWAM_MAX_NAME_LEN];
-	uint32_t nww_security_mode; /* a dladm_wlan_secmode_t */
-	uint32_t nww_speed; /* a dladm_wlan_speed_t */
-	uint32_t nww_channel; /* a dladm_wlan_channel_t */
-	uint32_t nww_bsstype; /* a dladm_wlan_bsstype_t */
-	uint_t nww_keyindex;
-	boolean_t nww_have_key;
-	boolean_t nww_selected;
-	boolean_t nww_connected;
+	uint32_t nww_wlanid;
+	uint8_t nww_bssid[8];
+	uint8_t nww_essid[34];
+	uint8_t nww_esslen;
+	uint8_t nww_security_mode; /* AP beacon security mode (wpa_ie+caps) */
+	uint16_t nww_freq; /* setting in Mhz */
+	uint8_t nww_strength; /* 0->127 */
+	uint8_t nww_rate;
+	uint16_t nww_scanid;
+	char	nww_ietxt[48];
 } nwam_wlan_t;
 
+/* Add known WLAN */
+extern nwam_error_t nwam_known_wlan_add_to_known_wlans(dladm_handle_t,
+    nwam_wlan_t *, dladm_wlan_key_t *, dladm_wlan_eap_t *, const char **);
+
 /*
  * Active WLAN definitions. Used to scan WLANs/choose a WLAN/set a WLAN key.
  */
 extern nwam_error_t nwam_wlan_scan(const char *);
 extern nwam_error_t nwam_wlan_get_scan_results(const char *, uint_t *,
     nwam_wlan_t **);
-extern nwam_error_t nwam_wlan_select(const char *, const char *, const char *,
-    uint32_t, boolean_t);
-extern nwam_error_t nwam_wlan_set_key(const char *, const char *, const char *,
-    uint32_t, uint_t, const char *);
-
+extern nwam_error_t nwam_wlan_select(const char *linkname,
+    const nwam_wlan_t *mywlan, const dladm_wlan_key_t *key_data,
+    const dladm_wlan_eap_t *eap_data);
 /*
  * Event notification definitions
  */
@@ -919,13 +899,14 @@
 #define	NWAM_EVENT_TYPE_PRIORITY_GROUP		5
 #define	NWAM_EVENT_TYPE_INFO			6
 #define	NWAM_EVENT_TYPE_WLAN_SCAN_REPORT	7
-#define	NWAM_EVENT_TYPE_WLAN_NEED_CHOICE	8
-#define	NWAM_EVENT_TYPE_WLAN_NEED_KEY		9
+#define	NWAM_EVENT_TYPE_WLAN_ASSOCIATION_REPORT	8
+#define	NWAM_EVENT_TYPE_WLAN_WRONG_KEY		9
 #define	NWAM_EVENT_TYPE_WLAN_CONNECTION_REPORT	10
-#define	NWAM_EVENT_TYPE_IF_ACTION		11
-#define	NWAM_EVENT_TYPE_IF_STATE		12
-#define	NWAM_EVENT_TYPE_LINK_ACTION		13
-#define	NWAM_EVENT_TYPE_LINK_STATE		14
+#define	NWAM_EVENT_TYPE_WLAN_DISASSOCIATION_REPORT 11
+#define	NWAM_EVENT_TYPE_IF_ACTION		12
+#define	NWAM_EVENT_TYPE_IF_STATE		13
+#define	NWAM_EVENT_TYPE_LINK_ACTION		14
+#define	NWAM_EVENT_TYPE_LINK_STATE		15
 #define	NWAM_EVENT_MAX				NWAM_EVENT_TYPE_LINK_STATE
 
 #define	NWAM_EVENT_STATUS_OK			0
@@ -935,6 +916,7 @@
 #define	NWAM_EVENT_NETWORK_OBJECT_LINK		1
 #define	NWAM_EVENT_NETWORK_OBJECT_INTERFACE	2
 
+/* Required by nwam-manager */
 #define	NWAM_EVENT_REQUEST_UNDEFINED		0
 #define	NWAM_EVENT_REQUEST_WLAN			1
 #define	NWAM_EVENT_REQUEST_KEY			2
@@ -993,21 +975,14 @@
 		} nwe_info;
 
 		/*
-		 * wlan_info stores both scan results and the single
-		 * WLAN we require a key for in the case of _WLAN_NEED_KEY
-		 * events.  For _WLAN_CONNECTION_REPORT events, it stores
-		 * the WLAN the connection succeeded/failed for, indicating
-		 * success/failure using the 'connected' boolean.
+		 * wlan_info stores both scan results and the single WLAN.
+		 * For _WLAN_CONNECTION_REPORT events, it stores
+		 * the WLAN the connection succeeded/failed for
 		 */
 		struct nwam_event_wlan_info {
 			char nwe_name[NWAM_MAX_NAME_LEN];
-			boolean_t nwe_connected;
-			uint16_t nwe_num_wlans;
-			nwam_wlan_t nwe_wlans[1];
-			/*
-			 * space may be allocated by user here for the
-			 * number of wlans
-			 */
+			uint16_t nwe_scanres_num;
+			nwam_wlan_t nwe_wlan;
 		} nwe_wlan_info;
 
 		struct nwam_event_if_action {
--- a/usr/src/lib/libnwam/common/libnwam_audit.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libnwam/common/libnwam_audit.c	Wed May 29 08:31:24 2013 +0200
@@ -25,9 +25,7 @@
  */
 
 #include <sys/types.h>
-#include <bsm/adt.h>
 #include <bsm/adt_event.h>
-
 #include <libnwam_priv.h>
 
 /*
--- a/usr/src/lib/libnwam/common/libnwam_files.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libnwam/common/libnwam_files.c	Wed May 29 08:31:24 2013 +0200
@@ -192,6 +192,7 @@
 		}
 		valbool = NULL;
 		valint = NULL;
+		valuint = NULL;
 		valstr = NULL;
 		switch (proptype) {
 		case NWAM_VALUE_TYPE_BOOLEAN:
@@ -259,6 +260,7 @@
 			if ((newvalbool = realloc(valbool,
 			    nelem * sizeof (boolean_t))) == NULL) {
 				nwam_free_object_list(*((char **)proplist));
+				free(valbool);
 				return (NWAM_NO_MEMORY);
 			}
 			if ((err = nwam_value_create_boolean_array(newvalbool,
@@ -277,6 +279,7 @@
 			if ((newvalint = realloc(valint,
 			    nelem * sizeof (int64_t))) == NULL) {
 				nwam_free_object_list(*((char **)proplist));
+				free(valint);
 				return (NWAM_NO_MEMORY);
 			}
 			if ((err = nwam_value_create_int64_array(newvalint,
@@ -295,6 +298,7 @@
 			if ((newvaluint = realloc(valuint,
 			    nelem * sizeof (uint64_t))) == NULL) {
 				nwam_free_object_list(*((char **)proplist));
+				free(valuint);
 				return (NWAM_NO_MEMORY);
 			}
 			if ((err = nwam_value_create_uint64_array(newvaluint,
@@ -313,6 +317,7 @@
 			if ((newvalstr = realloc(valstr,
 			    nelem * sizeof (char *))) == NULL) {
 				nwam_free_object_list(*((char **)proplist));
+				free(valstr);
 				return (NWAM_NO_MEMORY);
 			}
 			if ((err = nwam_value_create_string_array(newvalstr,
@@ -331,6 +336,8 @@
 			free(newvalstr);
 			nwam_value_free(val);
 			break;
+		default:
+			break;
 		}
 		prop = nextprop;
 	}
@@ -421,7 +428,7 @@
 	char *cp, *foundobjname, **objnames = NULL, **ncpfiles = NULL;
 	uint_t num_files = 0;
 	FILE *fp = NULL;
-	nwam_error_t err;
+	nwam_error_t err = NWAM_SUCCESS;
 	void *objlist = NULL, *proplist = NULL;
 	uint_t i = 0, j = 0;
 	nwam_value_t objnamesval = NULL;
--- a/usr/src/lib/libnwam/common/libnwam_impl.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libnwam/common/libnwam_impl.h	Wed May 29 08:31:24 2013 +0200
@@ -21,6 +21,7 @@
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 /*
@@ -37,7 +38,6 @@
 #endif
 
 #include <libnwam_priv.h>
-#include <libnwam.h>
 
 /*
  * We separate global flags (which are applicable to all object types) from
@@ -199,7 +199,8 @@
 extern nwam_error_t nwam_request_state(nwam_object_type_t, const char *,
 	const char *, nwam_state_t *, nwam_aux_state_t *);
 extern nwam_error_t nwam_request_wlan(nwam_request_type_t, const char *,
-	const char *, const char *, uint32_t, uint_t, const char *, boolean_t);
+	const nwam_wlan_t *, const dladm_wlan_key_t *,
+	const dladm_wlan_eap_t *eap_data);
 extern nwam_error_t nwam_request_wlan_scan_results(const char *name,
 	uint_t *, nwam_wlan_t **);
 extern nwam_error_t nwam_request_active_priority_group(int64_t *);
--- a/usr/src/lib/libnwam/common/libnwam_known_wlan.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libnwam/common/libnwam_known_wlan.c	Wed May 29 08:31:24 2013 +0200
@@ -22,6 +22,7 @@
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #include <assert.h>
@@ -33,12 +34,10 @@
 #include <stdlib.h>
 #include <strings.h>
 #include <unistd.h>
-#include <libdllink.h>
 #include <libdlwlan.h>
 
 #include "libnwam_impl.h"
 #include <libnwam_priv.h>
-#include <libnwam.h>
 
 /*
  * Functions to support creating, modifying and destroying
@@ -46,33 +45,62 @@
  * and are used by nwamd to identify and connect to known WLANs in
  * scan results.
  */
-
-static nwam_error_t valid_keyname(nwam_value_t);
-static nwam_error_t valid_keyslot(nwam_value_t);
-static nwam_error_t valid_secmode(nwam_value_t);
+static nwam_error_t nwam_valid_ssid(nwam_value_t);
+static nwam_error_t nwam_valid_secobj(nwam_value_t);
+static nwam_error_t nwam_valid_priority(nwam_value_t);
+static nwam_error_t nwam_valid_eapuser(nwam_value_t);
+static nwam_error_t nwam_valid_certfile(nwam_value_t);
+static nwam_error_t nwam_valid_priv(nwam_value_t);
 
 struct nwam_prop_table_entry known_wlan_prop_table_entries[] = {
-	{NWAM_KNOWN_WLAN_PROP_PRIORITY, NWAM_VALUE_TYPE_UINT64, B_FALSE,
-	    1, 1, nwam_valid_uint64,
-	    "specifies priority of known WLAN - lower values are prioritized",
+	{NWAM_KNOWN_WLAN_PROP_SSID, NWAM_VALUE_TYPE_STRING, B_FALSE,
+	    1, 1, nwam_valid_ssid,
+	    "Service set identifier (network name) [max:32chars]",
 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
-	{NWAM_KNOWN_WLAN_PROP_BSSIDS, NWAM_VALUE_TYPE_STRING, B_FALSE,
-	    0, NWAM_MAX_NUM_VALUES, nwam_valid_mac_addr,
-	    "specifies BSSID(s) (of the form aa:bb:cc:dd:ee:ff) associated "
-	    "with known WLAN",
+	{NWAM_KNOWN_WLAN_PROP_BSSID, NWAM_VALUE_TYPE_STRING, B_FALSE,
+	    0, 1, nwam_valid_mac_addr,
+	    "BSSID (mac-addr in the form aa:bb:cc:dd:ee:ff) (default=any)",
 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
 	{NWAM_KNOWN_WLAN_PROP_KEYNAME, NWAM_VALUE_TYPE_STRING, B_FALSE,
-	    0, 1, valid_keyname,
-	    "specifies security key name used with known WLAN",
+	    0, 1, nwam_valid_secobj,
+	    "Existing and Valid secure object name [max:32chars] \n"
+	    "Wlan Security Policy follows secure object class \n"
+	    "(default=plaintext)",
+	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
+	{NWAM_KNOWN_WLAN_PROP_PRIORITY, NWAM_VALUE_TYPE_UINT64, B_FALSE,
+	    0, 1, nwam_valid_priority,
+	    "Wlans with higher priority values are matched earlier \n"
+	    "Valid Range is [0->2147483647] (default=1)",
+	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
+	{NWAM_KNOWN_WLAN_PROP_DISABLED, NWAM_VALUE_TYPE_BOOLEAN, B_FALSE,
+	    0, 1, nwam_valid_boolean,
+	    "If known WLAN should be ignored during selection (default=false)",
+	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
+	{NWAM_KNOWN_WLAN_PROP_EAP_USER, NWAM_VALUE_TYPE_STRING, B_FALSE,
+	    0, 1, nwam_valid_eapuser,
+	    "Identity string for EAP (Network Access Identifier) \n"
+	    "[required for EAP-TLS/TTLS/PEAP] [max:256chars]",
 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
-	{NWAM_KNOWN_WLAN_PROP_KEYSLOT, NWAM_VALUE_TYPE_UINT64, B_FALSE,
-	    0, 1, valid_keyslot,
-	    "specifies key slot [1-4] for security key used with known WLAN",
+	{NWAM_KNOWN_WLAN_PROP_EAP_ANON, NWAM_VALUE_TYPE_STRING, B_FALSE,
+	    0, 1, nwam_valid_eapuser,
+	    "Anonymous Identity string for EAP \n"
+	    "[EAP-TLS/TTLS/PEAP only] [max:256chars] (default=empty)",
+	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
+	{NWAM_KNOWN_WLAN_PROP_CA_CERT, NWAM_VALUE_TYPE_STRING, B_FALSE,
+	    0, 1, nwam_valid_certfile,
+	    "File path to CA certificate (PEM/DER) \n"
+	    "[EAP-TLS/TTLS/PEAP only] (default=empty)",
 	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
-	{NWAM_KNOWN_WLAN_PROP_SECURITY_MODE, NWAM_VALUE_TYPE_UINT64, B_FALSE,
-	    0, 1, valid_secmode,
-	    "specifies security mode used for known WLAN",
-	    NWAM_TYPE_ANY, NWAM_CLASS_ANY}
+	{NWAM_KNOWN_WLAN_PROP_PRIV, NWAM_VALUE_TYPE_STRING, B_FALSE,
+	    0, 1, nwam_valid_priv,
+	    "File path to Client Private Key (PEM/DER/PKCS#12) \n"
+	    "[required for EAP-TLS] ",
+	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
+	{NWAM_KNOWN_WLAN_PROP_CLI_CERT, NWAM_VALUE_TYPE_STRING, B_FALSE,
+	    0, 1, nwam_valid_certfile,
+	    "File path to Client Certificate (PEM/DER) \n"
+	    "[required if Client Private Key file does not contain both]",
+	    NWAM_TYPE_ANY, NWAM_CLASS_ANY},
 };
 
 #define	NWAM_NUM_KNOWN_WLAN_PROPS	\
@@ -82,6 +110,43 @@
 struct nwam_prop_table known_wlan_prop_table =
 	{ NWAM_NUM_KNOWN_WLAN_PROPS, known_wlan_prop_table_entries };
 
+static int
+find_highest_id(nwam_known_wlan_handle_t kwh, void *data)
+{
+	uint32_t *topid = data;
+	int currid = -1;
+	char *curridstr;
+
+	if (nwam_known_wlan_get_name(kwh, &curridstr) != NWAM_SUCCESS)
+		return (-1);
+
+	currid = atoi(curridstr);
+
+	if (currid > 0 && currid < INT_MAX - 1 && currid > *topid)
+		*topid = currid;
+
+	free(curridstr);
+	return (0);
+}
+
+static boolean_t
+nwam_valid_wlanid(const char *name)
+{
+	long wlanid;
+	char *endptr;
+
+	wlanid = strtol(name, &endptr, 10);
+	if (wlanid == 0 && endptr == name)
+		return (B_FALSE);
+	if (wlanid <= 0 || wlanid >= INT_MAX)
+		return (B_FALSE);
+
+	if (*endptr == '\0')
+		return (B_TRUE);
+
+	return (B_FALSE);
+}
+
 nwam_error_t
 nwam_known_wlan_read(const char *name, uint64_t flags,
     nwam_known_wlan_handle_t *kwhp)
@@ -94,28 +159,21 @@
 nwam_known_wlan_create(const char *name, nwam_known_wlan_handle_t *kwhp)
 {
 	nwam_error_t err;
-	nwam_value_t priorityval = NULL;
 
 	assert(kwhp != NULL && name != NULL);
 
+	if (!nwam_valid_wlanid(name))
+		return (NWAM_INVALID_ARG);
+
 	if ((err = nwam_create(NWAM_OBJECT_TYPE_KNOWN_WLAN,
 	    NWAM_KNOWN_WLAN_CONF_FILE, name, kwhp)) != NWAM_SUCCESS)
 		return (err);
 
 	/*
-	 * Create new object list for known WLAN.  The initial priority is
-	 * also set.
+	 * Create new object list for known WLAN.
 	 */
-	if ((err = nwam_alloc_object_list(&((*kwhp)->nwh_data)))
-	    != NWAM_SUCCESS)
-		goto finish;
-	if ((err = nwam_value_create_uint64(0, &priorityval)) != NWAM_SUCCESS)
-		goto finish;
-	err = nwam_set_prop_value((*kwhp)->nwh_data,
-	    NWAM_KNOWN_WLAN_PROP_PRIORITY, priorityval);
+	err = nwam_alloc_object_list(&((*kwhp)->nwh_data));
 
-finish:
-	nwam_value_free(priorityval);
 	if (err != NWAM_SUCCESS) {
 		nwam_known_wlan_free(*kwhp);
 		*kwhp = NULL;
@@ -132,6 +190,11 @@
 nwam_error_t
 nwam_known_wlan_set_name(nwam_known_wlan_handle_t kwh, const char *name)
 {
+	assert(kwh != NULL && name != NULL);
+
+	if (!nwam_valid_wlanid(name))
+		return (NWAM_INVALID_ARG);
+
 	return (nwam_set_name(kwh, name));
 }
 
@@ -142,141 +205,18 @@
 }
 
 /*
- * Used to store wlan names/priorities for prioritized walk.
- */
-struct nwam_wlan_info {
-	char *wlan_name;
-	uint64_t wlan_priority;
-	boolean_t wlan_walked;
-};
-
-struct nwam_wlan_info_list {
-	struct nwam_wlan_info **list;
-	uint_t num_wlans;
-};
-
-/*
- * Used to read in each known WLAN name/priority.
- */
-static int
-get_wlans_cb(nwam_known_wlan_handle_t kwh, void *data)
-{
-	struct nwam_wlan_info_list *wil = data;
-	struct nwam_wlan_info **list = wil->list;
-	struct nwam_wlan_info **newlist = NULL;
-	nwam_error_t err;
-	nwam_value_t priorityval = NULL;
-	uint_t num_wlans = wil->num_wlans;
-
-	/* Reallocate WLAN list and allocate new info list element. */
-	if ((newlist = realloc(list,
-	    sizeof (struct nwam_wlan_info *) * ++num_wlans)) == NULL ||
-	    (newlist[num_wlans - 1] = calloc(1,
-	    sizeof (struct nwam_wlan_info))) == NULL) {
-		if (newlist != NULL)
-			free(newlist);
-		return (NWAM_NO_MEMORY);
-	}
-
-	/* Update list since realloc() may have relocated it */
-	wil->list = newlist;
-
-	/* Retrieve name/priority */
-	if ((err = nwam_known_wlan_get_name(kwh,
-	    &((newlist[num_wlans - 1])->wlan_name))) != NWAM_SUCCESS ||
-	    (err = nwam_known_wlan_get_prop_value(kwh,
-	    NWAM_KNOWN_WLAN_PROP_PRIORITY, &priorityval)) != NWAM_SUCCESS ||
-	    (err = nwam_value_get_uint64(priorityval,
-	    &((newlist[num_wlans - 1])->wlan_priority))) != NWAM_SUCCESS) {
-		free(newlist[num_wlans - 1]->wlan_name);
-		nwam_value_free(priorityval);
-		free(newlist[num_wlans - 1]);
-		return (err);
-	}
-	nwam_value_free(priorityval);
-
-	(newlist[num_wlans - 1])->wlan_walked = B_FALSE;
-
-	wil->num_wlans = num_wlans;
-
-	return (NWAM_SUCCESS);
-}
-
-/*
  * Some recursion is required here, since if _WALK_PRIORITY_ORDER is specified,
  * we need to first walk the list of known WLANs to retrieve names
  * and priorities, then utilize that list to carry out an in-order walk.
  */
 nwam_error_t
 nwam_walk_known_wlans(int(*cb)(nwam_known_wlan_handle_t, void *), void *data,
-    uint64_t flags, int *retp)
+    int *retp)
 {
-	nwam_known_wlan_handle_t kwh;
-	nwam_error_t err;
-	int ret = 0;
-
 	assert(cb != NULL);
 
-	if ((err = nwam_valid_flags(flags,
-	    NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER | NWAM_FLAG_BLOCKING))
-	    != NWAM_SUCCESS)
-		return (err);
-
-	if ((flags & NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER) != 0) {
-		struct nwam_wlan_info_list wil = { NULL, 0};
-		uint64_t iflags = flags &~
-		    NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER;
-		uint64_t minpriority;
-		int errval, i, j, minindex;
-
-		if (nwam_walk_known_wlans(get_wlans_cb, &wil, iflags, &errval)
-		    != NWAM_SUCCESS) {
-			err = (nwam_error_t)errval;
-			goto done;
-		}
-
-		err = NWAM_SUCCESS;
-
-		for (i = 0; i < wil.num_wlans; i++) {
-			/* Find lowest priority value not walked so far. */
-			minpriority = (uint64_t)-1;
-			for (j = 0; j < wil.num_wlans; j++) {
-				if (wil.list[j]->wlan_priority < minpriority &&
-				    !(wil.list[j]->wlan_walked)) {
-					minpriority =
-					    wil.list[j]->wlan_priority;
-					minindex = j;
-				}
-			}
-			wil.list[minindex]->wlan_walked = B_TRUE;
-			if ((err = nwam_known_wlan_read
-			    (wil.list[minindex]->wlan_name,
-			    iflags, &kwh)) != NWAM_SUCCESS) {
-				goto done;
-			}
-			ret = cb(kwh, data);
-			if (ret != 0) {
-				nwam_known_wlan_free(kwh);
-				err = NWAM_WALK_HALTED;
-				goto done;
-			}
-			nwam_known_wlan_free(kwh);
-		}
-done:
-		if (wil.list != NULL) {
-			for (j = 0; j < wil.num_wlans; j++) {
-				free(wil.list[j]->wlan_name);
-				free(wil.list[j]);
-			}
-			free(wil.list);
-		}
-		if (retp != NULL)
-			*retp = ret;
-		return (err);
-	}
-
 	return (nwam_walk(NWAM_OBJECT_TYPE_KNOWN_WLAN,
-	    NWAM_KNOWN_WLAN_CONF_FILE, cb, data, flags, retp, NULL));
+	    NWAM_KNOWN_WLAN_CONF_FILE, cb, data, 0, retp, NULL));
 }
 
 void
@@ -352,132 +292,38 @@
 	return (nwam_walk_props(kwh, cb, data, flags, retp));
 }
 
-struct priority_collision_data {
-	char *wlan_name;
-	uint64_t priority;
-};
-
-static int
-avoid_priority_collisions_cb(nwam_known_wlan_handle_t kwh, void *data)
-{
-	nwam_value_t priorityval;
-	nwam_error_t err;
-	struct priority_collision_data *pcd = data;
-	char *name;
-	uint64_t priority;
-
-	err = nwam_known_wlan_get_name(kwh, &name);
-	if (err != NWAM_SUCCESS)
-		return (err);
-	if (strcmp(name, pcd->wlan_name) == 0) {
-		/* skip to-be-updated wlan */
-		free(name);
-		return (NWAM_SUCCESS);
-	}
-	free(name);
-
-	err = nwam_known_wlan_get_prop_value(kwh, NWAM_KNOWN_WLAN_PROP_PRIORITY,
-	    &priorityval);
-	if (err != NWAM_SUCCESS)
-		return (err);
-	err = nwam_value_get_uint64(priorityval, &priority);
-	if (err != NWAM_SUCCESS)
-		return (err);
-	nwam_value_free(priorityval);
-
-	if (priority < pcd->priority)
-		return (NWAM_SUCCESS);
-
-	if (priority == pcd->priority) {
-		/* Two priority values collide.  Move this one up. */
-		err = nwam_value_create_uint64(priority + 1, &priorityval);
-		if (err != NWAM_SUCCESS)
-			return (err);
-		err = nwam_known_wlan_set_prop_value(kwh,
-		    NWAM_KNOWN_WLAN_PROP_PRIORITY, priorityval);
-		nwam_value_free(priorityval);
-		if (err != NWAM_SUCCESS) {
-			return (err);
-		}
-		/*
-		 * We are doing a walk, and will continue shifting until
-		 * we find a gap in the priority numbers; thus no need to
-		 * do collision checking here.
-		 */
-		err = nwam_known_wlan_commit(kwh,
-		    NWAM_FLAG_KNOWN_WLAN_NO_COLLISION_CHECK);
-		if (err != NWAM_SUCCESS)
-			return (err);
-
-		(pcd->priority)++;
-		return (NWAM_SUCCESS);
-	}
-
-	/*
-	 * Only possiblity left at this point is that we're looking
-	 * at a priority greater than the last one we wrote, so we've
-	 * found a gap.  We can halt the walk now.
-	 */
-	return (NWAM_WALK_HALTED);
-}
-
 nwam_error_t
-nwam_known_wlan_commit(nwam_known_wlan_handle_t kwh, uint64_t flags)
+nwam_known_wlan_commit(nwam_known_wlan_handle_t kwh)
 {
 	nwam_error_t err;
-	nwam_value_t priorityval;
-	int ret = 0;
-	struct priority_collision_data pcd;
 
 	assert(kwh != NULL && kwh->nwh_data != NULL);
 
 	if ((err = nwam_known_wlan_validate(kwh, NULL)) != NWAM_SUCCESS)
 		return (err);
 
-	/*
-	 * If the NO_COLLISION_CHECK flag is set, no need to check for
-	 * collision.
-	 */
-	if (flags & NWAM_FLAG_KNOWN_WLAN_NO_COLLISION_CHECK)
-		return (nwam_commit(NWAM_KNOWN_WLAN_CONF_FILE, kwh,
-		    (flags & NWAM_FLAG_GLOBAL_MASK) |
-		    NWAM_FLAG_ENTITY_KNOWN_WLAN));
-
-	/*
-	 * We need to do priority checking.  Walk the list, looking
-	 * for the first entry with priority greater than or equal
-	 * to the entry we're adding.  Commit the new one (without
-	 * doing additional checking), and then increment other
-	 * entries as needed.
-	 */
-	err = nwam_known_wlan_get_prop_value(kwh,
-	    NWAM_KNOWN_WLAN_PROP_PRIORITY, &priorityval);
-	if (err != NWAM_SUCCESS)
-		return (err);
-	err = nwam_value_get_uint64(priorityval, &(pcd.priority));
-	nwam_value_free(priorityval);
-	if (err != NWAM_SUCCESS)
-		return (err);
-	err = nwam_known_wlan_get_name(kwh, &(pcd.wlan_name));
-	if (err != NWAM_SUCCESS)
-		return (err);
-	err = nwam_walk_known_wlans(avoid_priority_collisions_cb, &pcd,
-	    NWAM_FLAG_KNOWN_WLAN_WALK_PRIORITY_ORDER, &ret);
-	free(pcd.wlan_name);
-	/*
-	 * a halted walk is okay, it just means we didn't have
-	 * to walk the entire list to resolve priorities
-	 */
-	if (ret != NWAM_SUCCESS && ret != NWAM_WALK_HALTED)
-		return (ret);
-
-	return (nwam_known_wlan_commit(kwh,
-	    flags | NWAM_FLAG_KNOWN_WLAN_NO_COLLISION_CHECK));
+	return (nwam_commit(NWAM_KNOWN_WLAN_CONF_FILE, kwh,
+	    NWAM_FLAG_ENTITY_KNOWN_WLAN));
 }
 
 nwam_error_t
 nwam_known_wlan_destroy(nwam_known_wlan_handle_t kwh, uint64_t flags)
 {
+	nwam_value_t keynval;
+
+	if (nwam_known_wlan_get_prop_value(kwh, NWAM_KNOWN_WLAN_PROP_KEYNAME,
+	    &keynval) == NWAM_SUCCESS) {
+		dladm_handle_t adm_handle;
+		char *keyname;
+
+		if (nwam_value_get_string(keynval, &keyname) == NWAM_SUCCESS &&
+		    dladm_open(&adm_handle) == DLADM_STATUS_OK) {
+			(void) dladm_unset_secobj(adm_handle, keyname,
+			    DLADM_OPT_PERSIST);
+			dladm_close(adm_handle);
+		}
+		nwam_value_free(keynval);
+	}
 	return (nwam_destroy(NWAM_KNOWN_WLAN_CONF_FILE, kwh,
 	    flags | NWAM_FLAG_ENTITY_KNOWN_WLAN));
 }
@@ -493,8 +339,27 @@
 /* Property-specific value validation functions should go here. */
 
 static nwam_error_t
-valid_keyname(nwam_value_t value)
+nwam_valid_ssid(nwam_value_t value)
 {
+	char *essid;
+	uint8_t len;
+
+	if (nwam_value_get_string(value, &essid) != NWAM_SUCCESS)
+		return (NWAM_ENTITY_INVALID_VALUE);
+
+	len = strnlen(essid, DLADM_WLAN_MAX_ESSID_LEN);
+	/* ssid can contain control chars */
+	if (len == 0 || len == DLADM_WLAN_MAX_ESSID_LEN)
+		return (NWAM_ENTITY_INVALID_VALUE);
+
+	return (NWAM_SUCCESS);
+}
+
+static nwam_error_t
+nwam_valid_secobj(nwam_value_t value)
+{
+	dladm_handle_t adm_handle;
+	secobj_class_info_t key_if;
 	char *keyname;
 
 	if (nwam_value_get_string(value, &keyname) != NWAM_SUCCESS)
@@ -503,42 +368,100 @@
 	if (!dladm_valid_secobj_name(keyname))
 		return (NWAM_ENTITY_INVALID_VALUE);
 
+	if (dladm_open(&adm_handle) != DLADM_STATUS_OK)
+		return (NWAM_ENTITY_INVALID_VALUE);
+
+	key_if.sc_name = keyname;
+	key_if.sc_dladmclass = 0;
+	if (dladm_walk_secobj(adm_handle, &key_if, find_matching_secobj,
+	    DLADM_OPT_PERSIST)) {
+		dladm_close(adm_handle);
+		return (NWAM_ENTITY_INVALID_VALUE);
+	}
+
+	dladm_close(adm_handle);
+
+	/* not found */
+	if (!dladm_valid_secobjclass(key_if.sc_dladmclass))
+		return (NWAM_ENTITY_INVALID_VALUE);
+
 	return (NWAM_SUCCESS);
 }
 
 static nwam_error_t
-valid_keyslot(nwam_value_t value)
+nwam_valid_priority(nwam_value_t value)
 {
-	uint64_t keyslot;
+	uint64_t priv_val;
 
-	if (nwam_value_get_uint64(value, &keyslot) != NWAM_SUCCESS)
+	if (nwam_valid_uint64(value) != NWAM_SUCCESS)
 		return (NWAM_ENTITY_INVALID_VALUE);
 
-	if (keyslot < 1 || keyslot > 4)
+	if (nwam_value_get_uint64(value, &priv_val) != NWAM_SUCCESS)
+		return (NWAM_ENTITY_INVALID_VALUE);
+
+	if (priv_val >= INT_MAX)
 		return (NWAM_ENTITY_INVALID_VALUE);
 
 	return (NWAM_SUCCESS);
 }
 
 static nwam_error_t
-valid_secmode(nwam_value_t value)
+nwam_valid_eapuser(nwam_value_t value)
 {
-	uint64_t secmode;
+	char *user;
+	char testbuf[DLADM_STRSIZE];
 
-	if (nwam_value_get_uint64(value, &secmode) != NWAM_SUCCESS)
+	(void) memset(testbuf, 0, sizeof (testbuf));
+	if (nwam_value_get_string(value, &user) != NWAM_SUCCESS)
+		return (NWAM_ENTITY_INVALID_VALUE);
+
+	if (dladm_str2identity(user, testbuf) != DLADM_STATUS_OK)
 		return (NWAM_ENTITY_INVALID_VALUE);
 
-	if (secmode != DLADM_WLAN_SECMODE_NONE &&
-	    secmode != DLADM_WLAN_SECMODE_WEP &&
-	    secmode != DLADM_WLAN_SECMODE_WPA)
+	return (NWAM_SUCCESS);
+}
+
+static nwam_error_t
+nwam_valid_certfile(nwam_value_t value)
+{
+	char *cert;
+	char testbuf[DLADM_STRSIZE];
+
+	if (nwam_value_get_string(value, &cert) != NWAM_SUCCESS)
+		return (NWAM_ENTITY_INVALID_VALUE);
+
+	if (dladm_str2crtname(cert, testbuf) != DLADM_STATUS_OK)
 		return (NWAM_ENTITY_INVALID_VALUE);
 
 	return (NWAM_SUCCESS);
 }
 
+static nwam_error_t
+nwam_valid_priv(nwam_value_t value)
+{
+	char *priv;
+	char testbuf[DLADM_STRSIZE];
+
+	if (nwam_value_get_string(value, &priv) != NWAM_SUCCESS)
+		return (NWAM_ENTITY_INVALID_VALUE);
+
+	if (dladm_str2crtname(priv, testbuf) != DLADM_STATUS_OK)
+		return (NWAM_ENTITY_INVALID_VALUE);
+
+	/*
+	 * TODO: when we add PKCS#11 cert. by reference support,
+	 * restrict success only to pk12 files *
+	 */
+	return (NWAM_SUCCESS);
+}
+
 nwam_error_t
 nwam_known_wlan_validate(nwam_known_wlan_handle_t kwh, const char **errpropp)
 {
+	/*
+	 * TODO: when we add PKCS#11 cert. by reference support,
+	 * evaluating known_wlan_prop_table is not enough.
+	 */
 	return (nwam_validate(known_wlan_prop_table, kwh, errpropp));
 }
 
@@ -560,12 +483,6 @@
 }
 
 nwam_error_t
-nwam_known_wlan_prop_multivalued(const char *propname, boolean_t *multip)
-{
-	return (nwam_prop_multivalued(known_wlan_prop_table, propname, multip));
-}
-
-nwam_error_t
 nwam_known_wlan_get_default_proplist(const char ***prop_list,
     uint_t *numvaluesp)
 {
@@ -574,282 +491,204 @@
 }
 
 /*
- * Add the given ESSID, BSSID, secmode, keyslot and key name to known WLANs.
+ * Add the given ESSID, BSSID, key name to known WLANs.
  * BSSID and keyname can be NULL.
+ * Default Priority Group is 1 for known wlans
+ * By default new Known Wlans are enabled
+ *
+ * We always add a new wlan unless ESSID, BSSID and secobj class are the same
  */
 nwam_error_t
-nwam_known_wlan_add_to_known_wlans(const char *essid, const char *bssid,
-    uint32_t secmode, uint_t keyslot, const char *keyname)
+nwam_known_wlan_add_to_known_wlans(dladm_handle_t dh, nwam_wlan_t *mywlan,
+    dladm_wlan_key_t *key_data, dladm_wlan_eap_t *eap_data,
+    const char **invalid_prop)
 {
 	nwam_known_wlan_handle_t kwh;
-	nwam_value_t keynameval = NULL, keyslotval = NULL, bssidsval = NULL;
-	nwam_value_t secmodeval = NULL, priorityval = NULL;
-	char **old_bssids = NULL, **new_bssids;
-	uint_t nelem = 0;
 	nwam_error_t err;
-	int i, j;
 
-	/*
-	 * Check if the given ESSID already exists as known WLAN.  If so,
-	 * add the BSSID to the bssids property.  If not, create one with
-	 * the given ESSID and add BSSID if given.
-	 */
-	err = nwam_known_wlan_read(essid, 0, &kwh);
+	nwam_value_t keynameval = NULL, bssidval = NULL, ssidval = NULL;
+	nwam_value_t identityval = NULL, anonval = NULL, ca_certval = NULL;
+	nwam_value_t cli_certval = NULL, privval = NULL;
 
-	switch (err) {
-	case NWAM_ENTITY_NOT_FOUND:
-		if ((err = nwam_known_wlan_create(essid, &kwh)) != NWAM_SUCCESS)
-			return (err);
-		/* New known WLAN - set priority to 0 */
-		if ((err = nwam_value_create_uint64(0, &priorityval))
-		    != NWAM_SUCCESS) {
-			nwam_known_wlan_free(kwh);
-			return (err);
-		}
-		err = nwam_known_wlan_set_prop_value(kwh,
-		    NWAM_KNOWN_WLAN_PROP_PRIORITY, priorityval);
-		nwam_value_free(priorityval);
-		if (err != NWAM_SUCCESS) {
-			nwam_known_wlan_free(kwh);
-			return (err);
-		}
-		/* If BSSID is NULL, nothing more to do here. */
-		if (bssid == NULL)
-			break;
-		if ((err = nwam_value_create_string((char *)bssid, &bssidsval))
-		    != NWAM_SUCCESS) {
-			nwam_known_wlan_free(kwh);
-			return (err);
-		}
-		/* Set the bssids property */
-		err = nwam_known_wlan_set_prop_value(kwh,
-		    NWAM_KNOWN_WLAN_PROP_BSSIDS, bssidsval);
-		nwam_value_free(bssidsval);
-		if (err != NWAM_SUCCESS) {
-			nwam_known_wlan_free(kwh);
-			return (err);
-		}
-		break;
-	case NWAM_SUCCESS:
-		/* If no bssid is specified, nothing to do */
-		if (bssid == NULL)
-			break;
+	int ret = -1;
+	uint32_t freewlanid = 1;
+	char wname[16];
+	char bssidstr[DLADM_WLAN_BSSID_LEN * 3];
+
+	if (mywlan == NULL)
+		return (NWAM_INVALID_ARG);
+
+	err = nwam_walk_known_wlans(find_highest_id, &freewlanid, &ret);
+	if (err != NWAM_SUCCESS)
+		return (err);
 
-		/* known WLAN exists, retrieve the existing bssids property */
-		err = nwam_known_wlan_get_prop_value(kwh,
-		    NWAM_KNOWN_WLAN_PROP_BSSIDS, &bssidsval);
-		if (err != NWAM_SUCCESS && err != NWAM_ENTITY_NOT_FOUND) {
-			nwam_known_wlan_free(kwh);
-			return (err);
-		}
-		if (err == NWAM_SUCCESS) {
-			if ((err = nwam_value_get_string_array(bssidsval,
-			    &old_bssids, &nelem)) != NWAM_SUCCESS) {
-				nwam_value_free(bssidsval);
-				nwam_known_wlan_free(kwh);
-				return (err);
-			}
-		}
-		/* Create a new array to append given BSSID */
-		new_bssids = calloc(nelem + 1, sizeof (char *));
-		if (new_bssids == NULL) {
-			nwam_value_free(bssidsval);
-			nwam_known_wlan_free(kwh);
-			return (NWAM_NO_MEMORY);
-		}
+	if (ret == -1)
+		return (NWAM_ENTITY_NOT_FOUND);
+
+	freewlanid++;
+
+	(void) snprintf(wname, sizeof (wname), "%u", freewlanid);
+
+	if ((err = nwam_known_wlan_create(wname, &kwh)) != NWAM_SUCCESS)
+		return (err);
 
-		/*
-		 * Copy over existing BSSIDs to the new array.  Also, check
-		 * to make sure that the given BSSID doesn't already exist
-		 * in the known WLAN.  If so, do abort copying and return
-		 * NWAM_SUCCESS.
-		 */
-		for (i = 0; i < nelem; i++) {
-			if (strcmp(old_bssids[i], bssid) == 0) {
-				/* nothing to do, so free up everything */
-				for (j = 0; j < i; j++)
-					free(new_bssids[j]);
-				free(new_bssids);
-				nwam_value_free(bssidsval);
-				goto set_key_info;
-			}
-			new_bssids[i] = strdup(old_bssids[i]);
-		}
-		new_bssids[nelem] = strdup(bssid);
-		nwam_value_free(bssidsval);
+	/* NWAM_KNOWN_WLAN_PROP_SSID	"ssid" */
 
-		err = nwam_value_create_string_array(new_bssids, nelem + 1,
-		    &bssidsval);
-		for (i = 0; i < nelem + 1; i++)
-			free(new_bssids[i]);
-		free(new_bssids);
-		if (err != NWAM_SUCCESS) {
-			nwam_known_wlan_free(kwh);
-			return (err);
-		}
-		/* Set the bssids property */
-		err = nwam_known_wlan_set_prop_value(kwh,
-		    NWAM_KNOWN_WLAN_PROP_BSSIDS, bssidsval);
-		nwam_value_free(bssidsval);
-		if (err != NWAM_SUCCESS) {
-			nwam_known_wlan_free(kwh);
-			return (err);
-		}
-		break;
-	default:
+	if ((err = nwam_value_create_string((char *)mywlan->nww_essid,
+	    &ssidval)) != NWAM_SUCCESS) {
+		nwam_known_wlan_free(kwh);
+		return (err);
+	}
+	err = nwam_known_wlan_set_prop_value(kwh, NWAM_KNOWN_WLAN_PROP_SSID,
+	    ssidval);
+	nwam_value_free(ssidval);
+	if (err != NWAM_SUCCESS) {
+		nwam_known_wlan_free(kwh);
 		return (err);
 	}
 
-set_key_info:
-	/* Set the security mode property */
-	if ((err = nwam_value_create_uint64(secmode, &secmodeval))
-	    != NWAM_SUCCESS) {
+	/* NWAM_KNOWN_WLAN_PROP_BSSID	"bssid" */
+
+	(void) dladm_wlan_bssid2str(mywlan->nww_bssid, bssidstr);
+	if ((err = nwam_value_create_string(bssidstr, &bssidval)) !=
+	    NWAM_SUCCESS) {
 		nwam_known_wlan_free(kwh);
 		return (err);
 	}
-	err = nwam_known_wlan_set_prop_value(kwh,
-	    NWAM_KNOWN_WLAN_PROP_SECURITY_MODE, secmodeval);
-	nwam_value_free(secmodeval);
-
+	err = nwam_known_wlan_set_prop_value(kwh, NWAM_KNOWN_WLAN_PROP_BSSID,
+	    bssidval);
+	nwam_value_free(bssidval);
 	if (err != NWAM_SUCCESS) {
 		nwam_known_wlan_free(kwh);
 		return (err);
 	}
 
-	if (keyname != NULL) {
-		if ((err = nwam_value_create_string((char *)keyname,
-		    &keynameval)) != NWAM_SUCCESS) {
-			nwam_known_wlan_free(kwh);
-			return (err);
-		}
-		err = nwam_known_wlan_set_prop_value(kwh,
-		    NWAM_KNOWN_WLAN_PROP_KEYNAME, keynameval);
-		nwam_value_free(keynameval);
-		if (err != NWAM_SUCCESS) {
+	/* NWAM_KNOWN_WLAN_PROP_KEYNAME	"keyname" */
+
+	if (key_data == NULL)
+		goto commit;
+
+	(void) snprintf(key_data->wk_name, DLADM_SECOBJ_NAME_MAX, "nwam-%s",
+	    wname);
+
+	{
+		dladm_status_t status = DLADM_STATUS_OK;
+		status = dladm_set_secobj(dh, key_data, DLADM_OPT_PERSIST);
+		if (status != DLADM_STATUS_OK) {
 			nwam_known_wlan_free(kwh);
-			return (err);
+			return (NWAM_ERROR_INTERNAL);
 		}
-		if ((err = nwam_value_create_uint64(keyslot,
-		    &keyslotval)) != NWAM_SUCCESS) {
-			nwam_known_wlan_free(kwh);
-			return (err);
-		}
-		err = nwam_known_wlan_set_prop_value(kwh,
-		    NWAM_KNOWN_WLAN_PROP_KEYSLOT, keyslotval);
-		nwam_value_free(keyslotval);
 	}
 
-	err = nwam_known_wlan_commit(kwh, 0);
-	nwam_known_wlan_free(kwh);
-
-	return (err);
-}
-
-/*
- * Remove the given BSSID/keyname from the bssids/keyname property for the
- * given ESSID.
- */
-nwam_error_t
-nwam_known_wlan_remove_from_known_wlans(const char *essid, const char *bssid,
-    const char *keyname)
-{
-	nwam_known_wlan_handle_t kwh;
-	nwam_value_t bssidsval;
-	char **old_bssids, **new_bssids;
-	uint_t nelem;
-	nwam_error_t err;
-	int i, found = -1;
-
-	/* Retrieve the existing bssids */
-	if ((err = nwam_known_wlan_read(essid, 0, &kwh)) != NWAM_SUCCESS)
-		return (err);
-	if ((err = nwam_known_wlan_get_prop_value(kwh,
-	    NWAM_KNOWN_WLAN_PROP_BSSIDS, &bssidsval)) != NWAM_SUCCESS) {
+	if ((err = nwam_value_create_string(key_data->wk_name, &keynameval))
+	    != NWAM_SUCCESS) {
 		nwam_known_wlan_free(kwh);
 		return (err);
 	}
-	if ((err = nwam_value_get_string_array(bssidsval, &old_bssids, &nelem))
-	    != NWAM_SUCCESS) {
-		nwam_value_free(bssidsval);
+	err = nwam_known_wlan_set_prop_value(kwh, NWAM_KNOWN_WLAN_PROP_KEYNAME,
+	    keynameval);
+	nwam_value_free(keynameval);
+	if (err != NWAM_SUCCESS) {
 		nwam_known_wlan_free(kwh);
 		return (err);
 	}
 
-	/* Cycle through the BSSIDs array to find the BSSID to remove */
-	for (i = 0; i < nelem; i++) {
-		if (strcmp(old_bssids[i], bssid)  == 0) {
-			found = i;
-			break;
-		}
-	}
+	if (eap_data == NULL)
+		goto commit;
 
-	/* Given BSSID was not found in the array */
-	if (found == -1) {
-		nwam_value_free(bssidsval);
-		nwam_known_wlan_free(kwh);
-		return (NWAM_INVALID_ARG);
-	}
+	/* NWAM_KNOWN_WLAN_PROP_EAP_USER	"identity" */
 
-	/* If removing the only BSSID entry, remove the bssids property */
-	if (nelem == 1) {
-		nwam_value_free(bssidsval);
-		if ((err = nwam_known_wlan_delete_prop(kwh,
-		    NWAM_KNOWN_WLAN_PROP_BSSIDS)) != NWAM_SUCCESS) {
-			nwam_known_wlan_free(kwh);
-			return (err);
-		}
-		err = nwam_known_wlan_commit(kwh, 0);
+	if ((err = nwam_value_create_string(eap_data->eap_user, &identityval))
+	    != NWAM_SUCCESS) {
 		nwam_known_wlan_free(kwh);
 		return (err);
 	}
-
-	new_bssids = calloc(nelem - 1, sizeof (char *));
-	if (new_bssids == NULL) {
-		nwam_value_free(bssidsval);
-		nwam_known_wlan_free(kwh);
-		return (NWAM_NO_MEMORY);
-	}
-
-	/* Copy over other BSSIDs */
-	for (i = 0; i < found; i++)
-		new_bssids[i] = strdup(old_bssids[i]);
-	for (i = found + 1; i < nelem; i++)
-		new_bssids[i-1] = strdup(old_bssids[i]);
-	nwam_value_free(bssidsval);
-
-	err = nwam_value_create_string_array(new_bssids, nelem - 1, &bssidsval);
-	for (i = 0; i < nelem - 1; i++)
-		free(new_bssids[i]);
-	free(new_bssids);
+	err = nwam_known_wlan_set_prop_value(kwh, NWAM_KNOWN_WLAN_PROP_EAP_USER,
+	    identityval);
+	nwam_value_free(identityval);
 	if (err != NWAM_SUCCESS) {
 		nwam_known_wlan_free(kwh);
 		return (err);
 	}
 
-	/* Set the bssids property */
-	err = nwam_known_wlan_set_prop_value(kwh, NWAM_KNOWN_WLAN_PROP_BSSIDS,
-	    bssidsval);
-	nwam_value_free(bssidsval);
-	if (err != NWAM_SUCCESS) {
-		nwam_known_wlan_free(kwh);
-		return (err);
-	}
+	/* NWAM_KNOWN_WLAN_PROP_EAP_ANON	"anonymous_identity" */
 
-	if (keyname != NULL) {
-		if ((err = nwam_known_wlan_delete_prop(kwh,
-		    NWAM_KNOWN_WLAN_PROP_KEYNAME)) != NWAM_SUCCESS) {
+	if (eap_data->eap_valid & DLADM_EAP_ATTR_ANON) {
+		if ((err = nwam_value_create_string(eap_data->eap_anon,
+		    &anonval)) != NWAM_SUCCESS) {
+			nwam_known_wlan_free(kwh);
+			return (err);
+		}
+		err = nwam_known_wlan_set_prop_value(kwh,
+		    NWAM_KNOWN_WLAN_PROP_EAP_ANON, anonval);
+		nwam_value_free(anonval);
+		if (err != NWAM_SUCCESS) {
 			nwam_known_wlan_free(kwh);
 			return (err);
 		}
-		if ((err = nwam_known_wlan_delete_prop(kwh,
-		    NWAM_KNOWN_WLAN_PROP_KEYSLOT)) != NWAM_SUCCESS) {
+	}
+
+	/* NWAM_KNOWN_WLAN_PROP_CA_CERT	"ca_cert" */
+
+	if (eap_data->eap_valid & DLADM_EAP_ATTR_CACERT) {
+		if ((err = nwam_value_create_string(eap_data->eap_ca_cert,
+		    &ca_certval)) != NWAM_SUCCESS) {
+			nwam_known_wlan_free(kwh);
+			return (err);
+		}
+		err = nwam_known_wlan_set_prop_value(kwh,
+		    NWAM_KNOWN_WLAN_PROP_CA_CERT, ca_certval);
+		nwam_value_free(ca_certval);
+		if (err != NWAM_SUCCESS) {
 			nwam_known_wlan_free(kwh);
 			return (err);
 		}
 	}
 
-	err = nwam_known_wlan_commit(kwh, 0);
+	/* NWAM_KNOWN_WLAN_PROP_PRIV	"private_key" */
+
+	if (eap_data->eap_valid & DLADM_EAP_ATTR_PRIV) {
+		if ((err = nwam_value_create_string(eap_data->eap_priv,
+		    &privval)) != NWAM_SUCCESS) {
+			nwam_known_wlan_free(kwh);
+			return (err);
+		}
+		err = nwam_known_wlan_set_prop_value(kwh,
+		    NWAM_KNOWN_WLAN_PROP_PRIV, privval);
+		nwam_value_free(privval);
+		if (err != NWAM_SUCCESS) {
+			nwam_known_wlan_free(kwh);
+			return (err);
+		}
+	}
+
+	/* NWAM_KNOWN_WLAN_PROP_CLI_CERT	"client_cert" */
+
+	if (eap_data->eap_valid & DLADM_EAP_ATTR_PRIV) {
+		if ((err = nwam_value_create_string(eap_data->eap_cli_cert,
+		    &cli_certval)) != NWAM_SUCCESS) {
+			nwam_known_wlan_free(kwh);
+			return (err);
+		}
+		err = nwam_known_wlan_set_prop_value(kwh,
+		    NWAM_KNOWN_WLAN_PROP_CLI_CERT, cli_certval);
+		nwam_value_free(cli_certval);
+		if (err != NWAM_SUCCESS) {
+			nwam_known_wlan_free(kwh);
+			return (err);
+		}
+	}
+
+commit:
+	if (nwam_known_wlan_validate(kwh, invalid_prop) != NWAM_SUCCESS) {
+		nwam_known_wlan_free(kwh);
+		return (err);
+	}
+
+	err = nwam_known_wlan_commit(kwh);
 	nwam_known_wlan_free(kwh);
 
+	mywlan->nww_wlanid = freewlanid;
+
 	return (err);
 }
--- a/usr/src/lib/libnwam/common/libnwam_priv.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libnwam/common/libnwam_priv.h	Wed May 29 08:31:24 2013 +0200
@@ -21,6 +21,7 @@
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 /*
@@ -59,8 +60,7 @@
 	NWAM_REQUEST_TYPE_PRIORITY_GROUP,
 	NWAM_REQUEST_TYPE_WLAN_SCAN,
 	NWAM_REQUEST_TYPE_WLAN_SCAN_RESULTS,
-	NWAM_REQUEST_TYPE_WLAN_SELECT,
-	NWAM_REQUEST_TYPE_WLAN_SET_KEY
+	NWAM_REQUEST_TYPE_WLAN_SELECT
 } nwam_request_type_t;
 
 /* Status returned by nwamd door */
@@ -104,14 +104,10 @@
 	/* Used for WLAN request/responses */
 	struct {
 		char nwdad_name[NWAM_MAX_NAME_LEN];
-		char nwdad_essid[NWAM_MAX_NAME_LEN];
-		char nwdad_bssid[NWAM_MAX_NAME_LEN];
-		uint32_t nwdad_security_mode;
-		char nwdad_key[NWAM_MAX_NAME_LEN];
-		uint_t nwdad_keyslot;
-		boolean_t nwdad_add_to_known_wlans;
+		nwam_wlan_t nwdad_wlans[NWAMD_MAX_NUM_WLANS];
 		uint_t nwdad_num_wlans;
-		nwam_wlan_t nwdad_wlans[NWAMD_MAX_NUM_WLANS];
+		dladm_wlan_key_t nwdad_key;
+		dladm_wlan_eap_t nwdad_eap;
 	} nwdad_wlan_info;
 
 } nwamd_door_arg_data_t;
--- a/usr/src/lib/libnwam/common/libnwam_util.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libnwam/common/libnwam_util.c	Wed May 29 08:31:24 2013 +0200
@@ -22,6 +22,7 @@
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #include <arpa/inet.h>
@@ -46,7 +47,6 @@
 
 #include "libnwam_impl.h"
 #include <libnwam_priv.h>
-#include <libnwam.h>
 
 /*
  * Utility functions for door access, common validation functions etc.
@@ -202,41 +202,32 @@
 }
 
 nwam_error_t
-nwam_request_wlan(nwam_request_type_t type, const char *name,
-    const char *essid, const char *bssid, uint32_t security_mode,
-    uint_t keyslot, const char *key, boolean_t add_to_known_wlans)
+nwam_request_wlan(nwam_request_type_t type, const char *linkname,
+    const nwam_wlan_t *mywlan, const dladm_wlan_key_t *key_data,
+    const dladm_wlan_eap_t *eap_data)
 {
 	nwamd_door_arg_t req;
 
-	assert(name != NULL);
+	assert(linkname != NULL);
+
+	(void) memset(&req, 0, sizeof (nwamd_door_arg_t));
 
 	req.nwda_type = type;
 
-	(void) strlcpy(req.nwda_data.nwdad_wlan_info.nwdad_name, name,
+	(void) strlcpy(req.nwda_data.nwdad_wlan_info.nwdad_name, linkname,
 	    sizeof (req.nwda_data.nwdad_wlan_info));
-	if (essid != NULL) {
-		(void) strlcpy(req.nwda_data.nwdad_wlan_info.nwdad_essid, essid,
-		    sizeof (req.nwda_data.nwdad_wlan_info.nwdad_essid));
-	} else {
-		req.nwda_data.nwdad_wlan_info.nwdad_essid[0] = '\0';
-	}
-	if (bssid != NULL) {
-		(void) strlcpy(req.nwda_data.nwdad_wlan_info.nwdad_bssid, bssid,
-		    sizeof (req.nwda_data.nwdad_wlan_info.nwdad_bssid));
-	} else {
-		req.nwda_data.nwdad_wlan_info.nwdad_bssid[0] = '\0';
-	}
-	if (key != NULL) {
-		(void) strlcpy(req.nwda_data.nwdad_wlan_info.nwdad_key, key,
-		    sizeof (req.nwda_data.nwdad_wlan_info.nwdad_key));
-		req.nwda_data.nwdad_wlan_info.nwdad_keyslot = keyslot;
-	} else {
-		req.nwda_data.nwdad_wlan_info.nwdad_key[0] = '\0';
-	}
+
+	if (mywlan != NULL)
+		(void) memcpy(&req.nwda_data.nwdad_wlan_info.nwdad_wlans[0],
+		    mywlan, sizeof (nwam_wlan_t));
 
-	req.nwda_data.nwdad_wlan_info.nwdad_security_mode = security_mode;
-	req.nwda_data.nwdad_wlan_info.nwdad_add_to_known_wlans =
-	    add_to_known_wlans;
+	if (key_data != NULL)
+		(void) memcpy(&req.nwda_data.nwdad_wlan_info.nwdad_key,
+		    key_data, sizeof (dladm_wlan_key_t));
+
+	if (eap_data != NULL)
+		(void) memcpy(&req.nwda_data.nwdad_wlan_info.nwdad_eap,
+		    eap_data, sizeof (dladm_wlan_eap_t));
 
 	return (send_msg_to_nwam(&req));
 }
@@ -366,12 +357,14 @@
 		return ("INFO");
 	case NWAM_EVENT_TYPE_WLAN_SCAN_REPORT:
 		return ("WLAN_SCAN_REPORT");
-	case NWAM_EVENT_TYPE_WLAN_NEED_CHOICE:
-		return ("WLAN_NEED_CHOICE");
-	case NWAM_EVENT_TYPE_WLAN_NEED_KEY:
-		return ("WLAN_NEED_KEY");
+	case NWAM_EVENT_TYPE_WLAN_ASSOCIATION_REPORT:
+		return ("WLAN_ASSOCIATION_REPORT");
+	case NWAM_EVENT_TYPE_WLAN_WRONG_KEY:
+		return ("WLAN_WRONG_KEY");
 	case NWAM_EVENT_TYPE_WLAN_CONNECTION_REPORT:
 		return ("WLAN_CONNECTION_REPORT");
+	case NWAM_EVENT_TYPE_WLAN_DISASSOCIATION_REPORT:
+		return ("WLAN_DISASSOCIATION_REPORT");
 	case NWAM_EVENT_TYPE_IF_ACTION:
 		return ("IF_ACTION");
 	case NWAM_EVENT_TYPE_IF_STATE:
@@ -434,14 +427,10 @@
 		return ("method/service executing");
 	case NWAM_AUX_STATE_ACTIVE:
 		return ("active");
-	case NWAM_AUX_STATE_LINK_WIFI_SCANNING:
-		return ("scanning for WiFi networks");
-	case NWAM_AUX_STATE_LINK_WIFI_NEED_SELECTION:
-		return ("need WiFi network selection");
-	case NWAM_AUX_STATE_LINK_WIFI_NEED_KEY:
-		return ("need WiFi security key");
-	case NWAM_AUX_STATE_LINK_WIFI_CONNECTING:
-		return ("connecting to WiFi network");
+	case NWAM_AUX_STATE_LINK_WIFI_ASSOCIATED:
+		return ("associated to Wifi AP");
+	case NWAM_AUX_STATE_LINK_WIFI_CONNECTED:
+		return ("connected to WiFi network");
 	case NWAM_AUX_STATE_IF_WAITING_FOR_ADDR:
 		return ("waiting for IP address to be set");
 	case NWAM_AUX_STATE_IF_DHCP_TIMED_OUT:
--- a/usr/src/lib/libnwam/common/libnwam_values.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libnwam/common/libnwam_values.c	Wed May 29 08:31:24 2013 +0200
@@ -29,7 +29,6 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/types.h>
-#include <libdlwlan.h>
 #include <libnvpair.h>
 
 #include "libnwam_impl.h"
@@ -64,6 +63,8 @@
 			free(value->nwv_values.nwv_string[i]);
 		free(value->nwv_values.nwv_string);
 		break;
+	default:
+		break;
 	}
 	free(value);
 }
@@ -719,14 +720,6 @@
 	{ NULL, 0 }
 };
 
-struct nwam_value_entry known_wlan_prop_security_mode_entries[] =
-{
-	{ "none", DLADM_WLAN_SECMODE_NONE },
-	{ "wep", DLADM_WLAN_SECMODE_WEP },
-	{ "wpa", DLADM_WLAN_SECMODE_WPA },
-	{ NULL, 0 }
-};
-
 struct nwam_prop_value_entry {
 	const char		*prop_name;
 	struct nwam_value_entry	*value_entries;
@@ -748,8 +741,6 @@
 	    loc_prop_nameservice_configsrc_entries },
 	{ NWAM_LOC_PROP_LDAP_NAMESERVICE_CONFIGSRC,
 	    loc_prop_nameservice_configsrc_entries },
-	{ NWAM_KNOWN_WLAN_PROP_SECURITY_MODE,
-	    known_wlan_prop_security_mode_entries },
 	{ NULL, NULL }
 };
 
@@ -862,12 +853,6 @@
 		object_type_string =
 		    NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN_STRING;
 		break;
-	case NWAM_CONDITION_OBJECT_TYPE_ESSID:
-		object_type_string = NWAM_CONDITION_OBJECT_TYPE_ESSID_STRING;
-		break;
-	case NWAM_CONDITION_OBJECT_TYPE_BSSID:
-		object_type_string = NWAM_CONDITION_OBJECT_TYPE_BSSID_STRING;
-		break;
 	default:
 		return (NWAM_INVALID_ARG);
 
@@ -881,15 +866,13 @@
 		break;
 	case NWAM_CONDITION_CONTAINS:
 		if (object_type != NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN &&
-		    object_type != NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN &&
-		    object_type != NWAM_CONDITION_OBJECT_TYPE_ESSID)
+		    object_type != NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN)
 			return (NWAM_INVALID_ARG);
 		condition_string = NWAM_CONDITION_CONTAINS_STRING;
 		break;
 	case NWAM_CONDITION_DOES_NOT_CONTAIN:
 		if (object_type != NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN &&
-		    object_type != NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN &&
-		    object_type != NWAM_CONDITION_OBJECT_TYPE_ESSID)
+		    object_type != NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN)
 			return (NWAM_INVALID_ARG);
 
 		condition_string = NWAM_CONDITION_DOES_NOT_CONTAIN_STRING;
@@ -923,8 +906,6 @@
 	case NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS:
 	case NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN:
 	case NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN:
-	case NWAM_CONDITION_OBJECT_TYPE_ESSID:
-	case NWAM_CONDITION_OBJECT_TYPE_BSSID:
 		(void) snprintf(string, NWAM_MAX_VALUE_LEN,
 		    "%s %s %s", object_type_string,
 		    condition_string, object_name);
@@ -980,12 +961,6 @@
 	else if (strcmp(object_type_string,
 	    NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN_STRING) == 0)
 		*object_typep = NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN;
-	else if (strcmp(object_type_string,
-	    NWAM_CONDITION_OBJECT_TYPE_ESSID_STRING) == 0)
-		*object_typep = NWAM_CONDITION_OBJECT_TYPE_ESSID;
-	else if (strcmp(object_type_string,
-	    NWAM_CONDITION_OBJECT_TYPE_BSSID_STRING) == 0)
-		*object_typep = NWAM_CONDITION_OBJECT_TYPE_BSSID;
 	else {
 		free(copy);
 		return (NWAM_INVALID_ARG);
@@ -1053,8 +1028,7 @@
 			if (*object_typep !=
 			    NWAM_CONDITION_OBJECT_TYPE_ADV_DOMAIN &&
 			    *object_typep !=
-			    NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN &&
-			    *object_typep != NWAM_CONDITION_OBJECT_TYPE_ESSID) {
+			    NWAM_CONDITION_OBJECT_TYPE_SYS_DOMAIN) {
 				free(copy);
 				free(*object_namep);
 				return (NWAM_INVALID_ARG);
@@ -1069,6 +1043,8 @@
 				return (NWAM_INVALID_ARG);
 			}
 			break;
+		default:
+			break;
 		}
 
 		if ((object_name = strtok_r(NULL, " \t", &lasts)) == NULL) {
@@ -1110,12 +1086,6 @@
 		/* FALLTHRU */
 	case NWAM_CONDITION_OBJECT_TYPE_IP_ADDRESS:
 		(*ratep)++;
-		/* FALLTHRU */
-	case NWAM_CONDITION_OBJECT_TYPE_BSSID:
-		(*ratep)++;
-		/* FALLTHRU */
-	case NWAM_CONDITION_OBJECT_TYPE_ESSID:
-		(*ratep)++;
 		break;
 	default:
 		return (NWAM_INVALID_ARG);
--- a/usr/src/lib/libnwam/common/libnwam_wlan.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libnwam/common/libnwam_wlan.c	Wed May 29 08:31:24 2013 +0200
@@ -22,6 +22,7 @@
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #include "libnwam_impl.h"
@@ -39,7 +40,7 @@
 nwam_wlan_scan(const char *linkname)
 {
 	return (nwam_request_wlan(NWAM_REQUEST_TYPE_WLAN_SCAN, linkname,
-	    NULL, NULL, 0, 0, NULL, B_FALSE));
+	    NULL, NULL, NULL));
 }
 
 /*
@@ -49,28 +50,16 @@
 nwam_wlan_get_scan_results(const char *linkname, uint_t *num_wlansp,
     nwam_wlan_t **wlansp)
 {
-	return (nwam_request_wlan_scan_results(linkname, num_wlansp,
-	    wlansp));
+	return (nwam_request_wlan_scan_results(linkname, num_wlansp, wlansp));
 }
 
 /*
  * Select specified WLAN <essid, bssid> for link linkname.
  */
 nwam_error_t
-nwam_wlan_select(const char *linkname, const char *essid, const char *bssid,
-    uint32_t secmode, boolean_t add_to_known_wlans)
+nwam_wlan_select(const char *linkname, const nwam_wlan_t *mywlan,
+    const dladm_wlan_key_t *key_data, const dladm_wlan_eap_t *eap_data)
 {
-	return (nwam_request_wlan(NWAM_REQUEST_TYPE_WLAN_SELECT,
-	    linkname, essid, bssid, secmode, 0, NULL, add_to_known_wlans));
+	return (nwam_request_wlan(NWAM_REQUEST_TYPE_WLAN_SELECT, linkname,
+	    mywlan, key_data, eap_data));
 }
-
-/*
- * Create/update security key for WLAN <essid, bssid>.
- */
-nwam_error_t
-nwam_wlan_set_key(const char *linkname, const char *essid, const char *bssid,
-    uint32_t secmode, uint_t keyslot, const char *key)
-{
-	return (nwam_request_wlan(NWAM_REQUEST_TYPE_WLAN_SET_KEY,
-	    linkname, essid, bssid, secmode, keyslot, key, B_FALSE));
-}
--- a/usr/src/lib/libnwam/common/mapfile-vers	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libnwam/common/mapfile-vers	Wed May 29 08:31:24 2013 +0200
@@ -176,15 +176,12 @@
 	nwam_known_wlan_set_prop_value;
 	nwam_known_wlan_validate_prop;
 	nwam_known_wlan_get_prop_type;
-	nwam_known_wlan_prop_multivalued;
 	nwam_known_wlan_get_prop_description;
 	nwam_known_wlan_get_default_proplist;
 	nwam_known_wlan_add_to_known_wlans;
-	nwam_known_wlan_remove_from_known_wlans;
 	nwam_wlan_scan;
 	nwam_wlan_get_scan_results;
 	nwam_wlan_select;
-	nwam_wlan_set_key;
 	nwam_events_init;
 	nwam_events_fini;
 	nwam_event_wait;
--- a/usr/src/lib/librstp/common/uid_stp.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/librstp/common/uid_stp.h	Wed May 29 08:31:24 2013 +0200
@@ -53,7 +53,7 @@
 #define BR_CFG_AGE_MODE     (1L << 6)
 #define BR_CFG_AGE_TIME     (1L << 7)
 #define BR_CFG_HOLD_TIME    (1L << 8)
-#define BR_CFG_ALL BR_CFG_STATE     | \
+#define BR_CFG_ALL (BR_CFG_STATE     | \
                    BR_CFG_PRIO      | \
                    BR_CFG_AGE       | \
                    BR_CFG_HELLO     | \
@@ -61,7 +61,7 @@
                    BR_CFG_FORCE_VER | \
                    BR_CFG_AGE_MODE  | \
                    BR_CFG_AGE_TIME  | \
-                   BR_CFG_HOLD_TIME
+                   BR_CFG_HOLD_TIME)
 
 typedef struct {
   /* service data */
@@ -128,13 +128,13 @@
 #define PT_CFG_DBG_SKIP_TX (1L << 17)
 #endif
 
-#define PT_CFG_ALL PT_CFG_STATE  | \
+#define PT_CFG_ALL (PT_CFG_STATE  | \
                    PT_CFG_COST   | \
                    PT_CFG_PRIO   | \
                    PT_CFG_P2P    | \
                    PT_CFG_EDGE   | \
                    PT_CFG_MCHECK | \
-                   PT_CFG_NON_STP                  
+                   PT_CFG_NON_STP)
 
 #define ADMIN_PORT_PATH_COST_AUTO   0
 
--- a/usr/src/lib/libsecdb/auth_attr.txt	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libsecdb/auth_attr.txt	Wed May 29 08:31:24 2013 +0200
@@ -91,8 +91,6 @@
 solaris.network.ilb.enable:::Network ILB Enable Configuration::help=NetworkILBenable.html
 solaris.network.interface.config:::Network Interface Configuration::help=NetworkInterfaceConfig.html
 solaris.network.link.security:::Link Security::help=LinkSecurity.html
-solaris.network.wifi.config:::Wifi Config::help=WifiConfig.html
-solaris.network.wifi.wep:::Wifi Wep::help=WifiWep.html
 solaris.network.vrrp:::Administer VRRP::help=NetworkVRRP.html
 #
 solaris.print.:::Printer Management::help=PrintHeader.html
--- a/usr/src/lib/libsecdb/help/auths/Makefile	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/lib/libsecdb/help/auths/Makefile	Wed May 29 08:31:24 2013 +0200
@@ -132,8 +132,6 @@
 	NetworkHeader.html \
 	NetworkVRRP.html \
 	NetworkInterfaceConfig.html \
-	WifiConfig.html \
-	WifiWep.html \
 	LinkSecurity.html \
 	IdmapRules.html \
 	SmfIdmapStates.html \
--- a/usr/src/lib/libsecdb/help/auths/WifiConfig.html	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-<HTML>
-
-<!--
-    Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
-    Use is subject to license terms.
-
-    CDDL HEADER START
-
-    The contents of this file are subject to the terms of the
-    Common Development and Distribution License, Version 1.0 only
-    (the "License").  You may not use this file except in compliance
-    with the License.
-
-    You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-    or http://www.opensolaris.org/os/licensing.
-    See the License for the specific language governing permissions
-    and limitations under the License.
-
-    When distributing Covered Code, include this CDDL HEADER in each
-    file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-    If applicable, add the following below this CDDL HEADER, with the
-    fields enclosed by brackets "[]" replaced with your own identifying
-    information: Portions Copyright [yyyy] [name of copyright owner]
-
-    CDDL HEADER END
--->
-<!-- SCCS keyword
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
--->
-
-<HEAD>
-<!--
-META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"
--->
-<!-- 
-META NAME="GENERATOR" CONTENT="Mozilla/4.02 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]"
--->
-</HEAD>
-<BODY>
-When Wifi Config is in the Authorizations Included column, it grants permission to manage all the parameters of the wifi interface apart from wep key using wificonfig(1m) command.
-<p>
-If Wifi Config is grayed, then you are not entitled to Add or Remove this authorization.
-<BR>&nbsp;
-</BODY>
-</HTML>
--- a/usr/src/lib/libsecdb/help/auths/WifiWep.html	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-<HTML>
-
-<!--
-    Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
-    Use is subject to license terms.
-
-    CDDL HEADER START
-
-    The contents of this file are subject to the terms of the
-    Common Development and Distribution License, Version 1.0 only
-    (the "License").  You may not use this file except in compliance
-    with the License.
-
-    You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-    or http://www.opensolaris.org/os/licensing.
-    See the License for the specific language governing permissions
-    and limitations under the License.
-
-    When distributing Covered Code, include this CDDL HEADER in each
-    file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-    If applicable, add the following below this CDDL HEADER, with the
-    fields enclosed by brackets "[]" replaced with your own identifying
-    information: Portions Copyright [yyyy] [name of copyright owner]
-
-    CDDL HEADER END
--->
-<!-- SCCS keyword
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
--->
-
-<HEAD>
-<!--
-META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1"
--->
-<!-- 
-META NAME="GENERATOR" CONTENT="Mozilla/4.02 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]"
--->
-</HEAD>
-<BODY>
-When Wifi Wep is in the Authorizations Included column, it grants permission to configurate the wep key of the wifi interface using the wificonfig(1m) command.
-<p>
-If Wifi Wep is grayed, then you are not entitled to Add or Remove this authorization.
-<BR>&nbsp;
-</BODY>
-</HTML>
--- a/usr/src/man/man1m/Makefile	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/man/man1m/Makefile	Wed May 29 08:31:24 2013 +0200
@@ -572,8 +572,6 @@
 	 	 	wanboot_p12split.1m	\
 	 	 	wanbootutil.1m		\
 	 	 	whodo.1m		\
-	 	 	wificonfig.1m		\
-	 	 	wpad.1m			\
 	 	 	wracct.1m		\
 	 	 	wusbadm.1m		\
 	 	 	ypbind.1m		\
--- a/usr/src/man/man1m/dladm.1m	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/man/man1m/dladm.1m	Wed May 29 08:31:24 2013 +0200
@@ -1,27 +1,27 @@
-'\" te
 .\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved
+.\" Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
 .\" Sun Microsystems, Inc. gratefully acknowledges The Open Group for permission to reproduce portions of its copyrighted documentation. Original documentation from The Open Group can be obtained online at http://www.opengroup.org/bookstore/.
 .\" The Institute of Electrical and Electronics Engineers and The Open Group, have given us permission to reprint portions of their documentation. In the following statement, the phrase "this text" refers to portions of the system documentation. Portions of this text
 .\" are reprinted and reproduced in electronic form in the Sun OS Reference Manual, from IEEE Std 1003.1, 2004 Edition, Standard for Information Technology -- Portable Operating System Interface (POSIX), The Open Group Base Specifications Issue 6, Copyright (C) 2001-2004 by the Institute of Electrical
 .\" and Electronics Engineers, Inc and The Open Group. In the event of any discrepancy between these versions and the original IEEE and The Open Group Standard, the original IEEE and The Open Group Standard is the referee document. The original Standard can be obtained online at http://www.opengroup.org/unix/online.html.
-.\"  This notice shall appear on any product containing this material.
+.\" This notice shall appear on any product containing this material.
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License"). You may not use this file except in compliance with the License. You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.
 .\" See the License for the specific language governing permissions and limitations under the License. When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE. If applicable, add the following below this CDDL HEADER, with the
 .\" fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH DLADM 1M "Sep 23, 2009"
+.TH DLADM 1M "Nov 15, 2012"
 .SH NAME
-dladm \- administer data links
+dladm - administer data links
 .SH SYNOPSIS
 .LP
 .nf
-\fBdladm show-link\fR [\fB-P\fR] [\fB-s\fR [\fB-i\fR \fIinterval\fR]] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]] [\fIlink\fR]
+\fBdladm show-link\fR [\fB-P\fR] [\fB-s\fR [\fB-i\fR \fIinterval\fR]] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,\fIfield\fR]...] [\fIlink\fR]
 \fBdladm rename-link\fR [\fB-R\fR \fIroot-dir\fR] \fIlink\fR \fInew-link\fR
 .fi
 
 .LP
 .nf
 \fBdladm delete-phys\fR \fIphys-link\fR
-\fBdladm show-phys\fR [\fB-P\fR] [\fB-m\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]] [\fB-H\fR] [\fIphys-link\fR]
+\fBdladm show-phys\fR [\fB-P\fR] [\fB-m\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,\fIfield\fR]...] [\fB-H\fR] [\fIphys-link\fR]
 .fi
 
 .LP
@@ -35,7 +35,7 @@
      \fIaggr-link\fR
 \fBdladm remove-aggr\fR [\fB-t\fR] [\fB-R\fR \fIroot-dir\fR] \fB-l\fR \fIether-link1\fR [\fB-l\fR \fIether-link2\fR...]
      \fIaggr-link\fR
-\fBdladm show-aggr\fR [\fB-PLx\fR] [\fB-s\fR [\fB-i\fR \fIinterval\fR]] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]]
+\fBdladm show-aggr\fR [\fB-PLx\fR] [\fB-s\fR [\fB-i\fR \fIinterval\fR]] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,\fIfield\fR]...]
      [\fIaggr-link\fR]
 .fi
 
@@ -78,36 +78,40 @@
 .nf
 \fBdladm create-vlan\fR [\fB-ft\fR] [\fB-R\fR \fIroot-dir\fR] \fB-l\fR \fIether-link\fR \fB-v\fR \fIvid\fR [\fIvlan-link\fR]
 \fBdladm delete-vlan\fR [\fB-t\fR] [\fB-R\fR \fIroot-dir\fR] \fIvlan-link\fR
-\fBdladm show-vlan\fR [\fB-P\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]] [\fIvlan-link\fR]
+\fBdladm show-vlan\fR [\fB-P\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,\fIfield\fR]...] [\fIvlan-link\fR]
 .fi
 
 .LP
 .nf
-\fBdladm scan-wifi\fR [[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]] [\fIwifi-link\fR]
-\fBdladm connect-wifi\fR [\fB-e\fR \fIessid\fR] [\fB-i\fR \fIbssid\fR] [\fB-k\fR \fIkey\fR,...]
-     [\fB-s\fR none | wep | wpa ] [\fB-a\fR open | shared] [\fB-b\fR bss | ibss] [\fB-c\fR]
-     [\fB-m\fR a | b | g] [\fB-T\fR \fItime\fR] [\fIwifi-link\fR]
+\fBdladm scan-wifi\fR \fIwifi-link\fR
+\fBdladm connect-wifi\fR [\fB-e\fR \fIessid\fR] [\fB-k\fR \fIsecobj_name\fR,..]
+     [\fB-b\fR \fIbssid\fR] [\fB-i\fR ESS | IBSS]
+     [\fB-U\fR \fIusername\fR] [\fB-N\fR \fIanon_identity\fR]
+     [\fB-A\fR \fICA_Cert_filename\fR]
+     [\fB-C\fR \fIClient_Cert_filename\fR]
+     [\fB-K\fR \fIPrivate_Key_filename\fR]
+     [\fIwifi-link\fR]
 \fBdladm disconnect-wifi\fR [\fB-a\fR] [\fIwifi-link\fR]
-\fBdladm show-wifi\fR [[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]] [\fIwifi-link\fR]
+\fBdladm show-wifi\fR [\fIwifi-link\fR]
 .fi
 
 .LP
 .nf
-\fBdladm show-ether\fR [\fB-x\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]] [\fIether-link\fR]
+\fBdladm show-ether\fR [\fB-x\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,\fIfield\fR]...] [\fIether-link\fR]
 .fi
 
 .LP
 .nf
 \fBdladm set-linkprop\fR [\fB-t\fR] [\fB-R\fR \fIroot-dir\fR] \fB-p\fR \fIprop\fR=\fIvalue\fR[,...] \fIlink\fR
 \fBdladm reset-linkprop\fR [\fB-t\fR] [\fB-R\fR \fIroot-dir\fR] [\fB-p\fR \fIprop\fR[,...]] \fIlink\fR
-\fBdladm show-linkprop\fR [\fB-P\fR] [[\fB-c\fR] \fB-o\fR \fIfield\fR[,...]] [\fB-p\fR \fIprop\fR[,...]] [\fIlink\fR]
+\fBdladm show-linkprop\fR [\fB-P\fR] [[\fB-c\fR] \fB-o\fR \fIfield\fR[,\fIfield\fR]...] [\fB-p\fR \fIprop\fR[,...]] [\fIlink\fR]
 .fi
 
 .LP
 .nf
 \fBdladm create-secobj\fR [\fB-t\fR] [\fB-R\fR \fIroot-dir\fR] [\fB-f\fR \fIfile\fR] \fB-c\fR \fIclass\fR \fIsecobj\fR
 \fBdladm delete-secobj\fR [\fB-t\fR] [\fB-R\fR \fIroot-dir\fR] \fIsecobj\fR[,...]
-\fBdladm show-secobj\fR [\fB-P\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]] [\fIsecobj\fR,...]
+\fBdladm show-secobj\fR [\fB-t\fR] [\fB-R\fR \fIroot-dir\fR] [[\fB-p\fR] [\fB-o\fR \fIfield\fR,...] [\fIsecobj\fR,...]
 .fi
 
 .LP
@@ -116,7 +120,7 @@
      {factory \fB-n\fR \fIslot-identifier\fR]} | {random [\fB-r\fR \fIprefix\fR]}]
      [\fB-v\fR \fIvlan-id\fR] [\fB-p\fR \fIprop\fR=\fIvalue\fR[,...]] \fIvnic-link\fR
 \fBdladm delete-vnic\fR [\fB-t\fR] [\fB-R\fR \fIroot-dir\fR] \fIvnic-link\fR
-\fBdladm show-vnic\fR [\fB-pP\fR] [\fB-s\fR [\fB-i\fR \fIinterval\fR]] [\fB-o\fR \fIfield\fR[,...]]
+\fBdladm show-vnic\fR [\fB-pP\fR] [\fB-s\fR [\fB-i\fR \fIinterval\fR]] [\fB-o\fR \fIfield\fR[,\fIfield\fR]...]
      [\fB-l\fR \fIlink\fR] [\fIvnic-link\fR]
 .fi
 
@@ -133,7 +137,7 @@
      \fIiptun-link\fR
 \fBdladm modify-iptun\fR [\fB-t\fR] [\fB-R\fR \fIroot-dir\fR] [\fB-s\fR \fItsrc\fR] [\fB-d\fR \fItdst\fR] \fIiptun-link\fR
 \fBdladm delete-iptun\fR [\fB-t\fR] [\fB-R\fR \fIroot-dir\fR] \fIiptun-link\fR
-\fBdladm show-iptun\fR [\fB-P\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]] [\fIiptun-link\fR]
+\fBdladm show-iptun\fR [\fB-P\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,\fIfield\fR]...] [\fIiptun-link\fR]
 .fi
 
 .LP
@@ -216,7 +220,7 @@
 .ad
 .sp .6
 .RS 4n
-A WiFi datalink.
+A Wireless datalink.
 .RE
 
 .sp
@@ -291,9 +295,10 @@
 .sp .6
 .RS 4n
 A secure object, identified by an administratively-chosen name. The name can
-use any alphanumeric characters, as well as underscore (\fB_\fR), period
-(\fB\&.\fR), and hyphen (\fB-\fR). A secure object name can be at most 32
-characters.
+use any alphanumeric characters (a-z, A-Z, 0-9),
+as well as underscore (\fB_\fR), period (\fB\&.\fR),
+semicolon (\fB:\fR) and hyphen (\fB-\fR).
+A secure object name can be at most 31 characters.
 .RE
 
 .SS "Options"
@@ -320,7 +325,7 @@
 .ne 2
 .na
 \fB\fBdladm show-link\fR [\fB-P\fR] [\fB-s\fR [\fB-i\fR \fIinterval\fR]]
-[[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]][\fIlink\fR]\fR
+[[\fB-p\fR] \fB-o\fR \fIfield\fR[,\fIfield\fR]...][\fIlink\fR]\fR
 .ad
 .sp .6
 .RS 4n
@@ -330,7 +335,7 @@
 .sp
 .ne 2
 .na
-\fB\fB-o\fR \fIfield\fR[,...], \fB--output\fR=\fIfield\fR[,...]\fR
+\fB\fB-o\fR \fIfield\fR[,\fIfield\fR]..., \fB--output\fR=\fIfield\fR[,\fIfield\fR]...\fR
 .ad
 .sp .6
 .RS 4n
@@ -551,6 +556,9 @@
 .sp .6
 .RS 4n
 Display link statistics.
+If the link is a wifi link and the \fB-i\fR flag is omitted, link statistics
+
+include MIB (management information base) fields.
 .RE
 
 .sp
@@ -606,7 +614,7 @@
 .sp
 .ne 2
 .na
-\fB\fBdladm show-phys\fR [\fB-P\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]]
+\fB\fBdladm show-phys\fR [\fB-P\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,\fIfield\fR]...]
 [\fB-H\fR] [\fIphys-link\fR]\fR
 .ad
 .sp .6
@@ -1154,7 +1162,7 @@
 .ne 2
 .na
 \fB\fBdladm show-aggr\fR [\fB-PLx\fR] [\fB-s\fR [\fB-i\fR \fIinterval\fR]]
-[[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]] [\fIaggr-link\fR]\fR
+[[\fB-p\fR] \fB-o\fR \fIfield\fR[,\fIfield\fR]...] [\fIaggr-link\fR]\fR
 .ad
 .sp .6
 .RS 4n
@@ -1415,7 +1423,7 @@
 .sp
 .ne 2
 .na
-\fB\fB-o\fR \fIfield\fR[,...], \fB--output\fR=\fIfield\fR[,...]\fR
+\fB\fB-o\fR \fIfield\fR[,\fIfield\fR]..., \fB--output\fR=\fIfield\fR[,\fIfield\fR]...\fR
 .ad
 .sp .6
 .RS 4n
@@ -1755,7 +1763,7 @@
 .sp
 .ne 2
 .na
-\fB\fB-o\fR \fIfield\fR[,...], \fB--output\fR=\fIfield\fR[,...]\fR
+\fB\fB-o\fR \fIfield\fR[,\fIfield\fR]..., \fB--output\fR=\fIfield\fR[,\fIfield\fR]...\fR
 .ad
 .sp .6
 .RS 4n
@@ -2460,7 +2468,7 @@
 .sp
 .ne 2
 .na
-\fB\fBdladm show-vlan\fR [\fB-P\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]]
+\fB\fBdladm show-vlan\fR [\fB-P\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,\fIfield\fR]...]
 [\fIvlan-link\fR]\fR
 .ad
 .sp .6
@@ -2471,7 +2479,7 @@
 .sp
 .ne 2
 .na
-\fB\fB-o\fR \fIfield\fR[,...], \fB--output\fR=\fIfield\fR[,...]\fR
+\fB\fB-o\fR \fIfield\fR[,\fIfield\fR]..., \fB--output\fR=\fIfield\fR[,\fIfield\fR]...\fR
 .ad
 .sp .6
 .RS 4n
@@ -2570,45 +2578,16 @@
 .sp
 .ne 2
 .na
-\fB\fBdladm scan-wifi\fR [[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]]
-[\fIwifi-link\fR]\fR
-.ad
-.sp .6
-.RS 4n
-Scans for \fBWiFi\fR networks, either on all \fBWiFi\fR links, or just on the
-specified \fIwifi-link\fR.
-.sp
-By default, currently all fields but \fBBSSTYPE\fR are displayed.
-.sp
-.ne 2
-.na
-\fB\fB-o\fR \fIfield\fR[,...], \fB--output\fR=\fIfield\fR[,...]\fR
-.ad
-.sp .6
-.RS 4n
-A case-insensitive, comma-separated list of output fields to display. The field
-name must be one of the fields listed below, or the special value \fBall\fR to
-display all fields. For each \fBWiFi\fR network found, the following fields can
-be displayed:
-.sp
-.ne 2
-.na
-\fB\fBLINK\fR\fR
-.ad
-.sp .6
-.RS 4n
-The name of the link the \fBWiFi\fR network is on.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBESSID\fR\fR
-.ad
-.sp .6
-.RS 4n
-The \fBESSID\fR (name) of the \fBWiFi\fR network.
-.RE
+\fB\fBdladm scan-wifi\fR \fIwifi-link\fR
+
+.ad
+.sp .6
+.RS 4n
+Scans for \fBWiFi\fR networks on the specified \fIwifi-link\fR.
+.sp
+By default currently all fields are displayed.
+.sp
+.ne 2
 
 .sp
 .ne 2
@@ -2625,23 +2604,11 @@
 .sp
 .ne 2
 .na
-\fB\fBSEC\fR\fR
-.ad
-.sp .6
-.RS 4n
-Either \fBnone\fR for a \fBWiFi\fR network that uses no security, \fBwep\fR for
-a \fBWiFi\fR network that requires WEP (Wired Equivalent Privacy), or \fBwpa\fR
-for a WiFi network that requires WPA (Wi-Fi Protected Access).
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBMODE\fR\fR
-.ad
-.sp .6
-.RS 4n
-The supported connection modes: one or more of \fBa\fR, \fBb\fR, or \fBg\fR.
+\fB\fBCHANNEL\fR\fR
+.ad
+.sp .6
+.RS 4n
+The 802.11 channel on which the WiFi station is operating.
 .RE
 
 .sp
@@ -2651,8 +2618,8 @@
 .ad
 .sp .6
 .RS 4n
-The strength of the signal: one of \fBexcellent\fR, \fBvery good\fR,
-\fBgood\fR, \fBweak\fR, or \fBvery weak\fR.
+The strength of the signal: this is a value between 0 and 127.
+It is device driver dependent. For some devices its range is from 0 to 100.
 .RE
 
 .sp
@@ -2668,56 +2635,51 @@
 .sp
 .ne 2
 .na
-\fB\fBBSSTYPE\fR\fR
-.ad
-.sp .6
-.RS 4n
-Either \fBbss\fR for \fBBSS\fR (infrastructure) networks, or \fBibss\fR for
-\fBIBSS\fR (ad-hoc) networks.
-.RE
-
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-p\fR, \fB--parseable\fR\fR
-.ad
-.sp .6
-.RS 4n
-Display using a stable machine-parseable format. The \fB-o\fR option is
-required with \fB-p\fR. See "Parseable Output Format", below.
-.RE
-
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBdladm connect-wifi\fR [\fB-e\fR \fIessid\fR] [\fB-i\fR \fIbssid\fR]
-[\fB-k\fR \fIkey\fR,...] [\fB-s\fR \fBnone\fR | \fBwep\fR | \fBwpa\fR]
-[\fB-a\fR \fBopen\fR|\fBshared\fR] [\fB-b\fR \fBbss\fR|\fBibss\fR] [\fB-c\fR]
-[\fB-m\fR \fBa\fR|\fBb\fR|\fBg\fR] [\fB-T\fR \fItime\fR] [\fIwifi-link\fR]\fR
-.ad
-.sp .6
-.RS 4n
-Connects to a \fBWiFi\fR network. This consists of four steps: \fIdiscovery\fR,
-\fIfiltration\fR, \fIprioritization\fR, and \fIassociation\fR. However, to
-enable connections to non-broadcast \fBWiFi\fR networks and to improve
-performance, if a \fBBSSID\fR or \fBESSID\fR is specified using the \fB-e\fR or
-\fB-i\fR options, then the first three steps are skipped and \fBconnect-wifi\fR
-immediately attempts to associate with a \fBBSSID\fR or \fBESSID\fR that
-matches the rest of the provided parameters. If this association fails, but
-there is a possibility that other networks matching the specified criteria
-exist, then the traditional discovery process begins as specified below.
-.sp
-The discovery step finds all available \fBWiFi\fR networks on the specified
-WiFi link, which must not yet be connected. For administrative convenience, if
-there is only one \fBWiFi\fR link on the system, \fIwifi-link\fR can be
-omitted.
-.sp
-Once discovery is complete, the list of networks is filtered according to the
-value of the following options:
+\fB\fBESSID\fR\fR
+.ad
+.sp .6
+.RS 4n
+The \fBESSID\fR (name) of the \fBWiFi\fR network.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fSECMODE\fR\fR
+.ad
+.sp .6
+.RS 4n
+This string shows the key management method of the \fBWiFi\fR network.
+Additionally it shows the authentication algorithm (Open/Shared)
+and the BSS type (ESS for AP infrastructure mode or IBSS for adhoc mode).
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fBdladm connect-wifi\fR [\fB-e\fR \fIessid\fR] [\fB-k\fR \fIsecobj_name\fR,...]
+[\fB-b\fR \fIbssid\fR] [\fB-i\fR \fIESS\fR | \fIIBSS\fR]
+[\fB-U\fR \fIidentity\fR] [\fB-N\fR \fIanon_identity\fR]
+[\fB-A\fR \fICA_Cert_filename\fR]
+[\fB-C\fR \fIClient_Cert_filename\fR]
+[\fB-K\fR \fIPrivate_Key_filename\fR]
+[\fIwifi-link\fR]\fR
+.ad
+.sp .6
+.RS 4n
+Connects to a \fBWiFi\fR network. If association fails, dladm reports errors.
+These errors can show the reason why the association failed, for example a
+wrong password, an authentication timeout, etc...
+.sp
+By default, the user should specify a network listed in the last scan results.
+Otherwise dladm searches among all available \fBWiFi\fR networks on the specified
+WiFi link, which must not yet be connected, and searches an unsecured network.
+Dladm based on the other parameters provided by the user selects a suitable AP.
+Dladm associates with APs using the security policy of the specified secobj
+(\fB-k\fR \fIsecobj_name\fR), \fIESSID\fR and \fIBSSID\fR;
+The \fIBSSID\fR can be used to connect with AP not broadcasting their SSIDs.
+For administrative convenience, if there is only one \fBWiFi\fR link on the
+system, \fIwifi-link\fR can be omitted.
 .sp
 .ne 2
 .na
@@ -2725,91 +2687,40 @@
 .ad
 .sp .6
 .RS 4n
-Networks that do not have the same \fIessid\fR are filtered out.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-b\fR \fBbss\fR|\fBibss\fR, \fB--bsstype\fR=\fBbss\fR|\fBibss\fR\fR
-.ad
-.sp .6
-.RS 4n
-Networks that do not have the same \fBbsstype\fR are filtered out.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-m\fR \fBa\fR|\fBb\fR|\fBg\fR, \fB--mode\fR=\fBa\fR|\fBb\fR|\fBg\fR\fR
-.ad
-.sp .6
-.RS 4n
-Networks not appropriate for the specified 802.11 mode are filtered out.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-k\fR \fIkey,...\fR, \fB--key\fR=\fIkey, ...\fR\fR
-.ad
-.sp .6
-.RS 4n
-Use the specified \fBsecobj\fR named by the key to connect to the network.
-Networks not appropriate for the specified keys are filtered out.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-s\fR \fBnone\fR|\fBwep\fR|\fBwpa\fR,
-\fB--sec\fR=\fBnone\fR|\fBwep\fR|\fBwpa\fR\fR
-.ad
-.sp .6
-.RS 4n
-Networks not appropriate for the specified security mode are filtered out.
-.RE
-
-Next, the remaining networks are prioritized, first by signal strength, and
-then by maximum speed. Finally, an attempt is made to associate with each
-network in the list, in order, until one succeeds or no networks remain.
-.sp
-In addition to the options described above, the following options also control
-the behavior of \fBconnect-wifi\fR:
-.sp
-.ne 2
-.na
-\fB\fB-a\fR \fBopen\fR|\fBshared\fR, \fB--auth\fR=\fBopen\fR|\fBshared\fR\fR
-.ad
-.sp .6
-.RS 4n
-Connect using the specified authentication mode. By default, \fBopen\fR and
-\fBshared\fR are tried in order.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-c\fR, \fB--create-ibss\fR\fR
-.ad
-.sp .6
-.RS 4n
-Used with \fB-b ibss\fR to create a new ad-hoc network if one matching the
-specified \fBESSID\fR cannot be found. If no \fBESSID\fR is specified, then
-\fB-c -b ibss\fR always triggers the creation of a new ad-hoc network.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-T\fR \fItime\fR, \fB--timeout\fR=\fItime\fR\fR
-.ad
-.sp .6
-.RS 4n
-Specifies the number of seconds to wait for association to succeed. If
-\fItime\fR is \fBforever\fR, then the associate will wait indefinitely. The
-current default is ten seconds, but this might change in the future. Timeouts
-shorter than the default might not succeed reliably.
+SSID of the WiFi network. Network name ASCII string (max 31 chars).
+ESSID is mandatory if this is not an unsecured network.
+It must be specified if a secobj name is provided.
+It must be the exact string printed in scan results, otherwise dladm will not
+find the network in scan results and print eventually an association timeout.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-b\fR \fIbssid\fR, \fB--bssid\fR=\fIbssid\fR\fR
+.ad
+.sp .6
+.RS 4n
+If specified, dladm will associate only with APs with the given BSSID.
+If the AP does not broadcast its SSID the BSSID should be specified.
+Note: BSSID property does not control the BSSID used when creating an Ad-Hoc
+network. The original device BSSID is used in that case.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-b\fR \fBESS\fR|\fBIBSS\fR, \fB--bsstype\fR=\fBESS\fR|\fBIBSS\fR\fR
+.ad
+.sp .6
+.RS 4n
+WiFi network mode; one of 'infrastructure' (ESS) or 'adhoc' (IBSS).
+If blank, infrastructure is assumed. If 'adhoc' is used with \fB-e essid\fR,
+and one matching the specified \fBESSID\fR cannot be found,
+dladm creates a new ad-hoc network.
+If no \fBESSID\fR is specified, then \fB-i IBSS\fR always
+triggers the creation of a new ad-hoc network with the following ESSID:
+illumos-(random-8ciphers number)
 .RE
 
 .sp
@@ -2819,18 +2730,89 @@
 .ad
 .sp .6
 .RS 4n
-In addition to the filtering previously described, the specified keys will be
-used to secure the association. The security mode to use will be based on the
-key class; if a security mode was explicitly specified, it must be compatible
-with the key class. All keys must be of the same class.
-.sp
-For security modes that support multiple key slots, the slot to place the key
-will be specified by a colon followed by an index. Therefore, \fB-k mykey:3\fR
-places \fBmykey\fR in slot 3. By default, slot 1 is assumed. For security modes
-that support multiple keys, a comma-separated list can be specified, with the
-first key being the active key.
-.RE
-
+Use the specified \fBsecobj\fR to connect to the network.
+In addition to the previous filtering, the specified secobjs will be used for
+Wifi link layer security. The secobj class determines the security policy
+of the target AP. Networks not matching that security policy are filtered out.
+See the subcommand create-secobj documentation for details on how creating
+secure objects.
+.sp
+EAP authentication methods require use of certificates (EAP-PEAP, EAP-TTLS and EAP-TLS).
+Client side certificate is required only by EAP-TLS whereas
+server side certificate can be used optionally by all EAP methods.
+The server side certificate can be optionally verified by using
+a Certification Authority certificate (\fB-A\fR).
+When using EAP-TLS, a client side certificate must be provided (\fB-C\fR)
+together with a matching private key file (\fB-K\fR).
+If the private key file uses a passphrase, a secure object with the passphrase
+value must be first created and passed with the \fB-k\fR flag.
+If PKCS#11 token is used, private key file will be imported in the token and
+on the next connection attempts, the \fB-K\fR flag can be omitted.
+.RE
+
+.sp
+.ne 2
+.na
+\fB\fB-U\fR \fIusername\fR \fB--identity\fR=\fIusername\fR\fR
+.ad
+.sp .6
+.RS 4n
+Identity string for EAP. Identity string for EAP authentication methods.
+Often the user's login name or its email adress.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-N\fR \fIanon_identity\fR
+.ad
+.sp .6
+.RS 4n
+Anonymous identity string for EAP. To be used as the unencrypted identity with
+EAP types that support different tunnelled identity.
+Note that anonymous indentity still requires a password (\fB-k\fR).
+.RE
+
+.sp
+.ne 2
+.na
+\fB-A\fR \fICA_Cert_filename\fR
+.ad
+.sp .6
+.RS 4n
+File path to CA certificate file (PEM/DER formats are supported).
+Relative path can be used. This file can have one or more trusted CA certificates.
+If CA_Cert_filename is not specified, server certificate could not be verified.
+This is insecure and a trusted CA certificate should always be configured when using
+EAP-TLS/TTLS/PEAP.
+If a CA certificate is specified it will be added to the CA verification chain
+with the default system CA certificates, if any.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-C\fR \fIClient_Cert_filename\fR
+.ad
+.sp .6
+.RS 4n
+File path to client certificate file (PEM/DER supported formats).
+Relative path can be used. Omit this option if the Client Certificate is
+contained in the pkcs#12 file.
+.RE
+
+.sp
+.ne 2
+.na
+\fB-K\fR \fIPrivate_Key_filename\fR
+.ad
+.sp .6
+.RS 4n
+File path to client private key file (PEM/DER/PKCS#12). Relative path can be used.
+When PKCS#12 is used, Client_cert_filename should not be specified.
+Both private key and certificate will be read from the PKCS#12 file in this case.
+If the user wants to provide, with this parameter, only the private key,
+either PEM keypair or DER(ASN1) formats can be used.
 .RE
 
 .sp
@@ -2860,147 +2842,18 @@
 .sp
 .ne 2
 .na
-\fB\fBdladm show-wifi\fR [[\fB-p\fR] \fB-o\fR \fIfield\fR,...]
-[\fIwifi-link\fR]\fR
+\fB\fBdladm show-wifi\fR [\fIwifi-link\fR]\fR
 .ad
 .sp .6
 .RS 4n
 Shows \fBWiFi\fR configuration information either for all \fBWiFi\fR links or
 for the specified link \fIwifi-link\fR.
-.sp
-.ne 2
-.na
-\fB\fB-o\fR \fIfield,...\fR, \fB--output\fR=\fIfield\fR\fR
-.ad
-.sp .6
-.RS 4n
-A case-insensitive, comma-separated list of output fields to display. The field
-name must be one of the fields listed below, or the special value \fBall\fR, to
-display all fields. For each \fBWiFi\fR link, the following fields can be
-displayed:
-.sp
-.ne 2
-.na
-\fB\fBLINK\fR\fR
-.ad
-.sp .6
-.RS 4n
-The name of the link being displayed.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBSTATUS\fR\fR
-.ad
-.sp .6
-.RS 4n
-Either \fBconnected\fR if the link is connected, or \fBdisconnected\fR if it is
-not connected. If the link is disconnected, all remaining fields have the value
-\fB--\fR.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBESSID\fR\fR
-.ad
-.sp .6
-.RS 4n
-The \fBESSID\fR (name) of the connected \fBWiFi\fR network.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBBSSID\fR\fR
-.ad
-.sp .6
-.RS 4n
-Either the hardware address of the \fBWiFi\fR network's Access Point (for
-\fBBSS\fR networks), or the \fBWiFi\fR network's randomly generated unique
-token (for \fBIBSS\fR networks).
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBSEC\fR\fR
-.ad
-.sp .6
-.RS 4n
-Either \fBnone\fR for a \fBWiFi\fR network that uses no security, \fBwep\fR for
-a \fBWiFi\fR network that requires WEP, or \fBwpa\fR for a WiFi network that
-requires WPA.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBMODE\fR\fR
-.ad
-.sp .6
-.RS 4n
-The supported connection modes: one or more of \fBa\fR, \fBb\fR, or \fBg\fR.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBSTRENGTH\fR\fR
-.ad
-.sp .6
-.RS 4n
-The connection strength: one of \fBexcellent\fR, \fBvery good\fR, \fBgood\fR,
-\fBweak\fR, or \fBvery weak\fR.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBSPEED\fR\fR
-.ad
-.sp .6
-.RS 4n
-The connection speed, in megabits per second.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBAUTH\fR\fR
-.ad
-.sp .6
-.RS 4n
-Either \fBopen\fR or \fBshared\fR (see \fBconnect-wifi\fR).
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBBSSTYPE\fR\fR
-.ad
-.sp .6
-.RS 4n
-Either \fBbss\fR for \fBBSS\fR (infrastructure) networks, or \fBibss\fR for
-\fBIBSS\fR (ad-hoc) networks.
-.RE
-
-By default, currently all fields but \fBAUTH\fR, \fBBSSID\fR, \fBBSSTYPE\fR are
-displayed.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-p\fR, \fB--parseable\fR\fR
-.ad
-.sp .6
-.RS 4n
-Displays using a stable machine-parseable format. The \fB-o\fR option is
-required with \fB-p\fR. See "Parseable Output Format", below.
-.RE
-
+The information printed shows the current connection status of the link.
+If the link is not connected, only the link MAC address is shown.
+If the link is connecting or the link is up, this command shows all the link
+properties (Speed, 802.11 channel, Signal Strength) together with
+all the current wpa_s state details. These includes current association status,
+the key management methods used, the group cipher, etc...
 .RE
 
 .sp
@@ -3235,7 +3088,7 @@
 .ne 2
 .na
 \fB\fBdladm show-linkprop\fR [\fB-P\fR] [[\fB-c\fR] \fB-o\fR
-\fIfield\fR[,...]][\fB-p\fR \fIprop\fR[,...]] [\fIlink\fR]\fR
+\fIfield\fR[,\fIfield\fR]...][\fB-p\fR \fIprop\fR[,...]] [\fIlink\fR]\fR
 .ad
 .sp .6
 .RS 4n
@@ -3246,7 +3099,7 @@
 .sp
 .ne 2
 .na
-\fB\fB-o\fR \fIfield\fR[,...], \fB--output\fR=\fIfield\fR\fR
+\fB\fB-o\fR \fIfield\fR[,\fIfield\fR]..., \fB--output\fR=\fIfield\fR\fR
 .ad
 .sp .6
 .RS 4n
@@ -3372,18 +3225,45 @@
 .sp .6
 .RS 4n
 Create a secure object named \fIsecobj\fR in the specified \fIclass\fR to be
-later used as a WEP or WPA key in connecting to an encrypted network. The value
+later used as key/password in connecting to an encrypted network. The value
 of the secure object can either be provided interactively or read from a file.
 The sequence of interactive prompts and the file format depends on the class of
 the secure object.
 .sp
-Currently, the classes \fBwep\fR and \fBwpa\fR are supported. The \fBWEP\fR
+Currently, the classes \fBwep\fR, \fBpsk\fR, \fBeap-tls\fR,
+\fBeap-ttls\fR and \fBpeap\fR are supported. The \fBWEP\fR
 (Wired Equivalent Privacy) key can be either 5 or 13 bytes long. It can be
 provided either as an \fBASCII\fR or hexadecimal string -- thus, \fB12345\fR
 and \fB0x3132333435\fR are equivalent 5-byte keys (the \fB0x\fR prefix can be
 omitted). A file containing a \fBWEP\fR key must consist of a single line using
-either \fBWEP\fR key format. The WPA (Wi-Fi Protected Access) key must be
-provided as an ASCII string with a length between 8 and 63 bytes.
+either \fBWEP\fR key format. The PSK (Pre-shared_key) key must be
+provided either as an ASCII string with a length between 8 and 63 bytes or
+as a 64 bytes long precomputed hexadecimal string.
+\fBeap-tls\fR, \fBeap-ttls\fR and \fBpeap\fR are the supported WPA-EAP methods
+for authenticating to WPA-Enterprise networks.
+\fBeap-ttls\fR and \fBpeap\fR methods require
+a second level authentication method to be used
+when the TLS tunnel is enstablished between the two stations.
+The user will be asked to write a comma separated list of these inner
+authentication methods chosen from a predefined list.
+The user can input either none, one, or more of these phase2 methods.
+In case nothing is specified, all the supported methods are tried when
+connecting. \fBEAP-TTLS\fR and \fBPEAP\fR methods, in addition to phase2
+methods, require an ASCII password (up to 256 bytes). This password will be used
+together with the username provided in the \fBdladm connect-wifi\fR command
+(\fB-U\fR or \fB-N\fR flags) when connecting to WPA-Enterprise networks.
+\fBEAP-TLS\fR secobj requires only an ASCII passphrase (up to 256 bytes).
+When creating a \fBEAP-TLS\fR class secobj, a PKCS#11 token can be used to
+store a Private Key Passphrase, required for opening the Private Key file,
+specified with the \fB-K\fR flag in \fBdladm connect-wifi\fR command.
+When using PKCS#11 token the Private Key Passphrase will not be stored on the
+system but will only be used once to import the Private Key in the PKCS#11
+keystore. This also allows the user to delete the Private key local file after
+creating the \fBEAP-TLS\fR secobj. If the user chooses to not use PKCS#11
+token, the Private Key Passphrase is stored as a normal secure object and
+Private Key file will need to be provided at each connection.
+Refer to connect-wifi subcommand documentation for more details on
+the allowed combinations.
 .sp
 This subcommand is only usable by users or roles that belong to the "Network
 Link Security" \fBRBAC\fR profile.
@@ -3394,7 +3274,8 @@
 .ad
 .sp .6
 .RS 4n
-\fIclass\fR can be \fBwep\fR or \fBwpa\fR. See preceding discussion.
+\fIclass\fR can be \fBwep\fR, \fBpsk\fR, \fBeap-tls\fR,
+\fBeap-ttls\fR and \fBpeap\fR. See preceding discussion.
 .RE
 
 .sp
@@ -3404,8 +3285,8 @@
 .ad
 .sp .6
 .RS 4n
-Specifies that the creation is temporary. Temporary creation last until the
-next reboot.
+Specifies that the creation is temporary. The secobj is stored only in memory.
+Temporary creation last until the next reboot.
 .RE
 
 .sp
@@ -3442,6 +3323,7 @@
 .RS 4n
 Delete one or more specified secure objects. This subcommand is only usable by
 users or roles that belong to the "Network Link Security" \fBRBAC\fR profile.
+The secure objects names should be comma separated.
 .sp
 .ne 2
 .na
@@ -3449,8 +3331,8 @@
 .ad
 .sp .6
 .RS 4n
-Specifies that the deletions are temporary. Temporary deletions last until the
-next reboot.
+Specifies that the deletions are temporary. This deletion does not affect the
+secure objects permanently stored on the system.
 .RE
 
 .sp
@@ -3468,24 +3350,25 @@
 .sp
 .ne 2
 .na
-\fB\fBdladm show-secobj\fR [\fB-P\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]]
+\fB\fBdladm show-secobj\fR [\fB-P\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,\fIfield\fR]...]
 [\fIsecobj\fR,...]\fR
 .ad
 .sp .6
 .RS 4n
-Show current or persistent secure object information. If one or more secure
+Show persistent secure object information. If one or more secure
 objects are specified, then information for each is displayed. Otherwise, all
-current or persistent secure objects are displayed.
-.sp
-By default, current secure objects are displayed, which are all secure objects
-that have either been persistently created and not temporarily deleted, or
-temporarily created.
-.sp
-For security reasons, it is not possible to show the value of a secure object.
-.sp
-.ne 2
-.na
-\fB\fB-o\fR \fIfield\fR[,...] , \fB--output\fR=\fIfield\fR[,...]\fR
+persistent secure objects are displayed.
+.sp
+By default, persistent secure objects are displayed,
+which are all secure objects that are maintained across reboots.
+.sp
+For security reasons, it is not possible to show the value of a secure object by
+un-privileged users. Only root can show secure object values by specifying the
+\fBVALUE\fR field with \fB-o\fR flag.
+.sp
+.ne 2
+.na
+\fB\fB-o\fR \fIfield\fR[,\fIfield\fR]... , \fB--output\fR=\fIfield\fR[,\fIfield\fR]...\fR
 .ad
 .sp .6
 .RS 4n
@@ -3528,11 +3411,11 @@
 .sp
 .ne 2
 .na
-\fB\fB-P\fR, \fB--persistent\fR\fR
-.ad
-.sp .6
-.RS 4n
-Display persistent secure object information
+\fB\fB-t\fR, \fB--persistent\fR\fR
+.ad
+.sp .6
+.RS 4n
+Display temporary secure object information.
 .RE
 
 .RE
@@ -3703,7 +3586,7 @@
 .ne 2
 .na
 \fB\fBdladm show-vnic\fR [\fB-pP\fR] [\fB-s\fR [\fB-i\fR \fIinterval\fR]]
-[\fB-o\fR \fIfield\fR[,...]] [\fB-l\fR \fIlink\fR] [\fIvnic-link\fR]\fR
+[\fB-o\fR \fIfield\fR[,\fIfield\fR]...] [\fB-l\fR \fIlink\fR] [\fIvnic-link\fR]\fR
 .ad
 .sp .6
 .RS 4n
@@ -3712,7 +3595,7 @@
 .sp
 .ne 2
 .na
-\fB\fB-o\fR \fIfield\fR[,...] , \fB--output\fR=\fIfield\fR[,...]\fR
+\fB\fB-o\fR \fIfield\fR[,\fIfield\fR]... , \fB--output\fR=\fIfield\fR[,\fIfield\fR]...\fR
 .ad
 .sp .6
 .RS 4n
@@ -4135,7 +4018,7 @@
 .sp
 .ne 2
 .na
-\fB\fBdladm show-iptun\fR [\fB-P\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,...]]
+\fB\fBdladm show-iptun\fR [\fB-P\fR] [[\fB-p\fR] \fB-o\fR \fIfield\fR[,\fIfield\fR]...]
 [\fIiptun-link\fR]\fR
 .ad
 .sp .6
@@ -4165,7 +4048,7 @@
 .sp
 .ne 2
 .na
-\fB\fB-o\fR \fIfield\fR[,...], \fB--output\fR=\fIfield\fR[,...]\fR
+\fB\fB-o\fR \fIfield\fR[,\fIfield\fR]..., \fB--output\fR=\fIfield\fR[,\fIfield\fR]...\fR
 .ad
 .sp .6
 .RS 4n
@@ -4891,7 +4774,7 @@
 default value is 4. A value of 0 disables the encapsulation limit.
 .RE
 
-.SH EXAMPLES
+.SH "EXAMPLES"
 .LP
 \fBExample 1 \fRConfiguring an Aggregation
 .sp
@@ -4911,9 +4794,8 @@
 \fBExample 2 \fRConnecting to a WiFi Link
 .sp
 .LP
-To connect to the most optimal available unsecured network on a system with a
-single \fBWiFi\fR link (as per the prioritization rules specified for
-\fBconnect-wifi\fR), enter the following command:
+To connect to the most optimal available plaintext (unsecured) network
+on a system with a single \fBWiFi\fR link, enter the following command:
 
 .sp
 .in +2
@@ -4927,31 +4809,31 @@
 \fBExample 3 \fRCreating a WiFi Key
 .sp
 .LP
-To interactively create the \fBWEP\fR key \fBmykey\fR, enter the following
+To interactively create the \fBWEP\fR key \fBmywepkey\fR, enter the following
 command:
 
 .sp
 .in +2
 .nf
-# \fBdladm create-secobj -c wep mykey\fR
+# \fBdladm create-secobj -c wep mywepkey\fR
 .fi
 .in -2
 .sp
 
 .sp
 .LP
-Alternatively, to non-interactively create the \fBWEP\fR key \fBmykey\fR using
+Alternatively, to non-interactively create the \fBWEP\fR key \fBmywepkey\fR using
 the contents of a file:
 
 .sp
 .in +2
 .nf
 # \fBumask 077\fR
- # \fBcat >/tmp/mykey.$$ <<EOF\fR
+ # \fBcat >/tmp/mywepkey.$$ <<EOF\fR
  \fB12345\fR
  \fBEOF\fR
- # \fBdladm create-secobj -c wep -f /tmp/mykey.$$ mykey\fR
- # \fBrm /tmp/mykey.$$\fR
+ # \fBdladm create-secobj -c wep -f /tmp/mywepkey.$$ mykey\fR
+ # \fBrm /tmp/mywepkey.$$\fR
 .fi
 .in -2
 .sp
@@ -4966,49 +4848,62 @@
 .sp
 .in +2
 .nf
-# \fBdladm connect-wifi -k mykey -e wlan ath0\fR
+# \fBdladm connect-wifi -k mywepkey -e wlan ath0\fR
 .fi
 .in -2
 .sp
 
 .LP
-\fBExample 5 \fRChanging a Link Property
+\fBExample 5 \fRConnecting to a PSK WPA-Protected WiFi Link
 .sp
 .LP
-To set \fBpowermode\fR to the value \fBfast\fR on link \fBpcwl0\fR, enter the
-following command:
+Create a PSK key \fBpsk\fR, enter the following command:
 
 .sp
 .in +2
 .nf
-# \fBdladm set-linkprop -p powermode=fast pcwl0\fR
-.fi
-.in -2
-.sp
-
-.LP
-\fBExample 6 \fRConnecting to a WPA-Protected WiFi Link
-.sp
-.LP
-Create a WPA key \fBpsk\fR and enter the following command:
-
-.sp
-.in +2
-.nf
-# \fBdladm create-secobj -c wpa psk\fR
+# \fBdladm create-secobj -c psk mypsk\fR
 .fi
 .in -2
 .sp
 
 .sp
 .LP
-To then use key \fBpsk\fR to connect to ESSID \fBwlan\fR on link \fBath0\fR,
+Then use the key \fBmypsk\fR to connect to ESSID \fBwlan\fR on link \fBath0\fR.
+Enter the following command:
+
+.sp
+.in +2
+.nf
+# \fBdladm connect-wifi -k mypsk -e wlan ath0\fR
+.fi
+.in -2
+.sp
+
+.LP
+\fBExample 6 \fRConnecting to a WPA-EAP Protected WiFi Link
+.sp
+.LP
+Save the EAP-TTLS, EAP-PEAP or EAP-TLS password entering the following command
+(also, an inner authentication method must be chosen for EAP-TTLS and PEAP):
+
+.sp
+.in +2
+.nf
+# \fBdladm create-secobj -c eap-ttls myttls\fR
+.fi
+.in -2
+.sp
+
+.sp
+.LP
+Then use key \fBmyttls\fR to connect to ESSID \fBwlan\fR on link \fBrwn0\fR,
 enter the following command:
 
 .sp
 .in +2
 .nf
-# \fBdladm connect-wifi -k psk -e wlan ath0\fR
+# \fBdladm connect-wifi -k myttls -e wlan -U myusername -C CA_Cert_filename rwn0\fR
 .fi
 .in -2
 .sp
@@ -5366,7 +5261,7 @@
 interface. See \fBifconfig\fR(1M) for a description of how IPv6 addresses are
 configured on 6to4 tunnel links.
 
-.SH ATTRIBUTES
+.SH "ATTRIBUTES"
 .sp
 .LP
 See \fBattributes\fR(5) for descriptions of the following attributes:
@@ -5400,13 +5295,13 @@
 Interface Stability	Committed
 .TE
 
-.SH SEE ALSO
+.SH "SEE ALSO"
 .sp
 .LP
 \fBacctadm\fR(1M), \fBautopush\fR(1M), \fBifconfig\fR(1M), \fBipsecconf\fR(1M),
 \fBndd\fR(1M), \fBpsrset\fR(1M), \fBwpad\fR(1M), \fBzonecfg\fR(1M),
 \fBattributes\fR(5), \fBieee802.3\fR(5), \fBdlpi\fR(7P)
-.SH NOTES
+.SH "NOTES"
 .sp
 .LP
 The preferred method of referring to an aggregation in the aggregation
--- a/usr/src/man/man1m/wificonfig.1m	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1070 +0,0 @@
-'\" te
-.\" Copyright (c) 2003, Sun Microsystems, Inc. All Rights Reserved
-.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
-.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
-.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH WIFICONFIG 1M "Oct 31, 2007"
-.SH NAME
-wificonfig \- WLAN configuration
-.SH SYNOPSIS
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] [\fB-i\fR \fIinterface\fR] autoconf
-     [\fIwait\fR={\fIn\fR|\fIforever\fR}]
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] [\fB-i\fR \fIinterface\fR] connect profile
-     [\fIwait\fR={\fIn\fR|\fIforever\fR}]
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] [\fB-i\fR \fIinterface\fR] connect essid
-     [\fIwait\fR={\fIn\fR|\fIforever\fR}]
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] [\fB-i\fR \fIinterface\fR] disconnect
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] [\fB-i\fR \fIinterface\fR] getparam
-     [\fIparameter\fR []...]
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] [\fB-i\fR \fIinterface\fR] setparam
-     [\fIparameter\fR=\fIvalue\fR []...]
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] [\fB-i\fR \fIinterface\fR] restoredef
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] [\fB-i\fR \fIinterface\fR] scan
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] [\fB-i\fR \fIinterface\fR] showstatus
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] [\fB-i\fR \fIinterface\fR] setwepkey 1|2|3|4
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] createprofile profile
-     [\fIparameter\fR=\fIvalue\fR []...]
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] deleteprofile \fIprofile1\fR
-     [\fIprofile2\fR []...]
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] showprofile [\fIprofile\fR]
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] setprofilewepkey \fIprofile\fR 1|2|3|4
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] getprofileparam \fIprofile\fR
-     [\fIparameter\fR []...]
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] setprofileparam
-     [\fIparameter\fR=\fIvalue\fR []...]
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] history
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] listprefer
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] removeprefer \fIprofile\fR
-.fi
-
-.LP
-.nf
-\fBwificonfig\fR [\fB-R\fR \fIroot_path\fR] setprefer \fIprofile\fR [\fIn\fR]
-.fi
-
-.SH DESCRIPTION
-.sp
-.LP
-\fBwificonfig\fR defines a set of subcommands and parameters to configure
-\fBWiFi\fR interfaces in the system. A driver may support all parameters or a
-subset of these parameters.
-.sp
-.LP
-\fBwificonfig\fR uses \fBrbac\fR(5) to control user access to the interface.
-Only users with the "solaris.network.wifi.config" authorization can manage a
-\fBWiFi\fR interface, while only users with
-"solaris.network.wifi.wep"authorizations can configure the \fBWEP\fR (Wired
-Equivalent Privacy) key. Other users can only read parameters from the
-interface. By default, the "solaris.network.wifi.config" and
-"solaris.network.wifi.wep" authorizations are not granted to any user apart
-from root.
-.sp
-.LP
-\fBWificonfig\fR comes in two classes of forms. The first class, shown as the
-first set of synopsis combined with the optional interface name, is the
-subcommands used to a manipulate a particular \fBWiFi\fR network interface. The
-second class, shown as the second set of synopsis, is used to create and
-operate on \fBWiFi\fR Configuration Profiles. A Configuration Profile allows
-the user to pre-specify a set of parameters which can later be applied to a
-\fBWiFi\fR network interface using the \fBconnect\fR or \fBautoconf\fR
-subcommands.
-.sp
-.LP
-In the interface subcommands, if the interface is not specified (that is, the
-\fB-i\fR option is missing), \fBwificonfig\fR selects a random interface from
-the known \fBWiFi\fR interfaces on the system. If there are multiple \fBWiFi\fR
-network interfaces on the system, then the selection will be the same over time
-as long as the number of and names of the \fBWiFi\fR interfaces does not
-change.
-.sp
-.LP
-A Configuration Profile can be created for a \fBWLAN\fR by using the
-\fBcreateprofile\fR subcommand (see the SUBCOMMANDS section). The actual
-\fBWLAN\fR may be present or not.
-.sp
-.LP
-\fBwificonfig\fR also maintains a list of Configuration Profiles called the
-Preference List. This list makes automatic configuration possible. When the
-\fBautoconf\fR subcommand is used, \fBwificonfig\fR tries to connect to each
-pre-configured \fBWLAN\fR according to the order of the Preference List. If the
-Preference List is empty or none of the \fBWLAN\fRs in the Preference List can
-be found, \fBwificonfig\fR uses its built-in heuristics to automatically
-configure the interface. (See the \fBautoconf\fR subcommand for the
-heuristics). A few subcommands (\fBlistprefer\fR, \fBsetprefer\fR,
-\fBremoveprefer\fR) are defined to manipulate the Preference List.
-.SH OPTIONS
-.sp
-.LP
-The following options are supported:
-.sp
-.ne 2
-.na
-\fB\fB-i\fR \fIinterface\fR\fR
-.ad
-.RS 16n
-Specifies a wireless network interface to do the configuration.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-R\fR \fIroot_path\fR\fR
-.ad
-.RS 16n
-Defines the full path name of a directory to use as the \fIroot_path\fR. This
-affects the location of the private files where \fBwificonfig\fR stores the
-Configuration Profiles and \fBWEP\fR keys.
-.RE
-
-.SS "OPERANDS"
-.sp
-.LP
-The following operand is supported:
-.sp
-.ne 2
-.na
-\fBprofile\fR
-.ad
-.RS 11n
-The name of a \fBWiFi\fR profile. It can be a string between 1 and 32
-characters. However, "all", "{preference}", "{history}", "{active_profile}",
-and any strings contained in brackets, such as "[foo]", are not allowed as a
-profile name.
-.RE
-
-.SS "SUBCOMMANDS"
-.sp
-.LP
-The following subcommands are supported:
-.sp
-.ne 2
-.na
-\fB\fBautoconf\fR [wait={\fIn\fR|\fIforever\fR}]\fR
-.ad
-.sp .6
-.RS 4n
-Configures the interface automatically. The interface is configured according
-to the previously saved Preference List found in \fB/etc/inet/wifi\fR.
-\fBwificonfig\fR first gets a list of available \fBWLAN\fRs by scanning the
-radio. It then compares the list of available \fBWLAN\fRs with the Preference
-List. If the Preference List is empty, or if none of the \fBWLAN\fRs in the
-Preference List can be found, \fBwificonfig\fR chooses a \fBWLAN\fR to connect
-to using the following priorities: 1) the \fBWLAN\fRs without encryption, 2)
-the \fBWLAN\fRs with stronger signal strength, and 3) the \fBWLAN\fRs with
-higher transmit rates.
-.sp
-If the \fBWLAN\fRs in the Preference list are available, the user can specify
-the number of seconds to wait before \fBautoconf\fR returns using the wait
-option. By default (without the wait option), \fBautoconf\fR returns within 10
-seconds. If "\fIforever\fR" or -1 follows the wait option, \fBwificonfig\fR
-waits until the \fBNIC\fR is successfully connected to the \fBWLAN\fR specified
-by the profile in the Preference list.
-.sp
-The "solaris.network.wifi.config" authorization is required for this
-subcommand.
-.sp
-The \fBWiFi\fR device driver can not guarantee to retain the state for the
-connection when it is not held open. For this reason, it is strongly
-recommended that the \fBplumb\fR subcommand for \fBifconfig\fR(1M) is done
-before the \fBwificonfig autoconf\fR subcommand is given.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBconnect\fR \fIprofile\fR[wait={\fIn\fR|\fIforever\fR}]\fR
-.ad
-.br
-.na
-\fB\fBconnect\fR \fIessid\fR[wait={\fIn\fR|\fIforever\fR}]\fR
-.ad
-.sp .6
-.RS 4n
-Connects to a wireless network according to a pre-configured "profile". If the
-specified Configuration Profile exists in /etc/inet/wifi, the \fBconnect\fR
-subcommand uses that Configuration Profile to configure the interface. That
-profile subsequently becomes the current active profile of the interface after
-the \fBconnect\fR subcommand succeeds. If no existing Configuration Profile
-matches the specified name, the behavior of the \fBconnect\fR subcommand is
-equivalent to the \fBrestoredef\fR subcommand, except that the "essid"
-parameter is set as "profile".
-.sp
-If the \fBWLAN\fRs in the Preference list are available, the user can specify
-the number of seconds to wait before \fBconnect\fR returns using the wait
-option. By default (without the wait option), \fBconnect\fR trys for 10
-seconds. If "\fIforever\fR" or -1 follows the wait option, \fBwificonfig\fR
-tries until the \fBNIC\fR is successfully connected to the profile or essid
-that was specified.
-.sp
-The \fBconnect\fR subcommand prints one of the following lines depending on
-whether or not a Configuration Profile was found for the specified name:
-.sp
-.in +2
-.nf
-Connecting to profile <name>	
-Connecting to essid <name>
-.fi
-.in -2
-.sp
-
-The "solaris.network.wifi.config" authorization is required for this
-subcommand.
-.sp
-The \fBWiFi\fR device driver can not guarantee to retain the state for the
-connection when it is not held open. For this reason, it is strongly
-recommended that the \fBplumb\fR subcommand for \fBifconfig\fR(1M) is done
-before the \fBwificonfig autoconf\fR subcommand is given.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBdisconnect\fR\fR
-.ad
-.sp .6
-.RS 4n
-Disconnects the interface from the currently associated wireless network. The
-interface associates with none of the wireless networks.
-.sp
-The "solaris.network.wifi.config" authorization is required for this
-subcommand.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBgetparam\fR [parameter [...]]\fR
-.ad
-.br
-.na
-\fB\fBsetparam\fR [parameter=value [...]]\fR
-.ad
-.sp .6
-.RS 4n
-Gets or sets parameters in the network interface. This does not affect any
-profile. The \fBsetprofileparam\fR subcommand can be used to set and change
-parameters in a profile that has already been created.
-.sp
-The \fBsetparam\fR subcommand without any parameters displays the set of
-parameters supported by the network interface, including whether they are
-read/write or read only. The \fBgetparam\fR subcommand without any parameters
-displays all the parameters and their values.
-.sp
-The \fBsetparam wepkey1|wepkey2|wepkey3|wepkey4\fR subcommand requires the
-"solaris.network.wifi.wep" authorization. For all other parameters, the
-\fBsetparam\fR subcommand requires the
-"solaris.network.wifi.config"authorization.
-.sp
-For example,
-.sp
-.in +2
-.nf
-$ wificonfig setparam <parameter1=value1> [parameter2=value2 [...]]
-$ wificonfig getparam <parameter1> [parameter2 [...]]
-.fi
-.in -2
-.sp
-
-\fBwificonfig\fR currently supports the following parameters (the values are
-case insensitive).
-.sp
-.ne 2
-.na
-\fB\fIbssid\fR\fR
-.ad
-.sp .6
-.RS 4n
-\fBMAC\fR address of the associated Access Point. The valid value is a hex
-value of 6 bytes. The \fIbssid\fR can also be the \fBIBSSID\fR in an ad-hoc
-configuration. If the network interface is not connected to any \fBWLAN\fR,
-then the string "none" is shown instead of a 6 byte \fBMAC\fR address.
-Otherwise, the network interface is connected to a \fBWLAN\fR. The default
-value is "none". This parameter is read-only.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fIessid\fR\fR
-.ad
-.sp .6
-.RS 4n
-Network name. The valid value is a string of up to 32 chars. If \fIessid\fR is
-an empty string, the driver automatically scans and joins the \fBWLAN\fR using
-the built-in heuristics. The default value is an empty string.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fIbsstype\fR\fR
-.ad
-.sp .6
-.RS 4n
-Specifies whether the Infrastructure Mode or Ad-Hoc Mode is used. The valid
-values are "ap", "bss", or "infrastructure" to join a \fBWLAN\fR through an
-Access Point, that is, to use infrastructure mode. The valid values are "ibss"
-or "ad-hoc" to join a peer-to-peer WLAN (also named "ad-hoc"). The valid value
-of "auto" automatically switches between the two types. The default value is
-"infrastructure'".
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fIcreateibss\fR\fR
-.ad
-.sp .6
-.RS 4n
-Specifies whether to create an ad-hoc network (also called an \fIIBSS\fR if the
-\fBconnect\fR does not result in finding the desired network. This enables the
-user to start an ad-hoc network so that other hosts can join. The valid values
-are YES to start a new ad-hoc \fBWLAN\fR (instead of joining one) and NO to not
-start an ad-hoc \fBWLAN\fR. The default value is NO. The \fBNIC\fR always tries
-to join a \fBWLAN\fR first. If this is successful, the setting of
-\fIcreateibss\fR is ignored.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fIchannel\fR\fR
-.ad
-.sp .6
-.RS 4n
-An integer indicating the operating frequency. This channel number varies by
-regulatory domain. When the channel number is obtained by the \fBgetparam\fR
-subcommand, the value indicates the actual channel the card uses to connect to
-the network. The channel number is set by the \fBsetparam\fR subcommand, and
-the value is only applicable when the card is in ad-hoc mode. It indicates the
-operating channel of the \fIIBSS\fR. The default value is the channel number on
-the card.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fIrates\fR\fR
-.ad
-.sp .6
-.RS 4n
-Specifies the transmission rates. The valid values (in Mbit/s) are 1, 2, 5.5,
-6, 9, 11, 12, 18, 22, 24, 33, 36, 48, and 54. A \fBNIC\fR may support multiple
-transmission rates depending on its capability. This is the only parameter that
-accepts multiple values. When multiple values are supplied to set this
-parameter, each value must be separated by a comma (,). See the \fBEXAMPLES\fR
-section for details. The default values are the data rates supported by the
-chip.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fIpowermode\fR\fR
-.ad
-.sp .6
-.RS 4n
-Specifies the power management mode. The valid values are "off" to disable
-power management, "mps" for maximum power saving, and "fast" for the best
-combination of speed and power saving. The default value is "off".
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fIauthmode\fR\fR
-.ad
-.sp .6
-.RS 4n
-Specifies the authorization type. The valid values are "opensystem" for an open
-system, where anyone can be authenticated and "shared_key" for a Shared Key
-authentication mode. The default value is "opensystem".
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fIencryption\fR\fR
-.ad
-.sp .6
-.RS 4n
-Specifies the encryption algorithm to be used. The valid values are "none" for
-no encryption algorithm and "wep" to turn on \fBWEP\fR encryption. The default
-value is "none".
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fIwepkey1\fR|\fIwepkey2\fR|\fIwepkey3\fR|\fIwepkey4\fR\fR
-.ad
-.sp .6
-.RS 4n
-A maximum of 4 \fBWEP\fR keys (indexed 1 through 4) can be set in an \fBNIC\fR.
-They are write-only parameters which can be set by the \fBsetparam\fR
-subcommand, but cannot be read back by the \fBgetparam\fR subcommand. \fBWEP\fR
-keys can either be set by the \fBsetwepkey\fR or the \fBsetparam\fR subcommand.
-\fBsetparam\fR uses plain text but it's scriptable. See the \fBsetwepkey\fR
-subcommand for more information about how a \fBWEP\fR key is encoded. Setting
-\fBWEP\fR keys requires "solaris.network.wifi.wep"authorization.
-.sp
-When these subcommands are used to set a \fBWEP\fR key, any user on the system
-can read the key from the \fBps\fR(1) output. Thus, the \fBsetwepkey\fR
-subcommand is recommended for setting the \fBWEP\fR keys since it does not
-allow \fBps\fR(1) to read the keys.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fIwepkeyindex\fR\fR
-.ad
-.sp .6
-.RS 4n
-Specifies the encryption keys. The valid values are 1 to use wepkey1, 2 to use
-wepkey2, 3 to use wepkey3, and 4 to use wepkey4. The default value is 1. This
-subcommand is only valid when \fBWEP\fR is on.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fIsignal\fR\fR
-.ad
-.sp .6
-.RS 4n
-Specifies the strength of the received radio signal. The valid values are 0 -
-15 , where 0 is the weakest signal and 15 is the strongest signal. This
-parameter is read-only and indicates the radio signal strength received by the
-\fBNIC\fR.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fIradio\fR\fR
-.ad
-.sp .6
-.RS 4n
-Specifies whether the radio is turned on or off. The valid values are "on" to
-turn on the radio and "off" to turn off the radio. The default value is "on".
-.RE
-
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBrestoredef\fR\fR
-.ad
-.sp .6
-.RS 4n
-Forces the \fBNIC\fR to restore the network interface to use the default values
-for all the parameters. See the \fBgetparam\fR and \fBsetparam\fR subcommands
-for the default values of the parameters.
-.sp
-The "solaris.network.wifi.config" authorization is required for this
-subcommand.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBscan\fR\fR
-.ad
-.sp .6
-.RS 4n
-Scans and lists the currently available \fBWLAN\fRs.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBshowstatus\fR\fR
-.ad
-.sp .6
-.RS 4n
-Display the basic status of a \fBWLAN\fR interface. If the \fBWLAN\fR interface
-is connected, the basic status includes: the name of the current active
-profile, the name of the network, the \fIbssid\fR, whether the network is
-encrypted or not, and the signal strength.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBsetwepkey\fR 1|2|3|4\fR
-.ad
-.sp .6
-.RS 4n
-Sets one of the 4 \fBWEP\fR encryption keys. \fBWEP\fR keys are used to
-encrypt the content of the network packets which are transmitted on air. There
-are 4 \fBWEP\fR keys in the \fBNIC\fR according to the 802.11 standards. The
-\fBsetwepkey\fR subcommand is used to update one of the 4 keys by prompting the
-user for the key. The user must enter the key twice. The input is not echoed.
-For example, to update setwepkey2:
-.sp
-.in +2
-.nf
-example% wificonfig -i ath0 setwepkey 2
-input wepkey2: < user input here>
-confirm wepkey2: < user input here>
-.fi
-.in -2
-.sp
-
-A \fBWEP\fR key can be 5 bytes or 13 bytes long. There are two ways to enter a
-\fBWEP\fR key, by \fBASCII\fR values or by hex values. If the user enters 5 or
-13 characters, it is considered the \fBASCII\fR representation of the key. If
-the user enters 10 or 26 characters, it is considered the hex representation of
-the key. For example "1234" is equivalent to "6162636465". If the user enters
-other number of characters, the subcommand fails. \fBWEP\fR keys are
-write-only; they cannot be read back via \fBwificonfig\fR.
-.sp
-The \fBWEP\fR keys can also be set in plain text form by the \fBsetparam\fR
-subcommand. This makes setting \fBWEP\fR keys scriptable (see the parameters of
-\fBsetparam\fR for the details).
-.sp
-The "solaris.network.wifi.wep" authorization is required for this subcommand.
-.RE
-
-.sp
-.LP
-The following profile subcommands are supported:
-.sp
-.ne 2
-.na
-\fB\fBcreateprofile\fR \fIprofile\fR [parameter=value] [...]\fR
-.ad
-.sp .6
-.RS 4n
-Creates a Configuration Profile named \fIprofile\fR off-line. The specified
-parameters are saved as items of this Configuration Profile. The user can
-specify a group of parameters. At a minimum, the \fIessid\fR must be specified.
-.sp
-The "solaris.network.wifi.config" authorization is required for this
-subcommand.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBdeleteprofile\fR \fIprofile1\fR [\fIprofile2\fR [...]]\fR
-.ad
-.sp .6
-.RS 4n
-Deletes one or more Configuration Profiles according to the specified names. If
-the specified Configuration Profile does not exist, this subcommand fails. The
-wild-card "all" can be used to delete all profiles.
-.sp
-The "solaris.network.wifi.config" authorization is required for this
-subcommand.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBshowprofile\fR [\fIprofile\fR]\fR
-.ad
-.sp .6
-.RS 4n
-Displays the parameters in the Configuration Profile according to the specified
-\fIprofile\fR. \fBWEP\fR (wired equivalent privacy) keys are not printed
-because they are write-only parameters. If no \fIprofile\fR is specified, all
-the profiles are shown.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBsetprofilewepkey\fR 1|2|3|4\fR
-.ad
-.sp .6
-.RS 4n
-Sets one of the 4 \fBWEP\fR encryption keys in the specified Configuration
-Profile "profile". Like the other \fBprofile\fR subcommands,
-\fBsetprofilewepkey\fR does not affect the configuration of a network
-interface, even if a \fBWiFi\fR interface is currently running with the
-specified profile. In order for the modified profile to be applied to the
-network interface, the \fBconnect\fR or \fBautoconf\fR subcommands have to be
-used after the profile has been updated.
-.sp
-Other than that difference, the usage of \fBsetprofilewepkey\fR is the same as
-the \fBsetwepkey\fR subcommand. For example, to update wepkey 2 in profile
-"\fIhome\fR":
-.sp
-.in +2
-.nf
-example% wificonfig setprofilewepkey home 2
-input wepkey2: < user input here>
-confirm wepkey2: < user input here>
-.fi
-.in -2
-.sp
-
-The "solaris.network.wifi.wep" authorization is required for this subcommand.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBgetprofileparam\fR \fIprofile\fR [parameter]\  [...]]\fR
-.ad
-.br
-.na
-\fB\fBsetprofileparam\fR \fIprofile\fR [parameter=value]\  [...]]\fR
-.ad
-.sp .6
-.RS 4n
-Gets or sets parameters in the specified Configuration Profile "\fIprofile\fR".
-Like the other profile subcommands, these subcommands do not affect the
-configuration of a network interface, even if a \fBWiFi\fR interface is
-currently running with the specified profile. In order for the modified
-profile to be applied to the network interface, the \fBconnect\fR or
-\fBautoconf\fR subcommands have to be used after the profile has been updated.
-.sp
-A \fBgetprofileparam\fR without any parameters will display all the parameters
-and their values.
-.sp
-"Solaris.network.wifi.wep" authorization is required when the \fBsetparam\fR
-subcommand is used with the
-\fIwepkey1\fR|\fIwepkey2\fR|\fIwepkey3\fR|\fIwepkey4\fR parameter. For all
-other parameters, the \fBsetparam\fR subcommand requires
-"solaris.network.wifi.config"authorization.
-.sp
-For example, to change the settings for the "\fIhome\fR" Configuration Profile,
-use:
-.sp
-.in +2
-.nf
-$ wificonfig setprofileparam home <parameter1=value1> \e
-[parameter2=value2 [...]]
-$ wificonfig getprofileparam home <parameter1> [parameter2 [...]]
-.fi
-.in -2
-.sp
-
-The set of parameters and their allowed values are the same as those specified
-for the \fBsetparam\fR subcommand.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBhistory\fR\fR
-.ad
-.sp .6
-.RS 4n
-Lists the \fBWLAN\fRs in the History List. \fBwificonfig\fR automatically
-records the \fBWLAN\fRs that appear in every scanning attempt. The History List
-contains a maximum of 10 records of the most recent \fBWLAN\fRs, sorted by
-time. These records can be listed by using this subcommand.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBlistprefer\fR\fR
-.ad
-.sp .6
-.RS 4n
-Lists the content of the Preference List.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBremoveprefer\fR \fIprofile\fR\fR
-.ad
-.sp .6
-.RS 4n
-Removes one or more profiles from the Preference List. The wild-card "all" can
-be used to delete all profiles.
-.sp
-The "solaris.network.wifi.config" authorization is required for this
-subcommand.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fBsetprefer\fR \fIprofile\fR [\fIn\fR]\fR
-.ad
-.sp .6
-.RS 4n
-Sets the position of a \fIprofile\fR in the Preference List. This may add or
-change the position of a \fIprofile\fR in the Preference List. The valid values
-of "\fIn\fR" range from 1 to 10. If "\fIn\fR" is missing, the default value of
-1 is assumed. If the specified position is already occupied, the occupying
-\fIprofile\fR is moved lower on the list. If "\fIn\fR" is off the end of the
-list, \fIprofile\fR is added to the end of the list. The Preference List can
-also be created by using this subcommand. If the \fBautoconf\fR subcommand is
-used at a later time, \fBwificonfig\fR tries to join the \fBWLAN\fRs according
-to the Preference List.
-.sp
-The "solaris.network.wifi.config" authorization is required for this
-subcommand.
-.RE
-
-.SH EXAMPLES
-.LP
-\fBExample 1 \fRListing the Parameters Supported by a Driver
-.sp
-.LP
-To display what parameters the \fIath\fR driver supports and the read/write
-modes of the parameters:
-
-.sp
-.in +2
-.nf
-% wificonfig -i ath0 setparam
-          parameter     property
-              bssid     read only
-              essid     read/write
-            bsstype     read/write
-              rates     read/write
-           authmode     read/write
-         encryption     read/write
-        wepkeyindex     read/write
-             signal     read only
-
-.fi
-.in -2
-.sp
-
-.LP
-\fBExample 2 \fRGetting and Setting Parameters on the WiFi interface
-.sp
-.LP
-To get the current rates and signal strength from the driver:
-
-.sp
-.in +2
-.nf
-% wificonfig -i ath0 getparam rates signal
-      ath0:
-         rates = 1,2,5.5,11
-         signal = 10
-.fi
-.in -2
-.sp
-
-.LP
-\fBExample 3 \fRManaging Configuration Profiles
-.sp
-.LP
-A Configuration Profile can be created offline and then connected to the
-network with the created Configuration Profile. The following series of
-commands creates the Configuration Profile, displays the contents of that
-profile, and connects to the network with the Configuration Profile:
-
-.sp
-.in +2
-.nf
-% wificonfig createprofile myXXX essid=rover encryption=WEP \e
-			wepkey1=12345
-% wificonfig showprofile myXXX
-  [myXXX]
-  essid=rover
-  encryption=WEP
-  wepkey1=[secret]
-
-% ifconfig ath0 plumb
-% wificonfig -i ath0 connect myXXX
-.fi
-.in -2
-.sp
-
-.LP
-\fBExample 4 \fRManaging the Preference List
-.sp
-.LP
-A profile can be added to the Preference List and then used by the
-\fBautoconf\fR subcommand. The following series of commands adds a profile
-named \fImyXXX\fR to the top of the Preference List, automatically connects
-\fIath0\fR to the first available \fBWLAN\fR in the Preference List, and
-removes \fImy_neighbor\fR from the Preference List
-
-.sp
-.in +2
-.nf
-% wificonfig setprefer myXXX 1
-% ifconfig ath0 plumb
-% wificonfig -i ath0 autoconf
-% wificonfig removeprefer my_neighbor
-.fi
-.in -2
-.sp
-
-.LP
-\fBExample 5 \fRViewing the History List
-.sp
-.LP
-To display the history of the \fBWLAN\fRs:
-
-.sp
-.in +2
-.nf
-% wificonfig history
-
-    WLAN history:
-
-  essid	        bssid	            encryption	last seen
-  myXXX           00:0f:24:11:12:14  WEP     	Fri Sep 13 09:15:24 2004
-  my_office_ssid  00:0f:24:11:12:15  WEP     	Fri Sep 13 13:20:04 2004
-  my_neighbor1    00:0f:24:11:12:16  NONE    	Fri Sep 14 08:01:26 2004
-  my_neighbor2    00:0f:24:11:12:17  WEP      Fri Sep 18 21:33:12 2004
-.fi
-.in -2
-.sp
-
-.LP
-\fBExample 6 \fRAutomatic Configuration
-.sp
-.LP
-To configure the interface according to the previously saved Preference List:
-
-.sp
-.in +2
-.nf
-% ifconfig ath0 plumb
-% wificonfig -i ath0 autoconf
-.fi
-.in -2
-.sp
-
-.sp
-.LP
-If the Preference List is empty, or none of the \fBWLAN\fRs listed by the
-Proference List can be found, \fBwificonfig\fR uses the default configuration,
-directs the interface to scan and join the \fBWLAN\fR using the built-in
-heuristics specified above.
-
-.LP
-\fBExample 7 \fRConnecting To a WLAN
-.sp
-.LP
-To search for a Configuration Profile with the name \fImyXXX\fR and configure
-the interface accordingly:
-
-.sp
-.in +2
-.nf
-% ifconfig ath0 plumb
-% wificonfig -i ath0 connect myXXX
-.fi
-.in -2
-.sp
-
-.sp
-.LP
-If the specified Configuration Profile does not exist, \fBwificonfig\fR
-interprets it as an \fIessid\fR and sets \fIath0\fR to use \fIessid\fR
-\fImyXXX\fR, and no other parameters are set.
-
-.LP
-\fBExample 8 \fRDisplaying the Content of a Configuration Profile
-.sp
-.LP
-To print the parameters of the previously Configured Profile named
-\fImy_home_ssid\fR:
-
-.sp
-.in +2
-.nf
-% wificonfig showprofile my_home_ssid
-.fi
-.in -2
-.sp
-
-.LP
-\fBExample 9 \fRMonitoring the link status
-.sp
-.LP
-To monitor the link status:
-
-.sp
-.in +2
-.nf
-% wificonfig -i ath0 showstatus
-        ath0:
-                linkstatus: not connected,
-.fi
-.in -2
-.sp
-
-.sp
-.LP
-or
-
-.sp
-.in +2
-.nf
-        ath0:
-                linkstatus: connected
-                active profile: [home]
-                essid: myhome
-                bssid: 00:0b:0e:12:e2:02
-                encryption: WEP
-                signal: medium(10)
-.fi
-.in -2
-.sp
-
-.LP
-\fBExample 10 \fRScanning for available networks
-.sp
-.LP
-To scan for available networks:
-
-.sp
-.in +2
-.nf
-% wificonfig -i ath0 scan
-essid           bssid             type          encryption      signal
-                                                                level
-ietf64-secure   00:0b:0e:12:e2:02 access point  WEP             9
-roomlinx        00:40:96:a1:13:70 access point  none            6
-ietf64          00:0b:0e:13:32:00 access point  none            3
-ietf64-secure   00:0b:0e:13:32:02 access point  WEP             3
-ietf64          00:0b:0e:12:e2:00 access point  none            9
-ietf64-secure   00:0b:0e:12:e4:c2 access point  WEP             8
-ietf64          00:0b:0e:12:e4:c0 access point  none            8
-roomlinx        00:40:96:a0:aa:aa access point  none            1
-roomlinx        00:40:96:a0:ab:39 access point  none            8
-.fi
-.in -2
-.sp
-
-.SH EXIT STATUS
-.sp
-.ne 2
-.na
-\fB\fB0\fR\fR
-.ad
-.RS 5n
-Successful operation
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB1\fR\fR
-.ad
-.RS 5n
-Fatal Error; the operation failed. For example, a connect failed to associate
-with an Access Point.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB2\fR\fR
-.ad
-.RS 5n
-Improper Use; help information will be printed
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB3\fR\fR
-.ad
-.RS 5n
-Minor error
-.RE
-
-.SH ATTRIBUTES
-.sp
-.LP
-See \fBattributes\fR(5) for descriptions of the following attributes:
-.sp
-
-.sp
-.TS
-box;
-c | c
-l | l .
-ATTRIBUTE TYPE	ATTRIBUTE VALUE
-_
-Interface Stability	Unstable
-.TE
-
-.SH SEE ALSO
-.sp
-.LP
-\fBps\fR(1), \fBifconfig\fR(1M), \fBattributes\fR(5), \fBath\fR(7D)
--- a/usr/src/man/man1m/wpad.1m	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,168 +0,0 @@
-'\" te
-.\" Copyright (c) 2008, Sun Microsystems, Inc. All Rights Reserved
-.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
-.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
-.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH WPAD 1M "Mar 11, 2008"
-.SH NAME
-wpad \- WPA and WPA2 protocol daemon
-.SH SYNOPSIS
-.LP
-.nf
-\fB/usr/lib/inet/wpad\fR [\fB-i\fR \fIinterface\fR] [\fB-k\fR \fIpre_shared_key_name\fR]
-.fi
-
-.SH DESCRIPTION
-.sp
-.LP
-The \fBwpad\fR daemon provides common client functionality for the WiFi
-Protected Access (WPA) versions 1 and 2, as defined by IEEE802.11i standard.
-WPA was created by the WiFi Alliance, an industry trade group. WPA implements
-the majority of the IEEE 802.11i standard, and was intended as an intermediate
-measure to take the place of Wired Equivalent Privacy (WEP) while 802.11i was
-prepared. WPA2 implements the full standard.
-.sp
-.LP
-\fBwpad\fR provides the following WPA/IEEE 802.11i features:
-.RS +4
-.TP
-.ie t \(bu
-.el o
-WPA-PSK ("WPA-Personal")
-.RE
-.RS +4
-.TP
-.ie t \(bu
-.el o
-Key management for CCMP, TKIP, WEP104, WEP40
-.RE
-.sp
-.LP
-Stop and start the \fBwpad\fR daemon using \fBdladm\fR(1M). Use:
-.sp
-.in +2
-.nf
-# \fBdladm connect-wifi\fR
-.fi
-.in -2
-.sp
-
-.sp
-.LP
-\&...to start the \fBwpad\fR daemon. Use:
-.sp
-.in +2
-.nf
-# \fBdladm disconnect-wifi\fR
-.fi
-.in -2
-.sp
-
-.sp
-.LP
-\&...to stop the daemon.
-.SH OPTIONS
-.sp
-.LP
-The following options are supported:
-.sp
-.ne 2
-.na
-\fB\fB-i\fR \fIinterface\fR\fR
-.ad
-.sp .6
-.RS 4n
-Specify a WiFi Link interface to start the \fBwpad\fR daemon.
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB-k\fR \fIpre_shared_key_name\fR\fR
-.ad
-.sp .6
-.RS 4n
-Specify the pre-shared key used for the WiFi Link.
-.RE
-
-.SH EXAMPLES
-.LP
-\fBExample 1 \fRStarting the \fBwpad\fR Daemon on Specific WiFi Link
-.sp
-.LP
-To create the WPA key \fBpsk\fR, enter the  following command:
-
-.sp
-.in +2
-.nf
-# \fBdladm create-secobj -c wpa psk\fR
-.fi
-.in -2
-.sp
-
-.sp
-.LP
-To use key \fBpsk\fR to connect to ESSID \fBwlan\fR on link \fBath0\fR, enter
-the following command:
-
-.sp
-.in +2
-.nf
-# \fBdladm connect-wifi -k psk -e wlan ath0\fR
-.fi
-.in -2
-.sp
-
-.LP
-\fBExample 2 \fRStopping the \fBwpad\fR Daemon on Specific WiFi Link
-.sp
-.LP
-To stop the daemon on the link \fBath0\fR, enter:
-
-.sp
-.in +2
-.nf
-# \fBdladm disconnect-wifi ath0\fR
-.fi
-.in -2
-.sp
-
-.SH ATTRIBUTES
-.sp
-.LP
-See \fBattributes\fR(5) for descriptions of the following attributes:
-.sp
-
-.sp
-.TS
-box;
-c | c
-l | l .
-ATTRIBUTE TYPE	ATTRIBUTE VALUE
-_
-Interface Stability	Uncommitted
-.TE
-
-.SH SEE ALSO
-.sp
-.LP
-\fBsvcs\fR(1), \fBdladm\fR(1M), \fBsvcadm\fR(1M), \fBattributes\fR(5),
-\fBsmf\fR(5)
-.SH NOTES
-.sp
-.LP
-The \fBwpad\fR service is managed by the service management facility,
-\fBsmf\fR(5), under the service identifier:
-.sp
-.in +2
-.nf
-svc:/network/wpa:\fI<link>\fR
-.fi
-.in -2
-.sp
-
-.sp
-.LP
-Administrative actions on this service, such as enabling, disabling, or
-requesting restart, can be performed using \fBsvcadm\fR(1M). The service's
-status can be queried using the \fBsvcs\fR(1) command.
--- a/usr/src/man/man7d/Makefile	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/man/man7d/Makefile	Wed May 29 08:31:24 2013 +0200
@@ -89,11 +89,9 @@
 	 	 	nxge.7d		\
 	 	 	ohci.7d		\
 	 	 	openprom.7d	\
-	 	 	pcan.7d		\
 	 	 	pcata.7d	\
 	 	 	pcic.7d		\
 	 	 	pcmcia.7d	\
-	 	 	pcwl.7d		\
 	 	 	physmem.7d	\
 	 	 	pm.7d		\
 	 	 	poll.7d		\
--- a/usr/src/man/man7d/pcan.7d	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,89 +0,0 @@
-'\" te
-.\" Copyright (c) 2007, Sun Microsystems, Inc.  All Rights Reserved
-.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
-.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
-.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH PCAN 7D "Jan 24, 2007"
-.SH NAME
-pcan \- Cisco Aironet 802.11b wireless NIC driver
-.SH DESCRIPTION
-.sp
-.LP
-The \fBpcan\fR wireless NIC driver is a multi-threaded, loadable, clonable,
-GLDv3-based STREAMS driver. It supports the pccard and PCI/MiniPCI cards with
-the Cisco Aironet \fI802.11b\fR chipset. For pccard, the driver works in both
-SPARC and x86 (32-bit/64-bit) modes. For PCI/MiniPCI card, the driver works in
-32-bit x86 mode only.
-.SH DRIVER CONFIGURATION
-.sp
-.LP
-The \fBpcan\fR driver supports \fI802.11b\fR data rates of 1, 2, 5.5 and 11
-(Mbits/sec). The default is 11.
-.sp
-.LP
-The \fBpcan\fR driver supports BSS networks (also known as "ap" or
-"infrastructure" networks) and IBSS networks (also known as "ad-hoc" networks).
-For authentication type, the \fBpcan\fR driver supports the "open" (or
-"open-system") mode. For encryption type, only WEP is currently supported. You
-perform configuration and administration tasks using the \fBdladm\fR(1M) and
-\fBwificonfig\fR(1M) utilities.
-.SH FILES
-.sp
-.ne 2
-.na
-\fB\fB/dev/pcan*\fR\fR
-.ad
-.RS 28n
-Special character device.
-.RE
-
-.sp
-.ne 2
-.na
-\fB/kernel/drv/pcan \fR
-.ad
-.RS 28n
-32-bit ELF kernel module (x86).
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB/kernel/drv/amd64/pcan\fR\fR
-.ad
-.RS 28n
-64-bit ELF kernel module (x86).
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB/kernel/drv/sparcv9/pcan\fR\fR
-.ad
-.RS 28n
-64-bit ELF kernel module (SPARC).
-.RE
-
-.SH ATTRIBUTES
-.sp
-.LP
-See \fBattributes\fR(5) for a description of the following attributes:
-.sp
-
-.sp
-.TS
-box;
-c | c
-l | l .
-ATTRIBUTE TYPE	ATTRIBUTE VALUE
-_
-Architecture	x86
-.TE
-
-.SH SEE ALSO
-.sp
-.LP
-\fBdladm\fR(1M), \fBwificonfig\fR(1M), \fBattributes\fR(5), \fBgld\fR(7D)
-.sp
-.LP
-\fI802.11b Standard for Wireless Local Area Networks (WLANs)\fR - IEEE
--- a/usr/src/man/man7d/pcwl.7d	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,88 +0,0 @@
-'\" te
-.\" Copyright (c) 2007, Sun Microsystems, Inc.  All Rights Reserved
-.\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License.
-.\" You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.  See the License for the specific language governing permissions and limitations under the License.
-.\" When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH PCWL 7D "Jan 24, 2007"
-.SH NAME
-pcwl \- Lucent/PrismII 802.11b wireless NIC driver
-.SH DESCRIPTION
-.sp
-.LP
-The  \fBpcwl\fR  \fI802.11b\fR wireless NIC driver is a multi- threaded,
-loadable, clonable, GLDv3-based STREAMS driver. It supports the pccard and
-PCI/MiniPCI cards with the Lucent and PrismII \fI802.11b\fR chipsets on x86 and
-SPARC.
-.SH DRIVER CONFIGURATION
-.sp
-.LP
-The \fBpcwl\fR driver supports \fI802.11b\fR data rates of 1, 2, 5.5 and 11
-(Mbits/sec). The default is 11.
-.sp
-.LP
-The \fBpcwl\fR driver supports BSS networks (also known as "ap" or
-"infrastructure" networks) and IBSS (or "ad-hoc") networks. For authentication
-type, the \fBpcwl\fR driver supports the "open" (or "open-system") mode and the
-"shared-key" mode. For encryption type, only WEP is currently supported. You
-perform configuration and administration tasks using the \fBdladm\fR(1M) and
-\fBwificonfig\fR(1M) utilities.
-.SH FILES
-.sp
-.ne 2
-.na
-\fB\fB/dev/pcwl*\fR\fR
-.ad
-.RS 28n
-Special character device.
-.RE
-
-.sp
-.ne 2
-.na
-\fB/kernel/drv/pcwl \fR
-.ad
-.RS 28n
-32-bit ELF kernel module (x86).
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB/kernel/drv/amd64/pcwl\fR\fR
-.ad
-.RS 28n
-64-bit ELF kernel module (x86).
-.RE
-
-.sp
-.ne 2
-.na
-\fB\fB/kernel/drv/sparcv9/pcwl\fR\fR
-.ad
-.RS 28n
-64-bit ELF kernel module (SPARC).
-.RE
-
-.SH ATTRIBUTES
-.sp
-.LP
-See \fBattributes\fR(5) for a description of the following attributes:
-.sp
-
-.sp
-.TS
-box;
-c | c
-l | l .
-ATTRIBUTE TYPE	ATTRIBUTE VALUE
-_
-Architecture	x86
-.TE
-
-.SH SEE ALSO
-.sp
-.LP
-\fBdladm\fR(1M), \fBwificonfig\fR(1M), \fBattributes\fR(5), \fBgld\fR(7D)
-.sp
-.LP
-\fI802.11b Standard for Wireless Local Area Networks (WLANs)\fR - IEEE
--- a/usr/src/pkg/manifests/SUNWcs.mf	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/pkg/manifests/SUNWcs.mf	Wed May 29 08:31:24 2013 +0200
@@ -1115,8 +1115,6 @@
 file path=usr/lib/help/auths/locale/C/SysShutdown.html
 file path=usr/lib/help/auths/locale/C/SysSyseventRead.html
 file path=usr/lib/help/auths/locale/C/SysSyseventWrite.html
-file path=usr/lib/help/auths/locale/C/WifiConfig.html
-file path=usr/lib/help/auths/locale/C/WifiWep.html
 file path=usr/lib/help/auths/locale/C/ZoneCloneFrom.html
 file path=usr/lib/help/auths/locale/C/ZoneHeader.html
 file path=usr/lib/help/auths/locale/C/ZoneLogin.html
--- a/usr/src/pkg/manifests/SUNWpcan.mf	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/pkg/manifests/SUNWpcan.mf	Wed May 29 08:31:24 2013 +0200
@@ -23,7 +23,8 @@
 # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
+# Was renamed to driver/network/pcan, both are now obsolete.
+
 set name=pkg.fmri value=pkg:/SUNWpcan@0.5.11,5.11-0.133
-set name=pkg.renamed value=true
+set name=pkg.obsolete value=true
 set name=variant.arch value=$(ARCH)
-depend fmri=pkg:/driver/network/pcan@0.5.11,5.11-0.133 type=require
--- a/usr/src/pkg/manifests/SUNWpcwl.mf	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/pkg/manifests/SUNWpcwl.mf	Wed May 29 08:31:24 2013 +0200
@@ -1,3 +1,4 @@
+
 #
 # CDDL HEADER START
 #
@@ -23,7 +24,8 @@
 # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
+# Was renamed to driver/network/pcwl, both are now obsolete.
+
 set name=pkg.fmri value=pkg:/SUNWpcwl@0.5.11,5.11-0.133
-set name=pkg.renamed value=true
+set name=pkg.obsolete value=true
 set name=variant.arch value=$(ARCH)
-depend fmri=pkg:/driver/network/pcwl@0.5.11,5.11-0.133 type=require
--- a/usr/src/pkg/manifests/SUNWwlan.mf	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/pkg/manifests/SUNWwlan.mf	Wed May 29 08:31:24 2013 +0200
@@ -23,7 +23,8 @@
 # Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
 #
 
+# Was renamed to pkg:/system/network/wificonfig, both are now obsolete.
+
 set name=pkg.fmri value=pkg:/SUNWwlan@0.5.11,5.11-0.133
-set name=pkg.renamed value=true
+set name=pkg.obsolete value=true
 set name=variant.arch value=$(ARCH)
-depend fmri=pkg:/system/network/wificonfig@0.5.11,5.11-0.133 type=require
--- a/usr/src/pkg/manifests/SUNWwpa.mf	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/pkg/manifests/SUNWwpa.mf	Wed May 29 08:31:24 2013 +0200
@@ -26,4 +26,4 @@
 set name=pkg.fmri value=pkg:/SUNWwpa@0.5.11,5.11-0.133
 set name=pkg.renamed value=true
 set name=variant.arch value=$(ARCH)
-depend fmri=pkg:/service/network/wpa@0.5.11,5.11-0.133 type=require
+depend fmri=pkg:/service/network/wpa_supplicant@$(PKGVERS) type=require
--- a/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/pkg/manifests/consolidation-osnet-osnet-message-files.mf	Wed May 29 08:31:24 2013 +0200
@@ -210,8 +210,6 @@
 file path=usr/lib/help/auths/locale/TNDaemon.html
 file path=usr/lib/help/auths/locale/TNctl.html
 file path=usr/lib/help/auths/locale/ValueTND.html
-file path=usr/lib/help/auths/locale/WifiConfig.html
-file path=usr/lib/help/auths/locale/WifiWep.html
 file path=usr/lib/help/auths/locale/ZoneCloneFrom.html
 file path=usr/lib/help/auths/locale/ZoneHeader.html
 file path=usr/lib/help/auths/locale/ZoneLogin.html
--- a/usr/src/pkg/manifests/driver-network-pcan.mf	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/pkg/manifests/driver-network-pcan.mf	Wed May 29 08:31:24 2013 +0200
@@ -30,25 +30,5 @@
 #
 <include global_zone_only_component>
 set name=pkg.fmri value=pkg:/driver/network/pcan@$(PKGVERS)
-set name=pkg.description value="Cisco-Aironet 802.11b driver"
-set name=pkg.summary value="Cisco-Aironet 802.11b driver"
-set name=info.classification \
-    value=org.opensolaris.category.2008:Drivers/Networking
+set name=pkg.obsolete value=true
 set name=variant.arch value=$(ARCH)
-dir path=kernel group=sys
-dir path=kernel/drv group=sys
-dir path=kernel/drv/$(ARCH64) group=sys
-dir path=usr/share/man
-dir path=usr/share/man/man7d
-driver name=pcan clone_perms="pcan 0666 root sys" perms="* 0666 root sys" \
-    alias=pccard15f,7 \
-    alias=pccard15f,a \
-    alias=pci14b9,5000 \
-    alias=pci14b9,a504
-file path=kernel/drv/$(ARCH64)/pcan group=sys
-$(i386_ONLY)file path=kernel/drv/pcan group=sys
-file path=usr/share/man/man7d/pcan.7d
-legacy pkg=SUNWpcan desc="Cisco-Aironet 802.11b driver" \
-    name="Cisco-Aironet 802.11b driver"
-license usr/src/uts/common/io/pcan/THIRDPARTYLICENSE \
-    license=usr/src/uts/common/io/pcan/THIRDPARTYLICENSE
--- a/usr/src/pkg/manifests/driver-network-pcwl.mf	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/pkg/manifests/driver-network-pcwl.mf	Wed May 29 08:31:24 2013 +0200
@@ -30,27 +30,5 @@
 #
 <include global_zone_only_component>
 set name=pkg.fmri value=pkg:/driver/network/pcwl@$(PKGVERS)
-set name=pkg.description value="Lucent/PRISM-II 802.11b driver"
-set name=pkg.summary value="Lucent/PRISM-II 802.11b driver"
-set name=info.classification \
-    value=org.opensolaris.category.2008:Drivers/Networking
+set name=pkg.obsolete value=true
 set name=variant.arch value=$(ARCH)
-dir path=kernel group=sys
-dir path=kernel/drv group=sys
-dir path=kernel/drv/$(ARCH64) group=sys
-dir path=usr/share/man
-dir path=usr/share/man/man7d
-driver name=pcwl clone_perms="pcwl 0666 root sys" perms="* 0666 root sys" \
-    alias=pccard138,2 \
-    alias=pccard156,2 \
-    alias=pccardb,7300 \
-    alias=pci1260,3872 \
-    alias=pci1260,3873 \
-    alias=pci1385,4105
-file path=kernel/drv/$(ARCH64)/pcwl group=sys
-$(i386_ONLY)file path=kernel/drv/pcwl group=sys
-file path=usr/share/man/man7d/pcwl.7d
-legacy pkg=SUNWpcwl desc="Lucent/PRISM-II 802.11b driver" \
-    name="Lucent/PRISM-II 802.11b driver"
-license usr/src/uts/common/io/pcwl/THIRDPARTYLICENSE \
-    license=usr/src/uts/common/io/pcwl/THIRDPARTYLICENSE
--- a/usr/src/pkg/manifests/service-network-wpa.mf	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/pkg/manifests/service-network-wpa.mf	Wed May 29 08:31:24 2013 +0200
@@ -24,30 +24,6 @@
 #
 
 set name=pkg.fmri value=pkg:/service/network/wpa@$(PKGVERS)
-set name=pkg.description \
-    value="The service implements the IEEE802.11i (WPA/WPA2) specification."
-set name=pkg.summary value="Wireless WPA Supplicant"
-set name=info.classification \
-    value=org.opensolaris.category.2008:System/Hardware
+set name=pkg.renamed value=true
 set name=variant.arch value=$(ARCH)
-dir path=lib
-dir path=lib/svc
-dir path=lib/svc/manifest group=sys
-dir path=lib/svc/manifest/network group=sys
-dir path=usr group=sys
-dir path=usr/lib
-dir path=usr/lib/inet
-dir path=usr/share/man/man1m
-file path=lib/svc/manifest/network/wpa.xml group=sys mode=0444
-file path=usr/lib/inet/wpad mode=0555
-file path=usr/share/man/man1m/wpad.1m
-legacy pkg=SUNWwpar \
-    desc="The service implements the IEEE802.11i (WPA/WPA2) specification." \
-    name="Wireless WPA Supplicant, (Root)"
-legacy pkg=SUNWwpau \
-    desc="The service implements the IEEE802.11i (WPA/WPA2) specification." \
-    name="Wireless WPA Supplicant, (Usr)"
-license cr_Sun license=cr_Sun
-license lic_CDDL license=lic_CDDL
-license usr/src/cmd/cmd-inet/usr.lib/wpad/THIRDPARTYLICENSE \
-    license=usr/src/cmd/cmd-inet/usr.lib/wpad/THIRDPARTYLICENSE
+depend fmri=pkg:/service/network/wpa_supplicant@$(PKGVERS) type=require
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/pkg/manifests/service-network-wpa_supplicant.mf	Wed May 29 08:31:24 2013 +0200
@@ -0,0 +1,59 @@
+#
+# CDDL HEADER START
+#
+# The contents of this file are subject to the terms of the
+# Common Development and Distribution License (the "License").
+# You may not use this file except in compliance with the License.
+#
+# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+# or http://www.opensolaris.org/os/licensing.
+# See the License for the specific language governing permissions
+# and limitations under the License.
+#
+# When distributing Covered Code, include this CDDL HEADER in each
+# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+# If applicable, add the following below this CDDL HEADER, with the
+# fields enclosed by brackets "[]" replaced with your own identifying
+# information: Portions Copyright [yyyy] [name of copyright owner]
+#
+# CDDL HEADER END
+#
+
+#
+# Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
+#
+<include global_zone_only_component>
+set name=pkg.fmri value=pkg:/service/network/wpa_supplicant@$(PKGVERS)
+set name=pkg.description \
+    value="The service implements the IEEE802.11i (WPA/WPA2) specification."
+set name=pkg.summary value="Wireless WPA Supplicant"
+set name=info.classification \
+    value=org.opensolaris.category.2008:System/Hardware
+set name=variant.arch value=$(ARCH)
+dir path=lib
+dir path=lib/svc
+dir path=lib/svc/manifest group=sys
+dir path=lib/svc/manifest/network group=sys
+dir path=lib/svc/method
+dir path=usr group=sys
+dir path=usr/lib
+dir path=usr/lib/inet
+file path=lib/svc/manifest/network/wpa_supplicant.xml mode=0444
+file path=lib/svc/method/svc-wpa_supplicant mode=0555
+file path=usr/lib/inet/wpa_supplicant mode=0555
+legacy pkg=SUNWwpar \
+    desc="The service implements the IEEE802.11i (WPA/WPA2) specification." \
+    name="Wireless WPA Supplicant, (Root)"
+legacy pkg=SUNWwpau \
+    desc="The service implements the IEEE802.11i (WPA/WPA2) specification." \
+    name="Wireless WPA Supplicant, (Usr)"
+license cr_Sun license=cr_Sun
+license lic_CDDL license=lic_CDDL
+license usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/THIRDPARTYLICENSE \
+    license=usr/src/cmd/cmd-inet/usr.lib/wpa_supplicant/THIRDPARTYLICENSE
+depend fmri=SUNWcs type=require
+depend fmri=SUNWcsd type=require
+depend fmri=system/library type=require
+depend fmri=system/library/platform type=require
+depend fmri=system/library/processor type=require
--- a/usr/src/pkg/manifests/system-network-wificonfig.mf	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/pkg/manifests/system-network-wificonfig.mf	Wed May 29 08:31:24 2013 +0200
@@ -24,19 +24,5 @@
 #
 
 set name=pkg.fmri value=pkg:/system/network/wificonfig@$(PKGVERS)
-set name=pkg.description value="wifi config tool"
-set name=pkg.summary value="wifi config tool"
-set name=info.classification \
-    value="org.opensolaris.category.2008:System/Administration and Configuration"
+set name=pkg.obsolete value=true
 set name=variant.arch value=$(ARCH)
-dir path=sbin group=sys
-dir path=usr group=sys
-dir path=usr/sbin
-dir path=usr/share/man/man1m
-file path=sbin/wificonfig mode=4755
-file path=usr/share/man/man1m/wificonfig.1m
-legacy pkg=SUNWwlanr desc="wifi config tool binaries" name="wifi config tool"
-legacy pkg=SUNWwlanu desc="wifi config tool" name="wifi config tool"
-license cr_Sun license=cr_Sun
-license lic_CDDL license=lic_CDDL
-link path=usr/sbin/wificonfig target=../../sbin/wificonfig
--- a/usr/src/uts/common/Makefile.files	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/Makefile.files	Wed May 29 08:31:24 2013 +0200
@@ -1708,14 +1708,10 @@
 
 PCS_OBJS += pcs.o
 
-PCAN_OBJS += pcan.o
-
 PCATA_OBJS += pcide.o pcdisk.o pclabel.o pcata.o
 
 PCSER_OBJS += pcser.o pcser_cis.o
 
-PCWL_OBJS += pcwl.o
-
 PSET_OBJS +=	pset.o
 
 OHCI_OBJS += ohci.o ohci_hub.o ohci_polled.o
--- a/usr/src/uts/common/Makefile.rules	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/Makefile.rules	Wed May 29 08:31:24 2013 +0200
@@ -968,18 +968,10 @@
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
-$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/pcan/%.c
-	$(COMPILE.c) -o $@ $<
-	$(CTFCONVERT_O)
-
 $(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/pcn/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
 
-$(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/pcwl/%.c
-	$(COMPILE.c) -o $@ $<
-	$(CTFCONVERT_O)
-
 $(OBJS_DIR)/%.o:		$(UTSBASE)/common/io/ppp/sppp/%.c
 	$(COMPILE.c) -o $@ $<
 	$(CTFCONVERT_O)
@@ -2271,15 +2263,9 @@
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/pcmcia/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
-$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/pcan/%.c
-	@($(LHEAD) $(LINT.c) $< $(LTAIL))
-
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/pcn/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
-$(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/pcwl/%.c
-	@($(LHEAD) $(LINT.c) $< $(LTAIL))
-
 $(LINTS_DIR)/%.ln:		$(UTSBASE)/common/io/ppp/sppp/%.c
 	@($(LHEAD) $(LINT.c) $< $(LTAIL))
 
--- a/usr/src/uts/common/inet/wifi_ioctl.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/inet/wifi_ioctl.h	Wed May 29 08:31:24 2013 +0200
@@ -21,10 +21,7 @@
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
- */
-
-/*
- * Macro and date structures defined for 802.11 wifi config tool.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 #ifndef	__WIFI_IOCTL_H
@@ -36,122 +33,37 @@
 extern "C" {
 #endif
 
-#define	MAX_KEY_LENGTH 26
-#define	MAX_ESSID_LENGTH (32 + 1)	/* max essid length is 32 */
-					/* one more for '\0' */
-#define	MAX_CHANNEL_NUM	99
-#define	MAX_RSSI 15
-#define	MAX_NWEPKEYS 4
-#define	NET_802_11 80211
-#define	MAX_BUF_LEN 65536
-#define	MAX_SCAN_SUPPORT_RATES 8
+#define	WPA_DOOR		"/var/run/wpa_door"
+
+#define	MAX_BUF_LEN		65536
+/*
+ * field_offset
+ */
+#define	WIFI_BUF_OFFSET		offsetof(wldp_t, wldp_buf)
+#define	WLDP_BUFSIZE		(MAX_BUF_LEN - WIFI_BUF_OFFSET)
 
 /*
  * ioctls
  */
 #define	WLAN_IOCTL_BASE 0x1000
-#define	WLAN_GET_VERSION (WLAN_IOCTL_BASE + 0x0)
-#define	WLAN_SET_PARAM (WLAN_IOCTL_BASE + 0x2)
-#define	WLAN_GET_PARAM (WLAN_IOCTL_BASE + 0x3)
 #define	WLAN_COMMAND (WLAN_IOCTL_BASE + 0x4)
 
 /*
- * parameters
- */
-#define	WL_PARAMETERS_BASE 0x2000
-#define	WL_BSSID (WL_PARAMETERS_BASE + 0x0)
-#define	WL_ESSID (WL_PARAMETERS_BASE + 0x1)
-#define	WL_NODE_NAME (WL_PARAMETERS_BASE + 0x2)
-#define	WL_PHY_SUPPORT (WL_PARAMETERS_BASE + 0x3)
-#define	WL_PHY_CONFIG (WL_PARAMETERS_BASE + 0x4)
-#define	WL_DOMAIN (WL_PARAMETERS_BASE + 0x5)
-#define	WL_POWER_MODE (WL_PARAMETERS_BASE + 0x6)
-#define	WL_TX_POWER (WL_PARAMETERS_BASE + 0x7)
-#define	WL_RSSI (WL_PARAMETERS_BASE + 0x8)
-#define	WL_RSSI_THRESHOLD (WL_PARAMETERS_BASE + 0x9)
-#define	WL_ESS_LIST (WL_PARAMETERS_BASE + 0xa)
-#define	WL_BSS_TYPE (WL_PARAMETERS_BASE + 0xb)
-#define	WL_CREATE_IBSS (WL_PARAMETERS_BASE + 0xc)
-#define	WL_RTS_THRESHOLD (WL_PARAMETERS_BASE + 0xd)
-#define	WL_SHORT_RETRY (WL_PARAMETERS_BASE + 0xe)
-#define	WL_LONG_RETRY (WL_PARAMETERS_BASE + 0xf)
-#define	WL_BEACON_PERIOD (WL_PARAMETERS_BASE + 0x10)
-#define	WL_TX_LIFETIME (WL_PARAMETERS_BASE + 0x11)
-#define	WL_RX_LIFETIME (WL_PARAMETERS_BASE + 0x12)
-#define	WL_FRAG_THRESHOLD (WL_PARAMETERS_BASE + 0x13)
-#define	WL_VENDOR_ID (WL_PARAMETERS_BASE + 0x14)
-#define	WL_PRODUCT_ID (WL_PARAMETERS_BASE + 0x15)
-#define	WL_NUM_ANTS (WL_PARAMETERS_BASE + 0x16)
-#define	WL_RX_ANTENNA (WL_PARAMETERS_BASE + 0x17)
-#define	WL_TX_ANTENNA (WL_PARAMETERS_BASE + 0x18)
-#define	WL_SUPPORTED_RATES (WL_PARAMETERS_BASE + 0x19)
-#define	WL_DESIRED_RATES (WL_PARAMETERS_BASE + 0x1a)
-#define	WL_WEP_KEY_TAB (WL_PARAMETERS_BASE + 0x1b)
-#define	WL_WEP_KEY_ID (WL_PARAMETERS_BASE + 0x1c)
-#define	WL_WEP_MAPPING_TAB (WL_PARAMETERS_BASE + 0x1d)
-#define	WL_WEP_MAPPING_LEN (WL_PARAMETERS_BASE + 0x1e)
-#define	WL_ENCRYPTION (WL_PARAMETERS_BASE + 0x1f)
-#define	WL_AUTH_MODE (WL_PARAMETERS_BASE + 0x20)
-#define	WL_EXCL_UNENC (WL_PARAMETERS_BASE + 0x21)
-#define	WL_RFMON (WL_PARAMETERS_BASE + 0x22)
-#define	WL_RADIO (WL_PARAMETERS_BASE + 0x23)
-#define	WL_LINKSTATUS (WL_PARAMETERS_BASE + 0x24)
-#define	WL_DEV_DEPEND (WL_PARAMETERS_BASE + 0x25)
-/*
  * commands
  */
 #define	WL_COMMAND_BASE 0x3000
 #define	WL_SCAN (WL_COMMAND_BASE + 0x0)
 #define	WL_DISASSOCIATE (WL_COMMAND_BASE + 0x1)
-#define	WL_REASSOCIATE (WL_COMMAND_BASE + 0x2)
-#define	WL_LOAD_DEFAULTS (WL_COMMAND_BASE + 0x3)
-#define	WL_ASSOCIAT (WL_COMMAND_BASE + 0x4)
 
 /*
- * domains
+ * power mode (not yet supported)
  */
-/* --USA */
-#define	WL_DOMAIN_BASE 0x4000
-#define	WL_DOMAIN_FCC (WL_DOMAIN_BASE + 0x0)
-/* --Canada */
-#define	WL_DOMAIN_DOC (WL_DOMAIN_BASE + 0x1)
-/* --Most of Europe */
-#define	WL_DOMAIN_ETSI (WL_DOMAIN_BASE + 0x2)
-/* --Spain */
-#define	WL_DOMAIN_SPAIN (WL_DOMAIN_BASE + 0x3)
-/* --France */
-#define	WL_DOMAIN_FRANCE (WL_DOMAIN_BASE + 0x4)
-/* --Japan */
-#define	WL_DOMAIN_MKK (WL_DOMAIN_BASE + 0x5)
-
-/*
- * power mode
- */
-
 #define	WL_PM_AM 0x0
 #define	WL_PM_MPS 0x1
 #define	WL_PM_FAST 0x2
 #define	WL_PM_USER 0x3
 
 /*
- * rates
- */
-#define	WL_RATE_BASIC_SET 0x80
-#define	WL_RATE_1M 2
-#define	WL_RATE_2M 4
-#define	WL_RATE_5_5M 11
-#define	WL_RATE_6M 12
-#define	WL_RATE_9M 18
-#define	WL_RATE_11M 22
-#define	WL_RATE_12M 24
-#define	WL_RATE_18M 36
-#define	WL_RATE_22M 44
-#define	WL_RATE_24M 48
-#define	WL_RATE_33M 66
-#define	WL_RATE_36M 72
-#define	WL_RATE_48M 96
-#define	WL_RATE_54M 108
-/*
  * wep operations
  */
 #define	WL_WEP_OPERATION_BASE 0x6000
@@ -163,29 +75,8 @@
 #define	WL_NOENCRYPTION 0x0
 #define	WL_ENC_WEP 0x1
 #define	WL_ENC_WPA 0x2
-#define	WL_OPENSYSTEM 0x1
-#define	WL_SHAREDKEY 0x2
 
 /*
- * linkstatus
- */
-#define	WL_CONNECTED 0x0
-#define	WL_NOTCONNECTED 0x1
-
-/*
- * prives
- */
-#define	WL_PRIV_BASE 0x7000
-#define	WL_PRIV_RW (WL_PRIV_BASE + 0x0)
-#define	WL_PRIV_R (WL_PRIV_BASE + 0x1)
-#define	WL_PRIV_W (WL_PRIV_BASE + 0x2)
-#define	WL_PRIV_INT (WL_PRIV_BASE + 0x3)
-#define	WL_PRIV_INT_ARRAY (WL_PRIV_BASE + 0x4)
-#define	WL_PRIV_BYTE (WL_PRIV_BASE + 0x5)
-#define	WL_PRIV_BYTE_ARRAY (WL_PRIV_BASE + 0x6)
-#define	WL_PRIV_STRING (WL_PRIV_BASE + 0x7)
-#define	WL_PRIV_STRING_ARRAY (WL_PRIV_BASE + 0x8)
-/*
  * return values
  */
 #define	WL_SUCCESS 0x0
@@ -208,29 +99,57 @@
 #define	WL_HRDS (WL_OTHER_BASE + 0x4)
 #define	WL_ERP (WL_OTHER_BASE + 0x5)
 
-#define	WL_BSS_BSS 1
-#define	WL_BSS_IBSS 3
-#define	WL_BSS_ANY 2
-/*
- * field_offset
- */
-#define	WIFI_BUF_OFFSET		offsetof(wldp_t, wldp_buf)
+/* common definitions (as in wpa_s driver.h) */
+#define	IEEE80211_MODE_INFRA	0
+#define	IEEE80211_MODE_IBSS	1
+#define	IEEE80211_MODE_AP	2
+
+#define	IEEE80211_CAP_ESS	0x0001
+#define	IEEE80211_CAP_IBSS	0x0002
+#define	IEEE80211_CAP_PRIVACY	0x0010
+
+/* space for both wpa tx+rx keys */
+#define	IEEE80211I_KEY_SIZE	16
+#define	IEEE80211I_MIC_SIZE	(8+8)
+
+/* supported event types (as in wpa_s driver.h) */
+enum wl_net80211_events {
+	NET80211_EVENT_ASSOC = 0,
+	NET80211_EVENT_DISASSOC = 1,
+	NET80211_EVENT_SCAN_RESULTS = 3,
+	NET80211_EVENT_INTERFACE_STATUS = 5,
+	NET80211_EVENT_ASSOC_REJECT = 13,
+	NET80211_EVENT_ASSOC_TIMED_OUT = 15
+};
 
 /*
- * type definationes
+ * type definitions
  */
 typedef boolean_t wl_create_ibss_t;
-typedef char wl_bssid_t[6];
+typedef boolean_t wl_wpa_t;
+typedef boolean_t wl_radio_t;
+typedef boolean_t wl_counterm_t;
+typedef boolean_t wl_linkstatus_t;
+typedef uint8_t wl_rssi_t; /* 0->127 */ /* driver specific */
+typedef uint8_t wl_bss_type_t;
+typedef uint8_t wl_authmode_t;
+typedef uint8_t wl_encryption_t;
+typedef uint16_t wl_beacon_period_t;
+typedef uint32_t wl_beacon_age_t;
+typedef uint64_t wl_beacon_tsf_t;
+/* ieee80211com */
+typedef uint32_t wl_capability_t;
+/* ieee80211node */
+typedef uint16_t wl_node_caps_t;
+
+typedef struct wl_bssid {
+	uint8_t wl_bssid_bssid[8];
+} wl_bssid_t;
 
 typedef struct wl_essid {
 	uint32_t wl_essid_length;
-	char wl_essid_essid[34];
-}wl_essid_t;
-
-typedef struct wl_nodename {
-	uint32_t wl_nodename_length;
-	char wl_nodename_name[34];
-} wl_nodename_t;
+	uint8_t wl_essid_essid[32];
+} wl_essid_t;
 
 typedef struct wl_phy_supported {
 	uint32_t wl_phy_support_num;
@@ -239,7 +158,7 @@
 
 typedef struct wl_fhss {
 	uint32_t wl_fhss_subtype;
-	uint32_t wl_fhss_channel;
+	uint32_t wl_fhss_frequency;
 	uint32_t wl_fhss_hoptime;
 	uint32_t wl_fhss_hoppattern;
 	uint32_t wl_fhss_hopset;
@@ -248,7 +167,7 @@
 
 typedef struct wl_dsss {
 	uint32_t wl_dsss_subtype;
-	uint32_t wl_dsss_channel;
+	uint32_t wl_dsss_frequency;
 	boolean_t wl_dsss_have_short_preamble;
 	uint32_t wl_dsss_preamble_mode;
 	boolean_t wl_dsss_agility_enabled;
@@ -265,7 +184,7 @@
 
 typedef struct wl_erp {
 	uint32_t wl_erp_subtype;
-	uint32_t wl_erp_channel;
+	uint32_t wl_erp_frequency;
 	boolean_t wl_erp_have_short_preamble;
 	uint32_t wl_erp_preamble_mode;
 	boolean_t wl_erp_have_agility;
@@ -286,8 +205,6 @@
 	wl_erp_t wl_phy_erp_conf;
 } wl_phy_conf_t;
 
-typedef uint32_t wl_domain_t;
-
 typedef struct wl_ps_mode {
 	uint32_t wl_ps_mode;
 	uint32_t wl_ps_max_sleep;
@@ -297,89 +214,92 @@
 	boolean_t wl_ps_nobroadcast;
 } wl_ps_mode_t;
 
-typedef uint32_t wl_linkstatus_t;
-typedef uint32_t wl_tx_pwer_t;
-typedef uint32_t wl_rssi_t;
-typedef uint32_t wl_rssi_threshold_t;
-typedef uint32_t wl_bss_type_t;
-typedef uint32_t wl_authmode_t;
-typedef uint32_t wl_encryption_t;
-typedef uint32_t wl_wep_key_id_t;
-typedef boolean_t wl_radio_t;
-typedef uint32_t wl_rts_threshold_t;
-typedef uint32_t wl_short_retry_t;
-typedef uint32_t wl_long_retry_t;
-typedef uint32_t wl_beacon_period_t;
-typedef uint32_t wl_tx_lifetime_t;
-typedef uint32_t wl_rx_lifetime_t;
-typedef uint32_t wl_frag_threshold_t;
-typedef char wl_vendor_t[128];
-typedef char wl_product_t[128];
-typedef uint32_t wl_num_ants_t;
-typedef uint32_t wl_rx_antenna_t;
-typedef uint32_t wl_tx_antenna_t;
-
 typedef struct wl_rates {
-	uint32_t wl_rates_num;
-	char wl_rates_rates[1];
+	uint8_t wl_rates_num;
+	uint8_t wl_rates_rates[15];  /* 0->127 */
 } wl_rates_t;
 
+/*
+ * Macro and data structures defined for 802.11i.
+ */
+typedef struct wl_wpa_ie {
+	uint8_t		wpa_ie[40];
+	uint8_t		wpa_ie_len;
+} wl_wpa_ie_t;
+
+/*
+ * WPA/RSN get/set key request.
+ * ik_type  : wep/tkip/aes
+ * ik_keyix : should be between 0 and 3, 0 will be used as default key.
+ * ik_keylen: key length in bytes.
+ * ik_keydata and ik_keylen include the DATA key and MIC key.
+ * ik_keyrsc/ik_keytsc: rx/tx seq number.
+ */
+#pragma pack(1)
+typedef struct wl_key {
+	uint8_t		ik_type;
+
+	uint8_t		ik_keylen;
+	uint16_t	ik_keyix;
+
+	uint16_t	ik_flags;
+
+	uint8_t		ik_macaddr[6];
+	uint64_t	ik_keyrsc;
+	uint64_t	ik_keytsc;
+
+	uint8_t		ik_keydata[IEEE80211I_KEY_SIZE+IEEE80211I_MIC_SIZE];
+} wl_key_t;
+#pragma pack()
+
+/* wpa only */
+typedef struct wl_del_key {
+	uint8_t		idk_keyix;
+	uint8_t		idk_macaddr[6];
+} wl_del_key_t;
+
+/*
+ * structure for WL_MLME state manipulation request.
+ * im_op: operations include auth/deauth/assoc/disassoc,
+ * im_reason: 802.11 reason code
+ */
+typedef struct wl_mlme {
+	uint16_t	im_reason;
+	uint8_t		im_macaddr[6];
+	uint8_t		im_op;
+} wl_mlme_t;
+
+/*
+ * beacon, probe response info
+ */
+#pragma pack(1)
 typedef struct wl_ess_conf {
-	uint32_t wl_ess_conf_length;
-	wl_essid_t wl_ess_conf_essid;
-	wl_bssid_t wl_ess_conf_bssid;
-	char wl_ess_conf_reserved[2];
-	wl_bss_type_t wl_ess_conf_bsstype;
-	wl_authmode_t wl_ess_conf_authmode;
-	boolean_t wl_ess_conf_wepenabled;
-	wl_rssi_t wl_ess_conf_sl;
-	union {
-		wl_fhss_t wl_phy_fhss_conf;
-		wl_dsss_t wl_phy_dsss_conf;
-		wl_ofdm_t wl_phy_ofdm_conf;
-		wl_erp_t wl_phy_erp_conf;
-	} wl_phy_conf;
-	char wl_supported_rates[MAX_SCAN_SUPPORT_RATES];
+	wl_essid_t 		wl_ess_conf_essid;
+	wl_bssid_t 		wl_ess_conf_bssid;
+	wl_beacon_tsf_t		wl_ess_conf_beacon_tsf;
+	wl_beacon_age_t		wl_ess_conf_beacon_age;
+	wl_rates_t		wl_ess_conf_rates;
+	wl_node_caps_t 		wl_ess_conf_caps;
+	wl_beacon_period_t	wl_ess_conf_beacon_period;
+	wl_phy_conf_t		wl_ess_conf_phys;
+	wl_wpa_ie_t		wl_ess_conf_wpa_ie;
+	wl_rssi_t 		wl_ess_conf_sl;
 } wl_ess_conf_t;
+#pragma pack()
 
 typedef struct wl_ess_list {
-	uint32_t wl_ess_list_num;
+	uint16_t wl_ess_list_size;
+	uint16_t wl_ess_list_num;
 	wl_ess_conf_t wl_ess_list_ess[1];
 } wl_ess_list_t;
 
 typedef struct wl_wep_key {
-	uint32_t wl_wep_length;
-	char wl_wep_key[MAX_KEY_LENGTH];
-	uint32_t wl_wep_operation;
+	uint16_t wl_wep_length;
+	uint16_t wl_wep_operation;
+	uint8_t	 wl_wep_keyval[26];
 } wl_wep_key_t;
-typedef wl_wep_key_t wl_wep_key_tab_t[MAX_NWEPKEYS];
-
-typedef struct wep_mapping {
-	uint32_t wl_wep_map_index;
-	boolean_t wl_wep_map_wepon;
-	char wl_wep_map_mac_addr[6];
-	char wl_wep_map_reserved[2];
-	wl_wep_key_t wl_wep_map_wepkey;
-} wep_mapping_t;
-typedef wep_mapping_t wep_mapping_tab_t[1];
 
-typedef struct wl_priv_param {
-	char wl_priv_name[8];
-	uint32_t wl_priv_type;
-	uint32_t wl_priv_size;
-	char wl_priv_value[1];
-} wl_priv_param_t;
-
-typedef struct wl_dev_depend {
-	uint32_t wl_dev_depend_num;
-	uint32_t wl_dev_depend_ret_idx;
-	wl_priv_param_t wl_dev_depend_priv[1];
-} wl_dev_depend_t;
-
-typedef struct wlan_ver {
-	uint32_t wl_ver_major;
-	uint32_t wl_ver_minor;
-} wlan_ver_t;
+typedef wl_wep_key_t wl_wep_key_tab_t[4];
 
 typedef struct wldp {
 	uint32_t wldp_length;
@@ -389,6 +309,13 @@
 	uint32_t wldp_buf[1];
 } wldp_t;
 
+/* event data passed through wpa door */
+typedef struct wl_event {
+	uint32_t wpa_ev_type;
+	uint16_t wpa_ev_reason;
+	uint8_t	wpa_ev_beacon[6];
+} wl_event_t;
+
 #ifdef __cplusplus
 }
 #endif
--- a/usr/src/uts/common/io/arn/arn_main.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/io/arn/arn_main.c	Wed May 29 08:31:24 2013 +0200
@@ -3162,10 +3162,8 @@
 	ic->ic_flags |= IEEE80211_F_DATAPAD;
 	/* Support WPA/WPA2 */
 	ic->ic_caps |= IEEE80211_C_WPA;
-#if 0
 	ic->ic_caps |= IEEE80211_C_TXFRAG; /* handle tx frags */
 	ic->ic_caps |= IEEE80211_C_BGSCAN; /* capable of bg scanning */
-#endif
 	ic->ic_phytype = IEEE80211_T_HT;
 	ic->ic_opmode = IEEE80211_M_STA;
 	ic->ic_state = IEEE80211_S_INIT;
--- a/usr/src/uts/common/io/arn/arn_recv.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/io/arn/arn_recv.c	Wed May 29 08:31:24 2013 +0200
@@ -615,19 +615,7 @@
 				    ds->ds_rxstat.rs_rssi;
 		}
 
-		/*
-		 * signal (13-15) DLADM_WLAN_STRENGTH_EXCELLENT
-		 * signal (10-12) DLADM_WLAN_STRENGTH_VERY_GOOD
-		 * signal (6-9)    DLADM_WLAN_STRENGTH_GOOD
-		 * signal (3-5)    DLADM_WLAN_STRENGTH_WEAK
-		 * signal (0-2)    DLADM_WLAN_STRENGTH_VERY_WEAK
-		 */
-		if (rs->rs_rssi == 0)
-			cur_signal = 0;
-		else if (rs->rs_rssi >= 45)
-			cur_signal = MAX_RSSI;
-		else
-			cur_signal = rs->rs_rssi * MAX_RSSI / 45 + 1;
+		cur_signal = rs->rs_rssi;
 
 		/*
 		 * Send the frame to net80211 for processing
--- a/usr/src/uts/common/io/dld/dld_drv.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/io/dld/dld_drv.c	Wed May 29 08:31:24 2013 +0200
@@ -1168,7 +1168,10 @@
 	sobjp = &ssp->ss_obj;
 
 	if (sobjp->so_class != DLD_SECOBJ_CLASS_WEP &&
-	    sobjp->so_class != DLD_SECOBJ_CLASS_WPA)
+	    sobjp->so_class != DLD_SECOBJ_CLASS_PSK &&
+	    sobjp->so_class != DLD_SECOBJ_CLASS_TLS &&
+	    sobjp->so_class != DLD_SECOBJ_CLASS_TTLS &&
+	    sobjp->so_class != DLD_SECOBJ_CLASS_PEAP)
 		return (EINVAL);
 
 	if (sobjp->so_name[DLD_SECOBJ_NAME_MAX - 1] != '\0' ||
--- a/usr/src/uts/common/io/ipw/ipw2100.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/io/ipw/ipw2100.c	Wed May 29 08:31:24 2013 +0200
@@ -163,11 +163,8 @@
  * IOCTL Handler
  */
 static int	ipw2100_ioctl(struct ipw2100_softc *sc, queue_t *q, mblk_t *m);
-static int	ipw2100_getset(struct ipw2100_softc *sc,
-    mblk_t *m, uint32_t cmd, boolean_t *need_net80211);
-static int	ipw_wificfg_radio(struct ipw2100_softc *sc,
-    uint32_t cmd,  wldp_t *outfp);
-static int	ipw_wificfg_desrates(wldp_t *outfp);
+static int	ipw2100_getset(struct ipw2100_softc *sc, mblk_t *m,
+    boolean_t *need_net80211);
 static int	ipw_wificfg_disassoc(struct ipw2100_softc *sc,
     wldp_t *outfp);
 
@@ -925,7 +922,7 @@
 	/*
 	 * use the value set to ic_bss to retrieve current sharedmode
 	 */
-	sec.authmode = (ic->ic_bss->in_authmode == WL_SHAREDKEY) ?
+	sec.authmode = (ic->ic_bss->in_authmode == IEEE80211_AUTH_SHARED) ?
 	    IPW2100_AUTH_SHARED : IPW2100_AUTH_OPEN;
 	sec.ciphers = LE_32(IPW2100_CIPHER_NONE);
 	IPW2100_DBG(IPW2100_DBG_WIFI, (sc->sc_dip, CE_CONT,
@@ -2326,12 +2323,8 @@
 	cmd = iocp->ioc_cmd;
 	need_privilege = B_TRUE;
 	switch (cmd) {
-	case WLAN_SET_PARAM:
 	case WLAN_COMMAND:
 		break;
-	case WLAN_GET_PARAM:
-		need_privilege = B_FALSE;
-		break;
 	default:
 		IPW2100_DBG(IPW2100_DBG_IOCTL, (sc->sc_dip, CE_CONT,
 		    "ieee80211_ioctl(): unknown cmd 0x%x", cmd));
@@ -2362,7 +2355,7 @@
 	}
 
 	need_net80211 = B_FALSE;
-	ret = ipw2100_getset(sc, m0, cmd, &need_net80211);
+	ret = ipw2100_getset(sc, m0, &need_net80211);
 	if (!need_net80211) {
 		len = msgdsize(m0);
 
@@ -2380,8 +2373,7 @@
 }
 
 static int
-ipw2100_getset(struct ipw2100_softc *sc, mblk_t *m, uint32_t cmd,
-	boolean_t *need_net80211)
+ipw2100_getset(struct ipw2100_softc *sc, mblk_t *m, boolean_t *need_net80211)
 {
 	wldp_t		*infp, *outfp;
 	uint32_t	id;
@@ -2396,19 +2388,6 @@
 	    "ipw2100_getset(): id = 0x%x\n", id));
 	switch (id) {
 	/*
-	 * which is not supported by net80211, so it
-	 * has to be handled from driver side
-	 */
-	case WL_RADIO:
-		ret = ipw_wificfg_radio(sc, cmd, outfp);
-		break;
-	/*
-	 * so far, drier doesn't support fix-rates
-	 */
-	case WL_DESIRED_RATES:
-		ret = ipw_wificfg_desrates(outfp);
-		break;
-	/*
 	 * current net80211 implementation clears the bssid while
 	 * this command received, which will result in the all zero
 	 * mac address for scan'ed AP which is just disconnected.
@@ -2440,12 +2419,11 @@
 		 * do is to check radio status firstly.  If radio is ON, pass
 		 * it to net80211, otherwise, return to upper layer directly.
 		 *
-		 * Considering the WL_SUCCESS also means WL_CONNECTED for
+		 * Considering the WL_SUCCESS also means CONNECTED for
 		 * checking linkstatus, one exception for WL_LINKSTATUS is to
 		 * let net80211 handle it.
 		 */
-		if ((ipw2100_get_radio(sc) == 0) &&
-		    (id != WL_LINKSTATUS)) {
+		if (ipw2100_get_radio(sc) == 0) {
 
 			IPW2100_REPORT((sc->sc_dip, CE_WARN,
 			    "ipw: RADIO is OFF\n"));
@@ -2549,36 +2527,6 @@
 }
 
 static int
-ipw_wificfg_radio(struct ipw2100_softc *sc, uint32_t cmd, wldp_t *outfp)
-{
-	uint32_t	ret = ENOTSUP;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		*(wl_linkstatus_t *)(outfp->wldp_buf) = ipw2100_get_radio(sc);
-		outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t);
-		outfp->wldp_result = WL_SUCCESS;
-		ret = 0; /* command sucess */
-		break;
-	case WLAN_SET_PARAM:
-	default:
-		break;
-	}
-	return (ret);
-}
-
-static int
-ipw_wificfg_desrates(wldp_t *outfp)
-{
-	/*
-	 * return success, but with result NOTSUPPORTED
-	 */
-	outfp->wldp_length = WIFI_BUF_OFFSET;
-	outfp->wldp_result = WL_NOTSUPPORTED;
-	return (0);
-}
-
-static int
 ipw_wificfg_disassoc(struct ipw2100_softc *sc, wldp_t *outfp)
 {
 	struct ieee80211com	*ic = &sc->sc_ic;
--- a/usr/src/uts/common/io/iwi/ipw2200.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/io/iwi/ipw2200.c	Wed May 29 08:31:24 2013 +0200
@@ -186,11 +186,8 @@
  * IOCTL Handler
  */
 static int	ipw2200_ioctl(struct ipw2200_softc *sc, queue_t *q, mblk_t *m);
-static int	ipw2200_getset(struct ipw2200_softc *sc,
-    mblk_t *m, uint32_t cmd, boolean_t *need_net80211);
-static int	iwi_wificfg_radio(struct ipw2200_softc *sc,
-    uint32_t cmd,  wldp_t *outfp);
-static int	iwi_wificfg_desrates(wldp_t *outfp);
+static int	ipw2200_getset(struct ipw2200_softc *sc, mblk_t *m,
+    boolean_t *need_net80211);
 
 /*
  * net80211 functions
@@ -1748,7 +1745,7 @@
 	/*
 	 * use the value set to ic_bss to retraive current sharedmode
 	 */
-	if (ic->ic_bss->in_authmode == WL_SHAREDKEY) {
+	if (ic->ic_bss->in_authmode == IEEE80211_AUTH_SHARED) {
 		assoc.auth = (ic->ic_def_txkey << 4) | IPW2200_AUTH_SHARED;
 		IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT,
 		    "ipw2200_auth_and_assoc(): "
@@ -2422,12 +2419,8 @@
 	cmd = iocp->ioc_cmd;
 	need_privilege = B_TRUE;
 	switch (cmd) {
-	case WLAN_SET_PARAM:
 	case WLAN_COMMAND:
 		break;
-	case WLAN_GET_PARAM:
-		need_privilege = B_FALSE;
-		break;
 	default:
 		IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT,
 		    "ipw2200_ioctl(): unknown cmd 0x%x", cmd));
@@ -2467,7 +2460,7 @@
 	}
 
 	need_net80211 = B_FALSE;
-	ret = ipw2200_getset(sc, m0, cmd, &need_net80211);
+	ret = ipw2200_getset(sc, m0, &need_net80211);
 	if (!need_net80211) {
 		len = msgdsize(m0);
 
@@ -2485,8 +2478,7 @@
 }
 
 static int
-ipw2200_getset(struct ipw2200_softc *sc, mblk_t *m, uint32_t cmd,
-	boolean_t *need_net80211)
+ipw2200_getset(struct ipw2200_softc *sc, mblk_t *m, boolean_t *need_net80211)
 {
 	wldp_t		*infp, *outfp;
 	uint32_t	id;
@@ -2500,12 +2492,6 @@
 	IPW2200_DBG(IPW2200_DBG_IOCTL, (sc->sc_dip, CE_CONT,
 	    "ipw2200_getset(): id = 0x%x\n", id));
 	switch (id) {
-	case WL_RADIO: /* which is not supported by net80211 */
-		ret = iwi_wificfg_radio(sc, cmd, outfp);
-		break;
-	case WL_DESIRED_RATES: /* hardware doesn't support fix-rates */
-		ret = iwi_wificfg_desrates(outfp);
-		break;
 	default:
 		/*
 		 * The wifi IOCTL net80211 supported:
@@ -2529,12 +2515,11 @@
 		 * do is to check radio status firstly.  If radio is ON, pass
 		 * it to net80211, otherwise, return to upper layer directly.
 		 *
-		 * Considering the WL_SUCCESS also means WL_CONNECTED for
+		 * Considering the WL_SUCCESS also means CONNECTED for
 		 * checking linkstatus, one exception for WL_LINKSTATUS is to
 		 * let net80211 handle it.
 		 */
-		if ((ipw2200_radio_status(sc) == 0) &&
-		    (id != WL_LINKSTATUS)) {
+		if (ipw2200_radio_status(sc) == 0) {
 
 			IPW2200_REPORT((sc->sc_dip, CE_CONT,
 			    "iwi: radio is OFF\n"));
@@ -2634,34 +2619,6 @@
 	return (err);
 }
 
-static int
-iwi_wificfg_radio(struct ipw2200_softc *sc, uint32_t cmd, wldp_t *outfp)
-{
-	uint32_t	ret = ENOTSUP;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		*(wl_linkstatus_t *)(outfp->wldp_buf) =
-		    ipw2200_radio_status(sc);
-		outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t);
-		outfp->wldp_result = WL_SUCCESS;
-		ret = 0; /* command success */
-		break;
-	case WLAN_SET_PARAM:
-	default:
-		break;
-	}
-	return (ret);
-}
-
-static int
-iwi_wificfg_desrates(wldp_t *outfp)
-{
-	/* return success, but with result NOTSUPPORTED */
-	outfp->wldp_length = WIFI_BUF_OFFSET;
-	outfp->wldp_result = WL_NOTSUPPORTED;
-	return (0);
-}
 /* End of IOCTL Handlers */
 
 void
@@ -2831,7 +2788,7 @@
 		 * scan complete
 		 */
 		sc->sc_flags &= ~IPW2200_FLAG_SCANNING;
-		ieee80211_end_scan(ic);
+		ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
 		break;
 
 	case IPW2200_NOTIF_TYPE_BEACON:
--- a/usr/src/uts/common/io/mac/mac.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/io/mac/mac.c	Wed May 29 08:31:24 2013 +0200
@@ -311,7 +311,6 @@
 #include <sys/pool_pset.h>
 #include <sys/cpupart.h>
 #include <inet/wifi_ioctl.h>
-#include <net/wpa.h>
 
 #define	IMPL_HASHSZ	67	/* prime */
 
@@ -2959,8 +2958,8 @@
 	case MAC_PROP_WL_WPA:
 		minsize = sizeof (wl_wpa_t);
 		break;
-	case MAC_PROP_WL_SCANRESULTS:
-		minsize = sizeof (wl_wpa_ess_t);
+	case MAC_PROP_WL_COUNTERM:
+		minsize = sizeof (boolean_t);
 		break;
 	case MAC_PROP_WL_POWER_MODE:
 		minsize = sizeof (wl_ps_mode_t);
@@ -2977,7 +2976,7 @@
 	case MAC_PROP_WL_CREATE_IBSS:
 		minsize = sizeof (wl_create_ibss_t);
 		break;
-	case MAC_PROP_WL_SETOPTIE:
+	case MAC_PROP_WL_OPTIE:
 		minsize = sizeof (wl_wpa_ie_t);
 		break;
 	case MAC_PROP_WL_DELKEY:
--- a/usr/src/uts/common/io/net80211/net80211.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/io/net80211/net80211.c	Wed May 29 08:31:24 2013 +0200
@@ -44,7 +44,6 @@
 #include <sys/cmn_err.h>
 #include <sys/modctl.h>
 #include <sys/stropts.h>
-#include <sys/door.h>
 #include <sys/mac_provider.h>
 #include "net80211_impl.h"
 
@@ -138,81 +137,6 @@
 }
 
 /*
- * ieee80211_event_thread
- * open door of wpa, send event to wpad service
- */
-static void
-ieee80211_event_thread(void *arg)
-{
-	ieee80211com_t *ic = arg;
-	door_handle_t event_door = NULL;	/* Door for upcalls */
-	wl_events_t ev;
-	door_arg_t darg;
-
-	mutex_enter(&ic->ic_doorlock);
-
-	ev.event = ic->ic_eventq[ic->ic_evq_head];
-	ic->ic_evq_head ++;
-	if (ic->ic_evq_head >= MAX_EVENT)
-		ic->ic_evq_head = 0;
-
-	ieee80211_dbg(IEEE80211_MSG_DEBUG, "ieee80211_event(%d)\n", ev.event);
-	/*
-	 * Locate the door used for upcalls
-	 */
-	if (door_ki_open(ic->ic_wpadoor, &event_door) != 0) {
-		ieee80211_err("ieee80211_event: door_ki_open(%s) failed\n",
-		    ic->ic_wpadoor);
-		goto out;
-	}
-
-	darg.data_ptr = (char *)&ev;
-	darg.data_size = sizeof (wl_events_t);
-	darg.desc_ptr = NULL;
-	darg.desc_num = 0;
-	darg.rbuf = NULL;
-	darg.rsize = 0;
-
-	if (door_ki_upcall_limited(event_door, &darg, NULL, SIZE_MAX, 0) != 0) {
-		ieee80211_err("ieee80211_event: door_ki_upcall() failed\n");
-	}
-
-	if (event_door) {	/* release our hold (if any) */
-		door_ki_rele(event_door);
-	}
-
-out:
-	mutex_exit(&ic->ic_doorlock);
-}
-
-/*
- * Notify state transition event message to WPA daemon
- */
-void
-ieee80211_notify(ieee80211com_t *ic, wpa_event_type event)
-{
-	if ((ic->ic_flags & IEEE80211_F_WPA) == 0)
-		return;		/* Not running on WPA mode */
-
-	ic->ic_eventq[ic->ic_evq_tail] = event;
-	ic->ic_evq_tail ++;
-	if (ic->ic_evq_tail >= MAX_EVENT) ic->ic_evq_tail = 0;
-
-	/* async */
-	(void) timeout(ieee80211_event_thread, (void *)ic, 0);
-}
-
-/*
- * Register WPA door
- */
-void
-ieee80211_register_door(ieee80211com_t *ic, const char *drvname, int inst)
-{
-	(void) snprintf(ic->ic_wpadoor, MAX_IEEE80211STR, "%s_%s%d",
-	    WPA_DOOR, drvname, inst);
-}
-
-/*
  * Default reset method for use with the ioctl support.  This
  * method is invoked after any state change in the 802.11
  * layer that should be propagated to the hardware but not
@@ -347,7 +271,7 @@
 	IEEE80211_LOCK(ic);
 	if ((im->im_mgt_timer != 0) && (--im->im_mgt_timer == 0)) {
 		IEEE80211_UNLOCK(ic);
-		ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+		ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
 		IEEE80211_LOCK(ic);
 	}
 
@@ -643,33 +567,6 @@
 }
 
 /*
- * Send system messages to notify the device has joined a WLAN.
- * This is an OS specific function. Solaris marks link status
- * as up.
- */
-void
-ieee80211_notify_node_join(ieee80211com_t *ic, ieee80211_node_t *in)
-{
-	if (in == ic->ic_bss)
-		mac_link_update(ic->ic_mach, LINK_STATE_UP);
-	ieee80211_notify(ic, EVENT_ASSOC);	/* notify WPA service */
-}
-
-/*
- * Send system messages to notify the device has left a WLAN.
- * This is an OS specific function. Solaris marks link status
- * as down.
- */
-void
-ieee80211_notify_node_leave(ieee80211com_t *ic, ieee80211_node_t *in)
-{
-	if (in == ic->ic_bss)
-		mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
-	ieee80211_notify(ic, EVENT_DISASSOC);	/* notify WPA service */
-}
-
-
-/*
  * Get 802.11 kstats defined in ieee802.11(5)
  *
  * Return 0 on success
@@ -821,6 +718,9 @@
 {
 	struct ieee80211_impl *im = ic->ic_private;
 
+	/* sync */
+	ieee80211_notify_detach(ic);
+
 	ieee80211_stop_watchdog(ic);
 	cv_destroy(&im->im_scan_cv);
 	kmem_free(im, sizeof (ieee80211_impl_t));
--- a/usr/src/uts/common/io/net80211/net80211_crypto.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/io/net80211/net80211_crypto.c	Wed May 29 08:31:24 2013 +0200
@@ -35,8 +35,6 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * IEEE 802.11 generic crypto support
  */
@@ -126,7 +124,7 @@
  *	ieee80211_key_update_end(ic);
  */
 int
-ieee80211_crypto_newkey(ieee80211com_t *ic, int cipher, int flags,
+ieee80211_crypto_newkey(ieee80211com_t *ic, uint8_t cipher, uint16_t flags,
     struct ieee80211_key *key)
 {
 	const struct ieee80211_cipher *cip;
@@ -171,7 +169,7 @@
 	 */
 	if (cipher == IEEE80211_CIPHER_TKIP &&
 	    (ic->ic_caps & IEEE80211_C_TKIPMIC) == 0) {
-		ieee80211_dbg(IEEE80211_MSG_CRYPTO,
+		ieee80211_dbg(IEEE80211_MSG_CRYPTO, "ieee80211_crypto_newkey: "
 		    "no h/w support for TKIP MIC, falling back to s/w\n");
 		flags |= IEEE80211_KEY_SWMIC;
 	}
@@ -190,7 +188,7 @@
 		 * different state and/or attach different method
 		 * pointers.
 		 */
-		key->wk_flags = (uint16_t)flags;
+		key->wk_flags = flags;
 		keyctx = cip->ic_attach(ic, key);
 		if (keyctx == NULL) {
 			ieee80211_dbg(IEEE80211_MSG_CRYPTO, "crypto_setkey: "
@@ -205,7 +203,7 @@
 	/*
 	 * Commit to requested usage so driver can see the flags.
 	 */
-	key->wk_flags = (uint16_t)flags;
+	key->wk_flags = flags;
 
 	/*
 	 * Ask the driver for a key index if we don't have one.
--- a/usr/src/uts/common/io/net80211/net80211_crypto_none.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/io/net80211/net80211_crypto_none.c	Wed May 29 08:31:24 2013 +0200
@@ -35,7 +35,7 @@
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
+#pragma ident   "%Z%%M% %I%     %E% SMI"
 
 /*
  * IEEE 802.11 NULL crypto support.
@@ -95,7 +95,7 @@
 	 * happen, at least, when changing keys.
 	 */
 	ieee80211_dbg(IEEE80211_MSG_CRYPTO, "none_encap: "
-		"key id %u is not set (encap)\n", keyid >> 6);
+	    "key id %u is not set (encap)\n", keyid >> 6);
 	return (0);
 }
 
@@ -111,8 +111,8 @@
 	 * happen, at least, when changing keys.
 	 */
 	ieee80211_dbg(IEEE80211_MSG_CRYPTO, "none_decap"
-		"key id %u is not set (decap)\n",
-		ivp[IEEE80211_WEP_IVLEN] >> 6);
+	    "key id %u is not set (decap)\n",
+	    ivp[IEEE80211_WEP_IVLEN] >> 6);
 	return (0);
 }
 
--- a/usr/src/uts/common/io/net80211/net80211_impl.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/io/net80211/net80211_impl.h	Wed May 29 08:31:24 2013 +0200
@@ -220,14 +220,6 @@
 #define	IEEE80211_FH_CHANPAT(chan)	\
 	((chan) % IEEE80211_FH_CHANMOD)
 
-#define	IEEE80211_NODE_AUTH	0x0001		/* authorized for data */
-#define	IEEE80211_NODE_QOS	0x0002		/* QoS enabled */
-#define	IEEE80211_NODE_ERP	0x0004		/* ERP enabled */
-#define	IEEE80211_NODE_PWR_MGT	0x0010		/* power save mode enabled */
-#define	IEEE80211_NODE_AREF	0x0020		/* authentication ref held */
-
-#define	IEEE80211_MAXRSSI	127
-
 /* Debug Flags */
 #define	IEEE80211_MSG_BRUSSELS  0x80000000	/* BRUSSELS */
 #define	IEEE80211_MSG_DEBUG	0x40000000	/* IFF_DEBUG equivalent */
@@ -401,7 +393,6 @@
 void ieee80211_err(const int8_t *, ...);
 void ieee80211_dbg(uint32_t, const int8_t *, ...);
 
-void ieee80211_notify(ieee80211com_t *, wpa_event_type);
 void ieee80211_mac_update(ieee80211com_t *);
 
 uint64_t ieee80211_read_6(uint8_t, uint8_t, uint8_t, uint8_t, uint8_t, uint8_t);
@@ -453,8 +444,15 @@
 
 /* generic */
 mblk_t *ieee80211_getmgtframe(uint8_t **, int);
+
+/* wpa_supplicant notification methods */
 void ieee80211_notify_node_join(ieee80211com_t *, ieee80211_node_t *);
 void ieee80211_notify_node_leave(ieee80211com_t *, ieee80211_node_t *);
+void ieee80211_notify_scan_res(ieee80211com_t *);
+void ieee80211_notify_rejected(ieee80211com_t *, ieee80211_node_t *in,
+    uint16_t);
+void ieee80211_notify_timedout(ieee80211com_t *, ieee80211_node_t *in);
+void ieee80211_notify_detach(ieee80211com_t *);
 
 /* WME */
 void	ieee80211_wme_initparams(struct ieee80211com *);
--- a/usr/src/uts/common/io/net80211/net80211_input.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/io/net80211/net80211_input.c	Wed May 29 08:31:24 2013 +0200
@@ -569,9 +569,14 @@
 		if (status != 0) {
 			ieee80211_dbg(IEEE80211_MSG_DEBUG | IEEE80211_MSG_AUTH,
 			    "open auth failed (reason %d)\n", status);
-			if (in != ic->ic_bss)
+			if (in != ic->ic_bss) {
 				in->in_fails++;
-			ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
+			} else {
+				IEEE80211_LOCK(ic);
+				ieee80211_notify_rejected(ic, in, status);
+				IEEE80211_UNLOCK(ic);
+			}
+			ieee80211_new_state(ic, IEEE80211_S_INIT, 0);
 		} else {
 			/* i_fc[0] - frame control's type & subtype field */
 			ieee80211_new_state(ic, IEEE80211_S_ASSOC,
@@ -678,6 +683,7 @@
 				    IEEE80211_MSG_AUTH,
 				    "shared key auth failed (reason %d)\n",
 				    status);
+				ieee80211_notify_rejected(ic, in, status);
 				if (in != ic->ic_bss)
 					in->in_fails++;
 				return;
@@ -963,6 +969,9 @@
 				}
 			}
 			break;
+		case IEEE80211_ELEMID_PWRCNSTR:
+			/* Note: This avoid debugging msgs to be printed */
+			break;
 		default:
 			ieee80211_dbg(IEEE80211_MSG_ELEMID,
 			    "ieee80211_recv_mgmt: ignore %s,"
@@ -984,25 +993,6 @@
 		    IEEE80211_SUBTYPE_NAME(subtype), scan.chan);
 		return;
 	}
-	if (scan.chan != scan.bchan &&
-	    ic->ic_phytype != IEEE80211_T_FH) {
-		/*
-		 * Frame was received on a channel different from the
-		 * one indicated in the DS params element id;
-		 * silently discard it.
-		 *
-		 * NB:	this can happen due to signal leakage.
-		 *	But we should take it for FH phy because
-		 *	the rssi value should be correct even for
-		 *	different hop pattern in FH.
-		 */
-		ieee80211_dbg(IEEE80211_MSG_ELEMID,
-		    "ieee80211_recv_mgmt: ignore %s ,"
-		    "phytype %u channel %u marked for %u\n",
-		    IEEE80211_SUBTYPE_NAME(subtype),
-		    ic->ic_phytype, scan.bchan, scan.chan);
-		return;
-	}
 	if (!(IEEE80211_BINTVAL_MIN <= scan.bintval &&
 	    scan.bintval <= IEEE80211_BINTVAL_MAX)) {
 		ieee80211_dbg(IEEE80211_MSG_ELEMID | IEEE80211_MSG_INPUT,
@@ -1325,6 +1315,7 @@
 		if (status != 0) {
 			ieee80211_dbg(IEEE80211_MSG_ASSOC,
 			    "assoc failed (reason %d)\n", status);
+			ieee80211_notify_rejected(ic, in, status);
 			in = ieee80211_find_node(&ic->ic_scan, wh->i_addr2);
 			if (in != NULL) {
 				in->in_fails++;
@@ -1390,7 +1381,7 @@
 		IEEE80211_VERIFY_ELEMENT(rates, IEEE80211_RATE_MAXSIZE, break);
 		/*
 		 * Adjust and check AP's rate list with device's
-		 * supported rate. Re-start scan if no rate is or the
+		 * supported rate. Stop association if no rate is set or the
 		 * fixed rate(if being set) cannot be supported by
 		 * either AP or the device.
 		 */
@@ -1402,8 +1393,11 @@
 			    "assoc failed (rate set mismatch)\n");
 			if (in != ic->ic_bss)
 				in->in_fails++;
+			else
+				ieee80211_notify_rejected(ic, in,
+				    IEEE80211_STATUS_BASIC_RATE);
 			IEEE80211_UNLOCK(ic);
-			ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
+			ieee80211_new_state(ic, IEEE80211_S_INIT, 0);
 			return;
 		}
 
@@ -1485,6 +1479,8 @@
 		    "recv deauthenticate (reason %d)\n", status);
 		switch (ic->ic_opmode) {
 		case IEEE80211_M_STA:
+			if (in == ic->ic_bss)
+				ieee80211_notify_rejected(ic, in, status);
 			IEEE80211_UNLOCK(ic);
 			ieee80211_new_state(ic, IEEE80211_S_AUTH,
 			    wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
@@ -1510,6 +1506,8 @@
 		    "recv disassociate (reason %d)\n", status);
 		switch (ic->ic_opmode) {
 		case IEEE80211_M_STA:
+			if (in == ic->ic_bss)
+				ieee80211_notify_rejected(ic, in, status);
 			IEEE80211_UNLOCK(ic);
 			ieee80211_new_state(ic, IEEE80211_S_ASSOC,
 			    wh->i_fc[0] & IEEE80211_FC0_SUBTYPE_MASK);
--- a/usr/src/uts/common/io/net80211/net80211_ioctl.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/io/net80211/net80211_ioctl.c	Wed May 29 08:31:24 2013 +0200
@@ -1,6 +1,7 @@
 /*
  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 /*
@@ -40,40 +41,11 @@
 #include <inet/common.h>
 #include <inet/nd.h>
 #include <inet/mi.h>
+#include <sys/door.h>
 #include <sys/note.h>
 #include <sys/mac_provider.h>
+#include "net80211_impl.h"
 #include <inet/wifi_ioctl.h>
-#include "net80211_impl.h"
-
-static int wl_set_essid(struct ieee80211com *, const void *);
-static void wl_get_essid(struct ieee80211com *, void *);
-static int wl_set_bssid(struct ieee80211com *, const void *);
-static void wl_get_bssid(struct ieee80211com *, void *);
-static int wl_set_bsstype(struct ieee80211com *, const void *);
-static void wl_get_bsstype(struct ieee80211com *, void *);
-static void wl_get_linkstatus(struct ieee80211com *, void *);
-static int wl_set_desrates(struct ieee80211com *, const void *);
-static void wl_get_desrates(struct ieee80211com *, void *);
-static int wl_set_authmode(struct ieee80211com *, const void *);
-static void wl_get_authmode(struct ieee80211com *, void *);
-static int wl_set_encrypt(struct ieee80211com *, const void *);
-static void wl_get_encrypt(struct ieee80211com *, void *);
-static void wl_get_rssi(struct ieee80211com *, void *);
-static int wl_set_phy(struct ieee80211com *, const void *);
-static int wl_get_phy(struct ieee80211com *, void *);
-static void wl_get_capability(struct ieee80211com *, void *);
-static int wl_set_wpa(struct ieee80211com *, const void *);
-static void wl_get_wpa(struct ieee80211com *, void *);
-static void wl_get_scanresults(struct ieee80211com *, void *);
-static void wl_get_esslist(struct ieee80211com *, void *);
-static int wl_set_wepkey(struct ieee80211com *, const void *);
-static int wl_set_optie(struct ieee80211com *, const void *);
-static int wl_set_delkey(struct ieee80211com *, const void *);
-static int wl_set_mlme(struct ieee80211com *, const void *);
-static int wl_set_wpakey(struct ieee80211com *, const void *);
-static void wl_get_suprates(struct ieee80211com *, void *);
-static int wl_set_createibss(struct ieee80211com *, const void *);
-static void wl_get_createibss(struct ieee80211com *, void *);
 
 static size_t
 wifi_strnlen(const char *s, size_t n)
@@ -102,600 +74,6 @@
 	mp->b_wptr = mp->b_rptr + wp->wldp_length;
 }
 
-/*
- * Allocate and initialize an output message.
- */
-static mblk_t *
-wifi_getoutmsg(mblk_t *mp, uint32_t cmd, int buflen)
-{
-	mblk_t *mp1;
-	int size;
-
-	size = WIFI_BUF_OFFSET;
-	if (cmd == WLAN_GET_PARAM)
-		size += buflen;	/* to hold output parameters */
-	mp1 = allocb(size, BPRI_HI);
-	if (mp1 == NULL) {
-		ieee80211_err("wifi_getoutbuf: allocb %d bytes failed!\n",
-		    size);
-		return (NULL);
-	}
-
-	bzero(mp1->b_rptr, size);
-	bcopy(mp->b_rptr, mp1->b_rptr, WIFI_BUF_OFFSET);
-	wifi_setupoutmsg(mp1, size - WIFI_BUF_OFFSET);
-
-	return (mp1);
-}
-
-static int
-wifi_cfg_essid(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
-	wldp_t *outp;
-	wl_essid_t *iw_essid = (wl_essid_t *)inp->wldp_buf;
-	wl_essid_t *ow_essid;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_essid_t))) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-	ow_essid = (wl_essid_t *)outp->wldp_buf;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		wl_get_essid(ic, ow_essid);
-		break;
-	case WLAN_SET_PARAM:
-		err = wl_set_essid(ic, iw_essid);
-		break;
-	default:
-		ieee80211_err("wifi_cfg_essid: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-static int
-wifi_cfg_bssid(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
-	wldp_t *outp;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_bssid_t))) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-
-	switch (cmd) {
-	case  WLAN_GET_PARAM:
-		wl_get_bssid(ic, outp->wldp_buf);
-		break;
-	case WLAN_SET_PARAM:
-		err = wl_set_bssid(ic, inp->wldp_buf);
-		ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_bssid: "
-		    "set bssid=%s\n",
-		    ieee80211_macaddr_sprintf(inp->wldp_buf));
-		break;
-	default:
-		ieee80211_err("wifi_cfg_bssid: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-static int
-wifi_cfg_nodename(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
-	wldp_t *outp;
-	wl_nodename_t *iw_name = (wl_nodename_t *)inp->wldp_buf;
-	wl_nodename_t *ow_name;
-	char *nodename;
-	int len, err;
-
-	err = 0;
-	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_nodename_t))) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-	ow_name = (wl_nodename_t *)outp->wldp_buf;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		len = wifi_strnlen((const char *)ic->ic_nickname,
-		    IEEE80211_NWID_LEN);
-		ow_name->wl_nodename_length = len;
-		bcopy(ic->ic_nickname, ow_name->wl_nodename_name, len);
-		break;
-	case WLAN_SET_PARAM:
-		if (iw_name->wl_nodename_length > IEEE80211_NWID_LEN) {
-			ieee80211_err("wifi_cfg_nodename: "
-			    "node name too long, %u\n",
-			    iw_name->wl_nodename_length);
-			outp->wldp_result = WL_NOTSUPPORTED;
-			err = EINVAL;
-			break;
-		}
-		nodename = iw_name->wl_nodename_name;
-		nodename[IEEE80211_NWID_LEN] = 0;
-		ieee80211_dbg(IEEE80211_MSG_CONFIG,
-		    "wifi_cfg_nodename: set nodename %s, len=%d\n",
-		    nodename, iw_name->wl_nodename_length);
-
-		len = iw_name->wl_nodename_length;
-		if (len > 0)
-			bcopy(nodename, ic->ic_nickname, len);
-		if (len < IEEE80211_NWID_LEN)
-			ic->ic_nickname[len] = 0;
-		break;
-	default:
-		ieee80211_err("wifi_cfg_nodename: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-static int
-wifi_cfg_phy(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
-	wldp_t *outp;
-	wl_phy_conf_t *iw_phy = (wl_phy_conf_t *)inp->wldp_buf;
-	wl_phy_conf_t *ow_phy;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_phy_conf_t))) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-	ow_phy = (wl_phy_conf_t *)outp->wldp_buf;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		err = wl_get_phy(ic, ow_phy);
-		break;
-
-	case WLAN_SET_PARAM:
-		err = wl_set_phy(ic, iw_phy);
-		break;
-
-	default:
-		ieee80211_err("wifi_cfg_phy: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	} /* switch (cmd) */
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-static int
-wifi_cfg_wepkey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
-	wldp_t *outp;
-	wl_wep_key_t *iw_wepkey = (wl_wep_key_t *)inp->wldp_buf;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		outp->wldp_result = WL_WRITEONLY;
-		err = EINVAL;
-		break;
-	case WLAN_SET_PARAM:
-		if (inp->wldp_length < sizeof (wl_wep_key_tab_t)) {
-			ieee80211_err("wifi_cfg_wepkey: "
-			    "parameter too short, %d, expected %d\n",
-			    inp->wldp_length, sizeof (wl_wep_key_tab_t));
-			outp->wldp_result = WL_NOTSUPPORTED;
-			err = EINVAL;
-			break;
-		}
-
-		err = wl_set_wepkey(ic, iw_wepkey);
-		break;
-	default:
-		ieee80211_err("wifi_cfg_wepkey: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-static int
-wifi_cfg_keyid(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
-	wldp_t *outp;
-	wl_wep_key_id_t *iw_kid = (wl_wep_key_id_t *)inp->wldp_buf;
-	wl_wep_key_id_t *ow_kid;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_wep_key_id_t))) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-	ow_kid = (wl_wep_key_id_t *)outp->wldp_buf;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		*ow_kid = (ic->ic_def_txkey == IEEE80211_KEYIX_NONE) ?
-		    0 : ic->ic_def_txkey;
-		break;
-	case  WLAN_SET_PARAM:
-		if (*iw_kid >= MAX_NWEPKEYS) {
-			ieee80211_err("wifi_cfg_keyid: "
-			    "keyid too large, %u\n", *iw_kid);
-			outp->wldp_result = WL_NOTSUPPORTED;
-			err = EINVAL;
-		} else {
-			ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cfg_keyid: "
-			    "set keyid=%u\n", *iw_kid);
-			ic->ic_def_txkey = *iw_kid;
-			err = ENETRESET;
-		}
-		break;
-	default:
-		ieee80211_err("wifi_cfg_keyid: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-static int
-wifi_cfg_authmode(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
-	wldp_t *outp;
-	wl_authmode_t *iw_auth = (wl_authmode_t *)inp->wldp_buf;
-	wl_authmode_t *ow_auth;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_authmode_t))) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-	ow_auth = (wl_authmode_t *)outp->wldp_buf;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		wl_get_authmode(ic, ow_auth);
-		break;
-	case WLAN_SET_PARAM:
-		err = wl_set_authmode(ic, iw_auth);
-		break;
-	default:
-		ieee80211_err("wifi_cfg_authmode: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-static int
-wifi_cfg_encrypt(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
-	wldp_t *outp;
-	wl_encryption_t *iw_encryp = (wl_encryption_t *)inp->wldp_buf;
-	wl_encryption_t *ow_encryp;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_encryption_t))) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-	ow_encryp = (wl_encryption_t *)outp->wldp_buf;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		wl_get_encrypt(ic, ow_encryp);
-		break;
-	case WLAN_SET_PARAM:
-		err = wl_set_encrypt(ic, iw_encryp);
-		break;
-	default:
-		ieee80211_err("wifi_cfg_encrypt: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-static int
-wifi_cfg_bsstype(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
-	wldp_t *outp;
-	wl_bss_type_t *iw_opmode = (wl_bss_type_t *)inp->wldp_buf;
-	wl_bss_type_t *ow_opmode;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_bss_type_t))) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-	ow_opmode = (wl_bss_type_t *)outp->wldp_buf;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		wl_get_bsstype(ic, ow_opmode);
-		break;
-	case  WLAN_SET_PARAM:
-		if (*iw_opmode == ic->ic_opmode)
-			break;
-
-		err = wl_set_bsstype(ic, iw_opmode);
-		break;
-	default:
-		ieee80211_err("wifi_cfg_bsstype: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-static int
-wifi_cfg_createibss(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
-	wldp_t *outp;
-	wl_create_ibss_t *iw_ibss = (wl_create_ibss_t *)inp->wldp_buf;
-	wl_create_ibss_t *ow_ibss;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_create_ibss_t))) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-	ow_ibss = (wl_create_ibss_t *)outp->wldp_buf;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		wl_get_createibss(ic, ow_ibss);
-		break;
-	case  WLAN_SET_PARAM:
-		err = wl_set_createibss(ic, iw_ibss);
-		break;
-	default:
-		ieee80211_err("wifi_cfg_bsstype: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-static int
-wifi_cfg_linkstatus(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *outp;
-	wl_linkstatus_t *ow_linkstat;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_linkstatus_t))) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-	ow_linkstat = (wl_linkstatus_t *)outp->wldp_buf;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		wl_get_linkstatus(ic, ow_linkstat);
-		break;
-	case WLAN_SET_PARAM:
-		outp->wldp_result = WL_READONLY;
-		err = EINVAL;
-		break;
-	default:
-		ieee80211_err("wifi_cfg_linkstatus: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-static int
-wifi_cfg_suprates(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *outp;
-	wl_rates_t *ow_rates;
-	int err, buflen;
-
-	err = 0;
-	/* rate value (wl_rates_rates) is of type char */
-	buflen = offsetof(wl_rates_t, wl_rates_rates) +
-	    sizeof (char) * IEEE80211_MODE_MAX * IEEE80211_RATE_MAXSIZE;
-	if ((omp = wifi_getoutmsg(*mp, cmd, buflen)) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-	ow_rates = (wl_rates_t *)outp->wldp_buf;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		(void) wl_get_suprates(ic, ow_rates);
-		break;
-	case WLAN_SET_PARAM:
-		outp->wldp_result = WL_READONLY;
-		err = EINVAL;
-		break;
-	default:
-		ieee80211_err("wifi_cfg_suprates: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-static int
-wifi_cfg_desrates(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
-	wl_rates_t *iw_rates = (wl_rates_t *)inp->wldp_buf;
-	mblk_t *omp;
-	wldp_t *outp;
-	wl_rates_t *ow_rates;
-	int err;
-
-	err = 0;
-	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_rates_t))) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-	ow_rates = (wl_rates_t *)outp->wldp_buf;
-
-	switch (cmd) {
-	case  WLAN_GET_PARAM:
-		wl_get_desrates(ic, ow_rates);
-		break;
-	case  WLAN_SET_PARAM:
-		err = wl_set_desrates(ic, iw_rates);
-		break;
-	default:
-		ieee80211_err("wifi_cfg_desrates: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-/*
- * Rescale device's RSSI value to (0, 15) as required by WiFi
- * driver IOCTLs (PSARC/2003/722)
- */
-static wl_rssi_t
-wifi_getrssi(struct ieee80211_node *in)
-{
-	struct ieee80211com *ic = in->in_ic;
-	wl_rssi_t rssi, max_rssi;
-
-	rssi = ic->ic_node_getrssi(in);
-	max_rssi = (ic->ic_maxrssi == 0) ? IEEE80211_MAXRSSI : ic->ic_maxrssi;
-	if (rssi == 0)
-		rssi = 0;
-	else if (rssi >= max_rssi)
-		rssi = MAX_RSSI;
-	else
-		rssi = rssi * MAX_RSSI / max_rssi + 1;
-
-	return (rssi);
-}
-
-static int
-wifi_cfg_rssi(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *outp;
-	wl_rssi_t *ow_rssi;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_rssi_t))) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-	ow_rssi = (wl_rssi_t *)outp->wldp_buf;
-
-	switch (cmd) {
-	case  WLAN_GET_PARAM:
-		*ow_rssi = wifi_getrssi(ic->ic_bss);
-		break;
-	case  WLAN_SET_PARAM:
-		outp->wldp_result = WL_READONLY;
-		err = EINVAL;
-		break;
-	default:
-		ieee80211_err("wifi_cfg_rssi: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		return (EINVAL);
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-/*
- * maximum scan wait time in second.
- * Time spent on scaning one channel is usually 100~200ms. The maximum
- * number of channels defined in wifi_ioctl.h is 99 (MAX_CHANNEL_NUM).
- * As a result the maximum total scan time is defined as below in ms.
- */
-#define	WAIT_SCAN_MAX	(200 * MAX_CHANNEL_NUM)
-
-static void
-wifi_wait_scan(struct ieee80211com *ic)
-{
-	ieee80211_impl_t *im = ic->ic_private;
-	clock_t delta = drv_usectohz(WAIT_SCAN_MAX * 1000);
-
-	while ((ic->ic_flags & (IEEE80211_F_SCAN | IEEE80211_F_ASCAN)) != 0) {
-		if (cv_reltimedwait_sig(&im->im_scan_cv, &ic->ic_genlock,
-		    delta, TR_CLOCK_TICK) != 0) {
-			break;
-		}
-	}
-}
-
 #define	WIFI_HAVE_CAP(in, flag)	(((in)->in_capinfo & (flag)) ? 1 : 0)
 #define	WIFI_HAVE_HTCAP(in)	(((in)->in_htcap != 0) ? 1 : 0)
 
@@ -714,57 +92,70 @@
 	struct ieee80211_rateset *rates = &(in->in_rates);
 	wl_ess_conf_t *conf;
 	uint8_t *end;
-	uint_t i, nrates;
+	uint_t i;
 
-	end = (uint8_t *)aps - WIFI_BUF_OFFSET + MAX_BUF_LEN -
-	    sizeof (wl_ess_list_t);
+	end = (uint8_t *)aps + aps->wl_ess_list_size - sizeof (wl_ess_list_t);
 	conf = &aps->wl_ess_list_ess[aps->wl_ess_list_num];
-	if ((uint8_t *)conf > end)
+	if ((uint8_t *)conf > end) {
+		aps->wl_ess_list_size = USHRT_MAX;
 		return;
-
-	conf->wl_ess_conf_length = sizeof (struct wl_ess_conf);
+	}
 
 	/* skip newly allocated NULL bss node */
 	if (IEEE80211_ADDR_EQ(in->in_macaddr, ic->ic_macaddr))
 		return;
 
-	conf->wl_ess_conf_essid.wl_essid_length = in->in_esslen;
-	bcopy(in->in_essid, conf->wl_ess_conf_essid.wl_essid_essid,
-	    in->in_esslen);
-	bcopy(in->in_bssid, conf->wl_ess_conf_bssid, IEEE80211_ADDR_LEN);
-	conf->wl_ess_conf_wepenabled =
-	    (in->in_capinfo & IEEE80211_CAPINFO_PRIVACY ?
-	    WL_ENC_WEP : WL_NOENCRYPTION);
-	conf->wl_ess_conf_bsstype =
-	    (in->in_capinfo & IEEE80211_CAPINFO_ESS ?
-	    WL_BSS_BSS : WL_BSS_IBSS);
-	conf->wl_ess_conf_sl = wifi_getrssi(in);
-	conf->wl_ess_conf_reserved[0] = (in->in_wpa_ie == NULL? 0 : 1);
+	if (in->in_esslen != 0) {
+		conf->wl_ess_conf_essid.wl_essid_length = in->in_esslen;
+		bcopy(in->in_essid, conf->wl_ess_conf_essid.wl_essid_essid,
+		    in->in_esslen);
+	} else {
+		conf->wl_ess_conf_essid.wl_essid_length = 0;
+	}
+
+	bcopy(in->in_bssid, conf->wl_ess_conf_bssid.wl_bssid_bssid,
+	    IEEE80211_ADDR_LEN);
+
+	conf->wl_ess_conf_beacon_period = in->in_intval;
+	conf->wl_ess_conf_beacon_tsf = in->in_tstamp.tsf;
+	conf->wl_ess_conf_beacon_age = in->in_rstamp;
+
+	conf->wl_ess_conf_sl = ic->ic_node_getrssi(in);
+
+	conf->wl_ess_conf_caps = in->in_capinfo;
+	/* authmode is set to IEEE80211_AUTH_OPEN = 1 by default */
+
+	if (in->in_wpa_ie == NULL) {
+		conf->wl_ess_conf_wpa_ie.wpa_ie_len = 0;
+	} else {
+		conf->wl_ess_conf_wpa_ie.wpa_ie_len = in->in_wpa_ie[1] + 2;
+		bcopy(in->in_wpa_ie, conf->wl_ess_conf_wpa_ie.wpa_ie,
+		    conf->wl_ess_conf_wpa_ie.wpa_ie_len);
+	}
 
 	/* physical (FH, DS, ERP) parameters */
 	if (IEEE80211_IS_CHAN_A(chan) || IEEE80211_IS_CHAN_T(chan)) {
-		wl_ofdm_t *ofdm =
-		    (wl_ofdm_t *)&((conf->wl_phy_conf).wl_phy_ofdm_conf);
+		wl_ofdm_t *ofdm = &conf->wl_ess_conf_phys.wl_phy_ofdm_conf;
 		ofdm->wl_ofdm_subtype = WL_OFDM;
 		ofdm->wl_ofdm_frequency = chan->ich_freq;
 		ofdm->wl_ofdm_ht_enabled = WIFI_HAVE_HTCAP(in);
 	} else {
 		switch (in->in_phytype) {
 		case IEEE80211_T_FH: {
-			wl_fhss_t *fhss = (wl_fhss_t *)
-			    &((conf->wl_phy_conf).wl_phy_fhss_conf);
+			wl_fhss_t *fhss =
+			    &conf->wl_ess_conf_phys.wl_phy_fhss_conf;
 
 			fhss->wl_fhss_subtype = WL_FHSS;
-			fhss->wl_fhss_channel = ieee80211_chan2ieee(ic, chan);
+			fhss->wl_fhss_frequency	= chan->ich_freq;
 			fhss->wl_fhss_dwelltime = in->in_fhdwell;
 			break;
 		}
 		case IEEE80211_T_DS: {
-			wl_dsss_t *dsss = (wl_dsss_t *)
-			    &((conf->wl_phy_conf).wl_phy_dsss_conf);
+			wl_dsss_t *dsss =
+			    &conf->wl_ess_conf_phys.wl_phy_dsss_conf;
 
 			dsss->wl_dsss_subtype = WL_DSSS;
-			dsss->wl_dsss_channel = ieee80211_chan2ieee(ic, chan);
+			dsss->wl_dsss_frequency = chan->ich_freq;
 			dsss->wl_dsss_have_short_preamble = WIFI_HAVE_CAP(in,
 			    IEEE80211_CAPINFO_SHORT_PREAMBLE);
 			dsss->wl_dsss_agility_enabled = WIFI_HAVE_CAP(in,
@@ -774,11 +165,10 @@
 			break;
 		}
 		case IEEE80211_T_OFDM: {
-			wl_erp_t *erp = (wl_erp_t *)
-			    &((conf->wl_phy_conf).wl_phy_erp_conf);
+			wl_erp_t *erp = &conf->wl_ess_conf_phys.wl_phy_erp_conf;
 
 			erp->wl_erp_subtype = WL_ERP;
-			erp->wl_erp_channel = ieee80211_chan2ieee(ic, chan);
+			erp->wl_erp_frequency = chan->ich_freq;
 			erp->wl_erp_have_short_preamble = WIFI_HAVE_CAP(in,
 			    IEEE80211_CAPINFO_SHORT_PREAMBLE);
 			erp->wl_erp_have_agility = erp->wl_erp_agility_enabled =
@@ -795,101 +185,24 @@
 		} /* switch in->in_phytype */
 	}
 
-	/* supported rates */
-	nrates = MIN(rates->ir_nrates, MAX_SCAN_SUPPORT_RATES);
-	/*
-	 * The number of supported rates might exceed
-	 * MAX_SCAN_SUPPORT_RATES. Fill in highest rates
-	 * first so userland command could properly show
-	 * maximum speed of AP
-	 */
-	for (i = 0; i < nrates; i++) {
-		conf->wl_supported_rates[i] =
+	for (i = 0; i < rates->ir_nrates; i++)
+		conf->wl_ess_conf_rates.wl_rates_rates[i] =
 		    rates->ir_rates[rates->ir_nrates - i - 1];
-	}
+	conf->wl_ess_conf_rates.wl_rates_num = rates->ir_nrates;
 
 	aps->wl_ess_list_num++;
 }
 
 static int
-wifi_cfg_esslist(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *outp;
-	wl_ess_list_t *ow_aps;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, MAX_BUF_LEN - WIFI_BUF_OFFSET)) ==
-	    NULL) {
-		return (ENOMEM);
-	}
-	outp = (wldp_t *)omp->b_rptr;
-	ow_aps = (wl_ess_list_t *)outp->wldp_buf;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		ow_aps->wl_ess_list_num = 0;
-		ieee80211_iterate_nodes(&ic->ic_scan, wifi_read_ap, ow_aps);
-		outp->wldp_length = WIFI_BUF_OFFSET +
-		    offsetof(wl_ess_list_t, wl_ess_list_ess) +
-		    ow_aps->wl_ess_list_num * sizeof (wl_ess_conf_t);
-		omp->b_wptr = omp->b_rptr + outp->wldp_length;
-		break;
-	case WLAN_SET_PARAM:
-		outp->wldp_result = WL_READONLY;
-		err = EINVAL;
-		break;
-	default:
-		ieee80211_err("wifi_cfg_esslist: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-/*
- * Scan the network for all available ESSs.
- * IEEE80211_F_SCANONLY is set when current state is INIT. And
- * with this flag, after scan the state will be changed back to
- * INIT. The reason is at the end of SCAN stage, the STA will
- * consequently connect to an AP. Then it looks unreasonable that
- * for a disconnected device, A SCAN command causes it connected.
- * So the state is changed back to INIT.
- */
-static int
 wifi_cmd_scan(struct ieee80211com *ic, mblk_t *mp)
 {
-	int ostate = ic->ic_state;
-
-	/*
-	 * Do not scan when current state is RUN. The reason is
-	 * when connected, STA is on the same channel as AP. But
-	 * to do scan, STA have to switch to each available channel,
-	 * send probe request and wait certian time for probe
-	 * response/beacon. Then when the STA switches to a channel
-	 * different than AP's, as a result it cannot send/receive
-	 * data packets to/from the connected WLAN. This eventually
-	 * will cause data loss.
-	 */
-	if (ostate == IEEE80211_S_RUN)
-		return (0);
+	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cmd_scan");
 
 	IEEE80211_UNLOCK(ic);
 
-	ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
-	IEEE80211_LOCK(ic);
-	if (ostate == IEEE80211_S_INIT)
-		ic->ic_flags |= IEEE80211_F_SCANONLY;
+	ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
 
-	/* Don't wait on WPA mode */
-	if ((ic->ic_flags & IEEE80211_F_WPA) == 0) {
-		/* wait scan complete */
-		wifi_wait_scan(ic);
-	}
+	IEEE80211_LOCK(ic);
 
 	wifi_setupoutmsg(mp, 0);
 	return (0);
@@ -905,16 +218,17 @@
 	bzero(ic->ic_des_essid, IEEE80211_NWID_LEN);
 	ic->ic_flags &= ~IEEE80211_F_DESBSSID;
 	bzero(ic->ic_des_bssid, IEEE80211_ADDR_LEN);
+
 	bzero(ic->ic_bss->in_bssid, IEEE80211_ADDR_LEN);
+
 	ic->ic_des_chan = IEEE80211_CHAN_ANYC;
 	ic->ic_fixed_rate = IEEE80211_FIXED_RATE_NONE;
-	bzero(ic->ic_nickname, IEEE80211_NWID_LEN);
 	in->in_authmode = IEEE80211_AUTH_OPEN;
+
 	ic->ic_flags &= ~IEEE80211_F_PRIVACY;
 	ic->ic_flags &= ~IEEE80211_F_WPA;	/* mask WPA mode */
-	ic->ic_evq_head = ic->ic_evq_tail = 0;	/* reset Queue */
-	ic->ic_def_txkey = 0;
-	for (i = 0; i < MAX_NWEPKEYS; i++) {
+
+	for (i = 0; i < IEEE80211_KEY_MAX; i++) {
 		ic->ic_nw_keys[i].wk_keylen = 0;
 		bzero(ic->ic_nw_keys[i].wk_key, IEEE80211_KEYBUF_SIZE);
 	}
@@ -924,16 +238,10 @@
 }
 
 static int
-wifi_cmd_loaddefaults(struct ieee80211com *ic, mblk_t *mp)
-{
-	wifi_loaddefdata(ic);
-	wifi_setupoutmsg(mp, 0);
-	return (ENETRESET);
-}
-
-static int
 wifi_cmd_disassoc(struct ieee80211com *ic, mblk_t *mp)
 {
+	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wifi_cmd_disassoc");
+
 	if (ic->ic_state != IEEE80211_S_INIT) {
 		IEEE80211_UNLOCK(ic);
 		(void) ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
@@ -944,300 +252,8 @@
 	return (0);
 }
 
-/*
- * Get the capabilities of drivers.
- */
 static int
-wifi_cfg_caps(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *outp;
-	wl_capability_t *o_caps;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_capability_t))) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-	o_caps = (wl_capability_t *)outp->wldp_buf;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		wl_get_capability(ic, o_caps);
-		break;
-	case WLAN_SET_PARAM:
-		outp->wldp_result = WL_READONLY;
-		err = EINVAL;
-		break;
-	default:
-		ieee80211_err("wifi_cfg_caps: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-/*
- * Operating on WPA mode.
- */
-static int
-wifi_cfg_wpa(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *outp;
-	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
-	wl_wpa_t *wpa = (wl_wpa_t *)inp->wldp_buf;
-	wl_wpa_t *o_wpa;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, sizeof (wl_wpa_t))) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-	o_wpa = (wl_wpa_t *)outp->wldp_buf;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		wl_get_wpa(ic, o_wpa);
-		break;
-	case WLAN_SET_PARAM:
-		err = wl_set_wpa(ic, wpa);
-		break;
-	default:
-		ieee80211_err("wifi_cfg_wpa: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-/*
- * WPA daemon set the WPA keys.
- * The WPA keys are negotiated with APs through wpa service.
- */
-static int
-wifi_cfg_wpakey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *outp;
-	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
-	wl_key_t *ik = (wl_key_t *)(inp->wldp_buf);
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		outp->wldp_result = WL_WRITEONLY;
-		err = EINVAL;
-		break;
-	case WLAN_SET_PARAM:
-		err = wl_set_wpakey(ic, ik);
-		break;
-	default:
-		ieee80211_err("wifi_cfg_wpakey: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-/*
- * Delete obsolete keys - keys are dynamically exchanged between APs
- * and wpa daemon.
- */
-static int
-wifi_cfg_delkey(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *outp;
-	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
-	wl_del_key_t *dk = (wl_del_key_t *)inp->wldp_buf;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		outp->wldp_result = WL_WRITEONLY;
-		err = EINVAL;
-		break;
-	case WLAN_SET_PARAM:
-		err = wl_set_delkey(ic, dk);
-		break;
-	default:
-		ieee80211_err("wifi_cfg_delkey: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-/*
- * The OPTIE will be used in the association request.
- */
-static int
-wifi_cfg_setoptie(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *outp;
-	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
-	wl_wpa_ie_t *ie_in = (wl_wpa_ie_t *)inp->wldp_buf;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		outp->wldp_result = WL_WRITEONLY;
-		err = EINVAL;
-		break;
-	case WLAN_SET_PARAM:
-		if ((err = wl_set_optie(ic, ie_in)) == EINVAL)
-			outp->wldp_result = WL_NOTSUPPORTED;
-		break;
-	default:
-		ieee80211_err("wifi_cfg_setoptie: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-/*
- * To be compatible with drivers/tools of OpenSolaris.org,
- * we use a different ID to filter out those APs of WPA mode.
- */
-static int
-wifi_cfg_scanresults(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *outp;
-	wl_wpa_ess_t *sr;
-	ieee80211_node_t *in;
-	ieee80211_node_table_t *nt;
-	int len, ap_num = 0;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, MAX_BUF_LEN - WIFI_BUF_OFFSET)) ==
-	    NULL) {
-		return (ENOMEM);
-	}
-	outp = (wldp_t *)omp->b_rptr;
-	sr = (wl_wpa_ess_t *)outp->wldp_buf;
-	sr->count = 0;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		ieee80211_dbg(IEEE80211_MSG_WPA, "wifi_cfg_scanresults\n");
-		nt = &ic->ic_scan;
-		IEEE80211_NODE_LOCK(nt);
-		in = list_head(&nt->nt_node);
-		while (in != NULL) {
-			/* filter out non-WPA APs */
-			if (in->in_wpa_ie == NULL) {
-				in = list_next(&nt->nt_node, in);
-				continue;
-			}
-			bcopy(in->in_bssid, sr->ess[ap_num].bssid,
-			    IEEE80211_ADDR_LEN);
-			sr->ess[ap_num].ssid_len = in->in_esslen;
-			bcopy(in->in_essid, sr->ess[ap_num].ssid,
-			    in->in_esslen);
-			sr->ess[ap_num].freq = in->in_chan->ich_freq;
-
-			len = in->in_wpa_ie[1] + 2;
-			bcopy(in->in_wpa_ie, sr->ess[ap_num].wpa_ie, len);
-			sr->ess[ap_num].wpa_ie_len = len;
-
-			ap_num ++;
-			in = list_next(&nt->nt_node, in);
-		}
-		IEEE80211_NODE_UNLOCK(nt);
-		sr->count = ap_num;
-		outp->wldp_length = WIFI_BUF_OFFSET +
-		    offsetof(wl_wpa_ess_t, ess) +
-		    sr->count * sizeof (struct wpa_ess);
-		omp->b_wptr = omp->b_rptr + outp->wldp_length;
-		break;
-	case WLAN_SET_PARAM:
-		outp->wldp_result = WL_READONLY;
-		err = EINVAL;
-		break;
-	default:
-		ieee80211_err("wifi_cfg_scanresults: unknown cmmand %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-/*
- * Manually control the state of AUTH | DEAUTH | DEASSOC | ASSOC
- */
-static int
-wifi_cfg_setmlme(struct ieee80211com *ic, uint32_t cmd, mblk_t **mp)
-{
-	mblk_t *omp;
-	wldp_t *outp;
-	wldp_t *inp = (wldp_t *)(*mp)->b_rptr;
-	wl_mlme_t *mlme = (wl_mlme_t *)inp->wldp_buf;
-	int err = 0;
-
-	if ((omp = wifi_getoutmsg(*mp, cmd, 0)) == NULL)
-		return (ENOMEM);
-	outp = (wldp_t *)omp->b_rptr;
-
-	switch (cmd) {
-	case WLAN_GET_PARAM:
-		outp->wldp_result = WL_WRITEONLY;
-		err = EINVAL;
-		break;
-	case WLAN_SET_PARAM:
-		err = wl_set_mlme(ic, mlme);
-		break;
-	default:
-		ieee80211_err("wifi_cfg_delkey: unknown command %x\n", cmd);
-		outp->wldp_result = WL_NOTSUPPORTED;
-		err = EINVAL;
-		break;
-	}
-
-	freemsg(*mp);
-	*mp = omp;
-	return (err);
-}
-
-static int
-wifi_cfg_getset(struct ieee80211com *ic, mblk_t **mp, uint32_t cmd)
+wifi_cfg_getset(struct ieee80211com *ic, mblk_t **mp)
 {
 	mblk_t *mp1 = *mp;
 	wldp_t *wp = (wldp_t *)mp1->b_rptr;
@@ -1256,82 +272,9 @@
 	case WL_SCAN:
 		err = wifi_cmd_scan(ic, mp1);
 		break;
-	case WL_LOAD_DEFAULTS:
-		err = wifi_cmd_loaddefaults(ic, mp1);
-		break;
 	case WL_DISASSOCIATE:
 		err = wifi_cmd_disassoc(ic, mp1);
 		break;
-	/* Parameters */
-	case WL_ESSID:
-		err = wifi_cfg_essid(ic, cmd, mp);
-		break;
-	case WL_BSSID:
-		err = wifi_cfg_bssid(ic, cmd, mp);
-		break;
-	case WL_NODE_NAME:
-		err = wifi_cfg_nodename(ic, cmd, mp);
-		break;
-	case WL_PHY_CONFIG:
-		err = wifi_cfg_phy(ic, cmd, mp);
-		break;
-	case WL_WEP_KEY_TAB:
-		err = wifi_cfg_wepkey(ic, cmd, mp);
-		break;
-	case WL_WEP_KEY_ID:
-		err = wifi_cfg_keyid(ic, cmd, mp);
-		break;
-	case WL_AUTH_MODE:
-		err = wifi_cfg_authmode(ic, cmd, mp);
-		break;
-	case WL_ENCRYPTION:
-		err = wifi_cfg_encrypt(ic, cmd, mp);
-		break;
-	case WL_BSS_TYPE:
-		err = wifi_cfg_bsstype(ic, cmd, mp);
-		break;
-	case WL_CREATE_IBSS:
-		err = wifi_cfg_createibss(ic, cmd, mp);
-		break;
-	case WL_DESIRED_RATES:
-		err = wifi_cfg_desrates(ic, cmd, mp);
-		break;
-	case WL_LINKSTATUS:
-		err = wifi_cfg_linkstatus(ic, cmd, mp);
-		break;
-	case WL_ESS_LIST:
-		err = wifi_cfg_esslist(ic, cmd, mp);
-		break;
-	case WL_SUPPORTED_RATES:
-		err = wifi_cfg_suprates(ic, cmd, mp);
-		break;
-	case WL_RSSI:
-		err = wifi_cfg_rssi(ic, cmd, mp);
-		break;
-	/*
-	 * WPA IOCTLs
-	 */
-	case WL_CAPABILITY:
-		err = wifi_cfg_caps(ic, cmd, mp);
-		break;
-	case WL_WPA:
-		err = wifi_cfg_wpa(ic, cmd, mp);
-		break;
-	case WL_KEY:
-		err = wifi_cfg_wpakey(ic, cmd, mp);
-		break;
-	case WL_DELKEY:
-		err = wifi_cfg_delkey(ic, cmd, mp);
-		break;
-	case WL_SETOPTIE:
-		err = wifi_cfg_setoptie(ic, cmd, mp);
-		break;
-	case WL_SCANRESULTS:
-		err = wifi_cfg_scanresults(ic, cmd, mp);
-		break;
-	case WL_MLME:
-		err = wifi_cfg_setmlme(ic, cmd, mp);
-		break;
 	default:
 		wifi_setupoutmsg(mp1, 0);
 		wp->wldp_result = WL_LACK_FEATURE;
@@ -1379,15 +322,11 @@
 	cmd = iocp->ioc_cmd;
 	need_privilege = B_TRUE;
 	switch (cmd) {
-	case WLAN_SET_PARAM:
 	case WLAN_COMMAND:
 		break;
-	case WLAN_GET_PARAM:
-		need_privilege = B_FALSE;
-		break;
 	default:
 		ieee80211_dbg(IEEE80211_MSG_ANY, "ieee80211_ioctl(): "
-		    "unknown cmd 0x%x\n", cmd);
+		    "unknown cmd 0x%x (%d) \n", cmd, cmd);
 		miocnak(wq, mp, 0, EINVAL);
 		return (EINVAL);
 	}
@@ -1414,7 +353,7 @@
 		mp1->b_cont = NULL;
 	}
 
-	err = wifi_cfg_getset(ic, &mp1, cmd);
+	err = wifi_cfg_getset(ic, &mp1);
 	mp->b_cont = mp1;
 	IEEE80211_UNLOCK(ic);
 
@@ -1438,54 +377,43 @@
 static int
 wl_set_essid(struct ieee80211com *ic, const void *wldp_buf)
 {
-	int err = 0;
-	char *essid;
 	wl_essid_t *iw_essid = (wl_essid_t *)wldp_buf;
 
-	if (iw_essid->wl_essid_length > IEEE80211_NWID_LEN) {
+	if (iw_essid->wl_essid_length > IEEE80211_NWID_LEN ||
+	    iw_essid->wl_essid_length == 0) {
 		ieee80211_err("wl_set_essid: "
 		    "essid too long, %u, max %u\n",
 		    iw_essid->wl_essid_length, IEEE80211_NWID_LEN);
 
-		err = EINVAL;
-		return (err);
+		return (EINVAL);
 	}
 
-	essid = iw_essid->wl_essid_essid;
-	essid[IEEE80211_NWID_LEN] = 0;
-
 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_essid: "
 	    "set essid=%s length=%d\n",
-	    essid, iw_essid->wl_essid_length);
+	    iw_essid->wl_essid_essid, iw_essid->wl_essid_length);
 
 	ic->ic_des_esslen = iw_essid->wl_essid_length;
-	if (ic->ic_des_esslen != 0)
-		bcopy(essid, ic->ic_des_essid, ic->ic_des_esslen);
-	if (ic->ic_des_esslen < IEEE80211_NWID_LEN)
-		ic->ic_des_essid[ic->ic_des_esslen] = 0;
+	bzero(ic->ic_des_essid, sizeof (ic->ic_des_essid));
+	bcopy(iw_essid->wl_essid_essid, ic->ic_des_essid,
+	    ic->ic_des_esslen);
 
-	err = ENETRESET;
-
-	return (err);
+	return (ENETRESET);
 }
 
 static void
 wl_get_essid(struct ieee80211com *ic, void *wldp_buf)
 {
-	char *essid;
-	wl_essid_t ow_essid;
-
-	essid = (char *)ic->ic_des_essid;
-	if (essid[0] == '\0')
-		essid = (char *)ic->ic_bss->in_essid;
+	uint8_t *essid;
+	wl_essid_t *ow_essid = wldp_buf;
 
-	bzero(&ow_essid, sizeof (wl_essid_t));
-	ow_essid.wl_essid_length = wifi_strnlen((const char *)essid,
+	essid = ic->ic_des_essid;
+	if (essid[0] == 0)
+		essid = ic->ic_bss->in_essid;
+
+	bzero(ow_essid, sizeof (wl_essid_t));
+	ow_essid->wl_essid_length = wifi_strnlen((const char *)essid,
 	    IEEE80211_NWID_LEN);
-	bcopy(essid, ow_essid.wl_essid_essid,
-	    ow_essid.wl_essid_length);
-	bcopy(&ow_essid, wldp_buf, sizeof (wl_essid_t));
-
+	bcopy(essid, &ow_essid->wl_essid_essid, ow_essid->wl_essid_length);
 }
 
 /*
@@ -1494,28 +422,31 @@
 static int
 wl_set_bssid(struct ieee80211com *ic, const void* wldp_buf)
 {
+	const wl_bssid_t *sta_bssid = wldp_buf;
 
 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_bssid: "
 	    "set bssid=%s\n",
 	    ieee80211_macaddr_sprintf(wldp_buf));
 
-	bcopy(wldp_buf, ic->ic_des_bssid, sizeof (wl_bssid_t));
+	bcopy(sta_bssid->wl_bssid_bssid, ic->ic_des_bssid, IEEE80211_ADDR_LEN);
 	ic->ic_flags |= IEEE80211_F_DESBSSID;
 
-	return (ENETRESET);
+	return (0);
 }
 
 static void
 wl_get_bssid(struct ieee80211com *ic, void *wldp_buf)
 {
 	uint8_t *bssid;
+	wl_bssid_t *ow_bssid = wldp_buf;
 
 	if (ic->ic_flags & IEEE80211_F_DESBSSID)
 		bssid = ic->ic_des_bssid;
 	else
 		bssid = ic->ic_bss->in_bssid;
-	bcopy(bssid, wldp_buf, sizeof (wl_bssid_t));
 
+	bzero(ow_bssid, sizeof (wl_bssid_t));
+	bcopy(bssid, ow_bssid->wl_bssid_bssid, IEEE80211_ADDR_LEN);
 }
 
 /*
@@ -1524,34 +455,28 @@
 static int
 wl_set_bsstype(struct ieee80211com *ic, const void *wldp_buf)
 {
-	int err = 0;
 	wl_bss_type_t *iw_opmode = (wl_bss_type_t *)wldp_buf;
 
 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_bsstype: "
 	    "set bsstype=%u\n", *iw_opmode);
 
 	switch (*iw_opmode) {
-	case WL_BSS_BSS:
+	case IEEE80211_MODE_INFRA:
 		ic->ic_flags &= ~IEEE80211_F_IBSSON;
 		ic->ic_opmode = IEEE80211_M_STA;
-		err = ENETRESET;
 		break;
-	case WL_BSS_IBSS:
-		if ((ic->ic_caps & IEEE80211_C_IBSS) == 0) {
-			err = ENOTSUP;
-			break;
-		}
+	case IEEE80211_MODE_IBSS:
+		if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
+			return (ENOTSUP);
 
 		ic->ic_opmode = IEEE80211_M_IBSS;
-		err = ENETRESET;
 		break;
 	default:
 		ieee80211_err("wl_set_bsstype: "
 		    "unknown opmode\n");
-		err = EINVAL;
-		break;
+		return (EINVAL);
 	}
-	return (err);
+	return (0);
 }
 
 static void
@@ -1561,13 +486,13 @@
 
 	switch (ic->ic_opmode) {
 	case IEEE80211_M_STA:
-		ow_opmode = WL_BSS_BSS;
+		ow_opmode = IEEE80211_MODE_INFRA;
 		break;
 	case IEEE80211_M_IBSS:
-		ow_opmode = WL_BSS_IBSS;
+		ow_opmode = IEEE80211_MODE_IBSS;
 		break;
 	default:
-		ow_opmode = WL_BSS_ANY;
+		ow_opmode = IEEE80211_MODE_INFRA;
 		break;
 	}
 
@@ -1580,25 +505,21 @@
 static void
 wl_get_linkstatus(struct ieee80211com *ic, void *wldp_buf)
 {
-	wl_linkstatus_t ow_linkstat;
+	wl_linkstatus_t ow_linkstat = (ic->ic_state == IEEE80211_S_RUN);
 
-	ow_linkstat = (ic->ic_state == IEEE80211_S_RUN) ?
-	    WL_CONNECTED : WL_NOTCONNECTED;
 	if ((ic->ic_flags & IEEE80211_F_WPA) &&
-	    (ieee80211_crypto_getciphertype(ic) != WIFI_SEC_WPA)) {
-		ow_linkstat = WL_NOTCONNECTED;
-	}
+	    (ieee80211_crypto_getciphertype(ic) != WIFI_SEC_WPA))
+		ow_linkstat = B_FALSE;
 
 	bcopy(&ow_linkstat, wldp_buf, sizeof (wl_linkstatus_t));
 }
 
 /*
- * MAC_PROP_WL_DESIRED_RATESa
+ * MAC_PROP_WL_DESIRED_RATES
  */
 static int
 wl_set_desrates(struct ieee80211com *ic, const void *wldp_buf)
 {
-	int err = 0;
 	int i, j;
 	uint8_t drate;
 	boolean_t isfound;
@@ -1608,7 +529,7 @@
 
 	drate = iw_rates->wl_rates_rates[0];
 	if (ic->ic_fixed_rate == drate)
-		return (err);
+		return (0);
 
 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_desrates: "
 	    "set desired rate=%u\n", drate);
@@ -1620,7 +541,7 @@
 			ieee80211_new_state(ic, IEEE80211_S_ASSOC, 0);
 			IEEE80211_LOCK(ic);
 		}
-		return (err);
+		return (0);
 	}
 
 	/*
@@ -1651,7 +572,7 @@
 				    IEEE80211_S_ASSOC, 0);
 				IEEE80211_LOCK(ic);
 			}
-			return (err);
+			return (0);
 		}
 	}
 
@@ -1674,14 +595,13 @@
 	if (!isfound) {
 		ieee80211_err("wl_set_desrates: "
 		    "invald rate %d\n", drate);
-		err = EINVAL;
-		return (err);
+		return (EINVAL);
 	}
 	ic->ic_fixed_rate = drate;
 	if (ic->ic_state != IEEE80211_S_SCAN)
-		err = ENETRESET;
+		return (ENETRESET);
 
-	return (err);
+	return (0);
 }
 
 static void
@@ -1707,29 +627,27 @@
 static int
 wl_set_authmode(struct ieee80211com *ic, const void *wldp_buf)
 {
-	int err = 0;
 	wl_authmode_t *iw_auth = (wl_authmode_t *)wldp_buf;
 
-	if (*iw_auth == ic->ic_bss->in_authmode)
-		return (err);
-
 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_authmode: "
 	    "set authmode=%u\n", *iw_auth);
 
+	if (*iw_auth == ic->ic_bss->in_authmode)
+		return (0);
+
 	switch (*iw_auth) {
-	case WL_OPENSYSTEM:
-	case WL_SHAREDKEY:
+	case IEEE80211_AUTH_OPEN:
+	case IEEE80211_AUTH_SHARED:
 		ic->ic_bss->in_authmode = *iw_auth;
-		err = ENETRESET;
 		break;
 	default:
+		ic->ic_bss->in_authmode = IEEE80211_AUTH_AUTO;
 		ieee80211_err("wl_set_authmode: "
-		    "unknown authmode %u\n", *iw_auth);
-		err = EINVAL;
+		    "unknown authmode %u\n, setting to AUTO", *iw_auth);
 		break;
 	}
 
-	return (err);
+	return (0);
 }
 
 static void
@@ -1748,7 +666,6 @@
 static int
 wl_set_encrypt(struct ieee80211com *ic, const void *wldp_buf)
 {
-	int err = 0;
 	uint32_t flags;
 	wl_encryption_t *iw_encryp = (wl_encryption_t *)wldp_buf;
 
@@ -1761,12 +678,10 @@
 	else
 		flags |= IEEE80211_F_PRIVACY;
 
-	if (ic->ic_flags != flags) {
+	if (ic->ic_flags != flags)
 		ic->ic_flags = flags;
-		err = ENETRESET;
-	}
 
-	return (err);
+	return (0);
 }
 
 static void
@@ -1788,26 +703,27 @@
 wl_get_rssi(struct ieee80211com *ic, void *wldp_buf)
 {
 	wl_rssi_t *ow_rssi;
+	struct ieee80211_node *in = ic->ic_bss;
 
 	ow_rssi = (wl_rssi_t *)wldp_buf;
-	*ow_rssi = wifi_getrssi(ic->ic_bss);
-
+	*ow_rssi = ic->ic_node_getrssi(in);
 }
 
 /*
  * MAC_PROP_WL_PHY_CONFIG
+ * Only used when setting IBSS mode channel
  */
 
 static int
 wl_set_phy(struct ieee80211com *ic, const void* wldp_buf)
 {
-	int err = 0;
 	int16_t ch;
 	wl_dsss_t *dsss;
 	wl_phy_conf_t *iw_phy = (wl_phy_conf_t *)wldp_buf;
 
 	dsss = (wl_dsss_t *)iw_phy;
-	ch = dsss->wl_dsss_channel;
+	/* this is actually the channel number */
+	ch = dsss->wl_dsss_frequency;
 
 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_phy: "
 	    "set channel=%d\n", ch);
@@ -1816,8 +732,7 @@
 		ic->ic_des_chan = IEEE80211_CHAN_ANYC;
 	} else if ((uint_t)ch > IEEE80211_CHAN_MAX ||
 	    ieee80211_isclr(ic->ic_chan_active, ch)) {
-		err = EINVAL;
-		return (err);
+		return (EINVAL);
 	} else {
 		ic->ic_des_chan = ic->ic_ibss_chan =
 		    &ic->ic_sup_channels[ch];
@@ -1826,8 +741,7 @@
 	switch (ic->ic_state) {
 	case IEEE80211_S_INIT:
 	case IEEE80211_S_SCAN:
-		err = ENETRESET;
-		break;
+		return (ENETRESET);
 	default:
 		/*
 		 * If hte desired channel has changed (to something
@@ -1837,11 +751,11 @@
 		if (ic->ic_des_chan != IEEE80211_CHAN_ANYC &&
 		    ic->ic_bss->in_chan != ic->ic_des_chan &&
 		    (ic->ic_flags & IEEE80211_F_SCAN) == 0)
-			err = ENETRESET;
+			return (ENETRESET);
 		break;
 	}
 
-	return (err);
+	return (0);
 }
 
 #define	WIFI_HT_MODE(in)	(((in)->in_flags & IEEE80211_NODE_HT) ? 1 : 0)
@@ -1868,22 +782,19 @@
 		case IEEE80211_T_FH: {
 			wl_fhss_t *fhss = (wl_fhss_t *)ow_phy;
 			fhss->wl_fhss_subtype = WL_FHSS;
-			fhss->wl_fhss_channel =
-			    ieee80211_chan2ieee(ic, ch);
+			fhss->wl_fhss_frequency = ch->ich_freq;
 			break;
 		}
 		case IEEE80211_T_DS: {
 			wl_dsss_t *dsss = (wl_dsss_t *)ow_phy;
 			dsss->wl_dsss_subtype = WL_DSSS;
-			dsss->wl_dsss_channel =
-			    ieee80211_chan2ieee(ic, ch);
+			dsss->wl_dsss_frequency = ch->ich_freq;
 			break;
 		}
 		case IEEE80211_T_OFDM: {
 			wl_erp_t *erp = (wl_erp_t *)ow_phy;
 			erp->wl_erp_subtype = WL_ERP;
-			erp->wl_erp_channel =
-			    ieee80211_chan2ieee(ic, ch);
+			erp->wl_erp_frequency = ch->ich_freq;
 			erp->wl_erp_ht_enabled = WIFI_HT_MODE(in);
 			break;
 		}
@@ -1906,7 +817,7 @@
 {
 	wl_capability_t ow_caps;
 
-	ow_caps.caps = ic->ic_caps;
+	ow_caps = ic->ic_caps;
 	bcopy(&ow_caps, wldp_buf, sizeof (wl_capability_t));
 
 }
@@ -1917,22 +828,23 @@
 static int
 wl_set_wpa(struct ieee80211com *ic, const void *wldp_buf)
 {
-	int err = 0;
 	wl_wpa_t *wpa = (wl_wpa_t *)wldp_buf;
 
 	ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_set_wpa: "
-	    "set wpa=%u\n", wpa->wpa_flag);
+	    "set wpa=%u\n", *wpa);
 
-	if (wpa->wpa_flag > 0) {
+	if (*wpa == B_TRUE) {
 		/* enable wpa mode */
 		ic->ic_flags |= IEEE80211_F_PRIVACY;
 		ic->ic_flags |= IEEE80211_F_WPA;
-	} else {
+	} else if (*wpa == B_FALSE) {
 		ic->ic_flags &= ~IEEE80211_F_PRIVACY;
 		ic->ic_flags &= ~IEEE80211_F_WPA;
+	} else {
+		return (EINVAL);
 	}
 
-	return (err);
+	return (0);
 }
 
 static void
@@ -1941,74 +853,57 @@
 	wl_wpa_t *wpa;
 
 	wpa = (wl_wpa_t *)wldp_buf;
-	wpa->wpa_flag = ((ic->ic_flags & IEEE80211_F_WPA) ? 1 : 0);
+	*wpa = ((ic->ic_flags & IEEE80211_F_WPA) ? B_TRUE : B_FALSE);
 
 	ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_get_wpa: "
-	    "get wpa=%u\n", wpa->wpa_flag);
+	    "get wpa=%u\n", *wpa);
 
 }
 
 /*
- * MAC_PROP_WL_SCANRESULTS
+ * MAC_PROP_WL_COUNTERM
  */
-
-static void
-wl_get_scanresults(struct ieee80211com *ic, void *wldp_buf)
+static int
+wl_set_counterm(struct ieee80211com *ic, const void *wldp_buf)
 {
-	wl_wpa_ess_t *sr;
-	ieee80211_node_t *in;
-	ieee80211_node_table_t *nt;
-	int ap_num;
-	int len;
+	boolean_t *counterm = (boolean_t *)wldp_buf;
 
-	sr = (wl_wpa_ess_t *)wldp_buf;
-	sr->count = 0;
-	ap_num = 0;
-
-	ieee80211_dbg(IEEE80211_MSG_WPA, "wl_get_scanrelults\n");
-
-	nt = &ic->ic_scan;
-	IEEE80211_NODE_LOCK(nt);
-	in = list_head(&nt->nt_node);
+	ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_set_counterm: "
+	    "set tkip countermeasures = %u\n", *counterm);
 
-	while (in != NULL) {
-		/* filter out non-wpa APs */
-		if (in->in_wpa_ie == NULL) {
-			in = list_next(&nt->nt_node, in);
-			continue;
-		}
-		bcopy(in->in_bssid, sr->ess[ap_num].bssid,
-		    IEEE80211_ADDR_LEN);
-		sr->ess[ap_num].ssid_len = in->in_esslen;
-		bcopy(in->in_essid, sr->ess[ap_num].ssid,
-		    in->in_esslen);
-		sr->ess[ap_num].freq = in->in_chan->ich_freq;
+	if (*counterm == B_FALSE) {
+		ic->ic_flags &= ~IEEE80211_F_COUNTERM;
+	} else {
+		if ((ic->ic_flags & IEEE80211_F_WPA) == 0)
+			return (EOPNOTSUPP);
+		ic->ic_flags |= IEEE80211_F_COUNTERM;
+	}
 
-		len = in->in_wpa_ie[1] + 2;
-		bcopy(in->in_wpa_ie, sr->ess[ap_num].wpa_ie, len);
-		sr->ess[ap_num].wpa_ie_len = len;
-
-		ap_num++;
-		in = list_next(&nt->nt_node, in);
-	}
-	IEEE80211_NODE_UNLOCK(nt);
-	sr->count = ap_num;
-
+	return (0);
 }
 
 /*
  * MAC_PROP_WL_ESS_LIST
  */
-static void
-wl_get_esslist(struct ieee80211com *ic, void *wldp_buf)
+static int
+wl_get_esslist(struct ieee80211com *ic, void *wldp_buf, uint_t wldp_length)
 {
 	wl_ess_list_t *ess_list;
 
 	ess_list = (wl_ess_list_t *)wldp_buf;
 
 	ess_list->wl_ess_list_num = 0;
+	ess_list->wl_ess_list_size = (uint16_t)wldp_length;
+
 	ieee80211_iterate_nodes(&ic->ic_scan, wifi_read_ap, ess_list);
 
+	if (ess_list->wl_ess_list_size == USHRT_MAX)
+		return (ENOSPC);
+
+	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_get_esslist: "
+	    "nodes num=%u\n", ess_list->wl_ess_list_num);
+
+	return (0);
 }
 
 /*
@@ -2017,22 +912,20 @@
 static int
 wl_set_wepkey(struct ieee80211com *ic, const void *wldp_buf)
 {
-	int	 err = 0;
 	uint16_t i;
 	uint32_t klen;
 	struct ieee80211_key *key;
 	wl_wep_key_t *wepkey = (wl_wep_key_t *)wldp_buf;
 
 	/* set all valid keys */
-	for (i = 0; i < MAX_NWEPKEYS; i++) {
+	for (i = 0; i < IEEE80211_KEY_MAX; i++) {
 		if (wepkey[i].wl_wep_operation != WL_ADD)
 			continue;
 		klen = wepkey[i].wl_wep_length;
 		if (klen > IEEE80211_KEYBUF_SIZE) {
 			ieee80211_err("wl_set_wepkey: "
 			    "invalid wepkey length, %u\n", klen);
-			err = EINVAL;
-			continue;  /* continue to set other keys */
+			return (EINVAL);
 		}
 		if (klen == 0)
 			continue;
@@ -2047,62 +940,78 @@
 		    IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV, key) == 0) {
 			ieee80211_err("wl_set_wepkey: "
 			    "abort, create key failed. id=%u\n", i);
-			err = EIO;
-			continue;
+			return (EIO);
 		}
 
 		key->wk_keyix = i;
 		key->wk_keylen = (uint8_t)klen;
 		key->wk_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV;
 		bzero(key->wk_key, IEEE80211_KEYBUF_SIZE);
-		bcopy(wepkey[i].wl_wep_key, key->wk_key, klen);
+		bcopy(wepkey[i].wl_wep_keyval, key->wk_key, klen);
 		if (ieee80211_crypto_setkey(ic, key, ic->ic_macaddr)
 		    == 0) {
 			ieee80211_err("wl_set_wepkey: "
 			    "set key failed len=%u\n", klen);
-			err = EIO;
+			return (EIO);
 		}
 	}
-	if (err == 0)
-		err = ENETRESET;
 
-	return (err);
+	return (0);
 }
 
 /*
- * MAC_PROP_WL_SETOPTIE
+ * MAC_PROP_WL_OPTIE
  */
+
+static int
+wl_get_optie(struct ieee80211com *ic, const void *wldp_buf)
+{
+	wl_wpa_ie_t *ie_in = (wl_wpa_ie_t *)wldp_buf;
+
+	if (ic->ic_opmode != IEEE80211_M_STA) {
+		ieee80211_err("wl_get_optie: opmode err\n");
+		return (EINVAL);
+	}
+	if (ic->ic_opt_ie_len == 0 ||
+	    ic->ic_opt_ie_len > IEEE80211_MAX_OPT_IE) {
+		ieee80211_err("wl_get_optie: optie is not set\n");
+		return (EINVAL);
+	}
+	if (ic->ic_opt_ie == NULL) {
+		ieee80211_dbg(IEEE80211_MSG_BRUSSELS,
+		    "wl_get_optie: ic_opt_ie == NULL\n");
+		return (EINVAL);
+	}
+	(void) memcpy(ie_in->wpa_ie, ic->ic_opt_ie, ic->ic_opt_ie_len);
+	ie_in->wpa_ie_len = ic->ic_opt_ie_len;
+
+	return (0);
+}
+
 static int
 wl_set_optie(struct ieee80211com *ic, const void *wldp_buf)
 {
-	int err = 0;
-	char *ie;
+	uint8_t *ie;
 	wl_wpa_ie_t *ie_in = (wl_wpa_ie_t *)wldp_buf;
 
 	if (ic->ic_opmode != IEEE80211_M_STA) {
 		ieee80211_err("wl_set_optie: opmode err\n");
-		err = EINVAL;
-		return (err);
+		return (EINVAL);
 	}
-	if (ie_in->wpa_ie_len > IEEE80211_MAX_OPT_IE) {
 
-		ieee80211_err("wl_set_optie: optie is too long\n");
+	ieee80211_dbg(IEEE80211_MSG_BRUSSELS,
+	    "wl_set_optie: opt_ie len %u\n", ie_in->wpa_ie_len);
 
-		err = EINVAL;
-		return (err);
-	}
+	if (ic->ic_opt_ie != NULL)
+		ieee80211_free(ic->ic_opt_ie);
 
 	ie = ieee80211_malloc(ie_in->wpa_ie_len);
 	(void) memcpy(ie, ie_in->wpa_ie, ie_in->wpa_ie_len);
-	if (ic->ic_opt_ie != NULL) {
-		ieee80211_dbg(IEEE80211_MSG_BRUSSELS,
-		    "wl_set_optie:ic_opt_ie!=NULL\n");
-		ieee80211_free(ic->ic_opt_ie);
-	}
+
 	ic->ic_opt_ie = ie;
 	ic->ic_opt_ie_len = ie_in->wpa_ie_len;
 
-	return (err);
+	return (0);
 }
 
 /*
@@ -2111,7 +1020,6 @@
 static int
 wl_set_delkey(struct ieee80211com *ic, const void *wldp_buf)
 {
-	int err = 0;
 	int kid;
 	wl_del_key_t *dk = (wl_del_key_t *)wldp_buf;
 
@@ -2123,15 +1031,14 @@
 	if (kid == IEEE80211_KEYIX_NONE ||
 	    kid >= IEEE80211_WEP_NKID) {
 		ieee80211_err("wl_set_delkey: incorrect keyix\n");
-		err = EINVAL;
-		return (err);
+		return (EINVAL);
 	} else {
 		(void) ieee80211_crypto_delkey(ic,
 		    &ic->ic_nw_keys[kid]);
 		ieee80211_mac_update(ic);
 	}
 
-	return (err);
+	return (0);
 }
 
 /*
@@ -2141,40 +1048,34 @@
 static int
 wl_set_mlme(struct ieee80211com *ic, const void *wldp_buf)
 {
-	int err = 0;
-	uint32_t flags;
 	ieee80211_node_t *in;
 	wl_mlme_t *mlme = (wl_mlme_t *)wldp_buf;
 
-	ieee80211_dbg(IEEE80211_MSG_WPA, "wl_set_mlme: "
-	    "op=%d\n", mlme->im_op);
-
 	switch (mlme->im_op) {
 	case IEEE80211_MLME_DISASSOC:
 	case IEEE80211_MLME_DEAUTH:
 		if (ic->ic_opmode == IEEE80211_M_STA) {
-			/*
-			 * Mask ic_flags of IEEE80211_F_WPA to disable
-			 * ieee80211_notify temporarily.
-			 */
-			flags = ic->ic_flags;
-			ic->ic_flags &= ~IEEE80211_F_WPA;
-
+			ieee80211_dbg(IEEE80211_MSG_WPA,
+			    "wl_set_mlme: DISASSOC <%s> \n",
+			    ieee80211_macaddr_sprintf(mlme->im_macaddr));
 			IEEE80211_UNLOCK(ic);
 			ieee80211_new_state(ic, IEEE80211_S_INIT,
 			    mlme->im_reason);
 			IEEE80211_LOCK(ic);
-
-			ic->ic_flags = flags;
 		}
 		break;
 	case IEEE80211_MLME_ASSOC:
 		if (ic->ic_opmode != IEEE80211_M_STA) {
 			ieee80211_err("wifi_cfg_setmlme: opmode err\n");
-			err = EINVAL;
-			break;
+			return (EINVAL);
 		}
-		if (ic->ic_des_esslen != 0) {
+		ieee80211_dbg(IEEE80211_MSG_WPA,
+		    "wl_set_mlme: ASSOC <%s> \n",
+		    ieee80211_macaddr_sprintf(mlme->im_macaddr));
+		if (ic->ic_flags & IEEE80211_F_DESBSSID) {
+			in = ieee80211_find_node(&ic->ic_scan,
+			    ic->ic_des_bssid);
+		} else if (ic->ic_des_esslen != 0) {
 		/*
 		 * Desired ssid specified; must match both bssid and
 		 * ssid to distinguish ap advertising multiple ssid's.
@@ -2191,21 +1092,18 @@
 			    mlme->im_macaddr);
 		}
 		if (in == NULL) {
-			ieee80211_err("wifi_cfg_setmlme: "
-			    "no matched node\n");
-			err = EINVAL;
-			break;
+			ieee80211_err("wifi_cfg_setmlme: no matched node\n");
+			return (EINVAL);
 		}
 		IEEE80211_UNLOCK(ic);
 		ieee80211_sta_join(ic, in);
 		IEEE80211_LOCK(ic);
 		break;
 	default:
-		err = EINVAL;
-		break;
+		return (EINVAL);
 	}
 
-	return (err);
+	return (0);
 }
 
 /*
@@ -2215,35 +1113,46 @@
 wl_set_wpakey(struct ieee80211com *ic, const void *wldp_buf)
 {
 	int err = 0;
-	uint16_t kid;
 	struct ieee80211_node *in;
 	struct ieee80211_key *wk;
+	uint16_t kid;
 	wl_key_t ik;
 
 	bcopy(wldp_buf, &ik, sizeof (wl_key_t));
 
+	/* Note: cipher support is verified by ieee80211_crypt_newkey */
+	/* Note: this also checks ik->ik_keylen > sizeof (wk->wk_key) */
+	if (ik.ik_keylen > sizeof (ik.ik_keydata))
+		return (E2BIG);
+
 	ieee80211_dbg(IEEE80211_MSG_BRUSSELS, "wl_set_wpakey: "
-	    "idx=%d\n", ik.ik_keyix);
+	    "idx=%u flags=0x%x\n", ik.ik_keyix, ik.ik_flags);
 
-	/*
-	 * cipher support is verified by ieee80211_crypt_newkey
-	 * this also checks ik.ik_keylen > sizeof(wk->wk_key)
-	 */
-	if (ik.ik_keylen > sizeof (ik.ik_keydata)) {
-		ieee80211_err("wl_set_wpakey: key is too long\n");
-		err = EINVAL;
-		return (err);
-	}
 	kid = ik.ik_keyix;
-	if (kid == IEEE80211_KEYIX_NONE || kid >= IEEE80211_WEP_NKID) {
-		ieee80211_err("wl_set_wpakey: incorrect keyix\n");
-		err = EINVAL;
-		return (err);
+	if (kid == IEEE80211_KEYIX_NONE) {
+		/* XXX unicast keys currently must be tx/rx */
+		if (ik.ik_flags != (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV |
+		    IEEE80211_KEY_DEFAULT))
+			return (EINVAL);
+		if (ic->ic_opmode == IEEE80211_M_STA) {
+			in = ieee80211_ref_node(ic->ic_bss);
+			if (!IEEE80211_ADDR_EQ(ik.ik_macaddr, in->in_bssid)) {
+				ieee80211_free_node(in);
+				return (EADDRNOTAVAIL);
+			}
+		} else {
+			in = ieee80211_find_node(&ic->ic_sta, ik.ik_macaddr);
+			if (in == NULL)
+				return (ENOENT);
+		}
+		wk = &ic->ic_nw_keys[ic->ic_def_txkey];
 	} else {
+		if (kid >= IEEE80211_WEP_NKID)
+			return (EINVAL);
 		wk = &ic->ic_nw_keys[kid];
 		/*
-		 * Globle slots start off w/o any assigned key index.
-		 * Force one here for consistency with WEPKEY.
+		 * Global slots start off w/o any assigned key index.
+		 * Force one here for consistency with IEEE80211_IOC_WEPKEY.
 		 */
 		if (wk->wk_keyix == IEEE80211_KEYIX_NONE)
 			wk->wk_keyix = kid;
@@ -2251,30 +1160,26 @@
 	}
 
 	KEY_UPDATE_BEGIN(ic);
-	if (ieee80211_crypto_newkey(ic, ik.ik_type,
-	    ik.ik_flags, wk)) {
+	if (ieee80211_crypto_newkey(ic, ik.ik_type, ik.ik_flags, wk)) {
 		wk->wk_keylen = ik.ik_keylen;
-		/* MIC presence is implied by cipher type */
+		/* Note: MIC presence is implied by cipher type */
 		if (wk->wk_keylen > IEEE80211_KEYBUF_SIZE)
 			wk->wk_keylen = IEEE80211_KEYBUF_SIZE;
 		wk->wk_keyrsc = ik.ik_keyrsc;
-		wk->wk_keytsc = 0;
-		wk->wk_flags |= ik.ik_flags &
-		    (IEEE80211_KEY_XMIT | IEEE80211_KEY_RECV);
-		(void) memset(wk->wk_key, 0, sizeof (wk->wk_key));
-		(void) memcpy(wk->wk_key, ik.ik_keydata,
-		    ik.ik_keylen);
+		wk->wk_keytsc = 0;			/* new key, reset */
+		bzero(wk->wk_key, sizeof (wk->wk_key));
+		bcopy(ik.ik_keydata, wk->wk_key, ik.ik_keylen);
 		if (!ieee80211_crypto_setkey(ic, wk,
 		    in != NULL ? in->in_macaddr : ik.ik_macaddr)) {
 			err = EIO;
 		} else if ((ik.ik_flags & IEEE80211_KEY_DEFAULT)) {
-			ic->ic_def_txkey = kid;
 			ieee80211_mac_update(ic);
 		}
-	} else {
-		err = EIO;
-	}
+	} else
+		err = ENXIO;
 	KEY_UPDATE_END(ic);
+	if (in != NULL)
+		ieee80211_free_node(in);
 
 	return (err);
 }
@@ -2326,15 +1231,13 @@
 wl_set_createibss(struct ieee80211com *ic, const void *wldp_buf)
 {
 	wl_create_ibss_t *iw_ibss = (wl_create_ibss_t *)wldp_buf;
-	int err = 0;
 
 	ieee80211_dbg(IEEE80211_MSG_CONFIG, "wl_set_ibss: "
 	    "set createibss=%u\n", *iw_ibss);
 
-	if ((ic->ic_caps & IEEE80211_C_IBSS) == 0) {
-		err = ENOTSUP;
-		return (err);
-	}
+	if ((ic->ic_caps & IEEE80211_C_IBSS) == 0)
+		return (ENOTSUP);
+
 	if (*iw_ibss) {
 		if ((ic->ic_flags & IEEE80211_F_IBSSON) == 0) {
 			ic->ic_flags |= IEEE80211_F_IBSSON;
@@ -2345,16 +1248,15 @@
 			 * everything is setup appropriately.
 			 */
 			ieee80211_reset_erp(ic);
-			err = ENETRESET;
+			ieee80211_create_ibss(ic, ic->ic_ibss_chan);
+			return (0);
 		}
 	} else {
-		if (ic->ic_flags & IEEE80211_F_IBSSON) {
+		if (ic->ic_flags & IEEE80211_F_IBSSON)
 			ic->ic_flags &= ~IEEE80211_F_IBSSON;
-			err = ENETRESET;
-		}
 	}
 
-	return (err);
+	return (ENETRESET);
 }
 
 static void
@@ -2369,7 +1271,7 @@
  * Typically invoked by drivers in response to request for
  * information or to change settings from the userland.
  *
- * Return value should be checked by WiFI drivers. Return 0
+ * Return value should be checked by WiFi drivers. Return 0
  * on success. Otherwise, return non-zero value to indicate
  * the error. Driver should operate as below when the return
  * error is:
@@ -2378,7 +1280,12 @@
  * 		parameter has been changed.
  * 		When acknowledge a M_IOCTL message, this error
  * 		is ignored
+ *
+ * Not yet implemented:
+ * MAC_PROP_WL_POWER_MODE
+ * MAC_PROP_WL_RADIO,
  */
+
 /* ARGSUSED */
 int
 ieee80211_setprop(void *ic_arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
@@ -2419,13 +1326,16 @@
 	case MAC_PROP_WL_WPA:
 		err = wl_set_wpa(ic, wldp_buf);
 		break;
+	case MAC_PROP_WL_COUNTERM:
+		err = wl_set_counterm(ic, wldp_buf);
+		break;
 	case MAC_PROP_WL_KEY:
 		err = wl_set_wpakey(ic, wldp_buf);
 		break;
 	case MAC_PROP_WL_DELKEY:
 		err = wl_set_delkey(ic, wldp_buf);
 		break;
-	case MAC_PROP_WL_SETOPTIE:
+	case MAC_PROP_WL_OPTIE:
 		err = wl_set_optie(ic, wldp_buf);
 		break;
 	case MAC_PROP_WL_MLME:
@@ -2439,10 +1349,6 @@
 	case MAC_PROP_WL_SUPPORTED_RATES:
 	case MAC_PROP_WL_RSSI:
 	case MAC_PROP_WL_CAPABILITY:
-	case MAC_PROP_WL_SCANRESULTS:
-		ieee80211_err("ieee80211_setprop: opmode err\n");
-		err = EINVAL;
-		break;
 	default:
 		ieee80211_err("ieee80211_setprop: opmode not support\n");
 		err = ENOTSUP;
@@ -2492,7 +1398,7 @@
 		wl_get_linkstatus(ic, wldp_buf);
 		break;
 	case MAC_PROP_WL_ESS_LIST:
-		wl_get_esslist(ic, wldp_buf);
+		err = wl_get_esslist(ic, wldp_buf, wldp_length);
 		break;
 	case MAC_PROP_WL_SUPPORTED_RATES:
 		wl_get_suprates(ic, wldp_buf);
@@ -2506,16 +1412,16 @@
 	case MAC_PROP_WL_WPA:
 		wl_get_wpa(ic, wldp_buf);
 		break;
-	case MAC_PROP_WL_SCANRESULTS:
-		wl_get_scanresults(ic, wldp_buf);
-		break;
 	case MAC_PROP_WL_CREATE_IBSS:
 		wl_get_createibss(ic, wldp_buf);
 		break;
+	case MAC_PROP_WL_OPTIE:
+		err = wl_get_optie(ic, wldp_buf);
+		break;
 	case MAC_PROP_WL_KEY_TAB:
 	case MAC_PROP_WL_KEY:
 	case MAC_PROP_WL_DELKEY:
-	case MAC_PROP_WL_SETOPTIE:
+	case MAC_PROP_WL_COUNTERM:
 	case MAC_PROP_WL_MLME:
 		ieee80211_err("ieee80211_setprop: opmode err\n");
 		err = EINVAL;
@@ -2547,8 +1453,149 @@
 	case MAC_PROP_WL_SUPPORTED_RATES:
 	case MAC_PROP_WL_RSSI:
 	case MAC_PROP_WL_CAPABILITY:
-	case MAC_PROP_WL_SCANRESULTS:
 	case MAC_PROP_WL_CREATE_IBSS:
 		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
 	}
 }
+
+/*
+ * Register WPA door
+ */
+void
+ieee80211_register_door(ieee80211com_t *ic, const char *drvname, int inst)
+{
+	(void) snprintf(ic->ic_wpadoor, MAX_IEEE80211STR, "%s_%s%d",
+	    WPA_DOOR, drvname, inst);
+}
+
+/*
+ * ieee80211_event_thread
+ * open wpa door, send event to wpa_supplicant
+ */
+static void
+ieee80211_event_thread(void *arg)
+{
+	ieee80211com_t *ic = arg;
+	door_handle_t event_door = NULL;	/* Door for upcalls */
+	door_info_t dinfo;
+	door_arg_t darg;
+	wl_event_t ev;
+
+	if (arg == NULL)
+		return;
+
+	mutex_enter(&ic->ic_doorlock);
+
+	ieee80211_dbg(IEEE80211_MSG_DEBUG, "ieee80211_event_thread(%d)\n",
+	    ic->ic_ev_type);
+
+	ev.wpa_ev_type = ic->ic_ev_type;
+	ev.wpa_ev_reason = ic->ic_ev_reason;
+	bcopy(ic->ic_ev_beacon, ev.wpa_ev_beacon, IEEE80211_ADDR_LEN);
+
+	/*
+	 * Locate the door used for upcalls
+	 */
+	if (door_ki_open(ic->ic_wpadoor, &event_door) != 0) {
+		if (ic->ic_ev_type != NET80211_EVENT_INTERFACE_STATUS)
+			ieee80211_err("ieee80211_event_thread: door_ki_open(%s)"
+			    " err\n", ic->ic_wpadoor);
+		goto out;
+	}
+
+	if (door_ki_info(event_door, &dinfo) != 0) {
+		ieee80211_err("ieee80211_event_thread: door_ki_info(%s) err\n",
+		    ic->ic_wpadoor);
+		goto out;
+	}
+
+	if ((dinfo.di_attributes & DOOR_REVOKED) ||
+	    (dinfo.di_attributes & DOOR_IS_UNREF)) {
+		ieee80211_err("ieee80211_event_thread: door revoked (%s) err\n",
+		    ic->ic_wpadoor);
+		goto out;
+	}
+
+	darg.data_ptr = (char *)&ev;
+	darg.data_size = sizeof (wl_event_t);
+	darg.desc_ptr = NULL;
+	darg.desc_num = 0;
+	darg.rbuf = NULL;
+	darg.rsize = 0;
+
+	if (door_ki_upcall_limited(event_door, &darg, NULL, 0, 0) != 0)
+		ieee80211_err("ieee80211_event_thread: door_ki_upcall() err\n");
+
+out:
+	if (event_door)	/* release our hold (if any) */
+		door_ki_rele(event_door);
+
+	mutex_exit(&ic->ic_doorlock);
+}
+
+/*
+ * Send system messages to notify the device has joined a WLAN.
+ * This is an OS specific function. illumos marks link status as up.
+ */
+void
+ieee80211_notify_node_join(ieee80211com_t *ic, ieee80211_node_t *in)
+{
+	ieee80211_dbg(IEEE80211_MSG_WPA, "ieee80211_notify_node_join()");
+	ic->ic_ev_type = NET80211_EVENT_ASSOC;
+	if (in == ic->ic_bss)
+		mac_link_update(ic->ic_mach, LINK_STATE_UP);
+
+	/* notify after state change is over */
+	(void) timeout(ieee80211_event_thread, (void *)ic, 0);
+}
+
+void
+ieee80211_notify_node_leave(ieee80211com_t *ic, ieee80211_node_t *in)
+{
+	ieee80211_dbg(IEEE80211_MSG_WPA, "ieee80211_notify_node_leave()");
+	ic->ic_ev_type = NET80211_EVENT_DISASSOC;
+	if (in == ic->ic_bss)
+		mac_link_update(ic->ic_mach, LINK_STATE_DOWN);
+	(void) timeout(ieee80211_event_thread, (void *)ic, 0);
+}
+
+void
+ieee80211_notify_scan_res(ieee80211com_t *ic)
+{
+	ieee80211_dbg(IEEE80211_MSG_WPA, "ieee80211_notify_scan_res()");
+	ic->ic_ev_type = NET80211_EVENT_SCAN_RESULTS;
+
+	/* notify after state change is over */
+	(void) timeout(ieee80211_event_thread, (void *)ic, 0);
+}
+
+void
+ieee80211_notify_rejected(ieee80211com_t *ic, ieee80211_node_t *in,
+    uint16_t code)
+{
+	ieee80211_dbg(IEEE80211_MSG_WPA, "ieee80211_notify_rejected()");
+	ic->ic_ev_type = NET80211_EVENT_ASSOC_REJECT;
+	ic->ic_ev_reason = code;
+	bcopy(in->in_bssid, ic->ic_ev_beacon, IEEE80211_ADDR_LEN);
+	(void) timeout(ieee80211_event_thread, (void *)ic, 0);
+}
+
+void
+ieee80211_notify_timedout(ieee80211com_t *ic, ieee80211_node_t *in)
+{
+	ieee80211_dbg(IEEE80211_MSG_WPA, "ieee80211_notify_timedout()");
+	ic->ic_ev_type = NET80211_EVENT_ASSOC_TIMED_OUT;
+	bcopy(in->in_bssid, ic->ic_ev_beacon, IEEE80211_ADDR_LEN);
+	(void) timeout(ieee80211_event_thread, (void *)ic, 0);
+}
+
+void
+ieee80211_notify_detach(ieee80211com_t *ic)
+{
+	size_t len;
+	ieee80211_dbg(IEEE80211_MSG_WPA, "ieee80211_notify_detach()");
+	ic->ic_ev_type = NET80211_EVENT_INTERFACE_STATUS;
+	len = wifi_strnlen(WPA_DOOR, 100);
+	bcopy(ic->ic_wpadoor + len, ic->ic_ev_beacon, IEEE80211_ADDR_LEN);
+	ieee80211_event_thread(ic);
+}
--- a/usr/src/uts/common/io/net80211/net80211_node.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/io/net80211/net80211_node.c	Wed May 29 08:31:24 2013 +0200
@@ -1,6 +1,7 @@
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 /*
@@ -50,7 +51,6 @@
 static void ieee80211_node_reclaim(ieee80211_node_table_t *,
     ieee80211_node_t *);
 static void ieee80211_free_node_locked(ieee80211_node_t *);
-static void ieee80211_free_allnodes(ieee80211_node_table_t *);
 static void ieee80211_node_leave(ieee80211com_t *, ieee80211_node_t *);
 static void ieee80211_timeout_scan_candidates(ieee80211_node_table_t *);
 static void ieee80211_timeout_stations(ieee80211_node_table_t *);
@@ -243,8 +243,6 @@
 	 * Clear scan state and flush any previously seen AP's.
 	 */
 	ieee80211_reset_scan(ic);
-	if (reset)
-		ieee80211_free_allnodes(&ic->ic_scan);
 
 	ic->ic_flags |= IEEE80211_F_SCAN;
 	IEEE80211_UNLOCK(ic);
@@ -295,12 +293,22 @@
 			ic->ic_bss->in_rates =
 			    ic->ic_sup_rates[ieee80211_chan2mode(ic, chan)];
 			IEEE80211_UNLOCK(ic);
-			ieee80211_new_state(ic, IEEE80211_S_SCAN, -1);
+			ieee80211_new_state(ic, IEEE80211_S_SCAN, 0);
 			return;
 		}
 	} while (chan != ic->ic_curchan);
 	IEEE80211_UNLOCK(ic);
-	ieee80211_end_scan(ic);
+
+	/*
+	 * some wifi device drivers need to cancel scan twice, now and
+	 * one more time after we move to INIT state
+	 */
+	ieee80211_cancel_scan(ic);
+	/*
+	 * We always need to return to INIT state when finished,
+	 * otherwise some device drivers won't be ready on the next active scan.
+	 */
+	ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
 }
 
 /*
@@ -468,67 +476,13 @@
 	((_rs).ir_rates[(_rs).ir_nrates - 1] & IEEE80211_RATE_VAL)
 
 /*
- * Compare the capabilities of node a with node b and decide which is
- * more desirable (return b if b is considered better than a).  Note
- * that we assume compatibility/usability has already been checked
- * so we don't need to (e.g. validate whether privacy is supported).
- * Used to select the best scan candidate for association in a BSS.
- *
- * Return desired node
- */
-static ieee80211_node_t *
-ieee80211_node_compare(ieee80211com_t *ic, ieee80211_node_t *a,
-    ieee80211_node_t *b)
-{
-	uint8_t maxa;
-	uint8_t maxb;
-	uint8_t rssia;
-	uint8_t rssib;
-
-	/* privacy support preferred */
-	if ((a->in_capinfo & IEEE80211_CAPINFO_PRIVACY) &&
-	    !(b->in_capinfo & IEEE80211_CAPINFO_PRIVACY)) {
-		return (a);
-	}
-	if (!(a->in_capinfo & IEEE80211_CAPINFO_PRIVACY) &&
-	    (b->in_capinfo & IEEE80211_CAPINFO_PRIVACY)) {
-		return (b);
-	}
-
-	/* compare count of previous failures */
-	if (b->in_fails != a->in_fails)
-		return ((a->in_fails > b->in_fails) ? b : a);
-
-	rssia = ic->ic_node_getrssi(a);
-	rssib = ic->ic_node_getrssi(b);
-	if (ABS(rssib - rssia) < IEEE80211_RSSI_CMP_THRESHOLD) {
-		/* best/max rate preferred if signal level close enough */
-		maxa = IEEE80211_MAXRATE(a->in_rates);
-		maxb = IEEE80211_MAXRATE(b->in_rates);
-		if (maxa != maxb)
-			return ((maxb > maxa) ? b : a);
-		/* for now just prefer 5Ghz band to all other bands */
-		if (IEEE80211_IS_CHAN_5GHZ(a->in_chan) &&
-		    !IEEE80211_IS_CHAN_5GHZ(b->in_chan)) {
-			return (a);
-		}
-		if (!IEEE80211_IS_CHAN_5GHZ(a->in_chan) &&
-		    IEEE80211_IS_CHAN_5GHZ(b->in_chan)) {
-			return (b);
-		}
-	}
-	/* all things being equal, compare signal level */
-	return ((rssib > rssia) ? b : a);
-}
-
-/*
  * Mark an ongoing scan stopped.
  */
 void
 ieee80211_cancel_scan(ieee80211com_t *ic)
 {
 	IEEE80211_LOCK(ic);
-	ieee80211_dbg(IEEE80211_MSG_SCAN, "ieee80211_cancel_scan()"
+	ieee80211_dbg(IEEE80211_MSG_SCAN, "ieee80211_cancel_scan(): "
 	    "end %s scan\n",
 	    (ic->ic_flags & IEEE80211_F_ASCAN) ?  "active" : "passive");
 	ic->ic_flags &= ~(IEEE80211_F_SCAN | IEEE80211_F_ASCAN);
@@ -537,105 +491,6 @@
 }
 
 /*
- * Complete a scan of potential channels. It is called by
- * ieee80211_next_scan() when the state machine has performed
- * a full cycle of scaning on all available radio channels.
- * ieee80211_end_scan() will inspect the node cache for suitable
- * APs found during scaning, and associate with one, should
- * the parameters of the node match those of the configuration
- * requested from userland.
- */
-void
-ieee80211_end_scan(ieee80211com_t *ic)
-{
-	ieee80211_node_table_t *nt = &ic->ic_scan;
-	ieee80211_node_t *in;
-	ieee80211_node_t *selbs;
-
-	ieee80211_cancel_scan(ic);
-	/* notify SCAN done */
-	ieee80211_notify(ic, EVENT_SCAN_RESULTS);
-	IEEE80211_LOCK(ic);
-
-	/*
-	 * Automatic sequencing; look for a candidate and
-	 * if found join the network.
-	 */
-	/* NB: unlocked read should be ok */
-	in = list_head(&nt->nt_node);
-	if (in == NULL && (ic->ic_flags & IEEE80211_F_WPA) == 0) {
-		ieee80211_dbg(IEEE80211_MSG_SCAN, "ieee80211_end_scan: "
-		    "no scan candidate\n");
-	notfound:
-		if (ic->ic_opmode == IEEE80211_M_IBSS &&
-		    (ic->ic_flags & IEEE80211_F_IBSSON) &&
-		    ic->ic_des_esslen != 0) {
-			ieee80211_create_ibss(ic, ic->ic_ibss_chan);
-			IEEE80211_UNLOCK(ic);
-			return;
-		}
-
-		/*
-		 * Reset the list of channels to scan and start again.
-		 */
-		ieee80211_reset_scan(ic);
-		ic->ic_flags |= IEEE80211_F_SCAN | IEEE80211_F_ASCAN;
-		IEEE80211_UNLOCK(ic);
-
-		ieee80211_next_scan(ic);
-		return;
-	}
-
-	if (ic->ic_flags & IEEE80211_F_SCANONLY ||
-	    ic->ic_flags & IEEE80211_F_WPA) {	/* scan only */
-		ic->ic_flags &= ~IEEE80211_F_SCANONLY;
-		IEEE80211_UNLOCK(ic);
-		ieee80211_new_state(ic, IEEE80211_S_INIT, -1);
-		return;
-	}
-
-	selbs = NULL;
-	IEEE80211_NODE_LOCK(nt);
-	while (in != NULL) {
-		if (in->in_fails >= IEEE80211_STA_FAILS_MAX) {
-			ieee80211_node_t *tmpin = in;
-
-			/*
-			 * The configuration of the access points may change
-			 * during my scan.  So delete the entry for the AP
-			 * and retry to associate if there is another beacon.
-			 */
-			in = list_next(&nt->nt_node, tmpin);
-			ieee80211_node_reclaim(nt, tmpin);
-			continue;
-		}
-		/*
-		 * It's possible at some special moments, the in_chan will
-		 * be none. Need to skip the null node.
-		 */
-		if (in->in_chan == IEEE80211_CHAN_ANYC) {
-			in = list_next(&nt->nt_node, in);
-			continue;
-		}
-		if (ieee80211_match_bss(ic, in) == 0) {
-			if (selbs == NULL)
-				selbs = in;
-			else
-				selbs = ieee80211_node_compare(ic, selbs, in);
-		}
-		in = list_next(&nt->nt_node, in);
-	}
-	if (selbs != NULL)	/* grab ref while dropping lock */
-		(void) ieee80211_ref_node(selbs);
-	IEEE80211_NODE_UNLOCK(nt);
-	if (selbs == NULL)
-		goto notfound;
-	IEEE80211_UNLOCK(ic);
-	ieee80211_sta_join(ic, selbs);
-}
-
-
-/*
  * Handle 802.11 ad hoc network merge.  The convention, set by the
  * Wireless Ethernet Compatibility Alliance (WECA), is that an 802.11
  * station will change its BSSID to match the "oldest" 802.11 ad hoc
@@ -1390,18 +1245,6 @@
 }
 
 /*
- * Iterate through the node list, calling ieee80211_node_reclaim() for
- * all nodes associated with the interface.
- */
-static void
-ieee80211_free_allnodes(ieee80211_node_table_t *nt)
-{
-	IEEE80211_NODE_LOCK(nt);
-	ieee80211_free_allnodes_locked(nt);
-	IEEE80211_NODE_UNLOCK(nt);
-}
-
-/*
  * Timeout entries in the scan cache. This is the timeout callback
  * function of node table ic_scan which is called when the inactivity
  * timer expires.
@@ -1499,6 +1342,7 @@
 			IEEE80211_NODE_UNLOCK(nt);
 			if (in->in_associd != 0) {
 				IEEE80211_UNLOCK(ic);
+				ieee80211_notify_timedout(ic, in);
 				IEEE80211_SEND_MGMT(ic, in,
 				    IEEE80211_FC0_SUBTYPE_DEAUTH,
 				    IEEE80211_REASON_AUTH_EXPIRE);
--- a/usr/src/uts/common/io/net80211/net80211_proto.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/io/net80211/net80211_proto.c	Wed May 29 08:31:24 2013 +0200
@@ -1,6 +1,7 @@
 /*
  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
+ * Copyright (c) 2012, Enrico Papi <enricop@computer.org>. All rights reserved.
  */
 
 /*
@@ -726,7 +727,7 @@
 /*
  * Process STA mode beacon miss events. Send a direct probe request
  * frame to the current ap bmiss_max times (w/o answer) before
- * scanning for a new ap.
+ * scanning.
  */
 void
 ieee80211_beacon_miss(ieee80211com_t *ic)
@@ -824,7 +825,10 @@
 		}
 		IEEE80211_LOCK(ic);
 		im->im_mgt_timer = 0;
-		ieee80211_reset_bss(ic);
+		if (ostate != IEEE80211_S_SCAN)
+			ieee80211_reset_bss(ic);
+		else
+			ieee80211_notify_scan_res(ic);
 		break;
 	case IEEE80211_S_SCAN:
 		switch (ostate) {
@@ -836,8 +840,7 @@
 			/*
 			 * Scan next. If doing an active scan and the
 			 * channel is not marked passive-only then send
-			 * a probe request.  Otherwise just listen for
-			 * beacons on the channel.
+			 * a probe request.
 			 */
 			if ((ic->ic_flags & IEEE80211_F_ASCAN) &&
 			    !IEEE80211_IS_CHAN_PASSIVE(ic->ic_curchan)) {
@@ -852,14 +855,15 @@
 			break;
 		case IEEE80211_S_RUN:
 			/* beacon miss */
+			ic->ic_state = ostate;	/* stay RUN */
 			ieee80211_dbg(IEEE80211_MSG_STATE,
 			    "no recent beacons from %s, rescanning\n",
 			    ieee80211_macaddr_sprintf(in->in_macaddr));
 			IEEE80211_UNLOCK(ic);
-			ieee80211_sta_leave(ic, in);
+			ieee80211_beacon_miss(ic);
 			IEEE80211_LOCK(ic);
 			ic->ic_flags &= ~IEEE80211_F_SIBSS;
-			/* FALLTHRU */
+			break;
 		case IEEE80211_S_AUTH:
 		case IEEE80211_S_ASSOC:
 			/* timeout restart scan */
@@ -869,18 +873,26 @@
 				in->in_fails++;
 				ieee80211_unref_node(&in);
 			}
-			break;
+			IEEE80211_UNLOCK(ic);
+			ieee80211_begin_scan(ic, B_FALSE);
+			return (0);
 		}
 		break;
 	case IEEE80211_S_AUTH:
 		ASSERT(ic->ic_opmode == IEEE80211_M_STA);
 		switch (ostate) {
 		case IEEE80211_S_INIT:
-		case IEEE80211_S_SCAN:
 			IEEE80211_UNLOCK(ic);
 			IEEE80211_SEND_MGMT(ic, in, IEEE80211_FC0_SUBTYPE_AUTH,
 			    1);
 			return (0);
+		case IEEE80211_S_SCAN:
+			IEEE80211_UNLOCK(ic);
+			ieee80211_cancel_scan(ic);
+			ieee80211_notify_scan_res(ic);
+			IEEE80211_SEND_MGMT(ic, in, IEEE80211_FC0_SUBTYPE_AUTH,
+			    1);
+			break;
 		case IEEE80211_S_AUTH:
 		case IEEE80211_S_ASSOC:
 			switch (arg) {
@@ -904,10 +916,9 @@
 				return (0);
 			case IEEE80211_FC0_SUBTYPE_DEAUTH:
 				IEEE80211_UNLOCK(ic);
+				IEEE80211_SEND_MGMT(ic, in,
+				    IEEE80211_FC0_SUBTYPE_DEAUTH, 1);
 				ieee80211_sta_leave(ic, in);
-				/* try to re-auth */
-				IEEE80211_SEND_MGMT(ic, in,
-				    IEEE80211_FC0_SUBTYPE_AUTH, 1);
 				return (0);
 			}
 			break;
@@ -949,8 +960,6 @@
 		case IEEE80211_S_ASSOC:		/* infra mode */
 			ASSERT(in->in_txrate < in->in_rates.ir_nrates);
 			im->im_mgt_timer = 0;
-			ieee80211_notify_node_join(ic, in);
-
 			/*
 			 * We can send data now; update the fastpath with our
 			 * current associated BSSID and other relevant settings.
@@ -968,6 +977,7 @@
 				}
 			}
 			(void) mac_pdata_update(ic->ic_mach, &wd, sizeof (wd));
+			ieee80211_notify_node_join(ic, in);
 			break;
 		}
 
--- a/usr/src/uts/common/io/pcan/THIRDPARTYLICENSE	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 1997, 1998, 1999
- *      Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *      This product includes software developed by Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * 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.
- */
--- a/usr/src/uts/common/io/pcan/THIRDPARTYLICENSE.descrip	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-PCAN DRIVER
--- a/usr/src/uts/common/io/pcan/pcan.c	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4651 +0,0 @@
-/*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 1997, 1998, 1999
- *      Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *      This product includes software developed by Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * 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.
- */
-
-#include <sys/conf.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-#include <sys/dlpi.h>
-#include <sys/ethernet.h>
-#include <sys/strsubr.h>
-#include <sys/strsun.h>
-#include <sys/stat.h>
-#include <sys/byteorder.h>
-#include <sys/pccard.h>
-#include <sys/pci.h>
-#include <sys/policy.h>
-#include <sys/mac_provider.h>
-#include <sys/stream.h>
-#include <inet/common.h>
-#include <inet/nd.h>
-#include <inet/mi.h>
-
-#include "pcan.h"
-#include <sys/mac_wifi.h>
-#include <inet/wifi_ioctl.h>
-
-#ifdef	DEBUG
-#define	PCAN_DBG_BASIC		0x1
-#define	PCAN_DBG_INFO		0x2
-#define	PCAN_DBG_SEND		0x4
-#define	PCAN_DBG_RCV		0x8
-#define	PCAN_DBG_LINKINFO	0x10
-#define	PCAN_DBG_FW_VERSION	0x20
-#define	PCAN_DBG_CMD		0x40
-uint32_t pcan_debug = 0;
-#define	PCANDBG(x) \
-	if (pcan_debug & PCAN_DBG_BASIC) cmn_err x
-#else
-#define	PCANDBG(x)
-#endif
-
-static ddi_device_acc_attr_t accattr = {
-		DDI_DEVICE_ATTR_V0,
-		DDI_STRUCTURE_LE_ACC,
-		DDI_STRICTORDER_ACC,
-};
-
-static ddi_dma_attr_t control_cmd_dma_attr = {
-	DMA_ATTR_V0,		/* version of this structure */
-	0,			/* lowest usable address */
-	0xffffffffffffffffull,	/* highest usable address */
-	0xffffffffull,		/* maximum DMAable byte count */
-	4,			/* alignment in bytes */
-	0xfff,			/* burst sizes (any) */
-	1,			/* minimum transfer */
-	0xffffull,		/* maximum transfer */
-	0xffffffffffffffffull,	/* maximum segment length */
-	1,			/* maximum number of segments */
-	1,			/* granularity */
-	0,			/* flags (reserved) */
-};
-
-void *pcan_soft_state_p = NULL;
-static int pcan_device_type;
-
-/*
- * brussels
- */
-static int	pcan_m_setprop(void *arg, const char *pr_name,
-    mac_prop_id_t wldp_pr_num, uint_t wldp_length,
-    const void *wldp_buf);
-static int	pcan_m_getprop(void *arg, const char *pr_name,
-    mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf);
-static void	pcan_m_propinfo(void *arg, const char *pr_name,
-    mac_prop_id_t wldp_pr_num, mac_prop_info_handle_t mph);
-
-mac_callbacks_t pcan_m_callbacks = {
-	MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
-	pcan_gstat,
-	pcan_start,
-	pcan_stop,
-	pcan_prom,
-	pcan_sdmulti,
-	pcan_saddr,
-	pcan_tx,
-	NULL,
-	pcan_ioctl,
-	NULL,
-	NULL,
-	NULL,
-	pcan_m_setprop,
-	pcan_m_getprop,
-	pcan_m_propinfo
-};
-
-static char *pcan_name_str = "pcan";
-
-#ifdef	__sparc
-#define	pcan_quiesce	ddi_quiesce_not_supported
-#else
-static int pcan_quiesce(dev_info_t *);
-#endif
-
-DDI_DEFINE_STREAM_OPS(pcan_dev_ops, nulldev, pcan_probe, pcan_attach,
-    pcan_detach, nodev, NULL, D_MP, NULL, pcan_quiesce);
-
-extern struct mod_ops mod_driverops;
-static struct modldrv modldrv = {
-	&mod_driverops,
-	"Cisco-Aironet 802.11b driver",
-	&pcan_dev_ops
-};
-
-static struct modlinkage modlinkage = {
-	MODREV_1, (void *)&modldrv, NULL
-	};
-
-int
-_init(void)
-{
-	int stat;
-
-	/* Allocate soft state */
-	if ((stat = ddi_soft_state_init(&pcan_soft_state_p,
-	    sizeof (pcan_maci_t), 2)) != DDI_SUCCESS)
-		return (stat);
-
-	mac_init_ops(&pcan_dev_ops, "pcan");
-	stat = mod_install(&modlinkage);
-	if (stat != 0) {
-		mac_fini_ops(&pcan_dev_ops);
-		ddi_soft_state_fini(&pcan_soft_state_p);
-	}
-
-	return (stat);
-}
-
-int
-_fini(void)
-{
-	int stat;
-
-	stat = mod_remove(&modlinkage);
-	if (stat != DDI_SUCCESS)
-		return (stat);
-	mac_fini_ops(&pcan_dev_ops);
-	ddi_soft_state_fini(&pcan_soft_state_p);
-	return (stat);
-}
-
-int
-_info(struct modinfo *modinfop)
-{
-	return (mod_info(&modlinkage, modinfop));
-}
-
-static int
-pcan_probe(dev_info_t *dip)
-{
-	int len, ret;
-	char *buf;
-	dev_info_t *pdip = ddi_get_parent(dip);
-
-	PCANDBG((CE_NOTE, "pcan probe: parent dip=0x%p-%s(%d)\n", (void *)pdip,
-	    ddi_driver_name(pdip), ddi_get_instance(pdip)));
-
-	ret = ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "device_type",
-	    (caddr_t)&buf, &len);
-	if (ret != DDI_SUCCESS)
-		return (DDI_PROBE_FAILURE);
-
-	PCANDBG((CE_NOTE, "pcan probe: device_type %s\n", buf));
-	if ((strcmp(buf, "pccard") == 0) || (strcmp(buf, "pcmcia") == 0)) {
-		pcan_device_type = PCAN_DEVICE_PCCARD;
-#ifdef DEBUG
-		if (pcan_debug & PCAN_DBG_FW_VERSION) {
-			cmn_err(CE_NOTE, "Cisco 802.11 pccard\n");
-		}
-#endif
-		ret = DDI_PROBE_SUCCESS;
-	} else if (strcmp(buf, "pci") == 0) {
-		pcan_device_type = PCAN_DEVICE_PCI;
-#ifdef DEBUG
-		if (pcan_debug & PCAN_DBG_FW_VERSION) {
-			cmn_err(CE_NOTE, "Cisco 802.11 minipci card\n");
-		}
-#endif
-		ret = DDI_PROBE_SUCCESS;
-	} else {
-		cmn_err(CE_NOTE, "pcan probe: unsupported card\n");
-		ret = DDI_PROBE_FAILURE;
-	}
-
-	kmem_free(buf, len);
-	return (ret);
-}
-
-static int
-pcan_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
-{
-	int ret;
-	int instance;
-	uint16_t stat;
-	uint32_t err;
-	pcan_maci_t *pcan_p;
-	wifi_data_t	wd = { 0 };
-	mac_register_t	*macp;
-	modify_config_t cfgmod;
-	char strbuf[256];
-
-	PCANDBG((CE_NOTE, "dip=0x%p cmd=%x\n", (void *)dip, cmd));
-	if (cmd != DDI_ATTACH)
-		goto attach_fail1;
-
-	/*
-	 * Since this driver is porting from freebsd, so just like
-	 * the original driver, the minipci card doesn't work on amd64
-	 * machine.
-	 * For sparc, since no pci card is available for the test, so this
-	 * version doesn't support sparc. If there is card available and
-	 * requirement, future version will try to support sparc.
-	 * This driver works well for minipci card on 32bit x86
-	 * machine, so keep the code to just support minipci card on 32bit
-	 * mode.
-	 */
-#if defined(sparc) || defined(__sparc)
-	if (pcan_device_type == PCAN_DEVICE_PCI) {
-		cmn_err(CE_NOTE, "pcan attach: this driver does not support "
-		    "PCI/MiniPCI card on Sparc\n");
-		goto attach_fail1;
-	}
-#endif /* sparc */
-#if defined(__amd64)
-	if (pcan_device_type == PCAN_DEVICE_PCI) {
-		cmn_err(CE_NOTE, "pcan attach: this driver does not support "
-		    "PCI/MiniPCI card on amd64\n");
-		goto attach_fail1;
-	}
-#endif /* amd64 */
-
-	/* Allocate soft state associated with this instance. */
-	if (ddi_soft_state_zalloc(pcan_soft_state_p,
-	    ddi_get_instance(dip)) != DDI_SUCCESS) {
-		cmn_err(CE_CONT, "pcan attach: alloc softstate failed\n");
-		goto attach_fail1;
-	}
-	pcan_p = (pcan_maci_t *)ddi_get_soft_state(pcan_soft_state_p,
-	    ddi_get_instance(dip));
-
-	pcan_p->pcan_device_type = pcan_device_type;
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-		if (ddi_regs_map_setup(dip, 0,
-		    (caddr_t *)&pcan_p->pcan_cfg_base, 0, 0,
-		    &accattr, &pcan_p->pcan_cfg_handle) != DDI_SUCCESS)
-			goto attach_fail2;
-
-		stat = ddi_get16(pcan_p->pcan_cfg_handle,
-		    (uint16_t *)(pcan_p->pcan_cfg_base + PCI_CONF_COMM));
-		stat |= (PCI_COMM_IO | PCI_COMM_MAE);
-		ddi_put16(pcan_p->pcan_cfg_handle,
-		    (uint16_t *)(pcan_p->pcan_cfg_base + PCI_CONF_COMM), stat);
-
-		ddi_regs_map_free(&pcan_p->pcan_cfg_handle);
-		if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcan_p->pcan_bar0,
-		    0, 0, &accattr, &pcan_p->pcan_handle0) != DDI_SUCCESS)
-			goto attach_fail3;
-		if (ddi_regs_map_setup(dip, 2, (caddr_t *)&pcan_p->pcan_bar1,
-		    0, 0, &accattr, &pcan_p->pcan_handle1) != DDI_SUCCESS)
-			goto attach_fail3;
-		if (ddi_regs_map_setup(dip, 3, (caddr_t *)&pcan_p->pcan_bar2,
-		    0, 0, &accattr, &pcan_p->pcan_handle2) != DDI_SUCCESS)
-			goto attach_fail3;
-	}
-
-	pcan_p->pcan_dip		= dip;
-	pcan_p->pcan_flag		= 0;
-	pcan_p->glds_nocarrier		= 0;
-	pcan_p->glds_noxmtbuf		= 0;
-	pcan_p->glds_norcvbuf		= 0;
-	pcan_p->pcan_socket		= ddi_getprop(DDI_DEV_T_NONE, dip,
-	    DDI_PROP_DONTPASS, "socket", -1);
-
-	pcan_p->pcan_reschedule_need = B_FALSE;
-	pcan_p->pcan_info_softint_pending = 0;
-	pcan_p->pcan_reset_delay = ddi_getprop(DDI_DEV_T_ANY, dip,
-	    DDI_PROP_DONTPASS, "reset-delay", 5000);
-
-	if (ddi_get_iblock_cookie(dip,
-	    0, &pcan_p->pcan_ib_cookie) != DDI_SUCCESS) {
-		cmn_err(CE_WARN, "pcan attach: get_iblk_cookie failed\n");
-		goto attach_fail3;
-	}
-
-	mutex_init(&pcan_p->pcan_glock, NULL,
-	    MUTEX_DRIVER, pcan_p->pcan_ib_cookie);
-	mutex_init(&pcan_p->pcan_scanlist_lock, NULL,
-	    MUTEX_DRIVER, pcan_p->pcan_ib_cookie);
-	mutex_init(&pcan_p->pcan_txring.an_tx_lock, NULL,
-	    MUTEX_DRIVER, pcan_p->pcan_ib_cookie);
-
-	if (ret = ddi_add_softintr(dip, DDI_SOFTINT_LOW,
-	    &pcan_p->pcan_info_softint_id, &pcan_p->pcan_ib_cookie, NULL,
-	    pcan_info_softint, (caddr_t)pcan_p)) {
-		cmn_err(CE_WARN, "pcan attach: add info_softintr failed\n");
-		goto attach_fail3a;
-	}
-
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-		if (ret = ddi_add_intr(dip, 0, NULL, NULL,
-		    pcan_intr, (caddr_t)pcan_p)) {
-			cmn_err(CE_WARN, "pcan attach: add intr failed\n");
-			goto attach_fail4;
-		}
-	} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
-		if (ret = pcan_register_cs(dip, pcan_p)) {
-			PCANDBG((CE_NOTE, "pcan attach: register_cs failed"
-			    " %x\n", ret));
-			goto attach_fail4;
-		}
-	} else {
-		cmn_err(CE_WARN, "pcan attach: unsupported device type\n");
-		goto attach_fail4;
-	}
-
-	mutex_enter(&pcan_p->pcan_glock);
-	pcan_reset_backend(pcan_p, pcan_p->pcan_reset_delay);
-	/* leaves IF down, intr disabled */
-
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-		if (ret = pcan_init_dma(dip, pcan_p)) {
-			cmn_err(CE_WARN, "pcan init_dma: failed\n");
-			mutex_exit(&pcan_p->pcan_glock);
-			goto attach_fail5;
-		}
-	}
-	if (ret = pcan_get_cap(pcan_p)) { /* sets macaddr for gld_register */
-		cmn_err(CE_WARN, "pcan attach: get_cap failed %x\n", ret);
-		mutex_exit(&pcan_p->pcan_glock);
-		goto attach_fail6;
-	}
-
-	mutex_exit(&pcan_p->pcan_glock);
-	/*
-	 * Provide initial settings for the WiFi plugin; whenever this
-	 * information changes, we need to call mac_pdata_update()
-	 */
-	wd.wd_secalloc = WIFI_SEC_NONE;
-	wd.wd_opmode = IEEE80211_M_STA;
-
-	macp = mac_alloc(MAC_VERSION);
-	if (macp == NULL) {
-		PCANDBG((CE_NOTE, "pcan attach: "
-		    "MAC version mismatch\n"));
-		goto attach_fail6;
-	}
-
-	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
-	macp->m_driver		= pcan_p;
-	macp->m_dip		= dip;
-	macp->m_src_addr	= pcan_p->pcan_mac_addr;
-	macp->m_callbacks	= &pcan_m_callbacks;
-	macp->m_min_sdu		= 0;
-	macp->m_max_sdu		= IEEE80211_MTU;
-	macp->m_pdata		= &wd;
-	macp->m_pdata_size	= sizeof (wd);
-
-	err = mac_register(macp, &pcan_p->pcan_mh);
-	mac_free(macp);
-	if (err != 0) {
-		PCANDBG((CE_NOTE, "pcan attach: "
-		    "mac_register err\n"));
-		goto attach_fail6;
-	}
-
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
-		/* turn on CS interrupt */
-		cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
-		    CONF_IRQ_CHANGE_VALID;
-		cfgmod.Vpp1 = 50;
-		cfgmod.Vpp2 = 50;
-		(void) csx_ModifyConfiguration(pcan_p->pcan_chdl, &cfgmod);
-
-		mutex_enter(&pcan_p->pcan_glock);
-		if (ret = pcan_init_nicmem(pcan_p)) {
-			cmn_err(CE_WARN, "pcan attach: init_nicmem failed %x\n",
-			    ret);
-			mutex_exit(&pcan_p->pcan_glock);
-			goto attach_fail7;
-		}
-		mutex_exit(&pcan_p->pcan_glock);
-	}
-	(void) ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
-	    "bad-rids", (caddr_t)&pcan_p->pcan_badrids,
-	    &pcan_p->pcan_badrids_len);
-
-	pcan_p->an_config.an_rxmode = AN_NORMAL_RXMODE;
-	ether_copy(pcan_p->pcan_mac_addr, pcan_p->an_config.an_macaddr);
-	mutex_enter(&pcan_p->pcan_glock);
-	list_create(&pcan_p->an_scan_list, sizeof (an_scan_list_t),
-	    offsetof(an_scan_list_t, an_scan_node));
-	pcan_p->an_scan_num = 0;
-	mutex_exit(&pcan_p->pcan_glock);
-	pcan_p->an_scanlist_timeout_id = timeout(pcan_scanlist_timeout,
-	    pcan_p, drv_usectohz(1000000));
-
-	instance = ddi_get_instance(dip);
-	(void) snprintf(strbuf, sizeof (strbuf), "pcan%d", instance);
-	if (ddi_create_minor_node(dip, strbuf, S_IFCHR,
-	    instance + 1, DDI_NT_NET_WIFI, 0) != DDI_SUCCESS) {
-		goto attach_fail8;
-	}
-	mutex_enter(&pcan_p->pcan_glock);
-	PCAN_DISABLE_INTR_CLEAR(pcan_p);
-	(void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
-	pcan_p->pcan_flag |= PCAN_ATTACHED;
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-		pcan_p->pcan_flag |= PCAN_CARD_READY;
-	}
-	mutex_exit(&pcan_p->pcan_glock);
-	return (DDI_SUCCESS);
-attach_fail8:
-	if (pcan_p->an_scanlist_timeout_id != 0) {
-		(void) untimeout(pcan_p->an_scanlist_timeout_id);
-		pcan_p->an_scanlist_timeout_id = 0;
-	}
-	list_destroy(&pcan_p->an_scan_list);
-attach_fail7:
-	(void) mac_unregister(pcan_p->pcan_mh);
-attach_fail6:
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI)
-		pcan_free_dma(pcan_p);
-attach_fail5:
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-		ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie);
-	} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
-		pcan_unregister_cs(pcan_p);
-	}
-attach_fail4:
-	if (pcan_p->pcan_info_softint_id)
-		ddi_remove_softintr(pcan_p->pcan_info_softint_id);
-attach_fail3a:
-	pcan_destroy_locks(pcan_p);
-attach_fail3:
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-		if (pcan_p->pcan_handle0)
-			ddi_regs_map_free(&pcan_p->pcan_handle0);
-		if (pcan_p->pcan_handle1)
-			ddi_regs_map_free(&pcan_p->pcan_handle1);
-		if (pcan_p->pcan_handle2)
-			ddi_regs_map_free(&pcan_p->pcan_handle2);
-	}
-attach_fail2:
-	ddi_soft_state_free(pcan_soft_state_p, ddi_get_instance(dip));
-attach_fail1:
-	return (DDI_FAILURE);
-}
-
-static int
-pcan_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
-{
-	pcan_maci_t *pcan_p;
-	an_scan_list_t *scan_item0;
-	int ret;
-	pcan_p = ddi_get_soft_state(pcan_soft_state_p, ddi_get_instance(dip));
-
-	if (cmd != DDI_DETACH)
-		return (DDI_FAILURE);
-	if (!(pcan_p->pcan_flag & PCAN_ATTACHED))
-		return (DDI_FAILURE);
-
-	ret = mac_disable(pcan_p->pcan_mh);
-	if (ret != 0)
-		return (DDI_FAILURE);
-
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-		mutex_enter(&pcan_p->pcan_glock);
-		pcan_stop_locked(pcan_p);
-		PCAN_DISABLE_INTR(pcan_p);
-		mutex_exit(&pcan_p->pcan_glock);
-	}
-	if (pcan_p->an_scanlist_timeout_id != 0) {
-		(void) untimeout(pcan_p->an_scanlist_timeout_id);
-		pcan_p->an_scanlist_timeout_id = 0;
-	}
-	if (pcan_p->pcan_connect_timeout_id != 0) {
-		(void) untimeout(pcan_p->pcan_connect_timeout_id);
-		pcan_p->pcan_connect_timeout_id = 0;
-	}
-	mutex_enter(&pcan_p->pcan_scanlist_lock);
-	scan_item0 = list_head(&pcan_p->an_scan_list);
-	while (scan_item0) {
-		pcan_delete_scan_item(pcan_p, scan_item0);
-		scan_item0 = list_head(&pcan_p->an_scan_list);
-	}
-	list_destroy(&pcan_p->an_scan_list);
-	mutex_exit(&pcan_p->pcan_scanlist_lock);
-
-	(void) mac_unregister(pcan_p->pcan_mh);
-
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-		mutex_enter(&pcan_p->pcan_glock);
-		ddi_remove_intr(dip, 0, pcan_p->pcan_ib_cookie);
-		pcan_free_dma(pcan_p);
-		if (pcan_p->pcan_handle0)
-			ddi_regs_map_free(&pcan_p->pcan_handle0);
-		if (pcan_p->pcan_handle1)
-			ddi_regs_map_free(&pcan_p->pcan_handle1);
-		if (pcan_p->pcan_handle2)
-			ddi_regs_map_free(&pcan_p->pcan_handle2);
-		mutex_exit(&pcan_p->pcan_glock);
-	} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
-		pcan_unregister_cs(pcan_p);
-	} else {
-		cmn_err(CE_WARN, "pcan detach: unsupported device type\n");
-	}
-	pcan_destroy_locks(pcan_p);
-	if (pcan_p->pcan_info_softint_id)
-		ddi_remove_softintr(pcan_p->pcan_info_softint_id);
-
-	if (pcan_p->pcan_badrids_len)
-		kmem_free(pcan_p->pcan_badrids, pcan_p->pcan_badrids_len);
-
-	ddi_soft_state_free(pcan_soft_state_p, ddi_get_instance(dip));
-	ddi_remove_minor_node(dip, NULL);
-
-	return (DDI_SUCCESS);
-}
-
-/*
- * card services and event handlers
- */
-
-static int
-pcan_register_cs(dev_info_t *dip, pcan_maci_t *pcan_p)
-{
-	int ret;
-	client_reg_t cr;
-	client_handle_t chdl; /* uint encoding of socket, function, client */
-	get_status_t card_status;
-	request_socket_mask_t sock_req;
-
-	bzero(&cr, sizeof (cr));
-	cr.Attributes	= INFO_IO_CLIENT|INFO_CARD_EXCL|INFO_CARD_SHARE;
-	cr.EventMask	= CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	    CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_REMOVAL_LOWP |
-	    CS_EVENT_CARD_READY | CS_EVENT_PM_RESUME | CS_EVENT_PM_SUSPEND |
-	    CS_EVENT_CLIENT_INFO;
-	cr.event_callback_args.client_data = pcan_p;
-	cr.Version = CS_VERSION;
-	cr.event_handler = (csfunction_t *)pcan_ev_hdlr;
-	cr.dip = dip;
-	(void) strcpy(cr.driver_name, pcan_name_str);
-	if (ret = csx_RegisterClient(&chdl, &cr)) {
-		cmn_err(CE_WARN, "pcan: RegisterClient failed %x", ret);
-		goto regcs_ret;
-	}
-
-	pcan_p->pcan_chdl = chdl;
-
-	bzero(&card_status, sizeof (card_status));
-	(void) csx_GetStatus(chdl, &card_status);
-	PCANDBG((CE_NOTE, "pcan: getstat Sock=%x CState=%x SState=%x rState=%x",
-	    card_status.Socket, card_status.CardState,
-	    card_status.SocketState, card_status.raw_CardState));
-	if (!(card_status.CardState & CS_STATUS_CARD_INSERTED)) {
-		/* card is not present, why are we attaching ? */
-		ret = CS_NO_CARD;
-		goto unreg;
-	}
-	cv_init(&pcan_p->pcan_cscv, NULL, CV_DRIVER, NULL);
-	mutex_init(&pcan_p->pcan_cslock, NULL, MUTEX_DRIVER, *cr.iblk_cookie);
-	mutex_enter(&pcan_p->pcan_cslock);
-	if (ret = csx_MapLogSocket(chdl, &pcan_p->pcan_log_sock)) {
-		cmn_err(CE_WARN, "pcan: MapLogSocket failed %x", ret);
-		goto fail;
-	}
-	PCANDBG((CE_NOTE, "pcan: logsock: LogSock=%x PhyAdapter=%x PhySock=%x",
-	    pcan_p->pcan_log_sock.LogSocket,
-	    pcan_p->pcan_log_sock.PhyAdapter,
-	    pcan_p->pcan_log_sock.PhySocket));
-
-	/* turn on initialization events */
-	sock_req.Socket = 0;
-	sock_req.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	    CS_EVENT_REGISTRATION_COMPLETE;
-	if (ret = csx_RequestSocketMask(chdl, &sock_req)) {
-		cmn_err(CE_WARN, "pcan: RequestSocketMask failed %x\n", ret);
-		goto fail;
-	}
-
-	/* wait for and process card insertion events */
-	while (!(pcan_p->pcan_flag & PCAN_CARD_READY))
-		cv_wait(&pcan_p->pcan_cscv, &pcan_p->pcan_cslock);
-	mutex_exit(&pcan_p->pcan_cslock);
-
-	pcan_p->pcan_flag |= PCAN_CS_REGISTERED;
-	return (CS_SUCCESS);
-fail:
-	mutex_destroy(&pcan_p->pcan_cslock);
-	cv_destroy(&pcan_p->pcan_cscv);
-unreg:
-	(void) csx_DeregisterClient(chdl);
-regcs_ret:
-	pcan_p->pcan_flag &= ~PCAN_CS_REGISTERED;
-	return (ret);
-}
-
-static void
-pcan_unregister_cs(pcan_maci_t *pcan_p)
-{
-	int ret;
-	release_socket_mask_t mask;
-	mask.Socket = pcan_p->pcan_socket;
-
-	/*
-	 * The card service not registered means register_cs function
-	 * doesnot return TRUE. Then all the lelated resource has been
-	 * released in register_cs.
-	 */
-	if (!(pcan_p->pcan_flag | PCAN_CS_REGISTERED))
-		return;
-	(void) csx_ReleaseSocketMask(pcan_p->pcan_chdl, &mask);
-
-	if (pcan_p->pcan_flag & PCAN_CARD_READY) {
-		pcan_card_remove(pcan_p);
-	}
-	mutex_destroy(&pcan_p->pcan_cslock);
-	cv_destroy(&pcan_p->pcan_cscv);
-	if (ret = csx_DeregisterClient(pcan_p->pcan_chdl))
-		cmn_err(CE_WARN, "pcan: deregister failed %x\n", ret);
-}
-static void
-pcan_destroy_locks(pcan_maci_t *pcan_p)
-{
-	mutex_destroy(&pcan_p->pcan_txring.an_tx_lock);
-	mutex_destroy(&pcan_p->pcan_scanlist_lock);
-	mutex_destroy(&pcan_p->pcan_glock);
-}
-
-static int
-pcan_ev_hdlr(event_t event, int priority, event_callback_args_t *arg)
-{
-	int ret = CS_SUCCESS;
-	pcan_maci_t *pcan_p = (pcan_maci_t *)arg->client_data;
-	client_info_t *ci_p = (client_info_t *)&arg->client_info;
-
-	mutex_enter(&pcan_p->pcan_cslock);
-	switch (event) {
-	case CS_EVENT_CARD_INSERTION:
-		ret = pcan_card_insert(pcan_p);
-		cv_broadcast(&pcan_p->pcan_cscv);
-		break;
-	case CS_EVENT_REGISTRATION_COMPLETE:
-		cv_broadcast(&pcan_p->pcan_cscv);
-		break;
-	case CS_EVENT_CARD_REMOVAL:
-		if (priority & CS_EVENT_PRI_HIGH)
-			break;
-		pcan_card_remove(pcan_p);
-		cv_broadcast(&pcan_p->pcan_cscv);
-		break;
-	case CS_EVENT_CLIENT_INFO:
-		if (GET_CLIENT_INFO_SUBSVC(ci_p->Attributes) !=
-		    CS_CLIENT_INFO_SUBSVC_CS)
-			break;
-
-		ci_p->Revision = 0x0101;
-		ci_p->CSLevel = CS_VERSION;
-		ci_p->RevDate = CS_CLIENT_INFO_MAKE_DATE(9, 12, 14);
-		(void) strcpy(ci_p->ClientName, PCAN_IDENT_STRING);
-		(void) strcpy(ci_p->VendorName, CS_SUN_VENDOR_DESCRIPTION);
-		ci_p->Attributes |= CS_CLIENT_INFO_VALID;
-		break;
-	case CS_EVENT_PM_SUSPEND:
-		pcan_do_suspend(pcan_p);
-		break;
-	default:
-		ret = CS_UNSUPPORTED_EVENT;
-		break;
-	}
-	mutex_exit(&pcan_p->pcan_cslock);
-	return (ret);
-}
-
-static int
-pcan_card_insert(pcan_maci_t *pcan_p)
-{
-	int ret, hi, lo;
-	tuple_t tuple;
-	cisparse_t cisparse;
-	io_req_t	io;
-	irq_req_t	irq;
-	config_req_t	cfg;
-	cistpl_config_t config;
-	cistpl_cftable_entry_t *tbl_p;
-	register client_handle_t chdl = pcan_p->pcan_chdl;
-	modify_config_t cfgmod;
-
-	bzero(&tuple, sizeof (tuple));
-	tuple.DesiredTuple = CISTPL_MANFID;
-	if (ret = csx_GetFirstTuple(chdl, &tuple)) {
-		cmn_err(CE_WARN, "pcan: get manufacture id failed %x\n", ret);
-		goto insert_ret;
-	}
-	bzero(&cisparse, sizeof (cisparse));
-	if (ret = csx_Parse_CISTPL_MANFID(chdl, &tuple, &cisparse.manfid)) {
-		cmn_err(CE_WARN, "pcan: parse manufacture id failed %x\n", ret);
-		goto insert_ret;
-	}
-	/* verify manufacture ID */
-	PCANDBG((CE_NOTE, "pcan: manufacturer_id=%x card=%x\n",
-	    cisparse.manfid.manf, cisparse.manfid.card));
-
-	bzero(&tuple, sizeof (tuple));
-	tuple.DesiredTuple = CISTPL_FUNCID;
-	if (ret = csx_GetFirstTuple(chdl, &tuple)) {
-		cmn_err(CE_WARN, "pcan: get function id failed %x\n", ret);
-		goto insert_ret;
-	}
-	bzero(&cisparse, sizeof (cisparse));
-	if (ret = csx_Parse_CISTPL_FUNCID(chdl, &tuple, &cisparse.funcid)) {
-		cmn_err(CE_WARN, "pcan: parse function id failed %x\n", ret);
-		goto insert_ret;
-	}
-	/* verify function ID */
-	PCANDBG((CE_NOTE, "funcid=%x\n", cisparse.funcid.function));
-
-	bzero(&tuple, sizeof (tuple));
-	tuple.DesiredTuple = CISTPL_CONFIG;
-	if (ret = csx_GetFirstTuple(chdl, &tuple)) {
-		cmn_err(CE_WARN, "pcan: get config failed %x\n", ret);
-		goto insert_ret;
-	}
-	bzero(&config, sizeof (config));
-	if (ret = csx_Parse_CISTPL_CONFIG(chdl, &tuple, &config)) {
-		cmn_err(CE_WARN, "pcan: parse config failed %x\n", ret);
-		goto insert_ret;
-	}
-	PCANDBG((CE_NOTE,
-	    "pcan: config present=%x nr=%x hr=%x regs[0]=%x base=%x last=%x\n",
-	    config.present, config.nr, config.hr, config.regs[0],
-	    config.base, config.last));
-
-	hi = 0;
-	lo = (int)-1;		/* really big number */
-	tbl_p = &cisparse.cftable;
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	for (tbl_p->index = 0; tbl_p->index <= config.hr; ) {
-		PCANDBG((CE_NOTE, "pcan: tuple idx=%x:\n", tbl_p->index));
-		if (ret = csx_GetNextTuple(chdl, &tuple)) {
-			cmn_err(CE_WARN, "pcan: get cftable failed %x\n", ret);
-			break;
-		}
-		bzero((caddr_t)&cisparse, sizeof (cisparse));
-		if (ret = csx_Parse_CISTPL_CFTABLE_ENTRY(chdl, &tuple, tbl_p)) {
-			cmn_err(CE_WARN, "pcan: parse cftable failed%x\n", ret);
-			break;
-		}
-		if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_PWR &&
-		    tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) {
-			if (tbl_p->pd.pd_vcc.avgI > hi) {
-				hi = tbl_p->pd.pd_vcc.avgI;
-				pcan_p->pcan_config_hi = tbl_p->index;
-			}
-			if (tbl_p->pd.pd_vcc.avgI < lo) {
-				lo = tbl_p->pd.pd_vcc.avgI;
-				pcan_p->pcan_config = tbl_p->index;
-			}
-		}
-		if (tbl_p->flags & CISTPL_CFTABLE_TPCE_DEFAULT) {
-			if (tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC)
-				pcan_p->pcan_vcc = tbl_p->pd.pd_vcc.nomV;
-			if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_IO)
-				pcan_p->pcan_iodecode = tbl_p->io.addr_lines;
-		}
-	}
-	PCANDBG((CE_NOTE, "pcan: cfg_hi=%x cfg=%x vcc=%x iodecode=%x\n",
-	    pcan_p->pcan_config_hi, pcan_p->pcan_config,
-	    pcan_p->pcan_vcc, pcan_p->pcan_iodecode));
-
-	bzero(&io, sizeof (io));
-	io.BasePort1.base = 0;
-	io.NumPorts1 = 1 << pcan_p->pcan_iodecode;
-	io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-	io.IOAddrLines = pcan_p->pcan_iodecode;
-	if (ret = csx_RequestIO(chdl, &io)) {
-		cmn_err(CE_WARN, "pcan: RequestIO failed %x\n", ret);
-		goto insert_ret;
-	}
-	pcan_p->pcan_port = io.BasePort1.handle;
-
-	if (ret = ddi_add_softintr(DIP(pcan_p), DDI_SOFTINT_HIGH,
-	    &pcan_p->pcan_softint_id, &pcan_p->pcan_ib_cookie, NULL,
-	    pcan_intr, (caddr_t)pcan_p)) {
-		cmn_err(CE_NOTE, "pcan: Add softintr failed\n");
-		goto insert_ret;
-	}
-	irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-	irq.irq_handler = ddi_intr_hilevel(DIP(pcan_p), 0) ?
-	    (csfunction_t *)pcan_intr_hi : (csfunction_t *)pcan_intr;
-	irq.irq_handler_arg = pcan_p;
-	if (ret = csx_RequestIRQ(chdl, &irq)) {
-		cmn_err(CE_WARN, "pcan: RequestIRQ failed %x\n", ret);
-		goto un_io;
-	}
-
-	bzero(&cfg, sizeof (cfg));
-	cfg.Attributes = 0; /* not ready for CONF_ENABLE_IRQ_STEERING yet */
-	cfg.Vcc = 50; /* pcan_vcc == 0 */
-	cfg.Vpp1 = 50;
-	cfg.Vpp2 = 50;
-	cfg.IntType = SOCKET_INTERFACE_MEMORY_AND_IO;
-	cfg.ConfigBase = config.base;
-	cfg.ConfigIndex = pcan_p->pcan_config;
-	cfg.Status = CCSR_IO_IS_8; /* no use */
-	cfg.Present = config.present;
-	pcan_p->pcan_flag |= PCAN_CARD_READY;
-	if (ret = csx_RequestConfiguration(chdl, &cfg)) {
-		cmn_err(CE_WARN, "pcan: RequestConfiguration failed %x\n", ret);
-		goto un_irq;
-	}
-
-	if (pcan_p->pcan_flag & PCAN_SUSPENDED) {
-		mutex_enter(&pcan_p->pcan_glock);
-		pcan_reset_backend(pcan_p, pcan_p->pcan_reset_delay);
-		/* turn on CS interrupt */
-		cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
-		    CONF_IRQ_CHANGE_VALID;
-		cfgmod.Vpp1 = 50;
-		cfgmod.Vpp2 = 50;
-		(void) csx_ModifyConfiguration(pcan_p->pcan_chdl, &cfgmod);
-
-		if (ret = pcan_init_nicmem(pcan_p)) {
-			cmn_err(CE_WARN, "pcan insert: init_nicmem failed %x\n",
-			    ret);
-		}
-		PCAN_DISABLE_INTR_CLEAR(pcan_p);
-		ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
-		PCANDBG((CE_NOTE, "pcan insert set cmd ret =%x\n", ret));
-		pcan_p->pcan_flag &= ~PCAN_SUSPENDED;
-		mutex_exit(&pcan_p->pcan_glock);
-	}
-
-	if (pcan_p->pcan_flag & PCAN_PLUMBED) {
-		(void) pcan_start(pcan_p);
-		pcan_p->pcan_flag &= ~PCAN_PLUMBED;
-		PCANDBG((CE_NOTE, "pcan insert: active interrupt\n"));
-	}
-	return (CS_SUCCESS);
-un_irq:
-	(void) csx_ReleaseIRQ(chdl, &irq);
-un_io:
-	ddi_remove_softintr(pcan_p->pcan_softint_id);
-
-	(void) csx_ReleaseIO(chdl, &io);
-	pcan_p->pcan_port = 0;
-insert_ret:
-	pcan_p->pcan_flag &= ~PCAN_CARD_READY;
-	return (ret);
-}
-
-/*
- * assume card is already removed, don't touch the hardware
- */
-static void
-pcan_do_suspend(pcan_maci_t *pcan_p)
-{
-	int ret;
-	if (pcan_p->pcan_flag & PCAN_CARD_LINKUP) {
-		if (pcan_p->pcan_connect_timeout_id != 0) {
-			(void) untimeout(pcan_p->pcan_connect_timeout_id);
-			pcan_p->pcan_connect_timeout_id = 0;
-		}
-		mutex_enter(&pcan_p->pcan_glock);
-		pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
-		if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))
-			PCANDBG((CE_NOTE, "pcan: disable failed, ret %d\n",
-			    ret));
-		if (ret = pcan_loaddef(pcan_p))
-			PCANDBG((CE_NOTE, "pcan: loaddef failed, ret %d\n",
-			    ret));
-		mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN);
-		mutex_exit(&pcan_p->pcan_glock);
-	}
-	pcan_p->pcan_flag |= PCAN_SUSPENDED;
-}
-
-
-/*
- * assume card is already removed, don't touch the hardware
- */
-static void
-pcan_card_remove(pcan_maci_t *pcan_p)
-{
-	int ret;
-	io_req_t io;
-	irq_req_t irq;
-
-	if (!(pcan_p->pcan_flag & PCAN_CARD_READY))
-		return;
-	if (pcan_p->pcan_connect_timeout_id != 0) {
-		(void) untimeout(pcan_p->pcan_connect_timeout_id);
-		pcan_p->pcan_connect_timeout_id = 0;
-	}
-
-	if (pcan_p->pcan_flag & PCAN_CARD_LINKUP) {
-		pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
-		mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN);
-	}
-	mutex_enter(&pcan_p->pcan_glock);
-	if (pcan_p->pcan_flag & PCAN_CARD_INTREN) {
-		pcan_stop_locked(pcan_p);
-		pcan_p->pcan_flag |= PCAN_PLUMBED;
-	}
-	pcan_p->pcan_flag &= ~PCAN_CARD_READY;
-	mutex_exit(&pcan_p->pcan_glock);
-
-	if (ret = csx_ReleaseConfiguration(pcan_p->pcan_chdl, NULL))
-		cmn_err(CE_WARN, "pcan: ReleaseConfiguration failed %x\n", ret);
-
-	bzero(&irq, sizeof (irq));
-	if (ret = csx_ReleaseIRQ(pcan_p->pcan_chdl, &irq))
-		cmn_err(CE_WARN, "pcan: ReleaseIRQ failed %x\n", ret);
-
-	ddi_remove_softintr(pcan_p->pcan_softint_id);
-	pcan_p->pcan_softint_id  = 0;
-
-	bzero(&io, sizeof (io));
-	io.BasePort1.handle = pcan_p->pcan_port;
-	io.NumPorts1 = 16;
-	if (ret = csx_ReleaseIO(pcan_p->pcan_chdl, &io))
-		cmn_err(CE_WARN, "pcan: Release IO failed %x\n", ret);
-
-	pcan_p->pcan_port = 0;
-	PCANDBG((CE_NOTE, "pcan: removed\n"));
-}
-
-/*
- * gld operation interface routines
- */
-static int
-pcan_start(void *arg)
-{
-	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
-
-	mutex_enter(&pcan_p->pcan_glock);
-	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
-		mutex_exit(&pcan_p->pcan_glock);
-		return (PCAN_FAIL);
-	}
-	(void) pcan_loaddef(pcan_p);
-	pcan_start_locked(pcan_p);
-	mutex_exit(&pcan_p->pcan_glock);
-	return (PCAN_SUCCESS);
-}
-
-static void
-pcan_stop(void *arg)
-{
-	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
-
-	mutex_enter(&pcan_p->pcan_glock);
-	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
-		mutex_exit(&pcan_p->pcan_glock);
-		return;
-	}
-	pcan_stop_locked(pcan_p);
-	mutex_exit(&pcan_p->pcan_glock);
-	if (pcan_p->pcan_connect_timeout_id != 0) {
-		(void) untimeout(pcan_p->pcan_connect_timeout_id);
-		pcan_p->pcan_connect_timeout_id = 0;
-	}
-}
-
-/*
- * mac address can only be set in 'disable' state and
- * be effective after 'enable' state.
- */
-static int
-pcan_saddr(void *arg, const uint8_t *macaddr)
-{
-	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
-	int ret = PCAN_SUCCESS;
-	ether_copy(macaddr, pcan_p->pcan_mac_addr);
-
-	mutex_enter(&pcan_p->pcan_glock);
-	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
-		ret = PCAN_FAIL;
-		goto done;
-	}
-	ether_copy(pcan_p->pcan_mac_addr, pcan_p->an_config.an_macaddr);
-	if (pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
-		cmn_err(CE_WARN, "pcan set mac addr: failed\n");
-		ret = PCAN_FAIL;
-		goto done;
-	}
-	if (pcan_config_mac(pcan_p)) {
-		cmn_err(CE_WARN, "pcan set mac addr: config_mac failed\n");
-		ret = PCAN_FAIL;
-		goto done;
-	}
-	if (pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) {
-		cmn_err(CE_WARN, "pcan set mac addr: failed\n");
-		ret = PCAN_FAIL;
-	}
-done:
-	mutex_exit(&pcan_p->pcan_glock);
-	return (ret);
-}
-
-/*
- * send a packet out for pccard
- */
-static int
-pcan_send(pcan_maci_t *pcan_p, mblk_t *mblk_p)
-{
-	char *buf, *buf_p;
-	an_txfrm_t *frm_p;
-#ifdef PCAN_SEND_DEBUG
-	struct an_ltv_status radio_status;
-#endif /* PCAN_SEND_DEBUG */
-	uint16_t pkt_len, xmt_id, ring_idx, r = 0;
-	struct ieee80211_frame *wh;
-	int i = 0;
-
-	mutex_enter(&pcan_p->pcan_glock);
-	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
-		mutex_exit(&pcan_p->pcan_glock);
-		freemsg(mblk_p);
-		return (PCAN_SUCCESS);		/* drop packet */
-	}
-	if (!(pcan_p->pcan_flag & PCAN_CARD_LINKUP)) {	/* link down */
-		PCANDBG((CE_NOTE, "pcan: link down, dropped\n"));
-		pcan_p->glds_nocarrier++;
-		mutex_exit(&pcan_p->pcan_glock);
-		freemsg(mblk_p);
-		return (PCAN_SUCCESS);		/* drop packet */
-	}
-	mutex_exit(&pcan_p->pcan_glock);
-	if (pullupmsg(mblk_p, -1) == 0) {
-		cmn_err(CE_NOTE, "pcan send: pullupmsg failed\n");
-		freemsg(mblk_p);
-		return (PCAN_SUCCESS);		/* drop packet */
-	}
-	wh = (struct ieee80211_frame *)mblk_p->b_rptr;
-
-	mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
-	ring_idx = pcan_p->pcan_txring.an_tx_prod;
-	pcan_p->pcan_txring.an_tx_prod = (ring_idx + 1) & AN_TX_RING_MASK;
-
-	/* check whether there is a xmt buffer available */
-	while ((i < AN_TX_RING_CNT) &&
-	    (pcan_p->pcan_txring.an_tx_ring[ring_idx])) {
-		ring_idx = pcan_p->pcan_txring.an_tx_prod;
-		pcan_p->pcan_txring.an_tx_prod =
-		    (ring_idx + 1) & AN_TX_RING_MASK;
-		i++;
-	}
-
-	if (i == AN_TX_RING_CNT) {
-		mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
-		PCANDBG((CE_NOTE, "pcan: ring full, retrying\n"));
-		mutex_enter(&pcan_p->pcan_glock);
-		pcan_p->pcan_reschedule_need = B_TRUE;
-		mutex_exit(&pcan_p->pcan_glock);
-		pcan_p->glds_noxmtbuf++;
-		return (PCAN_FAIL);
-	}
-	xmt_id = pcan_p->pcan_txring.an_tx_fids[ring_idx];
-	pcan_p->pcan_txring.an_tx_ring[ring_idx] = xmt_id;
-	mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
-
-	buf = kmem_zalloc(PCAN_NICMEM_SZ, KM_SLEEP); /* too big for stack */
-	buf_p = (ulong_t)buf & 1 ? buf + 1 : buf;	/* 16-bit round up */
-	frm_p = (an_txfrm_t *)buf_p;
-
-#ifdef DEBUG
-	if (pcan_debug & PCAN_DBG_SEND) {
-		cmn_err(CE_NOTE, "pcan send: packet from plugin");
-		for (i = 0; i < MBLKL(mblk_p); i++)
-			cmn_err(CE_NOTE, "%x: %x\n", i,
-			    *((unsigned char *)mblk_p->b_rptr + i));
-	}
-#endif
-	pkt_len = msgdsize(mblk_p);
-	if (pkt_len > PCAN_NICMEM_SZ - sizeof (an_txfrm_t)) {
-		cmn_err(CE_WARN, "pcan send: mblk is too long");
-		kmem_free(buf, PCAN_NICMEM_SZ);
-		freemsg(mblk_p);
-		return (PCAN_SUCCESS);		/* drop packet */
-	}
-	if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
-	    IEEE80211_FC1_DIR_TODS) {
-		kmem_free(buf, PCAN_NICMEM_SZ);
-		freemsg(mblk_p);
-		return (PCAN_SUCCESS);		/* drop packet */
-	}
-
-	/* initialize xmt frame header, payload_len must be stored in LE */
-	bzero(frm_p, sizeof (an_txfrm_t) + 2);
-	frm_p->an_tx_ctl = AN_TXCTL_8023;
-
-	/*
-	 * mblk sent down from plugin includes station mode 802.11 frame and
-	 * llc, so we here need to remove them and add an ethernet header.
-	 */
-	pkt_len = pkt_len - (sizeof (*wh) + sizeof (struct ieee80211_llc))
-	    + 2;
-	bcopy(wh->i_addr3, buf_p + 0x38, ETHERADDRL); /* dst macaddr */
-	bcopy(wh->i_addr2, buf_p + 0x3e, ETHERADDRL); /* src macaddr */
-	*((uint16_t *)(buf_p + 0x36)) = pkt_len;
-	bcopy(mblk_p->b_rptr + sizeof (*wh) + sizeof (struct ieee80211_llc)
-	    - 2, buf_p + 0x44, pkt_len);
-
-	if (pkt_len & 1) {	/* round up to 16-bit boundary and pad 0 */
-		buf_p[pkt_len + 0x44] = 0;
-		pkt_len++;
-	}
-	ASSERT(pkt_len <= PCAN_NICMEM_SZ);
-#ifdef DEBUG
-	if (pcan_debug & PCAN_DBG_SEND) {
-		cmn_err(CE_NOTE, "pcan send: packet to hardware--pkt_len=%x",
-		    pkt_len);
-		for (i = 0; i < pkt_len + 4; i++)
-			cmn_err(CE_NOTE, "%x: %x\n", i,
-			    *((unsigned char *)buf_p + 0x36 + i));
-	}
-#endif
-	mutex_enter(&pcan_p->pcan_glock);
-	(void) WRCH1(pcan_p, xmt_id, 0, (uint16_t *)buf_p, 0x38); /* frm */
-	(void) WRPKT(pcan_p, xmt_id, 0x38, (uint16_t *)(buf_p + 0x38),
-	    pkt_len + 12);
-	r = pcan_set_cmd(pcan_p, AN_CMD_TX, xmt_id);
-	mutex_exit(&pcan_p->pcan_glock);
-
-	PCANDBG((CE_NOTE, "pcan: pkt_len=0x44+%x=%x xmt=%x ret=%x\n",
-	    pkt_len, 0x44 + pkt_len, xmt_id, ring_idx));
-	kmem_free(buf, PCAN_NICMEM_SZ);
-#ifdef PCAN_SEND_DEBUG
-	if (pkt_len = pcan_status_ltv(PCAN_READ_LTV, pcan_p, &radio_status)) {
-		PCANDBG((CE_NOTE, "pcan: bad radio status %x\n", pkt_len));
-	} else {
-		PCANDBG((CE_NOTE, "pcan: radio status:\n"));
-	}
-#endif /* PCAN_SEND_DEBUG */
-	if (r)
-		return (PCAN_FAIL);
-	else {
-		freemsg(mblk_p);
-		return (PCAN_SUCCESS);
-	}
-}
-
-/*
- * send a packet out for PCI/MiniPCI card
- */
-static int
-pcian_send(pcan_maci_t *pcan_p, mblk_t *mblk_p)
-{
-	char *buf;
-	uint16_t pkt_len = msgdsize(mblk_p), ring_idx;
-	uint32_t i;
-	struct ieee80211_frame *wh;
-	struct an_card_tx_desc an_tx_desc;
-
-	ring_idx = pcan_p->pcan_txring.an_tx_prod;
-
-	mutex_enter(&pcan_p->pcan_glock);
-	if (!(pcan_p->pcan_flag & PCAN_CARD_LINKUP)) {	/* link down */
-		mutex_exit(&pcan_p->pcan_glock);
-		pcan_p->glds_nocarrier++;
-		freemsg(mblk_p);
-		return (PCAN_SUCCESS);		/* drop packet */
-	}
-	mutex_exit(&pcan_p->pcan_glock);
-	if (pullupmsg(mblk_p, -1) == 0) {
-		cmn_err(CE_NOTE, "pcan(pci) send: pullupmsg failed\n");
-		freemsg(mblk_p);
-		return (PCAN_SUCCESS);		/* drop packet */
-	}
-	wh = (struct ieee80211_frame *)mblk_p->b_rptr;
-
-	mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
-	if ((pcan_p->pcan_flag & PCAN_CARD_SEND) &&
-	    (ring_idx == pcan_p->pcan_txring.an_tx_cons)) {
-		pcan_p->glds_noxmtbuf++;
-		pcan_p->pcan_reschedule_need = B_TRUE;
-		mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
-		return (PCAN_FAIL);
-	}
-	mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
-
-#ifdef DEBUG
-	if (pcan_debug & PCAN_DBG_SEND) {
-		cmn_err(CE_NOTE, "pcan(pci) send: packet from plugin");
-		for (i = 0; i < MBLKL(mblk_p); i++)
-			cmn_err(CE_NOTE, "%x: %x\n", i,
-			    *((unsigned char *)mblk_p->b_rptr + i));
-	}
-#endif
-	mutex_enter(&pcan_p->pcan_glock);
-
-	buf = pcan_p->pcan_tx[ring_idx].dma_virtaddr;
-	bzero(buf, AN_TX_BUFFER_SIZE);
-
-	/*
-	 * mblk sent down from plugin includes station mode 802.11 frame and
-	 * llc, so we here need to remove them and add an ethernet header.
-	 */
-	*((uint16_t *)(buf + 8)) = htons(AN_TXCTL_8023);
-	pkt_len = pkt_len - (sizeof (*wh) + sizeof (struct ieee80211_llc))
-	    + 2;
-	bcopy(wh->i_addr3, buf + 0x38, ETHERADDRL); /* dst macaddr */
-	bcopy(wh->i_addr2, buf + 0x3e, ETHERADDRL); /* src macaddr */
-	*((uint16_t *)(buf + 0x36)) = pkt_len;
-	bcopy(mblk_p->b_rptr + sizeof (*wh) + sizeof (struct ieee80211_llc)
-	    - 2, buf + 0x44, pkt_len);
-
-#ifdef DEBUG
-	if (pcan_debug & PCAN_DBG_SEND) {
-		cmn_err(CE_NOTE, "pcan(pci) send: packet to hardware "
-		    "pkt_len=%x", pkt_len);
-		for (i = 0; i < pkt_len + 14; i++)
-			cmn_err(CE_NOTE, "%x: %x\n", i,
-			    *((unsigned char *)buf + 0x36 + i));
-	}
-#endif
-	bzero(&an_tx_desc, sizeof (an_tx_desc));
-	an_tx_desc.an_offset = 0;
-	an_tx_desc.an_eoc = (ring_idx == (AN_MAX_TX_DESC-1) ? 1 : 0);
-	an_tx_desc.an_valid = 1;
-	an_tx_desc.an_len =  0x44 + pkt_len;
-	an_tx_desc.an_phys  = pcan_p->pcan_tx[ring_idx].dma_physaddr;
-	for (i = 0; i < sizeof (an_tx_desc) / 4; i++) {
-		PCAN_AUX_PUT32(pcan_p, AN_TX_DESC_OFFSET +
-		    (ring_idx * sizeof (an_tx_desc)) + (i * 4),
-		    ((uint32_t *)&an_tx_desc)[i]);
-	}
-
-	mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
-	pcan_p->pcan_txring.an_tx_prod = (ring_idx + 1) % AN_MAX_TX_DESC;
-	pcan_p->pcan_flag |= PCAN_CARD_SEND;
-	PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC);
-	mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
-
-	freemsg(mblk_p);
-	mutex_exit(&pcan_p->pcan_glock);
-	return (PCAN_SUCCESS);
-}
-
-static mblk_t *
-pcan_tx(void *arg, mblk_t *mp)
-{
-	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
-	mblk_t *next;
-	int ret = 0;
-
-	ASSERT(mp != NULL);
-	mutex_enter(&pcan_p->pcan_glock);
-	if ((pcan_p->pcan_flag & (PCAN_CARD_LINKUP | PCAN_CARD_READY)) !=
-	    (PCAN_CARD_LINKUP | PCAN_CARD_READY)) {
-		mutex_exit(&pcan_p->pcan_glock);
-		freemsgchain(mp);
-		return (NULL);
-	}
-	mutex_exit(&pcan_p->pcan_glock);
-	while (mp != NULL) {
-		next =  mp->b_next;
-		mp->b_next = NULL;
-
-		if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-			ret = pcian_send(pcan_p, mp);
-		} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
-			ret = pcan_send(pcan_p, mp);
-		}
-		if (ret) {
-			mp->b_next = next;
-			break;
-		}
-		mp = next;
-	}
-	return (mp);
-}
-
-/*
- * this driver is porting from freebsd, the code in freebsd
- * doesn't show how to set promiscous mode.
- */
-/*ARGSUSED*/
-static int
-pcan_prom(void *arg, boolean_t on)
-{
-	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
-	int ret = PCAN_SUCCESS;
-
-	mutex_enter(&pcan_p->pcan_glock);
-	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
-		ret = PCAN_FAIL;
-	}
-	mutex_exit(&pcan_p->pcan_glock);
-	return (ret);
-}
-
-/*ARGSUSED*/
-static int
-pcan_gstat(void *arg, uint_t statitem, uint64_t *val)
-{
-	uint16_t i;
-	int ret = PCAN_SUCCESS;
-	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
-	uint64_t *cntr_p = pcan_p->pcan_cntrs_s;
-
-	PCANDBG((CE_NOTE, "pcan: gstat called\n"));
-
-	mutex_enter(&pcan_p->pcan_glock);
-	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
-		ret = PCAN_FAIL;
-		goto done;
-	}
-	if (pcan_get_ltv(pcan_p, sizeof (pcan_p->an_stats),
-	    AN_RID_16BITS_DELTACLR, (uint16_t *)&pcan_p->an_stats)) {
-		cmn_err(CE_WARN, "pcan kstat: get ltv(32 delta statistics)"
-		    " failed \n");
-		ret = PCAN_FAIL;
-		goto done;
-	}
-	for (i = 0; i < ANC_STAT_CNT; i++) {
-		cntr_p[i] += *((uint16_t *)&pcan_p->an_stats + 1 + i);
-	}
-	if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_status)) {
-		cmn_err(CE_WARN, "pcan kstat: read status failed \n");
-		ret = PCAN_FAIL;
-		goto done;
-	}
-
-	switch (statitem) {
-	case MAC_STAT_IFSPEED:
-		*val = 500000 * pcan_p->an_status.an_cur_tx_rate;
-		break;
-	case MAC_STAT_NOXMTBUF:
-		*val = pcan_p->glds_noxmtbuf;
-		break;
-	case MAC_STAT_NORCVBUF:
-		*val = pcan_p->glds_norcvbuf;
-		break;
-	case MAC_STAT_IERRORS:
-		*val = cntr_p[ANC_RX_OVERRUNS] +
-		    cntr_p[ANC_RX_PLCP_CSUM_ERRS] +
-		    cntr_p[ANC_RX_PLCP_FORMAT_ERRS] +
-		    cntr_p[ANC_RX_PLCP_LEN_ERRS] +
-		    cntr_p[ANC_RX_MAC_CRC_ERRS] +
-		    cntr_p[ANC_RX_WEP_ERRS];
-		break;
-	case MAC_STAT_OERRORS:
-		*val = cntr_p[ANC_TX_HOST_FAILED];
-		break;
-	case MAC_STAT_RBYTES:
-		*val = cntr_p[ANC_HOST_RX_BYTES];
-		break;
-	case MAC_STAT_IPACKETS:
-		*val = cntr_p[ANC_RX_HOST_UCASTS];
-		break;
-	case MAC_STAT_OBYTES:
-		*val = cntr_p[ANC_HOST_TX_BYTES];
-		break;
-	case MAC_STAT_OPACKETS:
-		*val = cntr_p[ANC_TX_HOST_UCASTS];
-		break;
-	case WIFI_STAT_TX_FAILED:
-		*val = cntr_p[ANC_TX_HOST_FAILED];
-		break;
-	case WIFI_STAT_TX_RETRANS:
-		*val = cntr_p[ANC_HOST_RETRIES];
-		break;
-	case WIFI_STAT_FCS_ERRORS:
-		*val = cntr_p[ANC_RX_MAC_CRC_ERRS];
-		break;
-	case WIFI_STAT_WEP_ERRORS:
-		*val = cntr_p[ANC_RX_WEP_ERRS];
-		break;
-	case WIFI_STAT_MCAST_TX:
-		*val = cntr_p[ANC_TX_HOST_MCASTS];
-		break;
-	case WIFI_STAT_MCAST_RX:
-		*val = cntr_p[ANC_RX_HOST_MCASTS];
-		break;
-	case WIFI_STAT_TX_FRAGS:
-	case WIFI_STAT_RX_FRAGS:
-		*val = 0;
-		break;
-	case WIFI_STAT_RTS_SUCCESS:
-		*val = cntr_p[ANC_TX_RTS_OK];
-		break;
-	case WIFI_STAT_RTS_FAILURE:
-		*val = cntr_p[ANC_NO_CTS];
-		break;
-	case WIFI_STAT_ACK_FAILURE:
-		*val = cntr_p[ANC_NO_ACK];
-		break;
-	case WIFI_STAT_RX_DUPS:
-		*val = cntr_p[ANC_RX_DUPS];
-		break;
-	default:
-		ret = ENOTSUP;
-	}
-
-
-done:
-	mutex_exit(&pcan_p->pcan_glock);
-	return (ret);
-}
-
-/*
- * this driver is porting from freebsd, the code in freebsd
- * doesn't show how to set multi address.
- */
-/*ARGSUSED*/
-static int
-pcan_sdmulti(void *arg, boolean_t add, const uint8_t *eth_p)
-{
-	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
-
-	mutex_enter(&pcan_p->pcan_glock);
-	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
-		mutex_exit(&pcan_p->pcan_glock);
-		return (PCAN_FAIL);
-	}
-	mutex_exit(&pcan_p->pcan_glock);
-	return (PCAN_SUCCESS);
-}
-
-static uint_t
-pcan_info_softint(caddr_t arg)
-{
-	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
-	wifi_data_t wd = { 0 };
-	uint16_t link;
-	uint32_t link_up;
-
-	mutex_enter(&pcan_p->pcan_glock);
-	if (pcan_p->pcan_info_softint_pending != 1) {
-		mutex_exit(&pcan_p->pcan_glock);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	PCAN_READ(pcan_p, AN_LINKSTAT(pcan_p), link);
-	link_up = pcan_p->pcan_flag & PCAN_CARD_LINKUP;
-	if ((link == AN_LINKSTAT_ASSOCIATED) && !link_up) {
-		pcan_p->pcan_flag |= PCAN_CARD_LINKUP;
-		mutex_exit(&pcan_p->pcan_glock);
-		if (pcan_p->pcan_connect_timeout_id != 0) {
-			(void) untimeout(pcan_p->pcan_connect_timeout_id);
-			pcan_p->pcan_connect_timeout_id = 0;
-		}
-		mac_link_update(GLD3(pcan_p), LINK_STATE_UP);
-		mutex_enter(&pcan_p->pcan_glock);
-		(void) pcan_status_ltv(PCAN_READ_LTV, pcan_p,
-		    &pcan_p->an_status);
-		bcopy(pcan_p->an_status.an_cur_bssid, wd.wd_bssid, 6);
-		wd.wd_secalloc = WIFI_SEC_NONE;
-		wd.wd_opmode = IEEE80211_M_STA;
-		(void) mac_pdata_update(pcan_p->pcan_mh, &wd,
-		    sizeof (wd));
-#ifdef DEBUG
-		if (pcan_debug & PCAN_DBG_LINKINFO) {
-			cmn_err(CE_NOTE, "pcan: link Up, chan=%d, "
-			    "ssid=\"%s\""
-			    " (%02x:%02x:%02x:%02x:%02x:%02x)\n",
-			    pcan_p->an_status.an_channel_set,
-			    pcan_p->an_status.an_ssid,
-			    pcan_p->an_status.an_cur_bssid[0],
-			    pcan_p->an_status.an_cur_bssid[1],
-			    pcan_p->an_status.an_cur_bssid[2],
-			    pcan_p->an_status.an_cur_bssid[3],
-			    pcan_p->an_status.an_cur_bssid[4],
-			    pcan_p->an_status.an_cur_bssid[5]);
-		}
-#endif
-	}
-	if ((link != AN_LINKSTAT_ASSOCIATED) && link_up) {
-		pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
-#ifdef DEBUG
-		if (pcan_debug & PCAN_DBG_LINKINFO) {
-			cmn_err(CE_NOTE, "pcan: link Down 0x%x\n", link);
-		}
-#endif
-		if (link != AN_LINKSTAT_SYNCLOST_HOSTREQ) {
-			pcan_p->pcan_connect_timeout_id =
-			    timeout(pcan_connect_timeout,
-			    pcan_p, drv_usectohz(1000));
-		}
-		mutex_exit(&pcan_p->pcan_glock);
-		mac_link_update(GLD3(pcan_p), LINK_STATE_DOWN);
-		mutex_enter(&pcan_p->pcan_glock);
-	}
-
-	pcan_p->pcan_info_softint_pending = 0;
-	mutex_exit(&pcan_p->pcan_glock);
-	return (DDI_INTR_CLAIMED);
-}
-
-static uint_t
-pcan_intr(caddr_t arg)
-{
-	uint16_t stat;
-	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
-
-	mutex_enter(&pcan_p->pcan_glock);
-	if ((pcan_p->pcan_flag & (PCAN_CARD_READY | PCAN_CARD_INTREN)) !=
-	    (PCAN_CARD_READY | PCAN_CARD_INTREN)) {
-		mutex_exit(&pcan_p->pcan_glock);
-		return (DDI_INTR_UNCLAIMED);
-	}
-	PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
-
-	if (!(stat & AN_INTRS(pcan_p)) || stat == AN_EV_ALL) {
-		mutex_exit(&pcan_p->pcan_glock);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	PCAN_DISABLE_INTR(pcan_p);
-	PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), ~AN_INTRS(pcan_p));
-
-	PCANDBG((CE_NOTE, "pcan intr: stat=%x pcan_flags=%x\n", stat,
-	    pcan_p->pcan_flag));
-
-	if (stat & AN_EV_AWAKE) {
-		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_AWAKE);
-		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_AWAKE);
-	}
-	if (stat & AN_EV_LINKSTAT) {
-		pcan_p->pcan_info_softint_pending = 1;
-		ddi_trigger_softintr(pcan_p->pcan_info_softint_id);
-		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_LINKSTAT);
-	}
-	if (stat & AN_EV_RX) {
-		if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-			pcian_rcv(pcan_p);
-		} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
-			pcan_rcv(pcan_p);
-		}
-		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_RX);
-	}
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-		if (stat & AN_EV_TX_CPY) {
-			(void) pcan_txdone(pcan_p, stat & AN_EV_TX_CPY);
-			if (pcan_p->pcan_reschedule_need == B_TRUE) {
-				mac_tx_update(GLD3(pcan_p));
-				pcan_p->pcan_reschedule_need = B_FALSE;
-			}
-			PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX_CPY);
-	}
-	}
-	if (stat & AN_EV_TX) {
-		if (pcan_txdone(pcan_p, stat & AN_EV_TX) == 0) {
-			if (pcan_p->pcan_reschedule_need == B_TRUE) {
-				mac_tx_update(GLD3(pcan_p));
-				pcan_p->pcan_reschedule_need = B_FALSE;
-			}
-		}
-		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX);
-	}
-	if (stat & AN_EV_TX_EXC) {
-		if (pcan_txdone(pcan_p, stat & AN_EV_TX_EXC) == 0) {
-			if (pcan_p->pcan_reschedule_need == B_TRUE) {
-				mutex_exit(&pcan_p->pcan_glock);
-				mac_tx_update(GLD3(pcan_p));
-				mutex_enter(&pcan_p->pcan_glock);
-				pcan_p->pcan_reschedule_need = B_FALSE;
-			}
-		}
-		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_TX_EXC);
-	}
-	if (stat & AN_EV_ALLOC) {
-		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC);
-		PCANDBG((CE_NOTE, "pcan intr: nicmem alloc done\n"));
-	}
-	if (stat & AN_EV_MIC) {
-		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_MIC);
-	}
-	PCAN_ENABLE_INTR(pcan_p);
-	mutex_exit(&pcan_p->pcan_glock);
-	return (DDI_INTR_CLAIMED);
-}
-
-static uint_t
-pcan_intr_hi(caddr_t arg)
-{
-	uint16_t stat;
-	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
-
-	mutex_enter(&pcan_p->pcan_glock);
-	if ((pcan_p->pcan_flag & (PCAN_CARD_READY | PCAN_CARD_INTREN)) !=
-	    (PCAN_CARD_READY | PCAN_CARD_INTREN)) {
-		mutex_exit(&pcan_p->pcan_glock);
-		return (DDI_INTR_UNCLAIMED);
-	}
-	PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
-	PCANDBG((CE_NOTE, "pcan intr(hi): stat=%x pcan_flags=%x\n", stat,
-	    pcan_p->pcan_flag));
-
-	if (!(stat & AN_INTRS(pcan_p)) || stat == AN_EV_ALL) {
-		mutex_exit(&pcan_p->pcan_glock);
-		return (DDI_INTR_UNCLAIMED);
-	}
-	/* disable interrupt without ack */
-	PCAN_WRITE(pcan_p, AN_INT_EN(pcan_p), 0);
-	mutex_exit(&pcan_p->pcan_glock);
-	ddi_trigger_softintr(pcan_p->pcan_softint_id);
-	return (DDI_INTR_CLAIMED);
-}
-
-/*
- * retrieve data from pccard
- */
-static void
-pcan_rcv(pcan_maci_t *pcan_p)
-{
-	uint16_t id, off, ret, data_len, pkt_stat, frm_ctl;
-	an_rxfrm_t frm;
-	struct ieee80211_llc *llc;
-
-	mblk_t *mp = allocb(PCAN_NICMEM_SZ, BPRI_MED);
-	if (!mp) {
-		cmn_err(CE_WARN, "pcan: failed to alloc rcv buf");
-		pcan_p->glds_norcvbuf++;
-		return;
-	}
-	ASSERT(mp->b_rptr == mp->b_wptr);
-
-	PCAN_READ(pcan_p, AN_RX_FID, id);
-	if (id == AN_INVALID_FID) {
-		PCANDBG((CE_NOTE, "pcan rcv: can't get rx_fid\n"));
-		pcan_p->glds_norcvbuf++;
-		ret = PCAN_FAIL;
-		goto done;
-	}
-	if (ret = RDCH0(pcan_p, id, 0, (uint16_t *)&frm, sizeof (frm))) {
-		PCANDBG((CE_NOTE, "pcan rcv: read frm err %x\n", ret));
-		goto done;
-	}
-	off = sizeof (frm);
-	if (frm.an_rx_status) {
-		PCANDBG((CE_NOTE, "pcan rcv: err stat %x\n", frm.an_rx_status));
-		ret = frm.an_rx_status;
-		goto done;
-	}
-	PCANDBG((CE_NOTE, "pcan rcv: payload_len=%x gap_len=%x\n",
-	    frm.an_rx_payload_len, frm.an_gaplen));
-	if (frm.an_rx_payload_len > PCAN_NICMEM_SZ ||
-	    frm.an_gaplen > AN_RXGAP_MAX) {
-		PCANDBG((CE_NOTE, "pcan rcv: bad len\n"));
-		ret = PCAN_FAIL;
-		goto done;
-	}
-	if (ret = RDCH0(pcan_p, id, off, &pkt_stat, sizeof (pkt_stat))) {
-		PCANDBG((CE_NOTE, "pcan rcv: pkt status err %x\n", ret));
-		ret = PCAN_FAIL;
-		goto done;
-	}
-	off += sizeof (pkt_stat);
-	if (ret = RDCH0(pcan_p, id, off, &data_len, sizeof (data_len))) {
-		PCANDBG((CE_NOTE, "pcan rcv: payload len err %x\n", ret));
-		ret = PCAN_FAIL;
-		goto done;
-	}
-	off += sizeof (data_len);
-	off += ETHERADDRL << 1;
-	PCANDBG((CE_NOTE, "pcan rcv: pkt_stat=%x payload_len=%x+c off=%x\n",
-	    pkt_stat, data_len, off));
-
-#ifdef DEBUG
-	if (pcan_debug & PCAN_DBG_RCV) {
-		int i;
-		cmn_err(CE_NOTE, "pcan rcv: frm header\n");
-		for (i = 0; i < sizeof (frm); i++)
-			cmn_err(CE_NOTE, "%x: %x\n", i,
-			    *((uint8_t *)&frm + i));
-	}
-#endif
-	/*
-	 * this driver deal with WEP by itself. so plugin always thinks no wep.
-	 */
-	frm.an_frame_ctl &= ~(IEEE80211_FC1_WEP << 8);
-	frm_ctl = frm.an_frame_ctl;
-	PCAN_SWAP16((uint16_t *)&frm.an_frame_ctl,
-	    sizeof (struct ieee80211_frame));
-	/*
-	 * discard those frames which are not from the AP we connect or
-	 * without 'ap->sta' direction
-	 */
-	if (((pcan_p->an_config.an_opmode == AN_OPMODE_INFR_STATION)) &&
-	    ((((frm_ctl >> 8) & IEEE80211_FC1_DIR_MASK) !=
-	    IEEE80211_FC1_DIR_FROMDS) ||
-	    bcmp(pcan_p->an_status.an_cur_bssid, frm.an_addr2, 6) != 0)) {
-		ret = PCAN_FAIL;
-		goto done;
-	}
-	bcopy(&frm.an_frame_ctl, mp->b_wptr,
-	    sizeof (struct ieee80211_frame));
-	mp->b_wptr += sizeof (struct ieee80211_frame);
-
-	/* the plugin need a llc here */
-	llc = (struct ieee80211_llc *)mp->b_wptr;
-	llc->illc_dsap = llc->illc_ssap = AN_SNAP_K1;
-	llc->illc_control = AN_SNAP_CONTROL;
-	bzero(llc->illc_oc, sizeof (llc->illc_oc));
-	mp->b_wptr += AN_SNAPHDR_LEN;
-
-	/* read in the rest of data */
-	data_len += data_len & 1;	/* adjust to word boundary */
-	if (data_len > MBLKSIZE(mp)) {
-		cmn_err(CE_NOTE, "pcan rcv: data over length%x\n", data_len);
-		ret = PCAN_FAIL;
-		goto done;
-	}
-
-	if (ret = RDPKT(pcan_p, id, off, (uint16_t *)mp->b_wptr, data_len)) {
-		PCANDBG((CE_NOTE, "pcan rcv: err read data %x\n", ret));
-	}
-done:
-	if (ret) {
-		PCANDBG((CE_NOTE, "pcan rcv: rd data %x\n", ret));
-		freemsg(mp);
-		return;
-	}
-	mp->b_wptr += data_len;
-#ifdef DEBUG
-	if (pcan_debug & PCAN_DBG_RCV) {
-		int i;
-		cmn_err(CE_NOTE, "pcan rcv: len=0x%x\n", data_len);
-		for (i = 0; i < data_len + sizeof (frm); i++)
-			cmn_err(CE_NOTE, "%x: %x\n", i,
-			    *((uint8_t *)mp->b_rptr + i));
-	}
-#endif
-	mutex_exit(&pcan_p->pcan_glock);
-	mac_rx(GLD3(pcan_p), NULL, mp);
-	mutex_enter(&pcan_p->pcan_glock);
-}
-
-/*
- * retrieve data from mini-pci card
- */
-static void
-pcian_rcv(pcan_maci_t *pcan_p)
-{
-	struct an_card_rx_desc an_rx_desc;
-	char *buf;
-	uint16_t ret = 0, data_len;
-	int i, j;
-	struct ieee80211_frame *frm;
-	struct ieee80211_llc *llc;
-
-	mblk_t *mp = allocb(AN_RX_BUFFER_SIZE, BPRI_MED);
-	if (!mp) {
-		cmn_err(CE_WARN, "pcan(pci): failed to alloc rcv buf");
-		pcan_p->glds_norcvbuf++;
-		return;
-	}
-	ASSERT(mp->b_rptr == mp->b_wptr);
-
-	for (i = 0; i < sizeof (an_rx_desc) / 4; i++)
-		PCAN_AUX_GET32(pcan_p, AN_RX_DESC_OFFSET + (i * 4),
-		    ((uint32_t *)&an_rx_desc)[i]);
-	if (an_rx_desc.an_done && !an_rx_desc.an_valid) {
-		buf = pcan_p->pcan_rx[0].dma_virtaddr;
-		data_len = an_rx_desc.an_len;
-#ifdef DEBUG
-		if (pcan_debug & PCAN_DBG_RCV) {
-			cmn_err(CE_NOTE, "pcan(pci) rcv: data_len=%x",
-			    data_len);
-			for (j = 0; j < data_len + 14; j++)
-				cmn_err(CE_NOTE, "pcan_rcv %d: %x", j,
-				    *((uint8_t *)buf + j));
-		}
-#endif
-		if (data_len > MBLKSIZE(mp)) {
-			cmn_err(CE_NOTE, "pcan(pci) rcv: data over length%x\n",
-			    data_len);
-			ret = PCAN_FAIL;
-			goto done;
-		}
-		/*
-		 * minipci card receive an ethernet frame, so assembly a 802.11
-		 * frame here manually.
-		 */
-		frm = (struct ieee80211_frame *)mp->b_wptr;
-		bzero(frm, sizeof (*frm));
-		frm->i_fc[0] |= IEEE80211_FC0_TYPE_DATA;
-		frm->i_fc[1] |= IEEE80211_FC1_DIR_FROMDS;
-		bcopy(pcan_p->an_status.an_cur_bssid, frm->i_addr2, 6);
-		bcopy(buf, frm->i_addr1, 6);
-		bcopy(buf + 6, frm->i_addr3, 6);
-		mp->b_wptr += sizeof (struct ieee80211_frame);
-
-		llc = (struct ieee80211_llc *)mp->b_wptr;
-		llc->illc_dsap = llc->illc_ssap = AN_SNAP_K1;
-		llc->illc_control = AN_SNAP_CONTROL;
-		bzero(llc->illc_oc, sizeof (llc->illc_oc));
-		mp->b_wptr += AN_SNAPHDR_LEN;
-
-		bcopy(buf + 12, mp->b_wptr, data_len);
-		mp->b_wptr += data_len;
-#ifdef DEBUG
-		if (pcan_debug & PCAN_DBG_RCV) {
-			int i;
-			cmn_err(CE_NOTE, "pcan(pci) rcv: len=0x%x\n", data_len);
-			for (i = 0; i < data_len + sizeof (*frm)
-			    + sizeof (*llc); i++)
-				cmn_err(CE_NOTE, "%x: %x\n", i,
-				    *((uint8_t *)mp->b_rptr + i));
-		}
-#endif
-		mutex_exit(&pcan_p->pcan_glock);
-		mac_rx(GLD3(pcan_p), NULL, mp);
-		mutex_enter(&pcan_p->pcan_glock);
-	}
-done:
-	bzero(&an_rx_desc, sizeof (an_rx_desc));
-	an_rx_desc.an_valid = 1;
-	an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
-	an_rx_desc.an_done = 0;
-	an_rx_desc.an_phys = pcan_p->pcan_rx[0].dma_physaddr;
-
-	for (i = 0; i < sizeof (an_rx_desc) / 4; i++)
-		PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET + (i * 4),
-		    ((uint32_t *)&an_rx_desc)[i]);
-	if (ret) {
-		freemsg(mp);
-	}
-}
-
-/*ARGSUSED*/
-static uint32_t
-pcan_txdone(pcan_maci_t *pcan_p, uint16_t err)
-{
-	uint16_t fid, i, ring_idx;
-	uint32_t ret = 0;
-
-	PCAN_READ(pcan_p, AN_TX_CMP_FID(pcan_p), fid);
-	mutex_enter(&pcan_p->pcan_txring.an_tx_lock);
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-		if (pcan_p->pcan_flag & PCAN_CARD_SEND) {
-			ring_idx = pcan_p->pcan_txring.an_tx_cons;
-			pcan_p->pcan_txring.an_tx_cons =
-			    (ring_idx + 1) % AN_MAX_TX_DESC;
-			if (pcan_p->pcan_txring.an_tx_prod ==
-			    pcan_p->pcan_txring.an_tx_cons) {
-				pcan_p->pcan_flag &= ~PCAN_CARD_SEND;
-			}
-		}
-		ret = 0;
-	} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
-		for (i = 0; i < AN_TX_RING_CNT; i++) {
-			if (fid == pcan_p->pcan_txring.an_tx_ring[i]) {
-				pcan_p->pcan_txring.an_tx_ring[i] = 0;
-				break;
-			}
-		}
-		pcan_p->pcan_txring.an_tx_cons =
-		    (pcan_p->pcan_txring.an_tx_cons + 1) & AN_TX_RING_MASK;
-		ret = (i == AN_TX_RING_CNT ? 1 : 0);
-	}
-	mutex_exit(&pcan_p->pcan_txring.an_tx_lock);
-	return (ret);
-}
-
-/*
- * delay in which the mutex is not hold.
- * assuming the mutex has already been hold.
- */
-static void
-pcan_delay(pcan_maci_t *pcan_p, clock_t microsecs)
-{
-	ASSERT(mutex_owned(&pcan_p->pcan_glock));
-
-	mutex_exit(&pcan_p->pcan_glock);
-	delay(drv_usectohz(microsecs));
-	mutex_enter(&pcan_p->pcan_glock);
-}
-
-static void
-pcan_reset_backend(pcan_maci_t *pcan_p, int timeout)
-{
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-		(void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
-		PCAN_DISABLE_INTR_CLEAR(pcan_p);
-		(void) pcan_set_cmd(pcan_p, AN_CMD_FW_RESTART, 0);
-		(void) pcan_set_cmd(pcan_p, AN_CMD_NOOP2, 0);
-		(void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
-	} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
-		(void) pcan_set_cmd0(pcan_p, AN_CMD_DISABLE, 0, 0, 0);
-		(void) pcan_set_cmd0(pcan_p, AN_CMD_NOOP2, 0, 0, 0);
-		PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), AN_CMD_FW_RESTART);
-		pcan_delay(pcan_p, timeout); /* wait for firmware restart */
-
-		(void) pcan_set_cmd(pcan_p, AN_CMD_NOOP, 0);
-		(void) pcan_set_cmd0(pcan_p, AN_CMD_DISABLE, 0, 0, 0);
-
-		PCAN_DISABLE_INTR_CLEAR(pcan_p);
-	}
-}
-
-/*
- * set command without the need of ACK.
- */
-static uint16_t
-pcan_set_cmd0(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t p0,
-    uint16_t p1, uint16_t p2)
-{
-	int i;
-	uint16_t stat, r0, r1, r2;
-
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-		for (i = 0; i < AN_TIMEOUT; i++) {
-			PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
-			if (!(stat & AN_CMD_BUSY))
-				break;
-		}
-		if (i == AN_TIMEOUT) {
-			PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p),
-			    AN_EV_CLR_STUCK_BUSY);
-			PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
-			drv_usecwait(10);
-		}
-		PCAN_WRITE(pcan_p, AN_PARAM0(pcan_p), p0);
-		PCAN_WRITE(pcan_p, AN_PARAM1(pcan_p), p1);
-		PCAN_WRITE(pcan_p, AN_PARAM2(pcan_p), p2);
-	}
-	PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd);
-	for (i = 0; i < AN_TIMEOUT; i++) {
-		PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
-		if (stat & AN_EV_CMD)
-			break;
-	}
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-		PCAN_READ(pcan_p, AN_RESP0(pcan_p), r0);
-		PCAN_READ(pcan_p, AN_RESP1(pcan_p), r1);
-		PCAN_READ(pcan_p, AN_RESP2(pcan_p), r2);
-		PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
-		if (stat & AN_CMD_BUSY)
-			PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p),
-			    AN_EV_CLR_STUCK_BUSY);
-		PCANDBG((CE_NOTE, "pcan set_cmd0: "
-		    "stat=%x, r0=%x, r1=%x, r2=%x\n",
-		    stat, r0, r1, r2));
-	}
-	PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
-	return (i == AN_TIMEOUT ? PCAN_TIMEDOUT_ACCESS : PCAN_SUCCESS);
-}
-
-static uint16_t
-pcan_set_cmd(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t param)
-{
-	int i;
-	uint16_t stat, r0, r1, r2;
-	uint16_t ret;
-
-	if (((cmd == AN_CMD_ENABLE) &&
-	    ((pcan_p->pcan_flag & PCAN_ENABLED) != 0)) ||
-	    ((cmd == AN_CMD_DISABLE) &&
-	    ((pcan_p->pcan_flag & PCAN_ENABLED) == 0)))
-		return (PCAN_SUCCESS);
-	for (i = 0; i < AN_TIMEOUT; i++) {
-		PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
-		if (!(stat & AN_CMD_BUSY)) {
-			break;
-		}
-	}
-	if (i == AN_TIMEOUT) {
-		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CLR_STUCK_BUSY);
-		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
-		drv_usecwait(10);
-	}
-
-	PCAN_WRITE(pcan_p, AN_PARAM0(pcan_p), param);
-	PCAN_WRITE(pcan_p, AN_PARAM1(pcan_p), 0);
-	PCAN_WRITE(pcan_p, AN_PARAM2(pcan_p), 0);
-	PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd);
-
-	for (i = 0; i < AN_TIMEOUT; i++) {
-		PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
-		if (stat & AN_EV_CMD) {
-			break;
-		}
-		PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
-		if (stat == cmd)
-			PCAN_WRITE(pcan_p, AN_COMMAND(pcan_p), cmd);
-	}
-	if (i == AN_TIMEOUT) {
-		if (cmd == AN_CMD_FW_RESTART) {
-			PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
-			return (PCAN_SUCCESS);
-		}
-#ifdef DEBUG
-		if (pcan_debug & PCAN_DBG_CMD) {
-			cmn_err(CE_WARN, "pcan set_cmd: %x timeout stat=%x\n",
-			    cmd, stat);
-		}
-#endif
-		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
-		return (PCAN_TIMEDOUT_CMD);
-	}
-
-	for (i = 0; i < AN_TIMEOUT; i++) {
-		PCAN_READ(pcan_p, AN_STATUS(pcan_p), stat);
-		PCAN_READ(pcan_p, AN_RESP0(pcan_p), r0);
-		PCAN_READ(pcan_p, AN_RESP1(pcan_p), r1);
-		PCAN_READ(pcan_p, AN_RESP2(pcan_p), r2);
-		if ((stat & AN_STAT_CMD_CODE) == (cmd & AN_STAT_CMD_CODE))
-			break;
-	}
-	if (cmd == AN_CMD_FW_RESTART) {
-		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
-		return (PCAN_SUCCESS);
-	}
-	if (i == AN_TIMEOUT) {
-#ifdef DEBUG
-		if (pcan_debug & PCAN_DBG_CMD) {
-			cmn_err(CE_WARN, "pcan set_cmd<%x,%x>: timeout "
-			    "%x,%x,%x,%x\n", cmd, param, stat, r0, r1, r2);
-		}
-#endif
-		ret = PCAN_TIMEDOUT_ACCESS;
-	} else {
-		if (stat & AN_STAT_CMD_RESULT) {
-#ifdef DEBUG
-			if (pcan_debug & PCAN_DBG_CMD) {
-				cmn_err(CE_WARN, "pcan set_cmd<%x,%x>: failed "
-				    "%x,%x,%x,%x\n",
-				    cmd, param, stat, r0, r1, r2);
-			}
-#endif
-			ret = PCAN_TIMEDOUT_ACCESS;
-		} else {
-			ret = PCAN_SUCCESS;
-		}
-	}
-	PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CMD);
-	PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
-	if (stat & AN_CMD_BUSY)
-		PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_CLR_STUCK_BUSY);
-	if (ret == PCAN_SUCCESS) {
-		if (cmd == AN_CMD_ENABLE)
-			pcan_p->pcan_flag |= PCAN_ENABLED;
-		if (cmd == AN_CMD_DISABLE)
-			pcan_p->pcan_flag &= (~PCAN_ENABLED);
-	}
-	return (ret);
-}
-
-static uint16_t
-pcan_set_ch(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t channel)
-{
-	int i;
-	uint16_t stat, select, offset;
-
-	if (channel) {
-		select = AN_SEL1;
-		offset = AN_OFF1;
-	} else {
-		select = AN_SEL0;
-		offset = AN_OFF0;
-	}
-	PCAN_WRITE(pcan_p, select, type);
-	PCAN_WRITE(pcan_p, offset, off);
-	for (i = 0; i < AN_TIMEOUT; i++) {
-		PCAN_READ(pcan_p, offset, stat);
-		if (!(stat & (AN_OFF_BUSY|AN_OFF_ERR)))
-			break;
-	}
-	if (stat & (AN_OFF_BUSY|AN_OFF_ERR)) { /* time out */
-		PCANDBG((CE_WARN, "pcan: set_ch%d %x %x TO %x\n",
-		    channel, type, off, stat));
-		return (PCAN_TIMEDOUT_TARGET);
-	}
-	return (PCAN_SUCCESS);
-}
-
-static uint16_t
-pcan_get_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type, uint16_t *val_p)
-{
-	uint16_t stat;
-
-	PCANDBG((CE_NOTE, "pcan: get_ltv(%p,%x,%x,%p)\n",
-	    (void *)pcan_p, len, type, (void *)val_p));
-	ASSERT(!(len & 1));
-
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-		uint32_t i;
-		struct an_card_rid_desc an_rid_desc;
-		struct an_ltv_gen *an_ltv;
-		if (!pcan_p->pcan_cmd.dma_virtaddr)
-			return (EIO);
-		an_rid_desc.an_valid = 1;
-		an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
-		an_rid_desc.an_rid = 0;
-		an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr;
-		bzero(pcan_p->pcan_cmd.dma_virtaddr, AN_RID_BUFFER_SIZE);
-
-		for (i = 0; i < sizeof (an_rid_desc) / 4; i++)
-			PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4,
-			    ((uint32_t *)&an_rid_desc)[i]);
-
-		if (pcan_set_cmd0(pcan_p, AN_CMD_ACCESS |
-		    AN_ACCESS_READ, type, 0, 0)) {
-			cmn_err(CE_WARN, "pcan get_ltv: set cmd error");
-			return (EIO);
-		}
-
-		an_ltv = (struct an_ltv_gen *)pcan_p->pcan_cmd.dma_virtaddr;
-#ifdef DEBUG
-		if (pcan_debug & PCAN_DBG_INFO) {
-			cmn_err(CE_NOTE, "pcan get_ltv: type=%x,"
-			    "expected len=%d," "actual len=%d",
-			    type, len, an_ltv->an_len);
-			for (i = 0; i < an_ltv->an_len; i++)
-				cmn_err(CE_NOTE, "%d: %x", i,
-				    *(((uint8_t *)an_ltv) + i));
-		}
-#endif
-		if (an_ltv->an_len != len) {
-			PCANDBG((CE_WARN, "pcan get_ltv: rid=%x expected len=%d"
-			    "actual: len=%d", type,
-			    len, an_ltv->an_len));
-			/* return (EIO); */
-		}
-		bcopy(an_ltv, val_p, len);
-	} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
-		len >>= 1;	/* convert bytes to 16-bit words */
-
-		/* 1. select read mode */
-		if (stat = pcan_set_cmd(pcan_p, AN_CMD_ACCESS |
-		    AN_ACCESS_READ, type))
-			return (stat);
-
-		/* 2. select Buffer Access Path (channel) 1 for PIO */
-		if (stat = pcan_set_ch(pcan_p, type, 0, 1))
-			return (stat);
-
-		/* 3. read length */
-		PCAN_READ(pcan_p, AN_DATA1, stat);
-		*val_p++ = stat;
-		if (stat != (len << 1)) {
-			PCANDBG((CE_NOTE, "pcan get_ltv[%x]:expect %x,"
-			    "got %x\n", type, (len + 1) << 1, stat));
-			stat = (stat >> 1) - 1;
-			len = MIN(stat, len);
-		}
-		/* 4. read value */
-		for (stat = 0; stat < len - 1; stat++, val_p++) {
-			PCAN_READ_P(pcan_p, AN_DATA1, val_p, 1);
-		}
-	}
-	return (PCAN_SUCCESS);
-}
-
-static uint16_t
-pcan_put_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type, uint16_t *val_p)
-{
-	uint16_t stat;
-	int i;
-
-	ASSERT(!(len & 1));
-
-	if (pcan_p->pcan_device_type == PCAN_DEVICE_PCI) {
-		struct an_card_rid_desc an_rid_desc;
-
-		for (i = 0; i < AN_TIMEOUT; i++) {
-			PCAN_READ(pcan_p, AN_COMMAND(pcan_p), stat);
-			if (!(stat & AN_CMD_BUSY)) {
-				break;
-			}
-		}
-		if (i == AN_TIMEOUT) {
-			cmn_err(CE_WARN, "pcan put_ltv: busy");
-		}
-
-		an_rid_desc.an_valid = 1;
-		an_rid_desc.an_len = len;
-		an_rid_desc.an_rid = type;
-		an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr;
-
-		bcopy(val_p, pcan_p->pcan_cmd.dma_virtaddr,
-		    an_rid_desc.an_len);
-
-		for (i = 0; i < sizeof (an_rid_desc) / 4; i++)
-			PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4,
-			    ((uint32_t *)&an_rid_desc)[i]);
-		pcan_delay(pcan_p, 100000);
-		stat = pcan_set_cmd0(pcan_p, AN_CMD_ACCESS |
-		    AN_ACCESS_WRITE, type, 0, 0);
-		pcan_delay(pcan_p, 100000);
-		return (stat);
-	} else if (pcan_p->pcan_device_type == PCAN_DEVICE_PCCARD) {
-		/* 0. select read mode first */
-		if (stat = pcan_set_cmd(pcan_p, AN_CMD_ACCESS |
-		    AN_ACCESS_READ, type))
-			return (stat);
-
-		/* 1. select Buffer Access Path (channel) 1 for PIO */
-		if (stat = pcan_set_ch(pcan_p, type, 0, 1))
-			return (stat);
-
-		/* 2. write length */
-		len >>= 1;		/* convert bytes to 16-bit words */
-		stat = len;
-		PCAN_WRITE(pcan_p, AN_DATA1, stat);
-
-		/* 3. write value */
-		val_p++;
-		for (stat = 0; stat < len-1; stat++, val_p++) {
-			PCAN_WRITE_P(pcan_p, AN_DATA1, val_p, 1);
-		}
-
-		/* 4. select write mode */
-		return (pcan_set_cmd(pcan_p, AN_CMD_ACCESS |
-		    AN_ACCESS_WRITE, type));
-	}
-	return (PCAN_FAIL);
-}
-
-/*ARGSUSED*/
-static uint16_t
-pcan_rdch0(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t *buf_p,
-	int len, int order)
-{
-	ASSERT(!(len & 1));
-
-	if (pcan_set_ch(pcan_p, type, off, 0) != PCAN_SUCCESS)
-		return (PCAN_FAIL);
-	len >>= 1;
-	for (off = 0; off < len; off++, buf_p++) {
-		PCAN_READ_P(pcan_p, AN_DATA0, buf_p, order);
-	}
-	return (PCAN_SUCCESS);
-}
-
-/*ARGSUSED*/
-static uint16_t
-pcan_wrch1(pcan_maci_t *pcan_p, uint16_t type, uint16_t off, uint16_t *buf_p,
-	int len, int order)
-{
-	ASSERT(!(len & 1));
-
-	if (pcan_set_ch(pcan_p, type, off, 1) != PCAN_SUCCESS)
-		return (PCAN_FAIL);
-	len >>= 1;
-	for (off = 0; off < len; off++, buf_p++) {
-		PCAN_WRITE_P(pcan_p, AN_DATA1, buf_p, order);
-	}
-	return (PCAN_SUCCESS);
-}
-
-static uint16_t
-pcan_status_ltv(int rw, pcan_maci_t *pcan_p, struct an_ltv_status *status_p)
-{
-	uint16_t ret, len;
-
-	if (rw != PCAN_READ_LTV) {
-		cmn_err(CE_WARN, "pcan status_ltv: unsupported op %x", rw);
-		return (PCAN_FAIL);
-	}
-	if (ret = pcan_get_ltv(pcan_p, sizeof (*status_p), AN_RID_STATUS,
-	    (uint16_t *)status_p))
-		return (ret);
-
-	PCAN_SWAP16_BUF(status_p->an_macaddr);
-	PCAN_SWAP16_BUF(status_p->an_ssid);
-	len = min(status_p->an_ssidlen, 31);
-	status_p->an_ssid[len] = '\0';
-	PCAN_SWAP16_BUF(status_p->an_ap_name);
-	PCAN_SWAP16_BUF(status_p->an_cur_bssid);
-	PCAN_SWAP16_BUF(status_p->an_prev_bssid1);
-	PCAN_SWAP16_BUF(status_p->an_prev_bssid2);
-	PCAN_SWAP16_BUF(status_p->an_prev_bssid3);
-	PCAN_SWAP16_BUF(status_p->an_ap_ip_address);
-	PCAN_SWAP16_BUF(status_p->an_carrier);
-	return (PCAN_SUCCESS);
-}
-
-static uint16_t
-pcan_cfg_ltv(int rw, pcan_maci_t *pcan_p, struct an_ltv_genconfig *cfg_p)
-{
-	uint16_t ret;
-	uint16_t rid = cfg_p == &pcan_p->an_config ?
-	    AN_RID_GENCONFIG : AN_RID_ACTUALCFG;
-
-	if (rw == PCAN_READ_LTV) {
-		if (ret = pcan_get_ltv(pcan_p, sizeof (*cfg_p), rid,
-		    (uint16_t *)cfg_p))
-			return (ret);
-		goto done;
-	}
-	PCAN_SWAP16_BUF(cfg_p->an_macaddr);
-	PCAN_SWAP16_BUF(cfg_p->an_rates);
-	if (ret = pcan_put_ltv(pcan_p, sizeof (*cfg_p),
-	    rid, (uint16_t *)cfg_p))
-		return (ret);
-done:
-	PCAN_SWAP16_BUF(cfg_p->an_macaddr);
-	PCAN_SWAP16_BUF(cfg_p->an_rates);
-	return (ret);
-}
-
-static uint16_t
-pcan_cap_ltv(int rw, pcan_maci_t *pcan_p)
-{
-	uint16_t ret;
-
-	if (rw != PCAN_READ_LTV) {
-		cmn_err(CE_WARN, "pcan cap_ltv: unsupported op %x", rw);
-		return (PCAN_FAIL);
-	}
-	if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_caps),
-	    AN_RID_CAPABILITIES, (uint16_t *)&pcan_p->an_caps))
-		return (ret);
-
-	PCAN_SWAP16_BUF(pcan_p->an_caps.an_oui);
-	PCAN_SWAP16_BUF(pcan_p->an_caps.an_manufname);
-	PCAN_SWAP16_BUF(pcan_p->an_caps.an_prodname);
-	PCAN_SWAP16_BUF(pcan_p->an_caps.an_prodvers);
-	PCAN_SWAP16_BUF(pcan_p->an_caps.an_oemaddr);
-	PCAN_SWAP16_BUF(pcan_p->an_caps.an_aironetaddr);
-	PCAN_SWAP16_BUF(pcan_p->an_caps.an_callid);
-	PCAN_SWAP16_BUF(pcan_p->an_caps.an_supported_rates);
-	return (PCAN_SUCCESS);
-}
-
-static uint16_t
-pcan_ssid_ltv(int rw, pcan_maci_t *pcan_p)
-{
-	uint16_t ret;
-
-	if (rw == PCAN_READ_LTV) {
-		if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_ssidlist),
-		    AN_RID_SSIDLIST, (uint16_t *)&pcan_p->an_ssidlist))
-			return (ret);
-		goto done;
-	}
-	PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid1);
-	PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid2);
-	PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid3);
-	if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_ssidlist),
-	    AN_RID_SSIDLIST, (uint16_t *)&pcan_p->an_ssidlist))
-		return (ret);
-done:
-	PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid1);
-	PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid2);
-	PCAN_SWAP16_BUF(pcan_p->an_ssidlist.an_ssid3);
-	return (ret);
-}
-
-static uint16_t
-pcan_aplist_ltv(int rw, pcan_maci_t *pcan_p)
-{
-	uint16_t ret;
-
-	if (rw == PCAN_READ_LTV) {
-		if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_aplist),
-		    AN_RID_APLIST, (uint16_t *)&pcan_p->an_aplist))
-			return (ret);
-		goto done;
-	}
-	PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap1);
-	PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap2);
-	PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap3);
-	PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap4);
-	if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_aplist),
-	    AN_RID_APLIST, (uint16_t *)&pcan_p->an_aplist))
-		return (ret);
-done:
-	PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap1);
-	PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap2);
-	PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap3);
-	PCAN_SWAP16_BUF(pcan_p->an_aplist.an_ap4);
-	return (ret);
-}
-
-static uint16_t
-pcan_scanresult_ltv(int rw, pcan_maci_t *pcan_p, uint16_t type,
-    struct an_ltv_scanresult *scanresult_p)
-{
-	uint16_t ret, len;
-	if (rw != PCAN_READ_LTV) {
-		cmn_err(CE_WARN, "pcan scan_ltv: readonly rid %x\n", type);
-		return (PCAN_FAIL);
-	}
-	if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_scanresult),
-	    type, (uint16_t *)scanresult_p))
-		return (ret);
-	PCAN_SWAP16_BUF(scanresult_p->an_bssid);
-	PCAN_SWAP16_BUF(scanresult_p->an_ssid);
-	len = min(scanresult_p->an_ssidlen, 31);
-	scanresult_p->an_ssid[len] = '\0';
-	PCAN_SWAP16_BUF(scanresult_p->an_rates);
-	return (PCAN_SUCCESS);
-}
-
-static uint16_t
-pcan_one_wepkey(int rw, pcan_maci_t *pcan_p, struct an_ltv_wepkey *wkp,
-    uint16_t rid)
-{
-	uint16_t ret;
-
-	if (rw == PCAN_READ_LTV) {
-		if (ret = pcan_get_ltv(pcan_p, sizeof (struct an_ltv_wepkey),
-		    rid, (uint16_t *)wkp)) {
-			return (ret);
-		}
-		goto done;
-	}
-	PCAN_SWAP16_BUF(wkp->an_macaddr);
-	PCAN_SWAP16_BUF(wkp->an_key);
-	if (ret = pcan_put_ltv(pcan_p, sizeof (struct an_ltv_wepkey),
-	    rid, (uint16_t *)wkp))
-		return (ret);
-done:
-	PCAN_SWAP16_BUF(wkp->an_macaddr);
-	PCAN_SWAP16_BUF(wkp->an_key);
-	return (ret);
-}
-
-static uint16_t
-pcan_wepkey_ltv(int rw, pcan_maci_t *pcan_p)
-{
-	uint16_t ret, i;
-	struct an_ltv_wepkey wk;
-
-	if (rw == PCAN_READ_LTV) {
-		uint16_t rid = AN_RID_WEPKEY2;
-
-		if (ret = pcan_one_wepkey(rw, pcan_p, &wk, rid))
-			return (ret);
-		for (i = 0; i < 5; i++) {
-			if (wk.an_index < 4)
-				pcan_p->an_wepkey[wk.an_index] = wk;
-			else if (wk.an_index == 0xffff)
-				pcan_p->an_cur_wepkey = wk.an_macaddr[0];
-			rid = AN_RID_WEPKEY;
-		}
-		return (PCAN_SUCCESS);
-	}
-	for (i = 0; i < MAX_NWEPKEYS; i++) {
-		if (pcan_p->an_wepkey[i].an_index == i) {
-			if (ret = pcan_one_wepkey(rw, pcan_p,
-			    &pcan_p->an_wepkey[i], AN_RID_WEPKEY2))
-				return (ret);
-		}
-	}
-	/* Now set the default key */
-	(void) memset(&wk, 0, sizeof (wk));
-	wk.an_index = 0xffff;
-	wk.an_macaddr[0] = pcan_p->an_cur_wepkey;
-	ret = pcan_one_wepkey(rw, pcan_p, &wk, AN_RID_WEPKEY2);
-	return (ret);
-}
-
-static uint16_t
-pcan_alloc_nicmem(pcan_maci_t *pcan_p, uint16_t len, uint16_t *id_p)
-{
-	int i;
-	uint16_t stat;
-
-	len = ((len + 1) >> 1) << 1;	/* round up to 16-bit boundary */
-
-	if (stat = pcan_set_cmd(pcan_p, AN_CMD_ALLOC_MEM, len))
-		return (stat);
-	for (i = 0; !(stat & AN_EV_ALLOC) && (i < AN_TIMEOUT); i++) {
-		PCAN_READ(pcan_p, AN_EVENT_STAT(pcan_p), stat);
-	}
-	if (!(stat & AN_EV_ALLOC))
-		return (PCAN_TIMEDOUT_ALLOC);
-	PCAN_READ(pcan_p, AN_ALLOC_FID, stat);
-	PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), AN_EV_ALLOC);
-	*id_p = stat;
-
-	/* zero fill the allocated NIC mem - sort of pcan_fill_ch0 */
-	(void) pcan_set_ch(pcan_p, stat, 0, 0);
-	for (len >>= 1, stat = 0; stat < len; stat++) {
-		PCAN_WRITE(pcan_p, AN_DATA0, 0);
-	}
-	return (PCAN_SUCCESS);
-}
-
-static void
-pcan_stop_rx_dma(pcan_maci_t *pcan_p)
-{
-	int i, j;
-	struct an_card_rx_desc  an_rx_desc;
-
-	for (i = 0; i < AN_MAX_RX_DESC; i++) {
-		bzero(&an_rx_desc, sizeof (an_rx_desc));
-		an_rx_desc.an_valid = 0;
-		an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
-		an_rx_desc.an_done = 1;
-		an_rx_desc.an_phys = pcan_p->pcan_rx[i].dma_physaddr;
-		for (j = 0; j < sizeof (an_rx_desc) / 4; j++)
-			PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET
-			    + (i * sizeof (an_rx_desc))
-			    + (j * 4), ((uint32_t *)&an_rx_desc)[j]);
-	}
-}
-
-static int
-pcan_init_dma_desc(pcan_maci_t *pcan_p)
-{
-	int i, j;
-	struct an_card_rid_desc an_rid_desc;
-	struct an_card_rx_desc  an_rx_desc;
-	struct an_card_tx_desc  an_tx_desc;
-
-	/* Allocate DMA for rx */
-	if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC,
-	    AN_DESCRIPTOR_RX, AN_RX_DESC_OFFSET,
-	    AN_MAX_RX_DESC) != PCAN_SUCCESS) {
-		cmn_err(CE_WARN, "pcan init_dma: fail to alloc rx descriptor");
-		goto error;
-	}
-	for (i = 0; i < AN_MAX_RX_DESC; i++) {
-		bzero(&an_rx_desc, sizeof (an_rx_desc));
-		an_rx_desc.an_valid = 1;
-		an_rx_desc.an_len = AN_RX_BUFFER_SIZE;
-		an_rx_desc.an_done = 0;
-		an_rx_desc.an_phys = pcan_p->pcan_rx[i].dma_physaddr;
-		for (j = 0; j < sizeof (an_rx_desc) / 4; j++)
-			PCAN_AUX_PUT32(pcan_p, AN_RX_DESC_OFFSET
-			    + (i * sizeof (an_rx_desc))
-			    + (j * 4), ((uint32_t *)&an_rx_desc)[j]);
-	}
-
-
-	/* Allocate DMA for tx */
-	if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC,
-	    AN_DESCRIPTOR_TX, AN_TX_DESC_OFFSET,
-	    AN_MAX_TX_DESC) != PCAN_SUCCESS) {
-		cmn_err(CE_WARN, "pcan init_dma: fail to alloc tx descriptor");
-		goto error;
-	}
-
-	for (i = 0; i < AN_MAX_TX_DESC; i++) {
-		an_tx_desc.an_offset = 0;
-		an_tx_desc.an_eoc = 0;
-		an_tx_desc.an_valid = 0;
-		an_tx_desc.an_len = 0;
-		an_tx_desc.an_phys = pcan_p->pcan_tx[i].dma_physaddr;
-
-		for (j = 0; j < sizeof (an_tx_desc) / 4; j++)
-			PCAN_AUX_PUT32(pcan_p, AN_TX_DESC_OFFSET
-			    + (i * sizeof (an_tx_desc))
-			    + (j * 4), ((uint32_t *)&an_tx_desc)[j]);
-	}
-
-	/* Allocate DMA for rid */
-	if (pcan_set_cmd0(pcan_p, AN_CMD_ALLOC_DESC,
-	    AN_DESCRIPTOR_HOSTRW, AN_HOST_DESC_OFFSET, 1) != PCAN_SUCCESS) {
-		cmn_err(CE_WARN, "pcan init_dma: fail to alloc rid descriptor");
-		goto error;
-	}
-	bzero(&an_rid_desc, sizeof (an_rid_desc));
-	an_rid_desc.an_valid = 1;
-	an_rid_desc.an_len = AN_RID_BUFFER_SIZE;
-	an_rid_desc.an_rid = 0;
-	an_rid_desc.an_phys = pcan_p->pcan_cmd.dma_physaddr;
-
-	for (i = 0; i < sizeof (an_rid_desc) / 4; i++)
-		PCAN_AUX_PUT32(pcan_p, AN_HOST_DESC_OFFSET + i * 4,
-		    ((uint32_t *)&an_rid_desc)[i]);
-
-	pcan_p->pcan_txring.an_tx_prod = 0;
-	pcan_p->pcan_txring.an_tx_cons = 0;
-	pcan_p->pcan_flag &= ~PCAN_CARD_SEND;
-	return (PCAN_SUCCESS);
-error:
-	return (PCAN_FAIL);
-}
-
-static int
-pcan_init_dma(dev_info_t *dip, pcan_maci_t *pcan_p)
-{
-	int i, ret = PCAN_FAIL;
-	ddi_dma_cookie_t dma_cookie;
-	size_t len;
-
-	/* Allocate DMA for rx */
-	for (i = 0; i < AN_MAX_RX_DESC; i++) {
-		if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr,
-		    DDI_DMA_SLEEP, 0,
-		    &pcan_p->pcan_rx[i].dma_handle) != DDI_SUCCESS)
-			goto error;
-
-		if (ddi_dma_mem_alloc(pcan_p->pcan_rx[i].dma_handle,
-		    AN_RX_BUFFER_SIZE, &accattr,
-		    DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0,
-		    (caddr_t *)&pcan_p->pcan_rx[i].dma_virtaddr, &len,
-		    &pcan_p->pcan_rx[i].dma_acc_handle) != DDI_SUCCESS) {
-			goto error;
-		}
-		if (ddi_dma_addr_bind_handle(
-		    pcan_p->pcan_rx[i].dma_handle,
-		    NULL, (caddr_t)pcan_p->pcan_rx[i].dma_virtaddr,
-		    len, DDI_DMA_READ |
-		    DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, &dma_cookie,
-		    &pcan_p->pcan_rx[i].ncookies) != DDI_DMA_MAPPED) {
-			goto error;
-		}
-		ASSERT(pcan_p->pcan_rx[i].ncookies == 1);
-		pcan_p->pcan_rx[i].dma_physaddr = dma_cookie.dmac_address;
-	}
-
-	/* Allocate DMA for tx */
-	for (i = 0; i < AN_MAX_TX_DESC; i++) {
-		if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr,
-		    DDI_DMA_SLEEP, 0,
-		    &pcan_p->pcan_tx[i].dma_handle) != DDI_SUCCESS)
-			goto error;
-
-		if (ddi_dma_mem_alloc(pcan_p->pcan_tx[i].dma_handle,
-		    AN_TX_BUFFER_SIZE, &accattr,
-		    DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0,
-		    (caddr_t *)&pcan_p->pcan_tx[i].dma_virtaddr, &len,
-		    &pcan_p->pcan_tx[i].dma_acc_handle) != DDI_SUCCESS) {
-			goto error;
-		}
-		if (ddi_dma_addr_bind_handle(
-		    pcan_p->pcan_tx[i].dma_handle,
-		    NULL, (caddr_t)pcan_p->pcan_tx[i].dma_virtaddr,
-		    len, DDI_DMA_WRITE |
-		    DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0, &dma_cookie,
-		    &pcan_p->pcan_tx[i].ncookies) != DDI_DMA_MAPPED) {
-			goto error;
-		}
-		ASSERT(pcan_p->pcan_tx[i].ncookies == 1);
-		pcan_p->pcan_tx[i].dma_physaddr = dma_cookie.dmac_address;
-	}
-
-	/* Allocate DMA for rid */
-	if (ddi_dma_alloc_handle(dip, &control_cmd_dma_attr,
-	    DDI_DMA_SLEEP, 0,
-	    &pcan_p->pcan_cmd.dma_handle) != DDI_SUCCESS)
-		goto error;
-
-	if (ddi_dma_mem_alloc(pcan_p->pcan_cmd.dma_handle,
-	    AN_RID_BUFFER_SIZE, &accattr,
-	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0,
-	    (caddr_t *)&pcan_p->pcan_cmd.dma_virtaddr, &len,
-	    &pcan_p->pcan_cmd.dma_acc_handle) != DDI_SUCCESS) {
-		goto error;
-	}
-	if (ddi_dma_addr_bind_handle(
-	    pcan_p->pcan_cmd.dma_handle,
-	    NULL, (caddr_t)pcan_p->pcan_cmd.dma_virtaddr,
-	    len, DDI_DMA_RDWR |
-	    DDI_DMA_CONSISTENT, DDI_DMA_SLEEP, 0, &dma_cookie,
-	    &pcan_p->pcan_cmd.ncookies) != DDI_DMA_MAPPED) {
-		goto error;
-	}
-	ASSERT(pcan_p->pcan_cmd.ncookies == 1);
-	pcan_p->pcan_cmd.dma_physaddr = dma_cookie.dmac_address;
-
-	if (ret = pcan_init_dma_desc(pcan_p)) {
-		cmn_err(CE_WARN, "pcan init_dma_desc: failed\n");
-		goto error;
-	}
-
-	return (PCAN_SUCCESS);
-error:
-	pcan_free_dma(pcan_p);
-	return (ret);
-}
-
-static void
-pcan_free_dma(pcan_maci_t *pcan_p)
-{
-	int i;
-
-	/* free RX dma */
-	pcan_stop_rx_dma(pcan_p);
-	for (i = 0; i < AN_MAX_RX_DESC; i++) {
-		if (pcan_p->pcan_rx[i].dma_handle != NULL) {
-			if (pcan_p->pcan_rx[i].ncookies) {
-				(void) ddi_dma_unbind_handle(
-				    pcan_p->pcan_rx[i].dma_handle);
-				pcan_p->pcan_rx[i].ncookies = 0;
-			}
-			ddi_dma_free_handle(
-			    &pcan_p->pcan_rx[i].dma_handle);
-			pcan_p->pcan_rx[i].dma_handle = NULL;
-		}
-		if (pcan_p->pcan_rx[i].dma_acc_handle != NULL) {
-			ddi_dma_mem_free(
-			    &pcan_p->pcan_rx[i].dma_acc_handle);
-			pcan_p->pcan_rx[i].dma_acc_handle = NULL;
-		}
-	}
-
-	/* free TX dma */
-	for (i = 0; i < AN_MAX_TX_DESC; i++) {
-		if (pcan_p->pcan_tx[i].dma_handle != NULL) {
-			if (pcan_p->pcan_tx[i].ncookies) {
-				(void) ddi_dma_unbind_handle(
-				    pcan_p->pcan_tx[i].dma_handle);
-				pcan_p->pcan_tx[i].ncookies = 0;
-			}
-			ddi_dma_free_handle(
-			    &pcan_p->pcan_tx[i].dma_handle);
-			pcan_p->pcan_tx[i].dma_handle = NULL;
-		}
-		if (pcan_p->pcan_tx[i].dma_acc_handle != NULL) {
-			ddi_dma_mem_free(
-			    &pcan_p->pcan_tx[i].dma_acc_handle);
-			pcan_p->pcan_tx[i].dma_acc_handle = NULL;
-		}
-	}
-
-	/* free cmd dma */
-	if (pcan_p->pcan_cmd.dma_handle != NULL) {
-		if (pcan_p->pcan_cmd.ncookies) {
-			(void) ddi_dma_unbind_handle(
-			    pcan_p->pcan_cmd.dma_handle);
-			pcan_p->pcan_cmd.ncookies = 0;
-		}
-		ddi_dma_free_handle(
-		    &pcan_p->pcan_cmd.dma_handle);
-		pcan_p->pcan_cmd.dma_handle = NULL;
-	}
-	if (pcan_p->pcan_cmd.dma_acc_handle != NULL) {
-		ddi_dma_mem_free(
-		    &pcan_p->pcan_cmd.dma_acc_handle);
-		pcan_p->pcan_cmd.dma_acc_handle = NULL;
-	}
-}
-
-/*
- * get card capability (WEP, default channel), setup broadcast, mac addresses
- */
-static uint32_t
-pcan_get_cap(pcan_maci_t *pcan_p)
-{
-	uint16_t stat;
-
-	if (stat = pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_config)) {
-		PCANDBG((CE_NOTE, "pcan get_cap: read cfg fail %x", stat));
-		return ((uint32_t)AN_RID_GENCONFIG << 16 | stat);
-	}
-
-	if (stat = pcan_cap_ltv(PCAN_READ_LTV, pcan_p)) {
-		PCANDBG((CE_NOTE, "pcan get_cap: read cap fail %x", stat));
-		return ((uint32_t)AN_RID_CAPABILITIES << 16 | stat);
-	}
-#ifdef DEBUG
-	if (pcan_debug & PCAN_DBG_FW_VERSION) {
-		cmn_err(CE_NOTE, "the version of the firmware in the wifi card "
-		    "'%s %s %s' is %s\n",
-		    pcan_p->an_caps.an_manufname,
-		    pcan_p->an_caps.an_prodname,
-		    pcan_p->pcan_device_type == PCAN_DEVICE_PCI ?
-		    "minipci" : "pccard",
-		    pcan_p->an_caps.an_prodvers);
-	}
-#endif
-
-	if (stat = pcan_ssid_ltv(PCAN_READ_LTV, pcan_p)) {
-		PCANDBG((CE_NOTE, "pcan get_cap: read ssid fail %x", stat));
-		return ((uint32_t)AN_RID_SSIDLIST << 16 | stat);
-	}
-
-	if (stat = pcan_aplist_ltv(PCAN_READ_LTV, pcan_p)) {
-		PCANDBG((CE_NOTE, "pcan get_cap: read aplist fail %x", stat));
-		return ((uint32_t)AN_RID_APLIST << 16 | stat);
-	}
-	if (stat = pcan_wepkey_ltv(PCAN_READ_LTV, pcan_p)) {
-		PCANDBG((CE_NOTE, "pcan get_cap: read wepkey fail %x", stat));
-		return ((uint32_t)AN_RID_WEPKEY2 << 16 | stat);
-	}
-	ether_copy(pcan_p->an_caps.an_oemaddr, pcan_p->pcan_mac_addr);
-	return (PCAN_SUCCESS);
-}
-
-static int
-pcan_config_mac(pcan_maci_t *pcan_p)
-{
-	uint16_t stat;
-
-	if (stat = pcan_ssid_ltv(PCAN_WRITE_LTV, pcan_p)) {
-		PCANDBG((CE_NOTE, "pcan config_mac: write SSID failed%x\n",
-		    stat));
-		return ((int)stat);
-	}
-
-	if (stat = pcan_aplist_ltv(PCAN_WRITE_LTV, pcan_p)) {
-		PCANDBG((CE_NOTE, "pcan config_mac: write APlist failed%x\n",
-		    stat));
-		return ((int)stat);
-	}
-	if (stat = pcan_wepkey_ltv(PCAN_WRITE_LTV, pcan_p)) {
-		PCANDBG((CE_NOTE, "pcan config_mac: write wepkey failed%x\n",
-		    stat));
-		return ((int)stat);
-	}
-	if (pcan_p->pcan_usewep)
-		pcan_p->an_config.an_authtype |=
-		    AN_AUTHTYPE_ENABLEWEP | AN_AUTHTYPE_ALLOW_UNENCRYPTED;
-	PCANDBG((CE_NOTE, "pcan config_mac: usewep=%x authtype=%x opmode=%x\n",
-	    pcan_p->pcan_usewep, pcan_p->an_config.an_authtype,
-	    pcan_p->an_config.an_opmode));
-
-	pcan_p->an_config.an_assoc_timeout = 5000; /* stop assoc seq in 5 sec */
-	if (stat = pcan_cfg_ltv(PCAN_WRITE_LTV, pcan_p, &pcan_p->an_config)) {
-		PCANDBG((CE_NOTE, "pcan config_mac: write cfg failed %x\n",
-		    stat));
-		return ((int)stat);
-	}
-
-	if (stat = pcan_cfg_ltv(PCAN_READ_LTV, pcan_p,
-	    &pcan_p->an_actual_config)) {
-		PCANDBG((CE_NOTE, "pcan config_mac: read cfg failed%x\n",
-		    stat));
-		return ((int)stat);
-	}
-	PCANDBG((CE_NOTE, "pcan config_mac: optionmask=%x authtype=%x\n", 0,
-	    pcan_p->an_actual_config.an_authtype));
-
-	if (stat = pcan_status_ltv(PCAN_READ_LTV, pcan_p, &pcan_p->an_status)) {
-		PCANDBG((CE_NOTE, "pcan config_mac: read status failed %x\n",
-		    stat));
-		return ((int)stat);
-	}
-	return (PCAN_SUCCESS);
-}
-
-static int
-pcan_loaddef(pcan_maci_t *pcan_p)
-{
-	int i;
-
-	pcan_p->an_ssidlist.an_ssid1_len = 0;
-	bzero(pcan_p->an_ssidlist.an_ssid1,
-	    sizeof (pcan_p->an_ssidlist.an_ssid1));
-	for (i = 0; i < MAX_NWEPKEYS; i++) {
-		pcan_p->an_wepkey[i].an_index = 0xffff;
-		bzero(pcan_p->an_wepkey[i].an_key,
-		    sizeof (pcan_p->an_wepkey[i].an_key));
-		pcan_p->an_wepkey[i].an_keylen = 0;
-		bzero(pcan_p->an_wepkey[i].an_macaddr,
-		    sizeof (pcan_p->an_wepkey[i].an_macaddr));
-		pcan_p->an_wepkey[i].an_macaddr[0] = 1;
-	}
-	pcan_p->an_cur_wepkey = 0;
-
-	pcan_p->pcan_usewep = 0;
-	pcan_p->an_config.an_opmode = AN_OPMODE_INFR_STATION;
-	pcan_p->an_config.an_authtype = AN_AUTHTYPE_OPEN;
-	pcan_p->an_config.an_stationary = 1;
-	pcan_p->an_config.an_max_beacon_lost_time = 0xffff;
-	i = pcan_config_mac(pcan_p);
-
-	return (i);
-}
-
-static int
-pcan_init_nicmem(pcan_maci_t *pcan_p)
-{
-	int i;
-	uint16_t ret;
-	pcan_txring_t *ring_p = &pcan_p->pcan_txring;
-
-	for (i = 0; i < AN_TX_RING_CNT; i++) {
-		uint16_t rc;
-		ret = pcan_alloc_nicmem(pcan_p, PCAN_NICMEM_SZ, &rc);
-		if (ret) {
-			cmn_err(CE_WARN, "pcan alloc NIC Tx buf[%x]: failed "
-			    "%x\n", i, ret);
-			return (DDI_FAILURE);
-		}
-		ring_p->an_tx_fids[i] = rc;
-		ring_p->an_tx_ring[i] = 0;
-		PCANDBG((CE_NOTE, "pcan: NIC tx_id[%x]=%x\n", i, rc));
-	}
-	ring_p->an_tx_prod = ring_p->an_tx_cons = 0;
-	return (PCAN_SUCCESS);
-}
-
-
-
-static void
-pcan_start_locked(pcan_maci_t *pcan_p)
-{
-	pcan_p->pcan_flag |= PCAN_CARD_INTREN;
-	PCAN_ENABLE_INTR(pcan_p);
-}
-
-static void
-pcan_stop_locked(pcan_maci_t *pcan_p)
-{
-	PCAN_DISABLE_INTR_CLEAR(pcan_p);
-	pcan_p->pcan_flag &= ~PCAN_CARD_INTREN;
-}
-
-/*
- * for scan result
- */
-static int
-pcan_add_scan_item(pcan_maci_t *pcan_p, struct an_ltv_scanresult s)
-{
-	an_scan_list_t *scan_item;
-
-	scan_item = kmem_zalloc(sizeof (an_scan_list_t), KM_SLEEP);
-	if (scan_item == NULL) {
-		cmn_err(CE_WARN, "pcan add_scan_item: zalloc failed\n");
-		return (PCAN_FAIL);
-	}
-	scan_item->an_val = s;
-	scan_item->an_timeout = AN_SCAN_TIMEOUT_MAX;
-	list_insert_tail(&pcan_p->an_scan_list, scan_item);
-	pcan_p->an_scan_num++;
-	return (PCAN_SUCCESS);
-}
-
-static void
-pcan_delete_scan_item(pcan_maci_t *pcan_p, an_scan_list_t *s)
-{
-	list_remove(&pcan_p->an_scan_list, s);
-	kmem_free(s, sizeof (*s));
-	pcan_p->an_scan_num--;
-}
-
-static void
-pcan_scanlist_timeout(void *arg)
-{
-	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
-	an_scan_list_t *scan_item0, *scan_item1;
-
-	mutex_enter(&pcan_p->pcan_scanlist_lock);
-	scan_item0 = list_head(&pcan_p->an_scan_list);
-	for (; scan_item0; ) {
-		PCANDBG((CE_NOTE, "pcan scanlist: ssid = %s\n",
-		    scan_item0->an_val.an_ssid));
-		PCANDBG((CE_NOTE, "pcan scanlist: timeout left: %ds",
-		    scan_item0->an_timeout));
-		scan_item1 = list_next(&pcan_p->an_scan_list, scan_item0);
-		if (scan_item0->an_timeout == 0) {
-			pcan_delete_scan_item(pcan_p, scan_item0);
-		} else {
-			scan_item0->an_timeout--;
-		}
-		scan_item0 = scan_item1;
-	}
-	mutex_exit(&pcan_p->pcan_scanlist_lock);
-	pcan_p->an_scanlist_timeout_id = timeout(pcan_scanlist_timeout,
-	    pcan_p, drv_usectohz(1000000));
-}
-
-/*
- * Brussels support
- */
-/*
- * MAC_PROP_WL_ESSID
- */
-static int
-pcan_set_essid(pcan_maci_t *pcan_p, const void *wldp_buf)
-{
-	char *value;
-	struct an_ltv_ssidlist 	*ssidlist_p;
-	wl_essid_t *iw_essid = (wl_essid_t *)wldp_buf;
-
-	ssidlist_p = &pcan_p->an_ssidlist;
-	bzero(ssidlist_p, sizeof (*ssidlist_p));
-	value = iw_essid->wl_essid_essid;
-	(void) strncpy(ssidlist_p->an_ssid1, value,
-	    MIN(32, strlen(value)));
-	ssidlist_p->an_ssid1_len = strlen(value);
-
-	return (ENETRESET);
-}
-
-static int
-pcan_get_essid(pcan_maci_t *pcan_p, void *wldp_buf)
-{
-	int err = 0;
-	struct an_ltv_status *status_p;
-	wl_essid_t *ow_essid = (wl_essid_t *)wldp_buf;
-
-	status_p = &pcan_p->an_status;
-
-	if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
-		err = EIO;
-		return (err);
-	}
-	ow_essid->wl_essid_length = status_p->an_ssidlen;
-	bcopy(status_p->an_ssid, ow_essid->wl_essid_essid,
-	    status_p->an_ssidlen);
-
-	return (err);
-}
-
-/*
- * MAC_PROP_WL_BSSID
- */
-static int
-pcan_set_bssid(pcan_maci_t *pcan_p, const void *wldp_buf)
-{
-	wl_bssid_t *value;
-	struct an_ltv_aplist *aplist_p;
-
-	aplist_p = &pcan_p->an_aplist;
-
-	value = (wl_bssid_t *)wldp_buf;
-	(void) strncpy((char *)aplist_p->an_ap1, (char *)value, 6);
-
-	return (ENETRESET);
-}
-
-static int
-pcan_get_bssid(pcan_maci_t *pcan_p, void *wldp_buf)
-{
-	int 	err = 0;
-	struct 	an_ltv_status *status_p;
-
-	status_p = &pcan_p->an_status;
-
-	if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
-		err = EIO;
-		return (err);
-	}
-
-	bcopy(status_p->an_cur_bssid, wldp_buf, sizeof (wl_bssid_t));
-	PCANDBG((CE_CONT,
-	    "pcan: cfg_bssid: bssid=%x %x %x %x %x %x\n",
-	    status_p->an_cur_bssid[0],
-	    status_p->an_cur_bssid[1],
-	    status_p->an_cur_bssid[2],
-	    status_p->an_cur_bssid[3],
-	    status_p->an_cur_bssid[4],
-	    status_p->an_cur_bssid[5]));
-
-	return (err);
-}
-
-/*
- * MAC_PROP_WL_LINKSTATUS
- */
-static void
-pcan_get_linkstatus(pcan_maci_t *pcan_p, void *wldp_buf)
-{
-	if (pcan_p->pcan_flag & PCAN_CARD_LINKUP)
-		*(wl_linkstatus_t *)wldp_buf = WL_CONNECTED;
-	else
-		*(wl_linkstatus_t *)wldp_buf = WL_NOTCONNECTED;
-
-}
-
-/*
- * MAC_PROP_WL_BSSTYP
- */
-static int
-pcan_set_bsstype(pcan_maci_t *pcan_p, const void *wldp_buf)
-{
-	struct an_ltv_genconfig *cfg_p;
-
-	cfg_p = &pcan_p->an_config;
-
-	if (*(wl_bss_type_t *)wldp_buf == WL_BSS_BSS)
-		cfg_p->an_opmode = AN_OPMODE_INFR_STATION;
-	if (*(wl_bss_type_t *)wldp_buf == WL_BSS_IBSS)
-		cfg_p->an_opmode = AN_OPMODE_IBSS_ADHOC;
-	if (*(wl_bss_type_t *)wldp_buf == WL_BSS_ANY)
-		cfg_p->an_opmode = AN_OPMODE_INFR_STATION;
-	cfg_p->an_assoc_timeout = 5000;
-
-	return (ENETRESET);
-}
-
-static void
-pcan_get_bsstype(pcan_maci_t *pcan_p, void *wldp_buf)
-{
-	struct an_ltv_genconfig *cfg_p;
-
-	cfg_p = &pcan_p->an_config;
-
-	if (cfg_p->an_opmode == AN_OPMODE_INFR_STATION) {
-		*(wl_bss_type_t *)wldp_buf = WL_BSS_BSS;
-	} else if (cfg_p->an_opmode == AN_OPMODE_IBSS_ADHOC) {
-		*(wl_bss_type_t *)wldp_buf = WL_BSS_IBSS;
-	}
-}
-
-/*
- * MAC_PROP_WL_PHY_CONFIG
- */
-static int
-pcan_set_phy(pcan_maci_t *pcan_p, const void *wldp_buf)
-{
-	uint16_t ret;
-	int err = ENETRESET;
-	wl_phy_conf_t *phy = (wl_phy_conf_t *)wldp_buf;
-	struct an_ltv_genconfig *cfg_p;
-
-	cfg_p = &pcan_p->an_config;
-
-	ret = (uint16_t)(phy->wl_phy_dsss_conf.wl_dsss_channel);
-	if (ret < 1 || ret > 14) {
-		err = ENOTSUP;
-		return (err);
-	}
-	cfg_p->an_ds_channel = ret;
-	cfg_p->an_assoc_timeout = 5000;
-
-	return (err);
-}
-
-static int
-pcan_get_phy(pcan_maci_t *pcan_p, void *wldp_buf)
-{
-	int err = 0;
-	struct an_ltv_status *status_p;
-	wl_dsss_t *dsss = (wl_dsss_t *)wldp_buf;
-
-	status_p = &pcan_p->an_status;
-
-	if (pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
-		err = EIO;
-		return (err);
-	}
-
-	dsss->wl_dsss_channel = status_p->an_channel_set;
-	dsss->wl_dsss_subtype = WL_DSSS;
-
-	return (err);
-}
-
-/*
- * MAC_PROP_WL_DESIRED_RATESa
- */
-static int
-pcan_set_desrates(pcan_maci_t *pcan_p, const void *wldp_buf)
-{
-	uint16_t i;
-	struct an_ltv_genconfig *cfg_p;
-
-	cfg_p = &pcan_p->an_config;
-
-	bzero(cfg_p->an_rates, sizeof (cfg_p->an_rates));
-	for (i = 0; i < ((wl_rates_t *)wldp_buf)->wl_rates_num; i++) {
-		cfg_p->an_rates[i] =
-		    (((wl_rates_t *)wldp_buf)->wl_rates_rates)[i];
-	}
-	cfg_p->an_assoc_timeout = 5000;
-
-	return (ENETRESET);
-}
-
-static int
-pcan_get_desrates(pcan_maci_t *pcan_p, void *wldp_buf)
-{
-	uint16_t i;
-	uint8_t rates = 0;
-	int	err = 0;
-	struct an_ltv_genconfig *actcfg_p;
-
-	actcfg_p = &pcan_p->an_actual_config;
-
-	if (pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, actcfg_p)) {
-		err = EIO;
-		return (err);
-	}
-
-	for (i = 0; i < sizeof (actcfg_p->an_rates); i++) {
-		if (actcfg_p->an_rates[i] == 0)
-			break;
-		rates = MAX(rates, actcfg_p->an_rates[i]);
-	}
-	(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] = rates;
-	((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
-
-	return (err);
-}
-
-/*
- * MAC_PROP_WL_SUP_RATE
- */
-static void
-pcan_get_suprates(void *wldp_buf)
-{
-	wl_rates_t *wl_rates = (wl_rates_t *)wldp_buf;
-
-	wl_rates->wl_rates_num = 4;
-	wl_rates->wl_rates_rates[0] = WL_RATE_1M;
-	wl_rates->wl_rates_rates[1] = WL_RATE_2M;
-	wl_rates->wl_rates_rates[2] = WL_RATE_5_5M;
-	wl_rates->wl_rates_rates[3] = WL_RATE_11M;
-}
-
-/*
- * MAC_PROP_WL_POWER_MODE
- */
-static int
-pcan_get_powermode(pcan_maci_t *pcan_p, void *wldp_buf)
-{
-	int err = 0;
-	wl_ps_mode_t *powermode = (wl_ps_mode_t *)wldp_buf;
-	struct an_ltv_genconfig *actcfg_p;
-
-	actcfg_p = &pcan_p->an_actual_config;
-	if (pcan_cfg_ltv(PCAN_READ_LTV, pcan_p, actcfg_p)) {
-		err = EIO;
-		return (err);
-	}
-	powermode->wl_ps_mode = actcfg_p->an_psave_mode;
-
-	return (err);
-}
-
-/*
- * MAC_PROP_AUTH_MODE
- */
-static int
-pcan_set_authmode(pcan_maci_t *pcan_p, const void *wldp_buf)
-{
-	struct an_ltv_genconfig *cfg_p;
-	int err = ENETRESET;
-
-	cfg_p = &pcan_p->an_config;
-	if (*(wl_authmode_t *)wldp_buf == WL_OPENSYSTEM) {
-		cfg_p->an_authtype |= AN_AUTHTYPE_OPEN;
-		cfg_p->an_assoc_timeout = 5000;
-	} else {
-		err = EINVAL;
-	}
-
-	return (err);
-}
-
-static void
-pcan_get_authmode(pcan_maci_t *pcan_p, void *wldp_buf)
-{
-	struct an_ltv_genconfig *cfg_p;
-
-	cfg_p = &pcan_p->an_config;
-	if (cfg_p->an_authtype & AN_AUTHTYPE_SHAREDKEY) {
-		*(wl_bss_type_t *)wldp_buf = WL_SHAREDKEY;
-	} else {
-		*(wl_bss_type_t *)wldp_buf = WL_OPENSYSTEM;
-	}
-}
-
-/*
- * MAC_PROP_WL_ENCRYPTION
- */
-static int
-pcan_set_encrypt(pcan_maci_t *pcan_p, const void *wldp_buf)
-{
-	struct an_ltv_genconfig *cfg_p;
-
-	cfg_p = &pcan_p->an_config;
-	if (*(wl_encryption_t *)wldp_buf == WL_ENC_WEP) {
-		cfg_p->an_authtype |= (AN_AUTHTYPE_ENABLEWEP |
-		    AN_AUTHTYPE_ALLOW_UNENCRYPTED);
-		pcan_p->pcan_usewep = 1;
-	}
-	if (*(wl_authmode_t *)wldp_buf == WL_NOENCRYPTION) {
-		cfg_p->an_authtype &= (~(AN_AUTHTYPE_ENABLEWEP |
-		    AN_AUTHTYPE_ALLOW_UNENCRYPTED));
-		pcan_p->pcan_usewep = 0;
-	}
-	cfg_p->an_assoc_timeout = 5000;
-
-	return (ENETRESET);
-}
-
-static void
-pcan_get_encrypt(pcan_maci_t *pcan_p, void *wldp_buf)
-{
-	struct an_ltv_genconfig *cfg_p;
-
-	cfg_p = &pcan_p->an_config;
-	if (cfg_p->an_authtype & AN_AUTHTYPE_ENABLEWEP) {
-		*(wl_bss_type_t *)wldp_buf = WL_ENC_WEP;
-	} else {
-		*(wl_bss_type_t *)wldp_buf = WL_NOENCRYPTION;
-	}
-}
-
-/*
- * MAC_PROP_WL_KEY_TAB
- */
-static int
-pcan_set_wepkey(pcan_maci_t *pcan_p, const void *wldp_buf)
-{
-	uint16_t i;
-	wl_wep_key_t *p_wepkey_tab;
-	struct an_ltv_wepkey *wepkey_p;
-
-	p_wepkey_tab = (wl_wep_key_t *)wldp_buf;
-	for (i = 0; i < MAX_NWEPKEYS; i++) {
-		if (p_wepkey_tab[i].wl_wep_operation == WL_ADD) {
-			wepkey_p = &pcan_p->an_wepkey[i];
-			bzero(wepkey_p, sizeof (*wepkey_p));
-			wepkey_p->an_keylen =
-			    p_wepkey_tab[i].wl_wep_length;
-			bcopy(p_wepkey_tab[i].wl_wep_key,
-			    wepkey_p->an_key,
-			    p_wepkey_tab[i].wl_wep_length);
-			wepkey_p->an_index = i;
-			wepkey_p->an_macaddr[0] = 1;
-		}
-	}
-
-	return (ENETRESET);
-}
-
-/*
- * MAC_PROP_WL_RSSI
- */
-static int
-pcan_get_rssi(pcan_maci_t *pcan_p, void *wldp_buf)
-{
-	uint16_t val;
-	int err = 0;
-	wl_rssi_t *rssi = (wl_rssi_t *)wldp_buf;
-	struct an_ltv_status *status_p;
-
-	status_p = &pcan_p->an_status;
-
-	if (val = pcan_status_ltv(PCAN_READ_LTV, pcan_p, status_p)) {
-		err = EIO;
-		return (err);
-	}
-	val = status_p->an_cur_signal_quality;
-	PCANDBG((CE_NOTE, "pcan cfg_rssi: sl=%x", val));
-	/*
-	 * we reflect the value to 1-15 as rssi
-	 */
-	*rssi = 15 - ((val & 0xff) * 15 / 128 + 1);
-
-	return (err);
-}
-
-/*
- * MAC_PROP_WL_RADIO
- */
-static void
-pcan_get_radio(void *wldp_buf)
-{
-	wl_radio_t *radio = (wl_radio_t *)wldp_buf;
-
-	*radio = B_TRUE;
-}
-
-/*
- * MAC_PROP_WL_ESSLIST
- */
-static void
-pcan_get_esslist(pcan_maci_t *pcan_p, void *wldp_buf)
-{
-	uint16_t 	i;
-	wl_ess_conf_t 	*p_ess_conf;
-	an_scan_list_t 	*scan_item;
-
-	mutex_enter(&pcan_p->pcan_scanlist_lock);
-
-	((wl_ess_list_t *)wldp_buf)->wl_ess_list_num =
-	    pcan_p->an_scan_num;
-	scan_item = list_head(&pcan_p->an_scan_list);
-	for (i = 0; i < pcan_p->an_scan_num; i++) {
-		if (!scan_item)
-			break;
-		p_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf +
-		    offsetof(wl_ess_list_t, wl_ess_list_ess) +
-		    i * sizeof (wl_ess_conf_t));
-		bcopy(scan_item->an_val.an_ssid,
-		    p_ess_conf->wl_ess_conf_essid.wl_essid_essid,
-		    mi_strlen(scan_item->an_val.an_ssid));
-		bcopy(scan_item->an_val.an_bssid,
-		    p_ess_conf->wl_ess_conf_bssid, 6);
-		(p_ess_conf->wl_phy_conf).wl_phy_dsss_conf.wl_dsss_subtype
-		    = WL_DSSS;
-		p_ess_conf->wl_ess_conf_wepenabled =
-		    (scan_item->an_val.an_cap & 0x10 ?
-		    WL_ENC_WEP : WL_NOENCRYPTION);
-		p_ess_conf->wl_ess_conf_bsstype =
-		    (scan_item->an_val.an_cap & 0x1 ?
-		    WL_BSS_BSS : WL_BSS_IBSS);
-		p_ess_conf->wl_phy_conf.wl_phy_dsss_conf.wl_dsss_channel =
-		    scan_item->an_val.an_dschannel;
-		p_ess_conf->wl_ess_conf_sl = 15 -
-		    ((scan_item->an_val.an_rssi & 0xff) * 15 / 128);
-		p_ess_conf->wl_supported_rates[0] = WL_RATE_1M;
-		p_ess_conf->wl_supported_rates[1] = WL_RATE_2M;
-		p_ess_conf->wl_supported_rates[2] = WL_RATE_5_5M;
-		p_ess_conf->wl_supported_rates[3] = WL_RATE_11M;
-		scan_item = list_next(&pcan_p->an_scan_list, scan_item);
-	}
-
-	mutex_exit(&pcan_p->pcan_scanlist_lock);
-}
-
-/*
- * for wificonfig and dlamd ioctl
- */
-static int
-pcan_cfg_essid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	uint16_t 		i;
-	wldp_t			*infp;
-	wldp_t 			*outfp;
-	char 			*buf;
-	int 			iret;
-	int			err = 0;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCANDBG((CE_NOTE, "pcan cfg_essid: failed to alloc "
-		    "memory(%d)\n", MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-
-	if (cmd == WLAN_GET_PARAM) {
-		err = pcan_get_essid(pcan_p, outfp->wldp_buf);
-		if (err == EIO) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_HW_ERROR;
-			goto done;
-		}
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		(void) pcan_set_essid(pcan_p, infp->wldp_buf);
-		outfp->wldp_length = WIFI_BUF_OFFSET;
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-
-done:
-	for (i = 0; i < (outfp->wldp_length); i++) {
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	}
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-static int
-pcan_cfg_bssid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	uint16_t 	i;
-	wldp_t 		*infp;
-	wldp_t 		*outfp;
-	char 		*buf;
-	int 		iret;
-	int 		err = 0;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCANDBG((CE_NOTE, "pcan cfg_bssid: failed to alloc "
-		    "memory(%d)\n", MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-
-	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bssid_t);
-
-	if (cmd == WLAN_GET_PARAM) {
-		err = pcan_get_bssid(pcan_p, outfp->wldp_buf);
-		if (err == EIO) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_HW_ERROR;
-			goto done;
-		}
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		(void) pcan_set_bssid(pcan_p, infp->wldp_buf);
-		outfp->wldp_length = WIFI_BUF_OFFSET;
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-
-done:
-	for (i = 0; i < (outfp->wldp_length); i++) {
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	}
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-/*ARGSUSED*/
-static int
-pcan_cmd_scan(pcan_maci_t *pcan_p)
-{
-	uint16_t i = 0, j, ret = WL_SUCCESS;
-	uint8_t	bssid_t[6];
-	uint32_t check_num, enable;
-	an_scan_list_t *scan_item0;
-
-	enable = pcan_p->pcan_flag & PCAN_ENABLED;
-	if ((!enable) &&
-	    (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0))) {
-		ret = (int)WL_HW_ERROR;
-		goto exit;
-	}
-	if (ret = pcan_set_cmd(pcan_p, AN_CMD_SCAN, 0)) {
-		ret = (int)WL_HW_ERROR;
-		goto exit;
-	}
-
-	pcan_delay(pcan_p, 500000);
-	ret =  pcan_scanresult_ltv(PCAN_READ_LTV,
-	    pcan_p, AN_RID_ESSIDLIST_FIRST, &pcan_p->an_scanresult[i]);
-	if ((ret) || pcan_p->an_scanresult[i].an_index == 0xffff) {
-		goto done;
-	}
-	do
-	{
-		i++;
-		ret =  pcan_scanresult_ltv(PCAN_READ_LTV,
-		    pcan_p, AN_RID_ESSIDLIST_NEXT, &pcan_p->an_scanresult[i]);
-	} while ((!ret) && (i < 32) &&
-	    (pcan_p->an_scanresult[i].an_index != 0xffff));
-done:
-	if ((!enable) &&
-	    (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))) {
-		ret = (int)WL_HW_ERROR;
-		goto exit;
-	}
-	/* record the scan result for future use */
-	bzero(bssid_t, sizeof (bssid_t));
-	for (j = 0; j < i; j++) {
-		/*
-		 * sometimes, those empty items are recorded by hardware,
-		 * this is wrong, just ignore those items here.
-		 */
-		if (bcmp(pcan_p->an_scanresult[j].an_bssid,
-		    bssid_t, 6) == 0) {
-			continue;
-		}
-		/*
-		 * save/update the scan item in scanlist
-		 */
-		mutex_enter(&pcan_p->pcan_scanlist_lock);
-		check_num = 0;
-		scan_item0 = list_head(&pcan_p->an_scan_list);
-		if (scan_item0 == NULL) {
-			if (pcan_add_scan_item(pcan_p,
-			    pcan_p->an_scanresult[j]) != 0) {
-				mutex_exit(&pcan_p->pcan_scanlist_lock);
-				return (WL_SUCCESS);
-			}
-		}
-		for (; scan_item0; ) {
-			if (bcmp(pcan_p->an_scanresult[j].an_bssid,
-			    scan_item0->an_val.an_bssid, 6) == 0) {
-				scan_item0->an_val = pcan_p->an_scanresult[j];
-				scan_item0->an_timeout = AN_SCAN_TIMEOUT_MAX;
-				break;
-			} else {
-				check_num++;
-			}
-			scan_item0 = list_next(&pcan_p->an_scan_list,
-			    scan_item0);
-		}
-		if (check_num == pcan_p->an_scan_num) {
-			if (pcan_add_scan_item(pcan_p,
-			    pcan_p->an_scanresult[j]) != 0) {
-				mutex_exit(&pcan_p->pcan_scanlist_lock);
-				return (WL_SUCCESS);
-			}
-		}
-		mutex_exit(&pcan_p->pcan_scanlist_lock);
-	}
-exit:
-	if (ret)
-		cmn_err(CE_WARN, "pcan: scan failed due to hardware error");
-	return (ret);
-}
-
-/*ARGSUSED*/
-static int
-pcan_cfg_scan(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	wldp_t 		*outfp;
-	char 		*buf;
-	uint16_t 	i;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCANDBG((CE_NOTE, "pcan cfg_scanlist: failed to alloc "
-		    "memory(%d)\n", MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-
-	pcan_get_esslist(pcan_p, outfp->wldp_buf);
-
-	outfp->wldp_length = WIFI_BUF_OFFSET +
-	    offsetof(wl_ess_list_t, wl_ess_list_ess) +
-	    pcan_p->an_scan_num * sizeof (wl_ess_conf_t);
-	outfp->wldp_result = WL_SUCCESS;
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (WL_SUCCESS);
-}
-
-/*ARGSUSED*/
-static int
-pcan_cfg_linkstatus(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	wldp_t *outfp;
-	char *buf;
-	uint16_t i;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCANDBG((CE_NOTE, "pcan cfg_linkstatus: failed to alloc "
-		    "memory(%d)\n", MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-
-	pcan_get_linkstatus(pcan_p, outfp->wldp_buf);
-
-	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_linkstatus_t);
-	outfp->wldp_result = WL_SUCCESS;
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (WL_SUCCESS);
-}
-
-static int
-pcan_cfg_bsstype(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	uint16_t i;
-	wldp_t	*infp;
-	wldp_t *outfp;
-	char *buf;
-	int iret;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCANDBG((CE_NOTE, "pcan cfg_bsstype: failed to alloc "
-		    "memory(%d)\n", MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-
-	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bss_type_t);
-
-	if (cmd == WLAN_GET_PARAM) {
-		pcan_get_bsstype(pcan_p, outfp->wldp_buf);
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		(void) pcan_set_bsstype(pcan_p, infp->wldp_buf);
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-static int
-pcan_cfg_phy(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	uint16_t 	i;
-	wldp_t		*infp;
-	wldp_t 		*outfp;
-	char 		*buf;
-	int 		iret;
-	int 		err = 0;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCANDBG((CE_NOTE, "pcan cfg_phy: failed to alloc "
-		    "memory(%d)\n", MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-
-	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_dsss_t);
-
-	if (cmd == WLAN_GET_PARAM) {
-		err = pcan_get_phy(pcan_p, outfp->wldp_buf);
-		if (err == EIO) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_HW_ERROR;
-			goto done;
-		}
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		err = pcan_set_phy(pcan_p, infp->wldp_buf);
-		if (err == ENOTSUP) {
-			outfp->wldp_result = WL_NOTSUPPORTED;
-			goto done;
-		}
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-
-}
-
-/*ARGSUSED*/
-static int
-pcan_cfg_desiredrates(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	uint16_t 	i;
-	wldp_t		*infp;
-	wldp_t 		*outfp;
-	char 		*buf;
-	int 		iret;
-	int 		err = 0;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCANDBG((CE_NOTE, "pcan cfg_rates: failed to alloc "
-		    "memory(%d)\n", MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-
-	if (cmd == WLAN_GET_PARAM) {
-		err = pcan_get_desrates(pcan_p, outfp->wldp_buf);
-		if (err == EIO) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_HW_ERROR;
-			goto done;
-		}
-		outfp->wldp_length = WIFI_BUF_OFFSET +
-		    offsetof(wl_rates_t, wl_rates_rates) + sizeof (char);
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		(void) pcan_set_desrates(pcan_p, infp->wldp_buf);
-		outfp->wldp_length = WIFI_BUF_OFFSET;
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-/*ARGSUSED*/
-static int
-pcan_cfg_supportrates(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	uint16_t i;
-	int iret;
-	wldp_t *outfp;
-	char *buf;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCANDBG((CE_NOTE, "pcan cfg_supportedrates: failed to alloc "
-		    "memory(%d)\n", MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-
-	if (cmd == WLAN_GET_PARAM) {
-		pcan_get_suprates(outfp->wldp_buf);
-		outfp->wldp_length = WIFI_BUF_OFFSET +
-		    offsetof(wl_rates_t, wl_rates_rates) +
-		    4 * sizeof (char);
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-/*ARGSUSED*/
-static int
-pcan_cfg_powermode(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	uint16_t 	i;
-	wldp_t 		*outfp;
-	char 		*buf;
-	int 		iret;
-	int 		err = 0;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCANDBG((CE_NOTE, "pcan cfg_powermode: failed to alloc "
-		    "memory(%d)\n", MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-
-	if (cmd == WLAN_GET_PARAM) {
-		err = pcan_get_powermode(pcan_p, outfp->wldp_buf);
-		if (err == EIO) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_HW_ERROR;
-			goto done;
-		}
-		outfp->wldp_length = WIFI_BUF_OFFSET +
-		    sizeof (wl_ps_mode_t);
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		outfp->wldp_length = WIFI_BUF_OFFSET;
-		outfp->wldp_result = WL_LACK_FEATURE;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-
-}
-
-static int
-pcan_cfg_authmode(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	uint16_t i;
-	wldp_t *outfp;
-	char *buf;
-	int iret;
-	int err = 0;
-	struct an_ltv_genconfig *actcfg_p;
-
-	actcfg_p = &pcan_p->an_actual_config;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCANDBG((CE_NOTE, "pcan cfg_autymode: failed to alloc "
-		    "memory(%d)\n", MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-
-	if (cmd == WLAN_GET_PARAM) {
-		pcan_get_authmode(pcan_p, outfp->wldp_buf);
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		err = pcan_set_authmode(pcan_p, outfp->wldp_buf);
-		if (err == EINVAL) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_LACK_FEATURE;
-		} else {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_SUCCESS;
-		}
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-	PCANDBG((CE_NOTE, "pcan cfg_authmode: actual.authmode=%x",
-	    actcfg_p->an_authtype));
-	PCANDBG((CE_NOTE, "pcan cfg_authmode: actual.home_product=%x",
-	    actcfg_p->an_rsvd6[2]));
-
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-static int
-pcan_cfg_encryption(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	uint16_t i;
-	wldp_t *outfp;
-	char *buf;
-	int iret;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCANDBG((CE_NOTE, "pcan cfg_encryption: failed to alloc "
-		    "memory(%d)\n", MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-
-	if (cmd == WLAN_GET_PARAM) {
-		pcan_get_encrypt(pcan_p, outfp->wldp_buf);
-		outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_encryption_t);
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		(void) pcan_set_encrypt(pcan_p, outfp->wldp_buf);
-		outfp->wldp_length = WIFI_BUF_OFFSET;
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-static int
-pcan_cfg_wepkeyid(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	uint16_t i, ret;
-	wldp_t	*infp;
-	wldp_t *outfp;
-	char *buf;
-	int iret;
-	struct an_ltv_wepkey wepkey;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCANDBG((CE_NOTE, "pcan cfg_wepkeyid: failed to alloc "
-		    "memory(%d)\n", MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-
-	if (cmd == WLAN_GET_PARAM) {
-		outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_id_t);
-		outfp->wldp_result = WL_SUCCESS;
-		*(wl_wep_key_id_t *)(outfp->wldp_buf) = pcan_p->an_cur_wepkey;
-	} else if (cmd == WLAN_SET_PARAM) {
-		ret = (uint16_t)(*(wl_wep_key_id_t *)(infp->wldp_buf));
-		if (ret > 3) {
-			kmem_free(buf, MAX_BUF_LEN);
-			return (EINVAL);
-		}
-		wepkey.an_index = 0xffff;
-		wepkey.an_macaddr[0] = ret & 0xff;
-		pcan_p->an_cur_wepkey = ret;
-		outfp->wldp_length = WIFI_BUF_OFFSET;
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-/*ARGSUSED*/
-static int
-pcan_cfg_createibss(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	uint16_t i;
-	wldp_t *outfp;
-	char *buf;
-	int iret;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCANDBG((CE_NOTE, "pcan cfg_createibss: failed to alloc "
-		    "memory(%d)\n", MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-
-	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_create_ibss_t);
-	outfp->wldp_result = WL_LACK_FEATURE;
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-static int
-pcan_cfg_rssi(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	uint16_t 	i;
-	int		iret;
-	wldp_t 		*outfp;
-	char 		*buf;
-	int 		err = 0;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCANDBG((CE_NOTE, "pcan cfg_rssi: failed to alloc "
-		    "memory(%d)\n", MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-
-	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_rssi_t);
-
-	if (cmd == WLAN_GET_PARAM) {
-		err = pcan_get_rssi(pcan_p, outfp->wldp_buf);
-		if (err == EIO) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_HW_ERROR;
-			goto done;
-		}
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		outfp->wldp_result = WL_READONLY;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-/*ARGSUSED*/
-static int
-pcan_cfg_radio(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	uint16_t i;
-	int iret;
-	wldp_t *outfp;
-	char *buf;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCANDBG((CE_NOTE, "pcan cfg_radio: failed to alloc "
-		    "memory(%d)\n", MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-
-	if (cmd == WLAN_GET_PARAM) {
-		*(wl_radio_t *)(outfp->wldp_buf) = B_TRUE;
-		outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_radio_t);
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		outfp->wldp_length = WIFI_BUF_OFFSET;
-		outfp->wldp_result = WL_LACK_FEATURE;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-static int
-pcan_cfg_wepkey(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	uint16_t i;
-	wldp_t *outfp;
-	char *buf;
-	int iret;
-	wldp_t	*infp;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCANDBG((CE_NOTE, "pcan cfg_wep: failed to alloc "
-		    "memory(%d)\n", MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-
-	if (cmd == WLAN_GET_PARAM) {
-		outfp->wldp_length = WIFI_BUF_OFFSET +
-		    sizeof (wl_wep_key_tab_t);
-		outfp->wldp_result = WL_WRITEONLY;
-	} else if (cmd == WLAN_SET_PARAM) {
-		(void) pcan_set_wepkey(pcan_p, infp->wldp_buf);
-		outfp->wldp_length = WIFI_BUF_OFFSET;
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-static void
-pcan_connect_timeout(void *arg)
-{
-	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
-	uint16_t ret;
-
-	mutex_enter(&pcan_p->pcan_glock);
-	if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0))
-		goto done;
-	pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
-	if (ret = pcan_config_mac(pcan_p))
-		goto done;
-	ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0);
-done:
-	if (ret)
-		cmn_err(CE_WARN, "pcan: connect failed due to hardware error");
-	mutex_exit(&pcan_p->pcan_glock);
-	pcan_p->pcan_connect_timeout_id = 0;
-}
-
-static int
-pcan_getset(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd)
-{
-	int ret = WL_SUCCESS;
-	int connect = 0;
-
-	mutex_enter(&pcan_p->pcan_glock);
-	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
-		mutex_exit(&pcan_p->pcan_glock);
-		return (PCAN_FAIL);
-	}
-
-	switch (((wldp_t *)mp->b_rptr)->wldp_id) {
-	case WL_ESSID:
-		ret = pcan_cfg_essid(mp, pcan_p, cmd);
-		connect = 1;
-		PCANDBG((CE_NOTE, "cfg_essid\n"));
-		break;
-	case WL_BSSID:
-		ret = pcan_cfg_bssid(mp, pcan_p, cmd);
-		connect = 1;
-		PCANDBG((CE_NOTE, "cfg_bssid\n"));
-		break;
-	case WL_ESS_LIST:
-		ret = pcan_cfg_scan(mp, pcan_p, cmd);
-		PCANDBG((CE_NOTE, "cfg_scan\n"));
-		break;
-	case WL_LINKSTATUS:
-		ret = pcan_cfg_linkstatus(mp, pcan_p, cmd);
-		PCANDBG((CE_NOTE, "cfg_linkstatus\n"));
-		break;
-	case WL_BSS_TYPE:
-		ret = pcan_cfg_bsstype(mp, pcan_p, cmd);
-		connect = 1;
-		PCANDBG((CE_NOTE, "cfg_bsstype\n"));
-		break;
-	case WL_PHY_CONFIG:
-		ret = pcan_cfg_phy(mp, pcan_p, cmd);
-		connect = 1;
-		PCANDBG((CE_NOTE, "cfg_phy\n"));
-		break;
-	case WL_DESIRED_RATES:
-		ret = pcan_cfg_desiredrates(mp, pcan_p, cmd);
-		connect = 1;
-		PCANDBG((CE_NOTE, "cfg_disred-rates\n"));
-		break;
-	case WL_SUPPORTED_RATES:
-		ret = pcan_cfg_supportrates(mp, pcan_p, cmd);
-		PCANDBG((CE_NOTE, "cfg_supported-rates\n"));
-		break;
-	case WL_POWER_MODE:
-		ret = pcan_cfg_powermode(mp, pcan_p, cmd);
-		PCANDBG((CE_NOTE, "cfg_powermode\n"));
-		break;
-	case WL_AUTH_MODE:
-		ret = pcan_cfg_authmode(mp, pcan_p, cmd);
-		connect = 1;
-		PCANDBG((CE_NOTE, "cfg_authmode\n"));
-		break;
-	case WL_ENCRYPTION:
-		ret = pcan_cfg_encryption(mp, pcan_p, cmd);
-		connect = 1;
-		PCANDBG((CE_NOTE, "cfg_encryption\n"));
-		break;
-	case WL_WEP_KEY_ID:
-		ret = pcan_cfg_wepkeyid(mp, pcan_p, cmd);
-		connect = 1;
-		PCANDBG((CE_NOTE, "cfg_wepkeyid\n"));
-		break;
-	case WL_CREATE_IBSS:
-		ret = pcan_cfg_createibss(mp, pcan_p, cmd);
-		connect = 1;
-		PCANDBG((CE_NOTE, "cfg_create-ibss\n"));
-		break;
-	case WL_RSSI:
-		ret = pcan_cfg_rssi(mp, pcan_p, cmd);
-		PCANDBG((CE_NOTE, "cfg_rssi\n"));
-		break;
-	case WL_RADIO:
-		ret = pcan_cfg_radio(mp, pcan_p, cmd);
-		PCANDBG((CE_NOTE, "cfg_radio\n"));
-		break;
-	case WL_WEP_KEY_TAB:
-		ret = pcan_cfg_wepkey(mp, pcan_p, cmd);
-		connect = 1;
-		PCANDBG((CE_NOTE, "cfg_wepkey\n"));
-		break;
-	case WL_SCAN:
-		mutex_exit(&pcan_p->pcan_glock);
-		if (pcan_p->pcan_connect_timeout_id != 0) {
-			(void) untimeout(pcan_p->pcan_connect_timeout_id);
-			pcan_p->pcan_connect_timeout_id = 0;
-		}
-		mutex_enter(&pcan_p->pcan_glock);
-		if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
-			mutex_exit(&pcan_p->pcan_glock);
-			return (PCAN_FAIL);
-		}
-		ret = pcan_cmd_scan(pcan_p);
-		/*
-		 * a trick here.
-		 * since the scan doesn't return too many items due to hardware
-		 * reason, so the current scan result is an accumulation of
-		 * several scans. For the first time or after many of the items
-		 * aged, we scan again if too few items now in the scan table.
-		 */
-		if (pcan_p->an_scan_num < AN_SCAN_AGAIN_THRESHOLD)
-			ret = pcan_cmd_scan(pcan_p);
-		break;
-	case WL_LOAD_DEFAULTS:
-		if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		if (ret = pcan_loaddef(pcan_p)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		if (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		PCANDBG((CE_NOTE, "loaddef\n"));
-		break;
-	case WL_DISASSOCIATE:
-		mutex_exit(&pcan_p->pcan_glock);
-		if (pcan_p->pcan_connect_timeout_id != 0) {
-			(void) untimeout(pcan_p->pcan_connect_timeout_id);
-			pcan_p->pcan_connect_timeout_id = 0;
-		}
-		mutex_enter(&pcan_p->pcan_glock);
-		if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
-			mutex_exit(&pcan_p->pcan_glock);
-			return (PCAN_FAIL);
-		}
-		pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
-		if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		if (ret = pcan_loaddef(pcan_p)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		PCANDBG((CE_NOTE, "disassociate\n"));
-		break;
-	case WL_REASSOCIATE:
-	case WL_ASSOCIAT:
-		mutex_exit(&pcan_p->pcan_glock);
-		if (pcan_p->pcan_connect_timeout_id != 0) {
-			(void) untimeout(pcan_p->pcan_connect_timeout_id);
-			pcan_p->pcan_connect_timeout_id = 0;
-		}
-		mutex_enter(&pcan_p->pcan_glock);
-		if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
-			mutex_exit(&pcan_p->pcan_glock);
-			return (PCAN_FAIL);
-		}
-		if (ret = pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
-		if (ret = pcan_config_mac(pcan_p)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		if (ret = pcan_set_cmd(pcan_p, AN_CMD_ENABLE, 0)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		PCANDBG((CE_NOTE, "associate"));
-		break;
-
-	default:
-		break;
-	}
-	mutex_exit(&pcan_p->pcan_glock);
-	if ((cmd == WLAN_SET_PARAM) && (ret == WL_SUCCESS) && (connect)) {
-		pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
-		(void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
-		if (pcan_p->pcan_connect_timeout_id != 0) {
-			(void) untimeout(pcan_p->pcan_connect_timeout_id);
-			pcan_p->pcan_connect_timeout_id = 0;
-		}
-		pcan_p->pcan_connect_timeout_id = timeout(pcan_connect_timeout,
-		    pcan_p, drv_usectohz(1000000));
-	}
-	return (ret);
-}
-
-static void
-pcan_wlan_ioctl(pcan_maci_t *pcan_p, queue_t *wq, mblk_t *mp, uint32_t cmd)
-{
-
-	struct	iocblk	*iocp = (struct iocblk *)mp->b_rptr;
-	uint32_t len, ret;
-	mblk_t	*mp1;
-
-	/* sanity check */
-	if (iocp->ioc_count == 0 || !(mp1 = mp->b_cont)) {
-		miocnak(wq, mp, 0, EINVAL);
-		return;
-	}
-
-	/* assuming single data block */
-	if (mp1->b_cont) {
-		freemsg(mp1->b_cont);
-		mp1->b_cont = NULL;
-	}
-
-	/* we will overwrite everything */
-	mp1->b_wptr = mp1->b_rptr;
-
-	ret = pcan_getset(mp1, pcan_p, cmd);
-	len = msgdsize(mp1);
-	miocack(wq, mp, len, ret);
-}
-
-static void
-pcan_ioctl(void *arg, queue_t *wq, mblk_t *mp)
-{
-	struct iocblk *iocp;
-	uint32_t cmd, ret;
-	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
-	boolean_t need_privilege = B_TRUE;
-
-	iocp = (struct iocblk *)mp->b_rptr;
-	iocp->ioc_error = 0;
-	cmd = iocp->ioc_cmd;
-	switch (cmd) {
-	default:
-		miocnak(wq, mp, 0, EINVAL);
-		return;
-	case WLAN_GET_PARAM:
-		need_privilege = B_FALSE;
-		break;
-	case WLAN_SET_PARAM:
-	case WLAN_COMMAND:
-		break;
-	}
-
-	if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0)
-		miocnak(wq, mp, 0, ret);
-	else
-		pcan_wlan_ioctl(pcan_p, wq, mp, cmd);
-}
-/*
- * brussels
- */
-/* ARGSUSED */
-static int
-pcan_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
-    uint_t wldp_length, const void *wldp_buf)
-{
-	int 		err = 0;
-	pcan_maci_t 	*pcan_p = (pcan_maci_t *)arg;
-
-	mutex_enter(&pcan_p->pcan_glock);
-	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
-		mutex_exit(&pcan_p->pcan_glock);
-		err = EINVAL;
-		return (err);
-	}
-
-	switch (wldp_pr_num) {
-	/* mac_prop_id */
-	case MAC_PROP_WL_ESSID:
-		err = pcan_set_essid(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_BSSID:
-		err = pcan_set_bssid(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_PHY_CONFIG:
-		err = pcan_set_phy(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_KEY_TAB:
-		err = pcan_set_wepkey(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_AUTH_MODE:
-		err = pcan_set_authmode(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_ENCRYPTION:
-		err = pcan_set_encrypt(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_BSSTYPE:
-		err = pcan_set_bsstype(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_DESIRED_RATES:
-		err = pcan_set_desrates(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_POWER_MODE:
-	case MAC_PROP_WL_CREATE_IBSS:
-	case MAC_PROP_WL_RADIO:
-	case MAC_PROP_WL_WPA:
-	case MAC_PROP_WL_KEY:
-	case MAC_PROP_WL_DELKEY:
-	case MAC_PROP_WL_SETOPTIE:
-	case MAC_PROP_WL_MLME:
-	case MAC_PROP_WL_LINKSTATUS:
-	case MAC_PROP_WL_ESS_LIST:
-	case MAC_PROP_WL_SUPPORTED_RATES:
-	case MAC_PROP_WL_RSSI:
-	case MAC_PROP_WL_CAPABILITY:
-	case MAC_PROP_WL_SCANRESULTS:
-		cmn_err(CE_WARN, "pcan_setprop:"
-		    "opmode not support\n");
-		err = ENOTSUP;
-		break;
-	default:
-		cmn_err(CE_WARN, "pcan_setprop:"
-		    "opmode err\n");
-		err = EINVAL;
-		break;
-	}
-
-	mutex_exit(&pcan_p->pcan_glock);
-
-	if (err == ENETRESET) {
-		pcan_p->pcan_flag &= ~PCAN_CARD_LINKUP;
-		(void) pcan_set_cmd(pcan_p, AN_CMD_DISABLE, 0);
-		if (pcan_p->pcan_connect_timeout_id != 0) {
-			(void) untimeout(pcan_p->pcan_connect_timeout_id);
-			pcan_p->pcan_connect_timeout_id = 0;
-		}
-		pcan_p->pcan_connect_timeout_id = timeout(pcan_connect_timeout,
-		    pcan_p, drv_usectohz(1000000));
-
-		err = 0;
-	}
-
-	return (err);
-} /* ARGSUSED */
-
-/* ARGSUSED */
-static int
-pcan_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
-    uint_t wldp_length, void *wldp_buf)
-{
-	int err = 0;
-	pcan_maci_t *pcan_p = (pcan_maci_t *)arg;
-
-	mutex_enter(&pcan_p->pcan_glock);
-	if (!(pcan_p->pcan_flag & PCAN_CARD_READY)) {
-		mutex_exit(&pcan_p->pcan_glock);
-		err = EINVAL;
-		return (err);
-	}
-
-	switch (wldp_pr_num) {
-	/* mac_prop_id */
-	case MAC_PROP_WL_ESSID:
-		err = pcan_get_essid(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_BSSID:
-		err = pcan_get_bssid(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_PHY_CONFIG:
-		err = pcan_get_phy(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_AUTH_MODE:
-		pcan_get_authmode(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_ENCRYPTION:
-		pcan_get_encrypt(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_BSSTYPE:
-		pcan_get_bsstype(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_LINKSTATUS:
-		pcan_get_linkstatus(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_ESS_LIST:
-		pcan_get_esslist(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_SUPPORTED_RATES:
-		pcan_get_suprates(wldp_buf);
-		break;
-	case MAC_PROP_WL_RSSI:
-		err = pcan_get_rssi(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_RADIO:
-		pcan_get_radio(wldp_buf);
-		break;
-	case MAC_PROP_WL_POWER_MODE:
-		err = pcan_get_powermode(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_DESIRED_RATES:
-		err = pcan_get_desrates(pcan_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_CREATE_IBSS:
-	case MAC_PROP_WL_CAPABILITY:
-	case MAC_PROP_WL_WPA:
-	case MAC_PROP_WL_SCANRESULTS:
-	case MAC_PROP_WL_KEY_TAB:
-	case MAC_PROP_WL_KEY:
-	case MAC_PROP_WL_DELKEY:
-	case MAC_PROP_WL_SETOPTIE:
-	case MAC_PROP_WL_MLME:
-		cmn_err(CE_WARN, "pcan_getprop:"
-		    "opmode not support %x\n", wldp_pr_num);
-		err = ENOTSUP;
-		break;
-	default:
-		cmn_err(CE_WARN, "pcan_getprop:"
-		    "opmode err\n");
-		err = EINVAL;
-		break;
-	}
-
-	mutex_exit(&pcan_p->pcan_glock);
-
-	return (err);
-}
-
-static void
-pcan_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
-    mac_prop_info_handle_t mph)
-{
-	_NOTE(ARGUNUSED(arg, pr_name));
-
-	switch (wldp_pr_num) {
-	case MAC_PROP_WL_BSSTYPE:
-	case MAC_PROP_WL_ESS_LIST:
-	case MAC_PROP_WL_SUPPORTED_RATES:
-	case MAC_PROP_WL_RSSI:
-		mac_prop_info_set_perm(mph, MAC_PROP_PERM_READ);
-		break;
-	}
-}
-
-
-/*
- * quiesce(9E) entry point.
- *
- * This function is called when the system is single-threaded at high
- * PIL with preemption disabled. Therefore, this function must not be
- * blocked.
- *
- * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
- * DDI_FAILURE indicates an error condition and should almost never happen.
- */
-#ifndef __sparc
-static int
-pcan_quiesce(dev_info_t *dip)
-{
-	pcan_maci_t *pcan_p;
-
-	pcan_p = ddi_get_soft_state(pcan_soft_state_p, ddi_get_instance(dip));
-	if (pcan_p == NULL)
-		return (DDI_FAILURE);
-
-	if (pcan_p->pcan_flag & PCAN_CARD_READY)
-		pcan_stop_locked(pcan_p);
-
-	return (DDI_SUCCESS);
-}
-#endif
--- a/usr/src/uts/common/io/pcan/pcan.h	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1394 +0,0 @@
-/*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 1997, 1998, 1999
- *      Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *      This product includes software developed by Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * 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.
- */
-
-
-#ifndef _SYS_PCAN_H
-#define	_SYS_PCAN_H
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-#define	AN_TIMEOUT	600000
-
-/*
- * Size of Aironet I/O space.
- */
-#define	AN_IOSIZ		0x40
-
-#define	PCAN_DEVICE_PCI		0x100
-#define	PCAN_DEVICE_PCCARD	0x200
-
-/*
- * Hermes register definitions and what little I know about them.
- */
-
-/*
- * Hermes command/status registers.
- */
-#define	AN_COMMAND(p)	(p->pcan_device_type == PCAN_DEVICE_PCI ? 0x00 : 0x00)
-#define	AN_PARAM0(p)	(p->pcan_device_type == PCAN_DEVICE_PCI ? 0x04 : 0x02)
-#define	AN_PARAM1(p)	(p->pcan_device_type == PCAN_DEVICE_PCI ? 0x08 : 0x04)
-#define	AN_PARAM2(p)	(p->pcan_device_type == PCAN_DEVICE_PCI ? 0x0c : 0x06)
-#define	AN_STATUS(p)	(p->pcan_device_type == PCAN_DEVICE_PCI ? 0x10 : 0x08)
-#define	AN_RESP0(p)	(p->pcan_device_type == PCAN_DEVICE_PCI ? 0x14 : 0x0A)
-#define	AN_RESP1(p)	(p->pcan_device_type == PCAN_DEVICE_PCI ? 0x18 : 0x0C)
-#define	AN_RESP2(p)	(p->pcan_device_type == PCAN_DEVICE_PCI ? 0x1c : 0x0E)
-#define	AN_LINKSTAT(p)	(p->pcan_device_type == PCAN_DEVICE_PCI ? 0x20 : 0x10)
-
-/*
- * Command register
- */
-#define	AN_CMD_BUSY		0x8000 /* busy bit */
-#define	AN_CMD_NO_ACK		0x0080 /* don't acknowledge command */
-#define	AN_CMD_CODE_MASK	0x003F
-#define	AN_CMD_QUAL_MASK	0x7F00
-
-/*
- * Command codes
- */
-#define	AN_CMD_NOOP		0x0000 /* no-op */
-#define	AN_CMD_ENABLE		0x0001 /* enable */
-#define	AN_CMD_DISABLE		0x0002 /* disable */
-#define	AN_CMD_FORCE_SYNCLOSS	0x0003 /* force loss of sync */
-#define	AN_CMD_FW_RESTART	0x0004 /* firmware resrart */
-#define	AN_CMD_HOST_SLEEP	0x0005
-#define	AN_CMD_MAGIC_PKT	0x0006
-#define	AN_CMD_READCFG		0x0008
-#define	AN_CMD_ALLOC_MEM	0x000A /* allocate NIC memory */
-#define	AN_CMD_TX		0x000B /* transmit */
-#define	AN_CMD_DEALLOC_MEM	0x000C
-#define	AN_CMD_NOOP2		0x0010
-#define	AN_CMD_ALLOC_DESC	0x0020
-#define	AN_CMD_ACCESS		0x0021
-#define	AN_CMD_ALLOC_BUF	0x0028
-#define	AN_CMD_PSP_NODES	0x0030
-#define	AN_CMD_SET_PHYREG	0x003E
-#define	AN_CMD_TX_TEST		0x003F
-#define	AN_CMD_SLEEP		0x0085
-#define	AN_CMD_SCAN		0x0103
-#define	AN_CMD_SAVECFG		0x0108
-
-/*
- * Reclaim qualifier bit, applicable to the
- * TX command.
- */
-#define	AN_RECLAIM		0x0100 /* reclaim NIC memory */
-
-/*
- * MPI 350 DMA descriptor information
- */
-#define	AN_DESCRIPTOR_TX	0x01
-#define	AN_DESCRIPTOR_RX	0x02
-#define	AN_DESCRIPTOR_TXCMP	0x04
-#define	AN_DESCRIPTOR_HOSTWRITE 0x08
-#define	AN_DESCRIPTOR_HOSTREAD  0x10
-#define	AN_DESCRIPTOR_HOSTRW    0x20
-
-#define	AN_MAX_RX_DESC 1
-#define	AN_MAX_TX_DESC 1
-#define	AN_HOSTBUFSIZ 1840
-
-/*
- * dma descriptor definition for miniPci card.
- * the miniPci card only works on x86.
- */
-struct an_card_rid_desc
-{
-	uint32_t	an_rid:16;
-	uint32_t	an_len:15;
-	uint32_t	an_valid:1;
-	uint64_t	an_phys;
-};
-
-struct an_card_rx_desc
-{
-	uint32_t	an_ctrl:15;
-	uint32_t	an_done:1;
-	uint32_t	an_len:15;
-	uint32_t	an_valid:1;
-	uint64_t	an_phys;
-};
-
-struct an_card_tx_desc
-{
-	uint32_t	an_offset:15;
-	uint32_t	an_eoc:1;
-	uint32_t	an_len:15;
-	uint32_t	an_valid:1;
-	uint64_t	an_phys;
-};
-
-#define	AN_MAX_DATALEN	4096
-#define	AN_RID_BUFFER_SIZE	AN_MAX_DATALEN
-#define	AN_RX_BUFFER_SIZE	AN_HOSTBUFSIZ
-#define	AN_TX_BUFFER_SIZE	AN_HOSTBUFSIZ
-#define	AN_HOST_DESC_OFFSET	0x800
-#define	AN_RX_DESC_OFFSET  (AN_HOST_DESC_OFFSET + \
-    sizeof (struct an_card_rid_desc))
-#define	AN_TX_DESC_OFFSET (AN_RX_DESC_OFFSET + \
-	(AN_MAX_RX_DESC * sizeof (struct an_card_rx_desc)))
-
-/*
- * ACCESS command qualifier bits.
- */
-#define	AN_ACCESS_READ		0x0000
-#define	AN_ACCESS_WRITE		0x0100
-
-/*
- * PROGRAM command qualifier bits.
- */
-#define	AN_PROGRAM_DISABLE	0x0000
-#define	AN_PROGRAM_ENABLE_RAM	0x0100
-#define	AN_PROGRAM_ENABLE_NVRAM	0x0200
-#define	AN_PROGRAM_NVRAM	0x0300
-
-/*
- * Status register values
- */
-#define	AN_STAT_CMD_CODE	0x003F
-#define	AN_STAT_CMD_RESULT	0x7F00
-
-/*
- * Linkstat register
- */
-#define	AN_LINKSTAT_ASSOCIATED		0x0400
-#define	AN_LINKSTAT_AUTHFAIL		0x0300
-#define	AN_LINKSTAT_ASSOC_FAIL		0x8400	/* (low byte is reason code) */
-#define	AN_LINKSTAT_DISASSOC		0x8200	/* (low byte is reason code) */
-#define	AN_LINKSTAT_DEAUTH		0x8100	/* (low byte is reason code) */
-#define	AN_LINKSTAT_SYNCLOST_TSF	0x8004
-#define	AN_LINKSTAT_SYNCLOST_HOSTREQ	0x8003
-#define	AN_LINKSTAT_SYNCLOST_AVGRETRY	0x8002
-#define	AN_LINKSTAT_SYNCLOST_MAXRETRY	0x8001
-#define	AN_LINKSTAT_SYNCLOST_MISSBEACON	0x8000
-
-/*
- * Link stat low byte reason code
- */
-#define	AN_LINKSTAT_RC_RESERVED		0 /* Reserved return code */
-#define	AN_LINKSTAT_RC_NOREASON		1 /* Unspecified reason */
-#define	AN_LINKSTAT_RC_AUTHINV		2 /* Prev auth invalid */
-#define	AN_LINKSTAT_RC_DEAUTH		3 /* Deauth due sender leaving */
-#define	AN_LINKSTAT_RC_NOACT		4 /* Disassociated due inactivity */
-#define	AN_LINKSTAT_RC_MAXLOAD		5 /* Disassociated due 2many stations */
-/*
- * Class 2 frame received from non-Authenticated station
- */
-#define	AN_LINKSTAT_RC_BADCLASS2	6
-/*
- * Class 3 frame received from non-Associated station
- */
-#define	AN_LINKSTAT_RC_BADCLASS3	7
-/*
- * Disassociated because sending station is leaving BSS
- */
-#define	AN_LINKSTAT_RC_STATLEAVE	8
-/*
- * Station requesting (Re)Association not Authenticated w/responding station
- */
-#define	AN_LINKSTAT_RC_NOAUTH		9
-
-/*
- * memory handle management registers
- */
-#define	AN_RX_FID		0x20
-#define	AN_ALLOC_FID		0x22
-#define	AN_TX_CMP_FID(p) \
-	(p->pcan_device_type == PCAN_DEVICE_PCI ? 0x1a : 0x24)
-
-#define	AN_INVALID_FID		0xffff  /* invalid fid value */
-
-/*
- * Buffer Access Path (BAP) registers.
- * These are I/O channels. I believe you can use each one for
- * any desired purpose independently of the other. In general
- * though, we use BAP1 for reading and writing LTV records and
- * reading received data frames, and BAP0 for writing transmit
- * frames. This is a convention though, not a rule.
- */
-#define	AN_SEL0			0x18
-#define	AN_SEL1			0x1A
-#define	AN_OFF0			0x1C
-#define	AN_OFF1			0x1E
-#define	AN_DATA0		0x36
-#define	AN_DATA1		0x38
-#define	AN_BAP0			AN_DATA0
-#define	AN_BAP1			AN_DATA1
-
-#define	AN_OFF_BUSY		0x8000
-#define	AN_OFF_ERR		0x4000
-#define	AN_OFF_DONE		0x2000
-#define	AN_OFF_DATAOFF		0x0FFF
-
-/*
- * Event registers
- */
-#define	AN_EVENT_STAT(p) (p->pcan_device_type == PCAN_DEVICE_PCI ? 0x60 : 0x30)
-/*
- * Interrupt enable/disable
- */
-#define	AN_INT_EN(p) (p->pcan_device_type == PCAN_DEVICE_PCI ? 0x64 : 0x32)
-#define	AN_EVENT_ACK(p)	(p->pcan_device_type == PCAN_DEVICE_PCI ? 0x68 : 0x34)
-
-/*
- * Events - AN_EVENT_ACK register only
- */
-#define	AN_EV_CLR_STUCK_BUSY	0x4000	/* clear stuck busy bit */
-#define	AN_EV_WAKEREQUEST	0x2000	/* awaken from PSP mode */
-					/* Events shared by all 3 event regs: */
-#define	AN_EV_MIC		0x1000	/* Message Integrity Check */
-#define	AN_EV_AWAKE		0x0100	/* station woke up from PSP mode */
-#define	AN_EV_LINKSTAT		0x0080	/* link status available */
-#define	AN_EV_CMD		0x0010	/* command completed */
-#define	AN_EV_ALLOC		0x0008	/* async alloc/reclaim completed */
-#define	AN_EV_TX_EXC		0x0004	/* async xmit completed with failure */
-#define	AN_EV_TX		0x0002	/* async xmit completed succesfully */
-#define	AN_EV_RX		0x0001	/* async rx completed */
-#define	AN_EV_TX_CPY		0x0400
-
-#define	AN_EV_ALL		0xffff	/* all events */
-#define	AN_INTRS(p) \
-	(p->pcan_device_type == PCAN_DEVICE_PCI ? \
-	(AN_EV_RX|AN_EV_TX|AN_EV_TX_EXC|AN_EV_ALLOC|AN_EV_LINKSTAT|AN_EV_MIC \
-	|AN_EV_TX_CPY) : \
-	(AN_EV_RX|AN_EV_TX|AN_EV_TX_EXC|AN_EV_ALLOC|AN_EV_LINKSTAT|AN_EV_MIC))
-
-/*
- * Host software registers
- */
-#define	AN_SW0(p)	(p->pcan_device_type == PCAN_DEVICE_PCI ? 0x50 : 0x28)
-#define	AN_SW1(p)	(p->pcan_device_type == PCAN_DEVICE_PCI ? 0x54 : 0x2A)
-#define	AN_SW2(p)	(p->pcan_device_type == PCAN_DEVICE_PCI ? 0x58 : 0x2C)
-#define	AN_SW3(p)	(p->pcan_device_type == PCAN_DEVICE_PCI ? 0x5c : 0x2E)
-
-#define	AN_CNTL			0x14
-
-#define	AN_CNTL_AUX_ENA		0xC000
-#define	AN_CNTL_AUX_ENA_STAT	0xC000
-#define	AN_CNTL_AUX_DIS_STAT	0x0000
-#define	AN_CNTL_AUX_ENA_CNTL	0x8000
-#define	AN_CNTL_AUX_DIS_CNTL	0x4000
-
-#define	AN_AUX_PAGE		0x3A
-#define	AN_AUX_OFFSET		0x3C
-#define	AN_AUX_DATA		0x3E
-
-struct an_ltv_gen {
-	uint16_t	an_len;
-	uint16_t	an_type;
-	uint16_t	an_val;
-};
-
-/*
- * General configuration information.
- */
-#define	AN_RID_GENCONFIG	0xFF10
-struct an_ltv_genconfig {
-	uint16_t	an_len;			/* 0x00 */
-	uint16_t	an_opmode;		/* 0x02 */
-	uint16_t	an_rxmode;		/* 0x04 */
-	uint16_t	an_fragthresh;		/* 0x06 */
-	uint16_t	an_rtsthresh;		/* 0x08 */
-	uint8_t		an_macaddr[6];		/* 0x0A */
-	uint8_t		an_rates[8];		/* 0x10 */
-	uint16_t	an_shortretry_limit;	/* 0x18 */
-	uint16_t	an_longretry_limit;	/* 0x1A */
-	uint16_t	an_tx_msdu_lifetime;	/* 0x1C */
-	uint16_t	an_rx_msdu_lifetime;	/* 0x1E */
-	uint16_t	an_stationary;		/* 0x20 */
-	uint16_t	an_ordering;		/* 0x22 */
-	uint16_t	an_devtype;		/* 0x24 */
-	uint16_t	an_rsvd0[5];		/* 0x26 */
-	/*
-	 * Scanning associating.
-	 */
-	uint16_t	an_scanmode;		/* 0x30 */
-	uint16_t	an_probedelay;		/* 0x32 */
-	uint16_t	an_probe_energy_timeout; /* 0x34 */
-	uint16_t	an_probe_response_timeout; /* 0x36 */
-	uint16_t	an_beacon_listen_timeout; /* 0x38 */
-	uint16_t	an_ibss_join_net_timeout; /* 0x3A */
-	uint16_t	an_auth_timeout;	/* 0x3C */
-	uint16_t	an_authtype;		/* 0x3E */
-	uint16_t	an_assoc_timeout;	/* 0x40 */
-	uint16_t	an_specified_ap_timeout; /* 0x42 */
-	uint16_t	an_offline_scan_interval; /* 0x44 */
-	uint16_t	an_offline_scan_duration; /* 0x46 */
-	uint16_t	an_link_loss_delay;	/* 0x48 */
-	uint16_t	an_max_beacon_lost_time; /* 0x4A */
-	uint16_t	an_refresh_interval;	/* 0x4C */
-	uint16_t	an_rsvd1;		/* 0x4E */
-	/*
-	 * Power save operation
-	 */
-	uint16_t	an_psave_mode;		/* 0x50 */
-	uint16_t	an_sleep_for_dtims;	/* 0x52 */
-	uint16_t	an_listen_interval;	/* 0x54 */
-	uint16_t	an_fast_listen_interval; /* 0x56 */
-	uint16_t	an_listen_decay;	/* 0x58 */
-	uint16_t	an_fast_listen_decay;	/* 0x5A */
-	uint16_t	an_rsvd2[2];		/* 0x5C */
-	/*
-	 * Ad-hoc (or AP) operation.
-	 */
-	uint16_t	an_beacon_period;	/* 0x60 */
-	uint16_t	an_atim_duration;	/* 0x62 */
-	uint16_t	an_rsvd3;		/* 0x64 */
-	uint16_t	an_ds_channel;		/* 0x66 */
-	uint16_t	an_rsvd4;		/* 0x68 */
-	uint16_t	an_dtim_period;		/* 0x6A */
-	uint16_t	an_rsvd5[2];		/* 0x6C */
-	/*
-	 * Radio operation.
-	 */
-	uint16_t	an_radiotype;		/* 0x70 */
-	uint16_t	an_diversity;		/* 0x72 */
-	uint16_t	an_tx_power;		/* 0x74 */
-	uint16_t	an_rss_thresh;		/* 0x76 */
-	uint16_t	an_rsvd6[4];		/* 0x78 */
-	/*
-	 * Aironet extensions.
-	 */
-	uint8_t		an_nodename[16];	/* 0x80 */
-	uint16_t	an_arl_thresh;		/* 0x90 */
-	uint16_t	an_arl_decay;		/* 0x92 */
-	uint16_t	an_arl_delay;		/* 0x94 */
-	uint8_t		an_rsvd7;		/* 0x96 */
-	uint8_t		an_rsvd8;		/* 0x97 */
-	uint8_t		an_magic_packet_action;	/* 0x98 */
-	uint8_t		an_magic_packet_ctl;	/* 0x99 */
-	uint16_t	an_auto_wake;		/* 0x9A */
-	uint16_t	an_pad[20];
-};
-
-#define	AN_OPMODE_IBSS_ADHOC			0x0000
-#define	AN_OPMODE_INFR_STATION			0x0001
-#define	AN_OPMODE_AP				0x0002
-#define	AN_OPMODE_AP_REPEATER			0x0003
-#define	AN_OPMODE_UNMODIFIED_PAYLOAD		0x0100
-#define	AN_OPMODE_AIRONET_EXTENSIONS		0x0200
-#define	AN_OPMODE_AP_EXTENSIONS			0x0400
-
-#define	AN_RXMODE_BC_MC_ADDR			0x0000
-#define	AN_RXMODE_BC_ADDR			0x0001
-#define	AN_RXMODE_ADDR				0x0002
-#define	AN_RXMODE_80211_MONITOR_CURBSS		0x0003
-#define	AN_RXMODE_80211_MONITOR_ANYBSS		0x0004
-#define	AN_RXMODE_LAN_MONITOR_CURBSS		0x0005
-#define	AN_RXMODE_NO_8023_HEADER		0x0100
-#define	AN_RXMODE_USE_8023_HEADER		0x0000
-
-#define	AN_RATE_1MBPS				0x0002
-#define	AN_RATE_2MBPS				0x0004
-#define	AN_RATE_5_5MBPS				0x000B
-#define	AN_RATE_11MBPS				0x0016
-
-#define	AN_DEVTYPE_PC4500			0x0065
-#define	AN_DEVTYPE_PC4800			0x006D
-
-#define	AN_SCANMODE_ACTIVE			0x0000
-#define	AN_SCANMODE_PASSIVE			0x0001
-#define	AN_SCANMODE_AIRONET_ACTIVE		0x0002
-
-#define	AN_AUTHTYPE_NONE			0x0000
-#define	AN_AUTHTYPE_OPEN			0x0001
-#define	AN_AUTHTYPE_SHAREDKEY			0x0002
-#define	AN_AUTHTYPE_EXCLUDE_UNENCRYPTED		0x0004
-#define	AN_AUTHTYPE_ENABLEWEP			0x0100
-#define	AN_AUTHTYPE_ALLOW_UNENCRYPTED		0x0200
-
-#define	AN_PSAVE_NONE				0x0000
-#define	AN_PSAVE_CAM				0x0001
-#define	AN_PSAVE_PSP				0x0002
-#define	AN_PSAVE_PSP_CAM			0x0003
-
-#define	AN_RADIOTYPE_80211_FH			0x0001
-#define	AN_RADIOTYPE_80211_DS			0x0002
-#define	AN_RADIOTYPE_LM2000_DS			0x0004
-
-#define	AN_DIVERSITY_FACTORY_DEFAULT		0x0000
-#define	AN_DIVERSITY_ANTENNA_1_ONLY		0x0001
-#define	AN_DIVERSITY_ANTENNA_2_ONLY		0x0002
-#define	AN_DIVERSITY_ANTENNA_1_AND_2		0x0003
-
-#define	AN_TXPOWER_FACTORY_DEFAULT		0x0000
-#define	AN_TXPOWER_50MW				50
-#define	AN_TXPOWER_100MW			100
-#define	AN_TXPOWER_250MW			250
-
-/*
- * Valid SSID list. You can specify up to three SSIDs denoting
- * the service sets that you want to join. The first SSID always
- * defaults to "tsunami" which is a handy way to detect the
- * card.
- */
-#define	AN_RID_SSIDLIST		0xFF11
-struct an_ltv_ssidlist {
-	uint16_t		an_len;
-	uint16_t		an_ssid1_len;
-	char			an_ssid1[32];
-	uint16_t		an_ssid2_len;
-	char			an_ssid2[32];
-	uint16_t		an_ssid3_len;
-	char			an_ssid3[32];
-	uint8_t			an_pad[748];
-};
-
-#define	AN_DEF_SSID_LEN		7
-#define	AN_DEF_SSID		"tsunami"
-
-/*
- * Valid AP list.
- */
-#define	AN_RID_APLIST		0xFF12
-struct an_ltv_aplist {
-	uint16_t	an_len;
-	uint8_t		an_ap1[6];
-	uint8_t		an_ap2[6];
-	uint8_t		an_ap3[6];
-	uint8_t		an_ap4[6];
-};
-
-/*
- * Driver name.
- */
-#define	AN_RID_DRVNAME		0xFF13
-struct an_ltv_drvname {
-	uint16_t	an_len;
-	uint8_t		an_drvname[16];
-};
-
-/*
- * Frame encapsulation.
- */
-#define	AN_RID_ENCAP		0xFF14
-struct an_rid_encap {
-	uint16_t		an_len;
-	uint16_t		an_ethertype_default;
-	uint16_t		an_action_default;
-	uint16_t		an_ethertype0;
-	uint16_t		an_action0;
-	uint16_t		an_ethertype1;
-	uint16_t		an_action1;
-	uint16_t		an_ethertype2;
-	uint16_t		an_action2;
-	uint16_t		an_ethertype3;
-	uint16_t		an_action3;
-	uint16_t		an_ethertype4;
-	uint16_t		an_action4;
-	uint16_t		an_ethertype5;
-	uint16_t		an_action5;
-	uint16_t		an_ethertype6;
-	uint16_t		an_action6;
-};
-
-#define	AN_ENCAP_ACTION_RX	0x0001
-#define	AN_ENCAP_ACTION_TX	0x0002
-
-#define	AN_RXENCAP_NONE		0x0000
-#define	AN_RXENCAP_RFC1024	0x0001
-
-#define	AN_TXENCAP_RFC1024	0x0000
-#define	AN_TXENCAP_80211	0x0002
-
-#define	AN_RID_WEPKEY		0xFF15
-#define	AN_RID_WEPKEY2		0xFF16
-struct an_ltv_wepkey {
-	uint16_t	an_len;
-	uint16_t	an_index;
-	uint8_t		an_macaddr[6];
-	uint16_t	an_keylen;	/* WEP40: 5, WEP128: 13 bytes */
-	uint8_t		an_key[16];	/* key value */
-};
-
-#define	AN_RID_CRYPT		0xFF18
-struct an_ltv_crypt {
-	uint16_t	an_operation;		/* 0: enable  1: disable */
-	uint8_t		an_optionmask[2];	/* 1: WEP40   2: WEP128 */
-	uint8_t		an_filler[8];		/* put struct 6 bytes longer */
-};
-
-/*
- * Actual config, same structure as general config (read only).
- */
-#define	AN_RID_ACTUALCFG	0xFF20
-
-/*
- * Card capabilities (read only).
- */
-#define	AN_RID_CAPABILITIES	0xFF00
-struct an_ltv_caps {
-	uint16_t	an_len;
-	uint8_t		an_oui[3];		/* 0x02 */
-	uint8_t		an_pad0;		/* 0x05 */
-	uint16_t	an_prodnum;		/* 0x06 */
-	uint8_t		an_manufname[32];	/* 0x08 */
-	uint8_t		an_prodname[16];	/* 0x28 */
-	uint8_t		an_prodvers[8];		/* 0x38 */
-	uint8_t		an_oemaddr[6];		/* 0x40 */
-	uint8_t		an_aironetaddr[6];	/* 0x46 */
-	uint16_t	an_radiotype;		/* 0x4C */
-	uint16_t	an_country;		/* 0x4E */
-	uint8_t		an_callid[6];		/* 0x50 */
-	uint8_t		an_supported_rates[8];	/* 0x56 */
-	uint8_t		an_rx_diversity;	/* 0x5E */
-	uint8_t		an_tx_diversity;	/* 0x5F */
-	uint16_t	an_tx_powerlevels[8];	/* 0x60 */
-	uint16_t	an_hwver;		/* 0x70 */
-	uint16_t	an_hwcaps;		/* 0x72 */
-	uint16_t	an_temprange;		/* 0x74 */
-	uint16_t	an_fwrev;		/* 0x76 */
-	uint16_t	an_fwsubrev;		/* 0x78 */
-	uint16_t	an_interfacerev;	/* 0x7A */
-	uint16_t	an_softcap;		/* 0x7C */
-	uint16_t	an_bootblockrev;	/* 0x7E */
-	uint16_t	an_requiredhw;		/* 0x80 */
-	uint16_t	an_pad;
-};
-
-/*
- * Access point (read only)
- */
-#define	AN_RID_APINFO		0xFF01
-struct an_ltv_apinfo {
-	uint16_t		an_len;
-	uint16_t		an_tim_addr;
-	uint16_t		an_airo_addr;
-};
-
-/*
- * Radio info (read only).
- */
-#define	AN_RID_RADIOINFO	0xFF02
-struct an_ltv_radioinfo {
-	uint16_t		an_len;
-	/*
-	 * some more fields here, waiting for freebsd code update.
-	 */
-};
-
-/*
- * Status (read only). Note: the manual claims this RID is 108 bytes
- * long (0x6A is the last datum, which is 2 bytes long) however when
- * this RID is read from the NIC, it returns a length of 110. To be
- * on the safe side, this structure is padded with an extra 16-bit
- * word. (There is a misprint in the manual which says the macaddr
- * field is 8 bytes long.)
- *
- * Also, the channel_set and current_channel fields appear to be
- * reversed. Either that, or the hop_period field is unused.
- */
-#define	AN_RID_STATUS		0xFF50
-struct an_ltv_status {
-	uint16_t	an_len;
-	uint8_t		an_macaddr[6];		/* 0x02 */
-	uint16_t	an_opmode;		/* 0x08 */
-	uint16_t	an_errcode;		/* 0x0A */
-	uint16_t	an_cur_signal_quality;	/* 0x0C */
-	uint16_t	an_ssidlen;		/* 0x0E */
-	uint8_t		an_ssid[32];		/* 0x10 */
-	uint8_t		an_ap_name[16];		/* 0x30 */
-	uint8_t		an_cur_bssid[6];	/* 0x40 */
-	uint8_t		an_prev_bssid1[6];	/* 0x46 */
-	uint8_t		an_prev_bssid2[6];	/* 0x4C */
-	uint8_t		an_prev_bssid3[6];	/* 0x52 */
-	uint16_t	an_beacon_period;	/* 0x58 */
-	uint16_t	an_dtim_period;		/* 0x5A */
-	uint16_t	an_atim_duration;	/* 0x5C */
-	uint16_t	an_hop_period;		/* 0x5E */
-	uint16_t	an_channel_set;		/* 0x60 */
-	uint16_t	an_cur_channel;		/* 0x62 */
-	uint16_t	an_hops_to_backbone;	/* 0x64 */
-	uint16_t	an_ap_total_load;	/* 0x66 */
-	uint16_t	an_our_generated_load;	/* 0x68 */
-	uint16_t	an_accumulated_arl;	/* 0x6A */
-	uint16_t	an_signale_quality;	/* 0x6C */
-	uint16_t	an_cur_tx_rate;		/* 0x6E */
-	uint16_t	an_ap_device;		/* 0x70 */
-	uint16_t	an_normallized_rssi;	/* 0x72 */
-	uint16_t	an_short_preamble;	/* 0x74 */
-	uint8_t		an_ap_ip_address[4];	/* 0x76 */
-	uint8_t		an_noise_pct;		/* 0x7A */
-	uint8_t		an_noise_dbm;		/* 0x7B */
-	uint8_t		an_noise_average_pct;	/* 0x7C */
-	uint8_t		an_noise_average_dbm;	/* 0x7D */
-	uint8_t		an_noise_max_pct;	/* 0x7E */
-	uint8_t		an_noise_max_dbm;	/* 0x7F */
-	uint16_t	an_load;		/* 0x80 */
-	uint8_t		an_carrier[4];		/* 0x82 */
-	uint16_t	an_assoc_status;	/* 0x86 */
-	uint16_t	an_pad;
-};
-
-#define	AN_STATUS_OPMODE_CONFIGURED		0x0001
-#define	AN_STATUS_OPMODE_MAC_ENABLED		0x0002
-#define	AN_STATUS_OPMODE_RX_ENABLED		0x0004
-#define	AN_STATUS_OPMODE_IN_SYNC		0x0010
-#define	AN_STATUS_OPMODE_ASSOCIATED		0x0020
-#define	AN_STATUS_OPMODE_ERROR			0x8000
-
-
-/*
- * Statistics
- */
-#define	AN_RID_16BITS_CUM	0xFF60	/* Cumulative 16-bit stats counters */
-#define	AN_RID_16BITS_DELTA	0xFF61	/* 16-bit stats (since last clear) */
-#define	AN_RID_16BITS_DELTACLR	0xFF62	/* 16-bit stats, clear on read */
-#define	AN_RID_32BITS_CUM	0xFF68	/* Cumulative 32-bit stats counters */
-#define	AN_RID_32BITS_DELTA	0xFF69	/* 32-bit stats (since last clear) */
-#define	AN_RID_32BITS_DELTACLR	0xFF6A	/* 32-bit stats, clear on read */
-
-/*
- * Grrr. The manual says the statistics record is 384 bytes in length,
- * but the card says the record is 404 bytes. There's some padding left
- * at the end of this structure to account for any discrepancies.
- */
-struct an_ltv_stats {
-	uint16_t		an_len;
-	uint16_t		an_rx_overruns;		/* 0x02 */
-	uint16_t		an_rx_plcp_csum_errs;	/* 0x04 */
-	uint16_t		an_rx_plcp_format_errs;	/* 0x06 */
-	uint16_t		an_rx_plcp_len_errs;	/* 0x08 */
-	uint16_t		an_rx_mac_crc_errs;	/* 0x0A */
-	uint16_t		an_rx_mac_crc_ok;	/* 0x0C */
-	uint16_t		an_rx_wep_errs;		/* 0x0E */
-	uint16_t		an_rx_wep_ok;		/* 0x10 */
-	uint16_t		an_retry_long;		/* 0x12 */
-	uint16_t		an_retry_short;		/* 0x14 */
-	uint16_t		an_retry_max;		/* 0x16 */
-	uint16_t		an_no_ack;		/* 0x18 */
-	uint16_t		an_no_cts;		/* 0x1A */
-	uint16_t		an_rx_ack_ok;		/* 0x1C */
-	uint16_t		an_rx_cts_ok;		/* 0x1E */
-	uint16_t		an_tx_ack_ok;		/* 0x20 */
-	uint16_t		an_tx_rts_ok;		/* 0x22 */
-	uint16_t		an_tx_cts_ok;		/* 0x24 */
-	uint16_t		an_tx_lmac_mcasts;	/* 0x26 */
-	uint16_t		an_tx_lmac_bcasts;	/* 0x28 */
-	uint16_t		an_tx_lmac_ucast_frags;	/* 0x2A */
-	uint16_t		an_tx_lmac_ucasts;	/* 0x2C */
-	uint16_t		an_tx_beacons;		/* 0x2E */
-	uint16_t		an_rx_beacons;		/* 0x30 */
-	uint16_t		an_tx_single_cols;	/* 0x32 */
-	uint16_t		an_tx_multi_cols;	/* 0x34 */
-	uint16_t		an_tx_defers_no;	/* 0x36 */
-	uint16_t		an_tx_defers_prot;	/* 0x38 */
-	uint16_t		an_tx_defers_energy;	/* 0x3A */
-	uint16_t		an_rx_dups;		/* 0x3C */
-	uint16_t		an_rx_partial;		/* 0x3E */
-	uint16_t		an_tx_too_old;		/* 0x40 */
-	uint16_t		an_rx_too_old;		/* 0x42 */
-	uint16_t		an_lostsync_max_retries; /* 0x44 */
-	uint16_t		an_lostsync_missed_beacons; /* 0x46 */
-	uint16_t		an_lostsync_arl_exceeded; /* 0x48 */
-	uint16_t		an_lostsync_deauthed;	/* 0x4A */
-	uint16_t		an_lostsync_disassociated; /* 0x4C */
-	uint16_t		an_lostsync_tsf_timing;	/* 0x4E */
-	uint16_t		an_tx_host_mcasts;	/* 0x50 */
-	uint16_t		an_tx_host_bcasts;	/* 0x52 */
-	uint16_t		an_tx_host_ucasts;	/* 0x54 */
-	uint16_t		an_tx_host_failed;	/* 0x56 */
-	uint16_t		an_rx_host_mcasts;	/* 0x58 */
-	uint16_t		an_rx_host_bcasts;	/* 0x5A */
-	uint16_t		an_rx_host_ucasts;	/* 0x5C */
-	uint16_t		an_rx_host_discarded;	/* 0x5E */
-	uint16_t		an_tx_hmac_mcasts;	/* 0x60 */
-	uint16_t		an_tx_hmac_bcasts;	/* 0x62 */
-	uint16_t		an_tx_hmac_ucasts;	/* 0x64 */
-	uint16_t		an_tx_hmac_failed;	/* 0x66 */
-	uint16_t		an_rx_hmac_mcasts;	/* 0x68 */
-	uint16_t		an_rx_hmac_bcasts;	/* 0x6A */
-	uint16_t		an_rx_hmac_ucasts;	/* 0x6C */
-	uint16_t		an_rx_hmac_discarded;	/* 0x6E */
-	uint16_t		an_tx_hmac_accepted;	/* 0x70 */
-	uint16_t		an_ssid_mismatches;	/* 0x72 */
-	uint16_t		an_ap_mismatches;	/* 0x74 */
-	uint16_t		an_rates_mismatches;	/* 0x76 */
-	uint16_t		an_auth_rejects;	/* 0x78 */
-	uint16_t		an_auth_timeouts;	/* 0x7A */
-	uint16_t		an_assoc_rejects;	/* 0x7C */
-	uint16_t		an_assoc_timeouts;	/* 0x7E */
-	uint16_t		an_reason_outside_table; /* 0x80 */
-	uint16_t		an_reason1;		/* 0x82 */
-	uint16_t		an_reason2;		/* 0x84 */
-	uint16_t		an_reason3;		/* 0x86 */
-	uint16_t		an_reason4;		/* 0x88 */
-	uint16_t		an_reason5;		/* 0x8A */
-	uint16_t		an_reason6;		/* 0x8C */
-	uint16_t		an_reason7;		/* 0x8E */
-	uint16_t		an_reason8;		/* 0x90 */
-	uint16_t		an_reason9;		/* 0x92 */
-	uint16_t		an_reason10;		/* 0x94 */
-	uint16_t		an_reason11;		/* 0x96 */
-	uint16_t		an_reason12;		/* 0x98 */
-	uint16_t		an_reason13;		/* 0x9A */
-	uint16_t		an_reason14;		/* 0x9C */
-	uint16_t		an_reason15;		/* 0x9E */
-	uint16_t		an_reason16;		/* 0xA0 */
-	uint16_t		an_reason17;		/* 0xA2 */
-	uint16_t		an_reason18;		/* 0xA4 */
-	uint16_t		an_reason19;		/* 0xA6 */
-	uint16_t		an_rx_mgmt_pkts;	/* 0xA8 */
-	uint16_t		an_tx_mgmt_pkts;	/* 0xAA */
-	uint16_t		an_rx_refresh_pkts;	/* 0xAC */
-	uint16_t		an_tx_refresh_pkts;	/* 0xAE */
-	uint16_t		an_rx_poll_pkts;	/* 0xB0 */
-	uint16_t		an_tx_poll_pkts;	/* 0xB2 */
-	uint16_t		an_host_retries;	/* 0xB4 */
-	uint16_t		an_lostsync_hostreq;	/* 0xB6 */
-	uint16_t		an_host_tx_bytes;	/* 0xB8 */
-	uint16_t		an_host_rx_bytes;	/* 0xBA */
-	uint16_t		an_uptime_usecs;	/* 0xBC */
-	uint16_t		an_uptime_secs;		/* 0xBE */
-	uint16_t		an_lostsync_better_ap;	/* 0xC0 */
-	uint16_t		an_privacy_mismatch;	/* 0xC2 */
-	uint16_t		an_jammed;		/* 0xC4 */
-	uint16_t		an_rx_disc_wep_off;	/* 0xC6 */
-	uint16_t		an_phy_ele_mismatch;	/* 0xC8 */
-	uint16_t		an_leap_success;	/* 0xCA */
-	uint16_t		an_leap_failure;	/* 0xCC */
-	uint16_t		an_leap_timeouts;	/* 0xCE */
-	uint16_t		an_leap_keylen_fail;	/* 0xD0 */
-};
-
-#define	AN_RID_ESSIDLIST_FIRST	0xFF72
-#define	AN_RID_ESSIDLIST_NEXT	0xFF73
-
-struct an_ltv_scanresult {
-	uint16_t	an_len;
-	uint16_t	an_index;
-	uint16_t	an_radiotype;
-	uint8_t		an_bssid[6];
-#ifdef	_BIG_ENDIAN
-	uint8_t		an_ssidlen;
-	uint8_t		an_zero;
-#else
-	uint8_t		an_zero;
-	uint8_t		an_ssidlen;
-#endif
-	char		an_ssid[32];
-	uint16_t	an_rssi;
-	uint16_t	an_cap;
-	uint16_t	an_beaconinterval;
-	uint8_t		an_rates[8];
-	struct {
-		uint16_t	dwell;
-		uint8_t		hopset;
-		uint8_t		hoppattern;
-		uint8_t		hopindex;
-		uint8_t		pad;
-	} an_fh;
-	uint16_t	an_dschannel;
-	uint16_t	an_atimwindow;
-};
-
-/*
- * seconds after which the scan item ages
- */
-#define	AN_SCAN_TIMEOUT_MAX	30
-
-/*
- * threshold of scan result items below which scan will run again.
- */
-#define	AN_SCAN_AGAIN_THRESHOLD	5
-
-typedef struct an_scan_list {
-	struct an_ltv_scanresult	an_val;
-	uint32_t			an_timeout;
-	list_node_t			an_scan_node;
-} an_scan_list_t;
-
-/*
- * Receive frame structure.
- */
-typedef struct an_rxframe {
-	uint32_t	an_rx_time;		/* 0x00 */
-	uint16_t	an_rx_status;		/* 0x04 */
-	uint16_t	an_rx_payload_len;	/* 0x06 */
-	uint8_t		an_rsvd0;		/* 0x08 */
-	uint8_t		an_rx_signal_strength;	/* 0x09 */
-	uint8_t		an_rx_rate;		/* 0x0A */
-	uint8_t		an_rx_chan;		/* 0x0B */
-	uint8_t		an_rx_assoc_cnt;	/* 0x0C */
-	uint8_t		an_rsvd1[3];		/* 0x0D */
-	uint8_t		an_plcp_hdr[4];		/* 0x10 */
-	uint16_t	an_frame_ctl;		/* 0x14 */
-	uint16_t	an_duration;		/* 0x16 */
-	uint8_t		an_addr1[6];		/* 0x18 */
-	uint8_t		an_addr2[6];		/* 0x1E */
-	uint8_t		an_addr3[6];		/* 0x24 */
-	uint16_t	an_seq_ctl;		/* 0x2A */
-	uint8_t		an_addr4[6];		/* 0x2C */
-	uint16_t	an_gaplen;		/* 0x32 */
-} an_rxfrm_t;
-
-#define	AN_RXGAP_MAX	8
-
-/*
- * Transmit frame structure.
- */
-typedef struct an_txframe {
-	uint32_t	an_tx_sw;		/* 0x00 */
-	uint16_t	an_tx_status;		/* 0x04 */
-	uint16_t	an_tx_payload_len;	/* 0x06 */
-	uint16_t	an_tx_ctl;		/* 0x08 */
-	uint16_t	an_tx_assoc_id;		/* 0x0A */
-	uint16_t	an_tx_retry;		/* 0x0C */
-	uint8_t		an_tx_assoc_cnt;	/* 0x0E */
-	uint8_t		an_tx_rate;		/* 0x0F */
-	uint8_t		an_tx_max_long_retries;	/* 0x10 */
-	uint8_t		an_tx_max_short_retries; /* 0x11 */
-	uint8_t		an_rsvd0[2];		/* 0x12 */
-	uint16_t	an_frame_ctl;		/* 0x14 */
-	uint16_t	an_duration;		/* 0x16 */
-	uint8_t		an_addr1[6];		/* 0x18 */
-	uint8_t		an_addr2[6];		/* 0x1E */
-	uint8_t		an_addr3[6];		/* 0x24 */
-	uint16_t	an_seq_ctl;		/* 0x2A */
-	uint8_t		an_addr4[6];		/* 0x2C */
-	uint16_t	an_gaplen;		/* 0x32 */
-} an_txfrm_t;
-
-typedef struct an_frame {
-	union {
-		an_rxfrm_t rxfrm;
-		an_txfrm_t txfrm;
-	} frm;
-} an_frm_t;
-
-#define	AN_TXSTAT_EXCESS_RETRY	0x0002
-#define	AN_TXSTAT_LIFE_EXCEEDED	0x0004
-#define	AN_TXSTAT_AID_FAIL	0x0008
-#define	AN_TXSTAT_MAC_DISABLED	0x0010
-#define	AN_TXSTAT_ASSOC_LOST	0x0020
-
-#define	AN_TXCTL_RSVD		0x0001
-#define	AN_TXCTL_TXOK_INTR	0x0002
-#define	AN_TXCTL_TXERR_INTR	0x0004
-#define	AN_TXCTL_HEADER_TYPE	0x0008
-#define	AN_TXCTL_PAYLOAD_TYPE	0x0010
-#define	AN_TXCTL_NORELEASE	0x0020
-#define	AN_TXCTL_NORETRIES	0x0040
-#define	AN_TXCTL_CLEAR_AID	0x0080
-#define	AN_TXCTL_STRICT_ORDER	0x0100
-#define	AN_TXCTL_USE_RTS	0x0200
-
-#define	AN_HEADERTYPE_8023	0x0000
-#define	AN_HEADERTYPE_80211	0x0008
-
-#define	AN_PAYLOADTYPE_ETHER	0x0000
-#define	AN_PAYLOADTYPE_LLC	0x0010
-
-typedef enum {
-	ANC_RX_OVERRUNS,		/* 0x04 */
-	ANC_RX_PLCP_CSUM_ERRS,		/* 0x08 */
-	ANC_RX_PLCP_FORMAT_ERRS,	/* 0x0c */
-	ANC_RX_PLCP_LEN_ERRS,		/* 0x10 */
-	ANC_RX_MAC_CRC_ERRS,		/* 0x14 */
-	ANC_RX_MAC_CRC_OK,		/* 0x18 */
-	ANC_RX_WEP_ERRS,		/* 0x1c */
-	ANC_RX_WEP_OK,			/* 0x20 */
-	ANC_RETRY_LONG,			/* 0x24 */
-	ANC_RETRY_SHORT,		/* 0x28 */
-	ANC_RETRY_MAX,			/* 0x2c */
-	ANC_NO_ACK,			/* 0x30 */
-	ANC_NO_CTS,			/* 0x34 */
-	ANC_RX_ACK_OK,			/* 0x38 */
-	ANC_RX_CTS_OK,			/* 0x3c */
-	ANC_TX_ACK_OK,			/* 0x40 */
-	ANC_TX_RTS_OK,			/* 0x44 */
-	ANC_TX_CTS_OK,			/* 0x48 */
-	ANC_TX_LMAC_MCASTS,		/* 0x4c */
-	ANC_TX_LMAC_BCASTS,		/* 0x50 */
-	ANC_TX_LMAC_UCAST_FRAGS,	/* 0x54 */
-	ANC_TX_LMAC_UCASTS,		/* 0x58 */
-	ANC_TX_BEACONS,			/* 0x5c */
-	ANC_RX_BEACONS,			/* 0x60 */
-	ANC_TX_SINGLE_COLS,		/* 0x64 */
-	ANC_TX_MULTI_COLS,		/* 0x68 */
-	ANC_TX_DEFERS_NO,		/* 0x6c */
-	ANC_TX_DEFERS_PROT,		/* 0x70 */
-	ANC_TX_DEFERS_ENERGY,		/* 0x74 */
-	ANC_RX_DUPS,			/* 0x78 */
-	ANC_RX_PARTIAL,			/* 0x7c */
-	ANC_TX_TOO_OLD,			/* 0x80 */
-	ANC_RX_TOO_OLD,			/* 0x84 */
-	ANC_LOSTSYNC_MAX_RETRIES,	/* 0x88 */
-	ANC_LOSTSYNC_MISSED_BEACONS,	/* 0x8c */
-	ANC_LOSTSYNC_ARL_EXCEEDED,	/* 0x90 */
-	ANC_LOSTSYNC_DEAUTHED,		/* 0x94 */
-	ANC_LOSTSYNC_DISASSOCIATED,	/* 0x98 */
-	ANC_LOSTSYNC_TSF_TIMING,	/* 0x9c */
-	ANC_TX_HOST_MCASTS,		/* 0xa0 */
-	ANC_TX_HOST_BCASTS,		/* 0xa4 */
-	ANC_TX_HOST_UCASTS,		/* 0xa8 */
-	ANC_TX_HOST_FAILED,		/* 0xac */
-	ANC_RX_HOST_MCASTS,		/* 0xb0 */
-	ANC_RX_HOST_BCASTS,		/* 0xb4 */
-	ANC_RX_HOST_UCASTS,		/* 0xb8 */
-	ANC_RX_HOST_DISCARDED,		/* 0xbc */
-	ANC_TX_HMAC_MCASTS,		/* 0xc0 */
-	ANC_TX_HMAC_BCASTS,		/* 0xc4 */
-	ANC_TX_HMAC_UCASTS,		/* 0xc8 */
-	ANC_TX_HMAC_FAILED,		/* 0xcc */
-	ANC_RX_HMAC_MCASTS,		/* 0xd0 */
-	ANC_RX_HMAC_BCASTS,		/* 0xd4 */
-	ANC_RX_HMAC_UCASTS,		/* 0xd8 */
-	ANC_RX_HMAC_DISCARDED,		/* 0xdc */
-	ANC_TX_HMAC_ACCEPTED,		/* 0xe0 */
-	ANC_SSID_MISMATCHES,		/* 0xe4 */
-	ANC_AP_MISMATCHES,		/* 0xe8 */
-	ANC_RATES_MISMATCHES,		/* 0xec */
-	ANC_AUTH_REJECTS,		/* 0xf0 */
-	ANC_AUTH_TIMEOUTS,		/* 0xf4 */
-	ANC_ASSOC_REJECTS,		/* 0xf8 */
-	ANC_ASSOC_TIMEOUTS,		/* 0xfc */
-	ANC_REASON_OUTSIDE_TABLE,	/* 0x100 */
-	ANC_REASON1,			/* 0x104 */
-	ANC_REASON2,			/* 0x108 */
-	ANC_REASON3,			/* 0x10c */
-	ANC_REASON4,			/* 0x110 */
-	ANC_REASON5,			/* 0x114 */
-	ANC_REASON6,			/* 0x118 */
-	ANC_REASON7,			/* 0x11c */
-	ANC_REASON8,			/* 0x120 */
-	ANC_REASON9,			/* 0x124 */
-	ANC_REASON10,			/* 0x128 */
-	ANC_REASON11,			/* 0x12c */
-	ANC_REASON12,			/* 0x130 */
-	ANC_REASON13,			/* 0x134 */
-	ANC_REASON14,			/* 0x138 */
-	ANC_REASON15,			/* 0x13c */
-	ANC_REASON16,			/* 0x140 */
-	ANC_REASON17,			/* 0x144 */
-	ANC_REASON18,			/* 0x148 */
-	ANC_REASON19,			/* 0x14c */
-	ANC_RX_MGMT_PKTS,		/* 0x150 */
-	ANC_TX_MGMT_PKTS,		/* 0x154 */
-	ANC_RX_REFRESH_PKTS,		/* 0x158 */
-	ANC_TX_REFRESH_PKTS,		/* 0x15c */
-	ANC_RX_POLL_PKTS,		/* 0x160 */
-	ANC_TX_POLL_PKTS,		/* 0x164 */
-	ANC_HOST_RETRIES,		/* 0x168 */
-	ANC_LOSTSYNC_HOSTREQ,		/* 0x16c */
-	ANC_HOST_TX_BYTES,		/* 0x170 */
-	ANC_HOST_RX_BYTES,		/* 0x174 */
-	ANC_UPTIME_USECS,		/* 0x178 */
-	ANC_UPTIME_SECS,		/* 0x17c */
-	ANC_LOSTSYNC_BETTER_AP,		/* 0x180 */
-	ANC_PRIVACY_MISMATCH,		/* 0x184 */
-	ANC_JAMMED,			/* 0x188 */
-	ANC_RX_DISC_WEP_OFF,		/* 0x18c */
-	ANC_PHY_ELE_MISMATCH,		/* 0x190 */
-	ANC_LEAP_SUCCESS,		/* 0x194 */
-	ANC_LEAP_FAILURE,		/* 0x198 */
-	ANC_LEAP_TIMEOUTS,		/* 0x19c */
-	ANC_LEAP_KEYLEN_FAIL,		/* 0x1a0 */
-	ANC_STAT_CNT			/* - keep it as the last entry */
-} pcan_cntr_offset;
-
-#define	AN_TXCTL_80211	(AN_TXCTL_TXOK_INTR | AN_TXCTL_TXERR_INTR | \
-		AN_HEADERTYPE_80211 | AN_PAYLOADTYPE_LLC | AN_TXCTL_NORELEASE)
-
-#define	AN_TXCTL_8023	(AN_TXCTL_TXOK_INTR | AN_TXCTL_TXERR_INTR |\
-		AN_HEADERTYPE_8023 | AN_PAYLOADTYPE_ETHER | AN_TXCTL_NORELEASE)
-
-#define	AN_TXGAP_80211		6
-#define	AN_TXGAP_8023		0
-
-#define	AN_NORMAL_RXMODE	(AN_RXMODE_BC_MC_ADDR | \
-					AN_RXMODE_USE_8023_HEADER)
-#define	AN_MONITOR_RXMODE	(AN_RXMODE_LAN_MONITOR_CURBSS | \
-					AN_RXMODE_USE_8023_HEADER)
-struct an_802_3_hdr {
-	uint16_t		an_8023_status;
-	uint16_t		an_8023_payload_len;
-	uint8_t			an_8023_dst_addr[6];
-	uint8_t			an_8023_src_addr[6];
-	uint16_t		an_8023_dat[3];	/* SNAP header */
-	uint16_t		an_8023_type;
-};
-
-typedef struct an_snap_hdr {
-	uint16_t		an_snap_dat[3];	/* SNAP header */
-	uint16_t		an_snap_type;
-} pcan_snaphdr_t;
-
-#define	AN_TX_RING_CNT		4
-#define	AN_TX_RING_MASK		(4 - 1)
-#define	AN_INC(x, y)		(x) = (x + 1) % (y)
-
-typedef struct an_tx_ring_data {
-	uint16_t		an_tx_fids[AN_TX_RING_CNT];
-	uint16_t		an_tx_ring[AN_TX_RING_CNT];
-	int			an_tx_prod;
-	int			an_tx_cons;
-	kmutex_t		an_tx_lock;	/* for send only */
-} pcan_txring_t;
-
-#define	AN_802_3_OFFSET		0x2E
-#define	AN_802_11_OFFSET	0x44
-#define	AN_802_11_OFFSET_RAW	0x3C
-
-#define	AN_STAT_BADCRC		0x0001
-#define	AN_STAT_UNDECRYPTABLE	0x0002
-#define	AN_STAT_ERRSTAT		0x0003
-#define	AN_STAT_MAC_PORT	0x0700
-#define	AN_STAT_1042		0x2000	/* RFC1042 encoded */
-#define	AN_STAT_TUNNEL		0x4000	/* Bridge-tunnel encoded */
-#define	AN_STAT_WMP_MSG		0x6000	/* WaveLAN-II management protocol */
-#define	AN_RXSTAT_MSG_TYPE	0xE000
-
-#define	AN_ENC_TX_802_3		0x00
-#define	AN_ENC_TX_802_11	0x11
-#define	AN_ENC_TX_E_II		0x0E
-
-#define	AN_ENC_TX_1042		0x00
-#define	AN_ENC_TX_TUNNEL	0xF8
-
-#define	AN_TXCNTL_MACPORT	0x00FF
-#define	AN_TXCNTL_STRUCTTYPE	0xFF00
-
-/*
- * SNAP (sub-network access protocol) constants for transmission
- * of IP datagrams over IEEE 802 networks, taken from RFC1042.
- * We need these for the LLC/SNAP header fields in the TX/RX frame
- * structure.
- */
-#define	AN_SNAP_K1		0xaa	/* assigned global SAP for SNAP */
-#define	AN_SNAP_K2		0x00
-#define	AN_SNAP_CONTROL		0x03	/* unnumbered information format */
-#define	AN_SNAP_WORD0		(AN_SNAP_K1 | (AN_SNAP_K1 << 8))
-#define	AN_SNAP_WORD1		(AN_SNAP_K2 | (AN_SNAP_CONTROL << 8))
-#define	AN_SNAPHDR_LEN		0x6
-
-#define	AN_FTYPE_DATA		0x8
-#define	ETH_HDRLEN		(sizeof (struct ether_header))	/* 14 bytes */
-#define	MLEN(mp)		((mp)->b_wptr - (mp)->b_rptr)
-
-typedef struct pcan_dma_info {
-	ddi_dma_handle_t	dma_handle;
-	ddi_acc_handle_t	dma_acc_handle;
-	uint32_t		dma_physaddr;
-	caddr_t			dma_virtaddr;
-	uint_t			ncookies;
-} pcan_dma_info_t;
-
-#define	PCAN_DMA_SYNC(hdl, len, flag) ((void) ddi_dma_sync(hdl, 0, len, (flag)))
-
-/*
- * The macinfo is really used as the softstate structure.
- *
- * pcan_mh	 - mac_handle_t structure
- * pcan_cslock	 - lock for card services request. Used with pcan_cscv
- * pcan_cscv	 - condition variable to wait for card events
- * pcan_chdl	 - client handle, an uint32_t bit mask encoding for socket,
- *			function, and client info.
- *			See cs_priv.h MAKE_CLIENT_HANDLE.
- * pcan_log_sock - holds the logical to physical translation for this card.
- *			Specifically has physical adapter and socket #.
- *			Socket # is the same as part of the pcan_chdl encoding.
- *			Physical adapter # is from card service socket impl.
- */
-typedef struct pcan_macinfo {
-	mac_handle_t		pcan_mh;
-	dev_info_t		*pcan_dip;
-
-	kmutex_t		pcan_cslock;	/* for card services */
-	kcondvar_t		pcan_cscv;	/* for card services */
-	client_handle_t		pcan_chdl;	/* s,f,c encoding, cs_priv.h */
-	map_log_socket_t	pcan_log_sock;	/* logical/phys socket map */
-	int			pcan_socket;	/* socket number */
-	int			pcan_config_hi;	/* cfttbl index */
-	int			pcan_config;	/* default config index */
-	int			pcan_vcc;	/* vcc level */
-	int			pcan_iodecode;	/* # of address lines */
-	int			pcan_usewep;
-	int			pcan_reset_delay;
-
-	caddr_t			pcan_cfg_base;
-	ddi_acc_handle_t	pcan_cfg_handle;
-	caddr_t			pcan_bar0;
-	ddi_acc_handle_t	pcan_handle0;
-	caddr_t			pcan_bar1;
-	ddi_acc_handle_t	pcan_handle1;
-	caddr_t			pcan_bar2;
-	ddi_acc_handle_t	pcan_handle2;
-	int			pcan_device_type; /* pci or pcmcia card */
-
-	uint8_t 		pcan_mac_addr[ETHERADDRL];
-	uint32_t		pcan_flag;
-	uint32_t		pcan_reschedule_need;
-	uint32_t		glds_nocarrier;
-	uint32_t		glds_noxmtbuf;
-	uint32_t		glds_norcvbuf;
-	uint32_t		glds_intr;
-
-	pcan_dma_info_t	pcan_cmd;
-	pcan_dma_info_t	pcan_rx[AN_MAX_RX_DESC];
-	pcan_dma_info_t	pcan_tx[AN_MAX_TX_DESC];
-
-	kmutex_t		pcan_glock;	/* generic lock */
-	kmutex_t		pcan_scanlist_lock;	/* scanlist lock */
-	pcan_txring_t		pcan_txring;
-
-	struct an_ltv_ssidlist	an_ssidlist;
-	struct an_ltv_aplist	an_aplist;
-	struct an_ltv_caps	an_caps;
-	struct an_ltv_crypt	an_crypt;
-	struct an_ltv_wepkey	an_wepkey[4];
-	struct an_ltv_scanresult an_scanresult[32];
-	uint16_t		an_cur_wepkey;
-	uint16_t		an_scan_num;
-	timeout_id_t		an_scanlist_timeout_id;
-	list_t			an_scan_list;
-	struct an_ltv_status	an_status;
-	struct an_ltv_genconfig	an_config;
-	struct an_ltv_genconfig	an_actual_config;
-	struct an_ltv_stats	an_stats;
-	uint64_t pcan_cntrs_s[ANC_STAT_CNT];
-
-	ddi_acc_handle_t	pcan_port;
-	ddi_iblock_cookie_t	pcan_ib_cookie;
-	ddi_softintr_t		pcan_softint_id;
-
-	ddi_softintr_t		pcan_info_softint_id;
-	uint32_t		pcan_info_softint_pending;
-
-	timeout_id_t		pcan_connect_timeout_id;
-	timeout_id_t		pcan_linkdown_timeout_id;
-	int			pcan_badrids_len;
-	prop_1275_cell_t	*pcan_badrids;
-} pcan_maci_t;
-
-#define	PCAN_IDENT_STRING	modldrv.drv_linkinfo
-
-#define	HDL(pcan_p)		((pcan_p)->pcan_port)
-#define	GLD3(pcan_p)		((pcan_p)->pcan_mh)
-#define	DIP(pcan_p)		((pcan_p)->pcan_dip)
-
-#define	PCAN_CARD_INTREN	0x1
-#define	PCAN_CARD_LINKUP	0x2
-#define	PCAN_ATTACHED		0x4
-#define	PCAN_CS_REGISTERED	0x8
-#define	PCAN_ENABLED		0x10
-#define	PCAN_CARD_SEND		0x20
-#define	PCAN_CARD_READY		0x40
-#define	PCAN_CARD_FAILED	0x80
-#define	PCAN_PLUMBED		0x100
-#define	PCAN_SUSPENDED		0x200
-
-#define	PCAN_STATE_IDLE		0x1
-
-#define	PCAN_NICMEM_SZ		(2048) /* 80211MTU set as 1500, so 2k here */
-
-static int	pcan_probe(dev_info_t *dip);
-static int	pcan_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
-static int	pcan_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
-
-static int	pcan_register_cs(dev_info_t *dip, pcan_maci_t *pcan_p);
-static void	pcan_unregister_cs(pcan_maci_t *pcan_p);
-static void	pcan_destroy_locks(pcan_maci_t *pcan_p);
-static void	pcan_reset_backend(pcan_maci_t *pcan_p, int timeout);
-static uint32_t	pcan_get_cap(pcan_maci_t *pcan_p);
-static int	pcan_card_insert(pcan_maci_t *pcan_p);
-static int	pcan_ev_hdlr(event_t ev, int pri, event_callback_args_t *arg);
-static void	pcan_card_remove(pcan_maci_t *pcan_p);
-static int	pcan_init_nicmem(pcan_maci_t *pcan_p);
-static void	pcan_do_suspend(pcan_maci_t *pcan_p);
-
-/*
- * high level device access primitives, glock must held before calling
- */
-static uint16_t	pcan_set_cmd0(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t p0,
-    uint16_t p1, uint16_t p2);
-static uint16_t	pcan_set_cmd(pcan_maci_t *pcan_p, uint16_t cmd, uint16_t param);
-static uint16_t pcan_set_ch(pcan_maci_t *, uint16_t, uint16_t, uint16_t);
-static int pcan_init_dma_desc(pcan_maci_t *pcan_p);
-static int pcan_init_dma(dev_info_t *dip, pcan_maci_t *pcan_p);
-static void pcan_free_dma(pcan_maci_t *pcan_p);
-static uint16_t pcan_put_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type,
-    uint16_t *val_p);
-static uint16_t	pcan_get_ltv(pcan_maci_t *pcan_p, uint16_t len, uint16_t type,
-    uint16_t *val_p);
-#define	PCAN_READ_LTV	0
-#define	PCAN_WRITE_LTV	1
-static uint16_t pcan_status_ltv(int rw, pcan_maci_t *pcan_p,
-    struct an_ltv_status *status_p);
-static uint16_t pcan_cfg_ltv(int rw, pcan_maci_t *pcan_p,
-    struct an_ltv_genconfig *cfg_p);
-static uint16_t pcan_cap_ltv(int rw, pcan_maci_t *pcan_p);
-static uint16_t pcan_ssid_ltv(int rw, pcan_maci_t *pcan_p);
-static uint16_t pcan_aplist_ltv(int rw, pcan_maci_t *pcan_p);
-static uint16_t pcan_scanresult_ltv(int rw, pcan_maci_t *pcan_p, uint16_t type,
-    struct an_ltv_scanresult *scanresult_p);
-static uint16_t pcan_wepkey_ltv(int rw, pcan_maci_t *pcan_p);
-static uint16_t pcan_rdch0(pcan_maci_t *pcan_p, uint16_t type, uint16_t off,
-    uint16_t *buf_p, int len, int order);
-static uint16_t pcan_wrch1(pcan_maci_t *pcan_p, uint16_t type, uint16_t off,
-    uint16_t *buf_p, int len, int order);
-static int	pcan_config_mac(pcan_maci_t *pcan_p);
-static void	pcan_start_locked(pcan_maci_t *pcan_p);
-static void	pcan_stop_locked(pcan_maci_t *pcan_p);
-static uint16_t	pcan_alloc_nicmem(pcan_maci_t *pcan_p, uint16_t len,
-    uint16_t *id_p);
-
-/*
- * Required driver entry points for gld
- */
-static int	pcan_start(void *);
-static void	pcan_stop(void *);
-static int	pcan_saddr(void *, const uint8_t *);
-static mblk_t	*pcan_tx(void *, mblk_t *);
-static int	pcan_send(pcan_maci_t *, mblk_t *);
-static int	pcian_send(pcan_maci_t *, mblk_t *);
-static int	pcan_prom(void *, boolean_t);
-static int	pcan_gstat(void *, uint_t, uint64_t *);
-static int	pcan_sdmulti(void *, boolean_t, const uint8_t *);
-static void	pcan_ioctl(void *, queue_t *, mblk_t *);
-
-static uint_t	pcan_intr(caddr_t arg);
-static uint_t	pcan_intr_hi(caddr_t arg);
-static void	pcan_rcv(pcan_maci_t *pcan_p);
-static void	pcian_rcv(pcan_maci_t *pcan_p);
-static uint_t	pcan_info_softint(caddr_t arg);
-static uint32_t	pcan_txdone(pcan_maci_t *pcan_p, uint16_t err);
-static int	pcan_getset(mblk_t *mp, pcan_maci_t *pcan_p, uint32_t cmd);
-static void	pcan_wlan_ioctl(pcan_maci_t *pcan_p, queue_t *wq,
-    mblk_t *mp, uint32_t cmd);
-static int	pcan_loaddef(pcan_maci_t *pcan_p);
-
-static void	pcan_scanlist_timeout(void *);
-static void	pcan_delete_scan_item(pcan_maci_t *, an_scan_list_t *);
-static int	pcan_add_scan_item(pcan_maci_t *, struct an_ltv_scanresult);
-static void	pcan_connect_timeout(void *arg);
-
-#define	RDCH0(h, t, o, bufp, l)		pcan_rdch0(h, t, o, bufp, l, 1)
-#define	WRCH1(h, t, o, bufp, l)		pcan_wrch1(h, t, o, bufp, l, 1)
-#define	RDPKT(h, t, o, bufp, l)		pcan_rdch0(h, t, o, bufp, l, 0)
-#define	WRPKT(h, t, o, bufp, l)		pcan_wrch1(h, t, o, bufp, l, 0)
-
-#define	PCAN_READ(p, o, v)	{ \
-	if (p->pcan_device_type == PCAN_DEVICE_PCI) { \
-		uint16_t t = ddi_get16(p->pcan_handle0, \
-		    (uint16_t *)(p->pcan_bar0 + o)); \
-		v = LE_16(t); \
-	} else { \
-		uint16_t t = csx_Get16(HDL(p), o); \
-		v = LE_16(t); \
-	}\
-}
-#define	PCAN_WRITE(p, o, v)	{ \
-	if (p->pcan_device_type == PCAN_DEVICE_PCI) { \
-		ddi_put16(p->pcan_handle0, \
-		    (uint16_t *)(p->pcan_bar0 + o), LE_16(v)); \
-	} else { \
-		csx_Put16(HDL(p), o, LE_16(v)); \
-	}\
-}
-#define	PCAN_READ_P(p, o, v, h)	{ \
-	if (p->pcan_device_type == PCAN_DEVICE_PCI) { \
-		uint16_t t = ddi_get16(p->pcan_handle0, \
-		    (uint16_t *)(p->pcan_bar0 + o)); \
-		*(v) = h ? LE_16(t) : t; \
-	} else { \
-		uint16_t t = csx_Get16(HDL(p), o); \
-		*(v) = h ? LE_16(t) : t; \
-	}\
-}
-#define	PCAN_WRITE_P(p, o, v, h)	{ \
-	if (p->pcan_device_type == PCAN_DEVICE_PCI) { \
-		ddi_put16(p->pcan_handle0, (uint16_t *)(p->pcan_bar0 + o), \
-		    h ? LE_16(*(v)) : (*(v))); \
-	} else {\
-		csx_Put16(HDL(p), o, h ? LE_16(*(v)) : (*(v))); \
-	}\
-}
-
-#ifdef _BIG_ENDIAN
-#define	PCAN_SWAP16(buf_p, len) { \
-	uint16_t pcan_swap_len = len; \
-	for (pcan_swap_len = (pcan_swap_len + 1) >> 1; pcan_swap_len; ) { \
-		uint16_t val; \
-		pcan_swap_len--; \
-		val = *((uint16_t *)(buf_p) + pcan_swap_len); \
-		*((uint16_t *)(buf_p) + pcan_swap_len) = LE_16(val); \
-	} \
-}
-#define	PCAN_SWAP16_BUF(buf_p) PCAN_SWAP16(buf_p, sizeof (buf_p))
-#else /* _BIG_ENDIAN */
-#define	PCAN_SWAP16(buf_p, len)
-#define	PCAN_SWAP16_BUF(buf_p)
-#endif /* _BIG_ENDIAN */
-
-#define	PCAN_ENABLE_INTR(pcan_p)	{\
-	PCAN_WRITE(pcan_p, AN_INT_EN(pcan_p), AN_INTRS(pcan_p));\
-}
-#define	PCAN_DISABLE_INTR(pcan_p)	{ \
-	PCAN_WRITE(pcan_p, AN_INT_EN(pcan_p), 0); \
-}
-#define	PCAN_DISABLE_INTR_CLEAR(pcan_p)	{ \
-	PCAN_WRITE(pcan_p, AN_INT_EN(pcan_p), 0); \
-	PCAN_WRITE(pcan_p, AN_EVENT_ACK(pcan_p), 0xffff);\
-}
-
-#define	PCAN_AUX_PUT32(p, o, v)\
-	ddi_put32(p->pcan_handle2, (uint32_t *)(p->pcan_bar2 + o), v)
-#define	PCAN_AUX_GET32(p, o, v) {\
-	v = ddi_get32(p->pcan_handle2, (uint32_t *)(p->pcan_bar2 + o));\
-}
-
-/*
- * 16-bit driver private status code
- */
-#define	PCAN_SUCCESS		0
-#define	PCAN_FAIL		1
-#define	PCAN_TIMEDOUT_CMD	0x10
-#define	PCAN_TIMEDOUT_ACCESS	0x11
-#define	PCAN_TIMEDOUT_TARGET	0x12
-#define	PCAN_BADLEN		0x13
-#define	PCAN_BADTYPE		0x14
-#define	PCAN_TIMEDOUT_ALLOC	0x15
-
-#define	PCAN_STATUS_MAX		0xffff
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif	/* _SYS_PCAN_H */
--- a/usr/src/uts/common/io/pcwl/THIRDPARTYLICENSE	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,31 +0,0 @@
-/*
- * Copyright (c) 1997, 1998, 1999
- *      Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *      This product includes software developed by Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * 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.
- */
--- a/usr/src/uts/common/io/pcwl/THIRDPARTYLICENSE.descrip	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-PCWL DRIVER
--- a/usr/src/uts/common/io/pcwl/pcwl.c	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,4528 +0,0 @@
-/*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 1997, 1998, 1999
- *      Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *      This product includes software developed by Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * 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.
- */
-
-#include <sys/conf.h>
-#include <sys/ddi.h>
-#include <sys/sunddi.h>
-#include <sys/dlpi.h>
-#include <sys/ethernet.h>
-#include <sys/strsubr.h>
-#include <sys/strsun.h>
-#include <sys/stat.h>
-#include <sys/byteorder.h>
-#include <sys/pccard.h>
-#include <sys/pci.h>
-#include <sys/policy.h>
-#include <sys/mac_provider.h>
-#include <sys/stream.h>
-#include <inet/common.h>
-#include <inet/nd.h>
-#include <inet/mi.h>
-
-#include "pcwl.h"
-#include <sys/mac_wifi.h>
-#include <inet/wifi_ioctl.h>
-
-#ifdef DEBUG
-#define	PCWL_DBG_BASIC		0x1
-#define	PCWL_DBG_INFO		0x2
-#define	PCWL_DBG_SEND		0x4
-#define	PCWL_DBG_RCV		0x8
-#define	PCWL_DBG_LINKINFO	0x10
-uint32_t pcwl_debug = 0;
-#define	PCWLDBG(x) \
-	if (pcwl_debug & PCWL_DBG_BASIC) cmn_err x
-#else
-#define	PCWLDBG(x)
-#endif
-
-/* for pci card */
-static ddi_device_acc_attr_t accattr = {
-		DDI_DEVICE_ATTR_V0,
-		DDI_NEVERSWAP_ACC,
-		DDI_STRICTORDER_ACC,
-		DDI_DEFAULT_ACC
-};
-
-void *pcwl_soft_state_p = NULL;
-static int pcwl_device_type;
-
-static int	pcwl_m_setprop(void *arg, const char *pr_name,
-    mac_prop_id_t wldp_pr_num, uint_t wldp_length,
-    const void *wldp_buf);
-static int	pcwl_m_getprop(void *arg, const char *pr_name,
-    mac_prop_id_t wldp_pr_num, uint_t wldp_length, void *wldp_buf);
-static void	pcwl_m_propinfo(void *arg, const char *pr_name,
-    mac_prop_id_t wlpd_pr_num, mac_prop_info_handle_t mph);
-static void
-pcwl_delay(pcwl_maci_t *, clock_t);
-
-mac_callbacks_t pcwl_m_callbacks = {
-	MC_IOCTL | MC_SETPROP | MC_GETPROP | MC_PROPINFO,
-	pcwl_gstat,
-	pcwl_start,
-	pcwl_stop,
-	pcwl_prom,
-	pcwl_sdmulti,
-	pcwl_saddr,
-	pcwl_tx,
-	NULL,
-	pcwl_ioctl,
-	NULL,
-	NULL,
-	NULL,
-	pcwl_m_setprop,
-	pcwl_m_getprop,
-	pcwl_m_propinfo
-};
-
-static char *pcwl_name_str = "pcwl";
-
-#ifdef	__sparc
-#define	pcwl_quiesce	ddi_quiesce_not_supported
-#else
-static int pcwl_quiesce(dev_info_t *);
-#endif
-
-DDI_DEFINE_STREAM_OPS(pcwl_dev_ops, nulldev, pcwl_probe, pcwl_attach,
-    pcwl_detach, nodev, NULL, D_MP, NULL, pcwl_quiesce);
-
-extern struct mod_ops mod_driverops;
-static struct modldrv modldrv = {
-	&mod_driverops,
-	"Lucent/PRISM-II 802.11b driver",
-	&pcwl_dev_ops
-};
-
-static struct modlinkage modlinkage = {
-	MODREV_1, (void *)&modldrv, NULL
-	};
-
-int
-_init(void)
-{
-	int stat;
-
-	/* Allocate soft state */
-	if ((stat = ddi_soft_state_init(&pcwl_soft_state_p,
-	    sizeof (pcwl_maci_t), N_PCWL)) != DDI_SUCCESS)
-		return (stat);
-
-	mac_init_ops(&pcwl_dev_ops, "pcwl");
-	wl_frame_default.wl_dat[0] = htons(WL_SNAP_WORD0);
-	wl_frame_default.wl_dat[1] = htons(WL_SNAP_WORD1);
-	stat = mod_install(&modlinkage);
-	if (stat != DDI_SUCCESS) {
-		mac_fini_ops(&pcwl_dev_ops);
-		ddi_soft_state_fini(&pcwl_soft_state_p);
-	}
-	return (stat);
-}
-
-int
-_fini(void)
-{
-	int stat;
-
-	if ((stat = mod_remove(&modlinkage)) != DDI_SUCCESS)
-		return (stat);
-	mac_fini_ops(&pcwl_dev_ops);
-	ddi_soft_state_fini(&pcwl_soft_state_p);
-
-	return (stat);
-}
-
-int
-_info(struct modinfo *modinfop)
-{
-	return (mod_info(&modlinkage, modinfop));
-}
-
-static int
-pcwl_probe(dev_info_t *dip)
-{
-	int len, ret;
-	char *buf;
-	dev_info_t *pdip = ddi_get_parent(dip);
-
-	ret = ddi_getlongprop(DDI_DEV_T_ANY, pdip, 0, "device_type",
-	    (caddr_t)&buf, &len);
-	if (ret != DDI_SUCCESS)
-		return (DDI_PROBE_FAILURE);
-
-	PCWLDBG((CE_NOTE, "pcwl probe: device_type %s\n", buf));
-	if ((strcmp(buf, "pccard") == 0) || (strcmp(buf, "pcmcia") == 0)) {
-		pcwl_device_type = PCWL_DEVICE_PCCARD;
-		ret = DDI_PROBE_SUCCESS;
-	} else if (strcmp(buf, "pci") == 0) {
-		pcwl_device_type = PCWL_DEVICE_PCI;
-		ret = DDI_PROBE_SUCCESS;
-	} else {
-		ret = DDI_PROBE_FAILURE;
-	}
-	kmem_free(buf, len);
-	return (ret);
-}
-
-static int
-pcwl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
-{
-	int ret, i;
-	int instance;
-	uint16_t stat;
-	uint32_t err;
-	pcwl_maci_t *pcwl_p;
-	wifi_data_t	wd = { 0 };
-	mac_register_t	*macp;
-	modify_config_t cfgmod;
-	char strbuf[256];
-
-	PCWLDBG((CE_NOTE, "pcwl attach: dip=0x%p cmd=%x\n", (void *)dip, cmd));
-	if (cmd != DDI_ATTACH)
-		goto attach_fail1;
-	/*
-	 * Allocate soft state associated with this instance.
-	 */
-	if (ddi_soft_state_zalloc(pcwl_soft_state_p,
-	    ddi_get_instance(dip)) != DDI_SUCCESS) {
-		cmn_err(CE_CONT, "pcwl attach: alloc softstate failed\n");
-		goto attach_fail1;
-	}
-	pcwl_p = (pcwl_maci_t *)ddi_get_soft_state(pcwl_soft_state_p,
-	    ddi_get_instance(dip));
-	pcwl_p->pcwl_device_type = pcwl_device_type;
-	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
-		if (ddi_regs_map_setup(dip, 0,
-		    (caddr_t *)&pcwl_p->pcwl_cfg_base, 0, 0,
-		    &accattr, &pcwl_p->pcwl_cfg_handle) != DDI_SUCCESS) {
-			cmn_err(CE_WARN, "pcwl(pci) attach: pci_regs_map_setup"
-			    " failed\n");
-			goto attach_fail2;
-		}
-
-		stat = ddi_get16(pcwl_p->pcwl_cfg_handle,
-		    (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM));
-		stat |= (PCI_COMM_IO | PCI_COMM_MAE);
-		ddi_put16(pcwl_p->pcwl_cfg_handle,
-		    (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM), stat);
-		stat = ddi_get16(pcwl_p->pcwl_cfg_handle,
-		    (uint16_t *)(pcwl_p->pcwl_cfg_base + PCI_CONF_COMM));
-		if ((stat & (PCI_COMM_IO | PCI_COMM_MAE)) !=
-		    (PCI_COMM_IO | PCI_COMM_MAE)) {
-			cmn_err(CE_WARN, "pcwl(pci) attach: pci command"
-			    " reg enable failed\n");
-			goto attach_fail2a;
-		}
-
-
-		if (ddi_regs_map_setup(dip, 1, (caddr_t *)&pcwl_p->pcwl_bar,
-		    0, 0, &accattr, (ddi_acc_handle_t *)&pcwl_p->pcwl_handle)
-		    != DDI_SUCCESS) {
-			cmn_err(CE_WARN, "pcwl(pci) attach: pci_regs_map_setup"
-			    " failed\n");
-			goto attach_fail2a;
-		}
-		PCWLDBG((CE_NOTE, "pcwl(pci): regs_map_setup,bar=%p\n",
-		    (void *)pcwl_p->pcwl_bar));
-
-		/*
-		 * tricky! copy from freebsd code.
-		 */
-		PCWL_WRITE(pcwl_p, 0x26, 0x80);
-		drv_usecwait(500000);
-		PCWL_WRITE(pcwl_p, 0x26, 0x0);
-		drv_usecwait(500000);
-
-		for (i = 0; i < WL_TIMEOUT; i++) {
-			PCWL_READ(pcwl_p, 0x0, stat);
-			if (stat & WL_CMD_BUSY)
-				drv_usecwait(10);
-			else
-				break;
-		}
-		if (i == WL_TIMEOUT) {
-			cmn_err(CE_WARN, "pcwl(pci) attach: hardware init"
-			    " failed\n");
-			goto attach_fail3;
-		}
-
-		/*
-		 * magic number verification.
-		 * tricky! copy from freebsd code.
-		 */
-		PCWL_WRITE(pcwl_p, 0x28, 0x4a2d);
-		PCWL_READ(pcwl_p, 0x28, stat);
-		PCWLDBG((CE_NOTE, "pcwl(pci):magic number = %x\n", stat));
-		if (stat != 0x4a2d) {
-			cmn_err(CE_WARN, "pcwl(pci) attach: magic verify"
-			    " failed\n");
-			goto attach_fail3;
-		}
-	}
-	pcwl_p->pcwl_dip	= dip;
-	pcwl_p->pcwl_flag	= 0;
-	pcwl_p->pcwl_socket	= ddi_getprop(DDI_DEV_T_NONE, dip,
-	    DDI_PROP_DONTPASS, "socket", -1);
-	pcwl_p->pcwl_reschedule_need = B_FALSE;
-
-	if (ddi_get_iblock_cookie(dip,
-	    0, &pcwl_p->pcwl_ib_cookie) != DDI_SUCCESS) {
-		cmn_err(CE_WARN, "pcwl attach: get_iblk_cookie failed\n");
-		goto attach_fail3;
-	}
-
-	mutex_init(&pcwl_p->pcwl_glock, NULL, MUTEX_DRIVER,
-	    pcwl_p->pcwl_ib_cookie);
-	mutex_init(&pcwl_p->pcwl_scanlist_lock, NULL, MUTEX_DRIVER,
-	    pcwl_p->pcwl_ib_cookie);
-	mutex_init(&pcwl_p->pcwl_txring.wl_tx_lock, NULL, MUTEX_DRIVER,
-	    pcwl_p->pcwl_ib_cookie);
-
-	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
-		if (ret = ddi_add_intr(dip, 0, NULL, NULL,
-		    pcwl_intr, (caddr_t)pcwl_p)) {
-			cmn_err(CE_NOTE, "pcwl(pci) attach: add intr failed\n");
-			goto attach_fail3a;
-		}
-	} else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
-		if (ret = pcwl_register_cs(dip, pcwl_p)) {
-			cmn_err(CE_WARN, "pcwl attach(pccard): "
-			    "register_cs err %x\n", ret);
-			goto attach_fail3a;
-		}
-	} else {
-		cmn_err(CE_WARN, "pcwl attach: unsupported device type\n");
-		goto attach_fail3a;
-	}
-	mutex_enter(&pcwl_p->pcwl_glock);
-	if (ret = pcwl_reset_backend(pcwl_p)) {
-		cmn_err(CE_WARN, "pcwl attach: reset_backend failed %x\n", ret);
-		mutex_exit(&pcwl_p->pcwl_glock);
-		goto attach_fail4;
-	}
-	if (ret = pcwl_get_cap(pcwl_p)) { /* sets macaddr for mac_register */
-		cmn_err(CE_WARN, "pcwl attach: get_cap failed %x\n", ret);
-		mutex_exit(&pcwl_p->pcwl_glock);
-		goto attach_fail4;
-	}
-	mutex_exit(&pcwl_p->pcwl_glock);
-	/*
-	 * Provide initial settings for the WiFi plugin; whenever this
-	 * information changes, we need to call mac_pdata_update()
-	 */
-	wd.wd_secalloc = WIFI_SEC_NONE;
-	wd.wd_opmode = IEEE80211_M_STA;
-
-	macp = mac_alloc(MAC_VERSION);
-	if (macp == NULL) {
-		PCWLDBG((CE_NOTE, "pcwl attach: "
-		    "MAC version mismatch\n"));
-		goto attach_fail4;
-	}
-
-	macp->m_type_ident	= MAC_PLUGIN_IDENT_WIFI;
-	macp->m_driver		= pcwl_p;
-	macp->m_dip		= dip;
-	macp->m_src_addr	= pcwl_p->pcwl_mac_addr;
-	macp->m_callbacks	= &pcwl_m_callbacks;
-	macp->m_min_sdu		= 0;
-	macp->m_max_sdu		= IEEE80211_MTU;
-	macp->m_pdata		= &wd;
-	macp->m_pdata_size	= sizeof (wd);
-
-	err = mac_register(macp, &pcwl_p->pcwl_mh);
-	mac_free(macp);
-	if (err != 0) {
-		PCWLDBG((CE_NOTE, "pcwl attach: "
-		    "mac_register err\n"));
-		goto attach_fail4;
-	}
-
-	mutex_enter(&pcwl_p->pcwl_glock);
-	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
-		/*
-		 * turn on CS interrupt
-		 */
-		cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
-		    CONF_IRQ_CHANGE_VALID;
-		cfgmod.Vpp1 = 0;
-		cfgmod.Vpp2 = 0;
-		(void) csx_ModifyConfiguration(pcwl_p->pcwl_chdl, &cfgmod);
-
-	}
-	if (ret = pcwl_init_nicmem(pcwl_p)) {
-		cmn_err(CE_WARN, "pcwl(pccard) attach: pcwl_init_nicmem"
-		    " failed %x\n", ret);
-		mutex_exit(&pcwl_p->pcwl_glock);
-		goto attach_fail5;
-	}
-	pcwl_chip_type(pcwl_p);
-	if (ret = pcwl_loaddef_rf(pcwl_p)) {
-		cmn_err(CE_WARN, "pcwl attach: config_rf failed%x\n", ret);
-		mutex_exit(&pcwl_p->pcwl_glock);
-		goto attach_fail5;
-	}
-	(void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
-	pcwl_stop_locked(pcwl_p);	/* leaves interface down */
-	list_create(&pcwl_p->pcwl_scan_list, sizeof (wl_scan_list_t),
-	    offsetof(wl_scan_list_t, wl_scan_node));
-	pcwl_p->pcwl_scan_num = 0;
-	mutex_exit(&pcwl_p->pcwl_glock);
-	pcwl_p->pcwl_scanlist_timeout_id = timeout(pcwl_scanlist_timeout,
-	    pcwl_p, drv_usectohz(1000000));
-	instance = ddi_get_instance(dip);
-	(void) snprintf(strbuf, sizeof (strbuf), "pcwl%d", instance);
-	if (ddi_create_minor_node(dip, strbuf, S_IFCHR,
-	    instance + 1, DDI_NT_NET_WIFI, 0) != DDI_SUCCESS) {
-		goto attach_fail6;
-	}
-	pcwl_p->pcwl_flag |= PCWL_ATTACHED;
-	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
-		pcwl_p->pcwl_flag |= PCWL_CARD_READY;
-	}
-	return (DDI_SUCCESS);
-attach_fail6:
-	if (pcwl_p->pcwl_scanlist_timeout_id != 0) {
-		(void) untimeout(pcwl_p->pcwl_scanlist_timeout_id);
-		pcwl_p->pcwl_scanlist_timeout_id = 0;
-	}
-	list_destroy(&pcwl_p->pcwl_scan_list);
-attach_fail5:
-	(void) mac_unregister(pcwl_p->pcwl_mh);
-attach_fail4:
-	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
-		ddi_remove_intr(dip, 0, pcwl_p->pcwl_ib_cookie);
-	} else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
-		pcwl_unregister_cs(pcwl_p);
-	}
-attach_fail3a:
-	pcwl_destroy_locks(pcwl_p);
-attach_fail3:
-	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI)
-		ddi_regs_map_free(&pcwl_p->pcwl_handle);
-attach_fail2a:
-	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI)
-		ddi_regs_map_free(&pcwl_p->pcwl_cfg_handle);
-attach_fail2:
-	ddi_soft_state_free(pcwl_soft_state_p, ddi_get_instance(dip));
-attach_fail1:
-	return (DDI_FAILURE);
-}
-
-static int
-pcwl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
-{
-	pcwl_maci_t *pcwl_p;
-	wl_scan_list_t *scan_item0;
-	int ret;
-	pcwl_p = ddi_get_soft_state(pcwl_soft_state_p, ddi_get_instance(dip));
-
-	PCWLDBG((CE_NOTE, "pcwl detach: dip=0x%p cmd=%x\n", (void *)dip, cmd));
-	if (cmd != DDI_DETACH)
-		return (DDI_FAILURE);
-	if (!(pcwl_p->pcwl_flag & PCWL_ATTACHED))
-		return (DDI_FAILURE);
-
-	ret = mac_disable(pcwl_p->pcwl_mh);
-	if (ret != 0)
-		return (DDI_FAILURE);
-
-	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
-		mutex_enter(&pcwl_p->pcwl_glock);
-		(void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
-		PCWL_DISABLE_INTR(pcwl_p);
-		mutex_exit(&pcwl_p->pcwl_glock);
-	}
-	if (pcwl_p->pcwl_scanlist_timeout_id != 0) {
-		(void) untimeout(pcwl_p->pcwl_scanlist_timeout_id);
-		pcwl_p->pcwl_scanlist_timeout_id = 0;
-	}
-	if (pcwl_p->pcwl_connect_timeout_id != 0) {
-		(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
-		pcwl_p->pcwl_connect_timeout_id = 0;
-	}
-	mutex_enter(&pcwl_p->pcwl_scanlist_lock);
-	scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
-	while (scan_item0) {
-		pcwl_delete_scan_item(pcwl_p, scan_item0);
-		scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
-	}
-	list_destroy(&pcwl_p->pcwl_scan_list);
-	mutex_exit(&pcwl_p->pcwl_scanlist_lock);
-	(void) mac_unregister(pcwl_p->pcwl_mh);
-
-	if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCI) {
-		mutex_enter(&pcwl_p->pcwl_glock);
-		ddi_remove_intr(dip, 0, pcwl_p->pcwl_ib_cookie);
-		ddi_regs_map_free(&pcwl_p->pcwl_handle);
-		ddi_regs_map_free(&pcwl_p->pcwl_cfg_handle);
-		mutex_exit(&pcwl_p->pcwl_glock);
-	} else if (pcwl_p->pcwl_device_type == PCWL_DEVICE_PCCARD) {
-		pcwl_unregister_cs(pcwl_p);
-	}
-	pcwl_destroy_locks(pcwl_p);
-	ddi_remove_minor_node(dip, NULL);
-	ddi_soft_state_free(pcwl_soft_state_p, ddi_get_instance(dip));
-	return (DDI_SUCCESS);
-}
-
-/*
- * card services and event handlers
- */
-static int
-pcwl_register_cs(dev_info_t *dip, pcwl_maci_t *pcwl_p)
-{
-	int ret;
-	client_reg_t cr;
-	client_handle_t chdl; /* uint encoding of socket, function, client */
-	get_status_t card_status;
-	request_socket_mask_t sock_req;
-
-	bzero(&cr, sizeof (cr));
-	cr.Attributes	= INFO_IO_CLIENT|INFO_CARD_EXCL|INFO_CARD_SHARE;
-	cr.EventMask	= CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	    CS_EVENT_REGISTRATION_COMPLETE | CS_EVENT_CARD_REMOVAL_LOWP |
-	    CS_EVENT_CARD_READY | CS_EVENT_PM_RESUME |
-	    CS_EVENT_PM_SUSPEND | CS_EVENT_CLIENT_INFO;
-	cr.event_callback_args.client_data = pcwl_p;
-	cr.Version = CS_VERSION;
-	cr.event_handler = (csfunction_t *)pcwl_ev_hdlr;
-	cr.dip = dip;
-	(void) strcpy(cr.driver_name, pcwl_name_str);
-	if (ret = csx_RegisterClient(&chdl, &cr)) {
-		cmn_err(CE_WARN, "pcwl: RegisterClient failed %x\n", ret);
-		goto regcs_ret;
-	}
-	pcwl_p->pcwl_chdl = chdl;
-
-	bzero(&card_status, sizeof (card_status));
-	(void) csx_GetStatus(chdl, &card_status);
-	PCWLDBG((CE_NOTE,
-	    "pcwl: register_cs: Sock=%x CState=%x SState=%x rState=%x\n",
-	    card_status.Socket, card_status.CardState,
-	    card_status.SocketState, card_status.raw_CardState));
-	if (!(card_status.CardState & CS_STATUS_CARD_INSERTED)) {
-		/* card is not present, why are we attaching ? */
-		ret = CS_NO_CARD;
-		goto regcs_unreg;
-	}
-	cv_init(&pcwl_p->pcwl_cscv, NULL, CV_DRIVER, NULL);
-	mutex_init(&pcwl_p->pcwl_cslock, NULL, MUTEX_DRIVER, *cr.iblk_cookie);
-	mutex_enter(&pcwl_p->pcwl_cslock);
-	if (ret = csx_MapLogSocket(chdl, &pcwl_p->pcwl_log_sock)) {
-		cmn_err(CE_WARN, "pcwl: MapLogSocket failed %x\n", ret);
-		goto regcs_fail;
-	}
-	PCWLDBG((CE_NOTE,
-	    "pcwl: register_cs: LogSock=%x PhyAdapter=%x PhySock=%x\n",
-	    pcwl_p->pcwl_log_sock.LogSocket,
-	    pcwl_p->pcwl_log_sock.PhyAdapter,
-	    pcwl_p->pcwl_log_sock.PhySocket));
-	/* turn on initialization events */
-	sock_req.Socket = 0;
-	sock_req.EventMask = CS_EVENT_CARD_INSERTION | CS_EVENT_CARD_REMOVAL |
-	    CS_EVENT_REGISTRATION_COMPLETE;
-	if (ret = csx_RequestSocketMask(chdl, &sock_req)) {
-		cmn_err(CE_WARN, "pcwl: RequestSocketMask failed %x\n", ret);
-		goto regcs_fail;
-	}
-	/* wait for and process card insertion events */
-	while (!(pcwl_p->pcwl_flag & PCWL_CARD_READY))
-		cv_wait(&pcwl_p->pcwl_cscv, &pcwl_p->pcwl_cslock);
-	mutex_exit(&pcwl_p->pcwl_cslock);
-
-	pcwl_p->pcwl_flag |= PCWL_CS_REGISTERED;
-	return (PCWL_SUCCESS);
-regcs_fail:
-	mutex_destroy(&pcwl_p->pcwl_cslock);
-	cv_destroy(&pcwl_p->pcwl_cscv);
-regcs_unreg:
-	(void) csx_DeregisterClient(chdl);
-regcs_ret:
-	pcwl_p->pcwl_flag &= ~PCWL_CS_REGISTERED;
-	return (ret);
-}
-
-static void
-pcwl_unregister_cs(pcwl_maci_t *pcwl_p)
-{
-	int ret;
-	release_socket_mask_t mask;
-	mask.Socket = pcwl_p->pcwl_socket;
-
-	/*
-	 * The card service not registered means register_cs function
-	 * doesnot return TRUE. Then all the lelated resource has been
-	 * released in register_cs.
-	 */
-	if (!(pcwl_p->pcwl_flag | PCWL_CS_REGISTERED))
-		return;
-
-	if (ret = csx_ReleaseSocketMask(pcwl_p->pcwl_chdl, &mask))
-		cmn_err(CE_WARN, "pcwl: ReleaseSocket mask failed %x\n", ret);
-
-	if (pcwl_p->pcwl_flag & PCWL_CARD_READY) {
-		pcwl_card_remove(pcwl_p);
-		pcwl_p->pcwl_flag &= ~PCWL_CARD_READY;
-	}
-	mutex_destroy(&pcwl_p->pcwl_cslock);
-	cv_destroy(&pcwl_p->pcwl_cscv);
-	if (ret = csx_DeregisterClient(pcwl_p->pcwl_chdl))
-		cmn_err(CE_WARN, "pcwl: Deregister failed %x\n", ret);
-}
-
-static void
-pcwl_destroy_locks(pcwl_maci_t *pcwl_p)
-{
-	mutex_destroy(&pcwl_p->pcwl_txring.wl_tx_lock);
-	mutex_destroy(&pcwl_p->pcwl_scanlist_lock);
-	mutex_destroy(&pcwl_p->pcwl_glock);
-}
-
-static void
-pcwl_do_suspend(pcwl_maci_t *pcwl_p);
-
-static int
-pcwl_ev_hdlr(event_t event, int priority, event_callback_args_t *arg)
-{
-	int ret = CS_SUCCESS;
-	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg->client_data;
-	client_info_t *ci_p = (client_info_t *)&arg->client_info;
-
-	mutex_enter(&pcwl_p->pcwl_cslock);
-	switch (event) {
-	case CS_EVENT_CARD_INSERTION:
-		ret = pcwl_card_insert(pcwl_p);
-		cv_broadcast(&pcwl_p->pcwl_cscv);
-		break;
-	case CS_EVENT_REGISTRATION_COMPLETE:
-		cv_broadcast(&pcwl_p->pcwl_cscv);
-		break;
-	case CS_EVENT_CARD_REMOVAL:
-		if (priority & CS_EVENT_PRI_HIGH)
-			break;
-		pcwl_card_remove(pcwl_p);
-		cv_broadcast(&pcwl_p->pcwl_cscv);
-		break;
-	case CS_EVENT_CLIENT_INFO:
-		if (GET_CLIENT_INFO_SUBSVC(ci_p->Attributes) !=
-		    CS_CLIENT_INFO_SUBSVC_CS)
-			break;
-
-		ci_p->Revision = 0x0101;
-		ci_p->CSLevel = CS_VERSION;
-		ci_p->RevDate = CS_CLIENT_INFO_MAKE_DATE(9, 12, 14);
-		(void) strcpy(ci_p->ClientName, PCWL_IDENT_STRING);
-		(void) strcpy(ci_p->VendorName, CS_SUN_VENDOR_DESCRIPTION);
-		ci_p->Attributes |= CS_CLIENT_INFO_VALID;
-		break;
-	case CS_EVENT_PM_SUSPEND:
-		pcwl_do_suspend(pcwl_p);
-		break;
-	default:
-		ret = CS_UNSUPPORTED_EVENT;
-		break;
-	}
-	mutex_exit(&pcwl_p->pcwl_cslock);
-	return (ret);
-}
-
-/*
- * assume card is already removed, don't touch the hardware
- */
-static void
-pcwl_do_suspend(pcwl_maci_t *pcwl_p)
-{
-	int ret;
-
-	if (pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) {
-		if (pcwl_p->pcwl_connect_timeout_id != 0) {
-			(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
-			pcwl_p->pcwl_connect_timeout_id = 0;
-		}
-		mutex_enter(&pcwl_p->pcwl_glock);
-		pcwl_p->pcwl_flag &= ~PCWL_CARD_LINKUP;
-		(void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
-		/*
-		 * A workaround here: If the card is in ad-hoc mode, the
-		 * following scan will not work correctly, so any
-		 * 'dladm connect-wifi' which need a scan first will not
-		 * succeed. software reset the card here as a workround.
-		 */
-		if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_IBSS) &&
-		    (pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT)) {
-			(void) pcwl_reset_backend(pcwl_p);
-			(void) pcwl_init_nicmem(pcwl_p);
-			pcwl_start_locked(pcwl_p);
-		}
-		if (ret = pcwl_loaddef_rf(pcwl_p)) {
-			PCWLDBG((CE_WARN, "cfg_loaddef_err %d\n", ret));
-		}
-		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
-			PCWLDBG((CE_WARN, "set enable cmd err\n"));
-		}
-		pcwl_delay(pcwl_p, 1000000);
-		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
-			PCWLDBG((CE_WARN, "set disable cmd err\n"));
-		}
-		mac_link_update(GLD3(pcwl_p), LINK_STATE_DOWN);
-		mutex_exit(&pcwl_p->pcwl_glock);
-	}
-	pcwl_p->pcwl_flag |= PCWL_CARD_SUSPEND;
-	PCWLDBG((CE_WARN, "pcwl: do suspend\n"));
-}
-
-
-static int
-pcwl_card_insert(pcwl_maci_t *pcwl_p)
-{
-	int ret, hi, lo;
-	tuple_t tuple;
-	cisparse_t cisparse;
-	io_req_t	io;
-	irq_req_t	irq;
-	config_req_t	cfg;
-	cistpl_config_t config;
-	cistpl_cftable_entry_t *tbl_p;
-	register client_handle_t chdl = pcwl_p->pcwl_chdl;
-	modify_config_t cfgmod;
-
-	bzero(&tuple, sizeof (tuple));
-	tuple.DesiredTuple = CISTPL_MANFID;
-	if (ret = csx_GetFirstTuple(chdl, &tuple)) {
-		cmn_err(CE_WARN, "pcwl: get manufacture id failed %x\n", ret);
-		goto insert_ret;
-	}
-	bzero(&cisparse, sizeof (cisparse));
-	if (ret = csx_Parse_CISTPL_MANFID(chdl, &tuple, &cisparse.manfid)) {
-		cmn_err(CE_WARN, "pcwl: parse manufacture id failed %x\n", ret);
-		goto insert_ret;
-	}
-
-	/*
-	 * verify manufacture ID
-	 */
-	PCWLDBG((CE_NOTE, "pcwl insert: manufacturer_id=%x card=%x\n",
-	    cisparse.manfid.manf, cisparse.manfid.card));
-	bzero(&tuple, sizeof (tuple));
-	tuple.DesiredTuple = CISTPL_FUNCID;
-	if (ret = csx_GetFirstTuple(chdl, &tuple)) {
-		cmn_err(CE_WARN, "pcwl: get function id failed %x\n", ret);
-		goto insert_ret;
-	}
-	bzero(&cisparse, sizeof (cisparse));
-	if (ret = csx_Parse_CISTPL_FUNCID(chdl, &tuple, &cisparse.funcid)) {
-		cmn_err(CE_WARN, "pcwl: parse function id failed %x\n", ret);
-		goto insert_ret;
-	}
-
-	/*
-	 * verify function ID
-	 */
-	PCWLDBG((CE_NOTE, "insert:fun_id=%x\n", cisparse.funcid.function));
-	bzero(&tuple, sizeof (tuple));
-	tuple.DesiredTuple = CISTPL_CONFIG;
-	if (ret = csx_GetFirstTuple(chdl, &tuple)) {
-		cmn_err(CE_WARN, "pcwl: get config failed %x\n", ret);
-		goto insert_ret;
-	}
-	bzero(&config, sizeof (config));
-	if (ret = csx_Parse_CISTPL_CONFIG(chdl, &tuple, &config)) {
-		cmn_err(CE_WARN, "pcwl: parse config failed %x\n", ret);
-		goto insert_ret;
-	}
-	PCWLDBG((CE_NOTE,
-	    "pcwl: config present=%x nr=%x hr=%x regs[0]=%x base=%x last=%x\n",
-	    config.present, config.nr, config.hr, config.regs[0],
-	    config.base, config.last));
-	hi = 0;
-	lo = (int)-1;		/* really big number */
-	tbl_p = &cisparse.cftable;
-	tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY;
-	for (tbl_p->index = 0; tbl_p->index <= config.hr; ) {
-		PCWLDBG((CE_NOTE, "pcwl insert:tuple idx=%x:\n", tbl_p->index));
-		if (ret = csx_GetNextTuple(chdl, &tuple)) {
-			cmn_err(CE_WARN, "pcwl: get cftable failed %x\n",
-			    ret);
-			break;
-		}
-		bzero((caddr_t)&cisparse, sizeof (cisparse));
-		if (ret = csx_Parse_CISTPL_CFTABLE_ENTRY(chdl, &tuple, tbl_p)) {
-			cmn_err(CE_WARN, "pcwl: parse cftable failed %x\n",
-			    ret);
-			break;
-		}
-		if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_PWR &&
-		    tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC) {
-			if (tbl_p->pd.pd_vcc.avgI > hi) {
-				hi = tbl_p->pd.pd_vcc.avgI;
-				pcwl_p->pcwl_config_hi = tbl_p->index;
-			}
-			if (tbl_p->pd.pd_vcc.avgI < lo) {
-				lo = tbl_p->pd.pd_vcc.avgI;
-				pcwl_p->pcwl_config = tbl_p->index;
-			}
-		}
-		if (tbl_p->flags & CISTPL_CFTABLE_TPCE_DEFAULT) {
-			if (tbl_p->pd.flags & CISTPL_CFTABLE_TPCE_FS_PWR_VCC)
-				pcwl_p->pcwl_vcc = tbl_p->pd.pd_vcc.nomV;
-			if (tbl_p->flags & CISTPL_CFTABLE_TPCE_FS_IO)
-				pcwl_p->pcwl_iodecode = tbl_p->io.addr_lines;
-		}
-	}
-	PCWLDBG((CE_NOTE, "pcwl: insert:cfg_hi=%x cfg=%x vcc=%x iodecode=%x\n",
-	    pcwl_p->pcwl_config_hi, pcwl_p->pcwl_config,
-	    pcwl_p->pcwl_vcc, pcwl_p->pcwl_iodecode));
-	bzero(&io, sizeof (io));
-	io.BasePort1.base = 0;
-	io.NumPorts1 = 1 << pcwl_p->pcwl_iodecode;
-	io.Attributes1 = IO_DATA_PATH_WIDTH_16;
-	io.IOAddrLines = pcwl_p->pcwl_iodecode;
-	if (ret = csx_RequestIO(chdl, &io)) {
-		cmn_err(CE_WARN, "pcwl: RequestIO failed %x\n", ret);
-		goto insert_ret;
-	}
-	pcwl_p->pcwl_port = io.BasePort1.handle;
-	if (ret = ddi_add_softintr(DIP(pcwl_p), DDI_SOFTINT_HIGH,
-	    &pcwl_p->pcwl_softint_id, &pcwl_p->pcwl_ib_cookie, NULL,
-	    pcwl_intr, (caddr_t)pcwl_p)) {
-		cmn_err(CE_NOTE, "pcwl(pccard): add softintr failed\n");
-		goto insert_ret;
-	}
-	irq.Attributes = IRQ_TYPE_EXCLUSIVE;
-	irq.irq_handler = ddi_intr_hilevel(DIP(pcwl_p), 0) ?
-	    (csfunction_t *)pcwl_intr_hi : (csfunction_t *)pcwl_intr;
-	irq.irq_handler_arg = pcwl_p;
-	if (ret = csx_RequestIRQ(pcwl_p->pcwl_chdl, &irq)) {
-		cmn_err(CE_WARN, "pcwl: RequestIRQ failed %x\n", ret);
-		goto un_io;
-	}
-	bzero(&cfg, sizeof (cfg));
-	cfg.Attributes = 0; /* not ready for CONF_ENABLE_IRQ_STEERING yet */
-	cfg.Vcc = 50;
-	cfg.IntType = SOCKET_INTERFACE_MEMORY_AND_IO;
-	cfg.ConfigBase = config.base;
-	cfg.ConfigIndex = pcwl_p->pcwl_config;
-	cfg.Status = CCSR_IO_IS_8;
-	cfg.Present = config.present;
-	pcwl_p->pcwl_flag |= PCWL_CARD_READY;
-	if (ret = csx_RequestConfiguration(chdl, &cfg)) {
-		cmn_err(CE_WARN, "pcwl: RequestConfiguration failed %x\n", ret);
-		goto un_irq;
-	}
-
-	if (pcwl_p->pcwl_flag & PCWL_CARD_SUSPEND) {
-		mutex_enter(&pcwl_p->pcwl_glock);
-		(void) pcwl_reset_backend(pcwl_p);
-		/* turn on CS interrupt */
-		cfgmod.Attributes = CONF_ENABLE_IRQ_STEERING |
-		    CONF_IRQ_CHANGE_VALID;
-		cfgmod.Vpp1 = 50;
-		cfgmod.Vpp2 = 50;
-		(void) csx_ModifyConfiguration(pcwl_p->pcwl_chdl, &cfgmod);
-
-		(void) pcwl_init_nicmem(pcwl_p);
-		pcwl_chip_type(pcwl_p);
-		(void) pcwl_loaddef_rf(pcwl_p);
-		(void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
-		pcwl_stop_locked(pcwl_p);	/* leaves interface down */
-		pcwl_p->pcwl_flag &= ~PCWL_CARD_SUSPEND;
-		mutex_exit(&pcwl_p->pcwl_glock);
-	}
-	if (pcwl_p->pcwl_flag & PCWL_CARD_PLUMBED) {
-		(void) pcwl_start(pcwl_p);
-		pcwl_p->pcwl_flag &= ~PCWL_CARD_PLUMBED;
-	}
-	return (CS_SUCCESS);
-un_irq:
-	(void) csx_ReleaseIRQ(chdl, &irq);
-un_io:
-	ddi_remove_softintr(pcwl_p->pcwl_softint_id);
-	(void) csx_ReleaseIO(chdl, &io);
-	pcwl_p->pcwl_port = 0;
-insert_ret:
-	pcwl_p->pcwl_flag &= ~PCWL_CARD_READY;
-	return (ret);
-
-}
-
-/*
- * assume card is already removed, don't touch the hardware
- */
-static void
-pcwl_card_remove(pcwl_maci_t *pcwl_p)
-{
-	int ret;
-	io_req_t io;
-	irq_req_t irq;
-
-	/*
-	 * The card not ready means Insert function doesnot return TRUE.
-	 * then the IO and IRQ has been released in Insert
-	 */
-	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY))
-		return;
-
-	if (pcwl_p->pcwl_connect_timeout_id != 0) {
-		(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
-		pcwl_p->pcwl_connect_timeout_id = 0;
-	}
-
-	if (pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) {
-		pcwl_p->pcwl_flag &= ~PCWL_CARD_LINKUP;
-		mac_link_update(GLD3(pcwl_p), LINK_STATE_DOWN);
-	}
-	mutex_enter(&pcwl_p->pcwl_glock);
-	if (pcwl_p->pcwl_flag & PCWL_CARD_INTREN) {
-		pcwl_stop_locked(pcwl_p);
-		pcwl_p->pcwl_flag |= PCWL_CARD_PLUMBED;
-	}
-	pcwl_p->pcwl_flag &= ~PCWL_CARD_READY;
-	mutex_exit(&pcwl_p->pcwl_glock);
-	if (ret = csx_ReleaseConfiguration(pcwl_p->pcwl_chdl, NULL))
-		cmn_err(CE_WARN, "pcwl: ReleaseConfiguration failed %x\n", ret);
-
-	bzero(&irq, sizeof (irq));
-	if (ret = csx_ReleaseIRQ(pcwl_p->pcwl_chdl, &irq))
-		cmn_err(CE_WARN, "pcwl: ReleaseIRQ failed %x\n", ret);
-
-	ddi_remove_softintr(pcwl_p->pcwl_softint_id);
-
-	bzero(&io, sizeof (io));
-	io.BasePort1.handle = pcwl_p->pcwl_port;
-	io.NumPorts1 = 16;
-	if (ret = csx_ReleaseIO(pcwl_p->pcwl_chdl, &io))
-		cmn_err(CE_WARN, "pcwl: ReleaseIO failed %x\n", ret);
-
-	pcwl_p->pcwl_port = 0;
-}
-
-/*
- * mac operation interface routines
- */
-static int
-pcwl_start(void *arg)
-{
-	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
-
-	mutex_enter(&pcwl_p->pcwl_glock);
-	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
-		mutex_exit(&pcwl_p->pcwl_glock);
-		return (PCWL_FAIL);
-	}
-	pcwl_start_locked(pcwl_p);
-	mutex_exit(&pcwl_p->pcwl_glock);
-	return (PCWL_SUCCESS);
-}
-
-static void
-pcwl_stop(void *arg)
-{
-	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
-
-	PCWLDBG((CE_NOTE, "pcwl_stop called\n"));
-	mutex_enter(&pcwl_p->pcwl_glock);
-	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
-		mutex_exit(&pcwl_p->pcwl_glock);
-		return;
-	}
-
-	pcwl_stop_locked(pcwl_p);
-	mutex_exit(&pcwl_p->pcwl_glock);
-	if (pcwl_p->pcwl_connect_timeout_id != 0) {
-		(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
-		pcwl_p->pcwl_connect_timeout_id = 0;
-	}
-}
-
-static int
-pcwl_saddr(void *arg, const uint8_t *macaddr)
-{
-	int ret = PCWL_SUCCESS;
-	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
-
-	mutex_enter(&pcwl_p->pcwl_glock);
-	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
-		ret = PCWL_FAIL;
-		goto done;
-	}
-	ether_copy(macaddr, pcwl_p->pcwl_mac_addr);
-	if (pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
-		ret = PCWL_FAIL;
-		goto done;
-	}
-	if (pcwl_saddr_locked(pcwl_p)) {
-		ret = PCWL_FAIL;
-		goto done;
-	}
-	if (pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
-		ret = PCWL_FAIL;
-	}
-done:
-	if (ret)
-		cmn_err(CE_WARN, "pcwl set_mac_addr: failed\n");
-	mutex_exit(&pcwl_p->pcwl_glock);
-	return (ret);
-}
-
-static int
-pcwl_send(pcwl_maci_t *pcwl_p, mblk_t *mblk_p)
-{
-	int i = 0;
-	char *buf, *buf_p;
-	wl_frame_t *frm_p;
-	uint16_t pkt_len, ret;
-	uint16_t xmt_id, ring_idx;
-	struct ieee80211_frame *wh;
-	struct ieee80211_llc *llc;
-
-	mutex_enter(&pcwl_p->pcwl_glock);
-	if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_LINKUP)) !=
-	    (PCWL_CARD_READY | PCWL_CARD_LINKUP)) {
-		mutex_exit(&pcwl_p->pcwl_glock);
-		freemsg(mblk_p);
-		return (PCWL_SUCCESS);		/* drop packet */
-	}
-	mutex_exit(&pcwl_p->pcwl_glock);
-
-	if (pullupmsg(mblk_p, -1) == 0) {
-		freemsg(mblk_p);
-		return (PCWL_SUCCESS);		/* drop packet */
-	}
-	wh = (struct ieee80211_frame *)mblk_p->b_rptr;
-	llc = (struct ieee80211_llc *)&wh[1];
-
-	mutex_enter(&pcwl_p->pcwl_txring.wl_tx_lock);
-	ring_idx = pcwl_p->pcwl_txring.wl_tx_prod;
-	pcwl_p->pcwl_txring.wl_tx_prod = (ring_idx + 1) & (WL_XMT_BUF_NUM - 1);
-
-	/*
-	 * check whether there is a xmt buffer available
-	 */
-	while ((i < WL_XMT_BUF_NUM) &&
-	    (pcwl_p->pcwl_txring.wl_tx_ring[ring_idx])) {
-		ring_idx = pcwl_p->pcwl_txring.wl_tx_prod;
-		pcwl_p->pcwl_txring.wl_tx_prod =
-		    (ring_idx + 1) & (WL_XMT_BUF_NUM - 1);
-		i++;
-	}
-	if (i == WL_XMT_BUF_NUM) {
-		mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock);
-		mutex_enter(&pcwl_p->pcwl_glock);
-		pcwl_p->pcwl_reschedule_need = B_TRUE;
-		mutex_exit(&pcwl_p->pcwl_glock);
-		pcwl_p->pcwl_noxmtbuf++;
-		return (PCWL_FAIL);
-	}
-	xmt_id = pcwl_p->pcwl_txring.wl_tx_fids[ring_idx];
-	pcwl_p->pcwl_txring.wl_tx_ring[ring_idx] = xmt_id;
-	mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock);
-
-	buf = kmem_zalloc(PCWL_NICMEM_SZ, KM_SLEEP);
-	buf_p = (ulong_t)buf & 1 ? buf + 1 : buf;
-	frm_p = (wl_frame_t *)buf_p;
-#ifdef DEBUG
-	if (pcwl_debug & PCWL_DBG_SEND) {
-		cmn_err(CE_NOTE, "pcwl send: packet");
-		for (i = 0; i < MBLKL(mblk_p); i++)
-			cmn_err(CE_NOTE, "%x: %x\n", i,
-			    *((unsigned char *)mblk_p->b_rptr + i));
-	}
-#endif
-	pkt_len = msgdsize(mblk_p);
-	if (pkt_len > (PCWL_NICMEM_SZ - sizeof (wl_frame_t))) {
-		cmn_err(CE_WARN, "pcwl: send mblk is too long");
-		kmem_free(buf, PCWL_NICMEM_SZ);
-		freemsg(mblk_p);
-		return (PCWL_SUCCESS);		/* drop packet */
-	}
-	if ((wh->i_fc[1] & IEEE80211_FC1_DIR_MASK) !=
-	    IEEE80211_FC1_DIR_TODS) {
-		kmem_free(buf, PCWL_NICMEM_SZ);
-		freemsg(mblk_p);
-		return (PCWL_SUCCESS);		/* drop packet */
-	}
-	bzero(frm_p, WL_802_11_HDRLEN);
-
-	frm_p->wl_tx_ctl = WL_TXCNTL_SET;
-	bcopy(wh->i_addr3, frm_p->wl_dst_addr, ETHERADDRL); /* dst macaddr */
-	bcopy(wh->i_addr2, frm_p->wl_src_addr, ETHERADDRL); /* src macaddr */
-	frm_p->wl_len = htons(pkt_len  - sizeof (*wh));
-	bcopy(llc, &frm_p->wl_dat[0], pkt_len - sizeof (*wh));
-	pkt_len = pkt_len - (sizeof (*wh) + sizeof (*llc)) +
-	    WL_802_11_HDRLEN;
-	PCWLDBG((CE_NOTE, "send: DIX frmsz=%x pkt_len=%x\n",
-	    WL_802_11_HDRLEN, pkt_len));
-
-	if (pkt_len & 1)	/* round up to 16-bit boundary and pad 0 */
-		buf_p[pkt_len++] = 0;
-
-	ASSERT(pkt_len <= PCWL_NICMEM_SZ);
-#ifdef DEBUG
-	if (pcwl_debug & PCWL_DBG_SEND) {
-		cmn_err(CE_NOTE, "pkt_len = %x\n", pkt_len);
-		for (i = 0; i < pkt_len; i++)
-			cmn_err(CE_NOTE, "%x: %x\n", i,
-			    *((unsigned char *)buf + i));
-	}
-#endif
-	mutex_enter(&pcwl_p->pcwl_glock);
-	ret = (WRCH1(pcwl_p, xmt_id, 0, (uint16_t *)buf_p, 0x2e) ||
-	    WRPKT(pcwl_p, xmt_id, 0x2e, (uint16_t *)(buf_p + 0x2e),
-	    pkt_len - 0x2e));
-	if (ret) {
-		goto done;
-	}
-	PCWLDBG((CE_NOTE, "send: xmt_id=%x send=%x\n", xmt_id, pkt_len));
-	(void) pcwl_set_cmd(pcwl_p, WL_CMD_TX | WL_RECLAIM, xmt_id);
-
-done:
-	mutex_exit(&pcwl_p->pcwl_glock);
-	kmem_free(buf, PCWL_NICMEM_SZ);
-	freemsg(mblk_p);
-	return (PCWL_SUCCESS);
-}
-
-static mblk_t *
-pcwl_tx(void *arg, mblk_t *mp)
-{
-	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
-	mblk_t *next;
-
-	ASSERT(mp != NULL);
-	mutex_enter(&pcwl_p->pcwl_glock);
-	if ((pcwl_p->pcwl_flag & (PCWL_CARD_LINKUP | PCWL_CARD_READY)) !=
-	    (PCWL_CARD_LINKUP | PCWL_CARD_READY)) {
-		mutex_exit(&pcwl_p->pcwl_glock);
-		freemsgchain(mp);
-		return (NULL);
-	}
-	mutex_exit(&pcwl_p->pcwl_glock);
-	while (mp != NULL) {
-		next =  mp->b_next;
-		mp->b_next = NULL;
-
-		if (pcwl_send(pcwl_p, mp)) {
-			mp->b_next = next;
-			break;
-		}
-		mp = next;
-	}
-	return (mp);
-}
-
-static int
-pcwl_prom(void *arg, boolean_t on)
-{
-	int ret = PCWL_SUCCESS;
-	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
-
-	mutex_enter(&pcwl_p->pcwl_glock);
-	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
-		ret = PCWL_FAIL;
-		goto done;
-	}
-
-	PCWLDBG((CE_NOTE, "pcwl_prom called %x\n", on));
-
-	if (on)
-		pcwl_p->pcwl_rf.rf_promiscuous = 1;
-	else
-		pcwl_p->pcwl_rf.rf_promiscuous = 0;
-	if (ret = pcwl_fil_ltv(pcwl_p, 2, WL_RID_PROMISC,
-	    pcwl_p->pcwl_rf.rf_promiscuous)) {
-		ret = PCWL_FAIL;
-	}
-done:
-	if (ret)
-		cmn_err(CE_WARN, "pcwl promisc: failed\n");
-	mutex_exit(&pcwl_p->pcwl_glock);
-	return (ret);
-}
-
-static int
-pcwl_gstat(void *arg, uint_t statitem, uint64_t *val)
-{
-	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
-	int ret = PCWL_SUCCESS;
-	uint64_t *cntr_p = pcwl_p->pcwl_cntrs_s;
-	uint16_t rate = 0;
-	uint64_t speed;
-
-	PCWLDBG((CE_NOTE, "pcwl_gstat called\n"));
-	mutex_enter(&pcwl_p->pcwl_glock);
-	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
-		ret = PCWL_FAIL;
-		goto done;
-	}
-
-	if (pcwl_get_ltv(pcwl_p, 2, WL_RID_CUR_TX_RATE, &rate)) {
-		cmn_err(CE_WARN, "pcwl kstat: get speed failed\n");
-		ret = PCWL_FAIL;
-		goto done;
-	}
-	switch (pcwl_p->pcwl_chip_type) {
-	case PCWL_CHIP_PRISMII:
-		switch (rate) {
-		case WL_SPEED_1Mbps_P2:		rate = 2;	break;
-		case WL_SPEED_2Mbps_P2:		rate = 4;	break;
-		case WL_SPEED_55Mbps_P2:	rate = 11;	break;
-		case WL_SPEED_11Mbps_P2:	rate = 22;	break;
-		default:			rate = 0;	break;
-		}
-		speed = rate * 500000;
-		break;
-	case PCWL_CHIP_LUCENT:
-	default:
-		speed = rate * 1000000;
-		if (rate == 6)
-			speed = 5500000;
-		break;
-	}
-
-	switch (statitem) {
-	case MAC_STAT_IFSPEED:
-		*val = speed;
-		break;
-	case MAC_STAT_NOXMTBUF:
-		*val = pcwl_p->pcwl_noxmtbuf;
-		break;
-	case MAC_STAT_NORCVBUF:
-		*val = cntr_p[WLC_RX_DISCARDS_NOBUF];
-		break;
-	case MAC_STAT_IERRORS:
-		*val = 0;
-		break;
-	case MAC_STAT_OERRORS:
-		*val = cntr_p[WLC_TX_DISCARDS] +
-		    cntr_p[WLC_TX_DISCARDS_WRONG_SA];
-		break;
-	case MAC_STAT_RBYTES:
-		*val = cntr_p[WLC_RX_UNICAST_OCTETS];
-		break;
-	case MAC_STAT_IPACKETS:
-		*val = cntr_p[WLC_RX_UNICAST_FRAMES];
-		break;
-	case MAC_STAT_OBYTES:
-		*val = cntr_p[WLC_TX_UNICAST_OCTETS];
-		break;
-	case MAC_STAT_OPACKETS:
-		*val = cntr_p[WLC_TX_UNICAST_FRAMES];
-		break;
-	case WIFI_STAT_TX_FAILED:
-		*val = cntr_p[WLC_TX_RETRY_LIMIT] +
-		    cntr_p[WLC_TX_DEFERRED_XMITS];
-		break;
-	case WIFI_STAT_TX_RETRANS:
-		*val = cntr_p[WLC_TX_SINGLE_RETRIES] +
-		    cntr_p[WLC_TX_MULTI_RETRIES];
-		break;
-	case WIFI_STAT_FCS_ERRORS:
-		*val = cntr_p[WLC_RX_FCS_ERRORS];
-		break;
-	case WIFI_STAT_WEP_ERRORS:
-		*val = cntr_p[WLC_RX_WEP_CANT_DECRYPT];
-		break;
-	case WIFI_STAT_MCAST_TX:
-		*val = cntr_p[WLC_TX_MULTICAST_FRAMES];
-		break;
-	case WIFI_STAT_MCAST_RX:
-		*val = cntr_p[WLC_RX_MULTICAST_FRAMES];
-		break;
-	case WIFI_STAT_TX_FRAGS:
-		*val = cntr_p[WLC_TX_FRAGMENTS];
-		break;
-	case WIFI_STAT_RX_FRAGS:
-		*val =	cntr_p[WLC_RX_FRAGMENTS] +
-		    cntr_p[WLC_RX_MSG_IN_MSG_FRAGS] +
-		    cntr_p[WLC_RX_MSG_IN_BAD_MSG_FRAGS];
-		break;
-	case WIFI_STAT_RTS_SUCCESS:
-	case WIFI_STAT_RTS_FAILURE:
-	case WIFI_STAT_ACK_FAILURE:
-	case WIFI_STAT_RX_DUPS:
-		*val = 0;
-		break;
-	default:
-		ret = ENOTSUP;
-	}
-done:
-	mutex_exit(&pcwl_p->pcwl_glock);
-	return (ret);
-}
-
-static int
-pcwl_sdmulti(void *arg, boolean_t add, const uint8_t *eth_p)
-{
-	int ret = PCWL_SUCCESS;
-	uint16_t i;
-	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
-	uint16_t *mc_p = pcwl_p->pcwl_mcast;
-
-	mutex_enter(&pcwl_p->pcwl_glock);
-	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
-		ret = PCWL_FAIL;
-		goto done;
-	}
-
-	if (add) { /* enable multicast on eth_p, search for available entries */
-		for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) {
-			if (!ether_cmp(eth_p, mc_p))
-				break;
-		}
-		if (i < 16)	/* already part of the filter */
-			goto done;
-		mc_p = pcwl_p->pcwl_mcast;	/* reset mc_p for 2nd scan */
-		for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) {
-			PCWLDBG((CE_NOTE, "smulti: mc[%x]=%s\n", i,
-			    ether_sprintf((struct ether_addr *)mc_p)));
-			if (mc_p[0] == 0 && mc_p[1] == 0 && mc_p[2] == 0)
-				break;
-		}
-		if (i >= 16)	/* can't find a vacant entry */
-			goto done;
-		ether_copy(eth_p, mc_p);
-	} else { /* disable multicast, locate the entry and clear it */
-		for (i = 0; i < 16; i++, mc_p += (ETHERADDRL >> 1)) {
-			if (!ether_cmp(eth_p, mc_p))
-				break;
-		}
-		if (i >= 16)
-			goto done;
-		mc_p[0] = 0;
-		mc_p[1] = 0;
-		mc_p[2] = 0;
-	}
-	/*
-	 * re-blow the entire 16 entries buffer
-	 */
-	if (i = pcwl_put_ltv(pcwl_p, ETHERADDRL << 4, WL_RID_MCAST,
-	    pcwl_p->pcwl_mcast)) {
-		ret = PCWL_FAIL;
-	}
-done:
-	if (ret)
-		cmn_err(CE_WARN, "pcwl set multi addr: failed\n");
-	mutex_exit(&pcwl_p->pcwl_glock);
-	return (ret);
-}
-
-static uint_t
-pcwl_intr(caddr_t arg)
-{
-	uint16_t stat;
-	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
-
-	mutex_enter(&pcwl_p->pcwl_glock);
-	if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_INTREN)) !=
-	    (PCWL_CARD_READY | PCWL_CARD_INTREN)) {
-		mutex_exit(&pcwl_p->pcwl_glock);
-		return (DDI_INTR_UNCLAIMED);
-	}
-	PCWL_READ(pcwl_p, WL_EVENT_STAT, stat);
-	if (!(stat & WL_INTRS) || stat == WL_EV_ALL) {
-		mutex_exit(&pcwl_p->pcwl_glock);
-		return (DDI_INTR_UNCLAIMED);
-	}
-
-	PCWL_WRITE(pcwl_p, WL_INT_EN, 0);
-	if (stat & WL_EV_RX) {
-		pcwl_rcv(pcwl_p);
-		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_RX);
-		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_RX);
-	}
-	if (stat & WL_EV_TX) {
-		if (pcwl_txdone(pcwl_p) == PCWL_SUCCESS) {
-			if (pcwl_p->pcwl_reschedule_need == B_TRUE) {
-				mutex_exit(&pcwl_p->pcwl_glock);
-				mac_tx_update(GLD3(pcwl_p));
-				mutex_enter(&pcwl_p->pcwl_glock);
-				pcwl_p->pcwl_reschedule_need = B_FALSE;
-			}
-		}
-		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX);
-		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX);
-	}
-	if (stat & WL_EV_ALLOC) {
-		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_ALLOC | 0x1000);
-		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, 0x1000);
-	}
-	if (stat & WL_EV_INFO) {
-		pcwl_infodone(pcwl_p);
-		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO);
-		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO);
-	}
-	if (stat & WL_EV_TX_EXC) {
-		if (pcwl_txdone(pcwl_p) == PCWL_SUCCESS) {
-			if (pcwl_p->pcwl_reschedule_need == B_TRUE) {
-				mutex_exit(&pcwl_p->pcwl_glock);
-				mac_tx_update(GLD3(pcwl_p));
-				mutex_enter(&pcwl_p->pcwl_glock);
-				pcwl_p->pcwl_reschedule_need = B_FALSE;
-			}
-		}
-		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX_EXC);
-		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX_EXC);
-	}
-	if (stat & WL_EV_INFO_DROP) {
-		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO_DROP);
-		PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_INFO_DROP);
-	}
-	PCWL_ENABLE_INTR(pcwl_p);
-	mutex_exit(&pcwl_p->pcwl_glock);
-
-	return (DDI_INTR_CLAIMED);
-}
-
-static uint_t
-pcwl_intr_hi(caddr_t arg)
-{
-	uint16_t stat;
-	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
-
-	mutex_enter(&pcwl_p->pcwl_glock);
-	if ((pcwl_p->pcwl_flag & (PCWL_CARD_READY | PCWL_CARD_INTREN)) !=
-	    (PCWL_CARD_READY | PCWL_CARD_INTREN)) {
-		mutex_exit(&pcwl_p->pcwl_glock);
-		return (DDI_INTR_UNCLAIMED);
-	}
-	PCWL_READ(pcwl_p, WL_EVENT_STAT, stat);
-	if (!(stat & WL_INTRS) || stat == WL_EV_ALL) {
-		mutex_exit(&pcwl_p->pcwl_glock);
-		return (DDI_INTR_UNCLAIMED);
-	}
-	PCWL_WRITE(pcwl_p, WL_INT_EN, 0); /* disable interrupt without ack */
-	mutex_exit(&pcwl_p->pcwl_glock);
-	ddi_trigger_softintr(pcwl_p->pcwl_softint_id);
-	return (DDI_INTR_CLAIMED);
-}
-
-/*
- * called at interrupt context to retrieve data from card
- */
-static void
-pcwl_rcv(pcwl_maci_t *pcwl_p)
-{
-	uint16_t id, len, off, ret, frm_ctl;
-	wl_frame_t frm;
-	mblk_t *mp = allocb(PCWL_NICMEM_SZ, BPRI_MED);
-	if (!mp)
-		return;
-	ASSERT(mp->b_rptr == mp->b_wptr);
-
-	PCWL_READ(pcwl_p, WL_RX_FID, id);
-	PCWL_WRITE(pcwl_p, WL_RX_FID, 0);
-	if (id == WL_INVALID_FID) {
-		PCWLDBG((CE_NOTE, "pcwl rcv: get rx_fid failed\n"));
-		ret = PCWL_FAIL;
-		goto done;
-	}
-	if (ret = RDCH0(pcwl_p, id, 0, (uint16_t *)&frm, sizeof (frm))) {
-		PCWLDBG((CE_NOTE, "pcwl rcv: read frm failed %x\n", ret));
-		goto done;
-	}
-	if (frm.wl_status & WL_STAT_ERRSTAT) {
-		PCWLDBG((CE_NOTE, "pcwl rcv: errstat %x\n", frm.wl_status));
-		ret = frm.wl_status;
-		goto done;
-	}
-	PCWLDBG((CE_NOTE, "pcwl rcv: frame type %x\n", frm.wl_status));
-#ifdef DEBUG
-	if (pcwl_debug & PCWL_DBG_RCV) {
-		int i;
-		cmn_err(CE_NOTE, "pcwl rcv: frm header\n");
-		for (i = 0; i < WL_802_11_HDRLEN; i++)
-			cmn_err(CE_NOTE, "%x: %x\n", i,
-			    *((uint8_t *)&frm + i));
-	}
-#endif
-	len = frm.wl_dat_len;
-	/*
-	 * this driver deal with WEP by itself. so plugin always thinks no wep.
-	 */
-	frm.wl_frame_ctl &= ~(IEEE80211_FC1_WEP << 8);
-	frm_ctl = frm.wl_frame_ctl;
-	switch (frm.wl_status) {
-	case WL_STAT_1042:
-	case WL_STAT_TUNNEL:
-	case WL_STAT_WMP_MSG:
-		PCWL_SWAP16((uint16_t *)&frm.wl_frame_ctl,
-		    sizeof (struct ieee80211_frame));
-		/*
-		 * discard those frames which are not from the AP we connect or
-		 * without 'ap->sta' direction
-		 */
-		if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_BSS) &&
-		    ((((frm_ctl >> 8) & IEEE80211_FC1_DIR_MASK) !=
-		    IEEE80211_FC1_DIR_FROMDS) ||
-		    bcmp(pcwl_p->pcwl_bssid, frm.wl_addr2, 6) != 0)) {
-			ret = PCWL_FAIL;
-			goto done;
-		}
-
-		bcopy(&frm.wl_frame_ctl, mp->b_wptr,
-		    sizeof (struct ieee80211_frame));
-		mp->b_wptr += sizeof (struct ieee80211_frame);
-
-		PCWL_SWAP16((uint16_t *)&frm.wl_dat[0],
-		    sizeof (struct ieee80211_llc));
-		bcopy(&frm.wl_dat[0], mp->b_wptr,
-		    sizeof (struct ieee80211_llc));
-		mp->b_wptr += sizeof (struct ieee80211_llc);
-
-		len -= (2 + WL_SNAPHDR_LEN);
-		off = WL_802_11_HDRLEN;
-		break;
-	default:
-		PCWLDBG((CE_NOTE, "pcwl rcv: incorrect pkt\n"));
-		break;
-	}
-	if (len > MBLKSIZE(mp)) {
-		PCWLDBG((CE_NOTE, "pcwl rcv: oversz pkt %x\n", len));
-		ret = PCWL_FAIL;
-		goto done;
-	}
-	if (len & 1)
-		len++;
-	ret = RDPKT(pcwl_p, id, off, (uint16_t *)mp->b_wptr, len);
-done:
-	if (ret) {
-		PCWLDBG((CE_NOTE, "pcwl rcv: rd data %x\n", ret));
-		freemsg(mp);
-		return;
-	}
-	mp->b_wptr = mp->b_wptr + len;
-#ifdef DEBUG
-	if (pcwl_debug & PCWL_DBG_RCV) {
-		int i;
-		cmn_err(CE_NOTE, "pcwl rcv: len=0x%x\n", len);
-		for (i = 0; i < len+14; i++)
-			cmn_err(CE_NOTE, "%x: %x\n", i,
-			    *((uint8_t *)mp->b_rptr + i));
-	}
-#endif
-	mutex_exit(&pcwl_p->pcwl_glock);
-	mac_rx(GLD3(pcwl_p), NULL, mp);
-	mutex_enter(&pcwl_p->pcwl_glock);
-}
-
-static uint32_t
-pcwl_txdone(pcwl_maci_t *pcwl_p)
-{
-	uint16_t fid, i;
-	PCWL_READ(pcwl_p, WL_ALLOC_FID, fid);
-	PCWL_WRITE(pcwl_p, WL_ALLOC_FID, 0);
-
-	mutex_enter(&pcwl_p->pcwl_txring.wl_tx_lock);
-	for (i = 0; i < WL_XMT_BUF_NUM; i++) {
-		if (fid == pcwl_p->pcwl_txring.wl_tx_ring[i]) {
-			pcwl_p->pcwl_txring.wl_tx_ring[i] = 0;
-			break;
-		}
-	}
-	pcwl_p->pcwl_txring.wl_tx_cons =
-	    (pcwl_p->pcwl_txring.wl_tx_cons + 1) & (WL_XMT_BUF_NUM - 1);
-	mutex_exit(&pcwl_p->pcwl_txring.wl_tx_lock);
-	if (i == WL_XMT_BUF_NUM)
-		return (PCWL_FAIL);
-	return (PCWL_SUCCESS);
-
-}
-
-static void
-pcwl_infodone(pcwl_maci_t *pcwl_p)
-{
-	uint16_t id, ret, i;
-	uint16_t linkStatus[2];
-	uint16_t linkStat;
-	wifi_data_t wd = { 0 };
-
-	PCWL_READ(pcwl_p, WL_INFO_FID, id);
-	if (id == WL_INVALID_FID) {
-		cmn_err(CE_WARN, "pcwl infodone: read info_fid failed\n");
-		return;
-	}
-	if (ret = RDCH0(pcwl_p, id, 0, linkStatus, sizeof (linkStatus))) {
-		PCWLDBG((CE_WARN, "pcwl infodone read infoFrm failed %x\n",
-		    ret));
-		return;
-	}
-	PCWLDBG((CE_NOTE, "pcwl infodone: Frame length= %x, Frame Type = %x\n",
-	    linkStatus[0], linkStatus[1]));
-
-	switch (linkStatus[1]) {
-	case WL_INFO_LINK_STAT:
-		(void) RDCH0(pcwl_p, id, sizeof (linkStatus), &linkStat,
-		    sizeof (linkStat));
-		PCWLDBG((CE_NOTE, "pcwl infodone: link status=%x\n", linkStat));
-		if (!(pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) &&
-		    linkStat == WL_LINK_CONNECT) {
-#ifdef DEBUG
-		if (pcwl_debug & PCWL_DBG_LINKINFO)
-			cmn_err(CE_NOTE, "pcwl: Link up \n");
-#endif
-			pcwl_p->pcwl_flag |= PCWL_CARD_LINKUP;
-			mutex_exit(&pcwl_p->pcwl_glock);
-			if (pcwl_p->pcwl_connect_timeout_id != 0) {
-				(void) untimeout(pcwl_p->
-				    pcwl_connect_timeout_id);
-				pcwl_p->pcwl_connect_timeout_id = 0;
-			}
-			mutex_enter(&pcwl_p->pcwl_glock);
-			mac_link_update(GLD3(pcwl_p), LINK_STATE_UP);
-			(void) pcwl_get_ltv(pcwl_p, 6,
-			    WL_RID_BSSID, (uint16_t *)pcwl_p->pcwl_bssid);
-			PCWL_SWAP16((uint16_t *)pcwl_p->pcwl_bssid, 6);
-			pcwl_get_rssi(pcwl_p);
-			bcopy(pcwl_p->pcwl_bssid, wd.wd_bssid, 6);
-			wd.wd_secalloc = WIFI_SEC_NONE;
-			wd.wd_opmode = IEEE80211_M_STA;
-			(void) mac_pdata_update(pcwl_p->pcwl_mh, &wd,
-			    sizeof (wd));
-		}
-		if ((pcwl_p->pcwl_flag & PCWL_CARD_LINKUP) &&
-		    ((linkStat == WL_LINK_DISCONNECT) ||
-		    (linkStat == WL_LINK_AP_OOR))) {
-#ifdef DEBUG
-		if (pcwl_debug & PCWL_DBG_LINKINFO)
-			cmn_err(CE_NOTE, "pcwl: Link down \n");
-#endif
-			PCWLDBG((CE_NOTE, "pcwl infodone: link status = %d\n",
-			    linkStat));
-			pcwl_p->pcwl_flag &= ~PCWL_CARD_LINKUP;
-			if (linkStat == WL_LINK_AP_OOR)
-				pcwl_p->pcwl_connect_timeout_id =
-				    timeout(pcwl_connect_timeout,
-				    pcwl_p, drv_usectohz(1000));
-			mutex_exit(&pcwl_p->pcwl_glock);
-			mac_link_update(GLD3(pcwl_p), LINK_STATE_DOWN);
-			mutex_enter(&pcwl_p->pcwl_glock);
-		}
-		break;
-	case WL_INFO_SCAN_RESULTS:
-	case WL_INFO_HSCAN_RESULTS:
-		pcwl_ssid_scan(pcwl_p, id, linkStatus[0], linkStatus[1]);
-			break;
-	case WL_INFO_COUNTERS:
-		linkStatus[0]--;
-		if (linkStatus[0] > WLC_STAT_CNT) {
-			linkStatus[0] = MIN(linkStatus[0], WLC_STAT_CNT);
-		}
-		(void) RDCH0(pcwl_p, id, sizeof (linkStatus),
-		    pcwl_p->pcwl_cntrs_t, linkStatus[0]<<1);
-		/*
-		 * accumulate all the statistics items for kstat use.
-		 */
-		for (i = 0; i < WLC_STAT_CNT; i++)
-			pcwl_p->pcwl_cntrs_s[i] += pcwl_p->pcwl_cntrs_t[i];
-		break;
-	default:
-		break;
-	}
-}
-
-static uint16_t
-pcwl_set_cmd(pcwl_maci_t *pcwl_p, uint16_t cmd, uint16_t param)
-{
-	int i;
-	uint16_t stat;
-
-	if (((cmd == WL_CMD_ENABLE) &&
-	    ((pcwl_p->pcwl_flag & PCWL_ENABLED) != 0)) ||
-	    ((cmd == WL_CMD_DISABLE) &&
-	    ((pcwl_p->pcwl_flag & PCWL_ENABLED) == 0)))
-		return (PCWL_SUCCESS);
-
-	for (i = 0; i < WL_TIMEOUT; i++) {
-		PCWL_READ(pcwl_p, WL_COMMAND, stat);
-		if (stat & WL_CMD_BUSY) {
-			drv_usecwait(1);
-		} else {
-			break;
-		}
-	}
-	if (i == WL_TIMEOUT) {
-		cmn_err(CE_WARN, "pcwl: setcmd %x, %x timeout %x due to "
-		    "busy bit\n", cmd, param, stat);
-		return (PCWL_TIMEDOUT_CMD);
-	}
-
-	PCWL_WRITE(pcwl_p, WL_PARAM0, param);
-	PCWL_WRITE(pcwl_p, WL_PARAM1, 0);
-	PCWL_WRITE(pcwl_p, WL_PARAM2, 0);
-	PCWL_WRITE(pcwl_p, WL_COMMAND, cmd);
-	if (cmd == WL_CMD_INI)
-		drv_usecwait(100000); /* wait .1 sec */
-
-	for (i = 0; i < WL_TIMEOUT; i++) {
-		PCWL_READ(pcwl_p, WL_EVENT_STAT, stat);
-		if (!(stat & WL_EV_CMD)) {
-			drv_usecwait(1);
-		} else {
-			break;
-		}
-	}
-	if (i == WL_TIMEOUT) {
-		cmn_err(CE_WARN, "pcwl: setcmd %x,%x timeout %x\n",
-		    cmd, param, stat);
-		if (stat & (WL_EV_ALLOC | WL_EV_RX))
-			PCWL_WRITE(pcwl_p, WL_EVENT_ACK, stat);
-		return (PCWL_TIMEDOUT_CMD);
-	}
-	PCWL_READ(pcwl_p, WL_STATUS, stat);
-	PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_CMD);
-	if (stat & WL_STAT_CMD_RESULT) { /* err in feedback status */
-		cmn_err(CE_WARN, "pcwl: set_cmd %x,%x failed %x\n",
-		    cmd, param, stat);
-		return (PCWL_FAILURE_CMD);
-	}
-	if (cmd == WL_CMD_ENABLE)
-		pcwl_p->pcwl_flag |= PCWL_ENABLED;
-	if (cmd == WL_CMD_DISABLE)
-		pcwl_p->pcwl_flag &= (~PCWL_ENABLED);
-	return (PCWL_SUCCESS);
-}
-
-static uint16_t
-pcwl_set_ch(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t channel)
-{
-	int i;
-	uint16_t stat, select, offset;
-
-	if (channel) {
-		select = WL_SEL1;
-		offset = WL_OFF1;
-	} else {
-		select = WL_SEL0;
-		offset = WL_OFF0;
-	}
-	PCWL_WRITE(pcwl_p, select, type);
-	PCWL_WRITE(pcwl_p, offset, off);
-	for (stat = 0, i = 0; i < WL_TIMEOUT; i++) {
-		PCWL_READ(pcwl_p, offset, stat);
-		if (!(stat & (WL_OFF_BUSY|WL_OFF_ERR)))
-			break;
-		else {
-			drv_usecwait(1);
-		}
-	}
-	if (i == WL_TIMEOUT) {
-		cmn_err(CE_WARN, "set_ch%d %x,%x failed %x\n",
-		    channel, type, off, stat);
-		return (PCWL_TIMEDOUT_TARGET);
-	}
-	return (PCWL_SUCCESS);
-}
-
-static uint16_t
-pcwl_get_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t *val_p)
-{
-	uint16_t stat;
-
-	ASSERT(!(len & 1));
-	len >>= 1;	/* convert bytes to 16-bit words */
-
-	/*
-	 * 1. select read mode
-	 */
-	if (stat = pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS | WL_ACCESS_READ, type))
-		return (stat);
-
-	/*
-	 * 2. select Buffer Access Path (channel) 1 for PIO
-	 */
-	if (stat = pcwl_set_ch(pcwl_p, type, 0, 1))
-		return (stat);
-
-	/*
-	 * 3. read length
-	 */
-	PCWL_READ(pcwl_p, WL_DATA1, stat);
-	if (stat != (len + 1)) {
-		PCWLDBG((CE_NOTE, "get_ltv 0x%x expected 0x%x+1, got 0x%x\n",
-		    type, (len + 1) << 1, stat));
-		stat = (stat >> 1) - 1;
-		len = MIN(stat, len);
-	}
-
-	/*
-	 * 4. read type
-	 */
-	PCWL_READ(pcwl_p, WL_DATA1, stat);
-	if (stat != type)
-		return (PCWL_BADTYPE);
-
-	/*
-	 * 5. read value
-	 */
-	for (stat = 0; stat < len; stat++, val_p++) {
-		PCWL_READ_P(pcwl_p, WL_DATA1, val_p, 1);
-	}
-	return (PCWL_SUCCESS);
-}
-
-static uint16_t
-pcwl_fil_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t val)
-{
-	uint16_t stat;
-
-	ASSERT(!(len & 1));
-
-	/*
-	 * 1. select Buffer Access Path (channel) 1 for PIO
-	 */
-	if (stat = pcwl_set_ch(pcwl_p, type, 0, 1))
-		return (stat);
-
-	/*
-	 * 2. write length
-	 */
-	len >>= 1;		/* convert bytes to 16-bit words */
-	stat = len + 1;		/* 1 extra word */
-	PCWL_WRITE(pcwl_p, WL_DATA1, stat);
-
-	/*
-	 * 3. write type
-	 */
-	PCWL_WRITE(pcwl_p, WL_DATA1, type);
-
-	/*
-	 * 4. fill value
-	 */
-	for (stat = 0; stat < len; stat++) {
-		PCWL_WRITE(pcwl_p, WL_DATA1, val);
-	}
-
-	/*
-	 * 5. select write mode
-	 */
-	return (pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS|WL_ACCESS_WRITE, type));
-}
-
-static uint16_t
-pcwl_put_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type, uint16_t *val_p)
-{
-	uint16_t stat;
-
-	ASSERT(!(len & 1));
-
-	/*
-	 * 1. select Buffer Access Path (channel) 1 for PIO
-	 */
-	if (stat = pcwl_set_ch(pcwl_p, type, 0, 1))
-		return (stat);
-
-	/*
-	 * 2. write length
-	 */
-	len >>= 1;		/* convert bytes to 16-bit words */
-	stat = len + 1;		/* 1 extra word */
-	PCWL_WRITE(pcwl_p, WL_DATA1, stat);
-
-	/*
-	 * 3. write type
-	 */
-	PCWL_WRITE(pcwl_p, WL_DATA1, type);
-
-	/*
-	 * 4. write value
-	 */
-	for (stat = 0; stat < len; stat++, val_p++) {
-		PCWL_WRITE_P(pcwl_p, WL_DATA1, val_p, 1);
-	}
-
-	/*
-	 * 5. select write mode
-	 */
-	return (pcwl_set_cmd(pcwl_p, WL_CMD_ACCESS|WL_ACCESS_WRITE, type));
-}
-
-#define	PCWL_COMPSTR_LEN	34
-static uint16_t
-pcwl_put_str(pcwl_maci_t *pcwl_p, uint16_t type, char *str_p)
-{
-	uint16_t buf[PCWL_COMPSTR_LEN / 2];
-	uint8_t str_len = strlen(str_p);
-
-	bzero(buf, PCWL_COMPSTR_LEN);
-	buf[0] = str_len;
-	bcopy(str_p, (caddr_t)(buf + 1), str_len);
-	PCWLDBG((CE_NOTE, "put_str: buf[0]=%x buf=%s\n",
-	    buf[0], (caddr_t)(buf + 1)));
-	PCWL_SWAP16(buf + 1, PCWL_COMPSTR_LEN - 2);
-	return (pcwl_put_ltv(pcwl_p, PCWL_COMPSTR_LEN, type, buf));
-}
-
-/*ARGSUSED*/
-static uint16_t
-pcwl_rdch0(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t *buf_p,
-	int len, int order)
-{
-	uint16_t o;
-	ASSERT(!(len & 1));
-	/*
-	 * It seems that for PrismII chip, frequently overlap use of path0
-	 * and path1 may hang the hardware. So for PrismII chip, just use
-	 * path1. Test proves this workaround is OK.
-	 */
-	if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
-		if (type = pcwl_set_ch(pcwl_p, type, off, 1))
-			return (type);
-		o = WL_DATA1;
-	} else {
-		if (type = pcwl_set_ch(pcwl_p, type, off, 0))
-			return (type);
-		o = WL_DATA0;
-	}
-	len >>= 1;
-	for (off = 0; off < len; off++, buf_p++) {
-		PCWL_READ_P(pcwl_p, o, buf_p, order);
-	}
-	return (PCWL_SUCCESS);
-}
-
-/*ARGSUSED*/
-static uint16_t
-pcwl_wrch1(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off, uint16_t *buf_p,
-	int len, int order)
-{
-	ASSERT(!(len & 1));
-	if (type = pcwl_set_ch(pcwl_p, type, off, 1))
-		return (type);
-	len >>= 1;
-	for (off = 0; off < len; off++, buf_p++) {
-		PCWL_WRITE_P(pcwl_p, WL_DATA1, buf_p, order);
-	}
-	return (PCWL_SUCCESS);
-}
-
-static uint16_t
-pcwl_alloc_nicmem(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t *id_p)
-{
-	int i;
-	uint16_t stat;
-
-	len = ((len + 1) >> 1) << 1;	/* round up to 16-bit boundary */
-
-	if (stat = pcwl_set_cmd(pcwl_p, WL_CMD_ALLOC_MEM, len))
-		return (stat);
-	for (stat = 0, i = 0; i < WL_TIMEOUT; i++) {
-		PCWL_READ(pcwl_p, WL_EVENT_STAT, stat);
-		if (stat & WL_EV_ALLOC)
-			break;
-		else
-			drv_usecwait(1);
-	}
-	if (i == WL_TIMEOUT)
-		return (PCWL_TIMEDOUT_ALLOC);
-	PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_ALLOC);
-	PCWL_READ(pcwl_p, WL_ALLOC_FID, stat);
-	*id_p = stat;
-
-	/*
-	 * zero fill the allocated NIC mem - sort of pcwl_fill_ch
-	 */
-	(void) pcwl_set_ch(pcwl_p, stat, 0, 1);
-
-	for (len >>= 1, stat = 0; stat < len; stat++) {
-		PCWL_WRITE(pcwl_p, WL_DATA1, 0);
-	}
-	return (PCWL_SUCCESS);
-}
-
-static int
-pcwl_add_scan_item(pcwl_maci_t *pcwl_p, wl_scan_result_t s)
-{
-	wl_scan_list_t *scan_item;
-
-	scan_item = kmem_zalloc(sizeof (wl_scan_list_t), KM_SLEEP);
-	if (scan_item == NULL) {
-		cmn_err(CE_WARN, "pcwl add_scan_item: zalloc failed\n");
-		return (PCWL_FAIL);
-	}
-	scan_item->wl_val = s;
-	scan_item->wl_timeout = WL_SCAN_TIMEOUT_MAX;
-	list_insert_tail(&pcwl_p->pcwl_scan_list, scan_item);
-	pcwl_p->pcwl_scan_num++;
-	return (PCWL_SUCCESS);
-}
-
-static void
-pcwl_delete_scan_item(pcwl_maci_t *pcwl_p, wl_scan_list_t *s)
-{
-	list_remove(&pcwl_p->pcwl_scan_list, s);
-	kmem_free(s, sizeof (*s));
-	pcwl_p->pcwl_scan_num--;
-}
-
-static void
-pcwl_scanlist_timeout(void *arg)
-{
-	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
-	wl_scan_list_t *scan_item0, *scan_item1;
-
-	mutex_enter(&pcwl_p->pcwl_scanlist_lock);
-	scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
-	for (; scan_item0; ) {
-		PCWLDBG((CE_NOTE, "ssid = %s\n",
-		    scan_item0->wl_val.wl_srt_ssid));
-		PCWLDBG((CE_NOTE, "timeout left: %ds",
-		    scan_item0->wl_timeout));
-		scan_item1 = list_next(&pcwl_p->pcwl_scan_list, scan_item0);
-		if (scan_item0->wl_timeout == 0) {
-			pcwl_delete_scan_item(pcwl_p, scan_item0);
-		} else {
-			scan_item0->wl_timeout--;
-		}
-		scan_item0 = scan_item1;
-	}
-	mutex_exit(&pcwl_p->pcwl_scanlist_lock);
-	pcwl_p->pcwl_scanlist_timeout_id = timeout(pcwl_scanlist_timeout,
-	    pcwl_p, drv_usectohz(1000000));
-}
-
-static void
-pcwl_get_rssi(pcwl_maci_t *pcwl_p)
-{
-	wl_scan_list_t *scan_item0;
-	uint16_t cq[3];
-
-	bzero(cq, sizeof (cq));
-	mutex_enter(&pcwl_p->pcwl_scanlist_lock);
-	scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
-	for (; scan_item0; ) {
-		if (bcmp(scan_item0->wl_val.wl_srt_bssid,
-		    pcwl_p->pcwl_bssid, 6) == 0) {
-			pcwl_p->pcwl_rssi = scan_item0->wl_val.wl_srt_sl;
-		}
-		scan_item0 = list_next(&pcwl_p->pcwl_scan_list, scan_item0);
-	}
-	mutex_exit(&pcwl_p->pcwl_scanlist_lock);
-	if (!pcwl_p->pcwl_rssi) {
-		(void) pcwl_get_ltv(pcwl_p, 6, WL_RID_COMMQUAL, cq);
-		pcwl_p->pcwl_rssi = cq[1];
-	}
-}
-
-/*
- * Note:
- * PrismII chipset has 2 extra space for the reason why scan is initiated
- */
-static void
-pcwl_ssid_scan(pcwl_maci_t *pcwl_p, uint16_t fid, uint16_t flen, uint16_t stype)
-{
-	uint16_t stat;
-	uint16_t ssidNum, i;
-	uint16_t off, szbuf;
-	uint16_t tmp[2];
-	wl_scan_list_t *scan_item0;
-	uint32_t check_num;
-	uint8_t	bssid_t[6];
-
-	wl_scan_result_t sctbl;
-
-	off = sizeof (uint16_t) * 2;
-	switch (pcwl_p->pcwl_chip_type) {
-	case PCWL_CHIP_PRISMII:
-		(void) RDCH0(pcwl_p, fid, off, tmp, 4);
-		off += 4;
-		szbuf = (stype == WL_INFO_SCAN_RESULTS ? 31 : 32);
-		PCWLDBG((CE_NOTE, "pcwl ssid_scan: PRISM chip\n"));
-		break;
-	case PCWL_CHIP_LUCENT:
-		PCWLDBG((CE_NOTE, "pcwl ssid_scan LUCENT chip\n"));
-	default:
-		szbuf = 25;
-	}
-
-	flen = flen + 1 - (off >> 1);
-	ssidNum = flen/szbuf;
-	ssidNum = min(WL_SRT_MAX_NUM, ssidNum);
-
-	PCWLDBG((CE_NOTE, "pcwl: ssid_scan frame length = %d\n", flen));
-
-	PCWLDBG((CE_NOTE, "pcwl ssid_scan: %d ssid(s) available", ssidNum));
-
-	bzero(bssid_t, sizeof (bssid_t));
-	for (i = 0; i < ssidNum; i++) {
-		(void) RDCH0(pcwl_p, fid, off, (uint16_t *)&sctbl, 2*szbuf);
-
-#ifdef DEBUG
-		if (pcwl_debug & PCWL_DBG_INFO) {
-			int j;
-			for (j = 0; j < sizeof (sctbl); j++)
-				cmn_err(CE_NOTE, "%d: %x\n", j,
-				    *((uint8_t *)&sctbl + j));
-		}
-#endif
-
-		off += (szbuf << 1);
-		stat = min(sctbl.wl_srt_ssidlen, 31);
-		PCWL_SWAP16((uint16_t *)(sctbl.wl_srt_bssid), 6);
-		PCWL_SWAP16((uint16_t *)(sctbl.wl_srt_ssid), stat);
-		sctbl.wl_srt_ssid[stat] = '\0';
-		sctbl.wl_srt_sl &= 0x7f;
-
-		/*
-		 * sometimes, those empty items are recorded by hardware,
-		 * this is wrong, just ignore those items here.
-		 */
-		if (bcmp(sctbl.wl_srt_bssid,
-		    bssid_t, 6) == 0) {
-			continue;
-		}
-		if (bcmp(sctbl.wl_srt_bssid,
-		    pcwl_p->pcwl_bssid, 6) == 0) {
-			pcwl_p->pcwl_rssi = sctbl.wl_srt_sl;
-		}
-		/*
-		 * save/update the scan item in scanlist
-		 */
-		mutex_enter(&pcwl_p->pcwl_scanlist_lock);
-		check_num = 0;
-		scan_item0 = list_head(&pcwl_p->pcwl_scan_list);
-		if (scan_item0 == NULL) {
-			if (pcwl_add_scan_item(pcwl_p, sctbl)
-			    != 0) {
-				mutex_exit(&pcwl_p->pcwl_scanlist_lock);
-				return;
-			}
-		}
-		for (; scan_item0; ) {
-			if (bcmp(sctbl.wl_srt_bssid,
-			    scan_item0->wl_val.wl_srt_bssid, 6) == 0) {
-				scan_item0->wl_val = sctbl;
-				scan_item0->wl_timeout = WL_SCAN_TIMEOUT_MAX;
-				break;
-			} else {
-				check_num++;
-			}
-			scan_item0 = list_next(&pcwl_p->pcwl_scan_list,
-			    scan_item0);
-		}
-		if (check_num == pcwl_p->pcwl_scan_num) {
-			if (pcwl_add_scan_item(pcwl_p, sctbl)
-			    != 0) {
-				mutex_exit(&pcwl_p->pcwl_scanlist_lock);
-				return;
-			}
-		}
-		mutex_exit(&pcwl_p->pcwl_scanlist_lock);
-		PCWLDBG((CE_NOTE, "pcwl ssid_scan: ssid%d = %s\n", i+1,
-		    sctbl.wl_srt_ssid));
-		PCWLDBG((CE_NOTE, "pcwl ssid_scan: channel = %d\n",
-		    sctbl.wl_srt_chid));
-		PCWLDBG((CE_NOTE, "pcwl ssid_scan: signal level= %d\n",
-		    sctbl.wl_srt_sl));
-		PCWLDBG((CE_NOTE, "pcwl ssid_scan: noise level = %d\n",
-		    sctbl.wl_srt_anl));
-		PCWLDBG((CE_NOTE, "pcwl ssid_scan: bssid%d ="
-		    " %x %x %x %x %x %x\n\n", i+1,
-		    sctbl.wl_srt_bssid[0],
-		    sctbl.wl_srt_bssid[1],
-		    sctbl.wl_srt_bssid[2],
-		    sctbl.wl_srt_bssid[3],
-		    sctbl.wl_srt_bssid[4],
-		    sctbl.wl_srt_bssid[5]));
-	}
-
-}
-
-/*
- * delay in which the mutex is not hold.
- * assuming the mutex has already been hold.
- */
-static void
-pcwl_delay(pcwl_maci_t *pcwl_p, clock_t microsecs)
-{
-	ASSERT(mutex_owned(&pcwl_p->pcwl_glock));
-
-	mutex_exit(&pcwl_p->pcwl_glock);
-	delay(drv_usectohz(microsecs));
-	mutex_enter(&pcwl_p->pcwl_glock);
-}
-
-static int
-pcwl_reset_backend(pcwl_maci_t *pcwl_p)
-{
-	uint16_t ret = 0;
-
-	if (ret =  pcwl_set_cmd(pcwl_p, WL_CMD_INI, 0)) {
-		return ((int)ret);
-	}
-
-	pcwl_delay(pcwl_p, 100000); /* wait .1 sec */
-
-	if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_INI, 0)) {
-		return ((int)ret);
-	}
-	pcwl_delay(pcwl_p, 100000); /* wait .1 sec */
-
-	PCWL_DISABLE_INTR(pcwl_p);
-	return (PCWL_SUCCESS);
-}
-
-
-/*
- * get card capability (WEP, default channel), setup broadcast, mac addresses
- */
-static int
-pcwl_get_cap(pcwl_maci_t *pcwl_p)
-{
-	uint16_t stat, ch_no;
-	uint16_t buf[ETHERADDRL >> 1];
-
-	bzero(buf, ETHERADDRL);
-	if (stat = pcwl_get_ltv(pcwl_p, 2, WL_RID_OWN_CHNL, &ch_no)) {
-		cmn_err(CE_CONT, "pcwl get_cap: get def channel failed"
-		    " %x\n", stat);
-		return ((int)stat);
-	}
-	if (stat = pcwl_get_ltv(pcwl_p, 2, WL_RID_WEP_AVAIL,
-	    &pcwl_p->pcwl_has_wep)) {
-		cmn_err(CE_CONT, "pcwl get_cap: get WEP capability failed"
-		    " %x\n", stat);
-		return ((int)stat);
-	}
-	if (stat = pcwl_get_ltv(pcwl_p, ETHERADDRL, WL_RID_MAC_NODE, buf)) {
-		cmn_err(CE_CONT, "pcwl get_cap: get macaddr failed"
-		    " %x\n", stat);
-		return ((int)stat);
-	}
-
-	/*
-	 * don't assume m_xxx members are 16-bit aligned
-	 */
-	PCWL_SWAP16(buf, ETHERADDRL);
-	ether_copy(buf, pcwl_p->pcwl_mac_addr);
-	return (PCWL_SUCCESS);
-}
-
-static int
-pcwl_init_nicmem(pcwl_maci_t *pcwl_p)
-{
-	uint16_t ret, i;
-	uint16_t rc;
-
-	for (i = 0; i < WL_XMT_BUF_NUM; i++) {
-		ret = pcwl_alloc_nicmem(pcwl_p, PCWL_NICMEM_SZ, &rc);
-		if (ret) {
-			cmn_err(CE_WARN,
-			    "pcwl: alloc NIC Tx buf failed %x\n", ret);
-			return (PCWL_FAIL);
-		}
-		pcwl_p->pcwl_txring.wl_tx_fids[i] = rc;
-		pcwl_p->pcwl_txring.wl_tx_ring[i] = 0;
-		PCWLDBG((CE_NOTE, "pcwl: alloc_nicmem_id[%d]=%x\n", i, rc));
-	}
-	pcwl_p->pcwl_txring.wl_tx_prod = pcwl_p->pcwl_txring.wl_tx_cons = 0;
-
-	ret = pcwl_alloc_nicmem(pcwl_p, PCWL_NICMEM_SZ, &pcwl_p->pcwl_mgmt_id);
-	if (ret) {
-		cmn_err(CE_WARN, "pcwl: alloc NIC Mgmt buf failed %x\n", ret);
-		return (PCWL_FAIL);
-	}
-	PCWLDBG((CE_NOTE, "pcwl: alloc_nicmem mgmt_id=%x\n",
-	    pcwl_p->pcwl_mgmt_id));
-	return (PCWL_SUCCESS);
-}
-
-static int
-pcwl_loaddef_rf(pcwl_maci_t *pcwl_p)
-{
-	pcwl_p->pcwl_rf.rf_max_datalen = WL_DEFAULT_DATALEN;
-	pcwl_p->pcwl_rf.rf_create_ibss = WL_DEFAULT_CREATE_IBSS;
-	pcwl_p->pcwl_rf.rf_porttype = WL_BSS_BSS;
-	pcwl_p->pcwl_rf.rf_rts_thresh = WL_DEFAULT_RTS_THRESH;
-	pcwl_p->pcwl_rf.rf_tx_rate = WL_TX_RATE_FIX_11M(pcwl_p);
-	pcwl_p->pcwl_rf.rf_pm_enabled = WL_DEFAULT_PM_ENABLED;
-	pcwl_p->pcwl_rf.rf_own_chnl = WL_DEFAULT_CHAN;
-	(void) strcpy(pcwl_p->pcwl_rf.rf_own_ssid, "");
-	(void) strcpy(pcwl_p->pcwl_rf.rf_desired_ssid, "");
-	(void) strcpy(pcwl_p->pcwl_rf.rf_nodename, "");
-	pcwl_p->pcwl_rf.rf_encryption = WL_NOENCRYPTION;
-	pcwl_p->pcwl_rf.rf_authtype = WL_OPENSYSTEM;
-	pcwl_p->pcwl_rf.rf_tx_crypt_key = WL_DEFAULT_TX_CRYPT_KEY;
-	bzero((pcwl_p->pcwl_rf.rf_ckeys), sizeof (rf_ckey_t) * 4);
-
-	pcwl_p->pcwl_rf.rf_promiscuous = 0;
-
-	return (pcwl_config_rf(pcwl_p));
-}
-
-static int
-pcwl_config_rf(pcwl_maci_t *pcwl_p)
-{
-	pcwl_rf_t *rf_p = &pcwl_p->pcwl_rf;
-	uint16_t create_ibss, porttype;
-
-	/*
-	 * Lucent card:
-	 * 0 Join ESS or IBSS; 1 Join ESS or join/create IBSS
-	 * PrismII card:
-	 * 3 Join ESS or IBSS(do not create IBSS);
-	 * 1 Join ESS or join/create IBSS
-	 */
-	create_ibss = rf_p->rf_create_ibss;
-	if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
-		if (rf_p->rf_create_ibss == 0)
-			create_ibss = 3;
-	}
-	/*
-	 * Lucent card:
-	 * 1 BSS; 3 pseudo IBSS(only for test,not the 802.11 IBSS)
-	 * so porttype register should always be set to 1
-	 * PrismII card:
-	 * 0 IBSS; 1 BSS; 2 WDS; 3 pseudo IBSS; 6 hostAP
-	 */
-	switch (pcwl_p->pcwl_chip_type) {
-	case PCWL_CHIP_PRISMII:
-		if (rf_p->rf_porttype == WL_BSS_BSS)
-			porttype = 1;
-		else if (rf_p->rf_porttype == WL_BSS_IBSS)
-			porttype = 0;
-		else
-			porttype = 0;
-		break;
-	case PCWL_CHIP_LUCENT:
-	default:
-		porttype = 1;
-	}
-
-
-	FIL_LTV(pcwl_p, PCWL_MCBUF_LEN, WL_RID_MCAST, 0);
-	FIL_LTV(pcwl_p, 2,	WL_RID_PROMISC,		0);
-	FIL_LTV(pcwl_p, 2,	WL_RID_TICK_TIME,	0);
-
-	FIL_LTV(pcwl_p, 2, WL_RID_MAX_DATALEN, rf_p->rf_max_datalen);
-	FIL_LTV(pcwl_p, 2, WL_RID_CREATE_IBSS, create_ibss);
-	FIL_LTV(pcwl_p, 2, WL_RID_PORTTYPE, porttype);
-	FIL_LTV(pcwl_p, 2, WL_RID_RTS_THRESH, rf_p->rf_rts_thresh);
-	FIL_LTV(pcwl_p, 2, WL_RID_TX_RATE, rf_p->rf_tx_rate);
-	FIL_LTV(pcwl_p, 2, WL_RID_SYSTEM_SCALE, rf_p->rf_system_scale);
-	FIL_LTV(pcwl_p, 2, WL_RID_PM_ENABLED, rf_p->rf_pm_enabled);
-	FIL_LTV(pcwl_p, 2, WL_RID_MAX_SLEEP, rf_p->rf_max_sleep);
-	FIL_LTV(pcwl_p, 2, WL_RID_OWN_CHNL, rf_p->rf_own_chnl);
-
-	PUT_STR(pcwl_p, WL_RID_OWN_SSID, rf_p->rf_own_ssid);
-	PUT_STR(pcwl_p, WL_RID_DESIRED_SSID, rf_p->rf_desired_ssid);
-	PUT_STR(pcwl_p, WL_RID_NODENAME, rf_p->rf_nodename);
-
-	if (!pcwl_p->pcwl_has_wep)
-		goto done;
-
-	switch (pcwl_p->pcwl_chip_type) {
-	case PCWL_CHIP_PRISMII: {
-		int i;
-
-		for (i = 0; i < 4; i++) {
-			int k_len = strlen((char *)rf_p->rf_ckeys[i].ckey_dat);
-			if (k_len == 0)
-				continue;
-			k_len = k_len > 5 ? 14 : 6;
-			PUT_LTV(pcwl_p, k_len, WL_RID_CRYPT_KEY0_P2 + i,
-			    (uint16_t *)&rf_p->rf_ckeys[i].ckey_dat);
-		}
-		FIL_LTV(pcwl_p, 2, WL_RID_TX_CRYPT_KEY_P2,
-		    rf_p->rf_tx_crypt_key);
-		FIL_LTV(pcwl_p, 2, WL_RID_AUTHTYPE_P2,
-		    rf_p->rf_authtype);
-		FIL_LTV(pcwl_p, 2, WL_RID_ENCRYPTION_P2,
-		    rf_p->rf_encryption);
-		if (pcwl_p->pcwl_rf.rf_promiscuous)
-			FIL_LTV(pcwl_p, 2, WL_RID_PROMISC, 1);
-		}
-		break;
-	case PCWL_CHIP_LUCENT:
-	default:
-		FIL_LTV(pcwl_p, 2, WL_RID_ENCRYPTION,
-		    rf_p->rf_encryption);
-		FIL_LTV(pcwl_p, 2, WL_RID_AUTHTYPE_L,
-		    rf_p->rf_authtype);
-		FIL_LTV(pcwl_p, 2, WL_RID_TX_CRYPT_KEY,
-		    rf_p->rf_tx_crypt_key);
-		PUT_LTV(pcwl_p, sizeof (rf_p->rf_ckeys),
-		    WL_RID_DEFLT_CRYPT_KEYS,
-		    (uint16_t *)rf_p->rf_ckeys);
-		break;
-	}
-done:
-	return (PCWL_SUCCESS);
-}
-
-static void
-pcwl_start_locked(pcwl_maci_t *pcwl_p)
-{
-	pcwl_p->pcwl_flag |= PCWL_CARD_INTREN;
-	PCWL_ENABLE_INTR(pcwl_p);
-}
-
-static void
-pcwl_stop_locked(pcwl_maci_t *pcwl_p)
-{
-	PCWL_DISABLE_INTR(pcwl_p);
-	pcwl_p->pcwl_flag &= (~PCWL_CARD_INTREN);
-	PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX|WL_EV_RX|WL_EV_TX_EXC|
-	    WL_EV_ALLOC|WL_EV_INFO|WL_EV_INFO_DROP);
-	PCWL_WRITE(pcwl_p, WL_EVENT_ACK, WL_EV_TX|WL_EV_RX|WL_EV_TX_EXC|
-	    WL_EV_ALLOC| WL_EV_INFO|WL_EV_INFO_DROP);
-}
-
-/*ARGSUSED*/
-static int
-pcwl_saddr_locked(pcwl_maci_t *pcwl_p)
-{
-	int ret;
-	uint16_t buf[ETHERADDRL >> 1];
-
-	ether_copy(pcwl_p->pcwl_mac_addr, buf);
-	PCWL_SWAP16(buf, ETHERADDRL);
-	ret = pcwl_put_ltv(pcwl_p, ETHERADDRL, WL_RID_MAC_NODE, buf);
-	if (ret) {
-		cmn_err(CE_WARN, "pcwl set_mac_addr: failed %x\n", ret);
-		return (PCWL_FAIL);
-	}
-	return (PCWL_SUCCESS);
-}
-
-static void
-pcwl_chip_type(pcwl_maci_t *pcwl_p)
-{
-	pcwl_ltv_ver_t ver;
-	pcwl_ltv_fwver_t f;
-
-	bzero(&ver, sizeof (ver));
-	(void) pcwl_get_ltv(pcwl_p, sizeof (ver),
-	    WL_RID_CARD_ID, (uint16_t *)&ver);
-	PCWLDBG((CE_NOTE, "card id:%04x-%04x-%04x-%04x\n",
-	    ver.wl_compid, ver.wl_variant, ver.wl_major, ver.wl_minor));
-	if ((ver.wl_compid & 0xf000) != 0x8000)
-		return;	/* lucent */
-
-	pcwl_p->pcwl_chip_type = PCWL_CHIP_PRISMII;
-	(void) pcwl_get_ltv(pcwl_p, sizeof (ver), WL_RID_COMP_IDENT,
-	    (uint16_t *)&ver);
-	PCWLDBG((CE_NOTE, "PRISM-II ver:%04x-%04x-%04x-%04x\n",
-	    ver.wl_compid, ver.wl_variant, ver.wl_major, ver.wl_minor));
-
-	bzero(&f, sizeof (f));
-	(void) pcwl_get_ltv(pcwl_p, sizeof (f), WL_RID_FWVER, (uint16_t *)&f);
-	PCWL_SWAP16((uint16_t *)&f, sizeof (f));
-	PCWLDBG((CE_NOTE, "Firmware Pri:%s 2,3:%s\n",
-	    (char *)f.pri, (char *)f.st));
-}
-
-/*
- * Brussels support
- */
-/*
- * MAC_PROP_WL_ESSID
- */
-static int
-pcwl_set_essid(pcwl_maci_t *pcwl_p, const void *wldp_buf)
-{
-	char 		*value;
-	pcwl_rf_t 	*rf_p;
-	wl_essid_t 	*iw_essid = (wl_essid_t *)wldp_buf;
-
-	rf_p = &pcwl_p->pcwl_rf;
-
-	value = iw_essid->wl_essid_essid;
-	(void) strncpy(rf_p->rf_desired_ssid, value,
-	    MIN(32, strlen(value)));
-	rf_p->rf_desired_ssid[strlen(value)] = '\0';
-	(void) strncpy(rf_p->rf_own_ssid, value,
-	    MIN(32, strlen(value)));
-	rf_p->rf_own_ssid[strlen(value)] = '\0';
-
-	PCWLDBG((CE_CONT, "pcwl: set: desired essid=%s\n",
-	    rf_p->rf_desired_ssid));
-
-	return (ENETRESET);
-
-}
-
-static int
-pcwl_get_essid(pcwl_maci_t *pcwl_p, void *wldp_buf)
-{
-	char		ssid[36];
-	uint16_t	ret;
-	uint16_t	val;
-	int		len;
-	int		err = 0;
-	wl_essid_t	ow_essid;
-	pcwl_rf_t	*rf_p;
-
-	rf_p = &pcwl_p->pcwl_rf;
-	bzero(&ow_essid, sizeof (wl_essid_t));
-	bzero(ssid, sizeof (ssid));
-
-	ret =  pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &val);
-	if (ret) {
-		err = EIO;
-		return (err);
-	}
-	PCWLDBG((CE_NOTE, "PortStatus = %d\n", val));
-
-	switch (val) {
-	case WL_PORT_DISABLED:
-	case WL_PORT_INITIAL:
-		len = mi_strlen(rf_p->rf_desired_ssid);
-		ow_essid.wl_essid_length = len;
-		bcopy(rf_p->rf_desired_ssid, ow_essid.wl_essid_essid,
-		    len);
-		break;
-	case WL_PORT_TO_IBSS:
-	case WL_PORT_TO_BSS:
-	case WL_PORT_OOR:
-		(void) pcwl_get_ltv((pcwl_p), 34, WL_RID_SSID,
-		    (uint16_t *)ssid);
-		PCWL_SWAP16((uint16_t *)(ssid+2), *(uint16_t *)ssid);
-		ssid[*(uint16_t *)ssid + 2] = '\0';
-		len = mi_strlen(ssid+2);
-		ow_essid.wl_essid_length = len;
-		bcopy(ssid + 2, ow_essid.wl_essid_essid, len);
-		break;
-	default:
-		err = EINVAL;
-		break;
-	}
-
-	bcopy(&ow_essid, wldp_buf, sizeof (wl_essid_t));
-
-	return (err);
-}
-
-/*
- * MAC_PROP_WL_BSSID
- */
-static int
-pcwl_get_bssid(pcwl_maci_t *pcwl_p, void *wldp_buf)
-{
-	uint16_t 	ret;
-	uint16_t 	retval;
-	uint8_t 	bssid[6];
-	int 		err = 0;
-
-	if (ret = pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &retval)) {
-		err = EIO;
-		return (err);
-	}
-
-	PCWLDBG((CE_NOTE, "PortStatus = %d\n", ret));
-
-	if (retval == WL_PORT_DISABLED || retval == WL_PORT_INITIAL) {
-		bzero(wldp_buf, sizeof (wl_bssid_t));
-	} else if (retval == WL_PORT_TO_IBSS ||
-	    retval == WL_PORT_TO_BSS || retval == WL_PORT_OOR) {
-		(void) pcwl_get_ltv(pcwl_p, 6,
-		    WL_RID_BSSID, (uint16_t *)bssid);
-		PCWL_SWAP16((uint16_t *)bssid, 6);
-		bcopy(bssid, wldp_buf, sizeof (wl_bssid_t));
-	}
-
-	PCWLDBG((CE_CONT, "pcwl_get_bssid: bssid=%x %x %x %x %x %x\n",
-	    bssid[0], bssid[1], bssid[2],
-	    bssid[3], bssid[4], bssid[5]));
-
-	return (err);
-}
-
-/*
- * MAC_PROP_WL_LINKSTATUS
- */
-static int
-pcwl_get_linkstatus(pcwl_maci_t *pcwl_p, void *wldp_buf)
-{
-	uint16_t 	ret;
-	uint16_t	retval;
-	int		err = 0;
-
-	ret =  pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &retval);
-	if (ret) {
-		err = EIO;
-		PCWLDBG((CE_WARN, "cfg_linkstatus_get_error\n"));
-		return (err);
-	}
-	PCWLDBG((CE_NOTE, "PortStatus = %d\n", retval));
-
-	switch (retval) {
-	case WL_PORT_DISABLED:
-	case WL_PORT_INITIAL:
-		*(wl_linkstatus_t *)wldp_buf = WL_NOTCONNECTED;
-		break;
-	case WL_PORT_TO_IBSS:
-	case WL_PORT_TO_BSS:
-	case WL_PORT_OOR:
-		*(wl_linkstatus_t *)wldp_buf = WL_CONNECTED;
-		break;
-	default:
-		err = EINVAL;
-		break;
-	}
-
-	return (err);
-}
-
-/*
- * MAC_PROP_WL_BSSTYP
- */
-static int
-pcwl_set_bsstype(pcwl_maci_t *pcwl_p, const void *wldp_buf)
-{
-	uint16_t 	ret;
-	pcwl_rf_t 	*rf_p;
-	int		err = ENETRESET;
-
-	rf_p = &pcwl_p->pcwl_rf;
-
-	ret = (uint16_t)(*(wl_bss_type_t *)wldp_buf);
-	if ((ret != WL_BSS_BSS) &&
-	    (ret != WL_BSS_IBSS) &&
-	    (ret != WL_BSS_ANY)) {
-		err = ENOTSUP;
-		return (err);
-	}
-
-	rf_p->rf_porttype = ret;
-
-	return (err);
-}
-
-static void
-pcwl_get_bsstype(pcwl_maci_t *pcwl_p, void *wldp_buf)
-{
-	pcwl_rf_t *rf_p;
-
-	rf_p = &pcwl_p->pcwl_rf;
-
-	*(wl_bss_type_t *)wldp_buf = rf_p->rf_porttype;
-
-	PCWLDBG((CE_CONT, "pcwl_get_bsstype: porttype=%d\n",
-	    rf_p->rf_porttype));
-}
-
-/*
- * MAC_PROP_WL_PHY_CONFIG
- */
-static int
-pcwl_set_phy(pcwl_maci_t *pcwl_p, const void *wldp_buf)
-{
-	uint16_t 	ret;
-	pcwl_rf_t 	*rf_p;
-	int		err = ENETRESET;
-	wl_phy_conf_t 	*phy = (wl_phy_conf_t *)wldp_buf;
-
-	rf_p = &pcwl_p->pcwl_rf;
-	ret = (uint16_t)(phy->wl_phy_dsss_conf.wl_dsss_channel);
-	if (ret < 1 || ret > 14) {
-		err = ENOTSUP;
-		return (err);
-	}
-
-	rf_p->rf_own_chnl = ret;
-
-	PCWLDBG((CE_CONT, "pcwl: set channel=%d\n", rf_p->rf_own_chnl));
-
-	return (err);
-}
-
-static int
-pcwl_get_phy(pcwl_maci_t *pcwl_p, void *wldp_buf)
-{
-	uint16_t	retval;
-	wl_dsss_t 	*dsss = (wl_dsss_t *)wldp_buf;
-	int		err = 0;
-
-	if (pcwl_get_ltv(pcwl_p, 2, WL_RID_CURRENT_CHNL, &retval)) {
-		err = EIO;
-		return (err);
-	}
-
-	dsss->wl_dsss_channel = retval;
-	PCWLDBG((CE_CONT, "pcwl_get_phy: channel=%d\n", retval));
-	dsss->wl_dsss_subtype = WL_DSSS;
-
-	return (err);
-}
-
-/*
- * MAC_PROP_WL_DESIRED_RATESa
- */
-static int
-pcwl_set_desrates(pcwl_maci_t *pcwl_p, const void *wldp_buf)
-{
-	int		err = ENETRESET;
-	char 		rates[4];
-	char 		maxrate;
-	uint16_t 	i;
-	pcwl_rf_t 	*rf_p;
-	wl_rates_t 	*iw_rates = (wl_rates_t *)wldp_buf;
-
-	rf_p = &pcwl_p->pcwl_rf;
-
-	bzero(rates, sizeof (rates));
-
-	for (i = 0; i < 4; i++) {
-		rates[i] = iw_rates->wl_rates_rates[i];
-		PCWLDBG((CE_CONT, "pcwl: set tx_rate[%d]=%d\n", i, rates[i]));
-	}
-	PCWLDBG((CE_CONT, "pcwl: set rate_num=%d\n", iw_rates->wl_rates_num));
-
-	switch (iw_rates->wl_rates_num) {
-	case 1:
-		switch (rates[0]) {
-		case WL_RATE_1M:
-			rf_p->rf_tx_rate = WL_TX_RATE_FIX_1M(pcwl_p);
-			break;
-		case WL_RATE_2M:
-			rf_p->rf_tx_rate = WL_TX_RATE_FIX_2M(pcwl_p);
-			break;
-		case WL_RATE_11M:
-			rf_p->rf_tx_rate = WL_TX_RATE_FIX_11M(pcwl_p);
-			break;
-		case WL_RATE_5_5M:
-			rf_p->rf_tx_rate = WL_TX_RATE_FIX_5M(pcwl_p);
-			break;
-		default:
-			err = EINVAL;
-			break;
-		}
-		break;
-	case 2:
-		maxrate = (rates[0] > rates[1] ? rates[0] : rates[1]);
-		switch (maxrate) {
-		case WL_RATE_2M:
-			rf_p->rf_tx_rate = WL_TX_RATE_AUTO_L(pcwl_p);
-			break;
-		case WL_RATE_11M:
-			rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p);
-			break;
-		case WL_RATE_5_5M:
-			rf_p->rf_tx_rate = WL_TX_RATE_AUTO_M(pcwl_p);
-			break;
-		default:
-			err = EINVAL;
-			break;
-		}
-		break;
-	case 3:
-		maxrate = (rates[0] > rates[1] ? rates[0] : rates[1]);
-		maxrate = (rates[2] > maxrate ? rates[2] : maxrate);
-		switch (maxrate) {
-		case WL_RATE_11M:
-			rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p);
-			break;
-		case WL_RATE_5_5M:
-			rf_p->rf_tx_rate = WL_TX_RATE_AUTO_M(pcwl_p);
-			break;
-		default:
-			err = EINVAL;
-			break;
-		}
-		break;
-	case 4:
-		rf_p->rf_tx_rate = WL_TX_RATE_AUTO_H(pcwl_p);
-		break;
-	default:
-		err = ENOTSUP;
-		break;
-	}
-	PCWLDBG((CE_CONT, "pcwl: set tx_rate=%d\n", rf_p->rf_tx_rate));
-
-	return (err);
-}
-
-static int
-pcwl_get_desrates(pcwl_maci_t *pcwl_p, void *wldp_buf)
-{
-	uint16_t 	rate;
-	int		err = 0;
-
-	if (pcwl_get_ltv(pcwl_p, 2, WL_RID_TX_RATE, &rate)) {
-		err = EIO;
-		return (err);
-	}
-
-	if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
-		((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
-		switch (rate) {
-		case WL_SPEED_1Mbps_P2:
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
-			    WL_RATE_1M;
-			break;
-		case WL_SPEED_2Mbps_P2:
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
-			    WL_RATE_2M;
-			break;
-		case WL_SPEED_55Mbps_P2:
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
-			    WL_RATE_5_5M;
-			break;
-		case WL_SPEED_11Mbps_P2:
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
-			    WL_RATE_11M;
-			break;
-		default:
-			err = EINVAL;
-			break;
-		}
-	} else {
-		switch (rate) {
-		case WL_L_TX_RATE_FIX_1M:
-			((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
-			    WL_RATE_1M;
-			break;
-		case WL_L_TX_RATE_FIX_2M:
-			((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
-			    WL_RATE_2M;
-			break;
-		case WL_L_TX_RATE_AUTO_H:
-			((wl_rates_t *)wldp_buf)->wl_rates_num = 4;
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
-			    WL_RATE_1M;
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[1] =
-			    WL_RATE_2M;
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[2] =
-			    WL_RATE_5_5M;
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[3] =
-			    WL_RATE_11M;
-			break;
-		case WL_L_TX_RATE_FIX_5M:
-			((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
-			    WL_RATE_5_5M;
-			break;
-		case WL_L_TX_RATE_FIX_11M:
-			((wl_rates_t *)wldp_buf)->wl_rates_num = 1;
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
-			    WL_RATE_11M;
-			break;
-		case WL_L_TX_RATE_AUTO_L:
-			((wl_rates_t *)wldp_buf)->wl_rates_num = 2;
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
-			    WL_RATE_1M;
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[1] =
-			    WL_RATE_2M;
-			break;
-		case WL_L_TX_RATE_AUTO_M:
-			((wl_rates_t *)wldp_buf)->wl_rates_num = 3;
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[0] =
-			    WL_RATE_1M;
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[1] =
-			    WL_RATE_2M;
-			(((wl_rates_t *)wldp_buf)->wl_rates_rates)[2] =
-			    WL_RATE_5_5M;
-			break;
-		default:
-			err = EINVAL;
-			break;
-		}
-	}
-	PCWLDBG((CE_CONT, "pcwl: get rate=%d\n", rate));
-
-	return (err);
-}
-
-/*
- * MAC_PROP_WL_SUP_RATE
- */
-static void
-pcwl_get_suprates(void *wldp_buf)
-{
-	wl_rates_t *wl_rates = (wl_rates_t *)wldp_buf;
-
-	wl_rates->wl_rates_num = 4;
-	wl_rates->wl_rates_rates[0] = WL_RATE_1M;
-	wl_rates->wl_rates_rates[1] = WL_RATE_2M;
-	wl_rates->wl_rates_rates[2] = WL_RATE_5_5M;
-	wl_rates->wl_rates_rates[3] = WL_RATE_11M;
-}
-
-/*
- * MAC_PROP_WL_POWER_MODE
- */
-static int
-pcwl_set_powermode(pcwl_maci_t *pcwl_p, const void *wldp_buf)
-{
-	uint16_t 	ret;
-	pcwl_rf_t 	*rf_p;
-	int		err = 0;
-
-	rf_p = &pcwl_p->pcwl_rf;
-
-	ret = (uint16_t)(((wl_ps_mode_t *)wldp_buf)->wl_ps_mode);
-	if (ret != WL_PM_AM && ret != WL_PM_MPS && ret != WL_PM_FAST) {
-		err = ENOTSUP;
-		return (err);
-	}
-
-	rf_p->rf_pm_enabled = ret;
-
-	return (err);
-
-}
-
-static void
-pcwl_get_powermode(pcwl_maci_t *pcwl_p, void *wldp_buf)
-{
-	pcwl_rf_t *rf_p;
-
-	rf_p = &pcwl_p->pcwl_rf;
-	((wl_ps_mode_t *)wldp_buf)->wl_ps_mode = rf_p->rf_pm_enabled;
-}
-
-/*
- * MAC_PROP_AUTH_MODE
- */
-static int
-pcwl_set_authmode(pcwl_maci_t *pcwl_p, const void *wldp_buf)
-{
-	uint16_t	ret;
-	pcwl_rf_t 	*rf_p;
-	int		err = ENETRESET;
-
-	rf_p = &pcwl_p->pcwl_rf;
-
-	ret = (uint16_t)(*(wl_authmode_t *)wldp_buf);
-	if (ret != WL_OPENSYSTEM && ret != WL_SHAREDKEY) {
-		err = ENOTSUP;
-		return (err);
-	}
-
-	rf_p->rf_authtype = ret;
-
-	return (err);
-}
-
-static void
-pcwl_get_authmode(pcwl_maci_t *pcwl_p, void *wldp_buf)
-{
-	pcwl_rf_t 	*rf_p;
-
-	rf_p = &pcwl_p->pcwl_rf;
-	*(wl_authmode_t *)wldp_buf = rf_p->rf_authtype;
-}
-
-/*
- * MAC_PROP_WL_ENCRYPTION
- */
-static int
-pcwl_set_encrypt(pcwl_maci_t *pcwl_p, const void *wldp_buf)
-{
-	uint16_t 	ret;
-	pcwl_rf_t 	*rf_p;
-	int		err = ENETRESET;
-
-	rf_p = &pcwl_p->pcwl_rf;
-
-	ret = (uint16_t)(*(wl_encryption_t *)wldp_buf);
-	PCWLDBG((CE_NOTE, "pcwl_set_encrypt: %d\n", ret));
-	if (ret != WL_NOENCRYPTION && ret != WL_ENC_WEP) {
-		err = ENOTSUP;
-		return (err);
-	}
-
-	rf_p->rf_encryption = ret;
-
-	return (err);
-}
-
-static void
-pcwl_get_encrypt(pcwl_maci_t *pcwl_p, void *wldp_buf)
-{
-	pcwl_rf_t *rf_p;
-
-	rf_p = &pcwl_p->pcwl_rf;
-	*(wl_encryption_t *)wldp_buf = rf_p->rf_encryption;
-}
-
-/*
- * MAC_PROP_WL_CREATE_IBSS
- */
-static int
-pcwl_set_ibss(pcwl_maci_t *pcwl_p, const void *wldp_buf)
-{
-	uint16_t 	ret;
-	pcwl_rf_t 	*rf_p;
-	int		err = ENETRESET;
-
-	rf_p = &pcwl_p->pcwl_rf;
-
-	ret = (uint16_t)(*(wl_create_ibss_t *)wldp_buf);
-	if (ret != 0 && ret != 1) {
-		err = ENOTSUP;
-		return (err);
-	}
-
-	rf_p->rf_create_ibss = ret;
-
-	return (err);
-}
-
-static void
-pcwl_get_ibss(pcwl_maci_t *pcwl_p, void *wldp_buf)
-{
-	pcwl_rf_t 	*rf_p;
-
-	rf_p = &pcwl_p->pcwl_rf;
-	*(wl_create_ibss_t *)wldp_buf = rf_p->rf_create_ibss;
-}
-
-/*
- * MAC_PROP_WL_RSSI
- */
-static void
-pcwl_get_param_rssi(pcwl_maci_t *pcwl_p, void *wldp_buf)
-{
-
-	if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
-		*(wl_rssi_t *)wldp_buf =
-		    min((pcwl_p->pcwl_rssi * 15 / 85 + 1), 15);
-	} else {
-		/*
-		 * According to the description of the
-		 * datasheet(Lucent card), the signal level
-		 * value is between 27 -- 154.
-		 * we reflect these value to 1-15 as rssi.
-		 */
-		if (pcwl_p->pcwl_rssi <= 27)
-			*(wl_rssi_t *)wldp_buf = 1;
-		else if (pcwl_p->pcwl_rssi > 154)
-			*(wl_rssi_t *)wldp_buf = 15;
-		else
-			*(wl_rssi_t *)wldp_buf =
-			    min(15, ((pcwl_p->pcwl_rssi - 27) * 15 / 127));
-	}
-}
-
-/*
- * MAC_PROP_WL_KEY_TAB
- */
-static int
-pcwl_set_wepkey(pcwl_maci_t *pcwl_p, const void *wldp_buf)
-{
-	uint16_t	i;
-	pcwl_rf_t 	*rf_p;
-	wl_wep_key_t 	*p_wepkey_tab;
-
-	rf_p = &pcwl_p->pcwl_rf;
-	bzero((rf_p->rf_ckeys), sizeof (rf_ckey_t) * MAX_NWEPKEYS);
-
-	p_wepkey_tab = (wl_wep_key_t *)wldp_buf;
-	for (i = 0; i < MAX_NWEPKEYS; i++) {
-		if (p_wepkey_tab[i].wl_wep_operation == WL_ADD) {
-			rf_p->rf_ckeys[i].ckey_len =
-			    p_wepkey_tab[i].wl_wep_length;
-			bcopy(p_wepkey_tab[i].wl_wep_key,
-			    rf_p->rf_ckeys[i].ckey_dat,
-			    p_wepkey_tab[i].wl_wep_length);
-			PCWL_SWAP16((uint16_t *)
-			    &rf_p->rf_ckeys[i].ckey_dat,
-			    rf_p->rf_ckeys[i].ckey_len + 1);
-			PCWLDBG((CE_CONT, "%s, %d\n",
-			    rf_p->rf_ckeys[i].ckey_dat, i));
-		}
-		PCWLDBG((CE_CONT, "pcwl: rf_ckeys[%d]=%s\n", i,
-		    (char *)(rf_p->rf_ckeys[i].ckey_dat)));
-	}
-
-	return (ENETRESET);
-}
-
-/*
- * MAC_PROP_WL_RADIO
- */
-static void
-pcwl_get_radio(void *wldp_buf)
-{
-	wl_radio_t *radio = (wl_radio_t *)wldp_buf;
-
-	*radio = B_TRUE;
-}
-
-/*
- * MAC_PROP_WL_ESSLIST
- */
-static void
-pcwl_get_esslist(pcwl_maci_t *pcwl_p, void *wldp_buf)
-{
-	uint16_t	i;
-	wl_ess_conf_t 	*p_ess_conf;
-	wl_scan_list_t	*scan_item;
-
-	mutex_enter(&pcwl_p->pcwl_scanlist_lock);
-
-	((wl_ess_list_t *)wldp_buf)->wl_ess_list_num =
-	    pcwl_p->pcwl_scan_num;
-
-	scan_item = list_head(&pcwl_p->pcwl_scan_list);
-
-	for (i = 0; i < pcwl_p->pcwl_scan_num; i++) {
-		if (!scan_item)
-			break;
-
-		p_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf +
-		    offsetof(wl_ess_list_t, wl_ess_list_ess) +
-		    i * sizeof (wl_ess_conf_t));
-		bcopy(scan_item->wl_val.wl_srt_ssid,
-		    p_ess_conf->wl_ess_conf_essid.wl_essid_essid,
-		    mi_strlen(scan_item->wl_val.wl_srt_ssid));
-		bcopy(scan_item->wl_val.wl_srt_bssid,
-		    p_ess_conf->wl_ess_conf_bssid, 6);
-		(p_ess_conf->wl_phy_conf).wl_phy_dsss_conf.wl_dsss_subtype
-		    = WL_DSSS;
-		p_ess_conf->wl_ess_conf_wepenabled =
-		    (scan_item->wl_val.wl_srt_cap & 0x10 ?
-		    WL_ENC_WEP : WL_NOENCRYPTION);
-		p_ess_conf->wl_ess_conf_bsstype =
-		    (scan_item->wl_val.wl_srt_cap & 0x1 ?
-		    WL_BSS_BSS : WL_BSS_IBSS);
-		p_ess_conf->wl_phy_conf.wl_phy_dsss_conf.wl_dsss_channel =
-		    scan_item->wl_val.wl_srt_chid;
-		if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
-			p_ess_conf->wl_ess_conf_sl =
-			    min(scan_item->wl_val.wl_srt_sl * 15 / 85 + 1,
-			    15);
-		} else {
-			if (scan_item->wl_val.wl_srt_sl <= 27)
-				p_ess_conf->wl_ess_conf_sl = 1;
-			else if (scan_item->wl_val.wl_srt_sl > 154)
-				p_ess_conf->wl_ess_conf_sl = 15;
-			else
-				p_ess_conf->wl_ess_conf_sl = min(15,
-				    ((scan_item->wl_val.wl_srt_sl - 27)
-				    * 15 / 127));
-		}
-
-		p_ess_conf->wl_supported_rates[0] = WL_RATE_1M;
-		p_ess_conf->wl_supported_rates[0] = WL_RATE_2M;
-		p_ess_conf->wl_supported_rates[0] = WL_RATE_5_5M;
-		p_ess_conf->wl_supported_rates[0] = WL_RATE_11M;
-
-		scan_item = list_next(&pcwl_p->pcwl_scan_list, scan_item);
-	}
-
-	mutex_exit(&pcwl_p->pcwl_scanlist_lock);
-}
-
-
-/*
- * for wificonfig and dladm ioctl
- */
-
-static int
-pcwl_cfg_essid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	char 		ssid[36];
-	uint16_t 	i;
-	uint16_t 	val;
-	pcwl_rf_t 	*rf_p;
-	wldp_t		*infp;
-	wldp_t 		*outfp;
-	char 		*buf;
-	int 		iret;
-	int 		err = 0;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
-		    MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-	rf_p = &pcwl_p->pcwl_rf;
-
-
-	bzero(ssid, sizeof (ssid));
-	if (cmd == WLAN_GET_PARAM) {
-		err = pcwl_get_essid(pcwl_p, outfp->wldp_buf);
-		if (err == EIO) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_HW_ERROR;
-			goto done;
-		}
-		(void) pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &val);
-		if (val == WL_PORT_DISABLED || val == WL_PORT_INITIAL) {
-			outfp->wldp_length = WIFI_BUF_OFFSET +
-			    offsetof(wl_essid_t, wl_essid_essid) +
-			    mi_strlen(rf_p->rf_desired_ssid);
-		} else if (val == WL_PORT_TO_IBSS ||
-		    val == WL_PORT_TO_BSS ||
-		    val == WL_PORT_OOR) {
-			outfp->wldp_length = WIFI_BUF_OFFSET +
-			    offsetof(wl_essid_t, wl_essid_essid) +
-			    mi_strlen(ssid+2);
-		} else {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-		}
-		outfp->wldp_result = WL_SUCCESS;
-		PCWLDBG((CE_CONT, "outfp->length=%d\n", outfp->wldp_length));
-		PCWLDBG((CE_CONT, "pcwl: get desired essid=%s\n",
-		    rf_p->rf_desired_ssid));
-	} else if (cmd == WLAN_SET_PARAM) {
-		(void) pcwl_set_essid(pcwl_p, infp->wldp_buf);
-		outfp->wldp_length = WIFI_BUF_OFFSET;
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-static int
-pcwl_cfg_bssid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	uint16_t 	i;
-	int 		iret;
-	wldp_t 		*outfp;
-	char 		*buf;
-	int 		err = 0;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
-		    MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-
-	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bssid_t);
-	if (cmd == WLAN_GET_PARAM) {
-		err = pcwl_get_bssid(pcwl_p, outfp->wldp_buf);
-		if (err == EIO) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_HW_ERROR;
-			goto done;
-		}
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		outfp->wldp_result = WL_READONLY;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-/*ARGSUSED*/
-static int
-pcwl_cmd_scan(pcwl_maci_t *pcwl_p)
-{
-	uint16_t vall[18], ret = WL_SUCCESS;
-	pcwl_rf_t *rf_p;
-	uint32_t enable, i;
-	size_t	len;
-
-	rf_p = &pcwl_p->pcwl_rf;
-
-	/*
-	 * The logic of this funtion is really tricky.
-	 * Firstly, the chip can only scan in BSS mode, so necessary
-	 * backup and restore is required before and after the scan
-	 * command.
-	 * Secondly, for Lucent chip, Alrealy associated with an AP
-	 * can only scan the APes on the fixed channel, so we must
-	 * set the desired_ssid as "" before scan and restore after.
-	 * Thirdly, scan cmd is effective only when the card is enabled
-	 * and any 'set' operation(such as set bsstype, ssid)must disable
-	 * the card first and then enable the card after the 'set'
-	 */
-	enable = pcwl_p->pcwl_flag & PCWL_ENABLED;
-	len = strlen(rf_p->rf_desired_ssid);
-
-	if (pcwl_p->pcwl_rf.rf_porttype != WL_BSS_BSS) {
-		if ((enable) &&
-		    (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) {
-			ret = (int)WL_HW_ERROR;
-			goto done;
-		}
-		FIL_LTV(pcwl_p, 2, WL_RID_PORTTYPE, WL_BSS_BSS);
-	}
-
-	if ((pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT) && (len != 0)) {
-		if ((enable) &&
-		    (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) {
-			ret = (int)WL_HW_ERROR;
-			goto done;
-		}
-		PUT_STR(pcwl_p, WL_RID_DESIRED_SSID, "");
-	}
-
-	if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
-		ret = (int)WL_HW_ERROR;
-		goto done;
-	}
-	pcwl_delay(pcwl_p, 1000000);
-
-	switch (pcwl_p->pcwl_chip_type) {
-	case PCWL_CHIP_PRISMII:
-		bzero(vall, sizeof (vall));
-		vall[0] = 0x3fff; /* channel mask */
-		vall[1] = 0x1; /* tx rate */
-		for (i = 0; i < WL_MAX_SCAN_TIMES; i++) {
-			PUT_LTV(pcwl_p, sizeof (vall),
-			    WL_RID_HSCAN_REQUEST, vall);
-			pcwl_delay(pcwl_p, 1000000);
-			if (pcwl_p->pcwl_scan_num >= WL_SCAN_AGAIN_THRESHOLD)
-				break;
-		}
-		PCWLDBG((CE_NOTE, "PRISM chip\n"));
-		break;
-
-	case PCWL_CHIP_LUCENT:
-		PCWLDBG((CE_NOTE, "LUCENT chip\n"));
-	default:
-		for (i = 0; i < WL_MAX_SCAN_TIMES; i++) {
-			if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_INQUIRE,
-			    WL_INFO_SCAN_RESULTS)) {
-				ret = (int)WL_HW_ERROR;
-				goto done;
-			}
-			pcwl_delay(pcwl_p, 500000);
-			if (pcwl_p->pcwl_scan_num >= WL_SCAN_AGAIN_THRESHOLD)
-				break;
-		}
-		break;
-	}
-	if ((pcwl_p->pcwl_rf.rf_porttype != WL_BSS_BSS) ||
-	    ((pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT) && (len != 0))) {
-		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
-			ret = (int)WL_HW_ERROR;
-			goto done;
-		}
-		if (ret = pcwl_config_rf(pcwl_p)) {
-			ret = (int)WL_HW_ERROR;
-			goto done;
-		}
-		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
-			ret = (int)WL_HW_ERROR;
-			goto done;
-		}
-
-		pcwl_delay(pcwl_p, 1000000);
-	}
-
-	if ((!enable) && (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0))) {
-		ret = (int)WL_HW_ERROR;
-	}
-done:
-	if (ret)
-		cmn_err(CE_WARN, "pcwl: scan failed due to hardware error");
-	return (ret);
-
-}
-
-/*ARGSUSED*/
-static int
-pcwl_cfg_scan(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	wldp_t 		*outfp;
-	char 		*buf;
-	uint16_t 	i;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
-		    MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-
-	pcwl_get_esslist(pcwl_p, outfp->wldp_buf);
-
-	outfp->wldp_length = WIFI_BUF_OFFSET +
-	    offsetof(wl_ess_list_t, wl_ess_list_ess) +
-	    pcwl_p->pcwl_scan_num * sizeof (wl_ess_conf_t);
-	outfp->wldp_result = WL_SUCCESS;
-
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (WL_SUCCESS);
-
-}
-
-/*ARGSUSED*/
-static int
-pcwl_cfg_linkstatus(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	wldp_t 		*outfp;
-	char 		*buf;
-	uint16_t 	i, val;
-	int 		iret;
-	int 		err = 0;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
-		    MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-
-	err = pcwl_get_linkstatus(pcwl_p, outfp->wldp_buf);
-	if (err == EIO) {
-		outfp->wldp_length = WIFI_BUF_OFFSET;
-		outfp->wldp_result = WL_HW_ERROR;
-		goto done;
-	}
-
-	(void) pcwl_get_ltv(pcwl_p, 2, WL_RID_PORTSTATUS, &val);
-	if (val == WL_PORT_DISABLED || val == WL_PORT_INITIAL) {
-		outfp->wldp_length = WIFI_BUF_OFFSET +
-		    sizeof (wl_linkstatus_t);
-	} else if (val == WL_PORT_TO_IBSS ||
-	    val == WL_PORT_TO_BSS ||
-	    val == WL_PORT_OOR) {
-		outfp->wldp_length = WIFI_BUF_OFFSET +
-		    sizeof (wl_linkstatus_t);
-	} else {
-		outfp->wldp_length = WIFI_BUF_OFFSET;
-	}
-
-	outfp->wldp_result = WL_SUCCESS;
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-static int
-pcwl_cfg_bsstype(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	uint16_t 	i;
-	wldp_t		*infp;
-	wldp_t 		*outfp;
-	char 		*buf;
-	int 		iret;
-	int		err = 0;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
-		    MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-
-	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_bss_type_t);
-	if (cmd == WLAN_GET_PARAM) {
-		pcwl_get_bsstype(pcwl_p, outfp->wldp_buf);
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		err = pcwl_set_bsstype(pcwl_p, infp->wldp_buf);
-		if (err == ENOTSUP) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_NOTSUPPORTED;
-			goto done;
-		}
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-static int
-pcwl_cfg_phy(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	uint16_t 	i;
-	wldp_t		*infp;
-	wldp_t 		*outfp;
-	char 		*buf;
-	int 		iret;
-	int 		err = 0;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
-		    MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-
-	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_dsss_t);
-	if (cmd == WLAN_GET_PARAM) {
-		err = pcwl_get_phy(pcwl_p, outfp->wldp_buf);
-		if (err == EIO) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_HW_ERROR;
-			goto done;
-		}
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		err = pcwl_set_phy(pcwl_p, infp->wldp_buf);
-		if (err == ENOTSUP) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_NOTSUPPORTED;
-			goto done;
-		}
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-
-}
-
-static int
-pcwl_cfg_desiredrates(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	uint16_t 	rate;
-	uint16_t 	i;
-	wldp_t		*infp;
-	wldp_t 		*outfp;
-	char 		*buf;
-	int 		iret;
-	int 		err = 0;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
-		    MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-
-	if (cmd == WLAN_GET_PARAM) {
-		err = pcwl_get_desrates(pcwl_p, outfp->wldp_buf);
-		if (err == EIO || err == EINVAL) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_NOTSUPPORTED;
-			goto done;
-		}
-		if (pcwl_p->pcwl_chip_type == PCWL_CHIP_PRISMII) {
-			outfp->wldp_length = WIFI_BUF_OFFSET +
-			    offsetof(wl_rates_t, wl_rates_rates) +
-			    1 * sizeof (char);
-		} else {
-			(void) pcwl_get_ltv(pcwl_p, 2, WL_RID_TX_RATE, &rate);
-			switch (rate) {
-			case WL_L_TX_RATE_FIX_1M:
-				outfp->wldp_length = WIFI_BUF_OFFSET +
-				    offsetof(wl_rates_t, wl_rates_rates) +
-				    1 * sizeof (char);
-				break;
-			case WL_L_TX_RATE_FIX_2M:
-				outfp->wldp_length = WIFI_BUF_OFFSET +
-				    offsetof(wl_rates_t, wl_rates_rates) +
-				    1 * sizeof (char);
-				break;
-			case WL_L_TX_RATE_AUTO_H:
-				outfp->wldp_length = WIFI_BUF_OFFSET +
-				    offsetof(wl_rates_t, wl_rates_rates) +
-				    4 * sizeof (char);
-				break;
-			case WL_L_TX_RATE_FIX_5M:
-				outfp->wldp_length = WIFI_BUF_OFFSET +
-				    offsetof(wl_rates_t, wl_rates_rates) +
-				    1 * sizeof (char);
-				break;
-			case WL_L_TX_RATE_FIX_11M:
-				outfp->wldp_length = WIFI_BUF_OFFSET +
-				    offsetof(wl_rates_t, wl_rates_rates) +
-				    1 * sizeof (char);
-				break;
-			case WL_L_TX_RATE_AUTO_L:
-				outfp->wldp_length = WIFI_BUF_OFFSET +
-				    offsetof(wl_rates_t, wl_rates_rates) +
-				    2 * sizeof (char);
-				break;
-			case WL_L_TX_RATE_AUTO_M:
-				outfp->wldp_length = WIFI_BUF_OFFSET +
-				    offsetof(wl_rates_t, wl_rates_rates) +
-				    3 * sizeof (char);
-				break;
-			default:
-				break;
-			}
-		}
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		err = pcwl_set_desrates(pcwl_p, infp->wldp_buf);
-		if (err == EINVAL) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_NOTSUPPORTED;
-			goto done;
-		}
-		if (err == ENOTSUP) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_LACK_FEATURE;
-			goto done;
-		}
-
-		outfp->wldp_length = WIFI_BUF_OFFSET;
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-/*ARGSUSED*/
-static int
-pcwl_cfg_supportrates(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	uint16_t i;
-	wldp_t *outfp;
-	char *buf;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
-		    MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-
-	if (cmd == WLAN_GET_PARAM) {
-		pcwl_get_suprates(outfp->wldp_buf);
-		outfp->wldp_length = WIFI_BUF_OFFSET +
-		    offsetof(wl_rates_t, wl_rates_rates) +
-		    4 * sizeof (char);
-		outfp->wldp_result = WL_SUCCESS;
-		for (i = 0; i < (outfp->wldp_length); i++)
-			(void) mi_mpprintf_putc((char *)mp, buf[i]);
-		kmem_free(buf, MAX_BUF_LEN);
-		return (WL_SUCCESS);
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-}
-
-static int
-pcwl_cfg_powermode(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	uint16_t 	i;
-	wldp_t		*infp;
-	wldp_t 		*outfp;
-	char 		*buf;
-	int 		iret;
-	int 		err = 0;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
-		    MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-
-	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_ps_mode_t);
-	if (cmd == WLAN_GET_PARAM) {
-		pcwl_get_powermode(pcwl_p, outfp->wldp_buf);
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		err = pcwl_set_powermode(pcwl_p, infp->wldp_buf);
-		if (err == ENOTSUP) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_NOTSUPPORTED;
-			goto done;
-		}
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-
-}
-
-static int
-pcwl_cfg_authmode(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	uint16_t 	i;
-	wldp_t		*infp;
-	wldp_t 		*outfp;
-	char 		*buf;
-	int 		iret;
-	int 		err = 0;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
-		    MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-
-	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_authmode_t);
-	if (cmd == WLAN_GET_PARAM) {
-		pcwl_get_authmode(pcwl_p, outfp->wldp_buf);
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		err = pcwl_set_authmode(pcwl_p, infp->wldp_buf);
-		if (err == ENOTSUP) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_NOTSUPPORTED;
-			goto done;
-		}
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-static int
-pcwl_cfg_encryption(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	uint16_t 	i;
-	wldp_t		*infp;
-	wldp_t 		*outfp;
-	char 		*buf;
-	int 		iret;
-	int 		err = 0;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
-		    MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-
-	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_encryption_t);
-	if (cmd == WLAN_GET_PARAM) {
-		pcwl_get_encrypt(pcwl_p, outfp->wldp_buf);
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		err = pcwl_set_encrypt(pcwl_p, infp->wldp_buf);
-		if (err == ENOTSUP) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_NOTSUPPORTED;
-			goto done;
-		}
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-static int
-pcwl_cfg_wepkeyid(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	uint16_t i, ret;
-	pcwl_rf_t *rf_p;
-	wldp_t	*infp;
-	wldp_t *outfp;
-	char *buf;
-	int iret;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
-		    MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-	rf_p = &pcwl_p->pcwl_rf;
-
-	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_id_t);
-	if (cmd == WLAN_GET_PARAM) {
-		*(wl_wep_key_id_t *)(outfp->wldp_buf) = rf_p->rf_tx_crypt_key;
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		ret = (uint16_t)(*(wl_wep_key_id_t *)(infp->wldp_buf));
-		if (ret >= MAX_NWEPKEYS) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_NOTSUPPORTED;
-			goto done;
-		}
-		rf_p->rf_tx_crypt_key = ret;
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-static int
-pcwl_cfg_createibss(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	uint16_t 	i;
-	wldp_t		*infp;
-	wldp_t 		*outfp;
-	char 		*buf;
-	int 		iret;
-	int 		err = 0;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
-		    MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-
-	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_create_ibss_t);
-	if (cmd == WLAN_GET_PARAM) {
-		pcwl_get_ibss(pcwl_p, outfp->wldp_buf);
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		err = pcwl_set_ibss(pcwl_p, infp->wldp_buf);
-		if (err == ENOTSUP) {
-			outfp->wldp_length = WIFI_BUF_OFFSET;
-			outfp->wldp_result = WL_NOTSUPPORTED;
-			goto done;
-		}
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-static int
-pcwl_cfg_rssi(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	uint16_t i;
-	int iret;
-	wldp_t *outfp;
-	char *buf;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
-		    MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-
-	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_rssi_t);
-
-	if (cmd == WLAN_GET_PARAM) {
-		pcwl_get_param_rssi(pcwl_p, outfp->wldp_buf);
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		outfp->wldp_result = WL_READONLY;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-/*ARGSUSED*/
-static int
-pcwl_cfg_radio(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	uint16_t i;
-	int iret;
-	wldp_t *outfp;
-	char *buf;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
-		    MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-
-	if (cmd == WLAN_GET_PARAM) {
-		*(wl_radio_t *)(outfp->wldp_buf) = B_TRUE;
-		outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_radio_t);
-		outfp->wldp_result = WL_SUCCESS;
-	} else if (cmd == WLAN_SET_PARAM) {
-		outfp->wldp_length = WIFI_BUF_OFFSET;
-		outfp->wldp_result = WL_LACK_FEATURE;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-static int
-pcwl_cfg_wepkey(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	uint16_t 	i;
-	wldp_t		*infp;
-	wldp_t 		*outfp;
-	char 		*buf;
-	int 		iret;
-
-	buf = kmem_zalloc(MAX_BUF_LEN, KM_NOSLEEP);
-	if (buf == NULL) {
-		PCWLDBG((CE_NOTE, "can not alloc so much memory!(%d)\n",
-		    MAX_BUF_LEN));
-		return (ENOMEM);
-	}
-	outfp = (wldp_t *)buf;
-	bcopy(mp->b_rptr, buf,  sizeof (wldp_t));
-	infp = (wldp_t *)mp->b_rptr;
-
-	outfp->wldp_length = WIFI_BUF_OFFSET + sizeof (wl_wep_key_tab_t);
-	if (cmd == WLAN_GET_PARAM) {
-		outfp->wldp_result = WL_WRITEONLY;
-	} else if (cmd == WLAN_SET_PARAM) {
-		(void) pcwl_set_wepkey(pcwl_p, infp->wldp_buf);
-		outfp->wldp_result = WL_SUCCESS;
-	} else {
-		kmem_free(buf, MAX_BUF_LEN);
-		return (EINVAL);
-	}
-done:
-	for (i = 0; i < (outfp->wldp_length); i++)
-		(void) mi_mpprintf_putc((char *)mp, buf[i]);
-	iret = (int)(outfp->wldp_result);
-	kmem_free(buf, MAX_BUF_LEN);
-	return (iret);
-}
-
-static void
-pcwl_connect_timeout(void *arg)
-{
-	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
-	uint16_t ret = 0;
-
-	mutex_enter(&pcwl_p->pcwl_glock);
-	PCWL_DISABLE_INTR(pcwl_p);
-	if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
-		goto done;
-	}
-	if (ret = pcwl_config_rf(pcwl_p)) {
-		goto done;
-	}
-	if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
-		goto done;
-	}
-	PCWL_ENABLE_INTR(pcwl_p);
-done:
-	if (ret)
-		cmn_err(CE_WARN, "pcwl: connect failed due to hardware error");
-	mutex_exit(&pcwl_p->pcwl_glock);
-	pcwl_p->pcwl_connect_timeout_id = 0;
-}
-
-static int
-pcwl_getset(mblk_t *mp, pcwl_maci_t *pcwl_p, uint32_t cmd)
-{
-	int ret = WL_SUCCESS;
-	int connect = 0;
-
-	mutex_enter(&pcwl_p->pcwl_glock);
-	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
-		mutex_exit(&pcwl_p->pcwl_glock);
-		return (PCWL_FAIL);
-	}
-	switch (((wldp_t *)mp->b_rptr)->wldp_id) {
-	case WL_ESSID:
-		ret = pcwl_cfg_essid(mp, pcwl_p, cmd);
-		connect = 1;
-		PCWLDBG((CE_NOTE, "cfg_essid\n"));
-		break;
-	case WL_BSSID:
-		ret = pcwl_cfg_bssid(mp, pcwl_p, cmd);
-		connect = 1;
-		PCWLDBG((CE_NOTE, "cfg_bssid\n"));
-		break;
-	case WL_ESS_LIST:
-		ret = pcwl_cfg_scan(mp, pcwl_p, cmd);
-		PCWLDBG((CE_NOTE, "cfg_scan\n"));
-		break;
-	case WL_LINKSTATUS:
-		ret = pcwl_cfg_linkstatus(mp, pcwl_p, cmd);
-		PCWLDBG((CE_NOTE, "cfg_linkstatus\n"));
-		break;
-	case WL_BSS_TYPE:
-		ret = pcwl_cfg_bsstype(mp, pcwl_p, cmd);
-		connect = 1;
-		PCWLDBG((CE_NOTE, "cfg_bsstype\n"));
-		break;
-	case WL_PHY_CONFIG:
-		ret = pcwl_cfg_phy(mp, pcwl_p, cmd);
-		connect = 1;
-		PCWLDBG((CE_NOTE, "cfg_phy\n"));
-		break;
-	case WL_DESIRED_RATES:
-		ret = pcwl_cfg_desiredrates(mp, pcwl_p, cmd);
-		connect = 1;
-		PCWLDBG((CE_NOTE, "cfg_disred-rates\n"));
-		break;
-	case WL_SUPPORTED_RATES:
-		ret = pcwl_cfg_supportrates(mp, pcwl_p, cmd);
-		PCWLDBG((CE_NOTE, "cfg_supported-rates\n"));
-		break;
-	case WL_POWER_MODE:
-		ret = pcwl_cfg_powermode(mp, pcwl_p, cmd);
-		PCWLDBG((CE_NOTE, "cfg_powermode\n"));
-		break;
-	case WL_AUTH_MODE:
-		ret = pcwl_cfg_authmode(mp, pcwl_p, cmd);
-		connect = 1;
-		PCWLDBG((CE_NOTE, "cfg_authmode\n"));
-		break;
-	case WL_ENCRYPTION:
-		ret = pcwl_cfg_encryption(mp, pcwl_p, cmd);
-		connect = 1;
-		PCWLDBG((CE_NOTE, "cfg_encryption\n"));
-		break;
-	case WL_WEP_KEY_ID:
-		ret = pcwl_cfg_wepkeyid(mp, pcwl_p, cmd);
-		connect = 1;
-		PCWLDBG((CE_NOTE, "cfg_wepkeyid\n"));
-		break;
-	case WL_CREATE_IBSS:
-		ret = pcwl_cfg_createibss(mp, pcwl_p, cmd);
-		connect = 1;
-		PCWLDBG((CE_NOTE, "cfg_create-ibss\n"));
-		break;
-	case WL_RSSI:
-		ret = pcwl_cfg_rssi(mp, pcwl_p, cmd);
-		PCWLDBG((CE_NOTE, "cfg_rssi\n"));
-		break;
-	case WL_RADIO:
-		ret = pcwl_cfg_radio(mp, pcwl_p, cmd);
-		PCWLDBG((CE_NOTE, "cfg_radio\n"));
-		break;
-	case WL_WEP_KEY_TAB:
-		ret = pcwl_cfg_wepkey(mp, pcwl_p, cmd);
-		connect = 1;
-		PCWLDBG((CE_NOTE, "cfg_wepkey\n"));
-		break;
-	case WL_SCAN:
-		mutex_exit(&pcwl_p->pcwl_glock);
-		if (pcwl_p->pcwl_connect_timeout_id != 0) {
-			(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
-			pcwl_p->pcwl_connect_timeout_id = 0;
-		}
-		mutex_enter(&pcwl_p->pcwl_glock);
-		ret = pcwl_cmd_scan(pcwl_p);
-		break;
-	case WL_LOAD_DEFAULTS:
-		mutex_exit(&pcwl_p->pcwl_glock);
-		if (pcwl_p->pcwl_connect_timeout_id != 0) {
-			(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
-			pcwl_p->pcwl_connect_timeout_id = 0;
-		}
-		mutex_enter(&pcwl_p->pcwl_glock);
-		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		if (ret = pcwl_loaddef_rf(pcwl_p)) {
-			ret = (int)WL_HW_ERROR;
-			PCWLDBG((CE_WARN, "cfg_loaddef_err\n"));
-			break;
-		}
-		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		pcwl_delay(pcwl_p, 1000000);
-		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		PCWLDBG((CE_NOTE, "loaddef\n"));
-		break;
-	case WL_DISASSOCIATE:
-		mutex_exit(&pcwl_p->pcwl_glock);
-		if (pcwl_p->pcwl_connect_timeout_id != 0) {
-			(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
-			pcwl_p->pcwl_connect_timeout_id = 0;
-		}
-
-		mutex_enter(&pcwl_p->pcwl_glock);
-		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		/*
-		 * A workaround here: If the card is in ad-hoc mode, the
-		 * following scan will not work correctly, so any
-		 * 'dladm connect-wifi' which need a scan first will not
-		 * succeed. software reset the card here as a workround.
-		 */
-		if ((pcwl_p->pcwl_rf.rf_porttype == WL_BSS_IBSS) &&
-		    (pcwl_p->pcwl_chip_type == PCWL_CHIP_LUCENT)) {
-			if (ret = pcwl_reset_backend(pcwl_p)) {
-				ret = (int)WL_HW_ERROR;
-				break;
-			}
-			if (ret = pcwl_init_nicmem(pcwl_p)) {
-				ret = (int)WL_HW_ERROR;
-				break;
-			}
-			pcwl_start_locked(pcwl_p);
-		}
-		if (ret = pcwl_loaddef_rf(pcwl_p)) {
-			ret = (int)WL_HW_ERROR;
-			PCWLDBG((CE_WARN, "cfg_loaddef_err\n"));
-			break;
-		}
-		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		pcwl_delay(pcwl_p, 1000000);
-		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		PCWLDBG((CE_NOTE, "disassociate\n"));
-		break;
-	case WL_REASSOCIATE:
-	case WL_ASSOCIAT:
-		mutex_exit(&pcwl_p->pcwl_glock);
-		if (pcwl_p->pcwl_connect_timeout_id != 0) {
-			(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
-			pcwl_p->pcwl_connect_timeout_id = 0;
-		}
-		mutex_enter(&pcwl_p->pcwl_glock);
-		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		if (ret = pcwl_config_rf(pcwl_p)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		if (ret = pcwl_set_cmd(pcwl_p, WL_CMD_ENABLE, 0)) {
-			ret = (int)WL_HW_ERROR;
-			break;
-		}
-		PCWLDBG((CE_NOTE, "associate"));
-		break;
-	default:
-		break;
-	}
-	mutex_exit(&pcwl_p->pcwl_glock);
-	if ((cmd == WLAN_SET_PARAM) && (connect)) {
-		(void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
-		if (pcwl_p->pcwl_connect_timeout_id != 0) {
-			(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
-			pcwl_p->pcwl_connect_timeout_id = 0;
-		}
-		pcwl_p->pcwl_connect_timeout_id = timeout(pcwl_connect_timeout,
-		    pcwl_p, 2 * drv_usectohz(1000000));
-	}
-	return (ret);
-}
-
-static void
-pcwl_wlan_ioctl(pcwl_maci_t *pcwl_p, queue_t *wq, mblk_t *mp, uint32_t cmd)
-{
-
-	struct	iocblk	*iocp = (struct iocblk *)mp->b_rptr;
-	wldp_t 	*infp;
-	uint32_t len, ret;
-	mblk_t		*mp1;
-
-	/*
-	 * sanity check
-	 */
-	if (iocp->ioc_count == 0 || !(mp1 = mp->b_cont)) {
-		miocnak(wq, mp, 0, EINVAL);
-		return;
-	}
-
-	/*
-	 * assuming single data block
-	 */
-	if (mp1->b_cont) {
-		freemsg(mp1->b_cont);
-		mp1->b_cont = NULL;
-	}
-
-	/*
-	 * we will overwrite everything
-	 */
-	mp1->b_wptr = mp1->b_rptr;
-
-	infp = (wldp_t *)mp1->b_rptr;
-	PCWLDBG((CE_NOTE, "pcwl: wldp->length=0x%x\n", infp->wldp_length));
-	PCWLDBG((CE_NOTE, "pcwl: wldp->type =:%s\n",
-	    infp->wldp_type == NET_802_11 ? "NET_802_11" : "Unknown"));
-	PCWLDBG((CE_NOTE, "pcwl: wldp->id=0x%x\n", infp->wldp_id));
-	PCWLDBG((CE_NOTE, "pcwl: wldp->result=0x%x\n", infp->wldp_result));
-
-	ret = pcwl_getset(mp1, pcwl_p, cmd);
-	len = msgdsize(mp1);
-	PCWLDBG((CE_CONT, "pcwl: ioctl message length = %d\n", len));
-	miocack(wq, mp, len, ret);
-
-}
-
-
-static void
-pcwl_ioctl(void *arg, queue_t *wq, mblk_t *mp)
-{
-	struct iocblk *iocp;
-	uint32_t cmd, ret;
-	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
-	boolean_t need_privilege = B_TRUE;
-
-	/*
-	 * Validate the command before bothering with the mutexen ...
-	 */
-	iocp = (struct iocblk *)mp->b_rptr;
-	iocp->ioc_error = 0;
-	cmd = iocp->ioc_cmd;
-	switch (cmd) {
-	default:
-		PCWLDBG((CE_CONT, "pcwl_ioctl: unknown cmd 0x%x", cmd));
-		miocnak(wq, mp, 0, EINVAL);
-		return;
-	case WLAN_GET_PARAM:
-		need_privilege = B_FALSE;
-		break;
-	case WLAN_SET_PARAM:
-	case WLAN_COMMAND:
-		break;
-	}
-
-	if (need_privilege && (ret = secpolicy_dl_config(iocp->ioc_cr)) != 0)
-		miocnak(wq, mp, 0, ret);
-	else
-		pcwl_wlan_ioctl(pcwl_p, wq, mp, cmd);
-}
-
-/*
- * brussels
- */
-/* ARGSUSED */
-static int
-pcwl_m_setprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
-    uint_t wldp_length, const void *wldp_buf)
-{
-	int 		err = 0;
-	pcwl_maci_t 	*pcwl_p = (pcwl_maci_t *)arg;
-
-	mutex_enter(&pcwl_p->pcwl_glock);
-	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
-		mutex_exit(&pcwl_p->pcwl_glock);
-		err = EINVAL;
-		return (err);
-	}
-
-	switch (wldp_pr_num) {
-	/* mac_prop_id */
-	case MAC_PROP_WL_ESSID:
-		err = pcwl_set_essid(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_PHY_CONFIG:
-		err = pcwl_set_phy(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_KEY_TAB:
-		err = pcwl_set_wepkey(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_AUTH_MODE:
-		err = pcwl_set_authmode(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_ENCRYPTION:
-		err = pcwl_set_encrypt(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_BSSTYPE:
-		err = pcwl_set_bsstype(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_DESIRED_RATES:
-		err = pcwl_set_desrates(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_POWER_MODE:
-		err = pcwl_set_powermode(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_CREATE_IBSS:
-		err = pcwl_set_ibss(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_BSSID:
-	case MAC_PROP_WL_RADIO:
-	case MAC_PROP_WL_WPA:
-	case MAC_PROP_WL_KEY:
-	case MAC_PROP_WL_DELKEY:
-	case MAC_PROP_WL_SETOPTIE:
-	case MAC_PROP_WL_MLME:
-	case MAC_PROP_WL_LINKSTATUS:
-	case MAC_PROP_WL_ESS_LIST:
-	case MAC_PROP_WL_SUPPORTED_RATES:
-	case MAC_PROP_WL_RSSI:
-	case MAC_PROP_WL_CAPABILITY:
-	case MAC_PROP_WL_SCANRESULTS:
-		cmn_err(CE_WARN, "pcwl_setprop:"
-		    "opmode not support\n");
-		err = ENOTSUP;
-		break;
-	default:
-		cmn_err(CE_WARN, "pcwl_setprop:"
-		    "opmode err\n");
-		err = EINVAL;
-		break;
-	}
-
-	mutex_exit(&pcwl_p->pcwl_glock);
-
-	if (err == ENETRESET) {
-		(void) pcwl_set_cmd(pcwl_p, WL_CMD_DISABLE, 0);
-		if (pcwl_p->pcwl_connect_timeout_id != 0) {
-			(void) untimeout(pcwl_p->pcwl_connect_timeout_id);
-			pcwl_p->pcwl_connect_timeout_id = 0;
-		}
-		pcwl_p->pcwl_connect_timeout_id = timeout(pcwl_connect_timeout,
-		    pcwl_p, 2 * drv_usectohz(1000000));
-
-		err = 0;
-	}
-
-	return (err);
-} /* ARGSUSED */
-
-/* ARGSUSED */
-static int
-pcwl_m_getprop(void *arg, const char *pr_name, mac_prop_id_t wldp_pr_num,
-    uint_t wldp_length, void *wldp_buf)
-{
-	int err = 0;
-	pcwl_maci_t *pcwl_p = (pcwl_maci_t *)arg;
-
-	mutex_enter(&pcwl_p->pcwl_glock);
-	if (!(pcwl_p->pcwl_flag & PCWL_CARD_READY)) {
-		mutex_exit(&pcwl_p->pcwl_glock);
-		err = EINVAL;
-		return (err);
-	}
-
-	switch (wldp_pr_num) {
-	/* mac_prop_id */
-	case MAC_PROP_WL_ESSID:
-		err = pcwl_get_essid(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_BSSID:
-		err = pcwl_get_bssid(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_PHY_CONFIG:
-		err = pcwl_get_phy(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_AUTH_MODE:
-		pcwl_get_authmode(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_ENCRYPTION:
-		pcwl_get_encrypt(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_BSSTYPE:
-		pcwl_get_bsstype(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_LINKSTATUS:
-		err = pcwl_get_linkstatus(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_ESS_LIST:
-		pcwl_get_esslist(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_SUPPORTED_RATES:
-		pcwl_get_suprates(wldp_buf);
-		break;
-	case MAC_PROP_WL_RSSI:
-		pcwl_get_param_rssi(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_RADIO:
-		pcwl_get_radio(wldp_buf);
-		break;
-	case MAC_PROP_WL_POWER_MODE:
-		pcwl_get_powermode(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_CREATE_IBSS:
-		pcwl_get_ibss(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_DESIRED_RATES:
-		err = pcwl_get_desrates(pcwl_p, wldp_buf);
-		break;
-	case MAC_PROP_WL_CAPABILITY:
-	case MAC_PROP_WL_WPA:
-	case MAC_PROP_WL_SCANRESULTS:
-	case MAC_PROP_WL_KEY_TAB:
-	case MAC_PROP_WL_KEY:
-	case MAC_PROP_WL_DELKEY:
-	case MAC_PROP_WL_SETOPTIE:
-	case MAC_PROP_WL_MLME:
-		cmn_err(CE_WARN, "pcwl_getprop:"
-		    "opmode not support\n");
-		err = ENOTSUP;
-		break;
-	default:
-		cmn_err(CE_WARN, "pcwl_getprop:"
-		    "opmode err\n");
-		err = EINVAL;
-		break;
-	}
-
-	mutex_exit(&pcwl_p->pcwl_glock);
-
-	return (err);
-}
-
-
-static void
-pcwl_m_propinfo(void *arg, const char *pr_name, mac_prop_id_t wlpd_pr_num,
-    mac_prop_info_handle_t prh)
-{
-        _NOTE(ARGUNUSED(arg, pr_name));
-
-	switch (wlpd_pr_num) {
-	case MAC_PROP_WL_LINKSTATUS:
-	case MAC_PROP_WL_ESS_LIST:
-	case MAC_PROP_WL_SUPPORTED_RATES:
-	case MAC_PROP_WL_RSSI:
-		mac_prop_info_set_perm(prh, MAC_PROP_PERM_READ);
-	}
-}
-
-
-/*
- * quiesce(9E) entry point.
- *
- * This function is called when the system is single-threaded at high
- * PIL with preemption disabled. Therefore, this function must not be
- * blocked.
- *
- * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
- * DDI_FAILURE indicates an error condition and should almost never happen.
- */
-#ifndef __sparc
-static int
-pcwl_quiesce(dev_info_t *dip)
-{
-	pcwl_maci_t *pcwl_p;
-
-	pcwl_p = ddi_get_soft_state(pcwl_soft_state_p, ddi_get_instance(dip));
-	if (pcwl_p == NULL)
-		return (DDI_FAILURE);
-
-	if (pcwl_p->pcwl_flag & PCWL_CARD_READY)
-		pcwl_stop_locked(pcwl_p);
-
-	return (DDI_SUCCESS);
-}
-#endif
--- a/usr/src/uts/common/io/pcwl/pcwl.h	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,948 +0,0 @@
-/*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Copyright (c) 1997, 1998, 1999
- *      Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *      This product includes software developed by Bill Paul.
- * 4. Neither the name of the author nor the names of any co-contributors
- *    may be used to endorse or promote products derived from this software
- *    without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY Bill Paul 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 Bill Paul OR THE VOICES IN HIS HEAD
- * 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.
- */
-
-/*
- * Hardware specific driver declarations for Lucent and PrismII
- * chipsets.
- */
-
-#ifndef _SYS_PCWL_H
-#define	_SYS_PCWL_H
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-#include <sys/list.h>
-
-/*
- * Encryption controls. We can enable or disable encryption as
- * well as specify up to 4 encryption keys. We can also specify
- * which of the four keys will be used for transmit encryption.
- */
-#define	WL_RID_ENCRYPTION	0xFC20
-#define	WL_RID_ENCRYPTION_P2	0xFC28
-#define	WL_RID_DEFLT_CRYPT_KEYS 0xFCB0
-#define	WL_RID_CRYPT_KEY0_P2	0xFC24
-#define	WL_RID_TX_CRYPT_KEY	0xFCB1
-#define	WL_RID_TX_CRYPT_KEY_P2	0xFC23
-#define	WL_RID_COMP_IDENT	0xFD20	/* version */
-#define	WL_RID_WEP_AVAIL	0xFD4F
-
-#define	WL_RID_AUTHTYPE_P2	0xFC2A	/* PRISM-II */
-#define	WL_RID_AUTHTYPE_L	0xFC21	/* 0xFC21 on Lucent */
-#define	WL_AUTHTYPE_SYS_P2	0x1
-#define	WL_AUTHTYPE_KEY_P2	0x2
-#define	WL_AUTHTYPE_ALL_P2	(WL_AUTHTYPE_SYS_P2 | WL_AUTHTYPE_KEY_P2)
-
-#define	WL_SPEED_1Mbps_P2	0x1
-#define	WL_SPEED_2Mbps_P2	0x2
-#define	WL_SPEED_55Mbps_P2	0x4
-#define	WL_SPEED_11Mbps_P2	0x8
-
-/*
- * PrismII Tx rate
- */
-#define	WL_P_TX_RATE_FIX_1M	WL_SPEED_1Mbps_P2
-#define	WL_P_TX_RATE_FIX_2M	WL_SPEED_2Mbps_P2
-#define	WL_P_TX_RATE_FIX_5M	WL_SPEED_55Mbps_P2
-#define	WL_P_TX_RATE_FIX_11M	WL_SPEED_11Mbps_P2
-#define	WL_P_TX_RATE_AUTO_H	\
-	(WL_SPEED_11Mbps_P2 | WL_SPEED_55Mbps_P2 | \
-	WL_SPEED_2Mbps_P2 | WL_SPEED_1Mbps_P2)
-#define	WL_P_TX_RATE_AUTO_M	\
-	(WL_SPEED_55Mbps_P2 | WL_SPEED_2Mbps_P2 | \
-	WL_SPEED_1Mbps_P2)
-#define	WL_P_TX_RATE_AUTO_L	\
-	(WL_SPEED_2Mbps_P2 | WL_SPEED_1Mbps_P2)
-
-
-#define	WL_TIMEOUT	500000
-
-/*
- * Default port: 0 (only 0 exists on stations)
- */
-#define	WL_DEFAULT_PORT		0
-
-/*
- * Lucent TX rate: Default 11Mbps
- */
-#define	WL_L_TX_RATE_FIX_1M	1
-#define	WL_L_TX_RATE_FIX_2M	2
-#define	WL_L_TX_RATE_AUTO_H	3
-#define	WL_L_TX_RATE_FIX_5M	4 /* 5.5M */
-#define	WL_L_TX_RATE_FIX_11M	5
-#define	WL_L_TX_RATE_AUTO_L	6
-#define	WL_L_TX_RATE_AUTO_M	7
-
-#define	WL_TX_RATE_FIX_1M(p) \
-	(p->pcwl_chip_type == PCWL_CHIP_PRISMII ? \
-	WL_P_TX_RATE_FIX_1M : WL_L_TX_RATE_FIX_1M)
-#define	WL_TX_RATE_FIX_2M(p) \
-	(p->pcwl_chip_type == PCWL_CHIP_PRISMII ? \
-	WL_P_TX_RATE_FIX_2M : WL_L_TX_RATE_FIX_2M)
-#define	WL_TX_RATE_AUTO_H(p) \
-	(p->pcwl_chip_type == PCWL_CHIP_PRISMII ? \
-	WL_P_TX_RATE_AUTO_H : WL_L_TX_RATE_AUTO_H)
-#define	WL_TX_RATE_FIX_5M(p) \
-	(p->pcwl_chip_type == PCWL_CHIP_PRISMII ? \
-	WL_P_TX_RATE_FIX_5M : WL_L_TX_RATE_FIX_5M)
-#define	WL_TX_RATE_FIX_11M(p) \
-	(p->pcwl_chip_type == PCWL_CHIP_PRISMII ? \
-	WL_P_TX_RATE_FIX_11M : WL_L_TX_RATE_FIX_11M)
-#define	WL_TX_RATE_AUTO_L(p) \
-	(p->pcwl_chip_type == PCWL_CHIP_PRISMII ? \
-	WL_P_TX_RATE_AUTO_L : WL_L_TX_RATE_AUTO_L)
-#define	WL_TX_RATE_AUTO_M(p) \
-	(p->pcwl_chip_type == PCWL_CHIP_PRISMII ? \
-	WL_P_TX_RATE_AUTO_M : WL_L_TX_RATE_AUTO_M)
-
-/*
- * Default network name: empty string implies any
- */
-#define	WL_DEFAULT_NETNAME	("")
-#define	WL_DEFAULT_NODENAME	("solaris node")
-#define	WL_DEFAULT_AP_DENSITY	1
-#define	WL_DEFAULT_RTS_THRESH	2347
-#define	WL_DEFAULT_DATALEN	2304
-#define	WL_DEFAULT_CREATE_IBSS	0
-#define	WL_DEFAULT_PM_ENABLED	0
-#define	WL_DEFAULT_MAX_SLEEP	100
-#define	WL_DEFAULT_CHAN		3
-#define	WL_DEFAULT_TX_CRYPT_KEY	0
-
-/*
- * Size of Hermes I/O space.
- */
-#define	WL_IOSIZ	0x40
-
-/*
- * Hermes command/status registers.
- */
-#define	WL_COMMAND	0x00
-#define	WL_PARAM0	0x02
-#define	WL_PARAM1	0x04
-#define	WL_PARAM2	0x06
-#define	WL_STATUS	0x08
-#define	WL_RESP0	0x0A
-#define	WL_RESP1	0x0C
-#define	WL_RESP2	0x0E
-
-/*
- * Command register values.
- */
-#define	WL_CMD_BUSY		0x8000 /* busy bit */
-#define	WL_CMD_INI		0x0000 /* initialize */
-#define	WL_CMD_ENABLE		0x0001 /* enable */
-#define	WL_CMD_DISABLE		0x0002 /* disable */
-#define	WL_CMD_DIAG		0x0003
-#define	WL_CMD_ALLOC_MEM	0x000A /* allocate NIC memory */
-#define	WL_CMD_TX		0x000B /* transmit */
-#define	WL_CMD_NOTIFY		0x0010
-#define	WL_CMD_INQUIRE		0x0011
-#define	WL_CMD_ACCESS		0x0021
-#define	WL_CMD_PROGRAM		0x0022
-
-#define	WL_CMD_CODE_MASK	0x003F
-
-/*
- * Reclaim qualifier bit, applicable to the
- * TX and INQUIRE commands.
- */
-#define	WL_RECLAIM		0x0100 /* reclaim NIC memory */
-
-/*
- * ACCESS command qualifier bits.
- */
-#define	WL_ACCESS_READ		0x0000
-#define	WL_ACCESS_WRITE		0x0100
-
-/*
- * PROGRAM command qualifier bits.
- */
-#define	WL_PROGRAM_DISABLE	0x0000
-#define	WL_PROGRAM_ENABLE_RAM	0x0100
-#define	WL_PROGRAM_ENABLE_NVRAM	0x0200
-#define	WL_PROGRAM_NVRAM	0x0300
-
-/*
- * Status register values
- */
-#define	WL_STAT_CMD_CODE	0x003F
-#define	WL_STAT_DIAG_ERR	0x0100
-#define	WL_STAT_INQ_ERR		0x0500
-#define	WL_STAT_CMD_RESULT	0x7F00
-
-/*
- * memory handle management registers
- */
-#define	WL_INFO_FID		0x10
-#define	WL_RX_FID		0x20
-#define	WL_ALLOC_FID		0x22
-#define	WL_TX_CMP_FID		0x24
-
-#define	WL_INVALID_FID		0xffff
-
-/*
- * Buffer Access Path (BAP) registers.
- * These are I/O channels.  you can use each one for
- * any desired purpose independently of the other. In general
- * though, we use BAP1 for reading and writing LTV records and
- * reading received data frames, and BAP0 for writing transmit
- * frames. This is a convention though, not a rule.
- * For PrismII chip, frequently overlap between BAP0 and BAP1
- * may hang the hardware. this is a known bug, so just use BAP1
- * for PrismII.
- */
-#define	WL_SEL0			0x18
-#define	WL_SEL1			0x1A
-#define	WL_OFF0			0x1C
-#define	WL_OFF1			0x1E
-#define	WL_DATA0		0x36
-#define	WL_DATA1		0x38
-#define	WL_BAP0			WL_DATA0
-#define	WL_BAP1			WL_DATA1
-
-#define	WL_OFF_BUSY		0x8000
-#define	WL_OFF_ERR		0x4000
-#define	WL_OFF_DATAOFF		0x0FFF
-
-/*
- * Event registers
- */
-#define	WL_EVENT_STAT		0x30	/* Event status */
-#define	WL_INT_EN		0x32	/* Interrupt enable/disable */
-#define	WL_EVENT_ACK		0x34	/* Ack event */
-
-/*
- * Events
- */
-#define	WL_EV_TICK		0x8000	/* aux timer tick */
-#define	WL_EV_RES		0x4000	/* controller h/w error (time out) */
-#define	WL_EV_INFO_DROP		0x2000	/* no RAM to build unsolicited frame */
-#define	WL_EV_NO_CARD		0x0800	/* card removed (hunh?) */
-#define	WL_EV_DUIF_RX		0x0400	/* wavelan management packet received */
-#define	WL_EV_INFO		0x0080	/* async info frame */
-#define	WL_EV_CMD		0x0010	/* command completed */
-#define	WL_EV_ALLOC		0x0008	/* async alloc/reclaim completed */
-#define	WL_EV_TX_EXC		0x0004	/* async xmit completed with failure */
-#define	WL_EV_TX		0x0002	/* async xmit completed succesfully */
-#define	WL_EV_RX		0x0001	/* async rx completed */
-
-#define	WL_EV_ALL		0xffff	/* all events */
-#define	WL_INTRS	\
-	(WL_EV_RX|WL_EV_TX|WL_EV_TX_EXC|WL_EV_ALLOC|WL_EV_INFO|WL_EV_INFO_DROP)
-
-/*
- * Host software registers
- */
-#define	WL_SW0			0x28
-#define	WL_SW1			0x2A
-#define	WL_SW2			0x2C
-#define	WL_SW3			0x2E
-
-#define	WL_CNTL			0x14
-
-#define	WL_CNTL_AUX_ENA		0xC000
-#define	WL_CNTL_AUX_ENA_STAT	0xC000
-#define	WL_CNTL_AUX_DIS_STAT	0x0000
-#define	WL_CNTL_AUX_ENA_CNTL	0x8000
-#define	WL_CNTL_AUX_DIS_CNTL	0x4000
-
-#define	WL_AUX_PAGE		0x3A
-#define	WL_AUX_OFFSET		0x3C
-#define	WL_AUX_DATA		0x3E
-
-#define	WL_RID_DNLD_BUF		0xFD01
-
-/*
- * Mem sizes (0xFD02).
- */
-#define	WL_RID_MEMSZ		0xFD02
-#define	WL_RID_FWIDENT_P2	0xFD02
-
-/*
- * NIC Identification (0xFD0B).
- */
-#define	WL_RID_CARD_ID	0xFD0B
-
-typedef struct pcwl_ltv_ver {
-	uint16_t	wl_compid;
-	uint16_t	wl_variant;
-	uint16_t	wl_major;
-	uint16_t	wl_minor;
-} pcwl_ltv_ver_t;
-
-#define	WL_RID_FWVER	0xFFFF
-typedef struct pcwl_ltv_fwver {
-	uint16_t	pri[7];
-	uint16_t	st[7];
-} pcwl_ltv_fwver_t;
-
-#define	WI_NIC_EVB2	0x8000
-#define	WI_NIC_HWB3763	0x8001
-#define	WI_NIC_HWB3163	0x8002
-#define	WI_NIC_HWB3163B	0x8003
-#define	WI_NIC_EVB3	0x8004
-#define	WI_NIC_HWB1153	0x8007
-#define	WI_NIC_P2_SST	0x8008	/* Prism2 with SST flush */
-#define	WI_NIC_PRISM2_5	0x800C
-#define	WI_NIC_3874A	0x8013	/* Prism2.5 Mini-PCI */
-
-/*
- * List of intended regulatory domains (0xFD11).
- */
-#define	WL_RID_DOMAINS		0xFD11
-/*
- * CIS struct (0xFD13).
- */
-#define	WL_RID_CIS		0xFD13
-
-/*
- * Current MAC port connection status
- */
-#define	WL_RID_PORTSTATUS	0xFD40
-#define	WL_PORT_DISABLED	1
-#define	WL_PORT_INITIAL		2
-#define	WL_PORT_TO_IBSS		3
-#define	WL_PORT_TO_BSS		4
-#define	WL_PORT_OOR		5
-#define	WL_PORT_RADIO_OFF	7 /* only for miniPci */
-
-/*
- * Current Service Set the station is connected to
- */
-#define	WL_RID_SSID		0xFD41
-
-/*
- * MAC address used as identifier of the BSS the station
- * is connected to
- */
-#define	WL_RID_BSSID		0xFD42
-
-/*
- * Communications quality (0xFD43).
- */
-#define	WL_RID_COMMQUAL		0xFD43
-
-/*
- * Actual system scale thresholds (0xFD46).
- */
-#define	WL_RID_SYSTEM_SCALE	0xFC06
-
-/*
- * Actual current transmission rate
- */
-#define	WL_RID_CUR_TX_RATE	0xFD44
-
-/*
- * Connection control characteristics.
- * 1 == Basic Service Set (BSS), a.k.a IEEE 802.11 Infrastructure
- * 2 == Wireless Distribudion System (WDS), Access Point only
- * 3 == Pseudo IBSS / Ad Hoc
- */
-#define	WL_RID_PORTTYPE		0xFC00
-#define	WL_PORTTYPE_BSS		0x1
-#define	WL_PORTTYPE_WDS		0x2
-#define	WL_PORTTYPE_ADHOC	0x3
-
-/*
- * Mac addresses.
- */
-#define	WL_RID_MAC_NODE		0xFC01
-#define	WL_RID_MAC_WDS		0xFC08
-
-/*
- * Station set identification (SSID).
- */
-#define	WL_RID_DESIRED_SSID	0xFC02
-#define	WL_RID_OWN_SSID		0xFC04
-
-/*
- * Set communications channel (radio frequency).
- */
-#define	WL_RID_OWN_CHNL		0xFC03
-#define	WL_RID_CURRENT_CHNL	0xFDC1
-
-/*
- * Frame data size.
- */
-#define	WL_RID_MAX_DATALEN	0xFC07
-
-/*
- * ESS power management enable
- */
-#define	WL_RID_PM_ENABLED	0xFC09
-
-/*
- * ESS max PM sleep internal
- */
-#define	WL_RID_MAX_SLEEP	0xFC0C
-
-/*
- * Set our station name.
- */
-#define	WL_RID_NODENAME		0xFC0E
-
-/*
- * Multicast addresses to be put in filter. We're
- * allowed up to 16 addresses in the filter.
- */
-#define	WL_RID_MCAST		0xFC80
-
-/*
- * Create IBSS.
- */
-#define	WL_RID_CREATE_IBSS	0xFC81
-
-#define	WL_RID_FRAG_THRESH	0xFC82
-#define	WL_RID_RTS_THRESH	0xFC83
-
-/*
- * TX rate control
- * 0 == Fixed 1mbps
- * 1 == Fixed 2mbps
- * 2 == auto fallback
- */
-#define	WL_RID_TX_RATE		0xFC84
-
-/*
- * promiscuous mode.
- */
-#define	WL_RID_PROMISC		0xFC85
-
-/*
- * scan ssid
- */
-#define	WL_RID_SCAN_SSID	0xFCB2
-
-/*
- * Auxiliary Timer tick interval
- */
-#define	WL_RID_TICK_TIME	0xFCE0
-
-/*
- * PrismII scan
- */
-#define	WL_RID_SCAN_REQUEST	0xFCE1
-#define	WL_RID_HSCAN_REQUEST	0xFCE5
-
-/*
- * Information frame types.
- */
-#define	WL_INFO_NOTIFY		0xF000	/* Handover address */
-#define	WL_INFO_COUNTERS	0xF100	/* Statistics counters */
-#define	WL_INFO_SCAN_RESULTS	0xF101	/* Scan results */
-#define	WL_INFO_HSCAN_RESULTS	0xF103	/* HostScan results */
-#define	WL_INFO_LINK_STAT	0xF200	/* Link status */
-#define	WL_INFO_ASSOC_STAT	0xF201	/* Association status */
-
-/*
- * Link status
- */
-#define	WL_LINK_CONNECT		1
-#define	WL_LINK_DISCONNECT	2
-#define	WL_LINK_AP_CR		3 /* AP change */
-#define	WL_LINK_AP_OOR		4 /* AP out of range */
-#define	WL_LINK_AP_IR		5 /* AP in range */
-
-typedef struct wl_scan_result {
-	uint16_t		wl_srt_chid;  /* bss channel id */
-	uint16_t		wl_srt_anl;   /* noise level */
-	uint16_t		wl_srt_sl;    /* signal level */
-	uint8_t			wl_srt_bssid[6];  /* mac address of the bss */
-	uint16_t		wl_srt_bcnint; /* bss beacon interval */
-	uint16_t		wl_srt_cap;    /* bss capability */
-
-	uint16_t		wl_srt_ssidlen;  /* ssid name length */
-	char			wl_srt_ssid[32]; /* ssid */
-
-	uint16_t		wl_srt_suprates[5]; /* supported rates */
-	uint16_t		wl_srt_rate; /* actual data rate of the probe */
-	uint16_t		wl_srt_atim;
-} wl_scan_result_t;
-
-#define	WL_SRT_MAX_NUM		32 /* max number of scan result stored */
-#define	WL_SCAN_TIMEOUT_MAX	30 /* seconds after which the scan item ages */
-#define	WL_SCAN_AGAIN_THRESHOLD	5 /* threshold below which card scan again */
-#define	WL_MAX_SCAN_TIMES	2 /* max scan times per scan command */
-
-typedef struct wl_scan_list {
-	wl_scan_result_t	wl_val;
-	uint32_t		wl_timeout;
-	list_node_t		wl_scan_node;
-} wl_scan_list_t;
-
-#define	WL_FTYPE_MGMT		0x0000
-#define	WL_FTYPE_CTL		0x0004
-#define	WL_FTYPE_DATA		0x0008
-
-/*
- * SNAP (sub-network access protocol) constants for transmission
- * of IP datagrams over IEEE 802 networks, taken from RFC1042.
- * We need these for the LLC/SNAP header fields in the TX/RX frame
- * structure.
- */
-#define	WL_SNAP_K1		0xaa	/* assigned global SAP for SNAP */
-#define	WL_SNAP_K2		0x00
-#define	WL_SNAP_CONTROL		0x03	/* unnumbered information format */
-#define	WL_SNAP_WORD0		(WL_SNAP_K1 | (WL_SNAP_K1 << 8))
-#define	WL_SNAP_WORD1		(WL_SNAP_K2 | (WL_SNAP_CONTROL << 8))
-#define	WL_SNAPHDR_LEN		0x6
-
-/*
- * Hermes transmit/receive frame structure
- */
-typedef struct wl_frame {
-	uint16_t		wl_status;	/* 0x00 */
-	uint16_t		wl_rsvd0;	/* 0x02 */
-	uint16_t		wl_rsvd1;	/* 0x04 */
-	uint16_t		wl_q_info;	/* 0x06 */
-	uint16_t		wl_rsvd2;	/* 0x08 */
-	uint16_t		wl_rsvd3;	/* 0x0A */
-	uint16_t		wl_tx_ctl;	/* 0x0C */
-	uint16_t		wl_frame_ctl;	/* 0x0E */
-	uint16_t		wl_id;		/* 0x10 */
-	uint8_t			wl_addr1[6];	/* 0x12 */
-	uint8_t			wl_addr2[6];	/* 0x18 */
-	uint8_t			wl_addr3[6];	/* 0x1E */
-	uint16_t		wl_seq_ctl;	/* 0x24 */
-	uint8_t			wl_addr4[6];	/* 0x26 */
-	uint16_t		wl_dat_len;	/* 0x2C */
-
-	uint8_t			wl_dst_addr[6];	/* 0x2E */
-	uint8_t			wl_src_addr[6];	/* 0x34 */
-	uint16_t		wl_len;		/* 0x3A */
-	uint16_t		wl_dat[3];	/* 0x3C */ /* SNAP header */
-	uint16_t		wl_type;	/* 0x42 */
-} wl_frame_t;
-
-static wl_frame_t wl_frame_default = {
-	0,			/* wl_status	   0x00 */
-	0,			/* wl_rsvd0	   0x02 */
-	0,			/* wl_rsvd1	   0x04 */
-	0,			/* wl_q_info	   0x06 */
-	0,			/* wl_rsvd2	   0x08 */
-	0,			/* wl_rsvd3	   0x0A */
-	0,			/* wl_tx_ctl	   0x0C */
-	WL_FTYPE_DATA,		/* wl_frame_ctl	   0x0E */
-	0,			/* wl_id	   0x10 */
-	{ 0, 0, 0, 0, 0, 0 },	/* wl_addr1[6]	   0x12 */
-	{ 0, 0, 0, 0, 0, 0 },	/* wl_addr2[6]	   0x18 */
-	{ 0, 0, 0, 0, 0, 0 },	/* wl_addr3[6]	   0x1E */
-	0,			/* wl_seq_ctl	   0x24 */
-	{ 0, 0, 0, 0, 0, 0 },	/* wl_addr4[6]	   0x26 */
-	(uint16_t)-WL_SNAPHDR_LEN, /* wl_dat_len	   0x2C */
-
-	{ 0, 0, 0, 0, 0, 0 },	/* wl_dst_addr[6]  0x2E */
-	{ 0, 0, 0, 0, 0, 0 },	/* wl_src_addr[6]  0x34 */
-	(uint16_t)-WL_SNAPHDR_LEN, /* wl_len	   0x3A */
-	{ WL_SNAP_WORD0,
-	WL_SNAP_WORD1, 0 },	/* wl_dat[3]	   0x3C */ /* SNAP header */
-	0			/* wl_type	   0x42 */
-};
-
-#define	MLEN(mp)		((mp)->b_wptr - (mp)->b_rptr)
-#define	ETH_HDRLEN		(sizeof (struct ether_header))
-#define	WL_802_3_HDRLEN		0x2E
-#define	WL_802_11_HDRLEN	0x44
-#define	WL_802_11_RAW_HDRLEN	0x3C
-
-#define	WL_STAT_BADCRC		0x0001
-#define	WL_STAT_UNDECRYPTABLE	0x0002
-#define	WL_STAT_ERRSTAT		0x0003
-#define	WL_STAT_MAC_PORT	0x0700
-#define	WL_STAT_1042		0x2000	/* RFC1042 encoded */
-#define	WL_STAT_TUNNEL		0x4000	/* Bridge-tunnel encoded */
-#define	WL_STAT_WMP_MSG		0x6000	/* WaveLAN-II management protocol */
-#define	WL_RXSTAT_MSG_TYPE	0xE000
-
-#define	WL_ENC_TX_802_3		0x00
-#define	WL_ENC_TX_802_11	0x11
-#define	WL_ENC_TX_E_II		0x0E
-
-#define	WL_ENC_TX_1042		0x00
-#define	WL_ENC_TX_TUNNEL	0xF8
-
-#define	WL_TXCNTL_MACPORT	0x00FF
-#define	WL_TXCNTL_STRUCTTYPE	0xFF00
-#define	WL_TXCNTL_TXOK		0x2
-#define	WL_TXCNTL_TXEX		0x4
-#define	WL_TXCNTL_SET	(WL_TXCNTL_TXOK | WL_TXCNTL_TXEX)
-
-typedef struct rf_ckey {
-	uint16_t	ckey_len;
-	uint8_t		ckey_dat[14];
-} rf_ckey_t;
-
-/*
- * Configurable parameters of the RF interface
- * All the info here is passed to the card through PIO.
- */
-typedef struct pcwl_rf {
-	uint16_t	rf_max_datalen;
-	uint16_t	rf_create_ibss;
-	uint16_t	rf_porttype;
-	uint16_t	rf_rts_thresh;
-	uint16_t	rf_tx_rate;
-	uint16_t	rf_system_scale;
-	uint16_t	rf_pm_enabled;
-	uint16_t	rf_max_sleep;
-	uint16_t	rf_own_chnl;
-	uint16_t	rf_port_no;
-	char		rf_own_ssid[34];
-	char		rf_desired_ssid[34];
-	char		rf_nodename[34];
-	uint16_t	rf_promiscuous;
-	uint16_t	rf_encryption;		/* use encryption? */
-	uint16_t	rf_authtype;		/* prism2 only */
-	uint16_t	rf_tx_crypt_key;
-	rf_ckey_t	rf_ckeys[4];
-} pcwl_rf_t;
-
-#define	PCWL_MCAST_ENTSHIFT	4
-#define	PCWL_MCAST_ENTRIES	(1 << PCWL_MCAST_ENTSHIFT)
-#define	PCWL_MCBUF_LEN		(ETHERADDRL << PCWL_MCAST_ENTSHIFT)
-#define	PCWL_MCBUF_WORDS	(PCWL_MCBUF_LEN >> 1)
-
-typedef enum {
-	WLC_TX_UNICAST_FRAMES,		/*  0+ */
-	WLC_TX_MULTICAST_FRAMES,	/*  1+ */
-	WLC_TX_FRAGMENTS,		/*  2+ */
-	WLC_TX_UNICAST_OCTETS,		/*  3+ */
-	WLC_TX_MULTICAST_OCTETS,	/*  4  */
-	WLC_TX_DEFERRED_XMITS,		/*  5+ */
-	WLC_TX_SINGLE_RETRIES,		/*  6+ */
-	WLC_TX_MULTI_RETRIES,		/*  7+ */
-	WLC_TX_RETRY_LIMIT,		/*  8+ */
-	WLC_TX_DISCARDS,		/*  9+ */
-	WLC_RX_UNICAST_FRAMES,		/* 10+ */
-	WLC_RX_MULTICAST_FRAMES,	/* 11+ */
-	WLC_RX_FRAGMENTS,		/* 12+ */
-	WLC_RX_UNICAST_OCTETS,		/* 13+ */
-	WLC_RX_MULTICAST_OCTETS,	/* 14  */
-	WLC_RX_FCS_ERRORS,		/* 15+ */
-	WLC_RX_DISCARDS_NOBUF,		/* 16+ */
-	WLC_TX_DISCARDS_WRONG_SA,	/* 17+ */
-	WLC_RX_WEP_CANT_DECRYPT,	/* 18+ */
-	WLC_RX_MSG_IN_MSG_FRAGS,	/* 19+ */
-	WLC_RX_MSG_IN_BAD_MSG_FRAGS,	/* 20+ */
-	WLC_STAT_CNT			/* 21 - keep it as the last entry */
-} pcwl_cntr_offset;
-
-#define	WL_XMT_BUF_NUM	8
-typedef struct	wl_tx_ring_data {
-	uint16_t		wl_tx_fids[WL_XMT_BUF_NUM];
-	uint16_t		wl_tx_ring[WL_XMT_BUF_NUM];
-	int			wl_tx_prod;
-	int			wl_tx_cons;
-	kmutex_t		wl_tx_lock;	/* for send only */
-} pcwl_txring_t;
-
-#define	PCWL_DEVICE_PCI		0
-#define	PCWL_DEVICE_PCCARD	1
-
-/*
- * The macinfo is really used as the softstate structure.
- *
- * pcwl_mh	 - mac_handle_t structure
- * pcwl_cslock	 - lock for card services request. Used with pcwl_cscv
- * pcwl_cscv	 - condition variable to wait for card events
- * pcwl_chdl	 - client handle, an uint32_t bit mask encoding for socket,
- *			function, and client info.
- *			See cs_priv.h MAKE_CLIENT_HANDLE.
- * pcwl_log_sock - holds the logical to physical translation for this card.
- *			Specifically has physical adapter and socket #.
- *			Socket # is the same as part of the pcwl_chdl encoding.
- *			Physical adapter # is from card service socket impl.
- */
-typedef struct pcwl_macinfo {
-	mac_handle_t		pcwl_mh;
-	dev_info_t		*pcwl_dip;
-	int			pcwl_device_type; /* pci or pcmcia card */
-	kmutex_t		pcwl_cslock;	/* for card services */
-	kcondvar_t		pcwl_cscv;	/* for card services */
-	client_handle_t		pcwl_chdl;	/* s,f,c encoding, cs_priv.h */
-	map_log_socket_t	pcwl_log_sock;	/* logical/phys socket map */
-
-	int			pcwl_socket;    /* socket number */
-	int			pcwl_config_hi;	/* cfttbl index */
-	int			pcwl_config;	/* default config index */
-	int			pcwl_vcc;	/* vcc level */
-	int			pcwl_iodecode;	/* # of address lines */
-	int			pcwl_chip_type;	/* Lucent or Prism-II */
-
-	uint8_t 		pcwl_mac_addr[ETHERADDRL];
-	uint8_t 		pcwl_bssid[ETHERADDRL];
-	uint16_t		pcwl_has_wep;	/* has encryption capability */
-	uint32_t		pcwl_flag;
-	uint32_t		pcwl_reschedule_need;
-	pcwl_rf_t		pcwl_rf;	/* RF interface parameters */
-
-	uint16_t		pcwl_dmem_id;	/* nic mem id for tx buffer */
-	uint16_t		pcwl_mgmt_id;	/* nic mem id for mgmt buffer */
-	pcwl_txring_t		pcwl_txring;
-
-	uint16_t		pcwl_mcast[PCWL_MCBUF_WORDS]; /* MC filters */
-
-	kmutex_t		pcwl_scanlist_lock;	/* scanlist lock */
-	kmutex_t		pcwl_glock;	/* generic lock */
-
-	caddr_t			pcwl_bar;	/* for pci device only */
-	ddi_acc_handle_t	pcwl_handle;
-	caddr_t			pcwl_cfg_base;
-	ddi_acc_handle_t	pcwl_cfg_handle;
-
-	ddi_acc_handle_t	pcwl_port;	/* for pcmcia device only */
-
-	ddi_iblock_cookie_t	pcwl_ib_cookie;
-	ddi_softintr_t		pcwl_softint_id; /* pcwl_intr soft intr id */
-
-	uint16_t		pcwl_cntrs_t[WLC_STAT_CNT];
-	uint64_t		pcwl_cntrs_s[WLC_STAT_CNT];
-	uint64_t		pcwl_noxmtbuf;
-	timeout_id_t		pcwl_scanlist_timeout_id;
-	list_t			pcwl_scan_list;
-	uint16_t		pcwl_scan_num;
-	uint16_t		pcwl_rssi;
-	timeout_id_t		pcwl_connect_timeout_id;
-} pcwl_maci_t;
-
-#define	PCWL_IDENT_STRING	modldrv.drv_linkinfo
-#define	PCWL_CHIP_LUCENT	0
-#define	PCWL_CHIP_PRISMII	1
-#define	HDL(pcwl_p)		((pcwl_p)->pcwl_port)
-#define	GLD3(pcwl_p)		((pcwl_p)->pcwl_mh)
-#define	DIP(pcwl_p)		((pcwl_p)->pcwl_dip)
-#define	RF(pcwl_p)		(&(pcwl_p)->pcwl_rf)
-
-#define	PCWL_CARD_INTREN	0x1
-#define	PCWL_SOFTINTR		0x2	/* high level and soft intr enabled */
-#define	PCWL_CARD_LINKUP	0x4	/* link status of the STA */
-#define	PCWL_CARD_GSTAT		0x8
-#define	PCWL_ATTACHED		0x10
-#define	PCWL_CS_REGISTERED	0x20
-#define	PCWL_ENABLED		0x40
-#define	PCWL_CARD_READY		0x80
-#define	PCWL_CARD_FAILED	0x100
-#define	PCWL_CARD_INTR		0x200
-#define	PCWL_CARD_PLUMBED	0x400
-#define	PCWL_CARD_SUSPEND	0x800
-
-#define	PCWL_STATE_IDLE		0x1
-
-#define	PCWL_NICMEM_SZ		(2048) /* 80211MTU set as 1500, so 2k here */
-
-static int	pcwl_probe(dev_info_t *dip);
-static int	pcwl_attach(dev_info_t *dip, ddi_attach_cmd_t cmd);
-static int	pcwl_detach(dev_info_t *dip, ddi_detach_cmd_t cmd);
-
-static int	pcwl_register_cs(dev_info_t *dip, pcwl_maci_t *pcwl_p);
-static void	pcwl_unregister_cs(pcwl_maci_t *pcwl_p);
-static void	pcwl_destroy_locks(pcwl_maci_t *pcwl_p);
-static int	pcwl_reset_backend(pcwl_maci_t *pcwl_p);
-static int	pcwl_get_cap(pcwl_maci_t *pcwl_p);
-static int	pcwl_card_insert(pcwl_maci_t *pcwl_p);
-static int	pcwl_ev_hdlr(event_t ev, int pri, event_callback_args_t *arg);
-static void	pcwl_card_remove(pcwl_maci_t *pcwl_p);
-static int	pcwl_init_nicmem(pcwl_maci_t *pcwl_p);
-
-/*
- * high level device access primitives, glock must held before calling
- */
-static uint16_t	pcwl_set_cmd(pcwl_maci_t *pcwl_p, uint16_t mode, uint16_t type);
-static uint16_t pcwl_set_ch(pcwl_maci_t *, uint16_t, uint16_t, uint16_t);
-static uint16_t	pcwl_get_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type,
-			uint16_t *val_p);
-static uint16_t	pcwl_put_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type,
-			uint16_t *val_p);
-static uint16_t	pcwl_fil_ltv(pcwl_maci_t *pcwl_p, uint16_t len, uint16_t type,
-			uint16_t val);
-static uint16_t	pcwl_put_str(pcwl_maci_t *pcwl_p, uint16_t type, char *str_p);
-static uint16_t pcwl_rdch0(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off,
-			uint16_t *buf_p, int len, int order);
-static uint16_t pcwl_wrch1(pcwl_maci_t *pcwl_p, uint16_t type, uint16_t off,
-			uint16_t *buf_p, int len, int order);
-static int	pcwl_config_rf(pcwl_maci_t *pcwl_p);
-static int	pcwl_loaddef_rf(pcwl_maci_t *pcwl_p);
-static void	pcwl_start_locked(pcwl_maci_t *pcwl_p);
-static void	pcwl_stop_locked(pcwl_maci_t *pcwl_p);
-static int	pcwl_saddr_locked(pcwl_maci_t *pcwl_p);
-static uint16_t	pcwl_alloc_nicmem(pcwl_maci_t *pcwl_p, uint16_t len,
-			uint16_t *id_p);
-static void	pcwl_chip_type(pcwl_maci_t *pcwl_p);
-
-/*
- * Required driver entry points for mac
- */
-static int	pcwl_start(void *);
-static void	pcwl_stop(void *);
-static int	pcwl_saddr(void *, const uint8_t *);
-static mblk_t	*pcwl_tx(void *, mblk_t *);
-static int	pcwl_send(pcwl_maci_t *, mblk_t *);
-static int	pcwl_prom(void *, boolean_t);
-static int	pcwl_gstat(void *, uint_t, uint64_t *);
-static int	pcwl_sdmulti(void *, boolean_t, const uint8_t *);
-static void 	pcwl_ioctl(void *, queue_t *, mblk_t *);
-
-static uint_t	pcwl_intr(caddr_t arg);
-static uint_t	pcwl_intr_hi(caddr_t arg);
-static void	pcwl_rcv(pcwl_maci_t *pcwl_p);
-static uint32_t pcwl_txdone(pcwl_maci_t *pcwl_p);
-static void pcwl_infodone(pcwl_maci_t *pcwl_p);
-static void 	pcwl_ssid_scan(pcwl_maci_t *, uint16_t, uint16_t, uint16_t);
-
-/*
- * prototypes of the function for wifi ioctl
- */
-static int	pcwl_cfg_essid(mblk_t *, pcwl_maci_t *, uint32_t);
-static int	pcwl_cfg_bssid(mblk_t *, pcwl_maci_t *, uint32_t);
-static int	pcwl_cfg_scan(mblk_t *, pcwl_maci_t *, uint32_t);
-static int	pcwl_cfg_linkstatus(mblk_t *, pcwl_maci_t *, uint32_t);
-static int	pcwl_cfg_bsstype(mblk_t *, pcwl_maci_t *, uint32_t);
-static int	pcwl_cfg_phy(mblk_t *, pcwl_maci_t *, uint32_t);
-static int	pcwl_cfg_desiredrates(mblk_t *, pcwl_maci_t *, uint32_t);
-static int	pcwl_cfg_supportrates(mblk_t *, pcwl_maci_t *, uint32_t);
-static int	pcwl_cfg_powermode(mblk_t *, pcwl_maci_t *, uint32_t);
-static int	pcwl_cfg_authmode(mblk_t *, pcwl_maci_t *, uint32_t);
-static int	pcwl_cfg_encryption(mblk_t *, pcwl_maci_t *, uint32_t);
-static int	pcwl_cfg_wepkeyid(mblk_t *, pcwl_maci_t *, uint32_t);
-static int	pcwl_cfg_createibss(mblk_t *, pcwl_maci_t *, uint32_t);
-static int	pcwl_cfg_rssi(mblk_t *, pcwl_maci_t *, uint32_t);
-static int	pcwl_cfg_radio(mblk_t *, pcwl_maci_t *, uint32_t);
-static int	pcwl_cfg_wepkey(mblk_t *, pcwl_maci_t *, uint32_t);
-static void	pcwl_wlan_ioctl(pcwl_maci_t *, queue_t *, mblk_t *, uint32_t);
-static int	pcwl_getset(mblk_t *, pcwl_maci_t *, uint32_t);
-
-static void	pcwl_scanlist_timeout(void *);
-static void	pcwl_delete_scan_item(pcwl_maci_t *, wl_scan_list_t *);
-static int	pcwl_add_scan_item(pcwl_maci_t *, wl_scan_result_t);
-static void	pcwl_get_rssi(pcwl_maci_t *);
-static void 	pcwl_connect_timeout(void *arg);
-
-#define	RDCH0(h, t, o, b_p, l)	pcwl_rdch0(h, t, o, b_p, l, 1)
-#define	WRCH1(h, t, o, b_p, l)	pcwl_wrch1(h, t, o, b_p, l, 1)
-#define	RDPKT(h, t, o, b_p, l)	pcwl_rdch0(h, t, o, b_p, l, 0)
-#define	WRPKT(h, t, o, b_p, l)	pcwl_wrch1(h, t, o, b_p, l, 0)
-
-#define	FIL_LTV(pcwl_p, len, type, val)	 \
-	(void) pcwl_fil_ltv(pcwl_p, len, type, val)
-#define	PUT_LTV(pcwl_p, len, type, v_p)	 \
-	(void) pcwl_put_ltv(pcwl_p, len, type, v_p)
-#define	PUT_STR(pcwl_p, type, str_p)	\
-	(void) pcwl_put_str(pcwl_p, type, str_p)
-
-#define	PCWL_READ(p, o, v)	{ \
-	if (p->pcwl_device_type == PCWL_DEVICE_PCI) { \
-		uint16_t t = ddi_get16(p->pcwl_handle, \
-		    (uint16_t *)(p->pcwl_bar + 2*(o))); \
-		v = LE_16(t); \
-	} else { \
-		uint16_t t = csx_Get16(HDL(p), o); \
-		v = LE_16(t); \
-	}\
-}
-#define	PCWL_WRITE(p, o, v)	{ \
-	if (p->pcwl_device_type == PCWL_DEVICE_PCI) { \
-		ddi_put16(p->pcwl_handle, \
-		    (uint16_t *)(p->pcwl_bar + 2*(o)), LE_16(v)); \
-	} else { \
-		csx_Put16(HDL(p), o, LE_16(v)); \
-	}\
-}
-#define	PCWL_READ_P(p, o, v, h)	{ \
-	if (p->pcwl_device_type == PCWL_DEVICE_PCI) { \
-		uint16_t t = ddi_get16(p->pcwl_handle, \
-		    (uint16_t *)(p->pcwl_bar + 2*(o))); \
-		*(v) = h ? LE_16(t) : t; \
-	} else { \
-		uint16_t t = csx_Get16(HDL(p), o); \
-		*(v) = h ? LE_16(t) : t; \
-	}\
-}
-#define	PCWL_WRITE_P(p, o, v, h)	{ \
-	if (p->pcwl_device_type == PCWL_DEVICE_PCI) { \
-		ddi_put16(p->pcwl_handle, (uint16_t *)(p->pcwl_bar + 2*(o)), \
-		    h ? LE_16(*(v)) : (*(v))); \
-	} else {\
-		csx_Put16(HDL(p), o, h ? LE_16(*(v)) : (*(v))); \
-	}\
-}
-
-#ifdef _BIG_ENDIAN
-#define	PCWL_SWAP16(buf_p, len) { \
-	int pcwl_swap_len = len; \
-	for (pcwl_swap_len = (pcwl_swap_len + 1) >> 1; pcwl_swap_len; ) { \
-		uint16_t val; \
-		pcwl_swap_len--; \
-		val = *((uint16_t *)(buf_p) + pcwl_swap_len); \
-		*((uint16_t *)(buf_p) + pcwl_swap_len) = LE_16(val); \
-	} \
-}
-#else /* _BIG_ENDIAN */
-#define	PCWL_SWAP16(buf_p, len)
-#endif /* _BIG_ENDIAN */
-
-#define	PCWL_ENABLE_INTR(pcwl_p)	{\
-	PCWL_WRITE(pcwl_p, WL_INT_EN, WL_INTRS);\
-}
-#define	PCWL_DISABLE_INTR(pcwl_p)	{ \
-	PCWL_WRITE(pcwl_p, WL_INT_EN, 0); \
-	PCWL_WRITE(pcwl_p, WL_EVENT_ACK, 0xffff);\
-}
-
-/*
- * 16-bit driver private status code
- */
-#define	PCWL_SUCCESS		0x0
-#define	PCWL_FAIL		0x1
-#define	PCWL_TIMEDOUT_CMD	0x10
-#define	PCWL_TIMEDOUT_ACCESS	0x11
-#define	PCWL_TIMEDOUT_TARGET	0x12
-#define	PCWL_BADLEN		0x13
-#define	PCWL_BADTYPE		0x14
-#define	PCWL_TIMEDOUT_ALLOC	0x15
-#define	PCWL_FAILURE_CMD	0x16
-
-#define	PCWL_STATUS_MAX		0xffff
-#define	N_PCWL			2
-
-#ifdef	__cplusplus
-}
-#endif
-
-#endif	/* _SYS_PCWL_H */
--- a/usr/src/uts/common/io/simnet/simnet.c	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/io/simnet/simnet.c	Wed May 29 08:31:24 2013 +0200
@@ -59,6 +59,8 @@
 #include "simnet_impl.h"
 
 #define	SIMNETINFO		"Simulated Network Driver"
+#define	WL_CONNECTED		B_TRUE
+#define	WL_NOTCONNECTED		B_FALSE
 
 static dev_info_t *simnet_dip;
 static ddi_taskq_t *simnet_rxq;
@@ -871,8 +873,6 @@
 	default:
 		miocnak(q, mp, 0, EINVAL);
 		return;
-	case WLAN_GET_PARAM:
-	case WLAN_SET_PARAM:
 	case WLAN_COMMAND:
 		break;
 	}
@@ -1117,8 +1117,8 @@
 
 	for (i = 0; i < wdev->swd_esslist_num; i++) {
 		wls = wdev->swd_esslist[i];
-		if (strcasecmp(wls->wl_ess_conf_essid.wl_essid_essid,
-		    essargs[0]) == 0)
+		if (memcmp(wls->wl_ess_conf_essid.wl_essid_essid, essargs[0],
+		    sizeof (wls->wl_ess_conf_essid.wl_essid_essid)) == 0)
 			return (EEXIST);
 	}
 
@@ -1126,15 +1126,15 @@
 		return (EINVAL);
 
 	wls = kmem_zalloc(sizeof (wl_ess_conf_t), KM_SLEEP);
-	(void) strlcpy(wls->wl_ess_conf_essid.wl_essid_essid,
+	(void) memcpy(wls->wl_ess_conf_essid.wl_essid_essid,
 	    essargs[0], sizeof (wls->wl_ess_conf_essid.wl_essid_essid));
 	wls->wl_ess_conf_essid.wl_essid_length =
-	    strlen(wls->wl_ess_conf_essid.wl_essid_essid);
+	    strlen((char *)wls->wl_ess_conf_essid.wl_essid_essid);
 	(void) random_get_pseudo_bytes((uint8_t *)
 	    &wls->wl_ess_conf_bssid, sizeof (wl_bssid_t));
 	(void) ddi_strtol(essargs[1], (char **)NULL, 0, &result);
 	wls->wl_ess_conf_sl = (wl_rssi_t)
-	    ((result > MAX_RSSI || result < 0) ? 0:result);
+	    ((result > sizeof (wl_rssi_t) || result < 0) ? 0:result);
 	wdev->swd_esslist[wdev->swd_esslist_num] = wls;
 	wdev->swd_esslist_num++;
 
@@ -1156,8 +1156,7 @@
 		if (pr_val == NULL)
 			return (EINVAL);
 		(void) ddi_strtol(pr_val, (char **)NULL, 0, &result);
-		wdev->swd_linkstatus = ((result == 1) ?
-		    WL_CONNECTED:WL_NOTCONNECTED);
+		wdev->swd_linkstatus = (result == 1);
 		return (0);
 	}
 
@@ -1200,8 +1199,10 @@
 		/* Lookup the signal strength of the connected ESSID */
 		for (i = 0; i < wdev->swd_esslist_num; i++) {
 			wls = wdev->swd_esslist[i];
-			if (strcasecmp(wls->wl_ess_conf_essid.wl_essid_essid,
-			    wdev->swd_essid.wl_essid_essid) == 0) {
+			if (memcmp(wls->wl_ess_conf_essid.wl_essid_essid,
+			    wdev->swd_essid.wl_essid_essid,
+			    sizeof (wls->wl_ess_conf_essid.wl_essid_essid)) ==
+			    0) {
 				wdev->swd_rssi = wls->wl_ess_conf_sl;
 				break;
 			}
@@ -1288,9 +1289,7 @@
 
 		((wl_ess_list_t *)wldp_buf)->wl_ess_list_num =
 		    wdev->swd_esslist_num;
-		/* LINTED E_BAD_PTR_CAST_ALIGN */
-		w_ess_conf = (wl_ess_conf_t *)((char *)wldp_buf +
-		    offsetof(wl_ess_list_t, wl_ess_list_ess));
+		w_ess_conf = ((wl_ess_list_t *)wldp_buf)->wl_ess_list_ess;
 		for (i = 0; i < wdev->swd_esslist_num; i++) {
 			(void) memcpy(w_ess_conf, wdev->swd_esslist[i],
 			    sizeof (wl_ess_conf_t));
--- a/usr/src/uts/common/net/Makefile	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/net/Makefile	Wed May 29 08:31:24 2013 +0200
@@ -28,7 +28,7 @@
 
 HDRS=	af.h if.h if_arp.h if_dl.h if_types.h route.h pfkeyv2.h pfpolicy.h \
 	ppp-comp.h ppp_defs.h pppio.h vjcompress.h sppptun.h pppoe.h radix.h \
-	wpa.h simnet.h bridge.h bridge_impl.h trill.h
+	simnet.h bridge.h bridge_impl.h trill.h
 
 ROOTDIRS= $(ROOT)/usr/include/net
 
--- a/usr/src/uts/common/net/wpa.h	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,144 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License (the "License").
- * You may not use this file except in compliance with the License.
- *
- * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
- * or http://www.opensolaris.org/os/licensing.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
- * If applicable, add the following below this CDDL HEADER, with the
- * fields enclosed by brackets "[]" replaced with your own identifying
- * information: Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- */
-/*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
- */
-
-/*
- * Macro and data structures defined for 802.11i.
- */
-
-#ifndef	__WPA_H
-#define	__WPA_H
-
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
-#include <inet/wifi_ioctl.h>
-#include <sys/net80211_crypto.h>
-
-#ifdef	__cplusplus
-extern "C" {
-#endif
-
-#define	SERVICE_NAME		"network/wpa"
-#define	WPA_DOOR 		"/var/run/wpa_door"
-#define	SVC_METHOD		"/usr/lib/inet/wpad"
-
-/*
- * Parameters.
- */
-#define	WL_WPA_BASE		(WL_PARAMETERS_BASE + 0x500)
-#define	WL_SETOPTIE		(WL_WPA_BASE + 0x0)
-#define	WL_WPA			(WL_WPA_BASE + 0x2)
-#define	WL_KEY			(WL_WPA_BASE + 0x3)
-#define	WL_DELKEY		(WL_WPA_BASE + 0x4)
-#define	WL_SCANRESULTS		(WL_WPA_BASE + 0x7)
-#define	WL_MLME			(WL_WPA_BASE + 0x8)
-#define	WL_CAPABILITY		(WL_WPA_BASE + 0x9)
-
-typedef struct wl_wpa_ie {
-	uint32_t	wpa_ie_len;
-	char		wpa_ie[1];	/* it's the head of wpa_ie */
-} wl_wpa_ie_t;
-
-typedef struct wl_wpa {
-	uint32_t	wpa_flag;
-} wl_wpa_t;
-
-typedef struct wl_capability {
-	uint32_t	caps;
-} wl_capability_t;
-
-/*
- * WPA/RSN get/set key request.
- * ik_type  : wep/tkip/aes
- * ik_keyix : should be between 0 and 3, 0 will be used as default key.
- * ik_keylen: key length in bytes.
- * ik_keydata and ik_keylen include the DATA key and MIC key.
- * ik_keyrsc/ik_keytsc: rx/tx seq number.
- */
-#pragma pack(1)
-typedef struct wl_key {
-	uint8_t		ik_type;
-	uint8_t		ik_pad;
-
-	uint16_t	ik_keyix;
-	uint8_t		ik_keylen;
-	uint8_t		ik_flags;
-
-	uint8_t		ik_macaddr[IEEE80211_ADDR_LEN];
-	uint64_t	ik_keyrsc;
-	uint64_t	ik_keytsc;
-
-	uint8_t ik_keydata[IEEE80211_KEYBUF_SIZE+IEEE80211_MICBUF_SIZE];
-} wl_key_t;
-#pragma pack()
-
-typedef struct wl_del_key {
-	uint8_t		idk_keyix;
-	uint8_t		idk_macaddr[IEEE80211_ADDR_LEN];
-} wl_del_key_t;
-
-struct wpa_ess {
-	uint8_t		bssid[IEEE80211_ADDR_LEN];
-	uint8_t		ssid[MAX_ESSID_LENGTH];
-	uint32_t	ssid_len;
-
-	uint8_t		wpa_ie[IEEE80211_MAX_WPA_IE];
-	uint32_t	wpa_ie_len;
-	int		freq;
-};
-
-typedef struct wl_wpa_ess {
-	uint32_t	count;
-	struct wpa_ess	ess[1];
-} wl_wpa_ess_t;
-
-/*
- * structure for WL_MLME state manipulation request.
- * im_op: operations include auth/deauth/assoc/disassoc,
- * im_reason: 802.11 reason code
- */
-typedef struct wl_mlme {
-	uint8_t		im_op;
-	uint16_t	im_reason;
-	uint8_t		im_macaddr[IEEE80211_ADDR_LEN];
-} wl_mlme_t;
-
-/*
- * State machine events
- */
-typedef enum {
-	EVENT_ASSOC,
-	EVENT_DISASSOC,
-	EVENT_SCAN_RESULTS
-} wpa_event_type;
-
-typedef struct  wl_events {
-	wpa_event_type	event;
-} wl_events_t;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __WPA_H */
--- a/usr/src/uts/common/sys/dld.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/sys/dld.h	Wed May 29 08:31:24 2013 +0200
@@ -117,17 +117,17 @@
 	char		dip_dev[MAXLINKNAMELEN];
 } dld_ioc_phys_attr_t;
 
-/*
- * Secure objects ioctls
- */
 typedef enum {
 	DLD_SECOBJ_CLASS_WEP = 1,
-	DLD_SECOBJ_CLASS_WPA
+	DLD_SECOBJ_CLASS_PSK,
+	DLD_SECOBJ_CLASS_TLS,
+	DLD_SECOBJ_CLASS_TTLS,
+	DLD_SECOBJ_CLASS_PEAP
 } dld_secobj_class_t;
 
 #define	DLD_SECOBJ_OPT_CREATE	0x00000001
 #define	DLD_SECOBJ_NAME_MAX	32
-#define	DLD_SECOBJ_VAL_MAX	256
+#define	DLD_SECOBJ_VAL_MAX	264
 typedef struct dld_secobj {
 	char			so_name[DLD_SECOBJ_NAME_MAX];
 	dld_secobj_class_t	so_class;
--- a/usr/src/uts/common/sys/mac.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/sys/mac.h	Wed May 29 08:31:24 2013 +0200
@@ -180,13 +180,13 @@
 	MAC_PROP_WL_PHY_CONFIG,
 	MAC_PROP_WL_CAPABILITY,
 	MAC_PROP_WL_WPA,
-	MAC_PROP_WL_SCANRESULTS,
+	MAC_PROP_WL_COUNTERM,
 	MAC_PROP_WL_POWER_MODE,
 	MAC_PROP_WL_RADIO,
 	MAC_PROP_WL_ESS_LIST,
 	MAC_PROP_WL_KEY_TAB,
 	MAC_PROP_WL_CREATE_IBSS,
-	MAC_PROP_WL_SETOPTIE,
+	MAC_PROP_WL_OPTIE,
 	MAC_PROP_WL_DELKEY,
 	MAC_PROP_WL_KEY,
 	MAC_PROP_WL_MLME,
--- a/usr/src/uts/common/sys/net80211.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/sys/net80211.h	Wed May 29 08:31:24 2013 +0200
@@ -44,7 +44,6 @@
 #include <sys/net80211_proto.h>
 #include <sys/net80211_crypto.h>
 #include <sys/net80211_ht.h>
-#include <net/wpa.h>
 
 /*
  * IEEE802.11 kernel support module
@@ -106,7 +105,6 @@
 /* NB: this is intentionally setup to be IEEE80211_CAPINFO_PRIVACY */
 #define	IEEE80211_F_PRIVACY	0x00000010	/* CONF: privacy enabled */
 #define	IEEE80211_F_PUREG	0x00000020	/* CONF: 11g w/o 11b sta's */
-#define	IEEE80211_F_SCANONLY	0x00000040	/* CONF: scan only */
 #define	IEEE80211_F_SCAN	0x00000080	/* STATUS: scanning */
 #define	IEEE80211_F_ASCAN	0x00000100	/* STATUS: active scan */
 #define	IEEE80211_F_SIBSS	0x00000200	/* STATUS: start IBSS */
@@ -226,7 +224,6 @@
 #define	WME_AC_VI		2	/* video */
 #define	WME_AC_VO		3	/* voice */
 
-#define	MAX_EVENT		16
 #define	MAX_IEEE80211STR	256
 
 /* For IEEE80211_RADIOTAP_FLAGS */
@@ -250,15 +247,16 @@
 
 /*
  * Authentication mode.
+ * auth_algs should be only OPEN/SHARED/LEAP
+ * see IEEE80211_AUTH_ALG_* in net80211_proto.h
+ * NONE/8021X/AUTO/WPA refer to key_mgmt protocols!
  */
 enum ieee80211_authmode {
 	IEEE80211_AUTH_NONE	= 0,
 	IEEE80211_AUTH_OPEN	= 1,	/* open */
 	IEEE80211_AUTH_SHARED	= 2,	/* shared-key */
 	IEEE80211_AUTH_8021X	= 3,	/* 802.1x */
-	IEEE80211_AUTH_AUTO	= 4,	/* auto-select/accept */
-	/* NB: these are used only for ioctls */
-	IEEE80211_AUTH_WPA	= 5	/* WPA/RSN w/ 802.1x/PSK */
+	IEEE80211_AUTH_AUTO	= 4	/* auto-select/accept */
 };
 
 enum ieee80211_state {
@@ -268,6 +266,7 @@
 	IEEE80211_S_ASSOC	= 3,	/* try to assoc */
 	IEEE80211_S_RUN		= 4	/* associated */
 };
+
 #define	IEEE80211_S_MAX	(IEEE80211_S_RUN+1)
 
 /*
@@ -277,6 +276,7 @@
 #define	IEEE80211_RATE_SIZE	8	/* 802.11 standard */
 #define	IEEE80211_XRATE_SIZE	(IEEE80211_RATE_MAXSIZE - IEEE80211_RATE_SIZE)
 					/* size of extended supported rates */
+
 struct ieee80211_rateset {
 	uint8_t			ir_nrates;
 	uint8_t			ir_rates[IEEE80211_RATE_MAXSIZE];
@@ -513,9 +513,9 @@
 
 	kmutex_t		ic_doorlock;
 	char			ic_wpadoor[MAX_IEEE80211STR];
-
-	wpa_event_type		ic_eventq[MAX_EVENT];
-	uint32_t		ic_evq_head, ic_evq_tail;
+	uint32_t		ic_ev_type;
+	uint16_t		ic_ev_reason;
+	uint8_t			ic_ev_beacon[IEEE80211_ADDR_LEN];
 
 	/* Runtime states */
 	uint32_t		ic_flags;	/* state/conf flags */
@@ -672,7 +672,6 @@
 
 void ieee80211_begin_scan(ieee80211com_t *, boolean_t);
 void ieee80211_next_scan(ieee80211com_t *);
-void ieee80211_end_scan(ieee80211com_t *);
 void ieee80211_cancel_scan(ieee80211com_t *);
 
 void ieee80211_sta_join(ieee80211com_t *, ieee80211_node_t *);
@@ -704,7 +703,7 @@
 extern struct ieee80211_key *ieee80211_crypto_encap(ieee80211com_t *, mblk_t *);
 extern struct ieee80211_key *ieee80211_crypto_decap(ieee80211com_t *, mblk_t *,
 	int);
-extern int ieee80211_crypto_newkey(ieee80211com_t *, int, int,
+extern int ieee80211_crypto_newkey(ieee80211com_t *, uint8_t, uint16_t,
 	struct ieee80211_key *);
 extern int ieee80211_crypto_delkey(ieee80211com_t *, struct ieee80211_key *);
 extern int ieee80211_crypto_setkey(ieee80211com_t *, struct ieee80211_key *,
--- a/usr/src/uts/common/sys/net80211_crypto.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/sys/net80211_crypto.h	Wed May 29 08:31:24 2013 +0200
@@ -42,8 +42,8 @@
 #ifdef _KERNEL
 #include <sys/stream.h>
 #include <sys/mac.h>
+#include <sys/net80211_proto.h>
 #endif
-#include <sys/net80211_proto.h>
 
 /*
  * 802.11 protocol crypto-related definitions.
@@ -108,6 +108,15 @@
 #define	IEEE80211_WEP_CRCLEN		4	/* CRC-32 */
 #define	IEEE80211_WEP_NKID		4	/* number of key ids */
 
+/* Maximum number of keys */
+#define	IEEE80211_KEY_MAX		IEEE80211_WEP_NKID
+
+typedef uint16_t	ieee80211_keyix;	/* h/w key index */
+
+#define	IEEE80211_KEYIX_NONE	((ieee80211_keyix) -1)
+
+#ifdef _KERNEL
+
 /*
  * 802.11i defines an extended IV for use with non-WEP ciphers.
  * When the EXTIV bit is set in the key id byte an additional
@@ -125,15 +134,6 @@
 	(sizeof (struct ieee80211_frame) +			\
 	IEEE80211_WEP_HDRLEN + IEEE80211_WEP_CRCLEN)
 
-/* Maximum number of keys */
-#define	IEEE80211_KEY_MAX		IEEE80211_WEP_NKID
-
-typedef uint16_t	ieee80211_keyix;	/* h/w key index */
-
-#define	IEEE80211_KEYIX_NONE	((ieee80211_keyix) -1)
-
-#ifdef _KERNEL
-
 struct ieee80211com;
 struct ieee80211_key;
 
--- a/usr/src/uts/common/sys/net80211_proto.h	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/common/sys/net80211_proto.h	Wed May 29 08:31:24 2013 +0200
@@ -789,7 +789,6 @@
 
 #define	WPA_OUI			0xf25000
 #define	WPA_OUI_TYPE		0x01
-#define	WPA_VERSION		1		/* current supported version */
 
 #define	IEEE80211_CHALLENGE_LEN			128
 
--- a/usr/src/uts/intel/Makefile.intel.shared	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/intel/Makefile.intel.shared	Wed May 29 08:31:24 2013 +0200
@@ -288,8 +288,6 @@
 DRV_KMODS	+= pcic
 DRV_KMODS	+= pcieb
 DRV_KMODS	+= physmem
-DRV_KMODS	+= pcan
-DRV_KMODS	+= pcwl
 DRV_KMODS	+= pit_beep
 DRV_KMODS	+= pm
 DRV_KMODS	+= poll
--- a/usr/src/uts/intel/pcan/Makefile	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,110 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-#
-#	This makefile drives the production of the pcan driver kernel module.
-#
-#	intel implementation architecture dependent
-#
-
-#
-#	Path to the base of the uts directory tree (usually /usr/src/uts).
-#
-UTSBASE	= ../..
-
-#
-#	Define the module and object file sets.
-#
-MODULE		= pcan
-OBJECTS		= $(PCAN_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(PCAN_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-
-
-#
-#	Include common rules.
-#
-include $(UTSBASE)/intel/Makefile.intel
-
-#
-#	Define targets
-#
-ALL_TARGET	= $(BINARY)  $(ITUMOD)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
-
-#
-#	Override defaults to build a unique, local modstubs.o.
-#
-MODSTUBS_DIR	 = $(OBJS_DIR)
-CLEANFILES	+= $(MODSTUBS_O)
-INC_PATH	+= -I$(UTSBASE)/common/pcmcia
-
-#
-# lint pass one enforcement
-#
-CFLAGS          += $(CCVERBOSE)
-
-#
-# STREAMS API limitations force us to turn off these lint checks.
-#
-LINTTAGS        += -erroff=E_BAD_PTR_CAST_ALIGN
-
-CERRWARN	+= -_gcc=-Wno-parentheses
-CERRWARN	+= -_gcc=-Wno-unused-label
-CERRWARN	+= -_gcc=-Wno-switch
-
-#
-# dependency
-#
-LDFLAGS		+= -dy -Nmisc/mac -Ndrv/ip
-
-#
-#	Default build targets.
-#
-.KEEP_STATE:
-
-def:		$(DEF_DEPS)
-
-all:		$(ALL_DEPS)
-
-clean:		$(CLEAN_DEPS)
-
-clobber:	$(CLOBBER_DEPS)
-
-lint:		$(LINT_DEPS)
-
-modlintlib:	$(MODLINTLIB_DEPS)
-
-clean.lint:	$(CLEAN_LINT_DEPS)
-
-install:	$(INSTALL_DEPS)
-
-#
-#	Include common targets.
-#
-include $(UTSBASE)/intel/Makefile.targ
-
--- a/usr/src/uts/intel/pcwl/Makefile	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,111 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-#
-#	This makefile drives the production of the pcwl driver kernel module.
-#
-#	intel implementation architecture dependent
-#
-
-#
-#	Path to the base of the uts directory tree (usually /usr/src/uts).
-#
-UTSBASE	= ../..
-
-#
-#	Define the module and object file sets.
-#
-MODULE		= pcwl
-OBJECTS		= $(PCWL_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(PCWL_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-
-
-#
-#	Include common rules.
-#
-include $(UTSBASE)/intel/Makefile.intel
-
-#
-#	Define targets
-#
-ALL_TARGET	= $(BINARY)  $(ITUMOD)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
-
-#
-#	Override defaults to build a unique, local modstubs.o.
-#
-MODSTUBS_DIR	 = $(OBJS_DIR)
-CLEANFILES	+= $(MODSTUBS_O)
-INC_PATH	+= -I$(UTSBASE)/common/pcmcia
-
-#
-# lint pass one enforcement
-#
-CFLAGS          += $(CCVERBOSE)
-
-#
-# STREAMS API limitations force us to turn off these lint checks.
-#
-LINTTAGS        += -erroff=E_BAD_PTR_CAST_ALIGN
-
-CERRWARN	+= -_gcc=-Wno-parentheses
-CERRWARN	+= -_gcc=-Wno-unused-label
-CERRWARN	+= -_gcc=-Wno-switch
-CERRWARN	+= -_gcc=-Wno-uninitialized
-
-#
-# dependency
-#
-LDFLAGS		+= -dy -Nmisc/mac -Ndrv/ip
-
-#
-#	Default build targets.
-#
-.KEEP_STATE:
-
-def:		$(DEF_DEPS)
-
-all:		$(ALL_DEPS)
-
-clean:		$(CLEAN_DEPS)
-
-clobber:	$(CLOBBER_DEPS)
-
-lint:		$(LINT_DEPS)
-
-modlintlib:	$(MODLINTLIB_DEPS)
-
-clean.lint:	$(CLEAN_LINT_DEPS)
-
-install:	$(INSTALL_DEPS)
-
-#
-#	Include common targets.
-#
-include $(UTSBASE)/intel/Makefile.targ
-
--- a/usr/src/uts/sparc/Makefile.sparc.shared	Sun May 19 12:27:58 2013 +0200
+++ b/usr/src/uts/sparc/Makefile.sparc.shared	Wed May 29 08:31:24 2013 +0200
@@ -254,8 +254,6 @@
 DRV_KMODS	+= efe
 DRV_KMODS	+= hxge
 DRV_KMODS	+= mxfe
-DRV_KMODS	+= pcan
-DRV_KMODS	+= pcwl
 DRV_KMODS	+= rge
 DRV_KMODS	+= rtls
 DRV_KMODS	+= sfe
--- a/usr/src/uts/sparc/pcan/Makefile	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-
-#
-# Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-#
-#	This makefile drives the production of the pcan driver kernel module.
-#
-
-#
-#	Path to the base of the uts directory tree (usually /usr/src/uts).
-#
-UTSBASE	= ../..
-
-#
-#	Define the module and object file sets.
-#
-MODULE		= pcan
-OBJECTS		= $(PCAN_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(PCAN_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-
-
-#
-#	Include common rules.
-#
-include $(UTSBASE)/sparc/Makefile.sparc
-
-#
-#	Define targets
-#
-ALL_TARGET	= $(BINARY)  $(ITUMOD)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
-
-#
-#	Override defaults to build a unique, local modstubs.o.
-#
-MODSTUBS_DIR	 = $(OBJS_DIR)
-CLEANFILES	+= $(MODSTUBS_O)
-INC_PATH	+= -I$(UTSBASE)/common/pcmcia
-
-#
-# lint pass one enforcement
-#
-CFLAGS          += -v
-
-#
-# STREAMS API limitations force us to turn off these lint checks.
-#
-LINTTAGS        += -erroff=E_BAD_PTR_CAST_ALIGN
-LINTTAGS        += -erroff=E_PTRDIFF_OVERFLOW
-
-CERRWARN	+= -_gcc=-Wno-parentheses
-CERRWARN	+= -_gcc=-Wno-unused-label
-CERRWARN	+= -_gcc=-Wno-switch
-
-#
-# dependency
-#
-LDFLAGS		+= -dy -Nmisc/mac -Ndrv/ip
-
-#
-#	Default build targets.
-#
-.KEEP_STATE:
-
-def:		$(DEF_DEPS)
-
-all:		$(ALL_DEPS)
-
-clean:		$(CLEAN_DEPS)
-
-clobber:	$(CLOBBER_DEPS)
-
-lint:		$(LINT_DEPS)
-
-modlintlib:	$(MODLINTLIB_DEPS)
-
-clean.lint:	$(CLEAN_LINT_DEPS)
-
-install:	$(INSTALL_DEPS)
-
-#
-#	Include common targets.
-#
-include $(UTSBASE)/sparc/Makefile.targ
-
--- a/usr/src/uts/sparc/pcwl/Makefile	Sun May 19 12:27:58 2013 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,109 +0,0 @@
-#
-# CDDL HEADER START
-#
-# The contents of this file are subject to the terms of the
-# Common Development and Distribution License (the "License").
-# You may not use this file except in compliance with the License.
-#
-# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
-# or http://www.opensolaris.org/os/licensing.
-# See the License for the specific language governing permissions
-# and limitations under the License.
-#
-# When distributing Covered Code, include this CDDL HEADER in each
-# file and include the License file at usr/src/OPENSOLARIS.LICENSE.
-# If applicable, add the following below this CDDL HEADER, with the
-# fields enclosed by brackets "[]" replaced with your own identifying
-# information: Portions Copyright [yyyy] [name of copyright owner]
-#
-# CDDL HEADER END
-#
-
-#
-# Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
-# Use is subject to license terms.
-#
-
-#
-#	This makefile drives the production of the pcwl driver kernel module.
-#
-
-#
-#	Path to the base of the uts directory tree (usually /usr/src/uts).
-#
-UTSBASE	= ../..
-
-#
-#	Define the module and object file sets.
-#
-MODULE		= pcwl
-OBJECTS		= $(PCWL_OBJS:%=$(OBJS_DIR)/%)
-LINTS		= $(PCWL_OBJS:%.o=$(LINTS_DIR)/%.ln)
-ROOTMODULE	= $(ROOT_DRV_DIR)/$(MODULE)
-
-
-#
-#	Include common rules.
-#
-include $(UTSBASE)/sparc/Makefile.sparc
-
-#
-#	Define targets
-#
-ALL_TARGET	= $(BINARY)  $(ITUMOD)
-LINT_TARGET	= $(MODULE).lint
-INSTALL_TARGET	= $(BINARY) $(ROOTMODULE)
-
-#
-#	Override defaults to build a unique, local modstubs.o.
-#
-MODSTUBS_DIR	 = $(OBJS_DIR)
-CLEANFILES	+= $(MODSTUBS_O)
-INC_PATH	+= -I$(UTSBASE)/common/pcmcia
-
-#
-# lint pass one enforcement
-#
-CFLAGS          += $(CCVERBOSE)
-
-#
-# STREAMS API limitations force us to turn off these lint checks.
-#
-LINTTAGS        += -erroff=E_BAD_PTR_CAST_ALIGN
-
-CERRWARN	+= -_gcc=-Wno-parentheses
-CERRWARN	+= -_gcc=-Wno-unused-label
-CERRWARN	+= -_gcc=-Wno-switch
-CERRWARN	+= -_gcc=-Wno-uninitialized
-
-#
-# dependency
-#
-LDFLAGS		+= -dy -Nmisc/mac -Ndrv/ip
-
-#
-#	Default build targets.
-#
-.KEEP_STATE:
-
-def:		$(DEF_DEPS)
-
-all:		$(ALL_DEPS)
-
-clean:		$(CLEAN_DEPS)
-
-clobber:	$(CLOBBER_DEPS)
-
-lint:		$(LINT_DEPS)
-
-modlintlib:	$(MODLINTLIB_DEPS)
-
-clean.lint:	$(CLEAN_LINT_DEPS)
-
-install:	$(INSTALL_DEPS)
-
-#
-#	Include common targets.
-#
-include $(UTSBASE)/sparc/Makefile.targ
-