summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorrpaulo <rpaulo@FreeBSD.org>2010-06-13 20:32:04 +0000
committerrpaulo <rpaulo@FreeBSD.org>2010-06-13 20:32:04 +0000
commit60c44471bf25f9e84d8701afe1bbcbcc88e18c89 (patch)
tree538db23d436787038f980271529ae2be44235c1b
parentced3a3de988600636bda6479d27de8823307f171 (diff)
downloadFreeBSD-src-60c44471bf25f9e84d8701afe1bbcbcc88e18c89.zip
FreeBSD-src-60c44471bf25f9e84d8701afe1bbcbcc88e18c89.tar.gz
Import wpa_supplicant & hostapd 0.6.9.
-rw-r--r--hostapd/.gitignore7
-rw-r--r--hostapd/ChangeLog32
-rw-r--r--hostapd/Makefile635
-rw-r--r--hostapd/README-WPS9
-rw-r--r--hostapd/ap.h2
-rw-r--r--hostapd/beacon.c8
-rw-r--r--hostapd/config.c101
-rw-r--r--hostapd/config.h10
-rw-r--r--hostapd/ctrl_iface.c80
-rw-r--r--hostapd/doc/.gitignore4
-rw-r--r--hostapd/driver_atheros.c1457
-rw-r--r--hostapd/driver_bsd.c839
-rw-r--r--hostapd/driver_hostap.c1279
-rw-r--r--hostapd/driver_madwifi.c1483
-rw-r--r--hostapd/driver_nl80211.c2708
-rw-r--r--hostapd/driver_none.c62
-rw-r--r--hostapd/driver_prism54.c1091
-rw-r--r--hostapd/driver_test.c1300
-rw-r--r--hostapd/driver_wired.c372
-rw-r--r--hostapd/drivers.c6
-rw-r--r--hostapd/hostapd.82
-rw-r--r--hostapd/hostapd.c44
-rw-r--r--hostapd/hostapd.conf47
-rw-r--r--hostapd/hostapd_cli.12
-rw-r--r--hostapd/hostapd_cli.c12
-rw-r--r--hostapd/hw_features.c7
-rw-r--r--hostapd/ieee802_11.c115
-rw-r--r--hostapd/ieee802_1x.c2
-rw-r--r--hostapd/preauth.c1
-rw-r--r--hostapd/prism54.h177
-rw-r--r--hostapd/priv_netlink.h71
-rw-r--r--hostapd/radiotap.c287
-rw-r--r--hostapd/radiotap.h242
-rw-r--r--hostapd/radiotap_iter.h41
-rw-r--r--hostapd/wme.c285
-rw-r--r--hostapd/wme.h167
-rw-r--r--hostapd/wpa.c71
-rw-r--r--hostapd/wpa.h2
-rw-r--r--hostapd/wpa_auth_i.h2
-rw-r--r--hostapd/wpa_auth_ie.c4
-rw-r--r--hostapd/wpa_ft.c13
-rw-r--r--hostapd/wps_hostapd.c67
-rw-r--r--hostapd/wps_hostapd.h2
-rw-r--r--src/common/.gitignore1
-rw-r--r--src/common/ieee802_11_common.c27
-rw-r--r--src/common/ieee802_11_common.h8
-rw-r--r--src/common/ieee802_11_defs.h55
-rw-r--r--src/common/nl80211_copy.h1434
-rw-r--r--src/common/version.h2
-rw-r--r--src/common/wireless_copy.h1099
-rw-r--r--src/common/wpa_common.c4
-rw-r--r--src/crypto/.gitignore1
-rw-r--r--src/crypto/crypto_cryptoapi.c21
-rw-r--r--src/crypto/crypto_gnutls.c2
-rw-r--r--src/crypto/crypto_internal.c9
-rw-r--r--src/crypto/dh_groups.c12
-rw-r--r--src/crypto/ms_funcs.c2
-rw-r--r--src/crypto/rc4.c16
-rw-r--r--src/crypto/rc4.h1
-rw-r--r--src/crypto/sha1.c4
-rw-r--r--src/crypto/sha256.c2
-rw-r--r--src/crypto/tls.h6
-rw-r--r--src/crypto/tls_gnutls.c61
-rw-r--r--src/crypto/tls_openssl.c95
-rw-r--r--src/drivers/Apple80211.h156
-rw-r--r--src/drivers/Makefile9
-rw-r--r--src/drivers/MobileApple80211.c189
-rw-r--r--src/drivers/MobileApple80211.h43
-rw-r--r--src/drivers/driver.h4
-rw-r--r--src/drivers/driver_atmel.c506
-rw-r--r--src/drivers/driver_broadcom.c604
-rw-r--r--src/drivers/driver_bsd.c794
-rw-r--r--src/drivers/driver_hostap.c513
-rw-r--r--src/drivers/driver_hostap.h153
-rw-r--r--src/drivers/driver_iphone.m466
-rw-r--r--src/drivers/driver_ipw.c463
-rw-r--r--src/drivers/driver_madwifi.c601
-rw-r--r--src/drivers/driver_ndis.c25
-rw-r--r--src/drivers/driver_ndis_.c105
-rw-r--r--src/drivers/driver_ndiswrapper.c370
-rw-r--r--src/drivers/driver_nl80211.c2766
-rw-r--r--src/drivers/driver_osx.m432
-rw-r--r--src/drivers/driver_prism54.c381
-rw-r--r--src/drivers/driver_privsep.c820
-rw-r--r--src/drivers/driver_ps3.c186
-rw-r--r--src/drivers/driver_ralink.c1505
-rw-r--r--src/drivers/driver_ralink.h382
-rw-r--r--src/drivers/driver_roboswitch.c476
-rw-r--r--src/drivers/driver_test.c1230
-rw-r--r--src/drivers/driver_wext.c2375
-rw-r--r--src/drivers/driver_wext.h82
-rw-r--r--src/drivers/driver_wired.c286
-rw-r--r--src/drivers/ndis_events.c808
-rw-r--r--src/drivers/priv_netlink.h104
-rw-r--r--src/drivers/radiotap.c287
-rw-r--r--src/drivers/radiotap.h242
-rw-r--r--src/drivers/radiotap_iter.h41
-rw-r--r--src/eap_common/.gitignore1
-rw-r--r--src/eap_common/eap_defs.h2
-rw-r--r--src/eap_common/eap_fast_common.h12
-rw-r--r--src/eap_common/eap_tlv_common.h5
-rw-r--r--src/eap_peer/.gitignore1
-rw-r--r--src/eap_peer/eap_fast.c7
-rw-r--r--src/eap_peer/eap_gpsk.c2
-rw-r--r--src/eap_peer/eap_methods.h5
-rw-r--r--src/eap_peer/eap_sim.c2
-rw-r--r--src/eap_peer/eap_tls_common.c14
-rw-r--r--src/eap_peer/eap_tnc.c11
-rw-r--r--src/eap_peer/eap_ttls.c2
-rw-r--r--src/eap_peer/eap_wsc.c2
-rw-r--r--src/eap_peer/tncc.c1
-rw-r--r--src/eap_server/.gitignore1
-rw-r--r--src/eap_server/eap.c15
-rw-r--r--src/eap_server/eap_fast.c77
-rw-r--r--src/eap_server/eap_gpsk.c2
-rw-r--r--src/eap_server/eap_i.h2
-rw-r--r--src/eap_server/eap_tls_common.c2
-rw-r--r--src/eap_server/eap_tnc.c2
-rw-r--r--src/eap_server/eap_ttls.c13
-rw-r--r--src/eapol_supp/.gitignore1
-rw-r--r--src/eapol_supp/eapol_supp_sm.c9
-rw-r--r--src/hlr_auc_gw/.gitignore1
-rw-r--r--src/hlr_auc_gw/hlr_auc_gw.c12
-rw-r--r--src/l2_packet/Makefile9
-rw-r--r--src/l2_packet/l2_packet_freebsd.c285
-rw-r--r--src/l2_packet/l2_packet_linux.c200
-rw-r--r--src/l2_packet/l2_packet_ndis.c516
-rw-r--r--src/l2_packet/l2_packet_none.c123
-rw-r--r--src/l2_packet/l2_packet_pcap.c386
-rw-r--r--src/l2_packet/l2_packet_privsep.c267
-rw-r--r--src/l2_packet/l2_packet_winpcap.c341
-rw-r--r--src/radius/.gitignore1
-rw-r--r--src/radius/radius_client.c30
-rw-r--r--src/radius/radius_server.c57
-rw-r--r--src/rsn_supp/.gitignore1
-rw-r--r--src/rsn_supp/wpa.c65
-rw-r--r--src/rsn_supp/wpa_ft.c13
-rw-r--r--src/rsn_supp/wpa_i.h2
-rw-r--r--src/tls/.gitignore1
-rw-r--r--src/tls/rsa.c2
-rw-r--r--src/tls/tlsv1_client.c11
-rw-r--r--src/tls/tlsv1_server_read.c10
-rw-r--r--src/utils/.gitignore1
-rw-r--r--src/utils/base64.c2
-rw-r--r--src/utils/common.c6
-rw-r--r--src/utils/common.h24
-rw-r--r--src/utils/eloop_none.c410
-rw-r--r--src/utils/eloop_win.c622
-rw-r--r--src/utils/os_none.c226
-rw-r--r--src/utils/os_unix.c3
-rw-r--r--src/utils/os_win32.c222
-rw-r--r--src/utils/wpa_debug.c28
-rw-r--r--src/utils/wpa_debug.h20
-rw-r--r--src/utils/wpabuf.c4
-rw-r--r--src/wps/.gitignore1
-rw-r--r--src/wps/httpread.c7
-rw-r--r--src/wps/wps.h21
-rw-r--r--src/wps/wps_attr_parse.c8
-rw-r--r--src/wps/wps_common.c68
-rw-r--r--src/wps/wps_enrollee.c47
-rw-r--r--src/wps/wps_i.h8
-rw-r--r--src/wps/wps_registrar.c234
-rw-r--r--src/wps/wps_upnp.c109
-rw-r--r--src/wps/wps_upnp_event.c4
-rw-r--r--src/wps/wps_upnp_i.h6
-rw-r--r--src/wps/wps_upnp_ssdp.c45
-rw-r--r--src/wps/wps_upnp_web.c2
-rw-r--r--wpa_supplicant/.gitignore8
-rw-r--r--wpa_supplicant/ChangeLog23
-rw-r--r--wpa_supplicant/Makefile1268
-rw-r--r--wpa_supplicant/README9
-rw-r--r--wpa_supplicant/README-WPS7
-rw-r--r--wpa_supplicant/README-Windows.txt450
-rw-r--r--wpa_supplicant/config_winreg.c980
-rw-r--r--wpa_supplicant/ctrl_iface_dbus.c62
-rw-r--r--wpa_supplicant/ctrl_iface_dbus.h6
-rw-r--r--wpa_supplicant/ctrl_iface_dbus_handlers.c81
-rw-r--r--wpa_supplicant/ctrl_iface_dbus_handlers.h6
-rw-r--r--wpa_supplicant/ctrl_iface_named_pipe.c835
-rw-r--r--wpa_supplicant/ctrl_iface_unix.c39
-rw-r--r--wpa_supplicant/defconfig3
-rw-r--r--wpa_supplicant/doc/.gitignore4
-rw-r--r--wpa_supplicant/doc/docbook/.gitignore6
-rw-r--r--wpa_supplicant/doc/docbook/wpa_background.82
-rw-r--r--wpa_supplicant/doc/docbook/wpa_cli.82
-rw-r--r--wpa_supplicant/doc/docbook/wpa_gui.82
-rw-r--r--wpa_supplicant/doc/docbook/wpa_passphrase.82
-rw-r--r--wpa_supplicant/doc/docbook/wpa_priv.82
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.82
-rw-r--r--wpa_supplicant/doc/docbook/wpa_supplicant.conf.52
-rw-r--r--wpa_supplicant/doc/porting.doxygen6
-rw-r--r--wpa_supplicant/eapol_test.c5
-rw-r--r--wpa_supplicant/events.c59
-rw-r--r--wpa_supplicant/main_none.c46
-rw-r--r--wpa_supplicant/main_symbian.cpp48
-rw-r--r--wpa_supplicant/main_winmain.c84
-rw-r--r--wpa_supplicant/main_winsvc.c464
-rw-r--r--wpa_supplicant/mlme.c35
-rw-r--r--wpa_supplicant/nmake.mak228
-rw-r--r--wpa_supplicant/scan.c46
-rw-r--r--wpa_supplicant/symbian/README.symbian24
-rw-r--r--wpa_supplicant/symbian/bld.inf8
-rw-r--r--wpa_supplicant/symbian/wpa_supplicant.mmp38
-rwxr-xr-xwpa_supplicant/vs2005/eapol_test/eapol_test.vcproj425
-rwxr-xr-xwpa_supplicant/vs2005/win_if_list/win_if_list.vcproj203
-rwxr-xr-xwpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj215
-rwxr-xr-xwpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj220
-rwxr-xr-xwpa_supplicant/vs2005/wpa_supplicant.sln52
-rwxr-xr-xwpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj421
-rwxr-xr-xwpa_supplicant/vs2005/wpasvc/wpasvc.vcproj421
-rwxr-xr-xwpa_supplicant/win_example.reg42
-rw-r--r--wpa_supplicant/win_if_list.c179
-rw-r--r--wpa_supplicant/wpa_gui-qt4/addinterface.cpp245
-rw-r--r--wpa_supplicant/wpa_gui-qt4/addinterface.h45
-rw-r--r--wpa_supplicant/wpa_gui-qt4/eventhistory.cpp130
-rw-r--r--wpa_supplicant/wpa_gui-qt4/eventhistory.h63
-rw-r--r--wpa_supplicant/wpa_gui-qt4/eventhistory.ui61
-rw-r--r--wpa_supplicant/wpa_gui-qt4/icons.qrc5
-rw-r--r--wpa_supplicant/wpa_gui-qt4/icons/Makefile27
-rw-r--r--wpa_supplicant/wpa_gui-qt4/icons/README7
-rw-r--r--wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg256
-rw-r--r--wpa_supplicant/wpa_gui-qt4/icons_png.qrc5
-rw-r--r--wpa_supplicant/wpa_gui-qt4/main.cpp70
-rw-r--r--wpa_supplicant/wpa_gui-qt4/networkconfig.cpp823
-rw-r--r--wpa_supplicant/wpa_gui-qt4/networkconfig.h61
-rw-r--r--wpa_supplicant/wpa_gui-qt4/networkconfig.ui425
-rw-r--r--wpa_supplicant/wpa_gui-qt4/scanresults.cpp144
-rw-r--r--wpa_supplicant/wpa_gui-qt4/scanresults.h46
-rw-r--r--wpa_supplicant/wpa_gui-qt4/scanresults.ui94
-rw-r--r--wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp100
-rw-r--r--wpa_supplicant/wpa_gui-qt4/userdatarequest.h46
-rw-r--r--wpa_supplicant/wpa_gui-qt4/userdatarequest.ui109
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop10
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpa_gui.pro62
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpagui.cpp1706
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpagui.h147
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpagui.ui517
-rw-r--r--wpa_supplicant/wpa_gui-qt4/wpamsg.h41
-rw-r--r--wpa_supplicant/wpa_gui/eventhistory.ui125
-rw-r--r--wpa_supplicant/wpa_gui/eventhistory.ui.h41
-rw-r--r--wpa_supplicant/wpa_gui/main.cpp30
-rw-r--r--wpa_supplicant/wpa_gui/networkconfig.ui475
-rw-r--r--wpa_supplicant/wpa_gui/networkconfig.ui.h552
-rw-r--r--wpa_supplicant/wpa_gui/scanresults.ui179
-rw-r--r--wpa_supplicant/wpa_gui/scanresults.ui.h101
-rwxr-xr-xwpa_supplicant/wpa_gui/setup-mingw-cross-compiling11
-rw-r--r--wpa_supplicant/wpa_gui/userdatarequest.ui163
-rw-r--r--wpa_supplicant/wpa_gui/userdatarequest.ui.h72
-rw-r--r--wpa_supplicant/wpa_gui/wpa_gui.pro50
-rw-r--r--wpa_supplicant/wpa_gui/wpagui.ui471
-rw-r--r--wpa_supplicant/wpa_gui/wpagui.ui.h730
-rw-r--r--wpa_supplicant/wpa_gui/wpamsg.h34
-rw-r--r--wpa_supplicant/wpa_priv.c4
-rw-r--r--wpa_supplicant/wpa_supplicant.c43
-rw-r--r--wpa_supplicant/wpa_supplicant_i.h12
-rw-r--r--wpa_supplicant/wpas_glue.c4
-rw-r--r--wpa_supplicant/wps_supplicant.c186
257 files changed, 52748 insertions, 916 deletions
diff --git a/hostapd/.gitignore b/hostapd/.gitignore
deleted file mode 100644
index 6dd2c2f..0000000
--- a/hostapd/.gitignore
+++ /dev/null
@@ -1,7 +0,0 @@
-*.d
-.config
-driver_conf.c
-hostapd
-hostapd_cli
-hlr_auc_gw
-nt_password_hash
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index 46f0852..18af4b1 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -1,5 +1,37 @@
ChangeLog for hostapd
+2010-01-12 - v0.6.10
+ * fixed SHA-256 based key derivation function to match with the
+ standard when using CCMP (for IEEE 802.11r and IEEE 802.11w)
+ (note: this breaks interoperability with previous version) [Bug 307]
+ * fixed WPS selected registrar expiration for internal PIN registrar
+ * disable PMTU discovery for RADIUS packets
+ * fixed WPS UPnP SSDP on 32-bit targets
+ * fixed WPS AP reconfiguration with drivers that do not use hostapd
+ MLME
+ * fixed RSN parameter setting for multi-BSS case
+ * added WPS workarounds for known interoperability issues with broken,
+ deployed implementation
+ * update IEEE 802.11w implementation to match with the published
+ standard
+ * fixed OpCode when proxying WSC_ACK or WSC_NACK from WPS ER
+ * fixed proxying of WSC_NACK to WPS ER
+ * fixed compilation with newer GnuTLS versions
+ * added support for defining timeout for WPS PINs
+ * fixed WPS Probe Request processing to handle missing required
+ attribute
+ * fixed PKCS#12 use with OpenSSL 1.0.0
+
+2009-03-23 - v0.6.9
+ * driver_nl80211: fixed STA accounting data collection (TX/RX bytes
+ reported correctly; TX/RX packets not yet available from kernel)
+ * fixed EAPOL/EAP reauthentication when using an external RADIUS
+ authentication server
+ * driver_prism54: fixed segmentation fault on initialization
+ * fixed TNC with EAP-TTLS
+ * fixed IEEE 802.11r key derivation function to match with the standard
+ (note: this breaks interoperability with previous version) [Bug 303]
+
2009-02-15 - v0.6.8
* increased hostapd_cli ping interval to 5 seconds and made this
configurable with a new command line options (-G<seconds>)
diff --git a/hostapd/Makefile b/hostapd/Makefile
new file mode 100644
index 0000000..3b3d7fe
--- /dev/null
+++ b/hostapd/Makefile
@@ -0,0 +1,635 @@
+ifndef CC
+CC=gcc
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to
+# a file (undefine it, if you want to save in binary size)
+CFLAGS += -DHOSTAPD_DUMP_STATE
+
+CFLAGS += -I../src
+CFLAGS += -I../src/crypto
+CFLAGS += -I../src/utils
+CFLAGS += -I../src/common
+
+# Uncomment following line and set the path to your kernel tree include
+# directory if your C library does not include all header files.
+# CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include
+
+-include .config
+
+ifndef CONFIG_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32
+endif
+
+OBJS = hostapd.o ieee802_1x.o eapol_sm.o \
+ ieee802_11.o config.o ieee802_11_auth.o accounting.o \
+ sta_info.o wpa.o ctrl_iface.o \
+ drivers.o preauth.o pmksa_cache.o beacon.o \
+ hw_features.o wme.o ap_list.o \
+ mlme.o vlan_init.o wpa_auth_ie.o
+
+OBJS += ../src/utils/eloop.o
+OBJS += ../src/utils/common.o
+OBJS += ../src/utils/wpa_debug.o
+OBJS += ../src/utils/wpabuf.o
+OBJS += ../src/utils/os_$(CONFIG_OS).o
+OBJS += ../src/utils/ip_addr.o
+
+OBJS += ../src/common/ieee802_11_common.o
+OBJS += ../src/common/wpa_common.o
+
+OBJS += ../src/radius/radius.o
+OBJS += ../src/radius/radius_client.o
+
+OBJS += ../src/crypto/md5.o
+OBJS += ../src/crypto/rc4.o
+OBJS += ../src/crypto/md4.o
+OBJS += ../src/crypto/sha1.o
+OBJS += ../src/crypto/des.o
+OBJS += ../src/crypto/aes_wrap.o
+OBJS += ../src/crypto/aes.o
+
+HOBJS=../src/hlr_auc_gw/hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/hlr_auc_gw/milenage.o ../src/crypto/aes_wrap.o ../src/crypto/aes.o
+
+CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
+
+ifdef CONFIG_IAPP
+CFLAGS += -DCONFIG_IAPP
+OBJS += iapp.o
+endif
+
+ifdef CONFIG_RSN_PREAUTH
+CFLAGS += -DCONFIG_RSN_PREAUTH
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_PEERKEY
+CFLAGS += -DCONFIG_PEERKEY
+OBJS += peerkey.o
+endif
+
+ifdef CONFIG_IEEE80211W
+CFLAGS += -DCONFIG_IEEE80211W
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211R
+OBJS += wpa_ft.o
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_IEEE80211N
+CFLAGS += -DCONFIG_IEEE80211N
+endif
+
+ifdef CONFIG_DRIVER_HOSTAP
+CFLAGS += -DCONFIG_DRIVER_HOSTAP
+OBJS += driver_hostap.o
+endif
+
+ifdef CONFIG_DRIVER_WIRED
+CFLAGS += -DCONFIG_DRIVER_WIRED
+OBJS += driver_wired.o
+endif
+
+ifdef CONFIG_DRIVER_MADWIFI
+CFLAGS += -DCONFIG_DRIVER_MADWIFI
+OBJS += driver_madwifi.o
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_DRIVER_ATHEROS
+CFLAGS += -DCONFIG_DRIVER_ATHEROS
+OBJS += driver_atheros.o
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_DRIVER_PRISM54
+CFLAGS += -DCONFIG_DRIVER_PRISM54
+OBJS += driver_prism54.o
+endif
+
+ifdef CONFIG_DRIVER_NL80211
+CFLAGS += -DCONFIG_DRIVER_NL80211
+OBJS += driver_nl80211.o radiotap.o
+LIBS += -lnl
+ifdef CONFIG_LIBNL20
+LIBS += -lnl-genl
+CFLAGS += -DCONFIG_LIBNL20
+endif
+endif
+
+ifdef CONFIG_DRIVER_BSD
+CFLAGS += -DCONFIG_DRIVER_BSD
+OBJS += driver_bsd.o
+CONFIG_L2_PACKET=y
+CONFIG_DNET_PCAP=y
+CONFIG_L2_FREEBSD=y
+endif
+
+ifdef CONFIG_DRIVER_TEST
+CFLAGS += -DCONFIG_DRIVER_TEST
+OBJS += driver_test.o
+endif
+
+ifdef CONFIG_DRIVER_NONE
+CFLAGS += -DCONFIG_DRIVER_NONE
+OBJS += driver_none.o
+endif
+
+ifdef CONFIG_L2_PACKET
+ifdef CONFIG_DNET_PCAP
+ifdef CONFIG_L2_FREEBSD
+LIBS += -lpcap
+OBJS += ../src/l2_packet/l2_packet_freebsd.o
+else
+LIBS += -ldnet -lpcap
+OBJS += ../src/l2_packet/l2_packet_pcap.o
+endif
+else
+OBJS += ../src/l2_packet/l2_packet_linux.o
+endif
+else
+OBJS += ../src/l2_packet/l2_packet_none.o
+endif
+
+
+ifdef CONFIG_EAP_MD5
+CFLAGS += -DEAP_MD5
+OBJS += ../src/eap_server/eap_md5.o
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_TLS
+CFLAGS += -DEAP_TLS
+OBJS += ../src/eap_server/eap_tls.o
+TLS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_PEAP
+CFLAGS += -DEAP_PEAP
+OBJS += ../src/eap_server/eap_peap.o
+OBJS += ../src/eap_common/eap_peap_common.o
+TLS_FUNCS=y
+CONFIG_EAP_MSCHAPV2=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+CFLAGS += -DEAP_TTLS
+OBJS += ../src/eap_server/eap_ttls.o
+TLS_FUNCS=y
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+CFLAGS += -DEAP_MSCHAPv2
+OBJS += ../src/eap_server/eap_mschapv2.o
+MS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_GTC
+CFLAGS += -DEAP_GTC
+OBJS += ../src/eap_server/eap_gtc.o
+endif
+
+ifdef CONFIG_EAP_SIM
+CFLAGS += -DEAP_SIM
+OBJS += ../src/eap_server/eap_sim.o
+CONFIG_EAP_SIM_COMMON=y
+endif
+
+ifdef CONFIG_EAP_AKA
+CFLAGS += -DEAP_AKA
+OBJS += ../src/eap_server/eap_aka.o
+CONFIG_EAP_SIM_COMMON=y
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_EAP_AKA_PRIME
+CFLAGS += -DEAP_AKA_PRIME
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += ../src/eap_common/eap_sim_common.o
+# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
+# replaced with another file implementating the interface specified in
+# eap_sim_db.h.
+OBJS += ../src/eap_server/eap_sim_db.o
+NEED_FIPS186_2_PRF=y
+endif
+
+ifdef CONFIG_EAP_PAX
+CFLAGS += -DEAP_PAX
+OBJS += ../src/eap_server/eap_pax.o ../src/eap_common/eap_pax_common.o
+endif
+
+ifdef CONFIG_EAP_PSK
+CFLAGS += -DEAP_PSK
+OBJS += ../src/eap_server/eap_psk.o ../src/eap_common/eap_psk_common.o
+endif
+
+ifdef CONFIG_EAP_SAKE
+CFLAGS += -DEAP_SAKE
+OBJS += ../src/eap_server/eap_sake.o ../src/eap_common/eap_sake_common.o
+endif
+
+ifdef CONFIG_EAP_GPSK
+CFLAGS += -DEAP_GPSK
+OBJS += ../src/eap_server/eap_gpsk.o ../src/eap_common/eap_gpsk_common.o
+ifdef CONFIG_EAP_GPSK_SHA256
+CFLAGS += -DEAP_GPSK_SHA256
+endif
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+CFLAGS += -DEAP_VENDOR_TEST
+OBJS += ../src/eap_server/eap_vendor_test.o
+endif
+
+ifdef CONFIG_EAP_FAST
+CFLAGS += -DEAP_FAST
+OBJS += ../src/eap_server/eap_fast.o
+OBJS += ../src/eap_common/eap_fast_common.o
+TLS_FUNCS=y
+NEED_T_PRF=y
+endif
+
+ifdef CONFIG_WPS
+CFLAGS += -DCONFIG_WPS -DEAP_WSC
+OBJS += ../src/utils/uuid.o
+OBJS += wps_hostapd.o
+OBJS += ../src/eap_server/eap_wsc.o ../src/eap_common/eap_wsc_common.o
+OBJS += ../src/wps/wps.o
+OBJS += ../src/wps/wps_common.o
+OBJS += ../src/wps/wps_attr_parse.o
+OBJS += ../src/wps/wps_attr_build.o
+OBJS += ../src/wps/wps_attr_process.o
+OBJS += ../src/wps/wps_dev_attr.o
+OBJS += ../src/wps/wps_enrollee.o
+OBJS += ../src/wps/wps_registrar.o
+NEED_DH_GROUPS=y
+NEED_SHA256=y
+NEED_CRYPTO=y
+NEED_BASE64=y
+
+ifdef CONFIG_WPS_UPNP
+CFLAGS += -DCONFIG_WPS_UPNP
+OBJS += ../src/wps/wps_upnp.o
+OBJS += ../src/wps/wps_upnp_ssdp.o
+OBJS += ../src/wps/wps_upnp_web.o
+OBJS += ../src/wps/wps_upnp_event.o
+OBJS += ../src/wps/httpread.o
+endif
+
+endif
+
+ifdef CONFIG_EAP_IKEV2
+CFLAGS += -DEAP_IKEV2
+OBJS += ../src/eap_server/eap_ikev2.o ../src/eap_server/ikev2.o
+OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+endif
+
+ifdef CONFIG_EAP_TNC
+CFLAGS += -DEAP_TNC
+OBJS += ../src/eap_server/eap_tnc.o
+OBJS += ../src/eap_server/tncs.o
+NEED_BASE64=y
+ifndef CONFIG_DRIVER_BSD
+LIBS += -ldl
+endif
+endif
+
+# Basic EAP functionality is needed for EAPOL
+OBJS += ../src/eap_server/eap.o
+OBJS += ../src/eap_common/eap_common.o
+OBJS += ../src/eap_server/eap_methods.o
+OBJS += ../src/eap_server/eap_identity.o
+
+ifdef CONFIG_EAP
+CFLAGS += -DEAP_SERVER
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
+endif
+
+ifeq ($(CONFIG_TLS), internal)
+ifndef CONFIG_CRYPTO
+CONFIG_CRYPTO=internal
+endif
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+CFLAGS += -DCONFIG_INTERNAL_X509
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+CFLAGS += -DCONFIG_INTERNAL_X509
+endif
+
+
+ifdef TLS_FUNCS
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
+CFLAGS += -DEAP_TLS_FUNCS
+OBJS += ../src/eap_server/eap_tls_common.o
+NEED_TLS_PRF=y
+ifeq ($(CONFIG_TLS), openssl)
+OBJS += ../src/crypto/tls_openssl.o
+LIBS += -lssl -lcrypto
+LIBS_p += -lcrypto
+LIBS_h += -lcrypto
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+OBJS += ../src/crypto/tls_gnutls.o
+LIBS += -lgnutls -lgcrypt -lgpg-error
+LIBS_p += -lgcrypt
+LIBS_h += -lgcrypt
+endif
+ifdef CONFIG_GNUTLS_EXTRA
+CFLAGS += -DCONFIG_GNUTLS_EXTRA
+LIBS += -lgnutls-extra
+endif
+ifeq ($(CONFIG_TLS), internal)
+OBJS += ../src/crypto/tls_internal.o
+OBJS += ../src/tls/tlsv1_common.o ../src/tls/tlsv1_record.o
+OBJS += ../src/tls/tlsv1_cred.o ../src/tls/tlsv1_server.o
+OBJS += ../src/tls/tlsv1_server_write.o ../src/tls/tlsv1_server_read.o
+OBJS += ../src/tls/asn1.o ../src/tls/x509v3.o
+OBJS_p += ../src/tls/asn1.o
+OBJS_p += ../src/crypto/rc4.o ../src/crypto/aes_wrap.o ../src/crypto/aes.o
+NEED_BASE64=y
+CFLAGS += -DCONFIG_TLS_INTERNAL
+CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+ifeq ($(CONFIG_CRYPTO), internal)
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+else
+LIBS += -ltommath
+LIBS_p += -ltommath
+endif
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+LIBS += -ltomcrypt -ltfm
+LIBS_p += -ltomcrypt -ltfm
+endif
+endif
+NEED_CRYPTO=y
+else
+OBJS += ../src/crypto/tls_none.o
+endif
+
+ifdef CONFIG_PKCS12
+CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef MS_FUNCS
+OBJS += ../src/crypto/ms_funcs.o
+NEED_CRYPTO=y
+endif
+
+ifdef CHAP
+OBJS += ../src/eap_common/chap.o
+endif
+
+ifdef NEED_CRYPTO
+ifndef TLS_FUNCS
+ifeq ($(CONFIG_TLS), openssl)
+LIBS += -lcrypto
+LIBS_p += -lcrypto
+LIBS_h += -lcrypto
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+LIBS += -lgcrypt
+LIBS_p += -lgcrypt
+LIBS_h += -lgcrypt
+endif
+ifeq ($(CONFIG_TLS), internal)
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+LIBS += -ltomcrypt -ltfm
+LIBS_p += -ltomcrypt -ltfm
+endif
+endif
+endif
+ifeq ($(CONFIG_TLS), openssl)
+OBJS += ../src/crypto/crypto_openssl.o
+OBJS_p += ../src/crypto/crypto_openssl.o
+HOBJS += ../src/crypto/crypto_openssl.o
+CONFIG_INTERNAL_SHA256=y
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+OBJS += ../src/crypto/crypto_gnutls.o
+OBJS_p += ../src/crypto/crypto_gnutls.o
+HOBJS += ../src/crypto/crypto_gnutls.o
+CONFIG_INTERNAL_SHA256=y
+endif
+ifeq ($(CONFIG_TLS), internal)
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS += ../src/crypto/crypto_libtomcrypt.o
+OBJS_p += ../src/crypto/crypto_libtomcrypt.o
+CONFIG_INTERNAL_SHA256=y
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+OBJS += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o
+OBJS_p += ../src/crypto/crypto_internal.o ../src/tls/rsa.o ../src/tls/bignum.o
+CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
+CFLAGS += -DLTM_FAST
+endif
+else
+LIBS += -ltommath
+LIBS_p += -ltommath
+endif
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_DES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+endif
+endif
+else
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+endif
+
+ifdef CONFIG_INTERNAL_AES
+CFLAGS += -DINTERNAL_AES
+endif
+ifdef CONFIG_INTERNAL_SHA1
+CFLAGS += -DINTERNAL_SHA1
+endif
+ifdef CONFIG_INTERNAL_SHA256
+CFLAGS += -DINTERNAL_SHA256
+endif
+ifdef CONFIG_INTERNAL_MD5
+CFLAGS += -DINTERNAL_MD5
+endif
+ifdef CONFIG_INTERNAL_MD4
+CFLAGS += -DINTERNAL_MD4
+endif
+ifdef CONFIG_INTERNAL_DES
+CFLAGS += -DINTERNAL_DES
+endif
+
+ifdef NEED_SHA256
+OBJS += ../src/crypto/sha256.o
+endif
+
+ifdef NEED_DH_GROUPS
+OBJS += ../src/crypto/dh_groups.o
+ifdef NEED_DH_GROUPS_ALL
+CFLAGS += -DALL_DH_GROUPS
+endif
+endif
+
+ifndef NEED_FIPS186_2_PRF
+CFLAGS += -DCONFIG_NO_FIPS186_2_PRF
+endif
+
+ifndef NEED_T_PRF
+CFLAGS += -DCONFIG_NO_T_PRF
+endif
+
+ifndef NEED_TLS_PRF
+CFLAGS += -DCONFIG_NO_TLS_PRF
+endif
+
+ifdef CONFIG_RADIUS_SERVER
+CFLAGS += -DRADIUS_SERVER
+OBJS += ../src/radius/radius_server.o
+endif
+
+ifdef CONFIG_IPV6
+CFLAGS += -DCONFIG_IPV6
+endif
+
+ifdef CONFIG_DRIVER_RADIUS_ACL
+CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
+endif
+
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
+# and vlan interfaces for the vlan feature.
+CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
+endif
+
+ifdef NEED_BASE64
+OBJS += ../src/utils/base64.o
+endif
+
+ifdef CONFIG_NO_STDOUT_DEBUG
+CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
+endif
+
+ifdef CONFIG_NO_AES_EXTRAS
+CFLAGS += -DCONFIG_NO_AES_UNWRAP
+CFLAGS += -DCONFIG_NO_AES_CTR -DCONFIG_NO_AES_OMAC1
+CFLAGS += -DCONFIG_NO_AES_EAX -DCONFIG_NO_AES_CBC
+CFLAGS += -DCONFIG_NO_AES_DECRYPT
+CFLAGS += -DCONFIG_NO_AES_ENCRYPT_BLOCK
+endif
+
+ALL=hostapd hostapd_cli
+
+all: verify_config $(ALL)
+
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+
+%.o: %.c
+ $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+ @$(E) " CC " $<
+
+verify_config:
+ @if [ ! -r .config ]; then \
+ echo 'Building hostapd requires a configuration file'; \
+ echo '(.config). See README for more instructions. You can'; \
+ echo 'run "cp defconfig .config" to create an example'; \
+ echo 'configuration.'; \
+ exit 1; \
+ fi
+
+install: all
+ for i in $(ALL); do cp $$i /usr/local/bin/$$i; done
+
+hostapd: $(OBJS)
+ $(CC) -o hostapd $(OBJS) $(LIBS)
+
+OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
+hostapd_cli: $(OBJS_c)
+ $(CC) -o hostapd_cli $(OBJS_c)
+
+NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o ../src/crypto/sha1.o ../src/crypto/rc4.o ../src/crypto/md5.o
+NOBJS += ../src/crypto/crypto_openssl.o ../src/utils/os_$(CONFIG_OS).o
+ifdef TLS_FUNCS
+LIBS_n += -lcrypto
+endif
+
+nt_password_hash: $(NOBJS)
+ $(CC) -o nt_password_hash $(NOBJS) $(LIBS_n)
+
+hlr_auc_gw: $(HOBJS)
+ $(CC) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
+
+clean:
+ $(MAKE) -C ../src clean
+ rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw
+ rm -f *.d
+
+%.eps: %.fig
+ fig2dev -L eps $*.fig $*.eps
+
+%.png: %.fig
+ fig2dev -L png -m 3 $*.fig | pngtopnm | pnmscale 0.4 | pnmtopng \
+ > $*.png
+
+docs-pics: doc/hostapd.png doc/hostapd.eps
+
+docs: docs-pics
+ (cd ..; doxygen hostapd/doc/doxygen.full; cd hostapd)
+ $(MAKE) -C doc/latex
+ cp doc/latex/refman.pdf hostapd-devel.pdf
+
+docs-fast: docs-pics
+ (cd ..; doxygen hostapd/doc/doxygen.fast; cd hostapd)
+
+clean-docs:
+ rm -rf doc/latex doc/html
+ rm -f doc/hostapd.{eps,png} hostapd-devel.pdf
+
+TEST_SRC_MILENAGE = ../src/hlr_auc_gw/milenage.c ../src/crypto/aes_wrap.c ../src/crypto/aes.c ../src/utils/common.c ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).c
+test-milenage: $(TEST_SRC_MILENAGE)
+ $(CC) -o test-milenage -Wall -Werror $(TEST_SRC_MILENAGE) \
+ -DTEST_MAIN_MILENAGE -I. -DINTERNAL_AES \
+ -I../src/crypto -I../src/utils
+ ./test-milenage
+ rm test-milenage
+
+-include $(OBJS:%.o=%.d)
diff --git a/hostapd/README-WPS b/hostapd/README-WPS
index b46d767..e0e370b 100644
--- a/hostapd/README-WPS
+++ b/hostapd/README-WPS
@@ -165,10 +165,17 @@ Example command to add a PIN (12345670) for an Enrollee:
hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c 12345670
If the UUID-E is not available (e.g., Enrollee waits for the Registrar
-to be selected before connecting), wildcard UUID may be used to allow the PIN to be used once with any UUID:
+to be selected before connecting), wildcard UUID may be used to allow
+the PIN to be used once with any UUID:
hostapd_cli wps_pin any 12345670
+To reduce likelihood of PIN being used with other devices or of
+forgetting an active PIN available for potential attackers, expiration
+time can be set for the new PIN:
+
+hostapd_cli wps_pin any 12345670 300
+
After this, the Enrollee can connect to the AP again and complete WPS
negotiation. At that point, a new, random WPA PSK is generated for the
diff --git a/hostapd/ap.h b/hostapd/ap.h
index 98f8ee7..2c6d7e9 100644
--- a/hostapd/ap.h
+++ b/hostapd/ap.h
@@ -30,7 +30,7 @@
#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
#define WLAN_STA_SHORT_PREAMBLE BIT(7)
#define WLAN_STA_PREAUTH BIT(8)
-#define WLAN_STA_WME BIT(9)
+#define WLAN_STA_WMM BIT(9)
#define WLAN_STA_MFP BIT(10)
#define WLAN_STA_HT BIT(11)
#define WLAN_STA_WPS BIT(12)
diff --git a/hostapd/beacon.c b/hostapd/beacon.c
index 31323e8..1f82d9c 100644
--- a/hostapd/beacon.c
+++ b/hostapd/beacon.c
@@ -298,8 +298,8 @@ void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta);
- /* Wi-Fi Wireless Multimedia Extensions */
- pos = hostapd_eid_wme(hapd, pos);
+ /* Wi-Fi Alliance WMM */
+ pos = hostapd_eid_wmm(hapd, pos);
pos = hostapd_eid_ht_capabilities_info(hapd, pos);
pos = hostapd_eid_ht_operation(hapd, pos);
@@ -395,8 +395,8 @@ void ieee802_11_set_beacon(struct hostapd_data *hapd)
tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
tailpos, NULL);
- /* Wi-Fi Wireless Multimedia Extensions */
- tailpos = hostapd_eid_wme(hapd, tailpos);
+ /* Wi-Fi Alliance WMM */
+ tailpos = hostapd_eid_wmm(hapd, tailpos);
#ifdef CONFIG_IEEE80211N
if (hapd->iconf->ieee80211n) {
diff --git a/hostapd/config.c b/hostapd/config.c
index 6ad14d2..692b1a4 100644
--- a/hostapd/config.c
+++ b/hostapd/config.c
@@ -201,15 +201,15 @@ static struct hostapd_config * hostapd_config_defaults(void)
struct hostapd_config *conf;
struct hostapd_bss_config *bss;
int i;
- const int aCWmin = 15, aCWmax = 1024;
- const struct hostapd_wme_ac_params ac_bk =
+ const int aCWmin = 4, aCWmax = 10;
+ const struct hostapd_wmm_ac_params ac_bk =
{ aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
- const struct hostapd_wme_ac_params ac_be =
+ const struct hostapd_wmm_ac_params ac_be =
{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
- const struct hostapd_wme_ac_params ac_vi = /* video traffic */
- { aCWmin >> 1, aCWmin, 2, 3000 / 32, 1 };
- const struct hostapd_wme_ac_params ac_vo = /* voice traffic */
- { aCWmin >> 2, aCWmin >> 1, 2, 1500 / 32, 1 };
+ const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
+ { aCWmin - 1, aCWmin, 2, 3000 / 32, 1 };
+ const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
+ { aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 1 };
conf = os_zalloc(sizeof(*conf));
bss = os_zalloc(sizeof(*bss));
@@ -251,10 +251,10 @@ static struct hostapd_config * hostapd_config_defaults(void)
for (i = 0; i < NUM_TX_QUEUES; i++)
conf->tx_queue[i].aifs = -1; /* use hw default */
- conf->wme_ac_params[0] = ac_be;
- conf->wme_ac_params[1] = ac_bk;
- conf->wme_ac_params[2] = ac_vi;
- conf->wme_ac_params[3] = ac_vo;
+ conf->wmm_ac_params[0] = ac_be;
+ conf->wmm_ac_params[1] = ac_bk;
+ conf->wmm_ac_params[2] = ac_vi;
+ conf->wmm_ac_params[3] = ac_vo;
#ifdef CONFIG_IEEE80211N
conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED;
@@ -1166,14 +1166,14 @@ static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
}
-static int hostapd_config_wme_ac(struct hostapd_config *conf, char *name,
- char *val)
+static int hostapd_config_wmm_ac(struct hostapd_config *conf, char *name,
+ char *val)
{
int num, v;
char *pos;
- struct hostapd_wme_ac_params *ac;
+ struct hostapd_wmm_ac_params *ac;
- /* skip 'wme_ac_' prefix */
+ /* skip 'wme_ac_' or 'wmm_ac_' prefix */
pos = name + 7;
if (os_strncmp(pos, "be_", 3) == 0) {
num = 0;
@@ -1188,11 +1188,11 @@ static int hostapd_config_wme_ac(struct hostapd_config *conf, char *name,
num = 3;
pos += 3;
} else {
- wpa_printf(MSG_ERROR, "Unknown wme name '%s'", pos);
+ wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
return -1;
}
- ac = &conf->wme_ac_params[num];
+ ac = &conf->wmm_ac_params[num];
if (os_strcmp(pos, "aifs") == 0) {
v = atoi(val);
@@ -1221,7 +1221,7 @@ static int hostapd_config_wme_ac(struct hostapd_config *conf, char *name,
wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
return -1;
}
- ac->txopLimit = v;
+ ac->txop_limit = v;
} else if (os_strcmp(pos, "acm") == 0) {
v = atoi(val);
if (v < 0 || v > 1) {
@@ -1230,7 +1230,7 @@ static int hostapd_config_wme_ac(struct hostapd_config *conf, char *name,
}
ac->admission_control_mandatory = v;
} else {
- wpa_printf(MSG_ERROR, "Unknown wme_ac_ field '%s'", pos);
+ wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
return -1;
}
@@ -1452,13 +1452,13 @@ struct hostapd_config * hostapd_config_read(const char *fname)
} else if (os_strcmp(buf, "bridge") == 0) {
os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
} else if (os_strcmp(buf, "driver") == 0) {
- int i;
+ int j;
/* clear to get error below if setting is invalid */
conf->driver = NULL;
- for (i = 0; hostapd_drivers[i]; i++) {
- if (os_strcmp(pos, hostapd_drivers[i]->name) ==
+ for (j = 0; hostapd_drivers[j]; j++) {
+ if (os_strcmp(pos, hostapd_drivers[j]->name) ==
0) {
- conf->driver = hostapd_drivers[i];
+ conf->driver = hostapd_drivers[j];
break;
}
}
@@ -2070,11 +2070,13 @@ struct hostapd_config * hostapd_config_read(const char *fname)
"queue item", line);
errors++;
}
- } else if (os_strcmp(buf, "wme_enabled") == 0) {
- bss->wme_enabled = atoi(pos);
- } else if (os_strncmp(buf, "wme_ac_", 7) == 0) {
- if (hostapd_config_wme_ac(conf, buf, pos)) {
- wpa_printf(MSG_ERROR, "Line %d: invalid wme "
+ } else if (os_strcmp(buf, "wme_enabled") == 0 ||
+ os_strcmp(buf, "wmm_enabled") == 0) {
+ bss->wmm_enabled = atoi(pos);
+ } else if (os_strncmp(buf, "wme_ac_", 7) == 0 ||
+ os_strncmp(buf, "wmm_ac_", 7) == 0) {
+ if (hostapd_config_wmm_ac(conf, buf, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
"ac item", line);
errors++;
}
@@ -2255,29 +2257,30 @@ struct hostapd_config * hostapd_config_read(const char *fname)
fclose(f);
- if (bss->individual_wep_key_len == 0) {
- /* individual keys are not use; can use key idx0 for broadcast
- * keys */
- bss->broadcast_key_idx_min = 0;
- }
-
- /* Select group cipher based on the enabled pairwise cipher suites */
- pairwise = 0;
- if (bss->wpa & 1)
- pairwise |= bss->wpa_pairwise;
- if (bss->wpa & 2) {
- if (bss->rsn_pairwise == 0)
- bss->rsn_pairwise = bss->wpa_pairwise;
- pairwise |= bss->rsn_pairwise;
- }
- if (pairwise & WPA_CIPHER_TKIP)
- bss->wpa_group = WPA_CIPHER_TKIP;
- else
- bss->wpa_group = WPA_CIPHER_CCMP;
-
for (i = 0; i < conf->num_bss; i++) {
bss = &conf->bss[i];
+ if (bss->individual_wep_key_len == 0) {
+ /* individual keys are not use; can use key idx0 for
+ * broadcast keys */
+ bss->broadcast_key_idx_min = 0;
+ }
+
+ /* Select group cipher based on the enabled pairwise cipher
+ * suites */
+ pairwise = 0;
+ if (bss->wpa & 1)
+ pairwise |= bss->wpa_pairwise;
+ if (bss->wpa & 2) {
+ if (bss->rsn_pairwise == 0)
+ bss->rsn_pairwise = bss->wpa_pairwise;
+ pairwise |= bss->rsn_pairwise;
+ }
+ if (pairwise & WPA_CIPHER_TKIP)
+ bss->wpa_group = WPA_CIPHER_TKIP;
+ else
+ bss->wpa_group = WPA_CIPHER_CCMP;
+
bss->radius->auth_server = bss->radius->auth_servers;
bss->radius->acct_server = bss->radius->acct_servers;
@@ -2476,6 +2479,8 @@ void hostapd_config_free(struct hostapd_config *conf)
for (i = 0; i < conf->num_bss; i++)
hostapd_config_free_bss(&conf->bss[i]);
os_free(conf->bss);
+ os_free(conf->supported_rates);
+ os_free(conf->basic_rates);
os_free(conf);
}
diff --git a/hostapd/config.h b/hostapd/config.h
index a3247f2..ea530d4 100644
--- a/hostapd/config.h
+++ b/hostapd/config.h
@@ -135,11 +135,11 @@ struct hostapd_tx_queue_params {
int configured;
};
-struct hostapd_wme_ac_params {
+struct hostapd_wmm_ac_params {
int cwmin;
int cwmax;
int aifs;
- int txopLimit; /* in units of 32us */
+ int txop_limit; /* in units of 32us */
int admission_control_mandatory;
};
@@ -271,7 +271,7 @@ struct hostapd_bss_config {
int ap_max_inactivity;
int ignore_broadcast_ssid;
- int wme_enabled;
+ int wmm_enabled;
struct hostapd_vlan *vlan, *vlan_tail;
@@ -371,13 +371,13 @@ struct hostapd_config {
struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
/*
- * WME AC parameters, in same order as 802.1D, i.e.
+ * 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_wme_ac_params wme_ac_params[4];
+ struct hostapd_wmm_ac_params wmm_ac_params[4];
enum {
INTERNAL_BRIDGE_DO_NOT_CONTROL = -1,
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index fe63e7c..9dec724 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -18,6 +18,7 @@
#include <sys/un.h>
#include <sys/stat.h>
+#include <stddef.h>
#include "hostapd.h"
#include "eloop.h"
@@ -60,7 +61,8 @@ static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
dst->next = hapd->ctrl_dst;
hapd->ctrl_dst = dst;
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
- (u8 *) from->sun_path, fromlen);
+ (u8 *) from->sun_path,
+ fromlen - offsetof(struct sockaddr_un, sun_path));
return 0;
}
@@ -74,15 +76,18 @@ static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
dst = hapd->ctrl_dst;
while (dst) {
if (fromlen == dst->addrlen &&
- os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) ==
- 0) {
+ os_memcmp(from->sun_path, dst->addr.sun_path,
+ fromlen - offsetof(struct sockaddr_un, sun_path))
+ == 0) {
if (prev == NULL)
hapd->ctrl_dst = dst->next;
else
prev->next = dst->next;
os_free(dst);
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
- (u8 *) from->sun_path, fromlen);
+ (u8 *) from->sun_path,
+ fromlen -
+ offsetof(struct sockaddr_un, sun_path));
return 0;
}
prev = dst;
@@ -104,10 +109,12 @@ static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
dst = hapd->ctrl_dst;
while (dst) {
if (fromlen == dst->addrlen &&
- os_memcmp(from->sun_path, dst->addr.sun_path, fromlen) ==
- 0) {
+ 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);
+ "level", (u8 *) from->sun_path, fromlen -
+ offsetof(struct sockaddr_un, sun_path));
dst->debug_level = atoi(level);
return 0;
}
@@ -246,10 +253,21 @@ static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
{
char *pin = os_strchr(txt, ' ');
+ char *timeout_txt;
+ int timeout;
+
if (pin == NULL)
return -1;
*pin++ = '\0';
- return hostapd_wps_add_pin(hapd, txt, pin);
+
+ timeout_txt = os_strchr(pin, ' ');
+ if (timeout_txt) {
+ *timeout_txt++ = '\0';
+ timeout = atoi(timeout_txt);
+ } else
+ timeout = 0;
+
+ return hostapd_wps_add_pin(hapd, txt, pin, timeout);
}
#endif /* CONFIG_WPS */
@@ -434,14 +452,44 @@ int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
}
os_memset(&addr, 0, sizeof(addr));
+#ifdef __FreeBSD__
+ addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
addr.sun_family = AF_UNIX;
fname = hostapd_ctrl_iface_path(hapd);
if (fname == NULL)
goto fail;
os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
- perror("bind(PF_UNIX)");
- goto fail;
+ wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
+ strerror(errno));
+ if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
+ " allow connections - assuming it was left"
+ "over from forced program termination");
+ if (unlink(fname) < 0) {
+ perror("unlink[ctrl_iface]");
+ wpa_printf(MSG_ERROR, "Could not unlink "
+ "existing ctrl_iface socket '%s'",
+ fname);
+ goto fail;
+ }
+ if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
+ 0) {
+ perror("bind(PF_UNIX)");
+ goto fail;
+ }
+ wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+ "ctrl_iface socket '%s'", fname);
+ } else {
+ wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
+ "be in use - cannot override it");
+ wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+ "not used anymore", fname);
+ os_free(fname);
+ fname = NULL;
+ goto fail;
+ }
}
if (hapd->conf->ctrl_interface_gid_set &&
@@ -536,15 +584,17 @@ static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
next = dst->next;
if (level >= dst->debug_level) {
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
- (u8 *) dst->addr.sun_path, dst->addrlen);
+ (u8 *) dst->addr.sun_path, dst->addrlen -
+ offsetof(struct sockaddr_un, sun_path));
msg.msg_name = &dst->addr;
msg.msg_namelen = dst->addrlen;
if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
- fprintf(stderr, "CTRL_IFACE monitor[%d]: ",
- idx);
- perror("sendmsg");
+ int _errno = errno;
+ wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
+ "%d - %s",
+ idx, errno, strerror(errno));
dst->errors++;
- if (dst->errors > 10) {
+ if (dst->errors > 10 || _errno == ENOENT) {
hostapd_ctrl_iface_detach(
hapd, &dst->addr,
dst->addrlen);
diff --git a/hostapd/doc/.gitignore b/hostapd/doc/.gitignore
deleted file mode 100644
index 987a5e9..0000000
--- a/hostapd/doc/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-html
-latex
-hostapd.eps
-hostapd.png
diff --git a/hostapd/driver_atheros.c b/hostapd/driver_atheros.c
new file mode 100644
index 0000000..558a8bb
--- /dev/null
+++ b/hostapd/driver_atheros.c
@@ -0,0 +1,1457 @@
+/*
+ * hostapd / Driver interaction with Atheros driver
+ * Copyright (c) 2004, Sam Leffler <sam@errno.com>
+ * Copyright (c) 2004, Video54 Technologies
+ * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2009, Atheros Communications
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include "common.h"
+#ifndef _BYTE_ORDER
+#ifdef WORDS_BIGENDIAN
+#define _BYTE_ORDER _BIG_ENDIAN
+#else
+#define _BYTE_ORDER _LITTLE_ENDIAN
+#endif
+#endif /* _BYTE_ORDER */
+
+#include <net80211/ieee80211.h>
+#include <net80211/_ieee80211.h>
+#include <net80211/ieee80211_crypto.h>
+
+/*
+ * Note, the ATH_WPS_IE setting must match with the driver build.. If the
+ * driver does not include this, the IEEE80211_IOCTL_GETWPAIE ioctl will fail.
+ */
+#define ATH_WPS_IE
+#include <net80211/ieee80211_ioctl.h>
+
+#ifdef CONFIG_WPS
+#ifdef IEEE80211_IOCTL_FILTERFRAME
+#include <netpacket/packet.h>
+
+#ifndef ETH_P_80211_RAW
+#define ETH_P_80211_RAW 0x0019
+#endif
+#endif /* IEEE80211_IOCTL_FILTERFRAME */
+#endif /* CONFIG_WPS */
+
+/*
+ * Avoid conflicts with hostapd definitions by undefining couple of defines
+ * from madwifi header files.
+ */
+#undef WPA_OUI_TYPE
+#undef WME_OUI_TYPE
+
+#include "wireless_copy.h"
+
+#include "hostapd.h"
+#include "driver.h"
+#include "eloop.h"
+#include "priv_netlink.h"
+#include "l2_packet/l2_packet.h"
+
+#include "wps_hostapd.h"
+#include "ieee802_11_defs.h"
+
+
+struct madwifi_driver_data {
+ struct hostapd_data *hapd; /* back pointer */
+
+ char iface[IFNAMSIZ + 1];
+ int ifindex;
+ struct l2_packet_data *sock_xmit; /* raw packet xmit socket */
+ struct l2_packet_data *sock_recv; /* raw packet recv socket */
+ int ioctl_sock; /* socket for ioctl() use */
+ int wext_sock; /* socket for wireless events */
+ int we_version;
+ u8 acct_mac[ETH_ALEN];
+ struct hostap_sta_driver_data acct_data;
+
+ struct l2_packet_data *sock_raw; /* raw 802.11 management frames */
+};
+
+static int madwifi_sta_deauth(void *priv, const u8 *addr, int reason_code);
+
+/* hostapd 0.7.x compatibility - START */
+#include "ieee802_1x.h"
+#include "sta_info.h"
+#include "wpa.h"
+#include "radius/radius.h"
+#include "ieee802_11.h"
+#include "accounting.h"
+
+static int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *ie, size_t ielen)
+{
+ struct sta_info *sta;
+ int new_assoc, res;
+
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "associated");
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta) {
+ accounting_sta_stop(hapd, sta);
+ } else {
+ sta = ap_sta_add(hapd, addr);
+ if (sta == NULL)
+ return -1;
+ }
+ sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
+
+ if (hapd->conf->wpa) {
+ if (ie == NULL || ielen == 0) {
+ if (hapd->conf->wps_state) {
+ wpa_printf(MSG_DEBUG, "STA did not include "
+ "WPA/RSN IE in (Re)Association "
+ "Request - possible WPS use");
+ sta->flags |= WLAN_STA_MAYBE_WPS;
+ goto skip_wpa_check;
+ }
+
+ wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
+ return -1;
+ }
+ if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
+ os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
+ sta->flags |= WLAN_STA_WPS;
+ goto skip_wpa_check;
+ }
+
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr);
+ if (sta->wpa_sm == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
+ "machine");
+ return -1;
+ }
+ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ ie, ielen, NULL, 0);
+ if (res != WPA_IE_OK) {
+ wpa_printf(MSG_DEBUG, "WPA/RSN information element "
+ "rejected? (res %u)", res);
+ wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
+ return -1;
+ }
+ } else if (hapd->conf->wps_state) {
+ if (ie && ielen > 4 && ie[0] == 0xdd && ie[1] >= 4 &&
+ os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
+ sta->flags |= WLAN_STA_WPS;
+ } else
+ sta->flags |= WLAN_STA_MAYBE_WPS;
+ }
+skip_wpa_check:
+
+ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
+ sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
+
+ hostapd_new_assoc_sta(hapd, sta, !new_assoc);
+
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+
+ return 0;
+}
+
+
+static void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
+{
+ struct sta_info *sta;
+
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "disassociated");
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "Disassociation notification for "
+ "unknown STA " MACSTR, MAC2STR(addr));
+ return;
+ }
+
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
+ sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+ ap_free_sta(hapd, sta);
+}
+
+
+static void hostapd_eapol_receive(struct hostapd_data *hapd, const u8 *sa,
+ const u8 *buf, size_t len)
+{
+ ieee802_1x_receive(hapd, sa, buf, len);
+}
+
+
+static void hostapd_michael_mic_failure(struct hostapd_data *hapd,
+ const u8 *addr)
+{
+ ieee80211_michael_mic_failure(hapd, addr, 1);
+}
+/* hostapd 0.7.x compatibility - END */
+
+static int
+set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len)
+{
+ struct iwreq iwr;
+ int do_inline = len < IFNAMSIZ;
+
+ /* Certain ioctls must use the non-inlined method */
+ if (op == IEEE80211_IOCTL_SET_APPIEBUF ||
+ op == IEEE80211_IOCTL_FILTERFRAME)
+ do_inline = 0;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ if (do_inline) {
+ /*
+ * Argument data fits inline; put it there.
+ */
+ memcpy(iwr.u.name, data, len);
+ } else {
+ /*
+ * Argument data too big for inline transfer; setup a
+ * parameter block instead; the kernel will transfer
+ * the data for the driver.
+ */
+ iwr.u.data.pointer = data;
+ iwr.u.data.length = len;
+ }
+
+ if (ioctl(drv->ioctl_sock, op, &iwr) < 0) {
+ int first = IEEE80211_IOCTL_SETPARAM;
+ static const char *opnames[] = {
+ "ioctl[IEEE80211_IOCTL_SETPARAM]",
+ "ioctl[IEEE80211_IOCTL_GETPARAM]",
+ "ioctl[IEEE80211_IOCTL_SETKEY]",
+ "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
+ "ioctl[IEEE80211_IOCTL_DELKEY]",
+ "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
+ "ioctl[IEEE80211_IOCTL_SETMLME]",
+ "ioctl[IEEE80211_IOCTL_GETCHANINFO]",
+ "ioctl[IEEE80211_IOCTL_SETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_GETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_ADDMAC]",
+ "ioctl[IEEE80211_IOCTL_DELMAC]",
+ "ioctl[IEEE80211_IOCTL_GETCHANLIST]",
+ "ioctl[IEEE80211_IOCTL_SETCHANLIST]",
+ "ioctl[IEEE80211_IOCTL_KICKMAC]",
+ "ioctl[IEEE80211_IOCTL_CHANSWITCH]",
+ "ioctl[IEEE80211_IOCTL_GETMODE]",
+ "ioctl[IEEE80211_IOCTL_SETMODE]",
+ "ioctl[IEEE80211_IOCTL_GET_APPIEBUF]",
+ "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_FILTERFRAME]",
+ };
+ int idx = op - first;
+ if (first <= op &&
+ idx < (int) (sizeof(opnames) / sizeof(opnames[0])) &&
+ opnames[idx])
+ perror(opnames[idx]);
+ else {
+ perror("ioctl[unknown???]");
+ wpa_printf(MSG_DEBUG, "Failed ioctl: 0x%x", op);
+ }
+ return -1;
+ }
+ return 0;
+}
+
+static int
+set80211param(struct madwifi_driver_data *drv, int op, int arg)
+{
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.mode = op;
+ memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg));
+
+ if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
+ perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
+ wpa_printf(MSG_DEBUG, "%s: Failed to set parameter (op %d "
+ "arg %d)", __func__, op, arg);
+ return -1;
+ }
+ return 0;
+}
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+static const char *
+ether_sprintf(const u8 *addr)
+{
+ static char buf[sizeof(MACSTR)];
+
+ if (addr != NULL)
+ snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+ else
+ snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
+ return buf;
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+/*
+ * Configure WPA parameters.
+ */
+static int
+madwifi_configure_wpa(struct madwifi_driver_data *drv)
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct hostapd_bss_config *conf = hapd->conf;
+ int v;
+
+ switch (conf->wpa_group) {
+ case WPA_CIPHER_CCMP:
+ v = IEEE80211_CIPHER_AES_CCM;
+ break;
+ case WPA_CIPHER_TKIP:
+ v = IEEE80211_CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_WEP104:
+ v = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_CIPHER_WEP40:
+ v = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_CIPHER_NONE:
+ v = IEEE80211_CIPHER_NONE;
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "Unknown group key cipher %u",
+ conf->wpa_group);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v);
+ if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) {
+ printf("Unable to set group key cipher to %u\n", v);
+ return -1;
+ }
+ if (v == IEEE80211_CIPHER_WEP) {
+ /* key length is done only for specific ciphers */
+ v = (conf->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
+ if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) {
+ printf("Unable to set group key length to %u\n", v);
+ return -1;
+ }
+ }
+
+ v = 0;
+ if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
+ v |= 1<<IEEE80211_CIPHER_AES_CCM;
+ if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
+ v |= 1<<IEEE80211_CIPHER_TKIP;
+ if (conf->wpa_pairwise & WPA_CIPHER_NONE)
+ v |= 1<<IEEE80211_CIPHER_NONE;
+ wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
+ if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) {
+ printf("Unable to set pairwise key ciphers to 0x%x\n", v);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
+ __func__, conf->wpa_key_mgmt);
+ if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS, conf->wpa_key_mgmt)) {
+ printf("Unable to set key management algorithms to 0x%x\n",
+ conf->wpa_key_mgmt);
+ return -1;
+ }
+
+ v = 0;
+ if (conf->rsn_preauth)
+ v |= BIT(0);
+ wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
+ __func__, conf->rsn_preauth);
+ if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
+ printf("Unable to set RSN capabilities to 0x%x\n", v);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, conf->wpa);
+ if (set80211param(drv, IEEE80211_PARAM_WPA, conf->wpa)) {
+ printf("Unable to set WPA to %u\n", conf->wpa);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int
+madwifi_set_iface_flags(void *priv, int dev_up)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ifreq ifr;
+
+ wpa_printf(MSG_DEBUG, "%s: dev_up=%d", __func__, dev_up);
+
+ if (drv->ioctl_sock < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ return -1;
+ }
+
+ if (dev_up)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCSIFFLAGS]");
+ return -1;
+ }
+
+ if (dev_up) {
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
+ ifr.ifr_mtu = HOSTAPD_MTU;
+ if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) {
+ perror("ioctl[SIOCSIFMTU]");
+ printf("Setting MTU failed - trying to survive with "
+ "current value\n");
+ }
+ }
+
+ return 0;
+}
+
+static int
+madwifi_set_ieee8021x(const char *ifname, void *priv, int enabled)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct hostapd_data *hapd = drv->hapd;
+ struct hostapd_bss_config *conf = hapd->conf;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+
+ if (!enabled) {
+ /* XXX restore state */
+ return set80211param(priv, IEEE80211_PARAM_AUTHMODE,
+ IEEE80211_AUTH_AUTO);
+ }
+ if (!conf->wpa && !conf->ieee802_1x) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
+ return -1;
+ }
+ if (conf->wpa && madwifi_configure_wpa(drv) != 0) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
+ return -1;
+ }
+ if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
+ (conf->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+madwifi_set_privacy(const char *ifname, void *priv, int enabled)
+{
+ struct madwifi_driver_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+
+ return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled);
+}
+
+static int
+madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
+ __func__, ether_sprintf(addr), authorized);
+
+ if (authorized)
+ mlme.im_op = IEEE80211_MLME_AUTHORIZE;
+ else
+ mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
+ mlme.im_reason = 0;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR,
+ __func__, authorized ? "" : "un", MAC2STR(addr));
+ }
+
+ return ret;
+}
+
+static int
+madwifi_sta_set_flags(void *priv, const u8 *addr, int total_flags,
+ int flags_or, int flags_and)
+{
+ /* For now, only support setting Authorized flag */
+ if (flags_or & WLAN_STA_AUTHORIZED)
+ return madwifi_set_sta_authorized(priv, addr, 1);
+ if (!(flags_and & WLAN_STA_AUTHORIZED))
+ return madwifi_set_sta_authorized(priv, addr, 0);
+ return 0;
+}
+
+static int
+madwifi_del_key(void *priv, const u8 *addr, int key_idx)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_del_key wk;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
+ __func__, ether_sprintf(addr), key_idx);
+
+ memset(&wk, 0, sizeof(wk));
+ if (addr != NULL) {
+ memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE;
+ } else {
+ wk.idk_keyix = key_idx;
+ }
+
+ ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s"
+ " key_idx %d)", __func__, ether_sprintf(addr),
+ key_idx);
+ }
+
+ return ret;
+}
+
+static int
+madwifi_set_key(const char *ifname, void *priv, const char *alg,
+ const u8 *addr, int key_idx,
+ const u8 *key, size_t key_len, int txkey)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_key wk;
+ u_int8_t cipher;
+ int ret;
+
+ if (strcmp(alg, "none") == 0)
+ return madwifi_del_key(drv, addr, key_idx);
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%s addr=%s key_idx=%d",
+ __func__, alg, ether_sprintf(addr), key_idx);
+
+ if (strcmp(alg, "WEP") == 0)
+ cipher = IEEE80211_CIPHER_WEP;
+ else if (strcmp(alg, "TKIP") == 0)
+ cipher = IEEE80211_CIPHER_TKIP;
+ else if (strcmp(alg, "CCMP") == 0)
+ cipher = IEEE80211_CIPHER_AES_CCM;
+ else {
+ printf("%s: unknown/unsupported algorithm %s\n",
+ __func__, alg);
+ return -1;
+ }
+
+ if (key_len > sizeof(wk.ik_keydata)) {
+ printf("%s: key length %lu too big\n", __func__,
+ (unsigned long) key_len);
+ return -3;
+ }
+
+ memset(&wk, 0, sizeof(wk));
+ wk.ik_type = cipher;
+ wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
+ if (addr == NULL) {
+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = key_idx;
+ wk.ik_flags |= IEEE80211_KEY_DEFAULT;
+ } else {
+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = IEEE80211_KEYIX_NONE;
+ }
+ wk.ik_keylen = key_len;
+ memcpy(wk.ik_keydata, key, key_len);
+
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s"
+ " key_idx %d alg '%s' key_len %lu txkey %d)",
+ __func__, ether_sprintf(wk.ik_macaddr), key_idx,
+ alg, (unsigned long) key_len, txkey);
+ }
+
+ return ret;
+}
+
+
+static int
+madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
+ u8 *seq)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_key wk;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
+ __func__, ether_sprintf(addr), idx);
+
+ memset(&wk, 0, sizeof(wk));
+ if (addr == NULL)
+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+ else
+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = idx;
+
+ if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data "
+ "(addr " MACSTR " key_idx %d)",
+ __func__, MAC2STR(wk.ik_macaddr), idx);
+ return -1;
+ }
+
+#ifdef WORDS_BIGENDIAN
+ {
+ /*
+ * wk.ik_keytsc is in host byte order (big endian), need to
+ * swap it to match with the byte order used in WPA.
+ */
+ int i;
+ u8 tmp[WPA_KEY_RSC_LEN];
+ memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+ for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
+ seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
+ }
+ }
+#else /* WORDS_BIGENDIAN */
+ memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+#endif /* WORDS_BIGENDIAN */
+ return 0;
+}
+
+
+static int
+madwifi_flush(void *priv)
+{
+ u8 allsta[IEEE80211_ADDR_LEN];
+ memset(allsta, 0xff, IEEE80211_ADDR_LEN);
+ return madwifi_sta_deauth(priv, allsta, IEEE80211_REASON_AUTH_LEAVE);
+}
+
+
+static int
+madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_sta_stats stats;
+
+ memset(data, 0, sizeof(*data));
+
+ /*
+ * Fetch statistics for station from the system.
+ */
+ memset(&stats, 0, sizeof(stats));
+ memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
+ if (set80211priv(drv, IEEE80211_IOCTL_STA_STATS,
+ &stats, sizeof(stats))) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr "
+ MACSTR ")", __func__, MAC2STR(addr));
+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
+ memcpy(data, &drv->acct_data, sizeof(*data));
+ return 0;
+ }
+
+ printf("Failed to get station stats information element.\n");
+ return -1;
+ }
+
+ data->rx_packets = stats.is_stats.ns_rx_data;
+ data->rx_bytes = stats.is_stats.ns_rx_bytes;
+ data->tx_packets = stats.is_stats.ns_tx_data;
+ data->tx_bytes = stats.is_stats.ns_tx_bytes;
+ return 0;
+}
+
+
+static int
+madwifi_sta_clear_stats(void *priv, const u8 *addr)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr));
+
+ mlme.im_op = IEEE80211_MLME_CLEAR_STATS;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
+ sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr "
+ MACSTR ")", __func__, MAC2STR(addr));
+ }
+
+ return ret;
+}
+
+
+static int
+madwifi_set_opt_ie(const char *ifname, void *priv, const u8 *ie, size_t ie_len)
+{
+ /*
+ * Do nothing; we setup parameters at startup that define the
+ * contents of the beacon information element.
+ */
+ return 0;
+}
+
+static int
+madwifi_sta_deauth(void *priv, const u8 *addr, int reason_code)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+ __func__, ether_sprintf(addr), reason_code);
+
+ mlme.im_op = IEEE80211_MLME_DEAUTH;
+ mlme.im_reason = reason_code;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR
+ " reason %d)",
+ __func__, MAC2STR(addr), reason_code);
+ }
+
+ return ret;
+}
+
+static int
+madwifi_sta_disassoc(void *priv, const u8 *addr, int reason_code)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+ __func__, ether_sprintf(addr), reason_code);
+
+ mlme.im_op = IEEE80211_MLME_DISASSOC;
+ mlme.im_reason = reason_code;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr "
+ MACSTR " reason %d)",
+ __func__, MAC2STR(addr), reason_code);
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_WPS
+static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+ struct madwifi_driver_data *drv = ctx;
+ const struct ieee80211_mgmt *mgmt;
+ const u8 *end, *ie;
+ u16 fc;
+ size_t ie_len;
+
+ /* Send Probe Request information to WPS processing */
+
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+ return;
+ mgmt = (const struct ieee80211_mgmt *) buf;
+
+ fc = le_to_host16(mgmt->frame_control);
+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
+ WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ)
+ return;
+
+ end = buf + len;
+ ie = mgmt->u.probe_req.variable;
+ ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+
+ hostapd_wps_probe_req_rx(drv->hapd, mgmt->sa, ie, ie_len);
+}
+#endif /* CONFIG_WPS */
+
+static int madwifi_receive_probe_req(struct madwifi_driver_data *drv)
+{
+ int ret = 0;
+#ifdef CONFIG_WPS
+ struct ieee80211req_set_filter filt;
+
+ wpa_printf(MSG_DEBUG, "%s Enter", __func__);
+ filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ;
+
+ ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
+ sizeof(struct ieee80211req_set_filter));
+ if (ret)
+ return ret;
+
+ drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW,
+ madwifi_raw_receive, drv, 1);
+ if (drv->sock_raw == NULL)
+ return -1;
+#endif /* CONFIG_WPS */
+ return ret;
+}
+
+#ifdef CONFIG_WPS
+static int
+madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
+{
+ struct madwifi_driver_data *drv = priv;
+ u8 buf[256];
+ struct ieee80211req_getset_appiebuf *beac_ie;
+
+ wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
+ (unsigned long) len);
+
+ beac_ie = (struct ieee80211req_getset_appiebuf *) buf;
+ beac_ie->app_frmtype = frametype;
+ beac_ie->app_buflen = len;
+ memcpy(&(beac_ie->app_buf[0]), ie, len);
+
+ return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie,
+ sizeof(struct ieee80211req_getset_appiebuf) + len);
+}
+
+static int
+madwifi_set_wps_beacon_ie(const char *ifname, void *priv, const u8 *ie,
+ size_t len)
+{
+ return madwifi_set_wps_ie(priv, ie, len, IEEE80211_APPIE_FRAME_BEACON);
+}
+
+static int
+madwifi_set_wps_probe_resp_ie(const char *ifname, void *priv, const u8 *ie,
+ size_t len)
+{
+ return madwifi_set_wps_ie(priv, ie, len,
+ IEEE80211_APPIE_FRAME_PROBE_RESP);
+}
+#else /* CONFIG_WPS */
+#define madwifi_set_wps_beacon_ie NULL
+#define madwifi_set_wps_probe_resp_ie NULL
+#endif /* CONFIG_WPS */
+
+static int
+madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct ieee80211req_wpaie ie;
+ int ielen = 0, res;
+ u8 *iebuf = NULL;
+
+ /*
+ * Fetch negotiated WPA/RSN parameters from the system.
+ */
+ memset(&ie, 0, sizeof(ie));
+ memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
+ if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) {
+ /*
+ * See ATH_WPS_IE comment in the beginning of the file for a
+ * possible cause for the failure..
+ */
+ wpa_printf(MSG_DEBUG, "%s: Failed to get WPA/RSN IE: %s",
+ __func__, strerror(errno));
+ goto no_ie;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE",
+ ie.wpa_ie, IEEE80211_MAX_OPT_IE);
+ wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE",
+ ie.rsn_ie, IEEE80211_MAX_OPT_IE);
+ iebuf = ie.wpa_ie;
+ /* madwifi seems to return some random data if WPA/RSN IE is not set.
+ * Assume the IE was not included if the IE type is unknown. */
+ if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC)
+ iebuf[1] = 0;
+ if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) {
+ /* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not
+ * set. This is needed for WPA2. */
+ iebuf = ie.rsn_ie;
+ if (iebuf[0] != WLAN_EID_RSN)
+ iebuf[1] = 0;
+ }
+
+ ielen = iebuf[1];
+ if (ielen == 0)
+ iebuf = NULL;
+ else
+ ielen += 2;
+
+no_ie:
+ res = hostapd_notif_assoc(hapd, addr, iebuf, ielen);
+
+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
+ /* Cached accounting data is not valid anymore. */
+ memset(drv->acct_mac, 0, ETH_ALEN);
+ memset(&drv->acct_data, 0, sizeof(drv->acct_data));
+ }
+
+ return res;
+}
+
+static void
+madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv,
+ char *custom, char *end)
+{
+ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
+
+ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ char *pos;
+ u8 addr[ETH_ALEN];
+ pos = strstr(custom, "addr=");
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "without sender address ignored");
+ return;
+ }
+ pos += 5;
+ if (hwaddr_aton(pos, addr) == 0) {
+ hostapd_michael_mic_failure(drv->hapd, addr);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "with invalid MAC address");
+ }
+ } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) {
+ char *key, *value;
+ u32 val;
+ key = custom;
+ while ((key = strchr(key, '\n')) != NULL) {
+ key++;
+ value = strchr(key, '=');
+ if (value == NULL)
+ continue;
+ *value++ = '\0';
+ val = strtoul(value, NULL, 10);
+ if (strcmp(key, "mac") == 0)
+ hwaddr_aton(value, drv->acct_mac);
+ else if (strcmp(key, "rx_packets") == 0)
+ drv->acct_data.rx_packets = val;
+ else if (strcmp(key, "tx_packets") == 0)
+ drv->acct_data.tx_packets = val;
+ else if (strcmp(key, "rx_bytes") == 0)
+ drv->acct_data.rx_bytes = val;
+ else if (strcmp(key, "tx_bytes") == 0)
+ drv->acct_data.tx_bytes = val;
+ key = value;
+ }
+#ifdef CONFIG_WPS
+ } else if (strncmp(custom, "PUSH-BUTTON.indication", 22) == 0) {
+ /* Some atheros kernels send push button as a wireless event */
+ /* PROBLEM! this event is received for ALL BSSs ...
+ * so all are enabled for WPS... ugh.
+ */
+ hostapd_wps_button_pushed(drv->hapd);
+ } else if (strncmp(custom, "Manage.prob_req ", 16) == 0) {
+ /*
+ * Atheros driver uses a hack to pass Probe Request frames as a
+ * binary data in the custom wireless event. The old way (using
+ * packet sniffing) didn't work when bridging.
+ * Format: "Manage.prob_req <frame len>" | zero padding | frame
+ */
+#define WPS_FRAM_TAG_SIZE 30 /* hardcoded in driver */
+ int len = atoi(custom + 16);
+ if (len < 0 || custom + WPS_FRAM_TAG_SIZE + len > end) {
+ wpa_printf(MSG_DEBUG, "Invalid Manage.prob_req event "
+ "length %d", len);
+ return;
+ }
+ madwifi_raw_receive(drv, NULL,
+ (u8 *) custom + WPS_FRAM_TAG_SIZE, len);
+#endif /* CONFIG_WPS */
+ }
+}
+
+static void
+madwifi_wireless_event_wireless(struct madwifi_driver_data *drv,
+ char *data, int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf;
+
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d",
+ iwe->cmd, iwe->len);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ return;
+
+ custom = pos + IW_EV_POINT_LEN;
+ if (drv->we_version > 18 &&
+ (iwe->cmd == IWEVMICHAELMICFAILURE ||
+ iwe->cmd == IWEVASSOCREQIE ||
+ iwe->cmd == IWEVCUSTOM)) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case IWEVEXPIRED:
+ hostapd_notif_disassoc(drv->hapd,
+ (u8 *) iwe->u.addr.sa_data);
+ break;
+ case IWEVREGISTERED:
+ madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data);
+ break;
+ case IWEVASSOCREQIE:
+ /* Driver hack.. Use IWEVASSOCREQIE to bypass
+ * IWEVCUSTOM size limitations. Need to handle this
+ * just like IWEVCUSTOM.
+ */
+ case IWEVCUSTOM:
+ if (custom + iwe->u.data.length > end)
+ return;
+ buf = malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return; /* XXX */
+ memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+ madwifi_wireless_event_wireless_custom(
+ drv, buf, buf + iwe->u.data.length);
+ free(buf);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+
+static void
+madwifi_wireless_event_rtm_newlink(struct madwifi_driver_data *drv,
+ struct nlmsghdr *h, int len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ if (len < (int) sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ if (ifi->ifi_index != drv->ifindex)
+ return;
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ madwifi_wireless_event_wireless(
+ drv, ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void
+madwifi_wireless_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ char buf[256];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ struct madwifi_driver_data *drv = eloop_ctx;
+
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("recvfrom(netlink)");
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (left >= (int) sizeof(*h)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ printf("Malformed netlink message: "
+ "len=%d left=%d plen=%d\n",
+ len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ madwifi_wireless_event_rtm_newlink(drv, h, plen);
+ break;
+ }
+
+ len = NLMSG_ALIGN(len);
+ left -= len;
+ h = (struct nlmsghdr *) ((char *) h + len);
+ }
+
+ if (left > 0) {
+ printf("%d extra bytes in the end of netlink message\n", left);
+ }
+}
+
+
+static int
+madwifi_get_we_version(struct madwifi_driver_data *drv)
+{
+ struct iw_range *range;
+ struct iwreq iwr;
+ int minlen;
+ size_t buflen;
+
+ drv->we_version = 0;
+
+ /*
+ * Use larger buffer than struct iw_range in order to allow the
+ * structure to grow in the future.
+ */
+ buflen = sizeof(struct iw_range) + 500;
+ range = os_zalloc(buflen);
+ if (range == NULL)
+ return -1;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buflen;
+
+ minlen = ((char *) &range->enc_capa) - (char *) range +
+ sizeof(range->enc_capa);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWRANGE]");
+ free(range);
+ return -1;
+ } else if (iwr.u.data.length >= minlen &&
+ range->we_version_compiled >= 18) {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+ "WE(source)=%d enc_capa=0x%x",
+ range->we_version_compiled,
+ range->we_version_source,
+ range->enc_capa);
+ drv->we_version = range->we_version_compiled;
+ }
+
+ free(range);
+ return 0;
+}
+
+
+static int
+madwifi_wireless_event_init(void *priv)
+{
+ struct madwifi_driver_data *drv = priv;
+ int s;
+ struct sockaddr_nl local;
+
+ madwifi_get_we_version(drv);
+
+ drv->wext_sock = -1;
+
+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (s < 0) {
+ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+ return -1;
+ }
+
+ memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ perror("bind(netlink)");
+ close(s);
+ return -1;
+ }
+
+ eloop_register_read_sock(s, madwifi_wireless_event_receive, drv, NULL);
+ drv->wext_sock = s;
+
+ return 0;
+}
+
+
+static void
+madwifi_wireless_event_deinit(void *priv)
+{
+ struct madwifi_driver_data *drv = priv;
+
+ if (drv != NULL) {
+ if (drv->wext_sock < 0)
+ return;
+ eloop_unregister_read_sock(drv->wext_sock);
+ close(drv->wext_sock);
+ }
+}
+
+
+static int
+madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
+ int encrypt, const u8 *own_addr)
+{
+ struct madwifi_driver_data *drv = priv;
+ unsigned char buf[3000];
+ unsigned char *bp = buf;
+ struct l2_ethhdr *eth;
+ size_t len;
+ int status;
+
+ /*
+ * Prepend the Ethernet header. If the caller left us
+ * space at the front we could just insert it but since
+ * we don't know we copy to a local buffer. Given the frequency
+ * and size of frames this probably doesn't matter.
+ */
+ len = data_len + sizeof(struct l2_ethhdr);
+ if (len > sizeof(buf)) {
+ bp = malloc(len);
+ if (bp == NULL) {
+ printf("EAPOL frame discarded, cannot malloc temp "
+ "buffer of size %lu!\n", (unsigned long) len);
+ return -1;
+ }
+ }
+ eth = (struct l2_ethhdr *) bp;
+ memcpy(eth->h_dest, addr, ETH_ALEN);
+ memcpy(eth->h_source, own_addr, ETH_ALEN);
+ eth->h_proto = host_to_be16(ETH_P_EAPOL);
+ memcpy(eth+1, data, data_len);
+
+ wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len);
+
+ status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len);
+
+ if (bp != buf)
+ free(bp);
+ return status;
+}
+
+static void
+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+{
+ struct madwifi_driver_data *drv = ctx;
+ hostapd_eapol_receive(drv->hapd, src_addr,
+ buf + sizeof(struct l2_ethhdr),
+ len - sizeof(struct l2_ethhdr));
+}
+
+static void *
+madwifi_init(struct hostapd_data *hapd)
+{
+ struct madwifi_driver_data *drv;
+ struct ifreq ifr;
+ struct iwreq iwr;
+
+ drv = os_zalloc(sizeof(struct madwifi_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for madwifi driver data\n");
+ return NULL;
+ }
+
+ drv->hapd = hapd;
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket[PF_INET,SOCK_DGRAM]");
+ goto bad;
+ }
+ memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface));
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
+ if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
+ perror("ioctl(SIOCGIFINDEX)");
+ goto bad;
+ }
+ drv->ifindex = ifr.ifr_ifindex;
+
+ drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
+ handle_read, drv, 1);
+ if (drv->sock_xmit == NULL)
+ goto bad;
+ if (l2_packet_get_own_addr(drv->sock_xmit, hapd->own_addr))
+ goto bad;
+ if (hapd->conf->bridge[0] != '\0') {
+ wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.",
+ hapd->conf->bridge);
+ drv->sock_recv = l2_packet_init(hapd->conf->bridge, NULL,
+ ETH_P_EAPOL, handle_read, drv,
+ 1);
+ if (drv->sock_recv == NULL)
+ goto bad;
+ } else
+ drv->sock_recv = drv->sock_xmit;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+
+ iwr.u.mode = IW_MODE_MASTER;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWMODE]");
+ printf("Could not set interface to master mode!\n");
+ goto bad;
+ }
+
+ madwifi_set_iface_flags(drv, 0); /* mark down during setup */
+ madwifi_set_privacy(drv->iface, drv, 0); /* default to no privacy */
+
+ madwifi_receive_probe_req(drv);
+
+ return drv;
+bad:
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+ if (drv != NULL)
+ free(drv);
+ return NULL;
+}
+
+
+static void
+madwifi_deinit(void *priv)
+{
+ struct madwifi_driver_data *drv = priv;
+
+ (void) madwifi_set_iface_flags(drv, 0);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+ if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
+ l2_packet_deinit(drv->sock_recv);
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
+ if (drv->sock_raw)
+ l2_packet_deinit(drv->sock_raw);
+ free(drv);
+}
+
+static int
+madwifi_set_ssid(const char *ifname, void *priv, const u8 *buf, int len)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.essid.flags = 1; /* SSID active */
+ iwr.u.essid.pointer = (caddr_t) buf;
+ iwr.u.essid.length = len + 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCSIWESSID]");
+ printf("len=%d\n", len);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+madwifi_get_ssid(const char *ifname, void *priv, u8 *buf, int len)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.essid.pointer = (caddr_t) buf;
+ iwr.u.essid.length = len;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCGIWESSID]");
+ ret = -1;
+ } else
+ ret = iwr.u.essid.length;
+
+ return ret;
+}
+
+static int
+madwifi_set_countermeasures(void *priv, int enabled)
+{
+ struct madwifi_driver_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled);
+}
+
+static int
+madwifi_commit(void *priv)
+{
+ return madwifi_set_iface_flags(priv, 1);
+}
+
+const struct wpa_driver_ops wpa_driver_atheros_ops = {
+ .name = "atheros",
+ .init = madwifi_init,
+ .deinit = madwifi_deinit,
+ .set_ieee8021x = madwifi_set_ieee8021x,
+ .set_privacy = madwifi_set_privacy,
+ .set_encryption = madwifi_set_key,
+ .get_seqnum = madwifi_get_seqnum,
+ .flush = madwifi_flush,
+ .set_generic_elem = madwifi_set_opt_ie,
+ .wireless_event_init = madwifi_wireless_event_init,
+ .wireless_event_deinit = madwifi_wireless_event_deinit,
+ .sta_set_flags = madwifi_sta_set_flags,
+ .read_sta_data = madwifi_read_sta_driver_data,
+ .send_eapol = madwifi_send_eapol,
+ .sta_disassoc = madwifi_sta_disassoc,
+ .sta_deauth = madwifi_sta_deauth,
+ .set_ssid = madwifi_set_ssid,
+ .get_ssid = madwifi_get_ssid,
+ .set_countermeasures = madwifi_set_countermeasures,
+ .sta_clear_stats = madwifi_sta_clear_stats,
+ .commit = madwifi_commit,
+ .set_wps_beacon_ie = madwifi_set_wps_beacon_ie,
+ .set_wps_probe_resp_ie = madwifi_set_wps_probe_resp_ie,
+};
diff --git a/hostapd/driver_bsd.c b/hostapd/driver_bsd.c
new file mode 100644
index 0000000..43d57d9
--- /dev/null
+++ b/hostapd/driver_bsd.c
@@ -0,0 +1,839 @@
+/*
+ * hostapd / Driver interaction with BSD net80211 layer
+ * Copyright (c) 2004, Sam Leffler <sam@errno.com>
+ * Copyright (c) 2004, 2Wire, Inc
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include <net/if.h>
+
+#include <net80211/ieee80211.h>
+#include <net80211/ieee80211_crypto.h>
+#include <net80211/ieee80211_ioctl.h>
+
+/*
+ * Avoid conflicts with hostapd definitions by undefining couple of defines
+ * from net80211 header files.
+ */
+#undef RSN_VERSION
+#undef WPA_VERSION
+#undef WPA_OUI_TYPE
+#undef WME_OUI_TYPE
+
+#include "hostapd.h"
+#include "driver.h"
+#include "ieee802_1x.h"
+#include "eloop.h"
+#include "sta_info.h"
+#include "l2_packet/l2_packet.h"
+
+#include "eapol_sm.h"
+#include "wpa.h"
+#include "radius/radius.h"
+#include "ieee802_11.h"
+#include "common.h"
+
+struct bsd_driver_data {
+ struct hostapd_data *hapd; /* back pointer */
+
+ char iface[IFNAMSIZ + 1];
+ struct l2_packet_data *sock_xmit; /* raw packet xmit socket */
+ int ioctl_sock; /* socket for ioctl() use */
+ int wext_sock; /* socket for wireless events */
+};
+
+static int bsd_sta_deauth(void *priv, const u8 *addr, int reason_code);
+
+static int
+set80211var(struct bsd_driver_data *drv, int op, const void *arg, int arg_len)
+{
+ struct ieee80211req ireq;
+
+ memset(&ireq, 0, sizeof(ireq));
+ os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ);
+ ireq.i_type = op;
+ ireq.i_len = arg_len;
+ ireq.i_data = (void *) arg;
+
+ if (ioctl(drv->ioctl_sock, SIOCS80211, &ireq) < 0) {
+ perror("ioctl[SIOCS80211]");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+get80211var(struct bsd_driver_data *drv, int op, void *arg, int arg_len)
+{
+ struct ieee80211req ireq;
+
+ memset(&ireq, 0, sizeof(ireq));
+ os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ);
+ ireq.i_type = op;
+ ireq.i_len = arg_len;
+ ireq.i_data = arg;
+
+ if (ioctl(drv->ioctl_sock, SIOCG80211, &ireq) < 0) {
+ perror("ioctl[SIOCG80211]");
+ return -1;
+ }
+ return ireq.i_len;
+}
+
+static int
+set80211param(struct bsd_driver_data *drv, int op, int arg)
+{
+ struct ieee80211req ireq;
+
+ memset(&ireq, 0, sizeof(ireq));
+ os_strlcpy(ireq.i_name, drv->iface, IFNAMSIZ);
+ ireq.i_type = op;
+ ireq.i_val = arg;
+
+ if (ioctl(drv->ioctl_sock, SIOCS80211, &ireq) < 0) {
+ perror("ioctl[SIOCS80211]");
+ return -1;
+ }
+ return 0;
+}
+
+static const char *
+ether_sprintf(const u8 *addr)
+{
+ static char buf[sizeof(MACSTR)];
+
+ if (addr != NULL)
+ snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+ else
+ snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
+ return buf;
+}
+
+/*
+ * Configure WPA parameters.
+ */
+static int
+bsd_configure_wpa(struct bsd_driver_data *drv)
+{
+ static const char *ciphernames[] =
+ { "WEP", "TKIP", "AES-OCB", "AES-CCM", "CKIP", "NONE" };
+ struct hostapd_data *hapd = drv->hapd;
+ struct hostapd_bss_config *conf = hapd->conf;
+ int v;
+
+ switch (conf->wpa_group) {
+ case WPA_CIPHER_CCMP:
+ v = IEEE80211_CIPHER_AES_CCM;
+ break;
+ case WPA_CIPHER_TKIP:
+ v = IEEE80211_CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_WEP104:
+ v = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_CIPHER_WEP40:
+ v = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_CIPHER_NONE:
+ v = IEEE80211_CIPHER_NONE;
+ break;
+ default:
+ printf("Unknown group key cipher %u\n",
+ conf->wpa_group);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "%s: group key cipher=%s (%u)",
+ __func__, ciphernames[v], v);
+ if (set80211param(drv, IEEE80211_IOC_MCASTCIPHER, v)) {
+ printf("Unable to set group key cipher to %u (%s)\n",
+ v, ciphernames[v]);
+ return -1;
+ }
+ if (v == IEEE80211_CIPHER_WEP) {
+ /* key length is done only for specific ciphers */
+ v = (conf->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
+ if (set80211param(drv, IEEE80211_IOC_MCASTKEYLEN, v)) {
+ printf("Unable to set group key length to %u\n", v);
+ return -1;
+ }
+ }
+
+ v = 0;
+ if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
+ v |= 1<<IEEE80211_CIPHER_AES_CCM;
+ if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
+ v |= 1<<IEEE80211_CIPHER_TKIP;
+ if (conf->wpa_pairwise & WPA_CIPHER_NONE)
+ v |= 1<<IEEE80211_CIPHER_NONE;
+ wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
+ if (set80211param(drv, IEEE80211_IOC_UCASTCIPHERS, v)) {
+ printf("Unable to set pairwise key ciphers to 0x%x\n", v);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
+ __func__, conf->wpa_key_mgmt);
+ if (set80211param(drv, IEEE80211_IOC_KEYMGTALGS, conf->wpa_key_mgmt)) {
+ printf("Unable to set key management algorithms to 0x%x\n",
+ conf->wpa_key_mgmt);
+ return -1;
+ }
+
+ v = 0;
+ if (conf->rsn_preauth)
+ v |= BIT(0);
+ wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
+ __func__, conf->rsn_preauth);
+ if (set80211param(drv, IEEE80211_IOC_RSNCAPS, v)) {
+ printf("Unable to set RSN capabilities to 0x%x\n", v);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: enable WPA= 0x%x", __func__, conf->wpa);
+ if (set80211param(drv, IEEE80211_IOC_WPA, conf->wpa)) {
+ printf("Unable to set WPA to %u\n", conf->wpa);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int
+bsd_set_iface_flags(void *priv, int dev_up)
+{
+ struct bsd_driver_data *drv = priv;
+ struct ifreq ifr;
+
+ wpa_printf(MSG_DEBUG, "%s: dev_up=%d", __func__, dev_up);
+
+ if (drv->ioctl_sock < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ return -1;
+ }
+
+ if (dev_up)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCSIFFLAGS]");
+ return -1;
+ }
+
+ if (dev_up) {
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
+ ifr.ifr_mtu = HOSTAPD_MTU;
+ if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) {
+ perror("ioctl[SIOCSIFMTU]");
+ printf("Setting MTU failed - trying to survive with "
+ "current value\n");
+ }
+ }
+
+ return 0;
+}
+
+static int
+bsd_set_ieee8021x(const char *ifname, void *priv, int enabled)
+{
+ struct bsd_driver_data *drv = priv;
+ struct hostapd_data *hapd = drv->hapd;
+ struct hostapd_bss_config *conf = hapd->conf;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+
+ if (!enabled) {
+ /* XXX restore state */
+ return set80211param(priv, IEEE80211_IOC_AUTHMODE,
+ IEEE80211_AUTH_AUTO);
+ }
+ if (!conf->wpa && !conf->ieee802_1x) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
+ return -1;
+ }
+ if (conf->wpa && bsd_configure_wpa(drv) != 0) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
+ return -1;
+ }
+ if (set80211param(priv, IEEE80211_IOC_AUTHMODE,
+ (conf->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
+ return -1;
+ }
+ return bsd_set_iface_flags(priv, 1);
+}
+
+static int
+bsd_set_privacy(const char *ifname, void *priv, int enabled)
+{
+ struct bsd_driver_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+
+ return set80211param(drv, IEEE80211_IOC_PRIVACY, enabled);
+}
+
+static int
+bsd_set_sta_authorized(void *priv, const u8 *addr, int authorized)
+{
+ struct bsd_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
+ __func__, ether_sprintf(addr), authorized);
+
+ if (authorized)
+ mlme.im_op = IEEE80211_MLME_AUTHORIZE;
+ else
+ mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
+ mlme.im_reason = 0;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
+}
+
+static int
+bsd_sta_set_flags(void *priv, const u8 *addr, int total_flags, int flags_or,
+ int flags_and)
+{
+ /* For now, only support setting Authorized flag */
+ if (flags_or & WLAN_STA_AUTHORIZED)
+ return bsd_set_sta_authorized(priv, addr, 1);
+ if (!(flags_and & WLAN_STA_AUTHORIZED))
+ return bsd_set_sta_authorized(priv, addr, 0);
+ return 0;
+}
+
+static int
+bsd_del_key(void *priv, const u8 *addr, int key_idx)
+{
+ struct bsd_driver_data *drv = priv;
+ struct ieee80211req_del_key wk;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
+ __func__, ether_sprintf(addr), key_idx);
+
+ memset(&wk, 0, sizeof(wk));
+ if (addr != NULL) {
+ memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.idk_keyix = (u_int8_t) IEEE80211_KEYIX_NONE; /* XXX */
+ } else {
+ wk.idk_keyix = key_idx;
+ }
+
+ return set80211var(drv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
+}
+
+static int
+bsd_set_key(const char *ifname, void *priv, const char *alg,
+ const u8 *addr, int key_idx,
+ const u8 *key, size_t key_len, int txkey)
+{
+ struct bsd_driver_data *drv = priv;
+ struct ieee80211req_key wk;
+ u_int8_t cipher;
+
+ if (strcmp(alg, "none") == 0)
+ return bsd_del_key(drv, addr, key_idx);
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%s addr=%s key_idx=%d",
+ __func__, alg, ether_sprintf(addr), key_idx);
+
+ if (strcmp(alg, "WEP") == 0)
+ cipher = IEEE80211_CIPHER_WEP;
+ else if (strcmp(alg, "TKIP") == 0)
+ cipher = IEEE80211_CIPHER_TKIP;
+ else if (strcmp(alg, "CCMP") == 0)
+ cipher = IEEE80211_CIPHER_AES_CCM;
+ else {
+ printf("%s: unknown/unsupported algorithm %s\n",
+ __func__, alg);
+ return -1;
+ }
+
+ if (key_len > sizeof(wk.ik_keydata)) {
+ printf("%s: key length %d too big\n", __func__, key_len);
+ return -3;
+ }
+
+ memset(&wk, 0, sizeof(wk));
+ wk.ik_type = cipher;
+ wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
+ if (addr == NULL) {
+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = key_idx;
+ wk.ik_flags |= IEEE80211_KEY_DEFAULT;
+ } else {
+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = IEEE80211_KEYIX_NONE;
+ }
+ wk.ik_keylen = key_len;
+ memcpy(wk.ik_keydata, key, key_len);
+
+ return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
+}
+
+
+static int
+bsd_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
+ u8 *seq)
+{
+ struct bsd_driver_data *drv = priv;
+ struct ieee80211req_key wk;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
+ __func__, ether_sprintf(addr), idx);
+
+ memset(&wk, 0, sizeof(wk));
+ if (addr == NULL)
+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+ else
+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = idx;
+
+ if (get80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk)) < 0) {
+ printf("Failed to get encryption.\n");
+ return -1;
+ }
+
+#ifdef WORDS_BIGENDIAN
+ {
+ /*
+ * wk.ik_keytsc is in host byte order (big endian), need to
+ * swap it to match with the byte order used in WPA.
+ */
+ int i;
+ u8 tmp[WPA_KEY_RSC_LEN];
+ memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+ for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
+ seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
+ }
+ }
+#else /* WORDS_BIGENDIAN */
+ memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+#endif /* WORDS_BIGENDIAN */
+ return 0;
+}
+
+
+static int
+bsd_flush(void *priv)
+{
+ u8 allsta[IEEE80211_ADDR_LEN];
+
+ memset(allsta, 0xff, IEEE80211_ADDR_LEN);
+ return bsd_sta_deauth(priv, allsta, IEEE80211_REASON_AUTH_LEAVE);
+}
+
+
+static int
+bsd_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct bsd_driver_data *drv = priv;
+ struct ieee80211req_sta_stats stats;
+
+ memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
+ if (get80211var(drv, IEEE80211_IOC_STA_STATS, &stats, sizeof(stats)) > 0) {
+ /* XXX? do packets counts include non-data frames? */
+ data->rx_packets = stats.is_stats.ns_rx_data;
+ data->rx_bytes = stats.is_stats.ns_rx_bytes;
+ data->tx_packets = stats.is_stats.ns_tx_data;
+ data->tx_bytes = stats.is_stats.ns_tx_bytes;
+ }
+ return 0;
+}
+
+static int
+bsd_set_opt_ie(const char *ifname, void *priv, const u8 *ie, size_t ie_len)
+{
+ /*
+ * Do nothing; we setup parameters at startup that define the
+ * contents of the beacon information element.
+ */
+ return 0;
+}
+
+static int
+bsd_sta_deauth(void *priv, const u8 *addr, int reason_code)
+{
+ struct bsd_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+ __func__, ether_sprintf(addr), reason_code);
+
+ mlme.im_op = IEEE80211_MLME_DEAUTH;
+ mlme.im_reason = reason_code;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
+}
+
+static int
+bsd_sta_disassoc(void *priv, const u8 *addr, int reason_code)
+{
+ struct bsd_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+ __func__, ether_sprintf(addr), reason_code);
+
+ mlme.im_op = IEEE80211_MLME_DISASSOC;
+ mlme.im_reason = reason_code;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
+}
+
+static int
+bsd_del_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct hostapd_bss_config *conf = hapd->conf;
+ struct sta_info *sta;
+
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "deassociated");
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta != NULL) {
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ if (conf->wpa)
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
+ sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+ ap_free_sta(hapd, sta);
+ }
+ return 0;
+}
+
+static int
+bsd_new_sta(struct bsd_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct hostapd_bss_config *conf = hapd->conf;
+ struct sta_info *sta;
+ struct ieee80211req_wpaie ie;
+ int new_assoc, ielen, res;
+
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "associated");
+
+ sta = ap_sta_add(hapd, addr);
+ if (sta == NULL)
+ return -1;
+ /*
+ * Fetch and validate any negotiated WPA/RSN parameters.
+ */
+ if (conf->wpa) {
+ memset(&ie, 0, sizeof(ie));
+ memcpy(ie.wpa_macaddr, addr, IEEE80211_ADDR_LEN);
+ if (get80211var(drv, IEEE80211_IOC_WPAIE, &ie, sizeof(ie)) < 0) {
+ printf("Failed to get WPA/RSN information element.\n");
+ return -1; /* XXX not right */
+ }
+ ielen = ie.wpa_ie[1];
+ if (ielen == 0) {
+ printf("No WPA/RSN information element for station!\n");
+ return -1; /* XXX not right */
+ }
+ ielen += 2;
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr);
+ if (sta->wpa_sm == NULL) {
+ printf("Failed to initialize WPA state machine\n");
+ return -1;
+ }
+ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ ie.wpa_ie, ielen, NULL, 0);
+ if (res != WPA_IE_OK) {
+ printf("WPA/RSN information element rejected? "
+ "(res %u)\n", res);
+ return -1;
+ }
+ }
+
+ /*
+ * Now that the internal station state is setup
+ * kick the authenticator into action.
+ */
+ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
+ sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
+ hostapd_new_assoc_sta(hapd, sta, !new_assoc);
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+ return 0;
+}
+
+#include <net/route.h>
+#include <net80211/ieee80211_freebsd.h>
+
+static void
+bsd_wireless_event_receive(int sock, void *ctx, void *sock_ctx)
+{
+ struct bsd_driver_data *drv = ctx;
+ struct hostapd_data *hapd = drv->hapd;
+ char buf[2048];
+ struct if_announcemsghdr *ifan;
+ struct rt_msghdr *rtm;
+ struct ieee80211_michael_event *mic;
+ struct ieee80211_join_event *join;
+ struct ieee80211_leave_event *leave;
+ int n;
+
+ n = read(sock, buf, sizeof(buf));
+ if (n < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("read(PF_ROUTE)");
+ return;
+ }
+
+ rtm = (struct rt_msghdr *) buf;
+ if (rtm->rtm_version != RTM_VERSION) {
+ wpa_printf(MSG_DEBUG, "Routing message version %d not "
+ "understood\n", rtm->rtm_version);
+ return;
+ }
+ ifan = (struct if_announcemsghdr *) rtm;
+ switch (rtm->rtm_type) {
+ case RTM_IEEE80211:
+ switch (ifan->ifan_what) {
+ case RTM_IEEE80211_ASSOC:
+ case RTM_IEEE80211_REASSOC:
+ case RTM_IEEE80211_DISASSOC:
+ case RTM_IEEE80211_SCAN:
+ break;
+ case RTM_IEEE80211_LEAVE:
+ leave = (struct ieee80211_leave_event *) &ifan[1];
+ bsd_del_sta(drv, leave->iev_addr);
+ break;
+ case RTM_IEEE80211_JOIN:
+#ifdef RTM_IEEE80211_REJOIN
+ case RTM_IEEE80211_REJOIN:
+#endif
+ join = (struct ieee80211_join_event *) &ifan[1];
+ bsd_new_sta(drv, join->iev_addr);
+ break;
+ case RTM_IEEE80211_REPLAY:
+ /* ignore */
+ break;
+ case RTM_IEEE80211_MICHAEL:
+ mic = (struct ieee80211_michael_event *) &ifan[1];
+ wpa_printf(MSG_DEBUG,
+ "Michael MIC failure wireless event: "
+ "keyix=%u src_addr=" MACSTR, mic->iev_keyix,
+ MAC2STR(mic->iev_src));
+ ieee80211_michael_mic_failure(hapd, mic->iev_src, 1);
+ break;
+ }
+ break;
+ }
+}
+
+static int
+bsd_wireless_event_init(void *priv)
+{
+ struct bsd_driver_data *drv = priv;
+ int s;
+
+ drv->wext_sock = -1;
+
+ s = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (s < 0) {
+ perror("socket(PF_ROUTE,SOCK_RAW)");
+ return -1;
+ }
+ eloop_register_read_sock(s, bsd_wireless_event_receive, drv, NULL);
+ drv->wext_sock = s;
+
+ return 0;
+}
+
+static void
+bsd_wireless_event_deinit(void *priv)
+{
+ struct bsd_driver_data *drv = priv;
+
+ if (drv != NULL) {
+ if (drv->wext_sock < 0)
+ return;
+ eloop_unregister_read_sock(drv->wext_sock);
+ close(drv->wext_sock);
+ }
+}
+
+
+static int
+bsd_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
+ int encrypt, const u8 *own_addr)
+{
+ struct bsd_driver_data *drv = priv;
+ unsigned char buf[3000];
+ unsigned char *bp = buf;
+ struct l2_ethhdr *eth;
+ size_t len;
+ int status;
+
+ /*
+ * Prepend the Etherent header. If the caller left us
+ * space at the front we could just insert it but since
+ * we don't know we copy to a local buffer. Given the frequency
+ * and size of frames this probably doesn't matter.
+ */
+ len = data_len + sizeof(struct l2_ethhdr);
+ if (len > sizeof(buf)) {
+ bp = malloc(len);
+ if (bp == NULL) {
+ printf("EAPOL frame discarded, cannot malloc temp "
+ "buffer of size %u!\n", len);
+ return -1;
+ }
+ }
+ eth = (struct l2_ethhdr *) bp;
+ memcpy(eth->h_dest, addr, ETH_ALEN);
+ memcpy(eth->h_source, own_addr, ETH_ALEN);
+ eth->h_proto = htons(ETH_P_EAPOL);
+ memcpy(eth+1, data, data_len);
+
+ wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len);
+
+ status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len);
+
+ if (bp != buf)
+ free(bp);
+ return status;
+}
+
+static void
+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+{
+ struct bsd_driver_data *drv = ctx;
+ struct hostapd_data *hapd = drv->hapd;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, src_addr);
+ if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
+ printf("Data frame from not associated STA %s\n",
+ ether_sprintf(src_addr));
+ /* XXX cannot happen */
+ return;
+ }
+ ieee802_1x_receive(hapd, src_addr, buf + sizeof(struct l2_ethhdr),
+ len - sizeof(struct l2_ethhdr));
+}
+
+static int
+bsd_get_ssid(const char *ifname, void *priv, u8 *buf, int len)
+{
+ struct bsd_driver_data *drv = priv;
+ int ssid_len = get80211var(drv, IEEE80211_IOC_SSID, buf, len);
+
+ wpa_printf(MSG_DEBUG, "%s: ssid=\"%.*s\"", __func__, ssid_len, buf);
+
+ return ssid_len;
+}
+
+static int
+bsd_set_ssid(const char *ifname, void *priv, const u8 *buf, int len)
+{
+ struct bsd_driver_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: ssid=\"%.*s\"", __func__, len, buf);
+
+ return set80211var(drv, IEEE80211_IOC_SSID, buf, len);
+}
+
+static void *
+bsd_init(struct hostapd_data *hapd)
+{
+ struct bsd_driver_data *drv;
+
+ drv = os_zalloc(sizeof(struct bsd_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for bsd driver data\n");
+ goto bad;
+ }
+
+ drv->hapd = hapd;
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket[PF_INET,SOCK_DGRAM]");
+ goto bad;
+ }
+ memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface));
+
+ drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
+ handle_read, drv, 1);
+ if (drv->sock_xmit == NULL)
+ goto bad;
+ if (l2_packet_get_own_addr(drv->sock_xmit, hapd->own_addr))
+ goto bad;
+
+ bsd_set_iface_flags(drv, 0); /* mark down during setup */
+
+ return drv;
+bad:
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+ if (drv != NULL)
+ free(drv);
+ return NULL;
+}
+
+
+static void
+bsd_deinit(void *priv)
+{
+ struct bsd_driver_data *drv = priv;
+
+ (void) bsd_set_iface_flags(drv, 0);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
+ free(drv);
+}
+
+const struct wpa_driver_ops wpa_driver_bsd_ops = {
+ .name = "bsd",
+ .init = bsd_init,
+ .deinit = bsd_deinit,
+ .set_ieee8021x = bsd_set_ieee8021x,
+ .set_privacy = bsd_set_privacy,
+ .set_encryption = bsd_set_key,
+ .get_seqnum = bsd_get_seqnum,
+ .flush = bsd_flush,
+ .set_generic_elem = bsd_set_opt_ie,
+ .wireless_event_init = bsd_wireless_event_init,
+ .wireless_event_deinit = bsd_wireless_event_deinit,
+ .sta_set_flags = bsd_sta_set_flags,
+ .read_sta_data = bsd_read_sta_driver_data,
+ .send_eapol = bsd_send_eapol,
+ .sta_disassoc = bsd_sta_disassoc,
+ .sta_deauth = bsd_sta_deauth,
+ .set_ssid = bsd_set_ssid,
+ .get_ssid = bsd_get_ssid,
+};
diff --git a/hostapd/driver_hostap.c b/hostapd/driver_hostap.c
new file mode 100644
index 0000000..ceff099
--- /dev/null
+++ b/hostapd/driver_hostap.c
@@ -0,0 +1,1279 @@
+/*
+ * hostapd / Kernel driver communication with Linux Host AP driver
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#ifdef USE_KERNEL_HEADERS
+/* compat-wireless does not include linux/compiler.h to define __user, so
+ * define it here */
+#ifndef __user
+#define __user
+#endif /* __user */
+#include <asm/types.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h> /* The L2 protocols */
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#else /* USE_KERNEL_HEADERS */
+#include <net/if_arp.h>
+#include <netpacket/packet.h>
+#include "wireless_copy.h"
+#endif /* USE_KERNEL_HEADERS */
+
+#include "hostapd.h"
+#include "driver.h"
+#include "ieee802_1x.h"
+#include "eloop.h"
+#include "priv_netlink.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "hostap_common.h"
+#include "hw_features.h"
+
+
+struct hostap_driver_data {
+ struct hostapd_data *hapd;
+
+ char iface[IFNAMSIZ + 1];
+ int sock; /* raw packet socket for driver access */
+ int ioctl_sock; /* socket for ioctl() use */
+ int wext_sock; /* socket for wireless events */
+
+ int we_version;
+
+ u8 *generic_ie;
+ size_t generic_ie_len;
+ u8 *wps_ie;
+ size_t wps_ie_len;
+};
+
+
+static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param,
+ int len);
+static int hostap_set_iface_flags(void *priv, int dev_up);
+
+static void handle_data(struct hostapd_data *hapd, u8 *buf, size_t len,
+ u16 stype)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc, ethertype;
+ u8 *pos, *sa;
+ size_t left;
+ struct sta_info *sta;
+
+ if (len < sizeof(struct ieee80211_hdr))
+ return;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+
+ if ((fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) != WLAN_FC_TODS) {
+ printf("Not ToDS data frame (fc=0x%04x)\n", fc);
+ return;
+ }
+
+ sa = hdr->addr2;
+ sta = ap_get_sta(hapd, sa);
+ if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
+ printf("Data frame from not associated STA " MACSTR "\n",
+ MAC2STR(sa));
+ if (sta && (sta->flags & WLAN_STA_AUTH))
+ hostapd_sta_disassoc(
+ hapd, sa,
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+ else
+ hostapd_sta_deauth(
+ hapd, sa,
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+ return;
+ }
+
+ pos = (u8 *) (hdr + 1);
+ left = len - sizeof(*hdr);
+
+ if (left < sizeof(rfc1042_header)) {
+ printf("Too short data frame\n");
+ return;
+ }
+
+ if (memcmp(pos, rfc1042_header, sizeof(rfc1042_header)) != 0) {
+ printf("Data frame with no RFC1042 header\n");
+ return;
+ }
+ pos += sizeof(rfc1042_header);
+ left -= sizeof(rfc1042_header);
+
+ if (left < 2) {
+ printf("No ethertype in data frame\n");
+ return;
+ }
+
+ ethertype = WPA_GET_BE16(pos);
+ pos += 2;
+ left -= 2;
+ switch (ethertype) {
+ case ETH_P_PAE:
+ ieee802_1x_receive(hapd, sa, pos, left);
+ break;
+
+ default:
+ printf("Unknown ethertype 0x%04x in data frame\n", ethertype);
+ break;
+ }
+}
+
+
+static void handle_tx_callback(struct hostapd_data *hapd, u8 *buf, size_t len,
+ int ok)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc, type, stype;
+ struct sta_info *sta;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ switch (type) {
+ case WLAN_FC_TYPE_MGMT:
+ wpa_printf(MSG_DEBUG, "MGMT (TX callback) %s",
+ ok ? "ACK" : "fail");
+ ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
+ break;
+ case WLAN_FC_TYPE_CTRL:
+ wpa_printf(MSG_DEBUG, "CTRL (TX callback) %s",
+ ok ? "ACK" : "fail");
+ break;
+ case WLAN_FC_TYPE_DATA:
+ wpa_printf(MSG_DEBUG, "DATA (TX callback) %s",
+ ok ? "ACK" : "fail");
+ sta = ap_get_sta(hapd, hdr->addr1);
+ if (sta && sta->flags & WLAN_STA_PENDING_POLL) {
+ wpa_printf(MSG_DEBUG, "STA " MACSTR
+ " %s pending activity poll",
+ MAC2STR(sta->addr),
+ ok ? "ACKed" : "did not ACK");
+ if (ok)
+ sta->flags &= ~WLAN_STA_PENDING_POLL;
+ }
+ if (sta)
+ ieee802_1x_tx_status(hapd, sta, buf, len, ok);
+ break;
+ default:
+ printf("unknown TX callback frame type %d\n", type);
+ break;
+ }
+}
+
+
+static void handle_frame(struct hostapd_data *hapd, u8 *buf, size_t len)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc, extra_len, type, stype;
+ unsigned char *extra = NULL;
+ size_t data_len = len;
+ int ver;
+
+ /* PSPOLL is only 16 bytes, but driver does not (at least yet) pass
+ * these to user space */
+ if (len < 24) {
+ wpa_printf(MSG_MSGDUMP, "handle_frame: too short (%lu)",
+ (unsigned long) len);
+ return;
+ }
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ if (type != WLAN_FC_TYPE_MGMT || stype != WLAN_FC_STYPE_BEACON) {
+ wpa_hexdump(MSG_MSGDUMP, "Received management frame",
+ buf, len);
+ }
+
+ ver = fc & WLAN_FC_PVER;
+
+ /* protocol version 3 is reserved for indicating extra data after the
+ * payload, version 2 for indicating ACKed frame (TX callbacks), and
+ * version 1 for indicating failed frame (no ACK, TX callbacks) */
+ if (ver == 3) {
+ u8 *pos = buf + len - 2;
+ extra_len = WPA_GET_LE16(pos);
+ printf("extra data in frame (elen=%d)\n", extra_len);
+ if ((size_t) extra_len + 2 > len) {
+ printf(" extra data overflow\n");
+ return;
+ }
+ len -= extra_len + 2;
+ extra = buf + len;
+ } else if (ver == 1 || ver == 2) {
+ handle_tx_callback(hapd, buf, data_len, ver == 2 ? 1 : 0);
+ return;
+ } else if (ver != 0) {
+ printf("unknown protocol version %d\n", ver);
+ return;
+ }
+
+ switch (type) {
+ case WLAN_FC_TYPE_MGMT:
+ if (stype != WLAN_FC_STYPE_BEACON)
+ wpa_printf(MSG_MSGDUMP, "MGMT");
+ ieee802_11_mgmt(hapd, buf, data_len, stype, NULL);
+ break;
+ case WLAN_FC_TYPE_CTRL:
+ wpa_printf(MSG_DEBUG, "CTRL");
+ break;
+ case WLAN_FC_TYPE_DATA:
+ wpa_printf(MSG_DEBUG, "DATA");
+ handle_data(hapd, buf, data_len, stype);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "unknown frame type %d", type);
+ break;
+ }
+}
+
+
+static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx;
+ int len;
+ unsigned char buf[3000];
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ handle_frame(hapd, buf, len);
+}
+
+
+static int hostap_init_sockets(struct hostap_driver_data *drv)
+{
+ struct ifreq ifr;
+ struct sockaddr_ll addr;
+
+ drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (drv->sock < 0) {
+ perror("socket[PF_PACKET,SOCK_RAW]");
+ return -1;
+ }
+
+ if (eloop_register_read_sock(drv->sock, handle_read, drv->hapd, NULL))
+ {
+ printf("Could not register read socket\n");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface);
+ if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
+ perror("ioctl(SIOCGIFINDEX)");
+ return -1;
+ }
+
+ if (hostap_set_iface_flags(drv, 1)) {
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sll_family = AF_PACKET;
+ addr.sll_ifindex = ifr.ifr_ifindex;
+ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
+ addr.sll_ifindex);
+
+ if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
+ if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
+ perror("ioctl(SIOCGIFHWADDR)");
+ return -1;
+ }
+
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ printf("Invalid HW-addr family 0x%04x\n",
+ ifr.ifr_hwaddr.sa_family);
+ return -1;
+ }
+ memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ return 0;
+}
+
+
+static int hostap_send_mgmt_frame(void *priv, const void *msg, size_t len,
+ int flags)
+{
+ struct hostap_driver_data *drv = priv;
+ struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) msg;
+ int res;
+
+ /* Request TX callback */
+ hdr->frame_control |= host_to_le16(BIT(1));
+ res = send(drv->sock, msg, len, flags);
+ hdr->frame_control &= ~host_to_le16(BIT(1));
+
+ return res;
+}
+
+
+static int hostap_send_eapol(void *priv, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt, const u8 *own_addr)
+{
+ struct hostap_driver_data *drv = priv;
+ struct ieee80211_hdr *hdr;
+ size_t len;
+ u8 *pos;
+ int res;
+
+ len = sizeof(*hdr) + sizeof(rfc1042_header) + 2 + data_len;
+ hdr = os_zalloc(len);
+ if (hdr == NULL) {
+ printf("malloc() failed for hostapd_send_data(len=%lu)\n",
+ (unsigned long) len);
+ return -1;
+ }
+
+ hdr->frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
+ hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
+ if (encrypt)
+ hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+ memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+ memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+ memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+
+ pos = (u8 *) (hdr + 1);
+ memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
+ pos += sizeof(rfc1042_header);
+ *((u16 *) pos) = htons(ETH_P_PAE);
+ pos += 2;
+ memcpy(pos, data, data_len);
+
+ res = hostap_send_mgmt_frame(drv, (u8 *) hdr, len, 0);
+ free(hdr);
+
+ if (res < 0) {
+ perror("hostapd_send_eapol: send");
+ printf("hostapd_send_eapol - packet len: %lu - failed\n",
+ (unsigned long) len);
+ }
+
+ return res;
+}
+
+
+static int hostap_sta_set_flags(void *priv, const u8 *addr,
+ int total_flags, int flags_or, int flags_and)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_SET_FLAGS_STA;
+ memcpy(param.sta_addr, addr, ETH_ALEN);
+ param.u.set_flags_sta.flags_or = flags_or;
+ param.u.set_flags_sta.flags_and = flags_and;
+ return hostapd_ioctl(drv, &param, sizeof(param));
+}
+
+
+static int hostap_set_iface_flags(void *priv, int dev_up)
+{
+ struct hostap_driver_data *drv = priv;
+ struct ifreq ifr;
+
+ if (drv->ioctl_sock < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ snprintf(ifr.ifr_name, IFNAMSIZ, "%sap", drv->iface);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ return -1;
+ }
+
+ if (dev_up)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCSIFFLAGS]");
+ return -1;
+ }
+
+ if (dev_up) {
+ memset(&ifr, 0, sizeof(ifr));
+ snprintf(ifr.ifr_name, IFNAMSIZ, "%sap", drv->iface);
+ ifr.ifr_mtu = HOSTAPD_MTU;
+ if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) {
+ perror("ioctl[SIOCSIFMTU]");
+ printf("Setting MTU failed - trying to survive with "
+ "current value\n");
+ }
+ }
+
+ return 0;
+}
+
+
+static int hostapd_ioctl(void *priv, struct prism2_hostapd_param *param,
+ int len)
+{
+ struct hostap_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) param;
+ iwr.u.data.length = len;
+
+ if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
+ perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostap_set_encryption(const char *ifname, void *priv,
+ const char *alg, const u8 *addr,
+ int idx, const u8 *key, size_t key_len,
+ int txkey)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param *param;
+ u8 *buf;
+ size_t blen;
+ int ret = 0;
+
+ blen = sizeof(*param) + key_len;
+ buf = os_zalloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ param = (struct prism2_hostapd_param *) buf;
+ param->cmd = PRISM2_SET_ENCRYPTION;
+ if (addr == NULL)
+ memset(param->sta_addr, 0xff, ETH_ALEN);
+ else
+ memcpy(param->sta_addr, addr, ETH_ALEN);
+ os_strlcpy((char *) param->u.crypt.alg, alg,
+ HOSTAP_CRYPT_ALG_NAME_LEN);
+ param->u.crypt.flags = txkey ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
+ param->u.crypt.idx = idx;
+ param->u.crypt.key_len = key_len;
+ memcpy((u8 *) (param + 1), key, key_len);
+
+ if (hostapd_ioctl(drv, param, blen)) {
+ printf("Failed to set encryption.\n");
+ ret = -1;
+ }
+ free(buf);
+
+ return ret;
+}
+
+
+static int hostap_get_seqnum(const char *ifname, void *priv, const u8 *addr,
+ int idx, u8 *seq)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param *param;
+ u8 *buf;
+ size_t blen;
+ int ret = 0;
+
+ blen = sizeof(*param) + 32;
+ buf = os_zalloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ param = (struct prism2_hostapd_param *) buf;
+ param->cmd = PRISM2_GET_ENCRYPTION;
+ if (addr == NULL)
+ memset(param->sta_addr, 0xff, ETH_ALEN);
+ else
+ memcpy(param->sta_addr, addr, ETH_ALEN);
+ param->u.crypt.idx = idx;
+
+ if (hostapd_ioctl(drv, param, blen)) {
+ printf("Failed to get encryption.\n");
+ ret = -1;
+ } else {
+ memcpy(seq, param->u.crypt.seq, 8);
+ }
+ free(buf);
+
+ return ret;
+}
+
+
+static int hostap_ioctl_prism2param(void *priv, int param, int value)
+{
+ struct hostap_driver_data *drv = priv;
+ struct iwreq iwr;
+ int *i;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ i = (int *) iwr.u.name;
+ *i++ = param;
+ *i++ = value;
+
+ if (ioctl(drv->ioctl_sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
+ perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostap_set_ieee8021x(const char *ifname, void *priv, int enabled)
+{
+ struct hostap_driver_data *drv = priv;
+
+ /* enable kernel driver support for IEEE 802.1X */
+ if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_IEEE_802_1X, enabled)) {
+ printf("Could not setup IEEE 802.1X support in kernel driver."
+ "\n");
+ return -1;
+ }
+
+ if (!enabled)
+ return 0;
+
+ /* use host driver implementation of encryption to allow
+ * individual keys and passing plaintext EAPOL frames */
+ if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_DECRYPT, 1) ||
+ hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOST_ENCRYPT, 1)) {
+ printf("Could not setup host-based encryption in kernel "
+ "driver.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostap_set_privacy(const char *ifname, void *priv, int enabled)
+{
+ struct hostap_drvier_data *drv = priv;
+
+ return hostap_ioctl_prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED,
+ enabled);
+}
+
+
+static int hostap_set_ssid(const char *ifname, void *priv, const u8 *buf,
+ int len)
+{
+ struct hostap_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.essid.flags = 1; /* SSID active */
+ iwr.u.essid.pointer = (caddr_t) buf;
+ iwr.u.essid.length = len + 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCSIWESSID]");
+ printf("len=%d\n", len);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostap_flush(void *priv)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_FLUSH;
+ return hostapd_ioctl(drv, &param, sizeof(param));
+}
+
+
+static int hostap_read_sta_data(void *priv,
+ struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct hostap_driver_data *drv = priv;
+ char buf[1024], line[128], *pos;
+ FILE *f;
+ unsigned long val;
+
+ memset(data, 0, sizeof(*data));
+ snprintf(buf, sizeof(buf), "/proc/net/hostap/%s/" MACSTR,
+ drv->iface, MAC2STR(addr));
+
+ f = fopen(buf, "r");
+ if (!f)
+ return -1;
+ /* Need to read proc file with in one piece, so use large enough
+ * buffer. */
+ setbuffer(f, buf, sizeof(buf));
+
+ while (fgets(line, sizeof(line), f)) {
+ pos = strchr(line, '=');
+ if (!pos)
+ continue;
+ *pos++ = '\0';
+ val = strtoul(pos, NULL, 10);
+ if (strcmp(line, "rx_packets") == 0)
+ data->rx_packets = val;
+ else if (strcmp(line, "tx_packets") == 0)
+ data->tx_packets = val;
+ else if (strcmp(line, "rx_bytes") == 0)
+ data->rx_bytes = val;
+ else if (strcmp(line, "tx_bytes") == 0)
+ data->tx_bytes = val;
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+
+static int hostap_sta_add(const char *ifname, void *priv, const u8 *addr,
+ u16 aid, u16 capability, u8 *supp_rates,
+ size_t supp_rates_len, int flags,
+ u16 listen_interval)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+ int tx_supp_rates = 0;
+ size_t i;
+
+#define WLAN_RATE_1M BIT(0)
+#define WLAN_RATE_2M BIT(1)
+#define WLAN_RATE_5M5 BIT(2)
+#define WLAN_RATE_11M BIT(3)
+
+ for (i = 0; i < supp_rates_len; i++) {
+ if ((supp_rates[i] & 0x7f) == 2)
+ tx_supp_rates |= WLAN_RATE_1M;
+ if ((supp_rates[i] & 0x7f) == 4)
+ tx_supp_rates |= WLAN_RATE_2M;
+ if ((supp_rates[i] & 0x7f) == 11)
+ tx_supp_rates |= WLAN_RATE_5M5;
+ if ((supp_rates[i] & 0x7f) == 22)
+ tx_supp_rates |= WLAN_RATE_11M;
+ }
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_ADD_STA;
+ memcpy(param.sta_addr, addr, ETH_ALEN);
+ param.u.add_sta.aid = aid;
+ param.u.add_sta.capability = capability;
+ param.u.add_sta.tx_supp_rates = tx_supp_rates;
+ return hostapd_ioctl(drv, &param, sizeof(param));
+}
+
+
+static int hostap_sta_remove(void *priv, const u8 *addr)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ hostap_sta_set_flags(drv, addr, 0, 0, ~WLAN_STA_AUTHORIZED);
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_REMOVE_STA;
+ memcpy(param.sta_addr, addr, ETH_ALEN);
+ if (hostapd_ioctl(drv, &param, sizeof(param))) {
+ printf("Could not remove station from kernel driver.\n");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int hostap_get_inact_sec(void *priv, const u8 *addr)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_GET_INFO_STA;
+ memcpy(param.sta_addr, addr, ETH_ALEN);
+ if (hostapd_ioctl(drv, &param, sizeof(param))) {
+ return -1;
+ }
+
+ return param.u.get_info_sta.inactive_sec;
+}
+
+
+static int hostap_sta_clear_stats(void *priv, const u8 *addr)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_STA_CLEAR_STATS;
+ memcpy(param.sta_addr, addr, ETH_ALEN);
+ if (hostapd_ioctl(drv, &param, sizeof(param))) {
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostap_set_assoc_ap(void *priv, const u8 *addr)
+{
+ struct hostap_driver_data *drv = priv;
+ struct prism2_hostapd_param param;
+
+ memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR;
+ memcpy(param.sta_addr, addr, ETH_ALEN);
+ if (hostapd_ioctl(drv, &param, sizeof(param)))
+ return -1;
+
+ return 0;
+}
+
+
+static int hostapd_ioctl_set_generic_elem(struct hostap_driver_data *drv)
+{
+ struct prism2_hostapd_param *param;
+ int res;
+ size_t blen, elem_len;
+
+ elem_len = drv->generic_ie_len + drv->wps_ie_len;
+ blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + elem_len;
+ if (blen < sizeof(*param))
+ blen = sizeof(*param);
+
+ param = os_zalloc(blen);
+ if (param == NULL)
+ return -1;
+
+ param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
+ param->u.generic_elem.len = elem_len;
+ if (drv->generic_ie) {
+ os_memcpy(param->u.generic_elem.data, drv->generic_ie,
+ drv->generic_ie_len);
+ }
+ if (drv->wps_ie) {
+ os_memcpy(&param->u.generic_elem.data[drv->generic_ie_len],
+ drv->wps_ie, drv->wps_ie_len);
+ }
+ wpa_hexdump(MSG_DEBUG, "hostap: Set generic IE",
+ param->u.generic_elem.data, elem_len);
+ res = hostapd_ioctl(drv, param, blen);
+
+ os_free(param);
+
+ return res;
+}
+
+
+static int hostap_set_generic_elem(const char *ifname, void *priv,
+ const u8 *elem, size_t elem_len)
+{
+ struct hostap_driver_data *drv = priv;
+
+ os_free(drv->generic_ie);
+ drv->generic_ie = NULL;
+ drv->generic_ie_len = 0;
+ if (elem) {
+ drv->generic_ie = os_malloc(elem_len);
+ if (drv->generic_ie == NULL)
+ return -1;
+ os_memcpy(drv->generic_ie, elem, elem_len);
+ drv->generic_ie_len = elem_len;
+ }
+
+ return hostapd_ioctl_set_generic_elem(drv);
+}
+
+
+static int hostap_set_wps_beacon_ie(const char *ifname, void *priv,
+ const u8 *ie, size_t len)
+{
+ /* Host AP driver supports only one set of extra IEs, so we need to
+ * use the ProbeResp IEs also for Beacon frames since they include more
+ * information. */
+ return 0;
+}
+
+
+static int hostap_set_wps_probe_resp_ie(const char *ifname, void *priv,
+ const u8 *ie, size_t len)
+{
+ struct hostap_driver_data *drv = priv;
+
+ os_free(drv->wps_ie);
+ drv->wps_ie = NULL;
+ drv->wps_ie_len = 0;
+ if (ie) {
+ drv->wps_ie = os_malloc(len);
+ if (drv->wps_ie == NULL)
+ return -1;
+ os_memcpy(drv->wps_ie, ie, len);
+ drv->wps_ie_len = len;
+ }
+
+ return hostapd_ioctl_set_generic_elem(drv);
+}
+
+
+static void
+hostapd_wireless_event_wireless_custom(struct hostap_driver_data *drv,
+ char *custom)
+{
+ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
+
+ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ char *pos;
+ u8 addr[ETH_ALEN];
+ pos = strstr(custom, "addr=");
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "without sender address ignored");
+ return;
+ }
+ pos += 5;
+ if (hwaddr_aton(pos, addr) == 0) {
+ ieee80211_michael_mic_failure(drv->hapd, addr, 1);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "with invalid MAC address");
+ }
+ }
+}
+
+
+static void hostapd_wireless_event_wireless(struct hostap_driver_data *drv,
+ char *data, int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf;
+
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
+ iwe->cmd, iwe->len);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ return;
+
+ custom = pos + IW_EV_POINT_LEN;
+ if (drv->we_version > 18 &&
+ (iwe->cmd == IWEVMICHAELMICFAILURE ||
+ iwe->cmd == IWEVCUSTOM)) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case IWEVCUSTOM:
+ if (custom + iwe->u.data.length > end)
+ return;
+ buf = malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return;
+ memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+ hostapd_wireless_event_wireless_custom(drv, buf);
+ free(buf);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+
+static void hostapd_wireless_event_rtm_newlink(struct hostap_driver_data *drv,
+ struct nlmsghdr *h, int len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ if (len < (int) sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ /* TODO: use ifi->ifi_index to filter out wireless events from other
+ * interfaces */
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ hostapd_wireless_event_wireless(
+ drv, ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void hostapd_wireless_event_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ char buf[256];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ struct hostap_driver_data *drv = eloop_ctx;
+
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("recvfrom(netlink)");
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (left >= (int) sizeof(*h)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ printf("Malformed netlink message: "
+ "len=%d left=%d plen=%d\n",
+ len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ hostapd_wireless_event_rtm_newlink(drv, h, plen);
+ break;
+ }
+
+ len = NLMSG_ALIGN(len);
+ left -= len;
+ h = (struct nlmsghdr *) ((char *) h + len);
+ }
+
+ if (left > 0) {
+ printf("%d extra bytes in the end of netlink message\n", left);
+ }
+}
+
+
+static int hostap_get_we_version(struct hostap_driver_data *drv)
+{
+ struct iw_range *range;
+ struct iwreq iwr;
+ int minlen;
+ size_t buflen;
+
+ drv->we_version = 0;
+
+ /*
+ * Use larger buffer than struct iw_range in order to allow the
+ * structure to grow in the future.
+ */
+ buflen = sizeof(struct iw_range) + 500;
+ range = os_zalloc(buflen);
+ if (range == NULL)
+ return -1;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buflen;
+
+ minlen = ((char *) &range->enc_capa) - (char *) range +
+ sizeof(range->enc_capa);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWRANGE]");
+ free(range);
+ return -1;
+ } else if (iwr.u.data.length >= minlen &&
+ range->we_version_compiled >= 18) {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+ "WE(source)=%d enc_capa=0x%x",
+ range->we_version_compiled,
+ range->we_version_source,
+ range->enc_capa);
+ drv->we_version = range->we_version_compiled;
+ }
+
+ free(range);
+ return 0;
+}
+
+
+static int hostap_wireless_event_init(void *priv)
+{
+ struct hostap_driver_data *drv = priv;
+ int s;
+ struct sockaddr_nl local;
+
+ hostap_get_we_version(drv);
+
+ drv->wext_sock = -1;
+
+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (s < 0) {
+ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+ return -1;
+ }
+
+ memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ perror("bind(netlink)");
+ close(s);
+ return -1;
+ }
+
+ eloop_register_read_sock(s, hostapd_wireless_event_receive, drv,
+ NULL);
+ drv->wext_sock = s;
+
+ return 0;
+}
+
+
+static void hostap_wireless_event_deinit(void *priv)
+{
+ struct hostap_driver_data *drv = priv;
+ if (drv->wext_sock < 0)
+ return;
+ eloop_unregister_read_sock(drv->wext_sock);
+ close(drv->wext_sock);
+}
+
+
+static void * hostap_init(struct hostapd_data *hapd)
+{
+ struct hostap_driver_data *drv;
+
+ drv = os_zalloc(sizeof(struct hostap_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for hostapd driver data\n");
+ return NULL;
+ }
+
+ drv->hapd = hapd;
+ drv->ioctl_sock = drv->sock = -1;
+ memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface));
+
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket[PF_INET,SOCK_DGRAM]");
+ free(drv);
+ return NULL;
+ }
+
+ if (hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 1)) {
+ printf("Could not enable hostapd mode for interface %s\n",
+ drv->iface);
+ close(drv->ioctl_sock);
+ free(drv);
+ return NULL;
+ }
+
+ if (hostap_init_sockets(drv)) {
+ close(drv->ioctl_sock);
+ free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static void hostap_driver_deinit(void *priv)
+{
+ struct hostap_driver_data *drv = priv;
+
+ (void) hostap_set_iface_flags(drv, 0);
+ (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD, 0);
+ (void) hostap_ioctl_prism2param(drv, PRISM2_PARAM_HOSTAPD_STA, 0);
+
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+
+ if (drv->sock >= 0)
+ close(drv->sock);
+
+ os_free(drv->generic_ie);
+ os_free(drv->wps_ie);
+
+ free(drv);
+}
+
+
+static int hostap_sta_deauth(void *priv, const u8 *addr, int reason)
+{
+ struct hostap_driver_data *drv = priv;
+ struct ieee80211_mgmt mgmt;
+
+ memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DEAUTH);
+ memcpy(mgmt.da, addr, ETH_ALEN);
+ memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN);
+ memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN);
+ mgmt.u.deauth.reason_code = host_to_le16(reason);
+ return hostap_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth), 0);
+}
+
+
+static int hostap_sta_disassoc(void *priv, const u8 *addr, int reason)
+{
+ struct hostap_driver_data *drv = priv;
+ struct ieee80211_mgmt mgmt;
+
+ memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DISASSOC);
+ memcpy(mgmt.da, addr, ETH_ALEN);
+ memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN);
+ memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN);
+ mgmt.u.disassoc.reason_code = host_to_le16(reason);
+ return hostap_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN +
+ sizeof(mgmt.u.disassoc), 0);
+}
+
+
+static struct hostapd_hw_modes * hostap_get_hw_feature_data(void *priv,
+ u16 *num_modes,
+ u16 *flags)
+{
+ struct hostapd_hw_modes *mode;
+ int i, clen, rlen;
+ const short chan2freq[14] = {
+ 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+ 2447, 2452, 2457, 2462, 2467, 2472, 2484
+ };
+
+ mode = os_zalloc(sizeof(struct hostapd_hw_modes));
+ if (mode == NULL)
+ return NULL;
+
+ *num_modes = 1;
+ *flags = 0;
+
+ mode->mode = HOSTAPD_MODE_IEEE80211B;
+ mode->num_channels = 14;
+ mode->num_rates = 4;
+
+ clen = mode->num_channels * sizeof(struct hostapd_channel_data);
+ rlen = mode->num_rates * sizeof(struct hostapd_rate_data);
+
+ mode->channels = os_zalloc(clen);
+ mode->rates = os_zalloc(rlen);
+ if (mode->channels == NULL || mode->rates == NULL) {
+ hostapd_free_hw_features(mode, *num_modes);
+ return NULL;
+ }
+
+ for (i = 0; i < 14; i++) {
+ mode->channels[i].chan = i + 1;
+ mode->channels[i].freq = chan2freq[i];
+ /* TODO: Get allowed channel list from the driver */
+ if (i >= 11)
+ mode->channels[i].flag = HOSTAPD_CHAN_DISABLED;
+ }
+
+ mode->rates[0].rate = 10;
+ mode->rates[0].flags = HOSTAPD_RATE_CCK;
+ mode->rates[1].rate = 20;
+ mode->rates[1].flags = HOSTAPD_RATE_CCK;
+ mode->rates[2].rate = 55;
+ mode->rates[2].flags = HOSTAPD_RATE_CCK;
+ mode->rates[3].rate = 110;
+ mode->rates[3].flags = HOSTAPD_RATE_CCK;
+
+ return mode;
+}
+
+
+const struct wpa_driver_ops wpa_driver_hostap_ops = {
+ .name = "hostap",
+ .init = hostap_init,
+ .deinit = hostap_driver_deinit,
+ .wireless_event_init = hostap_wireless_event_init,
+ .wireless_event_deinit = hostap_wireless_event_deinit,
+ .set_ieee8021x = hostap_set_ieee8021x,
+ .set_privacy = hostap_set_privacy,
+ .set_encryption = hostap_set_encryption,
+ .get_seqnum = hostap_get_seqnum,
+ .flush = hostap_flush,
+ .set_generic_elem = hostap_set_generic_elem,
+ .read_sta_data = hostap_read_sta_data,
+ .send_eapol = hostap_send_eapol,
+ .sta_set_flags = hostap_sta_set_flags,
+ .sta_deauth = hostap_sta_deauth,
+ .sta_disassoc = hostap_sta_disassoc,
+ .sta_remove = hostap_sta_remove,
+ .set_ssid = hostap_set_ssid,
+ .send_mgmt_frame = hostap_send_mgmt_frame,
+ .set_assoc_ap = hostap_set_assoc_ap,
+ .sta_add = hostap_sta_add,
+ .get_inact_sec = hostap_get_inact_sec,
+ .sta_clear_stats = hostap_sta_clear_stats,
+ .get_hw_feature_data = hostap_get_hw_feature_data,
+ .set_wps_beacon_ie = hostap_set_wps_beacon_ie,
+ .set_wps_probe_resp_ie = hostap_set_wps_probe_resp_ie,
+};
diff --git a/hostapd/driver_madwifi.c b/hostapd/driver_madwifi.c
new file mode 100644
index 0000000..4083fda
--- /dev/null
+++ b/hostapd/driver_madwifi.c
@@ -0,0 +1,1483 @@
+/*
+ * hostapd / Driver interaction with MADWIFI 802.11 driver
+ * Copyright (c) 2004, Sam Leffler <sam@errno.com>
+ * Copyright (c) 2004, Video54 Technologies
+ * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <net/if.h>
+#include <sys/ioctl.h>
+
+#include <include/compat.h>
+#include <net80211/ieee80211.h>
+#ifdef WME_NUM_AC
+/* Assume this is built against BSD branch of madwifi driver. */
+#define MADWIFI_BSD
+#include <net80211/_ieee80211.h>
+#endif /* WME_NUM_AC */
+#include <net80211/ieee80211_crypto.h>
+#include <net80211/ieee80211_ioctl.h>
+
+#ifdef CONFIG_WPS
+#ifdef IEEE80211_IOCTL_FILTERFRAME
+#include <netpacket/packet.h>
+
+#ifndef ETH_P_80211_RAW
+#define ETH_P_80211_RAW 0x0019
+#endif
+#endif /* IEEE80211_IOCTL_FILTERFRAME */
+#endif /* CONFIG_WPS */
+
+/*
+ * Avoid conflicts with hostapd definitions by undefining couple of defines
+ * from madwifi header files.
+ */
+#undef RSN_VERSION
+#undef WPA_VERSION
+#undef WPA_OUI_TYPE
+#undef WME_OUI_TYPE
+
+
+#ifdef IEEE80211_IOCTL_SETWMMPARAMS
+/* Assume this is built against madwifi-ng */
+#define MADWIFI_NG
+#endif /* IEEE80211_IOCTL_SETWMMPARAMS */
+
+#include "wireless_copy.h"
+
+#include "hostapd.h"
+#include "driver.h"
+#include "ieee802_1x.h"
+#include "eloop.h"
+#include "priv_netlink.h"
+#include "sta_info.h"
+#include "l2_packet/l2_packet.h"
+
+#include "wpa.h"
+#include "radius/radius.h"
+#include "ieee802_11.h"
+#include "accounting.h"
+#include "common.h"
+#include "wps_hostapd.h"
+
+
+struct madwifi_driver_data {
+ struct hostapd_data *hapd; /* back pointer */
+
+ char iface[IFNAMSIZ + 1];
+ int ifindex;
+ struct l2_packet_data *sock_xmit; /* raw packet xmit socket */
+ struct l2_packet_data *sock_recv; /* raw packet recv socket */
+ int ioctl_sock; /* socket for ioctl() use */
+ int wext_sock; /* socket for wireless events */
+ int we_version;
+ u8 acct_mac[ETH_ALEN];
+ struct hostap_sta_driver_data acct_data;
+
+ struct l2_packet_data *sock_raw; /* raw 802.11 management frames */
+};
+
+static int madwifi_sta_deauth(void *priv, const u8 *addr, int reason_code);
+
+static int
+set80211priv(struct madwifi_driver_data *drv, int op, void *data, int len)
+{
+ struct iwreq iwr;
+ int do_inline = len < IFNAMSIZ;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+#ifdef IEEE80211_IOCTL_FILTERFRAME
+ /* FILTERFRAME must be NOT inline, regardless of size. */
+ if (op == IEEE80211_IOCTL_FILTERFRAME)
+ do_inline = 0;
+#endif /* IEEE80211_IOCTL_FILTERFRAME */
+ if (op == IEEE80211_IOCTL_SET_APPIEBUF)
+ do_inline = 0;
+ if (do_inline) {
+ /*
+ * Argument data fits inline; put it there.
+ */
+ memcpy(iwr.u.name, data, len);
+ } else {
+ /*
+ * Argument data too big for inline transfer; setup a
+ * parameter block instead; the kernel will transfer
+ * the data for the driver.
+ */
+ iwr.u.data.pointer = data;
+ iwr.u.data.length = len;
+ }
+
+ if (ioctl(drv->ioctl_sock, op, &iwr) < 0) {
+#ifdef MADWIFI_NG
+ int first = IEEE80211_IOCTL_SETPARAM;
+ static const char *opnames[] = {
+ "ioctl[IEEE80211_IOCTL_SETPARAM]",
+ "ioctl[IEEE80211_IOCTL_GETPARAM]",
+ "ioctl[IEEE80211_IOCTL_SETMODE]",
+ "ioctl[IEEE80211_IOCTL_GETMODE]",
+ "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
+ "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
+ "ioctl[IEEE80211_IOCTL_SETCHANLIST]",
+ "ioctl[IEEE80211_IOCTL_GETCHANLIST]",
+ "ioctl[IEEE80211_IOCTL_CHANSWITCH]",
+ "ioctl[IEEE80211_IOCTL_GET_APPIEBUF]",
+ "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
+ "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
+ "ioctl[IEEE80211_IOCTL_FILTERFRAME]",
+ "ioctl[IEEE80211_IOCTL_GETCHANINFO]",
+ "ioctl[IEEE80211_IOCTL_SETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_GETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_SETMLME]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_SETKEY]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_DELKEY]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_ADDMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_DELMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_WDSMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_WDSDELMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_KICKMAC]",
+ };
+#else /* MADWIFI_NG */
+ int first = IEEE80211_IOCTL_SETPARAM;
+ static const char *opnames[] = {
+ "ioctl[IEEE80211_IOCTL_SETPARAM]",
+ "ioctl[IEEE80211_IOCTL_GETPARAM]",
+ "ioctl[IEEE80211_IOCTL_SETKEY]",
+ "ioctl[SIOCIWFIRSTPRIV+3]",
+ "ioctl[IEEE80211_IOCTL_DELKEY]",
+ "ioctl[SIOCIWFIRSTPRIV+5]",
+ "ioctl[IEEE80211_IOCTL_SETMLME]",
+ "ioctl[SIOCIWFIRSTPRIV+7]",
+ "ioctl[IEEE80211_IOCTL_SETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_GETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_ADDMAC]",
+ "ioctl[SIOCIWFIRSTPRIV+11]",
+ "ioctl[IEEE80211_IOCTL_DELMAC]",
+ "ioctl[SIOCIWFIRSTPRIV+13]",
+ "ioctl[IEEE80211_IOCTL_CHANLIST]",
+ "ioctl[SIOCIWFIRSTPRIV+15]",
+ "ioctl[IEEE80211_IOCTL_GETRSN]",
+ "ioctl[SIOCIWFIRSTPRIV+17]",
+ "ioctl[IEEE80211_IOCTL_GETKEY]",
+ };
+#endif /* MADWIFI_NG */
+ int idx = op - first;
+ if (first <= op &&
+ idx < (int) (sizeof(opnames) / sizeof(opnames[0])) &&
+ opnames[idx])
+ perror(opnames[idx]);
+ else
+ perror("ioctl[unknown???]");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+set80211param(struct madwifi_driver_data *drv, int op, int arg)
+{
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.mode = op;
+ memcpy(iwr.u.name+sizeof(__u32), &arg, sizeof(arg));
+
+ if (ioctl(drv->ioctl_sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
+ perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
+ wpa_printf(MSG_DEBUG, "%s: Failed to set parameter (op %d "
+ "arg %d)", __func__, op, arg);
+ return -1;
+ }
+ return 0;
+}
+
+static const char *
+ether_sprintf(const u8 *addr)
+{
+ static char buf[sizeof(MACSTR)];
+
+ if (addr != NULL)
+ snprintf(buf, sizeof(buf), MACSTR, MAC2STR(addr));
+ else
+ snprintf(buf, sizeof(buf), MACSTR, 0,0,0,0,0,0);
+ return buf;
+}
+
+/*
+ * Configure WPA parameters.
+ */
+static int
+madwifi_configure_wpa(struct madwifi_driver_data *drv)
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct hostapd_bss_config *conf = hapd->conf;
+ int v;
+
+ switch (conf->wpa_group) {
+ case WPA_CIPHER_CCMP:
+ v = IEEE80211_CIPHER_AES_CCM;
+ break;
+ case WPA_CIPHER_TKIP:
+ v = IEEE80211_CIPHER_TKIP;
+ break;
+ case WPA_CIPHER_WEP104:
+ v = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_CIPHER_WEP40:
+ v = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_CIPHER_NONE:
+ v = IEEE80211_CIPHER_NONE;
+ break;
+ default:
+ wpa_printf(MSG_ERROR, "Unknown group key cipher %u",
+ conf->wpa_group);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "%s: group key cipher=%d", __func__, v);
+ if (set80211param(drv, IEEE80211_PARAM_MCASTCIPHER, v)) {
+ printf("Unable to set group key cipher to %u\n", v);
+ return -1;
+ }
+ if (v == IEEE80211_CIPHER_WEP) {
+ /* key length is done only for specific ciphers */
+ v = (conf->wpa_group == WPA_CIPHER_WEP104 ? 13 : 5);
+ if (set80211param(drv, IEEE80211_PARAM_MCASTKEYLEN, v)) {
+ printf("Unable to set group key length to %u\n", v);
+ return -1;
+ }
+ }
+
+ v = 0;
+ if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
+ v |= 1<<IEEE80211_CIPHER_AES_CCM;
+ if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
+ v |= 1<<IEEE80211_CIPHER_TKIP;
+ if (conf->wpa_pairwise & WPA_CIPHER_NONE)
+ v |= 1<<IEEE80211_CIPHER_NONE;
+ wpa_printf(MSG_DEBUG, "%s: pairwise key ciphers=0x%x", __func__, v);
+ if (set80211param(drv, IEEE80211_PARAM_UCASTCIPHERS, v)) {
+ printf("Unable to set pairwise key ciphers to 0x%x\n", v);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: key management algorithms=0x%x",
+ __func__, conf->wpa_key_mgmt);
+ if (set80211param(drv, IEEE80211_PARAM_KEYMGTALGS, conf->wpa_key_mgmt)) {
+ printf("Unable to set key management algorithms to 0x%x\n",
+ conf->wpa_key_mgmt);
+ return -1;
+ }
+
+ v = 0;
+ if (conf->rsn_preauth)
+ v |= BIT(0);
+ wpa_printf(MSG_DEBUG, "%s: rsn capabilities=0x%x",
+ __func__, conf->rsn_preauth);
+ if (set80211param(drv, IEEE80211_PARAM_RSNCAPS, v)) {
+ printf("Unable to set RSN capabilities to 0x%x\n", v);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: enable WPA=0x%x", __func__, conf->wpa);
+ if (set80211param(drv, IEEE80211_PARAM_WPA, conf->wpa)) {
+ printf("Unable to set WPA to %u\n", conf->wpa);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int
+madwifi_set_iface_flags(void *priv, int dev_up)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ifreq ifr;
+
+ wpa_printf(MSG_DEBUG, "%s: dev_up=%d", __func__, dev_up);
+
+ if (drv->ioctl_sock < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ return -1;
+ }
+
+ if (dev_up)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCSIFFLAGS]");
+ return -1;
+ }
+
+ if (dev_up) {
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
+ ifr.ifr_mtu = HOSTAPD_MTU;
+ if (ioctl(drv->ioctl_sock, SIOCSIFMTU, &ifr) != 0) {
+ perror("ioctl[SIOCSIFMTU]");
+ printf("Setting MTU failed - trying to survive with "
+ "current value\n");
+ }
+ }
+
+ return 0;
+}
+
+static int
+madwifi_set_ieee8021x(const char *ifname, void *priv, int enabled)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct hostapd_data *hapd = drv->hapd;
+ struct hostapd_bss_config *conf = hapd->conf;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+
+ if (!enabled) {
+ /* XXX restore state */
+ return set80211param(priv, IEEE80211_PARAM_AUTHMODE,
+ IEEE80211_AUTH_AUTO);
+ }
+ if (!conf->wpa && !conf->ieee802_1x) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "No 802.1X or WPA enabled!");
+ return -1;
+ }
+ if (conf->wpa && madwifi_configure_wpa(drv) != 0) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "Error configuring WPA state!");
+ return -1;
+ }
+ if (set80211param(priv, IEEE80211_PARAM_AUTHMODE,
+ (conf->wpa ? IEEE80211_AUTH_WPA : IEEE80211_AUTH_8021X))) {
+ hostapd_logger(hapd, NULL, HOSTAPD_MODULE_DRIVER,
+ HOSTAPD_LEVEL_WARNING, "Error enabling WPA/802.1X!");
+ return -1;
+ }
+
+ return 0;
+}
+
+static int
+madwifi_set_privacy(const char *ifname, void *priv, int enabled)
+{
+ struct madwifi_driver_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+
+ return set80211param(drv, IEEE80211_PARAM_PRIVACY, enabled);
+}
+
+static int
+madwifi_set_sta_authorized(void *priv, const u8 *addr, int authorized)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s authorized=%d",
+ __func__, ether_sprintf(addr), authorized);
+
+ if (authorized)
+ mlme.im_op = IEEE80211_MLME_AUTHORIZE;
+ else
+ mlme.im_op = IEEE80211_MLME_UNAUTHORIZE;
+ mlme.im_reason = 0;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to %sauthorize STA " MACSTR,
+ __func__, authorized ? "" : "un", MAC2STR(addr));
+ }
+
+ return ret;
+}
+
+static int
+madwifi_sta_set_flags(void *priv, const u8 *addr, int total_flags,
+ int flags_or, int flags_and)
+{
+ /* For now, only support setting Authorized flag */
+ if (flags_or & WLAN_STA_AUTHORIZED)
+ return madwifi_set_sta_authorized(priv, addr, 1);
+ if (!(flags_and & WLAN_STA_AUTHORIZED))
+ return madwifi_set_sta_authorized(priv, addr, 0);
+ return 0;
+}
+
+static int
+madwifi_del_key(void *priv, const u8 *addr, int key_idx)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_del_key wk;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s key_idx=%d",
+ __func__, ether_sprintf(addr), key_idx);
+
+ memset(&wk, 0, sizeof(wk));
+ if (addr != NULL) {
+ memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.idk_keyix = (u8) IEEE80211_KEYIX_NONE;
+ } else {
+ wk.idk_keyix = key_idx;
+ }
+
+ ret = set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to delete key (addr %s"
+ " key_idx %d)", __func__, ether_sprintf(addr),
+ key_idx);
+ }
+
+ return ret;
+}
+
+static int
+madwifi_set_key(const char *ifname, void *priv, const char *alg,
+ const u8 *addr, int key_idx,
+ const u8 *key, size_t key_len, int txkey)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_key wk;
+ u_int8_t cipher;
+ int ret;
+
+ if (strcmp(alg, "none") == 0)
+ return madwifi_del_key(drv, addr, key_idx);
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%s addr=%s key_idx=%d",
+ __func__, alg, ether_sprintf(addr), key_idx);
+
+ if (strcmp(alg, "WEP") == 0)
+ cipher = IEEE80211_CIPHER_WEP;
+ else if (strcmp(alg, "TKIP") == 0)
+ cipher = IEEE80211_CIPHER_TKIP;
+ else if (strcmp(alg, "CCMP") == 0)
+ cipher = IEEE80211_CIPHER_AES_CCM;
+ else {
+ printf("%s: unknown/unsupported algorithm %s\n",
+ __func__, alg);
+ return -1;
+ }
+
+ if (key_len > sizeof(wk.ik_keydata)) {
+ printf("%s: key length %lu too big\n", __func__,
+ (unsigned long) key_len);
+ return -3;
+ }
+
+ memset(&wk, 0, sizeof(wk));
+ wk.ik_type = cipher;
+ wk.ik_flags = IEEE80211_KEY_RECV | IEEE80211_KEY_XMIT;
+ if (addr == NULL) {
+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = key_idx;
+ wk.ik_flags |= IEEE80211_KEY_DEFAULT;
+ } else {
+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = IEEE80211_KEYIX_NONE;
+ }
+ wk.ik_keylen = key_len;
+ memcpy(wk.ik_keydata, key, key_len);
+
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to set key (addr %s"
+ " key_idx %d alg '%s' key_len %lu txkey %d)",
+ __func__, ether_sprintf(wk.ik_macaddr), key_idx,
+ alg, (unsigned long) key_len, txkey);
+ }
+
+ return ret;
+}
+
+
+static int
+madwifi_get_seqnum(const char *ifname, void *priv, const u8 *addr, int idx,
+ u8 *seq)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_key wk;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s idx=%d",
+ __func__, ether_sprintf(addr), idx);
+
+ memset(&wk, 0, sizeof(wk));
+ if (addr == NULL)
+ memset(wk.ik_macaddr, 0xff, IEEE80211_ADDR_LEN);
+ else
+ memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = idx;
+
+ if (set80211priv(drv, IEEE80211_IOCTL_GETKEY, &wk, sizeof(wk))) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to get encryption data "
+ "(addr " MACSTR " key_idx %d)",
+ __func__, MAC2STR(wk.ik_macaddr), idx);
+ return -1;
+ }
+
+#ifdef WORDS_BIGENDIAN
+ {
+ /*
+ * wk.ik_keytsc is in host byte order (big endian), need to
+ * swap it to match with the byte order used in WPA.
+ */
+ int i;
+ u8 tmp[WPA_KEY_RSC_LEN];
+ memcpy(tmp, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+ for (i = 0; i < WPA_KEY_RSC_LEN; i++) {
+ seq[i] = tmp[WPA_KEY_RSC_LEN - i - 1];
+ }
+ }
+#else /* WORDS_BIGENDIAN */
+ memcpy(seq, &wk.ik_keytsc, sizeof(wk.ik_keytsc));
+#endif /* WORDS_BIGENDIAN */
+ return 0;
+}
+
+
+static int
+madwifi_flush(void *priv)
+{
+#ifdef MADWIFI_BSD
+ u8 allsta[IEEE80211_ADDR_LEN];
+ memset(allsta, 0xff, IEEE80211_ADDR_LEN);
+ return madwifi_sta_deauth(priv, allsta, IEEE80211_REASON_AUTH_LEAVE);
+#else /* MADWIFI_BSD */
+ return 0; /* XXX */
+#endif /* MADWIFI_BSD */
+}
+
+
+static int
+madwifi_read_sta_driver_data(void *priv, struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct madwifi_driver_data *drv = priv;
+
+#ifdef MADWIFI_BSD
+ struct ieee80211req_sta_stats stats;
+
+ memset(data, 0, sizeof(*data));
+
+ /*
+ * Fetch statistics for station from the system.
+ */
+ memset(&stats, 0, sizeof(stats));
+ memcpy(stats.is_u.macaddr, addr, IEEE80211_ADDR_LEN);
+ if (set80211priv(drv,
+#ifdef MADWIFI_NG
+ IEEE80211_IOCTL_STA_STATS,
+#else /* MADWIFI_NG */
+ IEEE80211_IOCTL_GETSTASTATS,
+#endif /* MADWIFI_NG */
+ &stats, sizeof(stats))) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to fetch STA stats (addr "
+ MACSTR ")", __func__, MAC2STR(addr));
+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
+ memcpy(data, &drv->acct_data, sizeof(*data));
+ return 0;
+ }
+
+ printf("Failed to get station stats information element.\n");
+ return -1;
+ }
+
+ data->rx_packets = stats.is_stats.ns_rx_data;
+ data->rx_bytes = stats.is_stats.ns_rx_bytes;
+ data->tx_packets = stats.is_stats.ns_tx_data;
+ data->tx_bytes = stats.is_stats.ns_tx_bytes;
+ return 0;
+
+#else /* MADWIFI_BSD */
+
+ char buf[1024], line[128], *pos;
+ FILE *f;
+ unsigned long val;
+
+ memset(data, 0, sizeof(*data));
+ snprintf(buf, sizeof(buf), "/proc/net/madwifi/%s/" MACSTR,
+ drv->iface, MAC2STR(addr));
+
+ f = fopen(buf, "r");
+ if (!f) {
+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) != 0)
+ return -1;
+ memcpy(data, &drv->acct_data, sizeof(*data));
+ return 0;
+ }
+ /* Need to read proc file with in one piece, so use large enough
+ * buffer. */
+ setbuffer(f, buf, sizeof(buf));
+
+ while (fgets(line, sizeof(line), f)) {
+ pos = strchr(line, '=');
+ if (!pos)
+ continue;
+ *pos++ = '\0';
+ val = strtoul(pos, NULL, 10);
+ if (strcmp(line, "rx_packets") == 0)
+ data->rx_packets = val;
+ else if (strcmp(line, "tx_packets") == 0)
+ data->tx_packets = val;
+ else if (strcmp(line, "rx_bytes") == 0)
+ data->rx_bytes = val;
+ else if (strcmp(line, "tx_bytes") == 0)
+ data->tx_bytes = val;
+ }
+
+ fclose(f);
+
+ return 0;
+#endif /* MADWIFI_BSD */
+}
+
+
+static int
+madwifi_sta_clear_stats(void *priv, const u8 *addr)
+{
+#if defined(MADWIFI_BSD) && defined(IEEE80211_MLME_CLEAR_STATS)
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s", __func__, ether_sprintf(addr));
+
+ mlme.im_op = IEEE80211_MLME_CLEAR_STATS;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
+ sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to clear STA stats (addr "
+ MACSTR ")", __func__, MAC2STR(addr));
+ }
+
+ return ret;
+#else /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */
+ return 0; /* FIX */
+#endif /* MADWIFI_BSD && IEEE80211_MLME_CLEAR_STATS */
+}
+
+
+static int
+madwifi_set_opt_ie(const char *ifname, void *priv, const u8 *ie, size_t ie_len)
+{
+ /*
+ * Do nothing; we setup parameters at startup that define the
+ * contents of the beacon information element.
+ */
+ return 0;
+}
+
+static int
+madwifi_sta_deauth(void *priv, const u8 *addr, int reason_code)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+ __func__, ether_sprintf(addr), reason_code);
+
+ mlme.im_op = IEEE80211_MLME_DEAUTH;
+ mlme.im_reason = reason_code;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to deauth STA (addr " MACSTR
+ " reason %d)",
+ __func__, MAC2STR(addr), reason_code);
+ }
+
+ return ret;
+}
+
+static int
+madwifi_sta_disassoc(void *priv, const u8 *addr, int reason_code)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s: addr=%s reason_code=%d",
+ __func__, ether_sprintf(addr), reason_code);
+
+ mlme.im_op = IEEE80211_MLME_DISASSOC;
+ mlme.im_reason = reason_code;
+ memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ ret = set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme));
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to disassoc STA (addr "
+ MACSTR " reason %d)",
+ __func__, MAC2STR(addr), reason_code);
+ }
+
+ return ret;
+}
+
+#ifdef CONFIG_WPS
+#ifdef IEEE80211_IOCTL_FILTERFRAME
+static void madwifi_raw_receive(void *ctx, const u8 *src_addr, const u8 *buf,
+ size_t len)
+{
+ struct madwifi_driver_data *drv = ctx;
+ const struct ieee80211_mgmt *mgmt;
+ const u8 *end, *ie;
+ u16 fc;
+ size_t ie_len;
+
+ /* Send Probe Request information to WPS processing */
+
+ if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+ return;
+ mgmt = (const struct ieee80211_mgmt *) buf;
+
+ fc = le_to_host16(mgmt->frame_control);
+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT ||
+ WLAN_FC_GET_STYPE(fc) != WLAN_FC_STYPE_PROBE_REQ)
+ return;
+
+ end = buf + len;
+ ie = mgmt->u.probe_req.variable;
+ ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+
+ hostapd_wps_probe_req_rx(drv->hapd, mgmt->sa, ie, ie_len);
+}
+#endif /* IEEE80211_IOCTL_FILTERFRAME */
+#endif /* CONFIG_WPS */
+
+static int madwifi_receive_probe_req(struct madwifi_driver_data *drv)
+{
+ int ret = 0;
+#ifdef CONFIG_WPS
+#ifdef IEEE80211_IOCTL_FILTERFRAME
+ struct ieee80211req_set_filter filt;
+
+ wpa_printf(MSG_DEBUG, "%s Enter", __func__);
+ filt.app_filterype = IEEE80211_FILTER_TYPE_PROBE_REQ;
+
+ ret = set80211priv(drv, IEEE80211_IOCTL_FILTERFRAME, &filt,
+ sizeof(struct ieee80211req_set_filter));
+ if (ret)
+ return ret;
+
+ drv->sock_raw = l2_packet_init(drv->iface, NULL, ETH_P_80211_RAW,
+ madwifi_raw_receive, drv, 1);
+ if (drv->sock_raw == NULL)
+ return -1;
+#endif /* IEEE80211_IOCTL_FILTERFRAME */
+#endif /* CONFIG_WPS */
+ return ret;
+}
+
+static int
+madwifi_del_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct sta_info *sta;
+
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "disassociated");
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta != NULL) {
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
+ sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+ ap_free_sta(hapd, sta);
+ }
+ return 0;
+}
+
+#ifdef CONFIG_WPS
+static int
+madwifi_set_wps_ie(void *priv, const u8 *ie, size_t len, u32 frametype)
+{
+ struct madwifi_driver_data *drv = priv;
+ u8 buf[256];
+ struct ieee80211req_getset_appiebuf *beac_ie;
+
+ wpa_printf(MSG_DEBUG, "%s buflen = %lu", __func__,
+ (unsigned long) len);
+
+ beac_ie = (struct ieee80211req_getset_appiebuf *) buf;
+ beac_ie->app_frmtype = frametype;
+ beac_ie->app_buflen = len;
+ memcpy(&(beac_ie->app_buf[0]), ie, len);
+
+ return set80211priv(drv, IEEE80211_IOCTL_SET_APPIEBUF, beac_ie,
+ sizeof(struct ieee80211req_getset_appiebuf) + len);
+}
+
+static int
+madwifi_set_wps_beacon_ie(const char *ifname, void *priv, const u8 *ie,
+ size_t len)
+{
+ return madwifi_set_wps_ie(priv, ie, len, IEEE80211_APPIE_FRAME_BEACON);
+}
+
+static int
+madwifi_set_wps_probe_resp_ie(const char *ifname, void *priv, const u8 *ie,
+ size_t len)
+{
+ return madwifi_set_wps_ie(priv, ie, len,
+ IEEE80211_APPIE_FRAME_PROBE_RESP);
+}
+#else /* CONFIG_WPS */
+#define madwifi_set_wps_beacon_ie NULL
+#define madwifi_set_wps_probe_resp_ie NULL
+#endif /* CONFIG_WPS */
+
+static int
+madwifi_process_wpa_ie(struct madwifi_driver_data *drv, struct sta_info *sta)
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct ieee80211req_wpaie ie;
+ int ielen, res;
+ u8 *iebuf;
+
+ /*
+ * Fetch negotiated WPA/RSN parameters from the system.
+ */
+ memset(&ie, 0, sizeof(ie));
+ memcpy(ie.wpa_macaddr, sta->addr, IEEE80211_ADDR_LEN);
+ if (set80211priv(drv, IEEE80211_IOCTL_GETWPAIE, &ie, sizeof(ie))) {
+ wpa_printf(MSG_ERROR, "%s: Failed to get WPA/RSN IE",
+ __func__);
+ printf("Failed to get WPA/RSN information element.\n");
+ return -1; /* XXX not right */
+ }
+ wpa_hexdump(MSG_MSGDUMP, "madwifi req WPA IE",
+ ie.wpa_ie, IEEE80211_MAX_OPT_IE);
+ iebuf = ie.wpa_ie;
+ /* madwifi seems to return some random data if WPA/RSN IE is not set.
+ * Assume the IE was not included if the IE type is unknown. */
+ if (iebuf[0] != WLAN_EID_VENDOR_SPECIFIC)
+ iebuf[1] = 0;
+#ifdef MADWIFI_NG
+ wpa_hexdump(MSG_MSGDUMP, "madwifi req RSN IE",
+ ie.rsn_ie, IEEE80211_MAX_OPT_IE);
+ if (iebuf[1] == 0 && ie.rsn_ie[1] > 0) {
+ /* madwifi-ng svn #1453 added rsn_ie. Use it, if wpa_ie was not
+ * set. This is needed for WPA2. */
+ iebuf = ie.rsn_ie;
+ if (iebuf[0] != WLAN_EID_RSN)
+ iebuf[1] = 0;
+ }
+#endif /* MADWIFI_NG */
+ ielen = iebuf[1];
+ if (ielen == 0) {
+#ifdef CONFIG_WPS
+ if (hapd->conf->wps_state) {
+ wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE "
+ "in (Re)Association Request - possible WPS "
+ "use");
+ sta->flags |= WLAN_STA_MAYBE_WPS;
+ return 0;
+ }
+#endif /* CONFIG_WPS */
+ printf("No WPA/RSN information element for station!?\n");
+ return -1; /* XXX not right */
+ }
+ ielen += 2;
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr);
+ if (sta->wpa_sm == NULL) {
+ printf("Failed to initialize WPA state machine\n");
+ return -1;
+ }
+ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ iebuf, ielen, NULL, 0);
+ if (res != WPA_IE_OK) {
+ printf("WPA/RSN information element rejected? (res %u)\n", res);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+madwifi_new_sta(struct madwifi_driver_data *drv, u8 addr[IEEE80211_ADDR_LEN])
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct sta_info *sta;
+ int new_assoc;
+
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "associated");
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta) {
+ accounting_sta_stop(hapd, sta);
+ } else {
+ sta = ap_sta_add(hapd, addr);
+ if (sta == NULL)
+ return -1;
+ }
+
+ if (memcmp(addr, drv->acct_mac, ETH_ALEN) == 0) {
+ /* Cached accounting data is not valid anymore. */
+ memset(drv->acct_mac, 0, ETH_ALEN);
+ memset(&drv->acct_data, 0, sizeof(drv->acct_data));
+ }
+
+ if (hapd->conf->wpa) {
+ if (madwifi_process_wpa_ie(drv, sta))
+ return -1;
+ }
+
+ /*
+ * Now that the internal station state is setup
+ * kick the authenticator into action.
+ */
+ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
+ sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
+ hostapd_new_assoc_sta(hapd, sta, !new_assoc);
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+ return 0;
+}
+
+static void
+madwifi_wireless_event_wireless_custom(struct madwifi_driver_data *drv,
+ char *custom)
+{
+ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
+
+ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ char *pos;
+ u8 addr[ETH_ALEN];
+ pos = strstr(custom, "addr=");
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "without sender address ignored");
+ return;
+ }
+ pos += 5;
+ if (hwaddr_aton(pos, addr) == 0) {
+ ieee80211_michael_mic_failure(drv->hapd, addr, 1);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "with invalid MAC address");
+ }
+ } else if (strncmp(custom, "STA-TRAFFIC-STAT", 16) == 0) {
+ char *key, *value;
+ u32 val;
+ key = custom;
+ while ((key = strchr(key, '\n')) != NULL) {
+ key++;
+ value = strchr(key, '=');
+ if (value == NULL)
+ continue;
+ *value++ = '\0';
+ val = strtoul(value, NULL, 10);
+ if (strcmp(key, "mac") == 0)
+ hwaddr_aton(value, drv->acct_mac);
+ else if (strcmp(key, "rx_packets") == 0)
+ drv->acct_data.rx_packets = val;
+ else if (strcmp(key, "tx_packets") == 0)
+ drv->acct_data.tx_packets = val;
+ else if (strcmp(key, "rx_bytes") == 0)
+ drv->acct_data.rx_bytes = val;
+ else if (strcmp(key, "tx_bytes") == 0)
+ drv->acct_data.tx_bytes = val;
+ key = value;
+ }
+ }
+}
+
+static void
+madwifi_wireless_event_wireless(struct madwifi_driver_data *drv,
+ char *data, int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf;
+
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ wpa_printf(MSG_MSGDUMP, "Wireless event: cmd=0x%x len=%d",
+ iwe->cmd, iwe->len);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ return;
+
+ custom = pos + IW_EV_POINT_LEN;
+ if (drv->we_version > 18 &&
+ (iwe->cmd == IWEVMICHAELMICFAILURE ||
+ iwe->cmd == IWEVCUSTOM)) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case IWEVEXPIRED:
+ madwifi_del_sta(drv, (u8 *) iwe->u.addr.sa_data);
+ break;
+ case IWEVREGISTERED:
+ madwifi_new_sta(drv, (u8 *) iwe->u.addr.sa_data);
+ break;
+ case IWEVCUSTOM:
+ if (custom + iwe->u.data.length > end)
+ return;
+ buf = malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return; /* XXX */
+ memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+ madwifi_wireless_event_wireless_custom(drv, buf);
+ free(buf);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+
+static void
+madwifi_wireless_event_rtm_newlink(struct madwifi_driver_data *drv,
+ struct nlmsghdr *h, int len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ if (len < (int) sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ if (ifi->ifi_index != drv->ifindex)
+ return;
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ madwifi_wireless_event_wireless(
+ drv, ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void
+madwifi_wireless_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ char buf[256];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ struct madwifi_driver_data *drv = eloop_ctx;
+
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("recvfrom(netlink)");
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (left >= (int) sizeof(*h)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ printf("Malformed netlink message: "
+ "len=%d left=%d plen=%d\n",
+ len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ madwifi_wireless_event_rtm_newlink(drv, h, plen);
+ break;
+ }
+
+ len = NLMSG_ALIGN(len);
+ left -= len;
+ h = (struct nlmsghdr *) ((char *) h + len);
+ }
+
+ if (left > 0) {
+ printf("%d extra bytes in the end of netlink message\n", left);
+ }
+}
+
+
+static int
+madwifi_get_we_version(struct madwifi_driver_data *drv)
+{
+ struct iw_range *range;
+ struct iwreq iwr;
+ int minlen;
+ size_t buflen;
+
+ drv->we_version = 0;
+
+ /*
+ * Use larger buffer than struct iw_range in order to allow the
+ * structure to grow in the future.
+ */
+ buflen = sizeof(struct iw_range) + 500;
+ range = os_zalloc(buflen);
+ if (range == NULL)
+ return -1;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buflen;
+
+ minlen = ((char *) &range->enc_capa) - (char *) range +
+ sizeof(range->enc_capa);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWRANGE]");
+ free(range);
+ return -1;
+ } else if (iwr.u.data.length >= minlen &&
+ range->we_version_compiled >= 18) {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+ "WE(source)=%d enc_capa=0x%x",
+ range->we_version_compiled,
+ range->we_version_source,
+ range->enc_capa);
+ drv->we_version = range->we_version_compiled;
+ }
+
+ free(range);
+ return 0;
+}
+
+
+static int
+madwifi_wireless_event_init(void *priv)
+{
+ struct madwifi_driver_data *drv = priv;
+ int s;
+ struct sockaddr_nl local;
+
+ madwifi_get_we_version(drv);
+
+ drv->wext_sock = -1;
+
+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (s < 0) {
+ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+ return -1;
+ }
+
+ memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ perror("bind(netlink)");
+ close(s);
+ return -1;
+ }
+
+ eloop_register_read_sock(s, madwifi_wireless_event_receive, drv, NULL);
+ drv->wext_sock = s;
+
+ return 0;
+}
+
+
+static void
+madwifi_wireless_event_deinit(void *priv)
+{
+ struct madwifi_driver_data *drv = priv;
+
+ if (drv != NULL) {
+ if (drv->wext_sock < 0)
+ return;
+ eloop_unregister_read_sock(drv->wext_sock);
+ close(drv->wext_sock);
+ }
+}
+
+
+static int
+madwifi_send_eapol(void *priv, const u8 *addr, const u8 *data, size_t data_len,
+ int encrypt, const u8 *own_addr)
+{
+ struct madwifi_driver_data *drv = priv;
+ unsigned char buf[3000];
+ unsigned char *bp = buf;
+ struct l2_ethhdr *eth;
+ size_t len;
+ int status;
+
+ /*
+ * Prepend the Ethernet header. If the caller left us
+ * space at the front we could just insert it but since
+ * we don't know we copy to a local buffer. Given the frequency
+ * and size of frames this probably doesn't matter.
+ */
+ len = data_len + sizeof(struct l2_ethhdr);
+ if (len > sizeof(buf)) {
+ bp = malloc(len);
+ if (bp == NULL) {
+ printf("EAPOL frame discarded, cannot malloc temp "
+ "buffer of size %lu!\n", (unsigned long) len);
+ return -1;
+ }
+ }
+ eth = (struct l2_ethhdr *) bp;
+ memcpy(eth->h_dest, addr, ETH_ALEN);
+ memcpy(eth->h_source, own_addr, ETH_ALEN);
+ eth->h_proto = htons(ETH_P_EAPOL);
+ memcpy(eth+1, data, data_len);
+
+ wpa_hexdump(MSG_MSGDUMP, "TX EAPOL", bp, len);
+
+ status = l2_packet_send(drv->sock_xmit, addr, ETH_P_EAPOL, bp, len);
+
+ if (bp != buf)
+ free(bp);
+ return status;
+}
+
+static void
+handle_read(void *ctx, const u8 *src_addr, const u8 *buf, size_t len)
+{
+ struct madwifi_driver_data *drv = ctx;
+ struct hostapd_data *hapd = drv->hapd;
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, src_addr);
+ if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
+ printf("Data frame from not associated STA %s\n",
+ ether_sprintf(src_addr));
+ /* XXX cannot happen */
+ return;
+ }
+ ieee802_1x_receive(hapd, src_addr, buf + sizeof(struct l2_ethhdr),
+ len - sizeof(struct l2_ethhdr));
+}
+
+static void *
+madwifi_init(struct hostapd_data *hapd)
+{
+ struct madwifi_driver_data *drv;
+ struct ifreq ifr;
+ struct iwreq iwr;
+
+ drv = os_zalloc(sizeof(struct madwifi_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for madwifi driver data\n");
+ return NULL;
+ }
+
+ drv->hapd = hapd;
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket[PF_INET,SOCK_DGRAM]");
+ goto bad;
+ }
+ memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface));
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
+ if (ioctl(drv->ioctl_sock, SIOCGIFINDEX, &ifr) != 0) {
+ perror("ioctl(SIOCGIFINDEX)");
+ goto bad;
+ }
+ drv->ifindex = ifr.ifr_ifindex;
+
+ drv->sock_xmit = l2_packet_init(drv->iface, NULL, ETH_P_EAPOL,
+ handle_read, drv, 1);
+ if (drv->sock_xmit == NULL)
+ goto bad;
+ if (l2_packet_get_own_addr(drv->sock_xmit, hapd->own_addr))
+ goto bad;
+ if (hapd->conf->bridge[0] != '\0') {
+ wpa_printf(MSG_DEBUG, "Configure bridge %s for EAPOL traffic.",
+ hapd->conf->bridge);
+ drv->sock_recv = l2_packet_init(hapd->conf->bridge, NULL,
+ ETH_P_EAPOL, handle_read, drv,
+ 1);
+ if (drv->sock_recv == NULL)
+ goto bad;
+ } else
+ drv->sock_recv = drv->sock_xmit;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+
+ iwr.u.mode = IW_MODE_MASTER;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWMODE]");
+ printf("Could not set interface to master mode!\n");
+ goto bad;
+ }
+
+ madwifi_set_iface_flags(drv, 0); /* mark down during setup */
+ madwifi_set_privacy(drv->iface, drv, 0); /* default to no privacy */
+
+ madwifi_receive_probe_req(drv);
+
+ return drv;
+bad:
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+ if (drv != NULL)
+ free(drv);
+ return NULL;
+}
+
+
+static void
+madwifi_deinit(void *priv)
+{
+ struct madwifi_driver_data *drv = priv;
+
+ (void) madwifi_set_iface_flags(drv, 0);
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+ if (drv->sock_recv != NULL && drv->sock_recv != drv->sock_xmit)
+ l2_packet_deinit(drv->sock_recv);
+ if (drv->sock_xmit != NULL)
+ l2_packet_deinit(drv->sock_xmit);
+ if (drv->sock_raw)
+ l2_packet_deinit(drv->sock_raw);
+ free(drv);
+}
+
+static int
+madwifi_set_ssid(const char *ifname, void *priv, const u8 *buf, int len)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.essid.flags = 1; /* SSID active */
+ iwr.u.essid.pointer = (caddr_t) buf;
+ iwr.u.essid.length = len + 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCSIWESSID]");
+ printf("len=%d\n", len);
+ return -1;
+ }
+ return 0;
+}
+
+static int
+madwifi_get_ssid(const char *ifname, void *priv, u8 *buf, int len)
+{
+ struct madwifi_driver_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.essid.pointer = (caddr_t) buf;
+ iwr.u.essid.length = len;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCGIWESSID]");
+ ret = -1;
+ } else
+ ret = iwr.u.essid.length;
+
+ return ret;
+}
+
+static int
+madwifi_set_countermeasures(void *priv, int enabled)
+{
+ struct madwifi_driver_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled);
+}
+
+static int
+madwifi_commit(void *priv)
+{
+ return madwifi_set_iface_flags(priv, 1);
+}
+
+const struct wpa_driver_ops wpa_driver_madwifi_ops = {
+ .name = "madwifi",
+ .init = madwifi_init,
+ .deinit = madwifi_deinit,
+ .set_ieee8021x = madwifi_set_ieee8021x,
+ .set_privacy = madwifi_set_privacy,
+ .set_encryption = madwifi_set_key,
+ .get_seqnum = madwifi_get_seqnum,
+ .flush = madwifi_flush,
+ .set_generic_elem = madwifi_set_opt_ie,
+ .wireless_event_init = madwifi_wireless_event_init,
+ .wireless_event_deinit = madwifi_wireless_event_deinit,
+ .sta_set_flags = madwifi_sta_set_flags,
+ .read_sta_data = madwifi_read_sta_driver_data,
+ .send_eapol = madwifi_send_eapol,
+ .sta_disassoc = madwifi_sta_disassoc,
+ .sta_deauth = madwifi_sta_deauth,
+ .set_ssid = madwifi_set_ssid,
+ .get_ssid = madwifi_get_ssid,
+ .set_countermeasures = madwifi_set_countermeasures,
+ .sta_clear_stats = madwifi_sta_clear_stats,
+ .commit = madwifi_commit,
+ .set_wps_beacon_ie = madwifi_set_wps_beacon_ie,
+ .set_wps_probe_resp_ie = madwifi_set_wps_probe_resp_ie,
+};
diff --git a/hostapd/driver_nl80211.c b/hostapd/driver_nl80211.c
new file mode 100644
index 0000000..4599e99
--- /dev/null
+++ b/hostapd/driver_nl80211.c
@@ -0,0 +1,2708 @@
+/*
+ * hostapd / Kernel driver communication via nl80211
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2007, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include <sys/ioctl.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/msg.h>
+#include <netlink/attr.h>
+#include "nl80211_copy.h"
+#include <net/if.h>
+#include <netpacket/packet.h>
+#include "wireless_copy.h"
+#include <linux/filter.h>
+#include <net/if_arp.h>
+
+#include "hostapd.h"
+#include "driver.h"
+#include "ieee802_1x.h"
+#include "eloop.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "hw_features.h"
+#include "mlme.h"
+#include "radiotap.h"
+#include "radiotap_iter.h"
+
+#ifdef CONFIG_LIBNL20
+/* libnl 2.0 compatibility code */
+#define nl_handle_alloc_cb nl_socket_alloc_cb
+#define nl_handle_destroy nl_socket_free
+#endif /* CONFIG_LIBNL20 */
+
+enum ieee80211_msg_type {
+ ieee80211_msg_normal = 0,
+ ieee80211_msg_tx_callback_ack = 1,
+ ieee80211_msg_tx_callback_fail = 2,
+};
+
+struct i802_driver_data {
+ struct hostapd_data *hapd;
+
+ char iface[IFNAMSIZ + 1];
+ int bridge;
+ int ioctl_sock; /* socket for ioctl() use */
+ int wext_sock; /* socket for wireless events */
+ int eapol_sock; /* socket for EAPOL frames */
+ int monitor_sock; /* socket for monitor */
+ int monitor_ifidx;
+
+ int default_if_indices[16];
+ int *if_indices;
+ int num_if_indices;
+
+ int we_version;
+ struct nl_handle *nl_handle;
+ struct nl_cache *nl_cache;
+ struct nl_cb *nl_cb;
+ struct genl_family *nl80211;
+ int dtim_period, beacon_int;
+ unsigned int beacon_set:1;
+ unsigned int ieee802_1x_active:1;
+
+ int last_freq;
+ int last_freq_ht;
+};
+
+
+static void add_ifidx(struct i802_driver_data *drv, int ifidx)
+{
+ int i;
+ int *old;
+
+ for (i = 0; i < drv->num_if_indices; i++) {
+ if (drv->if_indices[i] == 0) {
+ drv->if_indices[i] = ifidx;
+ return;
+ }
+ }
+
+ if (drv->if_indices != drv->default_if_indices)
+ old = drv->if_indices;
+ else
+ old = NULL;
+
+ drv->if_indices = realloc(old,
+ sizeof(int) * (drv->num_if_indices + 1));
+ if (!drv->if_indices) {
+ if (!old)
+ drv->if_indices = drv->default_if_indices;
+ else
+ drv->if_indices = old;
+ wpa_printf(MSG_ERROR, "Failed to reallocate memory for "
+ "interfaces");
+ wpa_printf(MSG_ERROR, "Ignoring EAPOL on interface %d", ifidx);
+ return;
+ }
+ drv->if_indices[drv->num_if_indices] = ifidx;
+ drv->num_if_indices++;
+}
+
+
+static void del_ifidx(struct i802_driver_data *drv, int ifidx)
+{
+ int i;
+
+ for (i = 0; i < drv->num_if_indices; i++) {
+ if (drv->if_indices[i] == ifidx) {
+ drv->if_indices[i] = 0;
+ break;
+ }
+ }
+}
+
+
+static int have_ifidx(struct i802_driver_data *drv, int ifidx)
+{
+ int i;
+
+ if (ifidx == drv->bridge)
+ return 1;
+
+ for (i = 0; i < drv->num_if_indices; i++)
+ if (drv->if_indices[i] == ifidx)
+ return 1;
+
+ return 0;
+}
+
+
+/* nl80211 code */
+static int ack_handler(struct nl_msg *msg, void *arg)
+{
+ int *err = arg;
+ *err = 0;
+ return NL_STOP;
+}
+
+static int finish_handler(struct nl_msg *msg, void *arg)
+{
+ int *ret = arg;
+ *ret = 0;
+ return NL_SKIP;
+}
+
+static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
+ void *arg)
+{
+ int *ret = arg;
+ *ret = err->error;
+ return NL_SKIP;
+}
+
+static int send_and_recv_msgs(struct i802_driver_data *drv,
+ struct nl_msg *msg,
+ int (*valid_handler)(struct nl_msg *, void *),
+ void *valid_data)
+{
+ struct nl_cb *cb;
+ int err = -ENOMEM;
+
+ cb = nl_cb_clone(drv->nl_cb);
+ if (!cb)
+ goto out;
+
+ err = nl_send_auto_complete(drv->nl_handle, msg);
+ if (err < 0)
+ goto out;
+
+ err = 1;
+
+ nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+
+ if (valid_handler)
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
+ valid_handler, valid_data);
+
+ while (err > 0)
+ nl_recvmsgs(drv->nl_handle, cb);
+ out:
+ nl_cb_put(cb);
+ nlmsg_free(msg);
+ return err;
+}
+
+static int hostapd_set_iface_flags(struct i802_driver_data *drv,
+ const char *ifname, int dev_up)
+{
+ struct ifreq ifr;
+
+ if (drv->ioctl_sock < 0)
+ return -1;
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ wpa_printf(MSG_DEBUG, "Could not read interface flags (%s)",
+ drv->iface);
+ return -1;
+ }
+
+ if (dev_up)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCSIFFLAGS]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int nl_set_encr(int ifindex, struct i802_driver_data *drv,
+ const char *alg, const u8 *addr, int idx, const u8 *key,
+ size_t key_len, int txkey)
+{
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ if (strcmp(alg, "none") == 0) {
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_KEY, 0);
+ } else {
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_NEW_KEY, 0);
+ NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
+ if (strcmp(alg, "WEP") == 0) {
+ if (key_len == 5)
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ 0x000FAC01);
+ else
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ 0x000FAC05);
+ } else if (strcmp(alg, "TKIP") == 0)
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02);
+ else if (strcmp(alg, "CCMP") == 0)
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04);
+ else if (strcmp(alg, "IGTK") == 0)
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC06);
+ else {
+ wpa_printf(MSG_ERROR, "%s: Unsupported encryption "
+ "algorithm '%s'", __func__, alg);
+ nlmsg_free(msg);
+ return -1;
+ }
+ }
+
+ if (addr)
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret == -ENOENT)
+ ret = 0;
+
+ /*
+ * If we failed or don't need to set the default TX key (below),
+ * we're done here.
+ */
+ if (ret || !txkey || addr)
+ return ret;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_KEY, 0);
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifindex);
+ if (strcmp(alg, "IGTK") == 0)
+ NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT_MGMT);
+ else
+ NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret == -ENOENT)
+ ret = 0;
+ return ret;
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int i802_set_encryption(const char *iface, void *priv, const char *alg,
+ const u8 *addr, int idx, const u8 *key,
+ size_t key_len, int txkey)
+{
+ struct i802_driver_data *drv = priv;
+ int ret;
+
+ ret = nl_set_encr(if_nametoindex(iface), drv, alg, addr, idx, key,
+ key_len, txkey);
+ if (ret < 0)
+ return ret;
+
+ return ret;
+}
+
+
+static inline int min_int(int a, int b)
+{
+ if (a < b)
+ return a;
+ return b;
+}
+
+
+static int get_key_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ /*
+ * TODO: validate the key index and mac address!
+ * Otherwise, there's a race condition as soon as
+ * the kernel starts sending key notifications.
+ */
+
+ if (tb[NL80211_ATTR_KEY_SEQ])
+ memcpy(arg, nla_data(tb[NL80211_ATTR_KEY_SEQ]),
+ min_int(nla_len(tb[NL80211_ATTR_KEY_SEQ]), 6));
+ return NL_SKIP;
+}
+
+
+static int i802_get_seqnum(const char *iface, void *priv, const u8 *addr,
+ int idx, u8 *seq)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_GET_KEY, 0);
+
+ if (addr)
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
+
+ memset(seq, 0, 6);
+
+ return send_and_recv_msgs(drv, msg, get_key_handler, seq);
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int i802_set_rate_sets(void *priv, int *supp_rates, int *basic_rates,
+ int mode)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ u8 rates[NL80211_MAX_SUPP_RATES];
+ u8 rates_len = 0;
+ int i;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_SET_BSS, 0);
+
+ for (i = 0; i < NL80211_MAX_SUPP_RATES && basic_rates[i] >= 0; i++)
+ rates[rates_len++] = basic_rates[i] / 5;
+
+ NLA_PUT(msg, NL80211_ATTR_BSS_BASIC_RATES, rates_len, rates);
+
+ /* TODO: multi-BSS support */
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int i802_send_frame(void *priv, const void *data, size_t len,
+ int encrypt, int flags)
+{
+ __u8 rtap_hdr[] = {
+ 0x00, 0x00, /* radiotap version */
+ 0x0e, 0x00, /* radiotap length */
+ 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
+ IEEE80211_RADIOTAP_F_FRAG, /* F_FRAG (fragment if required) */
+ 0x00, /* padding */
+ 0x00, 0x00, /* RX and TX flags to indicate that */
+ 0x00, 0x00, /* this is the injected frame directly */
+ };
+ struct i802_driver_data *drv = priv;
+ struct iovec iov[2] = {
+ {
+ .iov_base = &rtap_hdr,
+ .iov_len = sizeof(rtap_hdr),
+ },
+ {
+ .iov_base = (void*)data,
+ .iov_len = len,
+ }
+ };
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = iov,
+ .msg_iovlen = 2,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_flags = 0,
+ };
+
+ if (encrypt)
+ rtap_hdr[8] |= IEEE80211_RADIOTAP_F_WEP;
+
+ return sendmsg(drv->monitor_sock, &msg, flags);
+}
+
+static int i802_send_mgmt_frame(void *priv, const void *data, size_t len,
+ int flags)
+{
+ struct ieee80211_mgmt *mgmt;
+ int do_not_encrypt = 0;
+ u16 fc;
+
+ mgmt = (struct ieee80211_mgmt *) data;
+ fc = le_to_host16(mgmt->frame_control);
+
+ if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+ WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_AUTH) {
+ /*
+ * Only one of the authentication frame types is encrypted.
+ * In order for static WEP encryption to work properly (i.e.,
+ * to not encrypt the frame), we need to tell mac80211 about
+ * the frames that must not be encrypted.
+ */
+ u16 auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
+ u16 auth_trans = le_to_host16(mgmt->u.auth.auth_transaction);
+ if (auth_alg == WLAN_AUTH_OPEN ||
+ (auth_alg == WLAN_AUTH_SHARED_KEY && auth_trans != 3))
+ do_not_encrypt = 1;
+ }
+
+ return i802_send_frame(priv, data, len, !do_not_encrypt, flags);
+}
+
+/* Set kernel driver on given frequency (MHz) */
+static int i802_set_freq2(void *priv, struct hostapd_freq_params *freq)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ drv->last_freq = freq->freq;
+ drv->last_freq_ht = freq->ht_enabled;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_SET_WIPHY, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_FREQ, freq->freq);
+ if (freq->ht_enabled) {
+ switch (freq->sec_channel_offset) {
+ case -1:
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ NL80211_CHAN_HT40MINUS);
+ break;
+ case 1:
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ NL80211_CHAN_HT40PLUS);
+ break;
+ default:
+ NLA_PUT_U32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+ NL80211_CHAN_HT20);
+ break;
+ }
+ }
+
+ if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+ return 0;
+ nla_put_failure:
+ return -1;
+}
+
+
+static int i802_set_rts(void *priv, int rts)
+{
+ struct i802_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ);
+ iwr.u.rts.value = rts;
+ iwr.u.rts.fixed = 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWRTS, &iwr) < 0) {
+ perror("ioctl[SIOCSIWRTS]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int i802_get_rts(void *priv, int *rts)
+{
+ struct i802_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRTS, &iwr) < 0) {
+ perror("ioctl[SIOCGIWRTS]");
+ return -1;
+ }
+
+ *rts = iwr.u.rts.value;
+
+ return 0;
+}
+
+
+static int i802_set_frag(void *priv, int frag)
+{
+ struct i802_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ);
+ iwr.u.frag.value = frag;
+ iwr.u.frag.fixed = 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWFRAG, &iwr) < 0) {
+ perror("ioctl[SIOCSIWFRAG]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int i802_get_frag(void *priv, int *frag)
+{
+ struct i802_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWFRAG, &iwr) < 0) {
+ perror("ioctl[SIOCGIWFRAG]");
+ return -1;
+ }
+
+ *frag = iwr.u.frag.value;
+
+ return 0;
+}
+
+
+static int i802_set_retry(void *priv, int short_retry, int long_retry)
+{
+ struct i802_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ);
+
+ iwr.u.retry.value = short_retry;
+ iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
+ if (ioctl(drv->ioctl_sock, SIOCSIWRETRY, &iwr) < 0) {
+ perror("ioctl[SIOCSIWRETRY(short)]");
+ return -1;
+ }
+
+ iwr.u.retry.value = long_retry;
+ iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ if (ioctl(drv->ioctl_sock, SIOCSIWRETRY, &iwr) < 0) {
+ perror("ioctl[SIOCSIWRETRY(long)]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int i802_get_retry(void *priv, int *short_retry, int *long_retry)
+{
+ struct i802_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->hapd->conf->iface, IFNAMSIZ);
+
+ iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
+ if (ioctl(drv->ioctl_sock, SIOCGIWRETRY, &iwr) < 0) {
+ perror("ioctl[SIOCGIWFRAG(short)]");
+ return -1;
+ }
+ *short_retry = iwr.u.retry.value;
+
+ iwr.u.retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
+ if (ioctl(drv->ioctl_sock, SIOCGIWRETRY, &iwr) < 0) {
+ perror("ioctl[SIOCGIWFRAG(long)]");
+ return -1;
+ }
+ *long_retry = iwr.u.retry.value;
+
+ return 0;
+}
+
+
+static int i802_flush(void *priv)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_STATION, 0);
+
+ /*
+ * XXX: FIX! this needs to flush all VLANs too
+ */
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->iface));
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int get_sta_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct hostap_sta_driver_data *data = arg;
+ struct nlattr *stats[NL80211_STA_INFO_MAX + 1];
+ static struct nla_policy stats_policy[NL80211_STA_INFO_MAX + 1] = {
+ [NL80211_STA_INFO_INACTIVE_TIME] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_RX_BYTES] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_TX_BYTES] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_RX_PACKETS] = { .type = NLA_U32 },
+ [NL80211_STA_INFO_TX_PACKETS] = { .type = NLA_U32 },
+ };
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ /*
+ * TODO: validate the interface and mac address!
+ * Otherwise, there's a race condition as soon as
+ * the kernel starts sending station notifications.
+ */
+
+ if (!tb[NL80211_ATTR_STA_INFO]) {
+ wpa_printf(MSG_DEBUG, "sta stats missing!");
+ return NL_SKIP;
+ }
+ if (nla_parse_nested(stats, NL80211_STA_INFO_MAX,
+ tb[NL80211_ATTR_STA_INFO],
+ stats_policy)) {
+ wpa_printf(MSG_DEBUG, "failed to parse nested attributes!");
+ return NL_SKIP;
+ }
+
+ if (stats[NL80211_STA_INFO_INACTIVE_TIME])
+ data->inactive_msec =
+ nla_get_u32(stats[NL80211_STA_INFO_INACTIVE_TIME]);
+ if (stats[NL80211_STA_INFO_RX_BYTES])
+ data->rx_bytes = nla_get_u32(stats[NL80211_STA_INFO_RX_BYTES]);
+ if (stats[NL80211_STA_INFO_TX_BYTES])
+ data->tx_bytes = nla_get_u32(stats[NL80211_STA_INFO_TX_BYTES]);
+ if (stats[NL80211_STA_INFO_RX_PACKETS])
+ data->rx_packets =
+ nla_get_u32(stats[NL80211_STA_INFO_RX_PACKETS]);
+ if (stats[NL80211_STA_INFO_TX_PACKETS])
+ data->tx_packets =
+ nla_get_u32(stats[NL80211_STA_INFO_TX_PACKETS]);
+
+ return NL_SKIP;
+}
+
+static int i802_read_sta_data(void *priv, struct hostap_sta_driver_data *data,
+ const u8 *addr)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+
+ os_memset(data, 0, sizeof(*data));
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_GET_STATION, 0);
+
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
+
+ return send_and_recv_msgs(drv, msg, get_sta_handler, data);
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int i802_send_eapol(void *priv, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt, const u8 *own_addr)
+{
+ struct i802_driver_data *drv = priv;
+ struct ieee80211_hdr *hdr;
+ size_t len;
+ u8 *pos;
+ int res;
+#if 0 /* FIX */
+ int qos = sta->flags & WLAN_STA_WME;
+#else
+ int qos = 0;
+#endif
+
+ len = sizeof(*hdr) + (qos ? 2 : 0) + sizeof(rfc1042_header) + 2 +
+ data_len;
+ hdr = os_zalloc(len);
+ if (hdr == NULL) {
+ printf("malloc() failed for i802_send_data(len=%lu)\n",
+ (unsigned long) len);
+ return -1;
+ }
+
+ hdr->frame_control =
+ IEEE80211_FC(WLAN_FC_TYPE_DATA, WLAN_FC_STYPE_DATA);
+ hdr->frame_control |= host_to_le16(WLAN_FC_FROMDS);
+ if (encrypt)
+ hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+#if 0 /* To be enabled if qos determination is added above */
+ if (qos) {
+ hdr->frame_control |=
+ host_to_le16(WLAN_FC_STYPE_QOS_DATA << 4);
+ }
+#endif
+
+ memcpy(hdr->IEEE80211_DA_FROMDS, addr, ETH_ALEN);
+ memcpy(hdr->IEEE80211_BSSID_FROMDS, own_addr, ETH_ALEN);
+ memcpy(hdr->IEEE80211_SA_FROMDS, own_addr, ETH_ALEN);
+ pos = (u8 *) (hdr + 1);
+
+#if 0 /* To be enabled if qos determination is added above */
+ if (qos) {
+ /* add an empty QoS header if needed */
+ pos[0] = 0;
+ pos[1] = 0;
+ pos += 2;
+ }
+#endif
+
+ memcpy(pos, rfc1042_header, sizeof(rfc1042_header));
+ pos += sizeof(rfc1042_header);
+ WPA_PUT_BE16(pos, ETH_P_PAE);
+ pos += 2;
+ memcpy(pos, data, data_len);
+
+ res = i802_send_frame(drv, (u8 *) hdr, len, encrypt, 0);
+ free(hdr);
+
+ if (res < 0) {
+ perror("i802_send_eapol: send");
+ printf("i802_send_eapol - packet len: %lu - failed\n",
+ (unsigned long) len);
+ }
+
+ return res;
+}
+
+
+static int i802_sta_add2(const char *ifname, void *priv,
+ struct hostapd_sta_add_params *params)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_NEW_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->iface));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, params->addr);
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, params->aid);
+ NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, params->supp_rates_len,
+ params->supp_rates);
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL,
+ params->listen_interval);
+
+#ifdef CONFIG_IEEE80211N
+ if (params->ht_capabilities) {
+ NLA_PUT(msg, NL80211_ATTR_HT_CAPABILITY,
+ params->ht_capabilities->length,
+ &params->ht_capabilities->data);
+ }
+#endif /* CONFIG_IEEE80211N */
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret)
+ wpa_printf(MSG_DEBUG, "nl80211: NL80211_CMD_NEW_STATION "
+ "result: %d (%s)", ret, strerror(-ret));
+ if (ret == -EEXIST)
+ ret = 0;
+ nla_put_failure:
+ return ret;
+}
+
+
+static int i802_sta_remove(void *priv, const u8 *addr)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ int ret;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->iface));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret == -ENOENT)
+ return 0;
+ return ret;
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int i802_sta_set_flags(void *priv, const u8 *addr,
+ int total_flags, int flags_or, int flags_and)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg, *flags = NULL;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ flags = nlmsg_alloc();
+ if (!flags) {
+ nlmsg_free(msg);
+ return -ENOMEM;
+ }
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->iface));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+ if (total_flags & WLAN_STA_AUTHORIZED || !drv->ieee802_1x_active)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_AUTHORIZED);
+
+ if (total_flags & WLAN_STA_WMM)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_WME);
+
+ if (total_flags & WLAN_STA_SHORT_PREAMBLE)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_SHORT_PREAMBLE);
+
+ if (total_flags & WLAN_STA_MFP)
+ NLA_PUT_FLAG(flags, NL80211_STA_FLAG_MFP);
+
+ if (nla_put_nested(msg, NL80211_ATTR_STA_FLAGS, flags))
+ goto nla_put_failure;
+
+ nlmsg_free(flags);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+ nlmsg_free(flags);
+ return -ENOBUFS;
+}
+
+
+static int i802_set_regulatory_domain(void *priv, unsigned int rd)
+{
+ return -1;
+}
+
+
+static int i802_set_tx_queue_params(void *priv, int queue, int aifs,
+ int cw_min, int cw_max, int burst_time)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ struct nlattr *txq, *params;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_WIPHY, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
+
+ txq = nla_nest_start(msg, NL80211_ATTR_WIPHY_TXQ_PARAMS);
+ if (!txq)
+ goto nla_put_failure;
+
+ /* We are only sending parameters for a single TXQ at a time */
+ params = nla_nest_start(msg, 1);
+ if (!params)
+ goto nla_put_failure;
+
+ NLA_PUT_U8(msg, NL80211_TXQ_ATTR_QUEUE, queue);
+ /* Burst time is configured in units of 0.1 msec and TXOP parameter in
+ * 32 usec, so need to convert the value here. */
+ NLA_PUT_U16(msg, NL80211_TXQ_ATTR_TXOP, (burst_time * 100 + 16) / 32);
+ NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMIN, cw_min);
+ NLA_PUT_U16(msg, NL80211_TXQ_ATTR_CWMAX, cw_max);
+ NLA_PUT_U8(msg, NL80211_TXQ_ATTR_AIFS, aifs);
+
+ nla_nest_end(msg, params);
+
+ nla_nest_end(msg, txq);
+
+ if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+ return 0;
+ nla_put_failure:
+ return -1;
+}
+
+
+static void nl80211_remove_iface(struct i802_driver_data *drv, int ifidx)
+{
+ struct nl_msg *msg;
+
+ /* stop listening for EAPOL on this interface */
+ del_ifidx(drv, ifidx);
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto nla_put_failure;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
+
+ if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+ return;
+ nla_put_failure:
+ printf("Failed to remove interface.\n");
+}
+
+
+static int nl80211_create_iface(struct i802_driver_data *drv,
+ const char *ifname,
+ enum nl80211_iftype iftype,
+ const u8 *addr)
+{
+ struct nl_msg *msg, *flags = NULL;
+ int ifidx;
+ struct ifreq ifreq;
+ struct iwreq iwr;
+ int ret = -ENOBUFS;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_NEW_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->hapd->conf->iface));
+ NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
+
+ if (iftype == NL80211_IFTYPE_MONITOR) {
+ int err;
+
+ flags = nlmsg_alloc();
+ if (!flags)
+ goto nla_put_failure;
+
+ NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
+
+ err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
+
+ nlmsg_free(flags);
+
+ if (err)
+ goto nla_put_failure;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ nla_put_failure:
+ printf("Failed to create interface %s.\n", ifname);
+ return ret;
+ }
+
+ ifidx = if_nametoindex(ifname);
+
+ if (ifidx <= 0)
+ return -1;
+
+ /* start listening for EAPOL on this interface */
+ add_ifidx(drv, ifidx);
+
+ if (addr) {
+ switch (iftype) {
+ case NL80211_IFTYPE_AP:
+ os_strlcpy(ifreq.ifr_name, ifname, IFNAMSIZ);
+ memcpy(ifreq.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+ ifreq.ifr_hwaddr.sa_family = ARPHRD_ETHER;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifreq)) {
+ nl80211_remove_iface(drv, ifidx);
+ return -1;
+ }
+ break;
+ case NL80211_IFTYPE_WDS:
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ);
+ iwr.u.addr.sa_family = ARPHRD_ETHER;
+ memcpy(iwr.u.addr.sa_data, addr, ETH_ALEN);
+ if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr))
+ return -1;
+ break;
+ default:
+ /* nothing */
+ break;
+ }
+ }
+
+ return ifidx;
+}
+
+
+static int i802_bss_add(void *priv, const char *ifname, const u8 *bssid)
+{
+ int ifidx;
+
+ /*
+ * The kernel supports that when the low-level driver does,
+ * but we currently don't because we need per-BSS data that
+ * currently we can't handle easily.
+ */
+ return -1;
+
+ ifidx = nl80211_create_iface(priv, ifname, NL80211_IFTYPE_AP, bssid);
+ if (ifidx < 0)
+ return -1;
+ if (hostapd_set_iface_flags(priv, ifname, 1)) {
+ nl80211_remove_iface(priv, ifidx);
+ return -1;
+ }
+ return 0;
+}
+
+
+static int i802_bss_remove(void *priv, const char *ifname)
+{
+ nl80211_remove_iface(priv, if_nametoindex(ifname));
+ return 0;
+}
+
+
+static int i802_set_beacon(const char *iface, void *priv,
+ u8 *head, size_t head_len,
+ u8 *tail, size_t tail_len)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ u8 cmd = NL80211_CMD_NEW_BEACON;
+ int ret;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ if (drv->beacon_set)
+ cmd = NL80211_CMD_SET_BEACON;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, cmd, 0);
+ NLA_PUT(msg, NL80211_ATTR_BEACON_HEAD, head_len, head);
+ NLA_PUT(msg, NL80211_ATTR_BEACON_TAIL, tail_len, tail);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
+ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, drv->beacon_int);
+
+ if (!drv->dtim_period)
+ drv->dtim_period = 2;
+ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (!ret)
+ drv->beacon_set = 1;
+ return ret;
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int i802_del_beacon(struct i802_driver_data *drv)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_BEACON, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int i802_set_ieee8021x(const char *ifname, void *priv, int enabled)
+{
+ struct i802_driver_data *drv = priv;
+
+ /*
+ * FIXME: This needs to be per interface (BSS)
+ */
+ drv->ieee802_1x_active = enabled;
+ return 0;
+}
+
+
+static int i802_set_privacy(const char *ifname, void *priv, int enabled)
+{
+ struct i802_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+
+ os_strlcpy(iwr.ifr_name, ifname, IFNAMSIZ);
+ iwr.u.param.flags = IW_AUTH_PRIVACY_INVOKED;
+ iwr.u.param.value = enabled;
+
+ ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr);
+
+ /* ignore errors, the kernel/driver might not care */
+ return 0;
+}
+
+
+static int i802_set_internal_bridge(void *priv, int value)
+{
+ return -1;
+}
+
+
+static int i802_set_beacon_int(void *priv, int value)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+
+ drv->beacon_int = value;
+
+ if (!drv->beacon_set)
+ return 0;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_BEACON, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
+
+ NLA_PUT_U32(msg, NL80211_ATTR_BEACON_INTERVAL, value);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int i802_set_dtim_period(const char *iface, void *priv, int value)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_BEACON, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(iface));
+
+ drv->dtim_period = value;
+ NLA_PUT_U32(msg, NL80211_ATTR_DTIM_PERIOD, drv->dtim_period);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int i802_set_bss(void *priv, int cts, int preamble, int slot)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_SET_BSS, 0);
+
+ if (cts >= 0)
+ NLA_PUT_U8(msg, NL80211_ATTR_BSS_CTS_PROT, cts);
+ if (preamble >= 0)
+ NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_PREAMBLE, preamble);
+ if (slot >= 0)
+ NLA_PUT_U8(msg, NL80211_ATTR_BSS_SHORT_SLOT_TIME, slot);
+
+ /* TODO: multi-BSS support */
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int i802_set_cts_protect(void *priv, int value)
+{
+ return i802_set_bss(priv, value, -1, -1);
+}
+
+
+static int i802_set_preamble(void *priv, int value)
+{
+ return i802_set_bss(priv, -1, value, -1);
+}
+
+
+static int i802_set_short_slot_time(void *priv, int value)
+{
+ return i802_set_bss(priv, -1, -1, value);
+}
+
+
+static enum nl80211_iftype i802_if_type(enum hostapd_driver_if_type type)
+{
+ switch (type) {
+ case HOSTAPD_IF_VLAN:
+ return NL80211_IFTYPE_AP_VLAN;
+ case HOSTAPD_IF_WDS:
+ return NL80211_IFTYPE_WDS;
+ }
+ return -1;
+}
+
+
+static int i802_if_add(const char *iface, void *priv,
+ enum hostapd_driver_if_type type, char *ifname,
+ const u8 *addr)
+{
+ if (nl80211_create_iface(priv, ifname, i802_if_type(type), addr) < 0)
+ return -1;
+ return 0;
+}
+
+
+static int i802_if_update(void *priv, enum hostapd_driver_if_type type,
+ char *ifname, const u8 *addr)
+{
+ /* unused at the moment */
+ return -1;
+}
+
+
+static int i802_if_remove(void *priv, enum hostapd_driver_if_type type,
+ const char *ifname, const u8 *addr)
+{
+ nl80211_remove_iface(priv, if_nametoindex(ifname));
+ return 0;
+}
+
+
+struct phy_info_arg {
+ u16 *num_modes;
+ struct hostapd_hw_modes *modes;
+};
+
+static int phy_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct phy_info_arg *phy_info = arg;
+
+ struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+
+ struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
+ static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1] = {
+ [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = { .type = NLA_U32 },
+ };
+
+ struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
+ static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
+ [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
+ [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] = { .type = NLA_FLAG },
+ };
+
+ struct nlattr *nl_band;
+ struct nlattr *nl_freq;
+ struct nlattr *nl_rate;
+ int rem_band, rem_freq, rem_rate;
+ struct hostapd_hw_modes *mode;
+ int idx, mode_is_set;
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+ return NL_SKIP;
+
+ nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS], rem_band) {
+ mode = realloc(phy_info->modes, (*phy_info->num_modes + 1) * sizeof(*mode));
+ if (!mode)
+ return NL_SKIP;
+ phy_info->modes = mode;
+
+ mode_is_set = 0;
+
+ mode = &phy_info->modes[*(phy_info->num_modes)];
+ memset(mode, 0, sizeof(*mode));
+ *(phy_info->num_modes) += 1;
+
+ nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
+ nla_len(nl_band), NULL);
+
+ if (tb_band[NL80211_BAND_ATTR_HT_CAPA]) {
+ mode->ht_capab = nla_get_u16(
+ tb_band[NL80211_BAND_ATTR_HT_CAPA]);
+ }
+
+ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
+ nla_len(nl_freq), freq_policy);
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
+ mode->num_channels++;
+ }
+
+ mode->channels = calloc(mode->num_channels, sizeof(struct hostapd_channel_data));
+ if (!mode->channels)
+ return NL_SKIP;
+
+ idx = 0;
+
+ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS], rem_freq) {
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX, nla_data(nl_freq),
+ nla_len(nl_freq), freq_policy);
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
+
+ mode->channels[idx].freq = nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+ mode->channels[idx].flag = 0;
+
+ if (!mode_is_set) {
+ /* crude heuristic */
+ if (mode->channels[idx].freq < 4000)
+ mode->mode = HOSTAPD_MODE_IEEE80211B;
+ else
+ mode->mode = HOSTAPD_MODE_IEEE80211A;
+ mode_is_set = 1;
+ }
+
+ /* crude heuristic */
+ if (mode->channels[idx].freq < 4000)
+ if (mode->channels[idx].freq == 2484)
+ mode->channels[idx].chan = 14;
+ else
+ mode->channels[idx].chan = (mode->channels[idx].freq - 2407) / 5;
+ else
+ mode->channels[idx].chan = mode->channels[idx].freq/5 - 1000;
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+ mode->channels[idx].flag |=
+ HOSTAPD_CHAN_DISABLED;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
+ mode->channels[idx].flag |=
+ HOSTAPD_CHAN_PASSIVE_SCAN;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
+ mode->channels[idx].flag |=
+ HOSTAPD_CHAN_NO_IBSS;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_RADAR])
+ mode->channels[idx].flag |=
+ HOSTAPD_CHAN_RADAR;
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER] &&
+ !tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+ mode->channels[idx].max_tx_power =
+ nla_get_u32(tb_freq[NL80211_FREQUENCY_ATTR_MAX_TX_POWER]) / 100;
+
+ idx++;
+ }
+
+ nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
+ nla_len(nl_rate), rate_policy);
+ if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+ continue;
+ mode->num_rates++;
+ }
+
+ mode->rates = calloc(mode->num_rates, sizeof(struct hostapd_rate_data));
+ if (!mode->rates)
+ return NL_SKIP;
+
+ idx = 0;
+
+ nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES], rem_rate) {
+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX, nla_data(nl_rate),
+ nla_len(nl_rate), rate_policy);
+ if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+ continue;
+ mode->rates[idx].rate = nla_get_u32(tb_rate[NL80211_BITRATE_ATTR_RATE]);
+
+ /* crude heuristic */
+ if (mode->mode == HOSTAPD_MODE_IEEE80211B &&
+ mode->rates[idx].rate > 200)
+ mode->mode = HOSTAPD_MODE_IEEE80211G;
+
+ if (tb_rate[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE])
+ mode->rates[idx].flags |= HOSTAPD_RATE_PREAMBLE2;
+
+ idx++;
+ }
+ }
+
+ return NL_SKIP;
+}
+
+static struct hostapd_hw_modes *i802_add_11b(struct hostapd_hw_modes *modes,
+ u16 *num_modes)
+{
+ u16 m;
+ struct hostapd_hw_modes *mode11g = NULL, *nmodes, *mode;
+ int i, mode11g_idx = -1;
+
+ /* If only 802.11g mode is included, use it to construct matching
+ * 802.11b mode data. */
+
+ for (m = 0; m < *num_modes; m++) {
+ if (modes[m].mode == HOSTAPD_MODE_IEEE80211B)
+ return modes; /* 802.11b already included */
+ if (modes[m].mode == HOSTAPD_MODE_IEEE80211G)
+ mode11g_idx = m;
+ }
+
+ if (mode11g_idx < 0)
+ return modes; /* 2.4 GHz band not supported at all */
+
+ nmodes = os_realloc(modes, (*num_modes + 1) * sizeof(*nmodes));
+ if (nmodes == NULL)
+ return modes; /* Could not add 802.11b mode */
+
+ mode = &nmodes[*num_modes];
+ os_memset(mode, 0, sizeof(*mode));
+ (*num_modes)++;
+ modes = nmodes;
+
+ mode->mode = HOSTAPD_MODE_IEEE80211B;
+
+ mode11g = &modes[mode11g_idx];
+ mode->num_channels = mode11g->num_channels;
+ mode->channels = os_malloc(mode11g->num_channels *
+ sizeof(struct hostapd_channel_data));
+ if (mode->channels == NULL) {
+ (*num_modes)--;
+ return modes; /* Could not add 802.11b mode */
+ }
+ os_memcpy(mode->channels, mode11g->channels,
+ mode11g->num_channels * sizeof(struct hostapd_channel_data));
+
+ mode->num_rates = 0;
+ mode->rates = os_malloc(4 * sizeof(struct hostapd_rate_data));
+ if (mode->rates == NULL) {
+ os_free(mode->channels);
+ (*num_modes)--;
+ return modes; /* Could not add 802.11b mode */
+ }
+
+ for (i = 0; i < mode11g->num_rates; i++) {
+ if (mode11g->rates[i].rate > 110 ||
+ mode11g->rates[i].flags &
+ (HOSTAPD_RATE_ERP | HOSTAPD_RATE_OFDM))
+ continue;
+ mode->rates[mode->num_rates] = mode11g->rates[i];
+ mode->num_rates++;
+ if (mode->num_rates == 4)
+ break;
+ }
+
+ if (mode->num_rates == 0) {
+ os_free(mode->channels);
+ os_free(mode->rates);
+ (*num_modes)--;
+ return modes; /* No 802.11b rates */
+ }
+
+ wpa_printf(MSG_DEBUG, "nl80211: Added 802.11b mode based on 802.11g "
+ "information");
+
+ return modes;
+}
+
+static struct hostapd_hw_modes *i802_get_hw_feature_data(void *priv,
+ u16 *num_modes,
+ u16 *flags)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ struct phy_info_arg result = {
+ .num_modes = num_modes,
+ .modes = NULL,
+ };
+
+ *num_modes = 0;
+ *flags = 0;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return NULL;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_GET_WIPHY, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->iface));
+
+ if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0)
+ return i802_add_11b(result.modes, num_modes);
+ nla_put_failure:
+ return NULL;
+}
+
+
+static int i802_set_sta_vlan(void *priv, const u8 *addr,
+ const char *ifname, int vlan_id)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(drv->iface));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(ifname));
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int i802_set_country(void *priv, const char *country)
+{
+ struct i802_driver_data *drv = priv;
+ struct nl_msg *msg;
+ char alpha2[3];
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_REQ_SET_REG, 0);
+
+ alpha2[0] = country[0];
+ alpha2[1] = country[1];
+ alpha2[2] = '\0';
+ NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
+
+ return send_and_recv_msgs(drv, msg, NULL, NULL);
+ nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static void handle_unknown_sta(struct hostapd_data *hapd, u8 *ta)
+{
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, ta);
+ if (!sta || !(sta->flags & WLAN_STA_ASSOC)) {
+ printf("Data/PS-poll frame from not associated STA "
+ MACSTR "\n", MAC2STR(ta));
+ if (sta && (sta->flags & WLAN_STA_AUTH))
+ hostapd_sta_disassoc(
+ hapd, ta,
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+ else
+ hostapd_sta_deauth(
+ hapd, ta,
+ WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+ }
+}
+
+
+static void handle_tx_callback(struct hostapd_data *hapd, u8 *buf, size_t len,
+ int ok)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc, type, stype;
+ struct sta_info *sta;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ switch (type) {
+ case WLAN_FC_TYPE_MGMT:
+ wpa_printf(MSG_DEBUG, "MGMT (TX callback) %s",
+ ok ? "ACK" : "fail");
+ ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
+ break;
+ case WLAN_FC_TYPE_CTRL:
+ wpa_printf(MSG_DEBUG, "CTRL (TX callback) %s",
+ ok ? "ACK" : "fail");
+ break;
+ case WLAN_FC_TYPE_DATA:
+ sta = ap_get_sta(hapd, hdr->addr1);
+ if (sta && sta->flags & WLAN_STA_PENDING_POLL) {
+ wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
+ "activity poll", MAC2STR(sta->addr),
+ ok ? "ACKed" : "did not ACK");
+ if (ok)
+ sta->flags &= ~WLAN_STA_PENDING_POLL;
+ }
+ if (sta)
+ ieee802_1x_tx_status(hapd, sta, buf, len, ok);
+ break;
+ default:
+ printf("unknown TX callback frame type %d\n", type);
+ break;
+ }
+}
+
+
+static void handle_frame(struct hostapd_iface *iface, u8 *buf, size_t len,
+ struct hostapd_frame_info *hfi,
+ enum ieee80211_msg_type msg_type)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc, type, stype;
+ size_t data_len = len;
+ struct hostapd_data *hapd = NULL;
+ int broadcast_bssid = 0;
+ size_t i;
+ u8 *bssid;
+
+ /*
+ * PS-Poll frames are 16 bytes. All other frames are
+ * 24 bytes or longer.
+ */
+ if (len < 16)
+ return;
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+
+ type = WLAN_FC_GET_TYPE(fc);
+ stype = WLAN_FC_GET_STYPE(fc);
+
+ switch (type) {
+ case WLAN_FC_TYPE_DATA:
+ if (len < 24)
+ return;
+ switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
+ case WLAN_FC_TODS:
+ bssid = hdr->addr1;
+ break;
+ case WLAN_FC_FROMDS:
+ bssid = hdr->addr2;
+ break;
+ default:
+ /* discard */
+ return;
+ }
+ break;
+ case WLAN_FC_TYPE_CTRL:
+ /* discard non-ps-poll frames */
+ if (stype != WLAN_FC_STYPE_PSPOLL)
+ return;
+ bssid = hdr->addr1;
+ break;
+ case WLAN_FC_TYPE_MGMT:
+ bssid = hdr->addr3;
+ break;
+ default:
+ /* discard */
+ return;
+ }
+
+ /* find interface frame belongs to */
+ for (i = 0; i < iface->num_bss; i++) {
+ if (memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0) {
+ hapd = iface->bss[i];
+ break;
+ }
+ }
+
+ if (hapd == NULL) {
+ hapd = iface->bss[0];
+
+ if (bssid[0] != 0xff || bssid[1] != 0xff ||
+ bssid[2] != 0xff || bssid[3] != 0xff ||
+ bssid[4] != 0xff || bssid[5] != 0xff) {
+ /*
+ * Unknown BSSID - drop frame if this is not from
+ * passive scanning or a beacon (at least ProbeReq
+ * frames to other APs may be allowed through RX
+ * filtering in the wlan hw/driver)
+ */
+ if ((type != WLAN_FC_TYPE_MGMT ||
+ stype != WLAN_FC_STYPE_BEACON))
+ return;
+ } else
+ broadcast_bssid = 1;
+ }
+
+ switch (msg_type) {
+ case ieee80211_msg_normal:
+ /* continue processing */
+ break;
+ case ieee80211_msg_tx_callback_ack:
+ handle_tx_callback(hapd, buf, data_len, 1);
+ return;
+ case ieee80211_msg_tx_callback_fail:
+ handle_tx_callback(hapd, buf, data_len, 0);
+ return;
+ }
+
+ switch (type) {
+ case WLAN_FC_TYPE_MGMT:
+ if (stype != WLAN_FC_STYPE_BEACON &&
+ stype != WLAN_FC_STYPE_PROBE_REQ)
+ wpa_printf(MSG_MSGDUMP, "MGMT");
+ if (broadcast_bssid) {
+ for (i = 0; i < iface->num_bss; i++)
+ ieee802_11_mgmt(iface->bss[i], buf, data_len,
+ stype, hfi);
+ } else
+ ieee802_11_mgmt(hapd, buf, data_len, stype, hfi);
+ break;
+ case WLAN_FC_TYPE_CTRL:
+ /* can only get here with PS-Poll frames */
+ wpa_printf(MSG_DEBUG, "CTRL");
+ handle_unknown_sta(hapd, hdr->addr2);
+ break;
+ case WLAN_FC_TYPE_DATA:
+ handle_unknown_sta(hapd, hdr->addr2);
+ break;
+ }
+}
+
+
+static void handle_eapol(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct i802_driver_data *drv = eloop_ctx;
+ struct hostapd_data *hapd = drv->hapd;
+ struct sockaddr_ll lladdr;
+ unsigned char buf[3000];
+ int len;
+ socklen_t fromlen = sizeof(lladdr);
+
+ len = recvfrom(sock, buf, sizeof(buf), 0,
+ (struct sockaddr *)&lladdr, &fromlen);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ if (have_ifidx(drv, lladdr.sll_ifindex))
+ ieee802_1x_receive(hapd, lladdr.sll_addr, buf, len);
+}
+
+
+static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct i802_driver_data *drv = eloop_ctx;
+ int len;
+ unsigned char buf[3000];
+ struct hostapd_data *hapd = drv->hapd;
+ struct ieee80211_radiotap_iterator iter;
+ int ret;
+ struct hostapd_frame_info hfi;
+ int injected = 0, failed = 0, msg_type, rxflags = 0;
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ if (ieee80211_radiotap_iterator_init(&iter, (void*)buf, len)) {
+ printf("received invalid radiotap frame\n");
+ return;
+ }
+
+ memset(&hfi, 0, sizeof(hfi));
+
+ while (1) {
+ ret = ieee80211_radiotap_iterator_next(&iter);
+ if (ret == -ENOENT)
+ break;
+ if (ret) {
+ printf("received invalid radiotap frame (%d)\n", ret);
+ return;
+ }
+ switch (iter.this_arg_index) {
+ case IEEE80211_RADIOTAP_FLAGS:
+ if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
+ len -= 4;
+ break;
+ case IEEE80211_RADIOTAP_RX_FLAGS:
+ rxflags = 1;
+ break;
+ case IEEE80211_RADIOTAP_TX_FLAGS:
+ injected = 1;
+ failed = le_to_host16((*(uint16_t *) iter.this_arg)) &
+ IEEE80211_RADIOTAP_F_TX_FAIL;
+ break;
+ case IEEE80211_RADIOTAP_DATA_RETRIES:
+ break;
+ case IEEE80211_RADIOTAP_CHANNEL:
+ /* TODO convert from freq/flags to channel number
+ hfi.channel = XXX;
+ hfi.phytype = XXX;
+ */
+ break;
+ case IEEE80211_RADIOTAP_RATE:
+ hfi.datarate = *iter.this_arg * 5;
+ break;
+ case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
+ hfi.ssi_signal = *iter.this_arg;
+ break;
+ }
+ }
+
+ if (rxflags && injected)
+ return;
+
+ if (!injected)
+ msg_type = ieee80211_msg_normal;
+ else if (failed)
+ msg_type = ieee80211_msg_tx_callback_fail;
+ else
+ msg_type = ieee80211_msg_tx_callback_ack;
+
+ handle_frame(hapd->iface, buf + iter.max_length,
+ len - iter.max_length, &hfi, msg_type);
+}
+
+
+/*
+ * we post-process the filter code later and rewrite
+ * this to the offset to the last instruction
+ */
+#define PASS 0xFF
+#define FAIL 0xFE
+
+static struct sock_filter msock_filter_insns[] = {
+ /*
+ * do a little-endian load of the radiotap length field
+ */
+ /* load lower byte into A */
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 2),
+ /* put it into X (== index register) */
+ BPF_STMT(BPF_MISC| BPF_TAX, 0),
+ /* load upper byte into A */
+ BPF_STMT(BPF_LD | BPF_B | BPF_ABS, 3),
+ /* left-shift it by 8 */
+ BPF_STMT(BPF_ALU | BPF_LSH | BPF_K, 8),
+ /* or with X */
+ BPF_STMT(BPF_ALU | BPF_OR | BPF_X, 0),
+ /* put result into X */
+ BPF_STMT(BPF_MISC| BPF_TAX, 0),
+
+ /*
+ * Allow management frames through, this also gives us those
+ * management frames that we sent ourselves with status
+ */
+ /* load the lower byte of the IEEE 802.11 frame control field */
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
+ /* mask off frame type and version */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0xF),
+ /* accept frame if it's both 0, fall through otherwise */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0, PASS, 0),
+
+ /*
+ * TODO: add a bit to radiotap RX flags that indicates
+ * that the sending station is not associated, then
+ * add a filter here that filters on our DA and that flag
+ * to allow us to deauth frames to that bad station.
+ *
+ * Not a regression -- we didn't do it before either.
+ */
+
+#if 0
+ /*
+ * drop non-data frames, WDS frames
+ */
+ /* load the lower byte of the frame control field */
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
+ /* mask off QoS bit */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x0c),
+ /* drop non-data frames */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 8, 0, FAIL),
+ /* load the upper byte of the frame control field */
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
+ /* mask off toDS/fromDS */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x03),
+ /* drop WDS frames */
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 3, FAIL, 0),
+#endif
+
+ /*
+ * add header length to index
+ */
+ /* load the lower byte of the frame control field */
+ BPF_STMT(BPF_LD | BPF_B | BPF_IND, 0),
+ /* mask off QoS bit */
+ BPF_STMT(BPF_ALU | BPF_AND | BPF_K, 0x80),
+ /* right shift it by 6 to give 0 or 2 */
+ BPF_STMT(BPF_ALU | BPF_RSH | BPF_K, 6),
+ /* add data frame header length */
+ BPF_STMT(BPF_ALU | BPF_ADD | BPF_K, 24),
+ /* add index, was start of 802.11 header */
+ BPF_STMT(BPF_ALU | BPF_ADD | BPF_X, 0),
+ /* move to index, now start of LL header */
+ BPF_STMT(BPF_MISC | BPF_TAX, 0),
+
+ /*
+ * Accept empty data frames, we use those for
+ * polling activity.
+ */
+ BPF_STMT(BPF_LD | BPF_W | BPF_LEN, 0),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_X, 0, PASS, 0),
+
+ /*
+ * Accept EAPOL frames
+ */
+ BPF_STMT(BPF_LD | BPF_W | BPF_IND, 0),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0xAAAA0300, 0, FAIL),
+ BPF_STMT(BPF_LD | BPF_W | BPF_IND, 4),
+ BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, 0x0000888E, PASS, FAIL),
+
+ /* keep these last two statements or change the code below */
+ /* return 0 == "DROP" */
+ BPF_STMT(BPF_RET | BPF_K, 0),
+ /* return ~0 == "keep all" */
+ BPF_STMT(BPF_RET | BPF_K, ~0),
+};
+
+static struct sock_fprog msock_filter = {
+ .len = sizeof(msock_filter_insns)/sizeof(msock_filter_insns[0]),
+ .filter = msock_filter_insns,
+};
+
+
+static int add_monitor_filter(int s)
+{
+ int idx;
+
+ /* rewrite all PASS/FAIL jump offsets */
+ for (idx = 0; idx < msock_filter.len; idx++) {
+ struct sock_filter *insn = &msock_filter_insns[idx];
+
+ if (BPF_CLASS(insn->code) == BPF_JMP) {
+ if (insn->code == (BPF_JMP|BPF_JA)) {
+ if (insn->k == PASS)
+ insn->k = msock_filter.len - idx - 2;
+ else if (insn->k == FAIL)
+ insn->k = msock_filter.len - idx - 3;
+ }
+
+ if (insn->jt == PASS)
+ insn->jt = msock_filter.len - idx - 2;
+ else if (insn->jt == FAIL)
+ insn->jt = msock_filter.len - idx - 3;
+
+ if (insn->jf == PASS)
+ insn->jf = msock_filter.len - idx - 2;
+ else if (insn->jf == FAIL)
+ insn->jf = msock_filter.len - idx - 3;
+ }
+ }
+
+ if (setsockopt(s, SOL_SOCKET, SO_ATTACH_FILTER,
+ &msock_filter, sizeof(msock_filter))) {
+ perror("SO_ATTACH_FILTER");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int nl80211_create_monitor_interface(struct i802_driver_data *drv)
+{
+ char buf[IFNAMSIZ];
+ struct sockaddr_ll ll;
+ int optval;
+ socklen_t optlen;
+
+ snprintf(buf, IFNAMSIZ, "mon.%s", drv->iface);
+ buf[IFNAMSIZ - 1] = '\0';
+
+ drv->monitor_ifidx =
+ nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR, NULL);
+
+ if (drv->monitor_ifidx < 0)
+ return -1;
+
+ if (hostapd_set_iface_flags(drv, buf, 1))
+ goto error;
+
+ memset(&ll, 0, sizeof(ll));
+ ll.sll_family = AF_PACKET;
+ ll.sll_ifindex = drv->monitor_ifidx;
+ drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (drv->monitor_sock < 0) {
+ perror("socket[PF_PACKET,SOCK_RAW]");
+ goto error;
+ }
+
+ if (add_monitor_filter(drv->monitor_sock)) {
+ wpa_printf(MSG_INFO, "Failed to set socket filter for monitor "
+ "interface; do filtering in user space");
+ /* This works, but will cost in performance. */
+ }
+
+ if (bind(drv->monitor_sock, (struct sockaddr *) &ll,
+ sizeof(ll)) < 0) {
+ perror("monitor socket bind");
+ goto error;
+ }
+
+ optlen = sizeof(optval);
+ optval = 20;
+ if (setsockopt
+ (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
+ perror("Failed to set socket priority");
+ goto error;
+ }
+
+ if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
+ drv, NULL)) {
+ printf("Could not register monitor read socket\n");
+ goto error;
+ }
+
+ return 0;
+ error:
+ nl80211_remove_iface(drv, drv->monitor_ifidx);
+ return -1;
+}
+
+
+static int nl80211_set_master_mode(struct i802_driver_data *drv,
+ const char *ifname)
+{
+ struct nl_msg *msg;
+ int ret = -ENOBUFS;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX,
+ if_nametoindex(ifname));
+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, NL80211_IFTYPE_AP);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (!ret)
+ return 0;
+ nla_put_failure:
+ wpa_printf(MSG_ERROR, "Failed to set interface %s to master "
+ "mode.", ifname);
+ return ret;
+}
+
+
+static int i802_init_sockets(struct i802_driver_data *drv, const u8 *bssid)
+{
+ struct ifreq ifr;
+ struct sockaddr_ll addr;
+
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket[PF_INET,SOCK_DGRAM]");
+ return -1;
+ }
+
+ /* start listening for EAPOL on the default AP interface */
+ add_ifidx(drv, if_nametoindex(drv->iface));
+
+ if (hostapd_set_iface_flags(drv, drv->iface, 0))
+ return -1;
+
+ if (bssid) {
+ os_strlcpy(ifr.ifr_name, drv->iface, IFNAMSIZ);
+ memcpy(ifr.ifr_hwaddr.sa_data, bssid, ETH_ALEN);
+ ifr.ifr_hwaddr.sa_family = ARPHRD_ETHER;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIFHWADDR, &ifr)) {
+ perror("ioctl(SIOCSIFHWADDR)");
+ return -1;
+ }
+ }
+
+ /*
+ * initialise generic netlink and nl80211
+ */
+ drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (!drv->nl_cb) {
+ printf("Failed to allocate netlink callbacks.\n");
+ return -1;
+ }
+
+ drv->nl_handle = nl_handle_alloc_cb(drv->nl_cb);
+ if (!drv->nl_handle) {
+ printf("Failed to allocate netlink handle.\n");
+ return -1;
+ }
+
+ if (genl_connect(drv->nl_handle)) {
+ printf("Failed to connect to generic netlink.\n");
+ return -1;
+ }
+
+#ifdef CONFIG_LIBNL20
+ if (genl_ctrl_alloc_cache(drv->nl_handle, &drv->nl_cache) < 0) {
+ printf("Failed to allocate generic netlink cache.\n");
+ return -1;
+ }
+#else /* CONFIG_LIBNL20 */
+ drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle);
+ if (!drv->nl_cache) {
+ printf("Failed to allocate generic netlink cache.\n");
+ return -1;
+ }
+#endif /* CONFIG_LIBNL20 */
+
+ drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
+ if (!drv->nl80211) {
+ printf("nl80211 not found.\n");
+ return -1;
+ }
+
+ /* Initialise a monitor interface */
+ if (nl80211_create_monitor_interface(drv))
+ return -1;
+
+ if (nl80211_set_master_mode(drv, drv->iface))
+ goto fail1;
+
+ if (hostapd_set_iface_flags(drv, drv->iface, 1))
+ goto fail1;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sll_family = AF_PACKET;
+ addr.sll_ifindex = ifr.ifr_ifindex;
+ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
+ addr.sll_ifindex);
+
+ drv->eapol_sock = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_PAE));
+ if (drv->eapol_sock < 0) {
+ perror("socket(PF_PACKET, SOCK_DGRAM, ETH_P_PAE)");
+ goto fail1;
+ }
+
+ if (eloop_register_read_sock(drv->eapol_sock, handle_eapol, drv, NULL))
+ {
+ printf("Could not register read socket for eapol\n");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
+ if (ioctl(drv->ioctl_sock, SIOCGIFHWADDR, &ifr) != 0) {
+ perror("ioctl(SIOCGIFHWADDR)");
+ goto fail1;
+ }
+
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ printf("Invalid HW-addr family 0x%04x\n",
+ ifr.ifr_hwaddr.sa_family);
+ goto fail1;
+ }
+ memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ return 0;
+
+fail1:
+ nl80211_remove_iface(drv, drv->monitor_ifidx);
+ return -1;
+}
+
+
+static int i802_get_inact_sec(void *priv, const u8 *addr)
+{
+ struct hostap_sta_driver_data data;
+ int ret;
+
+ data.inactive_msec = (unsigned long) -1;
+ ret = i802_read_sta_data(priv, &data, addr);
+ if (ret || data.inactive_msec == (unsigned long) -1)
+ return -1;
+ return data.inactive_msec / 1000;
+}
+
+
+static int i802_sta_clear_stats(void *priv, const u8 *addr)
+{
+#if 0
+ /* TODO */
+#endif
+ return 0;
+}
+
+
+static void
+hostapd_wireless_event_wireless_custom(struct i802_driver_data *drv,
+ char *custom)
+{
+ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
+
+ if (strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ char *pos;
+ u8 addr[ETH_ALEN];
+ pos = strstr(custom, "addr=");
+ if (pos == NULL) {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "without sender address ignored");
+ return;
+ }
+ pos += 5;
+ if (hwaddr_aton(pos, addr) == 0) {
+ ieee80211_michael_mic_failure(drv->hapd, addr, 1);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MLME-MICHAELMICFAILURE.indication "
+ "with invalid MAC address");
+ }
+ }
+}
+
+
+static void hostapd_wireless_event_wireless(struct i802_driver_data *drv,
+ char *data, int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf;
+
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
+ iwe->cmd, iwe->len);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ return;
+
+ custom = pos + IW_EV_POINT_LEN;
+ if (drv->we_version > 18 &&
+ (iwe->cmd == IWEVMICHAELMICFAILURE ||
+ iwe->cmd == IWEVCUSTOM)) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case IWEVCUSTOM:
+ if (custom + iwe->u.data.length > end)
+ return;
+ buf = malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return;
+ memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+ hostapd_wireless_event_wireless_custom(drv, buf);
+ free(buf);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+
+static void hostapd_wireless_event_rtm_newlink(struct i802_driver_data *drv,
+ struct nlmsghdr *h, int len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, _nlmsg_len, rta_len;
+ struct rtattr *attr;
+
+ if (len < (int) sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ /* TODO: use ifi->ifi_index to filter out wireless events from other
+ * interfaces */
+
+ _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - _nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ hostapd_wireless_event_wireless(
+ drv, ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void hostapd_wireless_event_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ char buf[256];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ struct i802_driver_data *drv = eloop_ctx;
+
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("recvfrom(netlink)");
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (left >= (int) sizeof(*h)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ printf("Malformed netlink message: "
+ "len=%d left=%d plen=%d\n",
+ len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ hostapd_wireless_event_rtm_newlink(drv, h, plen);
+ break;
+ }
+
+ len = NLMSG_ALIGN(len);
+ left -= len;
+ h = (struct nlmsghdr *) ((char *) h + len);
+ }
+
+ if (left > 0) {
+ printf("%d extra bytes in the end of netlink message\n", left);
+ }
+}
+
+
+static int hostap_get_we_version(struct i802_driver_data *drv)
+{
+ struct iw_range *range;
+ struct iwreq iwr;
+ int minlen;
+ size_t buflen;
+
+ drv->we_version = 0;
+
+ /*
+ * Use larger buffer than struct iw_range in order to allow the
+ * structure to grow in the future.
+ */
+ buflen = sizeof(struct iw_range) + 500;
+ range = os_zalloc(buflen);
+ if (range == NULL)
+ return -1;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buflen;
+
+ minlen = ((char *) &range->enc_capa) - (char *) range +
+ sizeof(range->enc_capa);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWRANGE]");
+ free(range);
+ return -1;
+ } else if (iwr.u.data.length >= minlen &&
+ range->we_version_compiled >= 18) {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+ "WE(source)=%d enc_capa=0x%x",
+ range->we_version_compiled,
+ range->we_version_source,
+ range->enc_capa);
+ drv->we_version = range->we_version_compiled;
+ }
+
+ free(range);
+ return 0;
+}
+
+
+static int i802_wireless_event_init(void *priv)
+{
+ struct i802_driver_data *drv = priv;
+ int s;
+ struct sockaddr_nl local;
+
+ hostap_get_we_version(drv);
+
+ drv->wext_sock = -1;
+
+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (s < 0) {
+ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+ return -1;
+ }
+
+ memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ perror("bind(netlink)");
+ close(s);
+ return -1;
+ }
+
+ eloop_register_read_sock(s, hostapd_wireless_event_receive, drv,
+ NULL);
+ drv->wext_sock = s;
+
+ return 0;
+}
+
+
+static void i802_wireless_event_deinit(void *priv)
+{
+ struct i802_driver_data *drv = priv;
+ if (drv->wext_sock < 0)
+ return;
+ eloop_unregister_read_sock(drv->wext_sock);
+ close(drv->wext_sock);
+}
+
+
+static int i802_sta_deauth(void *priv, const u8 *addr, int reason)
+{
+ struct i802_driver_data *drv = priv;
+ struct ieee80211_mgmt mgmt;
+
+ memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DEAUTH);
+ memcpy(mgmt.da, addr, ETH_ALEN);
+ memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN);
+ memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN);
+ mgmt.u.deauth.reason_code = host_to_le16(reason);
+ return i802_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN +
+ sizeof(mgmt.u.deauth), 0);
+}
+
+
+static int i802_sta_disassoc(void *priv, const u8 *addr, int reason)
+{
+ struct i802_driver_data *drv = priv;
+ struct ieee80211_mgmt mgmt;
+
+ memset(&mgmt, 0, sizeof(mgmt));
+ mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_DISASSOC);
+ memcpy(mgmt.da, addr, ETH_ALEN);
+ memcpy(mgmt.sa, drv->hapd->own_addr, ETH_ALEN);
+ memcpy(mgmt.bssid, drv->hapd->own_addr, ETH_ALEN);
+ mgmt.u.disassoc.reason_code = host_to_le16(reason);
+ return i802_send_mgmt_frame(drv, &mgmt, IEEE80211_HDRLEN +
+ sizeof(mgmt.u.disassoc), 0);
+}
+
+
+static void *i802_init_bssid(struct hostapd_data *hapd, const u8 *bssid)
+{
+ struct i802_driver_data *drv;
+
+ drv = os_zalloc(sizeof(struct i802_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for i802 driver data\n");
+ return NULL;
+ }
+
+ drv->hapd = hapd;
+ memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface));
+
+ drv->num_if_indices = sizeof(drv->default_if_indices) / sizeof(int);
+ drv->if_indices = drv->default_if_indices;
+ drv->bridge = if_nametoindex(hapd->conf->bridge);
+
+ if (i802_init_sockets(drv, bssid))
+ goto failed;
+
+ return drv;
+
+failed:
+ free(drv);
+ return NULL;
+}
+
+
+static void *i802_init(struct hostapd_data *hapd)
+{
+ return i802_init_bssid(hapd, NULL);
+}
+
+
+static void i802_deinit(void *priv)
+{
+ struct i802_driver_data *drv = priv;
+
+ if (drv->last_freq_ht) {
+ /* Clear HT flags from the driver */
+ struct hostapd_freq_params freq;
+ os_memset(&freq, 0, sizeof(freq));
+ freq.freq = drv->last_freq;
+ i802_set_freq2(priv, &freq);
+ }
+
+ i802_del_beacon(drv);
+
+ /* remove monitor interface */
+ nl80211_remove_iface(drv, drv->monitor_ifidx);
+
+ (void) hostapd_set_iface_flags(drv, drv->iface, 0);
+
+ if (drv->monitor_sock >= 0) {
+ eloop_unregister_read_sock(drv->monitor_sock);
+ close(drv->monitor_sock);
+ }
+ if (drv->ioctl_sock >= 0)
+ close(drv->ioctl_sock);
+ if (drv->eapol_sock >= 0) {
+ eloop_unregister_read_sock(drv->eapol_sock);
+ close(drv->eapol_sock);
+ }
+
+ genl_family_put(drv->nl80211);
+ nl_cache_free(drv->nl_cache);
+ nl_handle_destroy(drv->nl_handle);
+ nl_cb_put(drv->nl_cb);
+
+ if (drv->if_indices != drv->default_if_indices)
+ free(drv->if_indices);
+
+ free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_nl80211_ops = {
+ .name = "nl80211",
+ .init = i802_init,
+ .init_bssid = i802_init_bssid,
+ .deinit = i802_deinit,
+ .wireless_event_init = i802_wireless_event_init,
+ .wireless_event_deinit = i802_wireless_event_deinit,
+ .set_ieee8021x = i802_set_ieee8021x,
+ .set_privacy = i802_set_privacy,
+ .set_encryption = i802_set_encryption,
+ .get_seqnum = i802_get_seqnum,
+ .flush = i802_flush,
+ .read_sta_data = i802_read_sta_data,
+ .send_eapol = i802_send_eapol,
+ .sta_set_flags = i802_sta_set_flags,
+ .sta_deauth = i802_sta_deauth,
+ .sta_disassoc = i802_sta_disassoc,
+ .sta_remove = i802_sta_remove,
+ .send_mgmt_frame = i802_send_mgmt_frame,
+ .sta_add2 = i802_sta_add2,
+ .get_inact_sec = i802_get_inact_sec,
+ .sta_clear_stats = i802_sta_clear_stats,
+ .set_freq2 = i802_set_freq2,
+ .set_rts = i802_set_rts,
+ .get_rts = i802_get_rts,
+ .set_frag = i802_set_frag,
+ .get_frag = i802_get_frag,
+ .set_retry = i802_set_retry,
+ .get_retry = i802_get_retry,
+ .set_rate_sets = i802_set_rate_sets,
+ .set_regulatory_domain = i802_set_regulatory_domain,
+ .set_beacon = i802_set_beacon,
+ .set_internal_bridge = i802_set_internal_bridge,
+ .set_beacon_int = i802_set_beacon_int,
+ .set_dtim_period = i802_set_dtim_period,
+ .set_cts_protect = i802_set_cts_protect,
+ .set_preamble = i802_set_preamble,
+ .set_short_slot_time = i802_set_short_slot_time,
+ .set_tx_queue_params = i802_set_tx_queue_params,
+ .bss_add = i802_bss_add,
+ .bss_remove = i802_bss_remove,
+ .if_add = i802_if_add,
+ .if_update = i802_if_update,
+ .if_remove = i802_if_remove,
+ .get_hw_feature_data = i802_get_hw_feature_data,
+ .set_sta_vlan = i802_set_sta_vlan,
+ .set_country = i802_set_country,
+};
diff --git a/hostapd/driver_none.c b/hostapd/driver_none.c
new file mode 100644
index 0000000..96e7e64
--- /dev/null
+++ b/hostapd/driver_none.c
@@ -0,0 +1,62 @@
+/*
+ * hostapd / Driver interface for RADIUS server only (no driver)
+ * Copyright (c) 2008, Atheros Communications
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "hostapd.h"
+#include "driver.h"
+
+
+struct none_driver_data {
+ struct hostapd_data *hapd;
+};
+
+
+static void * none_driver_init(struct hostapd_data *hapd)
+{
+ struct none_driver_data *drv;
+
+ drv = os_zalloc(sizeof(struct none_driver_data));
+ if (drv == NULL) {
+ wpa_printf(MSG_ERROR, "Could not allocate memory for none "
+ "driver data");
+ return NULL;
+ }
+ drv->hapd = hapd;
+
+ return drv;
+}
+
+
+static void none_driver_deinit(void *priv)
+{
+ struct none_driver_data *drv = priv;
+
+ os_free(drv);
+}
+
+
+static int none_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
+ u16 proto, const u8 *data, size_t data_len)
+{
+ return 0;
+}
+
+
+const struct wpa_driver_ops wpa_driver_none_ops = {
+ .name = "none",
+ .init = none_driver_init,
+ .deinit = none_driver_deinit,
+ .send_ether = none_driver_send_ether,
+};
diff --git a/hostapd/driver_prism54.c b/hostapd/driver_prism54.c
new file mode 100644
index 0000000..4e2189a
--- /dev/null
+++ b/hostapd/driver_prism54.c
@@ -0,0 +1,1091 @@
+/*
+ * hostapd / Driver interaction with Prism54 PIMFOR interface
+ * Copyright (c) 2004, Bell Kin <bell_kin@pek.com.tw>
+ * based on hostap driver.c, ieee802_11.c
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <sys/select.h>
+
+#ifdef USE_KERNEL_HEADERS
+/* compat-wireless does not include linux/compiler.h to define __user, so
+ * define it here */
+#ifndef __user
+#define __user
+#endif /* __user */
+#include <asm/types.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h> /* The L2 protocols */
+#include <linux/if_arp.h>
+#include <linux/wireless.h>
+#else /* USE_KERNEL_HEADERS */
+#include <net/if_arp.h>
+#include <netpacket/packet.h>
+#include "wireless_copy.h"
+#endif /* USE_KERNEL_HEADERS */
+
+#include "hostapd.h"
+#include "driver.h"
+#include "ieee802_1x.h"
+#include "eloop.h"
+#include "ieee802_11.h"
+#include "prism54.h"
+#include "wpa.h"
+#include "radius/radius.h"
+#include "sta_info.h"
+#include "accounting.h"
+
+const int PIM_BUF_SIZE = 4096;
+
+struct prism54_driver_data {
+ struct hostapd_data *hapd;
+ char iface[IFNAMSIZ + 1];
+ int sock; /* raw packet socket for 802.3 access */
+ int pim_sock; /* socket for pimfor packet */
+ char macs[2007][6];
+};
+
+
+static int mac_id_refresh(struct prism54_driver_data *data, int id, char *mac)
+{
+ if (id < 0 || id > 2006) {
+ return -1;
+ }
+ memcpy(&data->macs[id][0], mac, ETH_ALEN);
+ return 0;
+}
+
+
+static char * mac_id_get(struct prism54_driver_data *data, int id)
+{
+ if (id < 0 || id > 2006) {
+ return NULL;
+ }
+ return &data->macs[id][0];
+}
+
+
+/* wait for a specific pimfor, timeout in 10ms resolution */
+/* pim_sock must be non-block to prevent dead lock from no response */
+/* or same response type in series */
+static int prism54_waitpim(void *priv, unsigned long oid, void *buf, int len,
+ int timeout)
+{
+ struct prism54_driver_data *drv = priv;
+ struct timeval tv, stv, ctv;
+ fd_set pfd;
+ int rlen;
+ pimdev_hdr *pkt;
+
+ pkt = malloc(8192);
+ if (pkt == NULL)
+ return -1;
+
+ FD_ZERO(&pfd);
+ gettimeofday(&stv, NULL);
+ do {
+ FD_SET(drv->pim_sock, &pfd);
+ tv.tv_sec = 0;
+ tv.tv_usec = 10000;
+ if (select(drv->pim_sock + 1, &pfd, NULL, NULL, &tv)) {
+ rlen = recv(drv->pim_sock, pkt, 8192, 0);
+ if (rlen > 0) {
+ if (pkt->oid == htonl(oid)) {
+ if (rlen <= len) {
+ if (buf != NULL) {
+ memcpy(buf, pkt, rlen);
+ }
+ free(pkt);
+ return rlen;
+ } else {
+ printf("buffer too small\n");
+ free(pkt);
+ return -1;
+ }
+ } else {
+ gettimeofday(&ctv, NULL);
+ continue;
+ }
+ }
+ }
+ gettimeofday(&ctv, NULL);
+ } while (((ctv.tv_sec - stv.tv_sec) * 100 +
+ (ctv.tv_usec - stv.tv_usec) / 10000) > timeout);
+ free(pkt);
+ return 0;
+}
+
+
+/* send an eapol packet */
+static int prism54_send_eapol(void *priv, const u8 *addr,
+ const u8 *data, size_t data_len, int encrypt,
+ const u8 *own_addr)
+{
+ struct prism54_driver_data *drv = priv;
+ ieee802_3_hdr *hdr;
+ size_t len;
+ u8 *pos;
+ int res;
+
+ len = sizeof(*hdr) + data_len;
+ hdr = os_zalloc(len);
+ if (hdr == NULL) {
+ printf("malloc() failed for prism54_send_data(len=%lu)\n",
+ (unsigned long) len);
+ return -1;
+ }
+
+ memcpy(&hdr->da[0], addr, ETH_ALEN);
+ memcpy(&hdr->sa[0], own_addr, ETH_ALEN);
+ hdr->type = htons(ETH_P_PAE);
+ pos = (u8 *) (hdr + 1);
+ memcpy(pos, data, data_len);
+
+ res = send(drv->sock, hdr, len, 0);
+ free(hdr);
+
+ if (res < 0) {
+ perror("hostapd_send_eapol: send");
+ printf("hostapd_send_eapol - packet len: %lu - failed\n",
+ (unsigned long) len);
+ }
+
+ return res;
+}
+
+
+/* open data channel(auth-1) or eapol only(unauth-0) */
+static int prism54_set_sta_authorized(void *priv, const u8 *addr,
+ int authorized)
+{
+ struct prism54_driver_data *drv = priv;
+ pimdev_hdr *hdr;
+ char *pos;
+
+ hdr = malloc(sizeof(*hdr) + ETH_ALEN);
+ if (hdr == NULL)
+ return -1;
+ hdr->op = htonl(PIMOP_SET);
+ if (authorized) {
+ hdr->oid = htonl(DOT11_OID_EAPAUTHSTA);
+ } else {
+ hdr->oid = htonl(DOT11_OID_EAPUNAUTHSTA);
+ }
+ pos = (char *) (hdr + 1);
+ memcpy(pos, addr, ETH_ALEN);
+ send(drv->pim_sock, hdr, sizeof(*hdr) + ETH_ALEN, 0);
+ prism54_waitpim(priv, hdr->oid, hdr, sizeof(*hdr) + ETH_ALEN, 10);
+ free(hdr);
+ return 0;
+}
+
+
+static int
+prism54_sta_set_flags(void *priv, const u8 *addr, int total_flags,
+ int flags_or, int flags_and)
+{
+ /* For now, only support setting Authorized flag */
+ if (flags_or & WLAN_STA_AUTHORIZED)
+ return prism54_set_sta_authorized(priv, addr, 1);
+ if (flags_and & WLAN_STA_AUTHORIZED)
+ return prism54_set_sta_authorized(priv, addr, 0);
+ return 0;
+}
+
+
+/* set per station key */
+static int prism54_set_encryption(const char *ifname, void *priv,
+ const char *alg, const u8 *addr,
+ int idx, const u8 *key, size_t key_len,
+ int txkey)
+{
+ struct prism54_driver_data *drv = priv;
+ pimdev_hdr *hdr;
+ struct obj_stakey *keys;
+ u8 *buf;
+ size_t blen;
+ int ret = 0;
+
+ blen = sizeof(struct obj_stakey) + sizeof(pimdev_hdr);
+ hdr = malloc(blen);
+ if (hdr == NULL) {
+ printf("memory low\n");
+ return -1;
+ }
+ keys = (struct obj_stakey *) &hdr[1];
+ if (!addr) {
+ memset(&keys->address[0], 0xff, ETH_ALEN);
+ } else {
+ memcpy(&keys->address[0], addr, ETH_ALEN);
+ }
+ if (!strcmp(alg, "WEP")) {
+ keys->type = DOT11_PRIV_WEP;
+ } else if (!strcmp(alg, "TKIP")) {
+ keys->type = DOT11_PRIV_TKIP;
+ } else if (!strcmp(alg, "none")) {
+ /* the only way to clear the key is to deauth it */
+ /* and prism54 is capable to receive unencrypted packet */
+ /* so we do nothing here */
+ free(hdr);
+ return 0;
+ } else {
+ printf("bad auth type: %s\n", alg);
+ }
+ buf = (u8 *) &keys->key[0];
+ keys->length = key_len;
+ keys->keyid = idx;
+ keys->options = htons(DOT11_STAKEY_OPTION_DEFAULTKEY);
+ keys->reserved = 0;
+
+ hdr->op = htonl(PIMOP_SET);
+ hdr->oid = htonl(DOT11_OID_STAKEY);
+
+ memcpy(buf, key, key_len);
+
+ ret = send(drv->pim_sock, hdr, blen, 0);
+ if (ret < 0) {
+ free(hdr);
+ return ret;
+ }
+ prism54_waitpim(priv, hdr->oid, hdr, blen, 10);
+
+ free(hdr);
+
+ return 0;
+}
+
+
+/* get TKIP station sequence counter, prism54 is only 6 bytes */
+static int prism54_get_seqnum(const char *ifname, void *priv, const u8 *addr,
+ int idx, u8 *seq)
+{
+ struct prism54_driver_data *drv = priv;
+ struct obj_stasc *stasc;
+ pimdev_hdr *hdr;
+ size_t blen;
+ int ret = 0;
+
+ blen = sizeof(*stasc) + sizeof(*hdr);
+ hdr = malloc(blen);
+ if (hdr == NULL)
+ return -1;
+
+ stasc = (struct obj_stasc *) &hdr[1];
+
+ if (addr == NULL)
+ memset(&stasc->address[0], 0xff, ETH_ALEN);
+ else
+ memcpy(&stasc->address[0], addr, ETH_ALEN);
+
+ hdr->oid = htonl(DOT11_OID_STASC);
+ hdr->op = htonl(PIMOP_GET);
+ stasc->keyid = idx;
+ if (send(drv->pim_sock,hdr,blen,0) <= 0) {
+ free(hdr);
+ return -1;
+ }
+ if (prism54_waitpim(priv, DOT11_OID_STASC, hdr, blen, 10) <= 0) {
+ ret = -1;
+ } else {
+ if (hdr->op == (int) htonl(PIMOP_RESPONSE)) {
+ memcpy(seq + 2, &stasc->sc_high, ETH_ALEN);
+ memset(seq, 0, 2);
+ } else {
+ ret = -1;
+ }
+ }
+ free(hdr);
+
+ return ret;
+}
+
+
+/* include unencrypted, set mlme autolevel to extended */
+static int prism54_init_1x(void *priv)
+{
+ struct prism54_driver_data *drv = priv;
+ pimdev_hdr *hdr;
+ unsigned long *ul;
+ int blen = sizeof(*hdr) + sizeof(*ul);
+
+ hdr = malloc(blen);
+ if (hdr == NULL)
+ return -1;
+
+ ul = (unsigned long *) &hdr[1];
+ hdr->op = htonl(PIMOP_SET);
+ hdr->oid = htonl(DOT11_OID_EXUNENCRYPTED);
+ *ul = htonl(DOT11_BOOL_TRUE); /* not accept */
+ send(drv->pim_sock, hdr, blen, 0);
+ prism54_waitpim(priv, DOT11_OID_EXUNENCRYPTED, hdr, blen, 10);
+ hdr->op = htonl(PIMOP_SET);
+ hdr->oid = htonl(DOT11_OID_MLMEAUTOLEVEL);
+ *ul = htonl(DOT11_MLME_EXTENDED);
+ send(drv->pim_sock, hdr, blen, 0);
+ prism54_waitpim(priv, DOT11_OID_MLMEAUTOLEVEL, hdr, blen, 10);
+ hdr->op = htonl(PIMOP_SET);
+ hdr->oid = htonl(DOT11_OID_DOT1XENABLE);
+ *ul = htonl(DOT11_BOOL_TRUE);
+ send(drv->pim_sock, hdr, blen, 0);
+ prism54_waitpim(priv, DOT11_OID_DOT1XENABLE, hdr, blen, 10);
+ hdr->op = htonl(PIMOP_SET);
+ hdr->oid = htonl(DOT11_OID_AUTHENABLE);
+ *ul = htonl(DOT11_AUTH_OS); /* OS */
+ send(drv->pim_sock, hdr, blen, 0);
+ prism54_waitpim(priv, DOT11_OID_AUTHENABLE, hdr, blen, 10);
+ free(hdr);
+ return 0;
+}
+
+
+static int prism54_set_privacy_invoked(const char *ifname, void *priv,
+ int flag)
+{
+ struct prism54_driver_data *drv = priv;
+ pimdev_hdr *hdr;
+ unsigned long *ul;
+ int ret;
+ int blen = sizeof(*hdr) + sizeof(*ul);
+ hdr = malloc(blen);
+ if (hdr == NULL)
+ return -1;
+ ul = (unsigned long *) &hdr[1];
+ hdr->op = htonl(PIMOP_SET);
+ hdr->oid = htonl(DOT11_OID_PRIVACYINVOKED);
+ if (flag) {
+ *ul = htonl(DOT11_BOOL_TRUE); /* has privacy */
+ } else {
+ *ul = 0;
+ }
+ ret = send(drv->pim_sock, hdr, blen, 0);
+ if (ret >= 0) {
+ ret = prism54_waitpim(priv, DOT11_OID_PRIVACYINVOKED, hdr,
+ blen, 10);
+ }
+ free(hdr);
+ return ret;
+}
+
+
+static int prism54_ioctl_setiwessid(const char *ifname, void *priv,
+ const u8 *buf, int len)
+{
+#if 0
+ struct prism54_driver_data *drv = priv;
+ struct iwreq iwr;
+
+ memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->iface, IFNAMSIZ);
+ iwr.u.essid.flags = 1; /* SSID active */
+ iwr.u.essid.pointer = (caddr_t) buf;
+ iwr.u.essid.length = len + 1;
+
+ if (ioctl(drv->pim_sock, SIOCSIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCSIWESSID]");
+ printf("len=%d\n", len);
+ return -1;
+ }
+#endif
+ return 0;
+}
+
+
+/* kick all stations */
+/* does not work during init, but at least it won't crash firmware */
+static int prism54_flush(void *priv)
+{
+ struct prism54_driver_data *drv = priv;
+ struct obj_mlmeex *mlme;
+ pimdev_hdr *hdr;
+ int ret;
+ unsigned int i;
+ long *nsta;
+ int blen = sizeof(*hdr) + sizeof(*mlme);
+ char *mac_id;
+
+ hdr = os_zalloc(blen);
+ if (hdr == NULL)
+ return -1;
+
+ mlme = (struct obj_mlmeex *) &hdr[1];
+ nsta = (long *) &hdr[1];
+ hdr->op = htonl(PIMOP_GET);
+ hdr->oid = htonl(DOT11_OID_CLIENTS);
+ ret = send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(long), 0);
+ ret = prism54_waitpim(priv, DOT11_OID_CLIENTS, hdr, blen, 10);
+ if ((ret < 0) || (hdr->op != (int) htonl(PIMOP_RESPONSE)) ||
+ (le_to_host32(*nsta) > 2007)) {
+ free(hdr);
+ return 0;
+ }
+ for (i = 0; i < le_to_host32(*nsta); i++) {
+ mlme->id = -1;
+ mac_id = mac_id_get(drv, i);
+ if (mac_id)
+ memcpy(&mlme->address[0], mac_id, ETH_ALEN);
+ mlme->code = host_to_le16(WLAN_REASON_UNSPECIFIED);
+ mlme->state = htons(DOT11_STATE_NONE);
+ mlme->size = 0;
+ hdr->op = htonl(PIMOP_SET);
+ hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX);
+ ret = send(drv->pim_sock, hdr, blen, 0);
+ prism54_waitpim(priv, DOT11_OID_DISASSOCIATEEX, hdr, blen,
+ 100);
+ }
+ for (i = 0; i < le_to_host32(*nsta); i++) {
+ mlme->id = -1;
+ mac_id = mac_id_get(drv, i);
+ if (mac_id)
+ memcpy(&mlme->address[0], mac_id, ETH_ALEN);
+ mlme->code = host_to_le16(WLAN_REASON_UNSPECIFIED);
+ mlme->state = htons(DOT11_STATE_NONE);
+ mlme->size = 0;
+ hdr->op = htonl(PIMOP_SET);
+ hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX);
+ ret = send(drv->pim_sock, hdr, blen, 0);
+ prism54_waitpim(priv, DOT11_OID_DEAUTHENTICATEEX, hdr, blen,
+ 100);
+ }
+ free(hdr);
+ return 0;
+}
+
+
+static int prism54_sta_deauth(void *priv, const u8 *addr, int reason)
+{
+ struct prism54_driver_data *drv = priv;
+ pimdev_hdr *hdr;
+ struct obj_mlmeex *mlme;
+ int ret;
+ int blen = sizeof(*hdr) + sizeof(*mlme);
+ hdr = malloc(blen);
+ if (hdr == NULL)
+ return -1;
+ mlme = (struct obj_mlmeex *) &hdr[1];
+ hdr->op = htonl(PIMOP_SET);
+ hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX);
+ memcpy(&mlme->address[0], addr, ETH_ALEN);
+ mlme->id = -1;
+ mlme->state = htons(DOT11_STATE_NONE);
+ mlme->code = host_to_le16(reason);
+ mlme->size = 0;
+ ret = send(drv->pim_sock, hdr, blen, 0);
+ prism54_waitpim(priv, DOT11_OID_DEAUTHENTICATEEX, hdr, blen, 10);
+ free(hdr);
+ return ret;
+}
+
+
+static int prism54_sta_disassoc(void *priv, const u8 *addr, int reason)
+{
+ struct prism54_driver_data *drv = priv;
+ pimdev_hdr *hdr;
+ struct obj_mlmeex *mlme;
+ int ret;
+ int blen = sizeof(*hdr) + sizeof(*mlme);
+ hdr = malloc(blen);
+ if (hdr == NULL)
+ return -1;
+ mlme = (struct obj_mlmeex *) &hdr[1];
+ hdr->op = htonl(PIMOP_SET);
+ hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX);
+ memcpy(&mlme->address[0], addr, ETH_ALEN);
+ mlme->id = -1;
+ mlme->state = htons(DOT11_STATE_NONE);
+ mlme->code = host_to_le16(reason);
+ mlme->size = 0;
+ ret = send(drv->pim_sock, hdr, blen, 0);
+ prism54_waitpim(priv, DOT11_OID_DISASSOCIATEEX, hdr, blen, 10);
+ free(hdr);
+ return ret;
+}
+
+
+static int prism54_get_inact_sec(void *priv, const u8 *addr)
+{
+ struct prism54_driver_data *drv = priv;
+ pimdev_hdr *hdr;
+ struct obj_sta *sta;
+ int blen = sizeof(*hdr) + sizeof(*sta);
+ int ret;
+
+ hdr = malloc(blen);
+ if (hdr == NULL)
+ return -1;
+ hdr->op = htonl(PIMOP_GET);
+ hdr->oid = htonl(DOT11_OID_CLIENTFIND);
+ sta = (struct obj_sta *) &hdr[1];
+ memcpy(&sta->address[0], addr, ETH_ALEN);
+ ret = send(drv->pim_sock, hdr, blen, 0);
+ ret = prism54_waitpim(priv, DOT11_OID_CLIENTFIND, hdr, blen, 10);
+ if (ret != blen) {
+ printf("get_inact_sec: bad return %d\n", ret);
+ free(hdr);
+ return -1;
+ }
+ if (hdr->op != (int) htonl(PIMOP_RESPONSE)) {
+ printf("get_inact_sec: bad resp\n");
+ free(hdr);
+ return -1;
+ }
+ free(hdr);
+ return le_to_host16(sta->age);
+}
+
+
+/* set attachments */
+static int prism54_set_generic_elem(const char *ifname, void *priv,
+ const u8 *elem, size_t elem_len)
+{
+ struct prism54_driver_data *drv = priv;
+ pimdev_hdr *hdr;
+ char *pos;
+ struct obj_attachment_hdr *attach;
+ size_t blen = sizeof(*hdr) + sizeof(*attach) + elem_len;
+ hdr = os_zalloc(blen);
+ if (hdr == NULL) {
+ printf("%s: memory low\n", __func__);
+ return -1;
+ }
+ hdr->op = htonl(PIMOP_SET);
+ hdr->oid = htonl(DOT11_OID_ATTACHMENT);
+ attach = (struct obj_attachment_hdr *)&hdr[1];
+ attach->type = DOT11_PKT_BEACON;
+ attach->id = -1;
+ attach->size = host_to_le16((short)elem_len);
+ pos = ((char*) attach) + sizeof(*attach);
+ if (elem)
+ memcpy(pos, elem, elem_len);
+ send(drv->pim_sock, hdr, blen, 0);
+ attach->type = DOT11_PKT_PROBE_RESP;
+ send(drv->pim_sock, hdr, blen, 0);
+ free(hdr);
+ return 0;
+}
+
+
+/* tell the card to auth the sta */
+static void prism54_handle_probe(struct prism54_driver_data *drv,
+ void *buf, size_t len)
+{
+ struct obj_mlmeex *mlme;
+ pimdev_hdr *hdr;
+ struct sta_info *sta;
+ hdr = (pimdev_hdr *)buf;
+ mlme = (struct obj_mlmeex *) &hdr[1];
+ sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
+ if (sta != NULL) {
+ if (sta->flags & (WLAN_STA_AUTH | WLAN_STA_ASSOC))
+ return;
+ }
+ if (len < sizeof(*mlme)) {
+ printf("bad probe packet\n");
+ return;
+ }
+ mlme->state = htons(DOT11_STATE_AUTHING);
+ mlme->code = 0;
+ hdr->op = htonl(PIMOP_SET);
+ hdr->oid = htonl(DOT11_OID_AUTHENTICATEEX);
+ mlme->size = 0;
+ send(drv->pim_sock, hdr, sizeof(*hdr)+sizeof(*mlme), 0);
+}
+
+
+static void prism54_handle_deauth(struct prism54_driver_data *drv,
+ void *buf, size_t len)
+{
+ struct obj_mlme *mlme;
+ pimdev_hdr *hdr;
+ struct sta_info *sta;
+ char *mac_id;
+
+ hdr = (pimdev_hdr *) buf;
+ mlme = (struct obj_mlme *) &hdr[1];
+ sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
+ mac_id = mac_id_get(drv, mlme->id);
+ if (sta == NULL || mac_id == NULL)
+ return;
+ memcpy(&mlme->address[0], mac_id, ETH_ALEN);
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
+ sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+ ap_free_sta(drv->hapd, sta);
+}
+
+
+static void prism54_handle_disassoc(struct prism54_driver_data *drv,
+ void *buf, size_t len)
+{
+ struct obj_mlme *mlme;
+ pimdev_hdr *hdr;
+ struct sta_info *sta;
+ char *mac_id;
+
+ hdr = (pimdev_hdr *) buf;
+ mlme = (struct obj_mlme *) &hdr[1];
+ mac_id = mac_id_get(drv, mlme->id);
+ if (mac_id == NULL)
+ return;
+ memcpy(&mlme->address[0], mac_id, ETH_ALEN);
+ sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
+ if (sta == NULL) {
+ return;
+ }
+ sta->flags &= ~WLAN_STA_ASSOC;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
+ sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+ accounting_sta_stop(drv->hapd, sta);
+ ieee802_1x_free_station(sta);
+}
+
+
+/* to auth it, just allow it now, later for os/sk */
+static void prism54_handle_auth(struct prism54_driver_data *drv,
+ void *buf, size_t len)
+{
+ struct obj_mlmeex *mlme;
+ pimdev_hdr *hdr;
+ struct sta_info *sta;
+ int resp;
+
+ hdr = (pimdev_hdr *) buf;
+ mlme = (struct obj_mlmeex *) &hdr[1];
+ if (len < sizeof(*mlme)) {
+ printf("bad auth packet\n");
+ return;
+ }
+
+ if (mlme->state == htons(DOT11_STATE_AUTHING)) {
+ sta = ap_sta_add(drv->hapd, (u8 *) &mlme->address[0]);
+ if (drv->hapd->tkip_countermeasures) {
+ resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
+ goto fail;
+ }
+ mac_id_refresh(drv, mlme->id, &mlme->address[0]);
+ if (!sta) {
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ sta->flags &= ~WLAN_STA_PREAUTH;
+
+ ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
+ sta->flags |= WLAN_STA_AUTH;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+ mlme->code = 0;
+ mlme->state=htons(DOT11_STATE_AUTH);
+ hdr->op = htonl(PIMOP_SET);
+ hdr->oid = htonl(DOT11_OID_AUTHENTICATEEX);
+ mlme->size = 0;
+ sta->timeout_next = STA_NULLFUNC;
+ send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(*mlme), 0);
+ }
+ return;
+
+fail:
+ printf("auth fail: %x\n", resp);
+ mlme->code = host_to_le16(resp);
+ mlme->size = 0;
+ if (sta)
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ hdr->oid = htonl(DOT11_OID_DEAUTHENTICATEEX);
+ hdr->op = htonl(PIMOP_SET);
+ send(drv->pim_sock, hdr, sizeof(*hdr)+sizeof(*mlme), 0);
+}
+
+
+/* do the wpa thing */
+static void prism54_handle_assoc(struct prism54_driver_data *drv,
+ void *buf, size_t len)
+{
+ pimdev_hdr *hdr;
+ struct obj_mlmeex *mlme;
+ struct ieee802_11_elems elems;
+ struct sta_info *sta;
+ u8 *wpa_ie;
+ u8 *cb;
+ int ieofs = 0;
+ size_t wpa_ie_len;
+ int resp, new_assoc;
+ char *mac_id;
+
+ resp = 0;
+ hdr = (pimdev_hdr *) buf;
+ mlme = (struct obj_mlmeex *) &hdr[1];
+ switch (ntohl(hdr->oid)) {
+ case DOT11_OID_ASSOCIATE:
+ case DOT11_OID_REASSOCIATE:
+ mlme->size = 0;
+ default:
+ break;
+ }
+ if ((mlme->state == (int) htonl(DOT11_STATE_ASSOCING)) ||
+ (mlme->state == (int) htonl(DOT11_STATE_REASSOCING))) {
+ if (len < sizeof(pimdev_hdr) + sizeof(struct obj_mlme)) {
+ printf("bad assoc packet\n");
+ return;
+ }
+ mac_id = mac_id_get(drv, mlme->id);
+ if (mac_id == NULL)
+ return;
+ memcpy(&mlme->address[0], mac_id, ETH_ALEN);
+ sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
+ if (sta == NULL) {
+ printf("cannot get sta\n");
+ return;
+ }
+ cb = (u8 *) &mlme->data[0];
+ if (hdr->oid == htonl(DOT11_OID_ASSOCIATEEX)) {
+ ieofs = 4;
+ } else if (hdr->oid == htonl(DOT11_OID_REASSOCIATEEX)) {
+ ieofs = 10;
+ }
+ if (le_to_host16(mlme->size) <= ieofs) {
+ printf("attach too small\n");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ if (ieee802_11_parse_elems(cb + ieofs,
+ le_to_host16(mlme->size) - ieofs,
+ &elems, 1) == ParseFailed) {
+ printf("STA " MACSTR " sent invalid association "
+ "request\n", MAC2STR(sta->addr));
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ if ((drv->hapd->conf->wpa & WPA_PROTO_RSN) &&
+ elems.rsn_ie) {
+ wpa_ie = elems.rsn_ie;
+ wpa_ie_len = elems.rsn_ie_len;
+ } else if ((drv->hapd->conf->wpa & WPA_PROTO_WPA) &&
+ elems.wpa_ie) {
+ wpa_ie = elems.wpa_ie;
+ wpa_ie_len = elems.wpa_ie_len;
+ } else {
+ wpa_ie = NULL;
+ wpa_ie_len = 0;
+ }
+ if (drv->hapd->conf->wpa && wpa_ie == NULL) {
+ printf("STA " MACSTR ": No WPA/RSN IE in association "
+ "request\n", MAC2STR(sta->addr));
+ resp = WLAN_STATUS_INVALID_IE;
+ goto fail;
+ }
+ if (drv->hapd->conf->wpa) {
+ int res;
+ wpa_ie -= 2;
+ wpa_ie_len += 2;
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm = wpa_auth_sta_init(
+ drv->hapd->wpa_auth, sta->addr);
+ if (sta->wpa_sm == NULL) {
+ printf("Failed to initialize WPA state "
+ "machine\n");
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ goto fail;
+ }
+ res = wpa_validate_wpa_ie(drv->hapd->wpa_auth,
+ sta->wpa_sm,
+ wpa_ie, wpa_ie_len,
+ NULL, 0);
+ if (res == WPA_INVALID_GROUP)
+ resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+ else if (res == WPA_INVALID_PAIRWISE)
+ resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+ else if (res == WPA_INVALID_AKMP)
+ resp = WLAN_STATUS_AKMP_NOT_VALID;
+ else if (res == WPA_ALLOC_FAIL)
+ resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+ else if (res != WPA_IE_OK)
+ resp = WLAN_STATUS_INVALID_IE;
+ if (resp != WLAN_STATUS_SUCCESS)
+ goto fail;
+ }
+ hdr->oid = (hdr->oid == htonl(DOT11_OID_ASSOCIATEEX)) ?
+ htonl(DOT11_OID_ASSOCIATEEX) :
+ htonl(DOT11_OID_REASSOCIATEEX);
+ hdr->op = htonl(PIMOP_SET);
+ mlme->code = 0;
+ mlme->state = htons(DOT11_STATE_ASSOC);
+ mlme->size = 0;
+ send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(*mlme), 0);
+ return;
+ } else if (mlme->state==htons(DOT11_STATE_ASSOC)) {
+ if (len < sizeof(pimdev_hdr) + sizeof(struct obj_mlme)) {
+ printf("bad assoc packet\n");
+ return;
+ }
+ mac_id = mac_id_get(drv, mlme->id);
+ if (mac_id == NULL)
+ return;
+ memcpy(&mlme->address[0], mac_id, ETH_ALEN);
+ sta = ap_get_sta(drv->hapd, (u8 *) &mlme->address[0]);
+ if (sta == NULL) {
+ printf("cannot get sta\n");
+ return;
+ }
+ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
+ sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
+ hostapd_new_assoc_sta(drv->hapd, sta, !new_assoc);
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+ sta->timeout_next = STA_NULLFUNC;
+ return;
+ }
+ return;
+
+fail:
+ printf("Prism54: assoc fail: %x\n", resp);
+ mlme->code = host_to_le16(resp);
+ mlme->size = 0;
+ mlme->state = htons(DOT11_STATE_ASSOCING);
+ hdr->oid = htonl(DOT11_OID_DISASSOCIATEEX);
+ hdr->op = htonl(PIMOP_SET);
+ sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+ send(drv->pim_sock, hdr, sizeof(*hdr) + sizeof(*mlme), 0);
+}
+
+
+static void handle_pim(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct prism54_driver_data *drv = eloop_ctx;
+ int len;
+ pimdev_hdr *hdr;
+
+ hdr = malloc(PIM_BUF_SIZE);
+ if (hdr == NULL)
+ return;
+ len = recv(sock, hdr, PIM_BUF_SIZE, 0);
+ if (len < 0) {
+ perror("recv");
+ free(hdr);
+ return;
+ }
+ if (len < 8) {
+ printf("handle_pim: too short (%d)\n", len);
+ free(hdr);
+ return;
+ }
+
+ if (hdr->op != (int) htonl(PIMOP_TRAP)) {
+ free(hdr);
+ return;
+ }
+ switch (ntohl(hdr->oid)) {
+ case DOT11_OID_PROBE:
+ prism54_handle_probe(drv, hdr, len);
+ break;
+ case DOT11_OID_DEAUTHENTICATEEX:
+ case DOT11_OID_DEAUTHENTICATE:
+ prism54_handle_deauth(drv, hdr, len);
+ break;
+ case DOT11_OID_DISASSOCIATEEX:
+ case DOT11_OID_DISASSOCIATE:
+ prism54_handle_disassoc(drv, hdr, len);
+ break;
+ case DOT11_OID_AUTHENTICATEEX:
+ case DOT11_OID_AUTHENTICATE:
+ prism54_handle_auth(drv, hdr, len);
+ break;
+ case DOT11_OID_ASSOCIATEEX:
+ case DOT11_OID_REASSOCIATEEX:
+ case DOT11_OID_ASSOCIATE:
+ case DOT11_OID_REASSOCIATE:
+ prism54_handle_assoc(drv, hdr, len);
+ default:
+ break;
+ }
+
+ free(hdr);
+}
+
+
+static void handle_802_3(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx;
+ int len;
+ ieee802_3_hdr *hdr;
+
+ hdr = malloc(PIM_BUF_SIZE);
+ if (hdr == NULL)
+ return;
+ len = recv(sock, hdr, PIM_BUF_SIZE, 0);
+ if (len < 0) {
+ perror("recv");
+ free(hdr);
+ return;
+ }
+ if (len < 14) {
+ wpa_printf(MSG_MSGDUMP, "handle_802_3: too short (%d)", len);
+ free(hdr);
+ return;
+ }
+ if (hdr->type == htons(ETH_P_PAE)) {
+ ieee802_1x_receive(hapd, (u8 *) &hdr->sa[0], (u8 *) &hdr[1],
+ len - sizeof(*hdr));
+ }
+ free(hdr);
+}
+
+
+static int prism54_init_sockets(struct prism54_driver_data *drv)
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct ifreq ifr;
+ struct sockaddr_ll addr;
+
+ drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
+ if (drv->sock < 0) {
+ perror("socket[PF_PACKET,SOCK_RAW]");
+ return -1;
+ }
+
+ if (eloop_register_read_sock(drv->sock, handle_802_3, drv->hapd, NULL))
+ {
+ printf("Could not register read socket\n");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ if (hapd->conf->bridge[0] != '\0') {
+ printf("opening bridge: %s\n", hapd->conf->bridge);
+ os_strlcpy(ifr.ifr_name, hapd->conf->bridge,
+ sizeof(ifr.ifr_name));
+ } else {
+ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
+ }
+ if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
+ perror("ioctl(SIOCGIFINDEX)");
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sll_family = AF_PACKET;
+ addr.sll_ifindex = ifr.ifr_ifindex;
+ addr.sll_protocol = htons(ETH_P_PAE);
+ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
+ addr.sll_ifindex);
+
+ if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->iface, sizeof(ifr.ifr_name));
+ if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
+ perror("ioctl(SIOCGIFHWADDR)");
+ return -1;
+ }
+
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ printf("Invalid HW-addr family 0x%04x\n",
+ ifr.ifr_hwaddr.sa_family);
+ return -1;
+ }
+ memcpy(drv->hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ drv->pim_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (drv->pim_sock < 0) {
+ perror("socket[PF_PACKET,SOCK_RAW]");
+ return -1;
+ }
+
+ if (eloop_register_read_sock(drv->pim_sock, handle_pim, drv, NULL)) {
+ printf("Could not register read socket\n");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ snprintf(ifr.ifr_name, sizeof(ifr.ifr_name), "%sap", drv->iface);
+ if (ioctl(drv->pim_sock, SIOCGIFINDEX, &ifr) != 0) {
+ perror("ioctl(SIOCGIFINDEX)");
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sll_family = AF_PACKET;
+ addr.sll_ifindex = ifr.ifr_ifindex;
+ addr.sll_protocol = htons(ETH_P_ALL);
+ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
+ addr.sll_ifindex);
+
+ if (bind(drv->pim_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void * prism54_driver_init(struct hostapd_data *hapd)
+{
+ struct prism54_driver_data *drv;
+
+ drv = os_zalloc(sizeof(struct prism54_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for hostapd Prism54 driver "
+ "data\n");
+ return NULL;
+ }
+
+ drv->hapd = hapd;
+ drv->pim_sock = drv->sock = -1;
+ memcpy(drv->iface, hapd->conf->iface, sizeof(drv->iface));
+
+ if (prism54_init_sockets(drv)) {
+ free(drv);
+ return NULL;
+ }
+ prism54_init_1x(drv);
+ /* must clean previous elems */
+ prism54_set_generic_elem(drv->iface, drv, NULL, 0);
+
+ return drv;
+}
+
+
+static void prism54_driver_deinit(void *priv)
+{
+ struct prism54_driver_data *drv = priv;
+
+ if (drv->pim_sock >= 0)
+ close(drv->pim_sock);
+
+ if (drv->sock >= 0)
+ close(drv->sock);
+
+ free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_prism54_ops = {
+ .name = "prism54",
+ .init = prism54_driver_init,
+ .deinit = prism54_driver_deinit,
+ /* .set_ieee8021x = prism54_init_1x, */
+ .set_privacy = prism54_set_privacy_invoked,
+ .set_encryption = prism54_set_encryption,
+ .get_seqnum = prism54_get_seqnum,
+ .flush = prism54_flush,
+ .set_generic_elem = prism54_set_generic_elem,
+ .send_eapol = prism54_send_eapol,
+ .sta_set_flags = prism54_sta_set_flags,
+ .sta_deauth = prism54_sta_deauth,
+ .sta_disassoc = prism54_sta_disassoc,
+ .set_ssid = prism54_ioctl_setiwessid,
+ .get_inact_sec = prism54_get_inact_sec,
+};
diff --git a/hostapd/driver_test.c b/hostapd/driver_test.c
new file mode 100644
index 0000000..9930a82
--- /dev/null
+++ b/hostapd/driver_test.c
@@ -0,0 +1,1300 @@
+/*
+ * hostapd / Driver interface for development testing
+ * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/un.h>
+#include <dirent.h>
+
+#include "hostapd.h"
+#include "driver.h"
+#include "sha1.h"
+#include "eloop.h"
+#include "ieee802_1x.h"
+#include "sta_info.h"
+#include "wpa.h"
+#include "accounting.h"
+#include "radius/radius.h"
+#include "l2_packet/l2_packet.h"
+#include "ieee802_11.h"
+#include "hw_features.h"
+#include "wps_hostapd.h"
+
+
+struct test_client_socket {
+ struct test_client_socket *next;
+ u8 addr[ETH_ALEN];
+ struct sockaddr_un un;
+ socklen_t unlen;
+ struct test_driver_bss *bss;
+};
+
+struct test_driver_bss {
+ struct test_driver_bss *next;
+ char ifname[IFNAMSIZ + 1];
+ u8 bssid[ETH_ALEN];
+ u8 *ie;
+ size_t ielen;
+ u8 *wps_beacon_ie;
+ size_t wps_beacon_ie_len;
+ u8 *wps_probe_resp_ie;
+ size_t wps_probe_resp_ie_len;
+ u8 ssid[32];
+ size_t ssid_len;
+ int privacy;
+};
+
+struct test_driver_data {
+ struct hostapd_data *hapd;
+ struct test_client_socket *cli;
+ int test_socket;
+ struct test_driver_bss *bss;
+ char *socket_dir;
+ char *own_socket_path;
+ int udp_port;
+};
+
+
+static void test_driver_free_bss(struct test_driver_bss *bss)
+{
+ free(bss->ie);
+ free(bss->wps_beacon_ie);
+ free(bss->wps_probe_resp_ie);
+ free(bss);
+}
+
+
+static void test_driver_free_priv(struct test_driver_data *drv)
+{
+ struct test_driver_bss *bss, *prev;
+
+ if (drv == NULL)
+ return;
+
+ bss = drv->bss;
+ while (bss) {
+ prev = bss;
+ bss = bss->next;
+ test_driver_free_bss(prev);
+ }
+ free(drv->own_socket_path);
+ free(drv->socket_dir);
+ free(drv);
+}
+
+
+static struct test_client_socket *
+test_driver_get_cli(struct test_driver_data *drv, struct sockaddr_un *from,
+ socklen_t fromlen)
+{
+ struct test_client_socket *cli = drv->cli;
+
+ while (cli) {
+ if (cli->unlen == fromlen &&
+ strncmp(cli->un.sun_path, from->sun_path,
+ fromlen - sizeof(cli->un.sun_family)) == 0)
+ return cli;
+ cli = cli->next;
+ }
+
+ return NULL;
+}
+
+
+static int test_driver_send_eapol(void *priv, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt,
+ const u8 *own_addr)
+{
+ struct test_driver_data *drv = priv;
+ struct test_client_socket *cli;
+ struct msghdr msg;
+ struct iovec io[3];
+ struct l2_ethhdr eth;
+
+ if (drv->test_socket < 0)
+ return -1;
+
+ cli = drv->cli;
+ while (cli) {
+ if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
+ break;
+ cli = cli->next;
+ }
+
+ if (!cli) {
+ wpa_printf(MSG_DEBUG, "%s: no destination client entry",
+ __func__);
+ return -1;
+ }
+
+ memcpy(eth.h_dest, addr, ETH_ALEN);
+ memcpy(eth.h_source, own_addr, ETH_ALEN);
+ eth.h_proto = host_to_be16(ETH_P_EAPOL);
+
+ io[0].iov_base = "EAPOL ";
+ io[0].iov_len = 6;
+ io[1].iov_base = &eth;
+ io[1].iov_len = sizeof(eth);
+ io[2].iov_base = (u8 *) data;
+ io[2].iov_len = data_len;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 3;
+ msg.msg_name = &cli->un;
+ msg.msg_namelen = cli->unlen;
+ return sendmsg(drv->test_socket, &msg, 0);
+}
+
+
+static int test_driver_send_ether(void *priv, const u8 *dst, const u8 *src,
+ u16 proto, const u8 *data, size_t data_len)
+{
+ struct test_driver_data *drv = priv;
+ struct msghdr msg;
+ struct iovec io[3];
+ struct l2_ethhdr eth;
+ char desttxt[30];
+ struct sockaddr_un addr;
+ struct dirent *dent;
+ DIR *dir;
+ int ret = 0, broadcast = 0, count = 0;
+
+ if (drv->test_socket < 0 || drv->socket_dir == NULL) {
+ wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d "
+ "socket_dir=%p)",
+ __func__, drv->test_socket, drv->socket_dir);
+ return -1;
+ }
+
+ broadcast = memcmp(dst, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0;
+ snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dst));
+
+ memcpy(eth.h_dest, dst, ETH_ALEN);
+ memcpy(eth.h_source, src, ETH_ALEN);
+ eth.h_proto = host_to_be16(proto);
+
+ io[0].iov_base = "ETHER ";
+ io[0].iov_len = 6;
+ io[1].iov_base = &eth;
+ io[1].iov_len = sizeof(eth);
+ io[2].iov_base = (u8 *) data;
+ io[2].iov_len = data_len;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 3;
+
+ dir = opendir(drv->socket_dir);
+ if (dir == NULL) {
+ perror("test_driver: opendir");
+ return -1;
+ }
+ while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+ /* Skip the file if it is not a socket. Also accept
+ * DT_UNKNOWN (0) in case the C library or underlying file
+ * system does not support d_type. */
+ if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
+ continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
+ drv->socket_dir, dent->d_name);
+
+ if (strcmp(addr.sun_path, drv->own_socket_path) == 0)
+ continue;
+ if (!broadcast && strstr(dent->d_name, desttxt) == NULL)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "%s: Send ether frame to %s",
+ __func__, dent->d_name);
+
+ msg.msg_name = &addr;
+ msg.msg_namelen = sizeof(addr);
+ ret = sendmsg(drv->test_socket, &msg, 0);
+ if (ret < 0)
+ perror("driver_test: sendmsg");
+ count++;
+ }
+ closedir(dir);
+
+ if (!broadcast && count == 0) {
+ wpa_printf(MSG_DEBUG, "%s: Destination " MACSTR " not found",
+ __func__, MAC2STR(dst));
+ return -1;
+ }
+
+ return ret;
+}
+
+
+static int test_driver_send_mgmt_frame(void *priv, const void *buf,
+ size_t len, int flags)
+{
+ struct test_driver_data *drv = priv;
+ struct msghdr msg;
+ struct iovec io[2];
+ const u8 *dest;
+ int ret = 0, broadcast = 0;
+ char desttxt[30];
+ struct sockaddr_un addr;
+ struct dirent *dent;
+ DIR *dir;
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+
+ if (drv->test_socket < 0 || len < 10 || drv->socket_dir == NULL) {
+ wpa_printf(MSG_DEBUG, "%s: invalid parameters (sock=%d len=%lu"
+ " socket_dir=%p)",
+ __func__, drv->test_socket, (unsigned long) len,
+ drv->socket_dir);
+ return -1;
+ }
+
+ dest = buf;
+ dest += 4;
+ broadcast = memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0;
+ snprintf(desttxt, sizeof(desttxt), MACSTR, MAC2STR(dest));
+
+ io[0].iov_base = "MLME ";
+ io[0].iov_len = 5;
+ io[1].iov_base = (void *) buf;
+ io[1].iov_len = len;
+
+ memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 2;
+
+ dir = opendir(drv->socket_dir);
+ if (dir == NULL) {
+ perror("test_driver: opendir");
+ return -1;
+ }
+ while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+ /* Skip the file if it is not a socket. Also accept
+ * DT_UNKNOWN (0) in case the C library or underlying file
+ * system does not support d_type. */
+ if (dent->d_type != DT_SOCK && dent->d_type != DT_UNKNOWN)
+ continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
+ drv->socket_dir, dent->d_name);
+
+ if (strcmp(addr.sun_path, drv->own_socket_path) == 0)
+ continue;
+ if (!broadcast && strstr(dent->d_name, desttxt) == NULL)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "%s: Send management frame to %s",
+ __func__, dent->d_name);
+
+ msg.msg_name = &addr;
+ msg.msg_namelen = sizeof(addr);
+ ret = sendmsg(drv->test_socket, &msg, 0);
+ if (ret < 0)
+ perror("driver_test: sendmsg");
+ }
+ closedir(dir);
+
+ hdr = (struct ieee80211_hdr *) buf;
+ fc = le_to_host16(hdr->frame_control);
+ ieee802_11_mgmt_cb(drv->hapd, (u8 *) buf, len, WLAN_FC_GET_STYPE(fc),
+ ret >= 0);
+
+ return ret;
+}
+
+
+static void test_driver_scan(struct test_driver_data *drv,
+ struct sockaddr_un *from, socklen_t fromlen,
+ char *data)
+{
+ char buf[512], *pos, *end;
+ int ret;
+ struct test_driver_bss *bss;
+ u8 sa[ETH_ALEN];
+ u8 ie[512];
+ size_t ielen;
+
+ /* data: optional [ ' ' | STA-addr | ' ' | IEs(hex) ] */
+
+ wpa_printf(MSG_DEBUG, "test_driver: SCAN");
+
+ if (*data) {
+ if (*data != ' ' ||
+ hwaddr_aton(data + 1, sa)) {
+ wpa_printf(MSG_DEBUG, "test_driver: Unexpected SCAN "
+ "command format");
+ return;
+ }
+
+ data += 18;
+ while (*data == ' ')
+ data++;
+ ielen = os_strlen(data) / 2;
+ if (ielen > sizeof(ie))
+ ielen = sizeof(ie);
+ if (hexstr2bin(data, ie, ielen) < 0)
+ ielen = 0;
+
+ wpa_printf(MSG_DEBUG, "test_driver: Scan from " MACSTR,
+ MAC2STR(sa));
+ wpa_hexdump(MSG_MSGDUMP, "test_driver: scan IEs", ie, ielen);
+
+ hostapd_wps_probe_req_rx(drv->hapd, sa, ie, ielen);
+ }
+
+ for (bss = drv->bss; bss; bss = bss->next) {
+ pos = buf;
+ end = buf + sizeof(buf);
+
+ /* reply: SCANRESP BSSID SSID IEs */
+ ret = snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
+ MAC2STR(bss->bssid));
+ if (ret < 0 || ret >= end - pos)
+ return;
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, end - pos,
+ bss->ssid, bss->ssid_len);
+ ret = snprintf(pos, end - pos, " ");
+ if (ret < 0 || ret >= end - pos)
+ return;
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, end - pos, bss->ie, bss->ielen);
+ pos += wpa_snprintf_hex(pos, end - pos, bss->wps_probe_resp_ie,
+ bss->wps_probe_resp_ie_len);
+
+ if (bss->privacy) {
+ ret = snprintf(pos, end - pos, " PRIVACY");
+ if (ret < 0 || ret >= end - pos)
+ return;
+ pos += ret;
+ }
+
+ sendto(drv->test_socket, buf, pos - buf, 0,
+ (struct sockaddr *) from, fromlen);
+ }
+}
+
+
+static struct hostapd_data * test_driver_get_hapd(struct test_driver_data *drv,
+ struct test_driver_bss *bss)
+{
+ struct hostapd_iface *iface = drv->hapd->iface;
+ struct hostapd_data *hapd = NULL;
+ size_t i;
+
+ if (bss == NULL) {
+ wpa_printf(MSG_DEBUG, "%s: bss == NULL", __func__);
+ return NULL;
+ }
+
+ for (i = 0; i < iface->num_bss; i++) {
+ hapd = iface->bss[i];
+ if (memcmp(hapd->own_addr, bss->bssid, ETH_ALEN) == 0)
+ break;
+ }
+ if (i == iface->num_bss) {
+ wpa_printf(MSG_DEBUG, "%s: no matching interface entry found "
+ "for BSSID " MACSTR, __func__, MAC2STR(bss->bssid));
+ return NULL;
+ }
+
+ return hapd;
+}
+
+
+static int test_driver_new_sta(struct test_driver_data *drv,
+ struct test_driver_bss *bss, const u8 *addr,
+ const u8 *ie, size_t ielen)
+{
+ struct hostapd_data *hapd;
+ struct sta_info *sta;
+ int new_assoc, res;
+
+ hapd = test_driver_get_hapd(drv, bss);
+ if (hapd == NULL)
+ return -1;
+
+ hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "associated");
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta) {
+ accounting_sta_stop(hapd, sta);
+ } else {
+ sta = ap_sta_add(hapd, addr);
+ if (sta == NULL)
+ return -1;
+ }
+ sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS);
+
+ if (hapd->conf->wpa) {
+ if (ie == NULL || ielen == 0) {
+ if (hapd->conf->wps_state) {
+ sta->flags |= WLAN_STA_WPS;
+ goto skip_wpa_check;
+ }
+
+ printf("test_driver: no IE from STA\n");
+ return -1;
+ }
+ if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
+ os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
+ sta->flags |= WLAN_STA_WPS;
+ goto skip_wpa_check;
+ }
+
+ if (sta->wpa_sm == NULL)
+ sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+ sta->addr);
+ if (sta->wpa_sm == NULL) {
+ printf("test_driver: Failed to initialize WPA state "
+ "machine\n");
+ return -1;
+ }
+ res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+ ie, ielen, NULL, 0);
+ if (res != WPA_IE_OK) {
+ printf("WPA/RSN information element rejected? "
+ "(res %u)\n", res);
+ wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
+ return -1;
+ }
+ }
+skip_wpa_check:
+
+ new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
+ sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
+
+ hostapd_new_assoc_sta(hapd, sta, !new_assoc);
+
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+
+ return 0;
+}
+
+
+static void test_driver_assoc(struct test_driver_data *drv,
+ struct sockaddr_un *from, socklen_t fromlen,
+ char *data)
+{
+ struct test_client_socket *cli;
+ u8 ie[256], ssid[32];
+ size_t ielen, ssid_len = 0;
+ char *pos, *pos2, cmd[50];
+ struct test_driver_bss *bss;
+
+ /* data: STA-addr SSID(hex) IEs(hex) */
+
+ cli = os_zalloc(sizeof(*cli));
+ if (cli == NULL)
+ return;
+
+ if (hwaddr_aton(data, cli->addr)) {
+ printf("test_socket: Invalid MAC address '%s' in ASSOC\n",
+ data);
+ free(cli);
+ return;
+ }
+ pos = data + 17;
+ while (*pos == ' ')
+ pos++;
+ pos2 = strchr(pos, ' ');
+ ielen = 0;
+ if (pos2) {
+ ssid_len = (pos2 - pos) / 2;
+ if (hexstr2bin(pos, ssid, ssid_len) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Invalid SSID", __func__);
+ free(cli);
+ return;
+ }
+ wpa_hexdump_ascii(MSG_DEBUG, "test_driver_assoc: SSID",
+ ssid, ssid_len);
+
+ pos = pos2 + 1;
+ ielen = strlen(pos) / 2;
+ if (ielen > sizeof(ie))
+ ielen = sizeof(ie);
+ if (hexstr2bin(pos, ie, ielen) < 0)
+ ielen = 0;
+ }
+
+ for (bss = drv->bss; bss; bss = bss->next) {
+ if (bss->ssid_len == ssid_len &&
+ memcmp(bss->ssid, ssid, ssid_len) == 0)
+ break;
+ }
+ if (bss == NULL) {
+ wpa_printf(MSG_DEBUG, "%s: No matching SSID found from "
+ "configured BSSes", __func__);
+ free(cli);
+ return;
+ }
+
+ cli->bss = bss;
+ memcpy(&cli->un, from, sizeof(cli->un));
+ cli->unlen = fromlen;
+ cli->next = drv->cli;
+ drv->cli = cli;
+ wpa_hexdump_ascii(MSG_DEBUG, "test_socket: ASSOC sun_path",
+ (const u8 *) cli->un.sun_path,
+ cli->unlen - sizeof(cli->un.sun_family));
+
+ snprintf(cmd, sizeof(cmd), "ASSOCRESP " MACSTR " 0",
+ MAC2STR(bss->bssid));
+ sendto(drv->test_socket, cmd, strlen(cmd), 0,
+ (struct sockaddr *) from, fromlen);
+
+ if (test_driver_new_sta(drv, bss, cli->addr, ie, ielen) < 0) {
+ wpa_printf(MSG_DEBUG, "test_driver: failed to add new STA");
+ }
+}
+
+
+static void test_driver_disassoc(struct test_driver_data *drv,
+ struct sockaddr_un *from, socklen_t fromlen)
+{
+ struct test_client_socket *cli;
+ struct sta_info *sta;
+
+ cli = test_driver_get_cli(drv, from, fromlen);
+ if (!cli)
+ return;
+
+ hostapd_logger(drv->hapd, cli->addr, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_INFO, "disassociated");
+
+ sta = ap_get_sta(drv->hapd, cli->addr);
+ if (sta != NULL) {
+ sta->flags &= ~WLAN_STA_ASSOC;
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
+ sta->acct_terminate_cause =
+ RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+ ap_free_sta(drv->hapd, sta);
+ }
+}
+
+
+static void test_driver_eapol(struct test_driver_data *drv,
+ struct sockaddr_un *from, socklen_t fromlen,
+ u8 *data, size_t datalen)
+{
+ struct test_client_socket *cli;
+ if (datalen > 14) {
+ /* Skip Ethernet header */
+ wpa_printf(MSG_DEBUG, "test_driver: dst=" MACSTR " src="
+ MACSTR " proto=%04x",
+ MAC2STR(data), MAC2STR(data + ETH_ALEN),
+ WPA_GET_BE16(data + 2 * ETH_ALEN));
+ data += 14;
+ datalen -= 14;
+ }
+ cli = test_driver_get_cli(drv, from, fromlen);
+ if (cli) {
+ struct hostapd_data *hapd;
+ hapd = test_driver_get_hapd(drv, cli->bss);
+ if (hapd == NULL)
+ return;
+ ieee802_1x_receive(hapd, cli->addr, data, datalen);
+ } else {
+ wpa_printf(MSG_DEBUG, "test_socket: EAPOL from unknown "
+ "client");
+ }
+}
+
+
+static void test_driver_ether(struct test_driver_data *drv,
+ struct sockaddr_un *from, socklen_t fromlen,
+ u8 *data, size_t datalen)
+{
+ struct l2_ethhdr *eth;
+
+ if (datalen < sizeof(*eth))
+ return;
+
+ eth = (struct l2_ethhdr *) data;
+ wpa_printf(MSG_DEBUG, "test_driver: RX ETHER dst=" MACSTR " src="
+ MACSTR " proto=%04x",
+ MAC2STR(eth->h_dest), MAC2STR(eth->h_source),
+ be_to_host16(eth->h_proto));
+
+#ifdef CONFIG_IEEE80211R
+ if (be_to_host16(eth->h_proto) == ETH_P_RRB) {
+ wpa_ft_rrb_rx(drv->hapd->wpa_auth, eth->h_source,
+ data + sizeof(*eth), datalen - sizeof(*eth));
+ }
+#endif /* CONFIG_IEEE80211R */
+}
+
+
+static void test_driver_mlme(struct test_driver_data *drv,
+ struct sockaddr_un *from, socklen_t fromlen,
+ u8 *data, size_t datalen)
+{
+ struct ieee80211_hdr *hdr;
+ u16 fc;
+
+ hdr = (struct ieee80211_hdr *) data;
+
+ if (test_driver_get_cli(drv, from, fromlen) == NULL && datalen >= 16) {
+ struct test_client_socket *cli;
+ cli = os_zalloc(sizeof(*cli));
+ if (cli == NULL)
+ return;
+ wpa_printf(MSG_DEBUG, "Adding client entry for " MACSTR,
+ MAC2STR(hdr->addr2));
+ memcpy(cli->addr, hdr->addr2, ETH_ALEN);
+ memcpy(&cli->un, from, sizeof(cli->un));
+ cli->unlen = fromlen;
+ cli->next = drv->cli;
+ drv->cli = cli;
+ }
+
+ wpa_hexdump(MSG_MSGDUMP, "test_driver_mlme: received frame",
+ data, datalen);
+ fc = le_to_host16(hdr->frame_control);
+ if (WLAN_FC_GET_TYPE(fc) != WLAN_FC_TYPE_MGMT) {
+ wpa_printf(MSG_ERROR, "%s: received non-mgmt frame",
+ __func__);
+ return;
+ }
+ ieee802_11_mgmt(drv->hapd, data, datalen, WLAN_FC_GET_STYPE(fc), NULL);
+}
+
+
+static void test_driver_receive_unix(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct test_driver_data *drv = eloop_ctx;
+ char buf[2000];
+ int res;
+ struct sockaddr_un from;
+ socklen_t fromlen = sizeof(from);
+
+ res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ perror("recvfrom(test_socket)");
+ return;
+ }
+ buf[res] = '\0';
+
+ wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
+
+ if (strncmp(buf, "SCAN", 4) == 0) {
+ test_driver_scan(drv, &from, fromlen, buf + 4);
+ } else if (strncmp(buf, "ASSOC ", 6) == 0) {
+ test_driver_assoc(drv, &from, fromlen, buf + 6);
+ } else if (strcmp(buf, "DISASSOC") == 0) {
+ test_driver_disassoc(drv, &from, fromlen);
+ } else if (strncmp(buf, "EAPOL ", 6) == 0) {
+ test_driver_eapol(drv, &from, fromlen, (u8 *) buf + 6,
+ res - 6);
+ } else if (strncmp(buf, "ETHER ", 6) == 0) {
+ test_driver_ether(drv, &from, fromlen, (u8 *) buf + 6,
+ res - 6);
+ } else if (strncmp(buf, "MLME ", 5) == 0) {
+ test_driver_mlme(drv, &from, fromlen, (u8 *) buf + 5, res - 5);
+ } else {
+ wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
+ (u8 *) buf, res);
+ }
+}
+
+
+static struct test_driver_bss *
+test_driver_get_bss(struct test_driver_data *drv, const char *ifname)
+{
+ struct test_driver_bss *bss;
+
+ for (bss = drv->bss; bss; bss = bss->next) {
+ if (strcmp(bss->ifname, ifname) == 0)
+ return bss;
+ }
+ return NULL;
+}
+
+
+static int test_driver_set_generic_elem(const char *ifname, void *priv,
+ const u8 *elem, size_t elem_len)
+{
+ struct test_driver_data *drv = priv;
+ struct test_driver_bss *bss;
+
+ bss = test_driver_get_bss(drv, ifname);
+ if (bss == NULL)
+ return -1;
+
+ free(bss->ie);
+
+ if (elem == NULL) {
+ bss->ie = NULL;
+ bss->ielen = 0;
+ return 0;
+ }
+
+ bss->ie = malloc(elem_len);
+ if (bss->ie == NULL) {
+ bss->ielen = 0;
+ return -1;
+ }
+
+ memcpy(bss->ie, elem, elem_len);
+ bss->ielen = elem_len;
+ return 0;
+}
+
+
+static int test_driver_set_wps_beacon_ie(const char *ifname, void *priv,
+ const u8 *ie, size_t len)
+{
+ struct test_driver_data *drv = priv;
+ struct test_driver_bss *bss;
+
+ wpa_hexdump(MSG_DEBUG, "test_driver: Beacon WPS IE", ie, len);
+ bss = test_driver_get_bss(drv, ifname);
+ if (bss == NULL)
+ return -1;
+
+ free(bss->wps_beacon_ie);
+
+ if (ie == NULL) {
+ bss->wps_beacon_ie = NULL;
+ bss->wps_beacon_ie_len = 0;
+ return 0;
+ }
+
+ bss->wps_beacon_ie = malloc(len);
+ if (bss->wps_beacon_ie == NULL) {
+ bss->wps_beacon_ie_len = 0;
+ return -1;
+ }
+
+ memcpy(bss->wps_beacon_ie, ie, len);
+ bss->wps_beacon_ie_len = len;
+ return 0;
+}
+
+
+static int test_driver_set_wps_probe_resp_ie(const char *ifname, void *priv,
+ const u8 *ie, size_t len)
+{
+ struct test_driver_data *drv = priv;
+ struct test_driver_bss *bss;
+
+ wpa_hexdump(MSG_DEBUG, "test_driver: ProbeResp WPS IE", ie, len);
+ bss = test_driver_get_bss(drv, ifname);
+ if (bss == NULL)
+ return -1;
+
+ free(bss->wps_probe_resp_ie);
+
+ if (ie == NULL) {
+ bss->wps_probe_resp_ie = NULL;
+ bss->wps_probe_resp_ie_len = 0;
+ return 0;
+ }
+
+ bss->wps_probe_resp_ie = malloc(len);
+ if (bss->wps_probe_resp_ie == NULL) {
+ bss->wps_probe_resp_ie_len = 0;
+ return -1;
+ }
+
+ memcpy(bss->wps_probe_resp_ie, ie, len);
+ bss->wps_probe_resp_ie_len = len;
+ return 0;
+}
+
+
+static int test_driver_sta_deauth(void *priv, const u8 *addr, int reason)
+{
+ struct test_driver_data *drv = priv;
+ struct test_client_socket *cli;
+
+ if (drv->test_socket < 0)
+ return -1;
+
+ cli = drv->cli;
+ while (cli) {
+ if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
+ break;
+ cli = cli->next;
+ }
+
+ if (!cli)
+ return -1;
+
+ return sendto(drv->test_socket, "DEAUTH", 6, 0,
+ (struct sockaddr *) &cli->un, cli->unlen);
+}
+
+
+static int test_driver_sta_disassoc(void *priv, const u8 *addr, int reason)
+{
+ struct test_driver_data *drv = priv;
+ struct test_client_socket *cli;
+
+ if (drv->test_socket < 0)
+ return -1;
+
+ cli = drv->cli;
+ while (cli) {
+ if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
+ break;
+ cli = cli->next;
+ }
+
+ if (!cli)
+ return -1;
+
+ return sendto(drv->test_socket, "DISASSOC", 8, 0,
+ (struct sockaddr *) &cli->un, cli->unlen);
+}
+
+
+static struct hostapd_hw_modes *
+test_driver_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+{
+ struct hostapd_hw_modes *modes;
+
+ *num_modes = 3;
+ *flags = 0;
+ modes = os_zalloc(*num_modes * sizeof(struct hostapd_hw_modes));
+ if (modes == NULL)
+ return NULL;
+ modes[0].mode = HOSTAPD_MODE_IEEE80211G;
+ modes[0].num_channels = 1;
+ modes[0].num_rates = 1;
+ modes[0].channels = os_zalloc(sizeof(struct hostapd_channel_data));
+ modes[0].rates = os_zalloc(sizeof(struct hostapd_rate_data));
+ if (modes[0].channels == NULL || modes[0].rates == NULL) {
+ hostapd_free_hw_features(modes, *num_modes);
+ return NULL;
+ }
+ modes[0].channels[0].chan = 1;
+ modes[0].channels[0].freq = 2412;
+ modes[0].channels[0].flag = 0;
+ modes[0].rates[0].rate = 10;
+ modes[0].rates[0].flags = HOSTAPD_RATE_BASIC | HOSTAPD_RATE_SUPPORTED |
+ HOSTAPD_RATE_CCK | HOSTAPD_RATE_MANDATORY;
+
+ modes[1].mode = HOSTAPD_MODE_IEEE80211B;
+ modes[1].num_channels = 1;
+ modes[1].num_rates = 1;
+ modes[1].channels = os_zalloc(sizeof(struct hostapd_channel_data));
+ modes[1].rates = os_zalloc(sizeof(struct hostapd_rate_data));
+ if (modes[1].channels == NULL || modes[1].rates == NULL) {
+ hostapd_free_hw_features(modes, *num_modes);
+ return NULL;
+ }
+ modes[1].channels[0].chan = 1;
+ modes[1].channels[0].freq = 2412;
+ modes[1].channels[0].flag = 0;
+ modes[1].rates[0].rate = 10;
+ modes[1].rates[0].flags = HOSTAPD_RATE_BASIC | HOSTAPD_RATE_SUPPORTED |
+ HOSTAPD_RATE_CCK | HOSTAPD_RATE_MANDATORY;
+
+ modes[2].mode = HOSTAPD_MODE_IEEE80211A;
+ modes[2].num_channels = 1;
+ modes[2].num_rates = 1;
+ modes[2].channels = os_zalloc(sizeof(struct hostapd_channel_data));
+ modes[2].rates = os_zalloc(sizeof(struct hostapd_rate_data));
+ if (modes[2].channels == NULL || modes[2].rates == NULL) {
+ hostapd_free_hw_features(modes, *num_modes);
+ return NULL;
+ }
+ modes[2].channels[0].chan = 60;
+ modes[2].channels[0].freq = 5300;
+ modes[2].channels[0].flag = 0;
+ modes[2].rates[0].rate = 60;
+ modes[2].rates[0].flags = HOSTAPD_RATE_BASIC | HOSTAPD_RATE_SUPPORTED |
+ HOSTAPD_RATE_MANDATORY;
+
+ return modes;
+}
+
+
+static int test_driver_bss_add(void *priv, const char *ifname, const u8 *bssid)
+{
+ struct test_driver_data *drv = priv;
+ struct test_driver_bss *bss;
+
+ wpa_printf(MSG_DEBUG, "%s(ifname=%s bssid=" MACSTR ")",
+ __func__, ifname, MAC2STR(bssid));
+
+ bss = os_zalloc(sizeof(*bss));
+ if (bss == NULL)
+ return -1;
+
+ os_strlcpy(bss->ifname, ifname, IFNAMSIZ);
+ memcpy(bss->bssid, bssid, ETH_ALEN);
+
+ bss->next = drv->bss;
+ drv->bss = bss;
+
+ return 0;
+}
+
+
+static int test_driver_bss_remove(void *priv, const char *ifname)
+{
+ struct test_driver_data *drv = priv;
+ struct test_driver_bss *bss, *prev;
+ struct test_client_socket *cli, *prev_c;
+
+ wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, ifname);
+
+ for (prev = NULL, bss = drv->bss; bss; prev = bss, bss = bss->next) {
+ if (strcmp(bss->ifname, ifname) != 0)
+ continue;
+
+ if (prev)
+ prev->next = bss->next;
+ else
+ drv->bss = bss->next;
+
+ for (prev_c = NULL, cli = drv->cli; cli;
+ prev_c = cli, cli = cli->next) {
+ if (cli->bss != bss)
+ continue;
+ if (prev_c)
+ prev_c->next = cli->next;
+ else
+ drv->cli = cli->next;
+ free(cli);
+ break;
+ }
+
+ test_driver_free_bss(bss);
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int test_driver_if_add(const char *iface, void *priv,
+ enum hostapd_driver_if_type type, char *ifname,
+ const u8 *addr)
+{
+ wpa_printf(MSG_DEBUG, "%s(iface=%s type=%d ifname=%s)",
+ __func__, iface, type, ifname);
+ return 0;
+}
+
+
+static int test_driver_if_update(void *priv, enum hostapd_driver_if_type type,
+ char *ifname, const u8 *addr)
+{
+ wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s)", __func__, type, ifname);
+ return 0;
+}
+
+
+static int test_driver_if_remove(void *priv, enum hostapd_driver_if_type type,
+ const char *ifname, const u8 *addr)
+{
+ wpa_printf(MSG_DEBUG, "%s(type=%d ifname=%s)", __func__, type, ifname);
+ return 0;
+}
+
+
+static int test_driver_valid_bss_mask(void *priv, const u8 *addr,
+ const u8 *mask)
+{
+ return 0;
+}
+
+
+static int test_driver_set_ssid(const char *ifname, void *priv, const u8 *buf,
+ int len)
+{
+ struct test_driver_data *drv = priv;
+ struct test_driver_bss *bss;
+
+ wpa_printf(MSG_DEBUG, "%s(ifname=%s)", __func__, ifname);
+ wpa_hexdump_ascii(MSG_DEBUG, "test_driver_set_ssid: SSID", buf, len);
+
+ for (bss = drv->bss; bss; bss = bss->next) {
+ if (strcmp(bss->ifname, ifname) != 0)
+ continue;
+
+ if (len < 0 || (size_t) len > sizeof(bss->ssid))
+ return -1;
+
+ memcpy(bss->ssid, buf, len);
+ bss->ssid_len = len;
+
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int test_driver_set_privacy(const char *ifname, void *priv, int enabled)
+{
+ struct test_driver_data *drv = priv;
+ struct test_driver_bss *bss;
+
+ wpa_printf(MSG_DEBUG, "%s(ifname=%s enabled=%d)",
+ __func__, ifname, enabled);
+
+ for (bss = drv->bss; bss; bss = bss->next) {
+ if (strcmp(bss->ifname, ifname) != 0)
+ continue;
+
+ bss->privacy = enabled;
+
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static int test_driver_set_encryption(const char *iface, void *priv,
+ const char *alg, const u8 *addr, int idx,
+ const u8 *key, size_t key_len, int txkey)
+{
+ wpa_printf(MSG_DEBUG, "%s(iface=%s alg=%s idx=%d txkey=%d)",
+ __func__, iface, alg, idx, txkey);
+ if (addr)
+ wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
+ if (key)
+ wpa_hexdump_key(MSG_DEBUG, " key", key, key_len);
+ return 0;
+}
+
+
+static int test_driver_set_sta_vlan(void *priv, const u8 *addr,
+ const char *ifname, int vlan_id)
+{
+ wpa_printf(MSG_DEBUG, "%s(addr=" MACSTR " ifname=%s vlan_id=%d)",
+ __func__, MAC2STR(addr), ifname, vlan_id);
+ return 0;
+}
+
+
+static int test_driver_sta_add(const char *ifname, void *priv, const u8 *addr,
+ u16 aid, u16 capability, u8 *supp_rates,
+ size_t supp_rates_len, int flags,
+ u16 listen_interval)
+{
+ struct test_driver_data *drv = priv;
+ struct test_client_socket *cli;
+ struct test_driver_bss *bss;
+
+ wpa_printf(MSG_DEBUG, "%s(ifname=%s addr=" MACSTR " aid=%d "
+ "capability=0x%x flags=0x%x listen_interval=%d)",
+ __func__, ifname, MAC2STR(addr), aid, capability, flags,
+ listen_interval);
+ wpa_hexdump(MSG_DEBUG, "test_driver_sta_add - supp_rates",
+ supp_rates, supp_rates_len);
+
+ cli = drv->cli;
+ while (cli) {
+ if (memcmp(cli->addr, addr, ETH_ALEN) == 0)
+ break;
+ cli = cli->next;
+ }
+ if (!cli) {
+ wpa_printf(MSG_DEBUG, "%s: no matching client entry",
+ __func__);
+ return -1;
+ }
+
+ for (bss = drv->bss; bss; bss = bss->next) {
+ if (strcmp(ifname, bss->ifname) == 0)
+ break;
+ }
+ if (bss == NULL) {
+ wpa_printf(MSG_DEBUG, "%s: No matching interface found from "
+ "configured BSSes", __func__);
+ return -1;
+ }
+
+ cli->bss = bss;
+
+ return 0;
+}
+
+
+static void * test_driver_init(struct hostapd_data *hapd)
+{
+ struct test_driver_data *drv;
+ struct sockaddr_un addr_un;
+ struct sockaddr_in addr_in;
+ struct sockaddr *addr;
+ socklen_t alen;
+
+ drv = os_zalloc(sizeof(struct test_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for test driver data\n");
+ return NULL;
+ }
+ drv->bss = os_zalloc(sizeof(*drv->bss));
+ if (drv->bss == NULL) {
+ printf("Could not allocate memory for test driver BSS data\n");
+ free(drv);
+ return NULL;
+ }
+
+ drv->hapd = hapd;
+
+ /* Generate a MAC address to help testing with multiple APs */
+ hapd->own_addr[0] = 0x02; /* locally administered */
+ sha1_prf((const u8 *) hapd->conf->iface, strlen(hapd->conf->iface),
+ "hostapd test bssid generation",
+ (const u8 *) hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len,
+ hapd->own_addr + 1, ETH_ALEN - 1);
+
+ os_strlcpy(drv->bss->ifname, hapd->conf->iface, IFNAMSIZ);
+ memcpy(drv->bss->bssid, hapd->own_addr, ETH_ALEN);
+
+ if (hapd->conf->test_socket) {
+ if (strlen(hapd->conf->test_socket) >=
+ sizeof(addr_un.sun_path)) {
+ printf("Too long test_socket path\n");
+ test_driver_free_priv(drv);
+ return NULL;
+ }
+ if (strncmp(hapd->conf->test_socket, "DIR:", 4) == 0) {
+ size_t len = strlen(hapd->conf->test_socket) + 30;
+ drv->socket_dir = strdup(hapd->conf->test_socket + 4);
+ drv->own_socket_path = malloc(len);
+ if (drv->own_socket_path) {
+ snprintf(drv->own_socket_path, len,
+ "%s/AP-" MACSTR,
+ hapd->conf->test_socket + 4,
+ MAC2STR(hapd->own_addr));
+ }
+ } else if (strncmp(hapd->conf->test_socket, "UDP:", 4) == 0) {
+ drv->udp_port = atoi(hapd->conf->test_socket + 4);
+ } else {
+ drv->own_socket_path = strdup(hapd->conf->test_socket);
+ }
+ if (drv->own_socket_path == NULL && drv->udp_port == 0) {
+ test_driver_free_priv(drv);
+ return NULL;
+ }
+
+ drv->test_socket = socket(drv->udp_port ? PF_INET : PF_UNIX,
+ SOCK_DGRAM, 0);
+ if (drv->test_socket < 0) {
+ perror("socket");
+ test_driver_free_priv(drv);
+ return NULL;
+ }
+
+ if (drv->udp_port) {
+ os_memset(&addr_in, 0, sizeof(addr_in));
+ addr_in.sin_family = AF_INET;
+ addr_in.sin_port = htons(drv->udp_port);
+ addr = (struct sockaddr *) &addr_in;
+ alen = sizeof(addr_in);
+ } else {
+ os_memset(&addr_un, 0, sizeof(addr_un));
+ addr_un.sun_family = AF_UNIX;
+ os_strlcpy(addr_un.sun_path, drv->own_socket_path,
+ sizeof(addr_un.sun_path));
+ addr = (struct sockaddr *) &addr_un;
+ alen = sizeof(addr_un);
+ }
+ if (bind(drv->test_socket, addr, alen) < 0) {
+ perror("bind(PF_UNIX)");
+ close(drv->test_socket);
+ if (drv->own_socket_path)
+ unlink(drv->own_socket_path);
+ test_driver_free_priv(drv);
+ return NULL;
+ }
+ eloop_register_read_sock(drv->test_socket,
+ test_driver_receive_unix, drv, NULL);
+ } else
+ drv->test_socket = -1;
+
+ return drv;
+}
+
+
+static void test_driver_deinit(void *priv)
+{
+ struct test_driver_data *drv = priv;
+ struct test_client_socket *cli, *prev;
+
+ cli = drv->cli;
+ while (cli) {
+ prev = cli;
+ cli = cli->next;
+ free(prev);
+ }
+
+ if (drv->test_socket >= 0) {
+ eloop_unregister_read_sock(drv->test_socket);
+ close(drv->test_socket);
+ if (drv->own_socket_path)
+ unlink(drv->own_socket_path);
+ }
+
+ /* There should be only one BSS remaining at this point. */
+ if (drv->bss == NULL)
+ wpa_printf(MSG_ERROR, "%s: drv->bss == NULL", __func__);
+ else if (drv->bss->next)
+ wpa_printf(MSG_ERROR, "%s: drv->bss->next != NULL", __func__);
+
+ test_driver_free_priv(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_test_ops = {
+ .name = "test",
+ .init = test_driver_init,
+ .deinit = test_driver_deinit,
+ .send_eapol = test_driver_send_eapol,
+ .send_mgmt_frame = test_driver_send_mgmt_frame,
+ .set_generic_elem = test_driver_set_generic_elem,
+ .sta_deauth = test_driver_sta_deauth,
+ .sta_disassoc = test_driver_sta_disassoc,
+ .get_hw_feature_data = test_driver_get_hw_feature_data,
+ .bss_add = test_driver_bss_add,
+ .bss_remove = test_driver_bss_remove,
+ .if_add = test_driver_if_add,
+ .if_update = test_driver_if_update,
+ .if_remove = test_driver_if_remove,
+ .valid_bss_mask = test_driver_valid_bss_mask,
+ .set_ssid = test_driver_set_ssid,
+ .set_privacy = test_driver_set_privacy,
+ .set_encryption = test_driver_set_encryption,
+ .set_sta_vlan = test_driver_set_sta_vlan,
+ .sta_add = test_driver_sta_add,
+ .send_ether = test_driver_send_ether,
+ .set_wps_beacon_ie = test_driver_set_wps_beacon_ie,
+ .set_wps_probe_resp_ie = test_driver_set_wps_probe_resp_ie,
+};
diff --git a/hostapd/driver_wired.c b/hostapd/driver_wired.c
new file mode 100644
index 0000000..61cb667
--- /dev/null
+++ b/hostapd/driver_wired.c
@@ -0,0 +1,372 @@
+/*
+ * hostapd / Kernel driver communication for wired (Ethernet) drivers
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004, Gunter Burchardt <tira@isx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#ifdef USE_KERNEL_HEADERS
+#include <asm/types.h>
+#include <linux/if_packet.h>
+#include <linux/if_ether.h> /* The L2 protocols */
+#include <linux/if_arp.h>
+#include <linux/if.h>
+#else /* USE_KERNEL_HEADERS */
+#include <net/if_arp.h>
+#include <net/if.h>
+#include <netpacket/packet.h>
+#endif /* USE_KERNEL_HEADERS */
+
+#include "hostapd.h"
+#include "ieee802_1x.h"
+#include "eloop.h"
+#include "sta_info.h"
+#include "driver.h"
+#include "accounting.h"
+
+
+struct wired_driver_data {
+ struct hostapd_data *hapd;
+
+ int sock; /* raw packet socket for driver access */
+ int dhcp_sock; /* socket for dhcp packets */
+ int use_pae_group_addr;
+};
+
+
+#define WIRED_EAPOL_MULTICAST_GROUP {0x01,0x80,0xc2,0x00,0x00,0x03}
+
+
+/* TODO: detecting new devices should eventually be changed from using DHCP
+ * snooping to trigger on any packet from a new layer 2 MAC address, e.g.,
+ * based on ebtables, etc. */
+
+struct dhcp_message {
+ u_int8_t op;
+ u_int8_t htype;
+ u_int8_t hlen;
+ u_int8_t hops;
+ u_int32_t xid;
+ u_int16_t secs;
+ u_int16_t flags;
+ u_int32_t ciaddr;
+ u_int32_t yiaddr;
+ u_int32_t siaddr;
+ u_int32_t giaddr;
+ u_int8_t chaddr[16];
+ u_int8_t sname[64];
+ u_int8_t file[128];
+ u_int32_t cookie;
+ u_int8_t options[308]; /* 312 - cookie */
+};
+
+
+static void wired_possible_new_sta(struct hostapd_data *hapd, u8 *addr)
+{
+ struct sta_info *sta;
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR
+ " - adding a new STA", MAC2STR(addr));
+ sta = ap_sta_add(hapd, addr);
+ if (sta) {
+ hostapd_new_assoc_sta(hapd, sta, 0);
+ } else {
+ wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR,
+ MAC2STR(addr));
+ }
+}
+
+
+static void handle_data(struct hostapd_data *hapd, unsigned char *buf,
+ size_t len)
+{
+ struct ieee8023_hdr *hdr;
+ u8 *pos, *sa;
+ size_t left;
+
+ /* must contain at least ieee8023_hdr 6 byte source, 6 byte dest,
+ * 2 byte ethertype */
+ if (len < 14) {
+ wpa_printf(MSG_MSGDUMP, "handle_data: too short (%lu)",
+ (unsigned long) len);
+ return;
+ }
+
+ hdr = (struct ieee8023_hdr *) buf;
+
+ switch (ntohs(hdr->ethertype)) {
+ case ETH_P_PAE:
+ wpa_printf(MSG_MSGDUMP, "Received EAPOL packet");
+ sa = hdr->src;
+ wired_possible_new_sta(hapd, sa);
+
+ pos = (u8 *) (hdr + 1);
+ left = len - sizeof(*hdr);
+
+ ieee802_1x_receive(hapd, sa, pos, left);
+ break;
+
+ default:
+ wpa_printf(MSG_DEBUG, "Unknown ethertype 0x%04x in data frame",
+ ntohs(hdr->ethertype));
+ break;
+ }
+}
+
+
+static void handle_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx;
+ int len;
+ unsigned char buf[3000];
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ handle_data(hapd, buf, len);
+}
+
+
+static void handle_dhcp(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct hostapd_data *hapd = (struct hostapd_data *) eloop_ctx;
+ int len;
+ unsigned char buf[3000];
+ struct dhcp_message *msg;
+ u8 *mac_address;
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ /* must contain at least dhcp_message->chaddr */
+ if (len < 44) {
+ wpa_printf(MSG_MSGDUMP, "handle_dhcp: too short (%d)", len);
+ return;
+ }
+
+ msg = (struct dhcp_message *) buf;
+ mac_address = (u8 *) &(msg->chaddr);
+
+ wpa_printf(MSG_MSGDUMP, "Got DHCP broadcast packet from " MACSTR,
+ MAC2STR(mac_address));
+
+ wired_possible_new_sta(hapd, mac_address);
+}
+
+
+static int wired_init_sockets(struct wired_driver_data *drv)
+{
+ struct hostapd_data *hapd = drv->hapd;
+ struct ifreq ifr;
+ struct sockaddr_ll addr;
+ struct sockaddr_in addr2;
+ struct packet_mreq mreq;
+ u8 multicastgroup_eapol[6] = WIRED_EAPOL_MULTICAST_GROUP;
+ int n = 1;
+
+ drv->sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
+ if (drv->sock < 0) {
+ perror("socket[PF_PACKET,SOCK_RAW]");
+ return -1;
+ }
+
+ if (eloop_register_read_sock(drv->sock, handle_read, hapd, NULL)) {
+ printf("Could not register read socket\n");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, hapd->conf->iface, sizeof(ifr.ifr_name));
+ if (ioctl(drv->sock, SIOCGIFINDEX, &ifr) != 0) {
+ perror("ioctl(SIOCGIFINDEX)");
+ return -1;
+ }
+
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sll_family = AF_PACKET;
+ addr.sll_ifindex = ifr.ifr_ifindex;
+ wpa_printf(MSG_DEBUG, "Opening raw packet socket for ifindex %d",
+ addr.sll_ifindex);
+
+ if (bind(drv->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind");
+ return -1;
+ }
+
+ /* filter multicast address */
+ memset(&mreq, 0, sizeof(mreq));
+ mreq.mr_ifindex = ifr.ifr_ifindex;
+ mreq.mr_type = PACKET_MR_MULTICAST;
+ mreq.mr_alen = 6;
+ memcpy(mreq.mr_address, multicastgroup_eapol, mreq.mr_alen);
+
+ if (setsockopt(drv->sock, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mreq,
+ sizeof(mreq)) < 0) {
+ perror("setsockopt[SOL_SOCKET,PACKET_ADD_MEMBERSHIP]");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, hapd->conf->iface, sizeof(ifr.ifr_name));
+ if (ioctl(drv->sock, SIOCGIFHWADDR, &ifr) != 0) {
+ perror("ioctl(SIOCGIFHWADDR)");
+ return -1;
+ }
+
+ if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) {
+ printf("Invalid HW-addr family 0x%04x\n",
+ ifr.ifr_hwaddr.sa_family);
+ return -1;
+ }
+ memcpy(hapd->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ /* setup dhcp listen socket for sta detection */
+ if ((drv->dhcp_sock = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
+ perror("socket call failed for dhcp");
+ return -1;
+ }
+
+ if (eloop_register_read_sock(drv->dhcp_sock, handle_dhcp, hapd, NULL))
+ {
+ printf("Could not register read socket\n");
+ return -1;
+ }
+
+ memset(&addr2, 0, sizeof(addr2));
+ addr2.sin_family = AF_INET;
+ addr2.sin_port = htons(67);
+ addr2.sin_addr.s_addr = INADDR_ANY;
+
+ if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_REUSEADDR, (char *) &n,
+ sizeof(n)) == -1) {
+ perror("setsockopt[SOL_SOCKET,SO_REUSEADDR]");
+ return -1;
+ }
+ if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BROADCAST, (char *) &n,
+ sizeof(n)) == -1) {
+ perror("setsockopt[SOL_SOCKET,SO_BROADCAST]");
+ return -1;
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_ifrn.ifrn_name, hapd->conf->iface, IFNAMSIZ);
+ if (setsockopt(drv->dhcp_sock, SOL_SOCKET, SO_BINDTODEVICE,
+ (char *) &ifr, sizeof(ifr)) < 0) {
+ perror("setsockopt[SOL_SOCKET,SO_BINDTODEVICE]");
+ return -1;
+ }
+
+ if (bind(drv->dhcp_sock, (struct sockaddr *) &addr2,
+ sizeof(struct sockaddr)) == -1) {
+ perror("bind");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wired_send_eapol(void *priv, const u8 *addr,
+ const u8 *data, size_t data_len, int encrypt,
+ const u8 *own_addr)
+{
+ struct wired_driver_data *drv = priv;
+ u8 pae_group_addr[ETH_ALEN] = WIRED_EAPOL_MULTICAST_GROUP;
+ struct ieee8023_hdr *hdr;
+ size_t len;
+ u8 *pos;
+ int res;
+
+ len = sizeof(*hdr) + data_len;
+ hdr = os_zalloc(len);
+ if (hdr == NULL) {
+ printf("malloc() failed for wired_send_eapol(len=%lu)\n",
+ (unsigned long) len);
+ return -1;
+ }
+
+ memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
+ ETH_ALEN);
+ memcpy(hdr->src, own_addr, ETH_ALEN);
+ hdr->ethertype = htons(ETH_P_PAE);
+
+ pos = (u8 *) (hdr + 1);
+ memcpy(pos, data, data_len);
+
+ res = send(drv->sock, (u8 *) hdr, len, 0);
+ free(hdr);
+
+ if (res < 0) {
+ perror("wired_send_eapol: send");
+ printf("wired_send_eapol - packet len: %lu - failed\n",
+ (unsigned long) len);
+ }
+
+ return res;
+}
+
+
+static void * wired_driver_init(struct hostapd_data *hapd)
+{
+ struct wired_driver_data *drv;
+
+ drv = os_zalloc(sizeof(struct wired_driver_data));
+ if (drv == NULL) {
+ printf("Could not allocate memory for wired driver data\n");
+ return NULL;
+ }
+
+ drv->hapd = hapd;
+ drv->use_pae_group_addr = hapd->conf->use_pae_group_addr;
+
+ if (wired_init_sockets(drv)) {
+ free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static void wired_driver_deinit(void *priv)
+{
+ struct wired_driver_data *drv = priv;
+
+ if (drv->sock >= 0)
+ close(drv->sock);
+
+ if (drv->dhcp_sock >= 0)
+ close(drv->dhcp_sock);
+
+ free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_wired_ops = {
+ .name = "wired",
+ .init = wired_driver_init,
+ .deinit = wired_driver_deinit,
+ .send_eapol = wired_send_eapol,
+};
diff --git a/hostapd/drivers.c b/hostapd/drivers.c
index 3006190..bde6e60 100644
--- a/hostapd/drivers.c
+++ b/hostapd/drivers.c
@@ -27,6 +27,9 @@ extern struct wpa_driver_ops wpa_driver_prism54_ops; /* driver_prism54.c */
#ifdef CONFIG_DRIVER_MADWIFI
extern struct wpa_driver_ops wpa_driver_madwifi_ops; /* driver_madwifi.c */
#endif /* CONFIG_DRIVER_MADWIFI */
+#ifdef CONFIG_DRIVER_ATHEROS
+extern struct wpa_driver_ops wpa_driver_atheros_ops; /* driver_atheros.c */
+#endif /* CONFIG_DRIVER_ATHEROS */
#ifdef CONFIG_DRIVER_BSD
extern struct wpa_driver_ops wpa_driver_bsd_ops; /* driver_bsd.c */
#endif /* CONFIG_DRIVER_BSD */
@@ -55,6 +58,9 @@ struct wpa_driver_ops *hostapd_drivers[] =
#ifdef CONFIG_DRIVER_MADWIFI
&wpa_driver_madwifi_ops,
#endif /* CONFIG_DRIVER_MADWIFI */
+#ifdef CONFIG_DRIVER_ATHEROS
+ &wpa_driver_atheros_ops,
+#endif /* CONFIG_DRIVER_ATHEROS */
#ifdef CONFIG_DRIVER_BSD
&wpa_driver_bsd_ops,
#endif /* CONFIG_DRIVER_BSD */
diff --git a/hostapd/hostapd.8 b/hostapd/hostapd.8
index 9258512..a67a1bc 100644
--- a/hostapd/hostapd.8
+++ b/hostapd/hostapd.8
@@ -3,7 +3,7 @@
hostapd \- IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator
.SH SYNOPSIS
.B hostapd
-[-hdBKtv] [-P <PID file>] <configuration file(s)>
+[\-hdBKtv] [\-P <PID file>] <configuration file(s)>
.SH DESCRIPTION
This manual page documents briefly the
.B hostapd
diff --git a/hostapd/hostapd.c b/hostapd/hostapd.c
index df6062b..3fbd3d0 100644
--- a/hostapd/hostapd.c
+++ b/hostapd/hostapd.c
@@ -249,7 +249,7 @@ void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
if (!hapd->conf->ieee802_1x && !hapd->conf->wpa)
accounting_sta_start(hapd, sta);
- hostapd_wme_sta_config(hapd, sta);
+ hostapd_wmm_sta_config(hapd, sta);
/* Start IEEE 802.1X authentication process for new stations */
ieee802_1x_new_station(hapd, sta);
@@ -306,7 +306,7 @@ static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
wconf->rsn_preauth = conf->rsn_preauth;
wconf->eapol_version = conf->eapol_version;
wconf->peerkey = conf->peerkey;
- wconf->wme_enabled = conf->wme_enabled;
+ wconf->wmm_enabled = conf->wmm_enabled;
wconf->okc = conf->okc;
#ifdef CONFIG_IEEE80211W
wconf->ieee80211w = conf->ieee80211w;
@@ -339,6 +339,7 @@ int hostapd_reload_config(struct hostapd_iface *iface)
struct hostapd_data *hapd = iface->bss[0];
struct hostapd_config *newconf, *oldconf;
struct wpa_auth_config wpa_auth_conf;
+ size_t j;
newconf = hostapd_config_read(iface->config_fname);
if (newconf == NULL)
@@ -348,7 +349,8 @@ int hostapd_reload_config(struct hostapd_iface *iface)
* Deauthenticate all stations since the new configuration may not
* allow them to use the BSS anymore.
*/
- hostapd_flush_old_stations(hapd);
+ for (j = 0; j < iface->num_bss; j++)
+ hostapd_flush_old_stations(iface->bss[j]);
/* TODO: update dynamic data based on changed configuration
* items (e.g., open/close sockets, etc.) */
@@ -378,6 +380,16 @@ int hostapd_reload_config(struct hostapd_iface *iface)
ieee802_11_set_beacon(hapd);
+ if (hapd->conf->ssid.ssid_set &&
+ hostapd_set_ssid(hapd, (u8 *) hapd->conf->ssid.ssid,
+ hapd->conf->ssid.ssid_len)) {
+ wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
+ /* try to continue */
+ }
+
+ if (hapd->conf->ieee802_1x || hapd->conf->wpa)
+ hostapd_set_ieee8021x(hapd->conf->iface, hapd, 1);
+
hostapd_config_free(oldconf);
wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface);
@@ -465,7 +477,7 @@ static void hostapd_dump_state(struct hostapd_data *hapd)
(sta->flags & WLAN_STA_SHORT_PREAMBLE ?
"[SHORT_PREAMBLE]" : ""),
(sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
- (sta->flags & WLAN_STA_WME ? "[WME]" : ""),
+ (sta->flags & WLAN_STA_WMM ? "[WMM]" : ""),
(sta->flags & WLAN_STA_MFP ? "[MFP]" : ""),
(sta->flags & WLAN_STA_WPS ? "[WPS]" : ""),
(sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
@@ -1308,6 +1320,13 @@ static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
}
}
+ hostapd_flush_old_stations(hapd);
+ hostapd_set_privacy(hapd, 0);
+
+ hostapd_broadcast_wep_clear(hapd);
+ if (hostapd_setup_encryption(hapd->conf->iface, hapd))
+ return -1;
+
/*
* Fetch the SSID from the system and use it or,
* if one was specified in the config file, verify they
@@ -1510,7 +1529,6 @@ static int setup_interface(struct hostapd_iface *iface)
u8 *b = conf->bssid;
int freq;
size_t j;
- int ret = 0;
u8 *prev_addr;
/*
@@ -1582,9 +1600,6 @@ static int setup_interface(struct hostapd_iface *iface)
}
}
- hostapd_flush_old_stations(hapd);
- hostapd_set_privacy(hapd, 0);
-
if (hapd->iconf->channel) {
freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel);
wpa_printf(MSG_DEBUG, "Mode: %s Channel: %d "
@@ -1601,12 +1616,7 @@ static int setup_interface(struct hostapd_iface *iface)
}
}
- hostapd_broadcast_wep_clear(hapd);
- if (hostapd_setup_encryption(hapd->conf->iface, hapd))
- return -1;
-
hostapd_set_beacon_int(hapd, hapd->iconf->beacon_int);
- ieee802_11_set_beacon(hapd);
if (hapd->iconf->rts_threshold > -1 &&
hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) {
@@ -1644,7 +1654,7 @@ static int setup_interface(struct hostapd_iface *iface)
return -1;
}
- return ret;
+ return 0;
}
@@ -1867,7 +1877,7 @@ int main(int argc, char *argv[])
int ret = 1, k;
size_t i, j;
int c, debug = 0, daemonize = 0, tnc = 0;
- const char *pid_file = NULL;
+ char *pid_file = NULL;
hostapd_logger_register_cb(hostapd_logger_cb);
@@ -1891,7 +1901,8 @@ int main(int argc, char *argv[])
wpa_debug_show_keys++;
break;
case 'P':
- pid_file = optarg;
+ os_free(pid_file);
+ pid_file = os_rel2abs_path(optarg);
break;
case 't':
wpa_debug_timestamp++;
@@ -2022,6 +2033,7 @@ int main(int argc, char *argv[])
eap_server_unregister_methods();
os_daemonize_terminate(pid_file);
+ os_free(pid_file);
return ret;
}
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 0602cb0..703b646 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -245,14 +245,14 @@ ignore_broadcast_ssid=0
#tx_queue_beacon_cwmax=7
#tx_queue_beacon_burst=1.5
-# 802.1D Tag to AC mappings
+# 802.1D Tag (= UP) to AC mappings
# WMM specifies following mapping of data frames to different ACs. This mapping
# can be configured using Linux QoS/tc and sch_pktpri.o module.
# 802.1D Tag 802.1D Designation Access Category WMM Designation
# 1 BK AC_BK Background
# 2 - AC_BK Background
# 0 BE AC_BE Best Effort
-# 3 EE AC_VI Video
+# 3 EE AC_BE Best Effort
# 4 CL AC_VI Video
# 5 VI AC_VI Video
# 6 VO AC_VO Voice
@@ -273,38 +273,38 @@ ignore_broadcast_ssid=0
# note - here cwMin and cmMax are in exponent form. the actual cw value used
# will be (2^n)-1 where n is the value given here
#
-wme_enabled=1
+wmm_enabled=1
#
# Low priority / AC_BK = background
-wme_ac_bk_cwmin=4
-wme_ac_bk_cwmax=10
-wme_ac_bk_aifs=7
-wme_ac_bk_txop_limit=0
-wme_ac_bk_acm=0
+wmm_ac_bk_cwmin=4
+wmm_ac_bk_cwmax=10
+wmm_ac_bk_aifs=7
+wmm_ac_bk_txop_limit=0
+wmm_ac_bk_acm=0
# Note: for IEEE 802.11b mode: cWmin=5 cWmax=10
#
# Normal priority / AC_BE = best effort
-wme_ac_be_aifs=3
-wme_ac_be_cwmin=4
-wme_ac_be_cwmax=10
-wme_ac_be_txop_limit=0
-wme_ac_be_acm=0
+wmm_ac_be_aifs=3
+wmm_ac_be_cwmin=4
+wmm_ac_be_cwmax=10
+wmm_ac_be_txop_limit=0
+wmm_ac_be_acm=0
# Note: for IEEE 802.11b mode: cWmin=5 cWmax=7
#
# High priority / AC_VI = video
-wme_ac_vi_aifs=2
-wme_ac_vi_cwmin=3
-wme_ac_vi_cwmax=4
-wme_ac_vi_txop_limit=94
-wme_ac_vi_acm=0
+wmm_ac_vi_aifs=2
+wmm_ac_vi_cwmin=3
+wmm_ac_vi_cwmax=4
+wmm_ac_vi_txop_limit=94
+wmm_ac_vi_acm=0
# Note: for IEEE 802.11b mode: cWmin=4 cWmax=5 txop_limit=188
#
# Highest priority / AC_VO = voice
-wme_ac_vo_aifs=2
-wme_ac_vo_cwmin=2
-wme_ac_vo_cwmax=3
-wme_ac_vo_txop_limit=47
-wme_ac_vo_acm=0
+wmm_ac_vo_aifs=2
+wmm_ac_vo_cwmin=2
+wmm_ac_vo_cwmax=3
+wmm_ac_vo_txop_limit=47
+wmm_ac_vo_acm=0
# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102
# Static WEP key configuration
@@ -375,6 +375,7 @@ wme_ac_vo_acm=0
# ieee80211n: Whether IEEE 802.11n (HT) is enabled
# 0 = disabled (default)
# 1 = enabled
+# Note: You will also need to enable WMM for full HT functionality.
#ieee80211n=1
# ht_capab: HT capabilities (list of flags)
diff --git a/hostapd/hostapd_cli.1 b/hostapd/hostapd_cli.1
index 8d6587f..2fe4907 100644
--- a/hostapd/hostapd_cli.1
+++ b/hostapd/hostapd_cli.1
@@ -3,7 +3,7 @@
hostapd_cli \- hostapd command-line interface
.SH SYNOPSIS
.B hostapd_cli
-[-p<path>] [-i<ifname>] [-hv] [command..]
+[\-p<path>] [\-i<ifname>] [\-hv] [command..]
.SH DESCRIPTION
This manual page documents briefly the
.B hostapd_cli
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 2614113..c2ecd4e 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -87,7 +87,7 @@ static const char *commands_help =
" sa_query <addr> send SA Query to a station\n"
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_WPS
-" wps_pin <uuid> <pin> add WPS Enrollee PIN (Device Password)\n"
+" wps_pin <uuid> <pin> [timeout] add WPS Enrollee PIN (Device Password)\n"
" wps_pbc indicate button pushed to initiate PBC\n"
#endif /* CONFIG_WPS */
" help show this usage help\n"
@@ -260,12 +260,16 @@ static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
char *argv[])
{
char buf[64];
- if (argc != 2) {
- printf("Invalid 'wps_pin' command - exactly two arguments, "
+ if (argc < 2) {
+ printf("Invalid 'wps_pin' command - at least two arguments, "
"UUID and PIN, are required.\n");
return -1;
}
- snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
+ if (argc > 2)
+ snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
+ argv[0], argv[1], argv[2]);
+ else
+ snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
return wpa_ctrl_command(ctrl, buf);
}
diff --git a/hostapd/hw_features.c b/hostapd/hw_features.c
index f1288e0..1d6299e 100644
--- a/hostapd/hw_features.c
+++ b/hostapd/hw_features.c
@@ -382,6 +382,13 @@ int hostapd_select_hw_mode(struct hostapd_iface *iface)
break;
}
}
+ if (iface->conf->channel == 0) {
+ /* TODO: could request a scan of neighboring BSSes and select
+ * the channel automatically */
+ wpa_printf(MSG_ERROR, "Channel not configured "
+ "(hw_mode/channel in hostapd.conf)");
+ return -1;
+ }
if (ok == 0 && iface->conf->channel != 0) {
hostapd_logger(iface->bss[0], NULL,
HOSTAPD_MODULE_IEEE80211,
diff --git a/hostapd/ieee802_11.c b/hostapd/ieee802_11.c
index 8399d88..70491b4 100644
--- a/hostapd/ieee802_11.c
+++ b/hostapd/ieee802_11.c
@@ -384,8 +384,8 @@ static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
r = random();
os_memcpy(key, &now, 4);
os_memcpy(key + 4, &r, 4);
- rc4(sta->challenge, WLAN_AUTH_CHALLENGE_LEN,
- key, sizeof(key));
+ rc4_skip(key, sizeof(key), 0,
+ sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
}
return 0;
}
@@ -585,7 +585,7 @@ static void handle_auth(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
if (vlan_id > 0) {
if (hostapd_get_vlan_id_ifname(hapd->conf->vlan,
- sta->vlan_id) == NULL) {
+ vlan_id) == NULL) {
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
HOSTAPD_LEVEL_INFO, "Invalid VLAN ID "
"%d received from RADIUS server",
@@ -766,16 +766,16 @@ static void handle_assoc(struct hostapd_data *hapd,
goto fail;
}
- sta->flags &= ~WLAN_STA_WME;
- if (elems.wme && hapd->conf->wme_enabled) {
- if (hostapd_eid_wme_valid(hapd, elems.wme, elems.wme_len))
+ sta->flags &= ~WLAN_STA_WMM;
+ if (elems.wmm && hapd->conf->wmm_enabled) {
+ if (hostapd_eid_wmm_valid(hapd, elems.wmm, elems.wmm_len))
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_WPA,
HOSTAPD_LEVEL_DEBUG,
- "invalid WME element in association "
+ "invalid WMM element in association "
"request");
else
- sta->flags |= WLAN_STA_WME;
+ sta->flags |= WLAN_STA_WMM;
}
if (!elems.supp_rates) {
@@ -1124,8 +1124,8 @@ static void handle_assoc(struct hostapd_data *hapd,
p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
/* Extended supported rates */
p = hostapd_eid_ext_supp_rates(hapd, p);
- if (sta->flags & WLAN_STA_WME)
- p = hostapd_eid_wme(hapd, p);
+ if (sta->flags & WLAN_STA_WMM)
+ p = hostapd_eid_wmm(hapd, p);
p = hostapd_eid_ht_capabilities_info(hapd, p);
p = hostapd_eid_ht_operation(hapd, p);
@@ -1265,6 +1265,11 @@ void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
struct ieee80211_mgmt mgmt;
u8 *end;
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
+ MACSTR, MAC2STR(addr));
+ wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+ trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
os_memset(&mgmt, 0, sizeof(mgmt));
mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
WLAN_FC_STYPE_ACTION);
@@ -1302,6 +1307,12 @@ static void hostapd_sa_query_action(struct hostapd_data *hapd,
return;
}
+ wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
+ MACSTR, MAC2STR(mgmt->sa));
+ wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+ mgmt->u.action.u.sa_query_resp.trans_id,
+ WLAN_SA_QUERY_TR_ID_LEN);
+
/* MLME-SAQuery.confirm */
sta = ap_get_sta(hapd, mgmt->sa);
@@ -1330,12 +1341,21 @@ static void hostapd_sa_query_action(struct hostapd_data *hapd,
"Reply to pending SA Query received");
ap_sta_stop_sa_query(hapd, sta);
}
+
+
+static int robust_action_frame(u8 category)
+{
+ return category != WLAN_ACTION_PUBLIC &&
+ category != WLAN_ACTION_HT;
+}
#endif /* CONFIG_IEEE80211W */
static void handle_action(struct hostapd_data *hapd,
struct ieee80211_mgmt *mgmt, size_t len)
{
+ struct sta_info *sta;
+
if (len < IEEE80211_HDRLEN + 1) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
@@ -1344,13 +1364,23 @@ static void handle_action(struct hostapd_data *hapd,
return;
}
+ sta = ap_get_sta(hapd, mgmt->sa);
+#ifdef CONFIG_IEEE80211W
+ if (sta && (sta->flags & WLAN_STA_MFP) &&
+ !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
+ robust_action_frame(mgmt->u.action.category))) {
+ hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+ HOSTAPD_LEVEL_DEBUG,
+ "Dropped unprotected Robust Action frame from "
+ "an MFP STA");
+ return;
+ }
+#endif /* CONFIG_IEEE80211W */
+
switch (mgmt->u.action.category) {
#ifdef CONFIG_IEEE80211R
case WLAN_ACTION_FT:
{
- struct sta_info *sta;
-
- sta = ap_get_sta(hapd, mgmt->sa);
if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored FT Action "
"frame from unassociated STA " MACSTR,
@@ -1366,7 +1396,7 @@ static void handle_action(struct hostapd_data *hapd,
}
#endif /* CONFIG_IEEE80211R */
case WLAN_ACTION_WMM:
- hostapd_wme_action(hapd, mgmt, len);
+ hostapd_wmm_action(hapd, mgmt, len);
return;
#ifdef CONFIG_IEEE80211W
case WLAN_ACTION_SA_QUERY:
@@ -1527,6 +1557,26 @@ static void handle_auth_cb(struct hostapd_data *hapd,
}
+#ifdef CONFIG_IEEE80211N
+static void
+hostapd_get_ht_capab(struct hostapd_data *hapd,
+ struct ht_cap_ie *ht_cap_ie,
+ struct ht_cap_ie *neg_ht_cap_ie)
+{
+ u16 cap;
+
+ os_memcpy(neg_ht_cap_ie, ht_cap_ie, sizeof(struct ht_cap_ie));
+ cap = le_to_host16(neg_ht_cap_ie->data.capabilities_info);
+ cap &= hapd->iconf->ht_capab;
+ cap |= (hapd->iconf->ht_capab & HT_CAP_INFO_SMPS_DISABLED);
+
+ /* FIXME: Rx STBC needs to be handled specially */
+ cap |= (hapd->iconf->ht_capab & HT_CAP_INFO_RX_STBC_MASK);
+ neg_ht_cap_ie->data.capabilities_info = host_to_le16(cap);
+}
+#endif /* CONFIG_IEEE80211N */
+
+
static void handle_assoc_cb(struct hostapd_data *hapd,
struct ieee80211_mgmt *mgmt,
size_t len, int reassoc, int ok)
@@ -1534,7 +1584,11 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
u16 status;
struct sta_info *sta;
int new_assoc = 1;
- struct ht_cap_ie *ht_cap = NULL;
+#ifdef CONFIG_IEEE80211N
+ struct ht_cap_ie ht_cap;
+#endif /* CONFIG_IEEE80211N */
+ struct ht_cap_ie *ht_cap_ptr = NULL;
+ int set_flags, flags_and, flags_or;
if (!ok) {
hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
@@ -1584,18 +1638,27 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
mlme_associate_indication(hapd, sta);
#ifdef CONFIG_IEEE80211N
- if (sta->flags & WLAN_STA_HT)
- ht_cap = &sta->ht_capabilities;
+ if (sta->flags & WLAN_STA_HT) {
+ ht_cap_ptr = &ht_cap;
+ hostapd_get_ht_capab(hapd, &sta->ht_capabilities, ht_cap_ptr);
+ }
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211W
sta->sa_query_timed_out = 0;
#endif /* CONFIG_IEEE80211W */
+ /*
+ * Remove the STA entry in order to make sure the STA PS state gets
+ * cleared and configuration gets updated in case of reassociation back
+ * to the same AP.
+ */
+ hostapd_sta_remove(hapd, sta->addr);
+
if (hostapd_sta_add(hapd->conf->iface, hapd, sta->addr, sta->aid,
sta->capability, sta->supported_rates,
sta->supported_rates_len, 0, sta->listen_interval,
- ht_cap))
+ ht_cap_ptr))
{
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_NOTICE,
@@ -1613,13 +1676,15 @@ static void handle_assoc_cb(struct hostapd_data *hapd,
/* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
ap_sta_bind_vlan(hapd, sta, 0);
}
- if (sta->flags & WLAN_STA_SHORT_PREAMBLE) {
- hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
- WLAN_STA_SHORT_PREAMBLE, ~0);
- } else {
- hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
- 0, ~WLAN_STA_SHORT_PREAMBLE);
- }
+
+ set_flags = WLAN_STA_SHORT_PREAMBLE | WLAN_STA_WMM | WLAN_STA_MFP;
+ if (!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
+ sta->flags & WLAN_STA_AUTHORIZED)
+ set_flags |= WLAN_STA_AUTHORIZED;
+ flags_or = sta->flags & set_flags;
+ flags_and = sta->flags | ~set_flags;
+ hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
+ flags_or, flags_and);
if (sta->auth_alg == WLAN_AUTH_FT)
wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
diff --git a/hostapd/ieee802_1x.c b/hostapd/ieee802_1x.c
index 9b096d4..7fd8028 100644
--- a/hostapd/ieee802_1x.c
+++ b/hostapd/ieee802_1x.c
@@ -164,7 +164,7 @@ static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
}
os_memcpy(ekey, key->key_iv, sizeof(key->key_iv));
os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32);
- rc4((u8 *) (key + 1), key_len, ekey, ekey_len);
+ rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len);
os_free(ekey);
/* This header is needed here for HMAC-MD5, but it will be regenerated
diff --git a/hostapd/preauth.c b/hostapd/preauth.c
index 36af4e3..9ab41ed 100644
--- a/hostapd/preauth.c
+++ b/hostapd/preauth.c
@@ -171,6 +171,7 @@ int rsn_preauth_iface_init(struct hostapd_data *hapd)
if (rsn_preauth_iface_add(hapd, start)) {
rsn_preauth_iface_deinit(hapd);
+ os_free(tmp);
return -1;
}
diff --git a/hostapd/prism54.h b/hostapd/prism54.h
new file mode 100644
index 0000000..cb0a9a1
--- /dev/null
+++ b/hostapd/prism54.h
@@ -0,0 +1,177 @@
+#ifndef PRISM54_H
+#define PRISM54_H
+
+struct ieee802_3_hdr_s {
+ unsigned char da[6];
+ unsigned char sa[6];
+ unsigned short type;
+} __attribute__ ((packed));
+
+typedef struct ieee802_3_hdr_s ieee802_3_hdr;
+
+#define PIMOP_GET 0
+#define PIMOP_SET 1
+#define PIMOP_RESPONSE 2
+#define PIMOP_ERROR 3
+#define PIMOP_TRAP 4
+
+struct pimdev_hdr_s {
+ int op;
+ unsigned long oid;
+} __attribute__ ((packed));
+
+typedef struct pimdev_hdr_s pimdev_hdr;
+
+#define DOT11_OID_ATTACHMENT 0x19000003
+
+/* really need to check */
+#define DOT11_PKT_BEACON 0x80
+#define DOT11_PKT_ASSOC_RESP 0x10
+#define DOT11_PKT_REASSOC_RESP 0x30
+#define DOT11_PKT_PROBE_RESP 0x50
+
+struct obj_attachment_hdr {
+ char type;
+ char reserved;
+ short id;
+ short size;
+} __attribute__ ((packed));
+
+struct obj_attachment {
+ char type;
+ char reserved;
+ short id;
+ short size;
+ char data[1];
+} __attribute__ ((packed));
+
+#define DOT11_OID_MLMEAUTOLEVEL 0x19000001
+#define DOT11_MLME_AUTO 0
+#define DOT11_MLME_INTERMEDIATE 0x01000000
+#define DOT11_MLME_EXTENDED 0x02000000
+
+#define DOT11_OID_DEAUTHENTICATE 0x18000000
+#define DOT11_OID_AUTHENTICATE 0x18000001
+#define DOT11_OID_DISASSOCIATE 0x18000002
+#define DOT11_OID_ASSOCIATE 0x18000003
+#define DOT11_OID_BEACON 0x18000005
+#define DOT11_OID_PROBE 0x18000006
+#define DOT11_OID_REASSOCIATE 0x1800000b
+
+struct obj_mlme {
+ char address[6];
+ short id;
+ short state;
+ short code;
+} __attribute__ ((packed));
+
+#define DOT11_OID_DEAUTHENTICATEEX 0x18000007
+#define DOT11_OID_AUTHENTICATEEX 0x18000008
+#define DOT11_OID_DISASSOCIATEEX 0x18000009
+#define DOT11_OID_ASSOCIATEEX 0x1800000a
+#define DOT11_OID_REASSOCIATEEX 0x1800000c
+
+struct obj_mlmeex {
+ char address[6];
+ short id;
+ short state;
+ short code;
+ short size;
+ char data[1];
+} __attribute__ ((packed));
+
+#define DOT11_OID_STAKEY 0x12000008
+
+#define DOT11_PRIV_WEP 0
+#define DOT11_PRIV_TKIP 1
+
+/* endian reversed to bigger endian */
+#define DOT11_STAKEY_OPTION_DEFAULTKEY 0x100
+
+struct obj_stakey {
+ char address[6];
+ char keyid;
+ char reserved;
+ short options;
+ char type;
+ char length;
+ char key[32];
+} __attribute__ ((packed));
+
+#define DOT11_OID_DEFKEYID 0x12000003
+#define DOT11_OID_DEFKEY1 0x12000004
+#define DOT11_OID_DEFKEY2 0x12000005
+#define DOT11_OID_DEFKEY3 0x12000006
+#define DOT11_OID_DEFKEY4 0x12000007
+
+struct obj_key {
+ char type;
+ char length;
+ char key[32];
+} __attribute__ ((packed));
+
+#define DOT11_OID_STASC 0x1200000a
+
+struct obj_stasc {
+ char address[6];
+ char keyid;
+ char tx_sc;
+ unsigned long sc_high;
+ unsigned short sc_low;
+} __attribute__ ((packed));
+
+#define DOT11_OID_CLIENTS 0x15000001
+#define DOT11_OID_CLIENTSASSOCIATED 0x15000002
+#define DOT11_OID_CLIENTST 0x15000003
+#define DOT11_OID_CLIENTEND 0x150007d9
+#define DOT11_OID_CLIENTFIND 0x150007db
+
+#define DOT11_NODE_UNKNOWN
+#define DOT11_NODE_CLIENT
+#define DOT11_NODE_AP
+
+/* endian reversed to bigger endian */
+#define DOT11_STATE_NONE 0
+#define DOT11_STATE_AUTHING 0x100
+#define DOT11_STATE_AUTH 0x200
+#define DOT11_STATE_ASSOCING 0x300
+#define DOT11_STATE_REASSOCING 0x400
+#define DOT11_STATE_ASSOC 0x500
+#define DOT11_STATE_WDS 0x600
+
+struct obj_sta {
+ char address[6];
+ char pad[2];
+ char state;
+ char node;
+ short age;
+ char reserved1;
+ char rssi;
+ char rate;
+ char reserved2;
+} __attribute__ ((packed));
+
+#define DOT11_OID_SSID 0x10000002
+#define DOT11_OID_SSIDOVERRIDE 0x10000006
+
+struct obj_ssid {
+ char length;
+ char octets[33];
+} __attribute__ ((packed));
+
+#define DOT11_OID_EAPAUTHSTA 0x150007de
+#define DOT11_OID_EAPUNAUTHSTA 0x150007df
+/* not in 38801 datasheet??? */
+#define DOT11_OID_DOT1XENABLE 0x150007e0
+#define DOT11_OID_MICFAILURE 0x150007e1
+#define DOT11_OID_AUTHENABLE 0x12000000
+#define DOT11_OID_PRIVACYINVOKED 0x12000001
+#define DOT11_OID_EXUNENCRYPTED 0x12000002
+
+#define DOT11_AUTH_OS 0x01000000
+#define DOT11_AUTH_SK 0x02000000
+#define DOT11_AUTH_BOTH 0x03000000
+
+#define DOT11_BOOL_TRUE 0x01000000
+
+#endif /* PRISM54_H */
diff --git a/hostapd/priv_netlink.h b/hostapd/priv_netlink.h
new file mode 100644
index 0000000..d1f6f66
--- /dev/null
+++ b/hostapd/priv_netlink.h
@@ -0,0 +1,71 @@
+#ifndef PRIV_NETLINK_H
+#define PRIV_NETLINK_H
+
+/* Private copy of needed Linux netlink/rtnetlink definitions.
+ *
+ * This should be replaced with user space header once one is available with C
+ * library, etc..
+ */
+
+#ifndef IFLA_IFNAME
+#define IFLA_IFNAME 3
+#endif
+#ifndef IFLA_WIRELESS
+#define IFLA_WIRELESS 11
+#endif
+
+#define NETLINK_ROUTE 0
+#define RTMGRP_LINK 1
+#define RTM_BASE 0x10
+#define RTM_NEWLINK (RTM_BASE + 0)
+#define RTM_DELLINK (RTM_BASE + 1)
+
+#define NLMSG_ALIGNTO 4
+#define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1))
+#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0)))
+
+#define RTA_ALIGNTO 4
+#define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1))
+#define RTA_OK(rta,len) \
+((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \
+(rta)->rta_len <= (len))
+#define RTA_NEXT(rta,attrlen) \
+((attrlen) -= RTA_ALIGN((rta)->rta_len), \
+(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
+
+
+struct sockaddr_nl
+{
+ sa_family_t nl_family;
+ unsigned short nl_pad;
+ u32 nl_pid;
+ u32 nl_groups;
+};
+
+struct nlmsghdr
+{
+ u32 nlmsg_len;
+ u16 nlmsg_type;
+ u16 nlmsg_flags;
+ u32 nlmsg_seq;
+ u32 nlmsg_pid;
+};
+
+struct ifinfomsg
+{
+ unsigned char ifi_family;
+ unsigned char __ifi_pad;
+ unsigned short ifi_type;
+ int ifi_index;
+ unsigned ifi_flags;
+ unsigned ifi_change;
+};
+
+struct rtattr
+{
+ unsigned short rta_len;
+ unsigned short rta_type;
+};
+
+#endif /* PRIV_NETLINK_H */
diff --git a/hostapd/radiotap.c b/hostapd/radiotap.c
new file mode 100644
index 0000000..804473f
--- /dev/null
+++ b/hostapd/radiotap.c
@@ -0,0 +1,287 @@
+/*
+ * Radiotap parser
+ *
+ * Copyright 2007 Andy Green <andy@warmcat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ *
+ * Modified for userspace by Johannes Berg <johannes@sipsolutions.net>
+ * I only modified some things on top to ease syncing should bugs be found.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "radiotap_iter.h"
+
+#define le16_to_cpu le_to_host16
+#define le32_to_cpu le_to_host32
+#define __le32 uint32_t
+#define ulong unsigned long
+#define unlikely(cond) (cond)
+#define get_unaligned(p) \
+({ \
+ struct packed_dummy_struct { \
+ typeof(*(p)) __val; \
+ } __attribute__((packed)) *__ptr = (void *) (p); \
+ \
+ __ptr->__val; \
+})
+
+/* function prototypes and related defs are in radiotap_iter.h */
+
+/**
+ * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
+ * @iterator: radiotap_iterator to initialize
+ * @radiotap_header: radiotap header to parse
+ * @max_length: total length we can parse into (eg, whole packet length)
+ *
+ * Returns: 0 or a negative error code if there is a problem.
+ *
+ * This function initializes an opaque iterator struct which can then
+ * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap
+ * argument which is present in the header. It knows about extended
+ * present headers and handles them.
+ *
+ * How to use:
+ * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
+ * struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
+ * checking for a good 0 return code. Then loop calling
+ * __ieee80211_radiotap_iterator_next()... it returns either 0,
+ * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem.
+ * The iterator's @this_arg member points to the start of the argument
+ * associated with the current argument index that is present, which can be
+ * found in the iterator's @this_arg_index member. This arg index corresponds
+ * to the IEEE80211_RADIOTAP_... defines.
+ *
+ * Radiotap header length:
+ * You can find the CPU-endian total radiotap header length in
+ * iterator->max_length after executing ieee80211_radiotap_iterator_init()
+ * successfully.
+ *
+ * Alignment Gotcha:
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ *
+ * Example code:
+ * See Documentation/networking/radiotap-headers.txt
+ */
+
+int ieee80211_radiotap_iterator_init(
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length)
+{
+ /* Linux only supports version 0 radiotap format */
+ if (radiotap_header->it_version)
+ return -EINVAL;
+
+ /* sanity check for allowed length and radiotap length field */
+ if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
+ return -EINVAL;
+
+ iterator->rtheader = radiotap_header;
+ iterator->max_length = le16_to_cpu(get_unaligned(
+ &radiotap_header->it_len));
+ iterator->arg_index = 0;
+ iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
+ &radiotap_header->it_present));
+ iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
+ iterator->this_arg = NULL;
+
+ /* find payload start allowing for extended bitmap(s) */
+
+ if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
+ while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
+ (1<<IEEE80211_RADIOTAP_EXT)) {
+ iterator->arg += sizeof(u32);
+
+ /*
+ * check for insanity where the present bitmaps
+ * keep claiming to extend up to or even beyond the
+ * stated radiotap header length
+ */
+
+ if (((ulong)iterator->arg - (ulong)iterator->rtheader)
+ > (ulong)iterator->max_length)
+ return -EINVAL;
+ }
+
+ iterator->arg += sizeof(u32);
+
+ /*
+ * no need to check again for blowing past stated radiotap
+ * header length, because ieee80211_radiotap_iterator_next
+ * checks it before it is dereferenced
+ */
+ }
+
+ /* we are all initialized happily */
+
+ return 0;
+}
+
+
+/**
+ * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
+ * @iterator: radiotap_iterator to move to next arg (if any)
+ *
+ * Returns: 0 if there is an argument to handle,
+ * -ENOENT if there are no more args or -EINVAL
+ * if there is something else wrong.
+ *
+ * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
+ * in @this_arg_index and sets @this_arg to point to the
+ * payload for the field. It takes care of alignment handling and extended
+ * present fields. @this_arg can be changed by the caller (eg,
+ * incremented to move inside a compound argument like
+ * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
+ * little-endian format whatever the endianess of your CPU.
+ *
+ * Alignment Gotcha:
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ */
+
+int ieee80211_radiotap_iterator_next(
+ struct ieee80211_radiotap_iterator *iterator)
+{
+
+ /*
+ * small length lookup table for all radiotap types we heard of
+ * starting from b0 in the bitmap, so we can walk the payload
+ * area of the radiotap header
+ *
+ * There is a requirement to pad args, so that args
+ * of a given length must begin at a boundary of that length
+ * -- but note that compound args are allowed (eg, 2 x u16
+ * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
+ * a reliable indicator of alignment requirement.
+ *
+ * upper nybble: content alignment for arg
+ * lower nybble: content length for arg
+ */
+
+ static const u8 rt_sizes[] = {
+ [IEEE80211_RADIOTAP_TSFT] = 0x88,
+ [IEEE80211_RADIOTAP_FLAGS] = 0x11,
+ [IEEE80211_RADIOTAP_RATE] = 0x11,
+ [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
+ [IEEE80211_RADIOTAP_FHSS] = 0x22,
+ [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
+ [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
+ [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
+ [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
+ [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
+ [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
+ [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
+ [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
+ [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
+ [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
+ [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
+ [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
+ [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11,
+ /*
+ * add more here as they are defined in
+ * include/net/ieee80211_radiotap.h
+ */
+ };
+
+ /*
+ * for every radiotap entry we can at
+ * least skip (by knowing the length)...
+ */
+
+ while (iterator->arg_index < (int) sizeof(rt_sizes)) {
+ int hit = 0;
+ int pad;
+
+ if (!(iterator->bitmap_shifter & 1))
+ goto next_entry; /* arg not present */
+
+ /*
+ * arg is present, account for alignment padding
+ * 8-bit args can be at any alignment
+ * 16-bit args must start on 16-bit boundary
+ * 32-bit args must start on 32-bit boundary
+ * 64-bit args must start on 64-bit boundary
+ *
+ * note that total arg size can differ from alignment of
+ * elements inside arg, so we use upper nybble of length
+ * table to base alignment on
+ *
+ * also note: these alignments are ** relative to the
+ * start of the radiotap header **. There is no guarantee
+ * that the radiotap header itself is aligned on any
+ * kind of boundary.
+ *
+ * the above is why get_unaligned() is used to dereference
+ * multibyte elements from the radiotap area
+ */
+
+ pad = (((ulong)iterator->arg) -
+ ((ulong)iterator->rtheader)) &
+ ((rt_sizes[iterator->arg_index] >> 4) - 1);
+
+ if (pad)
+ iterator->arg +=
+ (rt_sizes[iterator->arg_index] >> 4) - pad;
+
+ /*
+ * this is what we will return to user, but we need to
+ * move on first so next call has something fresh to test
+ */
+ iterator->this_arg_index = iterator->arg_index;
+ iterator->this_arg = iterator->arg;
+ hit = 1;
+
+ /* internally move on the size of this arg */
+ iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
+
+ /*
+ * check for insanity where we are given a bitmap that
+ * claims to have more arg content than the length of the
+ * radiotap section. We will normally end up equalling this
+ * max_length on the last arg, never exceeding it.
+ */
+
+ if (((ulong)iterator->arg - (ulong)iterator->rtheader) >
+ (ulong) iterator->max_length)
+ return -EINVAL;
+
+ next_entry:
+ iterator->arg_index++;
+ if (unlikely((iterator->arg_index & 31) == 0)) {
+ /* completed current u32 bitmap */
+ if (iterator->bitmap_shifter & 1) {
+ /* b31 was set, there is more */
+ /* move to next u32 bitmap */
+ iterator->bitmap_shifter = le32_to_cpu(
+ get_unaligned(iterator->next_bitmap));
+ iterator->next_bitmap++;
+ } else
+ /* no more bitmaps: end */
+ iterator->arg_index = sizeof(rt_sizes);
+ } else /* just try the next bit */
+ iterator->bitmap_shifter >>= 1;
+
+ /* if we found a valid arg earlier, return it now */
+ if (hit)
+ return 0;
+ }
+
+ /* we don't know how to handle any more args, we're done */
+ return -ENOENT;
+}
diff --git a/hostapd/radiotap.h b/hostapd/radiotap.h
new file mode 100644
index 0000000..508264c
--- /dev/null
+++ b/hostapd/radiotap.h
@@ -0,0 +1,242 @@
+/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */
+/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */
+
+/*-
+ * Copyright (c) 2003, 2004 David Young. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of David Young may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
+ * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+/*
+ * Modifications to fit into the linux IEEE 802.11 stack,
+ * Mike Kershaw (dragorn@kismetwireless.net)
+ */
+
+#ifndef IEEE80211RADIOTAP_H
+#define IEEE80211RADIOTAP_H
+
+#include <stdint.h>
+
+/* Base version of the radiotap packet header data */
+#define PKTHDR_RADIOTAP_VERSION 0
+
+/* A generic radio capture format is desirable. There is one for
+ * Linux, but it is neither rigidly defined (there were not even
+ * units given for some fields) nor easily extensible.
+ *
+ * I suggest the following extensible radio capture format. It is
+ * based on a bitmap indicating which fields are present.
+ *
+ * I am trying to describe precisely what the application programmer
+ * should expect in the following, and for that reason I tell the
+ * units and origin of each measurement (where it applies), or else I
+ * use sufficiently weaselly language ("is a monotonically nondecreasing
+ * function of...") that I cannot set false expectations for lawyerly
+ * readers.
+ */
+
+/* The radio capture header precedes the 802.11 header.
+ * All data in the header is little endian on all platforms.
+ */
+struct ieee80211_radiotap_header {
+ uint8_t it_version; /* Version 0. Only increases
+ * for drastic changes,
+ * introduction of compatible
+ * new fields does not count.
+ */
+ uint8_t it_pad;
+ uint16_t it_len; /* length of the whole
+ * header in bytes, including
+ * it_version, it_pad,
+ * it_len, and data fields.
+ */
+ uint32_t it_present; /* A bitmap telling which
+ * fields are present. Set bit 31
+ * (0x80000000) to extend the
+ * bitmap by another 32 bits.
+ * Additional extensions are made
+ * by setting bit 31.
+ */
+};
+
+/* Name Data type Units
+ * ---- --------- -----
+ *
+ * IEEE80211_RADIOTAP_TSFT __le64 microseconds
+ *
+ * Value in microseconds of the MAC's 64-bit 802.11 Time
+ * Synchronization Function timer when the first bit of the
+ * MPDU arrived at the MAC. For received frames, only.
+ *
+ * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap
+ *
+ * Tx/Rx frequency in MHz, followed by flags (see below).
+ *
+ * IEEE80211_RADIOTAP_FHSS uint16_t see below
+ *
+ * For frequency-hopping radios, the hop set (first byte)
+ * and pattern (second byte).
+ *
+ * IEEE80211_RADIOTAP_RATE u8 500kb/s
+ *
+ * Tx/Rx data rate
+ *
+ * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
+ * one milliwatt (dBm)
+ *
+ * RF signal power at the antenna, decibel difference from
+ * one milliwatt.
+ *
+ * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
+ * one milliwatt (dBm)
+ *
+ * RF noise power at the antenna, decibel difference from one
+ * milliwatt.
+ *
+ * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB)
+ *
+ * RF signal power at the antenna, decibel difference from an
+ * arbitrary, fixed reference.
+ *
+ * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB)
+ *
+ * RF noise power at the antenna, decibel difference from an
+ * arbitrary, fixed reference point.
+ *
+ * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless
+ *
+ * Quality of Barker code lock. Unitless. Monotonically
+ * nondecreasing with "better" lock strength. Called "Signal
+ * Quality" in datasheets. (Is there a standard way to measure
+ * this?)
+ *
+ * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless
+ *
+ * Transmit power expressed as unitless distance from max
+ * power set at factory calibration. 0 is max power.
+ * Monotonically nondecreasing with lower power levels.
+ *
+ * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB)
+ *
+ * Transmit power expressed as decibel distance from max power
+ * set at factory calibration. 0 is max power. Monotonically
+ * nondecreasing with lower power levels.
+ *
+ * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
+ * one milliwatt (dBm)
+ *
+ * Transmit power expressed as dBm (decibels from a 1 milliwatt
+ * reference). This is the absolute power level measured at
+ * the antenna port.
+ *
+ * IEEE80211_RADIOTAP_FLAGS u8 bitmap
+ *
+ * Properties of transmitted and received frames. See flags
+ * defined below.
+ *
+ * IEEE80211_RADIOTAP_ANTENNA u8 antenna index
+ *
+ * Unitless indication of the Rx/Tx antenna for this packet.
+ * The first antenna is antenna 0.
+ *
+ * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap
+ *
+ * Properties of received frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap
+ *
+ * Properties of transmitted frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_RTS_RETRIES u8 data
+ *
+ * Number of rts retries a transmitted frame used.
+ *
+ * IEEE80211_RADIOTAP_DATA_RETRIES u8 data
+ *
+ * Number of unicast retries a transmitted frame used.
+ *
+ */
+enum ieee80211_radiotap_type {
+ IEEE80211_RADIOTAP_TSFT = 0,
+ IEEE80211_RADIOTAP_FLAGS = 1,
+ IEEE80211_RADIOTAP_RATE = 2,
+ IEEE80211_RADIOTAP_CHANNEL = 3,
+ IEEE80211_RADIOTAP_FHSS = 4,
+ IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
+ IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
+ IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
+ IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
+ IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
+ IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
+ IEEE80211_RADIOTAP_ANTENNA = 11,
+ IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
+ IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
+ IEEE80211_RADIOTAP_RX_FLAGS = 14,
+ IEEE80211_RADIOTAP_TX_FLAGS = 15,
+ IEEE80211_RADIOTAP_RTS_RETRIES = 16,
+ IEEE80211_RADIOTAP_DATA_RETRIES = 17,
+ IEEE80211_RADIOTAP_EXT = 31
+};
+
+/* Channel flags. */
+#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */
+#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */
+#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */
+#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */
+#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */
+#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
+#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
+#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
+
+/* For IEEE80211_RADIOTAP_FLAGS */
+#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received
+ * during CFP
+ */
+#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received
+ * with short
+ * preamble
+ */
+#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received
+ * with WEP encryption
+ */
+#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received
+ * with fragmentation
+ */
+#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */
+#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between
+ * 802.11 header and payload
+ * (to 32-bit boundary)
+ */
+/* For IEEE80211_RADIOTAP_RX_FLAGS */
+#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */
+
+/* For IEEE80211_RADIOTAP_TX_FLAGS */
+#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
+ * retries */
+#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
+#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
+
+#endif /* IEEE80211_RADIOTAP_H */
diff --git a/hostapd/radiotap_iter.h b/hostapd/radiotap_iter.h
new file mode 100644
index 0000000..92a798a
--- /dev/null
+++ b/hostapd/radiotap_iter.h
@@ -0,0 +1,41 @@
+#ifndef __RADIOTAP_ITER_H
+#define __RADIOTAP_ITER_H
+
+#include "radiotap.h"
+
+/* Radiotap header iteration
+ * implemented in radiotap.c
+ */
+/**
+ * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
+ * @rtheader: pointer to the radiotap header we are walking through
+ * @max_length: length of radiotap header in cpu byte ordering
+ * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
+ * @this_arg: pointer to current radiotap arg
+ * @arg_index: internal next argument index
+ * @arg: internal next argument pointer
+ * @next_bitmap: internal pointer to next present u32
+ * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
+ */
+
+struct ieee80211_radiotap_iterator {
+ struct ieee80211_radiotap_header *rtheader;
+ int max_length;
+ int this_arg_index;
+ unsigned char *this_arg;
+
+ int arg_index;
+ unsigned char *arg;
+ uint32_t *next_bitmap;
+ uint32_t bitmap_shifter;
+};
+
+extern int ieee80211_radiotap_iterator_init(
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length);
+
+extern int ieee80211_radiotap_iterator_next(
+ struct ieee80211_radiotap_iterator *iterator);
+
+#endif /* __RADIOTAP_ITER_H */
diff --git a/hostapd/wme.c b/hostapd/wme.c
index 727ee7e..f2bbbd9 100644
--- a/hostapd/wme.c
+++ b/hostapd/wme.c
@@ -24,47 +24,63 @@
/* TODO: maintain separate sequence and fragment numbers for each AC
* TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA
- * if only WME stations are receiving a certain group */
+ * if only WMM stations are receiving a certain group */
-static u8 wme_oui[3] = { 0x00, 0x50, 0xf2 };
+static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci)
+{
+ u8 ret;
+ ret = (aifsn << WMM_AC_AIFNS_SHIFT) & WMM_AC_AIFSN_MASK;
+ if (acm)
+ ret |= WMM_AC_ACM;
+ ret |= (aci << WMM_AC_ACI_SHIFT) & WMM_AC_ACI_MASK;
+ return ret;
+}
+
+
+static inline u8 wmm_ecw(int ecwmin, int ecwmax)
+{
+ return ((ecwmin << WMM_AC_ECWMIN_SHIFT) & WMM_AC_ECWMIN_MASK) |
+ ((ecwmax << WMM_AC_ECWMAX_SHIFT) & WMM_AC_ECWMAX_MASK);
+}
-/* Add WME Parameter Element to Beacon and Probe Response frames. */
-u8 * hostapd_eid_wme(struct hostapd_data *hapd, u8 *eid)
+/*
+ * Add WMM Parameter Element to Beacon, Probe Response, and (Re)Association
+ * Response frames.
+ */
+u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
{
u8 *pos = eid;
- struct wme_parameter_element *wme =
- (struct wme_parameter_element *) (pos + 2);
+ struct wmm_parameter_element *wmm =
+ (struct wmm_parameter_element *) (pos + 2);
int e;
- if (!hapd->conf->wme_enabled)
+ if (!hapd->conf->wmm_enabled)
return eid;
eid[0] = WLAN_EID_VENDOR_SPECIFIC;
- wme->oui[0] = 0x00;
- wme->oui[1] = 0x50;
- wme->oui[2] = 0xf2;
- wme->oui_type = WME_OUI_TYPE;
- wme->oui_subtype = WME_OUI_SUBTYPE_PARAMETER_ELEMENT;
- wme->version = WME_VERSION;
- wme->acInfo = hapd->parameter_set_count & 0xf;
+ wmm->oui[0] = 0x00;
+ wmm->oui[1] = 0x50;
+ wmm->oui[2] = 0xf2;
+ wmm->oui_type = WMM_OUI_TYPE;
+ wmm->oui_subtype = WMM_OUI_SUBTYPE_PARAMETER_ELEMENT;
+ wmm->version = WMM_VERSION;
+ wmm->qos_info = hapd->parameter_set_count & 0xf;
/* fill in a parameter set record for each AC */
for (e = 0; e < 4; e++) {
- struct wme_ac_parameter *ac = &wme->ac[e];
- struct hostapd_wme_ac_params *acp =
- &hapd->iconf->wme_ac_params[e];
-
- ac->aifsn = acp->aifs;
- ac->acm = acp->admission_control_mandatory;
- ac->aci = e;
- ac->reserved = 0;
- ac->eCWmin = acp->cwmin;
- ac->eCWmax = acp->cwmax;
- ac->txopLimit = host_to_le16(acp->txopLimit);
+ struct wmm_ac_parameter *ac = &wmm->ac[e];
+ struct hostapd_wmm_ac_params *acp =
+ &hapd->iconf->wmm_ac_params[e];
+
+ ac->aci_aifsn = wmm_aci_aifsn(acp->aifs,
+ acp->admission_control_mandatory,
+ e);
+ ac->cw = wmm_ecw(acp->cwmin, acp->cwmax);
+ ac->txop_limit = host_to_le16(acp->txop_limit);
}
- pos = (u8 *) (wme + 1);
+ pos = (u8 *) (wmm + 1);
eid[1] = pos - eid - 2; /* element length */
return pos;
@@ -72,31 +88,28 @@ u8 * hostapd_eid_wme(struct hostapd_data *hapd, u8 *eid)
/* This function is called when a station sends an association request with
- * WME info element. The function returns zero on success or non-zero on any
- * error in WME element. eid does not include Element ID and Length octets. */
-int hostapd_eid_wme_valid(struct hostapd_data *hapd, u8 *eid, size_t len)
+ * WMM info element. The function returns zero on success or non-zero on any
+ * error in WMM element. eid does not include Element ID and Length octets. */
+int hostapd_eid_wmm_valid(struct hostapd_data *hapd, u8 *eid, size_t len)
{
- struct wme_information_element *wme;
+ struct wmm_information_element *wmm;
- wpa_hexdump(MSG_MSGDUMP, "WME IE", eid, len);
+ wpa_hexdump(MSG_MSGDUMP, "WMM IE", eid, len);
- if (len < sizeof(struct wme_information_element)) {
- wpa_printf(MSG_DEBUG, "Too short WME IE (len=%lu)",
+ if (len < sizeof(struct wmm_information_element)) {
+ wpa_printf(MSG_DEBUG, "Too short WMM IE (len=%lu)",
(unsigned long) len);
return -1;
}
- wme = (struct wme_information_element *) eid;
- wpa_printf(MSG_DEBUG, "Validating WME IE: OUI %02x:%02x:%02x "
- "OUI type %d OUI sub-type %d version %d",
- wme->oui[0], wme->oui[1], wme->oui[2], wme->oui_type,
- wme->oui_subtype, wme->version);
- if (os_memcmp(wme->oui, wme_oui, sizeof(wme_oui)) != 0 ||
- wme->oui_type != WME_OUI_TYPE ||
- wme->oui_subtype != WME_OUI_SUBTYPE_INFORMATION_ELEMENT ||
- wme->version != WME_VERSION) {
- wpa_printf(MSG_DEBUG, "Unsupported WME IE OUI/Type/Subtype/"
- "Version");
+ wmm = (struct wmm_information_element *) eid;
+ wpa_printf(MSG_DEBUG, "Validating WMM IE: OUI %02x:%02x:%02x "
+ "OUI type %d OUI sub-type %d version %d QoS info 0x%x",
+ wmm->oui[0], wmm->oui[1], wmm->oui[2], wmm->oui_type,
+ wmm->oui_subtype, wmm->version, wmm->qos_info);
+ if (wmm->oui_subtype != WMM_OUI_SUBTYPE_INFORMATION_ELEMENT ||
+ wmm->version != WMM_VERSION) {
+ wpa_printf(MSG_DEBUG, "Unsupported WMM IE Subtype/Version");
return -1;
}
@@ -105,31 +118,30 @@ int hostapd_eid_wme_valid(struct hostapd_data *hapd, u8 *eid, size_t len)
/* This function is called when a station sends an ACK frame for an AssocResp
- * frame (status=success) and the matching AssocReq contained a WME element.
+ * frame (status=success) and the matching AssocReq contained a WMM element.
*/
-int hostapd_wme_sta_config(struct hostapd_data *hapd, struct sta_info *sta)
+int hostapd_wmm_sta_config(struct hostapd_data *hapd, struct sta_info *sta)
{
- /* update kernel STA data for WME related items (WLAN_STA_WPA flag) */
- if (sta->flags & WLAN_STA_WME)
+ /* update kernel STA data for WMM related items (WLAN_STA_WPA flag) */
+ if (sta->flags & WLAN_STA_WMM)
hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
- WLAN_STA_WME, ~0);
+ WLAN_STA_WMM, ~0);
else
hostapd_sta_set_flags(hapd, sta->addr, sta->flags,
- 0, ~WLAN_STA_WME);
+ 0, ~WLAN_STA_WMM);
return 0;
}
-static void wme_send_action(struct hostapd_data *hapd, const u8 *addr,
- const struct wme_tspec_info_element *tspec,
+static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
+ const struct wmm_tspec_element *tspec,
u8 action_code, u8 dialogue_token, u8 status_code)
{
u8 buf[256];
struct ieee80211_mgmt *m = (struct ieee80211_mgmt *) buf;
- struct wme_tspec_info_element *t =
- (struct wme_tspec_info_element *)
- m->u.action.u.wme_action.variable;
+ struct wmm_tspec_element *t = (struct wmm_tspec_element *)
+ m->u.action.u.wmm_action.variable;
int len;
hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
@@ -142,55 +154,117 @@ static void wme_send_action(struct hostapd_data *hapd, const u8 *addr,
os_memcpy(m->sa, hapd->own_addr, ETH_ALEN);
os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
m->u.action.category = WLAN_ACTION_WMM;
- m->u.action.u.wme_action.action_code = action_code;
- m->u.action.u.wme_action.dialog_token = dialogue_token;
- m->u.action.u.wme_action.status_code = status_code;
- os_memcpy(t, tspec, sizeof(struct wme_tspec_info_element));
+ m->u.action.u.wmm_action.action_code = action_code;
+ m->u.action.u.wmm_action.dialog_token = dialogue_token;
+ m->u.action.u.wmm_action.status_code = status_code;
+ os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
len = ((u8 *) (t + 1)) - buf;
if (hostapd_send_mgmt_frame(hapd, m, len, 0) < 0)
- perror("wme_send_action: send");
+ perror("wmm_send_action: send");
}
-/* given frame data payload size in bytes, and data_rate in bits per second
- * returns time to complete frame exchange */
-/* FIX: should not use floating point types */
-static double wme_frame_exchange_time(int bytes, int data_rate, int encryption,
- int cts_protection)
+static void wmm_addts_req(struct hostapd_data *hapd,
+ struct ieee80211_mgmt *mgmt,
+ struct wmm_tspec_element *tspec, size_t len)
{
- /* TODO: account for MAC/PHY headers correctly */
- /* TODO: account for encryption headers */
- /* TODO: account for WDS headers */
- /* TODO: account for CTS protection */
- /* TODO: account for SIFS + ACK at minimum PHY rate */
- return (bytes + 400) * 8.0 / data_rate;
-}
+ u8 *end = ((u8 *) mgmt) + len;
+ int medium_time, pps, duration;
+ int up, psb, dir, tid;
+ u16 val, surplus;
+ if ((u8 *) (tspec + 1) > end) {
+ wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request");
+ return;
+ }
-static void wme_setup_request(struct hostapd_data *hapd,
- struct ieee80211_mgmt *mgmt,
- struct wme_tspec_info_element *tspec, size_t len)
-{
- /* FIX: should not use floating point types */
- double medium_time, pps;
+ wpa_printf(MSG_DEBUG, "WMM: ADDTS Request (Dialog Token %d) for TSPEC "
+ "from " MACSTR,
+ mgmt->u.action.u.wmm_action.dialog_token,
+ MAC2STR(mgmt->sa));
+
+ up = (tspec->ts_info[1] >> 3) & 0x07;
+ psb = (tspec->ts_info[1] >> 2) & 0x01;
+ dir = (tspec->ts_info[0] >> 5) & 0x03;
+ tid = (tspec->ts_info[0] >> 1) & 0x0f;
+ wpa_printf(MSG_DEBUG, "WMM: TS Info: UP=%d PSB=%d Direction=%d TID=%d",
+ up, psb, dir, tid);
+ val = le_to_host16(tspec->nominal_msdu_size);
+ wpa_printf(MSG_DEBUG, "WMM: Nominal MSDU Size: %d%s",
+ val & 0x7fff, val & 0x8000 ? " (fixed)" : "");
+ wpa_printf(MSG_DEBUG, "WMM: Mean Data Rate: %u bps",
+ le_to_host32(tspec->mean_data_rate));
+ wpa_printf(MSG_DEBUG, "WMM: Minimum PHY Rate: %u bps",
+ le_to_host32(tspec->minimum_phy_rate));
+ val = le_to_host16(tspec->surplus_bandwidth_allowance);
+ wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance: %u.%04u",
+ val >> 13, 10000 * (val & 0x1fff) / 0x2000);
+
+ val = le_to_host16(tspec->nominal_msdu_size);
+ if (val == 0) {
+ wpa_printf(MSG_DEBUG, "WMM: Invalid Nominal MSDU Size (0)");
+ goto invalid;
+ }
+ /* pps = Ceiling((Mean Data Rate / 8) / Nominal MSDU Size) */
+ pps = ((le_to_host32(tspec->mean_data_rate) / 8) + val - 1) / val;
+ wpa_printf(MSG_DEBUG, "WMM: Packets-per-second estimate for TSPEC: %d",
+ pps);
+
+ if (le_to_host32(tspec->minimum_phy_rate) < 1000000) {
+ wpa_printf(MSG_DEBUG, "WMM: Too small Minimum PHY Rate");
+ goto invalid;
+ }
+
+ duration = (le_to_host16(tspec->nominal_msdu_size) & 0x7fff) * 8 /
+ (le_to_host32(tspec->minimum_phy_rate) / 1000000) +
+ 50 /* FIX: proper SIFS + ACK duration */;
+
+ /* unsigned binary number with an implicit binary point after the
+ * leftmost 3 bits, i.e., 0x2000 = 1.0 */
+ surplus = le_to_host16(tspec->surplus_bandwidth_allowance);
+ if (surplus <= 0x2000) {
+ wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance not "
+ "greater than unity");
+ goto invalid;
+ }
+
+ medium_time = surplus * pps * duration / 0x2000;
+ wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %u", medium_time);
+
+ /*
+ * TODO: store list of granted (and still active) TSPECs and check
+ * whether there is available medium time for this request. For now,
+ * just refuse requests that would by themselves take very large
+ * portion of the available bandwidth.
+ */
+ if (medium_time > 750000) {
+ wpa_printf(MSG_DEBUG, "WMM: Refuse TSPEC request for over "
+ "75%% of available bandwidth");
+ wmm_send_action(hapd, mgmt->sa, tspec,
+ WMM_ACTION_CODE_ADDTS_RESP,
+ mgmt->u.action.u.wmm_action.dialog_token,
+ WMM_ADDTS_STATUS_REFUSED);
+ return;
+ }
- /* TODO: account for airtime and answer no to tspec setup requests
- * when none left!! */
+ /* Convert to 32 microseconds per second unit */
+ tspec->medium_time = host_to_le16(medium_time / 32);
- pps = (tspec->mean_data_rate / 8.0) / tspec->nominal_msdu_size;
- medium_time = (tspec->surplus_bandwidth_allowance / 8) * pps *
- wme_frame_exchange_time(tspec->nominal_msdu_size,
- tspec->minimum_phy_rate, 0, 0);
- tspec->medium_time = medium_time * 1000000.0 / 32.0;
+ wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP,
+ mgmt->u.action.u.wmm_action.dialog_token,
+ WMM_ADDTS_STATUS_ADMISSION_ACCEPTED);
+ return;
- wme_send_action(hapd, mgmt->sa, tspec, WME_ACTION_CODE_SETUP_RESPONSE,
- mgmt->u.action.u.wme_action.dialog_token,
- WME_SETUP_RESPONSE_STATUS_ADMISSION_ACCEPTED);
+invalid:
+ wmm_send_action(hapd, mgmt->sa, tspec,
+ WMM_ACTION_CODE_ADDTS_RESP,
+ mgmt->u.action.u.wmm_action.dialog_token,
+ WMM_ADDTS_STATUS_INVALID_PARAMETERS);
}
-void hostapd_wme_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
+void hostapd_wmm_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
size_t len)
{
int action_code;
@@ -201,11 +275,11 @@ void hostapd_wme_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
/* check that the request comes from a valid station */
if (!sta ||
- (sta->flags & (WLAN_STA_ASSOC | WLAN_STA_WME)) !=
- (WLAN_STA_ASSOC | WLAN_STA_WME)) {
+ (sta->flags & (WLAN_STA_ASSOC | WLAN_STA_WMM)) !=
+ (WLAN_STA_ASSOC | WLAN_STA_WMM)) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "wme action received is not from associated wme"
+ "wmm action received is not from associated wmm"
" station");
/* TODO: respond with action frame refused status code */
return;
@@ -215,19 +289,18 @@ void hostapd_wme_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "hostapd_wme_action - could not parse wme "
+ "hostapd_wmm_action - could not parse wmm "
"action");
/* TODO: respond with action frame invalid parameters status
* code */
return;
}
- if (!elems.wme_tspec ||
- elems.wme_tspec_len != (sizeof(struct wme_tspec_info_element) - 2))
- {
+ if (!elems.wmm_tspec ||
+ elems.wmm_tspec_len != (sizeof(struct wmm_tspec_element) - 2)) {
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "hostapd_wme_action - missing or wrong length "
+ "hostapd_wmm_action - missing or wrong length "
"tspec");
/* TODO: respond with action frame invalid parameters status
* code */
@@ -237,26 +310,26 @@ void hostapd_wme_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
/* TODO: check the request is for an AC with ACM set, if not, refuse
* request */
- action_code = mgmt->u.action.u.wme_action.action_code;
+ action_code = mgmt->u.action.u.wmm_action.action_code;
switch (action_code) {
- case WME_ACTION_CODE_SETUP_REQUEST:
- wme_setup_request(hapd, mgmt, (struct wme_tspec_info_element *)
- elems.wme_tspec, len);
+ case WMM_ACTION_CODE_ADDTS_REQ:
+ wmm_addts_req(hapd, mgmt, (struct wmm_tspec_element *)
+ (elems.wmm_tspec - 2), len);
return;
#if 0
/* TODO: needed for client implementation */
- case WME_ACTION_CODE_SETUP_RESPONSE:
- wme_setup_request(hapd, mgmt, len);
+ case WMM_ACTION_CODE_ADDTS_RESP:
+ wmm_setup_request(hapd, mgmt, len);
return;
/* TODO: handle station teardown requests */
- case WME_ACTION_CODE_TEARDOWN:
- wme_teardown(hapd, mgmt, len);
+ case WMM_ACTION_CODE_DELTS:
+ wmm_teardown(hapd, mgmt, len);
return;
#endif
}
hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
- "hostapd_wme_action - unknown action code %d",
+ "hostapd_wmm_action - unknown action code %d",
action_code);
}
diff --git a/hostapd/wme.h b/hostapd/wme.h
index 4ee281a..e06b5bc 100644
--- a/hostapd/wme.h
+++ b/hostapd/wme.h
@@ -16,114 +16,97 @@
#ifndef WME_H
#define WME_H
-#ifdef __linux__
-#include <endian.h>
-#endif /* __linux__ */
-
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
-#include <sys/types.h>
-#include <sys/endian.h>
-#endif /* defined(__FreeBSD__) || defined(__NetBSD__) ||
- * defined(__DragonFly__) */
-
-
-extern inline u16 tsinfo(int tag1d, int contention_based, int direction)
-{
- return (tag1d << 11) | (contention_based << 7) | (direction << 5) |
- (tag1d << 1);
-}
-
-
-struct wme_information_element {
- /* required fields for WME version 1 */
- u8 oui[3];
- u8 oui_type;
- u8 oui_subtype;
- u8 version;
- u8 acInfo;
+/*
+ * 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 */
} __attribute__ ((packed));
-struct wme_ac_parameter {
-#if __BYTE_ORDER == __LITTLE_ENDIAN
- /* byte 1 */
- u8 aifsn:4,
- acm:1,
- aci:2,
- reserved:1;
-
- /* byte 2 */
- u8 eCWmin:4,
- eCWmax:4;
-#elif __BYTE_ORDER == __BIG_ENDIAN
- /* byte 1 */
- u8 reserved:1,
- aci:2,
- acm:1,
- aifsn:4;
-
- /* byte 2 */
- u8 eCWmax:4,
- eCWmin:4;
-#else
-#error "Please fix <endian.h>"
-#endif
-
- /* bytes 3 & 4 */
- le16 txopLimit;
+#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;
} __attribute__ ((packed));
-struct wme_parameter_element {
- /* required fields for WME version 1 */
- u8 oui[3];
- u8 oui_type;
- u8 oui_subtype;
- u8 version;
- u8 acInfo;
- u8 reserved;
- struct wme_ac_parameter ac[4];
+/*
+ * WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association
+ * Response frmaes)
+ */
+struct wmm_parameter_element {
+ /* Element ID: 221 (0xdd); Length: 24 */
+ /* required fields for WMM version 1 */
+ u8 oui[3]; /* 00:50:f2 */
+ u8 oui_type; /* 2 */
+ u8 oui_subtype; /* 1 */
+ u8 version; /* 1 for WMM version 1.0 */
+ u8 qos_info; /* AP/STA specif QoS info */
+ u8 reserved; /* 0 */
+ struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
} __attribute__ ((packed));
-struct wme_tspec_info_element {
- u8 eid;
- u8 length;
- u8 oui[3];
- u8 oui_type;
- u8 oui_subtype;
- u8 version;
- u16 ts_info;
- u16 nominal_msdu_size;
- u16 maximum_msdu_size;
- u32 minimum_service_interval;
- u32 maximum_service_interval;
- u32 inactivity_interval;
- u32 start_time;
- u32 minimum_data_rate;
- u32 mean_data_rate;
- u32 maximum_burst_size;
- u32 minimum_phy_rate;
- u32 peak_data_rate;
- u32 delay_bound;
- u16 surplus_bandwidth_allowance;
- u16 medium_time;
+/* 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;
} __attribute__ ((packed));
-/* Access Categories */
+/* Access Categories / ACI to AC coding */
enum {
- WME_AC_BK = 1,
- WME_AC_BE = 0,
- WME_AC_VI = 2,
- WME_AC_VO = 3
+ WMM_AC_BE = 0 /* Best Effort */,
+ WMM_AC_BK = 1 /* Background */,
+ WMM_AC_VI = 2 /* Video */,
+ WMM_AC_VO = 3 /* Voice */
};
struct ieee80211_mgmt;
-u8 * hostapd_eid_wme(struct hostapd_data *hapd, u8 *eid);
-int hostapd_eid_wme_valid(struct hostapd_data *hapd, u8 *eid, size_t len);
-int hostapd_wme_sta_config(struct hostapd_data *hapd, struct sta_info *sta);
-void hostapd_wme_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
+u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid);
+int hostapd_eid_wmm_valid(struct hostapd_data *hapd, u8 *eid, size_t len);
+int hostapd_wmm_sta_config(struct hostapd_data *hapd, struct sta_info *sta);
+void hostapd_wmm_action(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
size_t len);
#endif /* WME_H */
diff --git a/hostapd/wpa.c b/hostapd/wpa.c
index cf285b6..19b11d5 100644
--- a/hostapd/wpa.c
+++ b/hostapd/wpa.c
@@ -1,6 +1,6 @@
/*
* hostapd - IEEE 802.11i-2004 / WPA Authenticator
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -44,6 +44,8 @@ static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
struct wpa_group *group);
static void wpa_request_new_ptk(struct wpa_state_machine *sm);
+static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
+ struct wpa_group *group);
static const u32 dot11RSNAConfigGroupUpdateCount = 4;
static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
@@ -286,21 +288,9 @@ static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
}
-static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
- int vlan_id)
+static void wpa_group_set_key_len(struct wpa_group *group, int cipher)
{
- struct wpa_group *group;
- u8 buf[ETH_ALEN + 8 + sizeof(group)];
- u8 rkey[32];
-
- group = os_zalloc(sizeof(struct wpa_group));
- if (group == NULL)
- return NULL;
-
- group->GTKAuthenticator = TRUE;
- group->vlan_id = vlan_id;
-
- switch (wpa_auth->conf.wpa_group) {
+ switch (cipher) {
case WPA_CIPHER_CCMP:
group->GTK_len = 16;
break;
@@ -314,6 +304,24 @@ static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
group->GTK_len = 5;
break;
}
+}
+
+
+static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
+ int vlan_id)
+{
+ struct wpa_group *group;
+ u8 buf[ETH_ALEN + 8 + sizeof(group)];
+ u8 rkey[32];
+
+ group = os_zalloc(sizeof(struct wpa_group));
+ if (group == NULL)
+ return NULL;
+
+ group->GTKAuthenticator = TRUE;
+ group->vlan_id = vlan_id;
+
+ wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
/* Counter = PRF-256(Random number, "Init Counter",
* Local MAC Address || Time)
@@ -451,6 +459,7 @@ void wpa_deinit(struct wpa_authenticator *wpa_auth)
int wpa_reconfig(struct wpa_authenticator *wpa_auth,
struct wpa_auth_config *conf)
{
+ struct wpa_group *group;
if (wpa_auth == NULL)
return 0;
@@ -460,6 +469,17 @@ int wpa_reconfig(struct wpa_authenticator *wpa_auth,
return -1;
}
+ /*
+ * Reinitialize GTK to make sure it is suitable for the new
+ * configuration.
+ */
+ group = wpa_auth->group;
+ wpa_group_set_key_len(group, wpa_auth->conf.wpa_group);
+ group->GInit = TRUE;
+ wpa_group_sm_step(wpa_auth, group);
+ group->GInit = FALSE;
+ wpa_group_sm_step(wpa_auth, group);
+
return 0;
}
@@ -619,6 +639,22 @@ void wpa_receive(struct wpa_authenticator *wpa_auth,
return;
}
+ if (sm->wpa == WPA_VERSION_WPA2) {
+ if (key->type != EAPOL_KEY_TYPE_RSN) {
+ wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
+ "unexpected type %d in RSN mode",
+ key->type);
+ return;
+ }
+ } else {
+ if (key->type != EAPOL_KEY_TYPE_WPA) {
+ wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
+ "unexpected type %d in WPA mode",
+ key->type);
+ return;
+ }
+ }
+
/* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys
* are set */
@@ -1403,14 +1439,15 @@ SM_STATE(WPA_PTK, PTKSTART)
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,
struct wpa_ptk *ptk)
{
+ size_t ptk_len = sm->pairwise == WPA_CIPHER_CCMP ? 48 : 64;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
- return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
+ return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
#endif /* CONFIG_IEEE80211R */
wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce,
- (u8 *) ptk, sizeof(*ptk),
+ (u8 *) ptk, ptk_len,
wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
return 0;
diff --git a/hostapd/wpa.h b/hostapd/wpa.h
index d353844..7d9b3d3 100644
--- a/hostapd/wpa.h
+++ b/hostapd/wpa.h
@@ -141,7 +141,7 @@ struct wpa_auth_config {
int rsn_preauth;
int eapol_version;
int peerkey;
- int wme_enabled;
+ int wmm_enabled;
int okc;
#ifdef CONFIG_IEEE80211W
enum {
diff --git a/hostapd/wpa_auth_i.h b/hostapd/wpa_auth_i.h
index bcaeda5..925d3ee 100644
--- a/hostapd/wpa_auth_i.h
+++ b/hostapd/wpa_auth_i.h
@@ -213,7 +213,7 @@ void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
#ifdef CONFIG_IEEE80211R
int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk);
+ struct wpa_ptk *ptk, size_t ptk_len);
struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
#endif /* CONFIG_IEEE80211R */
diff --git a/hostapd/wpa_auth_ie.c b/hostapd/wpa_auth_ie.c
index 3ac9d67..7e01635 100644
--- a/hostapd/wpa_auth_ie.c
+++ b/hostapd/wpa_auth_ie.c
@@ -215,8 +215,8 @@ int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
capab |= WPA_CAPABILITY_PREAUTH;
if (conf->peerkey)
capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
- if (conf->wme_enabled) {
- /* 4 PTKSA replay counters when using WME */
+ if (conf->wmm_enabled) {
+ /* 4 PTKSA replay counters when using WMM */
capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
}
#ifdef CONFIG_IEEE80211W
diff --git a/hostapd/wpa_ft.c b/hostapd/wpa_ft.c
index 9cf6713..3139105 100644
--- a/hostapd/wpa_ft.c
+++ b/hostapd/wpa_ft.c
@@ -321,7 +321,7 @@ static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth,
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk)
+ struct wpa_ptk *ptk, size_t ptk_len)
{
u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
@@ -354,8 +354,8 @@ int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
sm->wpa_auth->addr, pmk_r1_name,
- (u8 *) ptk, sizeof(*ptk), ptk_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, sizeof(*ptk));
+ (u8 *) ptk, ptk_len, ptk_name);
+ wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
return 0;
@@ -714,7 +714,7 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
u8 ptk_name[WPA_PMK_NAME_LEN];
struct wpa_auth_config *conf;
struct wpa_ft_ies parse;
- size_t buflen;
+ size_t buflen, ptk_len;
int ret;
u8 *pos, *end;
@@ -804,11 +804,12 @@ static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
sm->ANonce, WPA_NONCE_LEN);
+ ptk_len = sm->pairwise == WPA_CIPHER_CCMP ? 48 : 64;
wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
sm->wpa_auth->addr, pmk_r1_name,
- (u8 *) &sm->PTK, sizeof(sm->PTK), ptk_name);
+ (u8 *) &sm->PTK, ptk_len, ptk_name);
wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
- (u8 *) &sm->PTK, sizeof(sm->PTK));
+ (u8 *) &sm->PTK, ptk_len);
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
wpa_ft_install_ptk(sm);
diff --git a/hostapd/wps_hostapd.c b/hostapd/wps_hostapd.c
index a824c16..818767e 100644
--- a/hostapd/wps_hostapd.c
+++ b/hostapd/wps_hostapd.c
@@ -219,13 +219,13 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
if ((hapd->conf->wps_cred_processing == 1 ||
hapd->conf->wps_cred_processing == 2) && cred->cred_attr) {
size_t blen = cred->cred_attr_len * 2 + 1;
- char *buf = os_malloc(blen);
- if (buf) {
- wpa_snprintf_hex(buf, blen,
+ char *_buf = os_malloc(blen);
+ if (_buf) {
+ wpa_snprintf_hex(_buf, blen,
cred->cred_attr, cred->cred_attr_len);
wpa_msg(hapd, MSG_INFO, "%s%s",
- WPS_EVENT_NEW_AP_SETTINGS, buf);
- os_free(buf);
+ WPS_EVENT_NEW_AP_SETTINGS, _buf);
+ os_free(_buf);
}
} else
wpa_msg(hapd, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS);
@@ -233,6 +233,28 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
if (hapd->conf->wps_cred_processing == 1)
return 0;
+ os_memcpy(hapd->wps->ssid, cred->ssid, cred->ssid_len);
+ hapd->wps->ssid_len = cred->ssid_len;
+ hapd->wps->encr_types = cred->encr_type;
+ hapd->wps->auth_types = cred->auth_type;
+ if (cred->key_len == 0) {
+ os_free(hapd->wps->network_key);
+ hapd->wps->network_key = NULL;
+ hapd->wps->network_key_len = 0;
+ } else {
+ if (hapd->wps->network_key == NULL ||
+ hapd->wps->network_key_len < cred->key_len) {
+ hapd->wps->network_key_len = 0;
+ os_free(hapd->wps->network_key);
+ hapd->wps->network_key = os_malloc(cred->key_len);
+ if (hapd->wps->network_key == NULL)
+ return -1;
+ }
+ hapd->wps->network_key_len = cred->key_len;
+ os_memcpy(hapd->wps->network_key, cred->key, cred->key_len);
+ }
+ hapd->wps->wps_state = WPS_STATE_CONFIGURED;
+
len = os_strlen(hapd->iface->config_fname) + 5;
tmp_fname = os_malloc(len);
if (tmp_fname == NULL)
@@ -326,15 +348,21 @@ static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
else
fprintf(nconf, "auth_algs=1\n");
- if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx < 4) {
- fprintf(nconf, "wep_default_key=%d\n", cred->key_idx);
- fprintf(nconf, "wep_key%d=", cred->key_idx);
- if (cred->key_len != 10 && cred->key_len != 26)
- fputc('"', nconf);
- for (i = 0; i < cred->key_len; i++)
- fputc(cred->key[i], nconf);
- if (cred->key_len != 10 && cred->key_len != 26)
- fputc('"', nconf);
+ if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx <= 4) {
+ int key_idx = cred->key_idx;
+ if (key_idx)
+ key_idx--;
+ fprintf(nconf, "wep_default_key=%d\n", key_idx);
+ fprintf(nconf, "wep_key%d=", key_idx);
+ if (cred->key_len == 10 || cred->key_len == 26) {
+ /* WEP key as a hex string */
+ for (i = 0; i < cred->key_len; i++)
+ fputc(cred->key[i], nconf);
+ } else {
+ /* Raw WEP key; convert to hex */
+ for (i = 0; i < cred->key_len; i++)
+ fprintf(nconf, "%02x", cred->key[i]);
+ }
fprintf(nconf, "\n");
}
}
@@ -620,6 +648,8 @@ int hostapd_init_wps(struct hostapd_data *hapd,
cfg.extra_cred_len = conf->extra_cred_len;
cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
conf->skip_cred_build;
+ if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
+ cfg.static_wep_only = 1;
wps->registrar = wps_registrar_init(wps, &cfg);
if (wps->registrar == NULL) {
@@ -669,7 +699,7 @@ void hostapd_deinit_wps(struct hostapd_data *hapd)
int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
- const char *pin)
+ const char *pin, int timeout)
{
u8 u[UUID_LEN];
int any = 0;
@@ -681,7 +711,8 @@ int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
else if (uuid_str2bin(uuid, u))
return -1;
return wps_registrar_add_pin(hapd->wps->registrar, any ? NULL : u,
- (const u8 *) pin, os_strlen(pin));
+ (const u8 *) pin, os_strlen(pin),
+ timeout);
}
@@ -864,8 +895,8 @@ static int hostapd_rx_req_put_wlan_response(
wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse ev_type=%d mac_addr="
MACSTR, ev_type, MAC2STR(mac_addr));
- wpa_hexdump_ascii(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage",
- wpabuf_head(msg), wpabuf_len(msg));
+ wpa_hexdump(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage",
+ wpabuf_head(msg), wpabuf_len(msg));
if (ev_type != UPNP_WPS_WLANEVENT_TYPE_EAP) {
wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored unexpected "
"PutWLANResponse WLANEventType %d", ev_type);
diff --git a/hostapd/wps_hostapd.h b/hostapd/wps_hostapd.h
index 6615c62a..e949bee 100644
--- a/hostapd/wps_hostapd.h
+++ b/hostapd/wps_hostapd.h
@@ -21,7 +21,7 @@ int hostapd_init_wps(struct hostapd_data *hapd,
struct hostapd_bss_config *conf);
void hostapd_deinit_wps(struct hostapd_data *hapd);
int hostapd_wps_add_pin(struct hostapd_data *hapd, const char *uuid,
- const char *pin);
+ const char *pin, int timeout);
int hostapd_wps_button_pushed(struct hostapd_data *hapd);
void hostapd_wps_probe_req_rx(struct hostapd_data *hapd, const u8 *addr,
const u8 *ie, size_t ie_len);
diff --git a/src/common/.gitignore b/src/common/.gitignore
deleted file mode 100644
index a438335..0000000
--- a/src/common/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.d
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index 991c989..242f933 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -49,26 +49,33 @@ static int ieee802_11_parse_vendor_specific(u8 *pos, size_t elen,
elems->wpa_ie = pos;
elems->wpa_ie_len = elen;
break;
- case WME_OUI_TYPE: /* this is a Wi-Fi WME info. element */
+ case WMM_OUI_TYPE:
+ /* WMM information element */
if (elen < 5) {
- wpa_printf(MSG_MSGDUMP, "short WME "
+ wpa_printf(MSG_MSGDUMP, "short WMM "
"information element ignored "
"(len=%lu)",
(unsigned long) elen);
return -1;
}
switch (pos[4]) {
- case WME_OUI_SUBTYPE_INFORMATION_ELEMENT:
- case WME_OUI_SUBTYPE_PARAMETER_ELEMENT:
- elems->wme = pos;
- elems->wme_len = elen;
+ case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
+ case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
+ /*
+ * Share same pointer since only one of these
+ * is used and they start with same data.
+ * Length field can be used to distinguish the
+ * IEs.
+ */
+ elems->wmm = pos;
+ elems->wmm_len = elen;
break;
- case WME_OUI_SUBTYPE_TSPEC_ELEMENT:
- elems->wme_tspec = pos;
- elems->wme_tspec_len = elen;
+ case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
+ elems->wmm_tspec = pos;
+ elems->wmm_tspec_len = elen;
break;
default:
- wpa_printf(MSG_MSGDUMP, "unknown WME "
+ wpa_printf(MSG_MSGDUMP, "unknown WMM "
"information element ignored "
"(subtype=%d len=%lu)",
pos[4], (unsigned long) elen);
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 2aff993..b7e497b 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -41,10 +41,10 @@ struct ieee802_11_elems {
u8 wpa_ie_len;
u8 *rsn_ie;
u8 rsn_ie_len;
- u8 *wme;
- u8 wme_len;
- u8 *wme_tspec;
- u8 wme_tspec_len;
+ u8 *wmm; /* WMM Information or Parameter Element */
+ u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
+ u8 *wmm_tspec;
+ u8 wmm_tspec_len;
u8 *wps_ie;
u8 wps_ie_len;
u8 *power_cap;
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 18220b0..d9e54a9 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -134,10 +134,9 @@
#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_EXPECTED_RESOURCE_REQ_FT 53
-#define WLAN_STATUS_INVALID_PMKID 54
-#define WLAN_STATUS_INVALID_MDIE 55
-#define WLAN_STATUS_INVALID_FTIE 56
+#define WLAN_STATUS_INVALID_PMKID 53
+#define WLAN_STATUS_INVALID_MDIE 54
+#define WLAN_STATUS_INVALID_FTIE 55
/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
#define WLAN_REASON_UNSPECIFIED 1
@@ -211,16 +210,18 @@
#define WLAN_ACTION_QOS 1
#define WLAN_ACTION_DLS 2
#define WLAN_ACTION_BLOCK_ACK 3
+#define WLAN_ACTION_PUBLIC 4
#define WLAN_ACTION_RADIO_MEASUREMENT 5
#define WLAN_ACTION_FT 6
+#define WLAN_ACTION_HT 7
#define WLAN_ACTION_SA_QUERY 8
-#define WLAN_ACTION_WMM 17
+#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
-/* SA Query Action frame (IEEE 802.11w/D7.0, 7.4.9) */
+/* 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 16
+#define WLAN_SA_QUERY_TR_ID_LEN 2
/* Timeout Interval Type */
#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
@@ -301,7 +302,7 @@ struct ieee80211_mgmt {
u8 dialog_token;
u8 status_code;
u8 variable[0];
- } STRUCT_PACKED wme_action;
+ } STRUCT_PACKED wmm_action;
struct{
u8 action_code;
u8 element_id;
@@ -562,23 +563,27 @@ struct mimo_pwr_save_action {
#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
* 00:50:F2 */
-#define WME_OUI_TYPE 2
-#define WME_OUI_SUBTYPE_INFORMATION_ELEMENT 0
-#define WME_OUI_SUBTYPE_PARAMETER_ELEMENT 1
-#define WME_OUI_SUBTYPE_TSPEC_ELEMENT 2
-#define WME_VERSION 1
-
-#define WME_ACTION_CODE_SETUP_REQUEST 0
-#define WME_ACTION_CODE_SETUP_RESPONSE 1
-#define WME_ACTION_CODE_TEARDOWN 2
-
-#define WME_SETUP_RESPONSE_STATUS_ADMISSION_ACCEPTED 0
-#define WME_SETUP_RESPONSE_STATUS_INVALID_PARAMETERS 1
-#define WME_SETUP_RESPONSE_STATUS_REFUSED 3
-
-#define WME_TSPEC_DIRECTION_UPLINK 0
-#define WME_TSPEC_DIRECTION_DOWNLINK 1
-#define WME_TSPEC_DIRECTION_BI_DIRECTIONAL 3
+#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
#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
diff --git a/src/common/nl80211_copy.h b/src/common/nl80211_copy.h
new file mode 100644
index 0000000..45db17f
--- /dev/null
+++ b/src/common/nl80211_copy.h
@@ -0,0 +1,1434 @@
+#ifndef __LINUX_NL80211_H
+#define __LINUX_NL80211_H
+/*
+ * 802.11 netlink interface public header
+ *
+ * Copyright 2006, 2007, 2008 Johannes Berg <johannes@sipsolutions.net>
+ * Copyright 2008 Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2008 Luis Carlos Cobo <luisca@cozybit.com>
+ * Copyright 2008 Michael Buesch <mb@bu3sch.de>
+ * Copyright 2008, 2009 Luis R. Rodriguez <lrodriguez@atheros.com>
+ * Copyright 2008 Jouni Malinen <jouni.malinen@atheros.com>
+ * Copyright 2008 Colin McCabe <colin@cozybit.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ */
+
+#include <linux/types.h>
+
+/**
+ * DOC: Station handling
+ *
+ * Stations are added per interface, but a special case exists with VLAN
+ * interfaces. When a station is bound to an AP interface, it may be moved
+ * into a VLAN identified by a VLAN interface index (%NL80211_ATTR_STA_VLAN).
+ * The station is still assumed to belong to the AP interface it was added
+ * to.
+ *
+ * TODO: need more info?
+ */
+
+/**
+ * enum nl80211_commands - supported nl80211 commands
+ *
+ * @NL80211_CMD_UNSPEC: unspecified command to catch errors
+ *
+ * @NL80211_CMD_GET_WIPHY: request information about a wiphy or dump request
+ * to get a list of all present wiphys.
+ * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
+ * %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
+ * %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ,
+ * %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT,
+ * %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+ * and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
+ * @NL80211_CMD_NEW_WIPHY: Newly created wiphy, response to get request
+ * or rename notification. Has attributes %NL80211_ATTR_WIPHY and
+ * %NL80211_ATTR_WIPHY_NAME.
+ * @NL80211_CMD_DEL_WIPHY: Wiphy deleted. Has attributes
+ * %NL80211_ATTR_WIPHY and %NL80211_ATTR_WIPHY_NAME.
+ *
+ * @NL80211_CMD_GET_INTERFACE: Request an interface's configuration;
+ * either a dump request on a %NL80211_ATTR_WIPHY or a specific get
+ * on an %NL80211_ATTR_IFINDEX is supported.
+ * @NL80211_CMD_SET_INTERFACE: Set type of a virtual interface, requires
+ * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_IFTYPE.
+ * @NL80211_CMD_NEW_INTERFACE: Newly created virtual interface or response
+ * to %NL80211_CMD_GET_INTERFACE. Has %NL80211_ATTR_IFINDEX,
+ * %NL80211_ATTR_WIPHY and %NL80211_ATTR_IFTYPE attributes. Can also
+ * be sent from userspace to request creation of a new virtual interface,
+ * then requires attributes %NL80211_ATTR_WIPHY, %NL80211_ATTR_IFTYPE and
+ * %NL80211_ATTR_IFNAME.
+ * @NL80211_CMD_DEL_INTERFACE: Virtual interface was deleted, has attributes
+ * %NL80211_ATTR_IFINDEX and %NL80211_ATTR_WIPHY. Can also be sent from
+ * userspace to request deletion of a virtual interface, then requires
+ * attribute %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_KEY: Get sequence counter information for a key specified
+ * by %NL80211_ATTR_KEY_IDX and/or %NL80211_ATTR_MAC.
+ * @NL80211_CMD_SET_KEY: Set key attributes %NL80211_ATTR_KEY_DEFAULT,
+ * %NL80211_ATTR_KEY_DEFAULT_MGMT, or %NL80211_ATTR_KEY_THRESHOLD.
+ * @NL80211_CMD_NEW_KEY: add a key with given %NL80211_ATTR_KEY_DATA,
+ * %NL80211_ATTR_KEY_IDX, %NL80211_ATTR_MAC, %NL80211_ATTR_KEY_CIPHER,
+ * and %NL80211_ATTR_KEY_SEQ attributes.
+ * @NL80211_CMD_DEL_KEY: delete a key identified by %NL80211_ATTR_KEY_IDX
+ * or %NL80211_ATTR_MAC.
+ *
+ * @NL80211_CMD_GET_BEACON: retrieve beacon information (returned in a
+ * %NL80222_CMD_NEW_BEACON message)
+ * @NL80211_CMD_SET_BEACON: set the beacon on an access point interface
+ * using the %NL80211_ATTR_BEACON_INTERVAL, %NL80211_ATTR_DTIM_PERIOD,
+ * %NL80211_ATTR_BEACON_HEAD and %NL80211_ATTR_BEACON_TAIL attributes.
+ * @NL80211_CMD_NEW_BEACON: add a new beacon to an access point interface,
+ * parameters are like for %NL80211_CMD_SET_BEACON.
+ * @NL80211_CMD_DEL_BEACON: remove the beacon, stop sending it
+ *
+ * @NL80211_CMD_GET_STATION: Get station attributes for station identified by
+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_STATION: Set station attributes for station identified by
+ * %NL80211_ATTR_MAC on the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_STATION: Add a station with given attributes to the
+ * the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_STATION: Remove a station identified by %NL80211_ATTR_MAC
+ * or, if no MAC address given, all stations, on the interface identified
+ * by %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_MPATH: Get mesh path attributes for mesh path to
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_MPATH: Set mesh path attributes for mesh path to
+ * destination %NL80211_ATTR_MAC on the interface identified by
+ * %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_NEW_PATH: Add a mesh path with given attributes to the
+ * the interface identified by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_DEL_PATH: Remove a mesh path identified by %NL80211_ATTR_MAC
+ * or, if no MAC address given, all mesh paths, on the interface identified
+ * by %NL80211_ATTR_IFINDEX.
+ * @NL80211_CMD_SET_BSS: Set BSS attributes for BSS identified by
+ * %NL80211_ATTR_IFINDEX.
+ *
+ * @NL80211_CMD_GET_REG: ask the wireless core to send us its currently set
+ * regulatory domain.
+ * @NL80211_CMD_SET_REG: Set current regulatory domain. CRDA sends this command
+ * after being queried by the kernel. CRDA replies by sending a regulatory
+ * domain structure which consists of %NL80211_ATTR_REG_ALPHA set to our
+ * current alpha2 if it found a match. It also provides
+ * NL80211_ATTR_REG_RULE_FLAGS, and a set of regulatory rules. Each
+ * regulatory rule is a nested set of attributes given by
+ * %NL80211_ATTR_REG_RULE_FREQ_[START|END] and
+ * %NL80211_ATTR_FREQ_RANGE_MAX_BW with an attached power rule given by
+ * %NL80211_ATTR_REG_RULE_POWER_MAX_ANT_GAIN and
+ * %NL80211_ATTR_REG_RULE_POWER_MAX_EIRP.
+ * @NL80211_CMD_REQ_SET_REG: ask the wireless core to set the regulatory domain
+ * to the the specified ISO/IEC 3166-1 alpha2 country code. The core will
+ * store this as a valid request and then query userspace for it.
+ *
+ * @NL80211_CMD_GET_MESH_PARAMS: Get mesh networking properties for the
+ * interface identified by %NL80211_ATTR_IFINDEX
+ *
+ * @NL80211_CMD_SET_MESH_PARAMS: Set mesh networking properties for the
+ * interface identified by %NL80211_ATTR_IFINDEX
+ *
+ * @NL80211_CMD_SET_MGMT_EXTRA_IE: Set extra IEs for management frames. The
+ * interface is identified with %NL80211_ATTR_IFINDEX and the management
+ * frame subtype with %NL80211_ATTR_MGMT_SUBTYPE. The extra IE data to be
+ * added to the end of the specified management frame is specified with
+ * %NL80211_ATTR_IE. If the command succeeds, the requested data will be
+ * added to all specified management frames generated by
+ * kernel/firmware/driver.
+ * Note: This command has been removed and it is only reserved at this
+ * point to avoid re-using existing command number. The functionality this
+ * command was planned for has been provided with cleaner design with the
+ * option to specify additional IEs in NL80211_CMD_TRIGGER_SCAN,
+ * NL80211_CMD_AUTHENTICATE, NL80211_CMD_ASSOCIATE,
+ * NL80211_CMD_DEAUTHENTICATE, and NL80211_CMD_DISASSOCIATE.
+ *
+ * @NL80211_CMD_GET_SCAN: get scan results
+ * @NL80211_CMD_TRIGGER_SCAN: trigger a new scan with the given parameters
+ * @NL80211_CMD_NEW_SCAN_RESULTS: scan notification (as a reply to
+ * NL80211_CMD_GET_SCAN and on the "scan" multicast group)
+ * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
+ * partial scan results may be available
+ *
+ * @NL80211_CMD_GET_SURVEY: get survey resuls, e.g. channel occupation
+ * or noise level
+ * @NL80211_CMD_NEW_SURVEY_RESULTS: survey data notification (as a reply to
+ * NL80211_CMD_GET_SURVEY and on the "scan" multicast group)
+ *
+ * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
+ * has been changed and provides details of the request information
+ * that caused the change such as who initiated the regulatory request
+ * (%NL80211_ATTR_REG_INITIATOR), the wiphy_idx
+ * (%NL80211_ATTR_REG_ALPHA2) on which the request was made from if
+ * the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or
+ * %NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain
+ * set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is
+ * %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on
+ * to (%NL80211_ATTR_REG_ALPHA2).
+ * @NL80211_CMD_REG_BEACON_HINT: indicates to userspace that an AP beacon
+ * has been found while world roaming thus enabling active scan or
+ * any mode of operation that initiates TX (beacons) on a channel
+ * where we would not have been able to do either before. As an example
+ * if you are world roaming (regulatory domain set to world or if your
+ * driver is using a custom world roaming regulatory domain) and while
+ * doing a passive scan on the 5 GHz band you find an AP there (if not
+ * on a DFS channel) you will now be able to actively scan for that AP
+ * or use AP mode on your card on that same channel. Note that this will
+ * never be used for channels 1-11 on the 2 GHz band as they are always
+ * enabled world wide. This beacon hint is only sent if your device had
+ * either disabled active scanning or beaconing on a channel. We send to
+ * userspace the wiphy on which we removed a restriction from
+ * (%NL80211_ATTR_WIPHY) and the channel on which this occurred
+ * before (%NL80211_ATTR_FREQ_BEFORE) and after (%NL80211_ATTR_FREQ_AFTER)
+ * the beacon hint was processed.
+ *
+ * @NL80211_CMD_AUTHENTICATE: authentication request and notification.
+ * This command is used both as a command (request to authenticate) and
+ * as an event on the "mlme" multicast group indicating completion of the
+ * authentication process.
+ * When used as a command, %NL80211_ATTR_IFINDEX is used to identify the
+ * interface. %NL80211_ATTR_MAC is used to specify PeerSTAAddress (and
+ * BSSID in case of station mode). %NL80211_ATTR_SSID is used to specify
+ * the SSID (mainly for association, but is included in authentication
+ * request, too, to help BSS selection. %NL80211_ATTR_WIPHY_FREQ is used
+ * to specify the frequence of the channel in MHz. %NL80211_ATTR_AUTH_TYPE
+ * is used to specify the authentication type. %NL80211_ATTR_IE is used to
+ * define IEs (VendorSpecificInfo, but also including RSN IE and FT IEs)
+ * to be added to the frame.
+ * When used as an event, this reports reception of an Authentication
+ * frame in station and IBSS modes when the local MLME processed the
+ * frame, i.e., it was for the local STA and was received in correct
+ * state. This is similar to MLME-AUTHENTICATE.confirm primitive in the
+ * MLME SAP interface (kernel providing MLME, userspace SME). The
+ * included %NL80211_ATTR_FRAME attribute contains the management frame
+ * (including both the header and frame body, but not FCS). This event is
+ * also used to indicate if the authentication attempt timed out. In that
+ * case the %NL80211_ATTR_FRAME attribute is replaced with a
+ * %NL80211_ATTR_TIMED_OUT flag (and %NL80211_ATTR_MAC to indicate which
+ * pending authentication timed out).
+ * @NL80211_CMD_ASSOCIATE: association request and notification; like
+ * NL80211_CMD_AUTHENTICATE but for Association and Reassociation
+ * (similar to MLME-ASSOCIATE.request, MLME-REASSOCIATE.request,
+ * MLME-ASSOCIATE.confirm or MLME-REASSOCIATE.confirm primitives).
+ * @NL80211_CMD_DEAUTHENTICATE: deauthentication request and notification; like
+ * NL80211_CMD_AUTHENTICATE but for Deauthentication frames (similar to
+ * MLME-DEAUTHENTICATION.request and MLME-DEAUTHENTICATE.indication
+ * primitives).
+ * @NL80211_CMD_DISASSOCIATE: disassociation request and notification; like
+ * NL80211_CMD_AUTHENTICATE but for Disassociation frames (similar to
+ * MLME-DISASSOCIATE.request and MLME-DISASSOCIATE.indication primitives).
+ *
+ * @NL80211_CMD_MICHAEL_MIC_FAILURE: notification of a locally detected Michael
+ * MIC (part of TKIP) failure; sent on the "mlme" multicast group; the
+ * event includes %NL80211_ATTR_MAC to describe the source MAC address of
+ * the frame with invalid MIC, %NL80211_ATTR_KEY_TYPE to show the key
+ * type, %NL80211_ATTR_KEY_IDX to indicate the key identifier, and
+ * %NL80211_ATTR_KEY_SEQ to indicate the TSC value of the frame; this
+ * event matches with MLME-MICHAELMICFAILURE.indication() primitive
+ *
+ * @NL80211_CMD_JOIN_IBSS: Join a new IBSS -- given at least an SSID and a
+ * FREQ attribute (for the initial frequency if no peer can be found)
+ * and optionally a MAC (as BSSID) and FREQ_FIXED attribute if those
+ * should be fixed rather than automatically determined. Can only be
+ * executed on a network interface that is UP, and fixed BSSID/FREQ
+ * may be rejected. Another optional parameter is the beacon interval,
+ * given in the %NL80211_ATTR_BEACON_INTERVAL attribute, which if not
+ * given defaults to 100 TU (102.4ms).
+ * @NL80211_CMD_LEAVE_IBSS: Leave the IBSS -- no special arguments, the IBSS is
+ * determined by the network interface.
+ *
+ * @NL80211_CMD_TESTMODE: testmode command, takes a wiphy (or ifindex) attribute
+ * to identify the device, and the TESTDATA blob attribute to pass through
+ * to the driver.
+ *
+ * @NL80211_CMD_CONNECT: connection request and notification; this command
+ * requests to connect to a specified network but without separating
+ * auth and assoc steps. For this, you need to specify the SSID in a
+ * %NL80211_ATTR_SSID attribute, and can optionally specify the association
+ * IEs in %NL80211_ATTR_IE, %NL80211_ATTR_AUTH_TYPE, %NL80211_ATTR_MAC,
+ * %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_CONTROL_PORT.
+ * It is also sent as an event, with the BSSID and response IEs when the
+ * connection is established or failed to be established. This can be
+ * determined by the STATUS_CODE attribute.
+ * @NL80211_CMD_ROAM: request that the card roam (currently not implemented),
+ * sent as an event when the card/driver roamed by itself.
+ * @NL80211_CMD_DISCONNECT: drop a given connection; also used to notify
+ * userspace that a connection was dropped by the AP or due to other
+ * reasons, for this the %NL80211_ATTR_DISCONNECTED_BY_AP and
+ * %NL80211_ATTR_REASON_CODE attributes are used.
+ *
+ * @NL80211_CMD_SET_WIPHY_NETNS: Set a wiphy's netns. Note that all devices
+ * associated with this wiphy must be down and will follow.
+ *
+ * @NL80211_CMD_MAX: highest used command number
+ * @__NL80211_CMD_AFTER_LAST: internal use
+ */
+enum nl80211_commands {
+/* don't change the order or add anything inbetween, this is ABI! */
+ NL80211_CMD_UNSPEC,
+
+ NL80211_CMD_GET_WIPHY, /* can dump */
+ NL80211_CMD_SET_WIPHY,
+ NL80211_CMD_NEW_WIPHY,
+ NL80211_CMD_DEL_WIPHY,
+
+ NL80211_CMD_GET_INTERFACE, /* can dump */
+ NL80211_CMD_SET_INTERFACE,
+ NL80211_CMD_NEW_INTERFACE,
+ NL80211_CMD_DEL_INTERFACE,
+
+ NL80211_CMD_GET_KEY,
+ NL80211_CMD_SET_KEY,
+ NL80211_CMD_NEW_KEY,
+ NL80211_CMD_DEL_KEY,
+
+ NL80211_CMD_GET_BEACON,
+ NL80211_CMD_SET_BEACON,
+ NL80211_CMD_NEW_BEACON,
+ NL80211_CMD_DEL_BEACON,
+
+ NL80211_CMD_GET_STATION,
+ NL80211_CMD_SET_STATION,
+ NL80211_CMD_NEW_STATION,
+ NL80211_CMD_DEL_STATION,
+
+ NL80211_CMD_GET_MPATH,
+ NL80211_CMD_SET_MPATH,
+ NL80211_CMD_NEW_MPATH,
+ NL80211_CMD_DEL_MPATH,
+
+ NL80211_CMD_SET_BSS,
+
+ NL80211_CMD_SET_REG,
+ NL80211_CMD_REQ_SET_REG,
+
+ NL80211_CMD_GET_MESH_PARAMS,
+ NL80211_CMD_SET_MESH_PARAMS,
+
+ NL80211_CMD_SET_MGMT_EXTRA_IE /* reserved; not used */,
+
+ NL80211_CMD_GET_REG,
+
+ NL80211_CMD_GET_SCAN,
+ NL80211_CMD_TRIGGER_SCAN,
+ NL80211_CMD_NEW_SCAN_RESULTS,
+ NL80211_CMD_SCAN_ABORTED,
+
+ NL80211_CMD_REG_CHANGE,
+
+ NL80211_CMD_AUTHENTICATE,
+ NL80211_CMD_ASSOCIATE,
+ NL80211_CMD_DEAUTHENTICATE,
+ NL80211_CMD_DISASSOCIATE,
+
+ NL80211_CMD_MICHAEL_MIC_FAILURE,
+
+ NL80211_CMD_REG_BEACON_HINT,
+
+ NL80211_CMD_JOIN_IBSS,
+ NL80211_CMD_LEAVE_IBSS,
+
+ NL80211_CMD_TESTMODE,
+
+ NL80211_CMD_CONNECT,
+ NL80211_CMD_ROAM,
+ NL80211_CMD_DISCONNECT,
+
+ NL80211_CMD_SET_WIPHY_NETNS,
+
+ NL80211_CMD_GET_SURVEY,
+ NL80211_CMD_NEW_SURVEY_RESULTS,
+
+ /* add new commands above here */
+
+ /* used to define NL80211_CMD_MAX below */
+ __NL80211_CMD_AFTER_LAST,
+ NL80211_CMD_MAX = __NL80211_CMD_AFTER_LAST - 1
+};
+
+/*
+ * Allow user space programs to use #ifdef on new commands by defining them
+ * here
+ */
+#define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS
+#define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE
+#define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE
+#define NL80211_CMD_AUTHENTICATE NL80211_CMD_AUTHENTICATE
+#define NL80211_CMD_ASSOCIATE NL80211_CMD_ASSOCIATE
+#define NL80211_CMD_DEAUTHENTICATE NL80211_CMD_DEAUTHENTICATE
+#define NL80211_CMD_DISASSOCIATE NL80211_CMD_DISASSOCIATE
+#define NL80211_CMD_REG_BEACON_HINT NL80211_CMD_REG_BEACON_HINT
+
+/**
+ * enum nl80211_attrs - nl80211 netlink attributes
+ *
+ * @NL80211_ATTR_UNSPEC: unspecified attribute to catch errors
+ *
+ * @NL80211_ATTR_WIPHY: index of wiphy to operate on, cf.
+ * /sys/class/ieee80211/<phyname>/index
+ * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
+ * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
+ * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
+ * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
+ * if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
+ * NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including
+ * this attribute)
+ * NL80211_CHAN_HT20 = HT20 only
+ * NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
+ * NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
+ * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is
+ * less than or equal to the RTS threshold; allowed range: 1..255;
+ * dot11ShortRetryLimit; u8
+ * @NL80211_ATTR_WIPHY_RETRY_LONG: TX retry limit for frames whose length is
+ * greater than the RTS threshold; allowed range: 1..255;
+ * dot11ShortLongLimit; u8
+ * @NL80211_ATTR_WIPHY_FRAG_THRESHOLD: fragmentation threshold, i.e., maximum
+ * length in octets for frames; allowed range: 256..8000, disable
+ * fragmentation with (u32)-1; dot11FragmentationThreshold; u32
+ * @NL80211_ATTR_WIPHY_RTS_THRESHOLD: RTS threshold (TX frames with length
+ * larger than or equal to this use RTS/CTS handshake); allowed range:
+ * 0..65536, disable with (u32)-1; dot11RTSThreshold; u32
+ *
+ * @NL80211_ATTR_IFINDEX: network interface index of the device to operate on
+ * @NL80211_ATTR_IFNAME: network interface name
+ * @NL80211_ATTR_IFTYPE: type of virtual interface, see &enum nl80211_iftype
+ *
+ * @NL80211_ATTR_MAC: MAC address (various uses)
+ *
+ * @NL80211_ATTR_KEY_DATA: (temporal) key data; for TKIP this consists of
+ * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ * keys
+ * @NL80211_ATTR_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_ATTR_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ * section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_ATTR_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ * CCMP keys, each six bytes in little endian
+ *
+ * @NL80211_ATTR_BEACON_INTERVAL: beacon interval in TU
+ * @NL80211_ATTR_DTIM_PERIOD: DTIM period for beaconing
+ * @NL80211_ATTR_BEACON_HEAD: portion of the beacon before the TIM IE
+ * @NL80211_ATTR_BEACON_TAIL: portion of the beacon after the TIM IE
+ *
+ * @NL80211_ATTR_STA_AID: Association ID for the station (u16)
+ * @NL80211_ATTR_STA_FLAGS: flags, nested element with NLA_FLAG attributes of
+ * &enum nl80211_sta_flags (deprecated, use %NL80211_ATTR_STA_FLAGS2)
+ * @NL80211_ATTR_STA_LISTEN_INTERVAL: listen interval as defined by
+ * IEEE 802.11 7.3.1.6 (u16).
+ * @NL80211_ATTR_STA_SUPPORTED_RATES: supported rates, array of supported
+ * rates as defined by IEEE 802.11 7.3.2.2 but without the length
+ * restriction (at most %NL80211_MAX_SUPP_RATES).
+ * @NL80211_ATTR_STA_VLAN: interface index of VLAN interface to move station
+ * to, or the AP interface the station was originally added to to.
+ * @NL80211_ATTR_STA_INFO: information about a station, part of station info
+ * given for %NL80211_CMD_GET_STATION, nested attribute containing
+ * info as possible, see &enum nl80211_sta_info.
+ *
+ * @NL80211_ATTR_WIPHY_BANDS: Information about an operating bands,
+ * consisting of a nested array.
+ *
+ * @NL80211_ATTR_MESH_ID: mesh id (1-32 bytes).
+ * @NL80211_ATTR_PLINK_ACTION: action to perform on the mesh peer link.
+ * @NL80211_ATTR_MPATH_NEXT_HOP: MAC address of the next hop for a mesh path.
+ * @NL80211_ATTR_MPATH_INFO: information about a mesh_path, part of mesh path
+ * info given for %NL80211_CMD_GET_MPATH, nested attribute described at
+ * &enum nl80211_mpath_info.
+ *
+ * @NL80211_ATTR_MNTR_FLAGS: flags, nested element with NLA_FLAG attributes of
+ * &enum nl80211_mntr_flags.
+ *
+ * @NL80211_ATTR_REG_ALPHA2: an ISO-3166-alpha2 country code for which the
+ * current regulatory domain should be set to or is already set to.
+ * For example, 'CR', for Costa Rica. This attribute is used by the kernel
+ * to query the CRDA to retrieve one regulatory domain. This attribute can
+ * also be used by userspace to query the kernel for the currently set
+ * regulatory domain. We chose an alpha2 as that is also used by the
+ * IEEE-802.11d country information element to identify a country.
+ * Users can also simply ask the wireless core to set regulatory domain
+ * to a specific alpha2.
+ * @NL80211_ATTR_REG_RULES: a nested array of regulatory domain regulatory
+ * rules.
+ *
+ * @NL80211_ATTR_BSS_CTS_PROT: whether CTS protection is enabled (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_SHORT_PREAMBLE: whether short preamble is enabled
+ * (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_SHORT_SLOT_TIME: whether short slot time enabled
+ * (u8, 0 or 1)
+ * @NL80211_ATTR_BSS_BASIC_RATES: basic rates, array of basic
+ * rates in format defined by IEEE 802.11 7.3.2.2 but without the length
+ * restriction (at most %NL80211_MAX_SUPP_RATES).
+ *
+ * @NL80211_ATTR_HT_CAPABILITY: HT Capability information element (from
+ * association request when used with NL80211_CMD_NEW_STATION)
+ *
+ * @NL80211_ATTR_SUPPORTED_IFTYPES: nested attribute containing all
+ * supported interface types, each a flag attribute with the number
+ * of the interface mode.
+ *
+ * @NL80211_ATTR_MGMT_SUBTYPE: Management frame subtype for
+ * %NL80211_CMD_SET_MGMT_EXTRA_IE.
+ *
+ * @NL80211_ATTR_IE: Information element(s) data (used, e.g., with
+ * %NL80211_CMD_SET_MGMT_EXTRA_IE).
+ *
+ * @NL80211_ATTR_MAX_NUM_SCAN_SSIDS: number of SSIDs you can scan with
+ * a single scan request, a wiphy attribute.
+ * @NL80211_ATTR_MAX_SCAN_IE_LEN: maximum length of information elements
+ * that can be added to a scan request
+ *
+ * @NL80211_ATTR_SCAN_FREQUENCIES: nested attribute with frequencies (in MHz)
+ * @NL80211_ATTR_SCAN_SSIDS: nested attribute with SSIDs, leave out for passive
+ * scanning and include a zero-length SSID (wildcard) for wildcard scan
+ * @NL80211_ATTR_BSS: scan result BSS
+ *
+ * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain
+ * currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_*
+ * @NL80211_ATTR_REG_TYPE: indicates the type of the regulatory domain currently
+ * set. This can be one of the nl80211_reg_type (%NL80211_REGDOM_TYPE_*)
+ *
+ * @NL80211_ATTR_SUPPORTED_COMMANDS: wiphy attribute that specifies
+ * an array of command numbers (i.e. a mapping index to command number)
+ * that the driver for the given wiphy supports.
+ *
+ * @NL80211_ATTR_FRAME: frame data (binary attribute), including frame header
+ * and body, but not FCS; used, e.g., with NL80211_CMD_AUTHENTICATE and
+ * NL80211_CMD_ASSOCIATE events
+ * @NL80211_ATTR_SSID: SSID (binary attribute, 0..32 octets)
+ * @NL80211_ATTR_AUTH_TYPE: AuthenticationType, see &enum nl80211_auth_type,
+ * represented as a u32
+ * @NL80211_ATTR_REASON_CODE: ReasonCode for %NL80211_CMD_DEAUTHENTICATE and
+ * %NL80211_CMD_DISASSOCIATE, u16
+ *
+ * @NL80211_ATTR_KEY_TYPE: Key Type, see &enum nl80211_key_type, represented as
+ * a u32
+ *
+ * @NL80211_ATTR_FREQ_BEFORE: A channel which has suffered a regulatory change
+ * due to considerations from a beacon hint. This attribute reflects
+ * the state of the channel _before_ the beacon hint processing. This
+ * attributes consists of a nested attribute containing
+ * NL80211_FREQUENCY_ATTR_*
+ * @NL80211_ATTR_FREQ_AFTER: A channel which has suffered a regulatory change
+ * due to considerations from a beacon hint. This attribute reflects
+ * the state of the channel _after_ the beacon hint processing. This
+ * attributes consists of a nested attribute containing
+ * NL80211_FREQUENCY_ATTR_*
+ *
+ * @NL80211_ATTR_CIPHER_SUITES: a set of u32 values indicating the supported
+ * cipher suites
+ *
+ * @NL80211_ATTR_FREQ_FIXED: a flag indicating the IBSS should not try to look
+ * for other networks on different channels
+ *
+ * @NL80211_ATTR_TIMED_OUT: a flag indicating than an operation timed out; this
+ * is used, e.g., with %NL80211_CMD_AUTHENTICATE event
+ *
+ * @NL80211_ATTR_USE_MFP: Whether management frame protection (IEEE 802.11w) is
+ * used for the association (&enum nl80211_mfp, represented as a u32);
+ * this attribute can be used
+ * with %NL80211_CMD_ASSOCIATE request
+ *
+ * @NL80211_ATTR_STA_FLAGS2: Attribute containing a
+ * &struct nl80211_sta_flag_update.
+ *
+ * @NL80211_ATTR_CONTROL_PORT: A flag indicating whether user space controls
+ * IEEE 802.1X port, i.e., sets/clears %NL80211_STA_FLAG_AUTHORIZED, in
+ * station mode. If the flag is included in %NL80211_CMD_ASSOCIATE
+ * request, the driver will assume that the port is unauthorized until
+ * authorized by user space. Otherwise, port is marked authorized by
+ * default in station mode.
+ *
+ * @NL80211_ATTR_TESTDATA: Testmode data blob, passed through to the driver.
+ * We recommend using nested, driver-specific attributes within this.
+ *
+ * @NL80211_ATTR_DISCONNECTED_BY_AP: A flag indicating that the DISCONNECT
+ * event was due to the AP disconnecting the station, and not due to
+ * a local disconnect request.
+ * @NL80211_ATTR_STATUS_CODE: StatusCode for the %NL80211_CMD_CONNECT
+ * event (u16)
+ * @NL80211_ATTR_PRIVACY: Flag attribute, used with connect(), indicating
+ * that protected APs should be used.
+ *
+ * @NL80211_ATTR_CIPHERS_PAIRWISE: Used with CONNECT and ASSOCIATE to
+ * indicate which unicast key ciphers will be used with the connection
+ * (an array of u32).
+ * @NL80211_ATTR_CIPHER_GROUP: Used with CONNECT and ASSOCIATE to indicate
+ * which group key cipher will be used with the connection (a u32).
+ * @NL80211_ATTR_WPA_VERSIONS: Used with CONNECT and ASSOCIATE to indicate
+ * which WPA version(s) the AP we want to associate with is using
+ * (a u32 with flags from &enum nl80211_wpa_versions).
+ * @NL80211_ATTR_AKM_SUITES: Used with CONNECT and ASSOCIATE to indicate
+ * which key management algorithm(s) to use (an array of u32).
+ *
+ * @NL80211_ATTR_REQ_IE: (Re)association request information elements as
+ * sent out by the card, for ROAM and successful CONNECT events.
+ * @NL80211_ATTR_RESP_IE: (Re)association response information elements as
+ * sent by peer, for ROAM and successful CONNECT events.
+ *
+ * @NL80211_ATTR_PREV_BSSID: previous BSSID, to be used by in ASSOCIATE
+ * commands to specify using a reassociate frame
+ *
+ * @NL80211_ATTR_KEY: key information in a nested attribute with
+ * %NL80211_KEY_* sub-attributes
+ * @NL80211_ATTR_KEYS: array of keys for static WEP keys for connect()
+ * and join_ibss(), key information is in a nested attribute each
+ * with %NL80211_KEY_* sub-attributes
+ *
+ * @NL80211_ATTR_PID: Process ID of a network namespace.
+ *
+ * @NL80211_ATTR_GENERATION: Used to indicate consistent snapshots for
+ * dumps. This number increases whenever the object list being
+ * dumped changes, and as such userspace can verify that it has
+ * obtained a complete and consistent snapshot by verifying that
+ * all dump messages contain the same generation number. If it
+ * changed then the list changed and the dump should be repeated
+ * completely from scratch.
+ *
+ * @NL80211_ATTR_4ADDR: Use 4-address frames on a virtual interface
+ *
+ * @NL80211_ATTR_SURVEY_INFO: survey information about a channel, part of
+ * the survey response for %NL80211_CMD_GET_SURVEY, nested attribute
+ * containing info as possible, see &enum survey_info.
+ *
+ * @NL80211_ATTR_MAX: highest attribute number currently defined
+ * @__NL80211_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_attrs {
+/* don't change the order or add anything inbetween, this is ABI! */
+ NL80211_ATTR_UNSPEC,
+
+ NL80211_ATTR_WIPHY,
+ NL80211_ATTR_WIPHY_NAME,
+
+ NL80211_ATTR_IFINDEX,
+ NL80211_ATTR_IFNAME,
+ NL80211_ATTR_IFTYPE,
+
+ NL80211_ATTR_MAC,
+
+ NL80211_ATTR_KEY_DATA,
+ NL80211_ATTR_KEY_IDX,
+ NL80211_ATTR_KEY_CIPHER,
+ NL80211_ATTR_KEY_SEQ,
+ NL80211_ATTR_KEY_DEFAULT,
+
+ NL80211_ATTR_BEACON_INTERVAL,
+ NL80211_ATTR_DTIM_PERIOD,
+ NL80211_ATTR_BEACON_HEAD,
+ NL80211_ATTR_BEACON_TAIL,
+
+ NL80211_ATTR_STA_AID,
+ NL80211_ATTR_STA_FLAGS,
+ NL80211_ATTR_STA_LISTEN_INTERVAL,
+ NL80211_ATTR_STA_SUPPORTED_RATES,
+ NL80211_ATTR_STA_VLAN,
+ NL80211_ATTR_STA_INFO,
+
+ NL80211_ATTR_WIPHY_BANDS,
+
+ NL80211_ATTR_MNTR_FLAGS,
+
+ NL80211_ATTR_MESH_ID,
+ NL80211_ATTR_STA_PLINK_ACTION,
+ NL80211_ATTR_MPATH_NEXT_HOP,
+ NL80211_ATTR_MPATH_INFO,
+
+ NL80211_ATTR_BSS_CTS_PROT,
+ NL80211_ATTR_BSS_SHORT_PREAMBLE,
+ NL80211_ATTR_BSS_SHORT_SLOT_TIME,
+
+ NL80211_ATTR_HT_CAPABILITY,
+
+ NL80211_ATTR_SUPPORTED_IFTYPES,
+
+ NL80211_ATTR_REG_ALPHA2,
+ NL80211_ATTR_REG_RULES,
+
+ NL80211_ATTR_MESH_PARAMS,
+
+ NL80211_ATTR_BSS_BASIC_RATES,
+
+ NL80211_ATTR_WIPHY_TXQ_PARAMS,
+ NL80211_ATTR_WIPHY_FREQ,
+ NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+
+ NL80211_ATTR_KEY_DEFAULT_MGMT,
+
+ NL80211_ATTR_MGMT_SUBTYPE,
+ NL80211_ATTR_IE,
+
+ NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
+
+ NL80211_ATTR_SCAN_FREQUENCIES,
+ NL80211_ATTR_SCAN_SSIDS,
+ NL80211_ATTR_GENERATION, /* replaces old SCAN_GENERATION */
+ NL80211_ATTR_BSS,
+
+ NL80211_ATTR_REG_INITIATOR,
+ NL80211_ATTR_REG_TYPE,
+
+ NL80211_ATTR_SUPPORTED_COMMANDS,
+
+ NL80211_ATTR_FRAME,
+ NL80211_ATTR_SSID,
+ NL80211_ATTR_AUTH_TYPE,
+ NL80211_ATTR_REASON_CODE,
+
+ NL80211_ATTR_KEY_TYPE,
+
+ NL80211_ATTR_MAX_SCAN_IE_LEN,
+ NL80211_ATTR_CIPHER_SUITES,
+
+ NL80211_ATTR_FREQ_BEFORE,
+ NL80211_ATTR_FREQ_AFTER,
+
+ NL80211_ATTR_FREQ_FIXED,
+
+
+ NL80211_ATTR_WIPHY_RETRY_SHORT,
+ NL80211_ATTR_WIPHY_RETRY_LONG,
+ NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
+ NL80211_ATTR_WIPHY_RTS_THRESHOLD,
+
+ NL80211_ATTR_TIMED_OUT,
+
+ NL80211_ATTR_USE_MFP,
+
+ NL80211_ATTR_STA_FLAGS2,
+
+ NL80211_ATTR_CONTROL_PORT,
+
+ NL80211_ATTR_TESTDATA,
+
+ NL80211_ATTR_PRIVACY,
+
+ NL80211_ATTR_DISCONNECTED_BY_AP,
+ NL80211_ATTR_STATUS_CODE,
+
+ NL80211_ATTR_CIPHER_SUITES_PAIRWISE,
+ NL80211_ATTR_CIPHER_SUITE_GROUP,
+ NL80211_ATTR_WPA_VERSIONS,
+ NL80211_ATTR_AKM_SUITES,
+
+ NL80211_ATTR_REQ_IE,
+ NL80211_ATTR_RESP_IE,
+
+ NL80211_ATTR_PREV_BSSID,
+
+ NL80211_ATTR_KEY,
+ NL80211_ATTR_KEYS,
+
+ NL80211_ATTR_PID,
+
+ NL80211_ATTR_4ADDR,
+
+ NL80211_ATTR_SURVEY_INFO,
+
+ /* add attributes here, update the policy in nl80211.c */
+
+ __NL80211_ATTR_AFTER_LAST,
+ NL80211_ATTR_MAX = __NL80211_ATTR_AFTER_LAST - 1
+};
+
+/* source-level API compatibility */
+#define NL80211_ATTR_SCAN_GENERATION NL80211_ATTR_GENERATION
+
+/*
+ * Allow user space programs to use #ifdef on new attributes by defining them
+ * here
+ */
+#define NL80211_CMD_CONNECT NL80211_CMD_CONNECT
+#define NL80211_ATTR_HT_CAPABILITY NL80211_ATTR_HT_CAPABILITY
+#define NL80211_ATTR_BSS_BASIC_RATES NL80211_ATTR_BSS_BASIC_RATES
+#define NL80211_ATTR_WIPHY_TXQ_PARAMS NL80211_ATTR_WIPHY_TXQ_PARAMS
+#define NL80211_ATTR_WIPHY_FREQ NL80211_ATTR_WIPHY_FREQ
+#define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE
+#define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE
+#define NL80211_ATTR_IE NL80211_ATTR_IE
+#define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR
+#define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE
+#define NL80211_ATTR_FRAME NL80211_ATTR_FRAME
+#define NL80211_ATTR_SSID NL80211_ATTR_SSID
+#define NL80211_ATTR_AUTH_TYPE NL80211_ATTR_AUTH_TYPE
+#define NL80211_ATTR_REASON_CODE NL80211_ATTR_REASON_CODE
+#define NL80211_ATTR_CIPHER_SUITES_PAIRWISE NL80211_ATTR_CIPHER_SUITES_PAIRWISE
+#define NL80211_ATTR_CIPHER_SUITE_GROUP NL80211_ATTR_CIPHER_SUITE_GROUP
+#define NL80211_ATTR_WPA_VERSIONS NL80211_ATTR_WPA_VERSIONS
+#define NL80211_ATTR_AKM_SUITES NL80211_ATTR_AKM_SUITES
+#define NL80211_ATTR_KEY NL80211_ATTR_KEY
+#define NL80211_ATTR_KEYS NL80211_ATTR_KEYS
+
+#define NL80211_MAX_SUPP_RATES 32
+#define NL80211_MAX_SUPP_REG_RULES 32
+#define NL80211_TKIP_DATA_OFFSET_ENCR_KEY 0
+#define NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY 16
+#define NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY 24
+#define NL80211_HT_CAPABILITY_LEN 26
+
+#define NL80211_MAX_NR_CIPHER_SUITES 5
+#define NL80211_MAX_NR_AKM_SUITES 2
+
+/**
+ * enum nl80211_iftype - (virtual) interface types
+ *
+ * @NL80211_IFTYPE_UNSPECIFIED: unspecified type, driver decides
+ * @NL80211_IFTYPE_ADHOC: independent BSS member
+ * @NL80211_IFTYPE_STATION: managed BSS member
+ * @NL80211_IFTYPE_AP: access point
+ * @NL80211_IFTYPE_AP_VLAN: VLAN interface for access points
+ * @NL80211_IFTYPE_WDS: wireless distribution interface
+ * @NL80211_IFTYPE_MONITOR: monitor interface receiving all frames
+ * @NL80211_IFTYPE_MESH_POINT: mesh point
+ * @NL80211_IFTYPE_MAX: highest interface type number currently defined
+ * @__NL80211_IFTYPE_AFTER_LAST: internal use
+ *
+ * These values are used with the %NL80211_ATTR_IFTYPE
+ * to set the type of an interface.
+ *
+ */
+enum nl80211_iftype {
+ NL80211_IFTYPE_UNSPECIFIED,
+ NL80211_IFTYPE_ADHOC,
+ NL80211_IFTYPE_STATION,
+ NL80211_IFTYPE_AP,
+ NL80211_IFTYPE_AP_VLAN,
+ NL80211_IFTYPE_WDS,
+ NL80211_IFTYPE_MONITOR,
+ NL80211_IFTYPE_MESH_POINT,
+
+ /* keep last */
+ __NL80211_IFTYPE_AFTER_LAST,
+ NL80211_IFTYPE_MAX = __NL80211_IFTYPE_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_sta_flags - station flags
+ *
+ * Station flags. When a station is added to an AP interface, it is
+ * assumed to be already associated (and hence authenticated.)
+ *
+ * @NL80211_STA_FLAG_AUTHORIZED: station is authorized (802.1X)
+ * @NL80211_STA_FLAG_SHORT_PREAMBLE: station is capable of receiving frames
+ * with short barker preamble
+ * @NL80211_STA_FLAG_WME: station is WME/QoS capable
+ * @NL80211_STA_FLAG_MFP: station uses management frame protection
+ */
+enum nl80211_sta_flags {
+ __NL80211_STA_FLAG_INVALID,
+ NL80211_STA_FLAG_AUTHORIZED,
+ NL80211_STA_FLAG_SHORT_PREAMBLE,
+ NL80211_STA_FLAG_WME,
+ NL80211_STA_FLAG_MFP,
+
+ /* keep last */
+ __NL80211_STA_FLAG_AFTER_LAST,
+ NL80211_STA_FLAG_MAX = __NL80211_STA_FLAG_AFTER_LAST - 1
+};
+
+/**
+ * struct nl80211_sta_flag_update - station flags mask/set
+ * @mask: mask of station flags to set
+ * @set: which values to set them to
+ *
+ * Both mask and set contain bits as per &enum nl80211_sta_flags.
+ */
+struct nl80211_sta_flag_update {
+ __u32 mask;
+ __u32 set;
+} __attribute__((packed));
+
+/**
+ * enum nl80211_rate_info - bitrate information
+ *
+ * These attribute types are used with %NL80211_STA_INFO_TXRATE
+ * when getting information about the bitrate of a station.
+ *
+ * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
+ * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
+ * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
+ * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
+ * @__NL80211_RATE_INFO_AFTER_LAST: internal use
+ */
+enum nl80211_rate_info {
+ __NL80211_RATE_INFO_INVALID,
+ NL80211_RATE_INFO_BITRATE,
+ NL80211_RATE_INFO_MCS,
+ NL80211_RATE_INFO_40_MHZ_WIDTH,
+ NL80211_RATE_INFO_SHORT_GI,
+
+ /* keep last */
+ __NL80211_RATE_INFO_AFTER_LAST,
+ NL80211_RATE_INFO_MAX = __NL80211_RATE_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_sta_info - station information
+ *
+ * These attribute types are used with %NL80211_ATTR_STA_INFO
+ * when getting information about a station.
+ *
+ * @__NL80211_STA_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_STA_INFO_INACTIVE_TIME: time since last activity (u32, msecs)
+ * @NL80211_STA_INFO_RX_BYTES: total received bytes (u32, from this station)
+ * @NL80211_STA_INFO_TX_BYTES: total transmitted bytes (u32, to this station)
+ * @__NL80211_STA_INFO_AFTER_LAST: internal
+ * @NL80211_STA_INFO_MAX: highest possible station info attribute
+ * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
+ * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
+ * containing info as possible, see &enum nl80211_sta_info_txrate.
+ * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
+ * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
+ * station)
+ */
+enum nl80211_sta_info {
+ __NL80211_STA_INFO_INVALID,
+ NL80211_STA_INFO_INACTIVE_TIME,
+ NL80211_STA_INFO_RX_BYTES,
+ NL80211_STA_INFO_TX_BYTES,
+ NL80211_STA_INFO_LLID,
+ NL80211_STA_INFO_PLID,
+ NL80211_STA_INFO_PLINK_STATE,
+ NL80211_STA_INFO_SIGNAL,
+ NL80211_STA_INFO_TX_BITRATE,
+ NL80211_STA_INFO_RX_PACKETS,
+ NL80211_STA_INFO_TX_PACKETS,
+
+ /* keep last */
+ __NL80211_STA_INFO_AFTER_LAST,
+ NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mpath_flags - nl80211 mesh path flags
+ *
+ * @NL80211_MPATH_FLAG_ACTIVE: the mesh path is active
+ * @NL80211_MPATH_FLAG_RESOLVING: the mesh path discovery process is running
+ * @NL80211_MPATH_FLAG_SN_VALID: the mesh path contains a valid SN
+ * @NL80211_MPATH_FLAG_FIXED: the mesh path has been manually set
+ * @NL80211_MPATH_FLAG_RESOLVED: the mesh path discovery process succeeded
+ */
+enum nl80211_mpath_flags {
+ NL80211_MPATH_FLAG_ACTIVE = 1<<0,
+ NL80211_MPATH_FLAG_RESOLVING = 1<<1,
+ NL80211_MPATH_FLAG_SN_VALID = 1<<2,
+ NL80211_MPATH_FLAG_FIXED = 1<<3,
+ NL80211_MPATH_FLAG_RESOLVED = 1<<4,
+};
+
+/**
+ * enum nl80211_mpath_info - mesh path information
+ *
+ * These attribute types are used with %NL80211_ATTR_MPATH_INFO when getting
+ * information about a mesh path.
+ *
+ * @__NL80211_MPATH_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_ATTR_MPATH_FRAME_QLEN: number of queued frames for this destination
+ * @NL80211_ATTR_MPATH_SN: destination sequence number
+ * @NL80211_ATTR_MPATH_METRIC: metric (cost) of this mesh path
+ * @NL80211_ATTR_MPATH_EXPTIME: expiration time for the path, in msec from now
+ * @NL80211_ATTR_MPATH_FLAGS: mesh path flags, enumerated in
+ * &enum nl80211_mpath_flags;
+ * @NL80211_ATTR_MPATH_DISCOVERY_TIMEOUT: total path discovery timeout, in msec
+ * @NL80211_ATTR_MPATH_DISCOVERY_RETRIES: mesh path discovery retries
+ */
+enum nl80211_mpath_info {
+ __NL80211_MPATH_INFO_INVALID,
+ NL80211_MPATH_INFO_FRAME_QLEN,
+ NL80211_MPATH_INFO_SN,
+ NL80211_MPATH_INFO_METRIC,
+ NL80211_MPATH_INFO_EXPTIME,
+ NL80211_MPATH_INFO_FLAGS,
+ NL80211_MPATH_INFO_DISCOVERY_TIMEOUT,
+ NL80211_MPATH_INFO_DISCOVERY_RETRIES,
+
+ /* keep last */
+ __NL80211_MPATH_INFO_AFTER_LAST,
+ NL80211_MPATH_INFO_MAX = __NL80211_MPATH_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_band_attr - band attributes
+ * @__NL80211_BAND_ATTR_INVALID: attribute number 0 is reserved
+ * @NL80211_BAND_ATTR_FREQS: supported frequencies in this band,
+ * an array of nested frequency attributes
+ * @NL80211_BAND_ATTR_RATES: supported bitrates in this band,
+ * an array of nested bitrate attributes
+ * @NL80211_BAND_ATTR_HT_MCS_SET: 16-byte attribute containing the MCS set as
+ * defined in 802.11n
+ * @NL80211_BAND_ATTR_HT_CAPA: HT capabilities, as in the HT information IE
+ * @NL80211_BAND_ATTR_HT_AMPDU_FACTOR: A-MPDU factor, as in 11n
+ * @NL80211_BAND_ATTR_HT_AMPDU_DENSITY: A-MPDU density, as in 11n
+ */
+enum nl80211_band_attr {
+ __NL80211_BAND_ATTR_INVALID,
+ NL80211_BAND_ATTR_FREQS,
+ NL80211_BAND_ATTR_RATES,
+
+ NL80211_BAND_ATTR_HT_MCS_SET,
+ NL80211_BAND_ATTR_HT_CAPA,
+ NL80211_BAND_ATTR_HT_AMPDU_FACTOR,
+ NL80211_BAND_ATTR_HT_AMPDU_DENSITY,
+
+ /* keep last */
+ __NL80211_BAND_ATTR_AFTER_LAST,
+ NL80211_BAND_ATTR_MAX = __NL80211_BAND_ATTR_AFTER_LAST - 1
+};
+
+#define NL80211_BAND_ATTR_HT_CAPA NL80211_BAND_ATTR_HT_CAPA
+
+/**
+ * enum nl80211_frequency_attr - frequency attributes
+ * @NL80211_FREQUENCY_ATTR_FREQ: Frequency in MHz
+ * @NL80211_FREQUENCY_ATTR_DISABLED: Channel is disabled in current
+ * regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_PASSIVE_SCAN: Only passive scanning is
+ * permitted on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_NO_IBSS: IBSS networks are not permitted
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_RADAR: Radar detection is mandatory
+ * on this channel in current regulatory domain.
+ * @NL80211_FREQUENCY_ATTR_MAX_TX_POWER: Maximum transmission power in mBm
+ * (100 * dBm).
+ */
+enum nl80211_frequency_attr {
+ __NL80211_FREQUENCY_ATTR_INVALID,
+ NL80211_FREQUENCY_ATTR_FREQ,
+ NL80211_FREQUENCY_ATTR_DISABLED,
+ NL80211_FREQUENCY_ATTR_PASSIVE_SCAN,
+ NL80211_FREQUENCY_ATTR_NO_IBSS,
+ NL80211_FREQUENCY_ATTR_RADAR,
+ NL80211_FREQUENCY_ATTR_MAX_TX_POWER,
+
+ /* keep last */
+ __NL80211_FREQUENCY_ATTR_AFTER_LAST,
+ NL80211_FREQUENCY_ATTR_MAX = __NL80211_FREQUENCY_ATTR_AFTER_LAST - 1
+};
+
+#define NL80211_FREQUENCY_ATTR_MAX_TX_POWER NL80211_FREQUENCY_ATTR_MAX_TX_POWER
+
+/**
+ * enum nl80211_bitrate_attr - bitrate attributes
+ * @NL80211_BITRATE_ATTR_RATE: Bitrate in units of 100 kbps
+ * @NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE: Short preamble supported
+ * in 2.4 GHz band.
+ */
+enum nl80211_bitrate_attr {
+ __NL80211_BITRATE_ATTR_INVALID,
+ NL80211_BITRATE_ATTR_RATE,
+ NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE,
+
+ /* keep last */
+ __NL80211_BITRATE_ATTR_AFTER_LAST,
+ NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_initiator - Indicates the initiator of a reg domain request
+ * @NL80211_REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world
+ * regulatory domain.
+ * @NL80211_REGDOM_SET_BY_USER: User asked the wireless core to set the
+ * regulatory domain.
+ * @NL80211_REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the
+ * wireless core it thinks its knows the regulatory domain we should be in.
+ * @NL80211_REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an
+ * 802.11 country information element with regulatory information it
+ * thinks we should consider.
+ */
+enum nl80211_reg_initiator {
+ NL80211_REGDOM_SET_BY_CORE,
+ NL80211_REGDOM_SET_BY_USER,
+ NL80211_REGDOM_SET_BY_DRIVER,
+ NL80211_REGDOM_SET_BY_COUNTRY_IE,
+};
+
+/**
+ * enum nl80211_reg_type - specifies the type of regulatory domain
+ * @NL80211_REGDOM_TYPE_COUNTRY: the regulatory domain set is one that pertains
+ * to a specific country. When this is set you can count on the
+ * ISO / IEC 3166 alpha2 country code being valid.
+ * @NL80211_REGDOM_TYPE_WORLD: the regulatory set domain is the world regulatory
+ * domain.
+ * @NL80211_REGDOM_TYPE_CUSTOM_WORLD: the regulatory domain set is a custom
+ * driver specific world regulatory domain. These do not apply system-wide
+ * and are only applicable to the individual devices which have requested
+ * them to be applied.
+ * @NL80211_REGDOM_TYPE_INTERSECTION: the regulatory domain set is the product
+ * of an intersection between two regulatory domains -- the previously
+ * set regulatory domain on the system and the last accepted regulatory
+ * domain request to be processed.
+ */
+enum nl80211_reg_type {
+ NL80211_REGDOM_TYPE_COUNTRY,
+ NL80211_REGDOM_TYPE_WORLD,
+ NL80211_REGDOM_TYPE_CUSTOM_WORLD,
+ NL80211_REGDOM_TYPE_INTERSECTION,
+};
+
+/**
+ * enum nl80211_reg_rule_attr - regulatory rule attributes
+ * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional
+ * considerations for a given frequency range. These are the
+ * &enum nl80211_reg_rule_flags.
+ * @NL80211_ATTR_FREQ_RANGE_START: starting frequencry for the regulatory
+ * rule in KHz. This is not a center of frequency but an actual regulatory
+ * band edge.
+ * @NL80211_ATTR_FREQ_RANGE_END: ending frequency for the regulatory rule
+ * in KHz. This is not a center a frequency but an actual regulatory
+ * band edge.
+ * @NL80211_ATTR_FREQ_RANGE_MAX_BW: maximum allowed bandwidth for this
+ * frequency range, in KHz.
+ * @NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN: the maximum allowed antenna gain
+ * for a given frequency range. The value is in mBi (100 * dBi).
+ * If you don't have one then don't send this.
+ * @NL80211_ATTR_POWER_RULE_MAX_EIRP: the maximum allowed EIRP for
+ * a given frequency range. The value is in mBm (100 * dBm).
+ */
+enum nl80211_reg_rule_attr {
+ __NL80211_REG_RULE_ATTR_INVALID,
+ NL80211_ATTR_REG_RULE_FLAGS,
+
+ NL80211_ATTR_FREQ_RANGE_START,
+ NL80211_ATTR_FREQ_RANGE_END,
+ NL80211_ATTR_FREQ_RANGE_MAX_BW,
+
+ NL80211_ATTR_POWER_RULE_MAX_ANT_GAIN,
+ NL80211_ATTR_POWER_RULE_MAX_EIRP,
+
+ /* keep last */
+ __NL80211_REG_RULE_ATTR_AFTER_LAST,
+ NL80211_REG_RULE_ATTR_MAX = __NL80211_REG_RULE_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_reg_rule_flags - regulatory rule flags
+ *
+ * @NL80211_RRF_NO_OFDM: OFDM modulation not allowed
+ * @NL80211_RRF_NO_CCK: CCK modulation not allowed
+ * @NL80211_RRF_NO_INDOOR: indoor operation not allowed
+ * @NL80211_RRF_NO_OUTDOOR: outdoor operation not allowed
+ * @NL80211_RRF_DFS: DFS support is required to be used
+ * @NL80211_RRF_PTP_ONLY: this is only for Point To Point links
+ * @NL80211_RRF_PTMP_ONLY: this is only for Point To Multi Point links
+ * @NL80211_RRF_PASSIVE_SCAN: passive scan is required
+ * @NL80211_RRF_NO_IBSS: no IBSS is allowed
+ */
+enum nl80211_reg_rule_flags {
+ NL80211_RRF_NO_OFDM = 1<<0,
+ NL80211_RRF_NO_CCK = 1<<1,
+ NL80211_RRF_NO_INDOOR = 1<<2,
+ NL80211_RRF_NO_OUTDOOR = 1<<3,
+ NL80211_RRF_DFS = 1<<4,
+ NL80211_RRF_PTP_ONLY = 1<<5,
+ NL80211_RRF_PTMP_ONLY = 1<<6,
+ NL80211_RRF_PASSIVE_SCAN = 1<<7,
+ NL80211_RRF_NO_IBSS = 1<<8,
+};
+
+/**
+ * enum nl80211_survey_info - survey information
+ *
+ * These attribute types are used with %NL80211_ATTR_SURVEY_INFO
+ * when getting information about a survey.
+ *
+ * @__NL80211_SURVEY_INFO_INVALID: attribute number 0 is reserved
+ * @NL80211_SURVEY_INFO_FREQUENCY: center frequency of channel
+ * @NL80211_SURVEY_INFO_NOISE: noise level of channel (u8, dBm)
+ */
+enum nl80211_survey_info {
+ __NL80211_SURVEY_INFO_INVALID,
+ NL80211_SURVEY_INFO_FREQUENCY,
+ NL80211_SURVEY_INFO_NOISE,
+
+ /* keep last */
+ __NL80211_SURVEY_INFO_AFTER_LAST,
+ NL80211_SURVEY_INFO_MAX = __NL80211_SURVEY_INFO_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_mntr_flags - monitor configuration flags
+ *
+ * Monitor configuration flags.
+ *
+ * @__NL80211_MNTR_FLAG_INVALID: reserved
+ *
+ * @NL80211_MNTR_FLAG_FCSFAIL: pass frames with bad FCS
+ * @NL80211_MNTR_FLAG_PLCPFAIL: pass frames with bad PLCP
+ * @NL80211_MNTR_FLAG_CONTROL: pass control frames
+ * @NL80211_MNTR_FLAG_OTHER_BSS: disable BSSID filtering
+ * @NL80211_MNTR_FLAG_COOK_FRAMES: report frames after processing.
+ * overrides all other flags.
+ *
+ * @__NL80211_MNTR_FLAG_AFTER_LAST: internal use
+ * @NL80211_MNTR_FLAG_MAX: highest possible monitor flag
+ */
+enum nl80211_mntr_flags {
+ __NL80211_MNTR_FLAG_INVALID,
+ NL80211_MNTR_FLAG_FCSFAIL,
+ NL80211_MNTR_FLAG_PLCPFAIL,
+ NL80211_MNTR_FLAG_CONTROL,
+ NL80211_MNTR_FLAG_OTHER_BSS,
+ NL80211_MNTR_FLAG_COOK_FRAMES,
+
+ /* keep last */
+ __NL80211_MNTR_FLAG_AFTER_LAST,
+ NL80211_MNTR_FLAG_MAX = __NL80211_MNTR_FLAG_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_meshconf_params - mesh configuration parameters
+ *
+ * Mesh configuration parameters
+ *
+ * @__NL80211_MESHCONF_INVALID: internal use
+ *
+ * @NL80211_MESHCONF_RETRY_TIMEOUT: specifies the initial retry timeout in
+ * millisecond units, used by the Peer Link Open message
+ *
+ * @NL80211_MESHCONF_CONFIRM_TIMEOUT: specifies the inital confirm timeout, in
+ * millisecond units, used by the peer link management to close a peer link
+ *
+ * @NL80211_MESHCONF_HOLDING_TIMEOUT: specifies the holding timeout, in
+ * millisecond units
+ *
+ * @NL80211_MESHCONF_MAX_PEER_LINKS: maximum number of peer links allowed
+ * on this mesh interface
+ *
+ * @NL80211_MESHCONF_MAX_RETRIES: specifies the maximum number of peer link
+ * open retries that can be sent to establish a new peer link instance in a
+ * mesh
+ *
+ * @NL80211_MESHCONF_TTL: specifies the value of TTL field set at a source mesh
+ * point.
+ *
+ * @NL80211_MESHCONF_AUTO_OPEN_PLINKS: whether we should automatically
+ * open peer links when we detect compatible mesh peers.
+ *
+ * @NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES: the number of action frames
+ * containing a PREQ that an MP can send to a particular destination (path
+ * target)
+ *
+ * @NL80211_MESHCONF_PATH_REFRESH_TIME: how frequently to refresh mesh paths
+ * (in milliseconds)
+ *
+ * @NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT: minimum length of time to wait
+ * until giving up on a path discovery (in milliseconds)
+ *
+ * @NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT: The time (in TUs) for which mesh
+ * points receiving a PREQ shall consider the forwarding information from the
+ * root to be valid. (TU = time unit)
+ *
+ * @NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL: The minimum interval of time (in
+ * TUs) during which an MP can send only one action frame containing a PREQ
+ * reference element
+ *
+ * @NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME: The interval of time (in TUs)
+ * that it takes for an HWMP information element to propagate across the mesh
+ *
+ * @NL80211_MESHCONF_ROOTMODE: whether root mode is enabled or not
+ *
+ * @NL80211_MESHCONF_ATTR_MAX: highest possible mesh configuration attribute
+ *
+ * @__NL80211_MESHCONF_ATTR_AFTER_LAST: internal use
+ */
+enum nl80211_meshconf_params {
+ __NL80211_MESHCONF_INVALID,
+ NL80211_MESHCONF_RETRY_TIMEOUT,
+ NL80211_MESHCONF_CONFIRM_TIMEOUT,
+ NL80211_MESHCONF_HOLDING_TIMEOUT,
+ NL80211_MESHCONF_MAX_PEER_LINKS,
+ NL80211_MESHCONF_MAX_RETRIES,
+ NL80211_MESHCONF_TTL,
+ NL80211_MESHCONF_AUTO_OPEN_PLINKS,
+ NL80211_MESHCONF_HWMP_MAX_PREQ_RETRIES,
+ NL80211_MESHCONF_PATH_REFRESH_TIME,
+ NL80211_MESHCONF_MIN_DISCOVERY_TIMEOUT,
+ NL80211_MESHCONF_HWMP_ACTIVE_PATH_TIMEOUT,
+ NL80211_MESHCONF_HWMP_PREQ_MIN_INTERVAL,
+ NL80211_MESHCONF_HWMP_NET_DIAM_TRVS_TIME,
+ NL80211_MESHCONF_HWMP_ROOTMODE,
+
+ /* keep last */
+ __NL80211_MESHCONF_ATTR_AFTER_LAST,
+ NL80211_MESHCONF_ATTR_MAX = __NL80211_MESHCONF_ATTR_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_txq_attr - TX queue parameter attributes
+ * @__NL80211_TXQ_ATTR_INVALID: Attribute number 0 is reserved
+ * @NL80211_TXQ_ATTR_QUEUE: TX queue identifier (NL80211_TXQ_Q_*)
+ * @NL80211_TXQ_ATTR_TXOP: Maximum burst time in units of 32 usecs, 0 meaning
+ * disabled
+ * @NL80211_TXQ_ATTR_CWMIN: Minimum contention window [a value of the form
+ * 2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_CWMAX: Maximum contention window [a value of the form
+ * 2^n-1 in the range 1..32767]
+ * @NL80211_TXQ_ATTR_AIFS: Arbitration interframe space [0..255]
+ * @__NL80211_TXQ_ATTR_AFTER_LAST: Internal
+ * @NL80211_TXQ_ATTR_MAX: Maximum TXQ attribute number
+ */
+enum nl80211_txq_attr {
+ __NL80211_TXQ_ATTR_INVALID,
+ NL80211_TXQ_ATTR_QUEUE,
+ NL80211_TXQ_ATTR_TXOP,
+ NL80211_TXQ_ATTR_CWMIN,
+ NL80211_TXQ_ATTR_CWMAX,
+ NL80211_TXQ_ATTR_AIFS,
+
+ /* keep last */
+ __NL80211_TXQ_ATTR_AFTER_LAST,
+ NL80211_TXQ_ATTR_MAX = __NL80211_TXQ_ATTR_AFTER_LAST - 1
+};
+
+enum nl80211_txq_q {
+ NL80211_TXQ_Q_VO,
+ NL80211_TXQ_Q_VI,
+ NL80211_TXQ_Q_BE,
+ NL80211_TXQ_Q_BK
+};
+
+enum nl80211_channel_type {
+ NL80211_CHAN_NO_HT,
+ NL80211_CHAN_HT20,
+ NL80211_CHAN_HT40MINUS,
+ NL80211_CHAN_HT40PLUS
+};
+
+/**
+ * enum nl80211_bss - netlink attributes for a BSS
+ *
+ * @__NL80211_BSS_INVALID: invalid
+ * @NL80211_BSS_FREQUENCY: frequency in MHz (u32)
+ * @NL80211_BSS_TSF: TSF of the received probe response/beacon (u64)
+ * @NL80211_BSS_BEACON_INTERVAL: beacon interval of the (I)BSS (u16)
+ * @NL80211_BSS_CAPABILITY: capability field (CPU order, u16)
+ * @NL80211_BSS_INFORMATION_ELEMENTS: binary attribute containing the
+ * raw information elements from the probe response/beacon (bin)
+ * @NL80211_BSS_SIGNAL_MBM: signal strength of probe response/beacon
+ * in mBm (100 * dBm) (s32)
+ * @NL80211_BSS_SIGNAL_UNSPEC: signal strength of the probe response/beacon
+ * in unspecified units, scaled to 0..100 (u8)
+ * @NL80211_BSS_STATUS: status, if this BSS is "used"
+ * @NL80211_BSS_SEEN_MS_AGO: age of this BSS entry in ms
+ * @__NL80211_BSS_AFTER_LAST: internal
+ * @NL80211_BSS_MAX: highest BSS attribute
+ */
+enum nl80211_bss {
+ __NL80211_BSS_INVALID,
+ NL80211_BSS_BSSID,
+ NL80211_BSS_FREQUENCY,
+ NL80211_BSS_TSF,
+ NL80211_BSS_BEACON_INTERVAL,
+ NL80211_BSS_CAPABILITY,
+ NL80211_BSS_INFORMATION_ELEMENTS,
+ NL80211_BSS_SIGNAL_MBM,
+ NL80211_BSS_SIGNAL_UNSPEC,
+ NL80211_BSS_STATUS,
+ NL80211_BSS_SEEN_MS_AGO,
+
+ /* keep last */
+ __NL80211_BSS_AFTER_LAST,
+ NL80211_BSS_MAX = __NL80211_BSS_AFTER_LAST - 1
+};
+
+/**
+ * enum nl80211_bss_status - BSS "status"
+ */
+enum nl80211_bss_status {
+ NL80211_BSS_STATUS_AUTHENTICATED,
+ NL80211_BSS_STATUS_ASSOCIATED,
+ NL80211_BSS_STATUS_IBSS_JOINED,
+};
+
+/**
+ * enum nl80211_auth_type - AuthenticationType
+ *
+ * @NL80211_AUTHTYPE_OPEN_SYSTEM: Open System authentication
+ * @NL80211_AUTHTYPE_SHARED_KEY: Shared Key authentication (WEP only)
+ * @NL80211_AUTHTYPE_FT: Fast BSS Transition (IEEE 802.11r)
+ * @NL80211_AUTHTYPE_NETWORK_EAP: Network EAP (some Cisco APs and mainly LEAP)
+ * @__NL80211_AUTHTYPE_NUM: internal
+ * @NL80211_AUTHTYPE_MAX: maximum valid auth algorithm
+ * @NL80211_AUTHTYPE_AUTOMATIC: determine automatically (if necessary by
+ * trying multiple times); this is invalid in netlink -- leave out
+ * the attribute for this on CONNECT commands.
+ */
+enum nl80211_auth_type {
+ NL80211_AUTHTYPE_OPEN_SYSTEM,
+ NL80211_AUTHTYPE_SHARED_KEY,
+ NL80211_AUTHTYPE_FT,
+ NL80211_AUTHTYPE_NETWORK_EAP,
+
+ /* keep last */
+ __NL80211_AUTHTYPE_NUM,
+ NL80211_AUTHTYPE_MAX = __NL80211_AUTHTYPE_NUM - 1,
+ NL80211_AUTHTYPE_AUTOMATIC
+};
+
+/**
+ * enum nl80211_key_type - Key Type
+ * @NL80211_KEYTYPE_GROUP: Group (broadcast/multicast) key
+ * @NL80211_KEYTYPE_PAIRWISE: Pairwise (unicast/individual) key
+ * @NL80211_KEYTYPE_PEERKEY: PeerKey (DLS)
+ */
+enum nl80211_key_type {
+ NL80211_KEYTYPE_GROUP,
+ NL80211_KEYTYPE_PAIRWISE,
+ NL80211_KEYTYPE_PEERKEY,
+};
+
+/**
+ * enum nl80211_mfp - Management frame protection state
+ * @NL80211_MFP_NO: Management frame protection not used
+ * @NL80211_MFP_REQUIRED: Management frame protection required
+ */
+enum nl80211_mfp {
+ NL80211_MFP_NO,
+ NL80211_MFP_REQUIRED,
+};
+
+enum nl80211_wpa_versions {
+ NL80211_WPA_VERSION_1 = 1 << 0,
+ NL80211_WPA_VERSION_2 = 1 << 1,
+};
+
+/**
+ * enum nl80211_key_attributes - key attributes
+ * @__NL80211_KEY_INVALID: invalid
+ * @NL80211_KEY_DATA: (temporal) key data; for TKIP this consists of
+ * 16 bytes encryption key followed by 8 bytes each for TX and RX MIC
+ * keys
+ * @NL80211_KEY_IDX: key ID (u8, 0-3)
+ * @NL80211_KEY_CIPHER: key cipher suite (u32, as defined by IEEE 802.11
+ * section 7.3.2.25.1, e.g. 0x000FAC04)
+ * @NL80211_KEY_SEQ: transmit key sequence number (IV/PN) for TKIP and
+ * CCMP keys, each six bytes in little endian
+ * @NL80211_KEY_DEFAULT: flag indicating default key
+ * @NL80211_KEY_DEFAULT_MGMT: flag indicating default management key
+ * @__NL80211_KEY_AFTER_LAST: internal
+ * @NL80211_KEY_MAX: highest key attribute
+ */
+enum nl80211_key_attributes {
+ __NL80211_KEY_INVALID,
+ NL80211_KEY_DATA,
+ NL80211_KEY_IDX,
+ NL80211_KEY_CIPHER,
+ NL80211_KEY_SEQ,
+ NL80211_KEY_DEFAULT,
+ NL80211_KEY_DEFAULT_MGMT,
+
+ /* keep last */
+ __NL80211_KEY_AFTER_LAST,
+ NL80211_KEY_MAX = __NL80211_KEY_AFTER_LAST - 1
+};
+
+#endif /* __LINUX_NL80211_H */
diff --git a/src/common/version.h b/src/common/version.h
index 9c4c6ca..b79c494 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -1,6 +1,6 @@
#ifndef VERSION_H
#define VERSION_H
-#define VERSION_STR "0.6.8"
+#define VERSION_STR "0.6.10"
#endif /* VERSION_H */
diff --git a/src/common/wireless_copy.h b/src/common/wireless_copy.h
new file mode 100644
index 0000000..ad76466
--- /dev/null
+++ b/src/common/wireless_copy.h
@@ -0,0 +1,1099 @@
+/* This is based on Linux Wireless Extensions header file from WIRELESS_EXT 18.
+ * I have just removed kernel related headers and added some typedefs etc. to
+ * make this easier to include into user space programs.
+ * Jouni Malinen, 2005-03-12.
+ */
+
+
+/*
+ * This file define a set of standard wireless extensions
+ *
+ * Version : 19 18.3.05
+ *
+ * Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
+ * Copyright (c) 1997-2005 Jean Tourrilhes, All Rights Reserved.
+ */
+
+#ifndef _LINUX_WIRELESS_H
+#define _LINUX_WIRELESS_H
+
+/************************** DOCUMENTATION **************************/
+/*
+ * Initial APIs (1996 -> onward) :
+ * -----------------------------
+ * Basically, the wireless extensions are for now a set of standard ioctl
+ * call + /proc/net/wireless
+ *
+ * The entry /proc/net/wireless give statistics and information on the
+ * driver.
+ * This is better than having each driver having its entry because
+ * its centralised and we may remove the driver module safely.
+ *
+ * Ioctl are used to configure the driver and issue commands. This is
+ * better than command line options of insmod because we may want to
+ * change dynamically (while the driver is running) some parameters.
+ *
+ * The ioctl mechanimsm are copied from standard devices ioctl.
+ * We have the list of command plus a structure descibing the
+ * data exchanged...
+ * Note that to add these ioctl, I was obliged to modify :
+ * # net/core/dev.c (two place + add include)
+ * # net/ipv4/af_inet.c (one place + add include)
+ *
+ * /proc/net/wireless is a copy of /proc/net/dev.
+ * We have a structure for data passed from the driver to /proc/net/wireless
+ * Too add this, I've modified :
+ * # net/core/dev.c (two other places)
+ * # include/linux/netdevice.h (one place)
+ * # include/linux/proc_fs.h (one place)
+ *
+ * New driver API (2002 -> onward) :
+ * -------------------------------
+ * This file is only concerned with the user space API and common definitions.
+ * The new driver API is defined and documented in :
+ * # include/net/iw_handler.h
+ *
+ * Note as well that /proc/net/wireless implementation has now moved in :
+ * # net/core/wireless.c
+ *
+ * Wireless Events (2002 -> onward) :
+ * --------------------------------
+ * Events are defined at the end of this file, and implemented in :
+ * # net/core/wireless.c
+ *
+ * Other comments :
+ * --------------
+ * Do not add here things that are redundant with other mechanisms
+ * (drivers init, ifconfig, /proc/net/dev, ...) and with are not
+ * wireless specific.
+ *
+ * These wireless extensions are not magic : each driver has to provide
+ * support for them...
+ *
+ * IMPORTANT NOTE : As everything in the kernel, this is very much a
+ * work in progress. Contact me if you have ideas of improvements...
+ */
+
+/***************************** INCLUDES *****************************/
+
+ /* jkm - replaced linux headers with C library headers, added typedefs */
+#if 0
+/* To minimise problems in user space, I might remove those headers
+ * at some point. Jean II */
+#include <linux/types.h> /* for "caddr_t" et al */
+#include <linux/socket.h> /* for "struct sockaddr" et al */
+#include <linux/if.h> /* for IFNAMSIZ and co... */
+#else
+#include <sys/types.h>
+#include <net/if.h>
+typedef __uint32_t __u32;
+typedef __int32_t __s32;
+typedef __uint16_t __u16;
+typedef __int16_t __s16;
+typedef __uint8_t __u8;
+#ifndef __user
+#define __user
+#endif /* __user */
+#endif
+
+/***************************** VERSION *****************************/
+/*
+ * This constant is used to know the availability of the wireless
+ * extensions and to know which version of wireless extensions it is
+ * (there is some stuff that will be added in the future...)
+ * I just plan to increment with each new version.
+ */
+#define WIRELESS_EXT 19
+
+/*
+ * Changes :
+ *
+ * V2 to V3
+ * --------
+ * Alan Cox start some incompatibles changes. I've integrated a bit more.
+ * - Encryption renamed to Encode to avoid US regulation problems
+ * - Frequency changed from float to struct to avoid problems on old 386
+ *
+ * V3 to V4
+ * --------
+ * - Add sensitivity
+ *
+ * V4 to V5
+ * --------
+ * - Missing encoding definitions in range
+ * - Access points stuff
+ *
+ * V5 to V6
+ * --------
+ * - 802.11 support (ESSID ioctls)
+ *
+ * V6 to V7
+ * --------
+ * - define IW_ESSID_MAX_SIZE and IW_MAX_AP
+ *
+ * V7 to V8
+ * --------
+ * - Changed my e-mail address
+ * - More 802.11 support (nickname, rate, rts, frag)
+ * - List index in frequencies
+ *
+ * V8 to V9
+ * --------
+ * - Support for 'mode of operation' (ad-hoc, managed...)
+ * - Support for unicast and multicast power saving
+ * - Change encoding to support larger tokens (>64 bits)
+ * - Updated iw_params (disable, flags) and use it for NWID
+ * - Extracted iw_point from iwreq for clarity
+ *
+ * V9 to V10
+ * ---------
+ * - Add PM capability to range structure
+ * - Add PM modifier : MAX/MIN/RELATIVE
+ * - Add encoding option : IW_ENCODE_NOKEY
+ * - Add TxPower ioctls (work like TxRate)
+ *
+ * V10 to V11
+ * ----------
+ * - Add WE version in range (help backward/forward compatibility)
+ * - Add retry ioctls (work like PM)
+ *
+ * V11 to V12
+ * ----------
+ * - Add SIOCSIWSTATS to get /proc/net/wireless programatically
+ * - Add DEV PRIVATE IOCTL to avoid collisions in SIOCDEVPRIVATE space
+ * - Add new statistics (frag, retry, beacon)
+ * - Add average quality (for user space calibration)
+ *
+ * V12 to V13
+ * ----------
+ * - Document creation of new driver API.
+ * - Extract union iwreq_data from struct iwreq (for new driver API).
+ * - Rename SIOCSIWNAME as SIOCSIWCOMMIT
+ *
+ * V13 to V14
+ * ----------
+ * - Wireless Events support : define struct iw_event
+ * - Define additional specific event numbers
+ * - Add "addr" and "param" fields in union iwreq_data
+ * - AP scanning stuff (SIOCSIWSCAN and friends)
+ *
+ * V14 to V15
+ * ----------
+ * - Add IW_PRIV_TYPE_ADDR for struct sockaddr private arg
+ * - Make struct iw_freq signed (both m & e), add explicit padding
+ * - Add IWEVCUSTOM for driver specific event/scanning token
+ * - Add IW_MAX_GET_SPY for driver returning a lot of addresses
+ * - Add IW_TXPOW_RANGE for range of Tx Powers
+ * - Add IWEVREGISTERED & IWEVEXPIRED events for Access Points
+ * - Add IW_MODE_MONITOR for passive monitor
+ *
+ * V15 to V16
+ * ----------
+ * - Increase the number of bitrates in iw_range to 32 (for 802.11g)
+ * - Increase the number of frequencies in iw_range to 32 (for 802.11b+a)
+ * - Reshuffle struct iw_range for increases, add filler
+ * - Increase IW_MAX_AP to 64 for driver returning a lot of addresses
+ * - Remove IW_MAX_GET_SPY because conflict with enhanced spy support
+ * - Add SIOCSIWTHRSPY/SIOCGIWTHRSPY and "struct iw_thrspy"
+ * - Add IW_ENCODE_TEMP and iw_range->encoding_login_index
+ *
+ * V16 to V17
+ * ----------
+ * - Add flags to frequency -> auto/fixed
+ * - Document (struct iw_quality *)->updated, add new flags (INVALID)
+ * - Wireless Event capability in struct iw_range
+ * - Add support for relative TxPower (yick !)
+ *
+ * V17 to V18 (From Jouni Malinen <j@w1.fi>)
+ * ----------
+ * - Add support for WPA/WPA2
+ * - Add extended encoding configuration (SIOCSIWENCODEEXT and
+ * SIOCGIWENCODEEXT)
+ * - Add SIOCSIWGENIE/SIOCGIWGENIE
+ * - Add SIOCSIWMLME
+ * - Add SIOCSIWPMKSA
+ * - Add struct iw_range bit field for supported encoding capabilities
+ * - Add optional scan request parameters for SIOCSIWSCAN
+ * - Add SIOCSIWAUTH/SIOCGIWAUTH for setting authentication and WPA
+ * related parameters (extensible up to 4096 parameter values)
+ * - Add wireless events: IWEVGENIE, IWEVMICHAELMICFAILURE,
+ * IWEVASSOCREQIE, IWEVASSOCRESPIE, IWEVPMKIDCAND
+ *
+ * V18 to V19
+ * ----------
+ * - Remove (struct iw_point *)->pointer from events and streams
+ * - Remove header includes to help user space
+ * - Increase IW_ENCODING_TOKEN_MAX from 32 to 64
+ * - Add IW_QUAL_ALL_UPDATED and IW_QUAL_ALL_INVALID macros
+ * - Add explicit flag to tell stats are in dBm : IW_QUAL_DBM
+ * - Add IW_IOCTL_IDX() and IW_EVENT_IDX() macros
+ */
+
+/**************************** CONSTANTS ****************************/
+
+/* -------------------------- IOCTL LIST -------------------------- */
+
+/* Wireless Identification */
+#define SIOCSIWCOMMIT 0x8B00 /* Commit pending changes to driver */
+#define SIOCGIWNAME 0x8B01 /* get name == wireless protocol */
+/* SIOCGIWNAME is used to verify the presence of Wireless Extensions.
+ * Common values : "IEEE 802.11-DS", "IEEE 802.11-FH", "IEEE 802.11b"...
+ * Don't put the name of your driver there, it's useless. */
+
+/* Basic operations */
+#define SIOCSIWNWID 0x8B02 /* set network id (pre-802.11) */
+#define SIOCGIWNWID 0x8B03 /* get network id (the cell) */
+#define SIOCSIWFREQ 0x8B04 /* set channel/frequency (Hz) */
+#define SIOCGIWFREQ 0x8B05 /* get channel/frequency (Hz) */
+#define SIOCSIWMODE 0x8B06 /* set operation mode */
+#define SIOCGIWMODE 0x8B07 /* get operation mode */
+#define SIOCSIWSENS 0x8B08 /* set sensitivity (dBm) */
+#define SIOCGIWSENS 0x8B09 /* get sensitivity (dBm) */
+
+/* Informative stuff */
+#define SIOCSIWRANGE 0x8B0A /* Unused */
+#define SIOCGIWRANGE 0x8B0B /* Get range of parameters */
+#define SIOCSIWPRIV 0x8B0C /* Unused */
+#define SIOCGIWPRIV 0x8B0D /* get private ioctl interface info */
+#define SIOCSIWSTATS 0x8B0E /* Unused */
+#define SIOCGIWSTATS 0x8B0F /* Get /proc/net/wireless stats */
+/* SIOCGIWSTATS is strictly used between user space and the kernel, and
+ * is never passed to the driver (i.e. the driver will never see it). */
+
+/* Spy support (statistics per MAC address - used for Mobile IP support) */
+#define SIOCSIWSPY 0x8B10 /* set spy addresses */
+#define SIOCGIWSPY 0x8B11 /* get spy info (quality of link) */
+#define SIOCSIWTHRSPY 0x8B12 /* set spy threshold (spy event) */
+#define SIOCGIWTHRSPY 0x8B13 /* get spy threshold */
+
+/* Access Point manipulation */
+#define SIOCSIWAP 0x8B14 /* set access point MAC addresses */
+#define SIOCGIWAP 0x8B15 /* get access point MAC addresses */
+#define SIOCGIWAPLIST 0x8B17 /* Deprecated in favor of scanning */
+#define SIOCSIWSCAN 0x8B18 /* trigger scanning (list cells) */
+#define SIOCGIWSCAN 0x8B19 /* get scanning results */
+
+/* 802.11 specific support */
+#define SIOCSIWESSID 0x8B1A /* set ESSID (network name) */
+#define SIOCGIWESSID 0x8B1B /* get ESSID */
+#define SIOCSIWNICKN 0x8B1C /* set node name/nickname */
+#define SIOCGIWNICKN 0x8B1D /* get node name/nickname */
+/* As the ESSID and NICKN are strings up to 32 bytes long, it doesn't fit
+ * within the 'iwreq' structure, so we need to use the 'data' member to
+ * point to a string in user space, like it is done for RANGE... */
+
+/* Other parameters useful in 802.11 and some other devices */
+#define SIOCSIWRATE 0x8B20 /* set default bit rate (bps) */
+#define SIOCGIWRATE 0x8B21 /* get default bit rate (bps) */
+#define SIOCSIWRTS 0x8B22 /* set RTS/CTS threshold (bytes) */
+#define SIOCGIWRTS 0x8B23 /* get RTS/CTS threshold (bytes) */
+#define SIOCSIWFRAG 0x8B24 /* set fragmentation thr (bytes) */
+#define SIOCGIWFRAG 0x8B25 /* get fragmentation thr (bytes) */
+#define SIOCSIWTXPOW 0x8B26 /* set transmit power (dBm) */
+#define SIOCGIWTXPOW 0x8B27 /* get transmit power (dBm) */
+#define SIOCSIWRETRY 0x8B28 /* set retry limits and lifetime */
+#define SIOCGIWRETRY 0x8B29 /* get retry limits and lifetime */
+
+/* Encoding stuff (scrambling, hardware security, WEP...) */
+#define SIOCSIWENCODE 0x8B2A /* set encoding token & mode */
+#define SIOCGIWENCODE 0x8B2B /* get encoding token & mode */
+/* Power saving stuff (power management, unicast and multicast) */
+#define SIOCSIWPOWER 0x8B2C /* set Power Management settings */
+#define SIOCGIWPOWER 0x8B2D /* get Power Management settings */
+
+/* WPA : Generic IEEE 802.11 informatiom element (e.g., for WPA/RSN/WMM).
+ * This ioctl uses struct iw_point and data buffer that includes IE id and len
+ * fields. More than one IE may be included in the request. Setting the generic
+ * IE to empty buffer (len=0) removes the generic IE from the driver. Drivers
+ * are allowed to generate their own WPA/RSN IEs, but in these cases, drivers
+ * are required to report the used IE as a wireless event, e.g., when
+ * associating with an AP. */
+#define SIOCSIWGENIE 0x8B30 /* set generic IE */
+#define SIOCGIWGENIE 0x8B31 /* get generic IE */
+
+/* WPA : IEEE 802.11 MLME requests */
+#define SIOCSIWMLME 0x8B16 /* request MLME operation; uses
+ * struct iw_mlme */
+/* WPA : Authentication mode parameters */
+#define SIOCSIWAUTH 0x8B32 /* set authentication mode params */
+#define SIOCGIWAUTH 0x8B33 /* get authentication mode params */
+
+/* WPA : Extended version of encoding configuration */
+#define SIOCSIWENCODEEXT 0x8B34 /* set encoding token & mode */
+#define SIOCGIWENCODEEXT 0x8B35 /* get encoding token & mode */
+
+/* WPA2 : PMKSA cache management */
+#define SIOCSIWPMKSA 0x8B36 /* PMKSA cache operation */
+
+/* -------------------- DEV PRIVATE IOCTL LIST -------------------- */
+
+/* These 32 ioctl are wireless device private, for 16 commands.
+ * Each driver is free to use them for whatever purpose it chooses,
+ * however the driver *must* export the description of those ioctls
+ * with SIOCGIWPRIV and *must* use arguments as defined below.
+ * If you don't follow those rules, DaveM is going to hate you (reason :
+ * it make mixed 32/64bit operation impossible).
+ */
+#define SIOCIWFIRSTPRIV 0x8BE0
+#define SIOCIWLASTPRIV 0x8BFF
+/* Previously, we were using SIOCDEVPRIVATE, but we now have our
+ * separate range because of collisions with other tools such as
+ * 'mii-tool'.
+ * We now have 32 commands, so a bit more space ;-).
+ * Also, all 'odd' commands are only usable by root and don't return the
+ * content of ifr/iwr to user (but you are not obliged to use the set/get
+ * convention, just use every other two command). More details in iwpriv.c.
+ * And I repeat : you are not forced to use them with iwpriv, but you
+ * must be compliant with it.
+ */
+
+/* ------------------------- IOCTL STUFF ------------------------- */
+
+/* The first and the last (range) */
+#define SIOCIWFIRST 0x8B00
+#define SIOCIWLAST SIOCIWLASTPRIV /* 0x8BFF */
+#define IW_IOCTL_IDX(cmd) ((cmd) - SIOCIWFIRST)
+
+/* Even : get (world access), odd : set (root access) */
+#define IW_IS_SET(cmd) (!((cmd) & 0x1))
+#define IW_IS_GET(cmd) ((cmd) & 0x1)
+
+/* ----------------------- WIRELESS EVENTS ----------------------- */
+/* Those are *NOT* ioctls, do not issue request on them !!! */
+/* Most events use the same identifier as ioctl requests */
+
+#define IWEVTXDROP 0x8C00 /* Packet dropped to excessive retry */
+#define IWEVQUAL 0x8C01 /* Quality part of statistics (scan) */
+#define IWEVCUSTOM 0x8C02 /* Driver specific ascii string */
+#define IWEVREGISTERED 0x8C03 /* Discovered a new node (AP mode) */
+#define IWEVEXPIRED 0x8C04 /* Expired a node (AP mode) */
+#define IWEVGENIE 0x8C05 /* Generic IE (WPA, RSN, WMM, ..)
+ * (scan results); This includes id and
+ * length fields. One IWEVGENIE may
+ * contain more than one IE. Scan
+ * results may contain one or more
+ * IWEVGENIE events. */
+#define IWEVMICHAELMICFAILURE 0x8C06 /* Michael MIC failure
+ * (struct iw_michaelmicfailure)
+ */
+#define IWEVASSOCREQIE 0x8C07 /* IEs used in (Re)Association Request.
+ * The data includes id and length
+ * fields and may contain more than one
+ * IE. This event is required in
+ * Managed mode if the driver
+ * generates its own WPA/RSN IE. This
+ * should be sent just before
+ * IWEVREGISTERED event for the
+ * association. */
+#define IWEVASSOCRESPIE 0x8C08 /* IEs used in (Re)Association
+ * Response. The data includes id and
+ * length fields and may contain more
+ * than one IE. This may be sent
+ * between IWEVASSOCREQIE and
+ * IWEVREGISTERED events for the
+ * association. */
+#define IWEVPMKIDCAND 0x8C09 /* PMKID candidate for RSN
+ * pre-authentication
+ * (struct iw_pmkid_cand) */
+
+#define IWEVFIRST 0x8C00
+#define IW_EVENT_IDX(cmd) ((cmd) - IWEVFIRST)
+
+/* ------------------------- PRIVATE INFO ------------------------- */
+/*
+ * The following is used with SIOCGIWPRIV. It allow a driver to define
+ * the interface (name, type of data) for its private ioctl.
+ * Privates ioctl are SIOCIWFIRSTPRIV -> SIOCIWLASTPRIV
+ */
+
+#define IW_PRIV_TYPE_MASK 0x7000 /* Type of arguments */
+#define IW_PRIV_TYPE_NONE 0x0000
+#define IW_PRIV_TYPE_BYTE 0x1000 /* Char as number */
+#define IW_PRIV_TYPE_CHAR 0x2000 /* Char as character */
+#define IW_PRIV_TYPE_INT 0x4000 /* 32 bits int */
+#define IW_PRIV_TYPE_FLOAT 0x5000 /* struct iw_freq */
+#define IW_PRIV_TYPE_ADDR 0x6000 /* struct sockaddr */
+
+#define IW_PRIV_SIZE_FIXED 0x0800 /* Variable or fixed number of args */
+
+#define IW_PRIV_SIZE_MASK 0x07FF /* Max number of those args */
+
+/*
+ * Note : if the number of args is fixed and the size < 16 octets,
+ * instead of passing a pointer we will put args in the iwreq struct...
+ */
+
+/* ----------------------- OTHER CONSTANTS ----------------------- */
+
+/* Maximum frequencies in the range struct */
+#define IW_MAX_FREQUENCIES 32
+/* Note : if you have something like 80 frequencies,
+ * don't increase this constant and don't fill the frequency list.
+ * The user will be able to set by channel anyway... */
+
+/* Maximum bit rates in the range struct */
+#define IW_MAX_BITRATES 32
+
+/* Maximum tx powers in the range struct */
+#define IW_MAX_TXPOWER 8
+/* Note : if you more than 8 TXPowers, just set the max and min or
+ * a few of them in the struct iw_range. */
+
+/* Maximum of address that you may set with SPY */
+#define IW_MAX_SPY 8
+
+/* Maximum of address that you may get in the
+ list of access points in range */
+#define IW_MAX_AP 64
+
+/* Maximum size of the ESSID and NICKN strings */
+#define IW_ESSID_MAX_SIZE 32
+
+/* Modes of operation */
+#define IW_MODE_AUTO 0 /* Let the driver decides */
+#define IW_MODE_ADHOC 1 /* Single cell network */
+#define IW_MODE_INFRA 2 /* Multi cell network, roaming, ... */
+#define IW_MODE_MASTER 3 /* Synchronisation master or Access Point */
+#define IW_MODE_REPEAT 4 /* Wireless Repeater (forwarder) */
+#define IW_MODE_SECOND 5 /* Secondary master/repeater (backup) */
+#define IW_MODE_MONITOR 6 /* Passive monitor (listen only) */
+
+/* Statistics flags (bitmask in updated) */
+#define IW_QUAL_QUAL_UPDATED 0x01 /* Value was updated since last read */
+#define IW_QUAL_LEVEL_UPDATED 0x02
+#define IW_QUAL_NOISE_UPDATED 0x04
+#define IW_QUAL_ALL_UPDATED 0x07
+#define IW_QUAL_DBM 0x08 /* Level + Noise are dBm */
+#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */
+#define IW_QUAL_LEVEL_INVALID 0x20
+#define IW_QUAL_NOISE_INVALID 0x40
+#define IW_QUAL_ALL_INVALID 0x70
+
+/* Frequency flags */
+#define IW_FREQ_AUTO 0x00 /* Let the driver decides */
+#define IW_FREQ_FIXED 0x01 /* Force a specific value */
+
+/* Maximum number of size of encoding token available
+ * they are listed in the range structure */
+#define IW_MAX_ENCODING_SIZES 8
+
+/* Maximum size of the encoding token in bytes */
+#define IW_ENCODING_TOKEN_MAX 64 /* 512 bits (for now) */
+
+/* Flags for encoding (along with the token) */
+#define IW_ENCODE_INDEX 0x00FF /* Token index (if needed) */
+#define IW_ENCODE_FLAGS 0xFF00 /* Flags defined below */
+#define IW_ENCODE_MODE 0xF000 /* Modes defined below */
+#define IW_ENCODE_DISABLED 0x8000 /* Encoding disabled */
+#define IW_ENCODE_ENABLED 0x0000 /* Encoding enabled */
+#define IW_ENCODE_RESTRICTED 0x4000 /* Refuse non-encoded packets */
+#define IW_ENCODE_OPEN 0x2000 /* Accept non-encoded packets */
+#define IW_ENCODE_NOKEY 0x0800 /* Key is write only, so not present */
+#define IW_ENCODE_TEMP 0x0400 /* Temporary key */
+
+/* Power management flags available (along with the value, if any) */
+#define IW_POWER_ON 0x0000 /* No details... */
+#define IW_POWER_TYPE 0xF000 /* Type of parameter */
+#define IW_POWER_PERIOD 0x1000 /* Value is a period/duration of */
+#define IW_POWER_TIMEOUT 0x2000 /* Value is a timeout (to go asleep) */
+#define IW_POWER_MODE 0x0F00 /* Power Management mode */
+#define IW_POWER_UNICAST_R 0x0100 /* Receive only unicast messages */
+#define IW_POWER_MULTICAST_R 0x0200 /* Receive only multicast messages */
+#define IW_POWER_ALL_R 0x0300 /* Receive all messages though PM */
+#define IW_POWER_FORCE_S 0x0400 /* Force PM procedure for sending unicast */
+#define IW_POWER_REPEATER 0x0800 /* Repeat broadcast messages in PM period */
+#define IW_POWER_MODIFIER 0x000F /* Modify a parameter */
+#define IW_POWER_MIN 0x0001 /* Value is a minimum */
+#define IW_POWER_MAX 0x0002 /* Value is a maximum */
+#define IW_POWER_RELATIVE 0x0004 /* Value is not in seconds/ms/us */
+
+/* Transmit Power flags available */
+#define IW_TXPOW_TYPE 0x00FF /* Type of value */
+#define IW_TXPOW_DBM 0x0000 /* Value is in dBm */
+#define IW_TXPOW_MWATT 0x0001 /* Value is in mW */
+#define IW_TXPOW_RELATIVE 0x0002 /* Value is in arbitrary units */
+#define IW_TXPOW_RANGE 0x1000 /* Range of value between min/max */
+
+/* Retry limits and lifetime flags available */
+#define IW_RETRY_ON 0x0000 /* No details... */
+#define IW_RETRY_TYPE 0xF000 /* Type of parameter */
+#define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries*/
+#define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */
+#define IW_RETRY_MODIFIER 0x000F /* Modify a parameter */
+#define IW_RETRY_MIN 0x0001 /* Value is a minimum */
+#define IW_RETRY_MAX 0x0002 /* Value is a maximum */
+#define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */
+
+/* Scanning request flags */
+#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */
+#define IW_SCAN_ALL_ESSID 0x0001 /* Scan all ESSIDs */
+#define IW_SCAN_THIS_ESSID 0x0002 /* Scan only this ESSID */
+#define IW_SCAN_ALL_FREQ 0x0004 /* Scan all Frequencies */
+#define IW_SCAN_THIS_FREQ 0x0008 /* Scan only this Frequency */
+#define IW_SCAN_ALL_MODE 0x0010 /* Scan all Modes */
+#define IW_SCAN_THIS_MODE 0x0020 /* Scan only this Mode */
+#define IW_SCAN_ALL_RATE 0x0040 /* Scan all Bit-Rates */
+#define IW_SCAN_THIS_RATE 0x0080 /* Scan only this Bit-Rate */
+/* struct iw_scan_req scan_type */
+#define IW_SCAN_TYPE_ACTIVE 0
+#define IW_SCAN_TYPE_PASSIVE 1
+/* Maximum size of returned data */
+#define IW_SCAN_MAX_DATA 4096 /* In bytes */
+
+/* Max number of char in custom event - use multiple of them if needed */
+#define IW_CUSTOM_MAX 256 /* In bytes */
+
+/* Generic information element */
+#define IW_GENERIC_IE_MAX 1024
+
+/* MLME requests (SIOCSIWMLME / struct iw_mlme) */
+#define IW_MLME_DEAUTH 0
+#define IW_MLME_DISASSOC 1
+
+/* SIOCSIWAUTH/SIOCGIWAUTH struct iw_param flags */
+#define IW_AUTH_INDEX 0x0FFF
+#define IW_AUTH_FLAGS 0xF000
+/* SIOCSIWAUTH/SIOCGIWAUTH parameters (0 .. 4095)
+ * (IW_AUTH_INDEX mask in struct iw_param flags; this is the index of the
+ * parameter that is being set/get to; value will be read/written to
+ * struct iw_param value field) */
+#define IW_AUTH_WPA_VERSION 0
+#define IW_AUTH_CIPHER_PAIRWISE 1
+#define IW_AUTH_CIPHER_GROUP 2
+#define IW_AUTH_KEY_MGMT 3
+#define IW_AUTH_TKIP_COUNTERMEASURES 4
+#define IW_AUTH_DROP_UNENCRYPTED 5
+#define IW_AUTH_80211_AUTH_ALG 6
+#define IW_AUTH_WPA_ENABLED 7
+#define IW_AUTH_RX_UNENCRYPTED_EAPOL 8
+#define IW_AUTH_ROAMING_CONTROL 9
+#define IW_AUTH_PRIVACY_INVOKED 10
+#define IW_AUTH_CIPHER_GROUP_MGMT 11
+#define IW_AUTH_MFP 12
+
+/* IW_AUTH_WPA_VERSION values (bit field) */
+#define IW_AUTH_WPA_VERSION_DISABLED 0x00000001
+#define IW_AUTH_WPA_VERSION_WPA 0x00000002
+#define IW_AUTH_WPA_VERSION_WPA2 0x00000004
+
+/* IW_AUTH_PAIRWISE_CIPHER and IW_AUTH_GROUP_CIPHER values (bit field) */
+#define IW_AUTH_CIPHER_NONE 0x00000001
+#define IW_AUTH_CIPHER_WEP40 0x00000002
+#define IW_AUTH_CIPHER_TKIP 0x00000004
+#define IW_AUTH_CIPHER_CCMP 0x00000008
+#define IW_AUTH_CIPHER_WEP104 0x00000010
+
+/* IW_AUTH_KEY_MGMT values (bit field) */
+#define IW_AUTH_KEY_MGMT_802_1X 1
+#define IW_AUTH_KEY_MGMT_PSK 2
+
+/* IW_AUTH_80211_AUTH_ALG values (bit field) */
+#define IW_AUTH_ALG_OPEN_SYSTEM 0x00000001
+#define IW_AUTH_ALG_SHARED_KEY 0x00000002
+#define IW_AUTH_ALG_LEAP 0x00000004
+
+/* IW_AUTH_ROAMING_CONTROL values */
+#define IW_AUTH_ROAMING_ENABLE 0 /* driver/firmware based roaming */
+#define IW_AUTH_ROAMING_DISABLE 1 /* user space program used for roaming
+ * control */
+
+/* IW_AUTH_MFP (management frame protection) values */
+#define IW_AUTH_MFP_DISABLED 0 /* MFP disabled */
+#define IW_AUTH_MFP_OPTIONAL 1 /* MFP optional */
+#define IW_AUTH_MFP_REQUIRED 2 /* MFP required */
+
+/* SIOCSIWENCODEEXT definitions */
+#define IW_ENCODE_SEQ_MAX_SIZE 8
+/* struct iw_encode_ext ->alg */
+#define IW_ENCODE_ALG_NONE 0
+#define IW_ENCODE_ALG_WEP 1
+#define IW_ENCODE_ALG_TKIP 2
+#define IW_ENCODE_ALG_CCMP 3
+#define IW_ENCODE_ALG_PMK 4
+#define IW_ENCODE_ALG_AES_CMAC 5
+/* struct iw_encode_ext ->ext_flags */
+#define IW_ENCODE_EXT_TX_SEQ_VALID 0x00000001
+#define IW_ENCODE_EXT_RX_SEQ_VALID 0x00000002
+#define IW_ENCODE_EXT_GROUP_KEY 0x00000004
+#define IW_ENCODE_EXT_SET_TX_KEY 0x00000008
+
+/* IWEVMICHAELMICFAILURE : struct iw_michaelmicfailure ->flags */
+#define IW_MICFAILURE_KEY_ID 0x00000003 /* Key ID 0..3 */
+#define IW_MICFAILURE_GROUP 0x00000004
+#define IW_MICFAILURE_PAIRWISE 0x00000008
+#define IW_MICFAILURE_STAKEY 0x00000010
+#define IW_MICFAILURE_COUNT 0x00000060 /* 1 or 2 (0 = count not supported)
+ */
+
+/* Bit field values for enc_capa in struct iw_range */
+#define IW_ENC_CAPA_WPA 0x00000001
+#define IW_ENC_CAPA_WPA2 0x00000002
+#define IW_ENC_CAPA_CIPHER_TKIP 0x00000004
+#define IW_ENC_CAPA_CIPHER_CCMP 0x00000008
+#define IW_ENC_CAPA_4WAY_HANDSHAKE 0x00000010
+
+/* Event capability macros - in (struct iw_range *)->event_capa
+ * Because we have more than 32 possible events, we use an array of
+ * 32 bit bitmasks. Note : 32 bits = 0x20 = 2^5. */
+#define IW_EVENT_CAPA_BASE(cmd) ((cmd >= SIOCIWFIRSTPRIV) ? \
+ (cmd - SIOCIWFIRSTPRIV + 0x60) : \
+ (cmd - SIOCSIWCOMMIT))
+#define IW_EVENT_CAPA_INDEX(cmd) (IW_EVENT_CAPA_BASE(cmd) >> 5)
+#define IW_EVENT_CAPA_MASK(cmd) (1 << (IW_EVENT_CAPA_BASE(cmd) & 0x1F))
+/* Event capability constants - event autogenerated by the kernel
+ * This list is valid for most 802.11 devices, customise as needed... */
+#define IW_EVENT_CAPA_K_0 (IW_EVENT_CAPA_MASK(0x8B04) | \
+ IW_EVENT_CAPA_MASK(0x8B06) | \
+ IW_EVENT_CAPA_MASK(0x8B1A))
+#define IW_EVENT_CAPA_K_1 (IW_EVENT_CAPA_MASK(0x8B2A))
+/* "Easy" macro to set events in iw_range (less efficient) */
+#define IW_EVENT_CAPA_SET(event_capa, cmd) (event_capa[IW_EVENT_CAPA_INDEX(cmd)] |= IW_EVENT_CAPA_MASK(cmd))
+#define IW_EVENT_CAPA_SET_KERNEL(event_capa) {event_capa[0] |= IW_EVENT_CAPA_K_0; event_capa[1] |= IW_EVENT_CAPA_K_1; }
+
+
+/****************************** TYPES ******************************/
+
+/* --------------------------- SUBTYPES --------------------------- */
+/*
+ * Generic format for most parameters that fit in an int
+ */
+struct iw_param
+{
+ __s32 value; /* The value of the parameter itself */
+ __u8 fixed; /* Hardware should not use auto select */
+ __u8 disabled; /* Disable the feature */
+ __u16 flags; /* Various specifc flags (if any) */
+};
+
+/*
+ * For all data larger than 16 octets, we need to use a
+ * pointer to memory allocated in user space.
+ */
+struct iw_point
+{
+ void __user *pointer; /* Pointer to the data (in user space) */
+ __u16 length; /* number of fields or size in bytes */
+ __u16 flags; /* Optional params */
+};
+
+/*
+ * A frequency
+ * For numbers lower than 10^9, we encode the number in 'm' and
+ * set 'e' to 0
+ * For number greater than 10^9, we divide it by the lowest power
+ * of 10 to get 'm' lower than 10^9, with 'm'= f / (10^'e')...
+ * The power of 10 is in 'e', the result of the division is in 'm'.
+ */
+struct iw_freq
+{
+ __s32 m; /* Mantissa */
+ __s16 e; /* Exponent */
+ __u8 i; /* List index (when in range struct) */
+ __u8 flags; /* Flags (fixed/auto) */
+};
+
+/*
+ * Quality of the link
+ */
+struct iw_quality
+{
+ __u8 qual; /* link quality (%retries, SNR,
+ %missed beacons or better...) */
+ __u8 level; /* signal level (dBm) */
+ __u8 noise; /* noise level (dBm) */
+ __u8 updated; /* Flags to know if updated */
+};
+
+/*
+ * Packet discarded in the wireless adapter due to
+ * "wireless" specific problems...
+ * Note : the list of counter and statistics in net_device_stats
+ * is already pretty exhaustive, and you should use that first.
+ * This is only additional stats...
+ */
+struct iw_discarded
+{
+ __u32 nwid; /* Rx : Wrong nwid/essid */
+ __u32 code; /* Rx : Unable to code/decode (WEP) */
+ __u32 fragment; /* Rx : Can't perform MAC reassembly */
+ __u32 retries; /* Tx : Max MAC retries num reached */
+ __u32 misc; /* Others cases */
+};
+
+/*
+ * Packet/Time period missed in the wireless adapter due to
+ * "wireless" specific problems...
+ */
+struct iw_missed
+{
+ __u32 beacon; /* Missed beacons/superframe */
+};
+
+/*
+ * Quality range (for spy threshold)
+ */
+struct iw_thrspy
+{
+ struct sockaddr addr; /* Source address (hw/mac) */
+ struct iw_quality qual; /* Quality of the link */
+ struct iw_quality low; /* Low threshold */
+ struct iw_quality high; /* High threshold */
+};
+
+/*
+ * Optional data for scan request
+ *
+ * Note: these optional parameters are controlling parameters for the
+ * scanning behavior, these do not apply to getting scan results
+ * (SIOCGIWSCAN). Drivers are expected to keep a local BSS table and
+ * provide a merged results with all BSSes even if the previous scan
+ * request limited scanning to a subset, e.g., by specifying an SSID.
+ * Especially, scan results are required to include an entry for the
+ * current BSS if the driver is in Managed mode and associated with an AP.
+ */
+struct iw_scan_req
+{
+ __u8 scan_type; /* IW_SCAN_TYPE_{ACTIVE,PASSIVE} */
+ __u8 essid_len;
+ __u8 num_channels; /* num entries in channel_list;
+ * 0 = scan all allowed channels */
+ __u8 flags; /* reserved as padding; use zero, this may
+ * be used in the future for adding flags
+ * to request different scan behavior */
+ struct sockaddr bssid; /* ff:ff:ff:ff:ff:ff for broadcast BSSID or
+ * individual address of a specific BSS */
+
+ /*
+ * Use this ESSID if IW_SCAN_THIS_ESSID flag is used instead of using
+ * the current ESSID. This allows scan requests for specific ESSID
+ * without having to change the current ESSID and potentially breaking
+ * the current association.
+ */
+ __u8 essid[IW_ESSID_MAX_SIZE];
+
+ /*
+ * Optional parameters for changing the default scanning behavior.
+ * These are based on the MLME-SCAN.request from IEEE Std 802.11.
+ * TU is 1.024 ms. If these are set to 0, driver is expected to use
+ * reasonable default values. min_channel_time defines the time that
+ * will be used to wait for the first reply on each channel. If no
+ * replies are received, next channel will be scanned after this. If
+ * replies are received, total time waited on the channel is defined by
+ * max_channel_time.
+ */
+ __u32 min_channel_time; /* in TU */
+ __u32 max_channel_time; /* in TU */
+
+ struct iw_freq channel_list[IW_MAX_FREQUENCIES];
+};
+
+/* ------------------------- WPA SUPPORT ------------------------- */
+
+/*
+ * Extended data structure for get/set encoding (this is used with
+ * SIOCSIWENCODEEXT/SIOCGIWENCODEEXT. struct iw_point and IW_ENCODE_*
+ * flags are used in the same way as with SIOCSIWENCODE/SIOCGIWENCODE and
+ * only the data contents changes (key data -> this structure, including
+ * key data).
+ *
+ * If the new key is the first group key, it will be set as the default
+ * TX key. Otherwise, default TX key index is only changed if
+ * IW_ENCODE_EXT_SET_TX_KEY flag is set.
+ *
+ * Key will be changed with SIOCSIWENCODEEXT in all cases except for
+ * special "change TX key index" operation which is indicated by setting
+ * key_len = 0 and ext_flags |= IW_ENCODE_EXT_SET_TX_KEY.
+ *
+ * tx_seq/rx_seq are only used when respective
+ * IW_ENCODE_EXT_{TX,RX}_SEQ_VALID flag is set in ext_flags. Normal
+ * TKIP/CCMP operation is to set RX seq with SIOCSIWENCODEEXT and start
+ * TX seq from zero whenever key is changed. SIOCGIWENCODEEXT is normally
+ * used only by an Authenticator (AP or an IBSS station) to get the
+ * current TX sequence number. Using TX_SEQ_VALID for SIOCSIWENCODEEXT and
+ * RX_SEQ_VALID for SIOCGIWENCODEEXT are optional, but can be useful for
+ * debugging/testing.
+ */
+struct iw_encode_ext
+{
+ __u32 ext_flags; /* IW_ENCODE_EXT_* */
+ __u8 tx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
+ __u8 rx_seq[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
+ struct sockaddr addr; /* ff:ff:ff:ff:ff:ff for broadcast/multicast
+ * (group) keys or unicast address for
+ * individual keys */
+ __u16 alg; /* IW_ENCODE_ALG_* */
+ __u16 key_len;
+ __u8 key[0];
+};
+
+/* SIOCSIWMLME data */
+struct iw_mlme
+{
+ __u16 cmd; /* IW_MLME_* */
+ __u16 reason_code;
+ struct sockaddr addr;
+};
+
+/* SIOCSIWPMKSA data */
+#define IW_PMKSA_ADD 1
+#define IW_PMKSA_REMOVE 2
+#define IW_PMKSA_FLUSH 3
+
+#define IW_PMKID_LEN 16
+
+struct iw_pmksa
+{
+ __u32 cmd; /* IW_PMKSA_* */
+ struct sockaddr bssid;
+ __u8 pmkid[IW_PMKID_LEN];
+};
+
+/* IWEVMICHAELMICFAILURE data */
+struct iw_michaelmicfailure
+{
+ __u32 flags;
+ struct sockaddr src_addr;
+ __u8 tsc[IW_ENCODE_SEQ_MAX_SIZE]; /* LSB first */
+};
+
+/* IWEVPMKIDCAND data */
+#define IW_PMKID_CAND_PREAUTH 0x00000001 /* RNS pre-authentication enabled */
+struct iw_pmkid_cand
+{
+ __u32 flags; /* IW_PMKID_CAND_* */
+ __u32 index; /* the smaller the index, the higher the
+ * priority */
+ struct sockaddr bssid;
+};
+
+/* ------------------------ WIRELESS STATS ------------------------ */
+/*
+ * Wireless statistics (used for /proc/net/wireless)
+ */
+struct iw_statistics
+{
+ __u16 status; /* Status
+ * - device dependent for now */
+
+ struct iw_quality qual; /* Quality of the link
+ * (instant/mean/max) */
+ struct iw_discarded discard; /* Packet discarded counts */
+ struct iw_missed miss; /* Packet missed counts */
+};
+
+/* ------------------------ IOCTL REQUEST ------------------------ */
+/*
+ * This structure defines the payload of an ioctl, and is used
+ * below.
+ *
+ * Note that this structure should fit on the memory footprint
+ * of iwreq (which is the same as ifreq), which mean a max size of
+ * 16 octets = 128 bits. Warning, pointers might be 64 bits wide...
+ * You should check this when increasing the structures defined
+ * above in this file...
+ */
+union iwreq_data
+{
+ /* Config - generic */
+ char name[IFNAMSIZ];
+ /* Name : used to verify the presence of wireless extensions.
+ * Name of the protocol/provider... */
+
+ struct iw_point essid; /* Extended network name */
+ struct iw_param nwid; /* network id (or domain - the cell) */
+ struct iw_freq freq; /* frequency or channel :
+ * 0-1000 = channel
+ * > 1000 = frequency in Hz */
+
+ struct iw_param sens; /* signal level threshold */
+ struct iw_param bitrate; /* default bit rate */
+ struct iw_param txpower; /* default transmit power */
+ struct iw_param rts; /* RTS threshold threshold */
+ struct iw_param frag; /* Fragmentation threshold */
+ __u32 mode; /* Operation mode */
+ struct iw_param retry; /* Retry limits & lifetime */
+
+ struct iw_point encoding; /* Encoding stuff : tokens */
+ struct iw_param power; /* PM duration/timeout */
+ struct iw_quality qual; /* Quality part of statistics */
+
+ struct sockaddr ap_addr; /* Access point address */
+ struct sockaddr addr; /* Destination address (hw/mac) */
+
+ struct iw_param param; /* Other small parameters */
+ struct iw_point data; /* Other large parameters */
+};
+
+/*
+ * The structure to exchange data for ioctl.
+ * This structure is the same as 'struct ifreq', but (re)defined for
+ * convenience...
+ * Do I need to remind you about structure size (32 octets) ?
+ */
+struct iwreq
+{
+ union
+ {
+ char ifrn_name[IFNAMSIZ]; /* if name, e.g. "eth0" */
+ } ifr_ifrn;
+
+ /* Data part (defined just above) */
+ union iwreq_data u;
+};
+
+/* -------------------------- IOCTL DATA -------------------------- */
+/*
+ * For those ioctl which want to exchange mode data that what could
+ * fit in the above structure...
+ */
+
+/*
+ * Range of parameters
+ */
+
+struct iw_range
+{
+ /* Informative stuff (to choose between different interface) */
+ __u32 throughput; /* To give an idea... */
+ /* In theory this value should be the maximum benchmarked
+ * TCP/IP throughput, because with most of these devices the
+ * bit rate is meaningless (overhead an co) to estimate how
+ * fast the connection will go and pick the fastest one.
+ * I suggest people to play with Netperf or any benchmark...
+ */
+
+ /* NWID (or domain id) */
+ __u32 min_nwid; /* Minimal NWID we are able to set */
+ __u32 max_nwid; /* Maximal NWID we are able to set */
+
+ /* Old Frequency (backward compat - moved lower ) */
+ __u16 old_num_channels;
+ __u8 old_num_frequency;
+
+ /* Wireless event capability bitmasks */
+ __u32 event_capa[6];
+
+ /* signal level threshold range */
+ __s32 sensitivity;
+
+ /* Quality of link & SNR stuff */
+ /* Quality range (link, level, noise)
+ * If the quality is absolute, it will be in the range [0 ; max_qual],
+ * if the quality is dBm, it will be in the range [max_qual ; 0].
+ * Don't forget that we use 8 bit arithmetics... */
+ struct iw_quality max_qual; /* Quality of the link */
+ /* This should contain the average/typical values of the quality
+ * indicator. This should be the threshold between a "good" and
+ * a "bad" link (example : monitor going from green to orange).
+ * Currently, user space apps like quality monitors don't have any
+ * way to calibrate the measurement. With this, they can split
+ * the range between 0 and max_qual in different quality level
+ * (using a geometric subdivision centered on the average).
+ * I expect that people doing the user space apps will feedback
+ * us on which value we need to put in each driver... */
+ struct iw_quality avg_qual; /* Quality of the link */
+
+ /* Rates */
+ __u8 num_bitrates; /* Number of entries in the list */
+ __s32 bitrate[IW_MAX_BITRATES]; /* list, in bps */
+
+ /* RTS threshold */
+ __s32 min_rts; /* Minimal RTS threshold */
+ __s32 max_rts; /* Maximal RTS threshold */
+
+ /* Frag threshold */
+ __s32 min_frag; /* Minimal frag threshold */
+ __s32 max_frag; /* Maximal frag threshold */
+
+ /* Power Management duration & timeout */
+ __s32 min_pmp; /* Minimal PM period */
+ __s32 max_pmp; /* Maximal PM period */
+ __s32 min_pmt; /* Minimal PM timeout */
+ __s32 max_pmt; /* Maximal PM timeout */
+ __u16 pmp_flags; /* How to decode max/min PM period */
+ __u16 pmt_flags; /* How to decode max/min PM timeout */
+ __u16 pm_capa; /* What PM options are supported */
+
+ /* Encoder stuff */
+ __u16 encoding_size[IW_MAX_ENCODING_SIZES]; /* Different token sizes */
+ __u8 num_encoding_sizes; /* Number of entry in the list */
+ __u8 max_encoding_tokens; /* Max number of tokens */
+ /* For drivers that need a "login/passwd" form */
+ __u8 encoding_login_index; /* token index for login token */
+
+ /* Transmit power */
+ __u16 txpower_capa; /* What options are supported */
+ __u8 num_txpower; /* Number of entries in the list */
+ __s32 txpower[IW_MAX_TXPOWER]; /* list, in bps */
+
+ /* Wireless Extension version info */
+ __u8 we_version_compiled; /* Must be WIRELESS_EXT */
+ __u8 we_version_source; /* Last update of source */
+
+ /* Retry limits and lifetime */
+ __u16 retry_capa; /* What retry options are supported */
+ __u16 retry_flags; /* How to decode max/min retry limit */
+ __u16 r_time_flags; /* How to decode max/min retry life */
+ __s32 min_retry; /* Minimal number of retries */
+ __s32 max_retry; /* Maximal number of retries */
+ __s32 min_r_time; /* Minimal retry lifetime */
+ __s32 max_r_time; /* Maximal retry lifetime */
+
+ /* Frequency */
+ __u16 num_channels; /* Number of channels [0; num - 1] */
+ __u8 num_frequency; /* Number of entry in the list */
+ struct iw_freq freq[IW_MAX_FREQUENCIES]; /* list */
+ /* Note : this frequency list doesn't need to fit channel numbers,
+ * because each entry contain its channel index */
+
+ __u32 enc_capa; /* IW_ENC_CAPA_* bit field */
+};
+
+/*
+ * Private ioctl interface information
+ */
+
+struct iw_priv_args
+{
+ __u32 cmd; /* Number of the ioctl to issue */
+ __u16 set_args; /* Type and number of args */
+ __u16 get_args; /* Type and number of args */
+ char name[IFNAMSIZ]; /* Name of the extension */
+};
+
+/* ----------------------- WIRELESS EVENTS ----------------------- */
+/*
+ * Wireless events are carried through the rtnetlink socket to user
+ * space. They are encapsulated in the IFLA_WIRELESS field of
+ * a RTM_NEWLINK message.
+ */
+
+/*
+ * A Wireless Event. Contains basically the same data as the ioctl...
+ */
+struct iw_event
+{
+ __u16 len; /* Real lenght of this stuff */
+ __u16 cmd; /* Wireless IOCTL */
+ union iwreq_data u; /* IOCTL fixed payload */
+};
+
+/* Size of the Event prefix (including padding and alignement junk) */
+#define IW_EV_LCP_LEN (sizeof(struct iw_event) - sizeof(union iwreq_data))
+/* Size of the various events */
+#define IW_EV_CHAR_LEN (IW_EV_LCP_LEN + IFNAMSIZ)
+#define IW_EV_UINT_LEN (IW_EV_LCP_LEN + sizeof(__u32))
+#define IW_EV_FREQ_LEN (IW_EV_LCP_LEN + sizeof(struct iw_freq))
+#define IW_EV_PARAM_LEN (IW_EV_LCP_LEN + sizeof(struct iw_param))
+#define IW_EV_ADDR_LEN (IW_EV_LCP_LEN + sizeof(struct sockaddr))
+#define IW_EV_QUAL_LEN (IW_EV_LCP_LEN + sizeof(struct iw_quality))
+
+/* iw_point events are special. First, the payload (extra data) come at
+ * the end of the event, so they are bigger than IW_EV_POINT_LEN. Second,
+ * we omit the pointer, so start at an offset. */
+#define IW_EV_POINT_OFF (((char *) &(((struct iw_point *) NULL)->length)) - \
+ (char *) NULL)
+#define IW_EV_POINT_LEN (IW_EV_LCP_LEN + sizeof(struct iw_point) - \
+ IW_EV_POINT_OFF)
+
+#endif /* _LINUX_WIRELESS_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index c9ff319..074cb80 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -56,10 +56,10 @@ int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
hmac_sha1(key, 16, buf, len, hash);
os_memcpy(mic, hash, MD5_MAC_LEN);
break;
-#ifdef CONFIG_IEEE80211R
+#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 */
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
default:
return -1;
}
diff --git a/src/crypto/.gitignore b/src/crypto/.gitignore
deleted file mode 100644
index a438335..0000000
--- a/src/crypto/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.d
diff --git a/src/crypto/crypto_cryptoapi.c b/src/crypto/crypto_cryptoapi.c
index bb05730..45333dd 100644
--- a/src/crypto/crypto_cryptoapi.c
+++ b/src/crypto/crypto_cryptoapi.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / Crypto wrapper for Microsoft CryptoAPI
- * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ * Crypto wrapper for Microsoft CryptoAPI
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -40,12 +40,6 @@ L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
* define here whatever extra is needed.
*/
-static PCCERT_CONTEXT WINAPI
-(*CertCreateCertificateContext)(DWORD dwCertEncodingType,
- const BYTE *pbCertEncoded,
- DWORD cbCertEncoded)
-= NULL; /* to be loaded from crypt32.dll */
-
static BOOL WINAPI
(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType,
PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
@@ -59,7 +53,7 @@ static int mingw_load_crypto_func(void)
/* MinGW does not yet have full CryptoAPI support, so load the needed
* function here. */
- if (CertCreateCertificateContext)
+ if (CryptImportPublicKeyInfo)
return 0;
dll = LoadLibrary("crypt32");
@@ -69,15 +63,6 @@ static int mingw_load_crypto_func(void)
return -1;
}
- CertCreateCertificateContext = (void *) GetProcAddress(
- dll, "CertCreateCertificateContext");
- if (CertCreateCertificateContext == NULL) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
- "CertCreateCertificateContext() address from "
- "crypt32 library");
- return -1;
- }
-
CryptImportPublicKeyInfo = GetProcAddress(
dll, "CryptImportPublicKeyInfo");
if (CryptImportPublicKeyInfo == NULL) {
diff --git a/src/crypto/crypto_gnutls.c b/src/crypto/crypto_gnutls.c
index 8023965..8f8611c 100644
--- a/src/crypto/crypto_gnutls.c
+++ b/src/crypto/crypto_gnutls.c
@@ -57,7 +57,6 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
}
-#ifdef EAP_TLS_FUNCS
void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
gcry_md_hd_t hd;
@@ -162,7 +161,6 @@ void aes_decrypt_deinit(void *ctx)
gcry_cipher_hd_t hd = ctx;
gcry_cipher_close(hd);
}
-#endif /* EAP_TLS_FUNCS */
int crypto_mod_exp(const u8 *base, size_t base_len,
diff --git a/src/crypto/crypto_internal.c b/src/crypto/crypto_internal.c
index a601cbf..cddfb4d 100644
--- a/src/crypto/crypto_internal.c
+++ b/src/crypto/crypto_internal.c
@@ -25,7 +25,7 @@
#include "tls/asn1.h"
-#ifdef EAP_TLS_FUNCS
+#ifdef CONFIG_CRYPTO_INTERNAL
#ifdef CONFIG_TLS_INTERNAL
@@ -435,6 +435,7 @@ struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
}
+#ifdef EAP_TLS_FUNCS
static struct crypto_private_key *
crypto_pkcs8_key_import(const u8 *buf, size_t len)
{
@@ -536,6 +537,7 @@ crypto_pkcs8_key_import(const u8 *buf, size_t len)
return (struct crypto_private_key *)
crypto_rsa_import_private_key(hdr.payload, hdr.length);
}
+#endif /* EAP_TLS_FUNCS */
struct crypto_private_key * crypto_private_key_import(const u8 *key,
@@ -788,6 +790,7 @@ int crypto_global_init(void)
void crypto_global_deinit(void)
{
}
+#endif /* CONFIG_TLS_INTERNAL */
#if defined(EAP_FAST) || defined(CONFIG_WPS)
@@ -830,6 +833,4 @@ error:
#endif /* EAP_FAST || CONFIG_WPS */
-#endif /* CONFIG_TLS_INTERNAL */
-
-#endif /* EAP_TLS_FUNCS */
+#endif /* CONFIG_CRYPTO_INTERNAL */
diff --git a/src/crypto/dh_groups.c b/src/crypto/dh_groups.c
index e351632..5f6008a 100644
--- a/src/crypto/dh_groups.c
+++ b/src/crypto/dh_groups.c
@@ -19,6 +19,8 @@
#include "dh_groups.h"
+#ifdef ALL_DH_GROUPS
+
/* RFC 4306, B.1. Group 1 - 768 Bit MODP
* Generator: 2
* Prime: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 }
@@ -63,6 +65,8 @@ static const u8 dh_group2_prime[128] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+#endif /* ALL_DH_GROUPS */
+
/* RFC 3526, 2. Group 5 - 1536 Bit MODP
* Generator: 2
* Prime: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }
@@ -95,6 +99,8 @@ static const u8 dh_group5_prime[192] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+#ifdef ALL_DH_GROUPS
+
/* RFC 3526, 3. Group 14 - 2048 Bit MODP
* Generator: 2
* Prime: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }
@@ -503,6 +509,8 @@ static const u8 dh_group18_prime[1024] = {
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
};
+#endif /* ALL_DH_GROUPS */
+
#define DH_GROUP(id) \
{ id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \
@@ -510,14 +518,16 @@ dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime) }
static struct dh_group dh_groups[] = {
+ DH_GROUP(5),
+#ifdef ALL_DH_GROUPS
DH_GROUP(1),
DH_GROUP(2),
- DH_GROUP(5),
DH_GROUP(14),
DH_GROUP(15),
DH_GROUP(16),
DH_GROUP(17),
DH_GROUP(18)
+#endif /* ALL_DH_GROUPS */
};
#define NUM_DH_GROUPS (sizeof(dh_groups) / sizeof(dh_groups[0]))
diff --git a/src/crypto/ms_funcs.c b/src/crypto/ms_funcs.c
index c14af64..7e2f0fa 100644
--- a/src/crypto/ms_funcs.c
+++ b/src/crypto/ms_funcs.c
@@ -379,7 +379,7 @@ int encrypt_pw_block_with_password_hash(
*/
pos = &pw_block[2 * 256];
WPA_PUT_LE16(pos, password_len * 2);
- rc4(pw_block, PWBLOCK_LEN, password_hash, 16);
+ rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
return 0;
}
diff --git a/src/crypto/rc4.c b/src/crypto/rc4.c
index 8480cc5..70c790e 100644
--- a/src/crypto/rc4.c
+++ b/src/crypto/rc4.c
@@ -68,19 +68,3 @@ void rc4_skip(const u8 *key, size_t keylen, size_t skip,
*pos++ ^= S[(S[i] + S[j]) & 0xff];
}
}
-
-
-/**
- * rc4 - XOR RC4 stream to given data
- * @buf: data to be XOR'ed with RC4 stream
- * @len: buf length
- * @key: RC4 key
- * @key_len: RC4 key length
- *
- * Generate RC4 pseudo random stream for the given key and XOR this with the
- * data buffer to perform RC4 encryption/decryption.
- */
-void rc4(u8 *buf, size_t len, const u8 *key, size_t key_len)
-{
- rc4_skip(key, key_len, 0, buf, len);
-}
diff --git a/src/crypto/rc4.h b/src/crypto/rc4.h
index 01f1383..35c7e41 100644
--- a/src/crypto/rc4.h
+++ b/src/crypto/rc4.h
@@ -17,6 +17,5 @@
void rc4_skip(const u8 *key, size_t keylen, size_t skip,
u8 *data, size_t data_len);
-void rc4(u8 *buf, size_t len, const u8 *key, size_t key_len);
#endif /* RC4_H */
diff --git a/src/crypto/sha1.c b/src/crypto/sha1.c
index ceec1a4..141e4f4 100644
--- a/src/crypto/sha1.c
+++ b/src/crypto/sha1.c
@@ -606,8 +606,8 @@ static void SHA1Transform(u32 state[5], const unsigned char buffer[64])
} CHAR64LONG16;
CHAR64LONG16* block;
#ifdef SHA1HANDSOFF
- u32 workspace[16];
- block = (CHAR64LONG16 *) workspace;
+ CHAR64LONG16 workspace;
+ block = &workspace;
os_memcpy(block, buffer, 64);
#else
block = (CHAR64LONG16 *) buffer;
diff --git a/src/crypto/sha256.c b/src/crypto/sha256.c
index 3d3958f..96dac0e 100644
--- a/src/crypto/sha256.c
+++ b/src/crypto/sha256.c
@@ -122,7 +122,7 @@ void hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
void sha256_prf(const u8 *key, size_t key_len, const char *label,
const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
{
- u16 counter = 0;
+ u16 counter = 1;
size_t pos, plen;
u8 hash[SHA256_MAC_LEN];
const u8 *addr[4];
diff --git a/src/crypto/tls.h b/src/crypto/tls.h
index dafe8bb..aafb7999 100644
--- a/src/crypto/tls.h
+++ b/src/crypto/tls.h
@@ -34,6 +34,9 @@ struct tls_config {
const char *pkcs11_module_path;
};
+#define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0)
+#define TLS_CONN_DISABLE_TIME_CHECKS BIT(1)
+
/**
* struct tls_connection_params - Parameters for TLS connection
* @ca_cert: File or reference name for CA X.509 certificate in PEM or DER
@@ -68,6 +71,7 @@ struct tls_config {
* @cert_id: the certificate's id when using engine
* @ca_cert_id: the CA certificate's id when using engine
* @tls_ia: Whether to enable TLS/IA (for EAP-TTLSv1)
+ * @flags: Parameter options (TLS_CONN_*)
*
* TLS connection parameters to be configured with tls_connection_set_params()
* and tls_global_set_params().
@@ -103,6 +107,8 @@ struct tls_connection_params {
const char *key_id;
const char *cert_id;
const char *ca_cert_id;
+
+ unsigned int flags;
};
diff --git a/src/crypto/tls_gnutls.c b/src/crypto/tls_gnutls.c
index db66ae1..2c5c5a2 100644
--- a/src/crypto/tls_gnutls.c
+++ b/src/crypto/tls_gnutls.c
@@ -35,8 +35,12 @@ int gnutls_ia_verify_endphase(gnutls_session_t session, char *checksum);
#include "tls.h"
+#ifndef TLS_RANDOM_SIZE
#define TLS_RANDOM_SIZE 32
+#endif
+#ifndef TLS_MASTER_SIZE
#define TLS_MASTER_SIZE 48
+#endif
#if LIBGNUTLS_VERSION_NUMBER < 0x010302
@@ -591,6 +595,17 @@ int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
return -1;
}
}
+
+ if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
+ gnutls_certificate_set_verify_flags(
+ conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
+ }
+
+ if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
+ gnutls_certificate_set_verify_flags(
+ conn->xcred,
+ GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
+ }
}
if (params->client_cert && params->private_key) {
@@ -711,6 +726,18 @@ int tls_global_set_params(void *tls_ctx,
goto fail;
}
}
+
+ if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
+ gnutls_certificate_set_verify_flags(
+ global->xcred,
+ GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
+ }
+
+ if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
+ gnutls_certificate_set_verify_flags(
+ global->xcred,
+ GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
+ }
}
if (params->client_cert && params->private_key) {
@@ -843,7 +870,8 @@ int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
}
-static int tls_connection_verify_peer(struct tls_connection *conn)
+static int tls_connection_verify_peer(struct tls_connection *conn,
+ gnutls_alert_description_t *err)
{
unsigned int status, num_certs, i;
struct os_time now;
@@ -853,22 +881,39 @@ static int tls_connection_verify_peer(struct tls_connection *conn)
if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
"certificate chain");
+ *err = GNUTLS_A_INTERNAL_ERROR;
return -1;
}
if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
+ if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
+ wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
+ "algorithm");
+ *err = GNUTLS_A_INSUFFICIENT_SECURITY;
+ }
+ if (status & GNUTLS_CERT_NOT_ACTIVATED) {
+ wpa_printf(MSG_INFO, "TLS: Certificate not yet "
+ "activated");
+ *err = GNUTLS_A_CERTIFICATE_EXPIRED;
+ }
+ if (status & GNUTLS_CERT_EXPIRED) {
+ wpa_printf(MSG_INFO, "TLS: Certificate expired");
+ *err = GNUTLS_A_CERTIFICATE_EXPIRED;
+ }
return -1;
}
if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
"known issuer");
+ *err = GNUTLS_A_UNKNOWN_CA;
return -1;
}
if (status & GNUTLS_CERT_REVOKED) {
wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
+ *err = GNUTLS_A_CERTIFICATE_REVOKED;
return -1;
}
@@ -878,6 +923,7 @@ static int tls_connection_verify_peer(struct tls_connection *conn)
if (certs == NULL) {
wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
"received");
+ *err = GNUTLS_A_UNKNOWN_CA;
return -1;
}
@@ -887,6 +933,7 @@ static int tls_connection_verify_peer(struct tls_connection *conn)
if (gnutls_x509_crt_init(&cert) < 0) {
wpa_printf(MSG_INFO, "TLS: Certificate initialization "
"failed");
+ *err = GNUTLS_A_BAD_CERTIFICATE;
return -1;
}
@@ -895,6 +942,7 @@ static int tls_connection_verify_peer(struct tls_connection *conn)
wpa_printf(MSG_INFO, "TLS: Could not parse peer "
"certificate %d/%d", i + 1, num_certs);
gnutls_x509_crt_deinit(cert);
+ *err = GNUTLS_A_BAD_CERTIFICATE;
return -1;
}
@@ -920,6 +968,7 @@ static int tls_connection_verify_peer(struct tls_connection *conn)
"not valid at this time",
i + 1, num_certs);
gnutls_x509_crt_deinit(cert);
+ *err = GNUTLS_A_CERTIFICATE_EXPIRED;
return -1;
}
@@ -981,19 +1030,24 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
}
} else {
size_t size;
+ gnutls_alert_description_t err;
- if (conn->verify_peer && tls_connection_verify_peer(conn)) {
+ if (conn->verify_peer &&
+ tls_connection_verify_peer(conn, &err)) {
wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
"failed validation");
conn->failed++;
- return NULL;
+ gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err);
+ goto out;
}
+#ifdef CONFIG_GNUTLS_EXTRA
if (conn->tls_ia && !gnutls_ia_handshake_p(conn->session)) {
wpa_printf(MSG_INFO, "TLS: No TLS/IA negotiation");
conn->failed++;
return NULL;
}
+#endif /* CONFIG_GNUTLS_EXTRA */
if (conn->tls_ia)
wpa_printf(MSG_DEBUG, "TLS: Start TLS/IA handshake");
@@ -1021,6 +1075,7 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
}
}
+out:
out_data = conn->push_buf;
*out_len = conn->push_buf_len;
conn->push_buf = NULL;
diff --git a/src/crypto/tls_openssl.c b/src/crypto/tls_openssl.c
index f290a39..b5a1d64 100644
--- a/src/crypto/tls_openssl.c
+++ b/src/crypto/tls_openssl.c
@@ -108,71 +108,9 @@ static void tls_show_errors(int level, const char *func, const char *txt)
* MinGW does not yet include all the needed definitions for CryptoAPI, so
* define here whatever extra is needed.
*/
-#define CALG_SSL3_SHAMD5 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SSL3SHAMD5)
#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16)
#define CERT_STORE_READONLY_FLAG 0x00008000
#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
-#define CRYPT_ACQUIRE_COMPARE_KEY_FLAG 0x00000004
-
-static BOOL WINAPI
-(*CryptAcquireCertificatePrivateKey)(PCCERT_CONTEXT pCert, DWORD dwFlags,
- void *pvReserved, HCRYPTPROV *phCryptProv,
- DWORD *pdwKeySpec, BOOL *pfCallerFreeProv)
-= NULL; /* to be loaded from crypt32.dll */
-
-#ifdef CONFIG_MINGW32_LOAD_CERTENUM
-static PCCERT_CONTEXT WINAPI
-(*CertEnumCertificatesInStore)(HCERTSTORE hCertStore,
- PCCERT_CONTEXT pPrevCertContext)
-= NULL; /* to be loaded from crypt32.dll */
-#endif /* CONFIG_MINGW32_LOAD_CERTENUM */
-
-static int mingw_load_crypto_func(void)
-{
- HINSTANCE dll;
-
- /* MinGW does not yet have full CryptoAPI support, so load the needed
- * function here. */
-
- if (CryptAcquireCertificatePrivateKey)
- return 0;
-
- dll = LoadLibrary("crypt32");
- if (dll == NULL) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
- "library");
- return -1;
- }
-
- CryptAcquireCertificatePrivateKey = GetProcAddress(
- dll, "CryptAcquireCertificatePrivateKey");
- if (CryptAcquireCertificatePrivateKey == NULL) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
- "CryptAcquireCertificatePrivateKey() address from "
- "crypt32 library");
- return -1;
- }
-
-#ifdef CONFIG_MINGW32_LOAD_CERTENUM
- CertEnumCertificatesInStore = (void *) GetProcAddress(
- dll, "CertEnumCertificatesInStore");
- if (CertEnumCertificatesInStore == NULL) {
- wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
- "CertEnumCertificatesInStore() address from "
- "crypt32 library");
- return -1;
- }
-#endif /* CONFIG_MINGW32_LOAD_CERTENUM */
-
- return 0;
-}
-
-#else /* __MINGW32_VERSION */
-
-static int mingw_load_crypto_func(void)
-{
- return 0;
-}
#endif /* __MINGW32_VERSION */
@@ -403,9 +341,6 @@ static int tls_cryptoapi_cert(SSL *ssl, const char *name)
goto err;
}
- if (mingw_load_crypto_func())
- goto err;
-
if (!CryptAcquireCertificatePrivateKey(priv->cert,
CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
NULL, &priv->crypt_prov,
@@ -476,9 +411,6 @@ static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
WCHAR *wstore;
#endif /* UNICODE */
- if (mingw_load_crypto_func())
- return -1;
-
if (name == NULL || strncmp(name, "cert_store://", 13) != 0)
return -1;
@@ -735,11 +667,23 @@ void * tls_init(const struct tls_config *conf)
if (tls_openssl_ref_count == 0) {
SSL_load_error_strings();
SSL_library_init();
+#ifndef OPENSSL_NO_SHA256
+ EVP_add_digest(EVP_sha256());
+#endif /* OPENSSL_NO_SHA256 */
/* TODO: if /dev/urandom is available, PRNG is seeded
* automatically. If this is not the case, random data should
* be added here. */
#ifdef PKCS12_FUNCS
+#ifndef OPENSSL_NO_RC2
+ /*
+ * 40-bit RC2 is commonly used in PKCS#12 files, so enable it.
+ * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8
+ * versions, but it looks like OpenSSL 1.0.0 does not do that
+ * anymore.
+ */
+ EVP_add_cipher(EVP_rc2_40_cbc());
+#endif /* OPENSSL_NO_RC2 */
PKCS12_PBE_add();
#endif /* PKCS12_FUNCS */
}
@@ -2105,9 +2049,18 @@ u8 * tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
if (*appl_data) {
res = SSL_read(conn->ssl, *appl_data, in_len);
if (res < 0) {
- tls_show_errors(MSG_INFO, __func__,
- "Failed to read possible "
- "Application Data");
+ 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");
+ }
os_free(*appl_data);
*appl_data = NULL;
} else {
diff --git a/src/drivers/Apple80211.h b/src/drivers/Apple80211.h
new file mode 100644
index 0000000..2a612e7
--- /dev/null
+++ b/src/drivers/Apple80211.h
@@ -0,0 +1,156 @@
+#ifndef APPLE80211_H
+#define APPLE80211_H
+
+/*
+ * Apple80211 framework definitions
+ * This is an undocumented interface and the definitions here are based on
+ * information from MacStumbler (http://www.macstumbler.com/Apple80211.h) and
+ * whatever related information can be found with google and experiments ;-).
+ */
+
+typedef struct __WirelessRef *WirelessRef;
+typedef SInt32 WirelessError;
+#define errWirelessNoError 0
+
+typedef struct WirelessInfo {
+ UInt16 link_qual;
+ UInt16 comms_qual;
+ UInt16 signal;
+ UInt16 noise;
+ UInt16 port_stat;
+ UInt16 client_mode;
+ UInt16 res1;
+ UInt16 power;
+ UInt16 res2;
+ UInt8 bssID[6];
+ UInt8 ssid[34];
+} WirelessInfo;
+
+typedef struct WirelessInfo2 {
+ /* TODO - these are probably not in correct order or complete */
+ WirelessInfo info1;
+ UInt8 macAddress[6];
+} WirelessInfo2;
+
+typedef struct WirelessNetworkInfo {
+ UInt16 channel;
+ UInt16 noise;
+ UInt16 signal;
+ UInt8 bssid[6];
+ UInt16 beacon_int;
+ UInt16 capability;
+ UInt16 ssid_len;
+ UInt8 ssid[32];
+} WirelessNetworkInfo;
+
+typedef int wirelessKeyType; /* TODO */
+
+int WirelessIsAvailable(void);
+WirelessError WirelessAttach(WirelessRef *ref, UInt32 res);
+WirelessError WirelessDetach(WirelessRef ref);
+WirelessError WirelessPrivate(WirelessRef ref, void *in_ptr, int in_bytes,
+ void *out_ptr, int out_bytes);
+WirelessError WirelessSetEnabled(WirelessRef ref, UInt8 enabled);
+WirelessError WirelessGetEnabled(WirelessRef ref, UInt8 *enabled);
+WirelessError WirelessSetPower(WirelessRef ref, UInt8 power);
+WirelessError WirelessGetPower(WirelessRef ref, UInt8 *power);
+WirelessError WirelessGetInfo(WirelessRef ref, WirelessInfo *info);
+WirelessError WirelessGetInfo2(WirelessRef ref, WirelessInfo2 *info);
+WirelessError WirelessScan(WirelessRef ref, CFArrayRef *results,
+ UInt32 strip_dups);
+WirelessError WirelessScanSplit(WirelessRef ref, CFArrayRef *ap_results,
+ CFArrayRef *ibss_results, UInt32 strip_dups);
+WirelessError WirelessDirectedScan(WirelessRef ref, CFArrayRef *results,
+ UInt32 strip_dups, CFStringRef ssid);
+WirelessError WirelessDirectedScan2(WirelessRef ref, CFDataRef ssid,
+ UInt32 strip_dups, CFArrayRef *results);
+WirelessError WirelessJoin(WirelessRef ref, CFStringRef ssid);
+WirelessError WirelessJoinWEP(WirelessRef ref, CFStringRef ssid,
+ CFStringRef passwd);
+WirelessError WirelessJoin8021x(WirelessRef ref, CFStringRef ssid);
+/*
+ * Set WEP key
+ * ref: wireless reference from WirelessAttach()
+ * type: ?
+ * key_idx: 0..3
+ * key_len: 13 for WEP-104 or 0 for clearing the key
+ * key: Pointer to the key or %NULL if key_len = 0
+ */
+WirelessError WirelessSetKey(WirelessRef ref, wirelessKeyType type,
+ int key_idx, int key_len,
+ const unsigned char *key);
+/*
+ * Set WPA key (e.g., PMK for 4-way handshake)
+ * ref: wireless reference from WirelessAttach()
+ * type: 0..4; 1 = PMK
+ * key_len: 16, 32, or 0
+ * key: Pointer to the key or %NULL if key_len = 0
+ */
+WirelessError WirelessSetWPAKey(WirelessRef ref, wirelessKeyType type,
+ int key_len, const unsigned char *key);
+WirelessError WirelessAssociate(WirelessRef ref, int type, CFDataRef ssid,
+ CFStringRef key);
+WirelessError WirelessAssociate2(WirelessRef ref, CFDictionaryRef scan_res,
+ CFStringRef key);
+WirelessError WirelessDisassociate(WirelessRef ref);
+
+/*
+ * Get a copy of scan results for the given SSID
+ * The returned dictionary includes following entries:
+ * beaconInterval: CFNumber(kCFNumberSInt32Type)
+ * SSID: CFData buffer of the SSID
+ * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 = WPA2
+ * name: Name of the network (SSID string)
+ * BSSID: CFData buffer of the BSSID
+ * channel: CFNumber(kCFNumberSInt32Type)
+ * signal: CFNumber(kCFNumberSInt32Type)
+ * appleIE: CFData
+ * WPSNOPINRequired: CFBoolean
+ * noise: CFNumber(kCFNumberSInt32Type)
+ * capability: CFNumber(kCFNumberSInt32Type)
+ * uniCipher: CFArray of CFNumber(kCFNumberSInt32Type)
+ * appleIE_Version: CFNumber(kCFNumberSInt32Type)
+ * appleIE_Robust: CFBoolean
+ * WPSConfigured: CFBoolean
+ * scanWasDirected: CFBoolean
+ * appleIE_Product: CFNumber(kCFNumberSInt32Type)
+ * authModes: CFArray of CFNumber(kCFNumberSInt32Type)
+ * multiCipher: CFNumber(kCFNumberSInt32Type)
+ */
+CFDictionaryRef WirelessSafeDirectedScanCopy(WirelessRef ref, CFDataRef ssid);
+
+/*
+ * Get information about the current association
+ * The returned dictionary includes following entries:
+ * keyData: CFData buffer of the key (e.g., 32-octet PSK)
+ * multiCipher: CFNumber(kCFNumberSInt32Type); 0 = none, 5 = CCMP?
+ * channel: CFNumber(kCFNumberSInt32Type)
+ * isIBSS: CFBoolean
+ * authMode: CFNumber(kCFNumberSInt32Type); 2 = WPA-Personal; 3 = open,
+ * 129 = WPA2-Enterprise
+ * isWPA: CFNumber(kCFNumberSInt32Type); 0 = not used, 1 = WPA, -128 == WPA2
+ * SSID: CFData buffer of the SSID
+ * cipherMode: CFNumber(kCFNumberSInt32Type); 0 = none, 4 = CCMP?
+ */
+CFDictionaryRef WirelessGetAssociationInfo(WirelessRef ref);
+
+WirelessError WirelessConfigure(WirelessRef ref);
+
+/*
+ * Get ASP information
+ * The returned dictionary includes following entries:
+ * Version: version number (e.g., 3.0)
+ * Channel: channel (e.g., 1)
+ * Vendor: vendor (e.g., 2)
+ */
+CFDictionaryRef WirelessGetInfoASP(void);
+
+/*
+ * Get a copy of the interface dictionary
+ * The returned dictionary has a key,value pairs for wireless interfaces.
+ * The key is the interface name and the value is the driver identifier, e.g.,
+ * en1: com.apple.driver.AirPort.Atheros
+ */
+CFDictionaryRef WirelessCopyInterfaceDict(void);
+
+#endif /* APPLE80211_H */
diff --git a/src/drivers/Makefile b/src/drivers/Makefile
new file mode 100644
index 0000000..cffba62
--- /dev/null
+++ b/src/drivers/Makefile
@@ -0,0 +1,9 @@
+all:
+ @echo Nothing to be made.
+
+clean:
+ for d in $(SUBDIRS); do make -C $$d clean; done
+ rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
diff --git a/src/drivers/MobileApple80211.c b/src/drivers/MobileApple80211.c
new file mode 100644
index 0000000..ce004fe
--- /dev/null
+++ b/src/drivers/MobileApple80211.c
@@ -0,0 +1,189 @@
+#include "includes.h"
+#include <dlfcn.h>
+
+#include "common.h"
+
+#include <CoreFoundation/CoreFoundation.h>
+#include "MobileApple80211.h"
+
+/*
+ * Code for dynamically loading Apple80211 functions from Aeropuerto to avoid
+ * having to link with full Preferences.framework.
+ */
+
+static void *aeropuerto = NULL;
+
+
+int _Apple80211Initialized(void)
+{
+ return aeropuerto ? 1 : 0;
+}
+
+
+static int (*__Apple80211Open)(Apple80211Ref *ctx) = NULL;
+
+int Apple80211Open(Apple80211Ref *ctx)
+{
+ return __Apple80211Open(ctx);
+}
+
+
+static int (*__Apple80211Close)(Apple80211Ref ctx) = NULL;
+
+int Apple80211Close(Apple80211Ref ctx)
+{
+ return __Apple80211Close(ctx);
+}
+
+
+static int (*__Apple80211GetIfListCopy)(Apple80211Ref handle, CFArrayRef *list)
+ = NULL;
+
+int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list)
+{
+ return __Apple80211GetIfListCopy(handle, list);
+}
+
+
+static int (*__Apple80211BindToInterface)(Apple80211Ref handle,
+ CFStringRef interface) = NULL;
+
+int Apple80211BindToInterface(Apple80211Ref handle,
+ CFStringRef interface)
+{
+ return __Apple80211BindToInterface(handle, interface);
+}
+
+
+static int (*__Apple80211GetInterfaceNameCopy)(Apple80211Ref handle,
+ CFStringRef *name) = NULL;
+
+int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
+ CFStringRef *name)
+{
+ return __Apple80211GetInterfaceNameCopy(handle, name);
+}
+
+
+static int (*__Apple80211GetInfoCopy)(Apple80211Ref handle,
+ CFDictionaryRef *info) = NULL;
+
+int Apple80211GetInfoCopy(Apple80211Ref handle,
+ CFDictionaryRef *info)
+{
+ return __Apple80211GetInfoCopy(handle, info);
+}
+
+
+static int (*__Apple80211GetPower)(Apple80211Ref handle, char *pwr) = NULL;
+
+int Apple80211GetPower(Apple80211Ref handle, char *pwr)
+{
+ return __Apple80211GetPower(handle, pwr);
+}
+
+
+static int (*__Apple80211SetPower)(Apple80211Ref handle, char pwr) = NULL;
+
+int Apple80211SetPower(Apple80211Ref handle, char pwr)
+{
+ return __Apple80211SetPower(handle, pwr);
+}
+
+
+static int (*__Apple80211Scan)(Apple80211Ref handle, CFArrayRef *list,
+ CFDictionaryRef parameters) = NULL;
+
+int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
+ CFDictionaryRef parameters)
+{
+ return __Apple80211Scan(handle, list, parameters);
+}
+
+
+static int (*__Apple80211Associate)(Apple80211Ref handle, CFDictionaryRef bss,
+ CFStringRef password) = NULL;
+
+int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
+ CFStringRef password)
+{
+ return __Apple80211Associate(handle, bss, password);
+}
+
+
+static int (*__Apple80211AssociateAndCopyInfo)(Apple80211Ref handle,
+ CFDictionaryRef bss,
+ CFStringRef password,
+ CFDictionaryRef *info) =
+ NULL;
+
+int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
+ CFStringRef password, CFDictionaryRef *info)
+{
+ return __Apple80211AssociateAndCopyInfo(handle, bss, password, info);
+}
+
+
+static int (*__Apple80211CopyValue)(Apple80211Ref handle, int field,
+ CFDictionaryRef arg2, void *value) = NULL;
+
+int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
+ void *value)
+{
+ return __Apple80211CopyValue(handle, field, arg2, value);
+}
+
+
+#define DLSYM(s) \
+do { \
+ __ ## s = dlsym(aeropuerto, #s); \
+ if (__ ## s == NULL) { \
+ wpa_printf(MSG_ERROR, "MobileApple80211: Could not resolve " \
+ "symbol '" #s "' (%s)", dlerror()); \
+ err = 1; \
+ } \
+} while (0)
+
+
+__attribute__ ((constructor))
+void _Apple80211_constructor(void)
+{
+ const char *fname = "/System/Library/SystemConfiguration/"
+ "Aeropuerto.bundle/Aeropuerto";
+ int err = 0;
+
+ aeropuerto = dlopen(fname, RTLD_LAZY);
+ if (!aeropuerto) {
+ wpa_printf(MSG_ERROR, "MobileApple80211: Failed to open %s "
+ "for symbols", fname);
+ return;
+ }
+
+ DLSYM(Apple80211Open);
+ DLSYM(Apple80211Close);
+ DLSYM(Apple80211GetIfListCopy);
+ DLSYM(Apple80211BindToInterface);
+ DLSYM(Apple80211GetInterfaceNameCopy);
+ DLSYM(Apple80211GetInfoCopy);
+ DLSYM(Apple80211GetPower);
+ DLSYM(Apple80211SetPower);
+ DLSYM(Apple80211Scan);
+ DLSYM(Apple80211Associate);
+ DLSYM(Apple80211AssociateAndCopyInfo);
+ DLSYM(Apple80211CopyValue);
+
+ if (err) {
+ dlclose(aeropuerto);
+ aeropuerto = NULL;
+ }
+}
+
+
+__attribute__ ((destructor))
+void _Apple80211_destructor(void)
+{
+ if (aeropuerto) {
+ dlclose(aeropuerto);
+ aeropuerto = NULL;
+ }
+}
diff --git a/src/drivers/MobileApple80211.h b/src/drivers/MobileApple80211.h
new file mode 100644
index 0000000..64d439d
--- /dev/null
+++ b/src/drivers/MobileApple80211.h
@@ -0,0 +1,43 @@
+#ifndef MOBILEAPPLE80211_H
+#define MOBILEAPPLE80211_H
+
+/*
+ * MobileApple80211 interface for iPhone/iPod touch
+ * These functions are available from Aeropuerto.
+ */
+
+struct Apple80211;
+typedef struct Apple80211 *Apple80211Ref;
+
+int Apple80211Open(Apple80211Ref *ctx);
+int Apple80211Close(Apple80211Ref ctx);
+int Apple80211GetIfListCopy(Apple80211Ref handle, CFArrayRef *list);
+int Apple80211BindToInterface(Apple80211Ref handle,
+ CFStringRef interface);
+int Apple80211GetInterfaceNameCopy(Apple80211Ref handle,
+ CFStringRef *name);
+int Apple80211GetInfoCopy(Apple80211Ref handle,
+ CFDictionaryRef *info);
+int Apple80211GetPower(Apple80211Ref handle, char *pwr);
+int Apple80211SetPower(Apple80211Ref handle, char pwr);
+
+/* parameters can be NULL; returns scan results in CFArrayRef *list;
+ * caller will need to free with CFRelease() */
+int Apple80211Scan(Apple80211Ref handle, CFArrayRef *list,
+ CFDictionaryRef parameters);
+
+int Apple80211Associate(Apple80211Ref handle, CFDictionaryRef bss,
+ CFStringRef password);
+int Apple80211AssociateAndCopyInfo(Apple80211Ref handle, CFDictionaryRef bss,
+ CFStringRef password,
+ CFDictionaryRef *info);
+
+enum {
+ APPLE80211_VALUE_SSID = 1,
+ APPLE80211_VALUE_BSSID = 9
+};
+
+int Apple80211CopyValue(Apple80211Ref handle, int field, CFDictionaryRef arg2,
+ void *value);
+
+#endif /* MOBILEAPPLE80211_H */
diff --git a/src/drivers/driver.h b/src/drivers/driver.h
index 9bce6c6..c2975d2 100644
--- a/src/drivers/driver.h
+++ b/src/drivers/driver.h
@@ -131,7 +131,7 @@ struct wpa_scan_results {
* @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_bame: struct wpa_driver_ops::name (note: unlike other strings, this one
+ * @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)
*/
@@ -702,7 +702,7 @@ struct wpa_driver_ops {
int (*flush_pmkid)(void *priv);
/**
- * flush_pmkid - Flush PMKSA cache
+ * get_capa - Get driver capabilities
* @priv: private driver interface data
*
* Returns: 0 on success, -1 on failure
diff --git a/src/drivers/driver_atmel.c b/src/drivers/driver_atmel.c
new file mode 100644
index 0000000..0a7a66d
--- /dev/null
+++ b/src/drivers/driver_atmel.c
@@ -0,0 +1,506 @@
+/*
+ * WPA Supplicant - Driver interaction with Atmel Wireless LAN drivers
+ * Copyright (c) 2000-2005, ATMEL Corporation
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+/******************************************************************************
+ Copyright 2000-2001 ATMEL Corporation.
+
+ WPA Supplicant - driver interaction with Atmel Wireless lan drivers.
+
+ This is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Atmel wireless lan drivers; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+******************************************************************************/
+
+/*
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "driver_wext.h"
+
+struct wpa_driver_atmel_data {
+ void *wext; /* private data for driver_wext */
+ void *ctx;
+ char ifname[IFNAMSIZ + 1];
+ int sock;
+};
+
+
+#define ATMEL_WPA_IOCTL (SIOCIWFIRSTPRIV + 2)
+#define ATMEL_WPA_IOCTL_PARAM (SIOCIWFIRSTPRIV + 3)
+#define ATMEL_WPA_IOCTL_GET_PARAM (SIOCIWFIRSTPRIV + 4)
+
+
+/* ATMEL_WPA_IOCTL ioctl() cmd: */
+enum {
+ SET_WPA_ENCRYPTION = 1,
+ SET_CIPHER_SUITES = 2,
+ MLME_STA_DEAUTH = 3,
+ MLME_STA_DISASSOC = 4
+};
+
+/* ATMEL_WPA_IOCTL_PARAM ioctl() cmd: */
+enum {
+ ATMEL_PARAM_WPA = 1,
+ ATMEL_PARAM_PRIVACY_INVOKED = 2,
+ ATMEL_PARAM_WPA_TYPE = 3
+};
+
+#define MAX_KEY_LENGTH 40
+
+struct atmel_param{
+ unsigned char sta_addr[6];
+ int cmd;
+ u8 alg;
+ u8 key_idx;
+ u8 set_tx;
+ u8 seq[8];
+ u8 seq_len;
+ u16 key_len;
+ u8 key[MAX_KEY_LENGTH];
+ struct{
+ int reason_code;
+ u8 state;
+ }mlme;
+ u8 pairwise_suite;
+ u8 group_suite;
+ u8 key_mgmt_suite;
+};
+
+
+
+static int atmel_ioctl(struct wpa_driver_atmel_data *drv,
+ struct atmel_param *param,
+ int len, int show_err)
+{
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) param;
+ iwr.u.data.length = len;
+
+ if (ioctl(drv->sock, ATMEL_WPA_IOCTL, &iwr) < 0) {
+ int ret;
+ ret = errno;
+ if (show_err)
+ perror("ioctl[ATMEL_WPA_IOCTL]");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int atmel2param(struct wpa_driver_atmel_data *drv, int param, int value)
+{
+ struct iwreq iwr;
+ int *i, ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ i = (int *) iwr.u.name;
+ *i++ = param;
+ *i++ = value;
+
+ if (ioctl(drv->sock, ATMEL_WPA_IOCTL_PARAM, &iwr) < 0) {
+ perror("ioctl[ATMEL_WPA_IOCTL_PARAM]");
+ ret = -1;
+ }
+ return ret;
+}
+
+
+#if 0
+static int wpa_driver_atmel_set_wpa_ie(struct wpa_driver_atmel_data *drv,
+ const char *wpa_ie, size_t wpa_ie_len)
+{
+ struct atmel_param *param;
+ int res;
+ size_t blen = ATMEL_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
+ if (blen < sizeof(*param))
+ blen = sizeof(*param);
+
+ param = os_zalloc(blen);
+ if (param == NULL)
+ return -1;
+
+ param->cmd = ATMEL_SET_GENERIC_ELEMENT;
+ param->u.generic_elem.len = wpa_ie_len;
+ os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
+ res = atmel_ioctl(drv, param, blen, 1);
+
+ os_free(param);
+
+ return res;
+}
+#endif
+
+
+static int wpa_driver_atmel_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ int ret = 0;
+
+ printf("wpa_driver_atmel_set_wpa %s\n", drv->ifname);
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+
+#if 0
+ if (!enabled && wpa_driver_atmel_set_wpa_ie(drv, NULL, 0) < 0)
+ ret = -1;
+#endif
+ if (atmel2param(drv, ATMEL_PARAM_PRIVACY_INVOKED, enabled) < 0)
+ ret = -1;
+ if (atmel2param(drv, ATMEL_PARAM_WPA, enabled) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int wpa_driver_atmel_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx,
+ int set_tx, const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ int ret = 0;
+ struct atmel_param *param;
+ u8 *buf;
+ u8 alg_type;
+
+ size_t blen;
+ char *alg_name;
+
+ switch (alg) {
+ case WPA_ALG_NONE:
+ alg_name = "none";
+ alg_type = 0;
+ break;
+ case WPA_ALG_WEP:
+ alg_name = "WEP";
+ alg_type = 1;
+ break;
+ case WPA_ALG_TKIP:
+ alg_name = "TKIP";
+ alg_type = 2;
+ break;
+ case WPA_ALG_CCMP:
+ alg_name = "CCMP";
+ alg_type = 3;
+ break;
+ default:
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
+ "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ if (seq_len > 8)
+ return -2;
+
+ blen = sizeof(*param) + key_len;
+ buf = os_zalloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ param = (struct atmel_param *) buf;
+
+ param->cmd = SET_WPA_ENCRYPTION;
+
+ if (addr == NULL)
+ os_memset(param->sta_addr, 0xff, ETH_ALEN);
+ else
+ os_memcpy(param->sta_addr, addr, ETH_ALEN);
+
+ param->alg = alg_type;
+ param->key_idx = key_idx;
+ param->set_tx = set_tx;
+ os_memcpy(param->seq, seq, seq_len);
+ param->seq_len = seq_len;
+ param->key_len = key_len;
+ os_memcpy((u8 *)param->key, key, key_len);
+
+ if (atmel_ioctl(drv, param, blen, 1)) {
+ wpa_printf(MSG_WARNING, "Failed to set encryption.");
+ /* TODO: show key error*/
+ ret = -1;
+ }
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int wpa_driver_atmel_set_countermeasures(void *priv,
+ int enabled)
+{
+ /* FIX */
+ printf("wpa_driver_atmel_set_countermeasures - not yet "
+ "implemented\n");
+ return 0;
+}
+
+
+static int wpa_driver_atmel_set_drop_unencrypted(void *priv,
+ int enabled)
+{
+ /* FIX */
+ printf("wpa_driver_atmel_set_drop_unencrypted - not yet "
+ "implemented\n");
+ return 0;
+}
+
+
+static int wpa_driver_atmel_mlme(void *priv, const u8 *addr, int cmd,
+ int reason_code)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ struct atmel_param param;
+ int ret;
+ int mgmt_error = 0xaa;
+
+ os_memset(&param, 0, sizeof(param));
+ os_memcpy(param.sta_addr, addr, ETH_ALEN);
+ param.cmd = cmd;
+ param.mlme.reason_code = reason_code;
+ param.mlme.state = mgmt_error;
+ ret = atmel_ioctl(drv, &param, sizeof(param), 1);
+ return ret;
+}
+
+
+#if 0
+static int wpa_driver_atmel_set_suites(struct wpa_driver_atmel_data *drv,
+ u8 pairwise_suite, u8 group_suite,
+ u8 key_mgmt_suite)
+{
+ struct atmel_param param;
+ int ret;
+
+ os_memset(&param, 0, sizeof(param));
+ param.cmd = SET_CIPHER_SUITES;
+ param.pairwise_suite = pairwise_suite;
+ param.group_suite = group_suite;
+ param.key_mgmt_suite = key_mgmt_suite;
+
+ ret = atmel_ioctl(drv, &param, sizeof(param), 1);
+ return ret;
+}
+#endif
+
+
+static int wpa_driver_atmel_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ printf("wpa_driver_atmel_deauthenticate\n");
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_atmel_mlme(drv, addr, MLME_STA_DEAUTH,
+ reason_code);
+
+}
+
+
+static int wpa_driver_atmel_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ printf("wpa_driver_atmel_disassociate\n");
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_atmel_mlme(drv, addr, MLME_STA_DISASSOC,
+ reason_code);
+
+}
+
+
+#if 0
+/* Atmel driver uses specific values for each cipher suite */
+static int convertSuiteToDriver(wpa_cipher suite)
+{
+ u8 suite_type;
+
+ switch(suite) {
+ case CIPHER_NONE:
+ suite_type = 0;
+ break;
+ case CIPHER_WEP40:
+ suite_type = 1;
+ break;
+ case CIPHER_TKIP:
+ suite_type = 2;
+ break;
+ case CIPHER_WEP104:
+ suite_type = 5;
+ break;
+ case CIPHER_CCMP:
+ suite_type = 3;
+ break;
+ default:
+ suite_type = 2;
+ }
+
+ return suite_type;
+
+}
+#endif
+
+static int
+wpa_driver_atmel_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ int ret = 0;
+#if 0
+ u8 pairwise_suite_driver;
+ u8 group_suite_driver;
+ u8 key_mgmt_suite_driver;
+
+ pairwise_suite_driver = convertSuiteToDriver(params->pairwise_suite);
+ group_suite_driver = convertSuiteToDriver(params->group_suite);
+ key_mgmt_suite_driver = convertSuiteToDriver(params->key_mgmt_suite);
+
+ if (wpa_driver_atmel_set_suites(drv, pairwise_suite_driver,
+ group_suite_driver,
+ key_mgmt_suite_driver) < 0){
+ printf("wpa_driver_atmel_set_suites.\n");
+ ret = -1;
+ }
+ if (wpa_driver_wext_set_freq(drv->wext, params->freq) < 0) {
+ printf("wpa_driver_atmel_set_freq.\n");
+ ret = -1;
+ }
+#endif
+ if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len)
+ < 0) {
+ printf("FAILED : wpa_driver_atmel_set_ssid.\n");
+ ret = -1;
+ }
+ if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0) {
+ printf("FAILED : wpa_driver_atmel_set_bssid.\n");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_atmel_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ return wpa_driver_wext_get_bssid(drv->wext, bssid);
+}
+
+
+static int wpa_driver_atmel_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ return wpa_driver_wext_get_ssid(drv->wext, ssid);
+}
+
+
+static int wpa_driver_atmel_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
+}
+
+
+static struct wpa_scan_results * wpa_driver_atmel_get_scan_results(void *priv)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ return wpa_driver_wext_get_scan_results(drv->wext);
+}
+
+
+static int wpa_driver_atmel_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ return wpa_driver_wext_set_operstate(drv->wext, state);
+}
+
+
+static void * wpa_driver_atmel_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_atmel_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->wext = wpa_driver_wext_init(ctx, ifname);
+ if (drv->wext == NULL) {
+ os_free(drv);
+ return NULL;
+ }
+
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->sock < 0) {
+ wpa_driver_wext_deinit(drv->wext);
+ os_free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_atmel_deinit(void *priv)
+{
+ struct wpa_driver_atmel_data *drv = priv;
+ wpa_driver_wext_deinit(drv->wext);
+ close(drv->sock);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_atmel_ops = {
+ .name = "atmel",
+ .desc = "ATMEL AT76C5XXx (USB, PCMCIA)",
+ .get_bssid = wpa_driver_atmel_get_bssid,
+ .get_ssid = wpa_driver_atmel_get_ssid,
+ .set_wpa = wpa_driver_atmel_set_wpa,
+ .set_key = wpa_driver_atmel_set_key,
+ .init = wpa_driver_atmel_init,
+ .deinit = wpa_driver_atmel_deinit,
+ .set_countermeasures = wpa_driver_atmel_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_atmel_set_drop_unencrypted,
+ .scan = wpa_driver_atmel_scan,
+ .get_scan_results2 = wpa_driver_atmel_get_scan_results,
+ .deauthenticate = wpa_driver_atmel_deauthenticate,
+ .disassociate = wpa_driver_atmel_disassociate,
+ .associate = wpa_driver_atmel_associate,
+ .set_operstate = wpa_driver_atmel_set_operstate,
+};
diff --git a/src/drivers/driver_broadcom.c b/src/drivers/driver_broadcom.c
new file mode 100644
index 0000000..3600dae
--- /dev/null
+++ b/src/drivers/driver_broadcom.c
@@ -0,0 +1,604 @@
+/*
+ * WPA Supplicant - driver interaction with old Broadcom wl.o driver
+ * Copyright (c) 2004, Nikki Chumkov <nikki@gattaca.ru>
+ * Copyright (c) 2004, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * Please note that the newer Broadcom driver ("hybrid Linux driver") supports
+ * Linux wireless extensions and does not need (or even work) with this old
+ * driver wrapper. Use driver_wext.c with that driver.
+ */
+
+#include "includes.h"
+
+#include <sys/ioctl.h>
+
+#include "common.h"
+
+#if 0
+#include <netpacket/packet.h>
+#include <net/ethernet.h> /* the L2 protocols */
+#else
+#include <linux/if_packet.h>
+#include <linux/if_ether.h> /* The L2 protocols */
+#endif
+#include <net/if.h>
+#include <typedefs.h>
+
+/* wlioctl.h is a Broadcom header file and it is available, e.g., from Linksys
+ * WRT54G GPL tarball. */
+#include <wlioctl.h>
+
+#include "driver.h"
+#include "eloop.h"
+
+struct wpa_driver_broadcom_data {
+ void *ctx;
+ int ioctl_sock;
+ int event_sock;
+ char ifname[IFNAMSIZ + 1];
+};
+
+
+#ifndef WLC_DEAUTHENTICATE
+#define WLC_DEAUTHENTICATE 143
+#endif
+#ifndef WLC_DEAUTHENTICATE_WITH_REASON
+#define WLC_DEAUTHENTICATE_WITH_REASON 201
+#endif
+#ifndef WLC_SET_TKIP_COUNTERMEASURES
+#define WLC_SET_TKIP_COUNTERMEASURES 202
+#endif
+
+#if !defined(PSK_ENABLED) /* NEW driver interface */
+#define WL_VERSION 360130
+/* wireless authentication bit vector */
+#define WPA_ENABLED 1
+#define PSK_ENABLED 2
+
+#define WAUTH_WPA_ENABLED(wauth) ((wauth) & WPA_ENABLED)
+#define WAUTH_PSK_ENABLED(wauth) ((wauth) & PSK_ENABLED)
+#define WAUTH_ENABLED(wauth) ((wauth) & (WPA_ENABLED | PSK_ENABLED))
+
+#define WSEC_PRIMARY_KEY WL_PRIMARY_KEY
+
+typedef wl_wsec_key_t wsec_key_t;
+#endif
+
+typedef struct {
+ uint32 val;
+ struct ether_addr ea;
+ uint16 res;
+} wlc_deauth_t;
+
+
+static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+
+static int broadcom_ioctl(struct wpa_driver_broadcom_data *drv, int cmd,
+ void *buf, int len)
+{
+ struct ifreq ifr;
+ wl_ioctl_t ioc;
+ int ret = 0;
+
+ wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl(%s,%d,len=%d,val=%p)",
+ drv->ifname, cmd, len, buf);
+ /* wpa_hexdump(MSG_MSGDUMP, "BROADCOM: wlioctl buf", buf, len); */
+
+ ioc.cmd = cmd;
+ ioc.buf = buf;
+ ioc.len = len;
+ os_strlcpy(ifr.ifr_name, drv->ifname, IFNAMSIZ);
+ ifr.ifr_data = (caddr_t) &ioc;
+ if ((ret = ioctl(drv->ioctl_sock, SIOCDEVPRIVATE, &ifr)) < 0) {
+ if (cmd != WLC_GET_MAGIC)
+ perror(ifr.ifr_name);
+ wpa_printf(MSG_MSGDUMP, "BROADCOM: wlioctl cmd=%d res=%d",
+ cmd, ret);
+ }
+
+ return ret;
+}
+
+static int wpa_driver_broadcom_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ if (broadcom_ioctl(drv, WLC_GET_BSSID, bssid, ETH_ALEN) == 0)
+ return 0;
+
+ os_memset(bssid, 0, ETH_ALEN);
+ return -1;
+}
+
+static int wpa_driver_broadcom_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ wlc_ssid_t s;
+
+ if (broadcom_ioctl(drv, WLC_GET_SSID, &s, sizeof(s)) == -1)
+ return -1;
+
+ os_memcpy(ssid, s.SSID, s.SSID_len);
+ return s.SSID_len;
+}
+
+static int wpa_driver_broadcom_set_wpa(void *priv, int enable)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ unsigned int wauth, wsec;
+ struct ether_addr ea;
+
+ os_memset(&ea, enable ? 0xff : 0, sizeof(ea));
+ if (broadcom_ioctl(drv, WLC_GET_WPA_AUTH, &wauth, sizeof(wauth)) ==
+ -1 ||
+ broadcom_ioctl(drv, WLC_GET_WSEC, &wsec, sizeof(wsec)) == -1)
+ return -1;
+
+ if (enable) {
+ wauth = PSK_ENABLED;
+ wsec = TKIP_ENABLED;
+ } else {
+ wauth = 255;
+ wsec &= ~(TKIP_ENABLED | AES_ENABLED);
+ }
+
+ if (broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wauth, sizeof(wauth)) ==
+ -1 ||
+ broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) == -1)
+ return -1;
+
+ /* FIX: magic number / error handling? */
+ broadcom_ioctl(drv, 122, &ea, sizeof(ea));
+
+ return 0;
+}
+
+static int wpa_driver_broadcom_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ int ret;
+ wsec_key_t wkt;
+
+ os_memset(&wkt, 0, sizeof wkt);
+ wpa_printf(MSG_MSGDUMP, "BROADCOM: SET %sKEY[%d] alg=%d",
+ set_tx ? "PRIMARY " : "", key_idx, alg);
+ if (key && key_len > 0)
+ wpa_hexdump_key(MSG_MSGDUMP, "BROADCOM: key", key, key_len);
+
+ switch (alg) {
+ case WPA_ALG_NONE:
+ wkt.algo = CRYPTO_ALGO_OFF;
+ break;
+ case WPA_ALG_WEP:
+ wkt.algo = CRYPTO_ALGO_WEP128; /* CRYPTO_ALGO_WEP1? */
+ break;
+ case WPA_ALG_TKIP:
+ wkt.algo = 0; /* CRYPTO_ALGO_TKIP? */
+ break;
+ case WPA_ALG_CCMP:
+ wkt.algo = 0; /* CRYPTO_ALGO_AES_CCM;
+ * AES_OCB_MSDU, AES_OCB_MPDU? */
+ break;
+ default:
+ wkt.algo = CRYPTO_ALGO_NALG;
+ break;
+ }
+
+ if (seq && seq_len > 0)
+ wpa_hexdump(MSG_MSGDUMP, "BROADCOM: SEQ", seq, seq_len);
+
+ if (addr)
+ wpa_hexdump(MSG_MSGDUMP, "BROADCOM: addr", addr, ETH_ALEN);
+
+ wkt.index = key_idx;
+ wkt.len = key_len;
+ if (key && key_len > 0) {
+ os_memcpy(wkt.data, key, key_len);
+ if (key_len == 32) {
+ /* hack hack hack XXX */
+ os_memcpy(&wkt.data[16], &key[24], 8);
+ os_memcpy(&wkt.data[24], &key[16], 8);
+ }
+ }
+ /* wkt.algo = CRYPTO_ALGO_...; */
+ wkt.flags = set_tx ? 0 : WSEC_PRIMARY_KEY;
+ if (addr && set_tx)
+ os_memcpy(&wkt.ea, addr, sizeof(wkt.ea));
+ ret = broadcom_ioctl(drv, WLC_SET_KEY, &wkt, sizeof(wkt));
+ if (addr && set_tx) {
+ /* FIX: magic number / error handling? */
+ broadcom_ioctl(drv, 121, &wkt.ea, sizeof(wkt.ea));
+ }
+ return ret;
+}
+
+
+static void wpa_driver_broadcom_event_receive(int sock, void *ctx,
+ void *sock_ctx)
+{
+ char buf[8192];
+ int left;
+ wl_wpa_header_t *wwh;
+ union wpa_event_data data;
+
+ if ((left = recv(sock, buf, sizeof buf, 0)) < 0)
+ return;
+
+ wpa_hexdump(MSG_DEBUG, "RECEIVE EVENT", (u8 *) buf, left);
+
+ if ((size_t) left < sizeof(wl_wpa_header_t))
+ return;
+
+ wwh = (wl_wpa_header_t *) buf;
+
+ if (wwh->snap.type != WL_WPA_ETHER_TYPE)
+ return;
+ if (os_memcmp(&wwh->snap, wl_wpa_snap_template, 6) != 0)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+
+ switch (wwh->type) {
+ case WLC_ASSOC_MSG:
+ left -= WL_WPA_HEADER_LEN;
+ wpa_printf(MSG_DEBUG, "BROADCOM: ASSOC MESSAGE (left: %d)",
+ left);
+ if (left > 0) {
+ data.assoc_info.resp_ies = os_malloc(left);
+ if (data.assoc_info.resp_ies == NULL)
+ return;
+ os_memcpy(data.assoc_info.resp_ies,
+ buf + WL_WPA_HEADER_LEN, left);
+ data.assoc_info.resp_ies_len = left;
+ wpa_hexdump(MSG_MSGDUMP, "BROADCOM: copying %d bytes "
+ "into resp_ies",
+ data.assoc_info.resp_ies, left);
+ }
+ /* data.assoc_info.req_ies = NULL; */
+ /* data.assoc_info.req_ies_len = 0; */
+
+ wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
+ wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+ break;
+ case WLC_DISASSOC_MSG:
+ wpa_printf(MSG_DEBUG, "BROADCOM: DISASSOC MESSAGE");
+ wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
+ break;
+ case WLC_PTK_MIC_MSG:
+ wpa_printf(MSG_DEBUG, "BROADCOM: PTK MIC MSG MESSAGE");
+ data.michael_mic_failure.unicast = 1;
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+ break;
+ case WLC_GTK_MIC_MSG:
+ wpa_printf(MSG_DEBUG, "BROADCOM: GTK MIC MSG MESSAGE");
+ data.michael_mic_failure.unicast = 0;
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "BROADCOM: UNKNOWN MESSAGE (%d)",
+ wwh->type);
+ break;
+ }
+ os_free(data.assoc_info.resp_ies);
+}
+
+static void * wpa_driver_broadcom_init(void *ctx, const char *ifname)
+{
+ int s;
+ struct sockaddr_ll ll;
+ struct wpa_driver_broadcom_data *drv;
+ struct ifreq ifr;
+
+ /* open socket to kernel */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("socket");
+ return NULL;
+ }
+ /* do it */
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
+ perror(ifr.ifr_name);
+ return NULL;
+ }
+
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->ioctl_sock = s;
+
+ s = socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2));
+ if (s < 0) {
+ perror("socket(PF_PACKET, SOCK_RAW, ntohs(ETH_P_802_2))");
+ close(drv->ioctl_sock);
+ os_free(drv);
+ return NULL;
+ }
+
+ os_memset(&ll, 0, sizeof(ll));
+ ll.sll_family = AF_PACKET;
+ ll.sll_protocol = ntohs(ETH_P_802_2);
+ ll.sll_ifindex = ifr.ifr_ifindex;
+ ll.sll_hatype = 0;
+ ll.sll_pkttype = PACKET_HOST;
+ ll.sll_halen = 0;
+
+ if (bind(s, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+ perror("bind(netlink)");
+ close(s);
+ close(drv->ioctl_sock);
+ os_free(drv);
+ return NULL;
+ }
+
+ eloop_register_read_sock(s, wpa_driver_broadcom_event_receive, ctx,
+ NULL);
+ drv->event_sock = s;
+
+ return drv;
+}
+
+static void wpa_driver_broadcom_deinit(void *priv)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
+ eloop_unregister_read_sock(drv->event_sock);
+ close(drv->event_sock);
+ close(drv->ioctl_sock);
+ os_free(drv);
+}
+
+static int wpa_driver_broadcom_set_countermeasures(void *priv,
+ int enabled)
+{
+#if 0
+ struct wpa_driver_broadcom_data *drv = priv;
+ /* FIX: ? */
+ return broadcom_ioctl(drv, WLC_SET_TKIP_COUNTERMEASURES, &enabled,
+ sizeof(enabled));
+#else
+ return 0;
+#endif
+}
+
+static int wpa_driver_broadcom_set_drop_unencrypted(void *priv, int enabled)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ /* SET_EAP_RESTRICT, SET_WEP_RESTRICT */
+ int restrict = (enabled ? 1 : 0);
+
+ if (broadcom_ioctl(drv, WLC_SET_WEP_RESTRICT,
+ &restrict, sizeof(restrict)) < 0 ||
+ broadcom_ioctl(drv, WLC_SET_EAP_RESTRICT,
+ &restrict, sizeof(restrict)) < 0)
+ return -1;
+
+ return 0;
+}
+
+static void wpa_driver_broadcom_scan_timeout(void *eloop_ctx,
+ void *timeout_ctx)
+{
+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+static int wpa_driver_broadcom_scan(void *priv, const u8 *ssid,
+ size_t ssid_len)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ wlc_ssid_t wst = { 0, "" };
+
+ if (ssid && ssid_len > 0 && ssid_len <= sizeof(wst.SSID)) {
+ wst.SSID_len = ssid_len;
+ os_memcpy(wst.SSID, ssid, ssid_len);
+ }
+
+ if (broadcom_ioctl(drv, WLC_SCAN, &wst, sizeof(wst)) < 0)
+ return -1;
+
+ eloop_cancel_timeout(wpa_driver_broadcom_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(3, 0, wpa_driver_broadcom_scan_timeout, drv,
+ drv->ctx);
+ return 0;
+}
+
+
+static const int frequency_list[] = {
+ 2412, 2417, 2422, 2427, 2432, 2437, 2442,
+ 2447, 2452, 2457, 2462, 2467, 2472, 2484
+};
+
+struct bss_ie_hdr {
+ u8 elem_id;
+ u8 len;
+ u8 oui[3];
+ /* u8 oui_type; */
+ /* u16 version; */
+} __attribute__ ((packed));
+
+static int
+wpa_driver_broadcom_get_scan_results(void *priv,
+ struct wpa_scan_result *results,
+ size_t max_size)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ char *buf;
+ wl_scan_results_t *wsr;
+ wl_bss_info_t *wbi;
+ size_t ap_num;
+
+ buf = os_malloc(WLC_IOCTL_MAXLEN);
+ if (buf == NULL)
+ return -1;
+
+ wsr = (wl_scan_results_t *) buf;
+
+ wsr->buflen = WLC_IOCTL_MAXLEN - sizeof(wsr);
+ wsr->version = 107;
+ wsr->count = 0;
+
+ if (broadcom_ioctl(drv, WLC_SCAN_RESULTS, buf, WLC_IOCTL_MAXLEN) < 0) {
+ os_free(buf);
+ return -1;
+ }
+
+ os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
+
+ for (ap_num = 0, wbi = wsr->bss_info; ap_num < wsr->count; ++ap_num) {
+ int left;
+ struct bss_ie_hdr *ie;
+
+ os_memcpy(results[ap_num].bssid, &wbi->BSSID, ETH_ALEN);
+ os_memcpy(results[ap_num].ssid, wbi->SSID, wbi->SSID_len);
+ results[ap_num].ssid_len = wbi->SSID_len;
+ results[ap_num].freq = frequency_list[wbi->channel - 1];
+ /* get ie's */
+ wpa_hexdump(MSG_MSGDUMP, "BROADCOM: AP IEs",
+ (u8 *) wbi + sizeof(*wbi), wbi->ie_length);
+ ie = (struct bss_ie_hdr *) ((u8 *) wbi + sizeof(*wbi));
+ for (left = wbi->ie_length; left > 0;
+ left -= (ie->len + 2), ie = (struct bss_ie_hdr *)
+ ((u8 *) ie + 2 + ie->len)) {
+ wpa_printf(MSG_MSGDUMP, "BROADCOM: IE: id:%x, len:%d",
+ ie->elem_id, ie->len);
+ if (ie->len >= 3)
+ wpa_printf(MSG_MSGDUMP,
+ "BROADCOM: oui:%02x%02x%02x",
+ ie->oui[0], ie->oui[1], ie->oui[2]);
+ if (ie->elem_id != 0xdd ||
+ ie->len < 6 ||
+ os_memcmp(ie->oui, WPA_OUI, 3) != 0)
+ continue;
+ os_memcpy(results[ap_num].wpa_ie, ie, ie->len + 2);
+ results[ap_num].wpa_ie_len = ie->len + 2;
+ break;
+ }
+
+ wbi = (wl_bss_info_t *) ((u8 *) wbi + wbi->length);
+ }
+
+ wpa_printf(MSG_MSGDUMP, "Received %d bytes of scan results (%lu "
+ "BSSes)",
+ wsr->buflen, (unsigned long) ap_num);
+
+ os_free(buf);
+ return ap_num;
+}
+
+static int wpa_driver_broadcom_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ wlc_deauth_t wdt;
+ wdt.val = reason_code;
+ os_memcpy(&wdt.ea, addr, sizeof wdt.ea);
+ wdt.res = 0x7fff;
+ return broadcom_ioctl(drv, WLC_DEAUTHENTICATE_WITH_REASON, &wdt,
+ sizeof(wdt));
+}
+
+static int wpa_driver_broadcom_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ return broadcom_ioctl(drv, WLC_DISASSOC, 0, 0);
+}
+
+static int
+wpa_driver_broadcom_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_broadcom_data *drv = priv;
+ wlc_ssid_t s;
+ int infra = 1;
+ int auth = 0;
+ int wsec = 4;
+ int dummy;
+ int wpa_auth;
+
+ s.SSID_len = params->ssid_len;
+ os_memcpy(s.SSID, params->ssid, params->ssid_len);
+
+ switch (params->pairwise_suite) {
+ case CIPHER_WEP40:
+ case CIPHER_WEP104:
+ wsec = 1;
+ break;
+
+ case CIPHER_TKIP:
+ wsec = 2;
+ break;
+
+ case CIPHER_CCMP:
+ wsec = 4;
+ break;
+
+ default:
+ wsec = 0;
+ break;
+ }
+
+ switch (params->key_mgmt_suite) {
+ case KEY_MGMT_802_1X:
+ wpa_auth = 1;
+ break;
+
+ case KEY_MGMT_PSK:
+ wpa_auth = 2;
+ break;
+
+ default:
+ wpa_auth = 255;
+ break;
+ }
+
+ /* printf("broadcom_associate: %u %u %u\n", pairwise_suite,
+ * group_suite, key_mgmt_suite);
+ * broadcom_ioctl(ifname, WLC_GET_WSEC, &wsec, sizeof(wsec));
+ * wl join uses wlc_sec_wep here, not wlc_set_wsec */
+
+ if (broadcom_ioctl(drv, WLC_SET_WSEC, &wsec, sizeof(wsec)) < 0 ||
+ broadcom_ioctl(drv, WLC_SET_WPA_AUTH, &wpa_auth,
+ sizeof(wpa_auth)) < 0 ||
+ broadcom_ioctl(drv, WLC_GET_WEP, &dummy, sizeof(dummy)) < 0 ||
+ broadcom_ioctl(drv, WLC_SET_INFRA, &infra, sizeof(infra)) < 0 ||
+ broadcom_ioctl(drv, WLC_SET_AUTH, &auth, sizeof(auth)) < 0 ||
+ broadcom_ioctl(drv, WLC_SET_WEP, &wsec, sizeof(wsec)) < 0 ||
+ broadcom_ioctl(drv, WLC_SET_SSID, &s, sizeof(s)) < 0)
+ return -1;
+
+ return 0;
+}
+
+const struct wpa_driver_ops wpa_driver_broadcom_ops = {
+ .name = "broadcom",
+ .desc = "Broadcom wl.o driver",
+ .get_bssid = wpa_driver_broadcom_get_bssid,
+ .get_ssid = wpa_driver_broadcom_get_ssid,
+ .set_wpa = wpa_driver_broadcom_set_wpa,
+ .set_key = wpa_driver_broadcom_set_key,
+ .init = wpa_driver_broadcom_init,
+ .deinit = wpa_driver_broadcom_deinit,
+ .set_countermeasures = wpa_driver_broadcom_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_broadcom_set_drop_unencrypted,
+ .scan = wpa_driver_broadcom_scan,
+ .get_scan_results = wpa_driver_broadcom_get_scan_results,
+ .deauthenticate = wpa_driver_broadcom_deauthenticate,
+ .disassociate = wpa_driver_broadcom_disassociate,
+ .associate = wpa_driver_broadcom_associate,
+};
diff --git a/src/drivers/driver_bsd.c b/src/drivers/driver_bsd.c
new file mode 100644
index 0000000..218d913
--- /dev/null
+++ b/src/drivers/driver_bsd.c
@@ -0,0 +1,794 @@
+/*
+ * WPA Supplicant - driver interaction with BSD net80211 layer
+ * Copyright (c) 2004, Sam Leffler <sam@errno.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "ieee802_11_defs.h"
+
+#include <net/if.h>
+
+#ifdef __NetBSD__
+#include <net/if_ether.h>
+#define COMPAT_FREEBSD_NET80211
+#else
+#include <net/ethernet.h>
+#endif
+
+#include <net80211/ieee80211.h>
+#include <net80211/ieee80211_crypto.h>
+#include <net80211/ieee80211_ioctl.h>
+
+struct wpa_driver_bsd_data {
+ int sock; /* open socket for 802.11 ioctls */
+ int route; /* routing socket for events */
+ char ifname[IFNAMSIZ+1]; /* interface name */
+ unsigned int ifindex; /* interface index */
+ void *ctx;
+ int prev_roaming; /* roaming state to restore on deinit */
+ int prev_privacy; /* privacy state to restore on deinit */
+ int prev_wpa; /* wpa state to restore on deinit */
+};
+
+static int
+set80211var(struct wpa_driver_bsd_data *drv, int op, const void *arg, int arg_len)
+{
+ struct ieee80211req ireq;
+
+ os_memset(&ireq, 0, sizeof(ireq));
+ os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
+ ireq.i_type = op;
+ ireq.i_len = arg_len;
+ ireq.i_data = (void *) arg;
+
+ if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
+ fprintf(stderr, "ioctl[SIOCS80211, op %u, len %u]: %s\n",
+ op, arg_len, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int
+get80211var(struct wpa_driver_bsd_data *drv, int op, void *arg, int arg_len)
+{
+ struct ieee80211req ireq;
+
+ os_memset(&ireq, 0, sizeof(ireq));
+ os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
+ ireq.i_type = op;
+ ireq.i_len = arg_len;
+ ireq.i_data = arg;
+
+ if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) {
+ fprintf(stderr, "ioctl[SIOCG80211, op %u, len %u]: %s\n",
+ op, arg_len, strerror(errno));
+ return -1;
+ }
+ return ireq.i_len;
+}
+
+static int
+set80211param(struct wpa_driver_bsd_data *drv, int op, int arg)
+{
+ struct ieee80211req ireq;
+
+ os_memset(&ireq, 0, sizeof(ireq));
+ os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
+ ireq.i_type = op;
+ ireq.i_val = arg;
+
+ if (ioctl(drv->sock, SIOCS80211, &ireq) < 0) {
+ fprintf(stderr, "ioctl[SIOCS80211, op %u, arg 0x%x]: %s\n",
+ op, arg, strerror(errno));
+ return -1;
+ }
+ return 0;
+}
+
+static int
+get80211param(struct wpa_driver_bsd_data *drv, int op)
+{
+ struct ieee80211req ireq;
+
+ os_memset(&ireq, 0, sizeof(ireq));
+ os_strlcpy(ireq.i_name, drv->ifname, IFNAMSIZ);
+ ireq.i_type = op;
+
+ if (ioctl(drv->sock, SIOCG80211, &ireq) < 0) {
+ fprintf(stderr, "ioctl[SIOCG80211, op %u]: %s\n",
+ op, strerror(errno));
+ return -1;
+ }
+ return ireq.i_val;
+}
+
+static int
+getifflags(struct wpa_driver_bsd_data *drv, int *flags)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+ if (ioctl(drv->sock, SIOCGIFFLAGS, (caddr_t)&ifr) < 0) {
+ perror("SIOCGIFFLAGS");
+ return errno;
+ }
+ *flags = ifr.ifr_flags & 0xffff;
+ return 0;
+}
+
+static int
+setifflags(struct wpa_driver_bsd_data *drv, int flags)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, drv->ifname, sizeof(ifr.ifr_name));
+ ifr.ifr_flags = flags & 0xffff;
+ if (ioctl(drv->sock, SIOCSIFFLAGS, (caddr_t)&ifr) < 0) {
+ perror("SIOCSIFFLAGS");
+ return errno;
+ }
+ return 0;
+}
+
+static int
+wpa_driver_bsd_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+
+ return get80211var(drv, IEEE80211_IOC_BSSID,
+ bssid, IEEE80211_ADDR_LEN) < 0 ? -1 : 0;
+}
+
+#if 0
+static int
+wpa_driver_bsd_set_bssid(void *priv, const char *bssid)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+
+ return set80211var(drv, IEEE80211_IOC_BSSID,
+ bssid, IEEE80211_ADDR_LEN);
+}
+#endif
+
+static int
+wpa_driver_bsd_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+
+ return get80211var(drv, IEEE80211_IOC_SSID,
+ ssid, IEEE80211_NWID_LEN);
+}
+
+static int
+wpa_driver_bsd_set_ssid(void *priv, const u8 *ssid,
+ size_t ssid_len)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+
+ return set80211var(drv, IEEE80211_IOC_SSID, ssid, ssid_len);
+}
+
+static int
+wpa_driver_bsd_set_wpa_ie(struct wpa_driver_bsd_data *drv,
+ const u8 *wpa_ie, size_t wpa_ie_len)
+{
+ return set80211var(drv, IEEE80211_IOC_OPTIE, wpa_ie, wpa_ie_len);
+}
+
+static int
+wpa_driver_bsd_set_wpa_internal(void *priv, int wpa, int privacy)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: wpa=%d privacy=%d",
+ __FUNCTION__, wpa, privacy);
+
+ if (!wpa && wpa_driver_bsd_set_wpa_ie(drv, NULL, 0) < 0)
+ ret = -1;
+ if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
+ ret = -1;
+ if (set80211param(drv, IEEE80211_IOC_WPA, wpa) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int
+wpa_driver_bsd_set_wpa(void *priv, int enabled)
+{
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+
+ return wpa_driver_bsd_set_wpa_internal(priv, enabled ? 3 : 0, enabled);
+}
+
+static int
+wpa_driver_bsd_del_key(struct wpa_driver_bsd_data *drv, int key_idx,
+ const unsigned char *addr)
+{
+ struct ieee80211req_del_key wk;
+
+ os_memset(&wk, 0, sizeof(wk));
+ if (addr != NULL &&
+ bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) != 0) {
+ struct ether_addr ea;
+
+ os_memcpy(&ea, addr, IEEE80211_ADDR_LEN);
+ wpa_printf(MSG_DEBUG, "%s: addr=%s keyidx=%d",
+ __func__, ether_ntoa(&ea), key_idx);
+ os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
+ wk.idk_keyix = (uint8_t) IEEE80211_KEYIX_NONE;
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __func__, key_idx);
+ wk.idk_keyix = key_idx;
+ }
+ return set80211var(drv, IEEE80211_IOC_DELKEY, &wk, sizeof(wk));
+}
+
+static int
+wpa_driver_bsd_set_key(void *priv, wpa_alg alg,
+ const unsigned char *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+ struct ieee80211req_key wk;
+ struct ether_addr ea;
+ char *alg_name;
+ u_int8_t cipher;
+
+ if (alg == WPA_ALG_NONE)
+ return wpa_driver_bsd_del_key(drv, key_idx, addr);
+
+ switch (alg) {
+ case WPA_ALG_WEP:
+ alg_name = "WEP";
+ cipher = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_ALG_TKIP:
+ alg_name = "TKIP";
+ cipher = IEEE80211_CIPHER_TKIP;
+ break;
+ case WPA_ALG_CCMP:
+ alg_name = "CCMP";
+ cipher = IEEE80211_CIPHER_AES_CCM;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
+ __func__, alg);
+ return -1;
+ }
+
+ os_memcpy(&ea, addr, IEEE80211_ADDR_LEN);
+ wpa_printf(MSG_DEBUG,
+ "%s: alg=%s addr=%s key_idx=%d set_tx=%d seq_len=%zu key_len=%zu",
+ __func__, alg_name, ether_ntoa(&ea), key_idx, set_tx,
+ seq_len, key_len);
+
+ if (seq_len > sizeof(u_int64_t)) {
+ wpa_printf(MSG_DEBUG, "%s: seq_len %zu too big",
+ __func__, seq_len);
+ return -2;
+ }
+ if (key_len > sizeof(wk.ik_keydata)) {
+ wpa_printf(MSG_DEBUG, "%s: key length %zu too big",
+ __func__, key_len);
+ return -3;
+ }
+
+ os_memset(&wk, 0, sizeof(wk));
+ wk.ik_type = cipher;
+ wk.ik_flags = IEEE80211_KEY_RECV;
+ if (set_tx)
+ wk.ik_flags |= IEEE80211_KEY_XMIT;
+ os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ /*
+ * Deduce whether group/global or unicast key by checking
+ * the address (yech). Note also that we can only mark global
+ * keys default; doing this for a unicast key is an error.
+ */
+ if (bcmp(addr, "\xff\xff\xff\xff\xff\xff", IEEE80211_ADDR_LEN) == 0) {
+ wk.ik_flags |= IEEE80211_KEY_GROUP;
+ wk.ik_keyix = key_idx;
+ } else {
+ wk.ik_keyix = (key_idx == 0 ? IEEE80211_KEYIX_NONE : key_idx);
+ }
+ if (wk.ik_keyix != IEEE80211_KEYIX_NONE && set_tx)
+ wk.ik_flags |= IEEE80211_KEY_DEFAULT;
+ wk.ik_keylen = key_len;
+ os_memcpy(&wk.ik_keyrsc, seq, seq_len);
+ os_memcpy(wk.ik_keydata, key, key_len);
+
+ return set80211var(drv, IEEE80211_IOC_WPAKEY, &wk, sizeof(wk));
+}
+
+static int
+wpa_driver_bsd_set_countermeasures(void *priv, int enabled)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+ return set80211param(drv, IEEE80211_IOC_COUNTERMEASURES, enabled);
+}
+
+
+static int
+wpa_driver_bsd_set_drop_unencrypted(void *priv, int enabled)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+ return set80211param(drv, IEEE80211_IOC_DROPUNENCRYPTED, enabled);
+}
+
+static int
+wpa_driver_bsd_deauthenticate(void *priv, const u8 *addr, int reason_code)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ os_memset(&mlme, 0, sizeof(mlme));
+ mlme.im_op = IEEE80211_MLME_DEAUTH;
+ mlme.im_reason = reason_code;
+ os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
+}
+
+static int
+wpa_driver_bsd_disassociate(void *priv, const u8 *addr, int reason_code)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ os_memset(&mlme, 0, sizeof(mlme));
+ mlme.im_op = IEEE80211_MLME_DISASSOC;
+ mlme.im_reason = reason_code;
+ os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ return set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme));
+}
+
+static int
+wpa_driver_bsd_associate(void *priv, struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int privacy;
+
+ wpa_printf(MSG_DEBUG,
+ "%s: ssid '%.*s' wpa ie len %u pairwise %u group %u key mgmt %u"
+ , __func__
+ , params->ssid_len, params->ssid
+ , params->wpa_ie_len
+ , params->pairwise_suite
+ , params->group_suite
+ , params->key_mgmt_suite
+ );
+
+ /* XXX error handling is wrong but unclear what to do... */
+ if (wpa_driver_bsd_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
+ return -1;
+
+ privacy = !(params->pairwise_suite == CIPHER_NONE &&
+ params->group_suite == CIPHER_NONE &&
+ params->key_mgmt_suite == KEY_MGMT_NONE &&
+ params->wpa_ie_len == 0);
+ wpa_printf(MSG_DEBUG, "%s: set PRIVACY %u", __func__, privacy);
+
+ if (set80211param(drv, IEEE80211_IOC_PRIVACY, privacy) < 0)
+ return -1;
+
+ if (params->wpa_ie_len &&
+ set80211param(drv, IEEE80211_IOC_WPA,
+ params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1) < 0)
+ return -1;
+
+ os_memset(&mlme, 0, sizeof(mlme));
+ mlme.im_op = IEEE80211_MLME_ASSOC;
+ if (params->ssid != NULL)
+ os_memcpy(mlme.im_ssid, params->ssid, params->ssid_len);
+ mlme.im_ssid_len = params->ssid_len;
+ if (params->bssid != NULL)
+ os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
+ if (set80211var(drv, IEEE80211_IOC_MLME, &mlme, sizeof(mlme)) < 0)
+ return -1;
+ return 0;
+}
+
+static int
+wpa_driver_bsd_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+ int authmode;
+
+ if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
+ (auth_alg & AUTH_ALG_SHARED_KEY))
+ authmode = IEEE80211_AUTH_AUTO;
+ else if (auth_alg & AUTH_ALG_SHARED_KEY)
+ authmode = IEEE80211_AUTH_SHARED;
+ else
+ authmode = IEEE80211_AUTH_OPEN;
+
+ return set80211param(drv, IEEE80211_IOC_AUTHMODE, authmode);
+}
+
+static int
+wpa_driver_bsd_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+ int flags;
+
+ /* NB: interface must be marked UP to do a scan */
+ if (getifflags(drv, &flags) != 0 || setifflags(drv, flags | IFF_UP) != 0)
+ return -1;
+
+ /* set desired ssid before scan */
+ if (wpa_driver_bsd_set_ssid(drv, ssid, ssid_len) < 0)
+ return -1;
+
+ /* NB: net80211 delivers a scan complete event so no need to poll */
+ return set80211param(drv, IEEE80211_IOC_SCAN_REQ, 0);
+}
+
+#include <net/route.h>
+#if __FreeBSD__
+#include <net80211/ieee80211_freebsd.h>
+#endif
+#if __NetBSD__
+#include <net80211/ieee80211_netbsd.h>
+#endif
+
+static void
+wpa_driver_bsd_event_receive(int sock, void *ctx, void *sock_ctx)
+{
+ struct wpa_driver_bsd_data *drv = sock_ctx;
+ char buf[2048];
+ struct if_announcemsghdr *ifan;
+ struct if_msghdr *ifm;
+ struct rt_msghdr *rtm;
+ union wpa_event_data event;
+ struct ieee80211_michael_event *mic;
+ int n;
+
+ n = read(sock, buf, sizeof(buf));
+ if (n < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("read(PF_ROUTE)");
+ return;
+ }
+
+ rtm = (struct rt_msghdr *) buf;
+ if (rtm->rtm_version != RTM_VERSION) {
+ wpa_printf(MSG_DEBUG, "Routing message version %d not "
+ "understood\n", rtm->rtm_version);
+ return;
+ }
+ os_memset(&event, 0, sizeof(event));
+ switch (rtm->rtm_type) {
+ case RTM_IFANNOUNCE:
+ ifan = (struct if_announcemsghdr *) rtm;
+ if (ifan->ifan_index != drv->ifindex)
+ break;
+ strlcpy(event.interface_status.ifname, drv->ifname,
+ sizeof(event.interface_status.ifname));
+ switch (ifan->ifan_what) {
+ case IFAN_DEPARTURE:
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ default:
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "RTM_IFANNOUNCE: Interface '%s' %s",
+ event.interface_status.ifname,
+ ifan->ifan_what == IFAN_DEPARTURE ?
+ "removed" : "added");
+ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+ break;
+ case RTM_IEEE80211:
+ ifan = (struct if_announcemsghdr *) rtm;
+ if (ifan->ifan_index != drv->ifindex)
+ break;
+ switch (ifan->ifan_what) {
+ case RTM_IEEE80211_ASSOC:
+ case RTM_IEEE80211_REASSOC:
+ wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+ break;
+ case RTM_IEEE80211_DISASSOC:
+ wpa_supplicant_event(ctx, EVENT_DISASSOC, NULL);
+ break;
+ case RTM_IEEE80211_SCAN:
+ wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
+ break;
+ case RTM_IEEE80211_REPLAY:
+ /* ignore */
+ break;
+ case RTM_IEEE80211_MICHAEL:
+ mic = (struct ieee80211_michael_event *) &ifan[1];
+ wpa_printf(MSG_DEBUG,
+ "Michael MIC failure wireless event: "
+ "keyix=%u src_addr=" MACSTR, mic->iev_keyix,
+ MAC2STR(mic->iev_src));
+
+ os_memset(&event, 0, sizeof(event));
+ event.michael_mic_failure.unicast =
+ !IEEE80211_IS_MULTICAST(mic->iev_dst);
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE,
+ &event);
+ break;
+ }
+ break;
+ case RTM_IFINFO:
+ ifm = (struct if_msghdr *) rtm;
+ if (ifm->ifm_index != drv->ifindex)
+ break;
+ if ((rtm->rtm_flags & RTF_UP) == 0) {
+ strlcpy(event.interface_status.ifname, drv->ifname,
+ sizeof(event.interface_status.ifname));
+ event.interface_status.ievent = EVENT_INTERFACE_REMOVED;
+ wpa_printf(MSG_DEBUG, "RTM_IFINFO: Interface '%s' DOWN",
+ event.interface_status.ifname);
+ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+ }
+ break;
+ }
+}
+
+/* Compare function for sorting scan results. Return >0 if @b is consider
+ * better. */
+static int
+wpa_scan_result_compar(const void *a, const void *b)
+{
+ const struct wpa_scan_result *wa = a;
+ const struct wpa_scan_result *wb = b;
+
+ /* WPA/WPA2 support preferred */
+ if ((wb->wpa_ie_len || wb->rsn_ie_len) &&
+ !(wa->wpa_ie_len || wa->rsn_ie_len))
+ return 1;
+ if (!(wb->wpa_ie_len || wb->rsn_ie_len) &&
+ (wa->wpa_ie_len || wa->rsn_ie_len))
+ return -1;
+
+ /* privacy support preferred */
+ if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) &&
+ (wb->caps & IEEE80211_CAPINFO_PRIVACY) == 0)
+ return 1;
+ if ((wa->caps & IEEE80211_CAPINFO_PRIVACY) == 0 &&
+ (wb->caps & IEEE80211_CAPINFO_PRIVACY))
+ return -1;
+
+ /* best/max rate preferred if signal level close enough XXX */
+ if (wa->maxrate != wb->maxrate && abs(wb->level - wa->level) < 5)
+ return wb->maxrate - wa->maxrate;
+
+ /* use freq for channel preference */
+
+ /* all things being equal, use signal level */
+ return wb->level - wa->level;
+}
+
+static int
+getmaxrate(uint8_t rates[15], uint8_t nrates)
+{
+ int i, maxrate = -1;
+
+ for (i = 0; i < nrates; i++) {
+ int rate = rates[i] & IEEE80211_RATE_VAL;
+ if (rate > maxrate)
+ rate = maxrate;
+ }
+ return maxrate;
+}
+
+/* unalligned little endian access */
+#define LE_READ_4(p) \
+ ((u_int32_t) \
+ ((((const u_int8_t *)(p))[0] ) | \
+ (((const u_int8_t *)(p))[1] << 8) | \
+ (((const u_int8_t *)(p))[2] << 16) | \
+ (((const u_int8_t *)(p))[3] << 24)))
+
+static int __inline
+iswpaoui(const u_int8_t *frm)
+{
+ return frm[1] > 3 && LE_READ_4(frm+2) == ((WPA_OUI_TYPE<<24)|WPA_OUI);
+}
+
+static int
+wpa_driver_bsd_get_scan_results(void *priv,
+ struct wpa_scan_result *results,
+ size_t max_size)
+{
+#define min(a,b) ((a)>(b)?(b):(a))
+ struct wpa_driver_bsd_data *drv = priv;
+ uint8_t buf[24*1024];
+ uint8_t *cp, *vp;
+ struct ieee80211req_scan_result *sr;
+ struct wpa_scan_result *wsr;
+ int len, ielen;
+
+ os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
+
+ len = get80211var(drv, IEEE80211_IOC_SCAN_RESULTS, buf, sizeof(buf));
+ if (len < 0)
+ return -1;
+ cp = buf;
+ wsr = results;
+ while (len >= sizeof(struct ieee80211req_scan_result)) {
+ sr = (struct ieee80211req_scan_result *) cp;
+ os_memcpy(wsr->bssid, sr->isr_bssid, IEEE80211_ADDR_LEN);
+ wsr->ssid_len = sr->isr_ssid_len;
+ wsr->freq = sr->isr_freq;
+ wsr->noise = sr->isr_noise;
+ wsr->qual = sr->isr_rssi;
+ wsr->level = 0; /* XXX? */
+ wsr->caps = sr->isr_capinfo;
+ wsr->maxrate = getmaxrate(sr->isr_rates, sr->isr_nrates);
+ vp = (u_int8_t *)(sr+1);
+ os_memcpy(wsr->ssid, vp, sr->isr_ssid_len);
+ if (sr->isr_ie_len > 0) {
+ vp += sr->isr_ssid_len;
+ ielen = sr->isr_ie_len;
+ while (ielen > 0) {
+ switch (vp[0]) {
+ case IEEE80211_ELEMID_VENDOR:
+ if (!iswpaoui(vp))
+ break;
+ wsr->wpa_ie_len =
+ min(2+vp[1], SSID_MAX_WPA_IE_LEN);
+ os_memcpy(wsr->wpa_ie, vp,
+ wsr->wpa_ie_len);
+ break;
+ case IEEE80211_ELEMID_RSN:
+ wsr->rsn_ie_len =
+ min(2+vp[1], SSID_MAX_WPA_IE_LEN);
+ os_memcpy(wsr->rsn_ie, vp,
+ wsr->rsn_ie_len);
+ break;
+ }
+ ielen -= 2+vp[1];
+ vp += 2+vp[1];
+ }
+ }
+
+ cp += sr->isr_len, len -= sr->isr_len;
+ wsr++;
+ }
+ qsort(results, wsr - results, sizeof(struct wpa_scan_result),
+ wpa_scan_result_compar);
+
+ wpa_printf(MSG_DEBUG, "Received %d bytes of scan results (%d BSSes)",
+ len, wsr - results);
+
+ return wsr - results;
+#undef min
+}
+
+static void *
+wpa_driver_bsd_init(void *ctx, const char *ifname)
+{
+#define GETPARAM(drv, param, v) \
+ (((v) = get80211param(drv, param)) != -1)
+ struct wpa_driver_bsd_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ /*
+ * NB: We require the interface name be mappable to an index.
+ * This implies we do not support having wpa_supplicant
+ * wait for an interface to appear. This seems ok; that
+ * doesn't belong here; it's really the job of devd.
+ */
+ drv->ifindex = if_nametoindex(ifname);
+ if (drv->ifindex == 0) {
+ wpa_printf(MSG_DEBUG, "%s: interface %s does not exist",
+ __func__, ifname);
+ goto fail1;
+ }
+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->sock < 0)
+ goto fail1;
+ drv->route = socket(PF_ROUTE, SOCK_RAW, 0);
+ if (drv->route < 0)
+ goto fail;
+ eloop_register_read_sock(drv->route,
+ wpa_driver_bsd_event_receive, ctx, drv);
+
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+ if (!GETPARAM(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming)) {
+ wpa_printf(MSG_DEBUG, "%s: failed to get roaming state: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+ if (!GETPARAM(drv, IEEE80211_IOC_PRIVACY, drv->prev_privacy)) {
+ wpa_printf(MSG_DEBUG, "%s: failed to get privacy state: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+ if (!GETPARAM(drv, IEEE80211_IOC_WPA, drv->prev_wpa)) {
+ wpa_printf(MSG_DEBUG, "%s: failed to get wpa state: %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+ if (set80211param(drv, IEEE80211_IOC_ROAMING, IEEE80211_ROAMING_MANUAL) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
+ "roaming: %s", __func__, strerror(errno));
+ goto fail;
+ }
+
+ if (set80211param(drv, IEEE80211_IOC_WPA, 1+2) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support %s",
+ __func__, strerror(errno));
+ goto fail;
+ }
+
+ return drv;
+fail:
+ close(drv->sock);
+fail1:
+ os_free(drv);
+ return NULL;
+#undef GETPARAM
+}
+
+static void
+wpa_driver_bsd_deinit(void *priv)
+{
+ struct wpa_driver_bsd_data *drv = priv;
+ int flags;
+
+ eloop_unregister_read_sock(drv->route);
+
+ /* NB: mark interface down */
+ if (getifflags(drv, &flags) == 0)
+ (void) setifflags(drv, flags &~ IFF_UP);
+
+ wpa_driver_bsd_set_wpa_internal(drv, drv->prev_wpa, drv->prev_privacy);
+ if (set80211param(drv, IEEE80211_IOC_ROAMING, drv->prev_roaming) < 0)
+ wpa_printf(MSG_DEBUG, "%s: failed to restore roaming state",
+ __func__);
+
+ (void) close(drv->route); /* ioctl socket */
+ (void) close(drv->sock); /* event socket */
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_bsd_ops = {
+ .name = "bsd",
+ .desc = "BSD 802.11 support (Atheros, etc.)",
+ .init = wpa_driver_bsd_init,
+ .deinit = wpa_driver_bsd_deinit,
+ .get_bssid = wpa_driver_bsd_get_bssid,
+ .get_ssid = wpa_driver_bsd_get_ssid,
+ .set_wpa = wpa_driver_bsd_set_wpa,
+ .set_key = wpa_driver_bsd_set_key,
+ .set_countermeasures = wpa_driver_bsd_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_bsd_set_drop_unencrypted,
+ .scan = wpa_driver_bsd_scan,
+ .get_scan_results = wpa_driver_bsd_get_scan_results,
+ .deauthenticate = wpa_driver_bsd_deauthenticate,
+ .disassociate = wpa_driver_bsd_disassociate,
+ .associate = wpa_driver_bsd_associate,
+ .set_auth_alg = wpa_driver_bsd_set_auth_alg,
+};
diff --git a/src/drivers/driver_hostap.c b/src/drivers/driver_hostap.c
new file mode 100644
index 0000000..84ef3bd
--- /dev/null
+++ b/src/drivers/driver_hostap.c
@@ -0,0 +1,513 @@
+/*
+ * WPA Supplicant - driver interaction with Linux Host AP driver
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "driver_wext.h"
+#include "eloop.h"
+#include "driver_hostap.h"
+
+
+struct wpa_driver_hostap_data {
+ void *wext; /* private data for driver_wext */
+ void *ctx;
+ char ifname[IFNAMSIZ + 1];
+ int sock;
+ int current_mode; /* infra/adhoc */
+};
+
+
+static int hostapd_ioctl(struct wpa_driver_hostap_data *drv,
+ struct prism2_hostapd_param *param,
+ int len, int show_err)
+{
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) param;
+ iwr.u.data.length = len;
+
+ if (ioctl(drv->sock, PRISM2_IOCTL_HOSTAPD, &iwr) < 0) {
+ int ret = errno;
+ if (show_err)
+ perror("ioctl[PRISM2_IOCTL_HOSTAPD]");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_hostap_set_wpa_ie(struct wpa_driver_hostap_data *drv,
+ const u8 *wpa_ie, size_t wpa_ie_len)
+{
+ struct prism2_hostapd_param *param;
+ int res;
+ size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
+ if (blen < sizeof(*param))
+ blen = sizeof(*param);
+
+ param = os_zalloc(blen);
+ if (param == NULL)
+ return -1;
+
+ param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
+ param->u.generic_elem.len = wpa_ie_len;
+ os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
+ res = hostapd_ioctl(drv, param, blen, 1);
+
+ os_free(param);
+
+ return res;
+}
+
+
+static int prism2param(struct wpa_driver_hostap_data *drv, int param,
+ int value)
+{
+ struct iwreq iwr;
+ int *i, ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ i = (int *) iwr.u.name;
+ *i++ = param;
+ *i++ = value;
+
+ if (ioctl(drv->sock, PRISM2_IOCTL_PRISM2_PARAM, &iwr) < 0) {
+ perror("ioctl[PRISM2_IOCTL_PRISM2_PARAM]");
+ ret = -1;
+ }
+ return ret;
+}
+
+
+static int wpa_driver_hostap_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+
+ if (!enabled && wpa_driver_hostap_set_wpa_ie(drv, NULL, 0) < 0)
+ ret = -1;
+ if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING, enabled ? 2 : 0) < 0)
+ ret = -1;
+ if (prism2param(drv, PRISM2_PARAM_WPA, enabled) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static void show_set_key_error(struct prism2_hostapd_param *param)
+{
+ switch (param->u.crypt.err) {
+ case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
+ wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
+ param->u.crypt.alg);
+ wpa_printf(MSG_INFO, "You may need to load kernel module to "
+ "register that algorithm.");
+ wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
+ "WEP.");
+ break;
+ case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
+ wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
+ MAC2STR(param->sta_addr));
+ break;
+ case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
+ wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
+ break;
+ case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
+ wpa_printf(MSG_INFO, "Key setting failed.");
+ break;
+ case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
+ wpa_printf(MSG_INFO, "TX key index setting failed.");
+ break;
+ case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
+ wpa_printf(MSG_INFO, "Card configuration failed.");
+ break;
+ }
+}
+
+
+static int wpa_driver_hostap_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx,
+ int set_tx, const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ struct prism2_hostapd_param *param;
+ u8 *buf;
+ size_t blen;
+ int ret = 0;
+ char *alg_name;
+
+ switch (alg) {
+ case WPA_ALG_NONE:
+ alg_name = "none";
+ break;
+ case WPA_ALG_WEP:
+ alg_name = "WEP";
+ break;
+ case WPA_ALG_TKIP:
+ alg_name = "TKIP";
+ break;
+ case WPA_ALG_CCMP:
+ alg_name = "CCMP";
+ break;
+ default:
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
+ "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ if (seq_len > 8)
+ return -2;
+
+ blen = sizeof(*param) + key_len;
+ buf = os_zalloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ param = (struct prism2_hostapd_param *) buf;
+ param->cmd = PRISM2_SET_ENCRYPTION;
+ /* TODO: In theory, STA in client mode can use five keys; four default
+ * keys for receiving (with keyidx 0..3) and one individual key for
+ * both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
+ * keyidx 0 is reserved for this unicast use and default keys can only
+ * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
+ * This should be fine for more or less all cases, but for completeness
+ * sake, the driver could be enhanced to support the missing key. */
+#if 0
+ if (addr == NULL)
+ os_memset(param->sta_addr, 0xff, ETH_ALEN);
+ else
+ os_memcpy(param->sta_addr, addr, ETH_ALEN);
+#else
+ os_memset(param->sta_addr, 0xff, ETH_ALEN);
+#endif
+ os_strlcpy((char *) param->u.crypt.alg, alg_name,
+ HOSTAP_CRYPT_ALG_NAME_LEN);
+ param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
+ param->u.crypt.idx = key_idx;
+ os_memcpy(param->u.crypt.seq, seq, seq_len);
+ param->u.crypt.key_len = key_len;
+ os_memcpy((u8 *) (param + 1), key, key_len);
+
+ if (hostapd_ioctl(drv, param, blen, 1)) {
+ wpa_printf(MSG_WARNING, "Failed to set encryption.");
+ show_set_key_error(param);
+ ret = -1;
+ }
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int wpa_driver_hostap_set_countermeasures(void *priv, int enabled)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return prism2param(drv, PRISM2_PARAM_TKIP_COUNTERMEASURES, enabled);
+}
+
+
+static int wpa_driver_hostap_set_drop_unencrypted(void *priv, int enabled)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return prism2param(drv, PRISM2_PARAM_DROP_UNENCRYPTED, enabled);
+}
+
+
+static int wpa_driver_hostap_reset(struct wpa_driver_hostap_data *drv,
+ int type)
+{
+ struct iwreq iwr;
+ int *i, ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: type=%d", __FUNCTION__, type);
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ i = (int *) iwr.u.name;
+ *i++ = type;
+
+ if (ioctl(drv->sock, PRISM2_IOCTL_RESET, &iwr) < 0) {
+ perror("ioctl[PRISM2_IOCTL_RESET]");
+ ret = -1;
+ }
+ return ret;
+}
+
+
+static int wpa_driver_hostap_mlme(struct wpa_driver_hostap_data *drv,
+ const u8 *addr, int cmd, int reason_code)
+{
+ struct prism2_hostapd_param param;
+ int ret;
+
+ /* There does not seem to be a better way of deauthenticating or
+ * disassociating with Prism2/2.5/3 than sending the management frame
+ * and then resetting the Port0 to make sure both the AP and the STA
+ * end up in disconnected state. */
+ os_memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_MLME;
+ os_memcpy(param.sta_addr, addr, ETH_ALEN);
+ param.u.mlme.cmd = cmd;
+ param.u.mlme.reason_code = reason_code;
+ ret = hostapd_ioctl(drv, &param, sizeof(param), 1);
+ if (ret == 0) {
+ os_sleep(0, 100000);
+ ret = wpa_driver_hostap_reset(drv, 2);
+ }
+ return ret;
+}
+
+
+static int wpa_driver_hostap_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DEAUTH,
+ reason_code);
+}
+
+
+static int wpa_driver_hostap_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_hostap_mlme(drv, addr, MLME_STA_DISASSOC,
+ reason_code);
+}
+
+
+static int
+wpa_driver_hostap_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ int ret = 0;
+ int allow_unencrypted_eapol;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (params->mode != drv->current_mode) {
+ /* At the moment, Host AP driver requires host_roaming=2 for
+ * infrastructure mode and host_roaming=0 for adhoc. */
+ if (prism2param(drv, PRISM2_PARAM_HOST_ROAMING,
+ params->mode == IEEE80211_MODE_IBSS ? 0 : 2) <
+ 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to set host_roaming",
+ __func__);
+ }
+ drv->current_mode = params->mode;
+ }
+
+ if (prism2param(drv, PRISM2_PARAM_PRIVACY_INVOKED,
+ params->key_mgmt_suite != KEY_MGMT_NONE) < 0)
+ ret = -1;
+ if (wpa_driver_hostap_set_wpa_ie(drv, params->wpa_ie,
+ params->wpa_ie_len) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_mode(drv->wext, params->mode) < 0)
+ ret = -1;
+ if (params->freq &&
+ wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_ssid(drv->wext, params->ssid, params->ssid_len)
+ < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
+ ret = -1;
+
+ /* Allow unencrypted EAPOL messages even if pairwise keys are set when
+ * not using WPA. IEEE 802.1X specifies that these frames are not
+ * encrypted, but WPA encrypts them when pairwise keys are in use. */
+ if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+ params->key_mgmt_suite == KEY_MGMT_PSK)
+ allow_unencrypted_eapol = 0;
+ else
+ allow_unencrypted_eapol = 1;
+
+ if (prism2param(drv, PRISM2_PARAM_IEEE_802_1X,
+ allow_unencrypted_eapol) < 0) {
+ wpa_printf(MSG_DEBUG, "hostap: Failed to configure "
+ "ieee_802_1x param");
+ /* Ignore this error.. driver_hostap.c can also be used with
+ * other drivers that do not support this prism2_param. */
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_hostap_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ struct prism2_hostapd_param param;
+ int ret;
+
+ if (ssid == NULL) {
+ /* Use standard Linux Wireless Extensions ioctl if possible
+ * because some drivers using hostap code in wpa_supplicant
+ * might not support Host AP specific scan request (with SSID
+ * info). */
+ return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
+ }
+
+ if (ssid_len > 32)
+ ssid_len = 32;
+
+ os_memset(&param, 0, sizeof(param));
+ param.cmd = PRISM2_HOSTAPD_SCAN_REQ;
+ param.u.scan_req.ssid_len = ssid_len;
+ os_memcpy(param.u.scan_req.ssid, ssid, ssid_len);
+ ret = hostapd_ioctl(drv, &param, sizeof(param), 1);
+
+ /* Not all drivers generate "scan completed" wireless event, so try to
+ * read results after a timeout. */
+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
+ drv->ctx);
+ eloop_register_timeout(3, 0, wpa_driver_wext_scan_timeout, drv->wext,
+ drv->ctx);
+
+ return ret;
+}
+
+
+static int wpa_driver_hostap_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ int algs = 0;
+
+ if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ algs |= 1;
+ if (auth_alg & AUTH_ALG_SHARED_KEY)
+ algs |= 2;
+ if (auth_alg & AUTH_ALG_LEAP)
+ algs |= 4;
+ if (algs == 0)
+ algs = 1; /* at least one algorithm should be set */
+
+ return prism2param(drv, PRISM2_PARAM_AP_AUTH_ALGS, algs);
+}
+
+
+static int wpa_driver_hostap_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ return wpa_driver_wext_get_bssid(drv->wext, bssid);
+}
+
+
+static int wpa_driver_hostap_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ return wpa_driver_wext_get_ssid(drv->wext, ssid);
+}
+
+
+static struct wpa_scan_results * wpa_driver_hostap_get_scan_results(void *priv)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ return wpa_driver_wext_get_scan_results(drv->wext);
+}
+
+
+static int wpa_driver_hostap_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ return wpa_driver_wext_set_operstate(drv->wext, state);
+}
+
+
+static void * wpa_driver_hostap_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_hostap_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->wext = wpa_driver_wext_init(ctx, ifname);
+ if (drv->wext == NULL) {
+ os_free(drv);
+ return NULL;
+ }
+
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->sock < 0) {
+ perror("socket");
+ wpa_driver_wext_deinit(drv->wext);
+ os_free(drv);
+ return NULL;
+ }
+
+ if (os_strncmp(ifname, "wlan", 4) == 0) {
+ /*
+ * Host AP driver may use both wlan# and wifi# interface in
+ * wireless events.
+ */
+ char ifname2[IFNAMSIZ + 1];
+ os_strlcpy(ifname2, ifname, sizeof(ifname2));
+ os_memcpy(ifname2, "wifi", 4);
+ wpa_driver_wext_alternative_ifindex(drv->wext, ifname2);
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_hostap_deinit(void *priv)
+{
+ struct wpa_driver_hostap_data *drv = priv;
+ wpa_driver_wext_deinit(drv->wext);
+ close(drv->sock);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_hostap_ops = {
+ .name = "hostap",
+ .desc = "Host AP driver (Intersil Prism2/2.5/3)",
+ .get_bssid = wpa_driver_hostap_get_bssid,
+ .get_ssid = wpa_driver_hostap_get_ssid,
+ .set_wpa = wpa_driver_hostap_set_wpa,
+ .set_key = wpa_driver_hostap_set_key,
+ .set_countermeasures = wpa_driver_hostap_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_hostap_set_drop_unencrypted,
+ .scan = wpa_driver_hostap_scan,
+ .get_scan_results2 = wpa_driver_hostap_get_scan_results,
+ .deauthenticate = wpa_driver_hostap_deauthenticate,
+ .disassociate = wpa_driver_hostap_disassociate,
+ .associate = wpa_driver_hostap_associate,
+ .set_auth_alg = wpa_driver_hostap_set_auth_alg,
+ .init = wpa_driver_hostap_init,
+ .deinit = wpa_driver_hostap_deinit,
+ .set_operstate = wpa_driver_hostap_set_operstate,
+};
diff --git a/src/drivers/driver_hostap.h b/src/drivers/driver_hostap.h
new file mode 100644
index 0000000..a2508ed
--- /dev/null
+++ b/src/drivers/driver_hostap.h
@@ -0,0 +1,153 @@
+/*
+ * WPA Supplicant - driver interaction with Linux Host AP driver
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef HOSTAP_DRIVER_H
+#define HOSTAP_DRIVER_H
+
+#define PRISM2_IOCTL_PRISM2_PARAM (SIOCIWFIRSTPRIV + 0)
+#define PRISM2_IOCTL_RESET (SIOCIWFIRSTPRIV + 6)
+#define PRISM2_IOCTL_HOSTAPD (SIOCDEVPRIVATE + 14)
+
+/* PRISM2_IOCTL_PRISM2_PARAM ioctl() subtypes: */
+enum {
+ /* PRISM2_PARAM_PTYPE = 1, */ /* REMOVED 2003-10-22 */
+ PRISM2_PARAM_TXRATECTRL = 2,
+ PRISM2_PARAM_BEACON_INT = 3,
+ PRISM2_PARAM_PSEUDO_IBSS = 4,
+ PRISM2_PARAM_ALC = 5,
+ /* PRISM2_PARAM_TXPOWER = 6, */ /* REMOVED 2003-10-22 */
+ PRISM2_PARAM_DUMP = 7,
+ PRISM2_PARAM_OTHER_AP_POLICY = 8,
+ PRISM2_PARAM_AP_MAX_INACTIVITY = 9,
+ PRISM2_PARAM_AP_BRIDGE_PACKETS = 10,
+ PRISM2_PARAM_DTIM_PERIOD = 11,
+ PRISM2_PARAM_AP_NULLFUNC_ACK = 12,
+ PRISM2_PARAM_MAX_WDS = 13,
+ PRISM2_PARAM_AP_AUTOM_AP_WDS = 14,
+ PRISM2_PARAM_AP_AUTH_ALGS = 15,
+ PRISM2_PARAM_MONITOR_ALLOW_FCSERR = 16,
+ PRISM2_PARAM_HOST_ENCRYPT = 17,
+ PRISM2_PARAM_HOST_DECRYPT = 18,
+ PRISM2_PARAM_BUS_MASTER_THRESHOLD_RX = 19,
+ PRISM2_PARAM_BUS_MASTER_THRESHOLD_TX = 20,
+ PRISM2_PARAM_HOST_ROAMING = 21,
+ PRISM2_PARAM_BCRX_STA_KEY = 22,
+ PRISM2_PARAM_IEEE_802_1X = 23,
+ PRISM2_PARAM_ANTSEL_TX = 24,
+ PRISM2_PARAM_ANTSEL_RX = 25,
+ PRISM2_PARAM_MONITOR_TYPE = 26,
+ PRISM2_PARAM_WDS_TYPE = 27,
+ PRISM2_PARAM_HOSTSCAN = 28,
+ PRISM2_PARAM_AP_SCAN = 29,
+ PRISM2_PARAM_ENH_SEC = 30,
+ PRISM2_PARAM_IO_DEBUG = 31,
+ PRISM2_PARAM_BASIC_RATES = 32,
+ PRISM2_PARAM_OPER_RATES = 33,
+ PRISM2_PARAM_HOSTAPD = 34,
+ PRISM2_PARAM_HOSTAPD_STA = 35,
+ PRISM2_PARAM_WPA = 36,
+ PRISM2_PARAM_PRIVACY_INVOKED = 37,
+ PRISM2_PARAM_TKIP_COUNTERMEASURES = 38,
+ PRISM2_PARAM_DROP_UNENCRYPTED = 39,
+ PRISM2_PARAM_SCAN_CHANNEL_MASK = 40,
+};
+
+/* PRISM2_IOCTL_HOSTAPD ioctl() cmd: */
+enum {
+ PRISM2_HOSTAPD_FLUSH = 1,
+ PRISM2_HOSTAPD_ADD_STA = 2,
+ PRISM2_HOSTAPD_REMOVE_STA = 3,
+ PRISM2_HOSTAPD_GET_INFO_STA = 4,
+ /* REMOVED: PRISM2_HOSTAPD_RESET_TXEXC_STA = 5, */
+ PRISM2_SET_ENCRYPTION = 6,
+ PRISM2_GET_ENCRYPTION = 7,
+ PRISM2_HOSTAPD_SET_FLAGS_STA = 8,
+ PRISM2_HOSTAPD_GET_RID = 9,
+ PRISM2_HOSTAPD_SET_RID = 10,
+ PRISM2_HOSTAPD_SET_ASSOC_AP_ADDR = 11,
+ PRISM2_HOSTAPD_SET_GENERIC_ELEMENT = 12,
+ PRISM2_HOSTAPD_MLME = 13,
+ PRISM2_HOSTAPD_SCAN_REQ = 14,
+ PRISM2_HOSTAPD_STA_CLEAR_STATS = 15,
+};
+
+#define PRISM2_HOSTAPD_MAX_BUF_SIZE 1024
+#define PRISM2_HOSTAPD_RID_HDR_LEN \
+((size_t) (&((struct prism2_hostapd_param *) 0)->u.rid.data))
+#define PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN \
+((size_t) (&((struct prism2_hostapd_param *) 0)->u.generic_elem.data))
+
+/* Maximum length for algorithm names (-1 for nul termination) used in ioctl()
+ */
+#define HOSTAP_CRYPT_ALG_NAME_LEN 16
+
+
+struct prism2_hostapd_param {
+ u32 cmd;
+ u8 sta_addr[ETH_ALEN];
+ union {
+ struct {
+ u16 aid;
+ u16 capability;
+ u8 tx_supp_rates;
+ } add_sta;
+ struct {
+ u32 inactive_sec;
+ } get_info_sta;
+ struct {
+ u8 alg[HOSTAP_CRYPT_ALG_NAME_LEN];
+ u32 flags;
+ u32 err;
+ u8 idx;
+ u8 seq[8]; /* sequence counter (set: RX, get: TX) */
+ u16 key_len;
+ u8 key[0];
+ } crypt;
+ struct {
+ u32 flags_and;
+ u32 flags_or;
+ } set_flags_sta;
+ struct {
+ u16 rid;
+ u16 len;
+ u8 data[0];
+ } rid;
+ struct {
+ u8 len;
+ u8 data[0];
+ } generic_elem;
+ struct {
+#define MLME_STA_DEAUTH 0
+#define MLME_STA_DISASSOC 1
+ u16 cmd;
+ u16 reason_code;
+ } mlme;
+ struct {
+ u8 ssid_len;
+ u8 ssid[32];
+ } scan_req;
+ } u;
+};
+
+#define HOSTAP_CRYPT_FLAG_SET_TX_KEY 0x01
+#define HOSTAP_CRYPT_FLAG_PERMANENT 0x02
+
+#define HOSTAP_CRYPT_ERR_UNKNOWN_ALG 2
+#define HOSTAP_CRYPT_ERR_UNKNOWN_ADDR 3
+#define HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED 4
+#define HOSTAP_CRYPT_ERR_KEY_SET_FAILED 5
+#define HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED 6
+#define HOSTAP_CRYPT_ERR_CARD_CONF_FAILED 7
+
+#endif /* HOSTAP_DRIVER_H */
diff --git a/src/drivers/driver_iphone.m b/src/drivers/driver_iphone.m
new file mode 100644
index 0000000..8e64ffd
--- /dev/null
+++ b/src/drivers/driver_iphone.m
@@ -0,0 +1,466 @@
+/*
+ * WPA Supplicant - iPhone/iPod touch Apple80211 driver interface
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#define Boolean __DummyBoolean
+#include <CoreFoundation/CoreFoundation.h>
+#undef Boolean
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "ieee802_11_defs.h"
+
+#include "MobileApple80211.h"
+
+struct wpa_driver_iphone_data {
+ void *ctx;
+ Apple80211Ref wireless_ctx;
+ CFArrayRef scan_results;
+ int ctrl_power;
+};
+
+
+static const void * cfdict_get_key_str(CFDictionaryRef dict, const char *key)
+{
+ const void *res;
+ CFStringRef str = CFStringCreateWithCString(kCFAllocatorDefault, key,
+ kCFStringEncodingMacRoman);
+ if (str == NULL)
+ return NULL;
+
+ res = CFDictionaryGetValue(dict, str);
+ CFRelease(str);
+ return res;
+}
+
+
+static int wpa_driver_iphone_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ CFDataRef data;
+ int err, len;
+
+ err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_SSID, 0,
+ &data);
+ if (err != 0) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(SSID) "
+ "failed: %d", err);
+ return -1;
+ }
+
+ len = CFDataGetLength(data);
+ if (len > 32) {
+ CFRelease(data);
+ return -1;
+ }
+ os_memcpy(ssid, CFDataGetBytePtr(data), len);
+ CFRelease(data);
+
+ return len;
+}
+
+
+static int wpa_driver_iphone_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ CFStringRef data;
+ int err;
+ int a1, a2, a3, a4, a5, a6;
+
+ err = Apple80211CopyValue(drv->wireless_ctx, APPLE80211_VALUE_BSSID, 0,
+ &data);
+ if (err != 0) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211CopyValue(BSSID) "
+ "failed: %d", err);
+ return -1;
+ }
+
+ sscanf(CFStringGetCStringPtr(data, kCFStringEncodingMacRoman),
+ "%x:%x:%x:%x:%x:%x", &a1, &a2, &a3, &a4, &a5, &a6);
+ bssid[0] = a1;
+ bssid[1] = a2;
+ bssid[2] = a3;
+ bssid[3] = a4;
+ bssid[4] = a5;
+ bssid[5] = a6;
+
+ CFRelease(data);
+
+ return 0;
+}
+
+
+static void wpa_driver_iphone_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+static int wpa_driver_iphone_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ int err;
+
+ if (drv->scan_results) {
+ CFRelease(drv->scan_results);
+ drv->scan_results = NULL;
+ }
+
+ err = Apple80211Scan(drv->wireless_ctx, &drv->scan_results, NULL);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211Scan failed: %d",
+ err);
+ return -1;
+ }
+
+ eloop_register_timeout(0, 0, wpa_driver_iphone_scan_timeout, drv,
+ drv->ctx);
+ return 0;
+}
+
+
+static int wpa_driver_iphone_get_scan_results(void *priv,
+ struct wpa_scan_result *results,
+ size_t max_size)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ size_t i, num;
+
+ if (drv->scan_results == NULL)
+ return 0;
+
+ num = CFArrayGetCount(drv->scan_results);
+ if (num > max_size)
+ num = max_size;
+ os_memset(results, 0, num * sizeof(struct wpa_scan_result));
+
+ for (i = 0; i < num; i++) {
+ struct wpa_scan_result *res = &results[i];
+ CFDictionaryRef dict =
+ CFArrayGetValueAtIndex(drv->scan_results, i);
+ CFDataRef data;
+ CFStringRef str;
+ CFNumberRef num;
+ int val;
+
+ data = cfdict_get_key_str(dict, "SSID");
+ if (data) {
+ res->ssid_len = CFDataGetLength(data);
+ if (res->ssid_len > 32)
+ res->ssid_len = 32;
+ os_memcpy(res->ssid, CFDataGetBytePtr(data),
+ res->ssid_len);
+ }
+
+ str = cfdict_get_key_str(dict, "BSSID");
+ if (str) {
+ int a1, a2, a3, a4, a5, a6;
+ sscanf(CFStringGetCStringPtr(
+ str, kCFStringEncodingMacRoman),
+ "%x:%x:%x:%x:%x:%x",
+ &a1, &a2, &a3, &a4, &a5, &a6);
+ res->bssid[0] = a1;
+ res->bssid[1] = a2;
+ res->bssid[2] = a3;
+ res->bssid[3] = a4;
+ res->bssid[4] = a5;
+ res->bssid[5] = a6;
+ }
+
+ num = cfdict_get_key_str(dict, "CAPABILITIES");
+ if (num) {
+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+ res->caps = val;
+ }
+
+ num = cfdict_get_key_str(dict, "CHANNEL");
+ if (num) {
+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+ res->freq = 2407 + val * 5;
+ }
+
+ num = cfdict_get_key_str(dict, "RSSI");
+ if (num) {
+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+ res->level = val;
+ }
+
+ num = cfdict_get_key_str(dict, "NOISE");
+ if (num) {
+ if (CFNumberGetValue(num, kCFNumberSInt32Type, &val))
+ res->noise = val;
+ }
+
+ data = cfdict_get_key_str(dict, "IE");
+ if (data) {
+ u8 *ptr = (u8 *) CFDataGetBytePtr(data);
+ int len = CFDataGetLength(data);
+ u8 *pos = ptr, *end = ptr + len;
+
+ while (pos + 2 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == WLAN_EID_RSN &&
+ pos[1] <= SSID_MAX_WPA_IE_LEN) {
+ os_memcpy(res->rsn_ie, pos,
+ 2 + pos[1]);
+ res->rsn_ie_len = 2 + pos[1];
+ }
+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
+ pos[1] > 4 && pos[2] == 0x00 &&
+ pos[3] == 0x50 && pos[4] == 0xf2 &&
+ pos[5] == 0x01) {
+ os_memcpy(res->wpa_ie, pos,
+ 2 + pos[1]);
+ res->wpa_ie_len = 2 + pos[1];
+ }
+
+ pos = pos + 2 + pos[1];
+ }
+ }
+ }
+
+ return num;
+}
+
+
+static void wpa_driver_iphone_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_driver_iphone_data *drv = eloop_ctx;
+ u8 bssid[ETH_ALEN];
+
+ if (wpa_driver_iphone_get_bssid(drv, bssid) != 0) {
+ eloop_register_timeout(1, 0, wpa_driver_iphone_assoc_timeout,
+ drv, drv->ctx);
+ return;
+ }
+
+ wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
+}
+
+
+static int wpa_driver_iphone_associate(
+ void *priv, struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ int i, num, err;
+ size_t ssid_len;
+ CFDictionaryRef bss = NULL;
+
+ /*
+ * TODO: Consider generating parameters instead of just using an entry
+ * from scan results in order to support ap_scan=2.
+ */
+
+ if (drv->scan_results == NULL) {
+ wpa_printf(MSG_DEBUG, "iPhone: No scan results - cannot "
+ "associate");
+ return -1;
+ }
+
+ num = CFArrayGetCount(drv->scan_results);
+
+ for (i = 0; i < num; i++) {
+ CFDictionaryRef dict =
+ CFArrayGetValueAtIndex(drv->scan_results, i);
+ CFDataRef data;
+
+ data = cfdict_get_key_str(dict, "SSID");
+ if (data == NULL)
+ continue;
+
+ ssid_len = CFDataGetLength(data);
+ if (ssid_len != params->ssid_len ||
+ os_memcmp(CFDataGetBytePtr(data), params->ssid, ssid_len)
+ != 0)
+ continue;
+
+ bss = dict;
+ break;
+ }
+
+ if (bss == NULL) {
+ wpa_printf(MSG_DEBUG, "iPhone: Could not find SSID from scan "
+ "results - cannot associate");
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "iPhone: Trying to associate with a BSS found "
+ "from scan results");
+
+ err = Apple80211Associate(drv->wireless_ctx, bss, NULL);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211Associate() failed: "
+ "%d", err);
+ return -1;
+ }
+
+ /*
+ * Driver is actually already associated; report association from an
+ * eloop callback.
+ */
+ eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
+ eloop_register_timeout(0, 0, wpa_driver_iphone_assoc_timeout, drv,
+ drv->ctx);
+
+ return 0;
+}
+
+
+static int wpa_driver_iphone_set_key(void *priv, wpa_alg alg, const u8 *addr,
+ int key_idx, int set_tx, const u8 *seq,
+ size_t seq_len, const u8 *key,
+ size_t key_len)
+{
+ /*
+ * TODO: Need to either support configuring PMK for 4-way handshake or
+ * PTK for TKIP/CCMP.
+ */
+ return -1;
+}
+
+
+static int wpa_driver_iphone_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ os_memset(capa, 0, sizeof(*capa));
+
+ capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
+ WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
+ capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+ capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+
+ return 0;
+}
+
+
+static void * wpa_driver_iphone_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_iphone_data *drv;
+ int err;
+ char power;
+ CFStringRef name;
+ CFDictionaryRef dict;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ err = Apple80211Open(&drv->wireless_ctx);
+ if (err) {
+ wpa_printf(MSG_ERROR, "iPhone: Apple80211Open failed: %d",
+ err);
+ os_free(drv);
+ return NULL;
+ }
+
+ name = CFStringCreateWithCString(kCFAllocatorDefault, ifname,
+ kCFStringEncodingISOLatin1);
+ if (name == NULL) {
+ wpa_printf(MSG_ERROR, "iPhone: ifname -> CFString failed");
+ Apple80211Close(drv->wireless_ctx);
+ os_free(drv);
+ return NULL;
+ }
+
+ err = Apple80211BindToInterface(drv->wireless_ctx, name);
+ CFRelease(name);
+
+ if (err) {
+ wpa_printf(MSG_ERROR, "iPhone: Apple80211BindToInterface "
+ "failed: %d", err);
+ Apple80211Close(drv->wireless_ctx);
+ os_free(drv);
+ return NULL;
+ }
+
+ err = Apple80211GetPower(drv->wireless_ctx, &power);
+ if (err)
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211GetPower failed: %d",
+ err);
+
+ wpa_printf(MSG_DEBUG, "iPhone: Power=%d", power);
+
+ if (!power) {
+ drv->ctrl_power = 1;
+ err = Apple80211SetPower(drv->wireless_ctx, 1);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower "
+ "failed: %d", err);
+ Apple80211Close(drv->wireless_ctx);
+ os_free(drv);
+ return NULL;
+ }
+ }
+
+ err = Apple80211GetInfoCopy(drv->wireless_ctx, &dict);
+ if (err == 0) {
+ CFShow(dict);
+ CFRelease(dict);
+ } else {
+ printf("Apple80211GetInfoCopy: %d\n", err);
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_iphone_deinit(void *priv)
+{
+ struct wpa_driver_iphone_data *drv = priv;
+ int err;
+
+ eloop_cancel_timeout(wpa_driver_iphone_scan_timeout, drv, drv->ctx);
+ eloop_cancel_timeout(wpa_driver_iphone_assoc_timeout, drv, drv->ctx);
+
+ if (drv->ctrl_power) {
+ wpa_printf(MSG_DEBUG, "iPhone: Power down the interface");
+ err = Apple80211SetPower(drv->wireless_ctx, 0);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211SetPower(0) "
+ "failed: %d", err);
+ }
+ }
+
+ err = Apple80211Close(drv->wireless_ctx);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "iPhone: Apple80211Close failed: %d",
+ err);
+ }
+
+ if (drv->scan_results)
+ CFRelease(drv->scan_results);
+
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_iphone_ops = {
+ .name = "iphone",
+ .desc = "iPhone/iPod touch Apple80211 driver",
+ .get_ssid = wpa_driver_iphone_get_ssid,
+ .get_bssid = wpa_driver_iphone_get_bssid,
+ .init = wpa_driver_iphone_init,
+ .deinit = wpa_driver_iphone_deinit,
+ .scan = wpa_driver_iphone_scan,
+ .get_scan_results = wpa_driver_iphone_get_scan_results,
+ .associate = wpa_driver_iphone_associate,
+ .set_key = wpa_driver_iphone_set_key,
+ .get_capa = wpa_driver_iphone_get_capa,
+};
diff --git a/src/drivers/driver_ipw.c b/src/drivers/driver_ipw.c
new file mode 100644
index 0000000..3c19ccc
--- /dev/null
+++ b/src/drivers/driver_ipw.c
@@ -0,0 +1,463 @@
+/*
+ * WPA Supplicant - driver interaction with Linux ipw2100/2200 drivers
+ * Copyright (c) 2005 Zhu Yi <yi.zhu@intel.com>
+ * Copyright (c) 2004 Lubomir Gelo <lgelo@cnc.sk>
+ * Copyright (c) 2003-2004, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * Please note that ipw2100/2200 drivers change to use generic Linux wireless
+ * extensions if the kernel includes support for WE-18 or newer (Linux 2.6.13
+ * or newer). driver_wext.c should be used in those cases.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "driver_wext.h"
+
+struct wpa_driver_ipw_data {
+ void *wext; /* private data for driver_wext */
+ void *ctx;
+ char ifname[IFNAMSIZ + 1];
+ int sock;
+};
+
+/* following definitions must be kept in sync with ipw2100.c and ipw2200.c */
+
+#define IPW_IOCTL_WPA_SUPPLICANT SIOCIWFIRSTPRIV+30
+
+#define IPW_CMD_SET_WPA_PARAM 1
+#define IPW_CMD_SET_WPA_IE 2
+#define IPW_CMD_SET_ENCRYPTION 3
+#define IPW_CMD_MLME 4
+
+#define IPW_PARAM_WPA_ENABLED 1
+#define IPW_PARAM_TKIP_COUNTERMEASURES 2
+#define IPW_PARAM_DROP_UNENCRYPTED 3
+#define IPW_PARAM_PRIVACY_INVOKED 4
+#define IPW_PARAM_AUTH_ALGS 5
+#define IPW_PARAM_IEEE_802_1X 6
+
+#define IPW_MLME_STA_DEAUTH 1
+#define IPW_MLME_STA_DISASSOC 2
+
+#define IPW_CRYPT_ERR_UNKNOWN_ALG 2
+#define IPW_CRYPT_ERR_UNKNOWN_ADDR 3
+#define IPW_CRYPT_ERR_CRYPT_INIT_FAILED 4
+#define IPW_CRYPT_ERR_KEY_SET_FAILED 5
+#define IPW_CRYPT_ERR_TX_KEY_SET_FAILED 6
+#define IPW_CRYPT_ERR_CARD_CONF_FAILED 7
+
+#define IPW_CRYPT_ALG_NAME_LEN 16
+
+struct ipw_param {
+ u32 cmd;
+ u8 sta_addr[ETH_ALEN];
+ union {
+ struct {
+ u8 name;
+ u32 value;
+ } wpa_param;
+ struct {
+ u32 len;
+ u8 reserved[32];
+ u8 data[0];
+ } wpa_ie;
+ struct{
+ u32 command;
+ u32 reason_code;
+ } mlme;
+ struct {
+ u8 alg[IPW_CRYPT_ALG_NAME_LEN];
+ u8 set_tx;
+ u32 err;
+ u8 idx;
+ u8 seq[8];
+ u16 key_len;
+ u8 key[0];
+ } crypt;
+
+ } u;
+};
+
+/* end of ipw2100.c and ipw2200.c code */
+
+static int ipw_ioctl(struct wpa_driver_ipw_data *drv,
+ struct ipw_param *param, int len, int show_err)
+{
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) param;
+ iwr.u.data.length = len;
+
+ if (ioctl(drv->sock, IPW_IOCTL_WPA_SUPPLICANT, &iwr) < 0) {
+ int ret = errno;
+ if (show_err)
+ perror("ioctl[IPW_IOCTL_WPA_SUPPLICANT]");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static void ipw_show_set_key_error(struct ipw_param *param)
+{
+ switch (param->u.crypt.err) {
+ case IPW_CRYPT_ERR_UNKNOWN_ALG:
+ wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
+ param->u.crypt.alg);
+ wpa_printf(MSG_INFO, "You may need to load kernel module to "
+ "register that algorithm.");
+ wpa_printf(MSG_INFO, "E.g., 'modprobe ieee80211_crypt_wep' for"
+ " WEP.");
+ break;
+ case IPW_CRYPT_ERR_UNKNOWN_ADDR:
+ wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
+ MAC2STR(param->sta_addr));
+ break;
+ case IPW_CRYPT_ERR_CRYPT_INIT_FAILED:
+ wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
+ break;
+ case IPW_CRYPT_ERR_KEY_SET_FAILED:
+ wpa_printf(MSG_INFO, "Key setting failed.");
+ break;
+ case IPW_CRYPT_ERR_TX_KEY_SET_FAILED:
+ wpa_printf(MSG_INFO, "TX key index setting failed.");
+ break;
+ case IPW_CRYPT_ERR_CARD_CONF_FAILED:
+ wpa_printf(MSG_INFO, "Card configuration failed.");
+ break;
+ }
+}
+
+
+static int ipw_set_wpa_ie(struct wpa_driver_ipw_data *drv,
+ const u8 *wpa_ie, size_t wpa_ie_len)
+{
+ struct ipw_param *param;
+ int ret;
+ size_t blen = sizeof(*param) + wpa_ie_len;
+
+ param = os_zalloc(blen);
+ if (param == NULL)
+ return -1;
+
+ param->cmd = IPW_CMD_SET_WPA_IE;
+ param->u.wpa_ie.len = wpa_ie_len;
+ os_memcpy(param->u.wpa_ie.data, wpa_ie, wpa_ie_len);
+
+ ret = ipw_ioctl(drv, param, blen, 1);
+
+ os_free(param);
+ return ret;
+}
+
+
+static int ipw_set_wpa_param(struct wpa_driver_ipw_data *drv, u8 name,
+ u32 value)
+{
+ struct ipw_param param;
+
+ os_memset(&param, 0, sizeof(param));
+ param.cmd = IPW_CMD_SET_WPA_PARAM;
+ param.u.wpa_param.name = name;
+ param.u.wpa_param.value = value;
+
+ return ipw_ioctl(drv, &param, sizeof(param), 1);
+}
+
+
+static int ipw_mlme(struct wpa_driver_ipw_data *drv, const u8 *addr,
+ int cmd, int reason)
+{
+ struct ipw_param param;
+
+ os_memset(&param, 0, sizeof(param));
+ os_memcpy(param.sta_addr, addr, ETH_ALEN);
+ param.cmd = IPW_CMD_MLME;
+ param.u.mlme.command = cmd;
+ param.u.mlme.reason_code = reason;
+
+ return ipw_ioctl(drv, &param, sizeof(param), 1);
+}
+
+
+static int wpa_driver_ipw_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+
+ if (!enabled && ipw_set_wpa_ie(drv, NULL, 0) < 0)
+ ret = -1;
+
+ if (ipw_set_wpa_param(drv, IPW_PARAM_WPA_ENABLED, enabled) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int wpa_driver_ipw_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ struct ipw_param *param;
+ u8 *buf;
+ size_t blen;
+ int ret = 0;
+ char *alg_name;
+
+ switch (alg) {
+ case WPA_ALG_NONE:
+ alg_name = "none";
+ break;
+ case WPA_ALG_WEP:
+ alg_name = "WEP";
+ break;
+ case WPA_ALG_TKIP:
+ alg_name = "TKIP";
+ break;
+ case WPA_ALG_CCMP:
+ alg_name = "CCMP";
+ break;
+ default:
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
+ "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ if (seq_len > 8)
+ return -2;
+
+ blen = sizeof(*param) + key_len;
+ buf = os_zalloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ param = (struct ipw_param *) buf;
+ param->cmd = IPW_CMD_SET_ENCRYPTION;
+ os_memset(param->sta_addr, 0xff, ETH_ALEN);
+ os_strlcpy((char *) param->u.crypt.alg, alg_name,
+ IPW_CRYPT_ALG_NAME_LEN);
+ param->u.crypt.set_tx = set_tx ? 1 : 0;
+ param->u.crypt.idx = key_idx;
+ os_memcpy(param->u.crypt.seq, seq, seq_len);
+ param->u.crypt.key_len = key_len;
+ os_memcpy((u8 *) (param + 1), key, key_len);
+
+ if (ipw_ioctl(drv, param, blen, 1)) {
+ wpa_printf(MSG_WARNING, "Failed to set encryption.");
+ ipw_show_set_key_error(param);
+ ret = -1;
+ }
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int wpa_driver_ipw_set_countermeasures(void *priv, int enabled)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return ipw_set_wpa_param(drv, IPW_PARAM_TKIP_COUNTERMEASURES,
+ enabled);
+
+}
+
+
+static int wpa_driver_ipw_set_drop_unencrypted(void *priv, int enabled)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return ipw_set_wpa_param(drv, IPW_PARAM_DROP_UNENCRYPTED,
+ enabled);
+}
+
+
+static int wpa_driver_ipw_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ return ipw_mlme(drv, addr, IPW_MLME_STA_DEAUTH, reason_code);
+}
+
+
+static int wpa_driver_ipw_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ return ipw_mlme(drv, addr, IPW_MLME_STA_DISASSOC, reason_code);
+}
+
+
+static int
+wpa_driver_ipw_associate(void *priv, struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ int ret = 0;
+ int unencrypted_eapol;
+
+ if (ipw_set_wpa_ie(drv, params->wpa_ie, params->wpa_ie_len) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
+ params->ssid_len) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
+ ret = -1;
+
+ if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+ params->key_mgmt_suite == KEY_MGMT_PSK)
+ unencrypted_eapol = 0;
+ else
+ unencrypted_eapol = 1;
+
+ if (ipw_set_wpa_param(drv, IPW_PARAM_IEEE_802_1X,
+ unencrypted_eapol) < 0) {
+ wpa_printf(MSG_DEBUG, "ipw: Failed to configure "
+ "ieee_802_1x param");
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_ipw_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ int algs = 0;
+
+ if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ algs |= 1;
+ if (auth_alg & AUTH_ALG_SHARED_KEY)
+ algs |= 2;
+ if (auth_alg & AUTH_ALG_LEAP)
+ algs |= 4;
+ if (algs == 0)
+ algs = 1; /* at least one algorithm should be set */
+
+ wpa_printf(MSG_DEBUG, "%s: auth_alg=0x%x", __FUNCTION__, algs);
+ return ipw_set_wpa_param(drv, IPW_PARAM_AUTH_ALGS, algs);
+}
+
+
+static int wpa_driver_ipw_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ return wpa_driver_wext_get_bssid(drv->wext, bssid);
+}
+
+
+static int wpa_driver_ipw_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ return wpa_driver_wext_get_ssid(drv->wext, ssid);
+}
+
+
+static int wpa_driver_ipw_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
+}
+
+
+static struct wpa_scan_results * wpa_driver_ipw_get_scan_results(void *priv)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ return wpa_driver_wext_get_scan_results(drv->wext);
+}
+
+
+static int wpa_driver_ipw_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ return wpa_driver_wext_set_operstate(drv->wext, state);
+}
+
+
+static void * wpa_driver_ipw_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_ipw_data *drv;
+ int ver;
+
+ wpa_printf(MSG_DEBUG, "%s is called", __FUNCTION__);
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->wext = wpa_driver_wext_init(ctx, ifname);
+ if (drv->wext == NULL) {
+ os_free(drv);
+ return NULL;
+ }
+
+ ver = wpa_driver_wext_get_version(drv->wext);
+ if (ver >= 18) {
+ wpa_printf(MSG_WARNING, "Linux wireless extensions version %d "
+ "detected.", ver);
+ wpa_printf(MSG_WARNING, "ipw2x00 driver uses driver_wext "
+ "(-Dwext) instead of driver_ipw.");
+ }
+
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->sock < 0) {
+ wpa_driver_wext_deinit(drv->wext);
+ os_free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_ipw_deinit(void *priv)
+{
+ struct wpa_driver_ipw_data *drv = priv;
+ wpa_driver_wext_deinit(drv->wext);
+ close(drv->sock);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_ipw_ops = {
+ .name = "ipw",
+ .desc = "Intel ipw2100/2200 driver (old; use wext with Linux 2.6.13 "
+ "or newer)",
+ .get_bssid = wpa_driver_ipw_get_bssid,
+ .get_ssid = wpa_driver_ipw_get_ssid,
+ .set_wpa = wpa_driver_ipw_set_wpa,
+ .set_key = wpa_driver_ipw_set_key,
+ .set_countermeasures = wpa_driver_ipw_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_ipw_set_drop_unencrypted,
+ .scan = wpa_driver_ipw_scan,
+ .get_scan_results2 = wpa_driver_ipw_get_scan_results,
+ .deauthenticate = wpa_driver_ipw_deauthenticate,
+ .disassociate = wpa_driver_ipw_disassociate,
+ .associate = wpa_driver_ipw_associate,
+ .set_auth_alg = wpa_driver_ipw_set_auth_alg,
+ .init = wpa_driver_ipw_init,
+ .deinit = wpa_driver_ipw_deinit,
+ .set_operstate = wpa_driver_ipw_set_operstate,
+};
diff --git a/src/drivers/driver_madwifi.c b/src/drivers/driver_madwifi.c
new file mode 100644
index 0000000..7521037
--- /dev/null
+++ b/src/drivers/driver_madwifi.c
@@ -0,0 +1,601 @@
+/*
+ * WPA Supplicant - driver interaction with MADWIFI 802.11 driver
+ * Copyright (c) 2004, Sam Leffler <sam@errno.com>
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * Please note that madwifi supports WPA configuration via Linux wireless
+ * extensions and if the kernel includes support for this, driver_wext.c should
+ * be used instead of this driver wrapper.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "common.h"
+#include "driver.h"
+#include "driver_wext.h"
+#include "eloop.h"
+#include "ieee802_11_defs.h"
+#include "wireless_copy.h"
+
+/*
+ * Avoid conflicts with wpa_supplicant definitions by undefining a definition.
+ */
+#undef WME_OUI_TYPE
+
+#include <include/compat.h>
+#include <net80211/ieee80211.h>
+#ifdef WME_NUM_AC
+/* Assume this is built against BSD branch of madwifi driver. */
+#define MADWIFI_BSD
+#include <net80211/_ieee80211.h>
+#endif /* WME_NUM_AC */
+#include <net80211/ieee80211_crypto.h>
+#include <net80211/ieee80211_ioctl.h>
+
+
+#ifdef IEEE80211_IOCTL_SETWMMPARAMS
+/* Assume this is built against madwifi-ng */
+#define MADWIFI_NG
+#endif /* IEEE80211_IOCTL_SETWMMPARAMS */
+
+struct wpa_driver_madwifi_data {
+ void *wext; /* private data for driver_wext */
+ void *ctx;
+ char ifname[IFNAMSIZ + 1];
+ int sock;
+};
+
+static int
+set80211priv(struct wpa_driver_madwifi_data *drv, int op, void *data, int len,
+ int show_err)
+{
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ if (len < IFNAMSIZ &&
+ op != IEEE80211_IOCTL_SET_APPIEBUF) {
+ /*
+ * Argument data fits inline; put it there.
+ */
+ os_memcpy(iwr.u.name, data, len);
+ } else {
+ /*
+ * Argument data too big for inline transfer; setup a
+ * parameter block instead; the kernel will transfer
+ * the data for the driver.
+ */
+ iwr.u.data.pointer = data;
+ iwr.u.data.length = len;
+ }
+
+ if (ioctl(drv->sock, op, &iwr) < 0) {
+ if (show_err) {
+#ifdef MADWIFI_NG
+ int first = IEEE80211_IOCTL_SETPARAM;
+ int last = IEEE80211_IOCTL_KICKMAC;
+ static const char *opnames[] = {
+ "ioctl[IEEE80211_IOCTL_SETPARAM]",
+ "ioctl[IEEE80211_IOCTL_GETPARAM]",
+ "ioctl[IEEE80211_IOCTL_SETMODE]",
+ "ioctl[IEEE80211_IOCTL_GETMODE]",
+ "ioctl[IEEE80211_IOCTL_SETWMMPARAMS]",
+ "ioctl[IEEE80211_IOCTL_GETWMMPARAMS]",
+ "ioctl[IEEE80211_IOCTL_SETCHANLIST]",
+ "ioctl[IEEE80211_IOCTL_GETCHANLIST]",
+ "ioctl[IEEE80211_IOCTL_CHANSWITCH]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_SET_APPIEBUF]",
+ "ioctl[IEEE80211_IOCTL_GETSCANRESULTS]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_GETCHANINFO]",
+ "ioctl[IEEE80211_IOCTL_SETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_GETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_SETMLME]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_SETKEY]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_DELKEY]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_ADDMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_DELMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_WDSMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_WDSDELMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_KICKMAC]",
+ };
+#else /* MADWIFI_NG */
+ int first = IEEE80211_IOCTL_SETPARAM;
+ int last = IEEE80211_IOCTL_CHANLIST;
+ static const char *opnames[] = {
+ "ioctl[IEEE80211_IOCTL_SETPARAM]",
+ "ioctl[IEEE80211_IOCTL_GETPARAM]",
+ "ioctl[IEEE80211_IOCTL_SETKEY]",
+ "ioctl[IEEE80211_IOCTL_GETKEY]",
+ "ioctl[IEEE80211_IOCTL_DELKEY]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_SETMLME]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_SETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_GETOPTIE]",
+ "ioctl[IEEE80211_IOCTL_ADDMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_DELMAC]",
+ NULL,
+ "ioctl[IEEE80211_IOCTL_CHANLIST]",
+ };
+#endif /* MADWIFI_NG */
+ int idx = op - first;
+ if (first <= op && op <= last &&
+ idx < (int) (sizeof(opnames) / sizeof(opnames[0]))
+ && opnames[idx])
+ perror(opnames[idx]);
+ else
+ perror("ioctl[unknown???]");
+ }
+ return -1;
+ }
+ return 0;
+}
+
+static int
+set80211param(struct wpa_driver_madwifi_data *drv, int op, int arg,
+ int show_err)
+{
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.mode = op;
+ os_memcpy(iwr.u.name+sizeof(u32), &arg, sizeof(arg));
+
+ if (ioctl(drv->sock, IEEE80211_IOCTL_SETPARAM, &iwr) < 0) {
+ if (show_err)
+ perror("ioctl[IEEE80211_IOCTL_SETPARAM]");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+wpa_driver_madwifi_set_wpa_ie(struct wpa_driver_madwifi_data *drv,
+ const u8 *wpa_ie, size_t wpa_ie_len)
+{
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ /* NB: SETOPTIE is not fixed-size so must not be inlined */
+ iwr.u.data.pointer = (void *) wpa_ie;
+ iwr.u.data.length = wpa_ie_len;
+
+ if (ioctl(drv->sock, IEEE80211_IOCTL_SETOPTIE, &iwr) < 0) {
+ perror("ioctl[IEEE80211_IOCTL_SETOPTIE]");
+ return -1;
+ }
+ return 0;
+}
+
+static int
+wpa_driver_madwifi_del_key(struct wpa_driver_madwifi_data *drv, int key_idx,
+ const u8 *addr)
+{
+ struct ieee80211req_del_key wk;
+
+ wpa_printf(MSG_DEBUG, "%s: keyidx=%d", __FUNCTION__, key_idx);
+ os_memset(&wk, 0, sizeof(wk));
+ wk.idk_keyix = key_idx;
+ if (addr != NULL)
+ os_memcpy(wk.idk_macaddr, addr, IEEE80211_ADDR_LEN);
+
+ return set80211priv(drv, IEEE80211_IOCTL_DELKEY, &wk, sizeof(wk), 1);
+}
+
+static int
+wpa_driver_madwifi_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ struct ieee80211req_key wk;
+ char *alg_name;
+ u_int8_t cipher;
+
+ if (alg == WPA_ALG_NONE)
+ return wpa_driver_madwifi_del_key(drv, key_idx, addr);
+
+ switch (alg) {
+ case WPA_ALG_WEP:
+ if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
+ ETH_ALEN) == 0) {
+ /*
+ * madwifi did not seem to like static WEP key
+ * configuration with IEEE80211_IOCTL_SETKEY, so use
+ * Linux wireless extensions ioctl for this.
+ */
+ return wpa_driver_wext_set_key(drv->wext, alg, addr,
+ key_idx, set_tx,
+ seq, seq_len,
+ key, key_len);
+ }
+ alg_name = "WEP";
+ cipher = IEEE80211_CIPHER_WEP;
+ break;
+ case WPA_ALG_TKIP:
+ alg_name = "TKIP";
+ cipher = IEEE80211_CIPHER_TKIP;
+ break;
+ case WPA_ALG_CCMP:
+ alg_name = "CCMP";
+ cipher = IEEE80211_CIPHER_AES_CCM;
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "%s: unknown/unsupported algorithm %d",
+ __FUNCTION__, alg);
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
+ "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ if (seq_len > sizeof(u_int64_t)) {
+ wpa_printf(MSG_DEBUG, "%s: seq_len %lu too big",
+ __FUNCTION__, (unsigned long) seq_len);
+ return -2;
+ }
+ if (key_len > sizeof(wk.ik_keydata)) {
+ wpa_printf(MSG_DEBUG, "%s: key length %lu too big",
+ __FUNCTION__, (unsigned long) key_len);
+ return -3;
+ }
+
+ os_memset(&wk, 0, sizeof(wk));
+ wk.ik_type = cipher;
+ wk.ik_flags = IEEE80211_KEY_RECV;
+ if (addr == NULL ||
+ os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
+ wk.ik_flags |= IEEE80211_KEY_GROUP;
+ if (set_tx) {
+ wk.ik_flags |= IEEE80211_KEY_XMIT | IEEE80211_KEY_DEFAULT;
+ os_memcpy(wk.ik_macaddr, addr, IEEE80211_ADDR_LEN);
+ } else
+ os_memset(wk.ik_macaddr, 0, IEEE80211_ADDR_LEN);
+ wk.ik_keyix = key_idx;
+ wk.ik_keylen = key_len;
+#ifdef WORDS_BIGENDIAN
+#define WPA_KEY_RSC_LEN 8
+ {
+ size_t i;
+ u8 tmp[WPA_KEY_RSC_LEN];
+ os_memset(tmp, 0, sizeof(tmp));
+ for (i = 0; i < seq_len; i++)
+ tmp[WPA_KEY_RSC_LEN - i - 1] = seq[i];
+ os_memcpy(&wk.ik_keyrsc, tmp, WPA_KEY_RSC_LEN);
+ }
+#else /* WORDS_BIGENDIAN */
+ os_memcpy(&wk.ik_keyrsc, seq, seq_len);
+#endif /* WORDS_BIGENDIAN */
+ os_memcpy(wk.ik_keydata, key, key_len);
+
+ return set80211priv(drv, IEEE80211_IOCTL_SETKEY, &wk, sizeof(wk), 1);
+}
+
+static int
+wpa_driver_madwifi_set_countermeasures(void *priv, int enabled)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return set80211param(drv, IEEE80211_PARAM_COUNTERMEASURES, enabled, 1);
+}
+
+
+static int
+wpa_driver_madwifi_set_drop_unencrypted(void *priv, int enabled)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return set80211param(drv, IEEE80211_PARAM_DROPUNENCRYPTED, enabled, 1);
+}
+
+static int
+wpa_driver_madwifi_deauthenticate(void *priv, const u8 *addr, int reason_code)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ mlme.im_op = IEEE80211_MLME_DEAUTH;
+ mlme.im_reason = reason_code;
+ os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
+}
+
+static int
+wpa_driver_madwifi_disassociate(void *priv, const u8 *addr, int reason_code)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ mlme.im_op = IEEE80211_MLME_DISASSOC;
+ mlme.im_reason = reason_code;
+ os_memcpy(mlme.im_macaddr, addr, IEEE80211_ADDR_LEN);
+ return set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme, sizeof(mlme), 1);
+}
+
+static int
+wpa_driver_madwifi_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ struct ieee80211req_mlme mlme;
+ int ret = 0, privacy = 1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ /*
+ * NB: Don't need to set the freq or cipher-related state as
+ * this is implied by the bssid which is used to locate
+ * the scanned node state which holds it. The ssid is
+ * needed to disambiguate an AP that broadcasts multiple
+ * ssid's but uses the same bssid.
+ */
+ /* XXX error handling is wrong but unclear what to do... */
+ if (wpa_driver_madwifi_set_wpa_ie(drv, params->wpa_ie,
+ params->wpa_ie_len) < 0)
+ ret = -1;
+
+ if (params->pairwise_suite == CIPHER_NONE &&
+ params->group_suite == CIPHER_NONE &&
+ params->key_mgmt_suite == KEY_MGMT_NONE &&
+ params->wpa_ie_len == 0)
+ privacy = 0;
+
+ if (set80211param(drv, IEEE80211_PARAM_PRIVACY, privacy, 1) < 0)
+ ret = -1;
+
+ if (params->wpa_ie_len &&
+ set80211param(drv, IEEE80211_PARAM_WPA,
+ params->wpa_ie[0] == WLAN_EID_RSN ? 2 : 1, 1) < 0)
+ ret = -1;
+
+ if (params->bssid == NULL) {
+ /* ap_scan=2 mode - driver takes care of AP selection and
+ * roaming */
+ /* FIX: this does not seem to work; would probably need to
+ * change something in the driver */
+ if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0)
+ ret = -1;
+
+ if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
+ params->ssid_len) < 0)
+ ret = -1;
+ } else {
+ if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
+ params->ssid_len) < 0)
+ ret = -1;
+ os_memset(&mlme, 0, sizeof(mlme));
+ mlme.im_op = IEEE80211_MLME_ASSOC;
+ os_memcpy(mlme.im_macaddr, params->bssid, IEEE80211_ADDR_LEN);
+ if (set80211priv(drv, IEEE80211_IOCTL_SETMLME, &mlme,
+ sizeof(mlme), 1) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: SETMLME[ASSOC] failed",
+ __func__);
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+static int
+wpa_driver_madwifi_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ int authmode;
+
+ if ((auth_alg & AUTH_ALG_OPEN_SYSTEM) &&
+ (auth_alg & AUTH_ALG_SHARED_KEY))
+ authmode = IEEE80211_AUTH_AUTO;
+ else if (auth_alg & AUTH_ALG_SHARED_KEY)
+ authmode = IEEE80211_AUTH_SHARED;
+ else
+ authmode = IEEE80211_AUTH_OPEN;
+
+ return set80211param(drv, IEEE80211_PARAM_AUTHMODE, authmode, 1);
+}
+
+static int
+wpa_driver_madwifi_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ /* set desired ssid before scan */
+ /* FIX: scan should not break the current association, so using
+ * set_ssid may not be the best way of doing this.. */
+ if (wpa_driver_wext_set_ssid(drv->wext, ssid, ssid_len) < 0)
+ ret = -1;
+
+ if (ioctl(drv->sock, SIOCSIWSCAN, &iwr) < 0) {
+ perror("ioctl[SIOCSIWSCAN]");
+ ret = -1;
+ }
+
+ /*
+ * madwifi delivers a scan complete event so no need to poll, but
+ * register a backup timeout anyway to make sure that we recover even
+ * if the driver does not send this event for any reason. This timeout
+ * will only be used if the event is not delivered (event handler will
+ * cancel the timeout).
+ */
+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv->wext,
+ drv->ctx);
+ eloop_register_timeout(30, 0, wpa_driver_wext_scan_timeout, drv->wext,
+ drv->ctx);
+
+ return ret;
+}
+
+static int wpa_driver_madwifi_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ return wpa_driver_wext_get_bssid(drv->wext, bssid);
+}
+
+
+static int wpa_driver_madwifi_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ return wpa_driver_wext_get_ssid(drv->wext, ssid);
+}
+
+
+static struct wpa_scan_results *
+wpa_driver_madwifi_get_scan_results(void *priv)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ return wpa_driver_wext_get_scan_results(drv->wext);
+}
+
+
+static int wpa_driver_madwifi_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+ return wpa_driver_wext_set_operstate(drv->wext, state);
+}
+
+
+static int wpa_driver_madwifi_set_probe_req_ie(void *priv, const u8 *ies,
+ size_t ies_len)
+{
+ struct ieee80211req_getset_appiebuf *probe_req_ie;
+ int ret;
+
+ probe_req_ie = os_malloc(sizeof(*probe_req_ie) + ies_len);
+ if (probe_req_ie == NULL)
+ return -1;
+
+ probe_req_ie->app_frmtype = IEEE80211_APPIE_FRAME_PROBE_REQ;
+ probe_req_ie->app_buflen = ies_len;
+ os_memcpy(probe_req_ie->app_buf, ies, ies_len);
+
+ ret = set80211priv(priv, IEEE80211_IOCTL_SET_APPIEBUF, probe_req_ie,
+ sizeof(struct ieee80211req_getset_appiebuf) +
+ ies_len, 1);
+
+ os_free(probe_req_ie);
+
+ return ret;
+}
+
+
+static void * wpa_driver_madwifi_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_madwifi_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->wext = wpa_driver_wext_init(ctx, ifname);
+ if (drv->wext == NULL)
+ goto fail;
+
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->sock < 0)
+ goto fail2;
+
+ if (set80211param(drv, IEEE80211_PARAM_ROAMING, 2, 1) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to set wpa_supplicant-based "
+ "roaming", __FUNCTION__);
+ goto fail3;
+ }
+
+ if (set80211param(drv, IEEE80211_PARAM_WPA, 3, 1) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to enable WPA support",
+ __FUNCTION__);
+ goto fail3;
+ }
+
+ return drv;
+
+fail3:
+ close(drv->sock);
+fail2:
+ wpa_driver_wext_deinit(drv->wext);
+fail:
+ os_free(drv);
+ return NULL;
+}
+
+
+static void wpa_driver_madwifi_deinit(void *priv)
+{
+ struct wpa_driver_madwifi_data *drv = priv;
+
+ if (wpa_driver_madwifi_set_wpa_ie(drv, NULL, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to clear WPA IE",
+ __FUNCTION__);
+ }
+ if (set80211param(drv, IEEE80211_PARAM_ROAMING, 0, 1) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to enable driver-based "
+ "roaming", __FUNCTION__);
+ }
+ if (set80211param(drv, IEEE80211_PARAM_PRIVACY, 0, 1) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to disable forced Privacy "
+ "flag", __FUNCTION__);
+ }
+ if (set80211param(drv, IEEE80211_PARAM_WPA, 0, 1) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed to disable WPA",
+ __FUNCTION__);
+ }
+
+ wpa_driver_wext_deinit(drv->wext);
+
+ close(drv->sock);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_madwifi_ops = {
+ .name = "madwifi",
+ .desc = "MADWIFI 802.11 support (Atheros, etc.)",
+ .get_bssid = wpa_driver_madwifi_get_bssid,
+ .get_ssid = wpa_driver_madwifi_get_ssid,
+ .set_key = wpa_driver_madwifi_set_key,
+ .init = wpa_driver_madwifi_init,
+ .deinit = wpa_driver_madwifi_deinit,
+ .set_countermeasures = wpa_driver_madwifi_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_madwifi_set_drop_unencrypted,
+ .scan = wpa_driver_madwifi_scan,
+ .get_scan_results2 = wpa_driver_madwifi_get_scan_results,
+ .deauthenticate = wpa_driver_madwifi_deauthenticate,
+ .disassociate = wpa_driver_madwifi_disassociate,
+ .associate = wpa_driver_madwifi_associate,
+ .set_auth_alg = wpa_driver_madwifi_set_auth_alg,
+ .set_operstate = wpa_driver_madwifi_set_operstate,
+ .set_probe_req_ie = wpa_driver_madwifi_set_probe_req_ie,
+};
diff --git a/src/drivers/driver_ndis.c b/src/drivers/driver_ndis.c
index b22109b..a90e277 100644
--- a/src/drivers/driver_ndis.c
+++ b/src/drivers/driver_ndis.c
@@ -56,6 +56,10 @@ static int wpa_driver_ndis_adapter_open(struct wpa_driver_ndis_data *drv);
static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv);
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+
/* FIX: to be removed once this can be compiled with the complete NDIS
* header files */
#ifndef OID_802_11_BSSID
@@ -610,12 +614,7 @@ static int wpa_driver_ndis_get_bssid(void *priv, u8 *bssid)
* Report PAE group address as the "BSSID" for wired
* connection.
*/
- bssid[0] = 0x01;
- bssid[1] = 0x80;
- bssid[2] = 0xc2;
- bssid[3] = 0x00;
- bssid[4] = 0x00;
- bssid[5] = 0x03;
+ os_memcpy(bssid, pae_group_addr, ETH_ALEN);
return 0;
}
@@ -2704,6 +2703,19 @@ static void wpa_driver_ndis_adapter_close(struct wpa_driver_ndis_data *drv)
}
+static int ndis_add_multicast(struct wpa_driver_ndis_data *drv)
+{
+ if (ndis_set_oid(drv, OID_802_3_MULTICAST_LIST,
+ (const char *) pae_group_addr, ETH_ALEN) < 0) {
+ wpa_printf(MSG_DEBUG, "NDIS: Failed to add PAE group address "
+ "to the multicast list");
+ return -1;
+ }
+
+ return 0;
+}
+
+
static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
{
struct wpa_driver_ndis_data *drv;
@@ -2799,6 +2811,7 @@ static void * wpa_driver_ndis_init(void *ctx, const char *ifname)
"any wireless capabilities - assume it is "
"a wired interface");
drv->wired = 1;
+ ndis_add_multicast(drv);
}
}
diff --git a/src/drivers/driver_ndis_.c b/src/drivers/driver_ndis_.c
new file mode 100644
index 0000000..4bee9aa
--- /dev/null
+++ b/src/drivers/driver_ndis_.c
@@ -0,0 +1,105 @@
+/*
+ * WPA Supplicant - Windows/NDIS driver interface - event processing
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+
+/* Keep this event processing in a separate file and without WinPcap headers to
+ * avoid conflicts with some of the header files. */
+struct _ADAPTER;
+typedef struct _ADAPTER * LPADAPTER;
+#include "driver_ndis.h"
+
+
+void wpa_driver_ndis_event_connect(struct wpa_driver_ndis_data *drv);
+void wpa_driver_ndis_event_disconnect(struct wpa_driver_ndis_data *drv);
+void wpa_driver_ndis_event_media_specific(struct wpa_driver_ndis_data *drv,
+ const u8 *data, size_t data_len);
+void wpa_driver_ndis_event_adapter_arrival(struct wpa_driver_ndis_data *drv);
+void wpa_driver_ndis_event_adapter_removal(struct wpa_driver_ndis_data *drv);
+
+
+enum event_types { EVENT_CONNECT, EVENT_DISCONNECT,
+ EVENT_MEDIA_SPECIFIC, EVENT_ADAPTER_ARRIVAL,
+ EVENT_ADAPTER_REMOVAL };
+
+/* Event data:
+ * enum event_types (as int, i.e., 4 octets)
+ * data length (2 octets (big endian), optional)
+ * data (variable len, optional)
+ */
+
+
+static void wpa_driver_ndis_event_process(struct wpa_driver_ndis_data *drv,
+ u8 *buf, size_t len)
+{
+ u8 *pos, *data = NULL;
+ enum event_types type;
+ size_t data_len = 0;
+
+ wpa_hexdump(MSG_MSGDUMP, "NDIS: received event data", buf, len);
+ if (len < sizeof(int))
+ return;
+ type = *((int *) buf);
+ pos = buf + sizeof(int);
+ wpa_printf(MSG_DEBUG, "NDIS: event - type %d", type);
+
+ if (buf + len - pos > 2) {
+ data_len = (int) *pos++ << 8;
+ data_len += *pos++;
+ if (data_len > (size_t) (buf + len - pos)) {
+ wpa_printf(MSG_DEBUG, "NDIS: event data overflow");
+ return;
+ }
+ data = pos;
+ wpa_hexdump(MSG_MSGDUMP, "NDIS: event data", data, data_len);
+ }
+
+ switch (type) {
+ case EVENT_CONNECT:
+ wpa_driver_ndis_event_connect(drv);
+ break;
+ case EVENT_DISCONNECT:
+ wpa_driver_ndis_event_disconnect(drv);
+ break;
+ case EVENT_MEDIA_SPECIFIC:
+ wpa_driver_ndis_event_media_specific(drv, data, data_len);
+ break;
+ case EVENT_ADAPTER_ARRIVAL:
+ wpa_driver_ndis_event_adapter_arrival(drv);
+ break;
+ case EVENT_ADAPTER_REMOVAL:
+ wpa_driver_ndis_event_adapter_removal(drv);
+ break;
+ }
+}
+
+
+void wpa_driver_ndis_event_pipe_cb(void *eloop_data, void *user_data)
+{
+ struct wpa_driver_ndis_data *drv = eloop_data;
+ u8 buf[512];
+ DWORD len;
+
+ ResetEvent(drv->event_avail);
+ if (ReadFile(drv->events_pipe, buf, sizeof(buf), &len, NULL))
+ wpa_driver_ndis_event_process(drv, buf, len);
+ else {
+ wpa_printf(MSG_DEBUG, "%s: ReadFile() failed: %d", __func__,
+ (int) GetLastError());
+ }
+}
diff --git a/src/drivers/driver_ndiswrapper.c b/src/drivers/driver_ndiswrapper.c
new file mode 100644
index 0000000..b5c534a
--- /dev/null
+++ b/src/drivers/driver_ndiswrapper.c
@@ -0,0 +1,370 @@
+/*
+ * WPA Supplicant - driver interaction with Linux ndiswrapper
+ * Copyright (c) 2004-2006, Giridhar Pemmasani <giri@lmc.cs.sunysb.edu>
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * Please note that ndiswrapper supports WPA configuration via Linux wireless
+ * extensions and if the kernel includes support for this, driver_wext.c should
+ * be used instead of this driver wrapper.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "driver_wext.h"
+
+struct wpa_driver_ndiswrapper_data {
+ void *wext; /* private data for driver_wext */
+ void *ctx;
+ char ifname[IFNAMSIZ + 1];
+ int sock;
+};
+
+
+struct wpa_key
+{
+ wpa_alg alg;
+ const u8 *addr;
+ int key_index;
+ int set_tx;
+ const u8 *seq;
+ size_t seq_len;
+ const u8 *key;
+ size_t key_len;
+};
+
+struct wpa_assoc_info
+{
+ const u8 *bssid;
+ const u8 *ssid;
+ size_t ssid_len;
+ int freq;
+ const u8 *wpa_ie;
+ size_t wpa_ie_len;
+ wpa_cipher pairwise_suite;
+ wpa_cipher group_suite;
+ wpa_key_mgmt key_mgmt_suite;
+ int auth_alg;
+ int mode;
+};
+
+#define PRIV_RESET SIOCIWFIRSTPRIV+0
+#define WPA_SET_WPA SIOCIWFIRSTPRIV+1
+#define WPA_SET_KEY SIOCIWFIRSTPRIV+2
+#define WPA_ASSOCIATE SIOCIWFIRSTPRIV+3
+#define WPA_DISASSOCIATE SIOCIWFIRSTPRIV+4
+#define WPA_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+5
+#define WPA_SET_COUNTERMEASURES SIOCIWFIRSTPRIV+6
+#define WPA_DEAUTHENTICATE SIOCIWFIRSTPRIV+7
+#define WPA_SET_AUTH_ALG SIOCIWFIRSTPRIV+8
+#define WPA_INIT SIOCIWFIRSTPRIV+9
+#define WPA_DEINIT SIOCIWFIRSTPRIV+10
+#define WPA_GET_CAPA SIOCIWFIRSTPRIV+11
+
+static int get_socket(void)
+{
+ static const int families[] = {
+ AF_INET, AF_IPX, AF_AX25, AF_APPLETALK
+ };
+ unsigned int i;
+ int sock;
+
+ for (i = 0; i < sizeof(families) / sizeof(int); ++i) {
+ sock = socket(families[i], SOCK_DGRAM, 0);
+ if (sock >= 0)
+ return sock;
+ }
+
+ return -1;
+}
+
+static int iw_set_ext(struct wpa_driver_ndiswrapper_data *drv, int request,
+ struct iwreq *pwrq)
+{
+ os_strlcpy(pwrq->ifr_name, drv->ifname, IFNAMSIZ);
+ return ioctl(drv->sock, request, pwrq);
+}
+
+static int wpa_ndiswrapper_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ struct iwreq priv_req;
+ int ret = 0;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+
+ priv_req.u.data.flags = enabled;
+ if (iw_set_ext(drv, WPA_SET_WPA, &priv_req) < 0)
+ ret = -1;
+ return ret;
+}
+
+static int wpa_ndiswrapper_set_key(void *priv, wpa_alg alg, const u8 *addr,
+ int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ struct wpa_key wpa_key;
+ int ret = 0;
+ struct iwreq priv_req;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+
+ wpa_key.alg = alg;
+ wpa_key.addr = addr;
+ wpa_key.key_index = key_idx;
+ wpa_key.set_tx = set_tx;
+ wpa_key.seq = seq;
+ wpa_key.seq_len = seq_len;
+ wpa_key.key = key;
+ wpa_key.key_len = key_len;
+
+ priv_req.u.data.pointer = (void *)&wpa_key;
+ priv_req.u.data.length = sizeof(wpa_key);
+
+ if (iw_set_ext(drv, WPA_SET_KEY, &priv_req) < 0)
+ ret = -1;
+
+ if (alg == WPA_ALG_NONE) {
+ /*
+ * ndiswrapper did not seem to be clearing keys properly in
+ * some cases with WPA_SET_KEY. For example, roaming from WPA
+ * enabled AP to plaintext one seemed to fail since the driver
+ * did not associate. Try to make sure the keys are cleared so
+ * that plaintext APs can be used in all cases.
+ */
+ wpa_driver_wext_set_key(drv->wext, alg, addr, key_idx, set_tx,
+ seq, seq_len, key, key_len);
+ }
+
+ return ret;
+}
+
+static int wpa_ndiswrapper_set_countermeasures(void *priv, int enabled)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ int ret = 0;
+ struct iwreq priv_req;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+
+ priv_req.u.param.value = enabled;
+ if (iw_set_ext(drv, WPA_SET_COUNTERMEASURES, &priv_req) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static int wpa_ndiswrapper_set_drop_unencrypted(void *priv,
+ int enabled)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ int ret = 0;
+ struct iwreq priv_req;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+
+ priv_req.u.param.value = enabled;
+ if (iw_set_ext(drv, WPA_DROP_UNENCRYPTED, &priv_req) < 0)
+ ret = -1;
+ return ret;
+}
+
+static int wpa_ndiswrapper_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ int ret = 0;
+ struct iwreq priv_req;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+
+ priv_req.u.param.value = reason_code;
+ os_memcpy(&priv_req.u.ap_addr.sa_data, addr, ETH_ALEN);
+ if (iw_set_ext(drv, WPA_DEAUTHENTICATE, &priv_req) < 0)
+ ret = -1;
+ return ret;
+}
+
+static int wpa_ndiswrapper_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ int ret = 0;
+ struct iwreq priv_req;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+
+ os_memcpy(&priv_req.u.ap_addr.sa_data, addr, ETH_ALEN);
+ if (iw_set_ext(drv, WPA_DISASSOCIATE, &priv_req) < 0)
+ ret = -1;
+ return ret;
+}
+
+static int
+wpa_ndiswrapper_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ int ret = 0;
+ struct wpa_assoc_info wpa_assoc_info;
+ struct iwreq priv_req;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+ os_memset(&wpa_assoc_info, 0, sizeof(wpa_assoc_info));
+
+ wpa_assoc_info.bssid = params->bssid;
+ wpa_assoc_info.ssid = params->ssid;
+ wpa_assoc_info.ssid_len = params->ssid_len;
+ wpa_assoc_info.freq = params->freq;
+ wpa_assoc_info.wpa_ie = params->wpa_ie;
+ wpa_assoc_info.wpa_ie_len = params->wpa_ie_len;
+ wpa_assoc_info.pairwise_suite = params->pairwise_suite;
+ wpa_assoc_info.group_suite = params->group_suite;
+ wpa_assoc_info.key_mgmt_suite = params->key_mgmt_suite;
+ wpa_assoc_info.auth_alg = params->auth_alg;
+ wpa_assoc_info.mode = params->mode;
+
+ priv_req.u.data.pointer = (void *)&wpa_assoc_info;
+ priv_req.u.data.length = sizeof(wpa_assoc_info);
+
+ if (iw_set_ext(drv, WPA_ASSOCIATE, &priv_req) < 0)
+ ret = -1;
+ return ret;
+}
+
+static int wpa_ndiswrapper_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ int ret = 0;
+ struct iwreq priv_req;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+
+ priv_req.u.param.value = auth_alg;
+ if (iw_set_ext(drv, WPA_SET_AUTH_ALG, &priv_req) < 0)
+ ret = -1;
+ return ret;
+}
+
+static int wpa_ndiswrapper_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ return wpa_driver_wext_get_bssid(drv->wext, bssid);
+}
+
+
+static int wpa_ndiswrapper_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ return wpa_driver_wext_get_ssid(drv->wext, ssid);
+}
+
+
+static int wpa_ndiswrapper_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
+}
+
+
+static struct wpa_scan_results * wpa_ndiswrapper_get_scan_results(void *priv)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ return wpa_driver_wext_get_scan_results(drv->wext);
+}
+
+
+static int wpa_ndiswrapper_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ int ret = 0;
+ struct iwreq priv_req;
+
+ os_memset(&priv_req, 0, sizeof(priv_req));
+
+ priv_req.u.data.pointer = (void *) capa;
+ priv_req.u.data.length = sizeof(*capa);
+ if (iw_set_ext(drv, WPA_GET_CAPA, &priv_req) < 0)
+ ret = -1;
+ return ret;
+
+}
+
+
+static int wpa_ndiswrapper_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ return wpa_driver_wext_set_operstate(drv->wext, state);
+}
+
+
+static void * wpa_ndiswrapper_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_ndiswrapper_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->wext = wpa_driver_wext_init(ctx, ifname);
+ if (drv->wext == NULL) {
+ os_free(drv);
+ return NULL;
+ }
+
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->sock = get_socket();
+ if (drv->sock < 0) {
+ wpa_driver_wext_deinit(drv->wext);
+ os_free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static void wpa_ndiswrapper_deinit(void *priv)
+{
+ struct wpa_driver_ndiswrapper_data *drv = priv;
+ wpa_driver_wext_deinit(drv->wext);
+ close(drv->sock);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_ndiswrapper_ops = {
+ .name = "ndiswrapper",
+ .desc = "Linux ndiswrapper (deprecated; use wext)",
+ .set_wpa = wpa_ndiswrapper_set_wpa,
+ .set_key = wpa_ndiswrapper_set_key,
+ .set_countermeasures = wpa_ndiswrapper_set_countermeasures,
+ .set_drop_unencrypted = wpa_ndiswrapper_set_drop_unencrypted,
+ .deauthenticate = wpa_ndiswrapper_deauthenticate,
+ .disassociate = wpa_ndiswrapper_disassociate,
+ .associate = wpa_ndiswrapper_associate,
+ .set_auth_alg = wpa_ndiswrapper_set_auth_alg,
+
+ .get_bssid = wpa_ndiswrapper_get_bssid,
+ .get_ssid = wpa_ndiswrapper_get_ssid,
+ .scan = wpa_ndiswrapper_scan,
+ .get_scan_results2 = wpa_ndiswrapper_get_scan_results,
+ .init = wpa_ndiswrapper_init,
+ .deinit = wpa_ndiswrapper_deinit,
+ .get_capa = wpa_ndiswrapper_get_capa,
+ .set_operstate = wpa_ndiswrapper_set_operstate,
+};
diff --git a/src/drivers/driver_nl80211.c b/src/drivers/driver_nl80211.c
new file mode 100644
index 0000000..9ab6d17
--- /dev/null
+++ b/src/drivers/driver_nl80211.c
@@ -0,0 +1,2766 @@
+/*
+ * WPA Supplicant - driver interaction with Linux nl80211/cfg80211
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if_arp.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include "nl80211_copy.h"
+#ifdef CONFIG_CLIENT_MLME
+#include <netpacket/packet.h>
+#include <linux/if_ether.h>
+#include "radiotap.h"
+#include "radiotap_iter.h"
+#endif /* CONFIG_CLIENT_MLME */
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "ieee802_11_defs.h"
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
+#endif
+#ifndef IFF_DORMANT
+#define IFF_DORMANT 0x20000 /* driver signals dormant */
+#endif
+
+#ifndef IF_OPER_DORMANT
+#define IF_OPER_DORMANT 5
+#endif
+#ifndef IF_OPER_UP
+#define IF_OPER_UP 6
+#endif
+
+
+struct wpa_driver_nl80211_data {
+ void *ctx;
+ int wext_event_sock;
+ int ioctl_sock;
+ char ifname[IFNAMSIZ + 1];
+ int ifindex;
+ int if_removed;
+ u8 *assoc_req_ies;
+ size_t assoc_req_ies_len;
+ u8 *assoc_resp_ies;
+ size_t assoc_resp_ies_len;
+ struct wpa_driver_capa capa;
+ int has_capability;
+ int we_version_compiled;
+
+ /* for set_auth_alg fallback */
+ int use_crypt;
+ int auth_alg_fallback;
+
+ int operstate;
+
+ char mlmedev[IFNAMSIZ + 1];
+
+ int scan_complete_events;
+
+ struct nl_handle *nl_handle;
+ struct nl_cache *nl_cache;
+ struct nl_cb *nl_cb;
+ struct genl_family *nl80211;
+
+#ifdef CONFIG_CLIENT_MLME
+ int monitor_sock; /* socket for monitor */
+ int monitor_ifidx;
+#endif /* CONFIG_CLIENT_MLME */
+};
+
+
+static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx,
+ void *timeout_ctx);
+static int wpa_driver_nl80211_set_mode(void *priv, int mode);
+static int wpa_driver_nl80211_flush_pmkid(void *priv);
+static int wpa_driver_nl80211_get_range(void *priv);
+static void
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv);
+
+
+/* nl80211 code */
+static int ack_handler(struct nl_msg *msg, void *arg)
+{
+ int *err = arg;
+ *err = 0;
+ return NL_STOP;
+}
+
+static int finish_handler(struct nl_msg *msg, void *arg)
+{
+ int *ret = arg;
+ *ret = 0;
+ return NL_SKIP;
+}
+
+static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
+ void *arg)
+{
+ int *ret = arg;
+ *ret = err->error;
+ return NL_SKIP;
+}
+
+static int send_and_recv_msgs(struct wpa_driver_nl80211_data *drv,
+ struct nl_msg *msg,
+ int (*valid_handler)(struct nl_msg *, void *),
+ void *valid_data)
+{
+ struct nl_cb *cb;
+ int err = -ENOMEM;
+
+ cb = nl_cb_clone(drv->nl_cb);
+ if (!cb)
+ goto out;
+
+ err = nl_send_auto_complete(drv->nl_handle, msg);
+ if (err < 0)
+ goto out;
+
+ err = 1;
+
+ nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
+ nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
+ nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
+
+ if (valid_handler)
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
+ valid_handler, valid_data);
+
+ while (err > 0)
+ nl_recvmsgs(drv->nl_handle, cb);
+ out:
+ nl_cb_put(cb);
+ nlmsg_free(msg);
+ return err;
+}
+
+
+struct family_data {
+ const char *group;
+ int id;
+};
+
+
+static int family_handler(struct nl_msg *msg, void *arg)
+{
+ struct family_data *res = arg;
+ struct nlattr *tb[CTRL_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *mcgrp;
+ int i;
+
+ nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[CTRL_ATTR_MCAST_GROUPS])
+ return NL_SKIP;
+
+ nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
+ struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
+ nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
+ nla_len(mcgrp), NULL);
+ if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
+ !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
+ os_strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
+ res->group,
+ nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
+ continue;
+ res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
+ break;
+ };
+
+ return NL_SKIP;
+}
+
+
+static int nl_get_multicast_id(struct wpa_driver_nl80211_data *drv,
+ const char *family, const char *group)
+{
+ struct nl_msg *msg;
+ int ret = -1;
+ struct family_data res = { group, -ENOENT };
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+ genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"),
+ 0, 0, CTRL_CMD_GETFAMILY, 0);
+ NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
+
+ ret = send_and_recv_msgs(drv, msg, family_handler, &res);
+ msg = NULL;
+ if (ret == 0)
+ ret = res.id;
+
+nla_put_failure:
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_send_oper_ifla(
+ struct wpa_driver_nl80211_data *drv,
+ int linkmode, int operstate)
+{
+ struct {
+ struct nlmsghdr hdr;
+ struct ifinfomsg ifinfo;
+ char opts[16];
+ } req;
+ struct rtattr *rta;
+ static int nl_seq;
+ ssize_t ret;
+
+ os_memset(&req, 0, sizeof(req));
+
+ req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.hdr.nlmsg_type = RTM_SETLINK;
+ req.hdr.nlmsg_flags = NLM_F_REQUEST;
+ req.hdr.nlmsg_seq = ++nl_seq;
+ req.hdr.nlmsg_pid = 0;
+
+ req.ifinfo.ifi_family = AF_UNSPEC;
+ req.ifinfo.ifi_type = 0;
+ req.ifinfo.ifi_index = drv->ifindex;
+ req.ifinfo.ifi_flags = 0;
+ req.ifinfo.ifi_change = 0;
+
+ if (linkmode != -1) {
+ rta = aliasing_hide_typecast(
+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
+ struct rtattr);
+ rta->rta_type = IFLA_LINKMODE;
+ rta->rta_len = RTA_LENGTH(sizeof(char));
+ *((char *) RTA_DATA(rta)) = linkmode;
+ req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
+ RTA_LENGTH(sizeof(char));
+ }
+ if (operstate != -1) {
+ rta = (struct rtattr *)
+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
+ rta->rta_type = IFLA_OPERSTATE;
+ rta->rta_len = RTA_LENGTH(sizeof(char));
+ *((char *) RTA_DATA(rta)) = operstate;
+ req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
+ RTA_LENGTH(sizeof(char));
+ }
+
+ wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d",
+ linkmode, operstate);
+
+ ret = send(drv->wext_event_sock, &req, req.hdr.nlmsg_len, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: "
+ "%s (assume operstate is not supported)",
+ strerror(errno));
+ }
+
+ return ret < 0 ? -1 : 0;
+}
+
+
+static int wpa_driver_nl80211_set_auth_param(
+ struct wpa_driver_nl80211_data *drv, int idx, u32 value)
+{
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.param.flags = idx & IW_AUTH_INDEX;
+ iwr.u.param.value = value;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
+ if (errno != EOPNOTSUPP) {
+ wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
+ "value 0x%x) failed: %s)",
+ idx, value, strerror(errno));
+ }
+ ret = errno == EOPNOTSUPP ? -2 : -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
+ perror("ioctl[SIOCGIWAP]");
+ ret = -1;
+ }
+ os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_set_bssid(void *priv, const u8 *bssid)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.ap_addr.sa_family = ARPHRD_ETHER;
+ if (bssid)
+ os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN);
+ else
+ os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
+ perror("ioctl[SIOCSIWAP]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.essid.pointer = (caddr_t) ssid;
+ iwr.u.essid.length = 32;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCGIWESSID]");
+ ret = -1;
+ } else {
+ ret = iwr.u.essid.length;
+ if (ret > 32)
+ ret = 32;
+ /* Some drivers include nul termination in the SSID, so let's
+ * remove it here before further processing. WE-21 changes this
+ * to explicitly require the length _not_ to include nul
+ * termination. */
+ if (ret > 0 && ssid[ret - 1] == '\0' &&
+ drv->we_version_compiled < 21)
+ ret--;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_set_ssid(void *priv, const u8 *ssid,
+ size_t ssid_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+ char buf[33];
+
+ if (ssid_len > 32)
+ return -1;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ /* flags: 1 = ESSID is active, 0 = not (promiscuous) */
+ iwr.u.essid.flags = (ssid_len != 0);
+ os_memset(buf, 0, sizeof(buf));
+ os_memcpy(buf, ssid, ssid_len);
+ iwr.u.essid.pointer = (caddr_t) buf;
+ if (drv->we_version_compiled < 21) {
+ /* For historic reasons, set SSID length to include one extra
+ * character, C string nul termination, even though SSID is
+ * really an octet string that should not be presented as a C
+ * string. Some Linux drivers decrement the length by one and
+ * can thus end up missing the last octet of the SSID if the
+ * length is not incremented here. WE-21 changes this to
+ * explicitly require the length _not_ to include nul
+ * termination. */
+ if (ssid_len)
+ ssid_len++;
+ }
+ iwr.u.essid.length = ssid_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCSIWESSID]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_set_freq(void *priv, int freq)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.freq.m = freq * 100000;
+ iwr.u.freq.e = 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+ perror("ioctl[SIOCSIWFREQ]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static void
+wpa_driver_nl80211_event_wireless_custom(void *ctx, char *custom)
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'",
+ custom);
+
+ os_memset(&data, 0, sizeof(data));
+ /* Host AP driver */
+ if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ data.michael_mic_failure.unicast =
+ os_strstr(custom, " unicast ") != NULL;
+ /* TODO: parse parameters(?) */
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+ } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) {
+ char *spos;
+ int bytes;
+
+ spos = custom + 17;
+
+ bytes = strspn(spos, "0123456789abcdefABCDEF");
+ if (!bytes || (bytes & 1))
+ return;
+ bytes /= 2;
+
+ data.assoc_info.req_ies = os_malloc(bytes);
+ if (data.assoc_info.req_ies == NULL)
+ return;
+
+ data.assoc_info.req_ies_len = bytes;
+ hexstr2bin(spos, data.assoc_info.req_ies, bytes);
+
+ spos += bytes * 2;
+
+ data.assoc_info.resp_ies = NULL;
+ data.assoc_info.resp_ies_len = 0;
+
+ if (os_strncmp(spos, " RespIEs=", 9) == 0) {
+ spos += 9;
+
+ bytes = strspn(spos, "0123456789abcdefABCDEF");
+ if (!bytes || (bytes & 1))
+ goto done;
+ bytes /= 2;
+
+ data.assoc_info.resp_ies = os_malloc(bytes);
+ if (data.assoc_info.resp_ies == NULL)
+ goto done;
+
+ data.assoc_info.resp_ies_len = bytes;
+ hexstr2bin(spos, data.assoc_info.resp_ies, bytes);
+ }
+
+ wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
+
+ done:
+ os_free(data.assoc_info.resp_ies);
+ os_free(data.assoc_info.req_ies);
+#ifdef CONFIG_PEERKEY
+ } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
+ if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
+ wpa_printf(MSG_DEBUG, "WEXT: unrecognized "
+ "STKSTART.request '%s'", custom + 17);
+ return;
+ }
+ wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
+#endif /* CONFIG_PEERKEY */
+ }
+}
+
+
+static int wpa_driver_nl80211_event_wireless_michaelmicfailure(
+ void *ctx, const char *ev, size_t len)
+{
+ const struct iw_michaelmicfailure *mic;
+ union wpa_event_data data;
+
+ if (len < sizeof(*mic))
+ return -1;
+
+ mic = (const struct iw_michaelmicfailure *) ev;
+
+ wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: "
+ "flags=0x%x src_addr=" MACSTR, mic->flags,
+ MAC2STR(mic->src_addr.sa_data));
+
+ os_memset(&data, 0, sizeof(data));
+ data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP);
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_event_wireless_pmkidcand(
+ struct wpa_driver_nl80211_data *drv, const char *ev, size_t len)
+{
+ const struct iw_pmkid_cand *cand;
+ union wpa_event_data data;
+ const u8 *addr;
+
+ if (len < sizeof(*cand))
+ return -1;
+
+ cand = (const struct iw_pmkid_cand *) ev;
+ addr = (const u8 *) cand->bssid.sa_data;
+
+ wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: "
+ "flags=0x%x index=%d bssid=" MACSTR, cand->flags,
+ cand->index, MAC2STR(addr));
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN);
+ data.pmkid_candidate.index = cand->index;
+ data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH;
+ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_event_wireless_assocreqie(
+ struct wpa_driver_nl80211_data *drv, const char *ev, int len)
+{
+ if (len < 0)
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev,
+ len);
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = os_malloc(len);
+ if (drv->assoc_req_ies == NULL) {
+ drv->assoc_req_ies_len = 0;
+ return -1;
+ }
+ os_memcpy(drv->assoc_req_ies, ev, len);
+ drv->assoc_req_ies_len = len;
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_event_wireless_assocrespie(
+ struct wpa_driver_nl80211_data *drv, const char *ev, int len)
+{
+ if (len < 0)
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev,
+ len);
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = os_malloc(len);
+ if (drv->assoc_resp_ies == NULL) {
+ drv->assoc_resp_ies_len = 0;
+ return -1;
+ }
+ os_memcpy(drv->assoc_resp_ies, ev, len);
+ drv->assoc_resp_ies_len = len;
+
+ return 0;
+}
+
+
+static void wpa_driver_nl80211_event_assoc_ies(struct wpa_driver_nl80211_data *drv)
+{
+ union wpa_event_data data;
+
+ if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ if (drv->assoc_req_ies) {
+ data.assoc_info.req_ies = drv->assoc_req_ies;
+ drv->assoc_req_ies = NULL;
+ data.assoc_info.req_ies_len = drv->assoc_req_ies_len;
+ }
+ if (drv->assoc_resp_ies) {
+ data.assoc_info.resp_ies = drv->assoc_resp_ies;
+ drv->assoc_resp_ies = NULL;
+ data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
+
+ os_free(data.assoc_info.req_ies);
+ os_free(data.assoc_info.resp_ies);
+}
+
+
+static void wpa_driver_nl80211_event_wireless(struct wpa_driver_nl80211_data *drv,
+ void *ctx, char *data, int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf;
+
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
+ iwe->cmd, iwe->len);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ return;
+
+ custom = pos + IW_EV_POINT_LEN;
+ if (drv->we_version_compiled > 18 &&
+ (iwe->cmd == IWEVMICHAELMICFAILURE ||
+ iwe->cmd == IWEVCUSTOM ||
+ iwe->cmd == IWEVASSOCREQIE ||
+ iwe->cmd == IWEVASSOCRESPIE ||
+ iwe->cmd == IWEVPMKIDCAND)) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case SIOCGIWAP:
+ wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
+ MACSTR,
+ MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
+ if (is_zero_ether_addr(
+ (const u8 *) iwe->u.ap_addr.sa_data) ||
+ os_memcmp(iwe->u.ap_addr.sa_data,
+ "\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
+ 0) {
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = NULL;
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = NULL;
+ wpa_supplicant_event(ctx, EVENT_DISASSOC,
+ NULL);
+
+ } else {
+ wpa_driver_nl80211_event_assoc_ies(drv);
+ wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+ }
+ break;
+ case IWEVMICHAELMICFAILURE:
+ wpa_driver_nl80211_event_wireless_michaelmicfailure(
+ ctx, custom, iwe->u.data.length);
+ break;
+ case IWEVCUSTOM:
+ if (custom + iwe->u.data.length > end)
+ return;
+ buf = os_malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return;
+ os_memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+ wpa_driver_nl80211_event_wireless_custom(ctx, buf);
+ os_free(buf);
+ break;
+ case IWEVASSOCREQIE:
+ wpa_driver_nl80211_event_wireless_assocreqie(
+ drv, custom, iwe->u.data.length);
+ break;
+ case IWEVASSOCRESPIE:
+ wpa_driver_nl80211_event_wireless_assocrespie(
+ drv, custom, iwe->u.data.length);
+ break;
+ case IWEVPMKIDCAND:
+ wpa_driver_nl80211_event_wireless_pmkidcand(
+ drv, custom, iwe->u.data.length);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+
+static void wpa_driver_nl80211_event_link(struct wpa_driver_nl80211_data *drv,
+ void *ctx, char *buf, size_t len,
+ int del)
+{
+ union wpa_event_data event;
+
+ os_memset(&event, 0, sizeof(event));
+ if (len > sizeof(event.interface_status.ifname))
+ len = sizeof(event.interface_status.ifname) - 1;
+ os_memcpy(event.interface_status.ifname, buf, len);
+ event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
+ EVENT_INTERFACE_ADDED;
+
+ wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
+ del ? "DEL" : "NEW",
+ event.interface_status.ifname,
+ del ? "removed" : "added");
+
+ if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
+ if (del)
+ drv->if_removed = 1;
+ else
+ drv->if_removed = 0;
+ }
+
+ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+}
+
+
+static int wpa_driver_nl80211_own_ifname(struct wpa_driver_nl80211_data *drv,
+ struct nlmsghdr *h)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, _nlmsg_len, rta_len;
+ struct rtattr *attr;
+
+ ifi = NLMSG_DATA(h);
+
+ _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - _nlmsg_len;
+ if (attrlen < 0)
+ return 0;
+
+ attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ if (os_strcmp(((char *) attr) + rta_len, drv->ifname)
+ == 0)
+ return 1;
+ else
+ break;
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_own_ifindex(struct wpa_driver_nl80211_data *drv,
+ int ifindex, struct nlmsghdr *h)
+{
+ if (drv->ifindex == ifindex)
+ return 1;
+
+ if (drv->if_removed && wpa_driver_nl80211_own_ifname(drv, h)) {
+ drv->ifindex = if_nametoindex(drv->ifname);
+ wpa_printf(MSG_DEBUG, "nl80211: Update ifindex for a removed "
+ "interface");
+ wpa_driver_nl80211_finish_drv_init(drv);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void wpa_driver_nl80211_event_rtm_newlink(struct wpa_driver_nl80211_data *drv,
+ void *ctx, struct nlmsghdr *h,
+ size_t len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, _nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ if (len < sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ if (!wpa_driver_nl80211_own_ifindex(drv, ifi->ifi_index, h)) {
+ wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
+ ifi->ifi_index);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
+ "(%s%s%s%s)",
+ drv->operstate, ifi->ifi_flags,
+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+ /*
+ * Some drivers send the association event before the operup event--in
+ * this case, lifting operstate in wpa_driver_nl80211_set_operstate()
+ * fails. This will hit us when wpa_supplicant does not need to do
+ * IEEE 802.1X authentication
+ */
+ if (drv->operstate == 1 &&
+ (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
+ !(ifi->ifi_flags & IFF_RUNNING))
+ wpa_driver_nl80211_send_oper_ifla(drv, -1, IF_OPER_UP);
+
+ _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - _nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ wpa_driver_nl80211_event_wireless(
+ drv, ctx, ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ } else if (attr->rta_type == IFLA_IFNAME) {
+ wpa_driver_nl80211_event_link(
+ drv, ctx,
+ ((char *) attr) + rta_len,
+ attr->rta_len - rta_len, 0);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void wpa_driver_nl80211_event_rtm_dellink(struct wpa_driver_nl80211_data *drv,
+ void *ctx, struct nlmsghdr *h,
+ size_t len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, _nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ if (len < sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ _nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - _nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + _nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ wpa_driver_nl80211_event_link(
+ drv, ctx,
+ ((char *) attr) + rta_len,
+ attr->rta_len - rta_len, 1);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void wpa_driver_nl80211_event_receive_wext(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ char buf[8192];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ int max_events = 10;
+
+try_again:
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("recvfrom(netlink)");
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (left >= (int) sizeof(*h)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ wpa_printf(MSG_DEBUG, "Malformed netlink message: "
+ "len=%d left=%d plen=%d",
+ len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ wpa_driver_nl80211_event_rtm_newlink(eloop_ctx, sock_ctx,
+ h, plen);
+ break;
+ case RTM_DELLINK:
+ wpa_driver_nl80211_event_rtm_dellink(eloop_ctx, sock_ctx,
+ h, plen);
+ break;
+ }
+
+ len = NLMSG_ALIGN(len);
+ left -= len;
+ h = (struct nlmsghdr *) ((char *) h + len);
+ }
+
+ if (left > 0) {
+ wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink "
+ "message", left);
+ }
+
+ if (--max_events > 0) {
+ /*
+ * Try to receive all events in one eloop call in order to
+ * limit race condition on cases where AssocInfo event, Assoc
+ * event, and EAPOL frames are received more or less at the
+ * same time. We want to process the event messages first
+ * before starting EAPOL processing.
+ */
+ goto try_again;
+ }
+}
+
+
+static int no_seq_check(struct nl_msg *msg, void *arg)
+{
+ return NL_OK;
+}
+
+
+static int process_event(struct nl_msg *msg, void *arg)
+{
+ struct wpa_driver_nl80211_data *drv = arg;
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (tb[NL80211_ATTR_IFINDEX]) {
+ int ifindex = nla_get_u32(tb[NL80211_ATTR_IFINDEX]);
+ if (ifindex != drv->ifindex) {
+ wpa_printf(MSG_DEBUG, "nl80211: Ignored event (cmd=%d)"
+ " for foreign interface (ifindex %d)",
+ gnlh->cmd, ifindex);
+ return NL_SKIP;
+ }
+ }
+
+ switch (gnlh->cmd) {
+ case NL80211_CMD_TRIGGER_SCAN:
+ wpa_printf(MSG_DEBUG, "nl80211: Scan trigger");
+ break;
+ case NL80211_CMD_NEW_SCAN_RESULTS:
+ wpa_printf(MSG_DEBUG, "nl80211: New scan results available");
+ drv->scan_complete_events = 1;
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+ drv->ctx);
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
+ break;
+ case NL80211_CMD_SCAN_ABORTED:
+ wpa_printf(MSG_DEBUG, "nl80211: Scan aborted");
+ /*
+ * Need to indicate that scan results are available in order
+ * not to make wpa_supplicant stop its scanning.
+ */
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv,
+ drv->ctx);
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "nl0211: Ignored unknown event (cmd=%d)",
+ gnlh->cmd);
+ break;
+ }
+
+ return NL_SKIP;
+}
+
+
+static void wpa_driver_nl80211_event_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct nl_cb *cb;
+ struct wpa_driver_nl80211_data *drv = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "nl80211: Event message available");
+
+ cb = nl_cb_clone(drv->nl_cb);
+ if (!cb)
+ return;
+ nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, no_seq_check, NULL);
+ nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, process_event, drv);
+ nl_recvmsgs(drv->nl_handle, cb);
+ nl_cb_put(cb);
+}
+
+
+static int wpa_driver_nl80211_get_ifflags_ifname(struct wpa_driver_nl80211_data *drv,
+ const char *ifname, int *flags)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ return -1;
+ }
+ *flags = ifr.ifr_flags & 0xffff;
+ return 0;
+}
+
+
+/**
+ * wpa_driver_nl80211_get_ifflags - Get interface flags (SIOCGIFFLAGS)
+ * @drv: driver_nl80211 private data
+ * @flags: Pointer to returned flags value
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_get_ifflags(struct wpa_driver_nl80211_data *drv,
+ int *flags)
+{
+ return wpa_driver_nl80211_get_ifflags_ifname(drv, drv->ifname, flags);
+}
+
+
+static int wpa_driver_nl80211_set_ifflags_ifname(
+ struct wpa_driver_nl80211_data *drv,
+ const char *ifname, int flags)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_flags = flags & 0xffff;
+ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ perror("SIOCSIFFLAGS");
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * wpa_driver_nl80211_set_ifflags - Set interface flags (SIOCSIFFLAGS)
+ * @drv: driver_nl80211 private data
+ * @flags: New value for flags
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_set_ifflags(struct wpa_driver_nl80211_data *drv,
+ int flags)
+{
+ return wpa_driver_nl80211_set_ifflags_ifname(drv, drv->ifname, flags);
+}
+
+
+/**
+ * wpa_driver_nl80211_set_country - ask nl80211 to set the regulatory domain
+ * @priv: driver_nl80211 private data
+ * @alpha2_arg: country to which to switch to
+ * Returns: 0 on success, -1 on failure
+ *
+ * This asks nl80211 to set the regulatory domain for given
+ * country ISO / IEC alpha2.
+ */
+static int wpa_driver_nl80211_set_country(void *priv, const char *alpha2_arg)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ char alpha2[3];
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto nla_put_failure;
+
+ alpha2[0] = alpha2_arg[0];
+ alpha2[1] = alpha2_arg[1];
+ alpha2[2] = '\0';
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_REQ_SET_REG, 0);
+
+ NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, alpha2);
+ if (send_and_recv_msgs(drv, msg, NULL, NULL))
+ return -EINVAL;
+ return 0;
+nla_put_failure:
+ return -EINVAL;
+}
+
+
+static int wpa_driver_nl80211_set_probe_req_ie(void *priv, const u8 *ies,
+ size_t ies_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_SET_MGMT_EXTRA_IE, 0);
+
+ NLA_PUT_U8(msg, NL80211_ATTR_MGMT_SUBTYPE, 4 /* ProbeReq */);
+ if (ies)
+ NLA_PUT(msg, NL80211_ATTR_IE, ies_len, ies);
+
+ ret = 0;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ return ret;
+
+nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+#ifdef CONFIG_CLIENT_MLME
+
+static int nl80211_set_vif(struct wpa_driver_nl80211_data *drv,
+ int drop_unencrypted, int userspace_mlme)
+{
+#ifdef NL80211_CMD_SET_VIF
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_SET_VIF, 0);
+
+ if (drop_unencrypted >= 0)
+ NLA_PUT_U8(msg, NL80211_ATTR_VIF_DROP_UNENCRYPTED,
+ drop_unencrypted);
+ if (userspace_mlme >= 0)
+ NLA_PUT_U8(msg, NL80211_ATTR_VIF_USERSPACE_MLME,
+ userspace_mlme);
+
+ ret = 0;
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ return ret;
+
+nla_put_failure:
+ return -ENOBUFS;
+#else /* NL80211_CMD_SET_VIF */
+ return -1;
+#endif /* NL80211_CMD_SET_VIF */
+}
+
+
+static int wpa_driver_nl80211_set_userspace_mlme(
+ struct wpa_driver_nl80211_data *drv, int enabled)
+{
+ return nl80211_set_vif(drv, -1, enabled);
+}
+
+
+static void nl80211_remove_iface(struct wpa_driver_nl80211_data *drv,
+ int ifidx)
+{
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto nla_put_failure;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, ifidx);
+ if (send_and_recv_msgs(drv, msg, NULL, NULL) == 0)
+ return;
+nla_put_failure:
+ wpa_printf(MSG_ERROR, "nl80211: Failed to remove interface.");
+}
+
+
+static int nl80211_create_iface(struct wpa_driver_nl80211_data *drv,
+ const char *ifname, enum nl80211_iftype iftype)
+{
+ struct nl_msg *msg, *flags = NULL;
+ int ifidx, err;
+ int ret = -ENOBUFS;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_NEW_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, if_nametoindex(drv->ifname));
+ NLA_PUT_STRING(msg, NL80211_ATTR_IFNAME, ifname);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE, iftype);
+
+ if (iftype == NL80211_IFTYPE_MONITOR) {
+ flags = nlmsg_alloc();
+ if (!flags)
+ goto nla_put_failure;
+
+ NLA_PUT_FLAG(flags, NL80211_MNTR_FLAG_COOK_FRAMES);
+
+ err = nla_put_nested(msg, NL80211_ATTR_MNTR_FLAGS, flags);
+
+ nlmsg_free(flags);
+
+ if (err)
+ goto nla_put_failure;
+ }
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ nla_put_failure:
+ wpa_printf(MSG_ERROR, "nl80211: Failed to create interface %d",
+ ret);
+ return ret;
+ }
+
+ ifidx = if_nametoindex(ifname);
+ if (ifidx <= 0)
+ return -1;
+
+ return ifidx;
+}
+
+
+static void handle_monitor_read(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct wpa_driver_nl80211_data *drv = eloop_ctx;
+ int len;
+ unsigned char buf[3000];
+ struct ieee80211_radiotap_iterator iter;
+ int ret;
+ int injected = 0, failed = 0, rxflags = 0;
+ struct ieee80211_rx_status rx_status;
+
+ len = recv(sock, buf, sizeof(buf), 0);
+ if (len < 0) {
+ perror("recv");
+ return;
+ }
+
+ if (ieee80211_radiotap_iterator_init(&iter, (void *) buf, len)) {
+ wpa_printf(MSG_DEBUG, "nl80211: received invalid radiotap "
+ "frame");
+ return;
+ }
+
+ os_memset(&rx_status, 0, sizeof(rx_status));
+
+ while (1) {
+ ret = ieee80211_radiotap_iterator_next(&iter);
+ if (ret == -ENOENT)
+ break;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: received invalid "
+ "radiotap frame (%d)", ret);
+ return;
+ }
+ switch (iter.this_arg_index) {
+ case IEEE80211_RADIOTAP_FLAGS:
+ if (*iter.this_arg & IEEE80211_RADIOTAP_F_FCS)
+ len -= 4;
+ break;
+ case IEEE80211_RADIOTAP_RX_FLAGS:
+ rxflags = 1;
+ break;
+ case IEEE80211_RADIOTAP_TX_FLAGS:
+ injected = 1;
+ failed = le_to_host16((*(u16 *) iter.this_arg)) &
+ IEEE80211_RADIOTAP_F_TX_FAIL;
+ break;
+ case IEEE80211_RADIOTAP_DATA_RETRIES:
+ break;
+ case IEEE80211_RADIOTAP_CHANNEL:
+ /* TODO convert from freq/flags to channel number
+ * rx_status.channel = XXX;
+ */
+ break;
+ case IEEE80211_RADIOTAP_RATE:
+ break;
+ case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
+ rx_status.ssi = *iter.this_arg;
+ break;
+ }
+ }
+
+ if (rxflags && injected)
+ return;
+
+ if (!injected) {
+ wpa_supplicant_sta_rx(drv->ctx, buf + iter.max_length,
+ len - iter.max_length, &rx_status);
+ } else if (failed) {
+ /* TX failure callback */
+ } else {
+ /* TX success (ACK) callback */
+ }
+}
+
+
+static int wpa_driver_nl80211_create_monitor_interface(
+ struct wpa_driver_nl80211_data *drv)
+{
+ char buf[IFNAMSIZ];
+ struct sockaddr_ll ll;
+ int optval, flags;
+ socklen_t optlen;
+
+ os_snprintf(buf, IFNAMSIZ, "mon.%s", drv->ifname);
+ buf[IFNAMSIZ - 1] = '\0';
+
+ drv->monitor_ifidx =
+ nl80211_create_iface(drv, buf, NL80211_IFTYPE_MONITOR);
+
+ if (drv->monitor_ifidx < 0)
+ return -1;
+
+ if (wpa_driver_nl80211_get_ifflags_ifname(drv, buf, &flags) != 0 ||
+ wpa_driver_nl80211_set_ifflags_ifname(drv, buf, flags | IFF_UP) !=
+ 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Could not set interface '%s' "
+ "UP", buf);
+ goto error;
+ }
+
+ os_memset(&ll, 0, sizeof(ll));
+ ll.sll_family = AF_PACKET;
+ ll.sll_ifindex = drv->monitor_ifidx;
+ drv->monitor_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+ if (drv->monitor_sock < 0) {
+ perror("socket[PF_PACKET,SOCK_RAW]");
+ goto error;
+ }
+
+ if (bind(drv->monitor_sock, (struct sockaddr *) &ll,
+ sizeof(ll)) < 0) {
+ perror("monitor socket bind");
+ goto error;
+ }
+
+ optlen = sizeof(optval);
+ optval = 20;
+ if (setsockopt
+ (drv->monitor_sock, SOL_SOCKET, SO_PRIORITY, &optval, optlen)) {
+ perror("Failed to set socket priority");
+ goto error;
+ }
+
+ if (eloop_register_read_sock(drv->monitor_sock, handle_monitor_read,
+ drv, NULL)) {
+ wpa_printf(MSG_ERROR, "nl80211: Could not register monitor "
+ "read socket");
+ goto error;
+ }
+
+ return 0;
+
+ error:
+ nl80211_remove_iface(drv, drv->monitor_ifidx);
+ return -1;
+}
+
+#endif /* CONFIG_CLIENT_MLME */
+
+
+/**
+ * wpa_driver_nl80211_init - Initialize nl80211 driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * Returns: Pointer to private data, %NULL on failure
+ */
+static void * wpa_driver_nl80211_init(void *ctx, const char *ifname)
+{
+ int s, ret;
+ struct sockaddr_nl local;
+ struct wpa_driver_nl80211_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+ drv->nl_cb = nl_cb_alloc(NL_CB_DEFAULT);
+ if (drv->nl_cb == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+ "callbacks");
+ goto err1;
+ }
+
+ drv->nl_handle = nl_handle_alloc_cb(drv->nl_cb);
+ if (drv->nl_handle == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate netlink "
+ "callbacks");
+ goto err2;
+ }
+
+ if (genl_connect(drv->nl_handle)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to connect to generic "
+ "netlink");
+ goto err3;
+ }
+
+ drv->nl_cache = genl_ctrl_alloc_cache(drv->nl_handle);
+ if (drv->nl_cache == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to allocate generic "
+ "netlink cache");
+ goto err3;
+ }
+
+ drv->nl80211 = genl_ctrl_search_by_name(drv->nl_cache, "nl80211");
+ if (drv->nl80211 == NULL) {
+ wpa_printf(MSG_ERROR, "nl80211: 'nl80211' generic netlink not "
+ "found");
+ goto err4;
+ }
+
+ ret = nl_get_multicast_id(drv, "nl80211", "scan");
+ if (ret >= 0)
+ ret = nl_socket_add_membership(drv->nl_handle, ret);
+ if (ret < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Could not add multicast "
+ "membership for scan events: %d (%s)",
+ ret, strerror(-ret));
+ goto err4;
+ }
+ eloop_register_read_sock(nl_socket_get_fd(drv->nl_handle),
+ wpa_driver_nl80211_event_receive, drv, ctx);
+
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket(PF_INET,SOCK_DGRAM)");
+ goto err5;
+ }
+
+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (s < 0) {
+ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+ goto err6;
+ }
+
+ os_memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ perror("bind(netlink)");
+ close(s);
+ goto err6;
+ }
+
+ eloop_register_read_sock(s, wpa_driver_nl80211_event_receive_wext, drv,
+ ctx);
+ drv->wext_event_sock = s;
+
+ wpa_driver_nl80211_finish_drv_init(drv);
+
+ return drv;
+
+err6:
+ close(drv->ioctl_sock);
+err5:
+ genl_family_put(drv->nl80211);
+err4:
+ nl_cache_free(drv->nl_cache);
+err3:
+ nl_handle_destroy(drv->nl_handle);
+err2:
+ nl_cb_put(drv->nl_cb);
+err1:
+ os_free(drv);
+ return NULL;
+}
+
+
+static void
+wpa_driver_nl80211_finish_drv_init(struct wpa_driver_nl80211_data *drv)
+{
+ int flags;
+
+ drv->ifindex = if_nametoindex(drv->ifname);
+
+ if (wpa_driver_nl80211_set_mode(drv, 0) < 0) {
+ printf("Could not configure driver to use managed mode\n");
+ }
+
+ if (wpa_driver_nl80211_get_ifflags(drv, &flags) != 0)
+ printf("Could not get interface '%s' flags\n", drv->ifname);
+ else if (!(flags & IFF_UP)) {
+ if (wpa_driver_nl80211_set_ifflags(drv, flags | IFF_UP) != 0) {
+ printf("Could not set interface '%s' UP\n",
+ drv->ifname);
+ }
+ }
+
+ /*
+ * Make sure that the driver does not have any obsolete PMKID entries.
+ */
+ wpa_driver_nl80211_flush_pmkid(drv);
+
+ wpa_driver_nl80211_get_range(drv);
+
+ wpa_driver_nl80211_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
+}
+
+
+/**
+ * wpa_driver_nl80211_deinit - Deinitialize nl80211 driver interface
+ * @priv: Pointer to private nl80211 data from wpa_driver_nl80211_init()
+ *
+ * Shut down driver interface and processing of driver events. Free
+ * private data buffer if one was allocated in wpa_driver_nl80211_init().
+ */
+static void wpa_driver_nl80211_deinit(void *priv)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int flags;
+
+#ifdef CONFIG_CLIENT_MLME
+ if (drv->monitor_sock >= 0) {
+ eloop_unregister_read_sock(drv->monitor_sock);
+ close(drv->monitor_sock);
+ }
+ if (drv->monitor_ifidx > 0)
+ nl80211_remove_iface(drv, drv->monitor_ifidx);
+ if (drv->capa.flags & WPA_DRIVER_FLAGS_USER_SPACE_MLME)
+ wpa_driver_nl80211_set_userspace_mlme(drv, 0);
+#endif /* CONFIG_CLIENT_MLME */
+
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+
+ /*
+ * Clear possibly configured driver parameters in order to make it
+ * easier to use the driver after wpa_supplicant has been terminated.
+ */
+ (void) wpa_driver_nl80211_set_bssid(drv,
+ (u8 *) "\x00\x00\x00\x00\x00\x00");
+
+ wpa_driver_nl80211_send_oper_ifla(priv, 0, IF_OPER_UP);
+
+ eloop_unregister_read_sock(drv->wext_event_sock);
+
+ if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0)
+ (void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP);
+
+ close(drv->wext_event_sock);
+ close(drv->ioctl_sock);
+ os_free(drv->assoc_req_ies);
+ os_free(drv->assoc_resp_ies);
+
+ eloop_unregister_read_sock(nl_socket_get_fd(drv->nl_handle));
+ genl_family_put(drv->nl80211);
+ nl_cache_free(drv->nl_cache);
+ nl_handle_destroy(drv->nl_handle);
+ nl_cb_put(drv->nl_cb);
+
+ os_free(drv);
+}
+
+
+/**
+ * wpa_driver_nl80211_scan_timeout - Scan timeout to report scan completion
+ * @eloop_ctx: Unused
+ * @timeout_ctx: ctx argument given to wpa_driver_nl80211_init()
+ *
+ * This function can be used as registered timeout when starting a scan to
+ * generate a scan completed event if the driver does not report this.
+ */
+static void wpa_driver_nl80211_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+/**
+ * wpa_driver_nl80211_scan - Request the driver to initiate scan
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * @ssid: Specific SSID to scan for (ProbeReq) or %NULL to scan for
+ * all SSIDs (either active scan with broadcast SSID or passive
+ * scan
+ * @ssid_len: Length of the SSID
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int ret = 0, timeout;
+ struct nl_msg *msg, *ssids;
+
+ msg = nlmsg_alloc();
+ ssids = nlmsg_alloc();
+ if (!msg || !ssids) {
+ nlmsg_free(msg);
+ nlmsg_free(ssids);
+ return -1;
+ }
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_TRIGGER_SCAN, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ if (ssid && ssid_len) {
+ /* Request an active scan for a specific SSID */
+ NLA_PUT(ssids, 1, ssid_len, ssid);
+ } else {
+ /* Request an active scan for wildcard SSID */
+ NLA_PUT(ssids, 1, 0, "");
+ }
+ nla_put_nested(msg, NL80211_ATTR_SCAN_SSIDS, ssids);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ msg = NULL;
+ if (ret) {
+ wpa_printf(MSG_DEBUG, "nl80211: Scan trigger failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+ goto nla_put_failure;
+ }
+
+ /* Not all drivers generate "scan completed" wireless event, so try to
+ * read results after a timeout. */
+ timeout = 10;
+ if (drv->scan_complete_events) {
+ /*
+ * The driver seems to deliver SIOCGIWSCAN events to notify
+ * when scan is complete, so use longer timeout to avoid race
+ * conditions with scanning and following association request.
+ */
+ timeout = 30;
+ }
+ wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
+ "seconds", ret, timeout);
+ eloop_cancel_timeout(wpa_driver_nl80211_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(timeout, 0, wpa_driver_nl80211_scan_timeout,
+ drv, drv->ctx);
+
+nla_put_failure:
+ nlmsg_free(ssids);
+ nlmsg_free(msg);
+ return ret;
+}
+
+
+static int bss_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct nlattr *bss[NL80211_BSS_MAX + 1];
+ static struct nla_policy bss_policy[NL80211_BSS_MAX + 1] = {
+ [NL80211_BSS_BSSID] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_FREQUENCY] = { .type = NLA_U32 },
+ [NL80211_BSS_TSF] = { .type = NLA_U64 },
+ [NL80211_BSS_BEACON_INTERVAL] = { .type = NLA_U16 },
+ [NL80211_BSS_CAPABILITY] = { .type = NLA_U16 },
+ [NL80211_BSS_INFORMATION_ELEMENTS] = { .type = NLA_UNSPEC },
+ [NL80211_BSS_SIGNAL_MBM] = { .type = NLA_U32 },
+ [NL80211_BSS_SIGNAL_UNSPEC] = { .type = NLA_U8 },
+ };
+ struct wpa_scan_results *res = arg;
+ struct wpa_scan_res **tmp;
+ struct wpa_scan_res *r;
+ const u8 *ie;
+ size_t ie_len;
+
+ nla_parse(tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+ if (!tb[NL80211_ATTR_BSS])
+ return NL_SKIP;
+ if (nla_parse_nested(bss, NL80211_BSS_MAX, tb[NL80211_ATTR_BSS],
+ bss_policy))
+ return NL_SKIP;
+ if (bss[NL80211_BSS_INFORMATION_ELEMENTS]) {
+ ie = nla_data(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ ie_len = nla_len(bss[NL80211_BSS_INFORMATION_ELEMENTS]);
+ } else {
+ ie = NULL;
+ ie_len = 0;
+ }
+
+ r = os_zalloc(sizeof(*r) + ie_len);
+ if (r == NULL)
+ return NL_SKIP;
+ if (bss[NL80211_BSS_BSSID])
+ os_memcpy(r->bssid, nla_data(bss[NL80211_BSS_BSSID]),
+ ETH_ALEN);
+ if (bss[NL80211_BSS_FREQUENCY])
+ r->freq = nla_get_u32(bss[NL80211_BSS_FREQUENCY]);
+ if (bss[NL80211_BSS_BEACON_INTERVAL])
+ r->beacon_int = nla_get_u16(bss[NL80211_BSS_BEACON_INTERVAL]);
+ if (bss[NL80211_BSS_CAPABILITY])
+ r->caps = nla_get_u16(bss[NL80211_BSS_CAPABILITY]);
+ if (bss[NL80211_BSS_SIGNAL_UNSPEC])
+ r->qual = nla_get_u8(bss[NL80211_BSS_SIGNAL_UNSPEC]);
+ if (bss[NL80211_BSS_SIGNAL_MBM])
+ r->level = nla_get_u32(bss[NL80211_BSS_SIGNAL_MBM]);
+ if (bss[NL80211_BSS_TSF])
+ r->tsf = nla_get_u64(bss[NL80211_BSS_TSF]);
+ r->ie_len = ie_len;
+ if (ie)
+ os_memcpy(r + 1, ie, ie_len);
+
+ tmp = os_realloc(res->res,
+ (res->num + 1) * sizeof(struct wpa_scan_res *));
+ if (tmp == NULL) {
+ os_free(r);
+ return NL_SKIP;
+ }
+ tmp[res->num++] = r;
+ res->res = tmp;
+
+ return NL_SKIP;
+}
+
+
+/**
+ * wpa_driver_nl80211_get_scan_results - Fetch the latest scan results
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * Returns: Scan results on success, -1 on failure
+ */
+static struct wpa_scan_results *
+wpa_driver_nl80211_get_scan_results(void *priv)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct nl_msg *msg;
+ struct wpa_scan_results *res;
+ int ret;
+
+ res = os_zalloc(sizeof(*res));
+ if (res == NULL)
+ return 0;
+ msg = nlmsg_alloc();
+ if (!msg)
+ goto nla_put_failure;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, NLM_F_DUMP,
+ NL80211_CMD_GET_SCAN, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ ret = send_and_recv_msgs(drv, msg, bss_info_handler, res);
+ msg = NULL;
+ if (ret == 0) {
+ wpa_printf(MSG_DEBUG, "Received scan results (%lu BSSes)",
+ (unsigned long) res->num);
+ return res;
+ }
+ wpa_printf(MSG_DEBUG, "nl80211: Scan result fetch failed: ret=%d "
+ "(%s)", ret, strerror(-ret));
+nla_put_failure:
+ nlmsg_free(msg);
+ wpa_scan_results_free(res);
+ return NULL;
+}
+
+
+static int wpa_driver_nl80211_get_range(void *priv)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iw_range *range;
+ struct iwreq iwr;
+ int minlen;
+ size_t buflen;
+
+ /*
+ * Use larger buffer than struct iw_range in order to allow the
+ * structure to grow in the future.
+ */
+ buflen = sizeof(struct iw_range) + 500;
+ range = os_zalloc(buflen);
+ if (range == NULL)
+ return -1;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buflen;
+
+ minlen = ((char *) &range->enc_capa) - (char *) range +
+ sizeof(range->enc_capa);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWRANGE]");
+ os_free(range);
+ return -1;
+ } else if (iwr.u.data.length >= minlen &&
+ range->we_version_compiled >= 18) {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+ "WE(source)=%d enc_capa=0x%x",
+ range->we_version_compiled,
+ range->we_version_source,
+ range->enc_capa);
+ drv->has_capability = 1;
+ drv->we_version_compiled = range->we_version_compiled;
+ if (range->enc_capa & IW_ENC_CAPA_WPA) {
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
+ }
+ if (range->enc_capa & IW_ENC_CAPA_WPA2) {
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ }
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
+ WPA_DRIVER_CAPA_ENC_WEP104;
+ if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+ if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+ drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+ WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+ wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x",
+ drv->capa.key_mgmt, drv->capa.enc);
+ } else {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
+ "assuming WPA is not supported");
+ }
+
+ os_free(range);
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ return wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_WPA_ENABLED,
+ enabled);
+}
+
+
+static int wpa_driver_nl80211_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx,
+ int set_tx, const u8 *seq,
+ size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int err;
+ struct nl_msg *msg;
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%d addr=%p key_idx=%d set_tx=%d "
+ "seq_len=%lu key_len=%lu",
+ __func__, alg, addr, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ msg = nlmsg_alloc();
+ if (msg == NULL)
+ return -1;
+
+ if (alg == WPA_ALG_NONE) {
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_DEL_KEY, 0);
+ } else {
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0, 0,
+ NL80211_CMD_NEW_KEY, 0);
+ NLA_PUT(msg, NL80211_ATTR_KEY_DATA, key_len, key);
+ switch (alg) {
+ case WPA_ALG_WEP:
+ if (key_len == 5)
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ 0x000FAC01);
+ else
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER,
+ 0x000FAC05);
+ break;
+ case WPA_ALG_TKIP:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC02);
+ break;
+ case WPA_ALG_CCMP:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC04);
+ break;
+#ifdef CONFIG_IEEE80211W
+ case WPA_ALG_IGTK:
+ NLA_PUT_U32(msg, NL80211_ATTR_KEY_CIPHER, 0x000FAC06);
+ break;
+#endif /* CONFIG_IEEE80211W */
+ default:
+ nlmsg_free(msg);
+ return -1;
+ }
+ }
+
+ if (addr && os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
+ {
+ wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ }
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ err = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "nl80211: set_key failed; err=%d", err);
+ return -1;
+ }
+
+ if (set_tx && alg != WPA_ALG_NONE) {
+ msg = nlmsg_alloc();
+ if (msg == NULL)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_KEY, 0);
+ NLA_PUT_U8(msg, NL80211_ATTR_KEY_IDX, key_idx);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_FLAG(msg, NL80211_ATTR_KEY_DEFAULT);
+
+ err = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "nl80211: set default key "
+ "failed; err=%d", err);
+ return -1;
+ }
+ }
+
+ return 0;
+
+nla_put_failure:
+ return -ENOBUFS;
+}
+
+
+static int wpa_driver_nl80211_set_countermeasures(void *priv,
+ int enabled)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_TKIP_COUNTERMEASURES,
+ enabled);
+}
+
+
+static int wpa_driver_nl80211_set_drop_unencrypted(void *priv,
+ int enabled)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ drv->use_crypt = enabled;
+ return wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
+ enabled);
+}
+
+
+static int wpa_driver_nl80211_mlme(struct wpa_driver_nl80211_data *drv,
+ const u8 *addr, int cmd, int reason_code)
+{
+ struct iwreq iwr;
+ struct iw_mlme mlme;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_memset(&mlme, 0, sizeof(mlme));
+ mlme.cmd = cmd;
+ mlme.reason_code = reason_code;
+ mlme.addr.sa_family = ARPHRD_ETHER;
+ os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN);
+ iwr.u.data.pointer = (caddr_t) &mlme;
+ iwr.u.data.length = sizeof(mlme);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
+ perror("ioctl[SIOCSIWMLME]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_nl80211_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
+}
+
+
+static int wpa_driver_nl80211_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_nl80211_mlme(drv, addr, IW_MLME_DISASSOC,
+ reason_code);
+}
+
+
+static int wpa_driver_nl80211_set_gen_ie(void *priv, const u8 *ie,
+ size_t ie_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) ie;
+ iwr.u.data.length = ie_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWGENIE]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_cipher2wext(int cipher)
+{
+ switch (cipher) {
+ case CIPHER_NONE:
+ return IW_AUTH_CIPHER_NONE;
+ case CIPHER_WEP40:
+ return IW_AUTH_CIPHER_WEP40;
+ case CIPHER_TKIP:
+ return IW_AUTH_CIPHER_TKIP;
+ case CIPHER_CCMP:
+ return IW_AUTH_CIPHER_CCMP;
+ case CIPHER_WEP104:
+ return IW_AUTH_CIPHER_WEP104;
+ default:
+ return 0;
+ }
+}
+
+
+static int wpa_driver_nl80211_keymgmt2wext(int keymgmt)
+{
+ switch (keymgmt) {
+ case KEY_MGMT_802_1X:
+ case KEY_MGMT_802_1X_NO_WPA:
+ return IW_AUTH_KEY_MGMT_802_1X;
+ case KEY_MGMT_PSK:
+ return IW_AUTH_KEY_MGMT_PSK;
+ default:
+ return 0;
+ }
+}
+
+
+static int
+wpa_driver_nl80211_auth_alg_fallback(struct wpa_driver_nl80211_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ struct iwreq iwr;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "WEXT: Driver did not support "
+ "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE");
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ /* Just changing mode, not actual keys */
+ iwr.u.encoding.flags = 0;
+ iwr.u.encoding.pointer = (caddr_t) NULL;
+ iwr.u.encoding.length = 0;
+
+ /*
+ * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two
+ * different things. Here they are used to indicate Open System vs.
+ * Shared Key authentication algorithm. However, some drivers may use
+ * them to select between open/restricted WEP encrypted (open = allow
+ * both unencrypted and encrypted frames; restricted = only allow
+ * encrypted frames).
+ */
+
+ if (!drv->use_crypt) {
+ iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+ } else {
+ if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ iwr.u.encoding.flags |= IW_ENCODE_OPEN;
+ if (params->auth_alg & AUTH_ALG_SHARED_KEY)
+ iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
+ }
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWENCODE]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_associate(
+ void *priv, struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int ret = 0;
+ int allow_unencrypted_eapol;
+ int value;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ /*
+ * If the driver did not support SIOCSIWAUTH, fallback to
+ * SIOCSIWENCODE here.
+ */
+ if (drv->auth_alg_fallback &&
+ wpa_driver_nl80211_auth_alg_fallback(drv, params) < 0)
+ ret = -1;
+
+ if (!params->bssid &&
+ wpa_driver_nl80211_set_bssid(drv, NULL) < 0)
+ ret = -1;
+
+ /* TODO: should consider getting wpa version and cipher/key_mgmt suites
+ * from configuration, not from here, where only the selected suite is
+ * available */
+ if (wpa_driver_nl80211_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
+ < 0)
+ ret = -1;
+ if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
+ value = IW_AUTH_WPA_VERSION_DISABLED;
+ else if (params->wpa_ie[0] == WLAN_EID_RSN)
+ value = IW_AUTH_WPA_VERSION_WPA2;
+ else
+ value = IW_AUTH_WPA_VERSION_WPA;
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_WPA_VERSION, value) < 0)
+ ret = -1;
+ value = wpa_driver_nl80211_cipher2wext(params->pairwise_suite);
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_CIPHER_PAIRWISE, value) < 0)
+ ret = -1;
+ value = wpa_driver_nl80211_cipher2wext(params->group_suite);
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_CIPHER_GROUP, value) < 0)
+ ret = -1;
+ value = wpa_driver_nl80211_keymgmt2wext(params->key_mgmt_suite);
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_KEY_MGMT, value) < 0)
+ ret = -1;
+ value = params->key_mgmt_suite != KEY_MGMT_NONE ||
+ params->pairwise_suite != CIPHER_NONE ||
+ params->group_suite != CIPHER_NONE ||
+ params->wpa_ie_len;
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_PRIVACY_INVOKED, value) < 0)
+ ret = -1;
+
+ /* Allow unencrypted EAPOL messages even if pairwise keys are set when
+ * not using WPA. IEEE 802.1X specifies that these frames are not
+ * encrypted, but WPA encrypts them when pairwise keys are in use. */
+ if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+ params->key_mgmt_suite == KEY_MGMT_PSK)
+ allow_unencrypted_eapol = 0;
+ else
+ allow_unencrypted_eapol = 1;
+
+ if (wpa_driver_nl80211_set_auth_param(drv,
+ IW_AUTH_RX_UNENCRYPTED_EAPOL,
+ allow_unencrypted_eapol) < 0)
+ ret = -1;
+ if (params->freq && wpa_driver_nl80211_set_freq(drv, params->freq) < 0)
+ ret = -1;
+ if (wpa_driver_nl80211_set_ssid(drv, params->ssid, params->ssid_len) < 0)
+ ret = -1;
+ if (params->bssid &&
+ wpa_driver_nl80211_set_bssid(drv, params->bssid) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int algs = 0, res;
+
+ if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ algs |= IW_AUTH_ALG_OPEN_SYSTEM;
+ if (auth_alg & AUTH_ALG_SHARED_KEY)
+ algs |= IW_AUTH_ALG_SHARED_KEY;
+ if (auth_alg & AUTH_ALG_LEAP)
+ algs |= IW_AUTH_ALG_LEAP;
+ if (algs == 0) {
+ /* at least one algorithm should be set */
+ algs = IW_AUTH_ALG_OPEN_SYSTEM;
+ }
+
+ res = wpa_driver_nl80211_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG,
+ algs);
+ drv->auth_alg_fallback = res == -2;
+ return res;
+}
+
+
+/**
+ * wpa_driver_nl80211_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE
+ * @priv: Pointer to private wext data from wpa_driver_nl80211_init()
+ * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS
+ * Returns: 0 on success, -1 on failure
+ */
+static int wpa_driver_nl80211_set_mode(void *priv, int mode)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ int ret = -1, flags;
+ struct nl_msg *msg;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE,
+ mode ? NL80211_IFTYPE_ADHOC : NL80211_IFTYPE_STATION);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (!ret)
+ return 0;
+ else
+ goto try_again;
+
+nla_put_failure:
+ wpa_printf(MSG_ERROR, "nl80211: Failed to set interface mode: %d (%s)",
+ ret, strerror(-ret));
+ return -1;
+
+try_again:
+ /* mac80211 doesn't allow mode changes while the device is up, so
+ * take the device down, try to set the mode again, and bring the
+ * device back up.
+ */
+ if (wpa_driver_nl80211_get_ifflags(drv, &flags) == 0) {
+ (void) wpa_driver_nl80211_set_ifflags(drv, flags & ~IFF_UP);
+
+ /* Try to set the mode again while the interface is down */
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -1;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_SET_INTERFACE, 0);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT_U32(msg, NL80211_ATTR_IFTYPE,
+ mode ? NL80211_IFTYPE_ADHOC :
+ NL80211_IFTYPE_STATION);
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ if (ret) {
+ wpa_printf(MSG_ERROR, "Failed to set interface %s "
+ "mode(try_again): %d (%s)",
+ drv->ifname, ret, strerror(-ret));
+ }
+
+ /* Ignore return value of get_ifflags to ensure that the device
+ * is always up like it was before this function was called.
+ */
+ (void) wpa_driver_nl80211_get_ifflags(drv, &flags);
+ (void) wpa_driver_nl80211_set_ifflags(drv, flags | IFF_UP);
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_pmksa(struct wpa_driver_nl80211_data *drv,
+ u32 cmd, const u8 *bssid, const u8 *pmkid)
+{
+ struct iwreq iwr;
+ struct iw_pmksa pmksa;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_memset(&pmksa, 0, sizeof(pmksa));
+ pmksa.cmd = cmd;
+ pmksa.bssid.sa_family = ARPHRD_ETHER;
+ if (bssid)
+ os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN);
+ if (pmkid)
+ os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN);
+ iwr.u.data.pointer = (caddr_t) &pmksa;
+ iwr.u.data.length = sizeof(pmksa);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
+ if (errno != EOPNOTSUPP)
+ perror("ioctl[SIOCSIWPMKSA]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_add_pmkid(void *priv, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid);
+}
+
+
+static int wpa_driver_nl80211_remove_pmkid(void *priv, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid);
+}
+
+
+static int wpa_driver_nl80211_flush_pmkid(void *priv)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ return wpa_driver_nl80211_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL);
+}
+
+
+static int wpa_driver_nl80211_get_capa(void *priv,
+ struct wpa_driver_capa *capa)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ if (!drv->has_capability)
+ return -1;
+ os_memcpy(capa, &drv->capa, sizeof(*capa));
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
+ __func__, drv->operstate, state, state ? "UP" : "DORMANT");
+ drv->operstate = state;
+ return wpa_driver_nl80211_send_oper_ifla(
+ drv, -1, state ? IF_OPER_UP : IF_OPER_DORMANT);
+}
+
+
+#ifdef CONFIG_CLIENT_MLME
+static int wpa_driver_nl80211_open_mlme(struct wpa_driver_nl80211_data *drv)
+{
+ if (wpa_driver_nl80211_set_userspace_mlme(drv, 1) < 0) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to enable userspace "
+ "MLME");
+ return -1;
+ }
+ if (wpa_driver_nl80211_create_monitor_interface(drv)) {
+ wpa_printf(MSG_ERROR, "nl80211: Failed to create monitor "
+ "interface");
+ return -1;
+ }
+ return 0;
+}
+#endif /* CONFIG_CLIENT_MLME */
+
+
+static int wpa_driver_nl80211_set_param(void *priv, const char *param)
+{
+#ifdef CONFIG_CLIENT_MLME
+ struct wpa_driver_nl80211_data *drv = priv;
+
+ if (param == NULL)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
+
+ if (os_strstr(param, "use_mlme=1")) {
+ wpa_printf(MSG_DEBUG, "nl80211: Using user space MLME");
+ drv->capa.flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
+
+ if (wpa_driver_nl80211_open_mlme(drv))
+ return -1;
+ }
+#endif /* CONFIG_CLIENT_MLME */
+
+ return 0;
+}
+
+
+#ifdef CONFIG_CLIENT_MLME
+
+struct phy_info_arg {
+ u16 *num_modes;
+ struct wpa_hw_modes *modes;
+};
+
+
+static int phy_info_handler(struct nl_msg *msg, void *arg)
+{
+ struct nlattr *tb_msg[NL80211_ATTR_MAX + 1];
+ struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
+ struct phy_info_arg *phy_info = arg;
+
+ struct nlattr *tb_band[NL80211_BAND_ATTR_MAX + 1];
+
+ struct nlattr *tb_freq[NL80211_FREQUENCY_ATTR_MAX + 1];
+ static struct nla_policy freq_policy[NL80211_FREQUENCY_ATTR_MAX + 1]
+ = {
+ [NL80211_FREQUENCY_ATTR_FREQ] = { .type = NLA_U32 },
+ [NL80211_FREQUENCY_ATTR_DISABLED] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_PASSIVE_SCAN] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_NO_IBSS] = { .type = NLA_FLAG },
+ [NL80211_FREQUENCY_ATTR_RADAR] = { .type = NLA_FLAG },
+ };
+
+ struct nlattr *tb_rate[NL80211_BITRATE_ATTR_MAX + 1];
+ static struct nla_policy rate_policy[NL80211_BITRATE_ATTR_MAX + 1] = {
+ [NL80211_BITRATE_ATTR_RATE] = { .type = NLA_U32 },
+ [NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE] =
+ { .type = NLA_FLAG },
+ };
+
+ struct nlattr *nl_band;
+ struct nlattr *nl_freq;
+ struct nlattr *nl_rate;
+ int rem_band, rem_freq, rem_rate;
+ struct wpa_hw_modes *mode;
+ int idx, mode_is_set;
+
+ nla_parse(tb_msg, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ genlmsg_attrlen(gnlh, 0), NULL);
+
+ if (!tb_msg[NL80211_ATTR_WIPHY_BANDS])
+ return NL_SKIP;
+
+ nla_for_each_nested(nl_band, tb_msg[NL80211_ATTR_WIPHY_BANDS],
+ rem_band) {
+ mode = os_realloc(phy_info->modes,
+ (*phy_info->num_modes + 1) * sizeof(*mode));
+ if (!mode)
+ return NL_SKIP;
+ phy_info->modes = mode;
+
+ mode_is_set = 0;
+
+ mode = &phy_info->modes[*(phy_info->num_modes)];
+ os_memset(mode, 0, sizeof(*mode));
+ *(phy_info->num_modes) += 1;
+
+ nla_parse(tb_band, NL80211_BAND_ATTR_MAX, nla_data(nl_band),
+ nla_len(nl_band), NULL);
+
+ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
+ rem_freq) {
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_freq), nla_len(nl_freq),
+ freq_policy);
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
+ mode->num_channels++;
+ }
+
+ mode->channels = os_zalloc(mode->num_channels *
+ sizeof(struct wpa_channel_data));
+ if (!mode->channels)
+ return NL_SKIP;
+
+ idx = 0;
+
+ nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
+ rem_freq) {
+ nla_parse(tb_freq, NL80211_FREQUENCY_ATTR_MAX,
+ nla_data(nl_freq), nla_len(nl_freq),
+ freq_policy);
+ if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
+ continue;
+
+ mode->channels[idx].freq = nla_get_u32(
+ tb_freq[NL80211_FREQUENCY_ATTR_FREQ]);
+ mode->channels[idx].flag |= WPA_CHAN_W_SCAN |
+ WPA_CHAN_W_ACTIVE_SCAN |
+ WPA_CHAN_W_IBSS;
+
+ if (!mode_is_set) {
+ /* crude heuristic */
+ if (mode->channels[idx].freq < 4000)
+ mode->mode = WPA_MODE_IEEE80211B;
+ else
+ mode->mode = WPA_MODE_IEEE80211A;
+ mode_is_set = 1;
+ }
+
+ /* crude heuristic */
+ if (mode->channels[idx].freq < 4000) {
+ if (mode->channels[idx].freq == 2484)
+ mode->channels[idx].chan = 14;
+ else
+ mode->channels[idx].chan =
+ (mode->channels[idx].freq -
+ 2407) / 5;
+ } else
+ mode->channels[idx].chan =
+ mode->channels[idx].freq / 5 - 1000;
+
+ if (tb_freq[NL80211_FREQUENCY_ATTR_DISABLED])
+ mode->channels[idx].flag &= ~WPA_CHAN_W_SCAN;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_PASSIVE_SCAN])
+ mode->channels[idx].flag &=
+ ~WPA_CHAN_W_ACTIVE_SCAN;
+ if (tb_freq[NL80211_FREQUENCY_ATTR_NO_IBSS])
+ mode->channels[idx].flag &= ~WPA_CHAN_W_IBSS;
+ idx++;
+ }
+
+ nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES],
+ rem_rate) {
+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
+ nla_data(nl_rate), nla_len(nl_rate),
+ rate_policy);
+ if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+ continue;
+ mode->num_rates++;
+ }
+
+ mode->rates = os_zalloc(mode->num_rates *
+ sizeof(struct wpa_rate_data));
+ if (!mode->rates)
+ return NL_SKIP;
+
+ idx = 0;
+
+ nla_for_each_nested(nl_rate, tb_band[NL80211_BAND_ATTR_RATES],
+ rem_rate) {
+ nla_parse(tb_rate, NL80211_BITRATE_ATTR_MAX,
+ nla_data(nl_rate), nla_len(nl_rate),
+ rate_policy);
+ if (!tb_rate[NL80211_BITRATE_ATTR_RATE])
+ continue;
+ mode->rates[idx].rate = nla_get_u32(
+ tb_rate[NL80211_BITRATE_ATTR_RATE]);
+
+ /* crude heuristic */
+ if (mode->mode == WPA_MODE_IEEE80211B &&
+ mode->rates[idx].rate > 200)
+ mode->mode = WPA_MODE_IEEE80211G;
+
+ if (tb_rate[NL80211_BITRATE_ATTR_2GHZ_SHORTPREAMBLE])
+ mode->rates[idx].flags |= WPA_RATE_PREAMBLE2;
+
+ idx++;
+ }
+ }
+
+ return NL_SKIP;
+}
+
+
+static struct wpa_hw_modes *
+wpa_driver_nl80211_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct nl_msg *msg;
+ struct phy_info_arg result = {
+ .num_modes = num_modes,
+ .modes = NULL,
+ };
+
+ *num_modes = 0;
+ *flags = 0;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return NULL;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_GET_WIPHY, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+
+ if (send_and_recv_msgs(drv, msg, phy_info_handler, &result) == 0)
+ return result.modes;
+nla_put_failure:
+ return NULL;
+}
+
+
+static int wpa_driver_nl80211_set_channel(void *priv, wpa_hw_mode phymode,
+ int chan, int freq)
+{
+ return wpa_driver_nl80211_set_freq(priv, freq);
+}
+
+
+static int wpa_driver_nl80211_send_mlme(void *priv, const u8 *data,
+ size_t data_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ __u8 rtap_hdr[] = {
+ 0x00, 0x00, /* radiotap version */
+ 0x0e, 0x00, /* radiotap length */
+ 0x02, 0xc0, 0x00, 0x00, /* bmap: flags, tx and rx flags */
+ 0x0c, /* F_WEP | F_FRAG (encrypt/fragment if required) */
+ 0x00, /* padding */
+ 0x00, 0x00, /* RX and TX flags to indicate that */
+ 0x00, 0x00, /* this is the injected frame directly */
+ };
+ struct iovec iov[2] = {
+ {
+ .iov_base = &rtap_hdr,
+ .iov_len = sizeof(rtap_hdr),
+ },
+ {
+ .iov_base = (void *) data,
+ .iov_len = data_len,
+ }
+ };
+ struct msghdr msg = {
+ .msg_name = NULL,
+ .msg_namelen = 0,
+ .msg_iov = iov,
+ .msg_iovlen = 2,
+ .msg_control = NULL,
+ .msg_controllen = 0,
+ .msg_flags = 0,
+ };
+
+ if (sendmsg(drv->monitor_sock, &msg, 0) < 0) {
+ perror("send[MLME]");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_nl80211_mlme_add_sta(void *priv, const u8 *addr,
+ const u8 *supp_rates,
+ size_t supp_rates_len)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_NEW_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+ /* TODO: Get proper Association ID and listen interval */
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_AID, 1);
+ NLA_PUT(msg, NL80211_ATTR_STA_SUPPORTED_RATES, supp_rates_len,
+ supp_rates);
+ NLA_PUT_U16(msg, NL80211_ATTR_STA_LISTEN_INTERVAL, 1);
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ /* ignore EEXIST, this happens if a STA associates while associated */
+ if (ret == -EEXIST || ret >= 0)
+ ret = 0;
+
+nla_put_failure:
+ return ret;
+}
+
+
+static int wpa_driver_nl80211_mlme_remove_sta(void *priv, const u8 *addr)
+{
+ struct wpa_driver_nl80211_data *drv = priv;
+ struct nl_msg *msg;
+ int ret = -1;
+
+ msg = nlmsg_alloc();
+ if (!msg)
+ return -ENOMEM;
+
+ genlmsg_put(msg, 0, 0, genl_family_get_id(drv->nl80211), 0,
+ 0, NL80211_CMD_DEL_STATION, 0);
+
+ NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, drv->ifindex);
+ NLA_PUT(msg, NL80211_ATTR_MAC, ETH_ALEN, addr);
+
+ ret = 0;
+
+ ret = send_and_recv_msgs(drv, msg, NULL, NULL);
+ return ret;
+
+nla_put_failure:
+ return -ENOBUFS;
+}
+
+#endif /* CONFIG_CLIENT_MLME */
+
+
+const struct wpa_driver_ops wpa_driver_nl80211_ops = {
+ .name = "nl80211",
+ .desc = "Linux nl80211/cfg80211",
+ .get_bssid = wpa_driver_nl80211_get_bssid,
+ .get_ssid = wpa_driver_nl80211_get_ssid,
+ .set_wpa = wpa_driver_nl80211_set_wpa,
+ .set_key = wpa_driver_nl80211_set_key,
+ .set_countermeasures = wpa_driver_nl80211_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_nl80211_set_drop_unencrypted,
+ .scan = wpa_driver_nl80211_scan,
+ .get_scan_results2 = wpa_driver_nl80211_get_scan_results,
+ .deauthenticate = wpa_driver_nl80211_deauthenticate,
+ .disassociate = wpa_driver_nl80211_disassociate,
+ .set_mode = wpa_driver_nl80211_set_mode,
+ .associate = wpa_driver_nl80211_associate,
+ .set_auth_alg = wpa_driver_nl80211_set_auth_alg,
+ .init = wpa_driver_nl80211_init,
+ .deinit = wpa_driver_nl80211_deinit,
+ .set_param = wpa_driver_nl80211_set_param,
+ .add_pmkid = wpa_driver_nl80211_add_pmkid,
+ .remove_pmkid = wpa_driver_nl80211_remove_pmkid,
+ .flush_pmkid = wpa_driver_nl80211_flush_pmkid,
+ .get_capa = wpa_driver_nl80211_get_capa,
+ .set_operstate = wpa_driver_nl80211_set_operstate,
+ .set_country = wpa_driver_nl80211_set_country,
+ .set_probe_req_ie = wpa_driver_nl80211_set_probe_req_ie,
+#ifdef CONFIG_CLIENT_MLME
+ .get_hw_feature_data = wpa_driver_nl80211_get_hw_feature_data,
+ .set_channel = wpa_driver_nl80211_set_channel,
+ .set_ssid = wpa_driver_nl80211_set_ssid,
+ .set_bssid = wpa_driver_nl80211_set_bssid,
+ .send_mlme = wpa_driver_nl80211_send_mlme,
+ .mlme_add_sta = wpa_driver_nl80211_mlme_add_sta,
+ .mlme_remove_sta = wpa_driver_nl80211_mlme_remove_sta,
+#endif /* CONFIG_CLIENT_MLME */
+};
diff --git a/src/drivers/driver_osx.m b/src/drivers/driver_osx.m
new file mode 100644
index 0000000..93d7df0
--- /dev/null
+++ b/src/drivers/driver_osx.m
@@ -0,0 +1,432 @@
+/*
+ * WPA Supplicant - Mac OS X Apple80211 driver interface
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#define Boolean __DummyBoolean
+#include <CoreFoundation/CoreFoundation.h>
+#undef Boolean
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+
+#include "Apple80211.h"
+
+struct wpa_driver_osx_data {
+ void *ctx;
+ WirelessRef wireless_ctx;
+ CFArrayRef scan_results;
+};
+
+
+#ifndef CONFIG_NO_STDOUT_DEBUG
+extern int wpa_debug_level;
+
+static void dump_dict_cb(const void *key, const void *value, void *context)
+{
+ if (MSG_DEBUG < wpa_debug_level)
+ return;
+
+ wpa_printf(MSG_DEBUG, "Key:");
+ CFShow(key);
+ wpa_printf(MSG_DEBUG, "Value:");
+ CFShow(value);
+}
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+static void wpa_driver_osx_dump_dict(CFDictionaryRef dict, const char *title)
+{
+#ifndef CONFIG_NO_STDOUT_DEBUG
+ wpa_printf(MSG_DEBUG, "OSX: Dump dictionary %s - %u entries",
+ title, (unsigned int) CFDictionaryGetCount(dict));
+ CFDictionaryApplyFunction(dict, dump_dict_cb, NULL);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+}
+
+
+static int wpa_driver_osx_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+ WirelessInfo info;
+ int len;
+
+ err = WirelessGetInfo(drv->wireless_ctx, &info);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
+ (int) err);
+ return -1;
+ }
+ if (!info.power) {
+ wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
+ return -1;
+ }
+
+ for (len = 0; len < 32; len++)
+ if (info.ssid[len] == 0)
+ break;
+
+ os_memcpy(ssid, info.ssid, len);
+ return len;
+}
+
+
+static int wpa_driver_osx_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+ WirelessInfo info;
+
+ err = WirelessGetInfo(drv->wireless_ctx, &info);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessGetInfo failed: %d",
+ (int) err);
+ return -1;
+ }
+ if (!info.power) {
+ wpa_printf(MSG_DEBUG, "OSX: Wireless device power off");
+ return -1;
+ }
+
+ os_memcpy(bssid, info.bssID, ETH_ALEN);
+ return 0;
+}
+
+
+static void wpa_driver_osx_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+static int wpa_driver_osx_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+
+ if (drv->scan_results) {
+ CFRelease(drv->scan_results);
+ drv->scan_results = NULL;
+ }
+
+ if (ssid) {
+ CFStringRef data;
+ data = CFStringCreateWithBytes(kCFAllocatorDefault,
+ ssid, ssid_len,
+ kCFStringEncodingISOLatin1,
+ FALSE);
+ if (data == NULL) {
+ wpa_printf(MSG_DEBUG, "CFStringCreateWithBytes "
+ "failed");
+ return -1;
+ }
+
+ err = WirelessDirectedScan(drv->wireless_ctx,
+ &drv->scan_results, 0, data);
+ CFRelease(data);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessDirectedScan "
+ "failed: 0x%08x", (unsigned int) err);
+ return -1;
+ }
+ } else {
+ err = WirelessScan(drv->wireless_ctx, &drv->scan_results, 0);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessScan failed: "
+ "0x%08x", (unsigned int) err);
+ return -1;
+ }
+ }
+
+ eloop_register_timeout(0, 0, wpa_driver_osx_scan_timeout, drv,
+ drv->ctx);
+ return 0;
+}
+
+
+static int wpa_driver_osx_get_scan_results(void *priv,
+ struct wpa_scan_result *results,
+ size_t max_size)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ size_t i, num;
+
+ if (drv->scan_results == NULL)
+ return 0;
+
+ num = CFArrayGetCount(drv->scan_results);
+ if (num > max_size)
+ num = max_size;
+ os_memset(results, 0, num * sizeof(struct wpa_scan_result));
+
+ for (i = 0; i < num; i++) {
+ struct wpa_scan_result *res = &results[i];
+ WirelessNetworkInfo *info;
+ info = (WirelessNetworkInfo *)
+ CFDataGetBytePtr(CFArrayGetValueAtIndex(
+ drv->scan_results, i));
+
+ os_memcpy(res->bssid, info->bssid, ETH_ALEN);
+ if (info->ssid_len > 32) {
+ wpa_printf(MSG_DEBUG, "OSX: Invalid SSID length %d in "
+ "scan results", (int) info->ssid_len);
+ continue;
+ }
+ os_memcpy(res->ssid, info->ssid, info->ssid_len);
+ res->ssid_len = info->ssid_len;
+ res->caps = info->capability;
+ res->freq = 2407 + info->channel * 5;
+ res->level = info->signal;
+ res->noise = info->noise;
+ }
+
+ return num;
+}
+
+
+static void wpa_driver_osx_assoc_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_driver_osx_data *drv = eloop_ctx;
+ u8 bssid[ETH_ALEN];
+ CFDictionaryRef ai;
+
+ if (wpa_driver_osx_get_bssid(drv, bssid) != 0) {
+ eloop_register_timeout(1, 0, wpa_driver_osx_assoc_timeout,
+ drv, drv->ctx);
+ return;
+ }
+
+ ai = WirelessGetAssociationInfo(drv->wireless_ctx);
+ if (ai) {
+ wpa_driver_osx_dump_dict(ai, "WirelessGetAssociationInfo");
+ CFRelease(ai);
+ } else {
+ wpa_printf(MSG_DEBUG, "OSX: Failed to get association info");
+ }
+
+ wpa_supplicant_event(timeout_ctx, EVENT_ASSOC, NULL);
+}
+
+
+static int wpa_driver_osx_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+ CFDataRef ssid;
+ CFStringRef key;
+ int assoc_type;
+
+ ssid = CFDataCreate(kCFAllocatorDefault, params->ssid,
+ params->ssid_len);
+ if (ssid == NULL)
+ return -1;
+
+ /* TODO: support for WEP */
+ if (params->key_mgmt_suite == KEY_MGMT_PSK) {
+ if (params->passphrase == NULL)
+ return -1;
+ key = CFStringCreateWithCString(kCFAllocatorDefault,
+ params->passphrase,
+ kCFStringEncodingISOLatin1);
+ if (key == NULL) {
+ CFRelease(ssid);
+ return -1;
+ }
+ } else
+ key = NULL;
+
+ if (params->key_mgmt_suite == KEY_MGMT_NONE)
+ assoc_type = 0;
+ else
+ assoc_type = 4;
+
+ wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate(type=%d key=%p)",
+ assoc_type, key);
+ err = WirelessAssociate(drv->wireless_ctx, assoc_type, ssid, key);
+ CFRelease(ssid);
+ if (key)
+ CFRelease(key);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessAssociate failed: 0x%08x",
+ (unsigned int) err);
+ return -1;
+ }
+
+ /*
+ * Driver is actually already associated; report association from an
+ * eloop callback.
+ */
+ eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
+ eloop_register_timeout(0, 0, wpa_driver_osx_assoc_timeout, drv,
+ drv->ctx);
+
+ return 0;
+}
+
+
+static int wpa_driver_osx_set_key(void *priv, wpa_alg alg, const u8 *addr,
+ int key_idx, int set_tx, const u8 *seq,
+ size_t seq_len, const u8 *key,
+ size_t key_len)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+
+ if (alg == WPA_ALG_WEP) {
+ err = WirelessSetKey(drv->wireless_ctx, 1, key_idx, key_len,
+ key);
+ if (err != 0) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetKey failed: "
+ "0x%08x", (unsigned int) err);
+ return -1;
+ }
+
+ return 0;
+ }
+
+ if (alg == WPA_ALG_PMK) {
+ err = WirelessSetWPAKey(drv->wireless_ctx, 1, key_len, key);
+ if (err != 0) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetWPAKey failed: "
+ "0x%08x", (unsigned int) err);
+ return -1;
+ }
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG, "OSX: Unsupported set_key alg %d", alg);
+ return -1;
+}
+
+
+static int wpa_driver_osx_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ os_memset(capa, 0, sizeof(*capa));
+
+ capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 | WPA_DRIVER_CAPA_ENC_WEP104 |
+ WPA_DRIVER_CAPA_ENC_TKIP | WPA_DRIVER_CAPA_ENC_CCMP;
+ capa->auth = WPA_DRIVER_AUTH_OPEN | WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+ capa->flags = WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+
+ return 0;
+}
+
+
+static void * wpa_driver_osx_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_osx_data *drv;
+ WirelessError err;
+ u8 enabled, power;
+
+ if (!WirelessIsAvailable()) {
+ wpa_printf(MSG_ERROR, "OSX: No wireless interface available");
+ return NULL;
+ }
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ err = WirelessAttach(&drv->wireless_ctx, 0);
+ if (err) {
+ wpa_printf(MSG_ERROR, "OSX: WirelessAttach failed: %d",
+ (int) err);
+ os_free(drv);
+ return NULL;
+ }
+
+ err = WirelessGetEnabled(drv->wireless_ctx, &enabled);
+ if (err)
+ wpa_printf(MSG_DEBUG, "OSX: WirelessGetEnabled failed: 0x%08x",
+ (unsigned int) err);
+ err = WirelessGetPower(drv->wireless_ctx, &power);
+ if (err)
+ wpa_printf(MSG_DEBUG, "OSX: WirelessGetPower failed: 0x%08x",
+ (unsigned int) err);
+
+ wpa_printf(MSG_DEBUG, "OSX: Enabled=%d Power=%d", enabled, power);
+
+ if (!enabled) {
+ err = WirelessSetEnabled(drv->wireless_ctx, 1);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetEnabled failed:"
+ " 0x%08x", (unsigned int) err);
+ WirelessDetach(drv->wireless_ctx);
+ os_free(drv);
+ return NULL;
+ }
+ }
+
+ if (!power) {
+ err = WirelessSetPower(drv->wireless_ctx, 1);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower failed: "
+ "0x%08x", (unsigned int) err);
+ WirelessDetach(drv->wireless_ctx);
+ os_free(drv);
+ return NULL;
+ }
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_osx_deinit(void *priv)
+{
+ struct wpa_driver_osx_data *drv = priv;
+ WirelessError err;
+
+ eloop_cancel_timeout(wpa_driver_osx_scan_timeout, drv, drv->ctx);
+ eloop_cancel_timeout(wpa_driver_osx_assoc_timeout, drv, drv->ctx);
+
+ err = WirelessSetPower(drv->wireless_ctx, 0);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessSetPower(0) failed: "
+ "0x%08x", (unsigned int) err);
+ }
+
+ err = WirelessDetach(drv->wireless_ctx);
+ if (err) {
+ wpa_printf(MSG_DEBUG, "OSX: WirelessDetach failed: 0x%08x",
+ (unsigned int) err);
+ }
+
+ if (drv->scan_results)
+ CFRelease(drv->scan_results);
+
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_osx_ops = {
+ .name = "osx",
+ .desc = "Mac OS X Apple80211 driver",
+ .get_ssid = wpa_driver_osx_get_ssid,
+ .get_bssid = wpa_driver_osx_get_bssid,
+ .init = wpa_driver_osx_init,
+ .deinit = wpa_driver_osx_deinit,
+ .scan = wpa_driver_osx_scan,
+ .get_scan_results = wpa_driver_osx_get_scan_results,
+ .associate = wpa_driver_osx_associate,
+ .set_key = wpa_driver_osx_set_key,
+ .get_capa = wpa_driver_osx_get_capa,
+};
diff --git a/src/drivers/driver_prism54.c b/src/drivers/driver_prism54.c
new file mode 100644
index 0000000..e64e762
--- /dev/null
+++ b/src/drivers/driver_prism54.c
@@ -0,0 +1,381 @@
+/*
+ * WPA Supplicant - driver interaction with Linux Prism54.org driver
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004, Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "driver_wext.h"
+#include "driver_hostap.h"
+
+struct wpa_driver_prism54_data {
+ void *wext; /* private data for driver_wext */
+ void *ctx;
+ char ifname[IFNAMSIZ + 1];
+ int sock;
+};
+
+#define PRISM54_SET_WPA SIOCIWFIRSTPRIV+12
+#define PRISM54_HOSTAPD SIOCIWFIRSTPRIV+25
+#define PRISM54_DROP_UNENCRYPTED SIOCIWFIRSTPRIV+26
+
+static void show_set_key_error(struct prism2_hostapd_param *);
+
+static int hostapd_ioctl_prism54(struct wpa_driver_prism54_data *drv,
+ struct prism2_hostapd_param *param,
+ int len, int show_err)
+{
+ struct iwreq iwr;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) param;
+ iwr.u.data.length = len;
+
+ if (ioctl(drv->sock, PRISM54_HOSTAPD, &iwr) < 0) {
+ int ret = errno;
+ if (show_err)
+ perror("ioctl[PRISM54_HOSTAPD]");
+ return ret;
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_prism54_set_wpa_ie(struct wpa_driver_prism54_data *drv,
+ const u8 *wpa_ie,
+ size_t wpa_ie_len)
+{
+ struct prism2_hostapd_param *param;
+ int res;
+ size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN + wpa_ie_len;
+ if (blen < sizeof(*param))
+ blen = sizeof(*param);
+
+ param = os_zalloc(blen);
+ if (param == NULL)
+ return -1;
+
+ param->cmd = PRISM2_HOSTAPD_SET_GENERIC_ELEMENT;
+ param->u.generic_elem.len = wpa_ie_len;
+ os_memcpy(param->u.generic_elem.data, wpa_ie, wpa_ie_len);
+ res = hostapd_ioctl_prism54(drv, param, blen, 1);
+
+ os_free(param);
+
+ return res;
+}
+
+
+/* This is called at wpa_supplicant daemon init time */
+static int wpa_driver_prism54_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ struct prism2_hostapd_param *param;
+ int res;
+ size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
+ if (blen < sizeof(*param))
+ blen = sizeof(*param);
+
+ param = os_zalloc(blen);
+ if (param == NULL)
+ return -1;
+
+ param->cmd = PRISM54_SET_WPA;
+ param->u.generic_elem.len = 0;
+ res = hostapd_ioctl_prism54(drv, param, blen, 1);
+
+ os_free(param);
+
+ return res;
+}
+
+
+static int wpa_driver_prism54_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ struct prism2_hostapd_param *param;
+ u8 *buf;
+ size_t blen;
+ int ret = 0;
+ char *alg_name;
+
+ switch (alg) {
+ case WPA_ALG_NONE:
+ alg_name = "none";
+ return -1;
+ break;
+ case WPA_ALG_WEP:
+ alg_name = "WEP";
+ return -1;
+ break;
+ case WPA_ALG_TKIP:
+ alg_name = "TKIP";
+ break;
+ case WPA_ALG_CCMP:
+ alg_name = "CCMP";
+ return -1;
+ break;
+ default:
+ return -1;
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%s key_idx=%d set_tx=%d seq_len=%lu "
+ "key_len=%lu", __FUNCTION__, alg_name, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ if (seq_len > 8)
+ return -2;
+
+ blen = sizeof(*param) + key_len;
+ buf = os_zalloc(blen);
+ if (buf == NULL)
+ return -1;
+
+ param = (struct prism2_hostapd_param *) buf;
+ param->cmd = PRISM2_SET_ENCRYPTION;
+ /* TODO: In theory, STA in client mode can use five keys; four default
+ * keys for receiving (with keyidx 0..3) and one individual key for
+ * both transmitting and receiving (keyidx 0) _unicast_ packets. Now,
+ * keyidx 0 is reserved for this unicast use and default keys can only
+ * use keyidx 1..3 (i.e., default key with keyidx 0 is not supported).
+ * This should be fine for more or less all cases, but for completeness
+ * sake, the driver could be enhanced to support the missing key. */
+#if 0
+ if (addr == NULL)
+ os_memset(param->sta_addr, 0xff, ETH_ALEN);
+ else
+ os_memcpy(param->sta_addr, addr, ETH_ALEN);
+#else
+ os_memset(param->sta_addr, 0xff, ETH_ALEN);
+#endif
+ os_strlcpy((char *) param->u.crypt.alg, alg_name,
+ HOSTAP_CRYPT_ALG_NAME_LEN);
+ param->u.crypt.flags = set_tx ? HOSTAP_CRYPT_FLAG_SET_TX_KEY : 0;
+ param->u.crypt.idx = key_idx;
+ os_memcpy(param->u.crypt.seq, seq, seq_len);
+ param->u.crypt.key_len = key_len;
+ os_memcpy((u8 *) (param + 1), key, key_len);
+
+ if (hostapd_ioctl_prism54(drv, param, blen, 1)) {
+ wpa_printf(MSG_WARNING, "Failed to set encryption.");
+ show_set_key_error(param);
+ ret = -1;
+ }
+ os_free(buf);
+
+ return ret;
+}
+
+
+static int wpa_driver_prism54_set_countermeasures(void *priv,
+ int enabled)
+{
+ /* FIX */
+ printf("wpa_driver_prism54_set_countermeasures - not yet "
+ "implemented\n");
+ return 0;
+}
+
+
+static int wpa_driver_prism54_set_drop_unencrypted(void *priv,
+ int enabled)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ struct prism2_hostapd_param *param;
+ int res;
+ size_t blen = PRISM2_HOSTAPD_GENERIC_ELEMENT_HDR_LEN;
+ if (blen < sizeof(*param))
+ blen = sizeof(*param);
+
+ param = os_zalloc(blen);
+ if (param == NULL)
+ return -1;
+
+ param->cmd = PRISM54_DROP_UNENCRYPTED;
+ param->u.generic_elem.len = 0;
+ res = hostapd_ioctl_prism54(drv, param, blen, 1);
+
+ os_free(param);
+
+ return res;
+}
+
+
+static int wpa_driver_prism54_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ /* FIX */
+ printf("wpa_driver_prism54_deauthenticate - not yet implemented\n");
+ return 0;
+}
+
+
+static int wpa_driver_prism54_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ /* FIX */
+ printf("wpa_driver_prism54_disassociate - not yet implemented\n");
+ return 0;
+}
+
+
+static int
+wpa_driver_prism54_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ int ret = 0;
+
+ if (wpa_driver_prism54_set_wpa_ie(drv, params->wpa_ie,
+ params->wpa_ie_len) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_freq(drv->wext, params->freq) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_ssid(drv->wext, params->ssid,
+ params->ssid_len) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_bssid(drv->wext, params->bssid) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+static void show_set_key_error(struct prism2_hostapd_param *param)
+{
+ switch (param->u.crypt.err) {
+ case HOSTAP_CRYPT_ERR_UNKNOWN_ALG:
+ wpa_printf(MSG_INFO, "Unknown algorithm '%s'.",
+ param->u.crypt.alg);
+ wpa_printf(MSG_INFO, "You may need to load kernel module to "
+ "register that algorithm.");
+ wpa_printf(MSG_INFO, "E.g., 'modprobe hostap_crypt_wep' for "
+ "WEP.");
+ break;
+ case HOSTAP_CRYPT_ERR_UNKNOWN_ADDR:
+ wpa_printf(MSG_INFO, "Unknown address " MACSTR ".",
+ MAC2STR(param->sta_addr));
+ break;
+ case HOSTAP_CRYPT_ERR_CRYPT_INIT_FAILED:
+ wpa_printf(MSG_INFO, "Crypt algorithm initialization failed.");
+ break;
+ case HOSTAP_CRYPT_ERR_KEY_SET_FAILED:
+ wpa_printf(MSG_INFO, "Key setting failed.");
+ break;
+ case HOSTAP_CRYPT_ERR_TX_KEY_SET_FAILED:
+ wpa_printf(MSG_INFO, "TX key index setting failed.");
+ break;
+ case HOSTAP_CRYPT_ERR_CARD_CONF_FAILED:
+ wpa_printf(MSG_INFO, "Card configuration failed.");
+ break;
+ }
+}
+
+
+static int wpa_driver_prism54_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ return wpa_driver_wext_get_bssid(drv->wext, bssid);
+}
+
+
+static int wpa_driver_prism54_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ return wpa_driver_wext_get_ssid(drv->wext, ssid);
+}
+
+
+static int wpa_driver_prism54_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ return wpa_driver_wext_scan(drv->wext, ssid, ssid_len);
+}
+
+
+static struct wpa_scan_results *
+wpa_driver_prism54_get_scan_results(void *priv)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ return wpa_driver_wext_get_scan_results(drv->wext);
+}
+
+
+static int wpa_driver_prism54_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ return wpa_driver_wext_set_operstate(drv->wext, state);
+}
+
+
+static void * wpa_driver_prism54_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_prism54_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->wext = wpa_driver_wext_init(ctx, ifname);
+ if (drv->wext == NULL) {
+ os_free(drv);
+ return NULL;
+ }
+
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->sock < 0) {
+ wpa_driver_wext_deinit(drv->wext);
+ os_free(drv);
+ return NULL;
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_prism54_deinit(void *priv)
+{
+ struct wpa_driver_prism54_data *drv = priv;
+ wpa_driver_wext_deinit(drv->wext);
+ close(drv->sock);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_prism54_ops = {
+ .name = "prism54",
+ .desc = "Prism54.org driver (Intersil Prism GT/Duette/Indigo)",
+ .get_bssid = wpa_driver_prism54_get_bssid,
+ .get_ssid = wpa_driver_prism54_get_ssid,
+ .set_wpa = wpa_driver_prism54_set_wpa,
+ .set_key = wpa_driver_prism54_set_key,
+ .set_countermeasures = wpa_driver_prism54_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_prism54_set_drop_unencrypted,
+ .scan = wpa_driver_prism54_scan,
+ .get_scan_results2 = wpa_driver_prism54_get_scan_results,
+ .deauthenticate = wpa_driver_prism54_deauthenticate,
+ .disassociate = wpa_driver_prism54_disassociate,
+ .associate = wpa_driver_prism54_associate,
+ .init = wpa_driver_prism54_init,
+ .deinit = wpa_driver_prism54_deinit,
+ .set_operstate = wpa_driver_prism54_set_operstate,
+};
diff --git a/src/drivers/driver_privsep.c b/src/drivers/driver_privsep.c
new file mode 100644
index 0000000..fdf299d
--- /dev/null
+++ b/src/drivers/driver_privsep.c
@@ -0,0 +1,820 @@
+/*
+ * WPA Supplicant - privilege separated driver interface
+ * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/un.h>
+
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "privsep_commands.h"
+
+
+struct wpa_driver_privsep_data {
+ void *ctx;
+ u8 own_addr[ETH_ALEN];
+ int priv_socket;
+ char *own_socket_path;
+ int cmd_socket;
+ char *own_cmd_path;
+ struct sockaddr_un priv_addr;
+ char ifname[16];
+};
+
+
+static int wpa_priv_reg_cmd(struct wpa_driver_privsep_data *drv, int cmd)
+{
+ int res;
+
+ res = sendto(drv->priv_socket, &cmd, sizeof(cmd), 0,
+ (struct sockaddr *) &drv->priv_addr,
+ sizeof(drv->priv_addr));
+ if (res < 0)
+ perror("sendto");
+ return res < 0 ? -1 : 0;
+}
+
+
+static int wpa_priv_cmd(struct wpa_driver_privsep_data *drv, int cmd,
+ const void *data, size_t data_len,
+ void *reply, size_t *reply_len)
+{
+ struct msghdr msg;
+ struct iovec io[2];
+
+ io[0].iov_base = &cmd;
+ io[0].iov_len = sizeof(cmd);
+ io[1].iov_base = (u8 *) data;
+ io[1].iov_len = data_len;
+
+ os_memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = data ? 2 : 1;
+ msg.msg_name = &drv->priv_addr;
+ msg.msg_namelen = sizeof(drv->priv_addr);
+
+ if (sendmsg(drv->cmd_socket, &msg, 0) < 0) {
+ perror("sendmsg(cmd_socket)");
+ return -1;
+ }
+
+ if (reply) {
+ fd_set rfds;
+ struct timeval tv;
+ int res;
+
+ FD_ZERO(&rfds);
+ FD_SET(drv->cmd_socket, &rfds);
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ res = select(drv->cmd_socket + 1, &rfds, NULL, NULL, &tv);
+ if (res < 0 && errno != EINTR) {
+ perror("select");
+ return -1;
+ }
+
+ if (FD_ISSET(drv->cmd_socket, &rfds)) {
+ res = recv(drv->cmd_socket, reply, *reply_len, 0);
+ if (res < 0) {
+ perror("recv");
+ return -1;
+ }
+ *reply_len = res;
+ } else {
+ wpa_printf(MSG_DEBUG, "PRIVSEP: Timeout while waiting "
+ "for reply (cmd=%d)", cmd);
+ return -1;
+ }
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_privsep_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_WPA, &enabled,
+ sizeof(enabled), NULL, NULL);
+}
+
+
+static int wpa_driver_privsep_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SCAN, ssid, ssid_len,
+ NULL, NULL);
+}
+
+
+static struct wpa_scan_results *
+wpa_driver_privsep_get_scan_results2(void *priv)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ int res, num;
+ u8 *buf, *pos, *end;
+ size_t reply_len = 60000;
+ struct wpa_scan_results *results;
+ struct wpa_scan_res *r;
+
+ buf = os_malloc(reply_len);
+ if (buf == NULL)
+ return NULL;
+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SCAN_RESULTS,
+ NULL, 0, buf, &reply_len);
+ if (res < 0) {
+ os_free(buf);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "privsep: Received %lu bytes of scan results",
+ (unsigned long) reply_len);
+ if (reply_len < sizeof(int)) {
+ wpa_printf(MSG_DEBUG, "privsep: Invalid scan result len %lu",
+ (unsigned long) reply_len);
+ os_free(buf);
+ return NULL;
+ }
+
+ pos = buf;
+ end = buf + reply_len;
+ os_memcpy(&num, pos, sizeof(int));
+ if (num < 0 || num > 1000) {
+ os_free(buf);
+ return NULL;
+ }
+ pos += sizeof(int);
+
+ results = os_zalloc(sizeof(*results));
+ if (results == NULL) {
+ os_free(buf);
+ return NULL;
+ }
+
+ results->res = os_zalloc(num * sizeof(struct wpa_scan_res *));
+ if (results->res == NULL) {
+ os_free(results);
+ os_free(buf);
+ return NULL;
+ }
+
+ while (results->num < (size_t) num && pos + sizeof(int) < end) {
+ int len;
+ os_memcpy(&len, pos, sizeof(int));
+ pos += sizeof(int);
+ if (len < 0 || len > 10000 || pos + len > end)
+ break;
+
+ r = os_malloc(len);
+ if (r == NULL)
+ break;
+ os_memcpy(r, pos, len);
+ pos += len;
+ if (sizeof(*r) + r->ie_len > (size_t) len) {
+ os_free(r);
+ break;
+ }
+
+ results->res[results->num++] = r;
+ }
+
+ os_free(buf);
+ return results;
+}
+
+
+static int wpa_driver_privsep_set_key(void *priv, wpa_alg alg, const u8 *addr,
+ int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ struct privsep_cmd_set_key cmd;
+
+ wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
+ __func__, priv, alg, key_idx, set_tx);
+
+ os_memset(&cmd, 0, sizeof(cmd));
+ cmd.alg = alg;
+ if (addr)
+ os_memcpy(cmd.addr, addr, ETH_ALEN);
+ else
+ os_memset(cmd.addr, 0xff, ETH_ALEN);
+ cmd.key_idx = key_idx;
+ cmd.set_tx = set_tx;
+ if (seq && seq_len > 0 && seq_len < sizeof(cmd.seq)) {
+ os_memcpy(cmd.seq, seq, seq_len);
+ cmd.seq_len = seq_len;
+ }
+ if (key && key_len > 0 && key_len < sizeof(cmd.key)) {
+ os_memcpy(cmd.key, key, key_len);
+ cmd.key_len = key_len;
+ }
+
+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_KEY, &cmd, sizeof(cmd),
+ NULL, NULL);
+}
+
+
+static int wpa_driver_privsep_associate(
+ void *priv, struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ struct privsep_cmd_associate *data;
+ int res;
+ size_t buflen;
+
+ wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
+ "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
+ __func__, priv, params->freq, params->pairwise_suite,
+ params->group_suite, params->key_mgmt_suite,
+ params->auth_alg, params->mode);
+
+ buflen = sizeof(*data) + params->wpa_ie_len;
+ data = os_zalloc(buflen);
+ if (data == NULL)
+ return -1;
+
+ if (params->bssid)
+ os_memcpy(data->bssid, params->bssid, ETH_ALEN);
+ os_memcpy(data->ssid, params->ssid, params->ssid_len);
+ data->ssid_len = params->ssid_len;
+ data->freq = params->freq;
+ data->pairwise_suite = params->pairwise_suite;
+ data->group_suite = params->group_suite;
+ data->key_mgmt_suite = params->key_mgmt_suite;
+ data->auth_alg = params->auth_alg;
+ data->mode = params->mode;
+ data->wpa_ie_len = params->wpa_ie_len;
+ if (params->wpa_ie)
+ os_memcpy(data + 1, params->wpa_ie, params->wpa_ie_len);
+ /* TODO: add support for other assoc parameters */
+
+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_ASSOCIATE, data, buflen,
+ NULL, NULL);
+ os_free(data);
+
+ return res;
+}
+
+
+static int wpa_driver_privsep_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ int res;
+ size_t len = ETH_ALEN;
+
+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_BSSID, NULL, 0, bssid, &len);
+ if (res < 0 || len != ETH_ALEN)
+ return -1;
+ return 0;
+}
+
+
+static int wpa_driver_privsep_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ int res, ssid_len;
+ u8 reply[sizeof(int) + 32];
+ size_t len = sizeof(reply);
+
+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_SSID, NULL, 0, reply, &len);
+ if (res < 0 || len < sizeof(int))
+ return -1;
+ os_memcpy(&ssid_len, reply, sizeof(int));
+ if (ssid_len < 0 || ssid_len > 32 || sizeof(int) + ssid_len > len) {
+ wpa_printf(MSG_DEBUG, "privsep: Invalid get SSID reply");
+ return -1;
+ }
+ os_memcpy(ssid, &reply[sizeof(int)], ssid_len);
+ return ssid_len;
+}
+
+
+static int wpa_driver_privsep_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ //struct wpa_driver_privsep_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
+ __func__, MAC2STR(addr), reason_code);
+ wpa_printf(MSG_DEBUG, "%s - TODO", __func__);
+ return 0;
+}
+
+
+static int wpa_driver_privsep_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ //struct wpa_driver_privsep_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
+ __func__, MAC2STR(addr), reason_code);
+ wpa_printf(MSG_DEBUG, "%s - TODO", __func__);
+ return 0;
+}
+
+
+static void wpa_driver_privsep_event_assoc(void *ctx, wpa_event_type event,
+ u8 *buf, size_t len)
+{
+ union wpa_event_data data;
+ int inc_data = 0;
+ u8 *pos, *end;
+ int ie_len;
+
+ os_memset(&data, 0, sizeof(data));
+
+ pos = buf;
+ end = buf + len;
+
+ if (end - pos < (int) sizeof(int))
+ return;
+ os_memcpy(&ie_len, pos, sizeof(int));
+ pos += sizeof(int);
+ if (ie_len < 0 || ie_len > end - pos)
+ return;
+ if (ie_len) {
+ data.assoc_info.req_ies = pos;
+ data.assoc_info.req_ies_len = ie_len;
+ pos += ie_len;
+ inc_data = 1;
+ }
+
+ wpa_supplicant_event(ctx, event, inc_data ? &data : NULL);
+}
+
+
+static void wpa_driver_privsep_event_interface_status(void *ctx, u8 *buf,
+ size_t len)
+{
+ union wpa_event_data data;
+ int ievent;
+
+ if (len < sizeof(int) ||
+ len - sizeof(int) > sizeof(data.interface_status.ifname))
+ return;
+
+ os_memcpy(&ievent, buf, sizeof(int));
+
+ os_memset(&data, 0, sizeof(data));
+ data.interface_status.ievent = ievent;
+ os_memcpy(data.interface_status.ifname, buf + sizeof(int),
+ len - sizeof(int));
+ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &data);
+}
+
+
+static void wpa_driver_privsep_event_michael_mic_failure(
+ void *ctx, u8 *buf, size_t len)
+{
+ union wpa_event_data data;
+
+ if (len != sizeof(int))
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(&data.michael_mic_failure.unicast, buf, sizeof(int));
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+}
+
+
+static void wpa_driver_privsep_event_pmkid_candidate(void *ctx, u8 *buf,
+ size_t len)
+{
+ union wpa_event_data data;
+
+ if (len != sizeof(struct pmkid_candidate))
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(&data.pmkid_candidate, buf, len);
+ wpa_supplicant_event(ctx, EVENT_PMKID_CANDIDATE, &data);
+}
+
+
+static void wpa_driver_privsep_event_stkstart(void *ctx, u8 *buf, size_t len)
+{
+ union wpa_event_data data;
+
+ if (len != ETH_ALEN)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.stkstart.peer, buf, ETH_ALEN);
+ wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
+}
+
+
+static void wpa_driver_privsep_event_ft_response(void *ctx, u8 *buf,
+ size_t len)
+{
+ union wpa_event_data data;
+
+ if (len < sizeof(int) + ETH_ALEN)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(&data.ft_ies.ft_action, buf, sizeof(int));
+ os_memcpy(data.ft_ies.target_ap, buf + sizeof(int), ETH_ALEN);
+ data.ft_ies.ies = buf + sizeof(int) + ETH_ALEN;
+ data.ft_ies.ies_len = len - sizeof(int) - ETH_ALEN;
+ wpa_supplicant_event(ctx, EVENT_FT_RESPONSE, &data);
+}
+
+
+static void wpa_driver_privsep_event_rx_eapol(void *ctx, u8 *buf, size_t len)
+{
+ if (len < ETH_ALEN)
+ return;
+
+ wpa_supplicant_rx_eapol(ctx, buf, buf + ETH_ALEN, len - ETH_ALEN);
+}
+
+
+static void wpa_driver_privsep_event_sta_rx(void *ctx, u8 *buf, size_t len)
+{
+#ifdef CONFIG_CLIENT_MLME
+ struct ieee80211_rx_status *rx_status;
+
+ if (len < sizeof(*rx_status))
+ return;
+ rx_status = (struct ieee80211_rx_status *) buf;
+ buf += sizeof(*rx_status);
+ len -= sizeof(*rx_status);
+
+ wpa_supplicant_sta_rx(ctx, buf, len, rx_status);
+#endif /* CONFIG_CLIENT_MLME */
+}
+
+
+static void wpa_driver_privsep_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct wpa_driver_privsep_data *drv = eloop_ctx;
+ u8 *buf, *event_buf;
+ size_t event_len;
+ int res, event;
+ enum privsep_event e;
+ struct sockaddr_un from;
+ socklen_t fromlen = sizeof(from);
+ const size_t buflen = 2000;
+
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return;
+ res = recvfrom(sock, buf, buflen, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ perror("recvfrom(priv_socket)");
+ os_free(buf);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "privsep_driver: received %u bytes", res);
+
+ if (res < (int) sizeof(int)) {
+ wpa_printf(MSG_DEBUG, "Too short event message (len=%d)", res);
+ return;
+ }
+
+ os_memcpy(&event, buf, sizeof(int));
+ event_buf = &buf[sizeof(int)];
+ event_len = res - sizeof(int);
+ wpa_printf(MSG_DEBUG, "privsep: Event %d received (len=%lu)",
+ event, (unsigned long) event_len);
+
+ e = event;
+ switch (e) {
+ case PRIVSEP_EVENT_SCAN_RESULTS:
+ wpa_supplicant_event(drv->ctx, EVENT_SCAN_RESULTS, NULL);
+ break;
+ case PRIVSEP_EVENT_ASSOC:
+ wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOC,
+ event_buf, event_len);
+ break;
+ case PRIVSEP_EVENT_DISASSOC:
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+ break;
+ case PRIVSEP_EVENT_ASSOCINFO:
+ wpa_driver_privsep_event_assoc(drv->ctx, EVENT_ASSOCINFO,
+ event_buf, event_len);
+ break;
+ case PRIVSEP_EVENT_MICHAEL_MIC_FAILURE:
+ wpa_driver_privsep_event_michael_mic_failure(
+ drv->ctx, event_buf, event_len);
+ break;
+ case PRIVSEP_EVENT_INTERFACE_STATUS:
+ wpa_driver_privsep_event_interface_status(drv->ctx, event_buf,
+ event_len);
+ break;
+ case PRIVSEP_EVENT_PMKID_CANDIDATE:
+ wpa_driver_privsep_event_pmkid_candidate(drv->ctx, event_buf,
+ event_len);
+ break;
+ case PRIVSEP_EVENT_STKSTART:
+ wpa_driver_privsep_event_stkstart(drv->ctx, event_buf,
+ event_len);
+ break;
+ case PRIVSEP_EVENT_FT_RESPONSE:
+ wpa_driver_privsep_event_ft_response(drv->ctx, event_buf,
+ event_len);
+ break;
+ case PRIVSEP_EVENT_RX_EAPOL:
+ wpa_driver_privsep_event_rx_eapol(drv->ctx, event_buf,
+ event_len);
+ break;
+ case PRIVSEP_EVENT_STA_RX:
+ wpa_driver_privsep_event_sta_rx(drv->ctx, event_buf,
+ event_len);
+ break;
+ }
+
+ os_free(buf);
+}
+
+
+static void * wpa_driver_privsep_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_privsep_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ drv->priv_socket = -1;
+ drv->cmd_socket = -1;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+ return drv;
+}
+
+
+static void wpa_driver_privsep_deinit(void *priv)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+
+ if (drv->priv_socket >= 0) {
+ wpa_priv_reg_cmd(drv, PRIVSEP_CMD_UNREGISTER);
+ eloop_unregister_read_sock(drv->priv_socket);
+ close(drv->priv_socket);
+ }
+
+ if (drv->own_socket_path) {
+ unlink(drv->own_socket_path);
+ os_free(drv->own_socket_path);
+ }
+
+ if (drv->cmd_socket >= 0) {
+ eloop_unregister_read_sock(drv->cmd_socket);
+ close(drv->cmd_socket);
+ }
+
+ if (drv->own_cmd_path) {
+ unlink(drv->own_cmd_path);
+ os_free(drv->own_cmd_path);
+ }
+
+ os_free(drv);
+}
+
+
+static int wpa_driver_privsep_set_param(void *priv, const char *param)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ const char *pos;
+ char *own_dir, *priv_dir;
+ static unsigned int counter = 0;
+ size_t len;
+ struct sockaddr_un addr;
+
+ wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
+ if (param == NULL)
+ pos = NULL;
+ else
+ pos = os_strstr(param, "own_dir=");
+ if (pos) {
+ char *end;
+ own_dir = os_strdup(pos + 8);
+ if (own_dir == NULL)
+ return -1;
+ end = os_strchr(own_dir, ' ');
+ if (end)
+ *end = '\0';
+ } else {
+ own_dir = os_strdup("/tmp");
+ if (own_dir == NULL)
+ return -1;
+ }
+
+ if (param == NULL)
+ pos = NULL;
+ else
+ pos = os_strstr(param, "priv_dir=");
+ if (pos) {
+ char *end;
+ priv_dir = os_strdup(pos + 9);
+ if (priv_dir == NULL) {
+ os_free(own_dir);
+ return -1;
+ }
+ end = os_strchr(priv_dir, ' ');
+ if (end)
+ *end = '\0';
+ } else {
+ priv_dir = os_strdup("/var/run/wpa_priv");
+ if (priv_dir == NULL) {
+ os_free(own_dir);
+ return -1;
+ }
+ }
+
+ len = os_strlen(own_dir) + 50;
+ drv->own_socket_path = os_malloc(len);
+ if (drv->own_socket_path == NULL) {
+ os_free(priv_dir);
+ os_free(own_dir);
+ return -1;
+ }
+ os_snprintf(drv->own_socket_path, len, "%s/wpa_privsep-%d-%d",
+ own_dir, getpid(), counter++);
+
+ len = os_strlen(own_dir) + 50;
+ drv->own_cmd_path = os_malloc(len);
+ if (drv->own_cmd_path == NULL) {
+ os_free(drv->own_socket_path);
+ drv->own_socket_path = NULL;
+ os_free(priv_dir);
+ os_free(own_dir);
+ return -1;
+ }
+ os_snprintf(drv->own_cmd_path, len, "%s/wpa_privsep-%d-%d",
+ own_dir, getpid(), counter++);
+
+ os_free(own_dir);
+
+ drv->priv_addr.sun_family = AF_UNIX;
+ os_snprintf(drv->priv_addr.sun_path, sizeof(drv->priv_addr.sun_path),
+ "%s/%s", priv_dir, drv->ifname);
+ os_free(priv_dir);
+
+ drv->priv_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (drv->priv_socket < 0) {
+ perror("socket(PF_UNIX)");
+ os_free(drv->own_socket_path);
+ drv->own_socket_path = NULL;
+ return -1;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
+ if (bind(drv->priv_socket, (struct sockaddr *) &addr, sizeof(addr)) <
+ 0) {
+ perror("bind(PF_UNIX)");
+ close(drv->priv_socket);
+ drv->priv_socket = -1;
+ unlink(drv->own_socket_path);
+ os_free(drv->own_socket_path);
+ drv->own_socket_path = NULL;
+ return -1;
+ }
+
+ eloop_register_read_sock(drv->priv_socket, wpa_driver_privsep_receive,
+ drv, NULL);
+
+ drv->cmd_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (drv->cmd_socket < 0) {
+ perror("socket(PF_UNIX)");
+ os_free(drv->own_cmd_path);
+ drv->own_cmd_path = NULL;
+ return -1;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_strlcpy(addr.sun_path, drv->own_cmd_path, sizeof(addr.sun_path));
+ if (bind(drv->cmd_socket, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+ {
+ perror("bind(PF_UNIX)");
+ close(drv->cmd_socket);
+ drv->cmd_socket = -1;
+ unlink(drv->own_cmd_path);
+ os_free(drv->own_cmd_path);
+ drv->own_cmd_path = NULL;
+ return -1;
+ }
+
+ if (wpa_priv_reg_cmd(drv, PRIVSEP_CMD_REGISTER) < 0) {
+ wpa_printf(MSG_ERROR, "Failed to register with wpa_priv");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_privsep_get_capa(void *priv,
+ struct wpa_driver_capa *capa)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ int res;
+ size_t len = sizeof(*capa);
+
+ res = wpa_priv_cmd(drv, PRIVSEP_CMD_GET_CAPA, NULL, 0, capa, &len);
+ if (res < 0 || len != sizeof(*capa))
+ return -1;
+ return 0;
+}
+
+
+static const u8 * wpa_driver_privsep_get_mac_addr(void *priv)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ return drv->own_addr;
+}
+
+
+static int wpa_driver_privsep_set_mode(void *priv, int mode)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s mode=%d", __func__, mode);
+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_MODE, &mode, sizeof(mode),
+ NULL, NULL);
+}
+
+
+static int wpa_driver_privsep_set_country(void *priv, const char *alpha2)
+{
+ struct wpa_driver_privsep_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s country='%s'", __func__, alpha2);
+ return wpa_priv_cmd(drv, PRIVSEP_CMD_SET_COUNTRY, alpha2,
+ os_strlen(alpha2), NULL, NULL);
+}
+
+
+struct wpa_driver_ops wpa_driver_privsep_ops = {
+ "privsep",
+ "wpa_supplicant privilege separated driver",
+ wpa_driver_privsep_get_bssid,
+ wpa_driver_privsep_get_ssid,
+ wpa_driver_privsep_set_wpa,
+ wpa_driver_privsep_set_key,
+ wpa_driver_privsep_init,
+ wpa_driver_privsep_deinit,
+ wpa_driver_privsep_set_param,
+ NULL /* set_countermeasures */,
+ NULL /* set_drop_unencrypted */,
+ wpa_driver_privsep_scan,
+ NULL /* get_scan_results */,
+ wpa_driver_privsep_deauthenticate,
+ wpa_driver_privsep_disassociate,
+ wpa_driver_privsep_associate,
+ NULL /* set_auth_alg */,
+ NULL /* add_pmkid */,
+ NULL /* remove_pmkid */,
+ NULL /* flush_pmkid */,
+ wpa_driver_privsep_get_capa,
+ NULL /* poll */,
+ NULL /* get_ifname */,
+ wpa_driver_privsep_get_mac_addr,
+ NULL /* send_eapol */,
+ NULL /* set_operstate */,
+ NULL /* mlme_setprotection */,
+ NULL /* get_hw_feature_data */,
+ NULL /* set_channel */,
+ NULL /* set_ssid */,
+ NULL /* set_bssid */,
+ NULL /* send_mlme */,
+ NULL /* mlme_add_sta */,
+ NULL /* mlme_remove_sta */,
+ NULL /* update_ft_ies */,
+ NULL /* send_ft_action */,
+ wpa_driver_privsep_get_scan_results2,
+ NULL /* set_probe_req_ie */,
+ wpa_driver_privsep_set_mode,
+ wpa_driver_privsep_set_country,
+ NULL /* global_init */,
+ NULL /* global_deinit */,
+ NULL /* init2 */,
+ NULL /* get_interfaces */
+};
+
+
+struct wpa_driver_ops *wpa_supplicant_drivers[] =
+{
+ &wpa_driver_privsep_ops,
+ NULL
+};
diff --git a/src/drivers/driver_ps3.c b/src/drivers/driver_ps3.c
new file mode 100644
index 0000000..fde3425
--- /dev/null
+++ b/src/drivers/driver_ps3.c
@@ -0,0 +1,186 @@
+/*
+ * WPA Supplicant - PS3 Linux wireless extension driver interface
+ * Copyright 2007, 2008 Sony Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include "wireless_copy.h"
+#include "common.h"
+#include "wpa_common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "driver_wext.h"
+#include "ieee802_11_defs.h"
+
+static int wpa_driver_ps3_set_wpa_key(struct wpa_driver_wext_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ int ret, i;
+ struct iwreq iwr;
+ char *buf, *str;
+
+ if (!params->psk && !params->passphrase) {
+ wpa_printf(MSG_INFO, "%s:no PSK error", __func__);
+ return -EINVAL;
+ }
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ if (params->psk) {
+ /* includes null */
+ iwr.u.data.length = PMK_LEN * 2 + 1;
+ buf = os_malloc(iwr.u.data.length);
+ if (!buf)
+ return -ENOMEM;
+ str = buf;
+ for (i = 0; i < PMK_LEN; i++) {
+ str += snprintf(str, iwr.u.data.length - (str - buf),
+ "%02x", params->psk[i]);
+ }
+ } else if (params->passphrase) {
+ /* including quotations and null */
+ iwr.u.data.length = strlen(params->passphrase) + 3;
+ buf = os_malloc(iwr.u.data.length);
+ if (!buf)
+ return -ENOMEM;
+ buf[0] = '"';
+ os_memcpy(buf + 1, params->passphrase, iwr.u.data.length - 3);
+ buf[iwr.u.data.length - 2] = '"';
+ buf[iwr.u.data.length - 1] = '\0';
+ } else
+ return -EINVAL;
+ iwr.u.data.pointer = (caddr_t) buf;
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ ret = ioctl(drv->ioctl_sock, SIOCIWFIRSTPRIV, &iwr);
+ os_free(buf);
+
+ return ret;
+}
+
+static int wpa_driver_ps3_set_wep_keys(struct wpa_driver_wext_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ int ret, i;
+ struct iwreq iwr;
+
+ for (i = 0; i < 4; i++) {
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.encoding.flags = i + 1;
+ if (params->wep_key_len[i]) {
+ iwr.u.encoding.pointer = (caddr_t) params->wep_key[i];
+ iwr.u.encoding.length = params->wep_key_len[i];
+ } else
+ iwr.u.encoding.flags = IW_ENCODE_NOKEY |
+ IW_ENCODE_DISABLED;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWENCODE]");
+ ret = -1;
+ }
+ }
+ return ret;
+}
+
+static int wpa_driver_ps3_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int ret, value;
+
+ wpa_printf(MSG_DEBUG, "%s: <-", __func__);
+
+ /* clear BSSID */
+ if (!params->bssid &&
+ wpa_driver_wext_set_bssid(drv, NULL) < 0)
+ ret = -1;
+
+ if (wpa_driver_wext_set_mode(drv, params->mode) < 0)
+ ret = -1;
+
+ if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
+ value = IW_AUTH_WPA_VERSION_DISABLED;
+ else if (params->wpa_ie[0] == WLAN_EID_RSN)
+ value = IW_AUTH_WPA_VERSION_WPA2;
+ else
+ value = IW_AUTH_WPA_VERSION_WPA;
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_WPA_VERSION, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_CIPHER_PAIRWISE, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_cipher2wext(params->group_suite);
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_CIPHER_GROUP, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
+ if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_KEY_MGMT, value) < 0)
+ ret = -1;
+
+ /* set selected BSSID */
+ if (params->bssid &&
+ wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
+ ret = -1;
+
+ switch (params->group_suite) {
+ case CIPHER_NONE:
+ ret = 0;
+ break;
+ case CIPHER_WEP40:
+ case CIPHER_WEP104:
+ ret = wpa_driver_ps3_set_wep_keys(drv, params);
+ break;
+ case CIPHER_TKIP:
+ case CIPHER_CCMP:
+ ret = wpa_driver_ps3_set_wpa_key(drv, params);
+ break;
+ }
+
+ /* start to associate */
+ ret = wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len);
+
+ wpa_printf(MSG_DEBUG, "%s: ->", __func__);
+
+ return ret;
+}
+
+static int wpa_driver_ps3_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ int ret;
+ wpa_printf(MSG_DEBUG, "%s:<-", __func__);
+
+ ret = wpa_driver_wext_get_capa(priv, capa);
+ if (ret) {
+ wpa_printf(MSG_INFO, "%s: base wext returns error %d",
+ __func__, ret);
+ return ret;
+ }
+ /* PS3 hypervisor does association and 4way handshake by itself */
+ capa->flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+ wpa_printf(MSG_DEBUG, "%s:->", __func__);
+ return 0;
+}
+
+const struct wpa_driver_ops wpa_driver_ps3_ops = {
+ .name = "ps3",
+ .desc = "PLAYSTATION3 Linux wireless extension driver",
+ .get_bssid = wpa_driver_wext_get_bssid,
+ .get_ssid = wpa_driver_wext_get_ssid,
+ .scan = wpa_driver_wext_scan,
+ .get_scan_results2 = wpa_driver_wext_get_scan_results,
+ .associate = wpa_driver_ps3_associate, /* PS3 */
+ .init = wpa_driver_wext_init,
+ .deinit = wpa_driver_wext_deinit,
+ .get_capa = wpa_driver_ps3_get_capa, /* PS3 */
+};
diff --git a/src/drivers/driver_ralink.c b/src/drivers/driver_ralink.c
new file mode 100644
index 0000000..e9313cb
--- /dev/null
+++ b/src/drivers/driver_ralink.c
@@ -0,0 +1,1505 @@
+/*
+ * WPA Supplicant - driver interaction with Ralink Wireless Client
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "l2_packet/l2_packet.h"
+#include "eloop.h"
+#include "ieee802_11_defs.h"
+#include "priv_netlink.h"
+#include "driver_ralink.h"
+
+static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx);
+
+#define MAX_SSID_LEN 32
+
+struct wpa_driver_ralink_data {
+ void *ctx;
+ int ioctl_sock;
+ int event_sock;
+ char ifname[IFNAMSIZ + 1];
+ u8 *assoc_req_ies;
+ size_t assoc_req_ies_len;
+ u8 *assoc_resp_ies;
+ size_t assoc_resp_ies_len;
+ int no_of_pmkid;
+ struct ndis_pmkid_entry *pmkid;
+ int we_version_compiled;
+ int ap_scan;
+ int scanning_done;
+ u8 g_driver_down;
+};
+
+static int ralink_set_oid(struct wpa_driver_ralink_data *drv,
+ unsigned short oid, char *data, int len)
+{
+ char *buf;
+ struct iwreq iwr;
+
+ buf = os_zalloc(len);
+ if (buf == NULL)
+ return -1;
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.flags = oid;
+ iwr.u.data.flags |= OID_GET_SET_TOGGLE;
+
+ if (data)
+ os_memcpy(buf, data, len);
+
+ iwr.u.data.pointer = (caddr_t) buf;
+ iwr.u.data.length = len;
+
+ if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: oid=0x%x len (%d) failed",
+ __func__, oid, len);
+ os_free(buf);
+ return -1;
+ }
+ os_free(buf);
+ return 0;
+}
+
+static int
+ralink_get_new_driver_flag(struct wpa_driver_ralink_data *drv)
+{
+ struct iwreq iwr;
+ UCHAR enabled = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (UCHAR*) &enabled;
+ iwr.u.data.flags = RT_OID_NEW_DRIVER;
+
+ if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed", __func__);
+ return 0;
+ }
+
+ return (enabled == 1) ? 1 : 0;
+}
+
+static int wpa_driver_ralink_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ if (drv->g_driver_down == 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
+ perror("ioctl[SIOCGIWAP]");
+ ret = -1;
+ }
+ os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
+
+ return ret;
+}
+
+static int wpa_driver_ralink_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+#if 0
+ struct wpa_supplicant *wpa_s = drv->ctx;
+ struct wpa_ssid *entry;
+#endif
+ int ssid_len;
+ u8 bssid[ETH_ALEN];
+ u8 ssid_str[MAX_SSID_LEN];
+ struct iwreq iwr;
+#if 0
+ int result = 0;
+#endif
+ int ret = 0;
+#if 0
+ BOOLEAN ieee8021x_mode = FALSE;
+ BOOLEAN ieee8021x_required_key = FALSE;
+#endif
+
+ if (drv->g_driver_down == 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.essid.pointer = (caddr_t) ssid;
+ iwr.u.essid.length = 32;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCGIWESSID]");
+ ret = -1;
+ } else
+ ret = iwr.u.essid.length;
+
+ if (ret <= 0)
+ return ret;
+
+ ssid_len = ret;
+ os_memset(ssid_str, 0, MAX_SSID_LEN);
+ os_memcpy(ssid_str, ssid, ssid_len);
+
+ if (drv->ap_scan == 0) {
+ /* Read BSSID form driver */
+ if (wpa_driver_ralink_get_bssid(priv, bssid) < 0) {
+ wpa_printf(MSG_WARNING, "Could not read BSSID from "
+ "driver.");
+ return ret;
+ }
+
+#if 0
+ entry = wpa_s->conf->ssid;
+ while (entry) {
+ if (!entry->disabled && ssid_len == entry->ssid_len &&
+ os_memcmp(ssid_str, entry->ssid, ssid_len) == 0 &&
+ (!entry->bssid_set ||
+ os_memcmp(bssid, entry->bssid, ETH_ALEN) == 0)) {
+ /* match the config of driver */
+ result = 1;
+ break;
+ }
+ entry = entry->next;
+ }
+
+ if (result) {
+ wpa_printf(MSG_DEBUG, "Ready to set 802.1x mode and "
+ "ieee_required_keys parameters to driver");
+
+ /* set 802.1x mode and ieee_required_keys parameter */
+ if (entry->key_mgmt == WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+ if ((entry->eapol_flags & (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST)))
+ ieee8021x_required_key = TRUE;
+ ieee8021x_mode = TRUE;
+ }
+
+ if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X, (char *) &ieee8021x_mode, sizeof(BOOLEAN)) < 0)
+ {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set OID_802_11_SET_IEEE8021X(%d)", (int) ieee8021x_mode);
+ }
+ else
+ {
+ wpa_printf(MSG_DEBUG, "ieee8021x_mode is %s", ieee8021x_mode ? "TRUE" : "FALSE");
+ }
+
+ if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, (char *) &ieee8021x_required_key, sizeof(BOOLEAN)) < 0)
+ {
+ wpa_printf(MSG_DEBUG, "ERROR: Failed to set OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)", (int) ieee8021x_required_key);
+ }
+ else
+ {
+ wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s and eapol_flag(%d)", ieee8021x_required_key ? "TRUE" : "FALSE",
+ entry->eapol_flags);
+ }
+ }
+#endif
+ }
+
+ return ret;
+}
+
+static int wpa_driver_ralink_set_ssid(struct wpa_driver_ralink_data *drv,
+ const u8 *ssid, size_t ssid_len)
+{
+ NDIS_802_11_SSID *buf;
+ int ret = 0;
+ struct iwreq iwr;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ buf = os_zalloc(sizeof(NDIS_802_11_SSID));
+ if (buf == NULL)
+ return -1;
+ os_memset(buf, 0, sizeof(buf));
+ buf->SsidLength = ssid_len;
+ os_memcpy(buf->Ssid, ssid, ssid_len);
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ iwr.u.data.flags = OID_802_11_SSID;
+ iwr.u.data.flags |= OID_GET_SET_TOGGLE;
+ iwr.u.data.pointer = (caddr_t) buf;
+ iwr.u.data.length = sizeof(NDIS_802_11_SSID);
+
+ if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
+ perror("ioctl[RT_PRIV_IOCTL] -- OID_802_11_SSID");
+ ret = -1;
+ }
+ os_free(buf);
+ return ret;
+}
+
+static void wpa_driver_ralink_event_pmkid(struct wpa_driver_ralink_data *drv,
+ const u8 *data, size_t data_len)
+{
+ NDIS_802_11_PMKID_CANDIDATE_LIST *pmkid;
+ size_t i;
+ union wpa_event_data event;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (data_len < 8) {
+ wpa_printf(MSG_DEBUG, "RALINK: Too short PMKID Candidate List "
+ "Event (len=%lu)", (unsigned long) data_len);
+ return;
+ }
+ pmkid = (NDIS_802_11_PMKID_CANDIDATE_LIST *) data;
+ wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List Event - Version %d"
+ " NumCandidates %d",
+ (int) pmkid->Version, (int) pmkid->NumCandidates);
+
+ if (pmkid->Version != 1) {
+ wpa_printf(MSG_DEBUG, "RALINK: Unsupported PMKID Candidate "
+ "List Version %d", (int) pmkid->Version);
+ return;
+ }
+
+ if (data_len < 8 + pmkid->NumCandidates * sizeof(PMKID_CANDIDATE)) {
+ wpa_printf(MSG_DEBUG, "RALINK: PMKID Candidate List "
+ "underflow");
+
+ return;
+ }
+
+
+
+ os_memset(&event, 0, sizeof(event));
+ for (i = 0; i < pmkid->NumCandidates; i++) {
+ PMKID_CANDIDATE *p = &pmkid->CandidateList[i];
+ wpa_printf(MSG_DEBUG, "RALINK: %lu: " MACSTR " Flags 0x%x",
+ (unsigned long) i, MAC2STR(p->BSSID),
+ (int) p->Flags);
+ os_memcpy(event.pmkid_candidate.bssid, p->BSSID, ETH_ALEN);
+ event.pmkid_candidate.index = i;
+ event.pmkid_candidate.preauth =
+ p->Flags & NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED;
+ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE,
+ &event);
+ }
+}
+
+static int wpa_driver_ralink_set_pmkid(struct wpa_driver_ralink_data *drv)
+{
+ int len, count, i, ret;
+ struct ndis_pmkid_entry *entry;
+ NDIS_802_11_PMKID *p;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ count = 0;
+ entry = drv->pmkid;
+ while (entry) {
+ count++;
+ if (count >= drv->no_of_pmkid)
+ break;
+ entry = entry->next;
+ }
+ len = 8 + count * sizeof(BSSID_INFO);
+ p = os_zalloc(len);
+ if (p == NULL)
+ return -1;
+ p->Length = len;
+ p->BSSIDInfoCount = count;
+ entry = drv->pmkid;
+ for (i = 0; i < count; i++) {
+ os_memcpy(&p->BSSIDInfo[i].BSSID, entry->bssid, ETH_ALEN);
+ os_memcpy(&p->BSSIDInfo[i].PMKID, entry->pmkid, 16);
+ entry = entry->next;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID",
+ (const u8 *) p, len);
+ ret = ralink_set_oid(drv, OID_802_11_PMKID, (char *) p, len);
+ os_free(p);
+ return ret;
+}
+
+static int wpa_driver_ralink_add_pmkid(void *priv, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ struct ndis_pmkid_entry *entry, *prev;
+
+ if (drv->g_driver_down == 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (drv->no_of_pmkid == 0)
+ return 0;
+
+ prev = NULL;
+ entry = drv->pmkid;
+ while (entry) {
+ if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0)
+ break;
+ prev = entry;
+ entry = entry->next;
+ }
+
+ if (entry) {
+ /* Replace existing entry for this BSSID and move it into the
+ * beginning of the list. */
+ os_memcpy(entry->pmkid, pmkid, 16);
+ if (prev) {
+ prev->next = entry->next;
+ entry->next = drv->pmkid;
+ drv->pmkid = entry;
+ }
+ } else {
+ entry = os_malloc(sizeof(*entry));
+ if (entry) {
+ os_memcpy(entry->bssid, bssid, ETH_ALEN);
+ os_memcpy(entry->pmkid, pmkid, 16);
+ entry->next = drv->pmkid;
+ drv->pmkid = entry;
+ }
+ }
+
+ return wpa_driver_ralink_set_pmkid(drv);
+}
+
+
+static int wpa_driver_ralink_remove_pmkid(void *priv, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ struct ndis_pmkid_entry *entry, *prev;
+
+ if (drv->g_driver_down == 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (drv->no_of_pmkid == 0)
+ return 0;
+
+ entry = drv->pmkid;
+ prev = NULL;
+ drv->pmkid = NULL;
+ while (entry) {
+ if (os_memcmp(entry->bssid, bssid, ETH_ALEN) == 0 &&
+ os_memcmp(entry->pmkid, pmkid, 16) == 0) {
+ if (prev)
+ prev->next = entry->next;
+ else
+ drv->pmkid = entry->next;
+ os_free(entry);
+ break;
+ }
+ prev = entry;
+ entry = entry->next;
+ }
+ return wpa_driver_ralink_set_pmkid(drv);
+}
+
+
+static int wpa_driver_ralink_flush_pmkid(void *priv)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ NDIS_802_11_PMKID p;
+ struct ndis_pmkid_entry *pmkid, *prev;
+
+ if (drv->g_driver_down == 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (drv->no_of_pmkid == 0)
+ return 0;
+
+ pmkid = drv->pmkid;
+ drv->pmkid = NULL;
+ while (pmkid) {
+ prev = pmkid;
+ pmkid = pmkid->next;
+ os_free(prev);
+ }
+
+ os_memset(&p, 0, sizeof(p));
+ p.Length = 8;
+ p.BSSIDInfoCount = 0;
+ wpa_hexdump(MSG_MSGDUMP, "NDIS: OID_802_11_PMKID (flush)",
+ (const u8 *) &p, 8);
+ return ralink_set_oid(drv, OID_802_11_PMKID, (char *) &p, 8);
+}
+
+static void
+wpa_driver_ralink_event_wireless_custom(struct wpa_driver_ralink_data *drv,
+ void *ctx, char *custom)
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ wpa_printf(MSG_DEBUG, "Custom wireless event: '%s'", custom);
+
+ os_memset(&data, 0, sizeof(data));
+ /* Host AP driver */
+ if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ /* receive a MICFAILURE report */
+ data.michael_mic_failure.unicast =
+ os_strstr(custom, " unicast") != NULL;
+ /* TODO: parse parameters(?) */
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+ } else if (os_strncmp(custom, "ASSOCINFO_ReqIEs=", 17) == 0) {
+ /* receive assoc. req. IEs */
+ char *spos;
+ int bytes;
+
+ spos = custom + 17;
+ /*get IE's length */
+ /*
+ * bytes = strlen(spos); ==> bug, bytes may less than original
+ * size by using this way to get size. snowpin 20070312
+ * if (!bytes)
+ * return;
+ */
+ bytes = drv->assoc_req_ies_len;
+
+ data.assoc_info.req_ies = os_malloc(bytes);
+ if (data.assoc_info.req_ies == NULL)
+ return;
+
+ data.assoc_info.req_ies_len = bytes;
+ os_memcpy(data.assoc_info.req_ies, spos, bytes);
+
+ /* skip the '\0' byte */
+ spos += bytes + 1;
+
+ data.assoc_info.resp_ies = NULL;
+ data.assoc_info.resp_ies_len = 0;
+
+ if (os_strncmp(spos, " RespIEs=", 9) == 0) {
+ /* receive assoc. resp. IEs */
+ spos += 9;
+ /* get IE's length */
+ bytes = os_strlen(spos);
+ if (!bytes)
+ goto done;
+
+
+ data.assoc_info.resp_ies = os_malloc(bytes);
+ if (data.assoc_info.resp_ies == NULL)
+ goto done;
+
+ data.assoc_info.resp_ies_len = bytes;
+ os_memcpy(data.assoc_info.resp_ies, spos, bytes);
+ }
+
+ wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
+
+ /* free allocated memory */
+ done:
+ os_free(data.assoc_info.resp_ies);
+ os_free(data.assoc_info.req_ies);
+ }
+}
+
+static void
+wpa_driver_ralink_event_wireless(struct wpa_driver_ralink_data *drv,
+ void *ctx, char *data, int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf, *assoc_info_buf, *info_pos;
+#if 0
+ BOOLEAN ieee8021x_required_key = FALSE;
+#endif
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ assoc_info_buf = info_pos = NULL;
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
+ iwe->cmd, iwe->len);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ return;
+
+ custom = pos + IW_EV_POINT_LEN;
+
+ if (drv->we_version_compiled > 18 && iwe->cmd == IWEVCUSTOM) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case IWEVCUSTOM:
+ if (custom + iwe->u.data.length > end)
+ return;
+ buf = os_malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return;
+ os_memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+
+ if (drv->ap_scan == 1) {
+ if ((iwe->u.data.flags == RT_ASSOC_EVENT_FLAG)
+ || (iwe->u.data.flags ==
+ RT_REQIE_EVENT_FLAG) ||
+ (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG)
+ || (iwe->u.data.flags ==
+ RT_ASSOCINFO_EVENT_FLAG)) {
+ if (drv->scanning_done == 0) {
+ os_free(buf);
+ return;
+ }
+ }
+ }
+
+ if (iwe->u.data.flags == RT_ASSOC_EVENT_FLAG) {
+ wpa_printf(MSG_DEBUG, "Custom wireless event: "
+ "receive ASSOCIATED_EVENT !!!");
+ /* determine whether the dynamic-WEP is used or
+ * not */
+#if 0
+ if (wpa_s && wpa_s->current_ssid &&
+ wpa_s->current_ssid->key_mgmt ==
+ WPA_KEY_MGMT_IEEE8021X_NO_WPA) {
+ if ((wpa_s->current_ssid->eapol_flags &
+ (EAPOL_FLAG_REQUIRE_KEY_UNICAST | EAPOL_FLAG_REQUIRE_KEY_BROADCAST))) {
+ //wpa_printf(MSG_DEBUG, "The current ssid - (%s), eapol_flag = %d.\n",
+ // wpa_ssid_txt(wpa_s->current_ssid->ssid, wpa_s->current_ssid->ssid_len),wpa_s->current_ssid->eapol_flags);
+ ieee8021x_required_key = TRUE;
+ }
+
+ if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X_REQUIRE_KEY, (char *) &ieee8021x_required_key, sizeof(BOOLEAN)) < 0)
+ {
+ wpa_printf(MSG_DEBUG, "ERROR: Failed to set OID_802_11_SET_IEEE8021X_REQUIRE_KEY(%d)",
+ (int) ieee8021x_required_key);
+ }
+
+ wpa_printf(MSG_DEBUG, "ieee8021x_required_key is %s and eapol_flag(%d).\n", ieee8021x_required_key ? "TRUE" : "FALSE",
+ wpa_s->current_ssid->eapol_flags);
+ }
+#endif
+
+ wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+ } else if (iwe->u.data.flags == RT_REQIE_EVENT_FLAG) {
+ wpa_printf(MSG_DEBUG, "Custom wireless event: "
+ "receive ReqIEs !!!");
+ drv->assoc_req_ies =
+ os_malloc(iwe->u.data.length);
+ if (drv->assoc_req_ies == NULL) {
+ os_free(buf);
+ return;
+ }
+
+ drv->assoc_req_ies_len = iwe->u.data.length;
+ os_memcpy(drv->assoc_req_ies, custom,
+ iwe->u.data.length);
+ } else if (iwe->u.data.flags == RT_RESPIE_EVENT_FLAG) {
+ wpa_printf(MSG_DEBUG, "Custom wireless event: "
+ "receive RespIEs !!!");
+ drv->assoc_resp_ies =
+ os_malloc(iwe->u.data.length);
+ if (drv->assoc_resp_ies == NULL) {
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = NULL;
+ os_free(buf);
+ return;
+ }
+
+ drv->assoc_resp_ies_len = iwe->u.data.length;
+ os_memcpy(drv->assoc_resp_ies, custom,
+ iwe->u.data.length);
+ } else if (iwe->u.data.flags ==
+ RT_ASSOCINFO_EVENT_FLAG) {
+ wpa_printf(MSG_DEBUG, "Custom wireless event: "
+ "receive ASSOCINFO_EVENT !!!");
+
+ assoc_info_buf =
+ os_zalloc(drv->assoc_req_ies_len +
+ drv->assoc_resp_ies_len + 1);
+
+ if (assoc_info_buf == NULL) {
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = NULL;
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = NULL;
+ os_free(buf);
+ return;
+ }
+
+ if (drv->assoc_req_ies) {
+ os_memcpy(assoc_info_buf,
+ drv->assoc_req_ies,
+ drv->assoc_req_ies_len);
+ }
+ info_pos = assoc_info_buf +
+ drv->assoc_req_ies_len;
+ if (drv->assoc_resp_ies) {
+ os_memcpy(info_pos,
+ drv->assoc_resp_ies,
+ drv->assoc_resp_ies_len);
+ }
+ assoc_info_buf[drv->assoc_req_ies_len +
+ drv->assoc_resp_ies_len] = '\0';
+ wpa_driver_ralink_event_wireless_custom(
+ drv, ctx, assoc_info_buf);
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = NULL;
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = NULL;
+ os_free(assoc_info_buf);
+ } else if (iwe->u.data.flags == RT_DISASSOC_EVENT_FLAG)
+ {
+ wpa_printf(MSG_DEBUG, "Custom wireless event: "
+ "receive DISASSOCIATED_EVENT !!!");
+ wpa_supplicant_event(ctx, EVENT_DISASSOC,
+ NULL);
+ } else if (iwe->u.data.flags == RT_PMKIDCAND_FLAG) {
+ wpa_printf(MSG_DEBUG, "Custom wireless event: "
+ "receive PMKIDCAND_EVENT !!!");
+ wpa_driver_ralink_event_pmkid(
+ drv, (const u8 *) custom,
+ iwe->u.data.length);
+ } else if (iwe->u.data.flags == RT_INTERFACE_DOWN) {
+ drv->g_driver_down = 1;
+ eloop_terminate();
+ } else if (iwe->u.data.flags == RT_REPORT_AP_INFO) {
+ if (drv->ap_scan != 1) {
+ typedef struct PACKED {
+ UCHAR bssid[MAC_ADDR_LEN];
+ UCHAR ssid[MAX_LEN_OF_SSID];
+ INT ssid_len;
+ UCHAR wpa_ie[40];
+ INT wpa_ie_len;
+ UCHAR rsn_ie[40];
+ INT rsn_ie_len;
+ INT freq;
+ USHORT caps;
+ } *PAPINFO;
+
+ wpa_printf(MSG_DEBUG, "Custom wireless"
+ " event: receive "
+ "RT_REPORT_AP_INFO !!!");
+ //printf("iwe->u.data.length = %d\n", iwe->u.data.length);
+ //wpa_hexdump(MSG_DEBUG, "AP_Info: ", buf, iwe->u.data.length);
+#if 0
+ wpa_s->num_scan_results = 1;
+ if (wpa_s->scan_results)
+ os_free(wpa_s->scan_results);
+ wpa_s->scan_results = os_malloc(sizeof(struct wpa_scan_result) + 1);
+ if (wpa_s->scan_results) {
+ PAPINFO pApInfo = (PAPINFO)buf;
+ os_memcpy(wpa_s->scan_results[0].bssid, pApInfo->bssid, ETH_ALEN);
+ os_memcpy(wpa_s->scan_results[0].ssid, pApInfo->ssid, pApInfo->ssid_len);
+ wpa_s->scan_results[0].ssid_len = pApInfo->ssid_len;
+ if (pApInfo->wpa_ie_len > 0) {
+ os_memcpy(wpa_s->scan_results[0].wpa_ie, pApInfo->wpa_ie, pApInfo->wpa_ie_len);
+ wpa_s->scan_results[0].wpa_ie_len = pApInfo->wpa_ie_len;
+ } else if (pApInfo->rsn_ie_len > 0) {
+ os_memcpy(wpa_s->scan_results[0].rsn_ie, pApInfo->rsn_ie, pApInfo->rsn_ie_len);
+ wpa_s->scan_results[0].rsn_ie_len = pApInfo->rsn_ie_len;
+ }
+ wpa_s->scan_results[0].caps = pApInfo->caps;
+ wpa_s->scan_results[0].freq = pApInfo->freq;
+ } else {
+ wpa_printf("wpa_s->scan_"
+ "results fail to "
+ "os_malloc!!\n");
+ }
+#endif
+ }
+ } else {
+ wpa_driver_ralink_event_wireless_custom(
+ drv, ctx, buf);
+ }
+ os_free(buf);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+static void
+wpa_driver_ralink_event_rtm_newlink(struct wpa_driver_ralink_data *drv,
+ void *ctx, struct nlmsghdr *h, int len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (len < (int) sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+ wpa_hexdump(MSG_DEBUG, "ifi: ", (u8 *) ifi, sizeof(struct ifinfomsg));
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ wpa_printf(MSG_DEBUG, "attrlen=%d", attrlen);
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+ wpa_hexdump(MSG_DEBUG, "attr1: ", (u8 *) attr, sizeof(struct rtattr));
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ wpa_hexdump(MSG_DEBUG, "attr2: ", (u8 *)attr,rta_len);
+ while (RTA_OK(attr, attrlen)) {
+ wpa_printf(MSG_DEBUG, "rta_type=%02x\n", attr->rta_type);
+ if (attr->rta_type == IFLA_WIRELESS) {
+ wpa_driver_ralink_event_wireless(
+ drv, ctx,
+ ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ wpa_hexdump(MSG_DEBUG, "attr3: ",
+ (u8 *) attr, sizeof(struct rtattr));
+ }
+}
+
+static void wpa_driver_ralink_event_receive(int sock, void *ctx,
+ void *sock_ctx)
+{
+ char buf[8192];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("recvfrom(netlink)");
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ wpa_hexdump(MSG_DEBUG, "h: ", (u8 *)h, h->nlmsg_len);
+
+ while (left >= (int) sizeof(*h)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ wpa_printf(MSG_DEBUG, "Malformed netlink message: "
+ "len=%d left=%d plen=%d", len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ wpa_driver_ralink_event_rtm_newlink(ctx, sock_ctx, h,
+ plen);
+ break;
+ }
+
+ len = NLMSG_ALIGN(len);
+ left -= len;
+ h = (struct nlmsghdr *) ((char *) h + len);
+ }
+
+ if (left > 0) {
+ wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink "
+ "message", left);
+ }
+
+}
+
+static int
+ralink_get_we_version_compiled(struct wpa_driver_ralink_data *drv)
+{
+ struct iwreq iwr;
+ UINT we_version_compiled = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) &we_version_compiled;
+ iwr.u.data.flags = RT_OID_WE_VERSION_COMPILED;
+
+ if (ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: failed", __func__);
+ return -1;
+ }
+
+ drv->we_version_compiled = we_version_compiled;
+
+ return 0;
+}
+
+static int
+ralink_set_iface_flags(void *priv, int dev_up)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ struct ifreq ifr;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (drv->ioctl_sock < 0)
+ return -1;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_snprintf(ifr.ifr_name, IFNAMSIZ, "%s", drv->ifname);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ return -1;
+ }
+
+ if (dev_up)
+ ifr.ifr_flags |= IFF_UP;
+ else
+ ifr.ifr_flags &= ~IFF_UP;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, &ifr) != 0) {
+ perror("ioctl[SIOCSIFFLAGS]");
+ return -1;
+ }
+
+ return 0;
+}
+
+static void * wpa_driver_ralink_init(void *ctx, const char *ifname)
+{
+ int s;
+ struct wpa_driver_ralink_data *drv;
+ struct ifreq ifr;
+ struct sockaddr_nl local;
+ UCHAR enable_wpa_supplicant = 0;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ /* open socket to kernel */
+ if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+ perror("socket");
+ return NULL;
+ }
+ /* do it */
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+
+ if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) {
+ perror(ifr.ifr_name);
+ return NULL;
+ }
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+
+ drv->scanning_done = 1;
+ drv->ap_scan = 1; /* for now - let's assume ap_scan=1 is used */
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->ioctl_sock = s;
+ drv->g_driver_down = 0;
+
+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (s < 0) {
+ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+ close(drv->ioctl_sock);
+ os_free(drv);
+ return NULL;
+ }
+
+ os_memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+
+ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ perror("bind(netlink)");
+ close(s);
+ close(drv->ioctl_sock);
+ os_free(drv);
+ return NULL;
+ }
+
+ eloop_register_read_sock(s, wpa_driver_ralink_event_receive, drv, ctx);
+ drv->event_sock = s;
+ drv->no_of_pmkid = 4; /* Number of PMKID saved supported */
+
+ ralink_set_iface_flags(drv, 1); /* mark up during setup */
+ ralink_get_we_version_compiled(drv);
+ wpa_driver_ralink_flush_pmkid(drv);
+
+ if (drv->ap_scan == 1)
+ enable_wpa_supplicant = 1;
+ else
+ enable_wpa_supplicant = 2;
+ /* trigger driver support wpa_supplicant */
+ if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
+ (PCHAR) &enable_wpa_supplicant, sizeof(UCHAR)) < 0)
+ {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+ "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
+ (int) enable_wpa_supplicant);
+ wpa_printf(MSG_ERROR, "RALINK: Driver does not support "
+ "wpa_supplicant");
+ close(s);
+ close(drv->ioctl_sock);
+ os_free(drv);
+ return NULL;
+ }
+
+ if (drv->ap_scan == 1)
+ drv->scanning_done = 0;
+
+ return drv;
+}
+
+static void wpa_driver_ralink_deinit(void *priv)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ UCHAR enable_wpa_supplicant;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ enable_wpa_supplicant = 0;
+
+ if (drv->g_driver_down == 0) {
+ /* trigger driver disable wpa_supplicant support */
+ if (ralink_set_oid(drv, RT_OID_WPA_SUPPLICANT_SUPPORT,
+ (char *) &enable_wpa_supplicant,
+ sizeof(BOOLEAN)) < 0) {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+ "RT_OID_WPA_SUPPLICANT_SUPPORT(%d)",
+ (int) enable_wpa_supplicant);
+ }
+
+ wpa_driver_ralink_flush_pmkid(drv);
+
+ sleep(1);
+ ralink_set_iface_flags(drv, 0);
+ }
+
+ eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx);
+ eloop_unregister_read_sock(drv->event_sock);
+ close(drv->event_sock);
+ close(drv->ioctl_sock);
+ os_free(drv);
+}
+
+static void wpa_driver_ralink_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_driver_ralink_data *drv = eloop_ctx;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+
+ drv->scanning_done = 1;
+
+}
+
+static int wpa_driver_ralink_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ if (drv->g_driver_down == 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (ssid_len > IW_ESSID_MAX_SIZE) {
+ wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
+ __FUNCTION__, (unsigned long) ssid_len);
+ return -1;
+ }
+
+ /* wpa_driver_ralink_set_ssid(drv, ssid, ssid_len); */
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
+ perror("ioctl[SIOCSIWSCAN]");
+ ret = -1;
+ }
+
+ /* Not all drivers generate "scan completed" wireless event, so try to
+ * read results after a timeout. */
+ eloop_cancel_timeout(wpa_driver_ralink_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(4, 0, wpa_driver_ralink_scan_timeout, drv,
+ drv->ctx);
+
+ drv->scanning_done = 0;
+
+ return ret;
+}
+
+static int
+wpa_driver_ralink_get_scan_results(void *priv,
+ struct wpa_scan_result *results,
+ size_t max_size)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ UCHAR *buf = NULL;
+ NDIS_802_11_BSSID_LIST_EX *wsr;
+ NDIS_WLAN_BSSID_EX *wbi;
+ struct iwreq iwr;
+ int rv = 0;
+ size_t ap_num;
+ u8 *pos, *end;
+
+ if (drv->g_driver_down == 1)
+ return -1;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (drv->we_version_compiled >= 17) {
+ buf = os_zalloc(8192);
+ iwr.u.data.length = 8192;
+ } else {
+ buf = os_zalloc(4096);
+ iwr.u.data.length = 4096;
+ }
+ if (buf == NULL)
+ return -1;
+
+ wsr = (NDIS_802_11_BSSID_LIST_EX *) buf;
+
+ wsr->NumberOfItems = 0;
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (void *) buf;
+ iwr.u.data.flags = OID_802_11_BSSID_LIST;
+
+ if ((rv = ioctl(drv->ioctl_sock, RT_PRIV_IOCTL, &iwr)) < 0) {
+ wpa_printf(MSG_DEBUG, "ioctl fail: rv = %d", rv);
+ os_free(buf);
+ return -1;
+ }
+
+ os_memset(results, 0, max_size * sizeof(struct wpa_scan_result));
+
+ for (ap_num = 0, wbi = wsr->Bssid; ap_num < wsr->NumberOfItems;
+ ++ap_num) {
+ os_memcpy(results[ap_num].bssid, &wbi->MacAddress, ETH_ALEN);
+ os_memcpy(results[ap_num].ssid, wbi->Ssid.Ssid,
+ wbi->Ssid.SsidLength);
+ results[ap_num].ssid_len = wbi->Ssid.SsidLength;
+ results[ap_num].freq = (wbi->Configuration.DSConfig / 1000);
+
+ /* get ie's */
+ wpa_hexdump(MSG_DEBUG, "RALINK: AP IEs",
+ (u8 *) wbi + sizeof(*wbi) - 1, wbi->IELength);
+
+ pos = (u8 *) wbi + sizeof(*wbi) - 1;
+ end = (u8 *) wbi + sizeof(*wbi) + wbi->IELength;
+
+ if (wbi->IELength < sizeof(NDIS_802_11_FIXED_IEs))
+ break;
+
+ pos += sizeof(NDIS_802_11_FIXED_IEs) - 2;
+ os_memcpy(&results[ap_num].caps, pos, 2);
+ pos += 2;
+
+ while (pos + 1 < end && pos + 2 + pos[1] <= end) {
+ u8 ielen = 2 + pos[1];
+
+ if (ielen > SSID_MAX_WPA_IE_LEN) {
+ pos += ielen;
+ continue;
+ }
+
+ if (pos[0] == WLAN_EID_VENDOR_SPECIFIC &&
+ pos[1] >= 4 &&
+ os_memcmp(pos + 2, "\x00\x50\xf2\x01", 4) == 0) {
+ os_memcpy(results[ap_num].wpa_ie, pos, ielen);
+ results[ap_num].wpa_ie_len = ielen;
+ } else if (pos[0] == WLAN_EID_RSN) {
+ os_memcpy(results[ap_num].rsn_ie, pos, ielen);
+ results[ap_num].rsn_ie_len = ielen;
+ }
+ pos += ielen;
+ }
+
+ wbi = (NDIS_WLAN_BSSID_EX *) ((u8 *) wbi + wbi->Length);
+ }
+
+ os_free(buf);
+ return ap_num;
+}
+
+static int ralink_set_auth_mode(struct wpa_driver_ralink_data *drv,
+ NDIS_802_11_AUTHENTICATION_MODE mode)
+{
+ NDIS_802_11_AUTHENTICATION_MODE auth_mode = mode;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (ralink_set_oid(drv, OID_802_11_AUTHENTICATION_MODE,
+ (char *) &auth_mode, sizeof(auth_mode)) < 0) {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+ "OID_802_11_AUTHENTICATION_MODE (%d)",
+ (int) auth_mode);
+ return -1;
+ }
+ return 0;
+}
+
+static int wpa_driver_ralink_remove_key(struct wpa_driver_ralink_data *drv,
+ int key_idx, const u8 *addr,
+ const u8 *bssid, int pairwise)
+{
+ NDIS_802_11_REMOVE_KEY rkey;
+ NDIS_802_11_KEY_INDEX _index;
+ int res, res2;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ os_memset(&rkey, 0, sizeof(rkey));
+
+ rkey.Length = sizeof(rkey);
+ rkey.KeyIndex = key_idx;
+
+ if (pairwise)
+ rkey.KeyIndex |= 1 << 30;
+
+ os_memcpy(rkey.BSSID, bssid, ETH_ALEN);
+
+ res = ralink_set_oid(drv, OID_802_11_REMOVE_KEY, (char *) &rkey,
+ sizeof(rkey));
+
+ /* AlbertY@20060210 removed it */
+ if (0 /* !pairwise */) {
+ res2 = ralink_set_oid(drv, OID_802_11_REMOVE_WEP,
+ (char *) &_index, sizeof(_index));
+ } else
+ res2 = 0;
+
+ if (res < 0 && res2 < 0)
+ return res;
+ return 0;
+}
+
+static int wpa_driver_ralink_add_wep(struct wpa_driver_ralink_data *drv,
+ int pairwise, int key_idx, int set_tx,
+ const u8 *key, size_t key_len)
+{
+ NDIS_802_11_WEP *wep;
+ size_t len;
+ int res;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ len = 12 + key_len;
+ wep = os_zalloc(len);
+ if (wep == NULL)
+ return -1;
+
+ wep->Length = len;
+ wep->KeyIndex = key_idx;
+
+ if (set_tx)
+ wep->KeyIndex |= 0x80000000;
+
+ wep->KeyLength = key_len;
+ os_memcpy(wep->KeyMaterial, key, key_len);
+
+ wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_WEP",
+ (const u8 *) wep, len);
+ res = ralink_set_oid(drv, OID_802_11_ADD_WEP, (char *) wep, len);
+
+ os_free(wep);
+
+ return res;
+}
+
+static int wpa_driver_ralink_set_key(void *priv, wpa_alg alg, const u8 *addr,
+ int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ size_t len, i;
+ NDIS_802_11_KEY *nkey;
+ int res, pairwise;
+ u8 bssid[ETH_ALEN];
+
+ if (drv->g_driver_down == 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (addr == NULL || os_memcmp(addr, "\xff\xff\xff\xff\xff\xff",
+ ETH_ALEN) == 0) {
+ /* Group Key */
+ pairwise = 0;
+ wpa_driver_ralink_get_bssid(drv, bssid);
+ } else {
+ /* Pairwise Key */
+ pairwise = 1;
+ os_memcpy(bssid, addr, ETH_ALEN);
+ }
+
+ if (alg == WPA_ALG_NONE || key_len == 0) {
+ return wpa_driver_ralink_remove_key(drv, key_idx, addr, bssid,
+ pairwise);
+ }
+
+ if (alg == WPA_ALG_WEP) {
+ return wpa_driver_ralink_add_wep(drv, pairwise, key_idx,
+ set_tx, key, key_len);
+ }
+
+ len = 12 + 6 + 6 + 8 + key_len;
+
+ nkey = os_zalloc(len);
+ if (nkey == NULL)
+ return -1;
+
+ nkey->Length = len;
+ nkey->KeyIndex = key_idx;
+
+ if (set_tx)
+ nkey->KeyIndex |= 1 << 31;
+
+ if (pairwise)
+ nkey->KeyIndex |= 1 << 30;
+
+ if (seq && seq_len)
+ nkey->KeyIndex |= 1 << 29;
+
+ nkey->KeyLength = key_len;
+ os_memcpy(nkey->BSSID, bssid, ETH_ALEN);
+
+ if (seq && seq_len) {
+ for (i = 0; i < seq_len; i++)
+ nkey->KeyRSC |= seq[i] << (i * 8);
+ }
+ if (alg == WPA_ALG_TKIP && key_len == 32) {
+ os_memcpy(nkey->KeyMaterial, key, 16);
+ os_memcpy(nkey->KeyMaterial + 16, key + 24, 8);
+ os_memcpy(nkey->KeyMaterial + 24, key + 16, 8);
+ } else {
+ os_memcpy(nkey->KeyMaterial, key, key_len);
+ }
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
+ "key_len=%lu", __FUNCTION__, alg, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ wpa_hexdump_key(MSG_MSGDUMP, "RALINK: OID_802_11_ADD_KEY",
+ (const u8 *) nkey, len);
+ res = ralink_set_oid(drv, OID_802_11_ADD_KEY, (char *) nkey, len);
+ os_free(nkey);
+
+ return res;
+}
+
+static int wpa_driver_ralink_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+
+ if (drv->g_driver_down == 1)
+ return -1;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ if (ralink_set_oid(drv, OID_802_11_DISASSOCIATE, " ", 4) < 0) {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+ "OID_802_11_DISASSOCIATE");
+ }
+
+ return 0;
+}
+
+static int wpa_driver_ralink_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "g_driver_down = %d", drv->g_driver_down);
+
+ if (drv->g_driver_down == 1)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ if (ralink_get_new_driver_flag(drv) == 0) {
+ return wpa_driver_ralink_disassociate(priv, addr, reason_code);
+ } else {
+ MLME_DEAUTH_REQ_STRUCT mlme;
+ os_memset(&mlme, 0, sizeof(MLME_DEAUTH_REQ_STRUCT));
+ mlme.Reason = reason_code;
+ os_memcpy(mlme.Addr, addr, MAC_ADDR_LEN);
+ return ralink_set_oid(drv, OID_802_11_DEAUTHENTICATION,
+ (char *) &mlme,
+ sizeof(MLME_DEAUTH_REQ_STRUCT));
+ }
+}
+
+static int
+wpa_driver_ralink_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+
+ NDIS_802_11_NETWORK_INFRASTRUCTURE mode;
+ NDIS_802_11_AUTHENTICATION_MODE auth_mode;
+ NDIS_802_11_WEP_STATUS encr;
+ BOOLEAN ieee8021xMode;
+
+ if (drv->g_driver_down == 1)
+ return -1;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (params->mode == IEEE80211_MODE_IBSS)
+ mode = Ndis802_11IBSS;
+ else
+ mode = Ndis802_11Infrastructure;
+
+ if (ralink_set_oid(drv, OID_802_11_INFRASTRUCTURE_MODE,
+ (char *) &mode, sizeof(mode)) < 0) {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+ "OID_802_11_INFRASTRUCTURE_MODE (%d)",
+ (int) mode);
+ /* Try to continue anyway */
+ }
+
+ if (params->wpa_ie == NULL || params->wpa_ie_len == 0) {
+ if (params->auth_alg & AUTH_ALG_SHARED_KEY) {
+ if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ auth_mode = Ndis802_11AuthModeAutoSwitch;
+ else
+ auth_mode = Ndis802_11AuthModeShared;
+ } else
+ auth_mode = Ndis802_11AuthModeOpen;
+ } else if (params->wpa_ie[0] == WLAN_EID_RSN) {
+ if (params->key_mgmt_suite == KEY_MGMT_PSK)
+ auth_mode = Ndis802_11AuthModeWPA2PSK;
+ else
+ auth_mode = Ndis802_11AuthModeWPA2;
+ } else {
+ if (params->key_mgmt_suite == KEY_MGMT_WPA_NONE)
+ auth_mode = Ndis802_11AuthModeWPANone;
+ else if (params->key_mgmt_suite == KEY_MGMT_PSK)
+ auth_mode = Ndis802_11AuthModeWPAPSK;
+ else
+ auth_mode = Ndis802_11AuthModeWPA;
+ }
+
+ switch (params->pairwise_suite) {
+ case CIPHER_CCMP:
+ encr = Ndis802_11Encryption3Enabled;
+ break;
+ case CIPHER_TKIP:
+ encr = Ndis802_11Encryption2Enabled;
+ break;
+ case CIPHER_WEP40:
+ case CIPHER_WEP104:
+ encr = Ndis802_11Encryption1Enabled;
+ break;
+ case CIPHER_NONE:
+ if (params->group_suite == CIPHER_CCMP)
+ encr = Ndis802_11Encryption3Enabled;
+ else if (params->group_suite == CIPHER_TKIP)
+ encr = Ndis802_11Encryption2Enabled;
+ else
+ encr = Ndis802_11EncryptionDisabled;
+ break;
+ default:
+ encr = Ndis802_11EncryptionDisabled;
+ break;
+ }
+
+ ralink_set_auth_mode(drv, auth_mode);
+
+ /* notify driver that IEEE8021x mode is enabled */
+ if (params->key_mgmt_suite == KEY_MGMT_802_1X_NO_WPA)
+ ieee8021xMode = TRUE;
+ else
+ ieee8021xMode = FALSE;
+
+ if (ralink_set_oid(drv, OID_802_11_SET_IEEE8021X,
+ (char *) &ieee8021xMode, sizeof(BOOLEAN)) < 0) {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+ "OID_802_11_SET_IEEE8021X(%d)",
+ (int) ieee8021xMode);
+ }
+
+ if (ralink_set_oid(drv, OID_802_11_WEP_STATUS,
+ (char *) &encr, sizeof(encr)) < 0) {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+ "OID_802_11_WEP_STATUS(%d)",
+ (int) encr);
+ }
+
+ if ((ieee8021xMode == FALSE) &&
+ (encr == Ndis802_11Encryption1Enabled)) {
+ /* static WEP */
+ int enabled = 0;
+ if (ralink_set_oid(drv, OID_802_11_DROP_UNENCRYPTED,
+ (char *) &enabled, sizeof(enabled)) < 0) {
+ wpa_printf(MSG_DEBUG, "RALINK: Failed to set "
+ "OID_802_11_DROP_UNENCRYPTED(%d)",
+ (int) encr);
+ }
+ }
+
+ return wpa_driver_ralink_set_ssid(drv, params->ssid, params->ssid_len);
+}
+
+static int
+wpa_driver_ralink_set_countermeasures(void *priv, int enabled)
+{
+ struct wpa_driver_ralink_data *drv = priv;
+ if (drv->g_driver_down == 1)
+ return -1;
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __FUNCTION__, enabled);
+ return ralink_set_oid(drv, OID_SET_COUNTERMEASURES, (char *) &enabled,
+ sizeof(int));
+}
+
+const struct wpa_driver_ops wpa_driver_ralink_ops = {
+ .name = "ralink",
+ .desc = "Ralink Wireless Client driver",
+ .get_bssid = wpa_driver_ralink_get_bssid,
+ .get_ssid = wpa_driver_ralink_get_ssid,
+ .set_key = wpa_driver_ralink_set_key,
+ .init = wpa_driver_ralink_init,
+ .deinit = wpa_driver_ralink_deinit,
+ .set_countermeasures = wpa_driver_ralink_set_countermeasures,
+ .scan = wpa_driver_ralink_scan,
+ .get_scan_results = wpa_driver_ralink_get_scan_results,
+ .deauthenticate = wpa_driver_ralink_deauthenticate,
+ .disassociate = wpa_driver_ralink_disassociate,
+ .associate = wpa_driver_ralink_associate,
+ .add_pmkid = wpa_driver_ralink_add_pmkid,
+ .remove_pmkid = wpa_driver_ralink_remove_pmkid,
+ .flush_pmkid = wpa_driver_ralink_flush_pmkid,
+};
diff --git a/src/drivers/driver_ralink.h b/src/drivers/driver_ralink.h
new file mode 100644
index 0000000..ddf44de
--- /dev/null
+++ b/src/drivers/driver_ralink.h
@@ -0,0 +1,382 @@
+/*
+ * WPA Supplicant - driver_ralink exported functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007, Snowpin Lee <snowpin_lee@ralinktech.com.tw>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+// Ralink defined OIDs
+#if WIRELESS_EXT <= 11
+#ifndef SIOCDEVPRIVATE
+#define SIOCDEVPRIVATE 0x8BE0
+#endif
+#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
+#endif
+
+#define RT_PRIV_IOCTL (SIOCIWFIRSTPRIV + 0x0E)
+#define RTPRIV_IOCTL_SET (SIOCIWFIRSTPRIV + 0x02)
+
+// IEEE 802.11 OIDs & Ralink defined OIDs ******
+
+// (RaConfig Set/QueryInform) ==>
+#define OID_GET_SET_TOGGLE 0x8000
+
+#define OID_802_11_ADD_WEP 0x0112
+#define OID_802_11_REMOVE_WEP 0x0113
+#define OID_802_11_DISASSOCIATE 0x0114
+#define OID_802_11_PRIVACY_FILTER 0x0118
+#define OID_802_11_ASSOCIATION_INFORMATION 0x011E
+#define OID_802_11_BSSID_LIST_SCAN 0x0508
+#define OID_802_11_SSID 0x0509
+#define OID_802_11_BSSID 0x050A
+#define OID_802_11_WEP_STATUS 0x0510
+#define OID_802_11_AUTHENTICATION_MODE 0x0511
+#define OID_802_11_INFRASTRUCTURE_MODE 0x0512
+#define OID_802_11_TX_POWER_LEVEL 0x0517
+#define OID_802_11_REMOVE_KEY 0x0519
+#define OID_802_11_ADD_KEY 0x0520
+#define OID_802_11_DEAUTHENTICATION 0x0526
+#define OID_802_11_DROP_UNENCRYPTED 0x0527
+#define OID_802_11_BSSID_LIST 0x0609
+#define OID_802_3_CURRENT_ADDRESS 0x060A
+#define OID_SET_COUNTERMEASURES 0x0616
+#define OID_802_11_SET_IEEE8021X 0x0617 // For IEEE8021x mode
+#define OID_802_11_SET_IEEE8021X_REQUIRE_KEY 0x0618 // For DynamicWEP in IEEE802.1x mode
+#define OID_802_11_PMKID 0x0620
+#define RT_OID_WPA_SUPPLICANT_SUPPORT 0x0621 // for trigger driver enable/disable wpa_supplicant support
+#define RT_OID_WE_VERSION_COMPILED 0x0622
+#define RT_OID_NEW_DRIVER 0x0623
+
+#define PACKED __attribute__ ((packed))
+
+//wpa_supplicant event flags
+#define RT_ASSOC_EVENT_FLAG 0x0101
+#define RT_DISASSOC_EVENT_FLAG 0x0102
+#define RT_REQIE_EVENT_FLAG 0x0103
+#define RT_RESPIE_EVENT_FLAG 0x0104
+#define RT_ASSOCINFO_EVENT_FLAG 0x0105
+#define RT_PMKIDCAND_FLAG 0x0106
+#define RT_INTERFACE_DOWN 0x0107
+#define RT_REPORT_AP_INFO 0x0108
+
+//
+// IEEE 802.11 Structures and definitions
+//
+// new types for Media Specific Indications
+
+#ifndef ULONG
+#define CHAR char
+#define INT int
+#define SHORT int
+#define UINT u32
+#undef ULONG
+//#define ULONG u32
+#define ULONG unsigned long /* 32-bit in 32-bit CPU or 64-bit in 64-bit CPU */
+#define USHORT unsigned short
+#define UCHAR unsigned char
+
+#define uint32 u32
+#define uint8 u8
+
+
+#define BOOLEAN u8
+//#define LARGE_INTEGER s64
+#define VOID void
+#define LONG long
+#define LONGLONG s64
+#define ULONGLONG u64
+typedef VOID *PVOID;
+typedef CHAR *PCHAR;
+typedef UCHAR *PUCHAR;
+typedef USHORT *PUSHORT;
+typedef LONG *PLONG;
+typedef ULONG *PULONG;
+
+typedef union _LARGE_INTEGER {
+ struct {
+ ULONG LowPart;
+ LONG HighPart;
+ }vv;
+ struct {
+ ULONG LowPart;
+ LONG HighPart;
+ } u;
+ s64 QuadPart;
+} LARGE_INTEGER;
+
+#endif
+
+#define NDIS_802_11_LENGTH_SSID 32
+#define NDIS_802_11_LENGTH_RATES 8
+#define NDIS_802_11_LENGTH_RATES_EX 16
+#define MAX_LEN_OF_SSID 32
+#define MAC_ADDR_LEN 6
+
+typedef UCHAR NDIS_802_11_MAC_ADDRESS[6];
+
+// mask for authentication/integrity fields
+#define NDIS_802_11_AUTH_REQUEST_AUTH_FIELDS 0x0f
+
+#define NDIS_802_11_AUTH_REQUEST_REAUTH 0x01
+#define NDIS_802_11_AUTH_REQUEST_KEYUPDATE 0x02
+#define NDIS_802_11_AUTH_REQUEST_PAIRWISE_ERROR 0x06
+#define NDIS_802_11_AUTH_REQUEST_GROUP_ERROR 0x0E
+
+// Added new types for OFDM 5G and 2.4G
+typedef enum _NDIS_802_11_NETWORK_TYPE
+{
+ Ndis802_11FH,
+ Ndis802_11DS,
+ Ndis802_11OFDM5,
+ Ndis802_11OFDM24,
+ Ndis802_11Automode,
+ Ndis802_11NetworkTypeMax // not a real type, defined as an upper bound
+} NDIS_802_11_NETWORK_TYPE, *PNDIS_802_11_NETWORK_TYPE;
+
+//
+// Received Signal Strength Indication
+//
+typedef LONG NDIS_802_11_RSSI; // in dBm
+
+typedef struct _NDIS_802_11_CONFIGURATION_FH
+{
+ ULONG Length; // Length of structure
+ ULONG HopPattern; // As defined by 802.11, MSB set
+ ULONG HopSet; // to one if non-802.11
+ ULONG DwellTime; // units are Kusec
+} NDIS_802_11_CONFIGURATION_FH, *PNDIS_802_11_CONFIGURATION_FH;
+
+typedef struct _NDIS_802_11_CONFIGURATION
+{
+ ULONG Length; // Length of structure
+ ULONG BeaconPeriod; // units are Kusec
+ ULONG ATIMWindow; // units are Kusec
+ ULONG DSConfig; // Frequency, units are kHz
+ NDIS_802_11_CONFIGURATION_FH FHConfig;
+} NDIS_802_11_CONFIGURATION, *PNDIS_802_11_CONFIGURATION;
+
+typedef ULONG NDIS_802_11_KEY_INDEX;
+typedef ULONGLONG NDIS_802_11_KEY_RSC;
+
+// Key mapping keys require a BSSID
+typedef struct _NDIS_802_11_KEY
+{
+ UINT Length; // Length of this structure
+ UINT KeyIndex;
+ UINT KeyLength; // length of key in bytes
+ NDIS_802_11_MAC_ADDRESS BSSID;
+ NDIS_802_11_KEY_RSC KeyRSC;
+ UCHAR KeyMaterial[1]; // variable length depending on above field
+} NDIS_802_11_KEY, *PNDIS_802_11_KEY;
+
+typedef struct _NDIS_802_11_REMOVE_KEY
+{
+ UINT Length; // Length of this structure
+ UINT KeyIndex;
+ NDIS_802_11_MAC_ADDRESS BSSID;
+} NDIS_802_11_REMOVE_KEY, *PNDIS_802_11_REMOVE_KEY;
+
+typedef struct PACKED _NDIS_802_11_WEP
+{
+ UINT Length; // Length of this structure
+ UINT KeyIndex; // 0 is the per-client key, 1-N are the
+ // global keys
+ UINT KeyLength; // length of key in bytes
+ UCHAR KeyMaterial[1];// variable length depending on above field
+} NDIS_802_11_WEP, *PNDIS_802_11_WEP;
+
+
+typedef enum _NDIS_802_11_NETWORK_INFRASTRUCTURE
+{
+ Ndis802_11IBSS,
+ Ndis802_11Infrastructure,
+ Ndis802_11AutoUnknown,
+ Ndis802_11InfrastructureMax // Not a real value, defined as upper bound
+} NDIS_802_11_NETWORK_INFRASTRUCTURE, *PNDIS_802_11_NETWORK_INFRASTRUCTURE;
+
+// PMKID Structures
+typedef UCHAR NDIS_802_11_PMKID_VALUE[16];
+
+typedef struct _BSSID_INFO
+{
+ NDIS_802_11_MAC_ADDRESS BSSID;
+ NDIS_802_11_PMKID_VALUE PMKID;
+} BSSID_INFO, *PBSSID_INFO;
+
+typedef struct _NDIS_802_11_PMKID
+{
+ ULONG Length;
+ ULONG BSSIDInfoCount;
+ BSSID_INFO BSSIDInfo[1];
+} NDIS_802_11_PMKID, *PNDIS_802_11_PMKID;
+
+//Added new types for PMKID Candidate lists.
+typedef struct _PMKID_CANDIDATE {
+ NDIS_802_11_MAC_ADDRESS BSSID;
+ ULONG Flags;
+} PMKID_CANDIDATE, *PPMKID_CANDIDATE;
+
+typedef struct _NDIS_802_11_PMKID_CANDIDATE_LIST
+{
+ ULONG Version; // Version of the structure
+ ULONG NumCandidates; // No. of pmkid candidates
+ PMKID_CANDIDATE CandidateList[1];
+} NDIS_802_11_PMKID_CANDIDATE_LIST, *PNDIS_802_11_PMKID_CANDIDATE_LIST;
+
+//Flags for PMKID Candidate list structure
+#define NDIS_802_11_PMKID_CANDIDATE_PREAUTH_ENABLED 0x01
+
+// Add new authentication modes
+typedef enum _NDIS_802_11_AUTHENTICATION_MODE
+{
+ Ndis802_11AuthModeOpen,
+ Ndis802_11AuthModeShared,
+ Ndis802_11AuthModeAutoSwitch,
+ Ndis802_11AuthModeWPA,
+ Ndis802_11AuthModeWPAPSK,
+ Ndis802_11AuthModeWPANone,
+ Ndis802_11AuthModeWPA2,
+ Ndis802_11AuthModeWPA2PSK,
+ Ndis802_11AuthModeMax // Not a real mode, defined as upper bound
+} NDIS_802_11_AUTHENTICATION_MODE, *PNDIS_802_11_AUTHENTICATION_MODE;
+
+typedef UCHAR NDIS_802_11_RATES[NDIS_802_11_LENGTH_RATES]; // Set of 8 data rates
+typedef UCHAR NDIS_802_11_RATES_EX[NDIS_802_11_LENGTH_RATES_EX]; // Set of 16 data rates
+
+typedef struct PACKED _NDIS_802_11_SSID
+{
+ INT SsidLength; // length of SSID field below, in bytes;
+ // this can be zero.
+ UCHAR Ssid[NDIS_802_11_LENGTH_SSID]; // SSID information field
+} NDIS_802_11_SSID, *PNDIS_802_11_SSID;
+
+
+typedef struct PACKED _NDIS_WLAN_BSSID
+{
+ ULONG Length; // Length of this structure
+ NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID
+ UCHAR Reserved[2];
+ NDIS_802_11_SSID Ssid; // SSID
+ ULONG Privacy; // WEP encryption requirement
+ NDIS_802_11_RSSI Rssi; // receive signal
+ // strength in dBm
+ NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
+ NDIS_802_11_CONFIGURATION Configuration;
+ NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
+ NDIS_802_11_RATES SupportedRates;
+} NDIS_WLAN_BSSID, *PNDIS_WLAN_BSSID;
+
+typedef struct PACKED _NDIS_802_11_BSSID_LIST
+{
+ UINT NumberOfItems; // in list below, at least 1
+ NDIS_WLAN_BSSID Bssid[1];
+} NDIS_802_11_BSSID_LIST, *PNDIS_802_11_BSSID_LIST;
+
+// Added Capabilities, IELength and IEs for each BSSID
+typedef struct PACKED _NDIS_WLAN_BSSID_EX
+{
+ ULONG Length; // Length of this structure
+ NDIS_802_11_MAC_ADDRESS MacAddress; // BSSID
+ UCHAR Reserved[2];
+ NDIS_802_11_SSID Ssid; // SSID
+ UINT Privacy; // WEP encryption requirement
+ NDIS_802_11_RSSI Rssi; // receive signal
+ // strength in dBm
+ NDIS_802_11_NETWORK_TYPE NetworkTypeInUse;
+ NDIS_802_11_CONFIGURATION Configuration;
+ NDIS_802_11_NETWORK_INFRASTRUCTURE InfrastructureMode;
+ NDIS_802_11_RATES_EX SupportedRates;
+ ULONG IELength;
+ UCHAR IEs[1];
+} NDIS_WLAN_BSSID_EX, *PNDIS_WLAN_BSSID_EX;
+
+typedef struct PACKED _NDIS_802_11_BSSID_LIST_EX
+{
+ UINT NumberOfItems; // in list below, at least 1
+ NDIS_WLAN_BSSID_EX Bssid[1];
+} NDIS_802_11_BSSID_LIST_EX, *PNDIS_802_11_BSSID_LIST_EX;
+
+typedef struct PACKED _NDIS_802_11_FIXED_IEs
+{
+ UCHAR Timestamp[8];
+ USHORT BeaconInterval;
+ USHORT Capabilities;
+} NDIS_802_11_FIXED_IEs, *PNDIS_802_11_FIXED_IEs;
+
+// Added new encryption types
+// Also aliased typedef to new name
+typedef enum _NDIS_802_11_WEP_STATUS
+{
+ Ndis802_11WEPEnabled,
+ Ndis802_11Encryption1Enabled = Ndis802_11WEPEnabled,
+ Ndis802_11WEPDisabled,
+ Ndis802_11EncryptionDisabled = Ndis802_11WEPDisabled,
+ Ndis802_11WEPKeyAbsent,
+ Ndis802_11Encryption1KeyAbsent = Ndis802_11WEPKeyAbsent,
+ Ndis802_11WEPNotSupported,
+ Ndis802_11EncryptionNotSupported = Ndis802_11WEPNotSupported,
+ Ndis802_11Encryption2Enabled,
+ Ndis802_11Encryption2KeyAbsent,
+ Ndis802_11Encryption3Enabled,
+ Ndis802_11Encryption3KeyAbsent
+} NDIS_802_11_WEP_STATUS, *PNDIS_802_11_WEP_STATUS,
+ NDIS_802_11_ENCRYPTION_STATUS, *PNDIS_802_11_ENCRYPTION_STATUS;
+
+typedef enum _NDIS_802_11_RELOAD_DEFAULTS
+{
+ Ndis802_11ReloadWEPKeys
+} NDIS_802_11_RELOAD_DEFAULTS, *PNDIS_802_11_RELOAD_DEFAULTS;
+
+#define NDIS_802_11_AI_REQFI_CAPABILITIES 1
+#define NDIS_802_11_AI_REQFI_LISTENINTERVAL 2
+#define NDIS_802_11_AI_REQFI_CURRENTAPADDRESS 4
+
+#define NDIS_802_11_AI_RESFI_CAPABILITIES 1
+#define NDIS_802_11_AI_RESFI_STATUSCODE 2
+#define NDIS_802_11_AI_RESFI_ASSOCIATIONID 4
+
+typedef struct _NDIS_802_11_AI_REQFI
+{
+ USHORT Capabilities;
+ USHORT ListenInterval;
+ NDIS_802_11_MAC_ADDRESS CurrentAPAddress;
+} NDIS_802_11_AI_REQFI, *PNDIS_802_11_AI_REQFI;
+
+typedef struct _NDIS_802_11_AI_RESFI
+{
+ USHORT Capabilities;
+ USHORT StatusCode;
+ USHORT AssociationId;
+} NDIS_802_11_AI_RESFI, *PNDIS_802_11_AI_RESFI;
+
+typedef struct _NDIS_802_11_ASSOCIATION_INFORMATION
+{
+ ULONG Length;
+ USHORT AvailableRequestFixedIEs;
+ NDIS_802_11_AI_REQFI RequestFixedIEs;
+ ULONG RequestIELength;
+ ULONG OffsetRequestIEs;
+ USHORT AvailableResponseFixedIEs;
+ NDIS_802_11_AI_RESFI ResponseFixedIEs;
+ ULONG ResponseIELength;
+ ULONG OffsetResponseIEs;
+} NDIS_802_11_ASSOCIATION_INFORMATION, *PNDIS_802_11_ASSOCIATION_INFORMATION;
+
+struct ndis_pmkid_entry {
+ struct ndis_pmkid_entry *next;
+ u8 bssid[ETH_ALEN];
+ u8 pmkid[16];
+};
+
+typedef struct _MLME_DEAUTH_REQ_STRUCT {
+ UCHAR Addr[MAC_ADDR_LEN];
+ USHORT Reason;
+} MLME_DEAUTH_REQ_STRUCT, *PMLME_DEAUTH_REQ_STRUCT;
diff --git a/src/drivers/driver_roboswitch.c b/src/drivers/driver_roboswitch.c
new file mode 100644
index 0000000..bc11a48
--- /dev/null
+++ b/src/drivers/driver_roboswitch.c
@@ -0,0 +1,476 @@
+/*
+ * WPA Supplicant - roboswitch driver interface
+ * Copyright (c) 2008-2009 Jouke Witteveen
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/sockios.h>
+#include <linux/if_ether.h>
+#include <linux/mii.h>
+
+#include "common.h"
+#include "driver.h"
+#include "l2_packet/l2_packet.h"
+
+#ifndef ETH_P_EAPOL
+#define ETH_P_EAPOL 0x888e
+#endif
+
+#define ROBO_PHY_ADDR 0x1e /* RoboSwitch PHY address */
+
+/* MII access registers */
+#define ROBO_MII_PAGE 0x10 /* MII page register */
+#define ROBO_MII_ADDR 0x11 /* MII address register */
+#define ROBO_MII_DATA_OFFSET 0x18 /* Start of MII data registers */
+
+#define ROBO_MII_PAGE_ENABLE 0x01 /* MII page op code */
+#define ROBO_MII_ADDR_WRITE 0x01 /* MII address write op code */
+#define ROBO_MII_ADDR_READ 0x02 /* MII address read op code */
+#define ROBO_MII_DATA_MAX 4 /* Consecutive MII data registers */
+#define ROBO_MII_RETRY_MAX 10 /* Read attempts before giving up */
+
+/* Page numbers */
+#define ROBO_ARLCTRL_PAGE 0x04 /* ARL control page */
+#define ROBO_VLAN_PAGE 0x34 /* VLAN page */
+
+/* ARL control page registers */
+#define ROBO_ARLCTRL_CONF 0x00 /* ARL configuration register */
+#define ROBO_ARLCTRL_ADDR_1 0x10 /* Multiport address 1 */
+#define ROBO_ARLCTRL_VEC_1 0x16 /* Multiport vector 1 */
+#define ROBO_ARLCTRL_ADDR_2 0x20 /* Multiport address 2 */
+#define ROBO_ARLCTRL_VEC_2 0x26 /* Multiport vector 2 */
+
+/* VLAN page registers */
+#define ROBO_VLAN_ACCESS 0x08 /* VLAN table access register */
+#define ROBO_VLAN_ACCESS_5350 0x06 /* VLAN table access register (5350) */
+#define ROBO_VLAN_READ 0x0c /* VLAN read register */
+#define ROBO_VLAN_MAX 0xff /* Maximum number of VLANs */
+
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+
+struct wpa_driver_roboswitch_data {
+ void *ctx;
+ struct l2_packet_data *l2;
+ char ifname[IFNAMSIZ + 1];
+ u8 own_addr[ETH_ALEN];
+ struct ifreq ifr;
+ int fd, is_5350;
+ u16 ports;
+};
+
+
+/* Copied from the kernel-only part of mii.h. */
+static inline struct mii_ioctl_data *if_mii(struct ifreq *rq)
+{
+ return (struct mii_ioctl_data *) &rq->ifr_ifru;
+}
+
+
+/*
+ * RoboSwitch uses 16-bit Big Endian addresses.
+ * The ordering of the words is reversed in the MII registers.
+ */
+static void wpa_driver_roboswitch_addr_be16(const u8 addr[ETH_ALEN], u16 *be)
+{
+ int i;
+ for (i = 0; i < ETH_ALEN; i += 2)
+ be[(ETH_ALEN - i) / 2 - 1] = WPA_GET_BE16(addr + i);
+}
+
+
+static u16 wpa_driver_roboswitch_mdio_read(
+ struct wpa_driver_roboswitch_data *drv, u8 reg)
+{
+ struct mii_ioctl_data *mii = if_mii(&drv->ifr);
+
+ mii->phy_id = ROBO_PHY_ADDR;
+ mii->reg_num = reg;
+
+ if (ioctl(drv->fd, SIOCGMIIREG, &drv->ifr) < 0) {
+ perror("ioctl[SIOCGMIIREG]");
+ return 0x00;
+ }
+ return mii->val_out;
+}
+
+
+static void wpa_driver_roboswitch_mdio_write(
+ struct wpa_driver_roboswitch_data *drv, u8 reg, u16 val)
+{
+ struct mii_ioctl_data *mii = if_mii(&drv->ifr);
+
+ mii->phy_id = ROBO_PHY_ADDR;
+ mii->reg_num = reg;
+ mii->val_in = val;
+
+ if (ioctl(drv->fd, SIOCSMIIREG, &drv->ifr) < 0) {
+ perror("ioctl[SIOCSMIIREG");
+ }
+}
+
+
+static int wpa_driver_roboswitch_reg(struct wpa_driver_roboswitch_data *drv,
+ u8 page, u8 reg, u8 op)
+{
+ int i;
+
+ /* set page number */
+ wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_PAGE,
+ (page << 8) | ROBO_MII_PAGE_ENABLE);
+ /* set register address */
+ wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_ADDR, (reg << 8) | op);
+
+ /* check if operation completed */
+ for (i = 0; i < ROBO_MII_RETRY_MAX; ++i) {
+ if ((wpa_driver_roboswitch_mdio_read(drv, ROBO_MII_ADDR) & 3)
+ == 0)
+ return 0;
+ }
+ /* timeout */
+ return -1;
+}
+
+
+static int wpa_driver_roboswitch_read(struct wpa_driver_roboswitch_data *drv,
+ u8 page, u8 reg, u16 *val, int len)
+{
+ int i;
+
+ if (len > ROBO_MII_DATA_MAX ||
+ wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_READ) < 0)
+ return -1;
+
+ for (i = 0; i < len; ++i) {
+ val[i] = wpa_driver_roboswitch_mdio_read(
+ drv, ROBO_MII_DATA_OFFSET + i);
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_roboswitch_write(struct wpa_driver_roboswitch_data *drv,
+ u8 page, u8 reg, u16 *val, int len)
+{
+ int i;
+
+ if (len > ROBO_MII_DATA_MAX) return -1;
+ for (i = 0; i < len; ++i) {
+ wpa_driver_roboswitch_mdio_write(drv, ROBO_MII_DATA_OFFSET + i,
+ val[i]);
+ }
+ return wpa_driver_roboswitch_reg(drv, page, reg, ROBO_MII_ADDR_WRITE);
+}
+
+
+static void wpa_driver_roboswitch_receive(void *priv, const u8 *src_addr,
+ const u8 *buf, size_t len)
+{
+ struct wpa_driver_roboswitch_data *drv = priv;
+
+ if (len > 14 && WPA_GET_BE16(buf + 12) == ETH_P_EAPOL &&
+ os_memcmp(buf, drv->own_addr, ETH_ALEN) == 0) {
+ wpa_supplicant_rx_eapol(drv->ctx, src_addr, buf + 14,
+ len - 14);
+ }
+}
+
+
+static int wpa_driver_roboswitch_get_ssid(void *priv, u8 *ssid)
+{
+ ssid[0] = 0;
+ return 0;
+}
+
+
+static int wpa_driver_roboswitch_get_bssid(void *priv, u8 *bssid)
+{
+ /* Report PAE group address as the "BSSID" for wired connection. */
+ os_memcpy(bssid, pae_group_addr, ETH_ALEN);
+ return 0;
+}
+
+
+static int wpa_driver_roboswitch_set_param(void *priv, const char *param)
+{
+ struct wpa_driver_roboswitch_data *drv = priv;
+ char *sep;
+
+ if (param == NULL || os_strstr(param, "multicast_only=1") == NULL) {
+ sep = drv->ifname + os_strlen(drv->ifname);
+ *sep = '.';
+ drv->l2 = l2_packet_init(drv->ifname, NULL, ETH_P_ALL,
+ wpa_driver_roboswitch_receive, drv,
+ 1);
+ if (drv->l2 == NULL) {
+ wpa_printf(MSG_INFO, "%s: Unable to listen on %s",
+ __func__, drv->ifname);
+ return -1;
+ }
+ *sep = '\0';
+ l2_packet_get_own_addr(drv->l2, drv->own_addr);
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: Ignoring unicast frames", __func__);
+ drv->l2 = NULL;
+ }
+ return 0;
+}
+
+
+static const char * wpa_driver_roboswitch_get_ifname(void *priv)
+{
+ struct wpa_driver_roboswitch_data *drv = priv;
+ return drv->ifname;
+}
+
+
+static int wpa_driver_roboswitch_join(struct wpa_driver_roboswitch_data *drv,
+ u16 ports, const u8 *addr)
+{
+ u16 read1[3], read2[3], addr_be16[3];
+
+ wpa_driver_roboswitch_addr_be16(addr, addr_be16);
+
+ if (wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_CONF, read1, 1) < 0)
+ return -1;
+ if (!(read1[0] & (1 << 4))) {
+ /* multiport addresses are not yet enabled */
+ read1[0] |= 1 << 4;
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1, addr_be16, 3);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1, &ports, 1);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2, addr_be16, 3);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2, &ports, 1);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_CONF, read1, 1);
+ } else {
+ /* if both multiport addresses are the same we can add */
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1, read1, 3);
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2, read2, 3);
+ if (os_memcmp(read1, read2, 6) != 0)
+ return -1;
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1, read1, 1);
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2, read2, 1);
+ if (read1[0] != read2[0])
+ return -1;
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1, addr_be16, 3);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1, &ports, 1);
+ }
+ return 0;
+}
+
+
+static int wpa_driver_roboswitch_leave(struct wpa_driver_roboswitch_data *drv,
+ u16 ports, const u8 *addr)
+{
+ u16 _read, addr_be16[3], addr_read[3], ports_read;
+
+ wpa_driver_roboswitch_addr_be16(addr, addr_be16);
+
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_CONF,
+ &_read, 1);
+ /* If ARL control is disabled, there is nothing to leave. */
+ if (!(_read & (1 << 4))) return -1;
+
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1, addr_read, 3);
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE, ROBO_ARLCTRL_VEC_1,
+ &ports_read, 1);
+ /* check if we occupy multiport address 1 */
+ if (os_memcmp(addr_read, addr_be16, 6) == 0 && ports_read == ports) {
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2, addr_read, 3);
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2, &ports_read, 1);
+ /* and multiport address 2 */
+ if (os_memcmp(addr_read, addr_be16, 6) == 0 &&
+ ports_read == ports) {
+ _read &= ~(1 << 4);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_CONF, &_read,
+ 1);
+ } else {
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1,
+ addr_read, 3);
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1,
+ &ports_read, 1);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2,
+ addr_read, 3);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2,
+ &ports_read, 1);
+ }
+ } else {
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_2, addr_read, 3);
+ wpa_driver_roboswitch_read(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_2, &ports_read, 1);
+ /* or multiport address 2 */
+ if (os_memcmp(addr_read, addr_be16, 6) == 0 &&
+ ports_read == ports) {
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_ADDR_1,
+ addr_read, 3);
+ wpa_driver_roboswitch_write(drv, ROBO_ARLCTRL_PAGE,
+ ROBO_ARLCTRL_VEC_1,
+ &ports_read, 1);
+ } else return -1;
+ }
+ return 0;
+}
+
+
+static void * wpa_driver_roboswitch_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_roboswitch_data *drv;
+ char *sep;
+ u16 vlan = 0, _read[2];
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL) return NULL;
+ drv->ctx = ctx;
+ drv->own_addr[0] = '\0';
+
+ /* copy ifname and take a pointer to the second to last character */
+ sep = drv->ifname +
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname)) - 2;
+ /* find the '.' seperating <interface> and <vlan> */
+ while (sep > drv->ifname && *sep != '.') sep--;
+ if (sep <= drv->ifname) {
+ wpa_printf(MSG_INFO, "%s: No <interface>.<vlan> pair in "
+ "interface name %s", __func__, drv->ifname);
+ os_free(drv);
+ return NULL;
+ }
+ *sep = '\0';
+ while (*++sep) {
+ if (*sep < '0' || *sep > '9') {
+ wpa_printf(MSG_INFO, "%s: Invalid vlan specification "
+ "in interface name %s", __func__, ifname);
+ os_free(drv);
+ return NULL;
+ }
+ vlan *= 10;
+ vlan += *sep - '0';
+ if (vlan > ROBO_VLAN_MAX) {
+ wpa_printf(MSG_INFO, "%s: VLAN out of range in "
+ "interface name %s", __func__, ifname);
+ os_free(drv);
+ return NULL;
+ }
+ }
+
+ drv->fd = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->fd < 0) {
+ wpa_printf(MSG_INFO, "%s: Unable to create socket", __func__);
+ os_free(drv);
+ return NULL;
+ }
+
+ os_memset(&drv->ifr, 0, sizeof(drv->ifr));
+ os_strlcpy(drv->ifr.ifr_name, drv->ifname, IFNAMSIZ);
+ if (ioctl(drv->fd, SIOCGMIIPHY, &drv->ifr) < 0) {
+ perror("ioctl[SIOCGMIIPHY]");
+ os_free(drv);
+ return NULL;
+ }
+ if (if_mii(&drv->ifr)->phy_id != ROBO_PHY_ADDR) {
+ wpa_printf(MSG_INFO, "%s: Invalid phy address (not a "
+ "RoboSwitch?)", __func__);
+ os_free(drv);
+ return NULL;
+ }
+
+ /* set and read back to see if the register can be used */
+ _read[0] = ROBO_VLAN_MAX;
+ wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350,
+ _read, 1);
+ wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_ACCESS_5350,
+ _read + 1, 1);
+ drv->is_5350 = _read[0] == _read[1];
+
+ /* set the read bit */
+ vlan |= 1 << 13;
+ wpa_driver_roboswitch_write(drv, ROBO_VLAN_PAGE,
+ drv->is_5350 ? ROBO_VLAN_ACCESS_5350
+ : ROBO_VLAN_ACCESS,
+ &vlan, 1);
+ wpa_driver_roboswitch_read(drv, ROBO_VLAN_PAGE, ROBO_VLAN_READ, _read,
+ drv->is_5350 ? 2 : 1);
+ if (!(drv->is_5350 ? _read[1] & (1 << 4) : _read[0] & (1 << 14))) {
+ wpa_printf(MSG_INFO, "%s: Could not get port information for "
+ "VLAN %d", __func__, vlan & ~(1 << 13));
+ os_free(drv);
+ return NULL;
+ }
+ drv->ports = _read[0] & 0x001F;
+ /* add the MII port */
+ drv->ports |= 1 << 8;
+ if (wpa_driver_roboswitch_join(drv, drv->ports, pae_group_addr) < 0) {
+ wpa_printf(MSG_INFO, "%s: Unable to join PAE group", __func__);
+ os_free(drv);
+ return NULL;
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: Added PAE group address to "
+ "RoboSwitch ARL", __func__);
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_roboswitch_deinit(void *priv)
+{
+ struct wpa_driver_roboswitch_data *drv = priv;
+
+ if (drv->l2) {
+ l2_packet_deinit(drv->l2);
+ drv->l2 = NULL;
+ }
+ if (wpa_driver_roboswitch_leave(drv, drv->ports, pae_group_addr) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Unable to leave PAE group",
+ __func__);
+ }
+
+ close(drv->fd);
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_roboswitch_ops = {
+ .name = "roboswitch",
+ .desc = "wpa_supplicant roboswitch driver",
+ .get_ssid = wpa_driver_roboswitch_get_ssid,
+ .get_bssid = wpa_driver_roboswitch_get_bssid,
+ .init = wpa_driver_roboswitch_init,
+ .deinit = wpa_driver_roboswitch_deinit,
+ .set_param = wpa_driver_roboswitch_set_param,
+ .get_ifname = wpa_driver_roboswitch_get_ifname,
+};
diff --git a/src/drivers/driver_test.c b/src/drivers/driver_test.c
new file mode 100644
index 0000000..2a41cf2
--- /dev/null
+++ b/src/drivers/driver_test.c
@@ -0,0 +1,1230 @@
+/*
+ * WPA Supplicant - testing driver interface
+ * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+/* Make dure we get winsock2.h for Windows build to get sockaddr_storage */
+#include "build_config.h"
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock2.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <sys/un.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#define DRIVER_TEST_UNIX
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "common.h"
+#include "driver.h"
+#include "l2_packet/l2_packet.h"
+#include "eloop.h"
+#include "sha1.h"
+#include "ieee802_11_defs.h"
+
+
+struct wpa_driver_test_global {
+ int dummy;
+};
+
+struct wpa_driver_test_data {
+ struct wpa_driver_test_global *global;
+ void *ctx;
+ u8 own_addr[ETH_ALEN];
+ int test_socket;
+#ifdef DRIVER_TEST_UNIX
+ struct sockaddr_un hostapd_addr;
+#endif /* DRIVER_TEST_UNIX */
+ int hostapd_addr_set;
+ struct sockaddr_in hostapd_addr_udp;
+ int hostapd_addr_udp_set;
+ char *own_socket_path;
+ char *test_dir;
+ u8 bssid[ETH_ALEN];
+ u8 ssid[32];
+ size_t ssid_len;
+#define MAX_SCAN_RESULTS 30
+ struct wpa_scan_res *scanres[MAX_SCAN_RESULTS];
+ size_t num_scanres;
+ int use_associnfo;
+ u8 assoc_wpa_ie[80];
+ size_t assoc_wpa_ie_len;
+ int use_mlme;
+ int associated;
+ u8 *probe_req_ie;
+ size_t probe_req_ie_len;
+};
+
+
+static void wpa_driver_test_poll(void *eloop_ctx, void *timeout_ctx)
+{
+ struct wpa_driver_test_data *drv = eloop_ctx;
+
+#ifdef DRIVER_TEST_UNIX
+ if (drv->associated && drv->hostapd_addr_set) {
+ struct stat st;
+ if (stat(drv->hostapd_addr.sun_path, &st) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: lost connection to AP: %s",
+ __func__, strerror(errno));
+ drv->associated = 0;
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+ }
+ }
+#endif /* DRIVER_TEST_UNIX */
+
+ eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
+}
+
+
+static int wpa_driver_test_set_wpa(void *priv, int enabled)
+{
+ wpa_printf(MSG_DEBUG, "%s: enabled=%d", __func__, enabled);
+ return 0;
+}
+
+
+static void wpa_driver_test_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+#ifdef DRIVER_TEST_UNIX
+static void wpa_driver_scan_dir(struct wpa_driver_test_data *drv,
+ const char *path)
+{
+ struct dirent *dent;
+ DIR *dir;
+ struct sockaddr_un addr;
+ char cmd[512], *pos, *end;
+ int ret;
+
+ dir = opendir(path);
+ if (dir == NULL)
+ return;
+
+ end = cmd + sizeof(cmd);
+ pos = cmd;
+ ret = os_snprintf(pos, end - pos, "SCAN " MACSTR,
+ MAC2STR(drv->own_addr));
+ if (ret >= 0 && ret < end - pos)
+ pos += ret;
+ if (drv->probe_req_ie) {
+ ret = os_snprintf(pos, end - pos, " ");
+ if (ret >= 0 && ret < end - pos)
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, end - pos, drv->probe_req_ie,
+ drv->probe_req_ie_len);
+ }
+ end[-1] = '\0';
+
+ while ((dent = readdir(dir))) {
+ if (os_strncmp(dent->d_name, "AP-", 3) != 0)
+ continue;
+ wpa_printf(MSG_DEBUG, "%s: SCAN %s", __func__, dent->d_name);
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_snprintf(addr.sun_path, sizeof(addr.sun_path), "%s/%s",
+ path, dent->d_name);
+
+ if (sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
+ (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("sendto(test_socket)");
+ }
+ }
+ closedir(dir);
+}
+#endif /* DRIVER_TEST_UNIX */
+
+
+static int wpa_driver_test_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_test_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: priv=%p", __func__, priv);
+
+ drv->num_scanres = 0;
+
+#ifdef DRIVER_TEST_UNIX
+ if (drv->test_socket >= 0 && drv->test_dir)
+ wpa_driver_scan_dir(drv, drv->test_dir);
+
+ if (drv->test_socket >= 0 && drv->hostapd_addr_set &&
+ sendto(drv->test_socket, "SCAN", 4, 0,
+ (struct sockaddr *) &drv->hostapd_addr,
+ sizeof(drv->hostapd_addr)) < 0) {
+ perror("sendto(test_socket)");
+ }
+#endif /* DRIVER_TEST_UNIX */
+
+ if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
+ sendto(drv->test_socket, "SCAN", 4, 0,
+ (struct sockaddr *) &drv->hostapd_addr_udp,
+ sizeof(drv->hostapd_addr_udp)) < 0) {
+ perror("sendto(test_socket)");
+ }
+
+ eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(1, 0, wpa_driver_test_scan_timeout, drv,
+ drv->ctx);
+ return 0;
+}
+
+
+static struct wpa_scan_results * wpa_driver_test_get_scan_results2(void *priv)
+{
+ struct wpa_driver_test_data *drv = priv;
+ struct wpa_scan_results *res;
+ size_t i;
+
+ res = os_zalloc(sizeof(*res));
+ if (res == NULL)
+ return NULL;
+
+ res->res = os_zalloc(drv->num_scanres * sizeof(struct wpa_scan_res *));
+ if (res->res == NULL) {
+ os_free(res);
+ return NULL;
+ }
+
+ for (i = 0; i < drv->num_scanres; i++) {
+ struct wpa_scan_res *r;
+ if (drv->scanres[i] == NULL)
+ continue;
+ r = os_malloc(sizeof(*r) + drv->scanres[i]->ie_len);
+ if (r == NULL)
+ break;
+ os_memcpy(r, drv->scanres[i],
+ sizeof(*r) + drv->scanres[i]->ie_len);
+ res->res[res->num++] = r;
+ }
+
+ return res;
+}
+
+
+static int wpa_driver_test_set_key(void *priv, wpa_alg alg, const u8 *addr,
+ int key_idx, int set_tx,
+ const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ wpa_printf(MSG_DEBUG, "%s: priv=%p alg=%d key_idx=%d set_tx=%d",
+ __func__, priv, alg, key_idx, set_tx);
+ if (addr) {
+ wpa_printf(MSG_DEBUG, " addr=" MACSTR, MAC2STR(addr));
+ }
+ if (seq) {
+ wpa_hexdump(MSG_DEBUG, " seq", seq, seq_len);
+ }
+ if (key) {
+ wpa_hexdump(MSG_DEBUG, " key", key, key_len);
+ }
+ return 0;
+}
+
+
+static int wpa_driver_test_associate(
+ void *priv, struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_test_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s: priv=%p freq=%d pairwise_suite=%d "
+ "group_suite=%d key_mgmt_suite=%d auth_alg=%d mode=%d",
+ __func__, priv, params->freq, params->pairwise_suite,
+ params->group_suite, params->key_mgmt_suite,
+ params->auth_alg, params->mode);
+ if (params->bssid) {
+ wpa_printf(MSG_DEBUG, " bssid=" MACSTR,
+ MAC2STR(params->bssid));
+ }
+ if (params->ssid) {
+ wpa_hexdump_ascii(MSG_DEBUG, " ssid",
+ params->ssid, params->ssid_len);
+ }
+ if (params->wpa_ie) {
+ wpa_hexdump(MSG_DEBUG, " wpa_ie",
+ params->wpa_ie, params->wpa_ie_len);
+ drv->assoc_wpa_ie_len = params->wpa_ie_len;
+ if (drv->assoc_wpa_ie_len > sizeof(drv->assoc_wpa_ie))
+ drv->assoc_wpa_ie_len = sizeof(drv->assoc_wpa_ie);
+ os_memcpy(drv->assoc_wpa_ie, params->wpa_ie,
+ drv->assoc_wpa_ie_len);
+ } else
+ drv->assoc_wpa_ie_len = 0;
+
+#ifdef DRIVER_TEST_UNIX
+ if (drv->test_dir && params->bssid) {
+ os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr));
+ drv->hostapd_addr.sun_family = AF_UNIX;
+ os_snprintf(drv->hostapd_addr.sun_path,
+ sizeof(drv->hostapd_addr.sun_path),
+ "%s/AP-" MACSTR,
+ drv->test_dir, MAC2STR(params->bssid));
+ drv->hostapd_addr_set = 1;
+ }
+#endif /* DRIVER_TEST_UNIX */
+
+ if (drv->test_socket >= 0 &&
+ (drv->hostapd_addr_set || drv->hostapd_addr_udp_set)) {
+ char cmd[200], *pos, *end;
+ int ret;
+ end = cmd + sizeof(cmd);
+ pos = cmd;
+ ret = os_snprintf(pos, end - pos, "ASSOC " MACSTR " ",
+ MAC2STR(drv->own_addr));
+ if (ret >= 0 && ret < end - pos)
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, end - pos, params->ssid,
+ params->ssid_len);
+ ret = os_snprintf(pos, end - pos, " ");
+ if (ret >= 0 && ret < end - pos)
+ pos += ret;
+ pos += wpa_snprintf_hex(pos, end - pos, params->wpa_ie,
+ params->wpa_ie_len);
+ end[-1] = '\0';
+#ifdef DRIVER_TEST_UNIX
+ if (drv->hostapd_addr_set &&
+ sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
+ (struct sockaddr *) &drv->hostapd_addr,
+ sizeof(drv->hostapd_addr)) < 0) {
+ perror("sendto(test_socket)");
+ return -1;
+ }
+#endif /* DRIVER_TEST_UNIX */
+ if (drv->hostapd_addr_udp_set &&
+ sendto(drv->test_socket, cmd, os_strlen(cmd), 0,
+ (struct sockaddr *) &drv->hostapd_addr_udp,
+ sizeof(drv->hostapd_addr_udp)) < 0) {
+ perror("sendto(test_socket)");
+ return -1;
+ }
+
+ os_memcpy(drv->ssid, params->ssid, params->ssid_len);
+ drv->ssid_len = params->ssid_len;
+ } else {
+ drv->associated = 1;
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_test_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_test_data *drv = priv;
+ os_memcpy(bssid, drv->bssid, ETH_ALEN);
+ return 0;
+}
+
+
+static int wpa_driver_test_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_test_data *drv = priv;
+ os_memcpy(ssid, drv->ssid, 32);
+ return drv->ssid_len;
+}
+
+
+static int wpa_driver_test_send_disassoc(struct wpa_driver_test_data *drv)
+{
+#ifdef DRIVER_TEST_UNIX
+ if (drv->test_socket >= 0 &&
+ sendto(drv->test_socket, "DISASSOC", 8, 0,
+ (struct sockaddr *) &drv->hostapd_addr,
+ sizeof(drv->hostapd_addr)) < 0) {
+ perror("sendto(test_socket)");
+ return -1;
+ }
+#endif /* DRIVER_TEST_UNIX */
+ if (drv->test_socket >= 0 && drv->hostapd_addr_udp_set &&
+ sendto(drv->test_socket, "DISASSOC", 8, 0,
+ (struct sockaddr *) &drv->hostapd_addr_udp,
+ sizeof(drv->hostapd_addr_udp)) < 0) {
+ perror("sendto(test_socket)");
+ return -1;
+ }
+ return 0;
+}
+
+
+static int wpa_driver_test_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_test_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
+ __func__, MAC2STR(addr), reason_code);
+ os_memset(drv->bssid, 0, ETH_ALEN);
+ drv->associated = 0;
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+ return wpa_driver_test_send_disassoc(drv);
+}
+
+
+static int wpa_driver_test_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_test_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s addr=" MACSTR " reason_code=%d",
+ __func__, MAC2STR(addr), reason_code);
+ os_memset(drv->bssid, 0, ETH_ALEN);
+ drv->associated = 0;
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+ return wpa_driver_test_send_disassoc(drv);
+}
+
+
+static void wpa_driver_test_scanresp(struct wpa_driver_test_data *drv,
+ struct sockaddr *from,
+ socklen_t fromlen,
+ const char *data)
+{
+ struct wpa_scan_res *res;
+ const char *pos, *pos2;
+ size_t len;
+ u8 *ie_pos, *ie_start, *ie_end;
+#define MAX_IE_LEN 1000
+
+ wpa_printf(MSG_DEBUG, "test_driver: SCANRESP %s", data);
+ if (drv->num_scanres >= MAX_SCAN_RESULTS) {
+ wpa_printf(MSG_DEBUG, "test_driver: No room for the new scan "
+ "result");
+ return;
+ }
+
+ /* SCANRESP BSSID SSID IEs */
+
+ res = os_zalloc(sizeof(*res) + MAX_IE_LEN);
+ if (res == NULL)
+ return;
+ ie_start = ie_pos = (u8 *) (res + 1);
+ ie_end = ie_pos + MAX_IE_LEN;
+
+ if (hwaddr_aton(data, res->bssid)) {
+ wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in scanres");
+ os_free(res);
+ return;
+ }
+
+ pos = data + 17;
+ while (*pos == ' ')
+ pos++;
+ pos2 = os_strchr(pos, ' ');
+ if (pos2 == NULL) {
+ wpa_printf(MSG_DEBUG, "test_driver: invalid SSID termination "
+ "in scanres");
+ os_free(res);
+ return;
+ }
+ len = (pos2 - pos) / 2;
+ if (len > 32)
+ len = 32;
+ /*
+ * Generate SSID IE from the SSID field since this IE is not included
+ * in the main IE field.
+ */
+ *ie_pos++ = WLAN_EID_SSID;
+ *ie_pos++ = len;
+ if (hexstr2bin(pos, ie_pos, len) < 0) {
+ wpa_printf(MSG_DEBUG, "test_driver: invalid SSID in scanres");
+ os_free(res);
+ return;
+ }
+ ie_pos += len;
+
+ pos = pos2 + 1;
+ pos2 = os_strchr(pos, ' ');
+ if (pos2 == NULL)
+ len = os_strlen(pos) / 2;
+ else
+ len = (pos2 - pos) / 2;
+ if ((int) len > ie_end - ie_pos)
+ len = ie_end - ie_pos;
+ if (hexstr2bin(pos, ie_pos, len) < 0) {
+ wpa_printf(MSG_DEBUG, "test_driver: invalid IEs in scanres");
+ os_free(res);
+ return;
+ }
+ ie_pos += len;
+ res->ie_len = ie_pos - ie_start;
+
+ if (pos2) {
+ pos = pos2 + 1;
+ while (*pos == ' ')
+ pos++;
+ if (os_strncmp(pos, "PRIVACY", 7) == 0)
+ res->caps |= IEEE80211_CAP_PRIVACY;
+ }
+
+ os_free(drv->scanres[drv->num_scanres]);
+ drv->scanres[drv->num_scanres++] = res;
+}
+
+
+static void wpa_driver_test_assocresp(struct wpa_driver_test_data *drv,
+ struct sockaddr *from,
+ socklen_t fromlen,
+ const char *data)
+{
+ /* ASSOCRESP BSSID <res> */
+ if (hwaddr_aton(data, drv->bssid)) {
+ wpa_printf(MSG_DEBUG, "test_driver: invalid BSSID in "
+ "assocresp");
+ }
+ if (drv->use_associnfo) {
+ union wpa_event_data event;
+ os_memset(&event, 0, sizeof(event));
+ event.assoc_info.req_ies = drv->assoc_wpa_ie;
+ event.assoc_info.req_ies_len = drv->assoc_wpa_ie_len;
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &event);
+ }
+ drv->associated = 1;
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOC, NULL);
+}
+
+
+static void wpa_driver_test_disassoc(struct wpa_driver_test_data *drv,
+ struct sockaddr *from,
+ socklen_t fromlen)
+{
+ drv->associated = 0;
+ wpa_supplicant_event(drv->ctx, EVENT_DISASSOC, NULL);
+}
+
+
+static void wpa_driver_test_eapol(struct wpa_driver_test_data *drv,
+ struct sockaddr *from,
+ socklen_t fromlen,
+ const u8 *data, size_t data_len)
+{
+ const u8 *src = drv->bssid;
+
+ if (data_len > 14) {
+ /* Skip Ethernet header */
+ src = data + ETH_ALEN;
+ data += 14;
+ data_len -= 14;
+ }
+ wpa_supplicant_rx_eapol(drv->ctx, src, data, data_len);
+}
+
+
+static void wpa_driver_test_mlme(struct wpa_driver_test_data *drv,
+ struct sockaddr *from,
+ socklen_t fromlen,
+ const u8 *data, size_t data_len)
+{
+#ifdef CONFIG_CLIENT_MLME
+ struct ieee80211_rx_status rx_status;
+ os_memset(&rx_status, 0, sizeof(rx_status));
+ wpa_supplicant_sta_rx(drv->ctx, data, data_len, &rx_status);
+#endif /* CONFIG_CLIENT_MLME */
+}
+
+
+static void wpa_driver_test_receive_unix(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ struct wpa_driver_test_data *drv = eloop_ctx;
+ char *buf;
+ int res;
+ struct sockaddr_storage from;
+ socklen_t fromlen = sizeof(from);
+ const size_t buflen = 2000;
+
+ buf = os_malloc(buflen);
+ if (buf == NULL)
+ return;
+ res = recvfrom(sock, buf, buflen - 1, 0,
+ (struct sockaddr *) &from, &fromlen);
+ if (res < 0) {
+ perror("recvfrom(test_socket)");
+ os_free(buf);
+ return;
+ }
+ buf[res] = '\0';
+
+ wpa_printf(MSG_DEBUG, "test_driver: received %u bytes", res);
+
+ if (os_strncmp(buf, "SCANRESP ", 9) == 0) {
+ wpa_driver_test_scanresp(drv, (struct sockaddr *) &from,
+ fromlen, buf + 9);
+ } else if (os_strncmp(buf, "ASSOCRESP ", 10) == 0) {
+ wpa_driver_test_assocresp(drv, (struct sockaddr *) &from,
+ fromlen, buf + 10);
+ } else if (os_strcmp(buf, "DISASSOC") == 0) {
+ wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
+ fromlen);
+ } else if (os_strcmp(buf, "DEAUTH") == 0) {
+ wpa_driver_test_disassoc(drv, (struct sockaddr *) &from,
+ fromlen);
+ } else if (os_strncmp(buf, "EAPOL ", 6) == 0) {
+ wpa_driver_test_eapol(drv, (struct sockaddr *) &from, fromlen,
+ (const u8 *) buf + 6, res - 6);
+ } else if (os_strncmp(buf, "MLME ", 5) == 0) {
+ wpa_driver_test_mlme(drv, (struct sockaddr *) &from, fromlen,
+ (const u8 *) buf + 5, res - 5);
+ } else {
+ wpa_hexdump_ascii(MSG_DEBUG, "Unknown test_socket command",
+ (u8 *) buf, res);
+ }
+ os_free(buf);
+}
+
+
+static void * wpa_driver_test_init2(void *ctx, const char *ifname,
+ void *global_priv)
+{
+ struct wpa_driver_test_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->global = global_priv;
+ drv->ctx = ctx;
+ drv->test_socket = -1;
+
+ /* Set dummy BSSID and SSID for testing. */
+ drv->bssid[0] = 0x02;
+ drv->bssid[1] = 0x00;
+ drv->bssid[2] = 0x00;
+ drv->bssid[3] = 0x00;
+ drv->bssid[4] = 0x00;
+ drv->bssid[5] = 0x01;
+ os_memcpy(drv->ssid, "test", 5);
+ drv->ssid_len = 4;
+
+ /* Generate a MAC address to help testing with multiple STAs */
+ drv->own_addr[0] = 0x02; /* locally administered */
+ sha1_prf((const u8 *) ifname, os_strlen(ifname),
+ "wpa_supplicant test mac addr generation",
+ NULL, 0, drv->own_addr + 1, ETH_ALEN - 1);
+ eloop_register_timeout(1, 0, wpa_driver_test_poll, drv, NULL);
+
+ return drv;
+}
+
+
+static void wpa_driver_test_close_test_socket(struct wpa_driver_test_data *drv)
+{
+ if (drv->test_socket >= 0) {
+ eloop_unregister_read_sock(drv->test_socket);
+ close(drv->test_socket);
+ drv->test_socket = -1;
+ }
+
+ if (drv->own_socket_path) {
+ unlink(drv->own_socket_path);
+ os_free(drv->own_socket_path);
+ drv->own_socket_path = NULL;
+ }
+}
+
+
+static void wpa_driver_test_deinit(void *priv)
+{
+ struct wpa_driver_test_data *drv = priv;
+ int i;
+ wpa_driver_test_close_test_socket(drv);
+ eloop_cancel_timeout(wpa_driver_test_scan_timeout, drv, drv->ctx);
+ eloop_cancel_timeout(wpa_driver_test_poll, drv, NULL);
+ os_free(drv->test_dir);
+ for (i = 0; i < MAX_SCAN_RESULTS; i++)
+ os_free(drv->scanres[i]);
+ os_free(drv->probe_req_ie);
+ os_free(drv);
+}
+
+
+static int wpa_driver_test_attach(struct wpa_driver_test_data *drv,
+ const char *dir)
+{
+#ifdef DRIVER_TEST_UNIX
+ static unsigned int counter = 0;
+ struct sockaddr_un addr;
+ size_t len;
+
+ os_free(drv->own_socket_path);
+ if (dir) {
+ len = os_strlen(dir) + 30;
+ drv->own_socket_path = os_malloc(len);
+ if (drv->own_socket_path == NULL)
+ return -1;
+ os_snprintf(drv->own_socket_path, len, "%s/STA-" MACSTR,
+ dir, MAC2STR(drv->own_addr));
+ } else {
+ drv->own_socket_path = os_malloc(100);
+ if (drv->own_socket_path == NULL)
+ return -1;
+ os_snprintf(drv->own_socket_path, 100,
+ "/tmp/wpa_supplicant_test-%d-%d",
+ getpid(), counter++);
+ }
+
+ drv->test_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (drv->test_socket < 0) {
+ perror("socket(PF_UNIX)");
+ os_free(drv->own_socket_path);
+ drv->own_socket_path = NULL;
+ return -1;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_strlcpy(addr.sun_path, drv->own_socket_path, sizeof(addr.sun_path));
+ if (bind(drv->test_socket, (struct sockaddr *) &addr,
+ sizeof(addr)) < 0) {
+ perror("bind(PF_UNIX)");
+ close(drv->test_socket);
+ unlink(drv->own_socket_path);
+ os_free(drv->own_socket_path);
+ drv->own_socket_path = NULL;
+ return -1;
+ }
+
+ eloop_register_read_sock(drv->test_socket,
+ wpa_driver_test_receive_unix, drv, NULL);
+
+ return 0;
+#else /* DRIVER_TEST_UNIX */
+ return -1;
+#endif /* DRIVER_TEST_UNIX */
+}
+
+
+static int wpa_driver_test_attach_udp(struct wpa_driver_test_data *drv,
+ char *dst)
+{
+ char *pos;
+
+ pos = os_strchr(dst, ':');
+ if (pos == NULL)
+ return -1;
+ *pos++ = '\0';
+ wpa_printf(MSG_DEBUG, "%s: addr=%s port=%s", __func__, dst, pos);
+
+ drv->test_socket = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->test_socket < 0) {
+ perror("socket(PF_INET)");
+ return -1;
+ }
+
+ os_memset(&drv->hostapd_addr_udp, 0, sizeof(drv->hostapd_addr_udp));
+ drv->hostapd_addr_udp.sin_family = AF_INET;
+#if defined(CONFIG_NATIVE_WINDOWS) || defined(CONFIG_ANSI_C_EXTRA)
+ {
+ int a[4];
+ u8 *pos;
+ sscanf(dst, "%d.%d.%d.%d", &a[0], &a[1], &a[2], &a[3]);
+ pos = (u8 *) &drv->hostapd_addr_udp.sin_addr;
+ *pos++ = a[0];
+ *pos++ = a[1];
+ *pos++ = a[2];
+ *pos++ = a[3];
+ }
+#else /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
+ inet_aton(dst, &drv->hostapd_addr_udp.sin_addr);
+#endif /* CONFIG_NATIVE_WINDOWS or CONFIG_ANSI_C_EXTRA */
+ drv->hostapd_addr_udp.sin_port = htons(atoi(pos));
+
+ drv->hostapd_addr_udp_set = 1;
+
+ eloop_register_read_sock(drv->test_socket,
+ wpa_driver_test_receive_unix, drv, NULL);
+
+ return 0;
+}
+
+
+static int wpa_driver_test_set_param(void *priv, const char *param)
+{
+ struct wpa_driver_test_data *drv = priv;
+ const char *pos;
+
+ wpa_printf(MSG_DEBUG, "%s: param='%s'", __func__, param);
+ if (param == NULL)
+ return 0;
+
+ wpa_driver_test_close_test_socket(drv);
+
+#ifdef DRIVER_TEST_UNIX
+ pos = os_strstr(param, "test_socket=");
+ if (pos) {
+ const char *pos2;
+ size_t len;
+
+ pos += 12;
+ pos2 = os_strchr(pos, ' ');
+ if (pos2)
+ len = pos2 - pos;
+ else
+ len = os_strlen(pos);
+ if (len > sizeof(drv->hostapd_addr.sun_path))
+ return -1;
+ os_memset(&drv->hostapd_addr, 0, sizeof(drv->hostapd_addr));
+ drv->hostapd_addr.sun_family = AF_UNIX;
+ os_memcpy(drv->hostapd_addr.sun_path, pos, len);
+ drv->hostapd_addr_set = 1;
+ }
+#endif /* DRIVER_TEST_UNIX */
+
+ pos = os_strstr(param, "test_dir=");
+ if (pos) {
+ char *end;
+ os_free(drv->test_dir);
+ drv->test_dir = os_strdup(pos + 9);
+ if (drv->test_dir == NULL)
+ return -1;
+ end = os_strchr(drv->test_dir, ' ');
+ if (end)
+ *end = '\0';
+ if (wpa_driver_test_attach(drv, drv->test_dir))
+ return -1;
+ } else {
+ pos = os_strstr(param, "test_udp=");
+ if (pos) {
+ char *dst, *epos;
+ dst = os_strdup(pos + 9);
+ if (dst == NULL)
+ return -1;
+ epos = os_strchr(dst, ' ');
+ if (epos)
+ *epos = '\0';
+ if (wpa_driver_test_attach_udp(drv, dst))
+ return -1;
+ os_free(dst);
+ } else if (wpa_driver_test_attach(drv, NULL))
+ return -1;
+ }
+
+ if (os_strstr(param, "use_associnfo=1")) {
+ wpa_printf(MSG_DEBUG, "test_driver: Use AssocInfo events");
+ drv->use_associnfo = 1;
+ }
+
+#ifdef CONFIG_CLIENT_MLME
+ if (os_strstr(param, "use_mlme=1")) {
+ wpa_printf(MSG_DEBUG, "test_driver: Use internal MLME");
+ drv->use_mlme = 1;
+ }
+#endif /* CONFIG_CLIENT_MLME */
+
+ return 0;
+}
+
+
+static const u8 * wpa_driver_test_get_mac_addr(void *priv)
+{
+ struct wpa_driver_test_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ return drv->own_addr;
+}
+
+
+static int wpa_driver_test_send_eapol(void *priv, const u8 *dest, u16 proto,
+ const u8 *data, size_t data_len)
+{
+ struct wpa_driver_test_data *drv = priv;
+ char *msg;
+ size_t msg_len;
+ struct l2_ethhdr eth;
+ struct sockaddr *addr;
+ socklen_t alen;
+#ifdef DRIVER_TEST_UNIX
+ struct sockaddr_un addr_un;
+#endif /* DRIVER_TEST_UNIX */
+
+ wpa_hexdump(MSG_MSGDUMP, "test_send_eapol TX frame", data, data_len);
+
+ os_memset(&eth, 0, sizeof(eth));
+ os_memcpy(eth.h_dest, dest, ETH_ALEN);
+ os_memcpy(eth.h_source, drv->own_addr, ETH_ALEN);
+ eth.h_proto = host_to_be16(proto);
+
+ msg_len = 6 + sizeof(eth) + data_len;
+ msg = os_malloc(msg_len);
+ if (msg == NULL)
+ return -1;
+ os_memcpy(msg, "EAPOL ", 6);
+ os_memcpy(msg + 6, &eth, sizeof(eth));
+ os_memcpy(msg + 6 + sizeof(eth), data, data_len);
+
+ if (os_memcmp(dest, drv->bssid, ETH_ALEN) == 0 ||
+ drv->test_dir == NULL) {
+ if (drv->hostapd_addr_udp_set) {
+ addr = (struct sockaddr *) &drv->hostapd_addr_udp;
+ alen = sizeof(drv->hostapd_addr_udp);
+ } else {
+#ifdef DRIVER_TEST_UNIX
+ addr = (struct sockaddr *) &drv->hostapd_addr;
+ alen = sizeof(drv->hostapd_addr);
+#else /* DRIVER_TEST_UNIX */
+ os_free(msg);
+ return -1;
+#endif /* DRIVER_TEST_UNIX */
+ }
+ } else {
+#ifdef DRIVER_TEST_UNIX
+ struct stat st;
+ os_memset(&addr_un, 0, sizeof(addr_un));
+ addr_un.sun_family = AF_UNIX;
+ os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
+ "%s/STA-" MACSTR, drv->test_dir, MAC2STR(dest));
+ if (stat(addr_un.sun_path, &st) < 0) {
+ os_snprintf(addr_un.sun_path, sizeof(addr_un.sun_path),
+ "%s/AP-" MACSTR,
+ drv->test_dir, MAC2STR(dest));
+ }
+ addr = (struct sockaddr *) &addr_un;
+ alen = sizeof(addr_un);
+#else /* DRIVER_TEST_UNIX */
+ os_free(msg);
+ return -1;
+#endif /* DRIVER_TEST_UNIX */
+ }
+
+ if (sendto(drv->test_socket, msg, msg_len, 0, addr, alen) < 0) {
+ perror("sendmsg(test_socket)");
+ os_free(msg);
+ return -1;
+ }
+
+ os_free(msg);
+ return 0;
+}
+
+
+static int wpa_driver_test_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ struct wpa_driver_test_data *drv = priv;
+ os_memset(capa, 0, sizeof(*capa));
+ capa->key_mgmt = WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE |
+ WPA_DRIVER_CAPA_KEY_MGMT_FT |
+ WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK;
+ capa->enc = WPA_DRIVER_CAPA_ENC_WEP40 |
+ WPA_DRIVER_CAPA_ENC_WEP104 |
+ WPA_DRIVER_CAPA_ENC_TKIP |
+ WPA_DRIVER_CAPA_ENC_CCMP;
+ capa->auth = WPA_DRIVER_AUTH_OPEN |
+ WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+ if (drv->use_mlme)
+ capa->flags |= WPA_DRIVER_FLAGS_USER_SPACE_MLME;
+
+ return 0;
+}
+
+
+static int wpa_driver_test_mlme_setprotection(void *priv, const u8 *addr,
+ int protect_type,
+ int key_type)
+{
+ wpa_printf(MSG_DEBUG, "%s: protect_type=%d key_type=%d",
+ __func__, protect_type, key_type);
+
+ if (addr) {
+ wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR,
+ __func__, MAC2STR(addr));
+ }
+
+ return 0;
+}
+
+
+#ifdef CONFIG_CLIENT_MLME
+static struct wpa_hw_modes *
+wpa_driver_test_get_hw_feature_data(void *priv, u16 *num_modes, u16 *flags)
+{
+ struct wpa_hw_modes *modes;
+
+ *num_modes = 1;
+ *flags = 0;
+ modes = os_zalloc(*num_modes * sizeof(struct wpa_hw_modes));
+ if (modes == NULL)
+ return NULL;
+ modes[0].mode = WPA_MODE_IEEE80211G;
+ modes[0].num_channels = 1;
+ modes[0].num_rates = 1;
+ modes[0].channels = os_zalloc(sizeof(struct wpa_channel_data));
+ modes[0].rates = os_zalloc(sizeof(struct wpa_rate_data));
+ if (modes[0].channels == NULL || modes[0].rates == NULL) {
+ wpa_supplicant_sta_free_hw_features(modes, *num_modes);
+ return NULL;
+ }
+ modes[0].channels[0].chan = 1;
+ modes[0].channels[0].freq = 2412;
+ modes[0].channels[0].flag = WPA_CHAN_W_SCAN | WPA_CHAN_W_ACTIVE_SCAN;
+ modes[0].rates[0].rate = 10;
+ modes[0].rates[0].flags = WPA_RATE_BASIC | WPA_RATE_SUPPORTED |
+ WPA_RATE_CCK | WPA_RATE_MANDATORY;
+
+ return modes;
+}
+
+
+static int wpa_driver_test_set_channel(void *priv, wpa_hw_mode phymode,
+ int chan, int freq)
+{
+ wpa_printf(MSG_DEBUG, "%s: phymode=%d chan=%d freq=%d",
+ __func__, phymode, chan, freq);
+ return 0;
+}
+
+
+static int wpa_driver_test_send_mlme(void *priv, const u8 *data,
+ size_t data_len)
+{
+ struct wpa_driver_test_data *drv = priv;
+ struct msghdr msg;
+ struct iovec io[2];
+ struct sockaddr_un addr;
+ const u8 *dest;
+ struct dirent *dent;
+ DIR *dir;
+
+ wpa_hexdump(MSG_MSGDUMP, "test_send_mlme", data, data_len);
+ if (data_len < 10)
+ return -1;
+ dest = data + 4;
+
+ io[0].iov_base = "MLME ";
+ io[0].iov_len = 5;
+ io[1].iov_base = (u8 *) data;
+ io[1].iov_len = data_len;
+
+ os_memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 2;
+ if (os_memcmp(dest, drv->bssid, ETH_ALEN) == 0 ||
+ drv->test_dir == NULL) {
+ if (drv->hostapd_addr_udp_set) {
+ msg.msg_name = &drv->hostapd_addr_udp;
+ msg.msg_namelen = sizeof(drv->hostapd_addr_udp);
+ } else {
+#ifdef DRIVER_TEST_UNIX
+ msg.msg_name = &drv->hostapd_addr;
+ msg.msg_namelen = sizeof(drv->hostapd_addr);
+#endif /* DRIVER_TEST_UNIX */
+ }
+ } else if (os_memcmp(dest, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
+ {
+ dir = opendir(drv->test_dir);
+ if (dir == NULL)
+ return -1;
+ while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+ /* Skip the file if it is not a socket.
+ * Also accept DT_UNKNOWN (0) in case
+ * the C library or underlying file
+ * system does not support d_type. */
+ if (dent->d_type != DT_SOCK &&
+ dent->d_type != DT_UNKNOWN)
+ continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+ if (os_strcmp(dent->d_name, ".") == 0 ||
+ os_strcmp(dent->d_name, "..") == 0)
+ continue;
+ wpa_printf(MSG_DEBUG, "%s: Send broadcast MLME to %s",
+ __func__, dent->d_name);
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+ "%s/%s", drv->test_dir, dent->d_name);
+
+ msg.msg_name = &addr;
+ msg.msg_namelen = sizeof(addr);
+
+ if (sendmsg(drv->test_socket, &msg, 0) < 0)
+ perror("sendmsg(test_socket)");
+ }
+ closedir(dir);
+ return 0;
+ } else {
+ struct stat st;
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+ "%s/AP-" MACSTR, drv->test_dir, MAC2STR(dest));
+ if (stat(addr.sun_path, &st) < 0) {
+ os_snprintf(addr.sun_path, sizeof(addr.sun_path),
+ "%s/STA-" MACSTR,
+ drv->test_dir, MAC2STR(dest));
+ }
+ msg.msg_name = &addr;
+ msg.msg_namelen = sizeof(addr);
+ }
+
+ if (sendmsg(drv->test_socket, &msg, 0) < 0) {
+ perror("sendmsg(test_socket)");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_test_mlme_add_sta(void *priv, const u8 *addr,
+ const u8 *supp_rates,
+ size_t supp_rates_len)
+{
+ wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr));
+ return 0;
+}
+
+
+static int wpa_driver_test_mlme_remove_sta(void *priv, const u8 *addr)
+{
+ wpa_printf(MSG_DEBUG, "%s: addr=" MACSTR, __func__, MAC2STR(addr));
+ return 0;
+}
+
+
+static int wpa_driver_test_set_ssid(void *priv, const u8 *ssid,
+ size_t ssid_len)
+{
+ wpa_printf(MSG_DEBUG, "%s", __func__);
+ return 0;
+}
+
+
+static int wpa_driver_test_set_bssid(void *priv, const u8 *bssid)
+{
+ wpa_printf(MSG_DEBUG, "%s: bssid=" MACSTR, __func__, MAC2STR(bssid));
+ return 0;
+}
+#endif /* CONFIG_CLIENT_MLME */
+
+
+static int wpa_driver_test_set_probe_req_ie(void *priv, const u8 *ies,
+ size_t ies_len)
+{
+ struct wpa_driver_test_data *drv = priv;
+
+ os_free(drv->probe_req_ie);
+ if (ies) {
+ drv->probe_req_ie = os_malloc(ies_len);
+ if (drv->probe_req_ie == NULL) {
+ drv->probe_req_ie_len = 0;
+ return -1;
+ }
+ os_memcpy(drv->probe_req_ie, ies, ies_len);
+ drv->probe_req_ie_len = ies_len;
+ } else {
+ drv->probe_req_ie = NULL;
+ drv->probe_req_ie_len = 0;
+ }
+ return 0;
+}
+
+
+static void * wpa_driver_test_global_init(void)
+{
+ struct wpa_driver_test_global *global;
+
+ global = os_zalloc(sizeof(*global));
+ return global;
+}
+
+
+static void wpa_driver_test_global_deinit(void *priv)
+{
+ struct wpa_driver_test_global *global = priv;
+ os_free(global);
+}
+
+
+static struct wpa_interface_info *
+wpa_driver_test_get_interfaces(void *global_priv)
+{
+ /* struct wpa_driver_test_global *global = priv; */
+ struct wpa_interface_info *iface;
+
+ iface = os_zalloc(sizeof(*iface));
+ if (iface == NULL)
+ return iface;
+ iface->ifname = os_strdup("sta0");
+ iface->desc = os_strdup("test interface 0");
+ iface->drv_name = "test";
+ iface->next = os_zalloc(sizeof(*iface));
+ if (iface->next) {
+ iface->next->ifname = os_strdup("sta1");
+ iface->next->desc = os_strdup("test interface 1");
+ iface->next->drv_name = "test";
+ }
+
+ return iface;
+}
+
+
+const struct wpa_driver_ops wpa_driver_test_ops = {
+ "test",
+ "wpa_supplicant test driver",
+ wpa_driver_test_get_bssid,
+ wpa_driver_test_get_ssid,
+ wpa_driver_test_set_wpa,
+ wpa_driver_test_set_key,
+ NULL /* init */,
+ wpa_driver_test_deinit,
+ wpa_driver_test_set_param,
+ NULL /* set_countermeasures */,
+ NULL /* set_drop_unencrypted */,
+ wpa_driver_test_scan,
+ NULL /* get_scan_results */,
+ wpa_driver_test_deauthenticate,
+ wpa_driver_test_disassociate,
+ wpa_driver_test_associate,
+ NULL /* set_auth_alg */,
+ NULL /* add_pmkid */,
+ NULL /* remove_pmkid */,
+ NULL /* flush_pmkid */,
+ wpa_driver_test_get_capa,
+ NULL /* poll */,
+ NULL /* get_ifname */,
+ wpa_driver_test_get_mac_addr,
+ wpa_driver_test_send_eapol,
+ NULL /* set_operstate */,
+ wpa_driver_test_mlme_setprotection,
+#ifdef CONFIG_CLIENT_MLME
+ wpa_driver_test_get_hw_feature_data,
+ wpa_driver_test_set_channel,
+ wpa_driver_test_set_ssid,
+ wpa_driver_test_set_bssid,
+ wpa_driver_test_send_mlme,
+ wpa_driver_test_mlme_add_sta,
+ wpa_driver_test_mlme_remove_sta,
+#else /* CONFIG_CLIENT_MLME */
+ NULL /* get_hw_feature_data */,
+ NULL /* set_channel */,
+ NULL /* set_ssid */,
+ NULL /* set_bssid */,
+ NULL /* send_mlme */,
+ NULL /* mlme_add_sta */,
+ NULL /* mlme_remove_sta */,
+#endif /* CONFIG_CLIENT_MLME */
+ NULL /* update_ft_ies */,
+ NULL /* send_ft_action */,
+ wpa_driver_test_get_scan_results2,
+ wpa_driver_test_set_probe_req_ie,
+ NULL /* set_mode */,
+ NULL /* set_country */,
+ wpa_driver_test_global_init,
+ wpa_driver_test_global_deinit,
+ wpa_driver_test_init2,
+ wpa_driver_test_get_interfaces
+};
diff --git a/src/drivers/driver_wext.c b/src/drivers/driver_wext.c
new file mode 100644
index 0000000..e771d37
--- /dev/null
+++ b/src/drivers/driver_wext.c
@@ -0,0 +1,2375 @@
+/*
+ * WPA Supplicant - driver interaction with generic Linux Wireless Extensions
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This file implements a driver interface for the Linux Wireless Extensions.
+ * When used with WE-18 or newer, this interface can be used as-is with number
+ * of drivers. In addition to this, some of the common functions in this file
+ * can be used by other driver interface implementations that use generic WE
+ * ioctls, but require private ioctls for some of the functionality.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if_arp.h>
+
+#include "wireless_copy.h"
+#include "common.h"
+#include "driver.h"
+#include "eloop.h"
+#include "priv_netlink.h"
+#include "driver_wext.h"
+#include "ieee802_11_defs.h"
+#include "wpa_common.h"
+
+
+static int wpa_driver_wext_flush_pmkid(void *priv);
+static int wpa_driver_wext_get_range(void *priv);
+static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv);
+static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv);
+
+
+static int wpa_driver_wext_send_oper_ifla(struct wpa_driver_wext_data *drv,
+ int linkmode, int operstate)
+{
+ struct {
+ struct nlmsghdr hdr;
+ struct ifinfomsg ifinfo;
+ char opts[16];
+ } req;
+ struct rtattr *rta;
+ static int nl_seq;
+ ssize_t ret;
+
+ os_memset(&req, 0, sizeof(req));
+
+ req.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct ifinfomsg));
+ req.hdr.nlmsg_type = RTM_SETLINK;
+ req.hdr.nlmsg_flags = NLM_F_REQUEST;
+ req.hdr.nlmsg_seq = ++nl_seq;
+ req.hdr.nlmsg_pid = 0;
+
+ req.ifinfo.ifi_family = AF_UNSPEC;
+ req.ifinfo.ifi_type = 0;
+ req.ifinfo.ifi_index = drv->ifindex;
+ req.ifinfo.ifi_flags = 0;
+ req.ifinfo.ifi_change = 0;
+
+ if (linkmode != -1) {
+ rta = aliasing_hide_typecast(
+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len)),
+ struct rtattr);
+ rta->rta_type = IFLA_LINKMODE;
+ rta->rta_len = RTA_LENGTH(sizeof(char));
+ *((char *) RTA_DATA(rta)) = linkmode;
+ req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
+ RTA_LENGTH(sizeof(char));
+ }
+ if (operstate != -1) {
+ rta = (struct rtattr *)
+ ((char *) &req + NLMSG_ALIGN(req.hdr.nlmsg_len));
+ rta->rta_type = IFLA_OPERSTATE;
+ rta->rta_len = RTA_LENGTH(sizeof(char));
+ *((char *) RTA_DATA(rta)) = operstate;
+ req.hdr.nlmsg_len = NLMSG_ALIGN(req.hdr.nlmsg_len) +
+ RTA_LENGTH(sizeof(char));
+ }
+
+ wpa_printf(MSG_DEBUG, "WEXT: Operstate: linkmode=%d, operstate=%d",
+ linkmode, operstate);
+
+ ret = send(drv->event_sock, &req, req.hdr.nlmsg_len, 0);
+ if (ret < 0) {
+ wpa_printf(MSG_DEBUG, "WEXT: Sending operstate IFLA failed: "
+ "%s (assume operstate is not supported)",
+ strerror(errno));
+ }
+
+ return ret < 0 ? -1 : 0;
+}
+
+
+int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
+ int idx, u32 value)
+{
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.param.flags = idx & IW_AUTH_INDEX;
+ iwr.u.param.value = value;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWAUTH, &iwr) < 0) {
+ if (errno != EOPNOTSUPP) {
+ wpa_printf(MSG_DEBUG, "WEXT: SIOCSIWAUTH(param %d "
+ "value 0x%x) failed: %s)",
+ idx, value, strerror(errno));
+ }
+ ret = errno == EOPNOTSUPP ? -2 : -1;
+ }
+
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_get_bssid - Get BSSID, SIOCGIWAP
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @bssid: Buffer for BSSID
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_get_bssid(void *priv, u8 *bssid)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWAP, &iwr) < 0) {
+ perror("ioctl[SIOCGIWAP]");
+ ret = -1;
+ }
+ os_memcpy(bssid, iwr.u.ap_addr.sa_data, ETH_ALEN);
+
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_set_bssid - Set BSSID, SIOCSIWAP
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @bssid: BSSID
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.ap_addr.sa_family = ARPHRD_ETHER;
+ if (bssid)
+ os_memcpy(iwr.u.ap_addr.sa_data, bssid, ETH_ALEN);
+ else
+ os_memset(iwr.u.ap_addr.sa_data, 0, ETH_ALEN);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWAP, &iwr) < 0) {
+ perror("ioctl[SIOCSIWAP]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_get_ssid - Get SSID, SIOCGIWESSID
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @ssid: Buffer for the SSID; must be at least 32 bytes long
+ * Returns: SSID length on success, -1 on failure
+ */
+int wpa_driver_wext_get_ssid(void *priv, u8 *ssid)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.essid.pointer = (caddr_t) ssid;
+ iwr.u.essid.length = 32;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCGIWESSID]");
+ ret = -1;
+ } else {
+ ret = iwr.u.essid.length;
+ if (ret > 32)
+ ret = 32;
+ /* Some drivers include nul termination in the SSID, so let's
+ * remove it here before further processing. WE-21 changes this
+ * to explicitly require the length _not_ to include nul
+ * termination. */
+ if (ret > 0 && ssid[ret - 1] == '\0' &&
+ drv->we_version_compiled < 21)
+ ret--;
+ }
+
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_set_ssid - Set SSID, SIOCSIWESSID
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @ssid: SSID
+ * @ssid_len: Length of SSID (0..32)
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+ char buf[33];
+
+ if (ssid_len > 32)
+ return -1;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ /* flags: 1 = ESSID is active, 0 = not (promiscuous) */
+ iwr.u.essid.flags = (ssid_len != 0);
+ os_memset(buf, 0, sizeof(buf));
+ os_memcpy(buf, ssid, ssid_len);
+ iwr.u.essid.pointer = (caddr_t) buf;
+ if (drv->we_version_compiled < 21) {
+ /* For historic reasons, set SSID length to include one extra
+ * character, C string nul termination, even though SSID is
+ * really an octet string that should not be presented as a C
+ * string. Some Linux drivers decrement the length by one and
+ * can thus end up missing the last octet of the SSID if the
+ * length is not incremented here. WE-21 changes this to
+ * explicitly require the length _not_ to include nul
+ * termination. */
+ if (ssid_len)
+ ssid_len++;
+ }
+ iwr.u.essid.length = ssid_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWESSID, &iwr) < 0) {
+ perror("ioctl[SIOCSIWESSID]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_set_freq - Set frequency/channel, SIOCSIWFREQ
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @freq: Frequency in MHz
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_freq(void *priv, int freq)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.freq.m = freq * 100000;
+ iwr.u.freq.e = 1;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWFREQ, &iwr) < 0) {
+ perror("ioctl[SIOCSIWFREQ]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static void
+wpa_driver_wext_event_wireless_custom(void *ctx, char *custom)
+{
+ union wpa_event_data data;
+
+ wpa_printf(MSG_MSGDUMP, "WEXT: Custom wireless event: '%s'",
+ custom);
+
+ os_memset(&data, 0, sizeof(data));
+ /* Host AP driver */
+ if (os_strncmp(custom, "MLME-MICHAELMICFAILURE.indication", 33) == 0) {
+ data.michael_mic_failure.unicast =
+ os_strstr(custom, " unicast ") != NULL;
+ /* TODO: parse parameters(?) */
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+ } else if (os_strncmp(custom, "ASSOCINFO(ReqIEs=", 17) == 0) {
+ char *spos;
+ int bytes;
+
+ spos = custom + 17;
+
+ bytes = strspn(spos, "0123456789abcdefABCDEF");
+ if (!bytes || (bytes & 1))
+ return;
+ bytes /= 2;
+
+ data.assoc_info.req_ies = os_malloc(bytes);
+ if (data.assoc_info.req_ies == NULL)
+ return;
+
+ data.assoc_info.req_ies_len = bytes;
+ hexstr2bin(spos, data.assoc_info.req_ies, bytes);
+
+ spos += bytes * 2;
+
+ data.assoc_info.resp_ies = NULL;
+ data.assoc_info.resp_ies_len = 0;
+
+ if (os_strncmp(spos, " RespIEs=", 9) == 0) {
+ spos += 9;
+
+ bytes = strspn(spos, "0123456789abcdefABCDEF");
+ if (!bytes || (bytes & 1))
+ goto done;
+ bytes /= 2;
+
+ data.assoc_info.resp_ies = os_malloc(bytes);
+ if (data.assoc_info.resp_ies == NULL)
+ goto done;
+
+ data.assoc_info.resp_ies_len = bytes;
+ hexstr2bin(spos, data.assoc_info.resp_ies, bytes);
+ }
+
+ wpa_supplicant_event(ctx, EVENT_ASSOCINFO, &data);
+
+ done:
+ os_free(data.assoc_info.resp_ies);
+ os_free(data.assoc_info.req_ies);
+#ifdef CONFIG_PEERKEY
+ } else if (os_strncmp(custom, "STKSTART.request=", 17) == 0) {
+ if (hwaddr_aton(custom + 17, data.stkstart.peer)) {
+ wpa_printf(MSG_DEBUG, "WEXT: unrecognized "
+ "STKSTART.request '%s'", custom + 17);
+ return;
+ }
+ wpa_supplicant_event(ctx, EVENT_STKSTART, &data);
+#endif /* CONFIG_PEERKEY */
+ }
+}
+
+
+static int wpa_driver_wext_event_wireless_michaelmicfailure(
+ void *ctx, const char *ev, size_t len)
+{
+ const struct iw_michaelmicfailure *mic;
+ union wpa_event_data data;
+
+ if (len < sizeof(*mic))
+ return -1;
+
+ mic = (const struct iw_michaelmicfailure *) ev;
+
+ wpa_printf(MSG_DEBUG, "Michael MIC failure wireless event: "
+ "flags=0x%x src_addr=" MACSTR, mic->flags,
+ MAC2STR(mic->src_addr.sa_data));
+
+ os_memset(&data, 0, sizeof(data));
+ data.michael_mic_failure.unicast = !(mic->flags & IW_MICFAILURE_GROUP);
+ wpa_supplicant_event(ctx, EVENT_MICHAEL_MIC_FAILURE, &data);
+
+ return 0;
+}
+
+
+static int wpa_driver_wext_event_wireless_pmkidcand(
+ struct wpa_driver_wext_data *drv, const char *ev, size_t len)
+{
+ const struct iw_pmkid_cand *cand;
+ union wpa_event_data data;
+ const u8 *addr;
+
+ if (len < sizeof(*cand))
+ return -1;
+
+ cand = (const struct iw_pmkid_cand *) ev;
+ addr = (const u8 *) cand->bssid.sa_data;
+
+ wpa_printf(MSG_DEBUG, "PMKID candidate wireless event: "
+ "flags=0x%x index=%d bssid=" MACSTR, cand->flags,
+ cand->index, MAC2STR(addr));
+
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.pmkid_candidate.bssid, addr, ETH_ALEN);
+ data.pmkid_candidate.index = cand->index;
+ data.pmkid_candidate.preauth = cand->flags & IW_PMKID_CAND_PREAUTH;
+ wpa_supplicant_event(drv->ctx, EVENT_PMKID_CANDIDATE, &data);
+
+ return 0;
+}
+
+
+static int wpa_driver_wext_event_wireless_assocreqie(
+ struct wpa_driver_wext_data *drv, const char *ev, int len)
+{
+ if (len < 0)
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG, "AssocReq IE wireless event", (const u8 *) ev,
+ len);
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = os_malloc(len);
+ if (drv->assoc_req_ies == NULL) {
+ drv->assoc_req_ies_len = 0;
+ return -1;
+ }
+ os_memcpy(drv->assoc_req_ies, ev, len);
+ drv->assoc_req_ies_len = len;
+
+ return 0;
+}
+
+
+static int wpa_driver_wext_event_wireless_assocrespie(
+ struct wpa_driver_wext_data *drv, const char *ev, int len)
+{
+ if (len < 0)
+ return -1;
+
+ wpa_hexdump(MSG_DEBUG, "AssocResp IE wireless event", (const u8 *) ev,
+ len);
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = os_malloc(len);
+ if (drv->assoc_resp_ies == NULL) {
+ drv->assoc_resp_ies_len = 0;
+ return -1;
+ }
+ os_memcpy(drv->assoc_resp_ies, ev, len);
+ drv->assoc_resp_ies_len = len;
+
+ return 0;
+}
+
+
+static void wpa_driver_wext_event_assoc_ies(struct wpa_driver_wext_data *drv)
+{
+ union wpa_event_data data;
+
+ if (drv->assoc_req_ies == NULL && drv->assoc_resp_ies == NULL)
+ return;
+
+ os_memset(&data, 0, sizeof(data));
+ if (drv->assoc_req_ies) {
+ data.assoc_info.req_ies = drv->assoc_req_ies;
+ drv->assoc_req_ies = NULL;
+ data.assoc_info.req_ies_len = drv->assoc_req_ies_len;
+ }
+ if (drv->assoc_resp_ies) {
+ data.assoc_info.resp_ies = drv->assoc_resp_ies;
+ drv->assoc_resp_ies = NULL;
+ data.assoc_info.resp_ies_len = drv->assoc_resp_ies_len;
+ }
+
+ wpa_supplicant_event(drv->ctx, EVENT_ASSOCINFO, &data);
+
+ os_free(data.assoc_info.req_ies);
+ os_free(data.assoc_info.resp_ies);
+}
+
+
+static void wpa_driver_wext_event_wireless(struct wpa_driver_wext_data *drv,
+ void *ctx, char *data, int len)
+{
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom, *buf;
+
+ pos = data;
+ end = data + len;
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ wpa_printf(MSG_DEBUG, "Wireless event: cmd=0x%x len=%d",
+ iwe->cmd, iwe->len);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ return;
+
+ custom = pos + IW_EV_POINT_LEN;
+ if (drv->we_version_compiled > 18 &&
+ (iwe->cmd == IWEVMICHAELMICFAILURE ||
+ iwe->cmd == IWEVCUSTOM ||
+ iwe->cmd == IWEVASSOCREQIE ||
+ iwe->cmd == IWEVASSOCRESPIE ||
+ iwe->cmd == IWEVPMKIDCAND)) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case SIOCGIWAP:
+ wpa_printf(MSG_DEBUG, "Wireless event: new AP: "
+ MACSTR,
+ MAC2STR((u8 *) iwe->u.ap_addr.sa_data));
+ if (is_zero_ether_addr(
+ (const u8 *) iwe->u.ap_addr.sa_data) ||
+ os_memcmp(iwe->u.ap_addr.sa_data,
+ "\x44\x44\x44\x44\x44\x44", ETH_ALEN) ==
+ 0) {
+ os_free(drv->assoc_req_ies);
+ drv->assoc_req_ies = NULL;
+ os_free(drv->assoc_resp_ies);
+ drv->assoc_resp_ies = NULL;
+ wpa_supplicant_event(ctx, EVENT_DISASSOC,
+ NULL);
+
+ } else {
+ wpa_driver_wext_event_assoc_ies(drv);
+ wpa_supplicant_event(ctx, EVENT_ASSOC, NULL);
+ }
+ break;
+ case IWEVMICHAELMICFAILURE:
+ if (custom + iwe->u.data.length > end) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+ "IWEVMICHAELMICFAILURE length");
+ return;
+ }
+ wpa_driver_wext_event_wireless_michaelmicfailure(
+ ctx, custom, iwe->u.data.length);
+ break;
+ case IWEVCUSTOM:
+ if (custom + iwe->u.data.length > end) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+ "IWEVCUSTOM length");
+ return;
+ }
+ buf = os_malloc(iwe->u.data.length + 1);
+ if (buf == NULL)
+ return;
+ os_memcpy(buf, custom, iwe->u.data.length);
+ buf[iwe->u.data.length] = '\0';
+ wpa_driver_wext_event_wireless_custom(ctx, buf);
+ os_free(buf);
+ break;
+ case SIOCGIWSCAN:
+ drv->scan_complete_events = 1;
+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout,
+ drv, ctx);
+ wpa_supplicant_event(ctx, EVENT_SCAN_RESULTS, NULL);
+ break;
+ case IWEVASSOCREQIE:
+ if (custom + iwe->u.data.length > end) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+ "IWEVASSOCREQIE length");
+ return;
+ }
+ wpa_driver_wext_event_wireless_assocreqie(
+ drv, custom, iwe->u.data.length);
+ break;
+ case IWEVASSOCRESPIE:
+ if (custom + iwe->u.data.length > end) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+ "IWEVASSOCRESPIE length");
+ return;
+ }
+ wpa_driver_wext_event_wireless_assocrespie(
+ drv, custom, iwe->u.data.length);
+ break;
+ case IWEVPMKIDCAND:
+ if (custom + iwe->u.data.length > end) {
+ wpa_printf(MSG_DEBUG, "WEXT: Invalid "
+ "IWEVPMKIDCAND length");
+ return;
+ }
+ wpa_driver_wext_event_wireless_pmkidcand(
+ drv, custom, iwe->u.data.length);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+}
+
+
+static void wpa_driver_wext_event_link(struct wpa_driver_wext_data *drv,
+ void *ctx, char *buf, size_t len,
+ int del)
+{
+ union wpa_event_data event;
+
+ os_memset(&event, 0, sizeof(event));
+ if (len > sizeof(event.interface_status.ifname))
+ len = sizeof(event.interface_status.ifname) - 1;
+ os_memcpy(event.interface_status.ifname, buf, len);
+ event.interface_status.ievent = del ? EVENT_INTERFACE_REMOVED :
+ EVENT_INTERFACE_ADDED;
+
+ wpa_printf(MSG_DEBUG, "RTM_%sLINK, IFLA_IFNAME: Interface '%s' %s",
+ del ? "DEL" : "NEW",
+ event.interface_status.ifname,
+ del ? "removed" : "added");
+
+ if (os_strcmp(drv->ifname, event.interface_status.ifname) == 0) {
+ if (del)
+ drv->if_removed = 1;
+ else
+ drv->if_removed = 0;
+ }
+
+ wpa_supplicant_event(ctx, EVENT_INTERFACE_STATUS, &event);
+}
+
+
+static int wpa_driver_wext_own_ifname(struct wpa_driver_wext_data *drv,
+ struct nlmsghdr *h)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr *attr;
+
+ ifi = NLMSG_DATA(h);
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ if (attrlen < 0)
+ return 0;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ if (os_strcmp(((char *) attr) + rta_len, drv->ifname)
+ == 0)
+ return 1;
+ else
+ break;
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+
+ return 0;
+}
+
+
+static int wpa_driver_wext_own_ifindex(struct wpa_driver_wext_data *drv,
+ int ifindex, struct nlmsghdr *h)
+{
+ if (drv->ifindex == ifindex || drv->ifindex2 == ifindex)
+ return 1;
+
+ if (drv->if_removed && wpa_driver_wext_own_ifname(drv, h)) {
+ drv->ifindex = if_nametoindex(drv->ifname);
+ wpa_printf(MSG_DEBUG, "WEXT: Update ifindex for a removed "
+ "interface");
+ wpa_driver_wext_finish_drv_init(drv);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static void wpa_driver_wext_event_rtm_newlink(struct wpa_driver_wext_data *drv,
+ void *ctx, struct nlmsghdr *h,
+ size_t len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ if (len < sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ if (!wpa_driver_wext_own_ifindex(drv, ifi->ifi_index, h)) {
+ wpa_printf(MSG_DEBUG, "Ignore event for foreign ifindex %d",
+ ifi->ifi_index);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "RTM_NEWLINK: operstate=%d ifi_flags=0x%x "
+ "(%s%s%s%s)",
+ drv->operstate, ifi->ifi_flags,
+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+ /*
+ * Some drivers send the association event before the operup event--in
+ * this case, lifting operstate in wpa_driver_wext_set_operstate()
+ * fails. This will hit us when wpa_supplicant does not need to do
+ * IEEE 802.1X authentication
+ */
+ if (drv->operstate == 1 &&
+ (ifi->ifi_flags & (IFF_LOWER_UP | IFF_DORMANT)) == IFF_LOWER_UP &&
+ !(ifi->ifi_flags & IFF_RUNNING))
+ wpa_driver_wext_send_oper_ifla(drv, -1, IF_OPER_UP);
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_WIRELESS) {
+ wpa_driver_wext_event_wireless(
+ drv, ctx, ((char *) attr) + rta_len,
+ attr->rta_len - rta_len);
+ } else if (attr->rta_type == IFLA_IFNAME) {
+ wpa_driver_wext_event_link(drv, ctx,
+ ((char *) attr) + rta_len,
+ attr->rta_len - rta_len, 0);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void wpa_driver_wext_event_rtm_dellink(struct wpa_driver_wext_data *drv,
+ void *ctx, struct nlmsghdr *h,
+ size_t len)
+{
+ struct ifinfomsg *ifi;
+ int attrlen, nlmsg_len, rta_len;
+ struct rtattr * attr;
+
+ if (len < sizeof(*ifi))
+ return;
+
+ ifi = NLMSG_DATA(h);
+
+ nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+ attrlen = h->nlmsg_len - nlmsg_len;
+ if (attrlen < 0)
+ return;
+
+ attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+ rta_len = RTA_ALIGN(sizeof(struct rtattr));
+ while (RTA_OK(attr, attrlen)) {
+ if (attr->rta_type == IFLA_IFNAME) {
+ wpa_driver_wext_event_link(drv, ctx,
+ ((char *) attr) + rta_len,
+ attr->rta_len - rta_len, 1);
+ }
+ attr = RTA_NEXT(attr, attrlen);
+ }
+}
+
+
+static void wpa_driver_wext_event_receive(int sock, void *eloop_ctx,
+ void *sock_ctx)
+{
+ char buf[8192];
+ int left;
+ struct sockaddr_nl from;
+ socklen_t fromlen;
+ struct nlmsghdr *h;
+ int max_events = 10;
+
+try_again:
+ fromlen = sizeof(from);
+ left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+ (struct sockaddr *) &from, &fromlen);
+ if (left < 0) {
+ if (errno != EINTR && errno != EAGAIN)
+ perror("recvfrom(netlink)");
+ return;
+ }
+
+ h = (struct nlmsghdr *) buf;
+ while (left >= (int) sizeof(*h)) {
+ int len, plen;
+
+ len = h->nlmsg_len;
+ plen = len - sizeof(*h);
+ if (len > left || plen < 0) {
+ wpa_printf(MSG_DEBUG, "Malformed netlink message: "
+ "len=%d left=%d plen=%d",
+ len, left, plen);
+ break;
+ }
+
+ switch (h->nlmsg_type) {
+ case RTM_NEWLINK:
+ wpa_driver_wext_event_rtm_newlink(eloop_ctx, sock_ctx,
+ h, plen);
+ break;
+ case RTM_DELLINK:
+ wpa_driver_wext_event_rtm_dellink(eloop_ctx, sock_ctx,
+ h, plen);
+ break;
+ }
+
+ len = NLMSG_ALIGN(len);
+ left -= len;
+ h = (struct nlmsghdr *) ((char *) h + len);
+ }
+
+ if (left > 0) {
+ wpa_printf(MSG_DEBUG, "%d extra bytes in the end of netlink "
+ "message", left);
+ }
+
+ if (--max_events > 0) {
+ /*
+ * Try to receive all events in one eloop call in order to
+ * limit race condition on cases where AssocInfo event, Assoc
+ * event, and EAPOL frames are received more or less at the
+ * same time. We want to process the event messages first
+ * before starting EAPOL processing.
+ */
+ goto try_again;
+ }
+}
+
+
+static int wpa_driver_wext_get_ifflags_ifname(struct wpa_driver_wext_data *drv,
+ const char *ifname, int *flags)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(drv->ioctl_sock, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ return -1;
+ }
+ *flags = ifr.ifr_flags & 0xffff;
+ return 0;
+}
+
+
+/**
+ * wpa_driver_wext_get_ifflags - Get interface flags (SIOCGIFFLAGS)
+ * @drv: driver_wext private data
+ * @flags: Pointer to returned flags value
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_get_ifflags(struct wpa_driver_wext_data *drv, int *flags)
+{
+ return wpa_driver_wext_get_ifflags_ifname(drv, drv->ifname, flags);
+}
+
+
+static int wpa_driver_wext_set_ifflags_ifname(struct wpa_driver_wext_data *drv,
+ const char *ifname, int flags)
+{
+ struct ifreq ifr;
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_flags = flags & 0xffff;
+ if (ioctl(drv->ioctl_sock, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ perror("SIOCSIFFLAGS");
+ return -1;
+ }
+ return 0;
+}
+
+
+/**
+ * wpa_driver_wext_set_ifflags - Set interface flags (SIOCSIFFLAGS)
+ * @drv: driver_wext private data
+ * @flags: New value for flags
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags)
+{
+ return wpa_driver_wext_set_ifflags_ifname(drv, drv->ifname, flags);
+}
+
+
+/**
+ * wpa_driver_wext_init - Initialize WE driver interface
+ * @ctx: context to be used when calling wpa_supplicant functions,
+ * e.g., wpa_supplicant_event()
+ * @ifname: interface name, e.g., wlan0
+ * Returns: Pointer to private data, %NULL on failure
+ */
+void * wpa_driver_wext_init(void *ctx, const char *ifname)
+{
+ int s;
+ struct sockaddr_nl local;
+ struct wpa_driver_wext_data *drv;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ drv->ctx = ctx;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+
+ drv->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+ if (drv->ioctl_sock < 0) {
+ perror("socket(PF_INET,SOCK_DGRAM)");
+ os_free(drv);
+ return NULL;
+ }
+
+ s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+ if (s < 0) {
+ perror("socket(PF_NETLINK,SOCK_RAW,NETLINK_ROUTE)");
+ close(drv->ioctl_sock);
+ os_free(drv);
+ return NULL;
+ }
+
+ os_memset(&local, 0, sizeof(local));
+ local.nl_family = AF_NETLINK;
+ local.nl_groups = RTMGRP_LINK;
+ if (bind(s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+ perror("bind(netlink)");
+ close(s);
+ close(drv->ioctl_sock);
+ os_free(drv);
+ return NULL;
+ }
+
+ eloop_register_read_sock(s, wpa_driver_wext_event_receive, drv, ctx);
+ drv->event_sock = s;
+
+ drv->mlme_sock = -1;
+
+ wpa_driver_wext_finish_drv_init(drv);
+
+ return drv;
+}
+
+
+static void wpa_driver_wext_finish_drv_init(struct wpa_driver_wext_data *drv)
+{
+ int flags;
+
+ if (wpa_driver_wext_get_ifflags(drv, &flags) != 0)
+ printf("Could not get interface '%s' flags\n", drv->ifname);
+ else if (!(flags & IFF_UP)) {
+ if (wpa_driver_wext_set_ifflags(drv, flags | IFF_UP) != 0) {
+ printf("Could not set interface '%s' UP\n",
+ drv->ifname);
+ } else {
+ /*
+ * Wait some time to allow driver to initialize before
+ * starting configuring the driver. This seems to be
+ * needed at least some drivers that load firmware etc.
+ * when the interface is set up.
+ */
+ wpa_printf(MSG_DEBUG, "Interface %s set UP - waiting "
+ "a second for the driver to complete "
+ "initialization", drv->ifname);
+ sleep(1);
+ }
+ }
+
+ /*
+ * Make sure that the driver does not have any obsolete PMKID entries.
+ */
+ wpa_driver_wext_flush_pmkid(drv);
+
+ if (wpa_driver_wext_set_mode(drv, 0) < 0) {
+ printf("Could not configure driver to use managed mode\n");
+ }
+
+ wpa_driver_wext_get_range(drv);
+
+ /*
+ * Unlock the driver's BSSID and force to a random SSID to clear any
+ * previous association the driver might have when the supplicant
+ * starts up.
+ */
+ wpa_driver_wext_disconnect(drv);
+
+ drv->ifindex = if_nametoindex(drv->ifname);
+
+ if (os_strncmp(drv->ifname, "wlan", 4) == 0) {
+ /*
+ * Host AP driver may use both wlan# and wifi# interface in
+ * wireless events. Since some of the versions included WE-18
+ * support, let's add the alternative ifindex also from
+ * driver_wext.c for the time being. This may be removed at
+ * some point once it is believed that old versions of the
+ * driver are not in use anymore.
+ */
+ char ifname2[IFNAMSIZ + 1];
+ os_strlcpy(ifname2, drv->ifname, sizeof(ifname2));
+ os_memcpy(ifname2, "wifi", 4);
+ wpa_driver_wext_alternative_ifindex(drv, ifname2);
+ }
+
+ wpa_driver_wext_send_oper_ifla(drv, 1, IF_OPER_DORMANT);
+}
+
+
+/**
+ * wpa_driver_wext_deinit - Deinitialize WE driver interface
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ *
+ * Shut down driver interface and processing of driver events. Free
+ * private data buffer if one was allocated in wpa_driver_wext_init().
+ */
+void wpa_driver_wext_deinit(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int flags;
+
+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
+
+ /*
+ * Clear possibly configured driver parameters in order to make it
+ * easier to use the driver after wpa_supplicant has been terminated.
+ */
+ wpa_driver_wext_disconnect(drv);
+
+ wpa_driver_wext_send_oper_ifla(priv, 0, IF_OPER_UP);
+
+ eloop_unregister_read_sock(drv->event_sock);
+ if (drv->mlme_sock >= 0)
+ eloop_unregister_read_sock(drv->mlme_sock);
+
+ if (wpa_driver_wext_get_ifflags(drv, &flags) == 0)
+ (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
+
+ close(drv->event_sock);
+ close(drv->ioctl_sock);
+ if (drv->mlme_sock >= 0)
+ close(drv->mlme_sock);
+ os_free(drv->assoc_req_ies);
+ os_free(drv->assoc_resp_ies);
+ os_free(drv);
+}
+
+
+/**
+ * wpa_driver_wext_scan_timeout - Scan timeout to report scan completion
+ * @eloop_ctx: Unused
+ * @timeout_ctx: ctx argument given to wpa_driver_wext_init()
+ *
+ * This function can be used as registered timeout when starting a scan to
+ * generate a scan completed event if the driver does not report this.
+ */
+void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ wpa_printf(MSG_DEBUG, "Scan timeout - try to get results");
+ wpa_supplicant_event(timeout_ctx, EVENT_SCAN_RESULTS, NULL);
+}
+
+
+/**
+ * wpa_driver_wext_scan - Request the driver to initiate scan
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @ssid: Specific SSID to scan for (ProbeReq) or %NULL to scan for
+ * all SSIDs (either active scan with broadcast SSID or passive
+ * scan
+ * @ssid_len: Length of the SSID
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_scan(void *priv, const u8 *ssid, size_t ssid_len)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0, timeout;
+ struct iw_scan_req req;
+
+ if (ssid_len > IW_ESSID_MAX_SIZE) {
+ wpa_printf(MSG_DEBUG, "%s: too long SSID (%lu)",
+ __FUNCTION__, (unsigned long) ssid_len);
+ return -1;
+ }
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ if (ssid && ssid_len) {
+ os_memset(&req, 0, sizeof(req));
+ req.essid_len = ssid_len;
+ req.bssid.sa_family = ARPHRD_ETHER;
+ os_memset(req.bssid.sa_data, 0xff, ETH_ALEN);
+ os_memcpy(req.essid, ssid, ssid_len);
+ iwr.u.data.pointer = (caddr_t) &req;
+ iwr.u.data.length = sizeof(req);
+ iwr.u.data.flags = IW_SCAN_THIS_ESSID;
+ }
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWSCAN, &iwr) < 0) {
+ perror("ioctl[SIOCSIWSCAN]");
+ ret = -1;
+ }
+
+ /* Not all drivers generate "scan completed" wireless event, so try to
+ * read results after a timeout. */
+ timeout = 5;
+ if (drv->scan_complete_events) {
+ /*
+ * The driver seems to deliver SIOCGIWSCAN events to notify
+ * when scan is complete, so use longer timeout to avoid race
+ * conditions with scanning and following association request.
+ */
+ timeout = 30;
+ }
+ wpa_printf(MSG_DEBUG, "Scan requested (ret=%d) - scan timeout %d "
+ "seconds", ret, timeout);
+ eloop_cancel_timeout(wpa_driver_wext_scan_timeout, drv, drv->ctx);
+ eloop_register_timeout(timeout, 0, wpa_driver_wext_scan_timeout, drv,
+ drv->ctx);
+
+ return ret;
+}
+
+
+static u8 * wpa_driver_wext_giwscan(struct wpa_driver_wext_data *drv,
+ size_t *len)
+{
+ struct iwreq iwr;
+ u8 *res_buf;
+ size_t res_buf_len;
+
+ res_buf_len = IW_SCAN_MAX_DATA;
+ for (;;) {
+ res_buf = os_malloc(res_buf_len);
+ if (res_buf == NULL)
+ return NULL;
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = res_buf;
+ iwr.u.data.length = res_buf_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWSCAN, &iwr) == 0)
+ break;
+
+ if (errno == E2BIG && res_buf_len < 65535) {
+ os_free(res_buf);
+ res_buf = NULL;
+ res_buf_len *= 2;
+ if (res_buf_len > 65535)
+ res_buf_len = 65535; /* 16-bit length field */
+ wpa_printf(MSG_DEBUG, "Scan results did not fit - "
+ "trying larger buffer (%lu bytes)",
+ (unsigned long) res_buf_len);
+ } else {
+ perror("ioctl[SIOCGIWSCAN]");
+ os_free(res_buf);
+ return NULL;
+ }
+ }
+
+ if (iwr.u.data.length > res_buf_len) {
+ os_free(res_buf);
+ return NULL;
+ }
+ *len = iwr.u.data.length;
+
+ return res_buf;
+}
+
+
+/*
+ * Data structure for collecting WEXT scan results. This is needed to allow
+ * the various methods of reporting IEs to be combined into a single IE buffer.
+ */
+struct wext_scan_data {
+ struct wpa_scan_res res;
+ u8 *ie;
+ size_t ie_len;
+ u8 ssid[32];
+ size_t ssid_len;
+ int maxrate;
+};
+
+
+static void wext_get_scan_mode(struct iw_event *iwe,
+ struct wext_scan_data *res)
+{
+ if (iwe->u.mode == IW_MODE_ADHOC)
+ res->res.caps |= IEEE80211_CAP_IBSS;
+ else if (iwe->u.mode == IW_MODE_MASTER || iwe->u.mode == IW_MODE_INFRA)
+ res->res.caps |= IEEE80211_CAP_ESS;
+}
+
+
+static void wext_get_scan_ssid(struct iw_event *iwe,
+ struct wext_scan_data *res, char *custom,
+ char *end)
+{
+ int ssid_len = iwe->u.essid.length;
+ if (custom + ssid_len > end)
+ return;
+ if (iwe->u.essid.flags &&
+ ssid_len > 0 &&
+ ssid_len <= IW_ESSID_MAX_SIZE) {
+ os_memcpy(res->ssid, custom, ssid_len);
+ res->ssid_len = ssid_len;
+ }
+}
+
+
+static void wext_get_scan_freq(struct iw_event *iwe,
+ struct wext_scan_data *res)
+{
+ int divi = 1000000, i;
+
+ if (iwe->u.freq.e == 0) {
+ /*
+ * Some drivers do not report frequency, but a channel.
+ * Try to map this to frequency by assuming they are using
+ * IEEE 802.11b/g. But don't overwrite a previously parsed
+ * frequency if the driver sends both frequency and channel,
+ * since the driver may be sending an A-band channel that we
+ * don't handle here.
+ */
+
+ if (res->res.freq)
+ return;
+
+ if (iwe->u.freq.m >= 1 && iwe->u.freq.m <= 13) {
+ res->res.freq = 2407 + 5 * iwe->u.freq.m;
+ return;
+ } else if (iwe->u.freq.m == 14) {
+ res->res.freq = 2484;
+ return;
+ }
+ }
+
+ if (iwe->u.freq.e > 6) {
+ wpa_printf(MSG_DEBUG, "Invalid freq in scan results (BSSID="
+ MACSTR " m=%d e=%d)",
+ MAC2STR(res->res.bssid), iwe->u.freq.m,
+ iwe->u.freq.e);
+ return;
+ }
+
+ for (i = 0; i < iwe->u.freq.e; i++)
+ divi /= 10;
+ res->res.freq = iwe->u.freq.m / divi;
+}
+
+
+static void wext_get_scan_qual(struct iw_event *iwe,
+ struct wext_scan_data *res)
+{
+ res->res.qual = iwe->u.qual.qual;
+ res->res.noise = iwe->u.qual.noise;
+ res->res.level = iwe->u.qual.level;
+}
+
+
+static void wext_get_scan_encode(struct iw_event *iwe,
+ struct wext_scan_data *res)
+{
+ if (!(iwe->u.data.flags & IW_ENCODE_DISABLED))
+ res->res.caps |= IEEE80211_CAP_PRIVACY;
+}
+
+
+static void wext_get_scan_rate(struct iw_event *iwe,
+ struct wext_scan_data *res, char *pos,
+ char *end)
+{
+ int maxrate;
+ char *custom = pos + IW_EV_LCP_LEN;
+ struct iw_param p;
+ size_t clen;
+
+ clen = iwe->len;
+ if (custom + clen > end)
+ return;
+ maxrate = 0;
+ while (((ssize_t) clen) >= (ssize_t) sizeof(struct iw_param)) {
+ /* Note: may be misaligned, make a local, aligned copy */
+ os_memcpy(&p, custom, sizeof(struct iw_param));
+ if (p.value > maxrate)
+ maxrate = p.value;
+ clen -= sizeof(struct iw_param);
+ custom += sizeof(struct iw_param);
+ }
+
+ /* Convert the maxrate from WE-style (b/s units) to
+ * 802.11 rates (500000 b/s units).
+ */
+ res->maxrate = maxrate / 500000;
+}
+
+
+static void wext_get_scan_iwevgenie(struct iw_event *iwe,
+ struct wext_scan_data *res, char *custom,
+ char *end)
+{
+ char *genie, *gpos, *gend;
+ u8 *tmp;
+
+ if (iwe->u.data.length == 0)
+ return;
+
+ gpos = genie = custom;
+ gend = genie + iwe->u.data.length;
+ if (gend > end) {
+ wpa_printf(MSG_INFO, "IWEVGENIE overflow");
+ return;
+ }
+
+ tmp = os_realloc(res->ie, res->ie_len + gend - gpos);
+ if (tmp == NULL)
+ return;
+ os_memcpy(tmp + res->ie_len, gpos, gend - gpos);
+ res->ie = tmp;
+ res->ie_len += gend - gpos;
+}
+
+
+static void wext_get_scan_custom(struct iw_event *iwe,
+ struct wext_scan_data *res, char *custom,
+ char *end)
+{
+ size_t clen;
+ u8 *tmp;
+
+ clen = iwe->u.data.length;
+ if (custom + clen > end)
+ return;
+
+ if (clen > 7 && os_strncmp(custom, "wpa_ie=", 7) == 0) {
+ char *spos;
+ int bytes;
+ spos = custom + 7;
+ bytes = custom + clen - spos;
+ if (bytes & 1 || bytes == 0)
+ return;
+ bytes /= 2;
+ tmp = os_realloc(res->ie, res->ie_len + bytes);
+ if (tmp == NULL)
+ return;
+ hexstr2bin(spos, tmp + res->ie_len, bytes);
+ res->ie = tmp;
+ res->ie_len += bytes;
+ } else if (clen > 7 && os_strncmp(custom, "rsn_ie=", 7) == 0) {
+ char *spos;
+ int bytes;
+ spos = custom + 7;
+ bytes = custom + clen - spos;
+ if (bytes & 1 || bytes == 0)
+ return;
+ bytes /= 2;
+ tmp = os_realloc(res->ie, res->ie_len + bytes);
+ if (tmp == NULL)
+ return;
+ hexstr2bin(spos, tmp + res->ie_len, bytes);
+ res->ie = tmp;
+ res->ie_len += bytes;
+ } else if (clen > 4 && os_strncmp(custom, "tsf=", 4) == 0) {
+ char *spos;
+ int bytes;
+ u8 bin[8];
+ spos = custom + 4;
+ bytes = custom + clen - spos;
+ if (bytes != 16) {
+ wpa_printf(MSG_INFO, "Invalid TSF length (%d)", bytes);
+ return;
+ }
+ bytes /= 2;
+ hexstr2bin(spos, bin, bytes);
+ res->res.tsf += WPA_GET_BE64(bin);
+ }
+}
+
+
+static int wext_19_iw_point(struct wpa_driver_wext_data *drv, u16 cmd)
+{
+ return drv->we_version_compiled > 18 &&
+ (cmd == SIOCGIWESSID || cmd == SIOCGIWENCODE ||
+ cmd == IWEVGENIE || cmd == IWEVCUSTOM);
+}
+
+
+static void wpa_driver_wext_add_scan_entry(struct wpa_scan_results *res,
+ struct wext_scan_data *data)
+{
+ struct wpa_scan_res **tmp;
+ struct wpa_scan_res *r;
+ size_t extra_len;
+ u8 *pos, *end, *ssid_ie = NULL, *rate_ie = NULL;
+
+ /* Figure out whether we need to fake any IEs */
+ pos = data->ie;
+ end = pos + data->ie_len;
+ while (pos && pos + 1 < end) {
+ if (pos + 2 + pos[1] > end)
+ break;
+ if (pos[0] == WLAN_EID_SSID)
+ ssid_ie = pos;
+ else if (pos[0] == WLAN_EID_SUPP_RATES)
+ rate_ie = pos;
+ else if (pos[0] == WLAN_EID_EXT_SUPP_RATES)
+ rate_ie = pos;
+ pos += 2 + pos[1];
+ }
+
+ extra_len = 0;
+ if (ssid_ie == NULL)
+ extra_len += 2 + data->ssid_len;
+ if (rate_ie == NULL && data->maxrate)
+ extra_len += 3;
+
+ r = os_zalloc(sizeof(*r) + extra_len + data->ie_len);
+ if (r == NULL)
+ return;
+ os_memcpy(r, &data->res, sizeof(*r));
+ r->ie_len = extra_len + data->ie_len;
+ pos = (u8 *) (r + 1);
+ if (ssid_ie == NULL) {
+ /*
+ * Generate a fake SSID IE since the driver did not report
+ * a full IE list.
+ */
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = data->ssid_len;
+ os_memcpy(pos, data->ssid, data->ssid_len);
+ pos += data->ssid_len;
+ }
+ if (rate_ie == NULL && data->maxrate) {
+ /*
+ * Generate a fake Supported Rates IE since the driver did not
+ * report a full IE list.
+ */
+ *pos++ = WLAN_EID_SUPP_RATES;
+ *pos++ = 1;
+ *pos++ = data->maxrate;
+ }
+ if (data->ie)
+ os_memcpy(pos, data->ie, data->ie_len);
+
+ tmp = os_realloc(res->res,
+ (res->num + 1) * sizeof(struct wpa_scan_res *));
+ if (tmp == NULL) {
+ os_free(r);
+ return;
+ }
+ tmp[res->num++] = r;
+ res->res = tmp;
+}
+
+
+/**
+ * wpa_driver_wext_get_scan_results - Fetch the latest scan results
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * Returns: Scan results on success, -1 on failure
+ */
+struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ size_t ap_num = 0, len;
+ int first;
+ u8 *res_buf;
+ struct iw_event iwe_buf, *iwe = &iwe_buf;
+ char *pos, *end, *custom;
+ struct wpa_scan_results *res;
+ struct wext_scan_data data;
+
+ res_buf = wpa_driver_wext_giwscan(drv, &len);
+ if (res_buf == NULL)
+ return NULL;
+
+ ap_num = 0;
+ first = 1;
+
+ res = os_zalloc(sizeof(*res));
+ if (res == NULL) {
+ os_free(res_buf);
+ return NULL;
+ }
+
+ pos = (char *) res_buf;
+ end = (char *) res_buf + len;
+ os_memset(&data, 0, sizeof(data));
+
+ while (pos + IW_EV_LCP_LEN <= end) {
+ /* Event data may be unaligned, so make a local, aligned copy
+ * before processing. */
+ os_memcpy(&iwe_buf, pos, IW_EV_LCP_LEN);
+ if (iwe->len <= IW_EV_LCP_LEN)
+ break;
+
+ custom = pos + IW_EV_POINT_LEN;
+ if (wext_19_iw_point(drv, iwe->cmd)) {
+ /* WE-19 removed the pointer from struct iw_point */
+ char *dpos = (char *) &iwe_buf.u.data.length;
+ int dlen = dpos - (char *) &iwe_buf;
+ os_memcpy(dpos, pos + IW_EV_LCP_LEN,
+ sizeof(struct iw_event) - dlen);
+ } else {
+ os_memcpy(&iwe_buf, pos, sizeof(struct iw_event));
+ custom += IW_EV_POINT_OFF;
+ }
+
+ switch (iwe->cmd) {
+ case SIOCGIWAP:
+ if (!first)
+ wpa_driver_wext_add_scan_entry(res, &data);
+ first = 0;
+ os_free(data.ie);
+ os_memset(&data, 0, sizeof(data));
+ os_memcpy(data.res.bssid,
+ iwe->u.ap_addr.sa_data, ETH_ALEN);
+ break;
+ case SIOCGIWMODE:
+ wext_get_scan_mode(iwe, &data);
+ break;
+ case SIOCGIWESSID:
+ wext_get_scan_ssid(iwe, &data, custom, end);
+ break;
+ case SIOCGIWFREQ:
+ wext_get_scan_freq(iwe, &data);
+ break;
+ case IWEVQUAL:
+ wext_get_scan_qual(iwe, &data);
+ break;
+ case SIOCGIWENCODE:
+ wext_get_scan_encode(iwe, &data);
+ break;
+ case SIOCGIWRATE:
+ wext_get_scan_rate(iwe, &data, pos, end);
+ break;
+ case IWEVGENIE:
+ wext_get_scan_iwevgenie(iwe, &data, custom, end);
+ break;
+ case IWEVCUSTOM:
+ wext_get_scan_custom(iwe, &data, custom, end);
+ break;
+ }
+
+ pos += iwe->len;
+ }
+ os_free(res_buf);
+ res_buf = NULL;
+ if (!first)
+ wpa_driver_wext_add_scan_entry(res, &data);
+ os_free(data.ie);
+
+ wpa_printf(MSG_DEBUG, "Received %lu bytes of scan results (%lu BSSes)",
+ (unsigned long) len, (unsigned long) res->num);
+
+ return res;
+}
+
+
+static int wpa_driver_wext_get_range(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iw_range *range;
+ struct iwreq iwr;
+ int minlen;
+ size_t buflen;
+
+ /*
+ * Use larger buffer than struct iw_range in order to allow the
+ * structure to grow in the future.
+ */
+ buflen = sizeof(struct iw_range) + 500;
+ range = os_zalloc(buflen);
+ if (range == NULL)
+ return -1;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) range;
+ iwr.u.data.length = buflen;
+
+ minlen = ((char *) &range->enc_capa) - (char *) range +
+ sizeof(range->enc_capa);
+
+ if (ioctl(drv->ioctl_sock, SIOCGIWRANGE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWRANGE]");
+ os_free(range);
+ return -1;
+ } else if (iwr.u.data.length >= minlen &&
+ range->we_version_compiled >= 18) {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: WE(compiled)=%d "
+ "WE(source)=%d enc_capa=0x%x",
+ range->we_version_compiled,
+ range->we_version_source,
+ range->enc_capa);
+ drv->has_capability = 1;
+ drv->we_version_compiled = range->we_version_compiled;
+ if (range->enc_capa & IW_ENC_CAPA_WPA) {
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK;
+ }
+ if (range->enc_capa & IW_ENC_CAPA_WPA2) {
+ drv->capa.key_mgmt |= WPA_DRIVER_CAPA_KEY_MGMT_WPA2 |
+ WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK;
+ }
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_WEP40 |
+ WPA_DRIVER_CAPA_ENC_WEP104;
+ if (range->enc_capa & IW_ENC_CAPA_CIPHER_TKIP)
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_TKIP;
+ if (range->enc_capa & IW_ENC_CAPA_CIPHER_CCMP)
+ drv->capa.enc |= WPA_DRIVER_CAPA_ENC_CCMP;
+ if (range->enc_capa & IW_ENC_CAPA_4WAY_HANDSHAKE)
+ drv->capa.flags |= WPA_DRIVER_FLAGS_4WAY_HANDSHAKE;
+ drv->capa.auth = WPA_DRIVER_AUTH_OPEN |
+ WPA_DRIVER_AUTH_SHARED |
+ WPA_DRIVER_AUTH_LEAP;
+
+ wpa_printf(MSG_DEBUG, " capabilities: key_mgmt 0x%x enc 0x%x "
+ "flags 0x%x",
+ drv->capa.key_mgmt, drv->capa.enc, drv->capa.flags);
+ } else {
+ wpa_printf(MSG_DEBUG, "SIOCGIWRANGE: too old (short) data - "
+ "assuming WPA is not supported");
+ }
+
+ os_free(range);
+ return 0;
+}
+
+
+static int wpa_driver_wext_set_wpa(void *priv, int enabled)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ return wpa_driver_wext_set_auth_param(drv, IW_AUTH_WPA_ENABLED,
+ enabled);
+}
+
+
+static int wpa_driver_wext_set_psk(struct wpa_driver_wext_data *drv,
+ const u8 *psk)
+{
+ struct iw_encode_ext *ext;
+ struct iwreq iwr;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ if (!(drv->capa.flags & WPA_DRIVER_FLAGS_4WAY_HANDSHAKE))
+ return 0;
+
+ if (!psk)
+ return 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+
+ ext = os_zalloc(sizeof(*ext) + PMK_LEN);
+ if (ext == NULL)
+ return -1;
+
+ iwr.u.encoding.pointer = (caddr_t) ext;
+ iwr.u.encoding.length = sizeof(*ext) + PMK_LEN;
+ ext->key_len = PMK_LEN;
+ os_memcpy(&ext->key, psk, ext->key_len);
+ ext->alg = IW_ENCODE_ALG_PMK;
+
+ ret = ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr);
+ if (ret < 0)
+ perror("ioctl[SIOCSIWENCODEEXT] PMK");
+ os_free(ext);
+
+ return ret;
+}
+
+
+static int wpa_driver_wext_set_key_ext(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx,
+ int set_tx, const u8 *seq,
+ size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+ struct iw_encode_ext *ext;
+
+ if (seq_len > IW_ENCODE_SEQ_MAX_SIZE) {
+ wpa_printf(MSG_DEBUG, "%s: Invalid seq_len %lu",
+ __FUNCTION__, (unsigned long) seq_len);
+ return -1;
+ }
+
+ ext = os_zalloc(sizeof(*ext) + key_len);
+ if (ext == NULL)
+ return -1;
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.encoding.flags = key_idx + 1;
+ iwr.u.encoding.flags |= IW_ENCODE_TEMP;
+ if (alg == WPA_ALG_NONE)
+ iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+ iwr.u.encoding.pointer = (caddr_t) ext;
+ iwr.u.encoding.length = sizeof(*ext) + key_len;
+
+ if (addr == NULL ||
+ os_memcmp(addr, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) == 0)
+ ext->ext_flags |= IW_ENCODE_EXT_GROUP_KEY;
+ if (set_tx)
+ ext->ext_flags |= IW_ENCODE_EXT_SET_TX_KEY;
+
+ ext->addr.sa_family = ARPHRD_ETHER;
+ if (addr)
+ os_memcpy(ext->addr.sa_data, addr, ETH_ALEN);
+ else
+ os_memset(ext->addr.sa_data, 0xff, ETH_ALEN);
+ if (key && key_len) {
+ os_memcpy(ext + 1, key, key_len);
+ ext->key_len = key_len;
+ }
+ switch (alg) {
+ case WPA_ALG_NONE:
+ ext->alg = IW_ENCODE_ALG_NONE;
+ break;
+ case WPA_ALG_WEP:
+ ext->alg = IW_ENCODE_ALG_WEP;
+ break;
+ case WPA_ALG_TKIP:
+ ext->alg = IW_ENCODE_ALG_TKIP;
+ break;
+ case WPA_ALG_CCMP:
+ ext->alg = IW_ENCODE_ALG_CCMP;
+ break;
+ case WPA_ALG_PMK:
+ ext->alg = IW_ENCODE_ALG_PMK;
+ break;
+#ifdef CONFIG_IEEE80211W
+ case WPA_ALG_IGTK:
+ ext->alg = IW_ENCODE_ALG_AES_CMAC;
+ break;
+#endif /* CONFIG_IEEE80211W */
+ default:
+ wpa_printf(MSG_DEBUG, "%s: Unknown algorithm %d",
+ __FUNCTION__, alg);
+ os_free(ext);
+ return -1;
+ }
+
+ if (seq && seq_len) {
+ ext->ext_flags |= IW_ENCODE_EXT_RX_SEQ_VALID;
+ os_memcpy(ext->rx_seq, seq, seq_len);
+ }
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODEEXT, &iwr) < 0) {
+ ret = errno == EOPNOTSUPP ? -2 : -1;
+ if (errno == ENODEV) {
+ /*
+ * ndiswrapper seems to be returning incorrect error
+ * code.. */
+ ret = -2;
+ }
+
+ perror("ioctl[SIOCSIWENCODEEXT]");
+ }
+
+ os_free(ext);
+ return ret;
+}
+
+
+/**
+ * wpa_driver_wext_set_key - Configure encryption key
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @priv: Private driver interface data
+ * @alg: Encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
+ * %WPA_ALG_TKIP, %WPA_ALG_CCMP); %WPA_ALG_NONE clears the key.
+ * @addr: Address of the peer STA or ff:ff:ff:ff:ff:ff for
+ * broadcast/default keys
+ * @key_idx: key index (0..3), usually 0 for unicast keys
+ * @set_tx: Configure this key as the default Tx key (only used when
+ * driver does not support separate unicast/individual key
+ * @seq: Sequence number/packet number, seq_len octets, the next
+ * packet number to be used for in replay protection; configured
+ * for Rx keys (in most cases, this is only used with broadcast
+ * keys and set to zero for unicast keys)
+ * @seq_len: Length of the seq, depends on the algorithm:
+ * TKIP: 6 octets, CCMP: 6 octets
+ * @key: Key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
+ * 8-byte Rx Mic Key
+ * @key_len: Length of the key buffer in octets (WEP: 5 or 13,
+ * TKIP: 32, CCMP: 16)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function uses SIOCSIWENCODEEXT by default, but tries to use
+ * SIOCSIWENCODE if the extended ioctl fails when configuring a WEP key.
+ */
+int wpa_driver_wext_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx,
+ int set_tx, const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "%s: alg=%d key_idx=%d set_tx=%d seq_len=%lu "
+ "key_len=%lu",
+ __FUNCTION__, alg, key_idx, set_tx,
+ (unsigned long) seq_len, (unsigned long) key_len);
+
+ ret = wpa_driver_wext_set_key_ext(drv, alg, addr, key_idx, set_tx,
+ seq, seq_len, key, key_len);
+ if (ret == 0)
+ return 0;
+
+ if (ret == -2 &&
+ (alg == WPA_ALG_NONE || alg == WPA_ALG_WEP)) {
+ wpa_printf(MSG_DEBUG, "Driver did not support "
+ "SIOCSIWENCODEEXT, trying SIOCSIWENCODE");
+ ret = 0;
+ } else {
+ wpa_printf(MSG_DEBUG, "Driver did not support "
+ "SIOCSIWENCODEEXT");
+ return ret;
+ }
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.encoding.flags = key_idx + 1;
+ iwr.u.encoding.flags |= IW_ENCODE_TEMP;
+ if (alg == WPA_ALG_NONE)
+ iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+ iwr.u.encoding.pointer = (caddr_t) key;
+ iwr.u.encoding.length = key_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWENCODE]");
+ ret = -1;
+ }
+
+ if (set_tx && alg != WPA_ALG_NONE) {
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.encoding.flags = key_idx + 1;
+ iwr.u.encoding.flags |= IW_ENCODE_TEMP;
+ iwr.u.encoding.pointer = (caddr_t) NULL;
+ iwr.u.encoding.length = 0;
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWENCODE] (set_tx)");
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_wext_set_countermeasures(void *priv,
+ int enabled)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ return wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_TKIP_COUNTERMEASURES,
+ enabled);
+}
+
+
+static int wpa_driver_wext_set_drop_unencrypted(void *priv,
+ int enabled)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ drv->use_crypt = enabled;
+ return wpa_driver_wext_set_auth_param(drv, IW_AUTH_DROP_UNENCRYPTED,
+ enabled);
+}
+
+
+static int wpa_driver_wext_mlme(struct wpa_driver_wext_data *drv,
+ const u8 *addr, int cmd, int reason_code)
+{
+ struct iwreq iwr;
+ struct iw_mlme mlme;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_memset(&mlme, 0, sizeof(mlme));
+ mlme.cmd = cmd;
+ mlme.reason_code = reason_code;
+ mlme.addr.sa_family = ARPHRD_ETHER;
+ os_memcpy(mlme.addr.sa_data, addr, ETH_ALEN);
+ iwr.u.data.pointer = (caddr_t) &mlme;
+ iwr.u.data.length = sizeof(mlme);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWMLME, &iwr) < 0) {
+ perror("ioctl[SIOCSIWMLME]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static void wpa_driver_wext_disconnect(struct wpa_driver_wext_data *drv)
+{
+ struct iwreq iwr;
+ const u8 null_bssid[ETH_ALEN] = { 0, 0, 0, 0, 0, 0 };
+ u8 ssid[32];
+ int i;
+
+ /*
+ * Only force-disconnect when the card is in infrastructure mode,
+ * otherwise the driver might interpret the cleared BSSID and random
+ * SSID as an attempt to create a new ad-hoc network.
+ */
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWMODE]");
+ iwr.u.mode = IW_MODE_INFRA;
+ }
+
+ if (iwr.u.mode == IW_MODE_INFRA) {
+ /*
+ * Clear the BSSID selection and set a random SSID to make sure
+ * the driver will not be trying to associate with something
+ * even if it does not understand SIOCSIWMLME commands (or
+ * tries to associate automatically after deauth/disassoc).
+ */
+ wpa_driver_wext_set_bssid(drv, null_bssid);
+
+ for (i = 0; i < 32; i++)
+ ssid[i] = rand() & 0xFF;
+ wpa_driver_wext_set_ssid(drv, ssid, 32);
+ }
+}
+
+
+static int wpa_driver_wext_deauthenticate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int ret;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DEAUTH, reason_code);
+ wpa_driver_wext_disconnect(drv);
+ return ret;
+}
+
+
+static int wpa_driver_wext_disassociate(void *priv, const u8 *addr,
+ int reason_code)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int ret;
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+ ret = wpa_driver_wext_mlme(drv, addr, IW_MLME_DISASSOC, reason_code);
+ wpa_driver_wext_disconnect(drv);
+ return ret;
+}
+
+
+static int wpa_driver_wext_set_gen_ie(void *priv, const u8 *ie,
+ size_t ie_len)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.data.pointer = (caddr_t) ie;
+ iwr.u.data.length = ie_len;
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWGENIE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWGENIE]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+int wpa_driver_wext_cipher2wext(int cipher)
+{
+ switch (cipher) {
+ case CIPHER_NONE:
+ return IW_AUTH_CIPHER_NONE;
+ case CIPHER_WEP40:
+ return IW_AUTH_CIPHER_WEP40;
+ case CIPHER_TKIP:
+ return IW_AUTH_CIPHER_TKIP;
+ case CIPHER_CCMP:
+ return IW_AUTH_CIPHER_CCMP;
+ case CIPHER_WEP104:
+ return IW_AUTH_CIPHER_WEP104;
+ default:
+ return 0;
+ }
+}
+
+
+int wpa_driver_wext_keymgmt2wext(int keymgmt)
+{
+ switch (keymgmt) {
+ case KEY_MGMT_802_1X:
+ case KEY_MGMT_802_1X_NO_WPA:
+ return IW_AUTH_KEY_MGMT_802_1X;
+ case KEY_MGMT_PSK:
+ return IW_AUTH_KEY_MGMT_PSK;
+ default:
+ return 0;
+ }
+}
+
+
+static int
+wpa_driver_wext_auth_alg_fallback(struct wpa_driver_wext_data *drv,
+ struct wpa_driver_associate_params *params)
+{
+ struct iwreq iwr;
+ int ret = 0;
+
+ wpa_printf(MSG_DEBUG, "WEXT: Driver did not support "
+ "SIOCSIWAUTH for AUTH_ALG, trying SIOCSIWENCODE");
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ /* Just changing mode, not actual keys */
+ iwr.u.encoding.flags = 0;
+ iwr.u.encoding.pointer = (caddr_t) NULL;
+ iwr.u.encoding.length = 0;
+
+ /*
+ * Note: IW_ENCODE_{OPEN,RESTRICTED} can be interpreted to mean two
+ * different things. Here they are used to indicate Open System vs.
+ * Shared Key authentication algorithm. However, some drivers may use
+ * them to select between open/restricted WEP encrypted (open = allow
+ * both unencrypted and encrypted frames; restricted = only allow
+ * encrypted frames).
+ */
+
+ if (!drv->use_crypt) {
+ iwr.u.encoding.flags |= IW_ENCODE_DISABLED;
+ } else {
+ if (params->auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ iwr.u.encoding.flags |= IW_ENCODE_OPEN;
+ if (params->auth_alg & AUTH_ALG_SHARED_KEY)
+ iwr.u.encoding.flags |= IW_ENCODE_RESTRICTED;
+ }
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWENCODE, &iwr) < 0) {
+ perror("ioctl[SIOCSIWENCODE]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+int wpa_driver_wext_associate(void *priv,
+ struct wpa_driver_associate_params *params)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int ret = 0;
+ int allow_unencrypted_eapol;
+ int value;
+
+ wpa_printf(MSG_DEBUG, "%s", __FUNCTION__);
+
+ /*
+ * If the driver did not support SIOCSIWAUTH, fallback to
+ * SIOCSIWENCODE here.
+ */
+ if (drv->auth_alg_fallback &&
+ wpa_driver_wext_auth_alg_fallback(drv, params) < 0)
+ ret = -1;
+
+ if (!params->bssid &&
+ wpa_driver_wext_set_bssid(drv, NULL) < 0)
+ ret = -1;
+
+ /* TODO: should consider getting wpa version and cipher/key_mgmt suites
+ * from configuration, not from here, where only the selected suite is
+ * available */
+ if (wpa_driver_wext_set_gen_ie(drv, params->wpa_ie, params->wpa_ie_len)
+ < 0)
+ ret = -1;
+ if (params->wpa_ie == NULL || params->wpa_ie_len == 0)
+ value = IW_AUTH_WPA_VERSION_DISABLED;
+ else if (params->wpa_ie[0] == WLAN_EID_RSN)
+ value = IW_AUTH_WPA_VERSION_WPA2;
+ else
+ value = IW_AUTH_WPA_VERSION_WPA;
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_WPA_VERSION, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_cipher2wext(params->pairwise_suite);
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_CIPHER_PAIRWISE, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_cipher2wext(params->group_suite);
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_CIPHER_GROUP, value) < 0)
+ ret = -1;
+ value = wpa_driver_wext_keymgmt2wext(params->key_mgmt_suite);
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_KEY_MGMT, value) < 0)
+ ret = -1;
+ value = params->key_mgmt_suite != KEY_MGMT_NONE ||
+ params->pairwise_suite != CIPHER_NONE ||
+ params->group_suite != CIPHER_NONE ||
+ params->wpa_ie_len;
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_PRIVACY_INVOKED, value) < 0)
+ ret = -1;
+
+ /* Allow unencrypted EAPOL messages even if pairwise keys are set when
+ * not using WPA. IEEE 802.1X specifies that these frames are not
+ * encrypted, but WPA encrypts them when pairwise keys are in use. */
+ if (params->key_mgmt_suite == KEY_MGMT_802_1X ||
+ params->key_mgmt_suite == KEY_MGMT_PSK)
+ allow_unencrypted_eapol = 0;
+ else
+ allow_unencrypted_eapol = 1;
+
+ if (wpa_driver_wext_set_psk(drv, params->psk) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_auth_param(drv,
+ IW_AUTH_RX_UNENCRYPTED_EAPOL,
+ allow_unencrypted_eapol) < 0)
+ ret = -1;
+#ifdef CONFIG_IEEE80211W
+ switch (params->mgmt_frame_protection) {
+ case NO_MGMT_FRAME_PROTECTION:
+ value = IW_AUTH_MFP_DISABLED;
+ break;
+ case MGMT_FRAME_PROTECTION_OPTIONAL:
+ value = IW_AUTH_MFP_OPTIONAL;
+ break;
+ case MGMT_FRAME_PROTECTION_REQUIRED:
+ value = IW_AUTH_MFP_REQUIRED;
+ break;
+ };
+ if (wpa_driver_wext_set_auth_param(drv, IW_AUTH_MFP, value) < 0)
+ ret = -1;
+#endif /* CONFIG_IEEE80211W */
+ if (params->freq && wpa_driver_wext_set_freq(drv, params->freq) < 0)
+ ret = -1;
+ if (wpa_driver_wext_set_ssid(drv, params->ssid, params->ssid_len) < 0)
+ ret = -1;
+ if (params->bssid &&
+ wpa_driver_wext_set_bssid(drv, params->bssid) < 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int wpa_driver_wext_set_auth_alg(void *priv, int auth_alg)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ int algs = 0, res;
+
+ if (auth_alg & AUTH_ALG_OPEN_SYSTEM)
+ algs |= IW_AUTH_ALG_OPEN_SYSTEM;
+ if (auth_alg & AUTH_ALG_SHARED_KEY)
+ algs |= IW_AUTH_ALG_SHARED_KEY;
+ if (auth_alg & AUTH_ALG_LEAP)
+ algs |= IW_AUTH_ALG_LEAP;
+ if (algs == 0) {
+ /* at least one algorithm should be set */
+ algs = IW_AUTH_ALG_OPEN_SYSTEM;
+ }
+
+ res = wpa_driver_wext_set_auth_param(drv, IW_AUTH_80211_AUTH_ALG,
+ algs);
+ drv->auth_alg_fallback = res == -2;
+ return res;
+}
+
+
+/**
+ * wpa_driver_wext_set_mode - Set wireless mode (infra/adhoc), SIOCSIWMODE
+ * @priv: Pointer to private wext data from wpa_driver_wext_init()
+ * @mode: 0 = infra/BSS (associate with an AP), 1 = adhoc/IBSS
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_driver_wext_set_mode(void *priv, int mode)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ struct iwreq iwr;
+ int ret = -1, flags;
+ unsigned int new_mode = mode ? IW_MODE_ADHOC : IW_MODE_INFRA;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ iwr.u.mode = new_mode;
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) == 0) {
+ ret = 0;
+ goto done;
+ }
+
+ if (errno != EBUSY) {
+ perror("ioctl[SIOCSIWMODE]");
+ goto done;
+ }
+
+ /* mac80211 doesn't allow mode changes while the device is up, so if
+ * the device isn't in the mode we're about to change to, take device
+ * down, try to set the mode again, and bring it back up.
+ */
+ if (ioctl(drv->ioctl_sock, SIOCGIWMODE, &iwr) < 0) {
+ perror("ioctl[SIOCGIWMODE]");
+ goto done;
+ }
+
+ if (iwr.u.mode == new_mode) {
+ ret = 0;
+ goto done;
+ }
+
+ if (wpa_driver_wext_get_ifflags(drv, &flags) == 0) {
+ (void) wpa_driver_wext_set_ifflags(drv, flags & ~IFF_UP);
+
+ /* Try to set the mode again while the interface is down */
+ iwr.u.mode = new_mode;
+ if (ioctl(drv->ioctl_sock, SIOCSIWMODE, &iwr) < 0)
+ perror("ioctl[SIOCSIWMODE]");
+ else
+ ret = 0;
+
+ /* Ignore return value of get_ifflags to ensure that the device
+ * is always up like it was before this function was called.
+ */
+ (void) wpa_driver_wext_get_ifflags(drv, &flags);
+ (void) wpa_driver_wext_set_ifflags(drv, flags | IFF_UP);
+ }
+
+done:
+ return ret;
+}
+
+
+static int wpa_driver_wext_pmksa(struct wpa_driver_wext_data *drv,
+ u32 cmd, const u8 *bssid, const u8 *pmkid)
+{
+ struct iwreq iwr;
+ struct iw_pmksa pmksa;
+ int ret = 0;
+
+ os_memset(&iwr, 0, sizeof(iwr));
+ os_strlcpy(iwr.ifr_name, drv->ifname, IFNAMSIZ);
+ os_memset(&pmksa, 0, sizeof(pmksa));
+ pmksa.cmd = cmd;
+ pmksa.bssid.sa_family = ARPHRD_ETHER;
+ if (bssid)
+ os_memcpy(pmksa.bssid.sa_data, bssid, ETH_ALEN);
+ if (pmkid)
+ os_memcpy(pmksa.pmkid, pmkid, IW_PMKID_LEN);
+ iwr.u.data.pointer = (caddr_t) &pmksa;
+ iwr.u.data.length = sizeof(pmksa);
+
+ if (ioctl(drv->ioctl_sock, SIOCSIWPMKSA, &iwr) < 0) {
+ if (errno != EOPNOTSUPP)
+ perror("ioctl[SIOCSIWPMKSA]");
+ ret = -1;
+ }
+
+ return ret;
+}
+
+
+static int wpa_driver_wext_add_pmkid(void *priv, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ return wpa_driver_wext_pmksa(drv, IW_PMKSA_ADD, bssid, pmkid);
+}
+
+
+static int wpa_driver_wext_remove_pmkid(void *priv, const u8 *bssid,
+ const u8 *pmkid)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ return wpa_driver_wext_pmksa(drv, IW_PMKSA_REMOVE, bssid, pmkid);
+}
+
+
+static int wpa_driver_wext_flush_pmkid(void *priv)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ return wpa_driver_wext_pmksa(drv, IW_PMKSA_FLUSH, NULL, NULL);
+}
+
+
+int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa)
+{
+ struct wpa_driver_wext_data *drv = priv;
+ if (!drv->has_capability)
+ return -1;
+ os_memcpy(capa, &drv->capa, sizeof(*capa));
+ return 0;
+}
+
+
+int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv,
+ const char *ifname)
+{
+ if (ifname == NULL) {
+ drv->ifindex2 = -1;
+ return 0;
+ }
+
+ drv->ifindex2 = if_nametoindex(ifname);
+ if (drv->ifindex2 <= 0)
+ return -1;
+
+ wpa_printf(MSG_DEBUG, "Added alternative ifindex %d (%s) for "
+ "wireless events", drv->ifindex2, ifname);
+
+ return 0;
+}
+
+
+int wpa_driver_wext_set_operstate(void *priv, int state)
+{
+ struct wpa_driver_wext_data *drv = priv;
+
+ wpa_printf(MSG_DEBUG, "%s: operstate %d->%d (%s)",
+ __func__, drv->operstate, state, state ? "UP" : "DORMANT");
+ drv->operstate = state;
+ return wpa_driver_wext_send_oper_ifla(
+ drv, -1, state ? IF_OPER_UP : IF_OPER_DORMANT);
+}
+
+
+int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv)
+{
+ return drv->we_version_compiled;
+}
+
+
+const struct wpa_driver_ops wpa_driver_wext_ops = {
+ .name = "wext",
+ .desc = "Linux wireless extensions (generic)",
+ .get_bssid = wpa_driver_wext_get_bssid,
+ .get_ssid = wpa_driver_wext_get_ssid,
+ .set_wpa = wpa_driver_wext_set_wpa,
+ .set_key = wpa_driver_wext_set_key,
+ .set_countermeasures = wpa_driver_wext_set_countermeasures,
+ .set_drop_unencrypted = wpa_driver_wext_set_drop_unencrypted,
+ .scan = wpa_driver_wext_scan,
+ .get_scan_results2 = wpa_driver_wext_get_scan_results,
+ .deauthenticate = wpa_driver_wext_deauthenticate,
+ .disassociate = wpa_driver_wext_disassociate,
+ .set_mode = wpa_driver_wext_set_mode,
+ .associate = wpa_driver_wext_associate,
+ .set_auth_alg = wpa_driver_wext_set_auth_alg,
+ .init = wpa_driver_wext_init,
+ .deinit = wpa_driver_wext_deinit,
+ .add_pmkid = wpa_driver_wext_add_pmkid,
+ .remove_pmkid = wpa_driver_wext_remove_pmkid,
+ .flush_pmkid = wpa_driver_wext_flush_pmkid,
+ .get_capa = wpa_driver_wext_get_capa,
+ .set_operstate = wpa_driver_wext_set_operstate,
+};
diff --git a/src/drivers/driver_wext.h b/src/drivers/driver_wext.h
new file mode 100644
index 0000000..b89c2cb
--- /dev/null
+++ b/src/drivers/driver_wext.h
@@ -0,0 +1,82 @@
+/*
+ * WPA Supplicant - driver_wext exported functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef DRIVER_WEXT_H
+#define DRIVER_WEXT_H
+
+#include <net/if.h>
+
+struct wpa_driver_wext_data {
+ void *ctx;
+ int event_sock;
+ int ioctl_sock;
+ int mlme_sock;
+ char ifname[IFNAMSIZ + 1];
+ int ifindex;
+ int ifindex2;
+ int if_removed;
+ u8 *assoc_req_ies;
+ size_t assoc_req_ies_len;
+ u8 *assoc_resp_ies;
+ size_t assoc_resp_ies_len;
+ struct wpa_driver_capa capa;
+ int has_capability;
+ int we_version_compiled;
+
+ /* for set_auth_alg fallback */
+ int use_crypt;
+ int auth_alg_fallback;
+
+ int operstate;
+
+ char mlmedev[IFNAMSIZ + 1];
+
+ int scan_complete_events;
+};
+
+int wpa_driver_wext_get_ifflags(struct wpa_driver_wext_data *drv, int *flags);
+int wpa_driver_wext_set_ifflags(struct wpa_driver_wext_data *drv, int flags);
+int wpa_driver_wext_get_bssid(void *priv, u8 *bssid);
+int wpa_driver_wext_set_bssid(void *priv, const u8 *bssid);
+int wpa_driver_wext_get_ssid(void *priv, u8 *ssid);
+int wpa_driver_wext_set_ssid(void *priv, const u8 *ssid, size_t ssid_len);
+int wpa_driver_wext_set_freq(void *priv, int freq);
+int wpa_driver_wext_set_mode(void *priv, int mode);
+int wpa_driver_wext_set_key(void *priv, wpa_alg alg,
+ const u8 *addr, int key_idx,
+ int set_tx, const u8 *seq, size_t seq_len,
+ const u8 *key, size_t key_len);
+int wpa_driver_wext_scan(void *priv, const u8 *ssid, size_t ssid_len);
+struct wpa_scan_results * wpa_driver_wext_get_scan_results(void *priv);
+
+void wpa_driver_wext_scan_timeout(void *eloop_ctx, void *timeout_ctx);
+
+int wpa_driver_wext_alternative_ifindex(struct wpa_driver_wext_data *drv,
+ const char *ifname);
+
+void * wpa_driver_wext_init(void *ctx, const char *ifname);
+void wpa_driver_wext_deinit(void *priv);
+
+int wpa_driver_wext_set_operstate(void *priv, int state);
+int wpa_driver_wext_get_version(struct wpa_driver_wext_data *drv);
+
+int wpa_driver_wext_associate(void *priv,
+ struct wpa_driver_associate_params *params);
+int wpa_driver_wext_get_capa(void *priv, struct wpa_driver_capa *capa);
+int wpa_driver_wext_set_auth_param(struct wpa_driver_wext_data *drv,
+ int idx, u32 value);
+int wpa_driver_wext_cipher2wext(int cipher);
+int wpa_driver_wext_keymgmt2wext(int keymgmt);
+
+#endif /* DRIVER_WEXT_H */
diff --git a/src/drivers/driver_wired.c b/src/drivers/driver_wired.c
new file mode 100644
index 0000000..098991a
--- /dev/null
+++ b/src/drivers/driver_wired.c
@@ -0,0 +1,286 @@
+/*
+ * WPA Supplicant - wired Ethernet driver interface
+ * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <net/if.h>
+#ifdef __linux__
+#include <netpacket/packet.h>
+#endif /* __linux__ */
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+#include <net/if_dl.h>
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) */
+
+#include "common.h"
+#include "driver.h"
+
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+
+struct wpa_driver_wired_data {
+ void *ctx;
+ int pf_sock;
+ char ifname[IFNAMSIZ + 1];
+ int membership, multi, iff_allmulti, iff_up;
+};
+
+
+static int wpa_driver_wired_get_ssid(void *priv, u8 *ssid)
+{
+ ssid[0] = 0;
+ return 0;
+}
+
+
+static int wpa_driver_wired_get_bssid(void *priv, u8 *bssid)
+{
+ /* Report PAE group address as the "BSSID" for wired connection. */
+ os_memcpy(bssid, pae_group_addr, ETH_ALEN);
+ return 0;
+}
+
+
+static int wpa_driver_wired_get_ifflags(const char *ifname, int *flags)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(s, SIOCGIFFLAGS, (caddr_t) &ifr) < 0) {
+ perror("ioctl[SIOCGIFFLAGS]");
+ close(s);
+ return -1;
+ }
+ close(s);
+ *flags = ifr.ifr_flags & 0xffff;
+ return 0;
+}
+
+
+static int wpa_driver_wired_set_ifflags(const char *ifname, int flags)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ ifr.ifr_flags = flags & 0xffff;
+ if (ioctl(s, SIOCSIFFLAGS, (caddr_t) &ifr) < 0) {
+ perror("ioctl[SIOCSIFFLAGS]");
+ close(s);
+ return -1;
+ }
+ close(s);
+ return 0;
+}
+
+
+static int wpa_driver_wired_multi(const char *ifname, const u8 *addr, int add)
+{
+ struct ifreq ifr;
+ int s;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return -1;
+ }
+
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, ifname, IFNAMSIZ);
+#ifdef __linux__
+ ifr.ifr_hwaddr.sa_family = AF_UNSPEC;
+ os_memcpy(ifr.ifr_hwaddr.sa_data, addr, ETH_ALEN);
+#endif /* __linux__ */
+#if defined(__FreeBSD__) || defined(__DragonFly__)
+ {
+ struct sockaddr_dl *dlp;
+ dlp = (struct sockaddr_dl *) &ifr.ifr_addr;
+ dlp->sdl_len = sizeof(struct sockaddr_dl);
+ dlp->sdl_family = AF_LINK;
+ dlp->sdl_index = 0;
+ dlp->sdl_nlen = 0;
+ dlp->sdl_alen = ETH_ALEN;
+ dlp->sdl_slen = 0;
+ os_memcpy(LLADDR(dlp), addr, ETH_ALEN);
+ }
+#endif /* defined(__FreeBSD__) || defined(__DragonFly__) */
+#if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__)
+ {
+ struct sockaddr *sap;
+ sap = (struct sockaddr *) &ifr.ifr_addr;
+ sap->sa_len = sizeof(struct sockaddr);
+ sap->sa_family = AF_UNSPEC;
+ os_memcpy(sap->sa_data, addr, ETH_ALEN);
+ }
+#endif /* defined(__NetBSD__) || defined(__OpenBSD__) || defined(__APPLE__) */
+
+ if (ioctl(s, add ? SIOCADDMULTI : SIOCDELMULTI, (caddr_t) &ifr) < 0) {
+ perror("ioctl[SIOC{ADD/DEL}MULTI]");
+ close(s);
+ return -1;
+ }
+ close(s);
+ return 0;
+}
+
+
+static int wpa_driver_wired_membership(struct wpa_driver_wired_data *drv,
+ const u8 *addr, int add)
+{
+#ifdef __linux__
+ struct packet_mreq mreq;
+
+ if (drv->pf_sock == -1)
+ return -1;
+
+ os_memset(&mreq, 0, sizeof(mreq));
+ mreq.mr_ifindex = if_nametoindex(drv->ifname);
+ mreq.mr_type = PACKET_MR_MULTICAST;
+ mreq.mr_alen = ETH_ALEN;
+ os_memcpy(mreq.mr_address, addr, ETH_ALEN);
+
+ if (setsockopt(drv->pf_sock, SOL_PACKET,
+ add ? PACKET_ADD_MEMBERSHIP : PACKET_DROP_MEMBERSHIP,
+ &mreq, sizeof(mreq)) < 0) {
+ perror("setsockopt");
+ return -1;
+ }
+ return 0;
+#else /* __linux__ */
+ return -1;
+#endif /* __linux__ */
+}
+
+
+static void * wpa_driver_wired_init(void *ctx, const char *ifname)
+{
+ struct wpa_driver_wired_data *drv;
+ int flags;
+
+ drv = os_zalloc(sizeof(*drv));
+ if (drv == NULL)
+ return NULL;
+ os_strlcpy(drv->ifname, ifname, sizeof(drv->ifname));
+ drv->ctx = ctx;
+
+#ifdef __linux__
+ drv->pf_sock = socket(PF_PACKET, SOCK_DGRAM, 0);
+ if (drv->pf_sock < 0)
+ perror("socket(PF_PACKET)");
+#else /* __linux__ */
+ drv->pf_sock = -1;
+#endif /* __linux__ */
+
+ if (wpa_driver_wired_get_ifflags(ifname, &flags) == 0 &&
+ !(flags & IFF_UP) &&
+ wpa_driver_wired_set_ifflags(ifname, flags | IFF_UP) == 0) {
+ drv->iff_up = 1;
+ }
+
+ if (wpa_driver_wired_membership(drv, pae_group_addr, 1) == 0) {
+ wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
+ "packet socket", __func__);
+ drv->membership = 1;
+ } else if (wpa_driver_wired_multi(ifname, pae_group_addr, 1) == 0) {
+ wpa_printf(MSG_DEBUG, "%s: Added multicast membership with "
+ "SIOCADDMULTI", __func__);
+ drv->multi = 1;
+ } else if (wpa_driver_wired_get_ifflags(ifname, &flags) < 0) {
+ wpa_printf(MSG_INFO, "%s: Could not get interface "
+ "flags", __func__);
+ os_free(drv);
+ return NULL;
+ } else if (flags & IFF_ALLMULTI) {
+ wpa_printf(MSG_DEBUG, "%s: Interface is already configured "
+ "for multicast", __func__);
+ } else if (wpa_driver_wired_set_ifflags(ifname,
+ flags | IFF_ALLMULTI) < 0) {
+ wpa_printf(MSG_INFO, "%s: Failed to enable allmulti",
+ __func__);
+ os_free(drv);
+ return NULL;
+ } else {
+ wpa_printf(MSG_DEBUG, "%s: Enabled allmulti mode",
+ __func__);
+ drv->iff_allmulti = 1;
+ }
+
+ return drv;
+}
+
+
+static void wpa_driver_wired_deinit(void *priv)
+{
+ struct wpa_driver_wired_data *drv = priv;
+ int flags;
+
+ if (drv->membership &&
+ wpa_driver_wired_membership(drv, pae_group_addr, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
+ "group (PACKET)", __func__);
+ }
+
+ if (drv->multi &&
+ wpa_driver_wired_multi(drv->ifname, pae_group_addr, 0) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to remove PAE multicast "
+ "group (SIOCDELMULTI)", __func__);
+ }
+
+ if (drv->iff_allmulti &&
+ (wpa_driver_wired_get_ifflags(drv->ifname, &flags) < 0 ||
+ wpa_driver_wired_set_ifflags(drv->ifname,
+ flags & ~IFF_ALLMULTI) < 0)) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to disable allmulti mode",
+ __func__);
+ }
+
+ if (drv->iff_up &&
+ wpa_driver_wired_get_ifflags(drv->ifname, &flags) == 0 &&
+ (flags & IFF_UP) &&
+ wpa_driver_wired_set_ifflags(drv->ifname, flags & ~IFF_UP) < 0) {
+ wpa_printf(MSG_DEBUG, "%s: Failed to set the interface down",
+ __func__);
+ }
+
+ if (drv->pf_sock != -1)
+ close(drv->pf_sock);
+
+ os_free(drv);
+}
+
+
+const struct wpa_driver_ops wpa_driver_wired_ops = {
+ .name = "wired",
+ .desc = "wpa_supplicant wired Ethernet driver",
+ .get_ssid = wpa_driver_wired_get_ssid,
+ .get_bssid = wpa_driver_wired_get_bssid,
+ .init = wpa_driver_wired_init,
+ .deinit = wpa_driver_wired_deinit,
+};
diff --git a/src/drivers/ndis_events.c b/src/drivers/ndis_events.c
new file mode 100644
index 0000000..f6eaa7c
--- /dev/null
+++ b/src/drivers/ndis_events.c
@@ -0,0 +1,808 @@
+/*
+ * ndis_events - Receive NdisMIndicateStatus() events using WMI
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#define _WIN32_WINNT 0x0400
+
+#include "includes.h"
+
+#ifndef COBJMACROS
+#define COBJMACROS
+#endif /* COBJMACROS */
+#include <wbemidl.h>
+
+#include "common.h"
+
+
+static int wmi_refcnt = 0;
+static int wmi_first = 1;
+
+struct ndis_events_data {
+ IWbemObjectSink sink;
+ IWbemObjectSinkVtbl sink_vtbl;
+
+ IWbemServices *pSvc;
+ IWbemLocator *pLoc;
+
+ HANDLE read_pipe, write_pipe, event_avail;
+ UINT ref;
+ int terminating;
+ char *ifname; /* {GUID..} */
+ WCHAR *adapter_desc;
+};
+
+#define BstrAlloc(x) (x) ? SysAllocString(x) : NULL
+#define BstrFree(x) if (x) SysFreeString(x)
+
+/* WBEM / WMI wrapper functions, to perform in-place conversion of WCHARs to
+ * BSTRs */
+HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecQuery(
+ IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
+ long lFlags, IWbemContext *pCtx, IEnumWbemClassObject **ppEnum)
+{
+ BSTR bsQueryLanguage, bsQuery;
+ HRESULT hr;
+
+ bsQueryLanguage = BstrAlloc(strQueryLanguage);
+ bsQuery = BstrAlloc(strQuery);
+
+ hr = IWbemServices_ExecQuery(pSvc, bsQueryLanguage, bsQuery, lFlags,
+ pCtx, ppEnum);
+
+ BstrFree(bsQueryLanguage);
+ BstrFree(bsQuery);
+
+ return hr;
+}
+
+
+HRESULT STDMETHODCALLTYPE call_IWbemServices_ExecNotificationQueryAsync(
+ IWbemServices *pSvc, LPCWSTR strQueryLanguage, LPCWSTR strQuery,
+ long lFlags, IWbemContext *pCtx, IWbemObjectSink *pResponseHandler)
+{
+ BSTR bsQueryLanguage, bsQuery;
+ HRESULT hr;
+
+ bsQueryLanguage = BstrAlloc(strQueryLanguage);
+ bsQuery = BstrAlloc(strQuery);
+
+ hr = IWbemServices_ExecNotificationQueryAsync(pSvc, bsQueryLanguage,
+ bsQuery, lFlags, pCtx,
+ pResponseHandler);
+
+ BstrFree(bsQueryLanguage);
+ BstrFree(bsQuery);
+
+ return hr;
+}
+
+
+HRESULT STDMETHODCALLTYPE call_IWbemLocator_ConnectServer(
+ IWbemLocator *pLoc, LPCWSTR strNetworkResource, LPCWSTR strUser,
+ LPCWSTR strPassword, LPCWSTR strLocale, long lSecurityFlags,
+ LPCWSTR strAuthority, IWbemContext *pCtx, IWbemServices **ppNamespace)
+{
+ BSTR bsNetworkResource, bsUser, bsPassword, bsLocale, bsAuthority;
+ HRESULT hr;
+
+ bsNetworkResource = BstrAlloc(strNetworkResource);
+ bsUser = BstrAlloc(strUser);
+ bsPassword = BstrAlloc(strPassword);
+ bsLocale = BstrAlloc(strLocale);
+ bsAuthority = BstrAlloc(strAuthority);
+
+ hr = IWbemLocator_ConnectServer(pLoc, bsNetworkResource, bsUser,
+ bsPassword, bsLocale, lSecurityFlags,
+ bsAuthority, pCtx, ppNamespace);
+
+ BstrFree(bsNetworkResource);
+ BstrFree(bsUser);
+ BstrFree(bsPassword);
+ BstrFree(bsLocale);
+ BstrFree(bsAuthority);
+
+ return hr;
+}
+
+
+enum event_types { EVENT_CONNECT, EVENT_DISCONNECT, EVENT_MEDIA_SPECIFIC,
+ EVENT_ADAPTER_ARRIVAL, EVENT_ADAPTER_REMOVAL };
+
+static int ndis_events_get_adapter(struct ndis_events_data *events,
+ const char *ifname, const char *desc);
+
+
+static int ndis_events_constructor(struct ndis_events_data *events)
+{
+ events->ref = 1;
+
+ if (!CreatePipe(&events->read_pipe, &events->write_pipe, NULL, 512)) {
+ wpa_printf(MSG_ERROR, "CreatePipe() failed: %d",
+ (int) GetLastError());
+ return -1;
+ }
+ events->event_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (events->event_avail == NULL) {
+ wpa_printf(MSG_ERROR, "CreateEvent() failed: %d",
+ (int) GetLastError());
+ CloseHandle(events->read_pipe);
+ CloseHandle(events->write_pipe);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void ndis_events_destructor(struct ndis_events_data *events)
+{
+ CloseHandle(events->read_pipe);
+ CloseHandle(events->write_pipe);
+ CloseHandle(events->event_avail);
+ IWbemServices_Release(events->pSvc);
+ IWbemLocator_Release(events->pLoc);
+ if (--wmi_refcnt == 0)
+ CoUninitialize();
+}
+
+
+static HRESULT STDMETHODCALLTYPE
+ndis_events_query_interface(IWbemObjectSink *this, REFIID riid, void **obj)
+{
+ *obj = NULL;
+
+ if (IsEqualIID(riid, &IID_IUnknown) ||
+ IsEqualIID(riid, &IID_IWbemObjectSink)) {
+ *obj = this;
+ IWbemObjectSink_AddRef(this);
+ return NOERROR;
+ }
+
+ return E_NOINTERFACE;
+}
+
+
+static ULONG STDMETHODCALLTYPE ndis_events_add_ref(IWbemObjectSink *this)
+{
+ struct ndis_events_data *events = (struct ndis_events_data *) this;
+ return ++events->ref;
+}
+
+
+static ULONG STDMETHODCALLTYPE ndis_events_release(IWbemObjectSink *this)
+{
+ struct ndis_events_data *events = (struct ndis_events_data *) this;
+
+ if (--events->ref != 0)
+ return events->ref;
+
+ ndis_events_destructor(events);
+ wpa_printf(MSG_DEBUG, "ndis_events: terminated");
+ os_free(events->adapter_desc);
+ os_free(events->ifname);
+ os_free(events);
+ return 0;
+}
+
+
+static int ndis_events_send_event(struct ndis_events_data *events,
+ enum event_types type,
+ char *data, size_t data_len)
+{
+ char buf[512], *pos, *end;
+ int _type;
+ DWORD written;
+
+ end = buf + sizeof(buf);
+ _type = (int) type;
+ os_memcpy(buf, &_type, sizeof(_type));
+ pos = buf + sizeof(_type);
+
+ if (data) {
+ if (2 + data_len > (size_t) (end - pos)) {
+ wpa_printf(MSG_DEBUG, "Not enough room for send_event "
+ "data (%d)", data_len);
+ return -1;
+ }
+ *pos++ = data_len >> 8;
+ *pos++ = data_len & 0xff;
+ os_memcpy(pos, data, data_len);
+ pos += data_len;
+ }
+
+ if (WriteFile(events->write_pipe, buf, pos - buf, &written, NULL)) {
+ SetEvent(events->event_avail);
+ return 0;
+ }
+ wpa_printf(MSG_INFO, "WriteFile() failed: %d", (int) GetLastError());
+ return -1;
+}
+
+
+static void ndis_events_media_connect(struct ndis_events_data *events)
+{
+ wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaConnect");
+ ndis_events_send_event(events, EVENT_CONNECT, NULL, 0);
+}
+
+
+static void ndis_events_media_disconnect(struct ndis_events_data *events)
+{
+ wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaDisconnect");
+ ndis_events_send_event(events, EVENT_DISCONNECT, NULL, 0);
+}
+
+
+static void ndis_events_media_specific(struct ndis_events_data *events,
+ IWbemClassObject *pObj)
+{
+ VARIANT vt;
+ HRESULT hr;
+ LONG lower, upper, k;
+ UCHAR ch;
+ char *data, *pos;
+ size_t data_len;
+
+ wpa_printf(MSG_DEBUG, "MSNdis_StatusMediaSpecificIndication");
+
+ /* This is the StatusBuffer from NdisMIndicateStatus() call */
+ hr = IWbemClassObject_Get(pObj, L"NdisStatusMediaSpecificIndication",
+ 0, &vt, NULL, NULL);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_DEBUG, "Could not get "
+ "NdisStatusMediaSpecificIndication from "
+ "the object?!");
+ return;
+ }
+
+ SafeArrayGetLBound(V_ARRAY(&vt), 1, &lower);
+ SafeArrayGetUBound(V_ARRAY(&vt), 1, &upper);
+ data_len = upper - lower + 1;
+ data = os_malloc(data_len);
+ if (data == NULL) {
+ wpa_printf(MSG_DEBUG, "Failed to allocate buffer for event "
+ "data");
+ VariantClear(&vt);
+ return;
+ }
+
+ pos = data;
+ for (k = lower; k <= upper; k++) {
+ SafeArrayGetElement(V_ARRAY(&vt), &k, &ch);
+ *pos++ = ch;
+ }
+ wpa_hexdump(MSG_DEBUG, "MediaSpecificEvent", (u8 *) data, data_len);
+
+ VariantClear(&vt);
+
+ ndis_events_send_event(events, EVENT_MEDIA_SPECIFIC, data, data_len);
+
+ os_free(data);
+}
+
+
+static void ndis_events_adapter_arrival(struct ndis_events_data *events)
+{
+ wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterArrival");
+ ndis_events_send_event(events, EVENT_ADAPTER_ARRIVAL, NULL, 0);
+}
+
+
+static void ndis_events_adapter_removal(struct ndis_events_data *events)
+{
+ wpa_printf(MSG_DEBUG, "MSNdis_NotifyAdapterRemoval");
+ ndis_events_send_event(events, EVENT_ADAPTER_REMOVAL, NULL, 0);
+}
+
+
+static HRESULT STDMETHODCALLTYPE
+ndis_events_indicate(IWbemObjectSink *this, long lObjectCount,
+ IWbemClassObject __RPC_FAR *__RPC_FAR *ppObjArray)
+{
+ struct ndis_events_data *events = (struct ndis_events_data *) this;
+ long i;
+
+ if (events->terminating) {
+ wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
+ "indication - terminating");
+ return WBEM_NO_ERROR;
+ }
+ /* wpa_printf(MSG_DEBUG, "Notification received - %d object(s)",
+ lObjectCount); */
+
+ for (i = 0; i < lObjectCount; i++) {
+ IWbemClassObject *pObj = ppObjArray[i];
+ HRESULT hr;
+ VARIANT vtClass, vt;
+
+ hr = IWbemClassObject_Get(pObj, L"__CLASS", 0, &vtClass, NULL,
+ NULL);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_DEBUG, "Failed to get __CLASS from "
+ "event.");
+ break;
+ }
+ /* wpa_printf(MSG_DEBUG, "CLASS: '%S'", vtClass.bstrVal); */
+
+ hr = IWbemClassObject_Get(pObj, L"InstanceName", 0, &vt, NULL,
+ NULL);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_DEBUG, "Failed to get InstanceName "
+ "from event.");
+ VariantClear(&vtClass);
+ break;
+ }
+
+ if (wcscmp(vtClass.bstrVal,
+ L"MSNdis_NotifyAdapterArrival") == 0) {
+ wpa_printf(MSG_DEBUG, "ndis_events_indicate: Try to "
+ "update adapter description since it may "
+ "have changed with new adapter instance");
+ ndis_events_get_adapter(events, events->ifname, NULL);
+ }
+
+ if (wcscmp(events->adapter_desc, vt.bstrVal) != 0) {
+ wpa_printf(MSG_DEBUG, "ndis_events_indicate: Ignore "
+ "indication for foreign adapter: "
+ "InstanceName: '%S' __CLASS: '%S'",
+ vt.bstrVal, vtClass.bstrVal);
+ VariantClear(&vtClass);
+ VariantClear(&vt);
+ continue;
+ }
+ VariantClear(&vt);
+
+ if (wcscmp(vtClass.bstrVal,
+ L"MSNdis_StatusMediaSpecificIndication") == 0) {
+ ndis_events_media_specific(events, pObj);
+ } else if (wcscmp(vtClass.bstrVal,
+ L"MSNdis_StatusMediaConnect") == 0) {
+ ndis_events_media_connect(events);
+ } else if (wcscmp(vtClass.bstrVal,
+ L"MSNdis_StatusMediaDisconnect") == 0) {
+ ndis_events_media_disconnect(events);
+ } else if (wcscmp(vtClass.bstrVal,
+ L"MSNdis_NotifyAdapterArrival") == 0) {
+ ndis_events_adapter_arrival(events);
+ } else if (wcscmp(vtClass.bstrVal,
+ L"MSNdis_NotifyAdapterRemoval") == 0) {
+ ndis_events_adapter_removal(events);
+ } else {
+ wpa_printf(MSG_DEBUG, "Unepected event - __CLASS: "
+ "'%S'", vtClass.bstrVal);
+ }
+
+ VariantClear(&vtClass);
+ }
+
+ return WBEM_NO_ERROR;
+}
+
+
+static HRESULT STDMETHODCALLTYPE
+ndis_events_set_status(IWbemObjectSink *this, long lFlags, HRESULT hResult,
+ BSTR strParam, IWbemClassObject __RPC_FAR *pObjParam)
+{
+ return WBEM_NO_ERROR;
+}
+
+
+static int notification_query(IWbemObjectSink *pDestSink,
+ IWbemServices *pSvc, const char *class_name)
+{
+ HRESULT hr;
+ WCHAR query[256];
+
+ _snwprintf(query, 256,
+ L"SELECT * FROM %S", class_name);
+ wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
+ hr = call_IWbemServices_ExecNotificationQueryAsync(
+ pSvc, L"WQL", query, 0, 0, pDestSink);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_DEBUG, "ExecNotificationQueryAsync for %s "
+ "failed with hresult of 0x%x",
+ class_name, (int) hr);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int register_async_notification(IWbemObjectSink *pDestSink,
+ IWbemServices *pSvc)
+{
+ int i;
+ const char *class_list[] = {
+ "MSNdis_StatusMediaConnect",
+ "MSNdis_StatusMediaDisconnect",
+ "MSNdis_StatusMediaSpecificIndication",
+ "MSNdis_NotifyAdapterArrival",
+ "MSNdis_NotifyAdapterRemoval",
+ NULL
+ };
+
+ for (i = 0; class_list[i]; i++) {
+ if (notification_query(pDestSink, pSvc, class_list[i]) < 0)
+ return -1;
+ }
+
+ return 0;
+}
+
+
+void ndis_events_deinit(struct ndis_events_data *events)
+{
+ events->terminating = 1;
+ IWbemServices_CancelAsyncCall(events->pSvc, &events->sink);
+ IWbemObjectSink_Release(&events->sink);
+ /*
+ * Rest of deinitialization is done in ndis_events_destructor() once
+ * all reference count drops to zero.
+ */
+}
+
+
+static int ndis_events_use_desc(struct ndis_events_data *events,
+ const char *desc)
+{
+ char *tmp, *pos;
+ size_t len;
+
+ if (desc == NULL) {
+ if (events->adapter_desc == NULL)
+ return -1;
+ /* Continue using old description */
+ return 0;
+ }
+
+ tmp = os_strdup(desc);
+ if (tmp == NULL)
+ return -1;
+
+ pos = os_strstr(tmp, " (Microsoft's Packet Scheduler)");
+ if (pos)
+ *pos = '\0';
+
+ len = os_strlen(tmp);
+ events->adapter_desc = os_malloc((len + 1) * sizeof(WCHAR));
+ if (events->adapter_desc == NULL) {
+ os_free(tmp);
+ return -1;
+ }
+ _snwprintf(events->adapter_desc, len + 1, L"%S", tmp);
+ os_free(tmp);
+ return 0;
+}
+
+
+static int ndis_events_get_adapter(struct ndis_events_data *events,
+ const char *ifname, const char *desc)
+{
+ HRESULT hr;
+ IWbemServices *pSvc;
+#define MAX_QUERY_LEN 256
+ WCHAR query[MAX_QUERY_LEN];
+ IEnumWbemClassObject *pEnumerator;
+ IWbemClassObject *pObj;
+ ULONG uReturned;
+ VARIANT vt;
+ int len, pos;
+
+ /*
+ * Try to get adapter descriptor through WMI CIMv2 Win32_NetworkAdapter
+ * to have better probability of matching with InstanceName from
+ * MSNdis events. If this fails, use the provided description.
+ */
+
+ os_free(events->adapter_desc);
+ events->adapter_desc = NULL;
+
+ hr = call_IWbemLocator_ConnectServer(
+ events->pLoc, L"ROOT\\CIMV2", NULL, NULL, 0, 0, 0, 0, &pSvc);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_ERROR, "ndis_events: Could not connect to WMI "
+ "server (ROOT\\CIMV2) - error 0x%x", (int) hr);
+ return ndis_events_use_desc(events, desc);
+ }
+ wpa_printf(MSG_DEBUG, "ndis_events: Connected to ROOT\\CIMV2.");
+
+ _snwprintf(query, MAX_QUERY_LEN,
+ L"SELECT Index FROM Win32_NetworkAdapterConfiguration "
+ L"WHERE SettingID='%S'", ifname);
+ wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
+
+ hr = call_IWbemServices_ExecQuery(
+ pSvc, L"WQL", query,
+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+ NULL, &pEnumerator);
+ if (!SUCCEEDED(hr)) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
+ "GUID from Win32_NetworkAdapterConfiguration: "
+ "0x%x", (int) hr);
+ IWbemServices_Release(pSvc);
+ return ndis_events_use_desc(events, desc);
+ }
+
+ uReturned = 0;
+ hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
+ &pObj, &uReturned);
+ if (!SUCCEEDED(hr) || uReturned == 0) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
+ "GUID from Win32_NetworkAdapterConfiguration: "
+ "0x%x", (int) hr);
+ IEnumWbemClassObject_Release(pEnumerator);
+ IWbemServices_Release(pSvc);
+ return ndis_events_use_desc(events, desc);
+ }
+ IEnumWbemClassObject_Release(pEnumerator);
+
+ VariantInit(&vt);
+ hr = IWbemClassObject_Get(pObj, L"Index", 0, &vt, NULL, NULL);
+ if (!SUCCEEDED(hr)) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Index from "
+ "Win32_NetworkAdapterConfiguration: 0x%x",
+ (int) hr);
+ IWbemServices_Release(pSvc);
+ return ndis_events_use_desc(events, desc);
+ }
+
+ _snwprintf(query, MAX_QUERY_LEN,
+ L"SELECT Name,PNPDeviceID FROM Win32_NetworkAdapter WHERE "
+ L"Index=%d",
+ vt.uintVal);
+ wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
+ VariantClear(&vt);
+ IWbemClassObject_Release(pObj);
+
+ hr = call_IWbemServices_ExecQuery(
+ pSvc, L"WQL", query,
+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+ NULL, &pEnumerator);
+ if (!SUCCEEDED(hr)) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
+ "from Win32_NetworkAdapter: 0x%x", (int) hr);
+ IWbemServices_Release(pSvc);
+ return ndis_events_use_desc(events, desc);
+ }
+
+ uReturned = 0;
+ hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
+ &pObj, &uReturned);
+ if (!SUCCEEDED(hr) || uReturned == 0) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
+ "from Win32_NetworkAdapter: 0x%x", (int) hr);
+ IEnumWbemClassObject_Release(pEnumerator);
+ IWbemServices_Release(pSvc);
+ return ndis_events_use_desc(events, desc);
+ }
+ IEnumWbemClassObject_Release(pEnumerator);
+
+ hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
+ if (!SUCCEEDED(hr)) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
+ "Win32_NetworkAdapter: 0x%x", (int) hr);
+ IWbemClassObject_Release(pObj);
+ IWbemServices_Release(pSvc);
+ return ndis_events_use_desc(events, desc);
+ }
+
+ wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::Name='%S'",
+ vt.bstrVal);
+ events->adapter_desc = _wcsdup(vt.bstrVal);
+ VariantClear(&vt);
+
+ /*
+ * Try to get even better candidate for matching with InstanceName
+ * from Win32_PnPEntity. This is needed at least for some USB cards
+ * that can change the InstanceName whenever being unplugged and
+ * plugged again.
+ */
+
+ hr = IWbemClassObject_Get(pObj, L"PNPDeviceID", 0, &vt, NULL, NULL);
+ if (!SUCCEEDED(hr)) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to get PNPDeviceID "
+ "from Win32_NetworkAdapter: 0x%x", (int) hr);
+ IWbemClassObject_Release(pObj);
+ IWbemServices_Release(pSvc);
+ if (events->adapter_desc == NULL)
+ return ndis_events_use_desc(events, desc);
+ return 0; /* use Win32_NetworkAdapter::Name */
+ }
+
+ wpa_printf(MSG_DEBUG, "ndis_events: Win32_NetworkAdapter::PNPDeviceID="
+ "'%S'", vt.bstrVal);
+
+ len = _snwprintf(query, MAX_QUERY_LEN,
+ L"SELECT Name FROM Win32_PnPEntity WHERE DeviceID='");
+ if (len < 0 || len >= MAX_QUERY_LEN - 1) {
+ VariantClear(&vt);
+ IWbemClassObject_Release(pObj);
+ IWbemServices_Release(pSvc);
+ if (events->adapter_desc == NULL)
+ return ndis_events_use_desc(events, desc);
+ return 0; /* use Win32_NetworkAdapter::Name */
+ }
+
+ /* Escape \ as \\ */
+ for (pos = 0; vt.bstrVal[pos] && len < MAX_QUERY_LEN - 2; pos++) {
+ if (vt.bstrVal[pos] == '\\') {
+ if (len >= MAX_QUERY_LEN - 3)
+ break;
+ query[len++] = '\\';
+ }
+ query[len++] = vt.bstrVal[pos];
+ }
+ query[len++] = L'\'';
+ query[len] = L'\0';
+ VariantClear(&vt);
+ IWbemClassObject_Release(pObj);
+ wpa_printf(MSG_DEBUG, "ndis_events: WMI: %S", query);
+
+ hr = call_IWbemServices_ExecQuery(
+ pSvc, L"WQL", query,
+ WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY,
+ NULL, &pEnumerator);
+ if (!SUCCEEDED(hr)) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to query interface "
+ "Name from Win32_PnPEntity: 0x%x", (int) hr);
+ IWbemServices_Release(pSvc);
+ if (events->adapter_desc == NULL)
+ return ndis_events_use_desc(events, desc);
+ return 0; /* use Win32_NetworkAdapter::Name */
+ }
+
+ uReturned = 0;
+ hr = IEnumWbemClassObject_Next(pEnumerator, WBEM_INFINITE, 1,
+ &pObj, &uReturned);
+ if (!SUCCEEDED(hr) || uReturned == 0) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to find interface "
+ "from Win32_PnPEntity: 0x%x", (int) hr);
+ IEnumWbemClassObject_Release(pEnumerator);
+ IWbemServices_Release(pSvc);
+ if (events->adapter_desc == NULL)
+ return ndis_events_use_desc(events, desc);
+ return 0; /* use Win32_NetworkAdapter::Name */
+ }
+ IEnumWbemClassObject_Release(pEnumerator);
+
+ hr = IWbemClassObject_Get(pObj, L"Name", 0, &vt, NULL, NULL);
+ if (!SUCCEEDED(hr)) {
+ wpa_printf(MSG_DEBUG, "ndis_events: Failed to get Name from "
+ "Win32_PnPEntity: 0x%x", (int) hr);
+ IWbemClassObject_Release(pObj);
+ IWbemServices_Release(pSvc);
+ if (events->adapter_desc == NULL)
+ return ndis_events_use_desc(events, desc);
+ return 0; /* use Win32_NetworkAdapter::Name */
+ }
+
+ wpa_printf(MSG_DEBUG, "ndis_events: Win32_PnPEntity::Name='%S'",
+ vt.bstrVal);
+ os_free(events->adapter_desc);
+ events->adapter_desc = _wcsdup(vt.bstrVal);
+ VariantClear(&vt);
+
+ IWbemClassObject_Release(pObj);
+
+ IWbemServices_Release(pSvc);
+
+ if (events->adapter_desc == NULL)
+ return ndis_events_use_desc(events, desc);
+
+ return 0;
+}
+
+
+struct ndis_events_data *
+ndis_events_init(HANDLE *read_pipe, HANDLE *event_avail,
+ const char *ifname, const char *desc)
+{
+ HRESULT hr;
+ IWbemObjectSink *pSink;
+ struct ndis_events_data *events;
+
+ events = os_zalloc(sizeof(*events));
+ if (events == NULL) {
+ wpa_printf(MSG_ERROR, "Could not allocate sink for events.");
+ return NULL;
+ }
+ events->ifname = os_strdup(ifname);
+ if (events->ifname == NULL) {
+ os_free(events);
+ return NULL;
+ }
+
+ if (wmi_refcnt++ == 0) {
+ hr = CoInitializeEx(0, COINIT_MULTITHREADED);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_ERROR, "CoInitializeEx() failed - "
+ "returned 0x%x", (int) hr);
+ os_free(events);
+ return NULL;
+ }
+ }
+
+ if (wmi_first) {
+ /* CoInitializeSecurity() must be called once and only once
+ * per process, so let's use wmi_first flag to protect against
+ * multiple calls. */
+ wmi_first = 0;
+
+ hr = CoInitializeSecurity(NULL, -1, NULL, NULL,
+ RPC_C_AUTHN_LEVEL_PKT_PRIVACY,
+ RPC_C_IMP_LEVEL_IMPERSONATE,
+ NULL, EOAC_SECURE_REFS, NULL);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_ERROR, "CoInitializeSecurity() failed "
+ "- returned 0x%x", (int) hr);
+ os_free(events);
+ return NULL;
+ }
+ }
+
+ hr = CoCreateInstance(&CLSID_WbemLocator, 0, CLSCTX_INPROC_SERVER,
+ &IID_IWbemLocator,
+ (LPVOID *) (void *) &events->pLoc);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_ERROR, "CoCreateInstance() failed - returned "
+ "0x%x", (int) hr);
+ CoUninitialize();
+ os_free(events);
+ return NULL;
+ }
+
+ if (ndis_events_get_adapter(events, ifname, desc) < 0) {
+ CoUninitialize();
+ os_free(events);
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "ndis_events: use adapter descriptor '%S'",
+ events->adapter_desc);
+
+ hr = call_IWbemLocator_ConnectServer(
+ events->pLoc, L"ROOT\\WMI", NULL, NULL,
+ 0, 0, 0, 0, &events->pSvc);
+ if (FAILED(hr)) {
+ wpa_printf(MSG_ERROR, "Could not connect to server - error "
+ "0x%x", (int) hr);
+ CoUninitialize();
+ os_free(events->adapter_desc);
+ os_free(events);
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "Connected to ROOT\\WMI.");
+
+ ndis_events_constructor(events);
+ pSink = &events->sink;
+ pSink->lpVtbl = &events->sink_vtbl;
+ events->sink_vtbl.QueryInterface = ndis_events_query_interface;
+ events->sink_vtbl.AddRef = ndis_events_add_ref;
+ events->sink_vtbl.Release = ndis_events_release;
+ events->sink_vtbl.Indicate = ndis_events_indicate;
+ events->sink_vtbl.SetStatus = ndis_events_set_status;
+
+ if (register_async_notification(pSink, events->pSvc) < 0) {
+ wpa_printf(MSG_DEBUG, "Failed to register async "
+ "notifications");
+ ndis_events_destructor(events);
+ os_free(events->adapter_desc);
+ os_free(events);
+ return NULL;
+ }
+
+ *read_pipe = events->read_pipe;
+ *event_avail = events->event_avail;
+
+ return events;
+}
diff --git a/src/drivers/priv_netlink.h b/src/drivers/priv_netlink.h
new file mode 100644
index 0000000..2a31e25
--- /dev/null
+++ b/src/drivers/priv_netlink.h
@@ -0,0 +1,104 @@
+/*
+ * wpa_supplicant - Private copy of Linux netlink/rtnetlink definitions.
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef PRIV_NETLINK_H
+#define PRIV_NETLINK_H
+
+/*
+ * This should be replaced with user space header once one is available with C
+ * library, etc..
+ */
+
+#ifndef IFF_LOWER_UP
+#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */
+#endif
+#ifndef IFF_DORMANT
+#define IFF_DORMANT 0x20000 /* driver signals dormant */
+#endif
+
+#ifndef IFLA_IFNAME
+#define IFLA_IFNAME 3
+#endif
+#ifndef IFLA_WIRELESS
+#define IFLA_WIRELESS 11
+#endif
+#ifndef IFLA_OPERSTATE
+#define IFLA_OPERSTATE 16
+#endif
+#ifndef IFLA_LINKMODE
+#define IFLA_LINKMODE 17
+#define IF_OPER_DORMANT 5
+#define IF_OPER_UP 6
+#endif
+
+#define NLM_F_REQUEST 1
+
+#define NETLINK_ROUTE 0
+#define RTMGRP_LINK 1
+#define RTM_BASE 0x10
+#define RTM_NEWLINK (RTM_BASE + 0)
+#define RTM_DELLINK (RTM_BASE + 1)
+#define RTM_SETLINK (RTM_BASE + 3)
+
+#define NLMSG_ALIGNTO 4
+#define NLMSG_ALIGN(len) (((len) + NLMSG_ALIGNTO - 1) & ~(NLMSG_ALIGNTO - 1))
+#define NLMSG_LENGTH(len) ((len) + NLMSG_ALIGN(sizeof(struct nlmsghdr)))
+#define NLMSG_DATA(nlh) ((void*) (((char*) nlh) + NLMSG_LENGTH(0)))
+
+#define RTA_ALIGNTO 4
+#define RTA_ALIGN(len) (((len) + RTA_ALIGNTO - 1) & ~(RTA_ALIGNTO - 1))
+#define RTA_OK(rta,len) \
+((len) > 0 && (rta)->rta_len >= sizeof(struct rtattr) && \
+(rta)->rta_len <= (len))
+#define RTA_NEXT(rta,attrlen) \
+((attrlen) -= RTA_ALIGN((rta)->rta_len), \
+(struct rtattr *) (((char *)(rta)) + RTA_ALIGN((rta)->rta_len)))
+#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
+#define RTA_DATA(rta) ((void *) (((char *) (rta)) + RTA_LENGTH(0)))
+
+
+struct sockaddr_nl
+{
+ sa_family_t nl_family;
+ unsigned short nl_pad;
+ u32 nl_pid;
+ u32 nl_groups;
+};
+
+struct nlmsghdr
+{
+ u32 nlmsg_len;
+ u16 nlmsg_type;
+ u16 nlmsg_flags;
+ u32 nlmsg_seq;
+ u32 nlmsg_pid;
+};
+
+struct ifinfomsg
+{
+ unsigned char ifi_family;
+ unsigned char __ifi_pad;
+ unsigned short ifi_type;
+ int ifi_index;
+ unsigned ifi_flags;
+ unsigned ifi_change;
+};
+
+struct rtattr
+{
+ unsigned short rta_len;
+ unsigned short rta_type;
+};
+
+#endif /* PRIV_NETLINK_H */
diff --git a/src/drivers/radiotap.c b/src/drivers/radiotap.c
new file mode 100644
index 0000000..804473f
--- /dev/null
+++ b/src/drivers/radiotap.c
@@ -0,0 +1,287 @@
+/*
+ * Radiotap parser
+ *
+ * Copyright 2007 Andy Green <andy@warmcat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ *
+ * Modified for userspace by Johannes Berg <johannes@sipsolutions.net>
+ * I only modified some things on top to ease syncing should bugs be found.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "radiotap_iter.h"
+
+#define le16_to_cpu le_to_host16
+#define le32_to_cpu le_to_host32
+#define __le32 uint32_t
+#define ulong unsigned long
+#define unlikely(cond) (cond)
+#define get_unaligned(p) \
+({ \
+ struct packed_dummy_struct { \
+ typeof(*(p)) __val; \
+ } __attribute__((packed)) *__ptr = (void *) (p); \
+ \
+ __ptr->__val; \
+})
+
+/* function prototypes and related defs are in radiotap_iter.h */
+
+/**
+ * ieee80211_radiotap_iterator_init - radiotap parser iterator initialization
+ * @iterator: radiotap_iterator to initialize
+ * @radiotap_header: radiotap header to parse
+ * @max_length: total length we can parse into (eg, whole packet length)
+ *
+ * Returns: 0 or a negative error code if there is a problem.
+ *
+ * This function initializes an opaque iterator struct which can then
+ * be passed to ieee80211_radiotap_iterator_next() to visit every radiotap
+ * argument which is present in the header. It knows about extended
+ * present headers and handles them.
+ *
+ * How to use:
+ * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
+ * struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
+ * checking for a good 0 return code. Then loop calling
+ * __ieee80211_radiotap_iterator_next()... it returns either 0,
+ * -ENOENT if there are no more args to parse, or -EINVAL if there is a problem.
+ * The iterator's @this_arg member points to the start of the argument
+ * associated with the current argument index that is present, which can be
+ * found in the iterator's @this_arg_index member. This arg index corresponds
+ * to the IEEE80211_RADIOTAP_... defines.
+ *
+ * Radiotap header length:
+ * You can find the CPU-endian total radiotap header length in
+ * iterator->max_length after executing ieee80211_radiotap_iterator_init()
+ * successfully.
+ *
+ * Alignment Gotcha:
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ *
+ * Example code:
+ * See Documentation/networking/radiotap-headers.txt
+ */
+
+int ieee80211_radiotap_iterator_init(
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length)
+{
+ /* Linux only supports version 0 radiotap format */
+ if (radiotap_header->it_version)
+ return -EINVAL;
+
+ /* sanity check for allowed length and radiotap length field */
+ if (max_length < le16_to_cpu(get_unaligned(&radiotap_header->it_len)))
+ return -EINVAL;
+
+ iterator->rtheader = radiotap_header;
+ iterator->max_length = le16_to_cpu(get_unaligned(
+ &radiotap_header->it_len));
+ iterator->arg_index = 0;
+ iterator->bitmap_shifter = le32_to_cpu(get_unaligned(
+ &radiotap_header->it_present));
+ iterator->arg = (u8 *)radiotap_header + sizeof(*radiotap_header);
+ iterator->this_arg = NULL;
+
+ /* find payload start allowing for extended bitmap(s) */
+
+ if (unlikely(iterator->bitmap_shifter & (1<<IEEE80211_RADIOTAP_EXT))) {
+ while (le32_to_cpu(get_unaligned((__le32 *)iterator->arg)) &
+ (1<<IEEE80211_RADIOTAP_EXT)) {
+ iterator->arg += sizeof(u32);
+
+ /*
+ * check for insanity where the present bitmaps
+ * keep claiming to extend up to or even beyond the
+ * stated radiotap header length
+ */
+
+ if (((ulong)iterator->arg - (ulong)iterator->rtheader)
+ > (ulong)iterator->max_length)
+ return -EINVAL;
+ }
+
+ iterator->arg += sizeof(u32);
+
+ /*
+ * no need to check again for blowing past stated radiotap
+ * header length, because ieee80211_radiotap_iterator_next
+ * checks it before it is dereferenced
+ */
+ }
+
+ /* we are all initialized happily */
+
+ return 0;
+}
+
+
+/**
+ * ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
+ * @iterator: radiotap_iterator to move to next arg (if any)
+ *
+ * Returns: 0 if there is an argument to handle,
+ * -ENOENT if there are no more args or -EINVAL
+ * if there is something else wrong.
+ *
+ * This function provides the next radiotap arg index (IEEE80211_RADIOTAP_*)
+ * in @this_arg_index and sets @this_arg to point to the
+ * payload for the field. It takes care of alignment handling and extended
+ * present fields. @this_arg can be changed by the caller (eg,
+ * incremented to move inside a compound argument like
+ * IEEE80211_RADIOTAP_CHANNEL). The args pointed to are in
+ * little-endian format whatever the endianess of your CPU.
+ *
+ * Alignment Gotcha:
+ * You must take care when dereferencing iterator.this_arg
+ * for multibyte types... the pointer is not aligned. Use
+ * get_unaligned((type *)iterator.this_arg) to dereference
+ * iterator.this_arg for type "type" safely on all arches.
+ */
+
+int ieee80211_radiotap_iterator_next(
+ struct ieee80211_radiotap_iterator *iterator)
+{
+
+ /*
+ * small length lookup table for all radiotap types we heard of
+ * starting from b0 in the bitmap, so we can walk the payload
+ * area of the radiotap header
+ *
+ * There is a requirement to pad args, so that args
+ * of a given length must begin at a boundary of that length
+ * -- but note that compound args are allowed (eg, 2 x u16
+ * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
+ * a reliable indicator of alignment requirement.
+ *
+ * upper nybble: content alignment for arg
+ * lower nybble: content length for arg
+ */
+
+ static const u8 rt_sizes[] = {
+ [IEEE80211_RADIOTAP_TSFT] = 0x88,
+ [IEEE80211_RADIOTAP_FLAGS] = 0x11,
+ [IEEE80211_RADIOTAP_RATE] = 0x11,
+ [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
+ [IEEE80211_RADIOTAP_FHSS] = 0x22,
+ [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
+ [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
+ [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
+ [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
+ [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
+ [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
+ [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
+ [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
+ [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
+ [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
+ [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
+ [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
+ [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11,
+ /*
+ * add more here as they are defined in
+ * include/net/ieee80211_radiotap.h
+ */
+ };
+
+ /*
+ * for every radiotap entry we can at
+ * least skip (by knowing the length)...
+ */
+
+ while (iterator->arg_index < (int) sizeof(rt_sizes)) {
+ int hit = 0;
+ int pad;
+
+ if (!(iterator->bitmap_shifter & 1))
+ goto next_entry; /* arg not present */
+
+ /*
+ * arg is present, account for alignment padding
+ * 8-bit args can be at any alignment
+ * 16-bit args must start on 16-bit boundary
+ * 32-bit args must start on 32-bit boundary
+ * 64-bit args must start on 64-bit boundary
+ *
+ * note that total arg size can differ from alignment of
+ * elements inside arg, so we use upper nybble of length
+ * table to base alignment on
+ *
+ * also note: these alignments are ** relative to the
+ * start of the radiotap header **. There is no guarantee
+ * that the radiotap header itself is aligned on any
+ * kind of boundary.
+ *
+ * the above is why get_unaligned() is used to dereference
+ * multibyte elements from the radiotap area
+ */
+
+ pad = (((ulong)iterator->arg) -
+ ((ulong)iterator->rtheader)) &
+ ((rt_sizes[iterator->arg_index] >> 4) - 1);
+
+ if (pad)
+ iterator->arg +=
+ (rt_sizes[iterator->arg_index] >> 4) - pad;
+
+ /*
+ * this is what we will return to user, but we need to
+ * move on first so next call has something fresh to test
+ */
+ iterator->this_arg_index = iterator->arg_index;
+ iterator->this_arg = iterator->arg;
+ hit = 1;
+
+ /* internally move on the size of this arg */
+ iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
+
+ /*
+ * check for insanity where we are given a bitmap that
+ * claims to have more arg content than the length of the
+ * radiotap section. We will normally end up equalling this
+ * max_length on the last arg, never exceeding it.
+ */
+
+ if (((ulong)iterator->arg - (ulong)iterator->rtheader) >
+ (ulong) iterator->max_length)
+ return -EINVAL;
+
+ next_entry:
+ iterator->arg_index++;
+ if (unlikely((iterator->arg_index & 31) == 0)) {
+ /* completed current u32 bitmap */
+ if (iterator->bitmap_shifter & 1) {
+ /* b31 was set, there is more */
+ /* move to next u32 bitmap */
+ iterator->bitmap_shifter = le32_to_cpu(
+ get_unaligned(iterator->next_bitmap));
+ iterator->next_bitmap++;
+ } else
+ /* no more bitmaps: end */
+ iterator->arg_index = sizeof(rt_sizes);
+ } else /* just try the next bit */
+ iterator->bitmap_shifter >>= 1;
+
+ /* if we found a valid arg earlier, return it now */
+ if (hit)
+ return 0;
+ }
+
+ /* we don't know how to handle any more args, we're done */
+ return -ENOENT;
+}
diff --git a/src/drivers/radiotap.h b/src/drivers/radiotap.h
new file mode 100644
index 0000000..508264c
--- /dev/null
+++ b/src/drivers/radiotap.h
@@ -0,0 +1,242 @@
+/* $FreeBSD: src/sys/net80211/ieee80211_radiotap.h,v 1.5 2005/01/22 20:12:05 sam Exp $ */
+/* $NetBSD: ieee80211_radiotap.h,v 1.11 2005/06/22 06:16:02 dyoung Exp $ */
+
+/*-
+ * Copyright (c) 2003, 2004 David Young. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of David Young may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
+ * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+/*
+ * Modifications to fit into the linux IEEE 802.11 stack,
+ * Mike Kershaw (dragorn@kismetwireless.net)
+ */
+
+#ifndef IEEE80211RADIOTAP_H
+#define IEEE80211RADIOTAP_H
+
+#include <stdint.h>
+
+/* Base version of the radiotap packet header data */
+#define PKTHDR_RADIOTAP_VERSION 0
+
+/* A generic radio capture format is desirable. There is one for
+ * Linux, but it is neither rigidly defined (there were not even
+ * units given for some fields) nor easily extensible.
+ *
+ * I suggest the following extensible radio capture format. It is
+ * based on a bitmap indicating which fields are present.
+ *
+ * I am trying to describe precisely what the application programmer
+ * should expect in the following, and for that reason I tell the
+ * units and origin of each measurement (where it applies), or else I
+ * use sufficiently weaselly language ("is a monotonically nondecreasing
+ * function of...") that I cannot set false expectations for lawyerly
+ * readers.
+ */
+
+/* The radio capture header precedes the 802.11 header.
+ * All data in the header is little endian on all platforms.
+ */
+struct ieee80211_radiotap_header {
+ uint8_t it_version; /* Version 0. Only increases
+ * for drastic changes,
+ * introduction of compatible
+ * new fields does not count.
+ */
+ uint8_t it_pad;
+ uint16_t it_len; /* length of the whole
+ * header in bytes, including
+ * it_version, it_pad,
+ * it_len, and data fields.
+ */
+ uint32_t it_present; /* A bitmap telling which
+ * fields are present. Set bit 31
+ * (0x80000000) to extend the
+ * bitmap by another 32 bits.
+ * Additional extensions are made
+ * by setting bit 31.
+ */
+};
+
+/* Name Data type Units
+ * ---- --------- -----
+ *
+ * IEEE80211_RADIOTAP_TSFT __le64 microseconds
+ *
+ * Value in microseconds of the MAC's 64-bit 802.11 Time
+ * Synchronization Function timer when the first bit of the
+ * MPDU arrived at the MAC. For received frames, only.
+ *
+ * IEEE80211_RADIOTAP_CHANNEL 2 x uint16_t MHz, bitmap
+ *
+ * Tx/Rx frequency in MHz, followed by flags (see below).
+ *
+ * IEEE80211_RADIOTAP_FHSS uint16_t see below
+ *
+ * For frequency-hopping radios, the hop set (first byte)
+ * and pattern (second byte).
+ *
+ * IEEE80211_RADIOTAP_RATE u8 500kb/s
+ *
+ * Tx/Rx data rate
+ *
+ * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
+ * one milliwatt (dBm)
+ *
+ * RF signal power at the antenna, decibel difference from
+ * one milliwatt.
+ *
+ * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
+ * one milliwatt (dBm)
+ *
+ * RF noise power at the antenna, decibel difference from one
+ * milliwatt.
+ *
+ * IEEE80211_RADIOTAP_DB_ANTSIGNAL u8 decibel (dB)
+ *
+ * RF signal power at the antenna, decibel difference from an
+ * arbitrary, fixed reference.
+ *
+ * IEEE80211_RADIOTAP_DB_ANTNOISE u8 decibel (dB)
+ *
+ * RF noise power at the antenna, decibel difference from an
+ * arbitrary, fixed reference point.
+ *
+ * IEEE80211_RADIOTAP_LOCK_QUALITY uint16_t unitless
+ *
+ * Quality of Barker code lock. Unitless. Monotonically
+ * nondecreasing with "better" lock strength. Called "Signal
+ * Quality" in datasheets. (Is there a standard way to measure
+ * this?)
+ *
+ * IEEE80211_RADIOTAP_TX_ATTENUATION uint16_t unitless
+ *
+ * Transmit power expressed as unitless distance from max
+ * power set at factory calibration. 0 is max power.
+ * Monotonically nondecreasing with lower power levels.
+ *
+ * IEEE80211_RADIOTAP_DB_TX_ATTENUATION uint16_t decibels (dB)
+ *
+ * Transmit power expressed as decibel distance from max power
+ * set at factory calibration. 0 is max power. Monotonically
+ * nondecreasing with lower power levels.
+ *
+ * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
+ * one milliwatt (dBm)
+ *
+ * Transmit power expressed as dBm (decibels from a 1 milliwatt
+ * reference). This is the absolute power level measured at
+ * the antenna port.
+ *
+ * IEEE80211_RADIOTAP_FLAGS u8 bitmap
+ *
+ * Properties of transmitted and received frames. See flags
+ * defined below.
+ *
+ * IEEE80211_RADIOTAP_ANTENNA u8 antenna index
+ *
+ * Unitless indication of the Rx/Tx antenna for this packet.
+ * The first antenna is antenna 0.
+ *
+ * IEEE80211_RADIOTAP_RX_FLAGS uint16_t bitmap
+ *
+ * Properties of received frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_TX_FLAGS uint16_t bitmap
+ *
+ * Properties of transmitted frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_RTS_RETRIES u8 data
+ *
+ * Number of rts retries a transmitted frame used.
+ *
+ * IEEE80211_RADIOTAP_DATA_RETRIES u8 data
+ *
+ * Number of unicast retries a transmitted frame used.
+ *
+ */
+enum ieee80211_radiotap_type {
+ IEEE80211_RADIOTAP_TSFT = 0,
+ IEEE80211_RADIOTAP_FLAGS = 1,
+ IEEE80211_RADIOTAP_RATE = 2,
+ IEEE80211_RADIOTAP_CHANNEL = 3,
+ IEEE80211_RADIOTAP_FHSS = 4,
+ IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
+ IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
+ IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
+ IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
+ IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
+ IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
+ IEEE80211_RADIOTAP_ANTENNA = 11,
+ IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
+ IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
+ IEEE80211_RADIOTAP_RX_FLAGS = 14,
+ IEEE80211_RADIOTAP_TX_FLAGS = 15,
+ IEEE80211_RADIOTAP_RTS_RETRIES = 16,
+ IEEE80211_RADIOTAP_DATA_RETRIES = 17,
+ IEEE80211_RADIOTAP_EXT = 31
+};
+
+/* Channel flags. */
+#define IEEE80211_CHAN_TURBO 0x0010 /* Turbo channel */
+#define IEEE80211_CHAN_CCK 0x0020 /* CCK channel */
+#define IEEE80211_CHAN_OFDM 0x0040 /* OFDM channel */
+#define IEEE80211_CHAN_2GHZ 0x0080 /* 2 GHz spectrum channel. */
+#define IEEE80211_CHAN_5GHZ 0x0100 /* 5 GHz spectrum channel */
+#define IEEE80211_CHAN_PASSIVE 0x0200 /* Only passive scan allowed */
+#define IEEE80211_CHAN_DYN 0x0400 /* Dynamic CCK-OFDM channel */
+#define IEEE80211_CHAN_GFSK 0x0800 /* GFSK channel (FHSS PHY) */
+
+/* For IEEE80211_RADIOTAP_FLAGS */
+#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received
+ * during CFP
+ */
+#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received
+ * with short
+ * preamble
+ */
+#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received
+ * with WEP encryption
+ */
+#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received
+ * with fragmentation
+ */
+#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */
+#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between
+ * 802.11 header and payload
+ * (to 32-bit boundary)
+ */
+/* For IEEE80211_RADIOTAP_RX_FLAGS */
+#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */
+
+/* For IEEE80211_RADIOTAP_TX_FLAGS */
+#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
+ * retries */
+#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
+#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
+
+#endif /* IEEE80211_RADIOTAP_H */
diff --git a/src/drivers/radiotap_iter.h b/src/drivers/radiotap_iter.h
new file mode 100644
index 0000000..92a798a
--- /dev/null
+++ b/src/drivers/radiotap_iter.h
@@ -0,0 +1,41 @@
+#ifndef __RADIOTAP_ITER_H
+#define __RADIOTAP_ITER_H
+
+#include "radiotap.h"
+
+/* Radiotap header iteration
+ * implemented in radiotap.c
+ */
+/**
+ * struct ieee80211_radiotap_iterator - tracks walk thru present radiotap args
+ * @rtheader: pointer to the radiotap header we are walking through
+ * @max_length: length of radiotap header in cpu byte ordering
+ * @this_arg_index: IEEE80211_RADIOTAP_... index of current arg
+ * @this_arg: pointer to current radiotap arg
+ * @arg_index: internal next argument index
+ * @arg: internal next argument pointer
+ * @next_bitmap: internal pointer to next present u32
+ * @bitmap_shifter: internal shifter for curr u32 bitmap, b0 set == arg present
+ */
+
+struct ieee80211_radiotap_iterator {
+ struct ieee80211_radiotap_header *rtheader;
+ int max_length;
+ int this_arg_index;
+ unsigned char *this_arg;
+
+ int arg_index;
+ unsigned char *arg;
+ uint32_t *next_bitmap;
+ uint32_t bitmap_shifter;
+};
+
+extern int ieee80211_radiotap_iterator_init(
+ struct ieee80211_radiotap_iterator *iterator,
+ struct ieee80211_radiotap_header *radiotap_header,
+ int max_length);
+
+extern int ieee80211_radiotap_iterator_next(
+ struct ieee80211_radiotap_iterator *iterator);
+
+#endif /* __RADIOTAP_ITER_H */
diff --git a/src/eap_common/.gitignore b/src/eap_common/.gitignore
deleted file mode 100644
index a438335..0000000
--- a/src/eap_common/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.d
diff --git a/src/eap_common/eap_defs.h b/src/eap_common/eap_defs.h
index 0ac95b5..0efe7ab 100644
--- a/src/eap_common/eap_defs.h
+++ b/src/eap_common/eap_defs.h
@@ -67,7 +67,7 @@ typedef enum {
EAP_TYPE_SAKE = 48 /* RFC 4763 */,
EAP_TYPE_IKEV2 = 49 /* RFC 5106 */,
EAP_TYPE_AKA_PRIME = 50 /* draft-arkko-eap-aka-kdf-10.txt */,
- EAP_TYPE_GPSK = 51 /* draft-ietf-emu-eap-gpsk-17.txt */,
+ EAP_TYPE_GPSK = 51 /* RFC 5433 */,
EAP_TYPE_EXPANDED = 254 /* RFC 3748 */
} EapType;
diff --git a/src/eap_common/eap_fast_common.h b/src/eap_common/eap_fast_common.h
index 257123e..c85fd37 100644
--- a/src/eap_common/eap_fast_common.h
+++ b/src/eap_common/eap_fast_common.h
@@ -24,8 +24,7 @@
#define TLS_EXT_PAC_OPAQUE 35
/*
- * draft-cam-winget-eap-fast-provisioning-04.txt:
- * Section 4.2.1 - Formats for PAC TLV Attributes / Type Field
+ * RFC 5422: Section 4.2.1 - Formats for PAC TLV Attributes / Type Field
* Note: bit 0x8000 (Mandatory) and bit 0x4000 (Reserved) are also defined
* in the general PAC TLV format (Section 4.2).
*/
@@ -59,10 +58,7 @@ struct pac_tlv_hdr {
#define EAP_FAST_PAC_KEY_LEN 32
-/* draft-cam-winget-eap-fast-provisioning-04.txt: 4.2.6 PAC-Type TLV
- * Note: Machine Authentication PAC and User Authorization PAC were removed in
- * draft-cam-winget-eap-fast-provisioning-03.txt
- */
+/* RFC 5422: 4.2.6 PAC-Type TLV */
#define PAC_TYPE_TUNNEL_PAC 1
/* Application Specific Short Lived PACs (only in volatile storage) */
/* User Authorization PAC */
@@ -73,8 +69,8 @@ struct pac_tlv_hdr {
/*
- * draft-cam-winget-eap-fast-provisioning-04.txt:
- * Section 3.4 - Key Derivations Used in the EAP-FAST Provisioning Exchange
+ * RFC 5422:
+ * Section 3.3 - Key Derivations Used in the EAP-FAST Provisioning Exchange
*/
struct eap_fast_key_block_provisioning {
/* Extra key material after TLS key_block */
diff --git a/src/eap_common/eap_tlv_common.h b/src/eap_common/eap_tlv_common.h
index e3836d5..f86015d 100644
--- a/src/eap_common/eap_tlv_common.h
+++ b/src/eap_common/eap_tlv_common.h
@@ -24,8 +24,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 /* draft-cam-winget-eap-fast-provisioning-04.txt,
- * Section 4.2 */
+#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
@@ -99,7 +98,7 @@ struct eap_tlv_request_action_tlv {
be16 action;
} STRUCT_PACKED;
-/* draft-cam-winget-eap-fast-provisiong-04.txt, Section 4.2.6 - PAC-Type TLV */
+/* RFC 5422, Section 4.2.6 - PAC-Type TLV */
struct eap_tlv_pac_type_tlv {
be16 tlv_type; /* PAC_TYPE_PAC_TYPE */
be16 length;
diff --git a/src/eap_peer/.gitignore b/src/eap_peer/.gitignore
deleted file mode 100644
index a438335..0000000
--- a/src/eap_peer/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.d
diff --git a/src/eap_peer/eap_fast.c b/src/eap_peer/eap_fast.c
index 07e345f..d008670 100644
--- a/src/eap_peer/eap_fast.c
+++ b/src/eap_peer/eap_fast.c
@@ -918,10 +918,7 @@ static int eap_fast_parse_pac_info(struct eap_fast_pac *entry, int type,
entry->a_id_info_len = len;
break;
case PAC_TYPE_PAC_TYPE:
- /*
- * draft-cam-winget-eap-fast-provisioning-04.txt,
- * Section 4.2.6 - PAC-Type TLV
- */
+ /* RFC 5422, Section 4.2.6 - PAC-Type TLV */
if (len != 2) {
wpa_printf(MSG_INFO, "EAP-FAST: Invalid PAC-Type "
"length %lu (expected 2)",
@@ -961,7 +958,7 @@ static int eap_fast_process_pac_info(struct eap_fast_pac *entry)
size_t left, len;
int type;
- /* draft-cam-winget-eap-fast-provisioning-04.txt, Section 4.2.4 */
+ /* RFC 5422, Section 4.2.4 */
/* PAC-Type defaults to Tunnel PAC (Type 1) */
entry->pac_type = PAC_TYPE_TUNNEL_PAC;
diff --git a/src/eap_peer/eap_gpsk.c b/src/eap_peer/eap_gpsk.c
index 9126e1c..f6a1955 100644
--- a/src/eap_peer/eap_gpsk.c
+++ b/src/eap_peer/eap_gpsk.c
@@ -1,5 +1,5 @@
/*
- * EAP peer method: EAP-GPSK (draft-ietf-emu-eap-gpsk-08.txt)
+ * EAP peer method: EAP-GPSK (RFC 5433)
* Copyright (c) 2006-2008, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/eap_peer/eap_methods.h b/src/eap_peer/eap_methods.h
index c11bd8c..9fd9b51 100644
--- a/src/eap_peer/eap_methods.h
+++ b/src/eap_peer/eap_methods.h
@@ -62,6 +62,11 @@ 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 */
diff --git a/src/eap_peer/eap_sim.c b/src/eap_peer/eap_sim.c
index a7e49f8..5e30d1f 100644
--- a/src/eap_peer/eap_sim.c
+++ b/src/eap_peer/eap_sim.c
@@ -468,8 +468,6 @@ static struct wpabuf * eap_sim_response_notification(struct eap_sim_data *data,
wpa_printf(MSG_DEBUG, "Generating EAP-SIM Notification (id=%d)", id);
msg = eap_sim_msg_init(EAP_CODE_RESPONSE, id,
EAP_TYPE_SIM, EAP_SIM_SUBTYPE_NOTIFICATION);
- wpa_printf(MSG_DEBUG, " AT_NOTIFICATION");
- eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, notification, NULL, 0);
if (k_aut && data->reauth) {
wpa_printf(MSG_DEBUG, " AT_IV");
wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
diff --git a/src/eap_peer/eap_tls_common.c b/src/eap_peer/eap_tls_common.c
index 19afb90..186feaa 100644
--- a/src/eap_peer/eap_tls_common.c
+++ b/src/eap_peer/eap_tls_common.c
@@ -45,6 +45,18 @@ static int eap_tls_check_blob(struct eap_sm *sm, const char **name,
}
+static void eap_tls_params_flags(struct tls_connection_params *params,
+ const char *txt)
+{
+ if (txt == NULL)
+ return;
+ if (os_strstr(txt, "tls_allow_md5=1"))
+ params->flags |= TLS_CONN_ALLOW_SIGN_RSA_MD5;
+ if (os_strstr(txt, "tls_disable_time_checks=1"))
+ params->flags |= TLS_CONN_DISABLE_TIME_CHECKS;
+}
+
+
static void eap_tls_params_from_conf1(struct tls_connection_params *params,
struct eap_peer_config *config)
{
@@ -62,6 +74,7 @@ static void eap_tls_params_from_conf1(struct tls_connection_params *params,
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);
}
@@ -82,6 +95,7 @@ static void eap_tls_params_from_conf2(struct tls_connection_params *params,
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);
}
diff --git a/src/eap_peer/eap_tnc.c b/src/eap_peer/eap_tnc.c
index 0a3a01c..c560015 100644
--- a/src/eap_peer/eap_tnc.c
+++ b/src/eap_peer/eap_tnc.c
@@ -295,7 +295,7 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
wpa_printf(MSG_DEBUG, "EAP-TNC: Server did not use "
"start flag in the first message");
ret->ignore = TRUE;
- return NULL;
+ goto fail;
}
tncc_init_connection(data->tncc);
@@ -308,7 +308,7 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
wpa_printf(MSG_DEBUG, "EAP-TNC: Server used start "
"flag again");
ret->ignore = TRUE;
- return NULL;
+ goto fail;
}
res = tncc_process_if_tnccs(data->tncc,
@@ -317,7 +317,7 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
switch (res) {
case TNCCS_PROCESS_ERROR:
ret->ignore = TRUE;
- return NULL;
+ goto fail;
case TNCCS_PROCESS_OK_NO_RECOMMENDATION:
case TNCCS_RECOMMENDATION_ERROR:
wpa_printf(MSG_DEBUG, "EAP-TNC: No "
@@ -404,6 +404,11 @@ static struct wpabuf * eap_tnc_process(struct eap_sm *sm, void *priv,
data->out_buf = resp;
data->state = PROC_MSG;
return eap_tnc_build_msg(data, ret, id);
+
+fail:
+ if (data->in_buf == &tmpbuf)
+ data->in_buf = NULL;
+ return NULL;
}
diff --git a/src/eap_peer/eap_ttls.c b/src/eap_peer/eap_ttls.c
index e1a0fbd..0851f8b 100644
--- a/src/eap_peer/eap_ttls.c
+++ b/src/eap_peer/eap_ttls.c
@@ -842,7 +842,7 @@ static int eap_ttls_phase2_request_pap(struct eap_sm *sm,
/* 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 = (16 - (password_len & 15)) & 15;
+ 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);
diff --git a/src/eap_peer/eap_wsc.c b/src/eap_peer/eap_wsc.c
index 17e42f4..7c8ad2f 100644
--- a/src/eap_peer/eap_wsc.c
+++ b/src/eap_peer/eap_wsc.c
@@ -144,7 +144,7 @@ static void * eap_wsc_init(struct eap_sm *sm)
if (registrar && cfg.pin) {
wps_registrar_add_pin(data->wps_ctx->registrar, NULL,
- cfg.pin, cfg.pin_len);
+ cfg.pin, cfg.pin_len, 0);
}
return data;
diff --git a/src/eap_peer/tncc.c b/src/eap_peer/tncc.c
index 662662d..eaaa168 100644
--- a/src/eap_peer/tncc.c
+++ b/src/eap_peer/tncc.c
@@ -1106,6 +1106,7 @@ static struct tnc_if_imc * tncc_parse_imc(char *start, char *end, int *error)
if (pos >= end || *pos != ' ') {
wpa_printf(MSG_ERROR, "TNC: Ignoring invalid IMC line '%s' "
"(no space after name)", start);
+ os_free(imc->name);
os_free(imc);
return NULL;
}
diff --git a/src/eap_server/.gitignore b/src/eap_server/.gitignore
deleted file mode 100644
index a438335..0000000
--- a/src/eap_server/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.d
diff --git a/src/eap_server/eap.c b/src/eap_server/eap.c
index dea91e6..897adc3 100644
--- a/src/eap_server/eap.c
+++ b/src/eap_server/eap.c
@@ -573,6 +573,13 @@ SM_STATE(EAP, SUCCESS2)
}
sm->eap_if.eapSuccess = TRUE;
+
+ /*
+ * Start reauthentication with identity request even though we know the
+ * previously used identity. This is needed to get reauthentication
+ * started properly.
+ */
+ sm->start_reauth = TRUE;
}
@@ -1070,7 +1077,7 @@ static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
static int eap_sm_Policy_getDecision(struct eap_sm *sm)
{
- if (!sm->eap_server && sm->identity) {
+ if (!sm->eap_server && sm->identity && !sm->start_reauth) {
wpa_printf(MSG_DEBUG, "EAP: getDecision: -> PASSTHROUGH");
return DECISION_PASSTHROUGH;
}
@@ -1091,7 +1098,8 @@ static int eap_sm_Policy_getDecision(struct eap_sm *sm)
return DECISION_FAILURE;
}
- if ((sm->user == NULL || sm->update_user) && sm->identity) {
+ if ((sm->user == NULL || sm->update_user) && sm->identity &&
+ !sm->start_reauth) {
/*
* Allow Identity method to be started once to allow identity
* selection hint to be sent from the authentication server,
@@ -1118,6 +1126,7 @@ static int eap_sm_Policy_getDecision(struct eap_sm *sm)
}
sm->update_user = FALSE;
}
+ sm->start_reauth = FALSE;
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
(sm->user->methods[sm->user_eap_method_index].vendor !=
@@ -1252,7 +1261,7 @@ void eap_server_sm_deinit(struct eap_sm *sm)
sm->m->reset(sm, sm->eap_method_priv);
wpabuf_free(sm->eap_if.eapReqData);
os_free(sm->eap_if.eapKeyData);
- os_free(sm->lastReqData);
+ wpabuf_free(sm->lastReqData);
wpabuf_free(sm->eap_if.eapRespData);
os_free(sm->identity);
os_free(sm->pac_opaque_encr_key);
diff --git a/src/eap_server/eap_fast.c b/src/eap_server/eap_fast.c
index b474c99..c06f396 100644
--- a/src/eap_server/eap_fast.c
+++ b/src/eap_server/eap_fast.c
@@ -73,6 +73,10 @@ struct eap_fast_data {
};
+static int eap_fast_process_phase2_start(struct eap_sm *sm,
+ struct eap_fast_data *data);
+
+
static const char * eap_fast_state_txt(int state)
{
switch (state) {
@@ -804,11 +808,48 @@ static struct wpabuf * eap_fast_build_pac(struct eap_sm *sm,
}
+static int eap_fast_encrypt_phase2(struct eap_sm *sm,
+ struct eap_fast_data *data,
+ struct wpabuf *plain, int piggyback)
+{
+ struct wpabuf *encr;
+
+ wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 TLVs",
+ plain);
+ encr = eap_server_tls_encrypt(sm, &data->ssl, wpabuf_mhead(plain),
+ wpabuf_len(plain));
+ wpabuf_free(plain);
+
+ if (data->ssl.out_buf && piggyback) {
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Piggyback Phase 2 data "
+ "(len=%d) with last Phase 1 Message (len=%d "
+ "used=%d)",
+ (int) wpabuf_len(encr),
+ (int) wpabuf_len(data->ssl.out_buf),
+ (int) data->ssl.out_used);
+ if (wpabuf_resize(&data->ssl.out_buf, wpabuf_len(encr)) < 0) {
+ wpa_printf(MSG_WARNING, "EAP-FAST: Failed to resize "
+ "output buffer");
+ wpabuf_free(encr);
+ return -1;
+ }
+ wpabuf_put_buf(data->ssl.out_buf, encr);
+ wpabuf_free(encr);
+ } else {
+ wpabuf_free(data->ssl.out_buf);
+ data->ssl.out_used = 0;
+ data->ssl.out_buf = encr;
+ }
+
+ return 0;
+}
+
+
static struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id)
{
struct eap_fast_data *data = priv;
struct wpabuf *req = NULL;
- struct wpabuf *encr;
+ int piggyback = 0;
if (data->ssl.state == FRAG_ACK) {
return eap_server_tls_build_ack(id, EAP_TYPE_FAST,
@@ -827,6 +868,19 @@ static struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id)
if (tls_connection_established(sm->ssl_ctx, data->ssl.conn)) {
if (eap_fast_phase1_done(sm, data) < 0)
return NULL;
+ if (data->state == PHASE2_START) {
+ /*
+ * Try to generate Phase 2 data to piggyback
+ * with the end of Phase 1 to avoid extra
+ * roundtrip.
+ */
+ wpa_printf(MSG_DEBUG, "EAP-FAST: Try to start "
+ "Phase 2");
+ if (eap_fast_process_phase2_start(sm, data))
+ break;
+ req = eap_fast_build_phase2_req(sm, data, id);
+ piggyback = 1;
+ }
}
break;
case PHASE2_ID:
@@ -856,18 +910,9 @@ static struct wpabuf * eap_fast_buildReq(struct eap_sm *sm, void *priv, u8 id)
return NULL;
}
- if (req) {
- wpa_hexdump_buf_key(MSG_DEBUG, "EAP-FAST: Encrypting Phase 2 "
- "TLVs", req);
- encr = eap_server_tls_encrypt(sm, &data->ssl,
- wpabuf_mhead(req),
- wpabuf_len(req));
- wpabuf_free(req);
-
- wpabuf_free(data->ssl.out_buf);
- data->ssl.out_used = 0;
- data->ssl.out_buf = encr;
- }
+ if (req &&
+ eap_fast_encrypt_phase2(sm, data, req, piggyback) < 0)
+ return NULL;
return eap_server_tls_build_msg(&data->ssl, EAP_TYPE_FAST,
data->fast_version, id);
@@ -1443,8 +1488,8 @@ static int eap_fast_process_phase1(struct eap_sm *sm,
}
-static void eap_fast_process_phase2_start(struct eap_sm *sm,
- struct eap_fast_data *data)
+static int eap_fast_process_phase2_start(struct eap_sm *sm,
+ struct eap_fast_data *data)
{
u8 next_type;
@@ -1474,7 +1519,7 @@ static void eap_fast_process_phase2_start(struct eap_sm *sm,
next_type = EAP_TYPE_IDENTITY;
}
- eap_fast_phase2_init(sm, data, next_type);
+ return eap_fast_phase2_init(sm, data, next_type);
}
diff --git a/src/eap_server/eap_gpsk.c b/src/eap_server/eap_gpsk.c
index c87d452..d0c7559 100644
--- a/src/eap_server/eap_gpsk.c
+++ b/src/eap_server/eap_gpsk.c
@@ -1,5 +1,5 @@
/*
- * hostapd / EAP-GPSK (draft-ietf-emu-eap-gpsk-08.txt) server
+ * hostapd / EAP-GPSK (RFC 5433) server
* Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
diff --git a/src/eap_server/eap_i.h b/src/eap_server/eap_i.h
index 61f564d..d52b86f 100644
--- a/src/eap_server/eap_i.h
+++ b/src/eap_server/eap_i.h
@@ -183,6 +183,8 @@ struct eap_sm {
int tnc;
struct wps_context *wps;
struct wpabuf *assoc_wps_ie;
+
+ Boolean start_reauth;
};
int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
diff --git a/src/eap_server/eap_tls_common.c b/src/eap_server/eap_tls_common.c
index befc1bf..bda1184 100644
--- a/src/eap_server/eap_tls_common.c
+++ b/src/eap_server/eap_tls_common.c
@@ -344,7 +344,7 @@ struct wpabuf * eap_server_tls_encrypt(struct eap_sm *sm,
size_t buf_len;
/* reserve some extra room for encryption overhead */
- buf_len = plain_len + 200;
+ buf_len = plain_len + 300;
buf = wpabuf_alloc(buf_len);
if (buf == NULL)
return NULL;
diff --git a/src/eap_server/eap_tnc.c b/src/eap_server/eap_tnc.c
index 834685b..4cb3ecf 100644
--- a/src/eap_server/eap_tnc.c
+++ b/src/eap_server/eap_tnc.c
@@ -500,7 +500,7 @@ static void eap_tnc_process(struct eap_sm *sm, void *priv,
static Boolean eap_tnc_isDone(struct eap_sm *sm, void *priv)
{
struct eap_tnc_data *data = priv;
- return data->state == DONE;
+ return data->state == DONE || data->state == FAIL;
}
diff --git a/src/eap_server/eap_ttls.c b/src/eap_server/eap_ttls.c
index b097ab2..21e4b21 100644
--- a/src/eap_server/eap_ttls.c
+++ b/src/eap_server/eap_ttls.c
@@ -954,7 +954,7 @@ static int eap_ttls_phase2_eap_init(struct eap_sm *sm,
sm->init_phase2 = 1;
data->phase2_priv = data->phase2_method->init(sm);
sm->init_phase2 = 0;
- return 0;
+ return data->phase2_priv == NULL ? -1 : 0;
}
@@ -1045,6 +1045,11 @@ static void eap_ttls_process_phase2_eap_response(struct eap_sm *sm,
next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
wpa_printf(MSG_DEBUG, "EAP-TTLS: try EAP type %d", next_type);
+ if (eap_ttls_phase2_eap_init(sm, data, next_type)) {
+ wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize "
+ "EAP type %d", next_type);
+ eap_ttls_state(data, FAILURE);
+ }
break;
case PHASE2_METHOD:
if (data->ttls_version > 0) {
@@ -1066,12 +1071,6 @@ static void eap_ttls_process_phase2_eap_response(struct eap_sm *sm,
__func__, data->state);
break;
}
-
- if (eap_ttls_phase2_eap_init(sm, data, next_type)) {
- wpa_printf(MSG_DEBUG, "EAP-TTLS: Failed to initialize EAP "
- "type %d", next_type);
- eap_ttls_state(data, FAILURE);
- }
}
diff --git a/src/eapol_supp/.gitignore b/src/eapol_supp/.gitignore
deleted file mode 100644
index a438335..0000000
--- a/src/eapol_supp/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.d
diff --git a/src/eapol_supp/eapol_supp_sm.c b/src/eapol_supp/eapol_supp_sm.c
index c832b5a..d163049 100644
--- a/src/eapol_supp/eapol_supp_sm.c
+++ b/src/eapol_supp/eapol_supp_sm.c
@@ -282,7 +282,12 @@ SM_STATE(SUPP_PAE, CONNECTING)
* 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;
@@ -737,8 +742,8 @@ static void eapol_sm_processKey(struct eapol_sm *sm)
os_memcpy(ekey + IEEE8021X_KEY_IV_LEN, keydata.encr_key,
encr_key_len);
os_memcpy(datakey, key + 1, key_len);
- rc4(datakey, key_len, ekey,
- IEEE8021X_KEY_IV_LEN + encr_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) {
diff --git a/src/hlr_auc_gw/.gitignore b/src/hlr_auc_gw/.gitignore
deleted file mode 100644
index a438335..0000000
--- a/src/hlr_auc_gw/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.d
diff --git a/src/hlr_auc_gw/hlr_auc_gw.c b/src/hlr_auc_gw/hlr_auc_gw.c
index 3d914e6..e318903 100644
--- a/src/hlr_auc_gw/hlr_auc_gw.c
+++ b/src/hlr_auc_gw/hlr_auc_gw.c
@@ -532,7 +532,7 @@ static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
char *imsi)
{
- char *auts, *rand;
+ char *auts, *__rand;
u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6];
struct milenage_parameters *m;
@@ -543,14 +543,14 @@ static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
return;
*auts++ = '\0';
- rand = strchr(auts, ' ');
- if (rand == NULL)
+ __rand = strchr(auts, ' ');
+ if (__rand == NULL)
return;
- *rand++ = '\0';
+ *__rand++ = '\0';
- printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, rand);
+ printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand);
if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
- hexstr2bin(rand, _rand, EAP_AKA_RAND_LEN)) {
+ hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) {
printf("Could not parse AUTS/RAND\n");
return;
}
diff --git a/src/l2_packet/Makefile b/src/l2_packet/Makefile
new file mode 100644
index 0000000..cffba62
--- /dev/null
+++ b/src/l2_packet/Makefile
@@ -0,0 +1,9 @@
+all:
+ @echo Nothing to be made.
+
+clean:
+ for d in $(SUBDIRS); do make -C $$d clean; done
+ rm -f *~ *.o *.d
+
+install:
+ @echo Nothing to be made.
diff --git a/src/l2_packet/l2_packet_freebsd.c b/src/l2_packet/l2_packet_freebsd.c
new file mode 100644
index 0000000..d1034aa
--- /dev/null
+++ b/src/l2_packet/l2_packet_freebsd.c
@@ -0,0 +1,285 @@
+/*
+ * WPA Supplicant - Layer2 packet handling with FreeBSD
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2005, Sam Leffler <sam@errno.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#ifdef __APPLE__
+#include <net/bpf.h>
+#endif /* __APPLE__ */
+#include <pcap.h>
+
+#include <sys/ioctl.h>
+#include <sys/sysctl.h>
+
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <net/route.h>
+#include <netinet/in.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+struct l2_packet_data {
+ pcap_t *pcap;
+ char ifname[100];
+ u8 own_addr[ETH_ALEN];
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len);
+ void *rx_callback_ctx;
+ int l2_hdr; /* whether to include layer 2 (Ethernet) header data
+ * buffers */
+};
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+ os_memcpy(addr, l2->own_addr, ETH_ALEN);
+ return 0;
+}
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+ const u8 *buf, size_t len)
+{
+ if (!l2->l2_hdr) {
+ int ret;
+ struct l2_ethhdr *eth = os_malloc(sizeof(*eth) + len);
+ if (eth == NULL)
+ return -1;
+ os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
+ os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
+ eth->h_proto = htons(proto);
+ os_memcpy(eth + 1, buf, len);
+ ret = pcap_inject(l2->pcap, (u8 *) eth, len + sizeof(*eth));
+ os_free(eth);
+ return ret;
+ } else
+ return pcap_inject(l2->pcap, buf, len);
+}
+
+
+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct l2_packet_data *l2 = eloop_ctx;
+ pcap_t *pcap = sock_ctx;
+ struct pcap_pkthdr hdr;
+ const u_char *packet;
+ struct l2_ethhdr *ethhdr;
+ unsigned char *buf;
+ size_t len;
+
+ packet = pcap_next(pcap, &hdr);
+
+ if (packet == NULL || hdr.caplen < sizeof(*ethhdr))
+ return;
+
+ ethhdr = (struct l2_ethhdr *) packet;
+ if (l2->l2_hdr) {
+ buf = (unsigned char *) ethhdr;
+ len = hdr.caplen;
+ } else {
+ buf = (unsigned char *) (ethhdr + 1);
+ len = hdr.caplen - sizeof(*ethhdr);
+ }
+ l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len);
+}
+
+
+static int l2_packet_init_libpcap(struct l2_packet_data *l2,
+ unsigned short protocol)
+{
+ bpf_u_int32 pcap_maskp, pcap_netp;
+ char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
+ struct bpf_program pcap_fp;
+
+ pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err);
+ l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 10, pcap_err);
+ if (l2->pcap == NULL) {
+ fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
+ fprintf(stderr, "ifname='%s'\n", l2->ifname);
+ return -1;
+ }
+ if (pcap_datalink(l2->pcap) != DLT_EN10MB &&
+ pcap_set_datalink(l2->pcap, DLT_EN10MB) < 0) {
+ fprintf(stderr, "pcap_set_datalink(DLT_EN10MB): %s\n",
+ pcap_geterr(l2->pcap));
+ return -1;
+ }
+ os_snprintf(pcap_filter, sizeof(pcap_filter),
+ "not ether src " MACSTR " and "
+ "( ether dst " MACSTR " or ether dst " MACSTR " ) and "
+ "ether proto 0x%x",
+ MAC2STR(l2->own_addr), /* do not receive own packets */
+ MAC2STR(l2->own_addr), MAC2STR(pae_group_addr),
+ protocol);
+ if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) {
+ fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap));
+ return -1;
+ }
+
+ if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) {
+ fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap));
+ return -1;
+ }
+
+ pcap_freecode(&pcap_fp);
+ /*
+ * When libpcap uses BPF we must enable "immediate mode" to
+ * receive frames right away; otherwise the system may
+ * buffer them for us.
+ */
+ {
+ unsigned int on = 1;
+ if (ioctl(pcap_fileno(l2->pcap), BIOCIMMEDIATE, &on) < 0) {
+ fprintf(stderr, "%s: cannot enable immediate mode on "
+ "interface %s: %s\n",
+ __func__, l2->ifname, strerror(errno));
+ /* XXX should we fail? */
+ }
+ }
+
+ eloop_register_read_sock(pcap_get_selectable_fd(l2->pcap),
+ l2_packet_receive, l2, l2->pcap);
+
+ return 0;
+}
+
+
+static int eth_get(const char *device, u8 ea[ETH_ALEN])
+{
+ struct if_msghdr *ifm;
+ struct sockaddr_dl *sdl;
+ u_char *p, *buf;
+ size_t len;
+ int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
+
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+ return -1;
+ if ((buf = os_malloc(len)) == NULL)
+ return -1;
+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+ os_free(buf);
+ return -1;
+ }
+ for (p = buf; p < buf + len; p += ifm->ifm_msglen) {
+ ifm = (struct if_msghdr *)p;
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+ if (ifm->ifm_type != RTM_IFINFO ||
+ (ifm->ifm_addrs & RTA_IFP) == 0)
+ continue;
+ if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
+ os_memcmp(sdl->sdl_data, device, sdl->sdl_nlen) != 0)
+ continue;
+ os_memcpy(ea, LLADDR(sdl), sdl->sdl_alen);
+ break;
+ }
+ os_free(buf);
+
+ if (p >= buf + len) {
+ errno = ESRCH;
+ return -1;
+ }
+ return 0;
+}
+
+
+struct l2_packet_data * l2_packet_init(
+ const char *ifname, const u8 *own_addr, unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ struct l2_packet_data *l2;
+
+ l2 = os_zalloc(sizeof(struct l2_packet_data));
+ if (l2 == NULL)
+ return NULL;
+ os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
+ l2->rx_callback = rx_callback;
+ l2->rx_callback_ctx = rx_callback_ctx;
+ l2->l2_hdr = l2_hdr;
+
+ if (eth_get(l2->ifname, l2->own_addr) < 0) {
+ fprintf(stderr, "Failed to get link-level address for "
+ "interface '%s'.\n", l2->ifname);
+ os_free(l2);
+ return NULL;
+ }
+
+ if (l2_packet_init_libpcap(l2, protocol)) {
+ os_free(l2);
+ return NULL;
+ }
+
+ return l2;
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+ if (l2 != NULL) {
+ if (l2->pcap) {
+ eloop_unregister_read_sock(
+ pcap_get_selectable_fd(l2->pcap));
+ pcap_close(l2->pcap);
+ }
+ os_free(l2);
+ }
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+ pcap_if_t *devs, *dev;
+ struct pcap_addr *addr;
+ struct sockaddr_in *saddr;
+ int found = 0;
+ char err[PCAP_ERRBUF_SIZE + 1];
+
+ if (pcap_findalldevs(&devs, err) < 0) {
+ wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err);
+ return -1;
+ }
+
+ for (dev = devs; dev && !found; dev = dev->next) {
+ if (os_strcmp(dev->name, l2->ifname) != 0)
+ continue;
+
+ addr = dev->addresses;
+ while (addr) {
+ saddr = (struct sockaddr_in *) addr->addr;
+ if (saddr && saddr->sin_family == AF_INET) {
+ os_strlcpy(buf, inet_ntoa(saddr->sin_addr),
+ len);
+ found = 1;
+ break;
+ }
+ addr = addr->next;
+ }
+ }
+
+ pcap_freealldevs(devs);
+
+ return found ? 0 : -1;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+}
diff --git a/src/l2_packet/l2_packet_linux.c b/src/l2_packet/l2_packet_linux.c
new file mode 100644
index 0000000..48d1bde
--- /dev/null
+++ b/src/l2_packet/l2_packet_linux.c
@@ -0,0 +1,200 @@
+/*
+ * WPA Supplicant - Layer2 packet handling with Linux packet sockets
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/ioctl.h>
+#include <netpacket/packet.h>
+#include <net/if.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+
+
+struct l2_packet_data {
+ int fd; /* packet socket for EAPOL frames */
+ char ifname[IFNAMSIZ + 1];
+ int ifindex;
+ u8 own_addr[ETH_ALEN];
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len);
+ void *rx_callback_ctx;
+ int l2_hdr; /* whether to include layer 2 (Ethernet) header data
+ * buffers */
+};
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+ os_memcpy(addr, l2->own_addr, ETH_ALEN);
+ return 0;
+}
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+ const u8 *buf, size_t len)
+{
+ int ret;
+ if (l2 == NULL)
+ return -1;
+ if (l2->l2_hdr) {
+ ret = send(l2->fd, buf, len, 0);
+ if (ret < 0)
+ perror("l2_packet_send - send");
+ } else {
+ struct sockaddr_ll ll;
+ os_memset(&ll, 0, sizeof(ll));
+ ll.sll_family = AF_PACKET;
+ ll.sll_ifindex = l2->ifindex;
+ ll.sll_protocol = htons(proto);
+ ll.sll_halen = ETH_ALEN;
+ os_memcpy(ll.sll_addr, dst_addr, ETH_ALEN);
+ ret = sendto(l2->fd, buf, len, 0, (struct sockaddr *) &ll,
+ sizeof(ll));
+ if (ret < 0)
+ perror("l2_packet_send - sendto");
+ }
+ return ret;
+}
+
+
+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct l2_packet_data *l2 = eloop_ctx;
+ u8 buf[2300];
+ int res;
+ struct sockaddr_ll ll;
+ socklen_t fromlen;
+
+ os_memset(&ll, 0, sizeof(ll));
+ fromlen = sizeof(ll);
+ res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &ll,
+ &fromlen);
+ if (res < 0) {
+ perror("l2_packet_receive - recvfrom");
+ return;
+ }
+
+ l2->rx_callback(l2->rx_callback_ctx, ll.sll_addr, buf, res);
+}
+
+
+struct l2_packet_data * l2_packet_init(
+ const char *ifname, const u8 *own_addr, unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ struct l2_packet_data *l2;
+ struct ifreq ifr;
+ struct sockaddr_ll ll;
+
+ l2 = os_zalloc(sizeof(struct l2_packet_data));
+ if (l2 == NULL)
+ return NULL;
+ os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
+ l2->rx_callback = rx_callback;
+ l2->rx_callback_ctx = rx_callback_ctx;
+ l2->l2_hdr = l2_hdr;
+
+ l2->fd = socket(PF_PACKET, l2_hdr ? SOCK_RAW : SOCK_DGRAM,
+ htons(protocol));
+ if (l2->fd < 0) {
+ perror("socket(PF_PACKET)");
+ os_free(l2);
+ return NULL;
+ }
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
+ if (ioctl(l2->fd, SIOCGIFINDEX, &ifr) < 0) {
+ perror("ioctl[SIOCGIFINDEX]");
+ close(l2->fd);
+ os_free(l2);
+ return NULL;
+ }
+ l2->ifindex = ifr.ifr_ifindex;
+
+ os_memset(&ll, 0, sizeof(ll));
+ ll.sll_family = PF_PACKET;
+ ll.sll_ifindex = ifr.ifr_ifindex;
+ ll.sll_protocol = htons(protocol);
+ if (bind(l2->fd, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+ perror("bind[PF_PACKET]");
+ close(l2->fd);
+ os_free(l2);
+ return NULL;
+ }
+
+ if (ioctl(l2->fd, SIOCGIFHWADDR, &ifr) < 0) {
+ perror("ioctl[SIOCGIFHWADDR]");
+ close(l2->fd);
+ os_free(l2);
+ return NULL;
+ }
+ os_memcpy(l2->own_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+ eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
+
+ return l2;
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+ if (l2 == NULL)
+ return;
+
+ if (l2->fd >= 0) {
+ eloop_unregister_read_sock(l2->fd);
+ close(l2->fd);
+ }
+
+ os_free(l2);
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+ int s;
+ struct ifreq ifr;
+ struct sockaddr_in *saddr;
+ size_t res;
+
+ s = socket(PF_INET, SOCK_DGRAM, 0);
+ if (s < 0) {
+ perror("socket");
+ return -1;
+ }
+ os_memset(&ifr, 0, sizeof(ifr));
+ os_strlcpy(ifr.ifr_name, l2->ifname, sizeof(ifr.ifr_name));
+ if (ioctl(s, SIOCGIFADDR, &ifr) < 0) {
+ if (errno != EADDRNOTAVAIL)
+ perror("ioctl[SIOCGIFADDR]");
+ close(s);
+ return -1;
+ }
+ close(s);
+ saddr = aliasing_hide_typecast(&ifr.ifr_addr, struct sockaddr_in);
+ if (saddr->sin_family != AF_INET)
+ return -1;
+ res = os_strlcpy(buf, inet_ntoa(saddr->sin_addr), len);
+ if (res >= len)
+ return -1;
+ return 0;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+}
diff --git a/src/l2_packet/l2_packet_ndis.c b/src/l2_packet/l2_packet_ndis.c
new file mode 100644
index 0000000..7de5880
--- /dev/null
+++ b/src/l2_packet/l2_packet_ndis.c
@@ -0,0 +1,516 @@
+/*
+ * WPA Supplicant - Layer2 packet handling with Microsoft NDISUIO
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This implementation requires Windows specific event loop implementation,
+ * i.e., eloop_win.c. In addition, the NDISUIO connection is shared with
+ * driver_ndis.c, so only that driver interface can be used and
+ * CONFIG_USE_NDISUIO must be defined.
+ *
+ * WinXP version of the code uses overlapped I/O and a single threaded design
+ * with callback functions from I/O code. WinCE version uses a separate RX
+ * thread that blocks on ReadFile() whenever the media status is connected.
+ */
+
+#include "includes.h"
+#include <winsock2.h>
+#include <ntddndis.h>
+
+#ifdef _WIN32_WCE
+#include <winioctl.h>
+#include <nuiouser.h>
+#endif /* _WIN32_WCE */
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+
+#ifndef _WIN32_WCE
+/* from nuiouser.h */
+#define FSCTL_NDISUIO_BASE FILE_DEVICE_NETWORK
+#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \
+ CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access)
+#define IOCTL_NDISUIO_SET_ETHER_TYPE \
+ _NDISUIO_CTL_CODE(0x202, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+#endif /* _WIN32_WCE */
+
+/* From driver_ndis.c to shared the handle to NDISUIO */
+HANDLE driver_ndis_get_ndisuio_handle(void);
+
+/*
+ * NDISUIO supports filtering of only one ethertype at the time, so we must
+ * fake support for two (EAPOL and RSN pre-auth) by switching to pre-auth
+ * whenever wpa_supplicant is trying to pre-authenticate and then switching
+ * back to EAPOL when pre-authentication has been completed.
+ */
+
+struct l2_packet_data;
+
+struct l2_packet_ndisuio_global {
+ int refcount;
+ unsigned short first_proto;
+ struct l2_packet_data *l2[2];
+#ifdef _WIN32_WCE
+ HANDLE rx_thread;
+ HANDLE stop_request;
+ HANDLE ready_for_read;
+ HANDLE rx_processed;
+#endif /* _WIN32_WCE */
+};
+
+static struct l2_packet_ndisuio_global *l2_ndisuio_global = NULL;
+
+struct l2_packet_data {
+ char ifname[100];
+ u8 own_addr[ETH_ALEN];
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len);
+ void *rx_callback_ctx;
+ int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to
+ * rx_callback and l2_packet_send() */
+ HANDLE rx_avail;
+#ifndef _WIN32_WCE
+ OVERLAPPED rx_overlapped;
+#endif /* _WIN32_WCE */
+ u8 rx_buf[1514];
+ DWORD rx_written;
+};
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+ os_memcpy(addr, l2->own_addr, ETH_ALEN);
+ return 0;
+}
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+ const u8 *buf, size_t len)
+{
+ BOOL res;
+ DWORD written;
+ struct l2_ethhdr *eth;
+#ifndef _WIN32_WCE
+ OVERLAPPED overlapped;
+#endif /* _WIN32_WCE */
+ OVERLAPPED *o;
+
+ if (l2 == NULL)
+ return -1;
+
+#ifdef _WIN32_WCE
+ o = NULL;
+#else /* _WIN32_WCE */
+ os_memset(&overlapped, 0, sizeof(overlapped));
+ o = &overlapped;
+#endif /* _WIN32_WCE */
+
+ if (l2->l2_hdr) {
+ res = WriteFile(driver_ndis_get_ndisuio_handle(), buf, len,
+ &written, o);
+ } else {
+ size_t mlen = sizeof(*eth) + len;
+ eth = os_malloc(mlen);
+ if (eth == NULL)
+ return -1;
+
+ os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
+ os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
+ eth->h_proto = htons(proto);
+ os_memcpy(eth + 1, buf, len);
+ res = WriteFile(driver_ndis_get_ndisuio_handle(), eth, mlen,
+ &written, o);
+ os_free(eth);
+ }
+
+ if (!res) {
+ DWORD err = GetLastError();
+#ifndef _WIN32_WCE
+ if (err == ERROR_IO_PENDING) {
+ /* For now, just assume that the packet will be sent in
+ * time before the next write happens. This could be
+ * cleaned up at some point to actually wait for
+ * completion before starting new writes.
+ */
+ return 0;
+ }
+#endif /* _WIN32_WCE */
+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): WriteFile failed: %d",
+ (int) GetLastError());
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void l2_packet_callback(struct l2_packet_data *l2);
+
+#ifdef _WIN32_WCE
+static void l2_packet_rx_thread_try_read(struct l2_packet_data *l2)
+{
+ HANDLE handles[2];
+
+ wpa_printf(MSG_MSGDUMP, "l2_packet_rx_thread: -> ReadFile");
+ if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf,
+ sizeof(l2->rx_buf), &l2->rx_written, NULL)) {
+ DWORD err = GetLastError();
+ wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: ReadFile failed: "
+ "%d", (int) err);
+ /*
+ * ReadFile on NDISUIO/WinCE returns ERROR_DEVICE_NOT_CONNECTED
+ * error whenever the connection is not up. Yield the thread to
+ * avoid triggering a busy loop. Connection event should stop
+ * us from looping for long, but we need to allow enough CPU
+ * for the main thread to process the media disconnection.
+ */
+ Sleep(100);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Read %d byte packet",
+ (int) l2->rx_written);
+
+ /*
+ * Notify the main thread about the availability of a frame and wait
+ * for the frame to be processed.
+ */
+ SetEvent(l2->rx_avail);
+ handles[0] = l2_ndisuio_global->stop_request;
+ handles[1] = l2_ndisuio_global->rx_processed;
+ WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+ ResetEvent(l2_ndisuio_global->rx_processed);
+}
+
+
+static DWORD WINAPI l2_packet_rx_thread(LPVOID arg)
+{
+ struct l2_packet_data *l2 = arg;
+ DWORD res;
+ HANDLE handles[2];
+ int run = 1;
+
+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread started");
+ handles[0] = l2_ndisuio_global->stop_request;
+ handles[1] = l2_ndisuio_global->ready_for_read;
+
+ /*
+ * Unfortunately, NDISUIO on WinCE does not seem to support waiting
+ * on the handle. There do not seem to be anything else that we could
+ * wait for either. If one were to modify NDISUIO to set a named event
+ * whenever packets are available, this event could be used here to
+ * avoid having to poll for new packets or we could even move to use a
+ * single threaded design.
+ *
+ * In addition, NDISUIO on WinCE is returning
+ * ERROR_DEVICE_NOT_CONNECTED whenever ReadFile() is attempted while
+ * the adapter is not in connected state. For now, we are just using a
+ * local event to allow ReadFile calls only after having received NDIS
+ * media connect event. This event could be easily converted to handle
+ * another event if the protocol driver is replaced with somewhat more
+ * useful design.
+ */
+
+ while (l2_ndisuio_global && run) {
+ res = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
+ switch (res) {
+ case WAIT_OBJECT_0:
+ wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: Received "
+ "request to stop RX thread");
+ run = 0;
+ break;
+ case WAIT_OBJECT_0 + 1:
+ l2_packet_rx_thread_try_read(l2);
+ break;
+ case WAIT_FAILED:
+ default:
+ wpa_printf(MSG_DEBUG, "l2_packet_rx_thread: "
+ "WaitForMultipleObjects failed: %d",
+ (int) GetLastError());
+ run = 0;
+ break;
+ }
+ }
+
+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread stopped");
+
+ return 0;
+}
+#else /* _WIN32_WCE */
+static int l2_ndisuio_start_read(struct l2_packet_data *l2, int recursive)
+{
+ os_memset(&l2->rx_overlapped, 0, sizeof(l2->rx_overlapped));
+ l2->rx_overlapped.hEvent = l2->rx_avail;
+ if (!ReadFile(driver_ndis_get_ndisuio_handle(), l2->rx_buf,
+ sizeof(l2->rx_buf), &l2->rx_written, &l2->rx_overlapped))
+ {
+ DWORD err = GetLastError();
+ if (err != ERROR_IO_PENDING) {
+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile failed: "
+ "%d", (int) err);
+ return -1;
+ }
+ /*
+ * Once read is completed, l2_packet_rx_event() will be
+ * called.
+ */
+ } else {
+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): ReadFile returned data "
+ "without wait for completion");
+ if (!recursive)
+ l2_packet_callback(l2);
+ }
+
+ return 0;
+}
+#endif /* _WIN32_WCE */
+
+
+static void l2_packet_callback(struct l2_packet_data *l2)
+{
+ const u8 *rx_buf, *rx_src;
+ size_t rx_len;
+ struct l2_ethhdr *ethhdr = (struct l2_ethhdr *) l2->rx_buf;
+
+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): Read %d bytes",
+ (int) l2->rx_written);
+
+ if (l2->l2_hdr || l2->rx_written < sizeof(*ethhdr)) {
+ rx_buf = (u8 *) ethhdr;
+ rx_len = l2->rx_written;
+ } else {
+ rx_buf = (u8 *) (ethhdr + 1);
+ rx_len = l2->rx_written - sizeof(*ethhdr);
+ }
+ rx_src = ethhdr->h_source;
+
+ l2->rx_callback(l2->rx_callback_ctx, rx_src, rx_buf, rx_len);
+#ifndef _WIN32_WCE
+ l2_ndisuio_start_read(l2, 1);
+#endif /* _WIN32_WCE */
+}
+
+
+static void l2_packet_rx_event(void *eloop_data, void *user_data)
+{
+ struct l2_packet_data *l2 = eloop_data;
+
+ if (l2_ndisuio_global)
+ l2 = l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1];
+
+ ResetEvent(l2->rx_avail);
+
+#ifndef _WIN32_WCE
+ if (!GetOverlappedResult(driver_ndis_get_ndisuio_handle(),
+ &l2->rx_overlapped, &l2->rx_written, FALSE)) {
+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): GetOverlappedResult "
+ "failed: %d", (int) GetLastError());
+ return;
+ }
+#endif /* _WIN32_WCE */
+
+ l2_packet_callback(l2);
+
+#ifdef _WIN32_WCE
+ SetEvent(l2_ndisuio_global->rx_processed);
+#endif /* _WIN32_WCE */
+}
+
+
+static int l2_ndisuio_set_ether_type(unsigned short protocol)
+{
+ USHORT proto = htons(protocol);
+ DWORD written;
+
+ if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(),
+ IOCTL_NDISUIO_SET_ETHER_TYPE, &proto,
+ sizeof(proto), NULL, 0, &written, NULL)) {
+ wpa_printf(MSG_ERROR, "L2(NDISUIO): "
+ "IOCTL_NDISUIO_SET_ETHER_TYPE failed: %d",
+ (int) GetLastError());
+ return -1;
+ }
+
+ return 0;
+}
+
+
+struct l2_packet_data * l2_packet_init(
+ const char *ifname, const u8 *own_addr, unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ struct l2_packet_data *l2;
+
+ if (l2_ndisuio_global == NULL) {
+ l2_ndisuio_global = os_zalloc(sizeof(*l2_ndisuio_global));
+ if (l2_ndisuio_global == NULL)
+ return NULL;
+ l2_ndisuio_global->first_proto = protocol;
+ }
+ if (l2_ndisuio_global->refcount >= 2) {
+ wpa_printf(MSG_ERROR, "L2(NDISUIO): Not more than two "
+ "simultaneous connections allowed");
+ return NULL;
+ }
+ l2_ndisuio_global->refcount++;
+
+ l2 = os_zalloc(sizeof(struct l2_packet_data));
+ if (l2 == NULL)
+ return NULL;
+ l2_ndisuio_global->l2[l2_ndisuio_global->refcount - 1] = l2;
+
+ os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
+ l2->rx_callback = rx_callback;
+ l2->rx_callback_ctx = rx_callback_ctx;
+ l2->l2_hdr = l2_hdr;
+
+ if (own_addr)
+ os_memcpy(l2->own_addr, own_addr, ETH_ALEN);
+
+ if (l2_ndisuio_set_ether_type(protocol) < 0) {
+ os_free(l2);
+ return NULL;
+ }
+
+ if (l2_ndisuio_global->refcount > 1) {
+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): Temporarily setting "
+ "filtering ethertype to %04x", protocol);
+ if (l2_ndisuio_global->l2[0])
+ l2->rx_avail = l2_ndisuio_global->l2[0]->rx_avail;
+ return l2;
+ }
+
+ l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (l2->rx_avail == NULL) {
+ os_free(l2);
+ return NULL;
+ }
+
+ eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail),
+ l2_packet_rx_event, l2, NULL);
+
+#ifdef _WIN32_WCE
+ l2_ndisuio_global->stop_request = CreateEvent(NULL, TRUE, FALSE, NULL);
+ /*
+ * This event is being set based on media connect/disconnect
+ * notifications in driver_ndis.c.
+ */
+ l2_ndisuio_global->ready_for_read =
+ CreateEvent(NULL, TRUE, FALSE, TEXT("WpaSupplicantConnected"));
+ l2_ndisuio_global->rx_processed = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (l2_ndisuio_global->stop_request == NULL ||
+ l2_ndisuio_global->ready_for_read == NULL ||
+ l2_ndisuio_global->rx_processed == NULL) {
+ if (l2_ndisuio_global->stop_request) {
+ CloseHandle(l2_ndisuio_global->stop_request);
+ l2_ndisuio_global->stop_request = NULL;
+ }
+ if (l2_ndisuio_global->ready_for_read) {
+ CloseHandle(l2_ndisuio_global->ready_for_read);
+ l2_ndisuio_global->ready_for_read = NULL;
+ }
+ if (l2_ndisuio_global->rx_processed) {
+ CloseHandle(l2_ndisuio_global->rx_processed);
+ l2_ndisuio_global->rx_processed = NULL;
+ }
+ eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
+ os_free(l2);
+ return NULL;
+ }
+
+ l2_ndisuio_global->rx_thread = CreateThread(NULL, 0,
+ l2_packet_rx_thread, l2, 0,
+ NULL);
+ if (l2_ndisuio_global->rx_thread == NULL) {
+ wpa_printf(MSG_INFO, "L2(NDISUIO): Failed to create RX "
+ "thread: %d", (int) GetLastError());
+ eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
+ CloseHandle(l2_ndisuio_global->stop_request);
+ l2_ndisuio_global->stop_request = NULL;
+ os_free(l2);
+ return NULL;
+ }
+#else /* _WIN32_WCE */
+ l2_ndisuio_start_read(l2, 0);
+#endif /* _WIN32_WCE */
+
+ return l2;
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+ if (l2 == NULL)
+ return;
+
+ if (l2_ndisuio_global) {
+ l2_ndisuio_global->refcount--;
+ l2_ndisuio_global->l2[l2_ndisuio_global->refcount] = NULL;
+ if (l2_ndisuio_global->refcount) {
+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): restore filtering "
+ "ethertype to %04x",
+ l2_ndisuio_global->first_proto);
+ l2_ndisuio_set_ether_type(
+ l2_ndisuio_global->first_proto);
+ return;
+ }
+
+#ifdef _WIN32_WCE
+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): Waiting for RX thread to "
+ "stop");
+ SetEvent(l2_ndisuio_global->stop_request);
+ /*
+ * Cancel pending ReadFile() in the RX thread (if we were still
+ * connected at this point).
+ */
+ if (!DeviceIoControl(driver_ndis_get_ndisuio_handle(),
+ IOCTL_CANCEL_READ, NULL, 0, NULL, 0, NULL,
+ NULL)) {
+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): IOCTL_CANCEL_READ "
+ "failed: %d", (int) GetLastError());
+ /* RX thread will exit blocking ReadFile once NDISUIO
+ * notices that the adapter is disconnected. */
+ }
+ WaitForSingleObject(l2_ndisuio_global->rx_thread, INFINITE);
+ wpa_printf(MSG_DEBUG, "L2(NDISUIO): RX thread exited");
+ CloseHandle(l2_ndisuio_global->rx_thread);
+ CloseHandle(l2_ndisuio_global->stop_request);
+ CloseHandle(l2_ndisuio_global->ready_for_read);
+ CloseHandle(l2_ndisuio_global->rx_processed);
+#endif /* _WIN32_WCE */
+
+ os_free(l2_ndisuio_global);
+ l2_ndisuio_global = NULL;
+ }
+
+#ifndef _WIN32_WCE
+ CancelIo(driver_ndis_get_ndisuio_handle());
+#endif /* _WIN32_WCE */
+
+ eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
+ CloseHandle(l2->rx_avail);
+ os_free(l2);
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+ return -1;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+}
diff --git a/src/l2_packet/l2_packet_none.c b/src/l2_packet/l2_packet_none.c
new file mode 100644
index 0000000..5e3f6e9
--- /dev/null
+++ b/src/l2_packet/l2_packet_none.c
@@ -0,0 +1,123 @@
+/*
+ * WPA Supplicant - Layer2 packet handling example with dummy functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This file can be used as a starting point for layer2 packet implementation.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+
+
+struct l2_packet_data {
+ char ifname[17];
+ u8 own_addr[ETH_ALEN];
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len);
+ void *rx_callback_ctx;
+ int l2_hdr; /* whether to include layer 2 (Ethernet) header data
+ * buffers */
+ int fd;
+};
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+ os_memcpy(addr, l2->own_addr, ETH_ALEN);
+ return 0;
+}
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+ const u8 *buf, size_t len)
+{
+ if (l2 == NULL)
+ return -1;
+
+ /*
+ * TODO: Send frame (may need different implementation depending on
+ * whether l2->l2_hdr is set).
+ */
+
+ return 0;
+}
+
+
+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct l2_packet_data *l2 = eloop_ctx;
+ u8 buf[2300];
+ int res;
+
+ /* TODO: receive frame (e.g., recv() using sock */
+ buf[0] = 0;
+ res = 0;
+
+ l2->rx_callback(l2->rx_callback_ctx, NULL /* TODO: src addr */,
+ buf, res);
+}
+
+
+struct l2_packet_data * l2_packet_init(
+ const char *ifname, const u8 *own_addr, unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ struct l2_packet_data *l2;
+
+ l2 = os_zalloc(sizeof(struct l2_packet_data));
+ if (l2 == NULL)
+ return NULL;
+ os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
+ l2->rx_callback = rx_callback;
+ l2->rx_callback_ctx = rx_callback_ctx;
+ l2->l2_hdr = l2_hdr;
+
+ /*
+ * TODO: open connection for receiving frames
+ */
+ l2->fd = -1;
+ eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
+
+ return l2;
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+ if (l2 == NULL)
+ return;
+
+ if (l2->fd >= 0) {
+ eloop_unregister_read_sock(l2->fd);
+ /* TODO: close connection */
+ }
+
+ os_free(l2);
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+ /* TODO: get interface IP address */
+ return -1;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+ /* This function can be left empty */
+}
diff --git a/src/l2_packet/l2_packet_pcap.c b/src/l2_packet/l2_packet_pcap.c
new file mode 100644
index 0000000..8156e29
--- /dev/null
+++ b/src/l2_packet/l2_packet_pcap.c
@@ -0,0 +1,386 @@
+/*
+ * WPA Supplicant - Layer2 packet handling with libpcap/libdnet and WinPcap
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <sys/ioctl.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+#include <pcap.h>
+#ifndef CONFIG_WINPCAP
+#include <dnet.h>
+#endif /* CONFIG_WINPCAP */
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+struct l2_packet_data {
+ pcap_t *pcap;
+#ifdef CONFIG_WINPCAP
+ unsigned int num_fast_poll;
+#else /* CONFIG_WINPCAP */
+ eth_t *eth;
+#endif /* CONFIG_WINPCAP */
+ char ifname[100];
+ u8 own_addr[ETH_ALEN];
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len);
+ void *rx_callback_ctx;
+ int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls
+ * to rx_callback */
+};
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+ os_memcpy(addr, l2->own_addr, ETH_ALEN);
+ return 0;
+}
+
+
+#ifndef CONFIG_WINPCAP
+static int l2_packet_init_libdnet(struct l2_packet_data *l2)
+{
+ eth_addr_t own_addr;
+
+ l2->eth = eth_open(l2->ifname);
+ if (!l2->eth) {
+ printf("Failed to open interface '%s'.\n", l2->ifname);
+ perror("eth_open");
+ return -1;
+ }
+
+ if (eth_get(l2->eth, &own_addr) < 0) {
+ printf("Failed to get own hw address from interface '%s'.\n",
+ l2->ifname);
+ perror("eth_get");
+ eth_close(l2->eth);
+ l2->eth = NULL;
+ return -1;
+ }
+ os_memcpy(l2->own_addr, own_addr.data, ETH_ALEN);
+
+ return 0;
+}
+#endif /* CONFIG_WINPCAP */
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+ const u8 *buf, size_t len)
+{
+ int ret;
+ struct l2_ethhdr *eth;
+
+ if (l2 == NULL)
+ return -1;
+
+ if (l2->l2_hdr) {
+#ifdef CONFIG_WINPCAP
+ ret = pcap_sendpacket(l2->pcap, buf, len);
+#else /* CONFIG_WINPCAP */
+ ret = eth_send(l2->eth, buf, len);
+#endif /* CONFIG_WINPCAP */
+ } else {
+ size_t mlen = sizeof(*eth) + len;
+ eth = os_malloc(mlen);
+ if (eth == NULL)
+ return -1;
+
+ os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
+ os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
+ eth->h_proto = htons(proto);
+ os_memcpy(eth + 1, buf, len);
+
+#ifdef CONFIG_WINPCAP
+ ret = pcap_sendpacket(l2->pcap, (u8 *) eth, mlen);
+#else /* CONFIG_WINPCAP */
+ ret = eth_send(l2->eth, (u8 *) eth, mlen);
+#endif /* CONFIG_WINPCAP */
+
+ os_free(eth);
+ }
+
+ return ret;
+}
+
+
+#ifndef CONFIG_WINPCAP
+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct l2_packet_data *l2 = eloop_ctx;
+ pcap_t *pcap = sock_ctx;
+ struct pcap_pkthdr hdr;
+ const u_char *packet;
+ struct l2_ethhdr *ethhdr;
+ unsigned char *buf;
+ size_t len;
+
+ packet = pcap_next(pcap, &hdr);
+
+ if (packet == NULL || hdr.caplen < sizeof(*ethhdr))
+ return;
+
+ ethhdr = (struct l2_ethhdr *) packet;
+ if (l2->l2_hdr) {
+ buf = (unsigned char *) ethhdr;
+ len = hdr.caplen;
+ } else {
+ buf = (unsigned char *) (ethhdr + 1);
+ len = hdr.caplen - sizeof(*ethhdr);
+ }
+ l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len);
+}
+#endif /* CONFIG_WINPCAP */
+
+
+#ifdef CONFIG_WINPCAP
+static void l2_packet_receive_cb(u_char *user, const struct pcap_pkthdr *hdr,
+ const u_char *pkt_data)
+{
+ struct l2_packet_data *l2 = (struct l2_packet_data *) user;
+ struct l2_ethhdr *ethhdr;
+ unsigned char *buf;
+ size_t len;
+
+ if (pkt_data == NULL || hdr->caplen < sizeof(*ethhdr))
+ return;
+
+ ethhdr = (struct l2_ethhdr *) pkt_data;
+ if (l2->l2_hdr) {
+ buf = (unsigned char *) ethhdr;
+ len = hdr->caplen;
+ } else {
+ buf = (unsigned char *) (ethhdr + 1);
+ len = hdr->caplen - sizeof(*ethhdr);
+ }
+ l2->rx_callback(l2->rx_callback_ctx, ethhdr->h_source, buf, len);
+ /*
+ * Use shorter poll interval for 3 seconds to reduce latency during key
+ * handshake.
+ */
+ l2->num_fast_poll = 3 * 50;
+}
+
+
+static void l2_packet_receive_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct l2_packet_data *l2 = eloop_ctx;
+ pcap_t *pcap = timeout_ctx;
+ int timeout;
+
+ if (l2->num_fast_poll > 0) {
+ timeout = 20000;
+ l2->num_fast_poll--;
+ } else
+ timeout = 100000;
+
+ /* Register new timeout before calling l2_packet_receive() since
+ * receive handler may free this l2_packet instance (which will
+ * cancel this timeout). */
+ eloop_register_timeout(0, timeout, l2_packet_receive_timeout,
+ l2, pcap);
+ pcap_dispatch(pcap, 10, l2_packet_receive_cb, (u_char *) l2);
+}
+#endif /* CONFIG_WINPCAP */
+
+
+static int l2_packet_init_libpcap(struct l2_packet_data *l2,
+ unsigned short protocol)
+{
+ bpf_u_int32 pcap_maskp, pcap_netp;
+ char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
+ struct bpf_program pcap_fp;
+
+#ifdef CONFIG_WINPCAP
+ char ifname[128];
+ os_snprintf(ifname, sizeof(ifname), "\\Device\\NPF_%s", l2->ifname);
+ pcap_lookupnet(ifname, &pcap_netp, &pcap_maskp, pcap_err);
+ l2->pcap = pcap_open_live(ifname, 2500, 0, 10, pcap_err);
+ if (l2->pcap == NULL) {
+ fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
+ fprintf(stderr, "ifname='%s'\n", ifname);
+ return -1;
+ }
+ if (pcap_setnonblock(l2->pcap, 1, pcap_err) < 0)
+ fprintf(stderr, "pcap_setnonblock: %s\n",
+ pcap_geterr(l2->pcap));
+#else /* CONFIG_WINPCAP */
+ pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err);
+ l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 10, pcap_err);
+ if (l2->pcap == NULL) {
+ fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
+ fprintf(stderr, "ifname='%s'\n", l2->ifname);
+ return -1;
+ }
+ if (pcap_datalink(l2->pcap) != DLT_EN10MB &&
+ pcap_set_datalink(l2->pcap, DLT_EN10MB) < 0) {
+ fprintf(stderr, "pcap_set_datalink(DLT_EN10MB): %s\n",
+ pcap_geterr(l2->pcap));
+ return -1;
+ }
+#endif /* CONFIG_WINPCAP */
+ os_snprintf(pcap_filter, sizeof(pcap_filter),
+ "not ether src " MACSTR " and "
+ "( ether dst " MACSTR " or ether dst " MACSTR " ) and "
+ "ether proto 0x%x",
+ MAC2STR(l2->own_addr), /* do not receive own packets */
+ MAC2STR(l2->own_addr), MAC2STR(pae_group_addr),
+ protocol);
+ if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) {
+ fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap));
+ return -1;
+ }
+
+ if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) {
+ fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap));
+ return -1;
+ }
+
+ pcap_freecode(&pcap_fp);
+#ifdef BIOCIMMEDIATE
+ /*
+ * When libpcap uses BPF we must enable "immediate mode" to
+ * receive frames right away; otherwise the system may
+ * buffer them for us.
+ */
+ {
+ unsigned int on = 1;
+ if (ioctl(pcap_fileno(l2->pcap), BIOCIMMEDIATE, &on) < 0) {
+ fprintf(stderr, "%s: cannot enable immediate mode on "
+ "interface %s: %s\n",
+ __func__, l2->ifname, strerror(errno));
+ /* XXX should we fail? */
+ }
+ }
+#endif /* BIOCIMMEDIATE */
+
+#ifdef CONFIG_WINPCAP
+ eloop_register_timeout(0, 100000, l2_packet_receive_timeout,
+ l2, l2->pcap);
+#else /* CONFIG_WINPCAP */
+ eloop_register_read_sock(pcap_get_selectable_fd(l2->pcap),
+ l2_packet_receive, l2, l2->pcap);
+#endif /* CONFIG_WINPCAP */
+
+ return 0;
+}
+
+
+struct l2_packet_data * l2_packet_init(
+ const char *ifname, const u8 *own_addr, unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ struct l2_packet_data *l2;
+
+ l2 = os_zalloc(sizeof(struct l2_packet_data));
+ if (l2 == NULL)
+ return NULL;
+ os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
+ l2->rx_callback = rx_callback;
+ l2->rx_callback_ctx = rx_callback_ctx;
+ l2->l2_hdr = l2_hdr;
+
+#ifdef CONFIG_WINPCAP
+ if (own_addr)
+ os_memcpy(l2->own_addr, own_addr, ETH_ALEN);
+#else /* CONFIG_WINPCAP */
+ if (l2_packet_init_libdnet(l2))
+ return NULL;
+#endif /* CONFIG_WINPCAP */
+
+ if (l2_packet_init_libpcap(l2, protocol)) {
+#ifndef CONFIG_WINPCAP
+ eth_close(l2->eth);
+#endif /* CONFIG_WINPCAP */
+ os_free(l2);
+ return NULL;
+ }
+
+ return l2;
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+ if (l2 == NULL)
+ return;
+
+#ifdef CONFIG_WINPCAP
+ eloop_cancel_timeout(l2_packet_receive_timeout, l2, l2->pcap);
+#else /* CONFIG_WINPCAP */
+ if (l2->eth)
+ eth_close(l2->eth);
+ eloop_unregister_read_sock(pcap_get_selectable_fd(l2->pcap));
+#endif /* CONFIG_WINPCAP */
+ if (l2->pcap)
+ pcap_close(l2->pcap);
+ os_free(l2);
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+ pcap_if_t *devs, *dev;
+ struct pcap_addr *addr;
+ struct sockaddr_in *saddr;
+ int found = 0;
+ char err[PCAP_ERRBUF_SIZE + 1];
+
+ if (pcap_findalldevs(&devs, err) < 0) {
+ wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err);
+ return -1;
+ }
+
+ for (dev = devs; dev && !found; dev = dev->next) {
+ if (os_strcmp(dev->name, l2->ifname) != 0)
+ continue;
+
+ addr = dev->addresses;
+ while (addr) {
+ saddr = (struct sockaddr_in *) addr->addr;
+ if (saddr && saddr->sin_family == AF_INET) {
+ os_strlcpy(buf, inet_ntoa(saddr->sin_addr),
+ len);
+ found = 1;
+ break;
+ }
+ addr = addr->next;
+ }
+ }
+
+ pcap_freealldevs(devs);
+
+ return found ? 0 : -1;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+#ifdef CONFIG_WINPCAP
+ /*
+ * Use shorter poll interval for 3 seconds to reduce latency during key
+ * handshake.
+ */
+ l2->num_fast_poll = 3 * 50;
+ eloop_cancel_timeout(l2_packet_receive_timeout, l2, l2->pcap);
+ eloop_register_timeout(0, 10000, l2_packet_receive_timeout,
+ l2, l2->pcap);
+#endif /* CONFIG_WINPCAP */
+}
diff --git a/src/l2_packet/l2_packet_privsep.c b/src/l2_packet/l2_packet_privsep.c
new file mode 100644
index 0000000..c0e7c49
--- /dev/null
+++ b/src/l2_packet/l2_packet_privsep.c
@@ -0,0 +1,267 @@
+/*
+ * WPA Supplicant - Layer2 packet handling with privilege separation
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <sys/un.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+#include "privsep_commands.h"
+
+
+struct l2_packet_data {
+ int fd; /* UNIX domain socket for privsep access */
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len);
+ void *rx_callback_ctx;
+ u8 own_addr[ETH_ALEN];
+ char *own_socket_path;
+ struct sockaddr_un priv_addr;
+};
+
+
+static int wpa_priv_cmd(struct l2_packet_data *l2, int cmd,
+ const void *data, size_t data_len)
+{
+ struct msghdr msg;
+ struct iovec io[2];
+
+ io[0].iov_base = &cmd;
+ io[0].iov_len = sizeof(cmd);
+ io[1].iov_base = (u8 *) data;
+ io[1].iov_len = data_len;
+
+ os_memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = data ? 2 : 1;
+ msg.msg_name = &l2->priv_addr;
+ msg.msg_namelen = sizeof(l2->priv_addr);
+
+ if (sendmsg(l2->fd, &msg, 0) < 0) {
+ perror("L2: sendmsg(cmd)");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+ os_memcpy(addr, l2->own_addr, ETH_ALEN);
+ return 0;
+}
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+ const u8 *buf, size_t len)
+{
+ struct msghdr msg;
+ struct iovec io[4];
+ int cmd = PRIVSEP_CMD_L2_SEND;
+
+ io[0].iov_base = &cmd;
+ io[0].iov_len = sizeof(cmd);
+ io[1].iov_base = &dst_addr;
+ io[1].iov_len = ETH_ALEN;
+ io[2].iov_base = &proto;
+ io[2].iov_len = 2;
+ io[3].iov_base = (u8 *) buf;
+ io[3].iov_len = len;
+
+ os_memset(&msg, 0, sizeof(msg));
+ msg.msg_iov = io;
+ msg.msg_iovlen = 4;
+ msg.msg_name = &l2->priv_addr;
+ msg.msg_namelen = sizeof(l2->priv_addr);
+
+ if (sendmsg(l2->fd, &msg, 0) < 0) {
+ perror("L2: sendmsg(packet_send)");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static void l2_packet_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct l2_packet_data *l2 = eloop_ctx;
+ u8 buf[2300];
+ int res;
+ struct sockaddr_un from;
+ socklen_t fromlen = sizeof(from);
+
+ os_memset(&from, 0, sizeof(from));
+ res = recvfrom(sock, buf, sizeof(buf), 0, (struct sockaddr *) &from,
+ &fromlen);
+ if (res < 0) {
+ perror("l2_packet_receive - recvfrom");
+ return;
+ }
+ if (res < ETH_ALEN) {
+ wpa_printf(MSG_DEBUG, "L2: Too show packet received");
+ return;
+ }
+
+ if (from.sun_family != AF_UNIX ||
+ os_strncmp(from.sun_path, l2->priv_addr.sun_path,
+ sizeof(from.sun_path)) != 0) {
+ wpa_printf(MSG_DEBUG, "L2: Received message from unexpected "
+ "source");
+ return;
+ }
+
+ l2->rx_callback(l2->rx_callback_ctx, buf, buf + ETH_ALEN,
+ res - ETH_ALEN);
+}
+
+
+struct l2_packet_data * l2_packet_init(
+ const char *ifname, const u8 *own_addr, unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ struct l2_packet_data *l2;
+ char *own_dir = "/tmp";
+ char *priv_dir = "/var/run/wpa_priv";
+ size_t len;
+ static unsigned int counter = 0;
+ struct sockaddr_un addr;
+ fd_set rfds;
+ struct timeval tv;
+ int res;
+ u8 reply[ETH_ALEN + 1];
+ int reg_cmd[2];
+
+ l2 = os_zalloc(sizeof(struct l2_packet_data));
+ if (l2 == NULL)
+ return NULL;
+ l2->rx_callback = rx_callback;
+ l2->rx_callback_ctx = rx_callback_ctx;
+
+ len = os_strlen(own_dir) + 50;
+ l2->own_socket_path = os_malloc(len);
+ if (l2->own_socket_path == NULL) {
+ os_free(l2);
+ return NULL;
+ }
+ os_snprintf(l2->own_socket_path, len, "%s/wpa_privsep-l2-%d-%d",
+ own_dir, getpid(), counter++);
+
+ l2->priv_addr.sun_family = AF_UNIX;
+ os_snprintf(l2->priv_addr.sun_path, sizeof(l2->priv_addr.sun_path),
+ "%s/%s", priv_dir, ifname);
+
+ l2->fd = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (l2->fd < 0) {
+ perror("socket(PF_UNIX)");
+ os_free(l2->own_socket_path);
+ l2->own_socket_path = NULL;
+ os_free(l2);
+ return NULL;
+ }
+
+ os_memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ os_strlcpy(addr.sun_path, l2->own_socket_path, sizeof(addr.sun_path));
+ if (bind(l2->fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind(PF_UNIX)");
+ goto fail;
+ }
+
+ reg_cmd[0] = protocol;
+ reg_cmd[1] = l2_hdr;
+ if (wpa_priv_cmd(l2, PRIVSEP_CMD_L2_REGISTER, reg_cmd, sizeof(reg_cmd))
+ < 0) {
+ wpa_printf(MSG_ERROR, "L2: Failed to register with wpa_priv");
+ goto fail;
+ }
+
+ FD_ZERO(&rfds);
+ FD_SET(l2->fd, &rfds);
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+ res = select(l2->fd + 1, &rfds, NULL, NULL, &tv);
+ if (res < 0 && errno != EINTR) {
+ perror("select");
+ goto fail;
+ }
+
+ if (FD_ISSET(l2->fd, &rfds)) {
+ res = recv(l2->fd, reply, sizeof(reply), 0);
+ if (res < 0) {
+ perror("recv");
+ goto fail;
+ }
+ } else {
+ wpa_printf(MSG_DEBUG, "L2: Timeout while waiting for "
+ "registration reply");
+ goto fail;
+ }
+
+ if (res != ETH_ALEN) {
+ wpa_printf(MSG_DEBUG, "L2: Unexpected registration reply "
+ "(len=%d)", res);
+ }
+ os_memcpy(l2->own_addr, reply, ETH_ALEN);
+
+ eloop_register_read_sock(l2->fd, l2_packet_receive, l2, NULL);
+
+ return l2;
+
+fail:
+ close(l2->fd);
+ l2->fd = -1;
+ unlink(l2->own_socket_path);
+ os_free(l2->own_socket_path);
+ l2->own_socket_path = NULL;
+ os_free(l2);
+ return NULL;
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+ if (l2 == NULL)
+ return;
+
+ if (l2->fd >= 0) {
+ wpa_priv_cmd(l2, PRIVSEP_CMD_L2_UNREGISTER, NULL, 0);
+ eloop_unregister_read_sock(l2->fd);
+ close(l2->fd);
+ }
+
+ if (l2->own_socket_path) {
+ unlink(l2->own_socket_path);
+ os_free(l2->own_socket_path);
+ }
+
+ os_free(l2);
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+ /* TODO */
+ return -1;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+ wpa_priv_cmd(l2, PRIVSEP_CMD_L2_NOTIFY_AUTH_START, NULL, 0);
+}
diff --git a/src/l2_packet/l2_packet_winpcap.c b/src/l2_packet/l2_packet_winpcap.c
new file mode 100644
index 0000000..f76b386
--- /dev/null
+++ b/src/l2_packet/l2_packet_winpcap.c
@@ -0,0 +1,341 @@
+/*
+ * WPA Supplicant - Layer2 packet handling with WinPcap RX thread
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This l2_packet implementation is explicitly for WinPcap and Windows events.
+ * l2_packet_pcap.c has support for WinPcap, but it requires polling to receive
+ * frames which means relatively long latency for EAPOL RX processing. The
+ * implementation here uses a separate thread to allow WinPcap to be receiving
+ * all the time to reduce latency for EAPOL receiving from about 100 ms to 3 ms
+ * when comparing l2_packet_pcap.c to l2_packet_winpcap.c. Extra sleep of 50 ms
+ * is added in to receive thread whenever no EAPOL frames has been received for
+ * a while. Whenever an EAPOL handshake is expected, this sleep is removed.
+ *
+ * The RX thread receives a frame and signals main thread through Windows event
+ * about the availability of a new frame. Processing the received frame is
+ * synchronized with pair of Windows events so that no extra buffer or queuing
+ * mechanism is needed. This implementation requires Windows specific event
+ * loop implementation, i.e., eloop_win.c.
+ *
+ * WinPcap has pcap_getevent() that could, in theory at least, be used to
+ * implement this kind of waiting with a simpler single-thread design. However,
+ * that event handle is not really signaled immediately when receiving each
+ * frame, so it does not really work for this kind of use.
+ */
+
+#include "includes.h"
+#include <pcap.h>
+
+#include "common.h"
+#include "eloop.h"
+#include "l2_packet.h"
+
+
+static const u8 pae_group_addr[ETH_ALEN] =
+{ 0x01, 0x80, 0xc2, 0x00, 0x00, 0x03 };
+
+/*
+ * Number of pcap_dispatch() iterations to do without extra wait after each
+ * received EAPOL packet or authentication notification. This is used to reduce
+ * latency for EAPOL receive.
+ */
+static const size_t no_wait_count = 750;
+
+struct l2_packet_data {
+ pcap_t *pcap;
+ unsigned int num_fast_poll;
+ char ifname[100];
+ u8 own_addr[ETH_ALEN];
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len);
+ void *rx_callback_ctx;
+ int l2_hdr; /* whether to include layer 2 (Ethernet) header in calls to
+ * rx_callback and l2_packet_send() */
+ int running;
+ HANDLE rx_avail, rx_done, rx_thread, rx_thread_done, rx_notify;
+ u8 *rx_buf, *rx_src;
+ size_t rx_len;
+ size_t rx_no_wait;
+};
+
+
+int l2_packet_get_own_addr(struct l2_packet_data *l2, u8 *addr)
+{
+ os_memcpy(addr, l2->own_addr, ETH_ALEN);
+ return 0;
+}
+
+
+int l2_packet_send(struct l2_packet_data *l2, const u8 *dst_addr, u16 proto,
+ const u8 *buf, size_t len)
+{
+ int ret;
+ struct l2_ethhdr *eth;
+
+ if (l2 == NULL)
+ return -1;
+
+ if (l2->l2_hdr) {
+ ret = pcap_sendpacket(l2->pcap, buf, len);
+ } else {
+ size_t mlen = sizeof(*eth) + len;
+ eth = os_malloc(mlen);
+ if (eth == NULL)
+ return -1;
+
+ os_memcpy(eth->h_dest, dst_addr, ETH_ALEN);
+ os_memcpy(eth->h_source, l2->own_addr, ETH_ALEN);
+ eth->h_proto = htons(proto);
+ os_memcpy(eth + 1, buf, len);
+ ret = pcap_sendpacket(l2->pcap, (u8 *) eth, mlen);
+ os_free(eth);
+ }
+
+ return ret;
+}
+
+
+/* pcap_dispatch() callback for the RX thread */
+static void l2_packet_receive_cb(u_char *user, const struct pcap_pkthdr *hdr,
+ const u_char *pkt_data)
+{
+ struct l2_packet_data *l2 = (struct l2_packet_data *) user;
+ struct l2_ethhdr *ethhdr;
+
+ if (pkt_data == NULL || hdr->caplen < sizeof(*ethhdr))
+ return;
+
+ ethhdr = (struct l2_ethhdr *) pkt_data;
+ if (l2->l2_hdr) {
+ l2->rx_buf = (u8 *) ethhdr;
+ l2->rx_len = hdr->caplen;
+ } else {
+ l2->rx_buf = (u8 *) (ethhdr + 1);
+ l2->rx_len = hdr->caplen - sizeof(*ethhdr);
+ }
+ l2->rx_src = ethhdr->h_source;
+ SetEvent(l2->rx_avail);
+ WaitForSingleObject(l2->rx_done, INFINITE);
+ ResetEvent(l2->rx_done);
+ l2->rx_no_wait = no_wait_count;
+}
+
+
+/* main RX loop that is running in a separate thread */
+static DWORD WINAPI l2_packet_receive_thread(LPVOID arg)
+{
+ struct l2_packet_data *l2 = arg;
+
+ while (l2->running) {
+ pcap_dispatch(l2->pcap, 1, l2_packet_receive_cb,
+ (u_char *) l2);
+ if (l2->rx_no_wait > 0)
+ l2->rx_no_wait--;
+ if (WaitForSingleObject(l2->rx_notify,
+ l2->rx_no_wait ? 0 : 50) ==
+ WAIT_OBJECT_0) {
+ l2->rx_no_wait = no_wait_count;
+ ResetEvent(l2->rx_notify);
+ }
+ }
+ SetEvent(l2->rx_thread_done);
+ ExitThread(0);
+ return 0;
+}
+
+
+/* main thread RX event handler */
+static void l2_packet_rx_event(void *eloop_data, void *user_data)
+{
+ struct l2_packet_data *l2 = eloop_data;
+ l2->rx_callback(l2->rx_callback_ctx, l2->rx_src, l2->rx_buf,
+ l2->rx_len);
+ ResetEvent(l2->rx_avail);
+ SetEvent(l2->rx_done);
+}
+
+
+static int l2_packet_init_libpcap(struct l2_packet_data *l2,
+ unsigned short protocol)
+{
+ bpf_u_int32 pcap_maskp, pcap_netp;
+ char pcap_filter[200], pcap_err[PCAP_ERRBUF_SIZE];
+ struct bpf_program pcap_fp;
+
+ pcap_lookupnet(l2->ifname, &pcap_netp, &pcap_maskp, pcap_err);
+ l2->pcap = pcap_open_live(l2->ifname, 2500, 0, 1, pcap_err);
+ if (l2->pcap == NULL) {
+ fprintf(stderr, "pcap_open_live: %s\n", pcap_err);
+ fprintf(stderr, "ifname='%s'\n", l2->ifname);
+ return -1;
+ }
+ os_snprintf(pcap_filter, sizeof(pcap_filter),
+ "not ether src " MACSTR " and "
+ "( ether dst " MACSTR " or ether dst " MACSTR " ) and "
+ "ether proto 0x%x",
+ MAC2STR(l2->own_addr), /* do not receive own packets */
+ MAC2STR(l2->own_addr), MAC2STR(pae_group_addr),
+ protocol);
+ if (pcap_compile(l2->pcap, &pcap_fp, pcap_filter, 1, pcap_netp) < 0) {
+ fprintf(stderr, "pcap_compile: %s\n", pcap_geterr(l2->pcap));
+ return -1;
+ }
+
+ if (pcap_setfilter(l2->pcap, &pcap_fp) < 0) {
+ fprintf(stderr, "pcap_setfilter: %s\n", pcap_geterr(l2->pcap));
+ return -1;
+ }
+
+ pcap_freecode(&pcap_fp);
+
+ return 0;
+}
+
+
+struct l2_packet_data * l2_packet_init(
+ const char *ifname, const u8 *own_addr, unsigned short protocol,
+ void (*rx_callback)(void *ctx, const u8 *src_addr,
+ const u8 *buf, size_t len),
+ void *rx_callback_ctx, int l2_hdr)
+{
+ struct l2_packet_data *l2;
+ DWORD thread_id;
+
+ l2 = os_zalloc(sizeof(struct l2_packet_data));
+ if (l2 == NULL)
+ return NULL;
+ if (os_strncmp(ifname, "\\Device\\NPF_", 12) == 0)
+ os_strlcpy(l2->ifname, ifname, sizeof(l2->ifname));
+ else
+ os_snprintf(l2->ifname, sizeof(l2->ifname), "\\Device\\NPF_%s",
+ ifname);
+ l2->rx_callback = rx_callback;
+ l2->rx_callback_ctx = rx_callback_ctx;
+ l2->l2_hdr = l2_hdr;
+
+ if (own_addr)
+ os_memcpy(l2->own_addr, own_addr, ETH_ALEN);
+
+ if (l2_packet_init_libpcap(l2, protocol)) {
+ os_free(l2);
+ return NULL;
+ }
+
+ l2->rx_avail = CreateEvent(NULL, TRUE, FALSE, NULL);
+ l2->rx_done = CreateEvent(NULL, TRUE, FALSE, NULL);
+ l2->rx_notify = CreateEvent(NULL, TRUE, FALSE, NULL);
+ if (l2->rx_avail == NULL || l2->rx_done == NULL ||
+ l2->rx_notify == NULL) {
+ CloseHandle(l2->rx_avail);
+ CloseHandle(l2->rx_done);
+ CloseHandle(l2->rx_notify);
+ pcap_close(l2->pcap);
+ os_free(l2);
+ return NULL;
+ }
+
+ eloop_register_event(l2->rx_avail, sizeof(l2->rx_avail),
+ l2_packet_rx_event, l2, NULL);
+
+ l2->running = 1;
+ l2->rx_thread = CreateThread(NULL, 0, l2_packet_receive_thread, l2, 0,
+ &thread_id);
+
+ return l2;
+}
+
+
+static void l2_packet_deinit_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+ struct l2_packet_data *l2 = eloop_ctx;
+
+ if (l2->rx_thread_done &&
+ WaitForSingleObject(l2->rx_thread_done, 2000) != WAIT_OBJECT_0) {
+ wpa_printf(MSG_DEBUG, "l2_packet_winpcap: RX thread did not "
+ "exit - kill it\n");
+ TerminateThread(l2->rx_thread, 0);
+ }
+ CloseHandle(l2->rx_thread_done);
+ CloseHandle(l2->rx_thread);
+ if (l2->pcap)
+ pcap_close(l2->pcap);
+ eloop_unregister_event(l2->rx_avail, sizeof(l2->rx_avail));
+ CloseHandle(l2->rx_avail);
+ CloseHandle(l2->rx_done);
+ CloseHandle(l2->rx_notify);
+ os_free(l2);
+}
+
+
+void l2_packet_deinit(struct l2_packet_data *l2)
+{
+ if (l2 == NULL)
+ return;
+
+ l2->rx_thread_done = CreateEvent(NULL, TRUE, FALSE, NULL);
+
+ l2->running = 0;
+ pcap_breakloop(l2->pcap);
+
+ /*
+ * RX thread may be waiting in l2_packet_receive_cb() for l2->rx_done
+ * event and this event is set in l2_packet_rx_event(). However,
+ * l2_packet_deinit() may end up being called from l2->rx_callback(),
+ * so we need to return from here and complete deinitialization in
+ * a registered timeout to avoid having to forcefully kill the RX
+ * thread.
+ */
+ eloop_register_timeout(0, 0, l2_packet_deinit_timeout, l2, NULL);
+}
+
+
+int l2_packet_get_ip_addr(struct l2_packet_data *l2, char *buf, size_t len)
+{
+ pcap_if_t *devs, *dev;
+ struct pcap_addr *addr;
+ struct sockaddr_in *saddr;
+ int found = 0;
+ char err[PCAP_ERRBUF_SIZE + 1];
+
+ if (pcap_findalldevs(&devs, err) < 0) {
+ wpa_printf(MSG_DEBUG, "pcap_findalldevs: %s\n", err);
+ return -1;
+ }
+
+ for (dev = devs; dev && !found; dev = dev->next) {
+ if (os_strcmp(dev->name, l2->ifname) != 0)
+ continue;
+
+ addr = dev->addresses;
+ while (addr) {
+ saddr = (struct sockaddr_in *) addr->addr;
+ if (saddr && saddr->sin_family == AF_INET) {
+ os_strlcpy(buf, inet_ntoa(saddr->sin_addr),
+ len);
+ found = 1;
+ break;
+ }
+ addr = addr->next;
+ }
+ }
+
+ pcap_freealldevs(devs);
+
+ return found ? 0 : -1;
+}
+
+
+void l2_packet_notify_auth_start(struct l2_packet_data *l2)
+{
+ if (l2)
+ SetEvent(l2->rx_notify);
+}
diff --git a/src/radius/.gitignore b/src/radius/.gitignore
deleted file mode 100644
index a438335..0000000
--- a/src/radius/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.d
diff --git a/src/radius/radius_client.c b/src/radius/radius_client.c
index 673e97e..826acad 100644
--- a/src/radius/radius_client.c
+++ b/src/radius/radius_client.c
@@ -917,6 +917,22 @@ static void radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
}
+static int radius_client_disable_pmtu_discovery(int s)
+{
+ int r = -1;
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+ /* Turn off Path MTU discovery on IPv4/UDP sockets. */
+ int action = IP_PMTUDISC_DONT;
+ r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
+ sizeof(action));
+ if (r == -1)
+ wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: "
+ "%s", strerror(errno));
+#endif
+ return r;
+}
+
+
static int radius_client_init_auth(struct radius_client_data *radius)
{
struct hostapd_radius_servers *conf = radius->conf;
@@ -925,8 +941,10 @@ static int radius_client_init_auth(struct radius_client_data *radius)
radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (radius->auth_serv_sock < 0)
perror("socket[PF_INET,SOCK_DGRAM]");
- else
+ else {
+ radius_client_disable_pmtu_discovery(radius->auth_serv_sock);
ok++;
+ }
#ifdef CONFIG_IPV6
radius->auth_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
@@ -975,8 +993,10 @@ static int radius_client_init_acct(struct radius_client_data *radius)
radius->acct_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
if (radius->acct_serv_sock < 0)
perror("socket[PF_INET,SOCK_DGRAM]");
- else
+ else {
+ radius_client_disable_pmtu_discovery(radius->acct_serv_sock);
ok++;
+ }
#ifdef CONFIG_IPV6
radius->acct_serv_sock6 = socket(PF_INET6, SOCK_DGRAM, 0);
@@ -1060,6 +1080,12 @@ void radius_client_deinit(struct radius_client_data *radius)
eloop_unregister_read_sock(radius->auth_serv_sock);
if (radius->acct_serv_sock >= 0)
eloop_unregister_read_sock(radius->acct_serv_sock);
+#ifdef CONFIG_IPV6
+ if (radius->auth_serv_sock6 >= 0)
+ eloop_unregister_read_sock(radius->auth_serv_sock6);
+ if (radius->acct_serv_sock6 >= 0)
+ eloop_unregister_read_sock(radius->acct_serv_sock6);
+#endif /* CONFIG_IPV6 */
eloop_cancel_timeout(radius_retry_primary_timer, radius, NULL);
diff --git a/src/radius/radius_server.c b/src/radius/radius_server.c
index 1bfb93c..4f399bc 100644
--- a/src/radius/radius_server.c
+++ b/src/radius/radius_server.c
@@ -117,7 +117,8 @@ wpa_hexdump_ascii(MSG_MSGDUMP, "RADIUS SRV: " args)
static void radius_server_session_timeout(void *eloop_ctx, void *timeout_ctx);
-
+static void radius_server_session_remove_timeout(void *eloop_ctx,
+ void *timeout_ctx);
static struct radius_client *
@@ -179,6 +180,7 @@ static void radius_server_session_free(struct radius_server_data *data,
struct radius_session *sess)
{
eloop_cancel_timeout(radius_server_session_timeout, data, sess);
+ eloop_cancel_timeout(radius_server_session_remove_timeout, data, sess);
eap_server_sm_deinit(sess->eap);
if (sess->last_msg) {
radius_msg_free(sess->last_msg);
@@ -194,9 +196,6 @@ static void radius_server_session_free(struct radius_server_data *data,
}
-static void radius_server_session_remove_timeout(void *eloop_ctx,
- void *timeout_ctx);
-
static void radius_server_session_remove(struct radius_server_data *data,
struct radius_session *sess)
{
@@ -493,6 +492,7 @@ static int radius_server_request(struct radius_server_data *data,
unsigned int state;
struct radius_session *sess;
struct radius_msg *reply;
+ int is_complete = 0;
if (force_sess)
sess = force_sess;
@@ -603,6 +603,9 @@ static int radius_server_request(struct radius_server_data *data,
return -1;
}
+ if (sess->eap_if->eapSuccess || sess->eap_if->eapFail)
+ is_complete = 1;
+
reply = radius_server_encapsulate_eap(data, client, sess, msg);
if (reply) {
@@ -644,7 +647,7 @@ static int radius_server_request(struct radius_server_data *data,
client->counters.packets_dropped++;
}
- if (sess->eap_if->eapSuccess || sess->eap_if->eapFail) {
+ if (is_complete) {
RADIUS_DEBUG("Removing completed session 0x%x after timeout",
sess->sess_id);
eloop_cancel_timeout(radius_server_session_remove_timeout,
@@ -663,7 +666,13 @@ static void radius_server_receive_auth(int sock, void *eloop_ctx,
{
struct radius_server_data *data = eloop_ctx;
u8 *buf = NULL;
- struct sockaddr_storage from;
+ union {
+ struct sockaddr_storage ss;
+ struct sockaddr_in sin;
+#ifdef CONFIG_IPV6
+ struct sockaddr_in6 sin6;
+#endif /* CONFIG_IPV6 */
+ } from;
socklen_t fromlen;
int len;
struct radius_client *client = NULL;
@@ -678,7 +687,7 @@ static void radius_server_receive_auth(int sock, void *eloop_ctx,
fromlen = sizeof(from);
len = recvfrom(sock, buf, RADIUS_MAX_MSG_LEN, 0,
- (struct sockaddr *) &from, &fromlen);
+ (struct sockaddr *) &from.ss, &fromlen);
if (len < 0) {
perror("recvfrom[radius_server]");
goto fail;
@@ -686,28 +695,26 @@ static void radius_server_receive_auth(int sock, void *eloop_ctx,
#ifdef CONFIG_IPV6
if (data->ipv6) {
- struct sockaddr_in6 *from6 = (struct sockaddr_in6 *) &from;
- if (inet_ntop(AF_INET6, &from6->sin6_addr, abuf, sizeof(abuf))
- == NULL)
+ if (inet_ntop(AF_INET6, &from.sin6.sin6_addr, abuf,
+ sizeof(abuf)) == NULL)
abuf[0] = '\0';
- from_port = ntohs(from6->sin6_port);
+ from_port = ntohs(from.sin6.sin6_port);
RADIUS_DEBUG("Received %d bytes from %s:%d",
len, abuf, from_port);
client = radius_server_get_client(data,
(struct in_addr *)
- &from6->sin6_addr, 1);
+ &from.sin6.sin6_addr, 1);
}
#endif /* CONFIG_IPV6 */
if (!data->ipv6) {
- struct sockaddr_in *from4 = (struct sockaddr_in *) &from;
- os_strlcpy(abuf, inet_ntoa(from4->sin_addr), sizeof(abuf));
- from_port = ntohs(from4->sin_port);
+ os_strlcpy(abuf, inet_ntoa(from.sin.sin_addr), sizeof(abuf));
+ from_port = ntohs(from.sin.sin_port);
RADIUS_DEBUG("Received %d bytes from %s:%d",
len, abuf, from_port);
- client = radius_server_get_client(data, &from4->sin_addr, 0);
+ client = radius_server_get_client(data, &from.sin.sin_addr, 0);
}
RADIUS_DUMP("Received data", buf, len);
@@ -765,6 +772,22 @@ fail:
}
+static int radius_server_disable_pmtu_discovery(int s)
+{
+ int r = -1;
+#if defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
+ /* Turn off Path MTU discovery on IPv4/UDP sockets. */
+ int action = IP_PMTUDISC_DONT;
+ r = setsockopt(s, IPPROTO_IP, IP_MTU_DISCOVER, &action,
+ sizeof(action));
+ if (r == -1)
+ wpa_printf(MSG_ERROR, "Failed to set IP_MTU_DISCOVER: "
+ "%s", strerror(errno));
+#endif
+ return r;
+}
+
+
static int radius_server_open_socket(int port)
{
int s;
@@ -776,6 +799,8 @@ static int radius_server_open_socket(int port)
return -1;
}
+ radius_server_disable_pmtu_discovery(s);
+
os_memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = htons(port);
diff --git a/src/rsn_supp/.gitignore b/src/rsn_supp/.gitignore
deleted file mode 100644
index a438335..0000000
--- a/src/rsn_supp/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.d
diff --git a/src/rsn_supp/wpa.c b/src/rsn_supp/wpa.c
index b221476..e611fc5 100644
--- a/src/rsn_supp/wpa.c
+++ b/src/rsn_supp/wpa.c
@@ -358,14 +358,15 @@ static int wpa_derive_ptk(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key,
struct wpa_ptk *ptk)
{
+ size_t ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->key_mgmt))
- return wpa_derive_ptk_ft(sm, src_addr, key, ptk);
+ 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, sizeof(*ptk),
+ (u8 *) ptk, ptk_len,
wpa_key_mgmt_sha256(sm->key_mgmt));
return 0;
}
@@ -407,13 +408,13 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
#endif /* CONFIG_NO_WPA2 */
if (wpa_supplicant_get_pmk(sm, src_addr, ie.pmkid))
- return;
+ goto failed;
if (sm->renew_snonce) {
if (os_get_random(sm->snonce, WPA_NONCE_LEN)) {
wpa_msg(sm->ctx->ctx, MSG_WARNING,
"WPA: Failed to get random data for SNonce");
- return;
+ goto failed;
}
sm->renew_snonce = 0;
wpa_hexdump(MSG_DEBUG, "WPA: Renewed SNonce",
@@ -433,9 +434,13 @@ static void wpa_supplicant_process_1_of_4(struct wpa_sm *sm,
if (wpa_supplicant_send_2_of_4(sm, sm->bssid, key, ver, sm->snonce,
sm->assoc_wpa_ie, sm->assoc_wpa_ie_len,
ptk))
- return;
+ goto failed;
os_memcpy(sm->anonce, key->key_nonce, WPA_NONCE_LEN);
+ return;
+
+failed:
+ wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
@@ -537,7 +542,8 @@ static int wpa_supplicant_install_ptk(struct wpa_sm *sm,
if (wpa_sm_set_key(sm, alg, sm->bssid, 0, 1, key_rsc, rsclen,
(u8 *) sm->ptk.tk1, keylen) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set PTK to the "
- "driver.");
+ "driver (alg=%d keylen=%d bssid=" MACSTR ")",
+ alg, keylen, MAC2STR(sm->bssid));
return -1;
}
@@ -647,7 +653,8 @@ static int wpa_supplicant_install_gtk(struct wpa_sm *sm,
gd->keyidx, gd->tx, key_rsc, gd->key_rsc_len,
_gtk, gd->gtk_len) < 0) {
wpa_printf(MSG_WARNING, "WPA: Failed to set GTK to "
- "the driver.");
+ "the driver (alg=%d keylen=%d keyidx=%d)",
+ gd->alg, gd->gtk_len, gd->keyidx);
return -1;
}
@@ -944,30 +951,30 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
wpa_supplicant_parse_ies(pos, len, &ie);
if (ie.gtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
wpa_printf(MSG_WARNING, "WPA: GTK IE in unencrypted key data");
- return;
+ goto failed;
}
#ifdef CONFIG_IEEE80211W
if (ie.igtk && !(key_info & WPA_KEY_INFO_ENCR_KEY_DATA)) {
wpa_printf(MSG_WARNING, "WPA: IGTK KDE in unencrypted key "
"data");
- return;
+ goto failed;
}
if (ie.igtk && ie.igtk_len != sizeof(struct wpa_igtk_kde)) {
wpa_printf(MSG_WARNING, "WPA: Invalid IGTK KDE length %lu",
(unsigned long) ie.igtk_len);
- return;
+ goto failed;
}
#endif /* CONFIG_IEEE80211W */
if (wpa_supplicant_validate_ie(sm, sm->bssid, &ie) < 0)
- return;
+ goto failed;
if (os_memcmp(sm->anonce, key->key_nonce, WPA_NONCE_LEN) != 0) {
wpa_printf(MSG_WARNING, "WPA: ANonce from message 1 of 4-Way "
"Handshake differs from 3 of 4-Way Handshake - drop"
" packet (src=" MACSTR ")", MAC2STR(sm->bssid));
- return;
+ goto failed;
}
keylen = WPA_GET_BE16(key->key_length);
@@ -977,7 +984,7 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
wpa_printf(MSG_WARNING, "WPA: Invalid CCMP key length "
"%d (src=" MACSTR ")",
keylen, MAC2STR(sm->bssid));
- return;
+ goto failed;
}
break;
case WPA_CIPHER_TKIP:
@@ -985,14 +992,15 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
wpa_printf(MSG_WARNING, "WPA: Invalid TKIP key length "
"%d (src=" MACSTR ")",
keylen, MAC2STR(sm->bssid));
- return;
+ goto failed;
}
break;
}
if (wpa_supplicant_send_4_of_4(sm, sm->bssid, key, ver, key_info,
- NULL, 0, &sm->ptk))
- return;
+ 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
@@ -1000,7 +1008,8 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
sm->renew_snonce = 1;
if (key_info & WPA_KEY_INFO_INSTALL) {
- wpa_supplicant_install_ptk(sm, key);
+ if (wpa_supplicant_install_ptk(sm, key))
+ goto failed;
}
if (key_info & WPA_KEY_INFO_SECURE) {
@@ -1015,10 +1024,18 @@ static void wpa_supplicant_process_3_of_4(struct wpa_sm *sm,
wpa_supplicant_pairwise_gtk(sm, key,
ie.gtk, ie.gtk_len, key_info) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to configure GTK");
+ goto failed;
}
- if (ieee80211w_set_keys(sm, &ie) < 0)
+ if (ieee80211w_set_keys(sm, &ie) < 0) {
wpa_printf(MSG_INFO, "RSN: Failed to configure IGTK");
+ goto failed;
+ }
+
+ return;
+
+failed:
+ wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
@@ -1209,11 +1226,11 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
wpa_sm_set_state(sm, WPA_GROUP_HANDSHAKE);
if (ret)
- return;
+ goto failed;
if (wpa_supplicant_install_gtk(sm, &gd, key->key_rsc) ||
wpa_supplicant_send_2_of_2(sm, key, ver, key_info))
- return;
+ goto failed;
if (rekey) {
wpa_msg(sm->ctx->ctx, MSG_INFO, "WPA: Group rekeying "
@@ -1226,6 +1243,10 @@ static void wpa_supplicant_process_1_of_2(struct wpa_sm *sm,
key_info &
WPA_KEY_INFO_SECURE);
}
+ return;
+
+failed:
+ wpa_sm_deauthenticate(sm, WLAN_REASON_UNSPECIFIED);
}
@@ -1468,9 +1489,9 @@ int wpa_sm_rx_eapol(struct wpa_sm *sm, const u8 *src_addr,
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 &&
-#ifdef CONFIG_IEEE80211R
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
ver != WPA_KEY_INFO_TYPE_AES_128_CMAC &&
-#endif /* CONFIG_IEEE80211R */
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
wpa_printf(MSG_INFO, "WPA: Unsupported EAPOL-Key descriptor "
"version %d.", ver);
diff --git a/src/rsn_supp/wpa_ft.c b/src/rsn_supp/wpa_ft.c
index c89b89a..557b311 100644
--- a/src/rsn_supp/wpa_ft.c
+++ b/src/rsn_supp/wpa_ft.c
@@ -25,7 +25,7 @@
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key,
- struct wpa_ptk *ptk)
+ struct wpa_ptk *ptk, size_t ptk_len)
{
u8 pmk_r1_name[WPA_PMK_NAME_LEN];
u8 ptk_name[WPA_PMK_NAME_LEN];
@@ -50,8 +50,8 @@ int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", pmk_r1_name, WPA_PMK_NAME_LEN);
wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, anonce, sm->own_addr,
sm->bssid, pmk_r1_name,
- (u8 *) ptk, sizeof(*ptk), ptk_name);
- wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, sizeof(*ptk));
+ (u8 *) ptk, ptk_len, ptk_name);
+ wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
return 0;
@@ -455,7 +455,7 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
int ft_action, const u8 *target_ap)
{
u8 *ft_ies;
- size_t ft_ies_len;
+ size_t ft_ies_len, ptk_len;
struct wpa_ft_ies parse;
struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
@@ -545,11 +545,12 @@ int wpa_ft_process_response(struct wpa_sm *sm, const u8 *ies, size_t ies_len,
sm->pmk_r1_name, WPA_PMK_NAME_LEN);
bssid = target_ap;
+ ptk_len = sm->pairwise_cipher == WPA_CIPHER_CCMP ? 48 : 64;
wpa_pmk_r1_to_ptk(sm->pmk_r1, sm->snonce, ftie->anonce, sm->own_addr,
bssid, sm->pmk_r1_name,
- (u8 *) &sm->ptk, sizeof(sm->ptk), ptk_name);
+ (u8 *) &sm->ptk, ptk_len, ptk_name);
wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
- (u8 *) &sm->ptk, sizeof(sm->ptk));
+ (u8 *) &sm->ptk, ptk_len);
wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
ft_ies = wpa_ft_gen_req_ies(sm, &ft_ies_len, ftie->anonce,
diff --git a/src/rsn_supp/wpa_i.h b/src/rsn_supp/wpa_i.h
index 95348da..e0dc6bd 100644
--- a/src/rsn_supp/wpa_i.h
+++ b/src/rsn_supp/wpa_i.h
@@ -240,6 +240,6 @@ int wpa_supplicant_send_4_of_4(struct wpa_sm *sm, const unsigned char *dst,
int wpa_derive_ptk_ft(struct wpa_sm *sm, const unsigned char *src_addr,
const struct wpa_eapol_key *key,
- struct wpa_ptk *ptk);
+ struct wpa_ptk *ptk, size_t ptk_len);
#endif /* WPA_I_H */
diff --git a/src/tls/.gitignore b/src/tls/.gitignore
deleted file mode 100644
index a438335..0000000
--- a/src/tls/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.d
diff --git a/src/tls/rsa.c b/src/tls/rsa.c
index bfc0d52..4965a2a 100644
--- a/src/tls/rsa.c
+++ b/src/tls/rsa.c
@@ -35,6 +35,7 @@ struct crypto_rsa_key {
};
+#ifdef EAP_TLS_FUNCS
static const u8 * crypto_rsa_parse_integer(const u8 *pos, const u8 *end,
struct bignum *num)
{
@@ -223,6 +224,7 @@ error:
crypto_rsa_free(key);
return NULL;
}
+#endif /* EAP_TLS_FUNCS */
/**
diff --git a/src/tls/tlsv1_client.c b/src/tls/tlsv1_client.c
index 302e3ee..0bf1174 100644
--- a/src/tls/tlsv1_client.c
+++ b/src/tls/tlsv1_client.c
@@ -620,6 +620,17 @@ int tlsv1_client_set_cipher_list(struct tlsv1_client *conn, u8 *ciphers)
suites[count++] = TLS_DH_anon_WITH_3DES_EDE_CBC_SHA;
suites[count++] = TLS_DH_anon_WITH_RC4_128_MD5;
suites[count++] = TLS_DH_anon_WITH_DES_CBC_SHA;
+
+ /*
+ * Cisco AP (at least 350 and 1200 series) local authentication
+ * server does not know how to search cipher suites from the
+ * list and seem to require that the last entry in the list is
+ * the one that it wants to use. However, TLS specification
+ * requires the list to be in the client preference order. As a
+ * workaround, add anon-DH AES-128-SHA1 again at the end of the
+ * list to allow the Cisco code to find it.
+ */
+ suites[count++] = TLS_DH_anon_WITH_AES_128_CBC_SHA;
conn->num_cipher_suites = count;
}
diff --git a/src/tls/tlsv1_server_read.c b/src/tls/tlsv1_server_read.c
index 0e299d8..397d74a 100644
--- a/src/tls/tlsv1_server_read.c
+++ b/src/tls/tlsv1_server_read.c
@@ -40,6 +40,7 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
u16 cipher_suite;
u16 num_suites;
int compr_null_found;
+ u16 ext_type, ext_len;
if (ct != TLS_CONTENT_TYPE_HANDSHAKE) {
wpa_printf(MSG_DEBUG, "TLSv1: Expected Handshake; "
@@ -183,10 +184,7 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
}
if (end - pos >= 2) {
- u16 ext_len;
-
/* Extension client_hello_extension_list<0..2^16-1> */
-
ext_len = WPA_GET_BE16(pos);
pos += 2;
@@ -195,7 +193,7 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
if (end - pos != ext_len) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid ClientHello "
"extension list length %u (expected %u)",
- ext_len, end - pos);
+ ext_len, (unsigned int) (end - pos));
goto decode_error;
}
@@ -207,8 +205,6 @@ static int tls_process_client_hello(struct tlsv1_server *conn, u8 ct,
*/
while (pos < end) {
- u16 ext_type, ext_len;
-
if (end - pos < 2) {
wpa_printf(MSG_DEBUG, "TLSv1: Invalid "
"extension_type field");
@@ -520,7 +516,7 @@ static int tls_process_client_key_exchange_rsa(
out, &outlen) < 0) {
wpa_printf(MSG_DEBUG, "TLSv1: Failed to decrypt "
"PreMasterSecret (encr_len=%d outlen=%lu)",
- end - pos, (unsigned long) outlen);
+ (int) (end - pos), (unsigned long) outlen);
use_random = 1;
}
diff --git a/src/utils/.gitignore b/src/utils/.gitignore
deleted file mode 100644
index a438335..0000000
--- a/src/utils/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.d
diff --git a/src/utils/base64.c b/src/utils/base64.c
index 0eadb81..13fc511 100644
--- a/src/utils/base64.c
+++ b/src/utils/base64.c
@@ -43,6 +43,8 @@ unsigned char * base64_encode(const unsigned char *src, size_t 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;
diff --git a/src/utils/common.c b/src/utils/common.c
index cb373c3..9a46ebe 100644
--- a/src/utils/common.c
+++ b/src/utils/common.c
@@ -325,3 +325,9 @@ const char * wpa_ssid_txt(const u8 *ssid, size_t ssid_len)
}
return ssid_txt;
}
+
+
+void * __hide_aliasing_typecast(void *foo)
+{
+ return foo;
+}
diff --git a/src/utils/common.h b/src/utils/common.h
index d0a2eb3..d649391 100644
--- a/src/utils/common.h
+++ b/src/utils/common.h
@@ -22,17 +22,24 @@
#include <byteswap.h>
#endif /* __linux__ */
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
+#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(__DragonFly__) || defined(__OpenBSD__) */
#ifdef __APPLE__
#include <sys/types.h>
@@ -435,4 +442,17 @@ static inline int is_zero_ether_addr(const u8 *a)
#include "wpa_debug.h"
+
+/*
+ * gcc 4.4 ends up generating strict-aliasing warnings about some very common
+ * networking socket uses that do not really result in a real problem and
+ * cannot be easily avoided with union-based type-punning due to struct
+ * definitions including another struct in system header files. To avoid having
+ * to fully disable strict-aliasing warnings, provide a mechanism to hide the
+ * typecast from aliasing for now. A cleaner solution will hopefully be found
+ * in the future to handle these cases.
+ */
+void * __hide_aliasing_typecast(void *foo);
+#define aliasing_hide_typecast(a,t) (t *) __hide_aliasing_typecast((a))
+
#endif /* COMMON_H */
diff --git a/src/utils/eloop_none.c b/src/utils/eloop_none.c
new file mode 100644
index 0000000..215030b
--- /dev/null
+++ b/src/utils/eloop_none.c
@@ -0,0 +1,410 @@
+/*
+ * Event loop - empty template (basic structure, but no OS specific operations)
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+
+
+struct eloop_sock {
+ int sock;
+ void *eloop_data;
+ void *user_data;
+ void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
+};
+
+struct eloop_timeout {
+ struct os_time time;
+ void *eloop_data;
+ void *user_data;
+ void (*handler)(void *eloop_ctx, void *sock_ctx);
+ struct eloop_timeout *next;
+};
+
+struct eloop_signal {
+ int sig;
+ void *user_data;
+ void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
+ int signaled;
+};
+
+struct eloop_data {
+ 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 pending_terminate;
+
+ int terminate;
+ int reader_table_changed;
+};
+
+static struct eloop_data eloop;
+
+
+int eloop_init(void *user_data)
+{
+ memset(&eloop, 0, sizeof(eloop));
+ eloop.user_data = user_data;
+ return 0;
+}
+
+
+int eloop_register_read_sock(int sock,
+ void (*handler)(int sock, void *eloop_ctx,
+ void *sock_ctx),
+ void *eloop_data, void *user_data)
+{
+ struct eloop_sock *tmp;
+
+ tmp = (struct eloop_sock *)
+ realloc(eloop.readers,
+ (eloop.reader_count + 1) * sizeof(struct eloop_sock));
+ if (tmp == NULL)
+ return -1;
+
+ tmp[eloop.reader_count].sock = sock;
+ tmp[eloop.reader_count].eloop_data = eloop_data;
+ tmp[eloop.reader_count].user_data = user_data;
+ tmp[eloop.reader_count].handler = handler;
+ eloop.reader_count++;
+ eloop.readers = tmp;
+ if (sock > eloop.max_sock)
+ eloop.max_sock = sock;
+ eloop.reader_table_changed = 1;
+
+ return 0;
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+ int i;
+
+ if (eloop.readers == NULL || eloop.reader_count == 0)
+ return;
+
+ for (i = 0; i < eloop.reader_count; i++) {
+ if (eloop.readers[i].sock == sock)
+ break;
+ }
+ if (i == eloop.reader_count)
+ return;
+ if (i != eloop.reader_count - 1) {
+ memmove(&eloop.readers[i], &eloop.readers[i + 1],
+ (eloop.reader_count - i - 1) *
+ sizeof(struct eloop_sock));
+ }
+ eloop.reader_count--;
+ eloop.reader_table_changed = 1;
+}
+
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+ void (*handler)(void *eloop_ctx, void *timeout_ctx),
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *timeout, *tmp, *prev;
+
+ timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
+ if (timeout == NULL)
+ return -1;
+ os_get_time(&timeout->time);
+ timeout->time.sec += secs;
+ timeout->time.usec += usecs;
+ while (timeout->time.usec >= 1000000) {
+ timeout->time.sec++;
+ timeout->time.usec -= 1000000;
+ }
+ timeout->eloop_data = eloop_data;
+ timeout->user_data = user_data;
+ timeout->handler = handler;
+ timeout->next = NULL;
+
+ if (eloop.timeout == NULL) {
+ eloop.timeout = timeout;
+ return 0;
+ }
+
+ prev = NULL;
+ tmp = eloop.timeout;
+ while (tmp != NULL) {
+ if (os_time_before(&timeout->time, &tmp->time))
+ break;
+ prev = tmp;
+ tmp = tmp->next;
+ }
+
+ if (prev == NULL) {
+ timeout->next = eloop.timeout;
+ eloop.timeout = timeout;
+ } else {
+ timeout->next = prev->next;
+ prev->next = timeout;
+ }
+
+ return 0;
+}
+
+
+int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *timeout, *prev, *next;
+ int removed = 0;
+
+ prev = NULL;
+ timeout = eloop.timeout;
+ while (timeout != NULL) {
+ next = timeout->next;
+
+ if (timeout->handler == handler &&
+ (timeout->eloop_data == eloop_data ||
+ eloop_data == ELOOP_ALL_CTX) &&
+ (timeout->user_data == user_data ||
+ user_data == ELOOP_ALL_CTX)) {
+ if (prev == NULL)
+ eloop.timeout = next;
+ else
+ prev->next = next;
+ free(timeout);
+ removed++;
+ } else
+ prev = timeout;
+
+ timeout = next;
+ }
+
+ return removed;
+}
+
+
+int eloop_is_timeout_registered(void (*handler)(void *eloop_ctx,
+ void *timeout_ctx),
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *tmp;
+
+ tmp = eloop.timeout;
+ while (tmp != NULL) {
+ if (tmp->handler == handler &&
+ tmp->eloop_data == eloop_data &&
+ tmp->user_data == user_data)
+ return 1;
+
+ tmp = tmp->next;
+ }
+
+ return 0;
+}
+
+
+/* TODO: replace with suitable signal handler */
+#if 0
+static void eloop_handle_signal(int sig)
+{
+ int i;
+
+ eloop.signaled++;
+ for (i = 0; i < eloop.signal_count; i++) {
+ if (eloop.signals[i].sig == sig) {
+ eloop.signals[i].signaled++;
+ break;
+ }
+ }
+}
+#endif
+
+
+static void eloop_process_pending_signals(void)
+{
+ int i;
+
+ if (eloop.signaled == 0)
+ return;
+ eloop.signaled = 0;
+
+ if (eloop.pending_terminate) {
+ eloop.pending_terminate = 0;
+ }
+
+ for (i = 0; i < eloop.signal_count; i++) {
+ if (eloop.signals[i].signaled) {
+ eloop.signals[i].signaled = 0;
+ eloop.signals[i].handler(eloop.signals[i].sig,
+ eloop.user_data,
+ eloop.signals[i].user_data);
+ }
+ }
+}
+
+
+int eloop_register_signal(int sig,
+ void (*handler)(int sig, void *eloop_ctx,
+ void *signal_ctx),
+ void *user_data)
+{
+ struct eloop_signal *tmp;
+
+ tmp = (struct eloop_signal *)
+ realloc(eloop.signals,
+ (eloop.signal_count + 1) *
+ sizeof(struct eloop_signal));
+ if (tmp == NULL)
+ return -1;
+
+ tmp[eloop.signal_count].sig = sig;
+ tmp[eloop.signal_count].user_data = user_data;
+ tmp[eloop.signal_count].handler = handler;
+ tmp[eloop.signal_count].signaled = 0;
+ eloop.signal_count++;
+ eloop.signals = tmp;
+
+ /* TODO: register signal handler */
+
+ return 0;
+}
+
+
+int eloop_register_signal_terminate(void (*handler)(int sig, void *eloop_ctx,
+ void *signal_ctx),
+ void *user_data)
+{
+#if 0
+ /* TODO: for example */
+ int ret = eloop_register_signal(SIGINT, handler, user_data);
+ if (ret == 0)
+ ret = eloop_register_signal(SIGTERM, handler, user_data);
+ return ret;
+#endif
+ return 0;
+}
+
+
+int eloop_register_signal_reconfig(void (*handler)(int sig, void *eloop_ctx,
+ void *signal_ctx),
+ void *user_data)
+{
+#if 0
+ /* TODO: for example */
+ return eloop_register_signal(SIGHUP, handler, user_data);
+#endif
+ return 0;
+}
+
+
+void eloop_run(void)
+{
+ int i;
+ struct os_time tv, now;
+
+ while (!eloop.terminate &&
+ (eloop.timeout || eloop.reader_count > 0)) {
+ if (eloop.timeout) {
+ os_get_time(&now);
+ if (os_time_before(&now, &eloop.timeout->time))
+ os_time_sub(&eloop.timeout->time, &now, &tv);
+ else
+ tv.sec = tv.usec = 0;
+ }
+
+ /*
+ * TODO: wait for any event (read socket ready, timeout (tv),
+ * signal
+ */
+ os_sleep(1, 0); /* just a dummy wait for testing */
+
+ eloop_process_pending_signals();
+
+ /* check if some registered timeouts have occurred */
+ if (eloop.timeout) {
+ struct eloop_timeout *tmp;
+
+ os_get_time(&now);
+ if (!os_time_before(&now, &eloop.timeout->time)) {
+ tmp = eloop.timeout;
+ eloop.timeout = eloop.timeout->next;
+ tmp->handler(tmp->eloop_data,
+ tmp->user_data);
+ free(tmp);
+ }
+
+ }
+
+ eloop.reader_table_changed = 0;
+ for (i = 0; i < eloop.reader_count; i++) {
+ /*
+ * TODO: call each handler that has pending data to
+ * read
+ */
+ if (0 /* TODO: eloop.readers[i].sock ready */) {
+ eloop.readers[i].handler(
+ eloop.readers[i].sock,
+ eloop.readers[i].eloop_data,
+ eloop.readers[i].user_data);
+ if (eloop.reader_table_changed)
+ break;
+ }
+ }
+ }
+}
+
+
+void eloop_terminate(void)
+{
+ eloop.terminate = 1;
+}
+
+
+void eloop_destroy(void)
+{
+ struct eloop_timeout *timeout, *prev;
+
+ timeout = eloop.timeout;
+ while (timeout != NULL) {
+ prev = timeout;
+ timeout = timeout->next;
+ free(prev);
+ }
+ free(eloop.readers);
+ free(eloop.signals);
+}
+
+
+int eloop_terminated(void)
+{
+ return eloop.terminate;
+}
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+ /*
+ * TODO: wait for the file descriptor to have something available for
+ * reading
+ */
+}
+
+
+void * eloop_get_user_data(void)
+{
+ return eloop.user_data;
+}
diff --git a/src/utils/eloop_win.c b/src/utils/eloop_win.c
new file mode 100644
index 0000000..c95aa76
--- /dev/null
+++ b/src/utils/eloop_win.c
@@ -0,0 +1,622 @@
+/*
+ * Event loop based on Windows events and WaitForMultipleObjects
+ * Copyright (c) 2002-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <winsock2.h>
+
+#include "common.h"
+#include "eloop.h"
+
+
+struct eloop_sock {
+ int sock;
+ void *eloop_data;
+ void *user_data;
+ eloop_sock_handler handler;
+ WSAEVENT event;
+};
+
+struct eloop_event {
+ void *eloop_data;
+ void *user_data;
+ eloop_event_handler handler;
+ HANDLE event;
+};
+
+struct eloop_timeout {
+ struct os_time time;
+ void *eloop_data;
+ void *user_data;
+ eloop_timeout_handler handler;
+ struct eloop_timeout *next;
+};
+
+struct eloop_signal {
+ int sig;
+ void *user_data;
+ eloop_signal_handler handler;
+ int signaled;
+};
+
+struct eloop_data {
+ void *user_data;
+
+ int max_sock;
+ size_t reader_count;
+ struct eloop_sock *readers;
+
+ size_t event_count;
+ struct eloop_event *events;
+
+ struct eloop_timeout *timeout;
+
+ int signal_count;
+ struct eloop_signal *signals;
+ int signaled;
+ int pending_terminate;
+
+ int terminate;
+ int reader_table_changed;
+
+ struct eloop_signal term_signal;
+ HANDLE term_event;
+
+ HANDLE *handles;
+ size_t num_handles;
+};
+
+static struct eloop_data eloop;
+
+
+int eloop_init(void *user_data)
+{
+ os_memset(&eloop, 0, sizeof(eloop));
+ eloop.user_data = user_data;
+ eloop.num_handles = 1;
+ eloop.handles = os_malloc(eloop.num_handles *
+ sizeof(eloop.handles[0]));
+ if (eloop.handles == NULL)
+ return -1;
+
+ eloop.term_event = CreateEvent(NULL, FALSE, FALSE, NULL);
+ if (eloop.term_event == NULL) {
+ printf("CreateEvent() failed: %d\n",
+ (int) GetLastError());
+ os_free(eloop.handles);
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int eloop_prepare_handles(void)
+{
+ HANDLE *n;
+
+ if (eloop.num_handles > eloop.reader_count + eloop.event_count + 8)
+ return 0;
+ n = os_realloc(eloop.handles,
+ eloop.num_handles * 2 * sizeof(eloop.handles[0]));
+ if (n == NULL)
+ return -1;
+ eloop.handles = n;
+ eloop.num_handles *= 2;
+ return 0;
+}
+
+
+int eloop_register_read_sock(int sock, eloop_sock_handler handler,
+ void *eloop_data, void *user_data)
+{
+ WSAEVENT event;
+ struct eloop_sock *tmp;
+
+ if (eloop_prepare_handles())
+ return -1;
+
+ event = WSACreateEvent();
+ if (event == WSA_INVALID_EVENT) {
+ printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
+ return -1;
+ }
+
+ if (WSAEventSelect(sock, event, FD_READ)) {
+ printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
+ WSACloseEvent(event);
+ return -1;
+ }
+ tmp = os_realloc(eloop.readers,
+ (eloop.reader_count + 1) * sizeof(struct eloop_sock));
+ if (tmp == NULL) {
+ WSAEventSelect(sock, event, 0);
+ WSACloseEvent(event);
+ return -1;
+ }
+
+ tmp[eloop.reader_count].sock = sock;
+ tmp[eloop.reader_count].eloop_data = eloop_data;
+ tmp[eloop.reader_count].user_data = user_data;
+ tmp[eloop.reader_count].handler = handler;
+ tmp[eloop.reader_count].event = event;
+ eloop.reader_count++;
+ eloop.readers = tmp;
+ if (sock > eloop.max_sock)
+ eloop.max_sock = sock;
+ eloop.reader_table_changed = 1;
+
+ return 0;
+}
+
+
+void eloop_unregister_read_sock(int sock)
+{
+ size_t i;
+
+ if (eloop.readers == NULL || eloop.reader_count == 0)
+ return;
+
+ for (i = 0; i < eloop.reader_count; i++) {
+ if (eloop.readers[i].sock == sock)
+ break;
+ }
+ if (i == eloop.reader_count)
+ return;
+
+ WSAEventSelect(eloop.readers[i].sock, eloop.readers[i].event, 0);
+ WSACloseEvent(eloop.readers[i].event);
+
+ if (i != eloop.reader_count - 1) {
+ os_memmove(&eloop.readers[i], &eloop.readers[i + 1],
+ (eloop.reader_count - i - 1) *
+ sizeof(struct eloop_sock));
+ }
+ eloop.reader_count--;
+ eloop.reader_table_changed = 1;
+}
+
+
+int eloop_register_event(void *event, size_t event_size,
+ eloop_event_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_event *tmp;
+ HANDLE h = event;
+
+ if (event_size != sizeof(HANDLE) || h == INVALID_HANDLE_VALUE)
+ return -1;
+
+ if (eloop_prepare_handles())
+ return -1;
+
+ tmp = os_realloc(eloop.events,
+ (eloop.event_count + 1) * sizeof(struct eloop_event));
+ if (tmp == NULL)
+ return -1;
+
+ tmp[eloop.event_count].eloop_data = eloop_data;
+ tmp[eloop.event_count].user_data = user_data;
+ tmp[eloop.event_count].handler = handler;
+ tmp[eloop.event_count].event = h;
+ eloop.event_count++;
+ eloop.events = tmp;
+
+ return 0;
+}
+
+
+void eloop_unregister_event(void *event, size_t event_size)
+{
+ size_t i;
+ HANDLE h = event;
+
+ if (eloop.events == NULL || eloop.event_count == 0 ||
+ event_size != sizeof(HANDLE))
+ return;
+
+ for (i = 0; i < eloop.event_count; i++) {
+ if (eloop.events[i].event == h)
+ break;
+ }
+ if (i == eloop.event_count)
+ return;
+
+ if (i != eloop.event_count - 1) {
+ os_memmove(&eloop.events[i], &eloop.events[i + 1],
+ (eloop.event_count - i - 1) *
+ sizeof(struct eloop_event));
+ }
+ eloop.event_count--;
+}
+
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+ eloop_timeout_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *timeout, *tmp, *prev;
+
+ timeout = os_malloc(sizeof(*timeout));
+ if (timeout == NULL)
+ return -1;
+ os_get_time(&timeout->time);
+ timeout->time.sec += secs;
+ timeout->time.usec += usecs;
+ while (timeout->time.usec >= 1000000) {
+ timeout->time.sec++;
+ timeout->time.usec -= 1000000;
+ }
+ timeout->eloop_data = eloop_data;
+ timeout->user_data = user_data;
+ timeout->handler = handler;
+ timeout->next = NULL;
+
+ if (eloop.timeout == NULL) {
+ eloop.timeout = timeout;
+ return 0;
+ }
+
+ prev = NULL;
+ tmp = eloop.timeout;
+ while (tmp != NULL) {
+ if (os_time_before(&timeout->time, &tmp->time))
+ break;
+ prev = tmp;
+ tmp = tmp->next;
+ }
+
+ if (prev == NULL) {
+ timeout->next = eloop.timeout;
+ eloop.timeout = timeout;
+ } else {
+ timeout->next = prev->next;
+ prev->next = timeout;
+ }
+
+ return 0;
+}
+
+
+int eloop_cancel_timeout(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *timeout, *prev, *next;
+ int removed = 0;
+
+ prev = NULL;
+ timeout = eloop.timeout;
+ while (timeout != NULL) {
+ next = timeout->next;
+
+ if (timeout->handler == handler &&
+ (timeout->eloop_data == eloop_data ||
+ eloop_data == ELOOP_ALL_CTX) &&
+ (timeout->user_data == user_data ||
+ user_data == ELOOP_ALL_CTX)) {
+ if (prev == NULL)
+ eloop.timeout = next;
+ else
+ prev->next = next;
+ os_free(timeout);
+ removed++;
+ } else
+ prev = timeout;
+
+ timeout = next;
+ }
+
+ return removed;
+}
+
+
+int eloop_is_timeout_registered(eloop_timeout_handler handler,
+ void *eloop_data, void *user_data)
+{
+ struct eloop_timeout *tmp;
+
+ tmp = eloop.timeout;
+ while (tmp != NULL) {
+ if (tmp->handler == handler &&
+ tmp->eloop_data == eloop_data &&
+ tmp->user_data == user_data)
+ return 1;
+
+ tmp = tmp->next;
+ }
+
+ return 0;
+}
+
+
+/* TODO: replace with suitable signal handler */
+#if 0
+static void eloop_handle_signal(int sig)
+{
+ int i;
+
+ eloop.signaled++;
+ for (i = 0; i < eloop.signal_count; i++) {
+ if (eloop.signals[i].sig == sig) {
+ eloop.signals[i].signaled++;
+ break;
+ }
+ }
+}
+#endif
+
+
+static void eloop_process_pending_signals(void)
+{
+ int i;
+
+ if (eloop.signaled == 0)
+ return;
+ eloop.signaled = 0;
+
+ if (eloop.pending_terminate) {
+ eloop.pending_terminate = 0;
+ }
+
+ for (i = 0; i < eloop.signal_count; i++) {
+ if (eloop.signals[i].signaled) {
+ eloop.signals[i].signaled = 0;
+ eloop.signals[i].handler(eloop.signals[i].sig,
+ eloop.user_data,
+ eloop.signals[i].user_data);
+ }
+ }
+
+ if (eloop.term_signal.signaled) {
+ eloop.term_signal.signaled = 0;
+ eloop.term_signal.handler(eloop.term_signal.sig,
+ eloop.user_data,
+ eloop.term_signal.user_data);
+ }
+}
+
+
+int eloop_register_signal(int sig, eloop_signal_handler handler,
+ void *user_data)
+{
+ struct eloop_signal *tmp;
+
+ tmp = os_realloc(eloop.signals,
+ (eloop.signal_count + 1) *
+ sizeof(struct eloop_signal));
+ if (tmp == NULL)
+ return -1;
+
+ tmp[eloop.signal_count].sig = sig;
+ tmp[eloop.signal_count].user_data = user_data;
+ tmp[eloop.signal_count].handler = handler;
+ tmp[eloop.signal_count].signaled = 0;
+ eloop.signal_count++;
+ eloop.signals = tmp;
+
+ /* TODO: register signal handler */
+
+ return 0;
+}
+
+
+#ifndef _WIN32_WCE
+static BOOL eloop_handle_console_ctrl(DWORD type)
+{
+ switch (type) {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ eloop.signaled++;
+ eloop.term_signal.signaled++;
+ SetEvent(eloop.term_event);
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+#endif /* _WIN32_WCE */
+
+
+int eloop_register_signal_terminate(eloop_signal_handler handler,
+ void *user_data)
+{
+#ifndef _WIN32_WCE
+ if (SetConsoleCtrlHandler((PHANDLER_ROUTINE) eloop_handle_console_ctrl,
+ TRUE) == 0) {
+ printf("SetConsoleCtrlHandler() failed: %d\n",
+ (int) GetLastError());
+ return -1;
+ }
+#endif /* _WIN32_WCE */
+
+ eloop.term_signal.handler = handler;
+ eloop.term_signal.user_data = user_data;
+
+ return 0;
+}
+
+
+int eloop_register_signal_reconfig(eloop_signal_handler handler,
+ void *user_data)
+{
+ /* TODO */
+ return 0;
+}
+
+
+void eloop_run(void)
+{
+ struct os_time tv, now;
+ DWORD count, ret, timeout, err;
+ size_t i;
+
+ while (!eloop.terminate &&
+ (eloop.timeout || eloop.reader_count > 0 ||
+ eloop.event_count > 0)) {
+ tv.sec = tv.usec = 0;
+ if (eloop.timeout) {
+ os_get_time(&now);
+ if (os_time_before(&now, &eloop.timeout->time))
+ os_time_sub(&eloop.timeout->time, &now, &tv);
+ }
+
+ count = 0;
+ for (i = 0; i < eloop.event_count; i++)
+ eloop.handles[count++] = eloop.events[i].event;
+
+ for (i = 0; i < eloop.reader_count; i++)
+ eloop.handles[count++] = eloop.readers[i].event;
+
+ if (eloop.term_event)
+ eloop.handles[count++] = eloop.term_event;
+
+ if (eloop.timeout)
+ timeout = tv.sec * 1000 + tv.usec / 1000;
+ else
+ timeout = INFINITE;
+
+ if (count > MAXIMUM_WAIT_OBJECTS) {
+ printf("WaitForMultipleObjects: Too many events: "
+ "%d > %d (ignoring extra events)\n",
+ (int) count, MAXIMUM_WAIT_OBJECTS);
+ count = MAXIMUM_WAIT_OBJECTS;
+ }
+#ifdef _WIN32_WCE
+ ret = WaitForMultipleObjects(count, eloop.handles, FALSE,
+ timeout);
+#else /* _WIN32_WCE */
+ ret = WaitForMultipleObjectsEx(count, eloop.handles, FALSE,
+ timeout, TRUE);
+#endif /* _WIN32_WCE */
+ err = GetLastError();
+
+ eloop_process_pending_signals();
+
+ /* check if some registered timeouts have occurred */
+ if (eloop.timeout) {
+ struct eloop_timeout *tmp;
+
+ os_get_time(&now);
+ if (!os_time_before(&now, &eloop.timeout->time)) {
+ tmp = eloop.timeout;
+ eloop.timeout = eloop.timeout->next;
+ tmp->handler(tmp->eloop_data,
+ tmp->user_data);
+ os_free(tmp);
+ }
+
+ }
+
+ if (ret == WAIT_FAILED) {
+ printf("WaitForMultipleObjects(count=%d) failed: %d\n",
+ (int) count, (int) err);
+ os_sleep(1, 0);
+ continue;
+ }
+
+#ifndef _WIN32_WCE
+ if (ret == WAIT_IO_COMPLETION)
+ continue;
+#endif /* _WIN32_WCE */
+
+ if (ret == WAIT_TIMEOUT)
+ continue;
+
+ while (ret >= WAIT_OBJECT_0 &&
+ ret < WAIT_OBJECT_0 + eloop.event_count) {
+ eloop.events[ret].handler(
+ eloop.events[ret].eloop_data,
+ eloop.events[ret].user_data);
+ ret = WaitForMultipleObjects(eloop.event_count,
+ eloop.handles, FALSE, 0);
+ }
+
+ eloop.reader_table_changed = 0;
+ for (i = 0; i < eloop.reader_count; i++) {
+ WSANETWORKEVENTS events;
+ if (WSAEnumNetworkEvents(eloop.readers[i].sock,
+ eloop.readers[i].event,
+ &events) == 0 &&
+ (events.lNetworkEvents & FD_READ)) {
+ eloop.readers[i].handler(
+ eloop.readers[i].sock,
+ eloop.readers[i].eloop_data,
+ eloop.readers[i].user_data);
+ if (eloop.reader_table_changed)
+ break;
+ }
+ }
+ }
+}
+
+
+void eloop_terminate(void)
+{
+ eloop.terminate = 1;
+ SetEvent(eloop.term_event);
+}
+
+
+void eloop_destroy(void)
+{
+ struct eloop_timeout *timeout, *prev;
+
+ timeout = eloop.timeout;
+ while (timeout != NULL) {
+ prev = timeout;
+ timeout = timeout->next;
+ os_free(prev);
+ }
+ os_free(eloop.readers);
+ os_free(eloop.signals);
+ if (eloop.term_event)
+ CloseHandle(eloop.term_event);
+ os_free(eloop.handles);
+ eloop.handles = NULL;
+ os_free(eloop.events);
+ eloop.events = NULL;
+}
+
+
+int eloop_terminated(void)
+{
+ return eloop.terminate;
+}
+
+
+void eloop_wait_for_read_sock(int sock)
+{
+ WSAEVENT event;
+
+ event = WSACreateEvent();
+ if (event == WSA_INVALID_EVENT) {
+ printf("WSACreateEvent() failed: %d\n", WSAGetLastError());
+ return;
+ }
+
+ if (WSAEventSelect(sock, event, FD_READ)) {
+ printf("WSAEventSelect() failed: %d\n", WSAGetLastError());
+ WSACloseEvent(event);
+ return ;
+ }
+
+ WaitForSingleObject(event, INFINITE);
+ WSAEventSelect(sock, event, 0);
+ WSACloseEvent(event);
+}
+
+
+void * eloop_get_user_data(void)
+{
+ return eloop.user_data;
+}
diff --git a/src/utils/os_none.c b/src/utils/os_none.c
new file mode 100644
index 0000000..bab8f17
--- /dev/null
+++ b/src/utils/os_none.c
@@ -0,0 +1,226 @@
+/*
+ * wpa_supplicant/hostapd / Empty OS specific functions
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This file can be used as a starting point when adding a new OS target. The
+ * functions here do not really work as-is since they are just empty or only
+ * return an error value. os_internal.c can be used as another starting point
+ * or reference since it has example implementation of many of these functions.
+ */
+
+#include "includes.h"
+
+#include "os.h"
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+}
+
+
+int os_get_time(struct os_time *t)
+{
+ return -1;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+ os_time_t *t)
+{
+ return -1;
+}
+
+
+int os_daemonize(const char *pid_file)
+{
+ return -1;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+ return -1;
+}
+
+
+unsigned long os_random(void)
+{
+ return 0;
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+ return NULL; /* strdup(rel_path) can be used here */
+}
+
+
+int os_program_init(void)
+{
+ return 0;
+}
+
+
+void os_program_deinit(void)
+{
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+ return -1;
+}
+
+
+int os_unsetenv(const char *name)
+{
+ return -1;
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+ return NULL;
+}
+
+
+void * os_zalloc(size_t size)
+{
+ return NULL;
+}
+
+
+#ifdef OS_NO_C_LIB_DEFINES
+void * os_malloc(size_t size)
+{
+ return NULL;
+}
+
+
+void * os_realloc(void *ptr, size_t size)
+{
+ return NULL;
+}
+
+
+void os_free(void *ptr)
+{
+}
+
+
+void * os_memcpy(void *dest, const void *src, size_t n)
+{
+ return dest;
+}
+
+
+void * os_memmove(void *dest, const void *src, size_t n)
+{
+ return dest;
+}
+
+
+void * os_memset(void *s, int c, size_t n)
+{
+ return s;
+}
+
+
+int os_memcmp(const void *s1, const void *s2, size_t n)
+{
+ return 0;
+}
+
+
+char * os_strdup(const char *s)
+{
+ return NULL;
+}
+
+
+size_t os_strlen(const char *s)
+{
+ return 0;
+}
+
+
+int os_strcasecmp(const char *s1, const char *s2)
+{
+ /*
+ * Ignoring case is not required for main functionality, so just use
+ * the case sensitive version of the function.
+ */
+ return os_strcmp(s1, s2);
+}
+
+
+int os_strncasecmp(const char *s1, const char *s2, size_t n)
+{
+ /*
+ * Ignoring case is not required for main functionality, so just use
+ * the case sensitive version of the function.
+ */
+ return os_strncmp(s1, s2, n);
+}
+
+
+char * os_strchr(const char *s, int c)
+{
+ return NULL;
+}
+
+
+char * os_strrchr(const char *s, int c)
+{
+ return NULL;
+}
+
+
+int os_strcmp(const char *s1, const char *s2)
+{
+ return 0;
+}
+
+
+int os_strncmp(const char *s1, const char *s2, size_t n)
+{
+ return 0;
+}
+
+
+char * os_strncpy(char *dest, const char *src, size_t n)
+{
+ return dest;
+}
+
+
+size_t os_strlcpy(char *dest, const char *src, size_t size)
+{
+ return 0;
+}
+
+
+char * os_strstr(const char *haystack, const char *needle)
+{
+ return NULL;
+}
+
+
+int os_snprintf(char *str, size_t size, const char *format, ...)
+{
+ return 0;
+}
+#endif /* OS_NO_C_LIB_DEFINES */
diff --git a/src/utils/os_unix.c b/src/utils/os_unix.c
index 060892d..bc2fc40 100644
--- a/src/utils/os_unix.c
+++ b/src/utils/os_unix.c
@@ -227,7 +227,8 @@ int os_setenv(const char *name, const char *value, int overwrite)
int os_unsetenv(const char *name)
{
-#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__)
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__APPLE__) || \
+ defined(__OpenBSD__)
unsetenv(name);
return 0;
#else
diff --git a/src/utils/os_win32.c b/src/utils/os_win32.c
new file mode 100644
index 0000000..0740964
--- /dev/null
+++ b/src/utils/os_win32.c
@@ -0,0 +1,222 @@
+/*
+ * wpa_supplicant/hostapd / OS specific functions for Win32 systems
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+#include <winsock2.h>
+#include <wincrypt.h>
+
+#include "os.h"
+
+void os_sleep(os_time_t sec, os_time_t usec)
+{
+ if (sec)
+ Sleep(sec * 1000);
+ if (usec)
+ Sleep(usec / 1000);
+}
+
+
+int os_get_time(struct os_time *t)
+{
+#define EPOCHFILETIME (116444736000000000ULL)
+ FILETIME ft;
+ LARGE_INTEGER li;
+ ULONGLONG tt;
+
+#ifdef _WIN32_WCE
+ SYSTEMTIME st;
+
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+#else /* _WIN32_WCE */
+ GetSystemTimeAsFileTime(&ft);
+#endif /* _WIN32_WCE */
+ li.LowPart = ft.dwLowDateTime;
+ li.HighPart = ft.dwHighDateTime;
+ tt = (li.QuadPart - EPOCHFILETIME) / 10;
+ t->sec = (os_time_t) (tt / 1000000);
+ t->usec = (os_time_t) (tt % 1000000);
+
+ return 0;
+}
+
+
+int os_mktime(int year, int month, int day, int hour, int min, int sec,
+ os_time_t *t)
+{
+ struct tm tm, *tm1;
+ time_t t_local, t1, t2;
+ os_time_t tz_offset;
+
+ if (year < 1970 || month < 1 || month > 12 || day < 1 || day > 31 ||
+ hour < 0 || hour > 23 || min < 0 || min > 59 || sec < 0 ||
+ sec > 60)
+ return -1;
+
+ memset(&tm, 0, sizeof(tm));
+ tm.tm_year = year - 1900;
+ tm.tm_mon = month - 1;
+ tm.tm_mday = day;
+ tm.tm_hour = hour;
+ tm.tm_min = min;
+ tm.tm_sec = sec;
+
+ t_local = mktime(&tm);
+
+ /* figure out offset to UTC */
+ tm1 = localtime(&t_local);
+ if (tm1) {
+ t1 = mktime(tm1);
+ tm1 = gmtime(&t_local);
+ if (tm1) {
+ t2 = mktime(tm1);
+ tz_offset = t2 - t1;
+ } else
+ tz_offset = 0;
+ } else
+ tz_offset = 0;
+
+ *t = (os_time_t) t_local - tz_offset;
+ return 0;
+}
+
+
+int os_daemonize(const char *pid_file)
+{
+ /* TODO */
+ return -1;
+}
+
+
+void os_daemonize_terminate(const char *pid_file)
+{
+}
+
+
+int os_get_random(unsigned char *buf, size_t len)
+{
+ HCRYPTPROV prov;
+ BOOL ret;
+
+ if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT))
+ return -1;
+
+ ret = CryptGenRandom(prov, len, buf);
+ CryptReleaseContext(prov, 0);
+
+ return ret ? 0 : -1;
+}
+
+
+unsigned long os_random(void)
+{
+ return rand();
+}
+
+
+char * os_rel2abs_path(const char *rel_path)
+{
+ return _strdup(rel_path);
+}
+
+
+int os_program_init(void)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+ WSADATA wsaData;
+ if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
+ printf("Could not find a usable WinSock.dll\n");
+ return -1;
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+ return 0;
+}
+
+
+void os_program_deinit(void)
+{
+#ifdef CONFIG_NATIVE_WINDOWS
+ WSACleanup();
+#endif /* CONFIG_NATIVE_WINDOWS */
+}
+
+
+int os_setenv(const char *name, const char *value, int overwrite)
+{
+ return -1;
+}
+
+
+int os_unsetenv(const char *name)
+{
+ return -1;
+}
+
+
+char * os_readfile(const char *name, size_t *len)
+{
+ FILE *f;
+ char *buf;
+
+ f = fopen(name, "rb");
+ if (f == NULL)
+ return NULL;
+
+ fseek(f, 0, SEEK_END);
+ *len = ftell(f);
+ fseek(f, 0, SEEK_SET);
+
+ buf = malloc(*len);
+ if (buf == NULL) {
+ fclose(f);
+ return NULL;
+ }
+
+ fread(buf, 1, *len, f);
+ fclose(f);
+
+ return buf;
+}
+
+
+void * os_zalloc(size_t size)
+{
+ return calloc(1, size);
+}
+
+
+size_t os_strlcpy(char *dest, const char *src, size_t siz)
+{
+ const char *s = src;
+ size_t left = siz;
+
+ if (left) {
+ /* Copy string up to the maximum size of the dest buffer */
+ while (--left != 0) {
+ if ((*dest++ = *s++) == '\0')
+ break;
+ }
+ }
+
+ if (left == 0) {
+ /* Not enough room for the string; force NUL-termination */
+ if (siz != 0)
+ *dest = '\0';
+ while (*s++)
+ ; /* determine total src string length */
+ }
+
+ return s - src - 1;
+}
diff --git a/src/utils/wpa_debug.c b/src/utils/wpa_debug.c
index e17cf06..4dd0732 100644
--- a/src/utils/wpa_debug.c
+++ b/src/utils/wpa_debug.c
@@ -56,7 +56,7 @@ void wpa_debug_print_timestamp(void)
*
* Note: New line '\n' is added to the end of the text when printing to stdout.
*/
-void wpa_printf(int level, char *fmt, ...)
+void wpa_printf(int level, const char *fmt, ...)
{
va_list ap;
@@ -267,7 +267,7 @@ void wpa_msg_register_cb(wpa_msg_cb_func func)
}
-void wpa_msg(void *ctx, int level, char *fmt, ...)
+void wpa_msg(void *ctx, int level, const char *fmt, ...)
{
va_list ap;
char *buf;
@@ -288,6 +288,30 @@ void wpa_msg(void *ctx, int level, char *fmt, ...)
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 */
diff --git a/src/utils/wpa_debug.h b/src/utils/wpa_debug.h
index 2d23f06..b4010d5 100644
--- a/src/utils/wpa_debug.h
+++ b/src/utils/wpa_debug.h
@@ -60,7 +60,7 @@ void wpa_debug_print_timestamp(void);
*
* Note: New line '\n' is added to the end of the text when printing to stdout.
*/
-void wpa_printf(int level, char *fmt, ...)
+void wpa_printf(int level, const char *fmt, ...)
PRINTF_FORMAT(2, 3);
/**
@@ -141,6 +141,7 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
#ifdef CONFIG_NO_WPA_MSG
#define wpa_msg(args...) do { } while (0)
+#define wpa_msg_ctrl(args...) do { } while (0)
#define wpa_msg_register_cb(f) do { } while (0)
#else /* CONFIG_NO_WPA_MSG */
/**
@@ -157,7 +158,22 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
*
* Note: New line '\n' is added to the end of the text when printing to stdout.
*/
-void wpa_msg(void *ctx, int level, char *fmt, ...) PRINTF_FORMAT(3, 4);
+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);
diff --git a/src/utils/wpabuf.c b/src/utils/wpabuf.c
index c544179..8181912 100644
--- a/src/utils/wpabuf.c
+++ b/src/utils/wpabuf.c
@@ -29,6 +29,10 @@ static void wpabuf_overflow(const struct wpabuf *buf, size_t len)
int wpabuf_resize(struct wpabuf **_buf, size_t add_len)
{
struct wpabuf *buf = *_buf;
+ if (buf == NULL) {
+ *_buf = wpabuf_alloc(add_len);
+ return *_buf == NULL ? -1 : 0;
+ }
if (buf->used + add_len > buf->size) {
unsigned char *nbuf;
if (buf->ext_data) {
diff --git a/src/wps/.gitignore b/src/wps/.gitignore
deleted file mode 100644
index a438335..0000000
--- a/src/wps/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-*.d
diff --git a/src/wps/httpread.c b/src/wps/httpread.c
index 313b468..0d7165e 100644
--- a/src/wps/httpread.c
+++ b/src/wps/httpread.c
@@ -206,7 +206,8 @@ static int httpread_hdr_option_analyze(
h->got_content_length = 1;
return 0;
}
- if (word_eq(hbp, "TRANSFER_ENCODING:")) {
+ if (word_eq(hbp, "TRANSFER_ENCODING:") ||
+ word_eq(hbp, "TRANSFER-ENCODING:")) {
while (isgraph(*hbp))
hbp++;
while (*hbp == ' ' || *hbp == '\t')
@@ -214,7 +215,7 @@ static int httpread_hdr_option_analyze(
/* There should (?) be no encodings of interest
* other than chunked...
*/
- if (os_strncmp(hbp, "CHUNKED", 7)) {
+ if (word_eq(hbp, "CHUNKED")) {
h->chunked = 1;
h->in_chunk_data = 0;
/* ignore possible ;<parameters> */
@@ -513,6 +514,8 @@ static void httpread_read_handler(int sd, void *eloop_ctx, void *sock_ctx)
* consists of chunks each with a header, ending with
* an ending header.
*/
+ if (nread == 0)
+ goto get_more;
if (!h->got_body) {
/* Here to get (more of) body */
/* ensure we have enough room for worst case for body
diff --git a/src/wps/wps.h b/src/wps/wps.h
index e0f2b2d..faf32c4 100644
--- a/src/wps/wps.h
+++ b/src/wps/wps.h
@@ -42,7 +42,7 @@ struct upnp_wps_device_sm;
* @key_idx: Key index
* @key: Key
* @key_len: Key length in octets
- * @mac_addr: MAC address of the peer
+ * @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
@@ -266,6 +266,11 @@ struct wps_registrar_config {
* 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;
};
@@ -291,7 +296,17 @@ enum wps_event {
/**
* WPS_EV_PWD_AUTH_FAIL - Password authentication failed
*/
- WPS_EV_PWD_AUTH_FAIL
+ 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
};
/**
@@ -500,7 +515,7 @@ wps_registrar_init(struct wps_context *wps,
const struct wps_registrar_config *cfg);
void wps_registrar_deinit(struct wps_registrar *reg);
int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
- const u8 *pin, size_t pin_len);
+ const u8 *pin, size_t pin_len, int timeout);
int wps_registrar_invalidate_pin(struct wps_registrar *reg, const u8 *uuid);
int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid);
int wps_registrar_button_pushed(struct wps_registrar *reg);
diff --git a/src/wps/wps_attr_parse.c b/src/wps/wps_attr_parse.c
index 25ff251..f50ae39 100644
--- a/src/wps/wps_attr_parse.c
+++ b/src/wps/wps_attr_parse.c
@@ -381,6 +381,14 @@ static int wps_set_attr(struct wps_parse_attr *attr, u16 type,
attr->eap_identity = pos;
attr->eap_identity_len = len;
break;
+ case ATTR_AP_SETUP_LOCKED:
+ if (len != 1) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid AP Setup Locked "
+ "length %u", len);
+ return -1;
+ }
+ attr->ap_setup_locked = pos;
+ break;
default:
wpa_printf(MSG_DEBUG, "WPS: Unsupported attribute type 0x%x "
"len=%u", type, len);
diff --git a/src/wps/wps_common.c b/src/wps/wps_common.c
index 48af303..4b45f00 100644
--- a/src/wps/wps_common.c
+++ b/src/wps/wps_common.c
@@ -128,56 +128,6 @@ int wps_derive_keys(struct wps_data *wps)
}
-int wps_derive_mgmt_keys(struct wps_data *wps)
-{
- u8 nonces[2 * WPS_NONCE_LEN];
- u8 keys[WPS_MGMTAUTHKEY_LEN + WPS_MGMTENCKEY_LEN];
- u8 hash[SHA256_MAC_LEN];
- const u8 *addr[2];
- size_t len[2];
- const char *auth_label = "WFA-WLAN-Management-MgmtAuthKey";
- const char *enc_label = "WFA-WLAN-Management-MgmtEncKey";
-
- /* MgmtAuthKey || MgmtEncKey =
- * kdf(EMSK, N1 || N2 || "WFA-WLAN-Management-Keys", 384) */
- os_memcpy(nonces, wps->nonce_e, WPS_NONCE_LEN);
- os_memcpy(nonces + WPS_NONCE_LEN, wps->nonce_r, WPS_NONCE_LEN);
- wps_kdf(wps->emsk, nonces, sizeof(nonces), "WFA-WLAN-Management-Keys",
- keys, sizeof(keys));
- os_memcpy(wps->mgmt_auth_key, keys, WPS_MGMTAUTHKEY_LEN);
- os_memcpy(wps->mgmt_enc_key, keys + WPS_MGMTAUTHKEY_LEN,
- WPS_MGMTENCKEY_LEN);
-
- addr[0] = nonces;
- len[0] = sizeof(nonces);
-
- /* MgmtEncKeyID = first 128 bits of
- * SHA-256(N1 || N2 || "WFA-WLAN-Management-MgmtAuthKey") */
- addr[1] = (const u8 *) auth_label;
- len[1] = os_strlen(auth_label);
- sha256_vector(2, addr, len, hash);
- os_memcpy(wps->mgmt_auth_key_id, hash, WPS_MGMT_KEY_ID_LEN);
-
- /* MgmtEncKeyID = first 128 bits of
- * SHA-256(N1 || N2 || "WFA-WLAN-Management-MgmtEncKey") */
- addr[1] = (const u8 *) enc_label;
- len[1] = os_strlen(enc_label);
- sha256_vector(2, addr, len, hash);
- os_memcpy(wps->mgmt_enc_key_id, hash, WPS_MGMT_KEY_ID_LEN);
-
- wpa_hexdump_key(MSG_DEBUG, "WPS: MgmtAuthKey",
- wps->mgmt_auth_key, WPS_MGMTAUTHKEY_LEN);
- wpa_hexdump(MSG_DEBUG, "WPS: MgmtAuthKeyID",
- wps->mgmt_auth_key_id, WPS_MGMT_KEY_ID_LEN);
- wpa_hexdump_key(MSG_DEBUG, "WPS: MgmtEncKey",
- wps->mgmt_enc_key, WPS_MGMTENCKEY_LEN);
- wpa_hexdump(MSG_DEBUG, "WPS: MgmtEncKeyID",
- wps->mgmt_enc_key_id, WPS_MGMT_KEY_ID_LEN);
-
- return 0;
-}
-
-
void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
size_t dev_passwd_len)
{
@@ -335,3 +285,21 @@ void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part)
data.pwd_auth_fail.part = part;
wps->event_cb(wps->cb_ctx, WPS_EV_PWD_AUTH_FAIL, &data);
}
+
+
+void wps_pbc_overlap_event(struct wps_context *wps)
+{
+ if (wps->event_cb == NULL)
+ return;
+
+ wps->event_cb(wps->cb_ctx, WPS_EV_PBC_OVERLAP, NULL);
+}
+
+
+void wps_pbc_timeout_event(struct wps_context *wps)
+{
+ if (wps->event_cb == NULL)
+ return;
+
+ wps->event_cb(wps->cb_ctx, WPS_EV_PBC_TIMEOUT, NULL);
+}
diff --git a/src/wps/wps_enrollee.c b/src/wps/wps_enrollee.c
index 179f7db..5cb3e1e 100644
--- a/src/wps/wps_enrollee.c
+++ b/src/wps/wps_enrollee.c
@@ -41,7 +41,7 @@ static int wps_build_wps_state(struct wps_data *wps, struct wpabuf *msg)
state);
wpabuf_put_be16(msg, ATTR_WPS_STATE);
wpabuf_put_be16(msg, 1);
- wpabuf_put_u8(msg, WPS_STATE_NOT_CONFIGURED);
+ wpabuf_put_u8(msg, state);
return 0;
}
@@ -521,10 +521,6 @@ static int wps_process_pubkey(struct wps_data *wps, const u8 *pk,
if (wps_derive_keys(wps) < 0)
return -1;
- if (wps->request_type == WPS_REQ_WLAN_MANAGER_REGISTRAR &&
- wps_derive_mgmt_keys(wps) < 0)
- return -1;
-
return 0;
}
@@ -650,6 +646,21 @@ static int wps_process_cred_e(struct wps_data *wps, const u8 *cred,
wps_process_cred(&attr, &wps->cred))
return -1;
+ if (os_memcmp(wps->cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) !=
+ 0) {
+ wpa_printf(MSG_DEBUG, "WPS: MAC Address in the Credential ("
+ MACSTR ") does not match with own address (" MACSTR
+ ")", MAC2STR(wps->cred.mac_addr),
+ MAC2STR(wps->wps->dev.mac_addr));
+ /*
+ * In theory, this could be consider fatal error, but there are
+ * number of deployed implementations using other address here
+ * due to unclarity in the specification. For interoperability
+ * reasons, allow this to be processed since we do not really
+ * use the MAC Address information for anything.
+ */
+ }
+
if (wps->wps->cred_cb) {
wps->cred.cred_attr = cred - 4;
wps->cred.cred_attr_len = cred_len + 4;
@@ -700,6 +711,21 @@ static int wps_process_ap_settings_e(struct wps_data *wps,
wpa_printf(MSG_INFO, "WPS: Received new AP configuration from "
"Registrar");
+ if (os_memcmp(cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN) !=
+ 0) {
+ wpa_printf(MSG_DEBUG, "WPS: MAC Address in the AP Settings ("
+ MACSTR ") does not match with own address (" MACSTR
+ ")", MAC2STR(cred.mac_addr),
+ MAC2STR(wps->wps->dev.mac_addr));
+ /*
+ * In theory, this could be consider fatal error, but there are
+ * number of deployed implementations using other address here
+ * due to unclarity in the specification. For interoperability
+ * reasons, allow this to be processed since we do not really
+ * use the MAC Address information for anything.
+ */
+ }
+
if (wps->wps->cred_cb) {
cred.cred_attr = wpabuf_head(attrs);
cred.cred_attr_len = wpabuf_len(attrs);
@@ -1159,6 +1185,17 @@ enum wps_process_res wps_enrollee_process_msg(struct wps_data *wps,
"op_code=%d)",
(unsigned long) wpabuf_len(msg), op_code);
+ if (op_code == WSC_UPnP) {
+ /* Determine the OpCode based on message type attribute */
+ struct wps_parse_attr attr;
+ if (wps_parse_msg(msg, &attr) == 0 && attr.msg_type) {
+ if (*attr.msg_type == WPS_WSC_ACK)
+ op_code = WSC_ACK;
+ else if (*attr.msg_type == WPS_WSC_NACK)
+ op_code = WSC_NACK;
+ }
+ }
+
switch (op_code) {
case WSC_MSG:
case WSC_UPnP:
diff --git a/src/wps/wps_i.h b/src/wps/wps_i.h
index 85adf28..3317a2c 100644
--- a/src/wps/wps_i.h
+++ b/src/wps/wps_i.h
@@ -62,10 +62,6 @@ struct wps_data {
u8 authkey[WPS_AUTHKEY_LEN];
u8 keywrapkey[WPS_KEYWRAPKEY_LEN];
u8 emsk[WPS_EMSK_LEN];
- u8 mgmt_auth_key[WPS_MGMTAUTHKEY_LEN];
- u8 mgmt_auth_key_id[WPS_MGMT_KEY_ID_LEN];
- u8 mgmt_enc_key[WPS_MGMTENCKEY_LEN];
- u8 mgmt_enc_key_id[WPS_MGMT_KEY_ID_LEN];
struct wpabuf *last_msg;
@@ -146,6 +142,7 @@ struct wps_parse_attr {
const u8 *selected_registrar; /* 1 octet (Bool) */
const u8 *request_type; /* 1 octet */
const u8 *response_type; /* 1 octet */
+ const u8 *ap_setup_locked; /* 1 octet */
/* variable length fields */
const u8 *manufacturer;
@@ -182,7 +179,6 @@ struct wps_parse_attr {
void wps_kdf(const u8 *key, const u8 *label_prefix, size_t label_prefix_len,
const char *label, u8 *res, size_t res_len);
int wps_derive_keys(struct wps_data *wps);
-int wps_derive_mgmt_keys(struct wps_data *wps);
void wps_derive_psk(struct wps_data *wps, const u8 *dev_passwd,
size_t dev_passwd_len);
struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
@@ -190,6 +186,8 @@ struct wpabuf * wps_decrypt_encr_settings(struct wps_data *wps, const u8 *encr,
void wps_fail_event(struct wps_context *wps, enum wps_msg_type msg);
void wps_success_event(struct wps_context *wps);
void wps_pwd_auth_fail_event(struct wps_context *wps, int enrollee, int part);
+void wps_pbc_overlap_event(struct wps_context *wps);
+void wps_pbc_timeout_event(struct wps_context *wps);
/* wps_attr_parse.c */
int wps_parse_msg(const struct wpabuf *msg, struct wps_parse_attr *attr);
diff --git a/src/wps/wps_registrar.c b/src/wps/wps_registrar.c
index f7eebdd..f34c9e9 100644
--- a/src/wps/wps_registrar.c
+++ b/src/wps/wps_registrar.c
@@ -23,6 +23,7 @@
#include "wps_dev_attr.h"
#include "wps_upnp.h"
+#define WPS_WORKAROUNDS
struct wps_uuid_pin {
struct wps_uuid_pin *next;
@@ -30,7 +31,10 @@ struct wps_uuid_pin {
int wildcard_uuid;
u8 *pin;
size_t pin_len;
- int locked;
+#define PIN_LOCKED BIT(0)
+#define PIN_EXPIRES BIT(1)
+ int flags;
+ struct os_time expiration;
};
@@ -98,6 +102,9 @@ struct wps_registrar {
int disable_auto_conf;
int sel_reg_dev_password_id_override;
int sel_reg_config_methods_override;
+ int static_wep_only;
+
+ int force_pbc_overlap;
};
@@ -376,6 +383,7 @@ wps_registrar_init(struct wps_context *wps,
reg->disable_auto_conf = cfg->disable_auto_conf;
reg->sel_reg_dev_password_id_override = -1;
reg->sel_reg_config_methods_override = -1;
+ reg->static_wep_only = cfg->static_wep_only;
if (wps_set_ie(reg)) {
wps_registrar_deinit(reg);
@@ -409,10 +417,11 @@ void wps_registrar_deinit(struct wps_registrar *reg)
* @uuid: UUID-E or %NULL for wildcard (any UUID)
* @pin: PIN (Device Password)
* @pin_len: Length of pin in octets
+ * @timeout: Time (in seconds) when the PIN will be invalidated; 0 = no timeout
* Returns: 0 on success, -1 on failure
*/
int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
- const u8 *pin, size_t pin_len)
+ const u8 *pin, size_t pin_len, int timeout)
{
struct wps_uuid_pin *p;
@@ -431,20 +440,59 @@ int wps_registrar_add_pin(struct wps_registrar *reg, const u8 *uuid,
os_memcpy(p->pin, pin, pin_len);
p->pin_len = pin_len;
+ if (timeout) {
+ p->flags |= PIN_EXPIRES;
+ os_get_time(&p->expiration);
+ p->expiration.sec += timeout;
+ }
+
p->next = reg->pins;
reg->pins = p;
- wpa_printf(MSG_DEBUG, "WPS: A new PIN configured");
+ wpa_printf(MSG_DEBUG, "WPS: A new PIN configured (timeout=%d)",
+ timeout);
wpa_hexdump(MSG_DEBUG, "WPS: UUID", uuid, WPS_UUID_LEN);
wpa_hexdump_ascii_key(MSG_DEBUG, "WPS: PIN", pin, pin_len);
reg->selected_registrar = 1;
reg->pbc = 0;
wps_set_ie(reg);
+ eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
+ eloop_register_timeout(WPS_PBC_WALK_TIME, 0,
+ wps_registrar_set_selected_timeout,
+ reg, NULL);
return 0;
}
+static void wps_registrar_expire_pins(struct wps_registrar *reg)
+{
+ struct wps_uuid_pin *pin, *prev, *del;
+ struct os_time now;
+
+ os_get_time(&now);
+ prev = NULL;
+ pin = reg->pins;
+ while (pin) {
+ if ((pin->flags & PIN_EXPIRES) &&
+ os_time_before(&pin->expiration, &now)) {
+ if (prev == NULL)
+ reg->pins = pin->next;
+ else
+ prev->next = pin->next;
+ del = pin;
+ pin = pin->next;
+ wpa_hexdump(MSG_DEBUG, "WPS: Expired PIN for UUID",
+ del->uuid, WPS_UUID_LEN);
+ wps_free_pin(del);
+ continue;
+ }
+ prev = pin;
+ pin = pin->next;
+ }
+}
+
+
/**
* wps_registrar_invalidate_pin - Invalidate a PIN for a specific UUID-E
* @reg: Registrar data from wps_registrar_init()
@@ -481,6 +529,8 @@ static const u8 * wps_registrar_get_pin(struct wps_registrar *reg,
{
struct wps_uuid_pin *pin;
+ wps_registrar_expire_pins(reg);
+
pin = reg->pins;
while (pin) {
if (!pin->wildcard_uuid &&
@@ -512,13 +562,13 @@ static const u8 * wps_registrar_get_pin(struct wps_registrar *reg,
* Lock the PIN to avoid attacks based on concurrent re-use of the PIN
* that could otherwise avoid PIN invalidations.
*/
- if (pin->locked) {
+ if (pin->flags & PIN_LOCKED) {
wpa_printf(MSG_DEBUG, "WPS: Selected PIN locked - do not "
"allow concurrent re-use");
return NULL;
}
*pin_len = pin->pin_len;
- pin->locked = 1;
+ pin->flags |= PIN_LOCKED;
return pin->pin;
}
@@ -545,7 +595,7 @@ int wps_registrar_unlock_pin(struct wps_registrar *reg, const u8 *uuid)
"wildcard PIN");
return wps_registrar_invalidate_pin(reg, uuid);
}
- pin->locked = 0;
+ pin->flags &= ~PIN_LOCKED;
return 0;
}
pin = pin->next;
@@ -568,6 +618,7 @@ static void wps_registrar_pbc_timeout(void *eloop_ctx, void *timeout_ctx)
struct wps_registrar *reg = eloop_ctx;
wpa_printf(MSG_DEBUG, "WPS: PBC timed out - disable PBC mode");
+ wps_pbc_timeout_event(reg->wps);
wps_registrar_stop_pbc(reg);
}
@@ -586,9 +637,11 @@ int wps_registrar_button_pushed(struct wps_registrar *reg)
if (wps_registrar_pbc_overlap(reg, NULL, NULL)) {
wpa_printf(MSG_DEBUG, "WPS: PBC overlap - do not start PBC "
"mode");
+ wps_pbc_overlap_event(reg->wps);
return -1;
}
wpa_printf(MSG_DEBUG, "WPS: Button pushed - PBC mode started");
+ reg->force_pbc_overlap = 0;
reg->selected_registrar = 1;
reg->pbc = 1;
wps_set_ie(reg);
@@ -607,6 +660,14 @@ static void wps_registrar_pbc_completed(struct wps_registrar *reg)
wps_registrar_stop_pbc(reg);
}
+static void wps_registrar_pin_completed(struct wps_registrar *reg)
+{
+ wpa_printf(MSG_DEBUG, "WPS: PIN completed using internal Registrar");
+ eloop_cancel_timeout(wps_registrar_set_selected_timeout, reg, NULL);
+ reg->selected_registrar = 0;
+ wps_set_ie(reg);
+}
+
/**
* wps_registrar_probe_req_rx - Notify Registrar of Probe Request
@@ -648,8 +709,18 @@ void wps_registrar_probe_req_rx(struct wps_registrar *reg, const u8 *addr,
wpa_printf(MSG_DEBUG, "WPS: Probe Request for PBC received from "
MACSTR, MAC2STR(addr));
+ if (attr.uuid_e == NULL) {
+ wpa_printf(MSG_DEBUG, "WPS: Invalid Probe Request WPS IE: No "
+ "UUID-E included");
+ return;
+ }
wps_registrar_add_pbc_session(reg, addr, attr.uuid_e);
+ if (wps_registrar_pbc_overlap(reg, addr, attr.uuid_e)) {
+ wpa_printf(MSG_DEBUG, "WPS: PBC session overlap detected");
+ reg->force_pbc_overlap = 1;
+ wps_pbc_overlap_event(reg->wps);
+ }
}
@@ -777,6 +848,28 @@ static int wps_set_ie(struct wps_registrar *reg)
return -1;
}
+ if (reg->static_wep_only) {
+ /*
+ * Windows XP and Vista clients can get confused about
+ * EAP-Identity/Request when they probe the network with
+ * EAPOL-Start. In such a case, they may assume the network is
+ * using IEEE 802.1X and prompt user for a certificate while
+ * the correct (non-WPS) behavior would be to ask for the
+ * static WEP key. As a workaround, use Microsoft Provisioning
+ * IE to advertise that legacy 802.1X is not supported.
+ */
+ const u8 ms_wps[7] = {
+ WLAN_EID_VENDOR_SPECIFIC, 5,
+ /* Microsoft Provisioning IE (00:50:f2:5) */
+ 0x00, 0x50, 0xf2, 5,
+ 0x00 /* no legacy 802.1X or MS WPS */
+ };
+ wpa_printf(MSG_DEBUG, "WPS: Add Microsoft Provisioning IE "
+ "into Beacon/Probe Response frames");
+ wpabuf_put_data(beacon, ms_wps, sizeof(ms_wps));
+ wpabuf_put_data(probe, ms_wps, sizeof(ms_wps));
+ }
+
ret = wps_cb_set_ie(reg, beacon, probe);
wpabuf_free(beacon);
wpabuf_free(probe);
@@ -1033,8 +1126,10 @@ static int wps_build_cred(struct wps_data *wps, struct wpabuf *msg)
}
}
wps->cred.encr_type = wps->encr_type;
- /* Set MAC address in the Credential to be the AP's address (BSSID) */
- os_memcpy(wps->cred.mac_addr, wps->wps->dev.mac_addr, ETH_ALEN);
+ /*
+ * Set MAC address in the Credential to be the Enrollee's MAC address
+ */
+ os_memcpy(wps->cred.mac_addr, wps->mac_addr_e, ETH_ALEN);
if (wps->wps->wps_state == WPS_STATE_NOT_CONFIGURED && wps->wps->ap &&
!wps->wps->registrar->disable_auto_conf) {
@@ -1159,14 +1254,15 @@ static struct wpabuf * wps_build_m2(struct wps_data *wps)
static struct wpabuf * wps_build_m2d(struct wps_data *wps)
{
struct wpabuf *msg;
- u16 err = WPS_CFG_NO_ERROR;
+ u16 err = wps->config_error;
wpa_printf(MSG_DEBUG, "WPS: Building Message M2D");
msg = wpabuf_alloc(1000);
if (msg == NULL)
return NULL;
- if (wps->wps->ap && wps->wps->ap_setup_locked)
+ if (wps->wps->ap && wps->wps->ap_setup_locked &&
+ err == WPS_CFG_NO_ERROR)
err = WPS_CFG_SETUP_LOCKED;
if (wps_build_version(msg) ||
@@ -1368,8 +1464,18 @@ struct wpabuf * wps_registrar_get_msg(struct wps_data *wps,
else
wps->wps->upnp_msgs = NULL;
msg = p->msg;
+ switch (p->type) {
+ case WPS_WSC_ACK:
+ *op_code = WSC_ACK;
+ break;
+ case WPS_WSC_NACK:
+ *op_code = WSC_NACK;
+ break;
+ default:
+ *op_code = WSC_MSG;
+ break;
+ }
os_free(p);
- *op_code = WSC_MSG;
if (wps->ext_reg == 0)
wps->ext_reg = 1;
return msg;
@@ -1654,7 +1760,21 @@ static int wps_process_auth_type_flags(struct wps_data *wps, const u8 *auth)
wpa_printf(MSG_DEBUG, "WPS: No match in supported "
"authentication types (own 0x%x Enrollee 0x%x)",
wps->wps->auth_types, auth_types);
+#ifdef WPS_WORKAROUNDS
+ /*
+ * Some deployed implementations seem to advertise incorrect
+ * information in this attribute. For example, Linksys WRT350N
+ * seems to have a byteorder bug that breaks this negotiation.
+ * In order to interoperate with existing implementations,
+ * assume that the Enrollee supports everything we do.
+ */
+ wpa_printf(MSG_DEBUG, "WPS: Workaround - assume Enrollee "
+ "does not advertise supported authentication types "
+ "correctly");
+ wps->auth_type = wps->wps->auth_types;
+#else /* WPS_WORKAROUNDS */
return -1;
+#endif /* WPS_WORKAROUNDS */
}
return 0;
@@ -1678,8 +1798,23 @@ static int wps_process_encr_type_flags(struct wps_data *wps, const u8 *encr)
wps->encr_type = wps->wps->encr_types & encr_types;
if (wps->encr_type == 0) {
wpa_printf(MSG_DEBUG, "WPS: No match in supported "
- "encryption types");
+ "encryption types (own 0x%x Enrollee 0x%x)",
+ wps->wps->encr_types, encr_types);
+#ifdef WPS_WORKAROUNDS
+ /*
+ * Some deployed implementations seem to advertise incorrect
+ * information in this attribute. For example, Linksys WRT350N
+ * seems to have a byteorder bug that breaks this negotiation.
+ * In order to interoperate with existing implementations,
+ * assume that the Enrollee supports everything we do.
+ */
+ wpa_printf(MSG_DEBUG, "WPS: Workaround - assume Enrollee "
+ "does not advertise supported encryption types "
+ "correctly");
+ wps->encr_type = wps->wps->encr_types;
+#else /* WPS_WORKAROUNDS */
return -1;
+#endif /* WPS_WORKAROUNDS */
}
return 0;
@@ -1806,11 +1941,15 @@ static enum wps_process_res wps_process_m1(struct wps_data *wps,
}
if (wps->dev_pw_id == DEV_PW_PUSHBUTTON) {
- if (wps_registrar_pbc_overlap(wps->wps->registrar,
+ if (wps->wps->registrar->force_pbc_overlap ||
+ wps_registrar_pbc_overlap(wps->wps->registrar,
wps->mac_addr_e, wps->uuid_e)) {
wpa_printf(MSG_DEBUG, "WPS: PBC overlap - deny PBC "
"negotiation");
wps->state = SEND_M2D;
+ wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
+ wps_pbc_overlap_event(wps->wps);
+ wps->wps->registrar->force_pbc_overlap = 1;
return WPS_CONTINUE;
}
wps_registrar_add_pbc_session(wps->wps->registrar,
@@ -1836,6 +1975,14 @@ static enum wps_process_res wps_process_m3(struct wps_data *wps,
return WPS_CONTINUE;
}
+ if (wps->pbc && wps->wps->registrar->force_pbc_overlap) {
+ wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
+ "session overlap");
+ wps->state = SEND_WSC_NACK;
+ wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
+ return WPS_CONTINUE;
+ }
+
if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
wps_process_authenticator(wps, attr->authenticator, msg) ||
wps_process_e_hash1(wps, attr->e_hash1) ||
@@ -1865,6 +2012,14 @@ static enum wps_process_res wps_process_m5(struct wps_data *wps,
return WPS_CONTINUE;
}
+ if (wps->pbc && wps->wps->registrar->force_pbc_overlap) {
+ wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
+ "session overlap");
+ wps->state = SEND_WSC_NACK;
+ wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
+ return WPS_CONTINUE;
+ }
+
if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
wps_process_authenticator(wps, attr->authenticator, msg)) {
wps->state = SEND_WSC_NACK;
@@ -1896,6 +2051,28 @@ static enum wps_process_res wps_process_m5(struct wps_data *wps,
}
+static void wps_sta_cred_cb(struct wps_data *wps)
+{
+ /*
+ * Update credential to only include a single authentication and
+ * encryption type in case the AP configuration includes more than one
+ * option.
+ */
+ if (wps->cred.auth_type & WPS_AUTH_WPA2PSK)
+ wps->cred.auth_type = WPS_AUTH_WPA2PSK;
+ else if (wps->cred.auth_type & WPS_AUTH_WPAPSK)
+ wps->cred.auth_type = WPS_AUTH_WPAPSK;
+ if (wps->cred.encr_type & WPS_ENCR_AES)
+ wps->cred.encr_type = WPS_ENCR_AES;
+ else if (wps->cred.encr_type & WPS_ENCR_TKIP)
+ wps->cred.encr_type = WPS_ENCR_TKIP;
+ wpa_printf(MSG_DEBUG, "WPS: Update local configuration based on the "
+ "AP configuration");
+ if (wps->wps->cred_cb)
+ wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
+}
+
+
static int wps_process_ap_settings_r(struct wps_data *wps,
struct wps_parse_attr *attr)
{
@@ -1908,12 +2085,21 @@ static int wps_process_ap_settings_r(struct wps_data *wps,
wpa_printf(MSG_INFO, "WPS: Received old AP configuration from AP");
+#if 0
/*
* TODO: Provide access to AP settings and allow changes before sending
* out M8. For now, just copy the settings unchanged into M8.
*/
return 0;
+#else
+ /*
+ * For now, use the AP PIN only to receive the current AP settings,
+ * not to reconfigure the AP.
+ */
+ wps_sta_cred_cb(wps);
+ return 1;
+#endif
}
@@ -1933,6 +2119,14 @@ static enum wps_process_res wps_process_m7(struct wps_data *wps,
return WPS_CONTINUE;
}
+ if (wps->pbc && wps->wps->registrar->force_pbc_overlap) {
+ wpa_printf(MSG_DEBUG, "WPS: Reject negotiation due to PBC "
+ "session overlap");
+ wps->state = SEND_WSC_NACK;
+ wps->config_error = WPS_CFG_MULTIPLE_PBC_DETECTED;
+ return WPS_CONTINUE;
+ }
+
if (wps_process_registrar_nonce(wps, attr->registrar_nonce) ||
wps_process_authenticator(wps, attr->authenticator, msg)) {
wps->state = SEND_WSC_NACK;
@@ -2281,12 +2475,8 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
wps->new_psk = NULL;
}
- if (!wps->wps->ap) {
- wpa_printf(MSG_DEBUG, "WPS: Update local configuration based "
- "on the modified AP configuration");
- if (wps->wps->cred_cb)
- wps->wps->cred_cb(wps->wps->cb_ctx, &wps->cred);
- }
+ if (!wps->wps->ap)
+ wps_sta_cred_cb(wps);
if (wps->new_psk) {
if (wps_cb_new_psk(wps->wps->registrar, wps->mac_addr_e,
@@ -2304,6 +2494,8 @@ static enum wps_process_res wps_process_wsc_done(struct wps_data *wps,
wps_registrar_remove_pbc_session(wps->wps->registrar,
wps->mac_addr_e, wps->uuid_e);
wps_registrar_pbc_completed(wps->wps->registrar);
+ } else {
+ wps_registrar_pin_completed(wps->wps->registrar);
}
wps_success_event(wps->wps);
@@ -2333,7 +2525,8 @@ enum wps_process_res wps_registrar_process_msg(struct wps_data *wps,
wps_registrar_free_pending_m2(wps->wps);
if (wps->wps->wps_upnp && wps->ext_reg &&
wps->wps->upnp_msgs == NULL &&
- (op_code == WSC_MSG || op_code == WSC_Done)) {
+ (op_code == WSC_MSG || op_code == WSC_Done || op_code == WSC_NACK))
+ {
struct wps_parse_attr attr;
int type;
if (wps_parse_msg(msg, &attr) < 0 || attr.msg_type == NULL)
@@ -2401,7 +2594,6 @@ static void wps_registrar_set_selected_timeout(void *eloop_ctx,
* wps_registrar_set_selected_registrar - Notification of SetSelectedRegistrar
* @reg: Registrar data from wps_registrar_init()
* @msg: Received message from SetSelectedRegistrar
- * @msg_len: Length of msg in octets
* Returns: 0 on success, -1 on failure
*
* This function is called when an AP receives a SetSelectedRegistrar UPnP
diff --git a/src/wps/wps_upnp.c b/src/wps/wps_upnp.c
index 6d2de0e..4c6aac2 100644
--- a/src/wps/wps_upnp.c
+++ b/src/wps/wps_upnp.c
@@ -47,9 +47,6 @@
* -- Needs renaming with module prefix to avoid polluting the debugger
* namespace and causing possible collisions with other static fncs
* and structure declarations when using the debugger.
- * -- Just what should be in the first event message sent after subscription
- * for the WLANEvent field? If i pass it empty, Vista replies with OK
- * but apparently barfs on the message.
* -- The http error code generation is pretty bogus, hopefully noone cares.
*
* Author: Ted Merrill, Atheros Communications, based upon earlier work
@@ -641,6 +638,27 @@ struct subscription * subscription_find(struct upnp_wps_device_sm *sm,
}
+static struct wpabuf * build_fake_wsc_ack(void)
+{
+ struct wpabuf *msg = wpabuf_alloc(100);
+ if (msg == NULL)
+ return NULL;
+ wpabuf_put_u8(msg, UPNP_WPS_WLANEVENT_TYPE_EAP);
+ wpabuf_put_str(msg, "00:00:00:00:00:00");
+ wps_build_version(msg);
+ wps_build_msg_type(msg, WPS_WSC_ACK);
+ /* Enrollee Nonce */
+ wpabuf_put_be16(msg, ATTR_ENROLLEE_NONCE);
+ wpabuf_put_be16(msg, WPS_NONCE_LEN);
+ wpabuf_put(msg, WPS_NONCE_LEN);
+ /* Registrar Nonce */
+ wpabuf_put_be16(msg, ATTR_REGISTRAR_NONCE);
+ wpabuf_put_be16(msg, WPS_NONCE_LEN);
+ wpabuf_put(msg, WPS_NONCE_LEN);
+ return msg;
+}
+
+
/* subscription_first_event -- send format/queue event that is automatically
* sent on a new subscription.
*/
@@ -665,6 +683,28 @@ static int subscription_first_event(struct subscription *s)
const char *tail = "</e:propertyset>\n";
char txt[10];
+ if (s->sm->wlanevent == NULL) {
+ /*
+ * There has been no events before the subscription. However,
+ * UPnP device architecture specification requires all the
+ * evented variables to be included, so generate a dummy event
+ * for this particular case using a WSC_ACK and all-zeros
+ * nonces. The ER (UPnP control point) will ignore this, but at
+ * least it will learn that WLANEvent variable will be used in
+ * event notifications in the future.
+ */
+ struct wpabuf *msg;
+ wpa_printf(MSG_DEBUG, "WPS UPnP: Use a fake WSC_ACK as the "
+ "initial WLANEvent");
+ msg = build_fake_wsc_ack();
+ if (msg) {
+ s->sm->wlanevent = (char *)
+ base64_encode(wpabuf_head(msg),
+ wpabuf_len(msg), NULL);
+ wpabuf_free(msg);
+ }
+ }
+
wlan_event = s->sm->wlanevent;
if (wlan_event == NULL || *wlan_event == '\0') {
wpa_printf(MSG_DEBUG, "WPS UPnP: WLANEvent not known for "
@@ -694,13 +734,13 @@ static int subscription_first_event(struct subscription *s)
/**
- * subscription_start - Rremember a UPnP control point to send events to.
+ * subscription_start - Remember a UPnP control point to send events to.
* @sm: WPS UPnP state machine from upnp_wps_device_init()
- * @callback_urls: malloc' mem given to the subscription
+ * @callback_urls: Callback URLs
* Returns: %NULL on error, or pointer to new subscription structure.
*/
struct subscription * subscription_start(struct upnp_wps_device_sm *sm,
- char *callback_urls)
+ const char *callback_urls)
{
struct subscription *s;
time_t now = time(NULL);
@@ -740,7 +780,6 @@ struct subscription * subscription_start(struct upnp_wps_device_sm *sm,
}
wpa_printf(MSG_DEBUG, "WPS UPnP: Subscription %p started with %s",
s, callback_urls);
- os_free(callback_urls);
/* Schedule sending this */
event_send_all_later(sm);
return s;
@@ -832,6 +871,50 @@ fail:
}
+#ifdef __FreeBSD__
+#include <sys/sysctl.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+
+static int eth_get(const char *device, u8 ea[ETH_ALEN])
+{
+ struct if_msghdr *ifm;
+ struct sockaddr_dl *sdl;
+ u_char *p, *buf;
+ size_t len;
+ int mib[] = { CTL_NET, AF_ROUTE, 0, AF_LINK, NET_RT_IFLIST, 0 };
+
+ if (sysctl(mib, 6, NULL, &len, NULL, 0) < 0)
+ return -1;
+ if ((buf = os_malloc(len)) == NULL)
+ return -1;
+ if (sysctl(mib, 6, buf, &len, NULL, 0) < 0) {
+ os_free(buf);
+ return -1;
+ }
+ for (p = buf; p < buf + len; p += ifm->ifm_msglen) {
+ ifm = (struct if_msghdr *)p;
+ sdl = (struct sockaddr_dl *)(ifm + 1);
+ if (ifm->ifm_type != RTM_IFINFO ||
+ (ifm->ifm_addrs & RTA_IFP) == 0)
+ continue;
+ if (sdl->sdl_family != AF_LINK || sdl->sdl_nlen == 0 ||
+ os_memcmp(sdl->sdl_data, device, sdl->sdl_nlen) != 0)
+ continue;
+ os_memcpy(ea, LLADDR(sdl), sdl->sdl_alen);
+ break;
+ }
+ os_free(buf);
+
+ if (p >= buf + len) {
+ errno = ESRCH;
+ return -1;
+ }
+ return 0;
+}
+#endif /* __FreeBSD__ */
+
+
/**
* get_netif_info - Get hw and IP addresses for network device
* @net_if: Selected network interface name
@@ -870,6 +953,7 @@ static int get_netif_info(const char *net_if, unsigned *ip_addr,
in_addr.s_addr = *ip_addr;
os_snprintf(*ip_addr_text, 16, "%s", inet_ntoa(in_addr));
+#ifdef __linux__
os_strlcpy(req.ifr_name, net_if, sizeof(req.ifr_name));
if (ioctl(sock, SIOCGIFHWADDR, &req) < 0) {
wpa_printf(MSG_ERROR, "WPS UPnP: SIOCGIFHWADDR failed: "
@@ -877,6 +961,14 @@ static int get_netif_info(const char *net_if, unsigned *ip_addr,
goto fail;
}
os_memcpy(mac, req.ifr_addr.sa_data, 6);
+#elif defined(__FreeBSD__)
+ if (eth_get(net_if, mac) < 0) {
+ wpa_printf(MSG_ERROR, "WPS UPnP: Failed to get MAC address");
+ goto fail;
+ }
+#else
+#error MAC address fetch not implemented
+#endif
os_snprintf(*mac_addr_text, 18, MACSTR, MAC2STR(req.ifr_addr.sa_data));
close(sock);
@@ -914,8 +1006,7 @@ void upnp_wps_device_stop(struct upnp_wps_device_sm *sm)
subscription_destroy(s);
}
- advertisement_state_machine_stop(sm);
- /* TODO: send byebye notifications */
+ advertisement_state_machine_stop(sm, 1);
event_send_stop_all(sm);
os_free(sm->wlanevent);
diff --git a/src/wps/wps_upnp_event.c b/src/wps/wps_upnp_event.c
index f278f35..4122a87 100644
--- a/src/wps/wps_upnp_event.c
+++ b/src/wps/wps_upnp_event.c
@@ -89,7 +89,7 @@ static void event_clean(struct wps_event_ *e)
/* event_delete -- delete single unqueued event
* (be sure to dequeue first if need be)
*/
-void event_delete(struct wps_event_ *e)
+static void event_delete(struct wps_event_ *e)
{
event_clean(e);
wpabuf_free(e->data);
@@ -432,7 +432,7 @@ static int event_send_start(struct subscription *s)
/* event_send_all_later_handler -- actually send events as needed */
-void event_send_all_later_handler(void *eloop_data, void *user_ctx)
+static void event_send_all_later_handler(void *eloop_data, void *user_ctx)
{
struct upnp_wps_device_sm *sm = user_ctx;
struct subscription *s;
diff --git a/src/wps/wps_upnp_i.h b/src/wps/wps_upnp_i.h
index d4b6569..ba4ec20 100644
--- a/src/wps/wps_upnp_i.h
+++ b/src/wps/wps_upnp_i.h
@@ -160,7 +160,7 @@ struct upnp_wps_device_sm {
/* wps_upnp.c */
void format_date(struct wpabuf *buf);
struct subscription * subscription_start(struct upnp_wps_device_sm *sm,
- char *callback_urls);
+ const char *callback_urls);
struct subscription * subscription_renew(struct upnp_wps_device_sm *sm,
const u8 uuid[UUID_LEN]);
void subscription_unlink(struct subscription *s);
@@ -172,7 +172,8 @@ int send_wpabuf(int fd, struct wpabuf *buf);
/* wps_upnp_ssdp.c */
void msearchreply_state_machine_stop(struct advertisement_state_machine *a);
int advertisement_state_machine_start(struct upnp_wps_device_sm *sm);
-void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm);
+void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm,
+ int send_byebye);
void ssdp_listener_stop(struct upnp_wps_device_sm *sm);
int ssdp_listener_start(struct upnp_wps_device_sm *sm);
int add_ssdp_network(char *net_if);
@@ -185,7 +186,6 @@ void web_listener_stop(struct upnp_wps_device_sm *sm);
/* wps_upnp_event.c */
int event_add(struct subscription *s, const struct wpabuf *data);
-void event_delete(struct wps_event_ *e);
void event_delete_all(struct subscription *s);
void event_send_all_later(struct upnp_wps_device_sm *sm);
void event_send_stop_all(struct upnp_wps_device_sm *sm);
diff --git a/src/wps/wps_upnp_ssdp.c b/src/wps/wps_upnp_ssdp.c
index 6a94c59..c1dc99d 100644
--- a/src/wps/wps_upnp_ssdp.c
+++ b/src/wps/wps_upnp_ssdp.c
@@ -229,10 +229,41 @@ static void advertisement_state_machine_handler(void *eloop_data,
/**
* advertisement_state_machine_stop - Stop SSDP advertisements
* @sm: WPS UPnP state machine from upnp_wps_device_init()
+ * @send_byebye: Send byebye advertisement messages immediately
*/
-void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm)
+void advertisement_state_machine_stop(struct upnp_wps_device_sm *sm,
+ int send_byebye)
{
+ struct advertisement_state_machine *a = &sm->advertisement;
+ int islast = 0;
+ struct wpabuf *msg;
+ struct sockaddr_in dest;
+
eloop_cancel_timeout(advertisement_state_machine_handler, NULL, sm);
+ if (!send_byebye || sm->multicast_sd < 0)
+ return;
+
+ a->type = ADVERTISE_DOWN;
+ a->state = 0;
+ a->sm = sm;
+
+ os_memset(&dest, 0, sizeof(dest));
+ dest.sin_family = AF_INET;
+ dest.sin_addr.s_addr = inet_addr(UPNP_MULTICAST_ADDRESS);
+ dest.sin_port = htons(UPNP_MULTICAST_PORT);
+
+ while (!islast) {
+ msg = next_advertisement(a, &islast);
+ if (msg == NULL)
+ break;
+ if (sendto(sm->multicast_sd, wpabuf_head(msg), wpabuf_len(msg),
+ 0, (struct sockaddr *) &dest, sizeof(dest)) < 0) {
+ wpa_printf(MSG_INFO, "WPS UPnP: Advertisement sendto "
+ "failed: %d (%s)", errno, strerror(errno));
+ }
+ wpabuf_free(msg);
+ a->state++;
+ }
}
@@ -318,7 +349,7 @@ int advertisement_state_machine_start(struct upnp_wps_device_sm *sm)
struct advertisement_state_machine *a = &sm->advertisement;
int next_timeout_msec;
- advertisement_state_machine_stop(sm);
+ advertisement_state_machine_stop(sm, 0);
/*
* Start out advertising down, this automatically switches
@@ -461,7 +492,7 @@ static void msearchreply_state_machine_start(struct upnp_wps_device_sm *sm,
a->type = MSEARCH_REPLY;
a->state = 0;
a->sm = sm;
- os_memcpy(&a->client, client, sizeof(client));
+ os_memcpy(&a->client, client, sizeof(*client));
/* Wait time depending on MX value */
next_timeout_msec = (1000 * mx * (os_random() & 0xFF)) >> 8;
next_timeout_sec = next_timeout_msec / 1000;
@@ -784,6 +815,7 @@ fail:
*/
int add_ssdp_network(char *net_if)
{
+#ifdef __linux__
int ret = -1;
int sock = -1;
struct rtentry rt;
@@ -798,11 +830,11 @@ int add_ssdp_network(char *net_if)
goto fail;
rt.rt_dev = net_if;
- sin = (struct sockaddr_in *) &rt.rt_dst;
+ sin = aliasing_hide_typecast(&rt.rt_dst, struct sockaddr_in);
sin->sin_family = AF_INET;
sin->sin_port = 0;
sin->sin_addr.s_addr = inet_addr(SSDP_TARGET);
- sin = (struct sockaddr_in *) &rt.rt_genmask;
+ sin = aliasing_hide_typecast(&rt.rt_genmask, struct sockaddr_in);
sin->sin_family = AF_INET;
sin->sin_port = 0;
sin->sin_addr.s_addr = inet_addr(SSDP_NETMASK);
@@ -826,6 +858,9 @@ fail:
close(sock);
return ret;
+#else /* __linux__ */
+ return 0;
+#endif /* __linux__ */
}
diff --git a/src/wps/wps_upnp_web.c b/src/wps/wps_upnp_web.c
index db47c29..b637454 100644
--- a/src/wps/wps_upnp_web.c
+++ b/src/wps/wps_upnp_web.c
@@ -1578,7 +1578,6 @@ static void web_connection_parse_subscribe(struct web_connection *c,
ret = HTTP_INTERNAL_SERVER_ERROR;
goto error;
}
- callback_urls = NULL; /* is now owned by subscription */
} else {
ret = HTTP_PRECONDITION_FAILED;
goto error;
@@ -1630,6 +1629,7 @@ error:
http_put_empty(buf, ret);
send_wpabuf(c->sd, buf);
wpabuf_free(buf);
+ os_free(callback_urls);
}
diff --git a/wpa_supplicant/.gitignore b/wpa_supplicant/.gitignore
deleted file mode 100644
index e7e034c..0000000
--- a/wpa_supplicant/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-*.d
-.config
-eapol_test
-preauth_test
-wpa_cli
-wpa_passphrase
-wpa_supplicant
-wpa_priv
diff --git a/wpa_supplicant/ChangeLog b/wpa_supplicant/ChangeLog
index 8f5b6fb..ab99514 100644
--- a/wpa_supplicant/ChangeLog
+++ b/wpa_supplicant/ChangeLog
@@ -1,5 +1,28 @@
ChangeLog for wpa_supplicant
+2010-01-12 - v0.6.10
+ * fixed SHA-256 based key derivation function to match with the
+ standard when using CCMP (for IEEE 802.11r and IEEE 802.11w)
+ (note: this breaks interoperability with previous version) [Bug 307]
+ * changed driver_wext to disconnect at init/deinit to clear state
+ * added explicit disconnect on 4-way handshake failures
+ * added WPS workarounds for known interoperability issues with broken,
+ deployed implementation
+ * update IEEE 802.11w implementation to match with the published
+ standard
+ * do not send WPS M8 message when learning current AP configuration as
+ an external Registrar
+ * added a workaround for race condition between receive EAPOL frames
+ and association events
+ * fixed compilation with newer GnuTLS versions
+ * fixed PKCS#12 use with OpenSSL 1.0.0
+
+2009-03-23 - v0.6.9
+ * driver_ndis: add PAE group address to the multicast address list to
+ fix wired IEEE 802.1X authentication
+ * fixed IEEE 802.11r key derivation function to match with the standard
+ (note: this breaks interoperability with previous version) [Bug 303]
+
2009-02-15 - v0.6.8
* increased wpa_cli ping interval to 5 seconds and made this
configurable with a new command line options (-G<seconds>)
diff --git a/wpa_supplicant/Makefile b/wpa_supplicant/Makefile
new file mode 100644
index 0000000..5a88fb3
--- /dev/null
+++ b/wpa_supplicant/Makefile
@@ -0,0 +1,1268 @@
+ifndef CC
+CC=gcc
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+export LIBDIR ?= /usr/local/lib/
+export BINDIR ?= /usr/local/sbin/
+
+CFLAGS += -I../src
+CFLAGS += -I../src/crypto
+CFLAGS += -I../src/utils
+CFLAGS += -I../src/common
+CFLAGS += -I../src/rsn_supp
+
+ALL=wpa_supplicant wpa_passphrase wpa_cli
+
+all: verify_config $(ALL) dynamic_eap_methods
+
+verify_config:
+ @if [ ! -r .config ]; then \
+ echo 'Building wpa_supplicant requires a configuration file'; \
+ echo '(.config). See README for more instructions. You can'; \
+ echo 'run "cp defconfig .config" to create an example'; \
+ echo 'configuration.'; \
+ exit 1; \
+ fi
+
+mkconfig:
+ @if [ -e .config ]; then \
+ echo '.config exists - did not replace it'; \
+ exit 1; \
+ fi
+ echo CONFIG_DRIVER_HOSTAP=y >> .config
+ echo CONFIG_DRIVER_WEXT=y >> .config
+
+install: all
+ mkdir -p $(DESTDIR)$(BINDIR)
+ for i in $(ALL); do cp $$i $(DESTDIR)$(BINDIR)/$$i; done
+ $(MAKE) -C ../src install
+
+OBJS = config.o
+OBJS += ../src/utils/common.o
+OBJS += ../src/utils/wpa_debug.o
+OBJS += ../src/utils/wpabuf.o
+OBJS += ../src/crypto/md5.o
+OBJS += ../src/crypto/rc4.o
+OBJS += ../src/crypto/md4.o
+OBJS += ../src/crypto/sha1.o
+OBJS += ../src/crypto/des.o
+OBJS_p = wpa_passphrase.o
+OBJS_p += ../src/utils/common.o
+OBJS_p += ../src/utils/wpa_debug.o
+OBJS_p += ../src/crypto/md5.o
+OBJS_p += ../src/crypto/md4.o
+OBJS_p += ../src/crypto/sha1.o
+OBJS_p += ../src/crypto/des.o
+OBJS_c = wpa_cli.o ../src/common/wpa_ctrl.o
+
+-include .config
+
+ifndef CONFIG_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+OBJS += ../src/utils/os_$(CONFIG_OS).o
+OBJS_p += ../src/utils/os_$(CONFIG_OS).o
+OBJS_c += ../src/utils/os_$(CONFIG_OS).o
+
+ifndef CONFIG_ELOOP
+CONFIG_ELOOP=eloop
+endif
+OBJS += ../src/utils/$(CONFIG_ELOOP).o
+
+
+ifdef CONFIG_EAPOL_TEST
+CFLAGS += -Werror -DEAPOL_TEST
+endif
+
+ifndef CONFIG_BACKEND
+CONFIG_BACKEND=file
+endif
+
+ifeq ($(CONFIG_BACKEND), file)
+OBJS += config_file.o
+ifndef CONFIG_NO_CONFIG_BLOBS
+NEED_BASE64=y
+endif
+CFLAGS += -DCONFIG_BACKEND_FILE
+endif
+
+ifeq ($(CONFIG_BACKEND), winreg)
+OBJS += config_winreg.o
+endif
+
+ifeq ($(CONFIG_BACKEND), none)
+OBJS += config_none.o
+endif
+
+ifdef CONFIG_NO_CONFIG_WRITE
+CFLAGS += -DCONFIG_NO_CONFIG_WRITE
+endif
+
+ifdef CONFIG_NO_CONFIG_BLOBS
+CFLAGS += -DCONFIG_NO_CONFIG_BLOBS
+endif
+
+ifdef CONFIG_NO_SCAN_PROCESSING
+CFLAGS += -DCONFIG_NO_SCAN_PROCESSING
+endif
+
+ifdef CONFIG_DRIVER_HOSTAP
+CFLAGS += -DCONFIG_DRIVER_HOSTAP
+OBJS_d += ../src/drivers/driver_hostap.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_WEXT
+CFLAGS += -DCONFIG_DRIVER_WEXT
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_NL80211
+CFLAGS += -DCONFIG_DRIVER_NL80211
+OBJS_d += ../src/drivers/driver_nl80211.o
+LIBS += -lnl
+ifdef CONFIG_CLIENT_MLME
+OBJS_d += ../src/drivers/radiotap.o
+endif
+endif
+
+ifdef CONFIG_DRIVER_PRISM54
+CFLAGS += -DCONFIG_DRIVER_PRISM54
+OBJS_d += ../src/drivers/driver_prism54.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_HERMES
+CFLAGS += -DCONFIG_DRIVER_HERMES
+OBJS_d += ../src/drivers/driver_hermes.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_MADWIFI
+CFLAGS += -DCONFIG_DRIVER_MADWIFI
+OBJS_d += ../src/drivers/driver_madwifi.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_ATMEL
+CFLAGS += -DCONFIG_DRIVER_ATMEL
+OBJS_d += ../src/drivers/driver_atmel.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_NDISWRAPPER
+CFLAGS += -DCONFIG_DRIVER_NDISWRAPPER
+OBJS_d += ../src/drivers/driver_ndiswrapper.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_RALINK
+CFLAGS += -DCONFIG_DRIVER_RALINK
+OBJS_d += ../src/drivers/driver_ralink.o
+endif
+
+ifdef CONFIG_DRIVER_BROADCOM
+CFLAGS += -DCONFIG_DRIVER_BROADCOM
+OBJS_d += ../src/drivers/driver_broadcom.o
+endif
+
+ifdef CONFIG_DRIVER_IPW
+CFLAGS += -DCONFIG_DRIVER_IPW
+OBJS_d += ../src/drivers/driver_ipw.o
+CONFIG_WIRELESS_EXTENSION=y
+endif
+
+ifdef CONFIG_DRIVER_BSD
+CFLAGS += -DCONFIG_DRIVER_BSD
+OBJS_d += ../src/drivers/driver_bsd.o
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=freebsd
+endif
+endif
+
+ifdef CONFIG_DRIVER_NDIS
+CFLAGS += -DCONFIG_DRIVER_NDIS
+OBJS_d += ../src/drivers/driver_ndis.o
+ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+OBJS_d += ../src/drivers/driver_ndis_.o
+endif
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=pcap
+endif
+CONFIG_WINPCAP=y
+ifdef CONFIG_USE_NDISUIO
+CFLAGS += -DCONFIG_USE_NDISUIO
+endif
+endif
+
+ifdef CONFIG_DRIVER_WIRED
+CFLAGS += -DCONFIG_DRIVER_WIRED
+OBJS_d += ../src/drivers/driver_wired.o
+endif
+
+ifdef CONFIG_DRIVER_TEST
+CFLAGS += -DCONFIG_DRIVER_TEST
+OBJS_d += ../src/drivers/driver_test.o
+endif
+
+ifdef CONFIG_DRIVER_OSX
+CFLAGS += -DCONFIG_DRIVER_OSX
+OBJS_d += ../src/drivers/driver_osx.o
+LDFLAGS += -framework CoreFoundation
+LDFLAGS += -F/System/Library/PrivateFrameworks -framework Apple80211
+endif
+
+ifdef CONFIG_DRIVER_PS3
+CFLAGS += -DCONFIG_DRIVER_PS3 -m64
+OBJS_d += ../src/drivers/driver_ps3.o
+LDFLAGS += -m64
+endif
+
+ifdef CONFIG_DRIVER_IPHONE
+CFLAGS += -DCONFIG_DRIVER_IPHONE
+OBJS_d += ../src/drivers/driver_iphone.o
+OBJS_d += ../src/drivers/MobileApple80211.o
+LIBS += -framework CoreFoundation
+endif
+
+ifdef CONFIG_DRIVER_ROBOSWITCH
+CFLAGS += -DCONFIG_DRIVER_ROBOSWITCH
+OBJS_d += ../src/drivers/driver_roboswitch.o
+endif
+
+ifndef CONFIG_L2_PACKET
+CONFIG_L2_PACKET=linux
+endif
+
+OBJS_l2 += ../src/l2_packet/l2_packet_$(CONFIG_L2_PACKET).o
+
+ifeq ($(CONFIG_L2_PACKET), pcap)
+ifdef CONFIG_WINPCAP
+CFLAGS += -DCONFIG_WINPCAP
+LIBS += -lwpcap -lpacket
+LIBS_w += -lwpcap
+else
+LIBS += -ldnet -lpcap
+endif
+endif
+
+ifeq ($(CONFIG_L2_PACKET), winpcap)
+LIBS += -lwpcap -lpacket
+LIBS_w += -lwpcap
+endif
+
+ifeq ($(CONFIG_L2_PACKET), freebsd)
+LIBS += -lpcap
+endif
+
+ifdef CONFIG_EAP_TLS
+# EAP-TLS
+ifeq ($(CONFIG_EAP_TLS), dyn)
+CFLAGS += -DEAP_TLS_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_tls.so
+else
+CFLAGS += -DEAP_TLS
+OBJS += ../src/eap_peer/eap_tls.o
+OBJS_h += ../src/eap_server/eap_tls.o
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_PEAP
+# EAP-PEAP
+ifeq ($(CONFIG_EAP_PEAP), dyn)
+CFLAGS += -DEAP_PEAP_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_peap.so
+else
+CFLAGS += -DEAP_PEAP
+OBJS += ../src/eap_peer/eap_peap.o
+OBJS += ../src/eap_common/eap_peap_common.o
+OBJS_h += ../src/eap_server/eap_peap.o
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+# EAP-TTLS
+ifeq ($(CONFIG_EAP_TTLS), dyn)
+CFLAGS += -DEAP_TTLS_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_ttls.so
+else
+CFLAGS += -DEAP_TTLS
+OBJS += ../src/eap_peer/eap_ttls.o
+OBJS_h += ../src/eap_server/eap_ttls.o
+endif
+MS_FUNCS=y
+TLS_FUNCS=y
+CHAP=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_MD5
+# EAP-MD5
+ifeq ($(CONFIG_EAP_MD5), dyn)
+CFLAGS += -DEAP_MD5_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_md5.so
+else
+CFLAGS += -DEAP_MD5
+OBJS += ../src/eap_peer/eap_md5.o
+OBJS_h += ../src/eap_server/eap_md5.o
+endif
+CHAP=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+# backwards compatibility for old spelling
+ifdef CONFIG_MSCHAPV2
+ifndef CONFIG_EAP_MSCHAPV2
+CONFIG_EAP_MSCHAPV2=y
+endif
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+# EAP-MSCHAPv2
+ifeq ($(CONFIG_EAP_MSCHAPV2), dyn)
+CFLAGS += -DEAP_MSCHAPv2_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_mschapv2.so
+EAPDYN += ../src/eap_peer/mschapv2.so
+else
+CFLAGS += -DEAP_MSCHAPv2
+OBJS += ../src/eap_peer/eap_mschapv2.o
+OBJS += ../src/eap_peer/mschapv2.o
+OBJS_h += ../src/eap_server/eap_mschapv2.o
+endif
+MS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_GTC
+# EAP-GTC
+ifeq ($(CONFIG_EAP_GTC), dyn)
+CFLAGS += -DEAP_GTC_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_gtc.so
+else
+CFLAGS += -DEAP_GTC
+OBJS += ../src/eap_peer/eap_gtc.o
+OBJS_h += ../src/eap_server/eap_gtc.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_OTP
+# EAP-OTP
+ifeq ($(CONFIG_EAP_OTP), dyn)
+CFLAGS += -DEAP_OTP_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_otp.so
+else
+CFLAGS += -DEAP_OTP
+OBJS += ../src/eap_peer/eap_otp.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_SIM
+# EAP-SIM
+ifeq ($(CONFIG_EAP_SIM), dyn)
+CFLAGS += -DEAP_SIM_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_sim.so
+else
+CFLAGS += -DEAP_SIM
+OBJS += ../src/eap_peer/eap_sim.o
+OBJS_h += ../src/eap_server/eap_sim.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_SIM_COMMON=y
+endif
+
+ifdef CONFIG_EAP_LEAP
+# EAP-LEAP
+ifeq ($(CONFIG_EAP_LEAP), dyn)
+CFLAGS += -DEAP_LEAP_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_leap.so
+else
+CFLAGS += -DEAP_LEAP
+OBJS += ../src/eap_peer/eap_leap.o
+endif
+MS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_PSK
+# EAP-PSK
+ifeq ($(CONFIG_EAP_PSK), dyn)
+CFLAGS += -DEAP_PSK_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_psk.so
+else
+CFLAGS += -DEAP_PSK
+OBJS += ../src/eap_peer/eap_psk.o ../src/eap_common/eap_psk_common.o
+OBJS_h += ../src/eap_server/eap_psk.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_AES=y
+endif
+
+ifdef CONFIG_EAP_AKA
+# EAP-AKA
+ifeq ($(CONFIG_EAP_AKA), dyn)
+CFLAGS += -DEAP_AKA_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_aka.so
+else
+CFLAGS += -DEAP_AKA
+OBJS += ../src/eap_peer/eap_aka.o
+OBJS_h += ../src/eap_server/eap_aka.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+CONFIG_EAP_SIM_COMMON=y
+endif
+
+ifdef CONFIG_EAP_AKA_PRIME
+# EAP-AKA'
+ifeq ($(CONFIG_EAP_AKA_PRIME), dyn)
+CFLAGS += -DEAP_AKA_PRIME_DYNAMIC
+else
+CFLAGS += -DEAP_AKA_PRIME
+endif
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += ../src/eap_common/eap_sim_common.o
+OBJS_h += ../src/eap_server/eap_sim_db.o
+NEED_AES=y
+NEED_FIPS186_2_PRF=y
+endif
+
+ifdef CONFIG_EAP_FAST
+# EAP-FAST
+ifeq ($(CONFIG_EAP_FAST), dyn)
+CFLAGS += -DEAP_FAST_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_fast.so
+EAPDYN += ../src/eap_common/eap_fast_common.o
+else
+CFLAGS += -DEAP_FAST
+OBJS += ../src/eap_peer/eap_fast.o ../src/eap_peer/eap_fast_pac.o
+OBJS += ../src/eap_common/eap_fast_common.o
+OBJS_h += ../src/eap_server/eap_fast.o
+endif
+TLS_FUNCS=y
+CONFIG_IEEE8021X_EAPOL=y
+NEED_T_PRF=y
+endif
+
+ifdef CONFIG_EAP_PAX
+# EAP-PAX
+ifeq ($(CONFIG_EAP_PAX), dyn)
+CFLAGS += -DEAP_PAX_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_pax.so
+else
+CFLAGS += -DEAP_PAX
+OBJS += ../src/eap_peer/eap_pax.o ../src/eap_common/eap_pax_common.o
+OBJS_h += ../src/eap_server/eap_pax.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_SAKE
+# EAP-SAKE
+ifeq ($(CONFIG_EAP_SAKE), dyn)
+CFLAGS += -DEAP_SAKE_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_sake.so
+else
+CFLAGS += -DEAP_SAKE
+OBJS += ../src/eap_peer/eap_sake.o ../src/eap_common/eap_sake_common.o
+OBJS_h += ../src/eap_server/eap_sake.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_GPSK
+# EAP-GPSK
+ifeq ($(CONFIG_EAP_GPSK), dyn)
+CFLAGS += -DEAP_GPSK_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_gpsk.so
+else
+CFLAGS += -DEAP_GPSK
+OBJS += ../src/eap_peer/eap_gpsk.o ../src/eap_common/eap_gpsk_common.o
+OBJS_h += ../src/eap_server/eap_gpsk.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+ifdef CONFIG_EAP_GPSK_SHA256
+CFLAGS += -DEAP_GPSK_SHA256
+endif
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_WPS
+# EAP-WSC
+CFLAGS += -DCONFIG_WPS -DEAP_WSC
+OBJS += wps_supplicant.o
+OBJS += ../src/utils/uuid.o
+OBJS += ../src/eap_peer/eap_wsc.o ../src/eap_common/eap_wsc_common.o
+OBJS += ../src/wps/wps.o
+OBJS += ../src/wps/wps_common.o
+OBJS += ../src/wps/wps_attr_parse.o
+OBJS += ../src/wps/wps_attr_build.o
+OBJS += ../src/wps/wps_attr_process.o
+OBJS += ../src/wps/wps_dev_attr.o
+OBJS += ../src/wps/wps_enrollee.o
+OBJS += ../src/wps/wps_registrar.o
+OBJS_h += ../src/eap_server/eap_wsc.o
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_CRYPTO=y
+NEED_80211_COMMON=y
+
+ifdef CONFIG_WPS_UPNP
+CFLAGS += -DCONFIG_WPS_UPNP
+OBJS += ../src/wps/wps_upnp.o
+OBJS += ../src/wps/wps_upnp_ssdp.o
+OBJS += ../src/wps/wps_upnp_web.o
+OBJS += ../src/wps/wps_upnp_event.o
+OBJS += ../src/wps/httpread.o
+endif
+
+endif
+
+ifdef CONFIG_EAP_IKEV2
+# EAP-IKEv2
+ifeq ($(CONFIG_EAP_IKEV2), dyn)
+CFLAGS += -DEAP_IKEV2_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_ikev2.so ../src/eap_peer/ikev2.o
+EAPDYN += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
+else
+CFLAGS += -DEAP_IKEV2
+OBJS += ../src/eap_peer/eap_ikev2.o ../src/eap_peer/ikev2.o
+OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
+OBJS_h += ../src/eap_server/eap_ikev2.o
+OBJS_h += ../src/eap_server/ikev2.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+ifeq ($(CONFIG_EAP_VENDOR_TEST), dyn)
+CFLAGS += -DEAP_VENDOR_TEST_DYNAMIC
+EAPDYN += ../src/eap_peer/eap_vendor_test.so
+else
+CFLAGS += -DEAP_VENDOR_TEST
+OBJS += ../src/eap_peer/eap_vendor_test.o
+OBJS_h += ../src/eap_server/eap_vendor_test.o
+endif
+CONFIG_IEEE8021X_EAPOL=y
+endif
+
+ifdef CONFIG_EAP_TNC
+# EAP-TNC
+CFLAGS += -DEAP_TNC
+OBJS += ../src/eap_peer/eap_tnc.o
+OBJS += ../src/eap_peer/tncc.o
+NEED_BASE64=y
+ifndef CONFIG_NATIVE_WINDOWS
+ifndef CONFIG_DRIVER_BSD
+LIBS += -ldl
+endif
+endif
+endif
+
+ifdef CONFIG_IEEE8021X_EAPOL
+# IEEE 802.1X/EAPOL state machines (e.g., for RADIUS authentication)
+CFLAGS += -DIEEE8021X_EAPOL
+OBJS += ../src/eapol_supp/eapol_supp_sm.o ../src/eap_peer/eap.o ../src/eap_common/eap_common.o ../src/eap_peer/eap_methods.o
+ifdef CONFIG_DYNAMIC_EAP_METHODS
+CFLAGS += -DCONFIG_DYNAMIC_EAP_METHODS
+LIBS += -ldl -rdynamic
+endif
+endif
+
+ifdef CONFIG_EAP_SERVER
+CFLAGS += -DEAP_SERVER
+OBJS_h += ../src/eap_server/eap.o
+OBJS_h += ../src/eap_server/eap_identity.o
+OBJS_h += ../src/eap_server/eap_methods.o
+endif
+
+ifdef CONFIG_RADIUS_CLIENT
+OBJS_h += ../src/utils/ip_addr.o
+OBJS_h += ../src/radius/radius.o
+OBJS_h += ../src/radius/radius_client.o
+endif
+
+ifdef CONFIG_AUTHENTICATOR
+OBJS_h += ../hostapd/eapol_sm.o
+OBJS_h += ../hostapd/ieee802_1x.o
+endif
+
+ifdef CONFIG_WPA_AUTHENTICATOR
+OBJS_h += ../hostapd/wpa.o
+OBJS_h += ../hostapd/wpa_auth_ie.o
+ifdef CONFIG_IEEE80211R
+OBJS_h += ../hostapd/wpa_ft.o
+endif
+ifdef CONFIG_PEERKEY
+OBJS_h += ../hostapd/peerkey.o
+endif
+endif
+
+ifdef CONFIG_PCSC
+# PC/SC interface for smartcards (USIM, GSM SIM)
+CFLAGS += -DPCSC_FUNCS -I/usr/include/PCSC
+OBJS += ../src/utils/pcsc_funcs.o
+# -lpthread may not be needed depending on how pcsc-lite was configured
+ifdef CONFIG_NATIVE_WINDOWS
+#Once MinGW gets support for WinScard, -lwinscard could be used instead of the
+#dynamic symbol loading that is now used in pcsc_funcs.c
+#LIBS += -lwinscard
+else
+LIBS += -lpcsclite -lpthread
+endif
+endif
+
+ifdef CONFIG_SIM_SIMULATOR
+CFLAGS += -DCONFIG_SIM_SIMULATOR
+NEED_MILENAGE=y
+endif
+
+ifdef CONFIG_USIM_SIMULATOR
+CFLAGS += -DCONFIG_USIM_SIMULATOR
+NEED_MILENAGE=y
+endif
+
+ifdef NEED_MILENAGE
+OBJS += ../src/hlr_auc_gw/milenage.o
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
+endif
+
+ifeq ($(CONFIG_TLS), internal)
+ifndef CONFIG_CRYPTO
+CONFIG_CRYPTO=internal
+endif
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+CFLAGS += -DCONFIG_INTERNAL_X509
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+CFLAGS += -DCONFIG_INTERNAL_X509
+endif
+
+
+ifdef TLS_FUNCS
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, EAP_TTLS, and EAP_FAST)
+CFLAGS += -DEAP_TLS_FUNCS
+OBJS += ../src/eap_peer/eap_tls_common.o
+OBJS_h += ../src/eap_server/eap_tls_common.o
+NEED_TLS_PRF=y
+ifeq ($(CONFIG_TLS), openssl)
+CFLAGS += -DEAP_TLS_OPENSSL
+OBJS += ../src/crypto/tls_openssl.o
+LIBS += -lssl -lcrypto
+LIBS_p += -lcrypto
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+OBJS += ../src/crypto/tls_gnutls.o
+LIBS += -lgnutls -lgcrypt -lgpg-error
+LIBS_p += -lgcrypt
+ifdef CONFIG_GNUTLS_EXTRA
+CFLAGS += -DCONFIG_GNUTLS_EXTRA
+LIBS += -lgnutls-extra
+endif
+endif
+ifeq ($(CONFIG_TLS), schannel)
+OBJS += ../src/crypto/tls_schannel.o
+endif
+ifeq ($(CONFIG_TLS), internal)
+OBJS += ../src/crypto/tls_internal.o
+OBJS += ../src/tls/tlsv1_common.o ../src/tls/tlsv1_record.o
+OBJS += ../src/tls/tlsv1_cred.o ../src/tls/tlsv1_client.o
+OBJS += ../src/tls/tlsv1_client_write.o ../src/tls/tlsv1_client_read.o
+OBJS += ../src/tls/asn1.o ../src/tls/rsa.o ../src/tls/x509v3.o
+OBJS_p += ../src/tls/asn1.o ../src/tls/rsa.o
+OBJS_p += ../src/crypto/rc4.o ../src/crypto/aes_wrap.o ../src/crypto/aes.o
+NEED_BASE64=y
+NEED_TLS_PRF=y
+CFLAGS += -DCONFIG_TLS_INTERNAL
+CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
+ifeq ($(CONFIG_CRYPTO), internal)
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+LIBS += -ltomcrypt -ltfm
+LIBS_p += -ltomcrypt -ltfm
+endif
+endif
+ifeq ($(CONFIG_TLS), none)
+OBJS += ../src/crypto/tls_none.o
+CFLAGS += -DEAP_TLS_NONE
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+endif
+ifdef CONFIG_SMARTCARD
+ifndef CONFIG_NATIVE_WINDOWS
+ifneq ($(CONFIG_L2_PACKET), freebsd)
+LIBS += -ldl
+endif
+endif
+endif
+NEED_CRYPTO=y
+else
+OBJS += ../src/crypto/tls_none.o
+endif
+
+ifdef CONFIG_PKCS12
+CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef CONFIG_SMARTCARD
+CFLAGS += -DCONFIG_SMARTCARD
+endif
+
+ifdef MS_FUNCS
+OBJS += ../src/crypto/ms_funcs.o
+NEED_CRYPTO=y
+endif
+
+ifdef CHAP
+OBJS += ../src/eap_common/chap.o
+endif
+
+ifdef NEED_CRYPTO
+ifndef TLS_FUNCS
+ifeq ($(CONFIG_TLS), openssl)
+LIBS += -lcrypto
+LIBS_p += -lcrypto
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+LIBS += -lgcrypt
+LIBS_p += -lgcrypt
+endif
+ifeq ($(CONFIG_TLS), schannel)
+endif
+ifeq ($(CONFIG_TLS), internal)
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+LIBS += -ltomcrypt -ltfm
+LIBS_p += -ltomcrypt -ltfm
+endif
+endif
+endif
+ifeq ($(CONFIG_TLS), openssl)
+OBJS += ../src/crypto/crypto_openssl.o
+OBJS_p += ../src/crypto/crypto_openssl.o
+CONFIG_INTERNAL_SHA256=y
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+OBJS += ../src/crypto/crypto_gnutls.o
+OBJS_p += ../src/crypto/crypto_gnutls.o
+CONFIG_INTERNAL_SHA256=y
+endif
+ifeq ($(CONFIG_TLS), schannel)
+OBJS += ../src/crypto/crypto_cryptoapi.o
+OBJS_p += ../src/crypto/crypto_cryptoapi.o
+CONFIG_INTERNAL_SHA256=y
+endif
+ifeq ($(CONFIG_TLS), internal)
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS += ../src/crypto/crypto_libtomcrypt.o
+OBJS_p += ../src/crypto/crypto_libtomcrypt.o
+CONFIG_INTERNAL_SHA256=y
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+OBJS += ../src/crypto/crypto_internal.o ../src/tls/bignum.o
+OBJS_p += ../src/crypto/crypto_internal.o ../src/tls/bignum.o
+CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
+CFLAGS += -DLTM_FAST
+endif
+else
+LIBS += -ltommath
+LIBS_p += -ltommath
+endif
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_DES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+endif
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+OBJS += ../src/crypto/crypto_cryptoapi.o
+OBJS_p += ../src/crypto/crypto_cryptoapi.o
+CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI
+CONFIG_INTERNAL_SHA256=y
+endif
+endif
+ifeq ($(CONFIG_TLS), none)
+OBJS += ../src/crypto/crypto_none.o
+OBJS_p += ../src/crypto/crypto_none.o
+CONFIG_INTERNAL_SHA256=y
+endif
+else
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+endif
+
+ifdef CONFIG_INTERNAL_AES
+CFLAGS += -DINTERNAL_AES
+endif
+ifdef CONFIG_INTERNAL_SHA1
+CFLAGS += -DINTERNAL_SHA1
+endif
+ifdef CONFIG_INTERNAL_SHA256
+CFLAGS += -DINTERNAL_SHA256
+endif
+ifdef CONFIG_INTERNAL_MD5
+CFLAGS += -DINTERNAL_MD5
+endif
+ifdef CONFIG_INTERNAL_MD4
+CFLAGS += -DINTERNAL_MD4
+endif
+ifdef CONFIG_INTERNAL_DES
+CFLAGS += -DINTERNAL_DES
+endif
+
+ifdef CONFIG_IEEE80211R
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_IEEE80211W
+CFLAGS += -DCONFIG_IEEE80211W
+NEED_SHA256=y
+endif
+
+ifdef NEED_SHA256
+OBJS += ../src/crypto/sha256.o
+CFLAGS += -DNEED_SHA256
+endif
+
+ifdef CONFIG_WIRELESS_EXTENSION
+OBJS_d += ../src/drivers/driver_wext.o
+endif
+
+ifdef CONFIG_CTRL_IFACE
+ifeq ($(CONFIG_CTRL_IFACE), y)
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_CTRL_IFACE=named_pipe
+else
+CONFIG_CTRL_IFACE=unix
+endif
+endif
+CFLAGS += -DCONFIG_CTRL_IFACE
+ifeq ($(CONFIG_CTRL_IFACE), unix)
+CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
+endif
+ifeq ($(CONFIG_CTRL_IFACE), udp)
+CFLAGS += -DCONFIG_CTRL_IFACE_UDP
+endif
+ifeq ($(CONFIG_CTRL_IFACE), named_pipe)
+CFLAGS += -DCONFIG_CTRL_IFACE_NAMED_PIPE
+endif
+OBJS += ctrl_iface.o ctrl_iface_$(CONFIG_CTRL_IFACE).o
+endif
+
+ifdef CONFIG_CTRL_IFACE_DBUS
+CFLAGS += -DCONFIG_CTRL_IFACE_DBUS -DDBUS_API_SUBJECT_TO_CHANGE
+OBJS += ctrl_iface_dbus.o ctrl_iface_dbus_handlers.o dbus_dict_helpers.o
+ifndef DBUS_LIBS
+DBUS_LIBS := $(shell pkg-config --libs dbus-1)
+endif
+LIBS += $(DBUS_LIBS)
+ifndef DBUS_INCLUDE
+DBUS_INCLUDE := $(shell pkg-config --cflags dbus-1)
+endif
+dbus_version=$(subst ., ,$(shell pkg-config --modversion dbus-1))
+DBUS_VERSION_MAJOR=$(word 1,$(dbus_version))
+DBUS_VERSION_MINOR=$(word 2,$(dbus_version))
+ifeq ($(DBUS_VERSION_MAJOR),)
+DBUS_VERSION_MAJOR=0
+endif
+ifeq ($(DBUS_VERSION_MINOR),)
+DBUS_VERSION_MINOR=0
+endif
+DBUS_INCLUDE += -DDBUS_VERSION_MAJOR=$(DBUS_VERSION_MAJOR)
+DBUS_INCLUDE += -DDBUS_VERSION_MINOR=$(DBUS_VERSION_MINOR)
+CFLAGS += $(DBUS_INCLUDE)
+endif
+
+ifdef CONFIG_READLINE
+CFLAGS += -DCONFIG_READLINE
+LIBS_c += -lncurses -lreadline
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32 -lgdi32 -lcrypt32
+LIBS_c += -lws2_32
+LIBS_p += -lws2_32 -lgdi32
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+LIBS_p += -lcrypt32
+endif
+endif
+
+ifdef CONFIG_NO_STDOUT_DEBUG
+CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
+ifndef CONFIG_CTRL_IFACE
+CFLAGS += -DCONFIG_NO_WPA_MSG
+endif
+endif
+
+ifdef CONFIG_IPV6
+# for eapol_test only
+CFLAGS += -DCONFIG_IPV6
+endif
+
+ifdef CONFIG_PEERKEY
+CFLAGS += -DCONFIG_PEERKEY
+endif
+
+ifdef CONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211R
+OBJS += ../src/rsn_supp/wpa_ft.o
+endif
+
+ifndef CONFIG_NO_WPA
+OBJS += ../src/rsn_supp/wpa.o
+OBJS += ../src/rsn_supp/preauth.o
+OBJS += ../src/rsn_supp/pmksa_cache.o
+OBJS += ../src/rsn_supp/peerkey.o
+OBJS += ../src/rsn_supp/wpa_ie.o
+OBJS += ../src/common/wpa_common.o
+NEED_AES=y
+else
+CFLAGS += -DCONFIG_NO_WPA -DCONFIG_NO_WPA2
+endif
+
+ifdef CONFIG_NO_WPA2
+CFLAGS += -DCONFIG_NO_WPA2
+endif
+
+ifdef CONFIG_NO_WPA_PASSPHRASE
+CFLAGS += -DCONFIG_NO_PBKDF2
+endif
+
+ifdef CONFIG_NO_AES_EXTRAS
+CFLAGS += -DCONFIG_NO_AES_WRAP
+CFLAGS += -DCONFIG_NO_AES_CTR -DCONFIG_NO_AES_OMAC1
+CFLAGS += -DCONFIG_NO_AES_EAX -DCONFIG_NO_AES_CBC
+CFLAGS += -DCONFIG_NO_AES_ENCRYPT
+CFLAGS += -DCONFIG_NO_AES_ENCRYPT_BLOCK
+endif
+
+ifdef NEED_AES
+OBJS += ../src/crypto/aes_wrap.o ../src/crypto/aes.o
+endif
+
+ifdef NEED_DH_GROUPS
+OBJS += ../src/crypto/dh_groups.o
+ifdef NEED_DH_GROUPS_ALL
+CFLAGS += -DALL_DH_GROUPS
+endif
+endif
+
+ifndef NEED_FIPS186_2_PRF
+CFLAGS += -DCONFIG_NO_FIPS186_2_PRF
+endif
+
+ifndef NEED_T_PRF
+CFLAGS += -DCONFIG_NO_T_PRF
+endif
+
+ifndef NEED_TLS_PRF
+CFLAGS += -DCONFIG_NO_TLS_PRF
+endif
+
+ifdef NEED_BASE64
+OBJS += ../src/utils/base64.o
+endif
+
+ifdef CONFIG_CLIENT_MLME
+OBJS += mlme.o ../src/common/ieee802_11_common.o
+CFLAGS += -DCONFIG_CLIENT_MLME
+endif
+
+ifndef CONFIG_MAIN
+CONFIG_MAIN=main
+endif
+
+ifdef CONFIG_DEBUG_SYSLOG
+CFLAGS += -DCONFIG_DEBUG_SYSLOG
+endif
+
+ifdef CONFIG_DEBUG_FILE
+CFLAGS += -DCONFIG_DEBUG_FILE
+endif
+
+ifdef CONFIG_DELAYED_MIC_ERROR_REPORT
+CFLAGS += -DCONFIG_DELAYED_MIC_ERROR_REPORT
+endif
+
+OBJS += ../src/drivers/scan_helpers.o
+
+OBJS_wpa_rm := ctrl_iface.o mlme.o ctrl_iface_unix.o
+OBJS_wpa := $(filter-out $(OBJS_wpa_rm),$(OBJS)) $(OBJS_h) tests/test_wpa.o
+ifdef CONFIG_AUTHENTICATOR
+OBJS_wpa += tests/link_test.o
+endif
+OBJS_wpa += $(OBJS_l2)
+OBJS += wpa_supplicant.o events.o blacklist.o wpas_glue.o scan.o
+OBJS_t := $(OBJS) $(OBJS_l2) eapol_test.o ../src/radius/radius.o ../src/radius/radius_client.o
+OBJS_t += ../src/utils/ip_addr.o
+OBJS_t2 := $(OBJS) $(OBJS_l2) preauth_test.o
+OBJS += $(CONFIG_MAIN).o
+
+ifdef CONFIG_PRIVSEP
+OBJS_priv += $(OBJS_d) ../src/drivers/drivers.o ../src/drivers/scan_helpers.o
+OBJS_priv += $(OBJS_l2)
+OBJS_priv += ../src/utils/os_$(CONFIG_OS).o
+OBJS_priv += ../src/utils/$(CONFIG_ELOOP).o
+OBJS_priv += ../src/utils/common.o
+OBJS_priv += ../src/utils/wpa_debug.o
+OBJS_priv += ../src/utils/wpabuf.o
+OBJS_priv += wpa_priv.o
+ifdef CONFIG_DRIVER_TEST
+OBJS_priv += ../src/crypto/sha1.o
+OBJS_priv += ../src/crypto/md5.o
+ifeq ($(CONFIG_TLS), openssl)
+OBJS_priv += ../src/crypto/crypto_openssl.o
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+OBJS_priv += ../src/crypto/crypto_gnutls.o
+endif
+ifeq ($(CONFIG_TLS), internal)
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS_priv += ../src/crypto/crypto_libtomcrypt.o
+else
+OBJS_priv += ../src/crypto/crypto_internal.o
+endif
+endif
+endif # CONFIG_DRIVER_TEST
+OBJS += ../src/l2_packet/l2_packet_privsep.o
+OBJS += ../src/drivers/driver_privsep.o
+EXTRA_progs += wpa_priv
+else
+OBJS += $(OBJS_d) ../src/drivers/drivers.o
+OBJS += $(OBJS_l2)
+endif
+
+ifdef CONFIG_NDIS_EVENTS_INTEGRATED
+CFLAGS += -DCONFIG_NDIS_EVENTS_INTEGRATED
+OBJS += ../src/drivers/ndis_events.o
+EXTRALIBS += -loleaut32 -lole32 -luuid
+ifdef PLATFORMSDKLIB
+EXTRALIBS += $(PLATFORMSDKLIB)/WbemUuid.Lib
+else
+EXTRALIBS += WbemUuid.Lib
+endif
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+dynamic_eap_methods: $(EAPDYN)
+
+wpa_priv: $(OBJS_priv)
+ $(LDO) $(LDFLAGS) -o wpa_priv $(OBJS_priv) $(LIBS)
+
+wpa_supplicant: .config $(OBJS) $(EXTRA_progs)
+ $(LDO) $(LDFLAGS) -o wpa_supplicant $(OBJS) $(LIBS) $(EXTRALIBS)
+
+eapol_test: .config $(OBJS_t)
+ $(LDO) $(LDFLAGS) -o eapol_test $(OBJS_t) $(LIBS)
+
+preauth_test: .config $(OBJS_t2)
+ $(LDO) $(LDFLAGS) -o preauth_test $(OBJS_t2) $(LIBS)
+
+wpa_passphrase: $(OBJS_p)
+ $(LDO) $(LDFLAGS) -o wpa_passphrase $(OBJS_p) $(LIBS_p)
+
+wpa_cli: $(OBJS_c)
+ $(LDO) $(LDFLAGS) -o wpa_cli $(OBJS_c) $(LIBS_c)
+
+link_test: $(OBJS) $(OBJS_h) tests/link_test.o
+ $(LDO) $(LDFLAGS) -o link_test $(OBJS) $(OBJS_h) tests/link_test.o $(LIBS)
+
+test_wpa: $(OBJS_wpa) $(OBJS_h)
+ $(LDO) $(LDFLAGS) -o test_wpa $(OBJS_wpa) $(LIBS)
+
+OBJSa=../src/tls/asn1_test.o ../src/tls/asn1.o ../src/tls/x509v3.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_unix.o \
+ ../src/crypto/crypto_$(CONFIG_CRYPTO).o ../src/crypto/md5.o ../src/crypto/sha1.o \
+ ../src/crypto/rc4.o ../src/crypto/des.o ../src/crypto/aes_wrap.o \
+ ../src/crypto/aes.o ../src/tls/bignum.o ../src/tls/rsa.o
+asn1_test: $(OBJSa)
+ $(LDO) $(LDFLAGS) -o asn1_test $(OBJSa)
+
+OBJSx=tests/test_x509v3.o ../src/tls/asn1.o ../src/tls/x509v3.o \
+ ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_unix.o \
+ ../src/crypto/crypto_$(CONFIG_CRYPTO).o \
+ ../src/crypto/md5.o ../src/crypto/sha1.o ../src/crypto/aes.o \
+ ../src/crypto/rc4.o ../src/crypto/des.o ../src/crypto/aes_wrap.o \
+ ../src/crypto/sha256.o \
+ ../src/tls/bignum.o ../src/tls/rsa.o
+test_x509v3: $(OBJSx)
+ $(LDO) $(LDFLAGS) -o test_x509v3 $(OBJSx)
+
+win_if_list: win_if_list.c
+ $(LDO) $(LDFLAGS) -o $@ win_if_list.c $(CFLAGS) $(LIBS_w)
+
+eap_psk.so: ../src/eap_peer/eap_psk.c ../src/eap_common/eap_psk_common.c
+ $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -Deap_peer_psk_register=eap_peer_method_dynamic_init
+
+eap_pax.so: ../src/eap_peer/eap_pax.c ../src/eap_common/eap_pax_common.c
+ $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -Deap_peer_pax_register=eap_peer_method_dynamic_init
+
+eap_sake.so: ../src/eap_peer/eap_sake.c ../src/eap_common/eap_sake_common.c
+ $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -Deap_peer_sake_register=eap_peer_method_dynamic_init
+
+eap_wsc.so: ../src/eap_peer/eap_wsc.c ../src/eap_common/eap_wsc_common.c ../src/wps/wps.c
+ $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -Deap_peer_wsc_register=eap_peer_method_dynamic_init
+
+eap_ikev2.so: ../src/eap_peer/eap_ikev2.c ../src/eap_peer/ikev2.c ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.c
+ $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $^ \
+ -Deap_peer_ikev2_register=eap_peer_method_dynamic_init
+
+%.so: %.c
+ $(CC) -o $@ $(CFLAGS) -shared -rdynamic -fPIC $< \
+ -D$(*F:eap_%=eap_peer_%)_register=eap_peer_method_dynamic_init
+
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+
+%.o: %.c
+ $(Q)$(CC) -c -o $@ $(CFLAGS) $<
+ @$(E) " CC " $<
+
+wpa_supplicant.exe: wpa_supplicant
+ mv -f $< $@
+wpa_cli.exe: wpa_cli
+ mv -f $< $@
+wpa_passphrase.exe: wpa_passphrase
+ mv -f $< $@
+win_if_list.exe: win_if_list
+ mv -f $< $@
+eapol_test.exe: eapol_test
+ mv -f $< $@
+
+WINALL=wpa_supplicant.exe wpa_cli.exe wpa_passphrase.exe win_if_list.exe
+
+windows-bin: $(WINALL)
+ $(STRIP) $(WINALL)
+
+wpa_gui/Makefile:
+ qmake -o wpa_gui/Makefile wpa_gui/wpa_gui.pro
+
+wpa_gui: wpa_gui/Makefile
+ $(MAKE) -C wpa_gui
+
+wpa_gui-qt4/Makefile:
+ qmake -o wpa_gui-qt4/Makefile wpa_gui-qt4/wpa_gui.pro
+
+wpa_gui-qt4: wpa_gui-qt4/Makefile
+ $(MAKE) -C wpa_gui-qt4
+
+TEST_MS_FUNCS_OBJS = ../src/crypto/crypto_openssl.o ../src/crypto/sha1.o ../src/crypto/md5.o \
+ ../src/utils/os_unix.o ../src/crypto/rc4.o tests/test_ms_funcs.o
+test-ms_funcs: $(TEST_MS_FUNCS_OBJS)
+ $(LDO) $(LDFLAGS) -o $@ $(TEST_MS_FUNCS_OBJS) $(LIBS) -lcrypto
+ ./test-ms_funcs
+ rm test-ms_funcs
+
+TEST_SHA1_OBJS = ../src/crypto/sha1.o ../src/crypto/md5.o tests/test_sha1.o #../src/crypto/crypto_openssl.o
+test-sha1: $(TEST_SHA1_OBJS)
+ $(LDO) $(LDFLAGS) -o $@ $(TEST_SHA1_OBJS) $(LIBS)
+ ./test-sha1
+ rm test-sha1
+
+TEST_SHA256_OBJS = ../src/crypto/sha256.o ../src/crypto/md5.o tests/test_sha256.o ../src/utils/os_unix.o ../src/crypto/crypto_openssl.o
+test-sha256: $(TEST_SHA256_OBJS)
+ $(LDO) $(LDFLAGS) -o $@ $(TEST_SHA256_OBJS) $(LIBS)
+ ./test-sha256
+ rm test-sha256
+
+TEST_AES_OBJS = ../src/crypto/aes_wrap.o ../src/crypto/aes.o tests/test_aes.o
+test-aes: $(TEST_AES_OBJS)
+ $(LDO) $(LDFLAGS) -o $@ $(TEST_AES_OBJS) $(LIBS)
+ ./test-aes
+ rm test-aes
+
+TEST_EAP_SIM_COMMON_OBJS = ../src/crypto/sha1.o ../src/crypto/md5.o \
+ ../src/crypto/aes_wrap.o ../src/utils/common.o ../src/utils/os_unix.o \
+ ../src/utils/wpa_debug.o ../src/crypto/aes.o \
+ tests/test_eap_sim_common.o
+test-eap_sim_common: $(TEST_EAP_SIM_COMMON_OBJS)
+ $(LDO) $(LDFLAGS) -o $@ $(TEST_AES_OBJS) $(LIBS)
+ ./test-eap_sim_common
+ rm test-eap_sim_common
+
+TEST_MD4_OBJS = ../src/crypto/md4.o tests/test_md4.o #../src/crypto/crypto_openssl.o
+test-md4: $(TEST_MD4_OBJS)
+ $(LDO) $(LDFLAGS) -o $@ $(TEST_MD4_OBJS) $(LIBS)
+ ./test-md4
+ rm test-md4
+
+TEST_MD5_OBJS = ../src/crypto/md5.o tests/test_md5.o #../src/crypto/crypto_openssl.o
+test-md5: $(TEST_MD5_OBJS)
+ $(LDO) $(LDFLAGS) -o $@ $(TEST_MD5_OBJS) $(LIBS)
+ ./test-md5
+ rm test-md5
+
+tests: test-ms_funcs test-sha1 test-aes test-eap_sim_common test-md4 test-md5
+
+clean:
+ $(MAKE) -C ../src clean
+ rm -f core *~ *.o *.d eap_*.so $(ALL) $(WINALL) eapol_test preauth_test
+ rm -f wpa_priv
+
+%.eps: %.fig
+ fig2dev -L eps $*.fig $*.eps
+
+%.png: %.fig
+ fig2dev -L png -m 3 $*.fig | pngtopnm | pnmscale 0.4 | pnmtopng \
+ > $*.png
+
+docs-pics: doc/wpa_supplicant.png doc/wpa_supplicant.eps
+
+docs: docs-pics
+ (cd ..; doxygen wpa_supplicant/doc/doxygen.full; cd wpa_supplicant)
+ $(MAKE) -C doc/latex
+ cp doc/latex/refman.pdf wpa_supplicant-devel.pdf
+
+docs-fast: docs-pics
+ (cd ..; doxygen wpa_supplicant/doc/doxygen.fast; cd wpa_supplicant)
+
+clean-docs:
+ rm -rf doc/latex doc/html
+ rm -f doc/wpa_supplicant.{eps,png} wpa_supplicant-devel.pdf
+
+-include $(OBJS:%.o=%.d)
diff --git a/wpa_supplicant/README b/wpa_supplicant/README
index 2b94c23..b282150 100644
--- a/wpa_supplicant/README
+++ b/wpa_supplicant/README
@@ -397,10 +397,8 @@ CONFIG_PCSC=y
Following options can be added to .config to select which driver
interfaces are included. Hermes driver interface needs to be downloaded
-from Agere (see above). CONFIG_WIRELESS_EXTENSION will be used
-automatically if any of the selected drivers need it.
+from Agere (see above).
-CONFIG_WIRELESS_EXTENSION=y
CONFIG_DRIVER_HOSTAP=y
CONFIG_DRIVER_HERMES=y
CONFIG_DRIVER_MADWIFI=y
@@ -426,7 +424,6 @@ CONFIG_DRIVER_BROADCOM=y
CONFIG_DRIVER_IPW=y
CONFIG_DRIVER_BSD=y
CONFIG_DRIVER_NDIS=y
-CONFIG_WIRELESS_EXTENSION=y
CONFIG_IEEE8021X_EAPOL=y
CONFIG_EAP_MD5=y
CONFIG_EAP_MSCHAPV2=y
@@ -520,11 +517,11 @@ drivers:
hostap = Host AP driver (Intersil Prism2/2.5/3) [default]
(this can also be used with Linuxant DriverLoader)
hermes = Agere Systems Inc. driver (Hermes-I/Hermes-II)
- madwifi = MADWIFI 802.11 support (Atheros, etc.)
+ madwifi = MADWIFI 802.11 support (Atheros, etc.) (deprecated; use wext)
atmel = ATMEL AT76C5XXx (USB, PCMCIA)
wext = Linux wireless extensions (generic)
ralink = Ralink Client driver
- ndiswrapper = Linux ndiswrapper
+ ndiswrapper = Linux ndiswrapper (deprecated; use wext)
broadcom = Broadcom wl.o driver
ipw = Intel ipw2100/2200 driver (old; use wext with Linux 2.6.13 or newer)
wired = wpa_supplicant wired Ethernet driver
diff --git a/wpa_supplicant/README-WPS b/wpa_supplicant/README-WPS
index 7fd358d..6b826a7 100644
--- a/wpa_supplicant/README-WPS
+++ b/wpa_supplicant/README-WPS
@@ -131,13 +131,18 @@ negotiation which will generate a new WPA PSK in the same way as the
PIN method described above.
-If the client wants to operation in the Registrar role to configure an
+If the client wants to operate in the Registrar role to configure an
AP, wpa_supplicant is notified over the control interface, e.g., with
wpa_cli:
wpa_cli wps_reg <AP BSSID> <AP PIN>
(example: wpa_cli wps_reg 02:34:56:78:9a:bc 12345670)
+This is currently only used to fetch the current AP settings instead
+of actually changing them. The main difference with the wps_pin
+command is that wps_reg uses the AP PIN (e.g., from a label on the AP)
+instead of a PIN generated at the client.
+
Scanning
--------
diff --git a/wpa_supplicant/README-Windows.txt b/wpa_supplicant/README-Windows.txt
new file mode 100644
index 0000000..292223d
--- /dev/null
+++ b/wpa_supplicant/README-Windows.txt
@@ -0,0 +1,450 @@
+wpa_supplicant for Windows
+==========================
+
+Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi> and contributors
+All Rights Reserved.
+
+This program is dual-licensed under both the GPL version 2 and BSD
+license. Either license may be used at your option.
+
+This product includes software developed by the OpenSSL Project
+for use in the OpenSSL Toolkit (http://www.openssl.org/). This
+product includes cryptographic software written by Eric Young
+(eay@cryptsoft.com).
+
+
+wpa_supplicant has support for being used as a WPA/WPA2/IEEE 802.1X
+Supplicant on Windows. The current port requires that WinPcap
+(http://winpcap.polito.it/) is installed for accessing packets and the
+driver interface. Both release versions 3.0 and 3.1 are supported.
+
+The current port is still somewhat experimental. It has been tested
+mainly on Windows XP (SP2) with limited set of NDIS drivers. In
+addition, the current version has been reported to work with Windows
+2000.
+
+All security modes have been verified to work (at least complete
+authentication and successfully ping a wired host):
+- plaintext
+- static WEP / open system authentication
+- static WEP / shared key authentication
+- IEEE 802.1X with dynamic WEP keys
+- WPA-PSK, TKIP, CCMP, TKIP+CCMP
+- WPA-EAP, TKIP, CCMP, TKIP+CCMP
+- WPA2-PSK, TKIP, CCMP, TKIP+CCMP
+- WPA2-EAP, TKIP, CCMP, TKIP+CCMP
+
+
+Binary version
+--------------
+
+Compiled binary version of the wpa_supplicant and additional tools is
+available from http://w1.fi/wpa_supplicant/. These binaries can be
+used after installing WinPcap.
+
+wpa_gui uses Qt 4 framework and may need additional dynamic libraries
+(DLLs). These libraries are available from
+http://w1.fi/wpa_supplicant/qt4/wpa_gui-qt433-windows-dll.zip
+You can copy the DLL files from this ZIP package into the same directory
+with wpa_gui.exe to allow wpa_gui to be started.
+
+
+Building wpa_supplicant with mingw
+----------------------------------
+
+The default build setup for wpa_supplicant is to use MinGW and
+cross-compiling from Linux to MinGW/Windows. It should also be
+possible to build this under Windows using the MinGW tools, but that
+is not tested nor supported and is likely to require some changes to
+the Makefile unless cygwin is used.
+
+
+Building wpa_supplicant with MSVC
+---------------------------------
+
+wpa_supplicant can be built with Microsoft Visual C++ compiler. This
+has been tested with Microsoft Visual C++ Toolkit 2003 and Visual
+Studio 2005 using the included nmake.mak as a Makefile for nmake. IDE
+can also be used by creating a project that includes the files and
+defines mentioned in nmake.mak. Example VS2005 solution and project
+files are included in vs2005 subdirectory. This can be used as a
+starting point for building the programs with VS2005 IDE. Visual Studio
+2008 Express Edition is also able to use these project files.
+
+WinPcap development package is needed for the build and this can be
+downloaded from http://www.winpcap.org/install/bin/WpdPack_4_0_2.zip. The
+default nmake.mak expects this to be unpacked into C:\dev\WpdPack so
+that Include and Lib directories are in this directory. The files can be
+stored elsewhere as long as the WINPCAPDIR in nmake.mak is updated to
+match with the selected directory. In case a project file in the IDE is
+used, these Include and Lib directories need to be added to project
+properties as additional include/library directories.
+
+OpenSSL source package can be downloaded from
+http://www.openssl.org/source/openssl-0.9.8i.tar.gz and built and
+installed following instructions in INSTALL.W32. Note that if EAP-FAST
+support will be included in the wpa_supplicant, OpenSSL needs to be
+patched to# support it openssl-0.9.8i-tls-extensions.patch. The example
+nmake.mak file expects OpenSSL to be installed into C:\dev\openssl, but
+this directory can be modified by changing OPENSSLDIR variable in
+nmake.mak.
+
+If you do not need EAP-FAST support, you may also be able to use Win32
+binary installation package of OpenSSL from
+http://www.slproweb.com/products/Win32OpenSSL.html instead of building
+the library yourself. In this case, you will need to copy Include and
+Lib directories in suitable directory, e.g., C:\dev\openssl for the
+default nmake.mak. Copy {Win32OpenSSLRoot}\include into
+C:\dev\openssl\include and make C:\dev\openssl\lib subdirectory with
+files from {Win32OpenSSLRoot}\VC (i.e., libeay*.lib and ssleay*.lib).
+This will end up using dynamically linked OpenSSL (i.e., .dll files are
+needed) for it. Alternative, you can copy files from
+{Win32OpenSSLRoot}\VC\static to create a static build (no OpenSSL .dll
+files needed).
+
+
+Building wpa_supplicant for cygwin
+----------------------------------
+
+wpa_supplicant can be built for cygwin by installing the needed
+development packages for cygwin. This includes things like compiler,
+make, openssl development package, etc. In addition, developer's pack
+for WinPcap (WPdpack.zip) from
+http://winpcap.polito.it/install/default.htm is needed.
+
+.config file should enable only one driver interface,
+CONFIG_DRIVER_NDIS. In addition, include directories may need to be
+added to match the system. An example configuration is available in
+defconfig. The library and include files for WinPcap will either need
+to be installed in compiler/linker default directories or their
+location will need to be adding to .config when building
+wpa_supplicant.
+
+Othen than this, the build should be more or less identical to Linux
+version, i.e., just run make after having created .config file. An
+additional tool, win_if_list.exe, can be built by running "make
+win_if_list".
+
+
+Building wpa_gui
+----------------
+
+wpa_gui uses Qt application framework from Trolltech. It can be built
+with the open source version of Qt4 and MinGW. Following commands can
+be used to build the binary in the Qt 4 Command Prompt:
+
+# go to the root directory of wpa_supplicant source code
+cd wpa_gui-qt4
+qmake -o Makefile wpa_gui.pro
+make
+# the wpa_gui.exe binary is created into 'release' subdirectory
+
+
+Using wpa_supplicant for Windows
+--------------------------------
+
+wpa_supplicant, wpa_cli, and wpa_gui behave more or less identically to
+Linux version, so instructions in README and example wpa_supplicant.conf
+should be applicable for most parts. In addition, there is another
+version of wpa_supplicant, wpasvc.exe, which can be used as a Windows
+service and which reads its configuration from registry instead of
+text file.
+
+When using access points in "hidden SSID" mode, ap_scan=2 mode need to
+be used (see wpa_supplicant.conf for more information).
+
+Windows NDIS/WinPcap uses quite long interface names, so some care
+will be needed when starting wpa_supplicant. Alternatively, the
+adapter description can be used as the interface name which may be
+easier since it is usually in more human-readable
+format. win_if_list.exe can be used to find out the proper interface
+name.
+
+Example steps in starting up wpa_supplicant:
+
+# win_if_list.exe
+ifname: \Device\NPF_GenericNdisWanAdapter
+description: Generic NdisWan adapter
+
+ifname: \Device\NPF_{769E012B-FD17-4935-A5E3-8090C38E25D2}
+description: Atheros Wireless Network Adapter (Microsoft's Packet Scheduler)
+
+ifname: \Device\NPF_{732546E7-E26C-48E3-9871-7537B020A211}
+description: Intel 8255x-based Integrated Fast Ethernet (Microsoft's Packet Scheduler)
+
+
+Since the example configuration used Atheros WLAN card, the middle one
+is the correct interface in this case. The interface name for -i
+command line option is the full string following "ifname:" (the
+"\Device\NPF_" prefix can be removed). In other words, wpa_supplicant
+would be started with the following command:
+
+# wpa_supplicant.exe -i'{769E012B-FD17-4935-A5E3-8090C38E25D2}' -c wpa_supplicant.conf -d
+
+-d optional enables some more debugging (use -dd for even more, if
+needed). It can be left out if debugging information is not needed.
+
+With the alternative mechanism for selecting the interface, this
+command has identical results in this case:
+
+# wpa_supplicant.exe -iAtheros -c wpa_supplicant.conf -d
+
+
+Simple configuration example for WPA-PSK:
+
+#ap_scan=2
+ctrl_interface=
+network={
+ ssid="test"
+ key_mgmt=WPA-PSK
+ proto=WPA
+ pairwise=TKIP
+ psk="secret passphrase"
+}
+
+(remove '#' from the comment out ap_scan line to enable mode in which
+wpa_supplicant tries to associate with the SSID without doing
+scanning; this allows APs with hidden SSIDs to be used)
+
+
+wpa_cli.exe and wpa_gui.exe can be used to interact with the
+wpa_supplicant.exe program in the same way as with Linux. Note that
+ctrl_interface is using UNIX domain sockets when built for cygwin, but
+the native build for Windows uses named pipes and the contents of the
+ctrl_interface configuration item is used to control access to the
+interface. Anyway, this variable has to be included in the configuration
+to enable the control interface.
+
+
+Example SDDL string formats:
+
+(local admins group has permission, but nobody else):
+
+ctrl_interface=SDDL=D:(A;;GA;;;BA)
+
+("A" == "access allowed", "GA" == GENERIC_ALL == all permissions, and
+"BA" == "builtin administrators" == the local admins. The empty fields
+are for flags and object GUIDs, none of which should be required in this
+case.)
+
+(local admins and the local "power users" group have permissions,
+but nobody else):
+
+ctrl_interface=SDDL=D:(A;;GA;;;BA)(A;;GA;;;PU)
+
+(One ACCESS_ALLOWED ACE for GENERIC_ALL for builtin administrators, and
+one ACCESS_ALLOWED ACE for GENERIC_ALL for power users.)
+
+(close to wide open, but you have to be a valid user on
+the machine):
+
+ctrl_interface=SDDL=D:(A;;GA;;;AU)
+
+(One ACCESS_ALLOWED ACE for GENERIC_ALL for the "authenticated users"
+group.)
+
+This one would allow absolutely everyone (including anonymous
+users) -- this is *not* recommended, since named pipes can be attached
+to from anywhere on the network (i.e. there's no "this machine only"
+like there is with 127.0.0.1 sockets):
+
+ctrl_interface=SDDL=D:(A;;GA;;;BU)(A;;GA;;;AN)
+
+(BU == "builtin users", "AN" == "anonymous")
+
+See also [1] for the format of ACEs, and [2] for the possible strings
+that can be used for principal names.
+
+[1]
+http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/ace_strings.asp
+[2]
+http://msdn.microsoft.com/library/default.asp?url=/library/en-us/secauthz/security/sid_strings.asp
+
+
+Starting wpa_supplicant as a Windows service (wpasvc.exe)
+---------------------------------------------------------
+
+wpa_supplicant can be started as a Windows service by using wpasvc.exe
+program that is alternative build of wpa_supplicant.exe. Most of the
+core functionality of wpasvc.exe is identical to wpa_supplicant.exe,
+but it is using Windows registry for configuration information instead
+of a text file and command line parameters. In addition, it can be
+registered as a service that can be started automatically or manually
+like any other Windows service.
+
+The root of wpa_supplicant configuration in registry is
+HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant. This level includes global
+parameters and a 'interfaces' subkey with all the interface configuration
+(adapter to confname mapping). Each such mapping is a subkey that has
+'adapter', 'config', and 'ctrl_interface' values.
+
+This program can be run either as a normal command line application,
+e.g., for debugging, with 'wpasvc.exe app' or as a Windows service.
+Service need to be registered with 'wpasvc.exe reg <full path to
+wpasvc.exe>'. Alternatively, 'wpasvc.exe reg' can be used to register
+the service with the current location of wpasvc.exe. After this, wpasvc
+can be started like any other Windows service (e.g., 'net start wpasvc')
+or it can be configured to start automatically through the Services tool
+in administrative tasks. The service can be unregistered with
+'wpasvc.exe unreg'.
+
+If the service is set to start during system bootup to make the
+network connection available before any user has logged in, there may
+be a long (half a minute or so) delay in starting up wpa_supplicant
+due to WinPcap needing a driver called "Network Monitor Driver" which
+is started by default on demand.
+
+To speed up wpa_supplicant start during system bootup, "Network
+Monitor Driver" can be configured to be started sooner by setting its
+startup type to System instead of the default Demand. To do this, open
+up Device Manager, select Show Hidden Devices, expand the "Non
+Plug-and-Play devices" branch, double click "Network Monitor Driver",
+go to the Driver tab, and change the Demand setting to System instead.
+
+Configuration data is in HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs
+key. Each configuration profile has its own key under this. In terms of text
+files, each profile would map to a separate text file with possibly multiple
+networks. Under each profile, there is a networks key that lists all
+networks as a subkey. Each network has set of values in the same way as
+network block in the configuration file. In addition, blobs subkey has
+possible blobs as values.
+
+HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000
+ ssid="example"
+ key_mgmt=WPA-PSK
+
+See win_example.reg for an example on how to setup wpasvc.exe
+parameters in registry. It can also be imported to registry as a
+starting point for the configuration.
+
+
+
+License information for third party software used in this product:
+
+ OpenSSL License
+ ---------------
+
+/* ====================================================================
+ * Copyright (c) 1998-2004 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+ Original SSLeay License
+ -----------------------
+
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+
+
+ Qt Open Source Edition
+ ----------------------
+
+The Qt GUI Toolkit is Copyright (C) 1994-2007 Trolltech ASA.
+Qt Open Source Edition is licensed under GPL version 2.
+
+Source code for the library is available at
+http://w1.fi/wpa_supplicant/qt4/qt-win-opensource-src-4.3.3.zip
diff --git a/wpa_supplicant/config_winreg.c b/wpa_supplicant/config_winreg.c
new file mode 100644
index 0000000..456d417
--- /dev/null
+++ b/wpa_supplicant/config_winreg.c
@@ -0,0 +1,980 @@
+/*
+ * WPA Supplicant / Configuration backend: Windows registry
+ * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This file implements a configuration backend for Windows registry. All the
+ * configuration information is stored in the registry and the format for
+ * network configuration fields is same as described in the sample
+ * configuration file, wpa_supplicant.conf.
+ *
+ * Configuration data is in
+ * \a HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant\\configs
+ * key. Each configuration profile has its own key under this. In terms of text
+ * files, each profile would map to a separate text file with possibly multiple
+ * networks. Under each profile, there is a networks key that lists all
+ * networks as a subkey. Each network has set of values in the same way as
+ * network block in the configuration file. In addition, blobs subkey has
+ * possible blobs as values.
+ *
+ * Example network configuration block:
+ * \verbatim
+HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000
+ ssid="example"
+ key_mgmt=WPA-PSK
+\endverbatim
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "uuid.h"
+#include "config.h"
+
+#ifndef WPA_KEY_ROOT
+#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE
+#endif
+#ifndef WPA_KEY_PREFIX
+#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant")
+#endif
+
+#ifdef UNICODE
+#define TSTR "%S"
+#else /* UNICODE */
+#define TSTR "%s"
+#endif /* UNICODE */
+
+
+static int wpa_config_read_blobs(struct wpa_config *config, HKEY hk)
+{
+ struct wpa_config_blob *blob;
+ int errors = 0;
+ HKEY bhk;
+ LONG ret;
+ DWORD i;
+
+ ret = RegOpenKeyEx(hk, TEXT("blobs"), 0, KEY_QUERY_VALUE, &bhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config "
+ "blobs key");
+ return 0; /* assume no blobs */
+ }
+
+ for (i = 0; ; i++) {
+#define TNAMELEN 255
+ TCHAR name[TNAMELEN];
+ char data[4096];
+ DWORD namelen, datalen, type;
+
+ namelen = TNAMELEN;
+ datalen = sizeof(data);
+ ret = RegEnumValue(bhk, i, name, &namelen, NULL, &type,
+ (LPBYTE) data, &datalen);
+
+ if (ret == ERROR_NO_MORE_ITEMS)
+ break;
+
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "RegEnumValue failed: 0x%x",
+ (unsigned int) ret);
+ break;
+ }
+
+ if (namelen >= TNAMELEN)
+ namelen = TNAMELEN - 1;
+ name[namelen] = TEXT('\0');
+ wpa_unicode2ascii_inplace(name);
+
+ if (datalen >= sizeof(data))
+ datalen = sizeof(data) - 1;
+
+ wpa_printf(MSG_MSGDUMP, "blob %d: field='%s' len %d",
+ (int) i, name, (int) datalen);
+
+ blob = os_zalloc(sizeof(*blob));
+ if (blob == NULL) {
+ errors++;
+ break;
+ }
+ blob->name = os_strdup((char *) name);
+ blob->data = os_malloc(datalen);
+ if (blob->name == NULL || blob->data == NULL) {
+ wpa_config_free_blob(blob);
+ errors++;
+ break;
+ }
+ os_memcpy(blob->data, data, datalen);
+ blob->len = datalen;
+
+ wpa_config_set_blob(config, blob);
+ }
+
+ RegCloseKey(bhk);
+
+ return errors ? -1 : 0;
+}
+
+
+static int wpa_config_read_reg_dword(HKEY hk, const TCHAR *name, int *_val)
+{
+ DWORD val, buflen;
+ LONG ret;
+
+ buflen = sizeof(val);
+ ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) &val, &buflen);
+ if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
+ wpa_printf(MSG_DEBUG, TSTR "=%d", name, (int) val);
+ *_val = val;
+ return 0;
+ }
+
+ return -1;
+}
+
+
+static char * wpa_config_read_reg_string(HKEY hk, const TCHAR *name)
+{
+ DWORD buflen;
+ LONG ret;
+ TCHAR *val;
+
+ buflen = 0;
+ ret = RegQueryValueEx(hk, name, NULL, NULL, NULL, &buflen);
+ if (ret != ERROR_SUCCESS)
+ return NULL;
+ val = os_malloc(buflen);
+ if (val == NULL)
+ return NULL;
+
+ ret = RegQueryValueEx(hk, name, NULL, NULL, (LPBYTE) val, &buflen);
+ if (ret != ERROR_SUCCESS) {
+ os_free(val);
+ return NULL;
+ }
+
+ wpa_unicode2ascii_inplace(val);
+ wpa_printf(MSG_DEBUG, TSTR "=%s", name, (char *) val);
+ return (char *) val;
+}
+
+
+#ifdef CONFIG_WPS
+static int wpa_config_read_global_uuid(struct wpa_config *config, HKEY hk)
+{
+ char *str;
+ int ret = 0;
+
+ str = wpa_config_read_reg_string(hk, TEXT("uuid"));
+ if (str == NULL)
+ return 0;
+
+ if (uuid_str2bin(str, config->uuid))
+ ret = -1;
+
+ os_free(str);
+
+ return ret;
+}
+
+
+static int wpa_config_read_global_os_version(struct wpa_config *config,
+ HKEY hk)
+{
+ char *str;
+ int ret = 0;
+
+ str = wpa_config_read_reg_string(hk, TEXT("os_version"));
+ if (str == NULL)
+ return 0;
+
+ if (hexstr2bin(str, config->os_version, 4))
+ ret = -1;
+
+ os_free(str);
+
+ return ret;
+}
+#endif /* CONFIG_WPS */
+
+
+static int wpa_config_read_global(struct wpa_config *config, HKEY hk)
+{
+ int errors = 0;
+
+ wpa_config_read_reg_dword(hk, TEXT("ap_scan"), &config->ap_scan);
+ wpa_config_read_reg_dword(hk, TEXT("fast_reauth"),
+ &config->fast_reauth);
+ wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"),
+ (int *) &config->dot11RSNAConfigPMKLifetime);
+ wpa_config_read_reg_dword(hk,
+ TEXT("dot11RSNAConfigPMKReauthThreshold"),
+ (int *)
+ &config->dot11RSNAConfigPMKReauthThreshold);
+ wpa_config_read_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"),
+ (int *) &config->dot11RSNAConfigSATimeout);
+ wpa_config_read_reg_dword(hk, TEXT("update_config"),
+ &config->update_config);
+
+ if (wpa_config_read_reg_dword(hk, TEXT("eapol_version"),
+ &config->eapol_version) == 0) {
+ if (config->eapol_version < 1 ||
+ config->eapol_version > 2) {
+ wpa_printf(MSG_ERROR, "Invalid EAPOL version (%d)",
+ config->eapol_version);
+ errors++;
+ }
+ }
+
+ config->ctrl_interface = wpa_config_read_reg_string(
+ hk, TEXT("ctrl_interface"));
+
+#ifdef CONFIG_WPS
+ if (wpa_config_read_global_uuid(config, hk))
+ errors++;
+ config->device_name = wpa_config_read_reg_string(
+ hk, TEXT("device_name"));
+ config->manufacturer = wpa_config_read_reg_string(
+ hk, TEXT("manufacturer"));
+ config->model_name = wpa_config_read_reg_string(
+ hk, TEXT("model_name"));
+ config->serial_number = wpa_config_read_reg_string(
+ hk, TEXT("serial_number"));
+ config->device_type = wpa_config_read_reg_string(
+ hk, TEXT("device_type"));
+ if (wpa_config_read_global_os_version(config, hk))
+ errors++;
+ wpa_config_read_reg_dword(hk, TEXT("wps_cred_processing"),
+ &config->wps_cred_processing);
+#endif /* CONFIG_WPS */
+
+ return errors ? -1 : 0;
+}
+
+
+static struct wpa_ssid * wpa_config_read_network(HKEY hk, const TCHAR *netw,
+ int id)
+{
+ HKEY nhk;
+ LONG ret;
+ DWORD i;
+ struct wpa_ssid *ssid;
+ int errors = 0;
+
+ ret = RegOpenKeyEx(hk, netw, 0, KEY_QUERY_VALUE, &nhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "Could not open wpa_supplicant config "
+ "network '" TSTR "'", netw);
+ return NULL;
+ }
+
+ wpa_printf(MSG_MSGDUMP, "Start of a new network '" TSTR "'", netw);
+ ssid = os_zalloc(sizeof(*ssid));
+ if (ssid == NULL) {
+ RegCloseKey(nhk);
+ return NULL;
+ }
+ ssid->id = id;
+
+ wpa_config_set_network_defaults(ssid);
+
+ for (i = 0; ; i++) {
+ TCHAR name[255], data[1024];
+ DWORD namelen, datalen, type;
+
+ namelen = 255;
+ datalen = sizeof(data);
+ ret = RegEnumValue(nhk, i, name, &namelen, NULL, &type,
+ (LPBYTE) data, &datalen);
+
+ if (ret == ERROR_NO_MORE_ITEMS)
+ break;
+
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "RegEnumValue failed: 0x%x",
+ (unsigned int) ret);
+ break;
+ }
+
+ if (namelen >= 255)
+ namelen = 255 - 1;
+ name[namelen] = TEXT('\0');
+
+ if (datalen >= 1024)
+ datalen = 1024 - 1;
+ data[datalen] = TEXT('\0');
+
+ wpa_unicode2ascii_inplace(name);
+ wpa_unicode2ascii_inplace(data);
+ if (wpa_config_set(ssid, (char *) name, (char *) data, 0) < 0)
+ errors++;
+ }
+
+ RegCloseKey(nhk);
+
+ if (ssid->passphrase) {
+ if (ssid->psk_set) {
+ wpa_printf(MSG_ERROR, "Both PSK and passphrase "
+ "configured for network '" TSTR "'.", netw);
+ errors++;
+ }
+ wpa_config_update_psk(ssid);
+ }
+
+ if ((ssid->key_mgmt & (WPA_KEY_MGMT_PSK | WPA_KEY_MGMT_FT_PSK |
+ WPA_KEY_MGMT_PSK_SHA256)) &&
+ !ssid->psk_set) {
+ wpa_printf(MSG_ERROR, "WPA-PSK accepted for key management, "
+ "but no PSK configured for network '" TSTR "'.",
+ netw);
+ errors++;
+ }
+
+ if ((ssid->group_cipher & WPA_CIPHER_CCMP) &&
+ !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
+ !(ssid->pairwise_cipher & WPA_CIPHER_NONE)) {
+ /* Group cipher cannot be stronger than the pairwise cipher. */
+ wpa_printf(MSG_DEBUG, "Removed CCMP from group cipher "
+ "list since it was not allowed for pairwise "
+ "cipher for network '" TSTR "'.", netw);
+ ssid->group_cipher &= ~WPA_CIPHER_CCMP;
+ }
+
+ if (errors) {
+ wpa_config_free_ssid(ssid);
+ ssid = NULL;
+ }
+
+ return ssid;
+}
+
+
+static int wpa_config_read_networks(struct wpa_config *config, HKEY hk)
+{
+ HKEY nhk;
+ struct wpa_ssid *ssid, *tail = NULL, *head = NULL;
+ int errors = 0;
+ LONG ret;
+ DWORD i;
+
+ ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_ENUMERATE_SUB_KEYS,
+ &nhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "Could not open wpa_supplicant networks "
+ "registry key");
+ return -1;
+ }
+
+ for (i = 0; ; i++) {
+ TCHAR name[255];
+ DWORD namelen;
+
+ namelen = 255;
+ ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL,
+ NULL);
+
+ if (ret == ERROR_NO_MORE_ITEMS)
+ break;
+
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x",
+ (unsigned int) ret);
+ break;
+ }
+
+ if (namelen >= 255)
+ namelen = 255 - 1;
+ name[namelen] = '\0';
+
+ ssid = wpa_config_read_network(nhk, name, i);
+ if (ssid == NULL) {
+ wpa_printf(MSG_ERROR, "Failed to parse network "
+ "profile '%s'.", name);
+ errors++;
+ continue;
+ }
+ if (head == NULL) {
+ head = tail = ssid;
+ } else {
+ tail->next = ssid;
+ tail = ssid;
+ }
+ if (wpa_config_add_prio_network(config, ssid)) {
+ wpa_printf(MSG_ERROR, "Failed to add network profile "
+ "'%s' to priority list.", name);
+ errors++;
+ continue;
+ }
+ }
+
+ RegCloseKey(nhk);
+
+ config->ssid = head;
+
+ return errors ? -1 : 0;
+}
+
+
+struct wpa_config * wpa_config_read(const char *name)
+{
+ TCHAR buf[256];
+ int errors = 0;
+ struct wpa_config *config;
+ HKEY hk;
+ LONG ret;
+
+ config = wpa_config_alloc_empty(NULL, NULL);
+ if (config == NULL)
+ return NULL;
+ wpa_printf(MSG_DEBUG, "Reading configuration profile '%s'", name);
+
+#ifdef UNICODE
+ _snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name);
+#else /* UNICODE */
+ os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name);
+#endif /* UNICODE */
+
+ ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_QUERY_VALUE, &hk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "Could not open wpa_supplicant "
+ "configuration registry HKLM\\" TSTR, buf);
+ os_free(config);
+ return NULL;
+ }
+
+ if (wpa_config_read_global(config, hk))
+ errors++;
+
+ if (wpa_config_read_networks(config, hk))
+ errors++;
+
+ if (wpa_config_read_blobs(config, hk))
+ errors++;
+
+ wpa_config_debug_dump_networks(config);
+
+ RegCloseKey(hk);
+
+ if (errors) {
+ wpa_config_free(config);
+ config = NULL;
+ }
+
+ return config;
+}
+
+
+static int wpa_config_write_reg_dword(HKEY hk, const TCHAR *name, int val,
+ int def)
+{
+ LONG ret;
+ DWORD _val = val;
+
+ if (val == def) {
+ RegDeleteValue(hk, name);
+ return 0;
+ }
+
+ ret = RegSetValueEx(hk, name, 0, REG_DWORD, (LPBYTE) &_val,
+ sizeof(_val));
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "WINREG: Failed to set %s=%d: error %d",
+ name, val, (int) GetLastError());
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_config_write_reg_string(HKEY hk, const char *name,
+ const char *val)
+{
+ LONG ret;
+ TCHAR *_name, *_val;
+
+ _name = wpa_strdup_tchar(name);
+ if (_name == NULL)
+ return -1;
+
+ if (val == NULL) {
+ RegDeleteValue(hk, _name);
+ os_free(_name);
+ return 0;
+ }
+
+ _val = wpa_strdup_tchar(val);
+ if (_val == NULL) {
+ os_free(_name);
+ return -1;
+ }
+ ret = RegSetValueEx(hk, _name, 0, REG_SZ, (BYTE *) _val,
+ (os_strlen(val) + 1) * sizeof(TCHAR));
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "WINREG: Failed to set %s='%s': "
+ "error %d", name, val, (int) GetLastError());
+ os_free(_name);
+ os_free(_val);
+ return -1;
+ }
+
+ os_free(_name);
+ os_free(_val);
+ return 0;
+}
+
+
+static int wpa_config_write_global(struct wpa_config *config, HKEY hk)
+{
+#ifdef CONFIG_CTRL_IFACE
+ wpa_config_write_reg_string(hk, "ctrl_interface",
+ config->ctrl_interface);
+#endif /* CONFIG_CTRL_IFACE */
+
+ wpa_config_write_reg_dword(hk, TEXT("eapol_version"),
+ config->eapol_version,
+ DEFAULT_EAPOL_VERSION);
+ wpa_config_write_reg_dword(hk, TEXT("ap_scan"), config->ap_scan,
+ DEFAULT_AP_SCAN);
+ wpa_config_write_reg_dword(hk, TEXT("fast_reauth"),
+ config->fast_reauth, DEFAULT_FAST_REAUTH);
+ wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigPMKLifetime"),
+ config->dot11RSNAConfigPMKLifetime, 0);
+ wpa_config_write_reg_dword(hk,
+ TEXT("dot11RSNAConfigPMKReauthThreshold"),
+ config->dot11RSNAConfigPMKReauthThreshold,
+ 0);
+ wpa_config_write_reg_dword(hk, TEXT("dot11RSNAConfigSATimeout"),
+ config->dot11RSNAConfigSATimeout, 0);
+ wpa_config_write_reg_dword(hk, TEXT("update_config"),
+ config->update_config,
+ 0);
+#ifdef CONFIG_WPS
+ if (!is_nil_uuid(config->uuid)) {
+ char buf[40];
+ uuid_bin2str(config->uuid, buf, sizeof(buf));
+ wpa_config_write_reg_string(hk, "uuid", buf);
+ }
+ wpa_config_write_reg_string(hk, "device_name", config->device_name);
+ wpa_config_write_reg_string(hk, "manufacturer", config->manufacturer);
+ wpa_config_write_reg_string(hk, "model_name", config->model_name);
+ wpa_config_write_reg_string(hk, "model_number", config->model_number);
+ wpa_config_write_reg_string(hk, "serial_number",
+ config->serial_number);
+ wpa_config_write_reg_string(hk, "device_type", config->device_type);
+ if (WPA_GET_BE32(config->os_version)) {
+ char vbuf[10];
+ os_snprintf(vbuf, sizeof(vbuf), "%08x",
+ WPA_GET_BE32(config->os_version));
+ wpa_config_write_reg_string(hk, "os_version", vbuf);
+ }
+ wpa_config_write_reg_dword(hk, TEXT("wps_cred_processing"),
+ config->wps_cred_processing, 0);
+#endif /* CONFIG_WPS */
+
+ return 0;
+}
+
+
+static int wpa_config_delete_subkeys(HKEY hk, const TCHAR *key)
+{
+ HKEY nhk;
+ int i, errors = 0;
+ LONG ret;
+
+ ret = RegOpenKeyEx(hk, key, 0, KEY_ENUMERATE_SUB_KEYS | DELETE, &nhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "WINREG: Could not open key '" TSTR
+ "' for subkey deletion: error 0x%x (%d)", key,
+ (unsigned int) ret, (int) GetLastError());
+ return 0;
+ }
+
+ for (i = 0; ; i++) {
+ TCHAR name[255];
+ DWORD namelen;
+
+ namelen = 255;
+ ret = RegEnumKeyEx(nhk, i, name, &namelen, NULL, NULL, NULL,
+ NULL);
+
+ if (ret == ERROR_NO_MORE_ITEMS)
+ break;
+
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "RegEnumKeyEx failed: 0x%x (%d)",
+ (unsigned int) ret, (int) GetLastError());
+ break;
+ }
+
+ if (namelen >= 255)
+ namelen = 255 - 1;
+ name[namelen] = TEXT('\0');
+
+ ret = RegDeleteKey(nhk, name);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "RegDeleteKey failed: 0x%x (%d)",
+ (unsigned int) ret, (int) GetLastError());
+ errors++;
+ }
+ }
+
+ RegCloseKey(nhk);
+
+ return errors ? -1 : 0;
+}
+
+
+static void write_str(HKEY hk, const char *field, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, field);
+ if (value == NULL)
+ return;
+ wpa_config_write_reg_string(hk, field, value);
+ os_free(value);
+}
+
+
+static void write_int(HKEY hk, const char *field, int value, int def)
+{
+ char val[20];
+ if (value == def)
+ return;
+ os_snprintf(val, sizeof(val), "%d", value);
+ wpa_config_write_reg_string(hk, field, val);
+}
+
+
+static void write_bssid(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, "bssid");
+ if (value == NULL)
+ return;
+ wpa_config_write_reg_string(hk, "bssid", value);
+ os_free(value);
+}
+
+
+static void write_psk(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value = wpa_config_get(ssid, "psk");
+ if (value == NULL)
+ return;
+ wpa_config_write_reg_string(hk, "psk", value);
+ os_free(value);
+}
+
+
+static void write_proto(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (ssid->proto == DEFAULT_PROTO)
+ return;
+
+ value = wpa_config_get(ssid, "proto");
+ if (value == NULL)
+ return;
+ if (value[0])
+ wpa_config_write_reg_string(hk, "proto", value);
+ os_free(value);
+}
+
+
+static void write_key_mgmt(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (ssid->key_mgmt == DEFAULT_KEY_MGMT)
+ return;
+
+ value = wpa_config_get(ssid, "key_mgmt");
+ if (value == NULL)
+ return;
+ if (value[0])
+ wpa_config_write_reg_string(hk, "key_mgmt", value);
+ os_free(value);
+}
+
+
+static void write_pairwise(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (ssid->pairwise_cipher == DEFAULT_PAIRWISE)
+ return;
+
+ value = wpa_config_get(ssid, "pairwise");
+ if (value == NULL)
+ return;
+ if (value[0])
+ wpa_config_write_reg_string(hk, "pairwise", value);
+ os_free(value);
+}
+
+
+static void write_group(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (ssid->group_cipher == DEFAULT_GROUP)
+ return;
+
+ value = wpa_config_get(ssid, "group");
+ if (value == NULL)
+ return;
+ if (value[0])
+ wpa_config_write_reg_string(hk, "group", value);
+ os_free(value);
+}
+
+
+static void write_auth_alg(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ if (ssid->auth_alg == 0)
+ return;
+
+ value = wpa_config_get(ssid, "auth_alg");
+ if (value == NULL)
+ return;
+ if (value[0])
+ wpa_config_write_reg_string(hk, "auth_alg", value);
+ os_free(value);
+}
+
+
+#ifdef IEEE8021X_EAPOL
+static void write_eap(HKEY hk, struct wpa_ssid *ssid)
+{
+ char *value;
+
+ value = wpa_config_get(ssid, "eap");
+ if (value == NULL)
+ return;
+
+ if (value[0])
+ wpa_config_write_reg_string(hk, "eap", value);
+ os_free(value);
+}
+#endif /* IEEE8021X_EAPOL */
+
+
+static void write_wep_key(HKEY hk, int idx, struct wpa_ssid *ssid)
+{
+ char field[20], *value;
+
+ os_snprintf(field, sizeof(field), "wep_key%d", idx);
+ value = wpa_config_get(ssid, field);
+ if (value) {
+ wpa_config_write_reg_string(hk, field, value);
+ os_free(value);
+ }
+}
+
+
+static int wpa_config_write_network(HKEY hk, struct wpa_ssid *ssid, int id)
+{
+ int i, errors = 0;
+ HKEY nhk, netw;
+ LONG ret;
+ TCHAR name[5];
+
+ ret = RegOpenKeyEx(hk, TEXT("networks"), 0, KEY_CREATE_SUB_KEY, &nhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "WINREG: Could not open networks key "
+ "for subkey addition: error 0x%x (%d)",
+ (unsigned int) ret, (int) GetLastError());
+ return 0;
+ }
+
+#ifdef UNICODE
+ wsprintf(name, L"%04d", id);
+#else /* UNICODE */
+ os_snprintf(name, sizeof(name), "%04d", id);
+#endif /* UNICODE */
+ ret = RegCreateKeyEx(nhk, name, 0, NULL, 0, KEY_WRITE, NULL, &netw,
+ NULL);
+ RegCloseKey(nhk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "WINREG: Could not add network key '%s':"
+ " error 0x%x (%d)",
+ name, (unsigned int) ret, (int) GetLastError());
+ return -1;
+ }
+
+#define STR(t) write_str(netw, #t, ssid)
+#define INT(t) write_int(netw, #t, ssid->t, 0)
+#define INTe(t) write_int(netw, #t, ssid->eap.t, 0)
+#define INT_DEF(t, def) write_int(netw, #t, ssid->t, def)
+#define INT_DEFe(t, def) write_int(netw, #t, ssid->eap.t, def)
+
+ STR(ssid);
+ INT(scan_ssid);
+ write_bssid(netw, ssid);
+ write_psk(netw, ssid);
+ write_proto(netw, ssid);
+ write_key_mgmt(netw, ssid);
+ write_pairwise(netw, ssid);
+ write_group(netw, ssid);
+ write_auth_alg(netw, ssid);
+#ifdef IEEE8021X_EAPOL
+ write_eap(netw, ssid);
+ STR(identity);
+ STR(anonymous_identity);
+ STR(password);
+ STR(ca_cert);
+ STR(ca_path);
+ STR(client_cert);
+ STR(private_key);
+ STR(private_key_passwd);
+ STR(dh_file);
+ STR(subject_match);
+ STR(altsubject_match);
+ STR(ca_cert2);
+ STR(ca_path2);
+ STR(client_cert2);
+ STR(private_key2);
+ STR(private_key2_passwd);
+ STR(dh_file2);
+ STR(subject_match2);
+ STR(altsubject_match2);
+ STR(phase1);
+ STR(phase2);
+ STR(pcsc);
+ STR(pin);
+ STR(engine_id);
+ STR(key_id);
+ STR(cert_id);
+ STR(ca_cert_id);
+ STR(key2_id);
+ STR(pin2);
+ STR(engine2_id);
+ STR(cert2_id);
+ STR(ca_cert2_id);
+ INTe(engine);
+ INTe(engine2);
+ INT_DEF(eapol_flags, DEFAULT_EAPOL_FLAGS);
+#endif /* IEEE8021X_EAPOL */
+ for (i = 0; i < 4; i++)
+ write_wep_key(netw, i, ssid);
+ INT(wep_tx_keyidx);
+ INT(priority);
+#ifdef IEEE8021X_EAPOL
+ INT_DEF(eap_workaround, DEFAULT_EAP_WORKAROUND);
+ STR(pac_file);
+ INT_DEFe(fragment_size, DEFAULT_FRAGMENT_SIZE);
+#endif /* IEEE8021X_EAPOL */
+ INT(mode);
+ INT(proactive_key_caching);
+ INT(disabled);
+ INT(peerkey);
+#ifdef CONFIG_IEEE80211W
+ INT(ieee80211w);
+#endif /* CONFIG_IEEE80211W */
+ STR(id_str);
+
+#undef STR
+#undef INT
+#undef INT_DEF
+
+ RegCloseKey(netw);
+
+ return errors ? -1 : 0;
+}
+
+
+static int wpa_config_write_blob(HKEY hk, struct wpa_config_blob *blob)
+{
+ HKEY bhk;
+ LONG ret;
+ TCHAR *name;
+
+ ret = RegCreateKeyEx(hk, TEXT("blobs"), 0, NULL, 0, KEY_WRITE, NULL,
+ &bhk, NULL);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_DEBUG, "WINREG: Could not add blobs key: "
+ "error 0x%x (%d)",
+ (unsigned int) ret, (int) GetLastError());
+ return -1;
+ }
+
+ name = wpa_strdup_tchar(blob->name);
+ ret = RegSetValueEx(bhk, name, 0, REG_BINARY, blob->data,
+ blob->len);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "WINREG: Failed to set blob %s': "
+ "error 0x%x (%d)", blob->name, (unsigned int) ret,
+ (int) GetLastError());
+ RegCloseKey(bhk);
+ os_free(name);
+ return -1;
+ }
+ os_free(name);
+
+ RegCloseKey(bhk);
+
+ return 0;
+}
+
+
+int wpa_config_write(const char *name, struct wpa_config *config)
+{
+ TCHAR buf[256];
+ HKEY hk;
+ LONG ret;
+ int errors = 0;
+ struct wpa_ssid *ssid;
+ struct wpa_config_blob *blob;
+ int id;
+
+ wpa_printf(MSG_DEBUG, "Writing configuration file '%s'", name);
+
+#ifdef UNICODE
+ _snwprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%S"), name);
+#else /* UNICODE */
+ os_snprintf(buf, 256, WPA_KEY_PREFIX TEXT("\\configs\\%s"), name);
+#endif /* UNICODE */
+
+ ret = RegOpenKeyEx(WPA_KEY_ROOT, buf, 0, KEY_SET_VALUE | DELETE, &hk);
+ if (ret != ERROR_SUCCESS) {
+ wpa_printf(MSG_ERROR, "Could not open wpa_supplicant "
+ "configuration registry %s: error %d", buf,
+ (int) GetLastError());
+ return -1;
+ }
+
+ if (wpa_config_write_global(config, hk)) {
+ wpa_printf(MSG_ERROR, "Failed to write global configuration "
+ "data");
+ errors++;
+ }
+
+ wpa_config_delete_subkeys(hk, TEXT("networks"));
+ for (ssid = config->ssid, id = 0; ssid; ssid = ssid->next, id++) {
+ if (ssid->key_mgmt == WPA_KEY_MGMT_WPS)
+ continue; /* do not save temporary WPS networks */
+ if (wpa_config_write_network(hk, ssid, id))
+ errors++;
+ }
+
+ RegDeleteKey(hk, TEXT("blobs"));
+ for (blob = config->blobs; blob; blob = blob->next) {
+ if (wpa_config_write_blob(hk, blob))
+ errors++;
+ }
+
+ RegCloseKey(hk);
+
+ wpa_printf(MSG_DEBUG, "Configuration '%s' written %ssuccessfully",
+ name, errors ? "un" : "");
+ return errors ? -1 : 0;
+}
diff --git a/wpa_supplicant/ctrl_iface_dbus.c b/wpa_supplicant/ctrl_iface_dbus.c
index c4e329c..8e69f4d 100644
--- a/wpa_supplicant/ctrl_iface_dbus.c
+++ b/wpa_supplicant/ctrl_iface_dbus.c
@@ -540,6 +540,8 @@ static DBusHandlerResult wpas_iface_message_handler(DBusConnection *connection,
wpa_s);
else if (!strcmp(method, "state"))
reply = wpas_dbus_iface_get_state(message, wpa_s);
+ else if (!strcmp(method, "scanning"))
+ reply = wpas_dbus_iface_get_scanning(message, wpa_s);
else if (!strcmp(method, "setBlobs"))
reply = wpas_dbus_iface_set_blobs(message, wpa_s);
else if (!strcmp(method, "removeBlobs"))
@@ -603,6 +605,9 @@ static DBusHandlerResult wpas_message_handler(DBusConnection *connection,
} else if (!strcmp(method, "getInterface")) {
reply = wpas_dbus_global_get_interface(
message, ctrl_iface->global);
+ } else if (!strcmp(method, "setDebugParams")) {
+ reply = wpas_dbus_global_set_debugparams(
+ message, ctrl_iface->global);
}
}
@@ -741,6 +746,58 @@ out:
}
+/**
+ * wpa_supplicant_dbus_notify_scanning - send scanning status
+ * @wpa_s: %wpa_supplicant network interface data
+ * Returns: 0 on success, -1 on failure
+ *
+ * Notify listeners of interface scanning state changes
+ */
+void wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
+{
+ struct ctrl_iface_dbus_priv *iface = wpa_s->global->dbus_ctrl_iface;
+ DBusMessage *_signal;
+ const char *path;
+ dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
+
+ /* Do nothing if the control interface is not turned on */
+ if (iface == NULL)
+ return;
+
+ path = wpa_supplicant_get_dbus_path(wpa_s);
+ if (path == NULL) {
+ perror("wpa_supplicant_dbus_notify_scanning[dbus]: interface "
+ "didn't have a dbus path");
+ wpa_printf(MSG_ERROR,
+ "%s[dbus]: interface didn't have a dbus path; "
+ "can't send scanning signal.", __FUNCTION__);
+ return;
+ }
+ _signal = dbus_message_new_signal(path, WPAS_DBUS_IFACE_INTERFACE,
+ "Scanning");
+ if (_signal == NULL) {
+ perror("wpa_supplicant_dbus_notify_scanning[dbus]: couldn't "
+ "create dbus signal; likely out of memory");
+ wpa_printf(MSG_ERROR, "%s[dbus]: dbus control interface: not "
+ "enough memory to send scan results signal.",
+ __FUNCTION__);
+ return;
+ }
+
+ if (dbus_message_append_args(_signal,
+ DBUS_TYPE_BOOLEAN, &scanning,
+ DBUS_TYPE_INVALID)) {
+ dbus_connection_send(iface->con, _signal, NULL);
+ } else {
+ perror("wpa_supplicant_dbus_notify_scanning[dbus]: not enough "
+ "memory to construct signal.");
+ wpa_printf(MSG_ERROR, "%s[dbus]: not enough memory to "
+ "construct signal.", __FUNCTION__);
+ }
+ dbus_message_unref(_signal);
+}
+
+
#ifdef CONFIG_WPS
void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
const struct wps_credential *cred)
@@ -795,6 +852,11 @@ void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
out:
dbus_message_unref(_signal);
}
+#else /* CONFIG_WPS */
+void wpa_supplicant_dbus_notify_wps_cred(struct wpa_supplicant *wpa_s,
+ const struct wps_credential *cred)
+{
+}
#endif /* CONFIG_WPS */
diff --git a/wpa_supplicant/ctrl_iface_dbus.h b/wpa_supplicant/ctrl_iface_dbus.h
index 68919de..059a373 100644
--- a/wpa_supplicant/ctrl_iface_dbus.h
+++ b/wpa_supplicant/ctrl_iface_dbus.h
@@ -83,6 +83,7 @@ struct ctrl_iface_dbus_priv *
wpa_supplicant_dbus_ctrl_iface_init(struct wpa_global *global);
void wpa_supplicant_dbus_ctrl_iface_deinit(struct ctrl_iface_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,
wpa_states new_state,
wpa_states old_state);
@@ -127,6 +128,11 @@ wpa_supplicant_dbus_notify_scan_results(struct wpa_supplicant *wpa_s)
}
static inline void
+wpa_supplicant_dbus_notify_scanning(struct wpa_supplicant *wpa_s)
+{
+}
+
+static inline void
wpa_supplicant_dbus_notify_state_change(struct wpa_supplicant *wpa_s,
wpa_states new_state,
wpa_states old_state)
diff --git a/wpa_supplicant/ctrl_iface_dbus_handlers.c b/wpa_supplicant/ctrl_iface_dbus_handlers.c
index 3c29804..d3250d3 100644
--- a/wpa_supplicant/ctrl_iface_dbus_handlers.c
+++ b/wpa_supplicant/ctrl_iface_dbus_handlers.c
@@ -24,7 +24,11 @@
#include "ieee802_11_defs.h"
#include "wpas_glue.h"
#include "eapol_supp/eapol_supp_sm.h"
+#include "wpa.h"
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+extern int wpa_debug_timestamp;
/**
* wpas_dbus_new_invalid_opts_error - Return a new invalid options error message
@@ -277,6 +281,51 @@ out:
return reply;
}
+/**
+ * wpas_dbus_global_set_debugparams- Set the debug params
+ * @message: Pointer to incoming dbus message
+ * @global: %wpa_supplicant global data structure
+ * Returns: a dbus message containing a UINT32 indicating success (1) or
+ * failure (0), or returns a dbus error message with more information
+ *
+ * Handler function for "setDebugParams" method call. Handles requests
+ * by dbus clients for the object path of an specific network interface.
+ */
+DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
+ struct wpa_global *global)
+{
+ DBusMessage *reply = NULL;
+ int debug_level;
+ dbus_bool_t debug_timestamp;
+ dbus_bool_t debug_show_keys;
+
+ if (!dbus_message_get_args(message, NULL,
+ DBUS_TYPE_INT32, &debug_level,
+ DBUS_TYPE_BOOLEAN, &debug_timestamp,
+ DBUS_TYPE_BOOLEAN, &debug_show_keys,
+ DBUS_TYPE_INVALID)) {
+ reply = wpas_dbus_new_invalid_opts_error(message, NULL);
+ goto out;
+ }
+
+ /* check for allowed debuglevels */
+ if (debug_level != MSG_MSGDUMP &&
+ debug_level != MSG_DEBUG &&
+ debug_level != MSG_INFO &&
+ debug_level != MSG_WARNING &&
+ debug_level != MSG_ERROR) {
+ reply = wpas_dbus_new_invalid_opts_error(message, NULL);
+ goto out;
+ }
+
+ wpa_debug_level = debug_level;
+ wpa_debug_timestamp = debug_timestamp ? 1 : 0;
+ wpa_debug_show_keys = debug_show_keys ? 1 : 0;
+ reply = wpas_dbus_new_success_reply(message);
+
+out:
+ return reply;
+}
/**
* wpas_dbus_iface_scan - Request a wireless scan on an interface
@@ -1246,8 +1295,11 @@ DBusMessage * wpas_dbus_iface_set_smartcard_modules(
wpa_s->conf->pkcs11_module_path = pkcs11_module_path;
#endif /* EAP_TLS_OPENSSL */
+ wpa_sm_set_eapol(wpa_s->wpa, NULL);
eapol_sm_deinit(wpa_s->eapol);
+ wpa_s->eapol = NULL;
wpa_supplicant_init_eapol(wpa_s);
+ wpa_sm_set_eapol(wpa_s->wpa, wpa_s->eapol);
return wpas_dbus_new_success_reply(message);
@@ -1285,6 +1337,35 @@ DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
/**
+ * wpas_dbus_iface_get_scanning - Get interface scanning state
+ * @message: Pointer to incoming dbus message
+ * @wpa_s: wpa_supplicant structure for a network interface
+ * Returns: A dbus message containing whether the interface is scanning
+ *
+ * Handler function for "scanning" method call.
+ */
+DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
+ struct wpa_supplicant *wpa_s)
+{
+ DBusMessage *reply = NULL;
+ dbus_bool_t scanning = wpa_s->scanning ? TRUE : FALSE;
+
+ reply = dbus_message_new_method_return(message);
+ if (reply != NULL) {
+ dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &scanning,
+ DBUS_TYPE_INVALID);
+ } else {
+ perror("wpas_dbus_iface_get_scanning[dbus]: out of "
+ "memory.");
+ wpa_printf(MSG_ERROR, "dbus control interface: not enough "
+ "memory to return scanning state.");
+ }
+
+ return reply;
+}
+
+
+/**
* wpas_dbus_iface_set_blobs - Store named binary blobs (ie, for certificates)
* @message: Pointer to incoming dbus message
* @wpa_s: %wpa_supplicant data structure
diff --git a/wpa_supplicant/ctrl_iface_dbus_handlers.h b/wpa_supplicant/ctrl_iface_dbus_handlers.h
index 9660f95..376d835 100644
--- a/wpa_supplicant/ctrl_iface_dbus_handlers.h
+++ b/wpa_supplicant/ctrl_iface_dbus_handlers.h
@@ -28,6 +28,9 @@ DBusMessage * wpas_dbus_global_remove_interface(DBusMessage *message,
DBusMessage * wpas_dbus_global_get_interface(DBusMessage *message,
struct wpa_global *global);
+DBusMessage * wpas_dbus_global_set_debugparams(DBusMessage *message,
+ struct wpa_global *global);
+
DBusMessage * wpas_dbus_iface_scan(DBusMessage *message,
struct wpa_supplicant *wpa_s);
@@ -74,6 +77,9 @@ DBusMessage * wpas_dbus_iface_set_smartcard_modules(
DBusMessage * wpas_dbus_iface_get_state(DBusMessage *message,
struct wpa_supplicant *wpa_s);
+DBusMessage * wpas_dbus_iface_get_scanning(DBusMessage *message,
+ struct wpa_supplicant *wpa_s);
+
DBusMessage * wpas_dbus_iface_set_blobs(DBusMessage *message,
struct wpa_supplicant *wpa_s);
diff --git a/wpa_supplicant/ctrl_iface_named_pipe.c b/wpa_supplicant/ctrl_iface_named_pipe.c
new file mode 100644
index 0000000..e8b53b1
--- /dev/null
+++ b/wpa_supplicant/ctrl_iface_named_pipe.c
@@ -0,0 +1,835 @@
+/*
+ * WPA Supplicant / Windows Named Pipe -based control interface
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "config.h"
+#include "eapol_supp/eapol_supp_sm.h"
+#include "wpa_supplicant_i.h"
+#include "ctrl_iface.h"
+#include "wpa_ctrl.h"
+
+#ifdef __MINGW32_VERSION
+/* mingw-w32api v3.1 does not yet include sddl.h, so define needed parts here
+ */
+#define SDDL_REVISION_1 1
+BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorA(
+ LPCSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG);
+BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW(
+ LPCWSTR, DWORD, PSECURITY_DESCRIPTOR *, PULONG);
+#ifdef UNICODE
+#define ConvertStringSecurityDescriptorToSecurityDescriptor \
+ConvertStringSecurityDescriptorToSecurityDescriptorW
+#else
+#define ConvertStringSecurityDescriptorToSecurityDescriptor \
+ConvertStringSecurityDescriptorToSecurityDescriptorA
+#endif
+#else /* __MINGW32_VERSION */
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#include <sddl.h>
+#endif /* __MINGW32_VERSION */
+
+#ifndef WPA_SUPPLICANT_NAMED_PIPE
+#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
+#endif
+#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
+
+/* Per-interface ctrl_iface */
+
+#define REQUEST_BUFSIZE 256
+#define REPLY_BUFSIZE 4096
+
+struct ctrl_iface_priv;
+
+/**
+ * struct wpa_ctrl_dst - Internal data structure of control interface clients
+ *
+ * This structure is used to store information about registered control
+ * interface monitors into struct wpa_supplicant. This data is private to
+ * ctrl_iface_named_pipe.c and should not be touched directly from other files.
+ */
+struct wpa_ctrl_dst {
+ /* Note: OVERLAPPED must be the first member of struct wpa_ctrl_dst */
+ OVERLAPPED overlap;
+ struct wpa_ctrl_dst *next, *prev;
+ struct ctrl_iface_priv *priv;
+ HANDLE pipe;
+ int attached;
+ int debug_level;
+ int errors;
+ char req_buf[REQUEST_BUFSIZE];
+ char *rsp_buf;
+ int used;
+};
+
+
+struct ctrl_iface_priv {
+ struct wpa_supplicant *wpa_s;
+ struct wpa_ctrl_dst *ctrl_dst;
+ SECURITY_ATTRIBUTES attr;
+ int sec_attr_set;
+};
+
+
+static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+ int level, const char *buf,
+ size_t len);
+
+static void ctrl_close_pipe(struct wpa_ctrl_dst *dst);
+static void wpa_supplicant_ctrl_iface_receive(void *, void *);
+static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes,
+ LPOVERLAPPED overlap);
+
+struct wpa_global_dst;
+static void global_close_pipe(struct wpa_global_dst *dst);
+static void wpa_supplicant_global_iface_receive(void *eloop_data,
+ void *user_ctx);
+static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes,
+ LPOVERLAPPED overlap);
+
+
+static int ctrl_broken_pipe(HANDLE pipe, int used)
+{
+ DWORD err;
+
+ if (PeekNamedPipe(pipe, NULL, 0, NULL, NULL, NULL))
+ return 0;
+
+ err = GetLastError();
+ if (err == ERROR_BROKEN_PIPE || (err == ERROR_BAD_PIPE && used))
+ return 1;
+ return 0;
+}
+
+
+static void ctrl_flush_broken_pipes(struct ctrl_iface_priv *priv)
+{
+ struct wpa_ctrl_dst *dst, *next;
+
+ dst = priv->ctrl_dst;
+
+ while (dst) {
+ next = dst->next;
+ if (ctrl_broken_pipe(dst->pipe, dst->used)) {
+ wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p",
+ dst);
+ ctrl_close_pipe(dst);
+ }
+ dst = next;
+ }
+}
+
+
+static int ctrl_open_pipe(struct ctrl_iface_priv *priv)
+{
+ struct wpa_ctrl_dst *dst;
+ DWORD err;
+ TCHAR name[256];
+
+ dst = os_zalloc(sizeof(*dst));
+ if (dst == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst);
+
+ dst->priv = priv;
+ dst->debug_level = MSG_INFO;
+ dst->pipe = INVALID_HANDLE_VALUE;
+
+ dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (dst->overlap.hEvent == NULL) {
+ wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d",
+ (int) GetLastError());
+ goto fail;
+ }
+
+ eloop_register_event(dst->overlap.hEvent,
+ sizeof(dst->overlap.hEvent),
+ wpa_supplicant_ctrl_iface_receive, dst, NULL);
+
+#ifdef UNICODE
+ _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
+ priv->wpa_s->ifname);
+#else /* UNICODE */
+ os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
+ priv->wpa_s->ifname);
+#endif /* UNICODE */
+
+ /* TODO: add support for configuring access list for the pipe */
+ dst->pipe = CreateNamedPipe(name,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_MESSAGE |
+ PIPE_READMODE_MESSAGE |
+ PIPE_WAIT,
+ 15, REPLY_BUFSIZE, REQUEST_BUFSIZE,
+ 1000,
+ priv->sec_attr_set ? &priv->attr : NULL);
+ if (dst->pipe == INVALID_HANDLE_VALUE) {
+ wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d",
+ (int) GetLastError());
+ goto fail;
+ }
+
+ if (ConnectNamedPipe(dst->pipe, &dst->overlap)) {
+ wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d",
+ (int) GetLastError());
+ CloseHandle(dst->pipe);
+ os_free(dst);
+ return -1;
+ }
+
+ err = GetLastError();
+ switch (err) {
+ case ERROR_IO_PENDING:
+ wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in "
+ "progress");
+ break;
+ case ERROR_PIPE_CONNECTED:
+ wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already "
+ "connected");
+ if (SetEvent(dst->overlap.hEvent))
+ break;
+ /* fall through */
+ default:
+ wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d",
+ (int) err);
+ CloseHandle(dst->pipe);
+ os_free(dst);
+ return -1;
+ }
+
+ dst->next = priv->ctrl_dst;
+ if (dst->next)
+ dst->next->prev = dst;
+ priv->ctrl_dst = dst;
+
+ return 0;
+
+fail:
+ ctrl_close_pipe(dst);
+ return -1;
+}
+
+
+static void ctrl_close_pipe(struct wpa_ctrl_dst *dst)
+{
+ wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst);
+
+ if (dst->overlap.hEvent) {
+ eloop_unregister_event(dst->overlap.hEvent,
+ sizeof(dst->overlap.hEvent));
+ CloseHandle(dst->overlap.hEvent);
+ }
+
+ if (dst->pipe != INVALID_HANDLE_VALUE) {
+ /*
+ * Could use FlushFileBuffers() here to guarantee that all data
+ * gets delivered to the client, but that can block, so let's
+ * not do this for now.
+ * FlushFileBuffers(dst->pipe);
+ */
+ CloseHandle(dst->pipe);
+ }
+
+ if (dst->prev)
+ dst->prev->next = dst->next;
+ else
+ dst->priv->ctrl_dst = dst->next;
+ if (dst->next)
+ dst->next->prev = dst->prev;
+
+ os_free(dst->rsp_buf);
+ os_free(dst);
+}
+
+
+static VOID WINAPI ctrl_iface_write_completed(DWORD err, DWORD bytes,
+ LPOVERLAPPED overlap)
+{
+ struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap;
+ wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p "
+ "err=%d bytes=%d", dst, (int) err, (int) bytes);
+ if (err) {
+ ctrl_close_pipe(dst);
+ return;
+ }
+
+ os_free(dst->rsp_buf);
+ dst->rsp_buf = NULL;
+
+ if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf),
+ &dst->overlap, ctrl_iface_read_completed)) {
+ wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d",
+ (int) GetLastError());
+ ctrl_close_pipe(dst);
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst);
+}
+
+
+static void wpa_supplicant_ctrl_iface_rx(struct wpa_ctrl_dst *dst, size_t len)
+{
+ struct wpa_supplicant *wpa_s = dst->priv->wpa_s;
+ char *reply = NULL, *send_buf;
+ size_t reply_len = 0, send_len;
+ int new_attached = 0;
+ char *buf = dst->req_buf;
+
+ dst->used = 1;
+ if (len >= REQUEST_BUFSIZE)
+ len = REQUEST_BUFSIZE - 1;
+ buf[len] = '\0';
+
+ if (os_strcmp(buf, "ATTACH") == 0) {
+ dst->attached = 1;
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor attached");
+ new_attached = 1;
+ reply_len = 2;
+ } else if (os_strcmp(buf, "DETACH") == 0) {
+ dst->attached = 0;
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor detached");
+ reply_len = 2;
+ } else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", buf + 6);
+ dst->debug_level = atoi(buf + 6);
+ reply_len = 2;
+ } else {
+ reply = wpa_supplicant_ctrl_iface_process(wpa_s, buf,
+ &reply_len);
+ }
+
+ if (reply) {
+ send_buf = reply;
+ send_len = reply_len;
+ } else if (reply_len == 2) {
+ send_buf = "OK\n";
+ send_len = 3;
+ } else {
+ send_buf = "FAIL\n";
+ send_len = 5;
+ }
+
+ os_free(dst->rsp_buf);
+ dst->rsp_buf = os_malloc(send_len);
+ if (dst->rsp_buf == NULL) {
+ ctrl_close_pipe(dst);
+ os_free(reply);
+ return;
+ }
+ os_memcpy(dst->rsp_buf, send_buf, send_len);
+ os_free(reply);
+
+ if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap,
+ ctrl_iface_write_completed)) {
+ wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d",
+ (int) GetLastError());
+ ctrl_close_pipe(dst);
+ } else {
+ wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p",
+ dst);
+ }
+
+ if (new_attached)
+ eapol_sm_notify_ctrl_attached(wpa_s->eapol);
+}
+
+
+static VOID WINAPI ctrl_iface_read_completed(DWORD err, DWORD bytes,
+ LPOVERLAPPED overlap)
+{
+ struct wpa_ctrl_dst *dst = (struct wpa_ctrl_dst *) overlap;
+ wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d "
+ "bytes=%d", dst, (int) err, (int) bytes);
+ if (err == 0 && bytes > 0)
+ wpa_supplicant_ctrl_iface_rx(dst, bytes);
+}
+
+
+static void wpa_supplicant_ctrl_iface_receive(void *eloop_data, void *user_ctx)
+{
+ struct wpa_ctrl_dst *dst = eloop_data;
+ struct ctrl_iface_priv *priv = dst->priv;
+ DWORD bytes;
+
+ wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_ctrl_iface_receive");
+ ResetEvent(dst->overlap.hEvent);
+
+ if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) {
+ wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d",
+ (int) GetLastError());
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client "
+ "connected");
+
+ /* Open a new named pipe for the next client. */
+ ctrl_open_pipe(priv);
+
+ /* Use write completion function to start reading a command */
+ ctrl_iface_write_completed(0, 0, &dst->overlap);
+
+ ctrl_flush_broken_pipes(priv);
+}
+
+
+static int ctrl_iface_parse(struct ctrl_iface_priv *priv, const char *params)
+{
+ const char *sddl = NULL;
+ TCHAR *t_sddl;
+
+ if (os_strncmp(params, "SDDL=", 5) == 0)
+ sddl = params + 5;
+ if (!sddl) {
+ sddl = os_strstr(params, " SDDL=");
+ if (sddl)
+ sddl += 6;
+ }
+
+ if (!sddl)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "CTRL: SDDL='%s'", sddl);
+ os_memset(&priv->attr, 0, sizeof(priv->attr));
+ priv->attr.nLength = sizeof(priv->attr);
+ priv->attr.bInheritHandle = FALSE;
+ t_sddl = wpa_strdup_tchar(sddl);
+ if (t_sddl == NULL)
+ return -1;
+ if (!ConvertStringSecurityDescriptorToSecurityDescriptor(
+ t_sddl, SDDL_REVISION_1,
+ (PSECURITY_DESCRIPTOR *) (void *)
+ &priv->attr.lpSecurityDescriptor,
+ NULL)) {
+ os_free(t_sddl);
+ wpa_printf(MSG_ERROR, "CTRL: SDDL='%s' - could not convert to "
+ "security descriptor: %d",
+ sddl, (int) GetLastError());
+ return -1;
+ }
+ os_free(t_sddl);
+
+ priv->sec_attr_set = 1;
+
+ return 0;
+}
+
+
+static void wpa_supplicant_ctrl_iface_msg_cb(void *ctx, int level,
+ const char *txt, size_t len)
+{
+ struct wpa_supplicant *wpa_s = ctx;
+ if (wpa_s == NULL || wpa_s->ctrl_iface == NULL)
+ return;
+ wpa_supplicant_ctrl_iface_send(wpa_s->ctrl_iface, level, txt, len);
+}
+
+
+struct ctrl_iface_priv *
+wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
+{
+ struct ctrl_iface_priv *priv;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+ priv->wpa_s = wpa_s;
+
+ if (wpa_s->conf->ctrl_interface == NULL)
+ return priv;
+
+ if (ctrl_iface_parse(priv, wpa_s->conf->ctrl_interface) < 0) {
+ os_free(priv);
+ return NULL;
+ }
+
+ if (ctrl_open_pipe(priv) < 0) {
+ os_free(priv);
+ return NULL;
+ }
+
+ wpa_msg_register_cb(wpa_supplicant_ctrl_iface_msg_cb);
+
+ return priv;
+}
+
+
+void wpa_supplicant_ctrl_iface_deinit(struct ctrl_iface_priv *priv)
+{
+ while (priv->ctrl_dst)
+ ctrl_close_pipe(priv->ctrl_dst);
+ if (priv->sec_attr_set)
+ LocalFree(priv->attr.lpSecurityDescriptor);
+ os_free(priv);
+}
+
+
+static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
+ int level, const char *buf,
+ size_t len)
+{
+ struct wpa_ctrl_dst *dst, *next;
+ char levelstr[10];
+ int idx;
+ char *sbuf;
+ int llen;
+ DWORD written;
+
+ dst = priv->ctrl_dst;
+ if (dst == NULL)
+ return;
+
+ os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+
+ llen = os_strlen(levelstr);
+ sbuf = os_malloc(llen + len);
+ if (sbuf == NULL)
+ return;
+
+ os_memcpy(sbuf, levelstr, llen);
+ os_memcpy(sbuf + llen, buf, len);
+
+ idx = 0;
+ while (dst) {
+ next = dst->next;
+ if (dst->attached && level >= dst->debug_level) {
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE monitor send %p",
+ dst);
+ if (!WriteFile(dst->pipe, sbuf, llen + len, &written,
+ NULL)) {
+ wpa_printf(MSG_DEBUG, "CTRL: WriteFile to dst "
+ "%p failed: %d",
+ dst, (int) GetLastError());
+ dst->errors++;
+ if (dst->errors > 10)
+ ctrl_close_pipe(dst);
+ } else
+ dst->errors = 0;
+ }
+ idx++;
+ dst = next;
+ }
+ os_free(sbuf);
+}
+
+
+void wpa_supplicant_ctrl_iface_wait(struct ctrl_iface_priv *priv)
+{
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE - %s - wait for monitor",
+ priv->wpa_s->ifname);
+ if (priv->ctrl_dst == NULL)
+ return;
+ WaitForSingleObject(priv->ctrl_dst->pipe, INFINITE);
+}
+
+
+/* Global ctrl_iface */
+
+struct ctrl_iface_global_priv;
+
+struct wpa_global_dst {
+ /* Note: OVERLAPPED must be the first member of struct wpa_global_dst
+ */
+ OVERLAPPED overlap;
+ struct wpa_global_dst *next, *prev;
+ struct ctrl_iface_global_priv *priv;
+ HANDLE pipe;
+ char req_buf[REQUEST_BUFSIZE];
+ char *rsp_buf;
+ int used;
+};
+
+struct ctrl_iface_global_priv {
+ struct wpa_global *global;
+ struct wpa_global_dst *ctrl_dst;
+};
+
+
+static void global_flush_broken_pipes(struct ctrl_iface_global_priv *priv)
+{
+ struct wpa_global_dst *dst, *next;
+
+ dst = priv->ctrl_dst;
+
+ while (dst) {
+ next = dst->next;
+ if (ctrl_broken_pipe(dst->pipe, dst->used)) {
+ wpa_printf(MSG_DEBUG, "CTRL: closing broken pipe %p",
+ dst);
+ global_close_pipe(dst);
+ }
+ dst = next;
+ }
+}
+
+
+static int global_open_pipe(struct ctrl_iface_global_priv *priv)
+{
+ struct wpa_global_dst *dst;
+ DWORD err;
+
+ dst = os_zalloc(sizeof(*dst));
+ if (dst == NULL)
+ return -1;
+ wpa_printf(MSG_DEBUG, "CTRL: Open pipe %p", dst);
+
+ dst->priv = priv;
+ dst->pipe = INVALID_HANDLE_VALUE;
+
+ dst->overlap.hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
+ if (dst->overlap.hEvent == NULL) {
+ wpa_printf(MSG_ERROR, "CTRL: CreateEvent failed: %d",
+ (int) GetLastError());
+ goto fail;
+ }
+
+ eloop_register_event(dst->overlap.hEvent,
+ sizeof(dst->overlap.hEvent),
+ wpa_supplicant_global_iface_receive, dst, NULL);
+
+ /* TODO: add support for configuring access list for the pipe */
+ dst->pipe = CreateNamedPipe(NAMED_PIPE_PREFIX,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_MESSAGE |
+ PIPE_READMODE_MESSAGE |
+ PIPE_WAIT,
+ 10, REPLY_BUFSIZE, REQUEST_BUFSIZE,
+ 1000, NULL);
+ if (dst->pipe == INVALID_HANDLE_VALUE) {
+ wpa_printf(MSG_ERROR, "CTRL: CreateNamedPipe failed: %d",
+ (int) GetLastError());
+ goto fail;
+ }
+
+ if (ConnectNamedPipe(dst->pipe, &dst->overlap)) {
+ wpa_printf(MSG_ERROR, "CTRL: ConnectNamedPipe failed: %d",
+ (int) GetLastError());
+ CloseHandle(dst->pipe);
+ os_free(dst);
+ return -1;
+ }
+
+ err = GetLastError();
+ switch (err) {
+ case ERROR_IO_PENDING:
+ wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: connection in "
+ "progress");
+ break;
+ case ERROR_PIPE_CONNECTED:
+ wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe: already "
+ "connected");
+ if (SetEvent(dst->overlap.hEvent))
+ break;
+ /* fall through */
+ default:
+ wpa_printf(MSG_DEBUG, "CTRL: ConnectNamedPipe error: %d",
+ (int) err);
+ CloseHandle(dst->pipe);
+ os_free(dst);
+ return -1;
+ }
+
+ dst->next = priv->ctrl_dst;
+ if (dst->next)
+ dst->next->prev = dst;
+ priv->ctrl_dst = dst;
+
+ return 0;
+
+fail:
+ global_close_pipe(dst);
+ return -1;
+}
+
+
+static void global_close_pipe(struct wpa_global_dst *dst)
+{
+ wpa_printf(MSG_DEBUG, "CTRL: close pipe %p", dst);
+
+ if (dst->overlap.hEvent) {
+ eloop_unregister_event(dst->overlap.hEvent,
+ sizeof(dst->overlap.hEvent));
+ CloseHandle(dst->overlap.hEvent);
+ }
+
+ if (dst->pipe != INVALID_HANDLE_VALUE) {
+ /*
+ * Could use FlushFileBuffers() here to guarantee that all data
+ * gets delivered to the client, but that can block, so let's
+ * not do this for now.
+ * FlushFileBuffers(dst->pipe);
+ */
+ CloseHandle(dst->pipe);
+ }
+
+ if (dst->prev)
+ dst->prev->next = dst->next;
+ else
+ dst->priv->ctrl_dst = dst->next;
+ if (dst->next)
+ dst->next->prev = dst->prev;
+
+ os_free(dst->rsp_buf);
+ os_free(dst);
+}
+
+
+static VOID WINAPI global_iface_write_completed(DWORD err, DWORD bytes,
+ LPOVERLAPPED overlap)
+{
+ struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap;
+ wpa_printf(MSG_DEBUG, "CTRL: Overlapped write completed: dst=%p "
+ "err=%d bytes=%d", dst, (int) err, (int) bytes);
+ if (err) {
+ global_close_pipe(dst);
+ return;
+ }
+
+ os_free(dst->rsp_buf);
+ dst->rsp_buf = NULL;
+
+ if (!ReadFileEx(dst->pipe, dst->req_buf, sizeof(dst->req_buf),
+ &dst->overlap, global_iface_read_completed)) {
+ wpa_printf(MSG_DEBUG, "CTRL: ReadFileEx failed: %d",
+ (int) GetLastError());
+ global_close_pipe(dst);
+ /* FIX: if this was the pipe waiting for new global
+ * connections, at this point there are no open global pipes..
+ * Should try to open a new pipe.. */
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "CTRL: Overlapped read started for %p", dst);
+}
+
+
+static void wpa_supplicant_global_iface_rx(struct wpa_global_dst *dst,
+ size_t len)
+{
+ struct wpa_global *global = dst->priv->global;
+ char *reply = NULL, *send_buf;
+ size_t reply_len = 0, send_len;
+ char *buf = dst->req_buf;
+
+ dst->used = 1;
+ if (len >= REQUEST_BUFSIZE)
+ len = REQUEST_BUFSIZE - 1;
+ buf[len] = '\0';
+
+ reply = wpa_supplicant_global_ctrl_iface_process(global, buf,
+ &reply_len);
+ if (reply) {
+ send_buf = reply;
+ send_len = reply_len;
+ } else if (reply_len) {
+ send_buf = "FAIL\n";
+ send_len = 5;
+ } else {
+ os_free(dst->rsp_buf);
+ dst->rsp_buf = NULL;
+ return;
+ }
+
+ os_free(dst->rsp_buf);
+ dst->rsp_buf = os_malloc(send_len);
+ if (dst->rsp_buf == NULL) {
+ global_close_pipe(dst);
+ os_free(reply);
+ return;
+ }
+ os_memcpy(dst->rsp_buf, send_buf, send_len);
+ os_free(reply);
+
+ if (!WriteFileEx(dst->pipe, dst->rsp_buf, send_len, &dst->overlap,
+ global_iface_write_completed)) {
+ wpa_printf(MSG_DEBUG, "CTRL: WriteFileEx failed: %d",
+ (int) GetLastError());
+ global_close_pipe(dst);
+ } else {
+ wpa_printf(MSG_DEBUG, "CTRL: Overlapped write started for %p",
+ dst);
+ }
+}
+
+
+static VOID WINAPI global_iface_read_completed(DWORD err, DWORD bytes,
+ LPOVERLAPPED overlap)
+{
+ struct wpa_global_dst *dst = (struct wpa_global_dst *) overlap;
+ wpa_printf(MSG_DEBUG, "CTRL: Overlapped read completed: dst=%p err=%d "
+ "bytes=%d", dst, (int) err, (int) bytes);
+ if (err == 0 && bytes > 0)
+ wpa_supplicant_global_iface_rx(dst, bytes);
+}
+
+
+static void wpa_supplicant_global_iface_receive(void *eloop_data,
+ void *user_ctx)
+{
+ struct wpa_global_dst *dst = eloop_data;
+ struct ctrl_iface_global_priv *priv = dst->priv;
+ DWORD bytes;
+
+ wpa_printf(MSG_DEBUG, "CTRL: wpa_supplicant_global_iface_receive");
+ ResetEvent(dst->overlap.hEvent);
+
+ if (!GetOverlappedResult(dst->pipe, &dst->overlap, &bytes, FALSE)) {
+ wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult failed: %d",
+ (int) GetLastError());
+ return;
+ }
+ wpa_printf(MSG_DEBUG, "CTRL: GetOverlappedResult: New client "
+ "connected");
+
+ /* Open a new named pipe for the next client. */
+ if (global_open_pipe(priv) < 0) {
+ wpa_printf(MSG_DEBUG, "CTRL: global_open_pipe failed");
+ return;
+ }
+
+ /* Use write completion function to start reading a command */
+ global_iface_write_completed(0, 0, &dst->overlap);
+
+ global_flush_broken_pipes(priv);
+}
+
+
+struct ctrl_iface_global_priv *
+wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
+{
+ struct ctrl_iface_global_priv *priv;
+
+ priv = os_zalloc(sizeof(*priv));
+ if (priv == NULL)
+ return NULL;
+ priv->global = global;
+
+ if (global_open_pipe(priv) < 0) {
+ os_free(priv);
+ return NULL;
+ }
+
+ return priv;
+}
+
+
+void
+wpa_supplicant_global_ctrl_iface_deinit(struct ctrl_iface_global_priv *priv)
+{
+ while (priv->ctrl_dst)
+ global_close_pipe(priv->ctrl_dst);
+ os_free(priv);
+}
diff --git a/wpa_supplicant/ctrl_iface_unix.c b/wpa_supplicant/ctrl_iface_unix.c
index bf6328e..2a62713 100644
--- a/wpa_supplicant/ctrl_iface_unix.c
+++ b/wpa_supplicant/ctrl_iface_unix.c
@@ -16,6 +16,7 @@
#include <sys/un.h>
#include <sys/stat.h>
#include <grp.h>
+#include <stddef.h>
#include "common.h"
#include "eloop.h"
@@ -69,7 +70,8 @@ static int wpa_supplicant_ctrl_iface_attach(struct ctrl_iface_priv *priv,
dst->next = priv->ctrl_dst;
priv->ctrl_dst = dst;
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
- (u8 *) from->sun_path, fromlen - sizeof(from->sun_family));
+ (u8 *) from->sun_path,
+ fromlen - offsetof(struct sockaddr_un, sun_path));
return 0;
}
@@ -84,7 +86,8 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
while (dst) {
if (fromlen == dst->addrlen &&
os_memcmp(from->sun_path, dst->addr.sun_path,
- fromlen - sizeof(from->sun_family)) == 0) {
+ fromlen - offsetof(struct sockaddr_un, sun_path))
+ == 0) {
if (prev == NULL)
priv->ctrl_dst = dst->next;
else
@@ -92,7 +95,8 @@ static int wpa_supplicant_ctrl_iface_detach(struct ctrl_iface_priv *priv,
os_free(dst);
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
(u8 *) from->sun_path,
- fromlen - sizeof(from->sun_family));
+ fromlen -
+ offsetof(struct sockaddr_un, sun_path));
return 0;
}
prev = dst;
@@ -115,10 +119,12 @@ static int wpa_supplicant_ctrl_iface_level(struct ctrl_iface_priv *priv,
while (dst) {
if (fromlen == dst->addrlen &&
os_memcmp(from->sun_path, dst->addr.sun_path,
- fromlen - sizeof(from->sun_family)) == 0) {
+ fromlen - offsetof(struct sockaddr_un, sun_path))
+ == 0) {
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
"level", (u8 *) from->sun_path,
- fromlen - sizeof(from->sun_family));
+ fromlen -
+ offsetof(struct sockaddr_un, sun_path));
dst->debug_level = atoi(level);
return 0;
}
@@ -326,6 +332,14 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
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");
@@ -339,6 +353,9 @@ wpa_supplicant_ctrl_iface_init(struct wpa_supplicant *wpa_s)
}
os_memset(&addr, 0, sizeof(addr));
+#ifdef __FreeBSD__
+ addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
addr.sun_family = AF_UNIX;
fname = wpa_supplicant_ctrl_iface_path(wpa_s);
if (fname == NULL)
@@ -510,13 +527,16 @@ static void wpa_supplicant_ctrl_iface_send(struct ctrl_iface_priv *priv,
if (level >= dst->debug_level) {
wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
(u8 *) dst->addr.sun_path, dst->addrlen -
- sizeof(dst->addr.sun_family));
+ offsetof(struct sockaddr_un, sun_path));
msg.msg_name = (void *) &dst->addr;
msg.msg_namelen = dst->addrlen;
if (sendmsg(priv->sock, &msg, 0) < 0) {
- perror("sendmsg(CTRL_IFACE monitor)");
+ int _errno = errno;
+ wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
+ "%d - %s",
+ idx, errno, strerror(errno));
dst->errors++;
- if (dst->errors > 10) {
+ if (dst->errors > 10 || _errno == ENOENT) {
wpa_supplicant_ctrl_iface_detach(
priv, &dst->addr,
dst->addrlen);
@@ -637,6 +657,9 @@ wpa_supplicant_global_ctrl_iface_init(struct wpa_global *global)
}
os_memset(&addr, 0, sizeof(addr));
+#ifdef __FreeBSD__
+ 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));
diff --git a/wpa_supplicant/defconfig b/wpa_supplicant/defconfig
index dd9460d..4d0aa8a 100644
--- a/wpa_supplicant/defconfig
+++ b/wpa_supplicant/defconfig
@@ -50,6 +50,7 @@ CONFIG_DRIVER_HOSTAP=y
#CFLAGS += -I../../include/wireless
# Driver interface for madwifi driver
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
#CONFIG_DRIVER_MADWIFI=y
# Set include directory to the madwifi source tree
#CFLAGS += -I../../madwifi
@@ -60,6 +61,7 @@ CONFIG_DRIVER_HOSTAP=y
#CONFIG_DRIVER_PRISM54=y
# Driver interface for ndiswrapper
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
#CONFIG_DRIVER_NDISWRAPPER=y
# Driver interface for Atmel driver
@@ -74,6 +76,7 @@ CONFIG_DRIVER_ATMEL=y
#CFLAGS += -I/opt/WRT54GS/release/src/include
# Driver interface for Intel ipw2100/2200 driver
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
#CONFIG_DRIVER_IPW=y
# Driver interface for Ralink driver
diff --git a/wpa_supplicant/doc/.gitignore b/wpa_supplicant/doc/.gitignore
deleted file mode 100644
index 59e4eb8..0000000
--- a/wpa_supplicant/doc/.gitignore
+++ /dev/null
@@ -1,4 +0,0 @@
-html
-latex
-wpa_supplicant.eps
-wpa_supplicant.png
diff --git a/wpa_supplicant/doc/docbook/.gitignore b/wpa_supplicant/doc/docbook/.gitignore
deleted file mode 100644
index 8c3945c..0000000
--- a/wpa_supplicant/doc/docbook/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-manpage.links
-manpage.refs
-*.8
-*.5
-*.html
-*.pdf
diff --git a/wpa_supplicant/doc/docbook/wpa_background.8 b/wpa_supplicant/doc/docbook/wpa_background.8
index 3bda3f4..81f771e 100644
--- a/wpa_supplicant/doc/docbook/wpa_background.8
+++ b/wpa_supplicant/doc/docbook/wpa_background.8
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
-.TH "WPA_BACKGROUND" "8" "15 February 2009" "" ""
+.TH "WPA_BACKGROUND" "8" "12 January 2010" "" ""
.SH NAME
wpa_background \- Background information on Wi-Fi Protected Access and IEEE 802.11i
diff --git a/wpa_supplicant/doc/docbook/wpa_cli.8 b/wpa_supplicant/doc/docbook/wpa_cli.8
index 4e4aa46..286cf06 100644
--- a/wpa_supplicant/doc/docbook/wpa_cli.8
+++ b/wpa_supplicant/doc/docbook/wpa_cli.8
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
-.TH "WPA_CLI" "8" "15 February 2009" "" ""
+.TH "WPA_CLI" "8" "12 January 2010" "" ""
.SH NAME
wpa_cli \- WPA command line client
diff --git a/wpa_supplicant/doc/docbook/wpa_gui.8 b/wpa_supplicant/doc/docbook/wpa_gui.8
index 2f4f638..66a279d 100644
--- a/wpa_supplicant/doc/docbook/wpa_gui.8
+++ b/wpa_supplicant/doc/docbook/wpa_gui.8
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
-.TH "WPA_GUI" "8" "15 February 2009" "" ""
+.TH "WPA_GUI" "8" "12 January 2010" "" ""
.SH NAME
wpa_gui \- WPA Graphical User Interface
diff --git a/wpa_supplicant/doc/docbook/wpa_passphrase.8 b/wpa_supplicant/doc/docbook/wpa_passphrase.8
index b123daa..d1d1800 100644
--- a/wpa_supplicant/doc/docbook/wpa_passphrase.8
+++ b/wpa_supplicant/doc/docbook/wpa_passphrase.8
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
-.TH "WPA_PASSPHRASE" "8" "15 February 2009" "" ""
+.TH "WPA_PASSPHRASE" "8" "12 January 2010" "" ""
.SH NAME
wpa_passphrase \- Generate a WPA PSK from an ASCII passphrase for a SSID
diff --git a/wpa_supplicant/doc/docbook/wpa_priv.8 b/wpa_supplicant/doc/docbook/wpa_priv.8
index 2191cec..a5fa2ea 100644
--- a/wpa_supplicant/doc/docbook/wpa_priv.8
+++ b/wpa_supplicant/doc/docbook/wpa_priv.8
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
-.TH "WPA_PRIV" "8" "15 February 2009" "" ""
+.TH "WPA_PRIV" "8" "12 January 2010" "" ""
.SH NAME
wpa_priv \- wpa_supplicant privilege separation helper
diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.8 b/wpa_supplicant/doc/docbook/wpa_supplicant.8
index 0106c69..69b8d2b 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.8
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.8
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
-.TH "WPA_SUPPLICANT" "8" "15 February 2009" "" ""
+.TH "WPA_SUPPLICANT" "8" "12 January 2010" "" ""
.SH NAME
wpa_supplicant \- Wi-Fi Protected Access client and IEEE 802.1X supplicant
diff --git a/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5 b/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
index 7a01ea2..796d891 100644
--- a/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
+++ b/wpa_supplicant/doc/docbook/wpa_supplicant.conf.5
@@ -3,7 +3,7 @@
.\" <http://shell.ipoline.com/~elmert/comp/docbook2X/>
.\" Please send any bug reports, improvements, comments, patches,
.\" etc. to Steve Cheng <steve@ggi-project.org>.
-.TH "WPA_SUPPLICANT.CONF" "5" "15 February 2009" "" ""
+.TH "WPA_SUPPLICANT.CONF" "5" "12 January 2010" "" ""
.SH NAME
wpa_supplicant.conf \- configuration file for wpa_supplicant
diff --git a/wpa_supplicant/doc/porting.doxygen b/wpa_supplicant/doc/porting.doxygen
index 0311134..7ea6a34 100644
--- a/wpa_supplicant/doc/porting.doxygen
+++ b/wpa_supplicant/doc/porting.doxygen
@@ -5,9 +5,9 @@
hardware (board, CPU) and software (OS, drivers) targets. It is
already used with number of operating systems and numerous wireless
card models and drivers. The main %wpa_supplicant repository includes
-support for Linux, FreeBSD, and Windows. In addition, at least VxWorks,
-PalmOS, Windows CE, and Windows Mobile are supported in separate
-repositories. On the hardware
+support for Linux, FreeBSD, and Windows. In addition, the code has been
+ported to number of other operating systems like VxWorks, PalmOS,
+Windows CE, and Windows Mobile. On the hardware
side, %wpa_supplicant is used on various systems: desktops, laptops,
PDAs, and embedded devices with CPUs including x86, PowerPC,
arm/xscale, and MIPS. Both big and little endian configurations are
diff --git a/wpa_supplicant/eapol_test.c b/wpa_supplicant/eapol_test.c
index d87aad7..b188549 100644
--- a/wpa_supplicant/eapol_test.c
+++ b/wpa_supplicant/eapol_test.c
@@ -617,7 +617,8 @@ static void ieee802_1x_decapsulate_radius(struct eapol_test_data *e)
static void ieee802_1x_get_keys(struct eapol_test_data *e,
struct radius_msg *msg, struct radius_msg *req,
- u8 *shared_secret, size_t shared_secret_len)
+ const u8 *shared_secret,
+ size_t shared_secret_len)
{
struct radius_ms_mppe_keys *keys;
@@ -664,7 +665,7 @@ static void ieee802_1x_get_keys(struct eapol_test_data *e,
/* Process the RADIUS frames from Authentication Server */
static RadiusRxResult
ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
- u8 *shared_secret, size_t shared_secret_len,
+ const u8 *shared_secret, size_t shared_secret_len,
void *data)
{
struct eapol_test_data *e = data;
diff --git a/wpa_supplicant/events.c b/wpa_supplicant/events.c
index dd4595a..39efedd 100644
--- a/wpa_supplicant/events.c
+++ b/wpa_supplicant/events.c
@@ -251,6 +251,11 @@ static int wpa_supplicant_match_privacy(struct wpa_scan_res *bss,
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;
@@ -410,6 +415,11 @@ wpa_supplicant_select_bss_wpa(struct wpa_supplicant *wpa_s,
continue;
}
+ if (ssid_len == 0) {
+ wpa_printf(MSG_DEBUG, " skip - SSID not known");
+ continue;
+ }
+
if (wpa_ie_len == 0 && rsn_ie_len == 0) {
wpa_printf(MSG_DEBUG, " skip - no WPA/RSN IE");
continue;
@@ -500,6 +510,11 @@ wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s,
continue;
}
+ if (ssid_len == 0) {
+ wpa_printf(MSG_DEBUG, " skip - SSID not known");
+ continue;
+ }
+
for (ssid = group; ssid; ssid = ssid->pnext) {
int check_ssid = ssid->ssid_len != 0;
@@ -536,7 +551,7 @@ wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s,
"BSSID mismatch");
continue;
}
-
+
if (!(ssid->key_mgmt & WPA_KEY_MGMT_NONE) &&
!(ssid->key_mgmt & WPA_KEY_MGMT_WPS) &&
!(ssid->key_mgmt & WPA_KEY_MGMT_IEEE8021X_NO_WPA))
@@ -546,7 +561,7 @@ wpa_supplicant_select_bss_non_wpa(struct wpa_supplicant *wpa_s,
continue;
}
- if ((ssid->key_mgmt &
+ if ((ssid->key_mgmt &
(WPA_KEY_MGMT_IEEE8021X | WPA_KEY_MGMT_PSK |
WPA_KEY_MGMT_FT_IEEE8021X | WPA_KEY_MGMT_FT_PSK |
WPA_KEY_MGMT_IEEE8021X_SHA256 |
@@ -608,6 +623,8 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s)
struct wpa_scan_res *selected = NULL;
struct wpa_ssid *ssid = NULL;
+ wpa_supplicant_notify_scanning(wpa_s, 0);
+
if (wpa_supplicant_get_scan_results(wpa_s) < 0) {
if (wpa_s->conf->ap_scan == 2)
return;
@@ -626,15 +643,20 @@ static void wpa_supplicant_event_scan_results(struct wpa_supplicant *wpa_s)
wpa_msg(wpa_s, MSG_DEBUG, "Cached scan results are "
"empty - not posting");
} else {
- wpa_msg(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
+ wpa_printf(MSG_DEBUG, "New scan results available");
+ wpa_msg_ctrl(wpa_s, MSG_INFO, WPA_EVENT_SCAN_RESULTS);
wpa_supplicant_dbus_notify_scan_results(wpa_s);
wpas_wps_notify_scan_results(wpa_s);
}
- if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s)) ||
- wpa_s->disconnected)
+ if ((wpa_s->conf->ap_scan == 2 && !wpas_wps_searching(wpa_s)))
return;
+ if (wpa_s->disconnected) {
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
+ return;
+ }
+
while (selected == NULL) {
for (prio = 0; prio < wpa_s->conf->num_prio; prio++) {
selected = wpa_supplicant_select_bss(
@@ -696,6 +718,14 @@ req_scan:
*/
wpa_s->scan_res_tried++;
timeout = 0;
+ } else if (!wpa_supplicant_enabled_networks(wpa_s->conf)) {
+ /*
+ * No networks are enabled; short-circuit request so
+ * we don't wait timeout seconds before transitioning
+ * to INACTIVE state.
+ */
+ wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
+ return;
}
wpa_supplicant_req_scan(wpa_s, timeout, 0);
}
@@ -864,6 +894,25 @@ static void wpa_supplicant_event_assoc(struct wpa_supplicant *wpa_s,
eapol_sm_notify_portValid(wpa_s->eapol, TRUE);
eapol_sm_notify_eap_success(wpa_s->eapol, TRUE);
}
+
+ if (wpa_s->pending_eapol_rx) {
+ struct os_time now, age;
+ os_get_time(&now);
+ os_time_sub(&now, &wpa_s->pending_eapol_rx_time, &age);
+ if (age.sec == 0 && age.usec < 100000 &&
+ os_memcmp(wpa_s->pending_eapol_rx_src, bssid, ETH_ALEN) ==
+ 0) {
+ wpa_printf(MSG_DEBUG, "Process pending EAPOL frame "
+ "that was received just before association "
+ "notification");
+ wpa_supplicant_rx_eapol(
+ wpa_s, wpa_s->pending_eapol_rx_src,
+ wpabuf_head(wpa_s->pending_eapol_rx),
+ wpabuf_len(wpa_s->pending_eapol_rx));
+ }
+ wpabuf_free(wpa_s->pending_eapol_rx);
+ wpa_s->pending_eapol_rx = NULL;
+ }
}
diff --git a/wpa_supplicant/main_none.c b/wpa_supplicant/main_none.c
new file mode 100644
index 0000000..993338a
--- /dev/null
+++ b/wpa_supplicant/main_none.c
@@ -0,0 +1,46 @@
+/*
+ * WPA Supplicant / Example program entrypoint
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+
+int main(int argc, char *argv[])
+{
+ struct wpa_interface iface;
+ int exitcode = 0;
+ struct wpa_params params;
+ struct wpa_global *global;
+
+ memset(&params, 0, sizeof(params));
+ params.wpa_debug_level = MSG_INFO;
+
+ global = wpa_supplicant_init(&params);
+ if (global == NULL)
+ return -1;
+
+ memset(&iface, 0, sizeof(iface));
+ /* TODO: set interface parameters */
+
+ if (wpa_supplicant_add_iface(global, &iface) == NULL)
+ exitcode = -1;
+
+ if (exitcode == 0)
+ exitcode = wpa_supplicant_run(global);
+
+ wpa_supplicant_deinit(global);
+
+ return exitcode;
+}
diff --git a/wpa_supplicant/main_symbian.cpp b/wpa_supplicant/main_symbian.cpp
new file mode 100644
index 0000000..4ff364b
--- /dev/null
+++ b/wpa_supplicant/main_symbian.cpp
@@ -0,0 +1,48 @@
+/*
+ * WPA Supplicant / Program entrypoint for Symbian
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+extern "C" {
+#include "common.h"
+#include "wpa_supplicant_i.h"
+}
+
+GLDEF_C TInt E32Main(void)
+{
+ struct wpa_interface iface;
+ int exitcode = 0;
+ struct wpa_params params;
+ struct wpa_global *global;
+
+ memset(&params, 0, sizeof(params));
+ params.wpa_debug_level = MSG_INFO;
+
+ global = wpa_supplicant_init(&params);
+ if (global == NULL)
+ return -1;
+
+ memset(&iface, 0, sizeof(iface));
+ /* TODO: set interface parameters */
+
+ if (wpa_supplicant_add_iface(global, &iface) == NULL)
+ exitcode = -1;
+
+ if (exitcode == 0)
+ exitcode = wpa_supplicant_run(global);
+
+ wpa_supplicant_deinit(global);
+
+ return exitcode;
+}
diff --git a/wpa_supplicant/main_winmain.c b/wpa_supplicant/main_winmain.c
new file mode 100644
index 0000000..19d9950
--- /dev/null
+++ b/wpa_supplicant/main_winmain.c
@@ -0,0 +1,84 @@
+/*
+ * WPA Supplicant / WinMain() function for Windows-based applications
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+
+#ifdef _WIN32_WCE
+#define CMDLINE LPWSTR
+#else /* _WIN32_WCE */
+#define CMDLINE LPSTR
+#endif /* _WIN32_WCE */
+
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+ CMDLINE lpCmdLine, int nShowCmd)
+{
+ int i;
+ struct wpa_interface *ifaces, *iface;
+ int iface_count, exitcode = -1;
+ struct wpa_params params;
+ struct wpa_global *global;
+
+ if (os_program_init())
+ return -1;
+
+ os_memset(&params, 0, sizeof(params));
+ params.wpa_debug_level = MSG_MSGDUMP;
+ params.wpa_debug_file_path = "\\Temp\\wpa_supplicant-log.txt";
+ params.wpa_debug_show_keys = 1;
+
+ iface = ifaces = os_zalloc(sizeof(struct wpa_interface));
+ if (ifaces == NULL)
+ return -1;
+ iface_count = 1;
+
+ iface->confname = "default";
+ iface->driver = "ndis";
+ iface->ifname = "";
+
+ exitcode = 0;
+ global = wpa_supplicant_init(&params);
+ if (global == NULL) {
+ printf("Failed to initialize wpa_supplicant\n");
+ exitcode = -1;
+ }
+
+ for (i = 0; exitcode == 0 && i < iface_count; i++) {
+ if ((ifaces[i].confname == NULL &&
+ ifaces[i].ctrl_interface == NULL) ||
+ ifaces[i].ifname == NULL) {
+ if (iface_count == 1 && (params.ctrl_interface ||
+ params.dbus_ctrl_interface))
+ break;
+ exitcode = -1;
+ break;
+ }
+ if (wpa_supplicant_add_iface(global, &ifaces[i]) == NULL)
+ exitcode = -1;
+ }
+
+ if (exitcode == 0)
+ exitcode = wpa_supplicant_run(global);
+
+ wpa_supplicant_deinit(global);
+
+ os_free(ifaces);
+
+ os_program_deinit();
+
+ return exitcode;
+}
diff --git a/wpa_supplicant/main_winsvc.c b/wpa_supplicant/main_winsvc.c
new file mode 100644
index 0000000..4a46ed5
--- /dev/null
+++ b/wpa_supplicant/main_winsvc.c
@@ -0,0 +1,464 @@
+/*
+ * WPA Supplicant / main() function for Win32 service
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * The root of wpa_supplicant configuration in registry is
+ * HKEY_LOCAL_MACHINE\\SOFTWARE\\%wpa_supplicant. This level includes global
+ * parameters and a 'interfaces' subkey with all the interface configuration
+ * (adapter to confname mapping). Each such mapping is a subkey that has
+ * 'adapter' and 'config' values.
+ *
+ * This program can be run either as a normal command line application, e.g.,
+ * for debugging, with 'wpasvc.exe app' or as a Windows service. Service need
+ * to be registered with 'wpasvc.exe reg <full path to wpasvc.exe>'. After
+ * this, it can be started like any other Windows service (e.g., 'net start
+ * wpasvc') or it can be configured to start automatically through the Services
+ * tool in administrative tasks. The service can be unregistered with
+ * 'wpasvc.exe unreg'.
+ */
+
+#include "includes.h"
+#include <windows.h>
+
+#include "common.h"
+#include "wpa_supplicant_i.h"
+#include "eloop.h"
+
+#ifndef WPASVC_NAME
+#define WPASVC_NAME TEXT("wpasvc")
+#endif
+#ifndef WPASVC_DISPLAY_NAME
+#define WPASVC_DISPLAY_NAME TEXT("wpa_supplicant service")
+#endif
+#ifndef WPASVC_DESCRIPTION
+#define WPASVC_DESCRIPTION \
+TEXT("Provides IEEE 802.1X and WPA/WPA2 supplicant functionality")
+#endif
+
+static HANDLE kill_svc;
+
+static SERVICE_STATUS_HANDLE svc_status_handle;
+static SERVICE_STATUS svc_status;
+
+
+#ifndef WPA_KEY_ROOT
+#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE
+#endif
+#ifndef WPA_KEY_PREFIX
+#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant")
+#endif
+
+#ifdef UNICODE
+#define TSTR "%S"
+#else /* UNICODE */
+#define TSTR "%s"
+#endif /* UNICODE */
+
+
+static int read_interface(struct wpa_global *global, HKEY _hk,
+ const TCHAR *name)
+{
+ HKEY hk;
+#define TBUFLEN 255
+ TCHAR adapter[TBUFLEN], config[TBUFLEN], ctrl_interface[TBUFLEN];
+ DWORD buflen, val;
+ LONG ret;
+ struct wpa_interface iface;
+ int skip_on_error = 0;
+
+ ret = RegOpenKeyEx(_hk, name, 0, KEY_QUERY_VALUE, &hk);
+ if (ret != ERROR_SUCCESS) {
+ printf("Could not open wpa_supplicant interface key\n");
+ return -1;
+ }
+
+ os_memset(&iface, 0, sizeof(iface));
+ iface.driver = "ndis";
+
+ buflen = sizeof(ctrl_interface);
+ ret = RegQueryValueEx(hk, TEXT("ctrl_interface"), NULL, NULL,
+ (LPBYTE) ctrl_interface, &buflen);
+ if (ret == ERROR_SUCCESS) {
+ ctrl_interface[TBUFLEN - 1] = TEXT('\0');
+ wpa_unicode2ascii_inplace(ctrl_interface);
+ printf("ctrl_interface[len=%d] '%s'\n",
+ (int) buflen, (char *) ctrl_interface);
+ iface.ctrl_interface = (char *) ctrl_interface;
+ }
+
+ buflen = sizeof(adapter);
+ ret = RegQueryValueEx(hk, TEXT("adapter"), NULL, NULL,
+ (LPBYTE) adapter, &buflen);
+ if (ret == ERROR_SUCCESS) {
+ adapter[TBUFLEN - 1] = TEXT('\0');
+ wpa_unicode2ascii_inplace(adapter);
+ printf("adapter[len=%d] '%s'\n",
+ (int) buflen, (char *) adapter);
+ iface.ifname = (char *) adapter;
+ }
+
+ buflen = sizeof(config);
+ ret = RegQueryValueEx(hk, TEXT("config"), NULL, NULL,
+ (LPBYTE) config, &buflen);
+ if (ret == ERROR_SUCCESS) {
+ config[sizeof(config) - 1] = '\0';
+ wpa_unicode2ascii_inplace(config);
+ printf("config[len=%d] '%s'\n",
+ (int) buflen, (char *) config);
+ iface.confname = (char *) config;
+ }
+
+ buflen = sizeof(val);
+ ret = RegQueryValueEx(hk, TEXT("skip_on_error"), NULL, NULL,
+ (LPBYTE) &val, &buflen);
+ if (ret == ERROR_SUCCESS && buflen == sizeof(val))
+ skip_on_error = val;
+
+ RegCloseKey(hk);
+
+ if (wpa_supplicant_add_iface(global, &iface) == NULL) {
+ if (skip_on_error)
+ wpa_printf(MSG_DEBUG, "Skipped interface '%s' due to "
+ "initialization failure", iface.ifname);
+ else
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int wpa_supplicant_thread(void)
+{
+ int exitcode;
+ struct wpa_params params;
+ struct wpa_global *global;
+ HKEY hk, ihk;
+ DWORD val, buflen, i;
+ LONG ret;
+
+ if (os_program_init())
+ return -1;
+
+ os_memset(&params, 0, sizeof(params));
+ params.wpa_debug_level = MSG_INFO;
+
+ ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX,
+ 0, KEY_QUERY_VALUE, &hk);
+ if (ret != ERROR_SUCCESS) {
+ printf("Could not open wpa_supplicant registry key\n");
+ return -1;
+ }
+
+ buflen = sizeof(val);
+ ret = RegQueryValueEx(hk, TEXT("debug_level"), NULL, NULL,
+ (LPBYTE) &val, &buflen);
+ if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
+ params.wpa_debug_level = val;
+ }
+
+ buflen = sizeof(val);
+ ret = RegQueryValueEx(hk, TEXT("debug_show_keys"), NULL, NULL,
+ (LPBYTE) &val, &buflen);
+ if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
+ params.wpa_debug_show_keys = val;
+ }
+
+ buflen = sizeof(val);
+ ret = RegQueryValueEx(hk, TEXT("debug_timestamp"), NULL, NULL,
+ (LPBYTE) &val, &buflen);
+ if (ret == ERROR_SUCCESS && buflen == sizeof(val)) {
+ params.wpa_debug_timestamp = val;
+ }
+
+ buflen = sizeof(val);
+ ret = RegQueryValueEx(hk, TEXT("debug_use_file"), NULL, NULL,
+ (LPBYTE) &val, &buflen);
+ if (ret == ERROR_SUCCESS && buflen == sizeof(val) && val) {
+ params.wpa_debug_file_path = "\\Temp\\wpa_supplicant-log.txt";
+ }
+
+ exitcode = 0;
+ global = wpa_supplicant_init(&params);
+ if (global == NULL) {
+ printf("Failed to initialize wpa_supplicant\n");
+ exitcode = -1;
+ }
+
+ ret = RegOpenKeyEx(hk, TEXT("interfaces"), 0, KEY_ENUMERATE_SUB_KEYS,
+ &ihk);
+ RegCloseKey(hk);
+ if (ret != ERROR_SUCCESS) {
+ printf("Could not open wpa_supplicant interfaces registry "
+ "key\n");
+ return -1;
+ }
+
+ for (i = 0; ; i++) {
+ TCHAR name[255];
+ DWORD namelen;
+
+ namelen = 255;
+ ret = RegEnumKeyEx(ihk, i, name, &namelen, NULL, NULL, NULL,
+ NULL);
+
+ if (ret == ERROR_NO_MORE_ITEMS)
+ break;
+
+ if (ret != ERROR_SUCCESS) {
+ printf("RegEnumKeyEx failed: 0x%x\n",
+ (unsigned int) ret);
+ break;
+ }
+
+ if (namelen >= 255)
+ namelen = 255 - 1;
+ name[namelen] = '\0';
+
+ wpa_printf(MSG_DEBUG, "interface %d: %s\n", (int) i, name);
+ if (read_interface(global, ihk, name) < 0)
+ exitcode = -1;
+ }
+
+ RegCloseKey(ihk);
+
+ if (exitcode == 0)
+ exitcode = wpa_supplicant_run(global);
+
+ wpa_supplicant_deinit(global);
+
+ os_program_deinit();
+
+ return exitcode;
+}
+
+
+static DWORD svc_thread(LPDWORD param)
+{
+ int ret = wpa_supplicant_thread();
+
+ svc_status.dwCurrentState = SERVICE_STOPPED;
+ svc_status.dwWaitHint = 0;
+ if (!SetServiceStatus(svc_status_handle, &svc_status)) {
+ printf("SetServiceStatus() failed: %d\n",
+ (int) GetLastError());
+ }
+
+ return ret;
+}
+
+
+static int register_service(const TCHAR *exe)
+{
+ SC_HANDLE svc, scm;
+ SERVICE_DESCRIPTION sd;
+
+ printf("Registering service: " TSTR "\n", WPASVC_NAME);
+
+ scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
+ if (!scm) {
+ printf("OpenSCManager failed: %d\n", (int) GetLastError());
+ return -1;
+ }
+
+ svc = CreateService(scm, WPASVC_NAME, WPASVC_DISPLAY_NAME,
+ SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
+ SERVICE_DEMAND_START, SERVICE_ERROR_NORMAL,
+ exe, NULL, NULL, NULL, NULL, NULL);
+
+ if (!svc) {
+ printf("CreateService failed: %d\n\n", (int) GetLastError());
+ CloseServiceHandle(scm);
+ return -1;
+ }
+
+ os_memset(&sd, 0, sizeof(sd));
+ sd.lpDescription = WPASVC_DESCRIPTION;
+ if (!ChangeServiceConfig2(svc, SERVICE_CONFIG_DESCRIPTION, &sd)) {
+ printf("ChangeServiceConfig2 failed: %d\n",
+ (int) GetLastError());
+ /* This is not a fatal error, so continue anyway. */
+ }
+
+ CloseServiceHandle(svc);
+ CloseServiceHandle(scm);
+
+ printf("Service registered successfully.\n");
+
+ return 0;
+}
+
+
+static int unregister_service(void)
+{
+ SC_HANDLE svc, scm;
+ SERVICE_STATUS status;
+
+ printf("Unregistering service: " TSTR "\n", WPASVC_NAME);
+
+ scm = OpenSCManager(0, 0, SC_MANAGER_CREATE_SERVICE);
+ if (!scm) {
+ printf("OpenSCManager failed: %d\n", (int) GetLastError());
+ return -1;
+ }
+
+ svc = OpenService(scm, WPASVC_NAME, SERVICE_ALL_ACCESS | DELETE);
+ if (!svc) {
+ printf("OpenService failed: %d\n\n", (int) GetLastError());
+ CloseServiceHandle(scm);
+ return -1;
+ }
+
+ if (QueryServiceStatus(svc, &status)) {
+ if (status.dwCurrentState != SERVICE_STOPPED) {
+ printf("Service currently active - stopping "
+ "service...\n");
+ if (!ControlService(svc, SERVICE_CONTROL_STOP,
+ &status)) {
+ printf("ControlService failed: %d\n",
+ (int) GetLastError());
+ }
+ Sleep(500);
+ }
+ }
+
+ if (DeleteService(svc)) {
+ printf("Service unregistered successfully.\n");
+ } else {
+ printf("DeleteService failed: %d\n", (int) GetLastError());
+ }
+
+ CloseServiceHandle(svc);
+ CloseServiceHandle(scm);
+
+ return 0;
+}
+
+
+static void WINAPI service_ctrl_handler(DWORD control_code)
+{
+ switch (control_code) {
+ case SERVICE_CONTROL_INTERROGATE:
+ break;
+ case SERVICE_CONTROL_SHUTDOWN:
+ case SERVICE_CONTROL_STOP:
+ svc_status.dwCurrentState = SERVICE_STOP_PENDING;
+ svc_status.dwWaitHint = 2000;
+ eloop_terminate();
+ SetEvent(kill_svc);
+ break;
+ }
+
+ if (!SetServiceStatus(svc_status_handle, &svc_status)) {
+ printf("SetServiceStatus() failed: %d\n",
+ (int) GetLastError());
+ }
+}
+
+
+static void WINAPI service_start(DWORD argc, LPTSTR *argv)
+{
+ DWORD id;
+
+ svc_status_handle = RegisterServiceCtrlHandler(WPASVC_NAME,
+ service_ctrl_handler);
+ if (svc_status_handle == (SERVICE_STATUS_HANDLE) 0) {
+ printf("RegisterServiceCtrlHandler failed: %d\n",
+ (int) GetLastError());
+ return;
+ }
+
+ os_memset(&svc_status, 0, sizeof(svc_status));
+ svc_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ svc_status.dwCurrentState = SERVICE_START_PENDING;
+ svc_status.dwWaitHint = 1000;
+
+ if (!SetServiceStatus(svc_status_handle, &svc_status)) {
+ printf("SetServiceStatus() failed: %d\n",
+ (int) GetLastError());
+ return;
+ }
+
+ kill_svc = CreateEvent(0, TRUE, FALSE, 0);
+ if (!kill_svc) {
+ printf("CreateEvent failed: %d\n", (int) GetLastError());
+ return;
+ }
+
+ if (CreateThread(0, 0, (LPTHREAD_START_ROUTINE) svc_thread, 0, 0, &id)
+ == 0) {
+ printf("CreateThread failed: %d\n", (int) GetLastError());
+ return;
+ }
+
+ if (svc_status.dwCurrentState == SERVICE_START_PENDING) {
+ svc_status.dwCurrentState = SERVICE_RUNNING;
+ svc_status.dwWaitHint = 0;
+ svc_status.dwControlsAccepted = SERVICE_ACCEPT_STOP |
+ SERVICE_ACCEPT_SHUTDOWN;
+ }
+
+ if (!SetServiceStatus(svc_status_handle, &svc_status)) {
+ printf("SetServiceStatus() failed: %d\n",
+ (int) GetLastError());
+ return;
+ }
+
+ /* wait until service gets killed */
+ WaitForSingleObject(kill_svc, INFINITE);
+}
+
+
+int main(int argc, char *argv[])
+{
+ SERVICE_TABLE_ENTRY dt[] = {
+ { WPASVC_NAME, service_start },
+ { NULL, NULL }
+ };
+
+ if (argc > 1) {
+ if (os_strcmp(argv[1], "reg") == 0) {
+ TCHAR *path;
+ int ret;
+
+ if (argc < 3) {
+ path = os_malloc(MAX_PATH * sizeof(TCHAR));
+ if (path == NULL)
+ return -1;
+ if (!GetModuleFileName(NULL, path, MAX_PATH)) {
+ printf("GetModuleFileName failed: "
+ "%d\n", (int) GetLastError());
+ os_free(path);
+ return -1;
+ }
+ } else {
+ path = wpa_strdup_tchar(argv[2]);
+ if (path == NULL)
+ return -1;
+ }
+ ret = register_service(path);
+ os_free(path);
+ return ret;
+ } else if (os_strcmp(argv[1], "unreg") == 0) {
+ return unregister_service();
+ } else if (os_strcmp(argv[1], "app") == 0) {
+ return wpa_supplicant_thread();
+ }
+ }
+
+ if (!StartServiceCtrlDispatcher(dt)) {
+ printf("StartServiceCtrlDispatcher failed: %d\n",
+ (int) GetLastError());
+ }
+
+ return 0;
+}
diff --git a/wpa_supplicant/mlme.c b/wpa_supplicant/mlme.c
index 0c63067..9885e19 100644
--- a/wpa_supplicant/mlme.c
+++ b/wpa_supplicant/mlme.c
@@ -459,9 +459,9 @@ static void ieee80211_send_assoc(struct wpa_supplicant *wpa_s)
*pos++ = 0x00; /* Microsoft OUI 00:50:F2 */
*pos++ = 0x50;
*pos++ = 0xf2;
- *pos++ = 2; /* WME */
- *pos++ = 0; /* WME info */
- *pos++ = 1; /* WME ver */
+ *pos++ = 2; /* WMM */
+ *pos++ = 0; /* WMM info */
+ *pos++ = 1; /* WMM ver */
*pos++ = 0;
}
@@ -1175,9 +1175,9 @@ static void ieee80211_rx_mgmt_assoc_resp(struct wpa_supplicant *wpa_s,
#if 0 /* FIX? */
sta->assoc_ap = 1;
- if (elems.wme && wpa_s->mlme.wmm_enabled) {
- sta->flags |= WLAN_STA_WME;
- ieee80211_sta_wmm_params(wpa_s, elems.wme, elems.wme_len);
+ if (elems.wmm && wpa_s->mlme.wmm_enabled) {
+ sta->flags |= WLAN_STA_WMM;
+ ieee80211_sta_wmm_params(wpa_s, elems.wmm, elems.wmm_len);
}
#endif
@@ -1488,18 +1488,18 @@ static void ieee80211_bss_info(struct wpa_supplicant *wpa_s,
bss->rsn_ie_len = 0;
}
- if (elems.wme &&
- (bss->wmm_ie == NULL || bss->wmm_ie_len != elems.wme_len ||
- os_memcmp(bss->wmm_ie, elems.wme, elems.wme_len))) {
+ if (elems.wmm &&
+ (bss->wmm_ie == NULL || bss->wmm_ie_len != elems.wmm_len ||
+ os_memcmp(bss->wmm_ie, elems.wmm, elems.wmm_len))) {
os_free(bss->wmm_ie);
- bss->wmm_ie = os_malloc(elems.wme_len + 2);
+ bss->wmm_ie = os_malloc(elems.wmm_len + 2);
if (bss->wmm_ie) {
- os_memcpy(bss->wmm_ie, elems.wme - 2,
- elems.wme_len + 2);
- bss->wmm_ie_len = elems.wme_len + 2;
+ os_memcpy(bss->wmm_ie, elems.wmm - 2,
+ elems.wmm_len + 2);
+ bss->wmm_ie_len = elems.wmm_len + 2;
} else
bss->wmm_ie_len = 0;
- } else if (!elems.wme && bss->wmm_ie) {
+ } else if (!elems.wmm && bss->wmm_ie) {
os_free(bss->wmm_ie);
bss->wmm_ie = NULL;
bss->wmm_ie_len = 0;
@@ -1595,9 +1595,9 @@ static void ieee80211_rx_mgmt_beacon(struct wpa_supplicant *wpa_s,
wpa_s->mlme.cts_protect_erp_frames = use_protection;
}
- if (elems.wme && wpa_s->mlme.wmm_enabled) {
- ieee80211_sta_wmm_params(wpa_s, elems.wme,
- elems.wme_len);
+ if (elems.wmm && wpa_s->mlme.wmm_enabled) {
+ ieee80211_sta_wmm_params(wpa_s, elems.wmm,
+ elems.wmm_len);
}
}
@@ -1709,7 +1709,6 @@ static void ieee80211_rx_mgmt_ft_action(struct wpa_supplicant *wpa_s,
wpa_printf(MSG_DEBUG, "MLME: Foreign STA Address " MACSTR
" in FT Action Response", MAC2STR(sta_addr));
return;
-
}
if (status) {
diff --git a/wpa_supplicant/nmake.mak b/wpa_supplicant/nmake.mak
new file mode 100644
index 0000000..5e39c11
--- /dev/null
+++ b/wpa_supplicant/nmake.mak
@@ -0,0 +1,228 @@
+# Makefile for Microsoft nmake to build wpa_supplicant
+
+# This can be run in Visual Studio 2005 Command Prompt
+
+# Note: Make sure that cl.exe is configured to include Platform SDK
+# include and lib directories (vsvars32.bat)
+
+all: wpa_supplicant.exe wpa_cli.exe wpa_passphrase.exe wpasvc.exe win_if_list.exe
+
+# Root directory for WinPcap developer's pack
+# (http://www.winpcap.org/install/bin/WpdPack_3_1.zip)
+WINPCAPDIR=C:\dev\WpdPack
+
+# Root directory for OpenSSL
+# (http://www.openssl.org/source/openssl-0.9.8a.tar.gz)
+# Build and installed following instructions in INSTALL.W32
+# Note: If EAP-FAST is included in the build, OpenSSL needs to be patched to
+# support it (openssl-tls-extensions.patch)
+# Alternatively, see README-Windows.txt for information about binary
+# installation package for OpenSSL.
+OPENSSLDIR=C:\dev\openssl
+
+CC = cl
+OBJDIR = objs
+
+CFLAGS = /DCONFIG_NATIVE_WINDOWS
+CFLAGS = $(CFLAGS) /DCONFIG_NDIS_EVENTS_INTEGRATED
+CFLAGS = $(CFLAGS) /DCONFIG_ANSI_C_EXTRA
+CFLAGS = $(CFLAGS) /DCONFIG_WINPCAP
+CFLAGS = $(CFLAGS) /DIEEE8021X_EAPOL
+CFLAGS = $(CFLAGS) /DEAP_TLS_FUNCS
+CFLAGS = $(CFLAGS) /DPKCS12_FUNCS
+CFLAGS = $(CFLAGS) /DEAP_MD5
+CFLAGS = $(CFLAGS) /DEAP_TLS
+CFLAGS = $(CFLAGS) /DEAP_MSCHAPv2
+CFLAGS = $(CFLAGS) /DEAP_PEAP
+CFLAGS = $(CFLAGS) /DEAP_TTLS
+CFLAGS = $(CFLAGS) /DEAP_GTC
+CFLAGS = $(CFLAGS) /DEAP_OTP
+CFLAGS = $(CFLAGS) /DEAP_SIM
+CFLAGS = $(CFLAGS) /DEAP_LEAP
+CFLAGS = $(CFLAGS) /DEAP_PSK
+CFLAGS = $(CFLAGS) /DEAP_AKA
+#CFLAGS = $(CFLAGS) /DEAP_FAST
+CFLAGS = $(CFLAGS) /DEAP_PAX
+CFLAGS = $(CFLAGS) /DEAP_TNC
+CFLAGS = $(CFLAGS) /DPCSC_FUNCS
+CFLAGS = $(CFLAGS) /DCONFIG_CTRL_IFACE
+CFLAGS = $(CFLAGS) /DCONFIG_CTRL_IFACE_NAMED_PIPE
+CFLAGS = $(CFLAGS) /DCONFIG_DRIVER_NDIS
+CFLAGS = $(CFLAGS) /I..\src /I..\src\utils /I..\src\common /I..\src\crypto
+CFLAGS = $(CFLAGS) /I..\src\rsn_supp /I..\src\eapol_supp /I.
+CFLAGS = $(CFLAGS) /DWIN32
+CFLAGS = $(CFLAGS) /Fo$(OBJDIR)\\ /c
+CFLAGS = $(CFLAGS) /W3
+
+#CFLAGS = $(CFLAGS) /WX
+
+# VS 2005 complains about lot of deprecated string functions; let's ignore them
+# at least for now since snprintf and strncpy can be used in a safe way
+CFLAGS = $(CFLAGS) /D_CRT_SECURE_NO_DEPRECATE
+
+OBJS = \
+ $(OBJDIR)\os_win32.obj \
+ $(OBJDIR)\eloop_win.obj \
+ $(OBJDIR)\sha1.obj \
+ $(OBJDIR)\md5.obj \
+ $(OBJDIR)\rc4.obj \
+ $(OBJDIR)\aes_wrap.obj \
+ $(OBJDIR)\common.obj \
+ $(OBJDIR)\wpa_debug.obj \
+ $(OBJDIR)\wpabuf.obj \
+ $(OBJDIR)\wpa_supplicant.obj \
+ $(OBJDIR)\wpa.obj \
+ $(OBJDIR)\wpa_common.obj \
+ $(OBJDIR)\wpa_ie.obj \
+ $(OBJDIR)\preauth.obj \
+ $(OBJDIR)\pmksa_cache.obj \
+ $(OBJDIR)\eapol_supp_sm.obj \
+ $(OBJDIR)\eap.obj \
+ $(OBJDIR)\eap_common.obj \
+ $(OBJDIR)\chap.obj \
+ $(OBJDIR)\eap_methods.obj \
+ $(OBJDIR)\eap_md5.obj \
+ $(OBJDIR)\eap_tls.obj \
+ $(OBJDIR)\eap_tls_common.obj \
+ $(OBJDIR)\eap_mschapv2.obj \
+ $(OBJDIR)\mschapv2.obj \
+ $(OBJDIR)\eap_peap.obj \
+ $(OBJDIR)\eap_peap_common.obj \
+ $(OBJDIR)\eap_ttls.obj \
+ $(OBJDIR)\eap_gtc.obj \
+ $(OBJDIR)\eap_otp.obj \
+ $(OBJDIR)\eap_leap.obj \
+ $(OBJDIR)\eap_sim.obj \
+ $(OBJDIR)\eap_sim_common.obj \
+ $(OBJDIR)\eap_aka.obj \
+ $(OBJDIR)\eap_pax.obj \
+ $(OBJDIR)\eap_pax_common.obj \
+ $(OBJDIR)\eap_psk.obj \
+ $(OBJDIR)\eap_psk_common.obj \
+ $(OBJDIR)\eap_tnc.obj \
+ $(OBJDIR)\tncc.obj \
+ $(OBJDIR)\base64.obj \
+ $(OBJDIR)\ctrl_iface.obj \
+ $(OBJDIR)\ctrl_iface_named_pipe.obj \
+ $(OBJDIR)\driver_ndis.obj \
+ $(OBJDIR)\driver_ndis_.obj \
+ $(OBJDIR)\scan_helpers.obj \
+ $(OBJDIR)\events.obj \
+ $(OBJDIR)\blacklist.obj \
+ $(OBJDIR)\scan.obj \
+ $(OBJDIR)\wpas_glue.obj \
+ $(OBJDIR)\config.obj \
+ $(OBJDIR)\l2_packet_winpcap.obj \
+ $(OBJDIR)\tls_openssl.obj \
+ $(OBJDIR)\ms_funcs.obj \
+ $(OBJDIR)\crypto_openssl.obj \
+ $(OBJDIR)\pcsc_funcs.obj \
+ $(OBJDIR)\ndis_events.obj
+
+# OBJS = $(OBJS) $(OBJDIR)\eap_fast.obj
+
+OBJS_t = $(OBJS) \
+ $(OBJDIR)\eapol_test.obj \
+ $(OBJDIR)\radius.obj \
+ $(OBJDIR)\radius_client.obj \
+ $(OBJDIR)\config_file.obj $(OBJDIR)\base64.obj
+
+OBJS_t2 = $(OBJS) \
+ $(OBJDIR)\preauth_test.obj \
+ $(OBJDIR)\config_file.obj $(OBJDIR)\base64.obj
+
+OBJS2 = $(OBJDIR)\drivers.obj \
+ $(OBJDIR)\config_file.obj \
+ $(OBJS2) $(OBJDIR)\main.obj
+
+OBJS3 = $(OBJDIR)\drivers.obj \
+ $(OBJDIR)\config_winreg.obj \
+ $(OBJS3) $(OBJDIR)\main_winsvc.obj
+
+OBJS_c = \
+ $(OBJDIR)\os_win32.obj \
+ $(OBJDIR)\wpa_cli.obj \
+ $(OBJDIR)\wpa_ctrl.obj \
+ $(OBJDIR)\common.obj
+
+OBJS_p = \
+ $(OBJDIR)\os_win32.obj \
+ $(OBJDIR)\common.obj \
+ $(OBJDIR)\sha1.obj \
+ $(OBJDIR)\md5.obj \
+ $(OBJDIR)\crypto_openssl.obj \
+ $(OBJDIR)\wpa_passphrase.obj
+
+LIBS = wbemuuid.lib libcmt.lib kernel32.lib uuid.lib ole32.lib oleaut32.lib \
+ ws2_32.lib Advapi32.lib Crypt32.lib Winscard.lib \
+ Packet.lib wpcap.lib \
+ libeay32.lib ssleay32.lib
+# If using Win32 OpenSSL binary installation from Shining Light Productions,
+# replace the last line with this for dynamic libraries
+# libeay32MT.lib ssleay32MT.lib
+# and this for static libraries
+# libeay32MT.lib ssleay32MT.lib Gdi32.lib User32.lib
+
+CFLAGS = $(CFLAGS) /I"$(WINPCAPDIR)/Include" /I"$(OPENSSLDIR)\include"
+LFLAGS = /libpath:"$(WINPCAPDIR)\Lib" /libpath:"$(OPENSSLDIR)\lib"
+
+wpa_supplicant.exe: $(OBJDIR) $(OBJS) $(OBJS2)
+ link.exe /out:wpa_supplicant.exe $(LFLAGS) $(OBJS) $(OBJS2) $(LIBS)
+
+wpasvc.exe: $(OBJDIR) $(OBJS) $(OBJS3)
+ link.exe /out:wpasvc.exe $(LFLAGS) $(OBJS) $(OBJS3) $(LIBS)
+
+wpa_cli.exe: $(OBJDIR) $(OBJS_c)
+ link.exe /out:wpa_cli.exe $(LFLAGS) $(OBJS_c) $(LIBS)
+
+wpa_passphrase.exe: $(OBJDIR) $(OBJS_p)
+ link.exe /out:wpa_passphrase.exe $(LFLAGS) $(OBJS_p) $(LIBS)
+
+eapol_test.exe: $(OBJDIR) $(OBJS_t)
+ link.exe /out:eapol_test.exe $(LFLAGS) $(OBJS_t) $(LIBS)
+
+preauth_test.exe: $(OBJDIR) $(OBJS_t2)
+ link.exe /out:preauth_test.exe $(LFLAGS) $(OBJS_t2) $(LIBS)
+
+win_if_list.exe: $(OBJDIR) $(OBJDIR)\win_if_list.obj
+ link.exe /out:win_if_list.exe $(LFLAGS) $(OBJDIR)\win_if_list.obj $(LIBS)
+
+
+{..\src\utils}.c{$(OBJDIR)}.obj::
+ $(CC) $(CFLAGS) $<
+
+{..\src\common}.c{$(OBJDIR)}.obj::
+ $(CC) $(CFLAGS) $<
+
+{..\src\rsn_supp}.c{$(OBJDIR)}.obj::
+ $(CC) $(CFLAGS) $<
+
+{..\src\eapol_supp}.c{$(OBJDIR)}.obj::
+ $(CC) $(CFLAGS) $<
+
+{..\src\crypto}.c{$(OBJDIR)}.obj::
+ $(CC) $(CFLAGS) $<
+
+{..\src\eap_peer}.c{$(OBJDIR)}.obj::
+ $(CC) $(CFLAGS) $<
+
+{..\src\eap_common}.c{$(OBJDIR)}.obj::
+ $(CC) $(CFLAGS) $<
+
+{..\src\drivers}.c{$(OBJDIR)}.obj::
+ $(CC) $(CFLAGS) $<
+
+{..\src\l2_packet}.c{$(OBJDIR)}.obj::
+ $(CC) $(CFLAGS) $<
+
+{.\}.c{$(OBJDIR)}.obj::
+ $(CC) $(CFLAGS) $<
+
+{.\}.cpp{$(OBJDIR)}.obj::
+ $(CC) $(CFLAGS) $<
+
+$(OBJDIR):
+ if not exist "$(OBJDIR)" mkdir "$(OBJDIR)"
+
+clean:
+ erase $(OBJDIR)\*.obj wpa_supplicant.exe
diff --git a/wpa_supplicant/scan.c b/wpa_supplicant/scan.c
index 67e2282..8cb7a42 100644
--- a/wpa_supplicant/scan.c
+++ b/wpa_supplicant/scan.c
@@ -20,6 +20,7 @@
#include "wpa_supplicant_i.h"
#include "mlme.h"
#include "wps_supplicant.h"
+#include "ctrl_iface_dbus.h"
static void wpa_supplicant_gen_assoc_event(struct wpa_supplicant *wpa_s)
@@ -65,11 +66,24 @@ static int wpas_wps_in_use(struct wpa_config *conf,
}
#endif /* CONFIG_WPS */
+
+int wpa_supplicant_enabled_networks(struct wpa_config *conf)
+{
+ struct wpa_ssid *ssid = conf->ssid;
+ while (ssid) {
+ if (!ssid->disabled)
+ return 1;
+ ssid = ssid->next;
+ }
+ return 0;
+}
+
+
static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
{
struct wpa_supplicant *wpa_s = eloop_ctx;
struct wpa_ssid *ssid;
- int enabled, scan_req = 0, ret;
+ int scan_req = 0, ret;
struct wpabuf *wps_ie = NULL;
const u8 *extra_ie = NULL;
size_t extra_ie_len = 0;
@@ -78,19 +92,13 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
enum wps_request_type req_type = WPS_REQ_ENROLLEE_INFO;
#endif /* CONFIG_WPS */
- if (wpa_s->disconnected && !wpa_s->scan_req)
+ if (wpa_s->disconnected && !wpa_s->scan_req) {
+ wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
return;
-
- enabled = 0;
- ssid = wpa_s->conf->ssid;
- while (ssid) {
- if (!ssid->disabled) {
- enabled++;
- break;
- }
- ssid = ssid->next;
}
- if (!enabled && !wpa_s->scan_req) {
+
+ if (!wpa_supplicant_enabled_networks(wpa_s->conf) &&
+ !wpa_s->scan_req) {
wpa_printf(MSG_DEBUG, "No enabled networks - do not scan");
wpa_supplicant_set_state(wpa_s, WPA_INACTIVE);
return;
@@ -189,6 +197,8 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
}
#endif /* CONFIG_WPS */
+ wpa_supplicant_notify_scanning(wpa_s, 1);
+
if (wpa_s->use_client_mlme) {
ieee80211_sta_set_probe_req_ie(wpa_s, extra_ie, extra_ie_len);
ret = ieee80211_sta_req_scan(wpa_s, ssid ? ssid->ssid : NULL,
@@ -203,6 +213,7 @@ static void wpa_supplicant_scan(void *eloop_ctx, void *timeout_ctx)
if (ret) {
wpa_printf(MSG_WARNING, "Failed to initiate AP scan.");
+ wpa_supplicant_notify_scanning(wpa_s, 0);
wpa_supplicant_req_scan(wpa_s, 10, 0);
} else
wpa_s->scan_runs++;
@@ -261,3 +272,14 @@ void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s)
wpa_msg(wpa_s, MSG_DEBUG, "Cancelling scan request");
eloop_cancel_timeout(wpa_supplicant_scan, wpa_s, NULL);
}
+
+
+void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
+ int scanning)
+{
+ if (wpa_s->scanning != scanning) {
+ wpa_s->scanning = scanning;
+ wpa_supplicant_dbus_notify_scanning(wpa_s);
+ }
+}
+
diff --git a/wpa_supplicant/symbian/README.symbian b/wpa_supplicant/symbian/README.symbian
new file mode 100644
index 0000000..9d3b811
--- /dev/null
+++ b/wpa_supplicant/symbian/README.symbian
@@ -0,0 +1,24 @@
+wpa_supplicant for Symbian
+==========================
+
+Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi> and
+contributors
+All Rights Reserved.
+
+This program is dual-licensed under both the GPL version 2 and BSD
+license. Either license may be used at your option.
+
+
+This directory includes project files for testing experimental Symbian
+(e.g., Nokia S60 3rd Ed) builds. The Symbian port is not really
+complete or expected to work, but these files can be used to verify
+that the build itself can be completed successfully.
+
+These files have been successfully tested with Nokia S60 3rd Edition
+MR SDK.
+
+Build files can be created and a phone release build can be run with
+following commands:
+
+bldmake bldfiles
+abld build gcce urel
diff --git a/wpa_supplicant/symbian/bld.inf b/wpa_supplicant/symbian/bld.inf
new file mode 100644
index 0000000..a1fc582
--- /dev/null
+++ b/wpa_supplicant/symbian/bld.inf
@@ -0,0 +1,8 @@
+PRJ_PLATFORMS
+WINSCW GCCE
+
+PRJ_EXPORTS
+
+PRJ_MMPFILES
+
+wpa_supplicant.mmp
diff --git a/wpa_supplicant/symbian/wpa_supplicant.mmp b/wpa_supplicant/symbian/wpa_supplicant.mmp
new file mode 100644
index 0000000..fad9626
--- /dev/null
+++ b/wpa_supplicant/symbian/wpa_supplicant.mmp
@@ -0,0 +1,38 @@
+TARGET wpa_supplicant.exe
+UID 0x0 0x0
+VENDORID 0
+TARGETTYPE exe
+
+SYSTEMINCLUDE \epoc32\include \epoc32\include\variant \epoc32\include\ecom \epoc32\include\libc
+
+USERINCLUDE .. ..\..\src ..\..\src\utils ..\..\src\common ..\..\src\crypto ..\..\src\rsn_supp
+
+SOURCEPATH ..
+SOURCE main_symbian.cpp
+SOURCE config.c config_file.c
+SOURCE eapol_sm.c
+SOURCE wpa_supplicant.c events.c
+SOURCEPATH ..\..\src\rsn_supp
+SOURCE wpa.c preauth.c pmksa_cache.c peerkey.c wpa_ie.c
+SOURCEPATH ..\..\src\drivers
+SOURCE drivers.c
+SOURCEPATH ..\..\src\common
+SOURCE wpa_common.c
+SOURCEPATH ..\..\src\utils
+SOURCE os_none.c common.c wpa_debug.c eloop_none.c base64.c
+SOURCEPATH ..\..\src\crypto
+SOURCE sha1.c md5.c rc4.c md4.c des.c aes_wrap.c aes.c ms_funcs.c
+SOURCE tls_internal.c crypto_internal.c
+SOURCEPATH ..\..\src\tls
+SOURCE asn1.c bignum.c rsa.c x509v3.c tlsv1_client.c tlsv1_common.c
+SOURCEPATH ..\..\src\l2_packet
+SOURCE l2_packet_none.c
+SOURCEPATH ..\..\src\eap_peer
+SOURCE eap.c eap_methods.c
+SOURCE eap_md5.c eap_tls.c eap_mschapv2.c eap_peap.c eap_gtc.c
+SOURCE eap_ttls.c eap_otp.c eap_leap.c eap_tls_common.c eap_tlv.c
+SOURCE eap_fast.c eap_fast_pac.c
+SOURCEPATH ..\..\src\eap_common
+SOURCE eap_common.c
+
+LIBRARY euser.lib estlib.lib
diff --git a/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj b/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj
new file mode 100755
index 0000000..9c46240
--- /dev/null
+++ b/wpa_supplicant/vs2005/eapol_test/eapol_test.vcproj
@@ -0,0 +1,425 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="eapol_test"
+ ProjectGUID="{0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}"
+ RootNamespace="eapol_test"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;..\..\..\src\common;..\..\..\src\crypto;..\..\..\src\rsn_supp;C:\dev\WpdPack\include;C:\dev\openssl\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4244;4267;4311"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;..\..\..\src\common;..\..\..\src\crypto;..\..\..\src\rsn_supp;C:\dev\WpdPack\include;C:\dev\openssl\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4267;4311"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\src\crypto\aes_wrap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\base64.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\blacklist.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\chap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\config.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\config_file.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\crypto_openssl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\ctrl_iface.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\ctrl_iface_named_pipe.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_aka.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\eap_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_gtc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_leap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_methods.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_mschapv2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_otp.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_peap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\eap_peap_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_sim.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\eap_sim_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tls.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tls_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tnc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_ttls.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eapol_supp\eapol_supp_sm.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\eapol_test.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\eloop_win.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\events.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\ip_addr.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\l2_packet\l2_packet_winpcap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\ms_funcs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\mschapv2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\os_win32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\pcsc_funcs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\peerkey.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\pmksa_cache.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\preauth.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\radius\radius.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\radius\radius_client.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\rc4.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\scan.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\scan_helpers.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\tls_openssl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\tncc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\wpa.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\common\wpa_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\wpa_debug.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\wpa_ie.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wpa_supplicant.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\wpabuf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wpas_glue.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj b/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj
new file mode 100755
index 0000000..e79fc0f
--- /dev/null
+++ b/wpa_supplicant/vs2005/win_if_list/win_if_list.vcproj
@@ -0,0 +1,203 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="win_if_list"
+ ProjectGUID="{9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}"
+ RootNamespace="win_if_list"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\src\utils;C:\dev\WpdPack\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wpcap.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="C:\dev\WpdPack\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\..\src\utils;C:\dev\WpdPack\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wpcap.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="C:\dev\WpdPack\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\win_if_list.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj b/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj
new file mode 100755
index 0000000..6d36cba
--- /dev/null
+++ b/wpa_supplicant/vs2005/wpa_cli/wpa_cli.vcproj
@@ -0,0 +1,215 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="wpa_cli"
+ ProjectGUID="{E3A7B181-22CC-4DA3-8410-6AD69879A9EC}"
+ RootNamespace="wpa_cli"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\src\utils;..\..\..\src\common"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4244;4267"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\..\src\utils;..\..\..\src\common"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4267"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\src\utils\common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\os_win32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wpa_cli.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\common\wpa_ctrl.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj b/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj
new file mode 100755
index 0000000..1a3618b
--- /dev/null
+++ b/wpa_supplicant/vs2005/wpa_passphrase/wpa_passphrase.vcproj
@@ -0,0 +1,220 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="wpa_passphrase"
+ ProjectGUID="{ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}"
+ RootNamespace="wpa_passphrase"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..\..\src\utils;..\..\..\src\crypto;C:\dev\openssl\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS;INTERNAL_SHA1;INTERNAL_MD5"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4244;4267"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories=""
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..\..\src\utils;..\..\..\src\crypto;C:\dev\openssl\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS;INTERNAL_SHA1;INTERNAL_MD5"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4267"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="ws2_32.lib"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\src\utils\common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\os_win32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wpa_passphrase.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/wpa_supplicant/vs2005/wpa_supplicant.sln b/wpa_supplicant/vs2005/wpa_supplicant.sln
new file mode 100755
index 0000000..df89e31
--- /dev/null
+++ b/wpa_supplicant/vs2005/wpa_supplicant.sln
@@ -0,0 +1,52 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpa_supplicant", "wpa_supplicant\wpa_supplicant.vcproj", "{8BCFDA77-AEDC-4168-8897-5B73105BBB87}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpa_cli", "wpa_cli\wpa_cli.vcproj", "{E3A7B181-22CC-4DA3-8410-6AD69879A9EC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpasvc", "wpasvc\wpasvc.vcproj", "{E2A4A85F-CA77-406D-8ABF-63EF94545ACC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wpa_passphrase", "wpa_passphrase\wpa_passphrase.vcproj", "{ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "win_if_list", "win_if_list\win_if_list.vcproj", "{9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "eapol_test", "eapol_test\eapol_test.vcproj", "{0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}"
+EndProject
+Global
+ GlobalSection(DPCodeReviewSolutionGUID) = preSolution
+ DPCodeReviewSolutionGUID = {00000000-0000-0000-0000-000000000000}
+ EndGlobalSection
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Debug|Win32.ActiveCfg = Debug|Win32
+ {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Debug|Win32.Build.0 = Debug|Win32
+ {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Release|Win32.ActiveCfg = Release|Win32
+ {8BCFDA77-AEDC-4168-8897-5B73105BBB87}.Release|Win32.Build.0 = Release|Win32
+ {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Debug|Win32.Build.0 = Debug|Win32
+ {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Release|Win32.ActiveCfg = Release|Win32
+ {E3A7B181-22CC-4DA3-8410-6AD69879A9EC}.Release|Win32.Build.0 = Release|Win32
+ {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Debug|Win32.ActiveCfg = Debug|Win32
+ {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Debug|Win32.Build.0 = Debug|Win32
+ {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Release|Win32.ActiveCfg = Release|Win32
+ {E2A4A85F-CA77-406D-8ABF-63EF94545ACC}.Release|Win32.Build.0 = Release|Win32
+ {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Debug|Win32.ActiveCfg = Debug|Win32
+ {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Debug|Win32.Build.0 = Debug|Win32
+ {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Release|Win32.ActiveCfg = Release|Win32
+ {ADBE4EA8-F0C5-40C2-AE89-C56D0F2EC1DF}.Release|Win32.Build.0 = Release|Win32
+ {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Debug|Win32.ActiveCfg = Debug|Win32
+ {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Debug|Win32.Build.0 = Debug|Win32
+ {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Release|Win32.ActiveCfg = Release|Win32
+ {9E87CD9C-60CE-4533-85CF-85CA3A9BF26A}.Release|Win32.Build.0 = Release|Win32
+ {0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}.Debug|Win32.ActiveCfg = Debug|Win32
+ {0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}.Debug|Win32.Build.0 = Debug|Win32
+ {0E3F2C6D-1372-48D6-BCAB-E584917C4DE3}.Release|Win32.ActiveCfg = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj b/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj
new file mode 100755
index 0000000..a733fea
--- /dev/null
+++ b/wpa_supplicant/vs2005/wpa_supplicant/wpa_supplicant.vcproj
@@ -0,0 +1,421 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="wpa_supplicant"
+ ProjectGUID="{8BCFDA77-AEDC-4168-8897-5B73105BBB87}"
+ RootNamespace="wpa_supplicant"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;..\..\..\src\common;..\..\..\src\crypto;..\..\..\src\rsn_supp;C:\dev\WpdPack\include;C:\dev\openssl\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4244;4267;4311"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wbemuuid.lib ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;..\..\..\src\common;..\..\..\src\crypto;..\..\..\src\rsn_supp;C:\dev\WpdPack\include;C:\dev\openssl\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4267;4311"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wbemuuid.lib ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\src\crypto\aes_wrap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\base64.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\blacklist.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\chap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\config.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\config_file.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\crypto_openssl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\ctrl_iface.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\ctrl_iface_named_pipe.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\driver_ndis.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\driver_ndis_.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\drivers.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\eap_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_gtc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_leap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_methods.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_mschapv2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_otp.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_peap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\eap_peap_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tls.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tls_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tnc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_ttls.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eapol_supp\eapol_supp_sm.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\eloop_win.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\events.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\l2_packet\l2_packet_winpcap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\main.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\md4.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\ms_funcs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\mschapv2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\ndis_events.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\os_win32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\pcsc_funcs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\peerkey.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\pmksa_cache.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\preauth.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\rc4.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\scan.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\scan_helpers.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\tls_openssl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\tncc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\wpa.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\common\wpa_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\wpa_debug.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\wpa_ie.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wpa_supplicant.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\wpabuf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wpas_glue.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj b/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj
new file mode 100755
index 0000000..9f9e438
--- /dev/null
+++ b/wpa_supplicant/vs2005/wpasvc/wpasvc.vcproj
@@ -0,0 +1,421 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="wpasvc"
+ ProjectGUID="{E2A4A85F-CA77-406D-8ABF-63EF94545ACC}"
+ RootNamespace="wpasvc"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;..\..\..\src\common;..\..\..\src\crypto;..\..\..\src\rsn_supp;C:\dev\WpdPack\include;C:\dev\openssl\include"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ DisableSpecificWarnings="4244;4267;4311"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wbemuuid.lib ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib"
+ LinkIncremental="2"
+ AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="$(SolutionDir)$(ConfigurationName)"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="0"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="..\..;..\..\..\src;..\..\..\src\utils;..\..\..\src\common;..\..\..\src\crypto;..\..\..\src\rsn_supp;C:\dev\WpdPack\include;C:\dev\openssl\include"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;CONFIG_WIN32_DEFAULTS"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ DisableSpecificWarnings="4244;4267;4311"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="wbemuuid.lib ws2_32.lib Crypt32.lib Winscard.lib Packet.lib wpcap.lib libeay32MT.lib ssleay32Mt.lib"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="C:\dev\WpdPack\lib;C:\dev\openssl\lib"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath="..\..\..\src\crypto\aes_wrap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\base64.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\blacklist.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\chap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\config.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\config_winreg.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\crypto_openssl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\ctrl_iface.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\ctrl_iface_named_pipe.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\driver_ndis.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\driver_ndis_.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\drivers.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\eap_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_gtc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_leap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_methods.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_mschapv2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_otp.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_peap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_common\eap_peap_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tls.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tls_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_tnc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\eap_ttls.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eapol_supp\eapol_supp_sm.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\eloop_win.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\events.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\l2_packet\l2_packet_winpcap.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\main_winsvc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\md4.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\md5.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\ms_funcs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\mschapv2.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\ndis_events.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\os_win32.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\pcsc_funcs.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\peerkey.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\pmksa_cache.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\preauth.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\rc4.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\scan.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\drivers\scan_helpers.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\sha1.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\crypto\tls_openssl.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\eap_peer\tncc.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\wpa.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\common\wpa_common.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\wpa_debug.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\rsn_supp\wpa_ie.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wpa_supplicant.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\..\src\utils\wpabuf.c"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wpas_glue.c"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/wpa_supplicant/win_example.reg b/wpa_supplicant/win_example.reg
new file mode 100755
index 0000000..875d4ef
--- /dev/null
+++ b/wpa_supplicant/win_example.reg
@@ -0,0 +1,42 @@
+REGEDIT4
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant]
+"debug_level"=dword:00000000
+"debug_show_keys"=dword:00000001
+"debug_timestamp"=dword:00000000
+"debug_use_file"=dword:00000000
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs]
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test]
+"ap_scan"=dword:00000002
+"update_config"=dword:00000001
+"uuid"="12345678-9abc-def0-1234-56789abcdef0"
+"device_name"="Wireless Client"
+"manufacturer"="Company"
+"model_name"="cmodel"
+"serial_number"="12345"
+"device_type"="1-0050F204-1"
+"os_version"="01020300"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\blobs]
+"testblob"=hex:01,02,03,04,05
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks]
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\configs\test\networks\0000]
+"ssid"="\"example network\""
+"key_mgmt"="WPA-PSK"
+"psk"="\"secret password\""
+"pairwise"="CCMP"
+"group"="CCMP"
+"proto"="WPA"
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\interfaces]
+
+[HKEY_LOCAL_MACHINE\SOFTWARE\wpa_supplicant\interfaces\0000]
+"adapter"="{A7627643-C310-49E5-BD89-7E77709C04AB}"
+"config"="test"
+"ctrl_interface"=""
+"skip_on_error"=dword:00000000
+
diff --git a/wpa_supplicant/win_if_list.c b/wpa_supplicant/win_if_list.c
new file mode 100644
index 0000000..0e1532e
--- /dev/null
+++ b/wpa_supplicant/win_if_list.c
@@ -0,0 +1,179 @@
+/*
+ * win_if_list - Display network interfaces with description (for Windows)
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This small tool is for the Windows build to provide an easy way of fetching
+ * a list of available network interfaces.
+ */
+
+#include "includes.h"
+#include <stdio.h>
+#ifdef CONFIG_USE_NDISUIO
+#include <winsock2.h>
+#include <ntddndis.h>
+#else /* CONFIG_USE_NDISUIO */
+#include "pcap.h"
+#include <winsock.h>
+#endif /* CONFIG_USE_NDISUIO */
+
+#ifdef CONFIG_USE_NDISUIO
+
+/* from nuiouser.h */
+#define FSCTL_NDISUIO_BASE FILE_DEVICE_NETWORK
+
+#define _NDISUIO_CTL_CODE(_Function, _Method, _Access) \
+ CTL_CODE(FSCTL_NDISUIO_BASE, _Function, _Method, _Access)
+
+#define IOCTL_NDISUIO_QUERY_BINDING \
+ _NDISUIO_CTL_CODE(0x203, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+#define IOCTL_NDISUIO_BIND_WAIT \
+ _NDISUIO_CTL_CODE(0x204, METHOD_BUFFERED, \
+ FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+typedef struct _NDISUIO_QUERY_BINDING
+{
+ ULONG BindingIndex;
+ ULONG DeviceNameOffset;
+ ULONG DeviceNameLength;
+ ULONG DeviceDescrOffset;
+ ULONG DeviceDescrLength;
+} NDISUIO_QUERY_BINDING, *PNDISUIO_QUERY_BINDING;
+
+
+static HANDLE ndisuio_open(void)
+{
+ DWORD written;
+ HANDLE h;
+
+ h = CreateFile(TEXT("\\\\.\\\\Ndisuio"),
+ GENERIC_READ | GENERIC_WRITE, 0, NULL,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
+ INVALID_HANDLE_VALUE);
+ if (h == INVALID_HANDLE_VALUE)
+ return h;
+
+#ifndef _WIN32_WCE
+ if (!DeviceIoControl(h, IOCTL_NDISUIO_BIND_WAIT, NULL, 0, NULL, 0,
+ &written, NULL)) {
+ printf("IOCTL_NDISUIO_BIND_WAIT failed: %d",
+ (int) GetLastError());
+ CloseHandle(h);
+ return INVALID_HANDLE_VALUE;
+ }
+#endif /* _WIN32_WCE */
+
+ return h;
+}
+
+
+static void ndisuio_query_bindings(HANDLE ndisuio)
+{
+ NDISUIO_QUERY_BINDING *b;
+ size_t blen = sizeof(*b) + 1024;
+ int i, error;
+ DWORD written;
+ char name[256], desc[256];
+ WCHAR *pos;
+ size_t j, len;
+
+ b = malloc(blen);
+ if (b == NULL)
+ return;
+
+ for (i = 0; ; i++) {
+ memset(b, 0, blen);
+ b->BindingIndex = i;
+ if (!DeviceIoControl(ndisuio, IOCTL_NDISUIO_QUERY_BINDING,
+ b, sizeof(NDISUIO_QUERY_BINDING), b,
+ (DWORD) blen, &written, NULL)) {
+ error = (int) GetLastError();
+ if (error == ERROR_NO_MORE_ITEMS)
+ break;
+ printf("IOCTL_NDISUIO_QUERY_BINDING failed: %d",
+ error);
+ break;
+ }
+
+ pos = (WCHAR *) ((char *) b + b->DeviceNameOffset);
+ len = b->DeviceNameLength;
+ if (len >= sizeof(name))
+ len = sizeof(name) - 1;
+ for (j = 0; j < len; j++)
+ name[j] = (char) pos[j];
+ name[len] = '\0';
+
+ pos = (WCHAR *) ((char *) b + b->DeviceDescrOffset);
+ len = b->DeviceDescrLength;
+ if (len >= sizeof(desc))
+ len = sizeof(desc) - 1;
+ for (j = 0; j < len; j++)
+ desc[j] = (char) pos[j];
+ desc[len] = '\0';
+
+ printf("ifname: %s\ndescription: %s\n\n", name, desc);
+ }
+
+ free(b);
+}
+
+
+static void ndisuio_enum_bindings(void)
+{
+ HANDLE ndisuio = ndisuio_open();
+ if (ndisuio == INVALID_HANDLE_VALUE)
+ return;
+
+ ndisuio_query_bindings(ndisuio);
+ CloseHandle(ndisuio);
+}
+
+#else /* CONFIG_USE_NDISUIO */
+
+static void show_dev(pcap_if_t *dev)
+{
+ printf("ifname: %s\ndescription: %s\n\n",
+ dev->name, dev->description);
+}
+
+
+static void pcap_enum_devs(void)
+{
+ pcap_if_t *devs, *dev;
+ char err[PCAP_ERRBUF_SIZE + 1];
+
+ if (pcap_findalldevs(&devs, err) < 0) {
+ fprintf(stderr, "Error - pcap_findalldevs: %s\n", err);
+ return;
+ }
+
+ for (dev = devs; dev; dev = dev->next) {
+ show_dev(dev);
+ }
+
+ pcap_freealldevs(devs);
+}
+
+#endif /* CONFIG_USE_NDISUIO */
+
+
+int main(int argc, char *argv[])
+{
+#ifdef CONFIG_USE_NDISUIO
+ ndisuio_enum_bindings();
+#else /* CONFIG_USE_NDISUIO */
+ pcap_enum_devs();
+#endif /* CONFIG_USE_NDISUIO */
+
+ return 0;
+}
diff --git a/wpa_supplicant/wpa_gui-qt4/addinterface.cpp b/wpa_supplicant/wpa_gui-qt4/addinterface.cpp
new file mode 100644
index 0000000..02fecfe
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/addinterface.cpp
@@ -0,0 +1,245 @@
+/*
+ * wpa_gui - AddInterface class
+ * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <cstdio>
+#include "wpa_ctrl.h"
+
+#include <QMessageBox>
+
+#include "wpagui.h"
+#include "addinterface.h"
+
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <windows.h>
+
+#ifndef WPA_KEY_ROOT
+#define WPA_KEY_ROOT HKEY_LOCAL_MACHINE
+#endif
+#ifndef WPA_KEY_PREFIX
+#define WPA_KEY_PREFIX TEXT("SOFTWARE\\wpa_supplicant")
+#endif
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+AddInterface::AddInterface(WpaGui *_wpagui, QWidget *parent)
+ : QDialog(parent), wpagui(_wpagui)
+{
+ setWindowTitle("Select network interface to add");
+ resize(400, 200);
+ vboxLayout = new QVBoxLayout(this);
+
+ interfaceWidget = new QTreeWidget(this);
+ interfaceWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ interfaceWidget->setUniformRowHeights(true);
+ interfaceWidget->setSortingEnabled(true);
+ interfaceWidget->setColumnCount(3);
+ interfaceWidget->headerItem()->setText(0, "driver");
+ interfaceWidget->headerItem()->setText(1, "interface");
+ interfaceWidget->headerItem()->setText(2, "description");
+ interfaceWidget->setItemsExpandable(FALSE);
+ interfaceWidget->setRootIsDecorated(FALSE);
+ vboxLayout->addWidget(interfaceWidget);
+
+ connect(interfaceWidget,
+ SIGNAL(itemActivated(QTreeWidgetItem *, int)), this,
+ SLOT(interfaceSelected(QTreeWidgetItem *)));
+
+ addInterfaces();
+}
+
+
+void AddInterface::addInterfaces()
+{
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+ struct wpa_ctrl *ctrl;
+ int ret;
+ char buf[2048];
+ size_t len;
+
+ ctrl = wpa_ctrl_open(NULL);
+ if (ctrl == NULL)
+ return;
+
+ len = sizeof(buf) - 1;
+ ret = wpa_ctrl_request(ctrl, "INTERFACE_LIST", 14, buf, &len, NULL);
+ if (ret < 0) {
+ wpa_ctrl_close(ctrl);
+ return;
+ }
+ buf[len] = '\0';
+
+ wpa_ctrl_close(ctrl);
+
+ QString ifaces(buf);
+ QStringList lines = ifaces.split(QRegExp("\\n"));
+ for (QStringList::Iterator it = lines.begin();
+ it != lines.end(); it++) {
+ QStringList arg = (*it).split(QChar('\t'));
+ if (arg.size() < 3)
+ continue;
+ QTreeWidgetItem *item = new QTreeWidgetItem(interfaceWidget);
+ if (!item)
+ break;
+
+ item->setText(0, arg[0]);
+ item->setText(1, arg[1]);
+ item->setText(2, arg[2]);
+ }
+
+ interfaceWidget->resizeColumnToContents(0);
+ interfaceWidget->resizeColumnToContents(1);
+ interfaceWidget->resizeColumnToContents(2);
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+}
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+bool AddInterface::addRegistryInterface(const QString &ifname)
+{
+ HKEY hk, ihk;
+ LONG ret;
+ int id, tmp;
+ TCHAR name[10];
+ DWORD val, i;
+
+ ret = RegOpenKeyEx(WPA_KEY_ROOT, WPA_KEY_PREFIX TEXT("\\interfaces"),
+ 0, KEY_ENUMERATE_SUB_KEYS | KEY_CREATE_SUB_KEY,
+ &hk);
+ if (ret != ERROR_SUCCESS)
+ return false;
+
+ id = -1;
+
+ for (i = 0; ; i++) {
+ TCHAR name[255];
+ DWORD namelen;
+
+ namelen = 255;
+ ret = RegEnumKeyEx(hk, i, name, &namelen, NULL, NULL, NULL,
+ NULL);
+
+ if (ret == ERROR_NO_MORE_ITEMS)
+ break;
+
+ if (ret != ERROR_SUCCESS)
+ break;
+
+ if (namelen >= 255)
+ namelen = 255 - 1;
+ name[namelen] = '\0';
+
+#ifdef UNICODE
+ QString s((QChar *) name, namelen);
+#else /* UNICODE */
+ QString s(name);
+#endif /* UNICODE */
+ tmp = s.toInt();
+ if (tmp > id)
+ id = tmp;
+ }
+
+ id += 1;
+
+#ifdef UNICODE
+ wsprintf(name, L"%04d", id);
+#else /* UNICODE */
+ os_snprintf(name, sizeof(name), "%04d", id);
+#endif /* UNICODE */
+ ret = RegCreateKeyEx(hk, name, 0, NULL, 0, KEY_WRITE, NULL, &ihk,
+ NULL);
+ RegCloseKey(hk);
+ if (ret != ERROR_SUCCESS)
+ return false;
+
+#ifdef UNICODE
+ RegSetValueEx(ihk, TEXT("adapter"), 0, REG_SZ,
+ (LPBYTE) ifname.unicode(),
+ (ifname.length() + 1) * sizeof(TCHAR));
+
+#else /* UNICODE */
+ RegSetValueEx(ihk, TEXT("adapter"), 0, REG_SZ,
+ (LPBYTE) ifname.toLocal8Bit(), ifname.length() + 1);
+#endif /* UNICODE */
+ RegSetValueEx(ihk, TEXT("config"), 0, REG_SZ,
+ (LPBYTE) TEXT("default"), 8 * sizeof(TCHAR));
+ RegSetValueEx(ihk, TEXT("ctrl_interface"), 0, REG_SZ,
+ (LPBYTE) TEXT(""), 1 * sizeof(TCHAR));
+ val = 1;
+ RegSetValueEx(ihk, TEXT("skip_on_error"), 0, REG_DWORD, (LPBYTE) &val,
+ sizeof(val));
+
+ RegCloseKey(ihk);
+ return true;
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+void AddInterface::interfaceSelected(QTreeWidgetItem *sel)
+{
+ if (!sel)
+ return;
+
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+ struct wpa_ctrl *ctrl;
+ int ret;
+ char buf[20], cmd[256];
+ size_t len;
+
+ /*
+ * INTERFACE_ADD <ifname>TAB<confname>TAB<driver>TAB<ctrl_interface>TAB
+ * <driver_param>TAB<bridge_name>
+ */
+ snprintf(cmd, sizeof(cmd),
+ "INTERFACE_ADD %s\t%s\t%s\t%s\t%s\t%s",
+ sel->text(1).toAscii().constData(),
+ "default",
+ sel->text(0).toAscii().constData(),
+ "yes", "", "");
+ cmd[sizeof(cmd) - 1] = '\0';
+
+ ctrl = wpa_ctrl_open(NULL);
+ if (ctrl == NULL)
+ return;
+
+ len = sizeof(buf) - 1;
+ ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len, NULL);
+ wpa_ctrl_close(ctrl);
+
+ if (ret < 0) {
+ QMessageBox::warning(this, "wpa_gui",
+ "Add interface command could not be "
+ "completed.");
+ return;
+ }
+
+ buf[len] = '\0';
+ if (buf[0] != 'O' || buf[1] != 'K') {
+ QMessageBox::warning(this, "wpa_gui",
+ "Failed to add the interface.");
+ return;
+ }
+
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+
+#ifdef CONFIG_NATIVE_WINDOWS
+ if (!addRegistryInterface(sel->text(1))) {
+ QMessageBox::information(this, "wpa_gui",
+ "Failed to add the interface into "
+ "registry.");
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ wpagui->selectAdapter(sel->text(1));
+ close();
+}
diff --git a/wpa_supplicant/wpa_gui-qt4/addinterface.h b/wpa_supplicant/wpa_gui-qt4/addinterface.h
new file mode 100644
index 0000000..9d9476a
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/addinterface.h
@@ -0,0 +1,45 @@
+/*
+ * wpa_gui - AddInterface class
+ * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef ADDINTERFACE_H
+#define ADDINTERFACE_H
+
+#include <QObject>
+
+#include <QtGui/QDialog>
+#include <QtGui/QTreeWidget>
+#include <QtGui/QVBoxLayout>
+
+class WpaGui;
+
+class AddInterface : public QDialog
+{
+ Q_OBJECT
+
+public:
+ AddInterface(WpaGui *_wpagui, QWidget *parent = 0);
+
+public slots:
+ virtual void interfaceSelected(QTreeWidgetItem *sel);
+
+private:
+ void addInterfaces();
+ bool addRegistryInterface(const QString &ifname);
+
+ QVBoxLayout *vboxLayout;
+ QTreeWidget *interfaceWidget;
+ WpaGui *wpagui;
+};
+
+#endif /* ADDINTERFACE_H */
diff --git a/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp b/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp
new file mode 100644
index 0000000..46deb96a
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/eventhistory.cpp
@@ -0,0 +1,130 @@
+/*
+ * wpa_gui - EventHistory class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <QHeaderView>
+#include <QScrollBar>
+
+#include "eventhistory.h"
+
+
+int EventListModel::rowCount(const QModelIndex &) const
+{
+ return msgList.count();
+}
+
+
+int EventListModel::columnCount(const QModelIndex &) const
+{
+ return 2;
+}
+
+
+QVariant EventListModel::data(const QModelIndex &index, int role) const
+{
+ if (!index.isValid())
+ return QVariant();
+
+ if (role == Qt::DisplayRole)
+ if (index.column() == 0) {
+ if (index.row() >= timeList.size())
+ return QVariant();
+ return timeList.at(index.row());
+ } else {
+ if (index.row() >= msgList.size())
+ return QVariant();
+ return msgList.at(index.row());
+ }
+ else
+ return QVariant();
+}
+
+
+QVariant EventListModel::headerData(int section, Qt::Orientation orientation,
+ int role) const
+{
+ if (role != Qt::DisplayRole)
+ return QVariant();
+
+ if (orientation == Qt::Horizontal) {
+ switch (section) {
+ case 0:
+ return QString("Timestamp");
+ case 1:
+ return QString("Message");
+ default:
+ return QVariant();
+ }
+ } else
+ return QString("%1").arg(section);
+}
+
+
+void EventListModel::addEvent(QString time, QString msg)
+{
+ beginInsertRows(QModelIndex(), msgList.size(), msgList.size() + 1);
+ timeList << time;
+ msgList << msg;
+ endInsertRows();
+}
+
+
+EventHistory::EventHistory(QWidget *parent, const char *, bool, Qt::WFlags)
+ : QDialog(parent)
+{
+ setupUi(this);
+
+ connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
+
+ eventListView->setItemsExpandable(FALSE);
+ eventListView->setRootIsDecorated(FALSE);
+ elm = new EventListModel(parent);
+ eventListView->setModel(elm);
+}
+
+
+EventHistory::~EventHistory()
+{
+ destroy();
+ delete elm;
+}
+
+
+void EventHistory::languageChange()
+{
+ retranslateUi(this);
+}
+
+
+void EventHistory::addEvents(WpaMsgList msgs)
+{
+ WpaMsgList::iterator it;
+ for (it = msgs.begin(); it != msgs.end(); it++)
+ addEvent(*it);
+}
+
+
+void EventHistory::addEvent(WpaMsg msg)
+{
+ bool scroll = true;
+
+ if (eventListView->verticalScrollBar()->value() <
+ eventListView->verticalScrollBar()->maximum())
+ scroll = false;
+
+ elm->addEvent(msg.getTimestamp().toString("yyyy-MM-dd hh:mm:ss.zzz"),
+ msg.getMsg());
+
+ if (scroll)
+ eventListView->scrollToBottom();
+}
diff --git a/wpa_supplicant/wpa_gui-qt4/eventhistory.h b/wpa_supplicant/wpa_gui-qt4/eventhistory.h
new file mode 100644
index 0000000..40dff6d
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/eventhistory.h
@@ -0,0 +1,63 @@
+/*
+ * wpa_gui - EventHistory class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef EVENTHISTORY_H
+#define EVENTHISTORY_H
+
+#include <QObject>
+#include "ui_eventhistory.h"
+
+
+class EventListModel : public QAbstractTableModel
+{
+ Q_OBJECT
+
+public:
+ EventListModel(QObject *parent = 0)
+ : QAbstractTableModel(parent) {}
+
+ int rowCount(const QModelIndex &parent = QModelIndex()) const;
+ int columnCount(const QModelIndex &parent = QModelIndex()) const;
+ QVariant data(const QModelIndex &index, int role) const;
+ QVariant headerData(int section, Qt::Orientation orientation,
+ int role = Qt::DisplayRole) const;
+ void addEvent(QString time, QString msg);
+
+private:
+ QStringList timeList;
+ QStringList msgList;
+};
+
+
+class EventHistory : public QDialog, public Ui::EventHistory
+{
+ Q_OBJECT
+
+public:
+ EventHistory(QWidget *parent = 0, const char *name = 0,
+ bool modal = false, Qt::WFlags fl = 0);
+ ~EventHistory();
+
+public slots:
+ virtual void addEvents(WpaMsgList msgs);
+ virtual void addEvent(WpaMsg msg);
+
+protected slots:
+ virtual void languageChange();
+
+private:
+ EventListModel *elm;
+};
+
+#endif /* EVENTHISTORY_H */
diff --git a/wpa_supplicant/wpa_gui-qt4/eventhistory.ui b/wpa_supplicant/wpa_gui-qt4/eventhistory.ui
new file mode 100644
index 0000000..afe9149
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/eventhistory.ui
@@ -0,0 +1,61 @@
+<ui version="4.0" >
+ <class>EventHistory</class>
+ <widget class="QDialog" name="EventHistory" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>533</width>
+ <height>285</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Event history</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" colspan="2" >
+ <widget class="QTreeView" name="eventListView" >
+ <property name="sizePolicy" >
+ <sizepolicy vsizetype="Expanding" hsizetype="Expanding" >
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="verticalScrollBarPolicy" >
+ <enum>Qt::ScrollBarAlwaysOn</enum>
+ </property>
+ <property name="selectionMode" >
+ <enum>QAbstractItemView::NoSelection</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QPushButton" name="closeButton" >
+ <property name="text" >
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <pixmapfunction></pixmapfunction>
+ <includes>
+ <include location="local" >wpamsg.h</include>
+ </includes>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/wpa_supplicant/wpa_gui-qt4/icons.qrc b/wpa_supplicant/wpa_gui-qt4/icons.qrc
new file mode 100644
index 0000000..93e94fc
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/icons.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/icons" >
+ <file alias="wpa_gui.svg">icons/wpa_gui.svg</file>
+ </qresource>
+</RCC>
diff --git a/wpa_supplicant/wpa_gui-qt4/icons/Makefile b/wpa_supplicant/wpa_gui-qt4/icons/Makefile
new file mode 100644
index 0000000..cb5c65e
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/icons/Makefile
@@ -0,0 +1,27 @@
+#!/usr/bin/make -f
+
+NAME := wpa_gui
+SVG := $(NAME).svg
+SIZES := 16x16 22x22 32x32 48x48 64x64 128x128
+ICONS := $(addsuffix .png,$(SIZES))
+ICONS += $(addsuffix .xpm,$(NAME) $(NAME)-16)
+
+all: $(ICONS)
+
+%.png:
+ mkdir -p hicolor/$(@:.png=)/apps/
+ inkscape $(SVG) --without-gui \
+ --export-width=$(word 1,$(subst x, ,$(@:.png=))) \
+ --export-height=$(word 2,$(subst x, ,$(@:.png=))) \
+ --export-png=hicolor/$(@:.png=)/apps/$(NAME).png
+
+$(NAME).xpm:
+ mkdir -p pixmaps/
+ convert hicolor/32x32/apps/$(NAME).png pixmaps/$@
+
+$(NAME)-16.xpm:
+ mkdir -p pixmaps/
+ convert hicolor/16x16/apps/$(NAME).png pixmaps/$@
+
+clean:
+ $(RM) -r pixmaps hicolor
diff --git a/wpa_supplicant/wpa_gui-qt4/icons/README b/wpa_supplicant/wpa_gui-qt4/icons/README
new file mode 100644
index 0000000..1584eb5
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/icons/README
@@ -0,0 +1,7 @@
+Copyright (c) 2008 Bernard Gray <bernard.gray@gmail.com>
+
+The wpa_gui icon is licensed under the GPL version 2. Alternatively, the icon
+may be distributed under the terms of BSD license.
+
+To convert the svg icon to other formats, make sure inkscape and imagemagick
+are installed and use `make' to create various sized png and xpm icons.
diff --git a/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg b/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg
new file mode 100644
index 0000000..b3abf0a
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/icons/wpa_gui.svg
@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ version="1.0"
+ width="128"
+ height="128"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.46"
+ sodipodi:docname="wpa_gui.svg"
+ inkscape:output_extension="org.inkscape.output.svg.inkscape">
+ <metadata
+ id="metadata47">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <sodipodi:namedview
+ inkscape:window-height="771"
+ inkscape:window-width="640"
+ inkscape:pageshadow="2"
+ inkscape:pageopacity="0.0"
+ guidetolerance="10.0"
+ gridtolerance="10.0"
+ objecttolerance="10.0"
+ borderopacity="1.0"
+ bordercolor="#666666"
+ pagecolor="#ffffff"
+ id="base"
+ showgrid="false"
+ inkscape:zoom="4.2421875"
+ inkscape:cx="64"
+ inkscape:cy="64"
+ inkscape:window-x="634"
+ inkscape:window-y="0"
+ inkscape:current-layer="svg2" />
+ <defs
+ id="defs4">
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 64 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="128 : 64 : 1"
+ inkscape:persp3d-origin="64 : 42.666667 : 1"
+ id="perspective49" />
+ <linearGradient
+ id="linearGradient39133">
+ <stop
+ id="stop39135"
+ style="stop-color:#252525;stop-opacity:1"
+ offset="0" />
+ <stop
+ id="stop39137"
+ style="stop-color:#515151;stop-opacity:1"
+ offset="0" />
+ <stop
+ id="stop39139"
+ style="stop-color:#878787;stop-opacity:1"
+ offset="0.28677997" />
+ <stop
+ id="stop39141"
+ style="stop-color:#000000;stop-opacity:1"
+ offset="0.92151743" />
+ <stop
+ id="stop39143"
+ style="stop-color:#ffffff;stop-opacity:0.73786408"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient39119">
+ <stop
+ id="stop39121"
+ style="stop-color:#ffffff;stop-opacity:0.82905984"
+ offset="0" />
+ <stop
+ id="stop39123"
+ style="stop-color:#ffffff;stop-opacity:0"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient39106">
+ <stop
+ id="stop39108"
+ style="stop-color:#ffffff;stop-opacity:1"
+ offset="0" />
+ <stop
+ id="stop39110"
+ style="stop-color:#a8a8a8;stop-opacity:0"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient39094">
+ <stop
+ id="stop39096"
+ style="stop-color:#000000;stop-opacity:1"
+ offset="0" />
+ <stop
+ id="stop39098"
+ style="stop-color:#333333;stop-opacity:1"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ id="linearGradient39062">
+ <stop
+ id="stop39064"
+ style="stop-color:#252525;stop-opacity:1"
+ offset="0" />
+ <stop
+ id="stop39086"
+ style="stop-color:#515151;stop-opacity:1"
+ offset="0.21101321" />
+ <stop
+ id="stop39088"
+ style="stop-color:#878787;stop-opacity:1"
+ offset="0.75" />
+ <stop
+ id="stop39090"
+ style="stop-color:#6c6c6c;stop-opacity:1"
+ offset="0.875" />
+ <stop
+ id="stop39066"
+ style="stop-color:#1e1e1e;stop-opacity:1"
+ offset="1" />
+ </linearGradient>
+ <linearGradient
+ x1="4"
+ y1="40"
+ x2="124"
+ y2="60"
+ id="linearGradient39068"
+ xlink:href="#linearGradient39062"
+ gradientUnits="userSpaceOnUse" />
+ <radialGradient
+ cx="100.70589"
+ cy="96"
+ r="60"
+ fx="158.07428"
+ fy="95.718063"
+ id="radialGradient39100"
+ xlink:href="#linearGradient39094"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(2.7837903e-8,-1,0.99999999,-2.1864248e-6,-32.000004,164.7061)" />
+ <radialGradient
+ cx="100.44444"
+ cy="34.363636"
+ r="32"
+ fx="83.18"
+ fy="34.228985"
+ id="radialGradient39104"
+ xlink:href="#linearGradient39106"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(3.1472435e-6,1.0227273,-0.87499999,-9.5061964e-8,94.067865,-4.7272712)" />
+ <radialGradient
+ cx="75.999977"
+ cy="-2.7730541"
+ r="48"
+ fx="55.266491"
+ fy="-2.5338216"
+ id="radialGradient39125"
+ xlink:href="#linearGradient39119"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(0,0.83333324,-1.6666667,2.518705e-6,59.378243,-35.333302)" />
+ <radialGradient
+ cx="64.066589"
+ cy="63.713329"
+ r="60"
+ fx="64.066589"
+ fy="63.713329"
+ id="radialGradient39131"
+ xlink:href="#linearGradient39133"
+ gradientUnits="userSpaceOnUse"
+ gradientTransform="matrix(1.1333333,5.1768857e-8,5.2556881e-6,1.1666667,-8.6091298,-10.332226)" />
+ <filter
+ id="filter39153">
+ <feGaussianBlur
+ id="feGaussianBlur39155"
+ stdDeviation="2.28"
+ inkscape:collect="always" />
+ </filter>
+ <filter
+ id="filter39159">
+ <feGaussianBlur
+ inkscape:collect="always"
+ stdDeviation="1.68"
+ id="feGaussianBlur39161" />
+ </filter>
+ </defs>
+ <g
+ id="layer1"
+ style="display:inline">
+ <path
+ d="M 29,4 C 15.147058,4 4,15.14706 4,29 l 0,70 c 0,13.85294 11.147058,25 25,25 l 70,0 c 13.85294,0 25,-11.14706 25,-25 l 0,-70 C 124,15.14706 112.85294,4 99,4 L 29,4 z"
+ id="path39151"
+ style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;filter:url(#filter39153)" />
+ <path
+ d="M 29,4 C 15.147058,4 4,15.14706 4,29 l 0,70 c 0,13.85294 11.147058,25 25,25 l 70,0 c 13.85294,0 25,-11.14706 25,-25 l 0,-70 C 124,15.14706 112.85294,4 99,4 L 29,4 z"
+ id="path39157"
+ style="opacity:1;fill:#000000;fill-opacity:1;stroke:none;filter:url(#filter39159)" />
+ <rect
+ width="120"
+ height="120"
+ ry="25.00531"
+ x="4"
+ y="0"
+ id="rect2573"
+ style="opacity:1;fill:url(#radialGradient39100);fill-opacity:1;stroke:none" />
+ <path
+ d="M 29,0 C 15.147058,0 4,11.14706 4,25 l 0,70 c 0,13.85294 11.147058,25 25,25 l 70,0 c 13.85294,0 25,-11.14706 25,-25 l 0,-70 C 124,11.14706 112.85294,0 99,0 L 29,0 z"
+ id="path39127"
+ style="opacity:0.20512821;fill:url(#radialGradient39131);fill-opacity:1;stroke:none" />
+ <path
+ d="m 44,68 40,0 12,40 c -20,7.27273 -44,7.27273 -64,0 L 44,68 z"
+ id="path39102"
+ style="opacity:0.53418801;fill:url(#radialGradient39104);fill-opacity:1;stroke:none" />
+ <path
+ d="M 25.339207,12 C 52,8 76,8 102.66079,12 107.83471,12 112,16.165286 112,21.339207 L 116,52 C 100,73.339207 28,73.339207 12,52 L 16,21.339207 C 16,16.165286 20.165286,12 25.339207,12 z"
+ id="rect39116"
+ style="opacity:0.92307691;fill:url(#radialGradient39125);fill-opacity:1;stroke:none" />
+ <path
+ d="M 29,8 C 15.147058,8 4,19.14706 4,33 l 0,70 c 0,13.85294 11.147058,25 25,25 l 70,0 c 13.85294,0 25,-11.14706 25,-25 l 0,-70 C 124,19.14706 112.85294,8 99,8 L 29,8 z"
+ id="path39147"
+ style="opacity:0.20512821;fill:#000000;fill-opacity:1;stroke:none" />
+ <path
+ d="M 29,0 C 15.147058,0 4,11.147058 4,25 l 0,70 c 0,13.85294 11.147058,25 25,25 l 70,0 c 13.85294,0 25,-11.14706 25,-25 l 0,-70 C 124,11.147058 112.85294,0 99,0 L 29,0 z m 0,4 70,0 c 11.70613,0 21,9.293869 21,21 l 0,70 c 0,11.70613 -9.29387,21 -21,21 l -70,0 C 17.293869,116 8,106.70613 8,95 L 8,25 C 8,13.293869 17.293869,4 29,4 z"
+ id="rect39029"
+ style="opacity:1;fill:url(#linearGradient39068);fill-opacity:1;stroke:none" />
+ <path
+ d="M 66.35081,74.771345 A 36,36 0 1 1 54.34964,35.777782"
+ transform="matrix(-0.16680323,0.53082142,-0.53082142,-0.16680323,103.31027,53.117897)"
+ id="path3351"
+ style="opacity:1;fill:none;stroke:#ffffff;stroke-width:21.56673813;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ <path
+ d="m 36,56 a 4,4 0 1 1 -8,0 4,4 0 1 1 8,0 z"
+ transform="matrix(1.4851301,0,0,1.4851301,16.475837,-23.948973)"
+ id="path3353"
+ style="opacity:1;fill:#ffffff;fill-opacity:1;stroke:none" />
+ <path
+ d="M 66.35081,74.771345 A 36,36 0 1 1 54.34964,35.777782"
+ transform="matrix(-0.35033273,1.1148712,-1.1148712,-0.35033273,146.5624,46.88078)"
+ id="path2622"
+ style="opacity:1;fill:none;stroke:#ffffff;stroke-width:10.26852894;stroke-linecap:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" />
+ </g>
+</svg>
diff --git a/wpa_supplicant/wpa_gui-qt4/icons_png.qrc b/wpa_supplicant/wpa_gui-qt4/icons_png.qrc
new file mode 100644
index 0000000..09f3d96
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/icons_png.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/icons" >
+ <file alias="wpa_gui.png">icons/hicolor/16x16/apps/wpa_gui.png</file>
+ </qresource>
+</RCC>
diff --git a/wpa_supplicant/wpa_gui-qt4/main.cpp b/wpa_supplicant/wpa_gui-qt4/main.cpp
new file mode 100644
index 0000000..c5e285f
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/main.cpp
@@ -0,0 +1,70 @@
+/*
+ * wpa_gui - Application startup
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+#include <QApplication>
+#include "wpagui.h"
+
+
+class WpaGuiApp : public QApplication
+{
+public:
+ WpaGuiApp(int &argc, char **argv);
+
+#ifndef QT_NO_SESSIONMANAGER
+ virtual void saveState(QSessionManager &manager);
+#endif
+
+ WpaGui *w;
+};
+
+WpaGuiApp::WpaGuiApp(int &argc, char **argv) : QApplication(argc, argv)
+{
+}
+
+#ifndef QT_NO_SESSIONMANAGER
+void WpaGuiApp::saveState(QSessionManager &manager)
+{
+ QApplication::saveState(manager);
+ w->saveState();
+}
+#endif
+
+
+int main(int argc, char *argv[])
+{
+ WpaGuiApp app(argc, argv);
+ WpaGui w(&app);
+ int ret;
+
+#ifdef CONFIG_NATIVE_WINDOWS
+ WSADATA wsaData;
+ if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
+ /* printf("Could not find a usable WinSock.dll\n"); */
+ return -1;
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ app.w = &w;
+
+ ret = app.exec();
+
+#ifdef CONFIG_NATIVE_WINDOWS
+ WSACleanup();
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ return ret;
+}
diff --git a/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp b/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp
new file mode 100644
index 0000000..dae9edd
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/networkconfig.cpp
@@ -0,0 +1,823 @@
+/*
+ * wpa_gui - NetworkConfig class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <cstdio>
+#include <QMessageBox>
+
+#include "networkconfig.h"
+#include "wpagui.h"
+
+enum {
+ AUTH_NONE = 0,
+ AUTH_IEEE8021X = 1,
+ AUTH_WPA_PSK = 2,
+ AUTH_WPA_EAP = 3,
+ AUTH_WPA2_PSK = 4,
+ AUTH_WPA2_EAP = 5
+};
+
+#define WPA_GUI_KEY_DATA "[key is configured]"
+
+
+NetworkConfig::NetworkConfig(QWidget *parent, const char *, bool, Qt::WFlags)
+ : QDialog(parent)
+{
+ setupUi(this);
+
+ connect(authSelect, SIGNAL(activated(int)), this,
+ SLOT(authChanged(int)));
+ connect(cancelButton, SIGNAL(clicked()), this, SLOT(close()));
+ connect(addButton, SIGNAL(clicked()), this, SLOT(addNetwork()));
+ connect(encrSelect, SIGNAL(activated(const QString &)), this,
+ SLOT(encrChanged(const QString &)));
+ connect(removeButton, SIGNAL(clicked()), this, SLOT(removeNetwork()));
+ connect(eapSelect, SIGNAL(activated(int)), this,
+ SLOT(eapChanged(int)));
+ connect(useWpsButton, SIGNAL(clicked()), this, SLOT(useWps()));
+
+ wpagui = NULL;
+ new_network = false;
+}
+
+
+NetworkConfig::~NetworkConfig()
+{
+}
+
+
+void NetworkConfig::languageChange()
+{
+ retranslateUi(this);
+}
+
+
+void NetworkConfig::paramsFromScanResults(QTreeWidgetItem *sel)
+{
+ new_network = true;
+
+ /* SSID BSSID frequency signal flags */
+ setWindowTitle(sel->text(0));
+ ssidEdit->setText(sel->text(0));
+
+ QString flags = sel->text(4);
+ int auth, encr = 0;
+ if (flags.indexOf("[WPA2-EAP") >= 0)
+ auth = AUTH_WPA2_EAP;
+ else if (flags.indexOf("[WPA-EAP") >= 0)
+ auth = AUTH_WPA_EAP;
+ else if (flags.indexOf("[WPA2-PSK") >= 0)
+ auth = AUTH_WPA2_PSK;
+ else if (flags.indexOf("[WPA-PSK") >= 0)
+ auth = AUTH_WPA_PSK;
+ else
+ auth = AUTH_NONE;
+
+ if (flags.indexOf("-CCMP") >= 0)
+ encr = 1;
+ else if (flags.indexOf("-TKIP") >= 0)
+ encr = 0;
+ else if (flags.indexOf("WEP") >= 0)
+ encr = 1;
+ else
+ encr = 0;
+
+ authSelect->setCurrentIndex(auth);
+ authChanged(auth);
+ encrSelect->setCurrentIndex(encr);
+
+ wepEnabled(auth == AUTH_NONE && encr == 1);
+
+ getEapCapa();
+
+ if (flags.indexOf("[WPS") >= 0)
+ useWpsButton->setEnabled(true);
+ bssid = sel->text(1);
+}
+
+
+void NetworkConfig::authChanged(int sel)
+{
+ pskEdit->setEnabled(sel == AUTH_WPA_PSK || sel == AUTH_WPA2_PSK);
+ bool eap = sel == AUTH_IEEE8021X || sel == AUTH_WPA_EAP ||
+ sel == AUTH_WPA2_EAP;
+ eapSelect->setEnabled(eap);
+ identityEdit->setEnabled(eap);
+ passwordEdit->setEnabled(eap);
+ cacertEdit->setEnabled(eap);
+ phase2Select->setEnabled(eap);
+ if (eap)
+ eapChanged(eapSelect->currentIndex());
+
+ while (encrSelect->count())
+ encrSelect->removeItem(0);
+
+ if (sel == AUTH_NONE || sel == AUTH_IEEE8021X) {
+ encrSelect->addItem("None");
+ encrSelect->addItem("WEP");
+ encrSelect->setCurrentIndex(sel == AUTH_NONE ? 0 : 1);
+ } else {
+ encrSelect->addItem("TKIP");
+ encrSelect->addItem("CCMP");
+ encrSelect->setCurrentIndex((sel == AUTH_WPA2_PSK ||
+ sel == AUTH_WPA2_EAP) ? 1 : 0);
+ }
+
+ wepEnabled(sel == AUTH_IEEE8021X);
+}
+
+
+void NetworkConfig::eapChanged(int sel)
+{
+ QString prev_val = phase2Select->currentText();
+ while (phase2Select->count())
+ phase2Select->removeItem(0);
+
+ QStringList inner;
+ inner << "PEAP" << "TTLS" << "FAST";
+ if (!inner.contains(eapSelect->itemText(sel)))
+ return;
+
+ phase2Select->addItem("[ any ]");
+
+ /* Add special cases based on outer method */
+ if (eapSelect->currentText().compare("TTLS") == 0) {
+ phase2Select->addItem("PAP");
+ phase2Select->addItem("CHAP");
+ phase2Select->addItem("MSCHAP");
+ phase2Select->addItem("MSCHAPv2");
+ } else if (eapSelect->currentText().compare("FAST") == 0)
+ phase2Select->addItem("GTC(auth) + MSCHAPv2(prov)");
+
+ /* Add all enabled EAP methods that can be used in the tunnel */
+ int i;
+ QStringList allowed;
+ allowed << "MSCHAPV2" << "MD5" << "GTC" << "TLS" << "OTP" << "SIM"
+ << "AKA";
+ for (i = 0; i < eapSelect->count(); i++) {
+ if (allowed.contains(eapSelect->itemText(i))) {
+ phase2Select->addItem("EAP-" + eapSelect->itemText(i));
+ }
+ }
+
+ for (i = 0; i < phase2Select->count(); i++) {
+ if (phase2Select->itemText(i).compare(prev_val) == 0) {
+ phase2Select->setCurrentIndex(i);
+ break;
+ }
+ }
+}
+
+
+void NetworkConfig::addNetwork()
+{
+ char reply[10], cmd[256];
+ size_t reply_len;
+ int id;
+ int psklen = pskEdit->text().length();
+ int auth = authSelect->currentIndex();
+
+ if (auth == AUTH_WPA_PSK || auth == AUTH_WPA2_PSK) {
+ if (psklen < 8 || psklen > 64) {
+ QMessageBox::warning(this, "WPA Pre-Shared Key Error",
+ "WPA-PSK requires a passphrase "
+ "of 8 to 63 characters\n"
+ "or 64 hex digit PSK");
+ pskEdit->setFocus();
+ return;
+ }
+ }
+
+ if (idstrEdit->isEnabled() && !idstrEdit->text().isEmpty()) {
+ QRegExp rx("^(\\w|-)+$");
+ if (rx.indexIn(idstrEdit->text()) < 0) {
+ QMessageBox::warning(this, "Network ID Error",
+ "Network ID String contains "
+ "non-word characters.\n"
+ "It must be a simple string, "
+ "without spaces, containing\n"
+ "only characters in this range: "
+ "[A-Za-z0-9_-]\n");
+ idstrEdit->setFocus();
+ return;
+ }
+ }
+
+ if (wpagui == NULL)
+ return;
+
+ memset(reply, 0, sizeof(reply));
+ reply_len = sizeof(reply) - 1;
+
+ if (new_network) {
+ wpagui->ctrlRequest("ADD_NETWORK", reply, &reply_len);
+ if (reply[0] == 'F') {
+ QMessageBox::warning(this, "wpa_gui", "Failed to add "
+ "network to wpa_supplicant\n"
+ "configuration.");
+ return;
+ }
+ id = atoi(reply);
+ } else
+ id = edit_network_id;
+
+ setNetworkParam(id, "ssid", ssidEdit->text().toAscii().constData(),
+ true);
+
+ const char *key_mgmt = NULL, *proto = NULL, *pairwise = NULL;
+ switch (auth) {
+ case AUTH_NONE:
+ key_mgmt = "NONE";
+ break;
+ case AUTH_IEEE8021X:
+ key_mgmt = "IEEE8021X";
+ break;
+ case AUTH_WPA_PSK:
+ key_mgmt = "WPA-PSK";
+ proto = "WPA";
+ break;
+ case AUTH_WPA_EAP:
+ key_mgmt = "WPA-EAP";
+ proto = "WPA";
+ break;
+ case AUTH_WPA2_PSK:
+ key_mgmt = "WPA-PSK";
+ proto = "WPA2";
+ break;
+ case AUTH_WPA2_EAP:
+ key_mgmt = "WPA-EAP";
+ proto = "WPA2";
+ break;
+ }
+
+ if (auth == AUTH_WPA_PSK || auth == AUTH_WPA_EAP ||
+ auth == AUTH_WPA2_PSK || auth == AUTH_WPA2_EAP) {
+ int encr = encrSelect->currentIndex();
+ if (encr == 0)
+ pairwise = "TKIP";
+ else
+ pairwise = "CCMP";
+ }
+
+ if (proto)
+ setNetworkParam(id, "proto", proto, false);
+ if (key_mgmt)
+ setNetworkParam(id, "key_mgmt", key_mgmt, false);
+ if (pairwise) {
+ setNetworkParam(id, "pairwise", pairwise, false);
+ setNetworkParam(id, "group", "TKIP CCMP WEP104 WEP40", false);
+ }
+ if (pskEdit->isEnabled() &&
+ strcmp(pskEdit->text().toAscii().constData(),
+ WPA_GUI_KEY_DATA) != 0)
+ setNetworkParam(id, "psk",
+ pskEdit->text().toAscii().constData(),
+ psklen != 64);
+ if (eapSelect->isEnabled()) {
+ const char *eap =
+ eapSelect->currentText().toAscii().constData();
+ setNetworkParam(id, "eap", eap, false);
+ if (strcmp(eap, "SIM") == 0 || strcmp(eap, "AKA") == 0)
+ setNetworkParam(id, "pcsc", "", true);
+ else
+ setNetworkParam(id, "pcsc", "NULL", false);
+ }
+ if (phase2Select->isEnabled()) {
+ QString eap = eapSelect->currentText();
+ QString inner = phase2Select->currentText();
+ char phase2[32];
+ phase2[0] = '\0';
+ if (eap.compare("PEAP") == 0) {
+ if (inner.startsWith("EAP-"))
+ snprintf(phase2, sizeof(phase2), "auth=%s",
+ inner.right(inner.size() - 4).
+ toAscii().constData());
+ } else if (eap.compare("TTLS") == 0) {
+ if (inner.startsWith("EAP-"))
+ snprintf(phase2, sizeof(phase2), "autheap=%s",
+ inner.right(inner.size() - 4).
+ toAscii().constData());
+ else
+ snprintf(phase2, sizeof(phase2), "auth=%s",
+ inner.toAscii().constData());
+ } else if (eap.compare("FAST") == 0) {
+ const char *provisioning = NULL;
+ if (inner.startsWith("EAP-")) {
+ snprintf(phase2, sizeof(phase2), "auth=%s",
+ inner.right(inner.size() - 4).
+ toAscii().constData());
+ provisioning = "fast_provisioning=2";
+ } else if (inner.compare("GTC(auth) + MSCHAPv2(prov)")
+ == 0) {
+ snprintf(phase2, sizeof(phase2),
+ "auth=GTC auth=MSCHAPV2");
+ provisioning = "fast_provisioning=1";
+ } else
+ provisioning = "fast_provisioning=3";
+ if (provisioning) {
+ char blob[32];
+ setNetworkParam(id, "phase1", provisioning,
+ true);
+ snprintf(blob, sizeof(blob),
+ "blob://fast-pac-%d", id);
+ setNetworkParam(id, "pac_file", blob, true);
+ }
+ }
+ if (phase2[0])
+ setNetworkParam(id, "phase2", phase2, true);
+ else
+ setNetworkParam(id, "phase2", "NULL", false);
+ } else
+ setNetworkParam(id, "phase2", "NULL", false);
+ if (identityEdit->isEnabled() && identityEdit->text().length() > 0)
+ setNetworkParam(id, "identity",
+ identityEdit->text().toAscii().constData(),
+ true);
+ else
+ setNetworkParam(id, "identity", "NULL", false);
+ if (passwordEdit->isEnabled() && passwordEdit->text().length() > 0 &&
+ strcmp(passwordEdit->text().toAscii().constData(),
+ WPA_GUI_KEY_DATA) != 0)
+ setNetworkParam(id, "password",
+ passwordEdit->text().toAscii().constData(),
+ true);
+ else if (passwordEdit->text().length() == 0)
+ setNetworkParam(id, "password", "NULL", false);
+ if (cacertEdit->isEnabled() && cacertEdit->text().length() > 0)
+ setNetworkParam(id, "ca_cert",
+ cacertEdit->text().toAscii().constData(),
+ true);
+ else
+ setNetworkParam(id, "ca_cert", "NULL", false);
+ writeWepKey(id, wep0Edit, 0);
+ writeWepKey(id, wep1Edit, 1);
+ writeWepKey(id, wep2Edit, 2);
+ writeWepKey(id, wep3Edit, 3);
+
+ if (wep0Radio->isEnabled() && wep0Radio->isChecked())
+ setNetworkParam(id, "wep_tx_keyidx", "0", false);
+ else if (wep1Radio->isEnabled() && wep1Radio->isChecked())
+ setNetworkParam(id, "wep_tx_keyidx", "1", false);
+ else if (wep2Radio->isEnabled() && wep2Radio->isChecked())
+ setNetworkParam(id, "wep_tx_keyidx", "2", false);
+ else if (wep3Radio->isEnabled() && wep3Radio->isChecked())
+ setNetworkParam(id, "wep_tx_keyidx", "3", false);
+
+ if (idstrEdit->isEnabled() && idstrEdit->text().length() > 0)
+ setNetworkParam(id, "id_str",
+ idstrEdit->text().toAscii().constData(),
+ true);
+ else
+ setNetworkParam(id, "id_str", "NULL", false);
+
+ if (prioritySpinBox->isEnabled()) {
+ QString prio;
+ prio = prio.setNum(prioritySpinBox->value());
+ setNetworkParam(id, "priority", prio.toAscii().constData(),
+ false);
+ }
+
+ snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %d", id);
+ reply_len = sizeof(reply);
+ wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (strncmp(reply, "OK", 2) != 0) {
+ QMessageBox::warning(this, "wpa_gui", "Failed to enable "
+ "network in wpa_supplicant\n"
+ "configuration.");
+ /* Network was added, so continue anyway */
+ }
+ wpagui->triggerUpdate();
+ wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len);
+
+ close();
+}
+
+
+void NetworkConfig::setWpaGui(WpaGui *_wpagui)
+{
+ wpagui = _wpagui;
+}
+
+
+int NetworkConfig::setNetworkParam(int id, const char *field,
+ const char *value, bool quote)
+{
+ char reply[10], cmd[256];
+ size_t reply_len;
+ snprintf(cmd, sizeof(cmd), "SET_NETWORK %d %s %s%s%s",
+ id, field, quote ? "\"" : "", value, quote ? "\"" : "");
+ reply_len = sizeof(reply);
+ wpagui->ctrlRequest(cmd, reply, &reply_len);
+ return strncmp(reply, "OK", 2) == 0 ? 0 : -1;
+}
+
+
+void NetworkConfig::encrChanged(const QString &sel)
+{
+ wepEnabled(sel.indexOf("WEP") == 0);
+}
+
+
+void NetworkConfig::wepEnabled(bool enabled)
+{
+ wep0Edit->setEnabled(enabled);
+ wep1Edit->setEnabled(enabled);
+ wep2Edit->setEnabled(enabled);
+ wep3Edit->setEnabled(enabled);
+ wep0Radio->setEnabled(enabled);
+ wep1Radio->setEnabled(enabled);
+ wep2Radio->setEnabled(enabled);
+ wep3Radio->setEnabled(enabled);
+}
+
+
+void NetworkConfig::writeWepKey(int network_id, QLineEdit *edit, int id)
+{
+ char buf[10];
+ bool hex;
+ const char *txt, *pos;
+ size_t len;
+
+ if (!edit->isEnabled() || edit->text().isEmpty())
+ return;
+
+ /*
+ * Assume hex key if only hex characters are present and length matches
+ * with 40, 104, or 128-bit key
+ */
+ txt = edit->text().toAscii().constData();
+ if (strcmp(txt, WPA_GUI_KEY_DATA) == 0)
+ return;
+ len = strlen(txt);
+ if (len == 0)
+ return;
+ pos = txt;
+ hex = true;
+ while (*pos) {
+ if (!((*pos >= '0' && *pos <= '9') ||
+ (*pos >= 'a' && *pos <= 'f') ||
+ (*pos >= 'A' && *pos <= 'F'))) {
+ hex = false;
+ break;
+ }
+ pos++;
+ }
+ if (hex && len != 10 && len != 26 && len != 32)
+ hex = false;
+ snprintf(buf, sizeof(buf), "wep_key%d", id);
+ setNetworkParam(network_id, buf, txt, !hex);
+}
+
+
+static int key_value_isset(const char *reply, size_t reply_len)
+{
+ return reply_len > 0 && (reply_len < 4 || memcmp(reply, "FAIL", 4) != 0);
+}
+
+
+void NetworkConfig::paramsFromConfig(int network_id)
+{
+ int i, res;
+
+ edit_network_id = network_id;
+ getEapCapa();
+
+ char reply[1024], cmd[256], *pos;
+ size_t reply_len;
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
+ reply_len >= 2 && reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ ssidEdit->setText(reply + 1);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d proto", network_id);
+ reply_len = sizeof(reply) - 1;
+ int wpa = 0;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
+ reply[reply_len] = '\0';
+ if (strstr(reply, "RSN") || strstr(reply, "WPA2"))
+ wpa = 2;
+ else if (strstr(reply, "WPA"))
+ wpa = 1;
+ }
+
+ int auth = AUTH_NONE, encr = 0;
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d key_mgmt", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
+ reply[reply_len] = '\0';
+ if (strstr(reply, "WPA-EAP"))
+ auth = wpa & 2 ? AUTH_WPA2_EAP : AUTH_WPA_EAP;
+ else if (strstr(reply, "WPA-PSK"))
+ auth = wpa & 2 ? AUTH_WPA2_PSK : AUTH_WPA_PSK;
+ else if (strstr(reply, "IEEE8021X")) {
+ auth = AUTH_IEEE8021X;
+ encr = 1;
+ }
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d pairwise", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
+ reply[reply_len] = '\0';
+ if (strstr(reply, "CCMP") && auth != AUTH_NONE)
+ encr = 1;
+ else if (strstr(reply, "TKIP"))
+ encr = 0;
+ else if (strstr(reply, "WEP"))
+ encr = 1;
+ else
+ encr = 0;
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d psk", network_id);
+ reply_len = sizeof(reply) - 1;
+ res = wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ pskEdit->setText(reply + 1);
+ } else if (res >= 0 && key_value_isset(reply, reply_len)) {
+ pskEdit->setText(WPA_GUI_KEY_DATA);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
+ reply_len >= 2 && reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ identityEdit->setText(reply + 1);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d password", network_id);
+ reply_len = sizeof(reply) - 1;
+ res = wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ passwordEdit->setText(reply + 1);
+ } else if (res >= 0 && key_value_isset(reply, reply_len)) {
+ passwordEdit->setText(WPA_GUI_KEY_DATA);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
+ reply_len >= 2 && reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ cacertEdit->setText(reply + 1);
+ }
+
+ enum { NO_INNER, PEAP_INNER, TTLS_INNER, FAST_INNER } eap = NO_INNER;
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d eap", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
+ reply_len >= 1) {
+ reply[reply_len] = '\0';
+ for (i = 0; i < eapSelect->count(); i++) {
+ if (eapSelect->itemText(i).compare(reply) == 0) {
+ eapSelect->setCurrentIndex(i);
+ if (strcmp(reply, "PEAP") == 0)
+ eap = PEAP_INNER;
+ else if (strcmp(reply, "TTLS") == 0)
+ eap = TTLS_INNER;
+ else if (strcmp(reply, "FAST") == 0)
+ eap = FAST_INNER;
+ break;
+ }
+ }
+ }
+
+ if (eap != NO_INNER) {
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d phase2",
+ network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
+ reply_len >= 1) {
+ reply[reply_len] = '\0';
+ eapChanged(eapSelect->currentIndex());
+ } else
+ eap = NO_INNER;
+ }
+
+ char *val;
+ val = reply + 1;
+ while (*(val + 1))
+ val++;
+ if (*val == '"')
+ *val = '\0';
+
+ switch (eap) {
+ case PEAP_INNER:
+ if (strncmp(reply, "\"auth=", 6))
+ break;
+ val = reply + 2;
+ memcpy(val, "EAP-", 4);
+ break;
+ case TTLS_INNER:
+ if (strncmp(reply, "\"autheap=", 9) == 0) {
+ val = reply + 5;
+ memcpy(val, "EAP-", 4);
+ } else if (strncmp(reply, "\"auth=", 6) == 0)
+ val = reply + 6;
+ break;
+ case FAST_INNER:
+ if (strncmp(reply, "\"auth=", 6))
+ break;
+ if (strcmp(reply + 6, "GTC auth=MSCHAPV2") == 0) {
+ val = (char *) "GTC(auth) + MSCHAPv2(prov)";
+ break;
+ }
+ val = reply + 2;
+ memcpy(val, "EAP-", 4);
+ break;
+ case NO_INNER:
+ break;
+ }
+
+ for (i = 0; i < phase2Select->count(); i++) {
+ if (phase2Select->itemText(i).compare(val) == 0) {
+ phase2Select->setCurrentIndex(i);
+ break;
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ QLineEdit *wepEdit;
+ switch (i) {
+ default:
+ case 0:
+ wepEdit = wep0Edit;
+ break;
+ case 1:
+ wepEdit = wep1Edit;
+ break;
+ case 2:
+ wepEdit = wep2Edit;
+ break;
+ case 3:
+ wepEdit = wep3Edit;
+ break;
+ }
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_key%d",
+ network_id, i);
+ reply_len = sizeof(reply) - 1;
+ res = wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
+ encr = 1;
+
+ wepEdit->setText(reply + 1);
+ } else if (res >= 0 && key_value_isset(reply, reply_len)) {
+ if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
+ encr = 1;
+ wepEdit->setText(WPA_GUI_KEY_DATA);
+ }
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1)
+ {
+ reply[reply_len] = '\0';
+ switch (atoi(reply)) {
+ case 0:
+ wep0Radio->setChecked(true);
+ break;
+ case 1:
+ wep1Radio->setChecked(true);
+ break;
+ case 2:
+ wep2Radio->setChecked(true);
+ break;
+ case 3:
+ wep3Radio->setChecked(true);
+ break;
+ }
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d id_str", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 &&
+ reply_len >= 2 && reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ idstrEdit->setText(reply + 1);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d priority", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1)
+ {
+ reply[reply_len] = '\0';
+ prioritySpinBox->setValue(atoi(reply));
+ }
+
+ authSelect->setCurrentIndex(auth);
+ authChanged(auth);
+ encrSelect->setCurrentIndex(encr);
+ if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
+ wepEnabled(encr == 1);
+
+ removeButton->setEnabled(true);
+ addButton->setText("Save");
+}
+
+
+void NetworkConfig::removeNetwork()
+{
+ char reply[10], cmd[256];
+ size_t reply_len;
+
+ if (QMessageBox::information(this, "wpa_gui",
+ "This will permanently remove the "
+ "network\n"
+ "from the configuration. Do you really "
+ "want\n"
+ "to remove this network?", "Yes", "No")
+ != 0)
+ return;
+
+ snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %d", edit_network_id);
+ reply_len = sizeof(reply);
+ wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (strncmp(reply, "OK", 2) != 0) {
+ QMessageBox::warning(this, "wpa_gui",
+ "Failed to remove network from "
+ "wpa_supplicant\n"
+ "configuration.");
+ } else {
+ wpagui->triggerUpdate();
+ wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len);
+ }
+
+ close();
+}
+
+
+void NetworkConfig::newNetwork()
+{
+ new_network = true;
+ getEapCapa();
+}
+
+
+void NetworkConfig::getEapCapa()
+{
+ char reply[256];
+ size_t reply_len;
+
+ if (wpagui == NULL)
+ return;
+
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest("GET_CAPABILITY eap", reply, &reply_len) < 0)
+ return;
+ reply[reply_len] = '\0';
+
+ QString res(reply);
+ QStringList types = res.split(QChar(' '));
+ eapSelect->insertItems(-1, types);
+}
+
+
+void NetworkConfig::useWps()
+{
+ if (wpagui == NULL)
+ return;
+ wpagui->setBssFromScan(bssid);
+ wpagui->wpsDialog();
+ close();
+}
diff --git a/wpa_supplicant/wpa_gui-qt4/networkconfig.h b/wpa_supplicant/wpa_gui-qt4/networkconfig.h
new file mode 100644
index 0000000..0ceeb41
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/networkconfig.h
@@ -0,0 +1,61 @@
+/*
+ * wpa_gui - NetworkConfig class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef NETWORKCONFIG_H
+#define NETWORKCONFIG_H
+
+#include <QObject>
+#include "ui_networkconfig.h"
+
+class WpaGui;
+
+class NetworkConfig : public QDialog, public Ui::NetworkConfig
+{
+ Q_OBJECT
+
+public:
+ NetworkConfig(QWidget *parent = 0, const char *name = 0,
+ bool modal = false, Qt::WFlags fl = 0);
+ ~NetworkConfig();
+
+ virtual void paramsFromScanResults(QTreeWidgetItem *sel);
+ virtual void setWpaGui(WpaGui *_wpagui);
+ virtual int setNetworkParam(int id, const char *field,
+ const char *value, bool quote);
+ virtual void paramsFromConfig(int network_id);
+ virtual void newNetwork();
+
+public slots:
+ virtual void authChanged(int sel);
+ virtual void addNetwork();
+ virtual void encrChanged(const QString &sel);
+ virtual void writeWepKey(int network_id, QLineEdit *edit, int id);
+ virtual void removeNetwork();
+ virtual void eapChanged(int sel);
+ virtual void useWps();
+
+protected slots:
+ virtual void languageChange();
+
+private:
+ WpaGui *wpagui;
+ int edit_network_id;
+ bool new_network;
+ QString bssid;
+
+ virtual void wepEnabled(bool enabled);
+ virtual void getEapCapa();
+};
+
+#endif /* NETWORKCONFIG_H */
diff --git a/wpa_supplicant/wpa_gui-qt4/networkconfig.ui b/wpa_supplicant/wpa_gui-qt4/networkconfig.ui
new file mode 100644
index 0000000..ede462f
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/networkconfig.ui
@@ -0,0 +1,425 @@
+<ui version="4.0" >
+ <class>NetworkConfig</class>
+ <widget class="QDialog" name="NetworkConfig" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>410</width>
+ <height>534</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>NetworkConfig</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="1" column="3" >
+ <widget class="QPushButton" name="cancelButton" >
+ <property name="text" >
+ <string>Cancel</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" colspan="4" >
+ <widget class="QFrame" name="frame9" >
+ <property name="frameShape" >
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow" >
+ <enum>QFrame::Plain</enum>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="ssidLabel" >
+ <property name="text" >
+ <string>SSID</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="ssidEdit" >
+ <property name="toolTip" >
+ <string>Network name (Service Set IDentifier)</string>
+ </property>
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="authLabel" >
+ <property name="text" >
+ <string>Authentication</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QComboBox" name="authSelect" >
+ <item>
+ <property name="text" >
+ <string>Plaintext or static WEP</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>IEEE 802.1X</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>WPA-Personal (PSK)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>WPA-Enterprise (EAP)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>WPA2-Personal (PSK)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>WPA2-Enterprise (EAP)</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="encrLabel" >
+ <property name="text" >
+ <string>Encryption</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QComboBox" name="encrSelect" >
+ <item>
+ <property name="text" >
+ <string>None</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>WEP</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>TKIP</string>
+ </property>
+ </item>
+ <item>
+ <property name="text" >
+ <string>CCMP</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="pskLabel" >
+ <property name="text" >
+ <string>PSK</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QLineEdit" name="pskEdit" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" >
+ <string>WPA/WPA2 pre-shared key or passphrase</string>
+ </property>
+ <property name="whatsThis" >
+ <string/>
+ </property>
+ <property name="echoMode" >
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="eapLabel" >
+ <property name="text" >
+ <string>EAP method</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" >
+ <widget class="QComboBox" name="eapSelect" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <widget class="QLabel" name="identityLabel" >
+ <property name="text" >
+ <string>Identity</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1" >
+ <widget class="QLineEdit" name="identityEdit" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" >
+ <string>Username/Identity for EAP methods</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0" >
+ <widget class="QLabel" name="passwordLabel" >
+ <property name="text" >
+ <string>Password</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1" >
+ <widget class="QLineEdit" name="passwordEdit" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" >
+ <string>Password for EAP methods</string>
+ </property>
+ <property name="echoMode" >
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="0" >
+ <widget class="QLabel" name="cacertLabel" >
+ <property name="text" >
+ <string>CA certificate</string>
+ </property>
+ </widget>
+ </item>
+ <item row="7" column="1" >
+ <widget class="QLineEdit" name="cacertEdit" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="8" column="0" colspan="2" >
+ <widget class="QGroupBox" name="wepBox" >
+ <property name="enabled" >
+ <bool>true</bool>
+ </property>
+ <property name="title" >
+ <string>WEP keys</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QRadioButton" name="wep0Radio" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>key 0</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QRadioButton" name="wep1Radio" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>key 1</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QRadioButton" name="wep3Radio" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>key 3</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QRadioButton" name="wep2Radio" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>key 2</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="wep0Edit" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QLineEdit" name="wep1Edit" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QLineEdit" name="wep2Edit" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QLineEdit" name="wep3Edit" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="9" column="0" colspan="2" >
+ <widget class="QGroupBox" name="optionalSettingsBox" >
+ <property name="enabled" >
+ <bool>true</bool>
+ </property>
+ <property name="title" >
+ <string>Optional Settings</string>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="1" >
+ <widget class="QLineEdit" name="idstrEdit" >
+ <property name="toolTip" >
+ <string>Network Identification String</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="3" >
+ <widget class="QSpinBox" name="prioritySpinBox" >
+ <property name="toolTip" >
+ <string>Network Priority</string>
+ </property>
+ <property name="maximum" >
+ <number>10000</number>
+ </property>
+ <property name="singleStep" >
+ <number>10</number>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="0" >
+ <widget class="QLabel" name="idstrLabel" >
+ <property name="text" >
+ <string>IDString</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="2" >
+ <widget class="QLabel" name="priorityLabel" >
+ <property name="text" >
+ <string>Priority</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="phase2Label" >
+ <property name="text" >
+ <string>Inner auth</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QComboBox" name="phase2Select" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QPushButton" name="addButton" >
+ <property name="text" >
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3" >
+ <widget class="QPushButton" name="removeButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QPushButton" name="useWpsButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>WPS</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <pixmapfunction></pixmapfunction>
+ <tabstops>
+ <tabstop>ssidEdit</tabstop>
+ <tabstop>authSelect</tabstop>
+ <tabstop>encrSelect</tabstop>
+ <tabstop>pskEdit</tabstop>
+ <tabstop>eapSelect</tabstop>
+ <tabstop>identityEdit</tabstop>
+ <tabstop>passwordEdit</tabstop>
+ <tabstop>cacertEdit</tabstop>
+ <tabstop>wep0Radio</tabstop>
+ <tabstop>wep0Edit</tabstop>
+ <tabstop>wep1Radio</tabstop>
+ <tabstop>wep1Edit</tabstop>
+ <tabstop>wep2Radio</tabstop>
+ <tabstop>wep2Edit</tabstop>
+ <tabstop>wep3Radio</tabstop>
+ <tabstop>wep3Edit</tabstop>
+ <tabstop>idstrEdit</tabstop>
+ <tabstop>prioritySpinBox</tabstop>
+ <tabstop>phase2Select</tabstop>
+ <tabstop>addButton</tabstop>
+ <tabstop>removeButton</tabstop>
+ <tabstop>cancelButton</tabstop>
+ </tabstops>
+ <includes>
+ <include location="global" >qtreewidget.h</include>
+ </includes>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.cpp b/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
new file mode 100644
index 0000000..459aa8c
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/scanresults.cpp
@@ -0,0 +1,144 @@
+/*
+ * wpa_gui - ScanResults class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include <cstdio>
+
+#include "scanresults.h"
+#include "wpagui.h"
+#include "networkconfig.h"
+
+
+ScanResults::ScanResults(QWidget *parent, const char *, bool, Qt::WFlags)
+ : QDialog(parent)
+{
+ setupUi(this);
+
+ connect(closeButton, SIGNAL(clicked()), this, SLOT(close()));
+ connect(scanButton, SIGNAL(clicked()), this, SLOT(scanRequest()));
+ connect(scanResultsWidget,
+ SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this,
+ SLOT(bssSelected(QTreeWidgetItem *)));
+
+ wpagui = NULL;
+ scanResultsWidget->setItemsExpandable(FALSE);
+ scanResultsWidget->setRootIsDecorated(FALSE);
+}
+
+
+ScanResults::~ScanResults()
+{
+}
+
+
+void ScanResults::languageChange()
+{
+ retranslateUi(this);
+}
+
+
+void ScanResults::setWpaGui(WpaGui *_wpagui)
+{
+ wpagui = _wpagui;
+ updateResults();
+}
+
+
+void ScanResults::updateResults()
+{
+ char reply[2048];
+ size_t reply_len;
+ int index;
+ char cmd[20];
+
+ scanResultsWidget->clear();
+
+ index = 0;
+ while (wpagui) {
+ snprintf(cmd, sizeof(cmd), "BSS %d", index++);
+ if (index > 1000)
+ break;
+
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) < 0)
+ break;
+ reply[reply_len] = '\0';
+
+ QString bss(reply);
+ if (bss.isEmpty() || bss.startsWith("FAIL"))
+ break;
+
+ QString ssid, bssid, freq, signal, flags;
+
+ QStringList lines = bss.split(QRegExp("\\n"));
+ for (QStringList::Iterator it = lines.begin();
+ it != lines.end(); it++) {
+ int pos = (*it).indexOf('=') + 1;
+ if (pos < 1)
+ continue;
+
+ if ((*it).startsWith("bssid="))
+ bssid = (*it).mid(pos);
+ else if ((*it).startsWith("freq="))
+ freq = (*it).mid(pos);
+ else if ((*it).startsWith("qual="))
+ signal = (*it).mid(pos);
+ else if ((*it).startsWith("flags="))
+ flags = (*it).mid(pos);
+ else if ((*it).startsWith("ssid="))
+ ssid = (*it).mid(pos);
+ }
+
+ QTreeWidgetItem *item = new QTreeWidgetItem(scanResultsWidget);
+ if (item) {
+ item->setText(0, ssid);
+ item->setText(1, bssid);
+ item->setText(2, freq);
+ item->setText(3, signal);
+ item->setText(4, flags);
+ }
+
+ if (bssid.isEmpty())
+ break;
+ }
+}
+
+
+void ScanResults::scanRequest()
+{
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+
+ if (wpagui == NULL)
+ return;
+
+ wpagui->ctrlRequest("SCAN", reply, &reply_len);
+}
+
+
+void ScanResults::getResults()
+{
+ updateResults();
+}
+
+
+void ScanResults::bssSelected(QTreeWidgetItem *sel)
+{
+ NetworkConfig *nc = new NetworkConfig();
+ if (nc == NULL)
+ return;
+ nc->setWpaGui(wpagui);
+ nc->paramsFromScanResults(sel);
+ nc->show();
+ nc->exec();
+}
diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.h b/wpa_supplicant/wpa_gui-qt4/scanresults.h
new file mode 100644
index 0000000..2c4a1b0
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/scanresults.h
@@ -0,0 +1,46 @@
+/*
+ * wpa_gui - ScanResults class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef SCANRESULTS_H
+#define SCANRESULTS_H
+
+#include <QObject>
+#include "ui_scanresults.h"
+
+class WpaGui;
+
+class ScanResults : public QDialog, public Ui::ScanResults
+{
+ Q_OBJECT
+
+public:
+ ScanResults(QWidget *parent = 0, const char *name = 0,
+ bool modal = false, Qt::WFlags fl = 0);
+ ~ScanResults();
+
+public slots:
+ virtual void setWpaGui(WpaGui *_wpagui);
+ virtual void updateResults();
+ virtual void scanRequest();
+ virtual void getResults();
+ virtual void bssSelected(QTreeWidgetItem *sel);
+
+protected slots:
+ virtual void languageChange();
+
+private:
+ WpaGui *wpagui;
+};
+
+#endif /* SCANRESULTS_H */
diff --git a/wpa_supplicant/wpa_gui-qt4/scanresults.ui b/wpa_supplicant/wpa_gui-qt4/scanresults.ui
new file mode 100644
index 0000000..81e405e
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/scanresults.ui
@@ -0,0 +1,94 @@
+<ui version="4.0" >
+ <class>ScanResults</class>
+ <widget class="QDialog" name="ScanResults" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>452</width>
+ <height>244</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Scan results</string>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QTreeWidget" name="scanResultsWidget" >
+ <property name="editTriggers" >
+ <set>QAbstractItemView::NoEditTriggers</set>
+ </property>
+ <property name="uniformRowHeights" >
+ <bool>true</bool>
+ </property>
+ <property name="sortingEnabled" >
+ <bool>true</bool>
+ </property>
+ <property name="columnCount" >
+ <number>5</number>
+ </property>
+ <column>
+ <property name="text" >
+ <string>SSID</string>
+ </property>
+ </column>
+ <column>
+ <property name="text" >
+ <string>BSSID</string>
+ </property>
+ </column>
+ <column>
+ <property name="text" >
+ <string>frequency</string>
+ </property>
+ </column>
+ <column>
+ <property name="text" >
+ <string>signal</string>
+ </property>
+ </column>
+ <column>
+ <property name="text" >
+ <string>flags</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <item>
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Horizontal</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>40</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="scanButton" >
+ <property name="text" >
+ <string>Scan</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="closeButton" >
+ <property name="text" >
+ <string>Close</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <pixmapfunction></pixmapfunction>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp b/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp
new file mode 100644
index 0000000..42fbdbc
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/userdatarequest.cpp
@@ -0,0 +1,100 @@
+/*
+ * wpa_gui - UserDataRequest class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "userdatarequest.h"
+#include "wpagui.h"
+#include "wpa_ctrl.h"
+
+
+UserDataRequest::UserDataRequest(QWidget *parent, const char *, bool,
+ Qt::WFlags)
+ : QDialog(parent)
+{
+ setupUi(this);
+
+ connect(buttonOk, SIGNAL(clicked()), this, SLOT(sendReply()));
+ connect(buttonCancel, SIGNAL(clicked()), this, SLOT(reject()));
+ connect(queryEdit, SIGNAL(returnPressed()), this, SLOT(sendReply()));
+}
+
+
+UserDataRequest::~UserDataRequest()
+{
+}
+
+
+void UserDataRequest::languageChange()
+{
+ retranslateUi(this);
+}
+
+
+int UserDataRequest::setParams(WpaGui *_wpagui, const char *reqMsg)
+{
+ char *tmp, *pos, *pos2;
+ wpagui = _wpagui;
+ tmp = strdup(reqMsg);
+ if (tmp == NULL)
+ return -1;
+ pos = strchr(tmp, '-');
+ if (pos == NULL) {
+ free(tmp);
+ return -1;
+ }
+ *pos++ = '\0';
+ field = tmp;
+ pos2 = strchr(pos, ':');
+ if (pos2 == NULL) {
+ free(tmp);
+ return -1;
+ }
+ *pos2++ = '\0';
+
+ networkid = atoi(pos);
+ queryInfo->setText(pos2);
+ if (strcmp(tmp, "PASSWORD") == 0) {
+ queryField->setText("Password: ");
+ queryEdit->setEchoMode(QLineEdit::Password);
+ } else if (strcmp(tmp, "NEW_PASSWORD") == 0) {
+ queryField->setText("New password: ");
+ queryEdit->setEchoMode(QLineEdit::Password);
+ } else if (strcmp(tmp, "IDENTITY") == 0)
+ queryField->setText("Identity: ");
+ else if (strcmp(tmp, "PASSPHRASE") == 0) {
+ queryField->setText("Private key passphrase: ");
+ queryEdit->setEchoMode(QLineEdit::Password);
+ } else
+ queryField->setText(field + ":");
+ free(tmp);
+
+ return 0;
+}
+
+
+void UserDataRequest::sendReply()
+{
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+
+ if (wpagui == NULL) {
+ reject();
+ return;
+ }
+
+ QString cmd = QString(WPA_CTRL_RSP) + field + '-' +
+ QString::number(networkid) + ':' +
+ queryEdit->text();
+ wpagui->ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
+ accept();
+}
diff --git a/wpa_supplicant/wpa_gui-qt4/userdatarequest.h b/wpa_supplicant/wpa_gui-qt4/userdatarequest.h
new file mode 100644
index 0000000..2b6e837
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/userdatarequest.h
@@ -0,0 +1,46 @@
+/*
+ * wpa_gui - UserDataRequest class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef USERDATAREQUEST_H
+#define USERDATAREQUEST_H
+
+#include <QObject>
+#include "ui_userdatarequest.h"
+
+class WpaGui;
+
+class UserDataRequest : public QDialog, public Ui::UserDataRequest
+{
+ Q_OBJECT
+
+public:
+ UserDataRequest(QWidget *parent = 0, const char *name = 0,
+ bool modal = false, Qt::WFlags fl = 0);
+ ~UserDataRequest();
+
+ int setParams(WpaGui *_wpagui, const char *reqMsg);
+
+public slots:
+ virtual void sendReply();
+
+protected slots:
+ virtual void languageChange();
+
+private:
+ WpaGui *wpagui;
+ int networkid;
+ QString field;
+};
+
+#endif /* USERDATAREQUEST_H */
diff --git a/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui b/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui
new file mode 100644
index 0000000..1de2a26
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/userdatarequest.ui
@@ -0,0 +1,109 @@
+<ui version="4.0" stdsetdef="1" >
+ <author></author>
+ <comment></comment>
+ <exportmacro></exportmacro>
+ <class>UserDataRequest</class>
+ <widget class="QDialog" name="UserDataRequest" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>216</width>
+ <height>103</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>Authentication credentials required</string>
+ </property>
+ <property name="sizeGripEnabled" >
+ <bool>true</bool>
+ </property>
+ <layout class="QVBoxLayout" >
+ <item>
+ <widget class="QLabel" name="queryInfo" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <widget class="QLabel" name="queryField" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLineEdit" name="queryEdit" >
+ <property name="enabled" >
+ <bool>true</bool>
+ </property>
+ <property name="echoMode" >
+ <enum>QLineEdit::Password</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" >
+ <property name="margin" >
+ <number>0</number>
+ </property>
+ <item>
+ <spacer name="spacer4" >
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ <property name="sizeType" >
+ <enum>Expanding</enum>
+ </property>
+ <property name="orientation" >
+ <enum>Horizontal</enum>
+ </property>
+ </spacer>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonOk" >
+ <property name="text" >
+ <string>&amp;OK</string>
+ </property>
+ <property name="shortcut" >
+ <string/>
+ </property>
+ <property name="autoDefault" >
+ <bool>true</bool>
+ </property>
+ <property name="default" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="buttonCancel" >
+ <property name="text" >
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="shortcut" >
+ <string/>
+ </property>
+ <property name="autoDefault" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <pixmapfunction></pixmapfunction>
+</ui>
diff --git a/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop b/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop
new file mode 100644
index 0000000..ccc7d87
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/wpa_gui.desktop
@@ -0,0 +1,10 @@
+[Desktop Entry]
+Version=1.0
+Name=wpa_gui
+Comment=Graphical user interface for wpa_supplicant
+Exec=wpa_gui
+Icon=wpa_gui
+GenericName=wpa_supplicant user interface
+Terminal=false
+Type=Application
+Categories=Qt;Network;
diff --git a/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro b/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
new file mode 100644
index 0000000..2317cbd
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/wpa_gui.pro
@@ -0,0 +1,62 @@
+TEMPLATE = app
+LANGUAGE = C++
+
+CONFIG += qt warn_on release
+
+DEFINES += CONFIG_CTRL_IFACE
+
+win32 {
+ LIBS += -lws2_32 -static
+ DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
+ SOURCES += ../../src/utils/os_win32.c
+} else:win32-g++ {
+ # cross compilation to win32
+ LIBS += -lws2_32 -static -mwindows
+ DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
+ SOURCES += ../../src/utils/os_win32.c
+ RESOURCES += icons_png.qrc
+} else:win32-x-g++ {
+ # cross compilation to win32
+ LIBS += -lws2_32 -static -mwindows
+ DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
+ DEFINES += _X86_
+ SOURCES += ../../src/utils/os_win32.c
+ RESOURCES += icons_png.qrc
+} else {
+ DEFINES += CONFIG_CTRL_IFACE_UNIX
+ SOURCES += ../../src/utils/os_unix.c
+}
+
+INCLUDEPATH += . .. ../../src/utils ../../src/common
+
+HEADERS += wpamsg.h \
+ wpagui.h \
+ eventhistory.h \
+ scanresults.h \
+ userdatarequest.h \
+ networkconfig.h \
+ addinterface.h
+
+SOURCES += main.cpp \
+ wpagui.cpp \
+ eventhistory.cpp \
+ scanresults.cpp \
+ userdatarequest.cpp \
+ networkconfig.cpp \
+ addinterface.cpp \
+ ../../src/common/wpa_ctrl.c
+
+RESOURCES += icons.qrc
+
+FORMS = wpagui.ui \
+ eventhistory.ui \
+ scanresults.ui \
+ userdatarequest.ui \
+ networkconfig.ui
+
+
+unix {
+ UI_DIR = .ui
+ MOC_DIR = .moc
+ OBJECTS_DIR = .obj
+}
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.cpp b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
new file mode 100644
index 0000000..a3fbf72
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.cpp
@@ -0,0 +1,1706 @@
+/*
+ * wpa_gui - WpaGui class
+ * Copyright (c) 2005-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifdef __MINGW32__
+/* Need to get getopt() */
+#include <unistd.h>
+#endif
+
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <windows.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include <cstdio>
+#include <QMessageBox>
+#include <QCloseEvent>
+#include <QImageReader>
+#include <QSettings>
+
+#include "wpagui.h"
+#include "dirent.h"
+#include "wpa_ctrl.h"
+#include "userdatarequest.h"
+#include "networkconfig.h"
+
+#if 1
+/* Silence stdout */
+#define printf wpagui_printf
+static int wpagui_printf(const char *, ...)
+{
+ return 0;
+}
+#endif
+
+WpaGui::WpaGui(QApplication *_app, QWidget *parent, const char *, Qt::WFlags)
+ : QMainWindow(parent), app(_app)
+{
+ setupUi(this);
+
+#ifdef CONFIG_NATIVE_WINDOWS
+ fileStopServiceAction = new QAction(this);
+ fileStopServiceAction->setObjectName("Stop Service");
+ fileStopServiceAction->setIconText("Stop Service");
+ fileMenu->insertAction(actionWPS, fileStopServiceAction);
+
+ fileStartServiceAction = new QAction(this);
+ fileStartServiceAction->setObjectName("Start Service");
+ fileStartServiceAction->setIconText("Start Service");
+ fileMenu->insertAction(fileStopServiceAction, fileStartServiceAction);
+
+ connect(fileStartServiceAction, SIGNAL(triggered()), this,
+ SLOT(startService()));
+ connect(fileStopServiceAction, SIGNAL(triggered()), this,
+ SLOT(stopService()));
+
+ addInterfaceAction = new QAction(this);
+ addInterfaceAction->setIconText("Add Interface");
+ fileMenu->insertAction(fileStartServiceAction, addInterfaceAction);
+
+ connect(addInterfaceAction, SIGNAL(triggered()), this,
+ SLOT(addInterface()));
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ (void) statusBar();
+
+ /*
+ * Disable WPS tab by default; it will be enabled if wpa_supplicant is
+ * built with WPS support.
+ */
+ wpsTab->setEnabled(false);
+ wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), false);
+
+ connect(fileEventHistoryAction, SIGNAL(triggered()), this,
+ SLOT(eventHistory()));
+ connect(fileSaveConfigAction, SIGNAL(triggered()), this,
+ SLOT(saveConfig()));
+ connect(actionWPS, SIGNAL(triggered()), this, SLOT(wpsDialog()));
+ connect(fileExitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
+ connect(networkAddAction, SIGNAL(triggered()), this,
+ SLOT(addNetwork()));
+ connect(networkEditAction, SIGNAL(triggered()), this,
+ SLOT(editSelectedNetwork()));
+ connect(networkRemoveAction, SIGNAL(triggered()), this,
+ SLOT(removeSelectedNetwork()));
+ connect(networkEnableAllAction, SIGNAL(triggered()), this,
+ SLOT(enableAllNetworks()));
+ connect(networkDisableAllAction, SIGNAL(triggered()), this,
+ SLOT(disableAllNetworks()));
+ connect(networkRemoveAllAction, SIGNAL(triggered()), this,
+ SLOT(removeAllNetworks()));
+ connect(helpIndexAction, SIGNAL(triggered()), this, SLOT(helpIndex()));
+ connect(helpContentsAction, SIGNAL(triggered()), this,
+ SLOT(helpContents()));
+ connect(helpAboutAction, SIGNAL(triggered()), this, SLOT(helpAbout()));
+ connect(disconnectButton, SIGNAL(clicked()), this, SLOT(disconnect()));
+ connect(scanButton, SIGNAL(clicked()), this, SLOT(scan()));
+ connect(connectButton, SIGNAL(clicked()), this, SLOT(connectB()));
+ connect(adapterSelect, SIGNAL(activated(const QString&)), this,
+ SLOT(selectAdapter(const QString&)));
+ connect(networkSelect, SIGNAL(activated(const QString&)), this,
+ SLOT(selectNetwork(const QString&)));
+ connect(addNetworkButton, SIGNAL(clicked()), this, SLOT(addNetwork()));
+ connect(editNetworkButton, SIGNAL(clicked()), this,
+ SLOT(editListedNetwork()));
+ connect(removeNetworkButton, SIGNAL(clicked()), this,
+ SLOT(removeListedNetwork()));
+ connect(networkList, SIGNAL(itemSelectionChanged()), this,
+ SLOT(updateNetworkDisabledStatus()));
+ connect(enableRadioButton, SIGNAL(toggled(bool)), this,
+ SLOT(enableListedNetwork(bool)));
+ connect(disableRadioButton, SIGNAL(toggled(bool)), this,
+ SLOT(disableListedNetwork(bool)));
+ connect(scanNetworkButton, SIGNAL(clicked()), this, SLOT(scan()));
+ connect(networkList, SIGNAL(itemDoubleClicked(QListWidgetItem *)),
+ this, SLOT(editListedNetwork()));
+ connect(wpaguiTab, SIGNAL(currentChanged(int)), this,
+ SLOT(tabChanged(int)));
+ connect(wpsPbcButton, SIGNAL(clicked()), this, SLOT(wpsPbc()));
+ connect(wpsPinButton, SIGNAL(clicked()), this, SLOT(wpsGeneratePin()));
+ connect(wpsApPinEdit, SIGNAL(textChanged(const QString &)), this,
+ SLOT(wpsApPinChanged(const QString &)));
+ connect(wpsApPinButton, SIGNAL(clicked()), this, SLOT(wpsApPin()));
+
+ eh = NULL;
+ scanres = NULL;
+ add_iface = NULL;
+ udr = NULL;
+ tray_icon = NULL;
+ startInTray = false;
+ ctrl_iface = NULL;
+ ctrl_conn = NULL;
+ monitor_conn = NULL;
+ msgNotifier = NULL;
+ ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
+
+ parse_argv();
+
+#ifndef QT_NO_SESSIONMANAGER
+ if (app->isSessionRestored()) {
+ QSettings settings("wpa_supplicant", "wpa_gui");
+ settings.beginGroup("state");
+ if (app->sessionId().compare(settings.value("session_id").
+ toString()) == 0)
+ startInTray = settings.value("in_tray").toBool();
+ settings.endGroup();
+ }
+#endif
+
+ if (QSystemTrayIcon::isSystemTrayAvailable())
+ createTrayIcon(startInTray);
+ else
+ show();
+
+ connectedToService = false;
+ textStatus->setText("connecting to wpa_supplicant");
+ timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), SLOT(ping()));
+ timer->setSingleShot(FALSE);
+ timer->start(1000);
+
+ if (openCtrlConnection(ctrl_iface) < 0) {
+ printf("Failed to open control connection to "
+ "wpa_supplicant.\n");
+ }
+
+ updateStatus();
+ networkMayHaveChanged = true;
+ updateNetworks();
+}
+
+
+WpaGui::~WpaGui()
+{
+ delete msgNotifier;
+
+ if (monitor_conn) {
+ wpa_ctrl_detach(monitor_conn);
+ wpa_ctrl_close(monitor_conn);
+ monitor_conn = NULL;
+ }
+ if (ctrl_conn) {
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
+ }
+
+ if (eh) {
+ eh->close();
+ delete eh;
+ eh = NULL;
+ }
+
+ if (scanres) {
+ scanres->close();
+ delete scanres;
+ scanres = NULL;
+ }
+
+ if (add_iface) {
+ add_iface->close();
+ delete add_iface;
+ add_iface = NULL;
+ }
+
+ if (udr) {
+ udr->close();
+ delete udr;
+ udr = NULL;
+ }
+
+ free(ctrl_iface);
+ ctrl_iface = NULL;
+
+ free(ctrl_iface_dir);
+ ctrl_iface_dir = NULL;
+}
+
+
+void WpaGui::languageChange()
+{
+ retranslateUi(this);
+}
+
+
+void WpaGui::parse_argv()
+{
+ int c;
+ for (;;) {
+ c = getopt(qApp->argc(), qApp->argv(), "i:p:t");
+ if (c < 0)
+ break;
+ switch (c) {
+ case 'i':
+ free(ctrl_iface);
+ ctrl_iface = strdup(optarg);
+ break;
+ case 'p':
+ free(ctrl_iface_dir);
+ ctrl_iface_dir = strdup(optarg);
+ break;
+ case 't':
+ startInTray = true;
+ break;
+ }
+ }
+}
+
+
+int WpaGui::openCtrlConnection(const char *ifname)
+{
+ char *cfile;
+ int flen;
+ char buf[2048], *pos, *pos2;
+ size_t len;
+
+ if (ifname) {
+ if (ifname != ctrl_iface) {
+ free(ctrl_iface);
+ ctrl_iface = strdup(ifname);
+ }
+ } else {
+#ifdef CONFIG_CTRL_IFACE_UDP
+ free(ctrl_iface);
+ ctrl_iface = strdup("udp");
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#ifdef CONFIG_CTRL_IFACE_UNIX
+ struct dirent *dent;
+ DIR *dir = opendir(ctrl_iface_dir);
+ free(ctrl_iface);
+ ctrl_iface = NULL;
+ if (dir) {
+ while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+ /* Skip the file if it is not a socket.
+ * Also accept DT_UNKNOWN (0) in case
+ * the C library or underlying file
+ * system does not support d_type. */
+ if (dent->d_type != DT_SOCK &&
+ dent->d_type != DT_UNKNOWN)
+ continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+ printf("Selected interface '%s'\n",
+ dent->d_name);
+ ctrl_iface = strdup(dent->d_name);
+ break;
+ }
+ closedir(dir);
+ }
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+ struct wpa_ctrl *ctrl;
+ int ret;
+
+ free(ctrl_iface);
+ ctrl_iface = NULL;
+
+ ctrl = wpa_ctrl_open(NULL);
+ if (ctrl) {
+ len = sizeof(buf) - 1;
+ ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf,
+ &len, NULL);
+ if (ret >= 0) {
+ connectedToService = true;
+ buf[len] = '\0';
+ pos = strchr(buf, '\n');
+ if (pos)
+ *pos = '\0';
+ ctrl_iface = strdup(buf);
+ }
+ wpa_ctrl_close(ctrl);
+ }
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+ }
+
+ if (ctrl_iface == NULL) {
+#ifdef CONFIG_NATIVE_WINDOWS
+ static bool first = true;
+ if (first && !serviceRunning()) {
+ first = false;
+ if (QMessageBox::warning(
+ this, qAppName(),
+ "wpa_supplicant service is not running.\n"
+ "Do you want to start it?",
+ QMessageBox::Yes | QMessageBox::No) ==
+ QMessageBox::Yes)
+ startService();
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+ return -1;
+ }
+
+#ifdef CONFIG_CTRL_IFACE_UNIX
+ flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
+ cfile = (char *) malloc(flen);
+ if (cfile == NULL)
+ return -1;
+ snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface);
+#else /* CONFIG_CTRL_IFACE_UNIX */
+ flen = strlen(ctrl_iface) + 1;
+ cfile = (char *) malloc(flen);
+ if (cfile == NULL)
+ return -1;
+ snprintf(cfile, flen, "%s", ctrl_iface);
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+
+ if (ctrl_conn) {
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
+ }
+
+ if (monitor_conn) {
+ delete msgNotifier;
+ msgNotifier = NULL;
+ wpa_ctrl_detach(monitor_conn);
+ wpa_ctrl_close(monitor_conn);
+ monitor_conn = NULL;
+ }
+
+ printf("Trying to connect to '%s'\n", cfile);
+ ctrl_conn = wpa_ctrl_open(cfile);
+ if (ctrl_conn == NULL) {
+ free(cfile);
+ return -1;
+ }
+ monitor_conn = wpa_ctrl_open(cfile);
+ free(cfile);
+ if (monitor_conn == NULL) {
+ wpa_ctrl_close(ctrl_conn);
+ return -1;
+ }
+ if (wpa_ctrl_attach(monitor_conn)) {
+ printf("Failed to attach to wpa_supplicant\n");
+ wpa_ctrl_close(monitor_conn);
+ monitor_conn = NULL;
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
+ return -1;
+ }
+
+#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
+ msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
+ QSocketNotifier::Read, this);
+ connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
+#endif
+
+ adapterSelect->clear();
+ adapterSelect->addItem(ctrl_iface);
+ adapterSelect->setCurrentIndex(0);
+
+ len = sizeof(buf) - 1;
+ if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >=
+ 0) {
+ buf[len] = '\0';
+ pos = buf;
+ while (*pos) {
+ pos2 = strchr(pos, '\n');
+ if (pos2)
+ *pos2 = '\0';
+ if (strcmp(pos, ctrl_iface) != 0)
+ adapterSelect->addItem(pos);
+ if (pos2)
+ pos = pos2 + 1;
+ else
+ break;
+ }
+ }
+
+ len = sizeof(buf) - 1;
+ if (wpa_ctrl_request(ctrl_conn, "GET_CAPABILITY eap", 18, buf, &len,
+ NULL) >= 0) {
+ buf[len] = '\0';
+
+ QString res(buf);
+ QStringList types = res.split(QChar(' '));
+ bool wps = types.contains("WSC");
+ actionWPS->setEnabled(wps);
+ wpsTab->setEnabled(wps);
+ wpaguiTab->setTabEnabled(wpaguiTab->indexOf(wpsTab), wps);
+ }
+
+ return 0;
+}
+
+
+static void wpa_gui_msg_cb(char *msg, size_t)
+{
+ /* This should not happen anymore since two control connections are
+ * used. */
+ printf("missed message: %s\n", msg);
+}
+
+
+int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
+{
+ int ret;
+
+ if (ctrl_conn == NULL)
+ return -3;
+ ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen,
+ wpa_gui_msg_cb);
+ if (ret == -2)
+ printf("'%s' command timed out.\n", cmd);
+ else if (ret < 0)
+ printf("'%s' command failed.\n", cmd);
+
+ return ret;
+}
+
+
+void WpaGui::updateStatus()
+{
+ char buf[2048], *start, *end, *pos;
+ size_t len;
+
+ pingsToStatusUpdate = 10;
+
+ len = sizeof(buf) - 1;
+ if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) {
+ textStatus->setText("Could not get status from "
+ "wpa_supplicant");
+ textAuthentication->clear();
+ textEncryption->clear();
+ textSsid->clear();
+ textBssid->clear();
+ textIpAddress->clear();
+
+#ifdef CONFIG_NATIVE_WINDOWS
+ static bool first = true;
+ if (first && connectedToService &&
+ (ctrl_iface == NULL || *ctrl_iface == '\0')) {
+ first = false;
+ if (QMessageBox::information(
+ this, qAppName(),
+ "No network interfaces in use.\n"
+ "Would you like to add one?",
+ QMessageBox::Yes | QMessageBox::No) ==
+ QMessageBox::Yes)
+ addInterface();
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+ return;
+ }
+
+ buf[len] = '\0';
+
+ bool auth_updated = false, ssid_updated = false;
+ bool bssid_updated = false, ipaddr_updated = false;
+ bool status_updated = false;
+ char *pairwise_cipher = NULL, *group_cipher = NULL;
+
+ start = buf;
+ while (*start) {
+ bool last = false;
+ end = strchr(start, '\n');
+ if (end == NULL) {
+ last = true;
+ end = start;
+ while (end[0] && end[1])
+ end++;
+ }
+ *end = '\0';
+
+ pos = strchr(start, '=');
+ if (pos) {
+ *pos++ = '\0';
+ if (strcmp(start, "bssid") == 0) {
+ bssid_updated = true;
+ textBssid->setText(pos);
+ } else if (strcmp(start, "ssid") == 0) {
+ ssid_updated = true;
+ textSsid->setText(pos);
+ } else if (strcmp(start, "ip_address") == 0) {
+ ipaddr_updated = true;
+ textIpAddress->setText(pos);
+ } else if (strcmp(start, "wpa_state") == 0) {
+ status_updated = true;
+ textStatus->setText(pos);
+ } else if (strcmp(start, "key_mgmt") == 0) {
+ auth_updated = true;
+ textAuthentication->setText(pos);
+ /* TODO: could add EAP status to this */
+ } else if (strcmp(start, "pairwise_cipher") == 0) {
+ pairwise_cipher = pos;
+ } else if (strcmp(start, "group_cipher") == 0) {
+ group_cipher = pos;
+ }
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+
+ if (pairwise_cipher || group_cipher) {
+ QString encr;
+ if (pairwise_cipher && group_cipher &&
+ strcmp(pairwise_cipher, group_cipher) != 0) {
+ encr.append(pairwise_cipher);
+ encr.append(" + ");
+ encr.append(group_cipher);
+ } else if (pairwise_cipher) {
+ encr.append(pairwise_cipher);
+ } else {
+ encr.append(group_cipher);
+ encr.append(" [group key only]");
+ }
+ textEncryption->setText(encr);
+ } else
+ textEncryption->clear();
+
+ if (!status_updated)
+ textStatus->clear();
+ if (!auth_updated)
+ textAuthentication->clear();
+ if (!ssid_updated)
+ textSsid->clear();
+ if (!bssid_updated)
+ textBssid->clear();
+ if (!ipaddr_updated)
+ textIpAddress->clear();
+}
+
+
+void WpaGui::updateNetworks()
+{
+ char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
+ size_t len;
+ int first_active = -1;
+ int was_selected = -1;
+ bool current = false;
+
+ if (!networkMayHaveChanged)
+ return;
+
+ if (networkList->currentRow() >= 0)
+ was_selected = networkList->currentRow();
+
+ networkSelect->clear();
+ networkList->clear();
+
+ if (ctrl_conn == NULL)
+ return;
+
+ len = sizeof(buf) - 1;
+ if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
+ return;
+
+ buf[len] = '\0';
+ start = strchr(buf, '\n');
+ if (start == NULL)
+ return;
+ start++;
+
+ while (*start) {
+ bool last = false;
+ end = strchr(start, '\n');
+ if (end == NULL) {
+ last = true;
+ end = start;
+ while (end[0] && end[1])
+ end++;
+ }
+ *end = '\0';
+
+ id = start;
+ ssid = strchr(id, '\t');
+ if (ssid == NULL)
+ break;
+ *ssid++ = '\0';
+ bssid = strchr(ssid, '\t');
+ if (bssid == NULL)
+ break;
+ *bssid++ = '\0';
+ flags = strchr(bssid, '\t');
+ if (flags == NULL)
+ break;
+ *flags++ = '\0';
+
+ QString network(id);
+ network.append(": ");
+ network.append(ssid);
+ networkSelect->addItem(network);
+ networkList->addItem(network);
+
+ if (strstr(flags, "[CURRENT]")) {
+ networkSelect->setCurrentIndex(networkSelect->count() -
+ 1);
+ current = true;
+ } else if (first_active < 0 &&
+ strstr(flags, "[DISABLED]") == NULL)
+ first_active = networkSelect->count() - 1;
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+
+ if (networkSelect->count() > 1)
+ networkSelect->addItem("Select any network");
+
+ if (!current && first_active >= 0)
+ networkSelect->setCurrentIndex(first_active);
+
+ if (was_selected >= 0 && networkList->count() > 0) {
+ if (was_selected < networkList->count())
+ networkList->setCurrentRow(was_selected);
+ else
+ networkList->setCurrentRow(networkList->count() - 1);
+ }
+ else
+ networkList->setCurrentRow(networkSelect->currentIndex());
+
+ networkMayHaveChanged = false;
+}
+
+
+void WpaGui::helpIndex()
+{
+ printf("helpIndex\n");
+}
+
+
+void WpaGui::helpContents()
+{
+ printf("helpContents\n");
+}
+
+
+void WpaGui::helpAbout()
+{
+ QMessageBox::about(this, "wpa_gui for wpa_supplicant",
+ "Copyright (c) 2003-2008,\n"
+ "Jouni Malinen <j@w1.fi>\n"
+ "and contributors.\n"
+ "\n"
+ "This program is free software. You can\n"
+ "distribute it and/or modify it under the terms "
+ "of\n"
+ "the GNU General Public License version 2.\n"
+ "\n"
+ "Alternatively, this software may be distributed\n"
+ "under the terms of the BSD license.\n"
+ "\n"
+ "This product includes software developed\n"
+ "by the OpenSSL Project for use in the\n"
+ "OpenSSL Toolkit (http://www.openssl.org/)\n");
+}
+
+
+void WpaGui::disconnect()
+{
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+ ctrlRequest("DISCONNECT", reply, &reply_len);
+ stopWpsRun(false);
+}
+
+
+void WpaGui::scan()
+{
+ if (scanres) {
+ scanres->close();
+ delete scanres;
+ }
+
+ scanres = new ScanResults();
+ if (scanres == NULL)
+ return;
+ scanres->setWpaGui(this);
+ scanres->show();
+ scanres->exec();
+}
+
+
+void WpaGui::eventHistory()
+{
+ if (eh) {
+ eh->close();
+ delete eh;
+ }
+
+ eh = new EventHistory();
+ if (eh == NULL)
+ return;
+ eh->addEvents(msgs);
+ eh->show();
+ eh->exec();
+}
+
+
+void WpaGui::ping()
+{
+ char buf[10];
+ size_t len;
+
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+ /*
+ * QSocketNotifier cannot be used with Windows named pipes, so use a
+ * timer to check for received messages for now. This could be
+ * optimized be doing something specific to named pipes or Windows
+ * events, but it is not clear what would be the best way of doing that
+ * in Qt.
+ */
+ receiveMsgs();
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+
+ if (scanres && !scanres->isVisible()) {
+ delete scanres;
+ scanres = NULL;
+ }
+
+ if (eh && !eh->isVisible()) {
+ delete eh;
+ eh = NULL;
+ }
+
+ if (udr && !udr->isVisible()) {
+ delete udr;
+ udr = NULL;
+ }
+
+ len = sizeof(buf) - 1;
+ if (ctrlRequest("PING", buf, &len) < 0) {
+ printf("PING failed - trying to reconnect\n");
+ if (openCtrlConnection(ctrl_iface) >= 0) {
+ printf("Reconnected successfully\n");
+ pingsToStatusUpdate = 0;
+ }
+ }
+
+ pingsToStatusUpdate--;
+ if (pingsToStatusUpdate <= 0) {
+ updateStatus();
+ updateNetworks();
+ }
+
+#ifndef CONFIG_CTRL_IFACE_NAMED_PIPE
+ /* Use less frequent pings and status updates when the main window is
+ * hidden (running in taskbar). */
+ int interval = isHidden() ? 5000 : 1000;
+ if (timer->interval() != interval)
+ timer->setInterval(interval);
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+}
+
+
+static int str_match(const char *a, const char *b)
+{
+ return strncmp(a, b, strlen(b)) == 0;
+}
+
+
+void WpaGui::processMsg(char *msg)
+{
+ char *pos = msg, *pos2;
+ int priority = 2;
+
+ if (*pos == '<') {
+ /* skip priority */
+ pos++;
+ priority = atoi(pos);
+ pos = strchr(pos, '>');
+ if (pos)
+ pos++;
+ else
+ pos = msg;
+ }
+
+ WpaMsg wm(pos, priority);
+ if (eh)
+ eh->addEvent(wm);
+ msgs.append(wm);
+ while (msgs.count() > 100)
+ msgs.pop_front();
+
+ /* Update last message with truncated version of the event */
+ if (strncmp(pos, "CTRL-", 5) == 0) {
+ pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' ');
+ if (pos2)
+ pos2++;
+ else
+ pos2 = pos;
+ } else
+ pos2 = pos;
+ QString lastmsg = pos2;
+ lastmsg.truncate(40);
+ textLastMessage->setText(lastmsg);
+
+ pingsToStatusUpdate = 0;
+ networkMayHaveChanged = true;
+
+ if (str_match(pos, WPA_CTRL_REQ))
+ processCtrlReq(pos + strlen(WPA_CTRL_REQ));
+ else if (str_match(pos, WPA_EVENT_SCAN_RESULTS) && scanres)
+ scanres->updateResults();
+ else if (str_match(pos, WPA_EVENT_DISCONNECTED))
+ showTrayMessage(QSystemTrayIcon::Information, 3,
+ "Disconnected from network.");
+ else if (str_match(pos, WPA_EVENT_CONNECTED)) {
+ showTrayMessage(QSystemTrayIcon::Information, 3,
+ "Connection to network established.");
+ QTimer::singleShot(5 * 1000, this, SLOT(showTrayStatus()));
+ stopWpsRun(true);
+ } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PBC)) {
+ showTrayMessage(QSystemTrayIcon::Information, 3,
+ "Wi-Fi Protected Setup (WPS) AP\n"
+ "in active PBC mode found.");
+ wpsStatusText->setText("WPS AP in active PBC mode found");
+ if (textStatus->text() == "INACTIVE" ||
+ textStatus->text() == "DISCONNECTED")
+ wpaguiTab->setCurrentWidget(wpsTab);
+ wpsInstructions->setText("Press the PBC button on the screen "
+ "to start registration");
+ } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE_PIN)) {
+ showTrayMessage(QSystemTrayIcon::Information, 3,
+ "Wi-Fi Protected Setup (WPS) AP\n"
+ " in active PIN mode found.");
+ wpsStatusText->setText("WPS AP with recently selected "
+ "registrar");
+ if (textStatus->text() == "INACTIVE" ||
+ textStatus->text() == "DISCONNECTED")
+ wpaguiTab->setCurrentWidget(wpsTab);
+ } else if (str_match(pos, WPS_EVENT_AP_AVAILABLE)) {
+ showTrayMessage(QSystemTrayIcon::Information, 3,
+ "Wi-Fi Protected Setup (WPS)\n"
+ "AP detected.");
+ wpsStatusText->setText("WPS AP detected");
+ } else if (str_match(pos, WPS_EVENT_OVERLAP)) {
+ showTrayMessage(QSystemTrayIcon::Information, 3,
+ "Wi-Fi Protected Setup (WPS)\n"
+ "PBC mode overlap detected.");
+ wpsStatusText->setText("PBC mode overlap detected");
+ wpsInstructions->setText("More than one AP is currently in "
+ "active WPS PBC mode. Wait couple of "
+ "minutes and try again");
+ wpaguiTab->setCurrentWidget(wpsTab);
+ } else if (str_match(pos, WPS_EVENT_CRED_RECEIVED)) {
+ wpsStatusText->setText("Network configuration received");
+ wpaguiTab->setCurrentWidget(wpsTab);
+ } else if (str_match(pos, WPA_EVENT_EAP_METHOD)) {
+ if (strstr(pos, "(WSC)"))
+ wpsStatusText->setText("Registration started");
+ } else if (str_match(pos, WPS_EVENT_M2D)) {
+ wpsStatusText->setText("Registrar does not yet know PIN");
+ } else if (str_match(pos, WPS_EVENT_FAIL)) {
+ wpsStatusText->setText("Registration failed");
+ } else if (str_match(pos, WPS_EVENT_SUCCESS)) {
+ wpsStatusText->setText("Registration succeeded");
+ }
+}
+
+
+void WpaGui::processCtrlReq(const char *req)
+{
+ if (udr) {
+ udr->close();
+ delete udr;
+ }
+ udr = new UserDataRequest();
+ if (udr == NULL)
+ return;
+ if (udr->setParams(this, req) < 0) {
+ delete udr;
+ udr = NULL;
+ return;
+ }
+ udr->show();
+ udr->exec();
+}
+
+
+void WpaGui::receiveMsgs()
+{
+ char buf[256];
+ size_t len;
+
+ while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
+ len = sizeof(buf) - 1;
+ if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
+ buf[len] = '\0';
+ processMsg(buf);
+ }
+ }
+}
+
+
+void WpaGui::connectB()
+{
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+ ctrlRequest("REASSOCIATE", reply, &reply_len);
+}
+
+
+void WpaGui::selectNetwork( const QString &sel )
+{
+ QString cmd(sel);
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+
+ if (cmd.startsWith("Select any")) {
+ cmd = "any";
+ } else {
+ int pos = cmd.indexOf(':');
+ if (pos < 0) {
+ printf("Invalid selectNetwork '%s'\n",
+ cmd.toAscii().constData());
+ return;
+ }
+ cmd.truncate(pos);
+ }
+ cmd.prepend("SELECT_NETWORK ");
+ ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
+ triggerUpdate();
+ stopWpsRun(false);
+}
+
+
+void WpaGui::enableNetwork(const QString &sel)
+{
+ QString cmd(sel);
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+
+ if (!cmd.startsWith("all")) {
+ int pos = cmd.indexOf(':');
+ if (pos < 0) {
+ printf("Invalid enableNetwork '%s'\n",
+ cmd.toAscii().constData());
+ return;
+ }
+ cmd.truncate(pos);
+ }
+ cmd.prepend("ENABLE_NETWORK ");
+ ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
+ triggerUpdate();
+}
+
+
+void WpaGui::disableNetwork(const QString &sel)
+{
+ QString cmd(sel);
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+
+ if (!cmd.startsWith("all")) {
+ int pos = cmd.indexOf(':');
+ if (pos < 0) {
+ printf("Invalid disableNetwork '%s'\n",
+ cmd.toAscii().constData());
+ return;
+ }
+ cmd.truncate(pos);
+ }
+ cmd.prepend("DISABLE_NETWORK ");
+ ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
+ triggerUpdate();
+}
+
+
+void WpaGui::editNetwork(const QString &sel)
+{
+ QString cmd(sel);
+ int id = -1;
+
+ if (!cmd.startsWith("Select any")) {
+ int pos = sel.indexOf(':');
+ if (pos < 0) {
+ printf("Invalid editNetwork '%s'\n",
+ cmd.toAscii().constData());
+ return;
+ }
+ cmd.truncate(pos);
+ id = cmd.toInt();
+ }
+
+ NetworkConfig *nc = new NetworkConfig();
+ if (nc == NULL)
+ return;
+ nc->setWpaGui(this);
+
+ if (id >= 0)
+ nc->paramsFromConfig(id);
+ else
+ nc->newNetwork();
+
+ nc->show();
+ nc->exec();
+}
+
+
+void WpaGui::editSelectedNetwork()
+{
+ if (networkSelect->count() < 1) {
+ QMessageBox::information(this, "No Networks",
+ "There are no networks to edit.\n");
+ return;
+ }
+ QString sel(networkSelect->currentText());
+ editNetwork(sel);
+}
+
+
+void WpaGui::editListedNetwork()
+{
+ if (networkList->currentRow() < 0) {
+ QMessageBox::information(this, "Select A Network",
+ "Select a network from the list to"
+ " edit it.\n");
+ return;
+ }
+ QString sel(networkList->currentItem()->text());
+ editNetwork(sel);
+}
+
+
+void WpaGui::triggerUpdate()
+{
+ updateStatus();
+ networkMayHaveChanged = true;
+ updateNetworks();
+}
+
+
+void WpaGui::addNetwork()
+{
+ NetworkConfig *nc = new NetworkConfig();
+ if (nc == NULL)
+ return;
+ nc->setWpaGui(this);
+ nc->newNetwork();
+ nc->show();
+ nc->exec();
+}
+
+
+void WpaGui::removeNetwork(const QString &sel)
+{
+ QString cmd(sel);
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+
+ if (cmd.startsWith("Select any"))
+ return;
+
+ if (!cmd.startsWith("all")) {
+ int pos = cmd.indexOf(':');
+ if (pos < 0) {
+ printf("Invalid removeNetwork '%s'\n",
+ cmd.toAscii().constData());
+ return;
+ }
+ cmd.truncate(pos);
+ }
+ cmd.prepend("REMOVE_NETWORK ");
+ ctrlRequest(cmd.toAscii().constData(), reply, &reply_len);
+ triggerUpdate();
+}
+
+
+void WpaGui::removeSelectedNetwork()
+{
+ if (networkSelect->count() < 1) {
+ QMessageBox::information(this, "No Networks",
+ "There are no networks to remove.\n");
+ return;
+ }
+ QString sel(networkSelect->currentText());
+ removeNetwork(sel);
+}
+
+
+void WpaGui::removeListedNetwork()
+{
+ if (networkList->currentRow() < 0) {
+ QMessageBox::information(this, "Select A Network",
+ "Select a network from the list to"
+ " remove it.\n");
+ return;
+ }
+ QString sel(networkList->currentItem()->text());
+ removeNetwork(sel);
+}
+
+
+void WpaGui::enableAllNetworks()
+{
+ QString sel("all");
+ enableNetwork(sel);
+}
+
+
+void WpaGui::disableAllNetworks()
+{
+ QString sel("all");
+ disableNetwork(sel);
+}
+
+
+void WpaGui::removeAllNetworks()
+{
+ QString sel("all");
+ removeNetwork(sel);
+}
+
+
+int WpaGui::getNetworkDisabled(const QString &sel)
+{
+ QString cmd(sel);
+ char reply[10];
+ size_t reply_len = sizeof(reply) - 1;
+ int pos = cmd.indexOf(':');
+ if (pos < 0) {
+ printf("Invalid getNetworkDisabled '%s'\n",
+ cmd.toAscii().constData());
+ return -1;
+ }
+ cmd.truncate(pos);
+ cmd.prepend("GET_NETWORK ");
+ cmd.append(" disabled");
+
+ if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) >= 0
+ && reply_len >= 1) {
+ reply[reply_len] = '\0';
+ if (!str_match(reply, "FAIL"))
+ return atoi(reply);
+ }
+
+ return -1;
+}
+
+
+void WpaGui::updateNetworkDisabledStatus()
+{
+ if (networkList->currentRow() < 0)
+ return;
+
+ QString sel(networkList->currentItem()->text());
+
+ switch (getNetworkDisabled(sel)) {
+ case 0:
+ if (!enableRadioButton->isChecked())
+ enableRadioButton->setChecked(true);
+ return;
+ case 1:
+ if (!disableRadioButton->isChecked())
+ disableRadioButton->setChecked(true);
+ return;
+ }
+}
+
+
+void WpaGui::enableListedNetwork(bool enabled)
+{
+ if (networkList->currentRow() < 0 || !enabled)
+ return;
+
+ QString sel(networkList->currentItem()->text());
+
+ if (getNetworkDisabled(sel) == 1)
+ enableNetwork(sel);
+}
+
+
+void WpaGui::disableListedNetwork(bool disabled)
+{
+ if (networkList->currentRow() < 0 || !disabled)
+ return;
+
+ QString sel(networkList->currentItem()->text());
+
+ if (getNetworkDisabled(sel) == 0)
+ disableNetwork(sel);
+}
+
+
+void WpaGui::saveConfig()
+{
+ char buf[10];
+ size_t len;
+
+ len = sizeof(buf) - 1;
+ ctrlRequest("SAVE_CONFIG", buf, &len);
+
+ buf[len] = '\0';
+
+ if (str_match(buf, "FAIL"))
+ QMessageBox::warning(this, "Failed to save configuration",
+ "The configuration could not be saved.\n"
+ "\n"
+ "The update_config=1 configuration option\n"
+ "must be used for configuration saving to\n"
+ "be permitted.\n");
+ else
+ QMessageBox::information(this, "Saved configuration",
+ "The current configuration was saved."
+ "\n");
+}
+
+
+void WpaGui::selectAdapter( const QString & sel )
+{
+ if (openCtrlConnection(sel.toAscii().constData()) < 0)
+ printf("Failed to open control connection to "
+ "wpa_supplicant.\n");
+ updateStatus();
+ updateNetworks();
+}
+
+
+void WpaGui::createTrayIcon(bool trayOnly)
+{
+ QApplication::setQuitOnLastWindowClosed(false);
+
+ tray_icon = new QSystemTrayIcon(this);
+ tray_icon->setToolTip(qAppName() + " - wpa_supplicant user interface");
+ if (QImageReader::supportedImageFormats().contains(QByteArray("svg")))
+ tray_icon->setIcon(QIcon(":/icons/wpa_gui.svg"));
+ else
+ tray_icon->setIcon(QIcon(":/icons/wpa_gui.png"));
+
+ connect(tray_icon,
+ SIGNAL(activated(QSystemTrayIcon::ActivationReason)),
+ this, SLOT(trayActivated(QSystemTrayIcon::ActivationReason)));
+
+ ackTrayIcon = false;
+
+ tray_menu = new QMenu(this);
+
+ disconnectAction = new QAction("&Disconnect", this);
+ reconnectAction = new QAction("Re&connect", this);
+ connect(disconnectAction, SIGNAL(triggered()), this,
+ SLOT(disconnect()));
+ connect(reconnectAction, SIGNAL(triggered()), this,
+ SLOT(connectB()));
+ tray_menu->addAction(disconnectAction);
+ tray_menu->addAction(reconnectAction);
+ tray_menu->addSeparator();
+
+ eventAction = new QAction("&Event History", this);
+ scanAction = new QAction("Scan &Results", this);
+ statAction = new QAction("S&tatus", this);
+ connect(eventAction, SIGNAL(triggered()), this, SLOT(eventHistory()));
+ connect(scanAction, SIGNAL(triggered()), this, SLOT(scan()));
+ connect(statAction, SIGNAL(triggered()), this, SLOT(showTrayStatus()));
+ tray_menu->addAction(eventAction);
+ tray_menu->addAction(scanAction);
+ tray_menu->addAction(statAction);
+ tray_menu->addSeparator();
+
+ showAction = new QAction("&Show Window", this);
+ hideAction = new QAction("&Hide Window", this);
+ quitAction = new QAction("&Quit", this);
+ connect(showAction, SIGNAL(triggered()), this, SLOT(show()));
+ connect(hideAction, SIGNAL(triggered()), this, SLOT(hide()));
+ connect(quitAction, SIGNAL(triggered()), qApp, SLOT(quit()));
+ tray_menu->addAction(showAction);
+ tray_menu->addAction(hideAction);
+ tray_menu->addSeparator();
+ tray_menu->addAction(quitAction);
+
+ tray_icon->setContextMenu(tray_menu);
+
+ tray_icon->show();
+
+ if (!trayOnly)
+ show();
+ inTray = trayOnly;
+}
+
+
+void WpaGui::showTrayMessage(QSystemTrayIcon::MessageIcon type, int sec,
+ const QString & msg)
+{
+ if (!QSystemTrayIcon::supportsMessages())
+ return;
+
+ if (isVisible() || !tray_icon || !tray_icon->isVisible())
+ return;
+
+ tray_icon->showMessage(qAppName(), msg, type, sec * 1000);
+}
+
+
+void WpaGui::trayActivated(QSystemTrayIcon::ActivationReason how)
+ {
+ switch (how) {
+ /* use close() here instead of hide() and allow the
+ * custom closeEvent handler take care of children */
+ case QSystemTrayIcon::Trigger:
+ ackTrayIcon = true;
+ if (isVisible()) {
+ close();
+ inTray = true;
+ } else {
+ show();
+ inTray = false;
+ }
+ break;
+ case QSystemTrayIcon::MiddleClick:
+ showTrayStatus();
+ break;
+ default:
+ break;
+ }
+}
+
+
+void WpaGui::showTrayStatus()
+{
+ char buf[2048];
+ size_t len;
+
+ len = sizeof(buf) - 1;
+ if (ctrlRequest("STATUS", buf, &len) < 0)
+ return;
+ buf[len] = '\0';
+
+ QString msg, status(buf);
+
+ QStringList lines = status.split(QRegExp("\\n"));
+ for (QStringList::Iterator it = lines.begin();
+ it != lines.end(); it++) {
+ int pos = (*it).indexOf('=') + 1;
+ if (pos < 1)
+ continue;
+
+ if ((*it).startsWith("bssid="))
+ msg.append("BSSID:\t" + (*it).mid(pos) + "\n");
+ else if ((*it).startsWith("ssid="))
+ msg.append("SSID: \t" + (*it).mid(pos) + "\n");
+ else if ((*it).startsWith("pairwise_cipher="))
+ msg.append("PAIR: \t" + (*it).mid(pos) + "\n");
+ else if ((*it).startsWith("group_cipher="))
+ msg.append("GROUP:\t" + (*it).mid(pos) + "\n");
+ else if ((*it).startsWith("key_mgmt="))
+ msg.append("AUTH: \t" + (*it).mid(pos) + "\n");
+ else if ((*it).startsWith("wpa_state="))
+ msg.append("STATE:\t" + (*it).mid(pos) + "\n");
+ else if ((*it).startsWith("ip_address="))
+ msg.append("IP: \t" + (*it).mid(pos) + "\n");
+ else if ((*it).startsWith("Supplicant PAE state="))
+ msg.append("PAE: \t" + (*it).mid(pos) + "\n");
+ else if ((*it).startsWith("EAP state="))
+ msg.append("EAP: \t" + (*it).mid(pos) + "\n");
+ }
+
+ if (!msg.isEmpty())
+ showTrayMessage(QSystemTrayIcon::Information, 10, msg);
+}
+
+
+void WpaGui::closeEvent(QCloseEvent *event)
+{
+ if (eh) {
+ eh->close();
+ delete eh;
+ eh = NULL;
+ }
+
+ if (scanres) {
+ scanres->close();
+ delete scanres;
+ scanres = NULL;
+ }
+
+ if (udr) {
+ udr->close();
+ delete udr;
+ udr = NULL;
+ }
+
+ if (tray_icon && !ackTrayIcon) {
+ /* give user a visual hint that the tray icon exists */
+ if (QSystemTrayIcon::supportsMessages()) {
+ hide();
+ showTrayMessage(QSystemTrayIcon::Information, 3,
+ qAppName() + " will keep running in "
+ "the system tray.");
+ } else {
+ QMessageBox::information(this, qAppName() + " systray",
+ "The program will keep "
+ "running in the system "
+ "tray.");
+ }
+ ackTrayIcon = true;
+ }
+
+ event->accept();
+}
+
+
+void WpaGui::wpsDialog()
+{
+ wpaguiTab->setCurrentWidget(wpsTab);
+}
+
+
+void WpaGui::tabChanged(int index)
+{
+ if (index != 2)
+ return;
+
+ if (wpsRunning)
+ return;
+
+ wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
+ if (bssFromScan.isEmpty())
+ wpsApPinButton->setEnabled(false);
+}
+
+
+void WpaGui::wpsPbc()
+{
+ char reply[20];
+ size_t reply_len = sizeof(reply);
+
+ if (ctrlRequest("WPS_PBC", reply, &reply_len) < 0)
+ return;
+
+ wpsPinEdit->setEnabled(false);
+ if (wpsStatusText->text().compare("WPS AP in active PBC mode found")) {
+ wpsInstructions->setText("Press the push button on the AP to "
+ "start the PBC mode.");
+ } else {
+ wpsInstructions->setText("If you have not yet done so, press "
+ "the push button on the AP to start "
+ "the PBC mode.");
+ }
+ wpsStatusText->setText("Waiting for Registrar");
+ wpsRunning = true;
+}
+
+
+void WpaGui::wpsGeneratePin()
+{
+ char reply[20];
+ size_t reply_len = sizeof(reply) - 1;
+
+ if (ctrlRequest("WPS_PIN any", reply, &reply_len) < 0)
+ return;
+
+ reply[reply_len] = '\0';
+
+ wpsPinEdit->setText(reply);
+ wpsPinEdit->setEnabled(true);
+ wpsInstructions->setText("Enter the generated PIN into the Registrar "
+ "(either the internal one in the AP or an "
+ "external one).");
+ wpsStatusText->setText("Waiting for Registrar");
+ wpsRunning = true;
+}
+
+
+void WpaGui::setBssFromScan(const QString &bssid)
+{
+ bssFromScan = bssid;
+ wpsApPinEdit->setEnabled(!bssFromScan.isEmpty());
+ wpsApPinButton->setEnabled(wpsApPinEdit->text().length() == 8);
+ wpsStatusText->setText("WPS AP selected from scan results");
+ wpsInstructions->setText("If you want to use an AP device PIN, e.g., "
+ "from a label in the device, enter the eight "
+ "digit AP PIN and click Use AP PIN button.");
+}
+
+
+void WpaGui::wpsApPinChanged(const QString &text)
+{
+ wpsApPinButton->setEnabled(text.length() == 8);
+}
+
+
+void WpaGui::wpsApPin()
+{
+ char reply[20];
+ size_t reply_len = sizeof(reply);
+
+ QString cmd("WPS_REG " + bssFromScan + " " + wpsApPinEdit->text());
+ if (ctrlRequest(cmd.toAscii().constData(), reply, &reply_len) < 0)
+ return;
+
+ wpsStatusText->setText("Waiting for AP/Enrollee");
+ wpsRunning = true;
+}
+
+
+void WpaGui::stopWpsRun(bool success)
+{
+ if (wpsRunning)
+ wpsStatusText->setText(success ? "Connected to the network" :
+ "Stopped");
+ else
+ wpsStatusText->setText("");
+ wpsPinEdit->setEnabled(false);
+ wpsInstructions->setText("");
+ wpsRunning = false;
+ bssFromScan = "";
+ wpsApPinEdit->setEnabled(false);
+ wpsApPinButton->setEnabled(false);
+}
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+
+#ifndef WPASVC_NAME
+#define WPASVC_NAME TEXT("wpasvc")
+#endif
+
+class ErrorMsg : public QMessageBox {
+public:
+ ErrorMsg(QWidget *parent, DWORD last_err = GetLastError());
+ void showMsg(QString msg);
+private:
+ DWORD err;
+};
+
+ErrorMsg::ErrorMsg(QWidget *parent, DWORD last_err) :
+ QMessageBox(parent), err(last_err)
+{
+ setWindowTitle("wpa_gui error");
+ setIcon(QMessageBox::Warning);
+}
+
+void ErrorMsg::showMsg(QString msg)
+{
+ LPTSTR buf;
+
+ setText(msg);
+ if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, err, 0, (LPTSTR) (void *) &buf,
+ 0, NULL) > 0) {
+ QString msg = QString::fromWCharArray(buf);
+ setInformativeText(QString("[%1] %2").arg(err).arg(msg));
+ LocalFree(buf);
+ } else {
+ setInformativeText(QString("[%1]").arg(err));
+ }
+
+ exec();
+}
+
+
+void WpaGui::startService()
+{
+ SC_HANDLE svc, scm;
+
+ scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
+ if (!scm) {
+ ErrorMsg(this).showMsg("OpenSCManager failed");
+ return;
+ }
+
+ svc = OpenService(scm, WPASVC_NAME, SERVICE_START);
+ if (!svc) {
+ ErrorMsg(this).showMsg("OpenService failed");
+ CloseServiceHandle(scm);
+ return;
+ }
+
+ if (!StartService(svc, 0, NULL)) {
+ ErrorMsg(this).showMsg("Failed to start wpa_supplicant "
+ "service");
+ }
+
+ CloseServiceHandle(svc);
+ CloseServiceHandle(scm);
+}
+
+
+void WpaGui::stopService()
+{
+ SC_HANDLE svc, scm;
+ SERVICE_STATUS status;
+
+ scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
+ if (!scm) {
+ ErrorMsg(this).showMsg("OpenSCManager failed");
+ return;
+ }
+
+ svc = OpenService(scm, WPASVC_NAME, SERVICE_STOP);
+ if (!svc) {
+ ErrorMsg(this).showMsg("OpenService failed");
+ CloseServiceHandle(scm);
+ return;
+ }
+
+ if (!ControlService(svc, SERVICE_CONTROL_STOP, &status)) {
+ ErrorMsg(this).showMsg("Failed to stop wpa_supplicant "
+ "service");
+ }
+
+ CloseServiceHandle(svc);
+ CloseServiceHandle(scm);
+}
+
+
+bool WpaGui::serviceRunning()
+{
+ SC_HANDLE svc, scm;
+ SERVICE_STATUS status;
+ bool running = false;
+
+ scm = OpenSCManager(0, 0, SC_MANAGER_CONNECT);
+ if (!scm) {
+ printf("OpenSCManager failed: %d\n", (int) GetLastError());
+ return false;
+ }
+
+ svc = OpenService(scm, WPASVC_NAME, SERVICE_QUERY_STATUS);
+ if (!svc) {
+ printf("OpenService failed: %d\n\n", (int) GetLastError());
+ CloseServiceHandle(scm);
+ return false;
+ }
+
+ if (QueryServiceStatus(svc, &status)) {
+ if (status.dwCurrentState != SERVICE_STOPPED)
+ running = true;
+ }
+
+ CloseServiceHandle(svc);
+ CloseServiceHandle(scm);
+
+ return running;
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+void WpaGui::addInterface()
+{
+ if (add_iface) {
+ add_iface->close();
+ delete add_iface;
+ }
+ add_iface = new AddInterface(this, this);
+ add_iface->show();
+ add_iface->exec();
+}
+
+
+#ifndef QT_NO_SESSIONMANAGER
+void WpaGui::saveState()
+{
+ QSettings settings("wpa_supplicant", "wpa_gui");
+ settings.beginGroup("state");
+ settings.setValue("session_id", app->sessionId());
+ settings.setValue("in_tray", inTray);
+ settings.endGroup();
+}
+#endif
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.h b/wpa_supplicant/wpa_gui-qt4/wpagui.h
new file mode 100644
index 0000000..741cf17
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.h
@@ -0,0 +1,147 @@
+/*
+ * wpa_gui - WpaGui class
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef WPAGUI_H
+#define WPAGUI_H
+
+#include <QSystemTrayIcon>
+#include <QObject>
+#include "ui_wpagui.h"
+#include "addinterface.h"
+
+class UserDataRequest;
+
+
+class WpaGui : public QMainWindow, public Ui::WpaGui
+{
+ Q_OBJECT
+
+public:
+ WpaGui(QApplication *app, QWidget *parent = 0, const char *name = 0,
+ Qt::WFlags fl = 0);
+ ~WpaGui();
+
+ virtual int ctrlRequest(const char *cmd, char *buf, size_t *buflen);
+ virtual void triggerUpdate();
+ virtual void editNetwork(const QString &sel);
+ virtual void removeNetwork(const QString &sel);
+ virtual void enableNetwork(const QString &sel);
+ virtual void disableNetwork(const QString &sel);
+ virtual int getNetworkDisabled(const QString &sel);
+ void setBssFromScan(const QString &bssid);
+#ifndef QT_NO_SESSIONMANAGER
+ void saveState();
+#endif
+
+public slots:
+ virtual void parse_argv();
+ virtual void updateStatus();
+ virtual void updateNetworks();
+ virtual void helpIndex();
+ virtual void helpContents();
+ virtual void helpAbout();
+ virtual void disconnect();
+ virtual void scan();
+ virtual void eventHistory();
+ virtual void ping();
+ virtual void processMsg(char *msg);
+ virtual void processCtrlReq(const char *req);
+ virtual void receiveMsgs();
+ virtual void connectB();
+ virtual void selectNetwork(const QString &sel);
+ virtual void editSelectedNetwork();
+ virtual void editListedNetwork();
+ virtual void removeSelectedNetwork();
+ virtual void removeListedNetwork();
+ virtual void addNetwork();
+ virtual void enableAllNetworks();
+ virtual void disableAllNetworks();
+ virtual void removeAllNetworks();
+ virtual void saveConfig();
+ virtual void selectAdapter(const QString &sel);
+ virtual void updateNetworkDisabledStatus();
+ virtual void enableListedNetwork(bool);
+ virtual void disableListedNetwork(bool);
+ virtual void showTrayMessage(QSystemTrayIcon::MessageIcon type,
+ int sec, const QString &msg);
+ virtual void showTrayStatus();
+ virtual void wpsDialog();
+ virtual void tabChanged(int index);
+ virtual void wpsPbc();
+ virtual void wpsGeneratePin();
+ virtual void wpsApPinChanged(const QString &text);
+ virtual void wpsApPin();
+#ifdef CONFIG_NATIVE_WINDOWS
+ virtual void startService();
+ virtual void stopService();
+#endif /* CONFIG_NATIVE_WINDOWS */
+ virtual void addInterface();
+
+protected slots:
+ virtual void languageChange();
+ virtual void trayActivated(QSystemTrayIcon::ActivationReason how);
+ virtual void closeEvent(QCloseEvent *event);
+
+private:
+ ScanResults *scanres;
+ bool networkMayHaveChanged;
+ char *ctrl_iface;
+ EventHistory *eh;
+ struct wpa_ctrl *ctrl_conn;
+ QSocketNotifier *msgNotifier;
+ QTimer *timer;
+ int pingsToStatusUpdate;
+ WpaMsgList msgs;
+ char *ctrl_iface_dir;
+ struct wpa_ctrl *monitor_conn;
+ UserDataRequest *udr;
+ QAction *disconnectAction;
+ QAction *reconnectAction;
+ QAction *eventAction;
+ QAction *scanAction;
+ QAction *statAction;
+ QAction *showAction;
+ QAction *hideAction;
+ QAction *quitAction;
+ QMenu *tray_menu;
+ QSystemTrayIcon *tray_icon;
+ void createTrayIcon(bool);
+ bool ackTrayIcon;
+ bool startInTray;
+
+ int openCtrlConnection(const char *ifname);
+
+ bool wpsRunning;
+
+ QString bssFromScan;
+
+ void stopWpsRun(bool success);
+
+#ifdef CONFIG_NATIVE_WINDOWS
+ QAction *fileStartServiceAction;
+ QAction *fileStopServiceAction;
+
+ bool serviceRunning();
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ QAction *addInterfaceAction;
+ AddInterface *add_iface;
+
+ bool connectedToService;
+
+ QApplication *app;
+ bool inTray;
+};
+
+#endif /* WPAGUI_H */
diff --git a/wpa_supplicant/wpa_gui-qt4/wpagui.ui b/wpa_supplicant/wpa_gui-qt4/wpagui.ui
new file mode 100644
index 0000000..cd67ecb
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/wpagui.ui
@@ -0,0 +1,517 @@
+<ui version="4.0" >
+ <class>WpaGui</class>
+ <widget class="QMainWindow" name="WpaGui" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>345</width>
+ <height>330</height>
+ </rect>
+ </property>
+ <property name="windowTitle" >
+ <string>wpa_gui</string>
+ </property>
+ <property name="windowIcon" >
+ <iconset resource="icons.qrc" >
+ <normaloff>:/icons/wpa_gui.svg</normaloff>:/icons/wpa_gui.svg</iconset>
+ </property>
+ <widget class="QWidget" name="widget" >
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="adapterLabel" >
+ <property name="text" >
+ <string>Adapter:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QComboBox" name="adapterSelect" />
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="networkLabel" >
+ <property name="text" >
+ <string>Network:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QComboBox" name="networkSelect" />
+ </item>
+ <item row="2" column="0" colspan="2" >
+ <widget class="QTabWidget" name="wpaguiTab" >
+ <property name="currentIndex" >
+ <number>0</number>
+ </property>
+ <widget class="QWidget" name="statusTab" >
+ <attribute name="title" >
+ <string>Current Status</string>
+ </attribute>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" colspan="5" >
+ <widget class="QFrame" name="frame3" >
+ <property name="frameShape" >
+ <enum>QFrame::NoFrame</enum>
+ </property>
+ <property name="frameShadow" >
+ <enum>QFrame::Plain</enum>
+ </property>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="statusLabel" >
+ <property name="text" >
+ <string>Status:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <widget class="QLabel" name="lastMessageLabel" >
+ <property name="text" >
+ <string>Last message:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" >
+ <widget class="QLabel" name="authenticationLabel" >
+ <property name="text" >
+ <string>Authentication:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" >
+ <widget class="QLabel" name="encryptionLabel" >
+ <property name="text" >
+ <string>Encryption:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" >
+ <widget class="QLabel" name="ssidLabel" >
+ <property name="text" >
+ <string>SSID:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="0" >
+ <widget class="QLabel" name="bssidLabel" >
+ <property name="text" >
+ <string>BSSID:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="0" >
+ <widget class="QLabel" name="ipAddressLabel" >
+ <property name="text" >
+ <string>IP address:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" >
+ <widget class="QLabel" name="textStatus" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1" colspan="3" >
+ <widget class="QLabel" name="textLastMessage" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QLabel" name="textAuthentication" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="1" >
+ <widget class="QLabel" name="textEncryption" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1" >
+ <widget class="QLabel" name="textSsid" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="5" column="1" >
+ <widget class="QLabel" name="textBssid" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="6" column="1" >
+ <widget class="QLabel" name="textIpAddress" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item row="1" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QPushButton" name="connectButton" >
+ <property name="text" >
+ <string>Connect</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QPushButton" name="disconnectButton" >
+ <property name="text" >
+ <string>Disconnect</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3" >
+ <widget class="QPushButton" name="scanButton" >
+ <property name="text" >
+ <string>Scan</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="4" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="networkconfigTab" >
+ <attribute name="title" >
+ <string>Manage Networks</string>
+ </attribute>
+ <layout class="QGridLayout" >
+ <item row="0" column="0" colspan="5" >
+ <widget class="QListWidget" name="networkList" >
+ <property name="selectionRectVisible" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item rowspan="2" row="1" column="0" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>61</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="1" column="1" >
+ <widget class="QRadioButton" name="enableRadioButton" >
+ <property name="text" >
+ <string>Enabled</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="2" >
+ <widget class="QPushButton" name="editNetworkButton" >
+ <property name="text" >
+ <string>Edit</string>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="3" >
+ <widget class="QPushButton" name="removeNetworkButton" >
+ <property name="text" >
+ <string>Remove</string>
+ </property>
+ </widget>
+ </item>
+ <item rowspan="2" row="1" column="4" >
+ <spacer>
+ <property name="orientation" >
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" >
+ <size>
+ <width>20</width>
+ <height>61</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ <item row="2" column="1" >
+ <widget class="QRadioButton" name="disableRadioButton" >
+ <property name="text" >
+ <string>Disabled</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2" >
+ <widget class="QPushButton" name="addNetworkButton" >
+ <property name="text" >
+ <string>Add</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="3" >
+ <widget class="QPushButton" name="scanNetworkButton" >
+ <property name="text" >
+ <string>Scan</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QWidget" name="wpsTab" >
+ <attribute name="title" >
+ <string>WPS</string>
+ </attribute>
+ <layout class="QGridLayout" name="wpsGridLayout" >
+ <item row="0" column="0" >
+ <widget class="QLabel" name="label_2" >
+ <property name="text" >
+ <string>Status:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1" colspan="3" >
+ <widget class="QLabel" name="wpsStatusText" >
+ <property name="text" >
+ <string/>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0" colspan="2" >
+ <widget class="QPushButton" name="wpsPbcButton" >
+ <property name="text" >
+ <string>PBC - push button</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="0" colspan="2" >
+ <widget class="QPushButton" name="wpsPinButton" >
+ <property name="text" >
+ <string>Generate PIN</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="2" >
+ <widget class="QLabel" name="label" >
+ <property name="text" >
+ <string>PIN:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="3" >
+ <widget class="QLineEdit" name="wpsPinEdit" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2" >
+ <widget class="QPushButton" name="wpsApPinButton" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>Use AP PIN</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="2" >
+ <widget class="QLabel" name="label_3" >
+ <property name="text" >
+ <string>AP PIN:</string>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="3" >
+ <widget class="QLineEdit" name="wpsApPinEdit" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="0" colspan="4" >
+ <widget class="QTextEdit" name="wpsInstructions" >
+ <property name="readOnly" >
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <widget class="QMenuBar" name="MenuBar" >
+ <property name="geometry" >
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>345</width>
+ <height>24</height>
+ </rect>
+ </property>
+ <widget class="QMenu" name="fileMenu" >
+ <property name="title" >
+ <string>&amp;File</string>
+ </property>
+ <addaction name="fileEventHistoryAction" />
+ <addaction name="fileSaveConfigAction" />
+ <addaction name="actionWPS" />
+ <addaction name="separator" />
+ <addaction name="fileExitAction" />
+ </widget>
+ <widget class="QMenu" name="networkMenu" >
+ <property name="title" >
+ <string>&amp;Network</string>
+ </property>
+ <addaction name="networkAddAction" />
+ <addaction name="networkEditAction" />
+ <addaction name="networkRemoveAction" />
+ <addaction name="separator" />
+ <addaction name="networkEnableAllAction" />
+ <addaction name="networkDisableAllAction" />
+ <addaction name="networkRemoveAllAction" />
+ </widget>
+ <widget class="QMenu" name="helpMenu" >
+ <property name="title" >
+ <string>&amp;Help</string>
+ </property>
+ <addaction name="helpContentsAction" />
+ <addaction name="helpIndexAction" />
+ <addaction name="separator" />
+ <addaction name="helpAboutAction" />
+ </widget>
+ <addaction name="fileMenu" />
+ <addaction name="networkMenu" />
+ <addaction name="helpMenu" />
+ </widget>
+ <action name="fileEventHistoryAction" >
+ <property name="text" >
+ <string>Event &amp;History</string>
+ </property>
+ </action>
+ <action name="fileSaveConfigAction" >
+ <property name="text" >
+ <string>&amp;Save Configuration</string>
+ </property>
+ <property name="shortcut" >
+ <string>Ctrl+S</string>
+ </property>
+ </action>
+ <action name="fileExitAction" >
+ <property name="text" >
+ <string>E&amp;xit</string>
+ </property>
+ <property name="shortcut" >
+ <string>Ctrl+Q</string>
+ </property>
+ </action>
+ <action name="networkAddAction" >
+ <property name="text" >
+ <string>&amp;Add</string>
+ </property>
+ </action>
+ <action name="networkEditAction" >
+ <property name="text" >
+ <string>&amp;Edit</string>
+ </property>
+ </action>
+ <action name="networkRemoveAction" >
+ <property name="text" >
+ <string>&amp;Remove</string>
+ </property>
+ </action>
+ <action name="networkEnableAllAction" >
+ <property name="text" >
+ <string>E&amp;nable All</string>
+ </property>
+ </action>
+ <action name="networkDisableAllAction" >
+ <property name="text" >
+ <string>&amp;Disable All</string>
+ </property>
+ </action>
+ <action name="networkRemoveAllAction" >
+ <property name="text" >
+ <string>Re&amp;move All</string>
+ </property>
+ </action>
+ <action name="helpContentsAction" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>&amp;Contents...</string>
+ </property>
+ </action>
+ <action name="helpIndexAction" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>&amp;Index...</string>
+ </property>
+ </action>
+ <action name="helpAboutAction" >
+ <property name="text" >
+ <string>&amp;About</string>
+ </property>
+ </action>
+ <action name="actionWPS" >
+ <property name="enabled" >
+ <bool>false</bool>
+ </property>
+ <property name="text" >
+ <string>&amp;Wi-Fi Protected Setup</string>
+ </property>
+ </action>
+ </widget>
+ <layoutdefault spacing="6" margin="11" />
+ <pixmapfunction></pixmapfunction>
+ <includes>
+ <include location="global" >qtimer.h</include>
+ <include location="global" >qsocketnotifier.h</include>
+ <include location="local" >wpamsg.h</include>
+ <include location="local" >eventhistory.h</include>
+ <include location="local" >scanresults.h</include>
+ </includes>
+ <resources>
+ <include location="icons.qrc" />
+ </resources>
+ <connections/>
+</ui>
diff --git a/wpa_supplicant/wpa_gui-qt4/wpamsg.h b/wpa_supplicant/wpa_gui-qt4/wpamsg.h
new file mode 100644
index 0000000..4950b21
--- /dev/null
+++ b/wpa_supplicant/wpa_gui-qt4/wpamsg.h
@@ -0,0 +1,41 @@
+/*
+ * wpa_gui - WpaMsg class for storing event messages
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef WPAMSG_H
+#define WPAMSG_H
+
+#include <QDateTime>
+#include <QLinkedList>
+
+class WpaMsg {
+public:
+ WpaMsg(const QString &_msg, int _priority = 2)
+ : msg(_msg), priority(_priority)
+ {
+ timestamp = QDateTime::currentDateTime();
+ }
+
+ QString getMsg() const { return msg; }
+ int getPriority() const { return priority; }
+ QDateTime getTimestamp() const { return timestamp; }
+
+private:
+ QString msg;
+ int priority;
+ QDateTime timestamp;
+};
+
+typedef QLinkedList<WpaMsg> WpaMsgList;
+
+#endif /* WPAMSG_H */
diff --git a/wpa_supplicant/wpa_gui/eventhistory.ui b/wpa_supplicant/wpa_gui/eventhistory.ui
new file mode 100644
index 0000000..3735fb7
--- /dev/null
+++ b/wpa_supplicant/wpa_gui/eventhistory.ui
@@ -0,0 +1,125 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>EventHistory</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>EventHistory</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>533</width>
+ <height>285</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Event history</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>Timestamp</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Message</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>eventListView</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>7</hsizetype>
+ <vsizetype>7</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="resizePolicy">
+ <enum>Manual</enum>
+ </property>
+ <property name="selectionMode">
+ <enum>NoSelection</enum>
+ </property>
+ <property name="resizeMode">
+ <enum>LastColumn</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout30</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer3</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>closeButton</cstring>
+ </property>
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>closeButton</sender>
+ <signal>clicked()</signal>
+ <receiver>EventHistory</receiver>
+ <slot>close()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in declaration">wpamsg.h</include>
+ <include location="local" impldecl="in implementation">eventhistory.ui.h</include>
+</includes>
+<slots>
+ <slot>addEvents( WpaMsgList msgs )</slot>
+ <slot>addEvent( WpaMsg msg )</slot>
+</slots>
+<functions>
+ <function access="private" specifier="non virtual">init()</function>
+ <function access="private" specifier="non virtual">destroy()</function>
+</functions>
+<pixmapinproject/>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/wpa_supplicant/wpa_gui/eventhistory.ui.h b/wpa_supplicant/wpa_gui/eventhistory.ui.h
new file mode 100644
index 0000000..cb2caab
--- /dev/null
+++ b/wpa_supplicant/wpa_gui/eventhistory.ui.h
@@ -0,0 +1,41 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+void EventHistory::init()
+{
+}
+
+
+void EventHistory::destroy()
+{
+}
+
+
+void EventHistory::addEvents(WpaMsgList msgs)
+{
+ WpaMsgList::iterator it;
+ for (it = msgs.begin(); it != msgs.end(); it++) {
+ addEvent(*it);
+ }
+}
+
+
+void EventHistory::addEvent(WpaMsg msg)
+{
+ Q3ListViewItem *item;
+ item = new Q3ListViewItem(eventListView,
+ msg.getTimestamp().toString("yyyy-MM-dd hh:mm:ss.zzz"),
+ msg.getMsg());
+ if (item == NULL)
+ return;
+ eventListView->setSelected(item, false);
+}
diff --git a/wpa_supplicant/wpa_gui/main.cpp b/wpa_supplicant/wpa_gui/main.cpp
new file mode 100644
index 0000000..a78473a
--- /dev/null
+++ b/wpa_supplicant/wpa_gui/main.cpp
@@ -0,0 +1,30 @@
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+#include <qapplication.h>
+#include "wpagui.h"
+
+int main( int argc, char ** argv )
+{
+ QApplication a( argc, argv );
+ WpaGui w;
+ int ret;
+
+#ifdef CONFIG_NATIVE_WINDOWS
+ WSADATA wsaData;
+ if (WSAStartup(MAKEWORD(2, 0), &wsaData)) {
+ printf("Could not find a usable WinSock.dll\n");
+ return -1;
+ }
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ w.show();
+ a.connect( &a, SIGNAL( lastWindowClosed() ), &a, SLOT( quit() ) );
+ ret = a.exec();
+
+#ifdef CONFIG_NATIVE_WINDOWS
+ WSACleanup();
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+ return ret;
+}
diff --git a/wpa_supplicant/wpa_gui/networkconfig.ui b/wpa_supplicant/wpa_gui/networkconfig.ui
new file mode 100644
index 0000000..019ecf7
--- /dev/null
+++ b/wpa_supplicant/wpa_gui/networkconfig.ui
@@ -0,0 +1,475 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>NetworkConfig</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>NetworkConfig</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>380</width>
+ <height>430</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>NetworkConfig</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QPushButton" row="1" column="3">
+ <property name="name">
+ <cstring>cancelButton</cstring>
+ </property>
+ <property name="text">
+ <string>Cancel</string>
+ </property>
+ </widget>
+ <widget class="QFrame" row="0" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>frame9</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel0</cstring>
+ </property>
+ <property name="text">
+ <string>SSID</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>ssidEdit</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Network name (Service Set IDentifier)</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Network ID</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>idstrEdit</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Network Identification String</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Authentication</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="2" column="1">
+ <item>
+ <property name="text">
+ <string>Plaintext or static WEP</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>IEEE 802.1X</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>WPA-Personal (PSK)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>WPA-Enterprise (EAP)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>WPA2-Personal (PSK)</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>WPA2-Enterprise (EAP)</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>authSelect</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Encryption</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="3" column="1">
+ <item>
+ <property name="text">
+ <string>None</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>WEP</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>TKIP</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>CCMP</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>encrSelect</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>PSK</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="4" column="1">
+ <property name="name">
+ <cstring>pskEdit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="echoMode">
+ <enum>Password</enum>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>WPA/WPA2 pre-shared key or passphrase</string>
+ </property>
+ <property name="whatsThis" stdset="0">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>EAP method</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="5" column="1">
+ <property name="name">
+ <cstring>eapSelect</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="0">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>Identity</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="6" column="1">
+ <property name="name">
+ <cstring>identityEdit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Username/Identity for EAP methods</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="7" column="0">
+ <property name="name">
+ <cstring>textLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>Password</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="7" column="1">
+ <property name="name">
+ <cstring>passwordEdit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="echoMode">
+ <enum>Password</enum>
+ </property>
+ <property name="toolTip" stdset="0">
+ <string>Password for EAP methods</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="8" column="0">
+ <property name="name">
+ <cstring>textLabel1_2</cstring>
+ </property>
+ <property name="text">
+ <string>CA certificate</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="8" column="1">
+ <property name="name">
+ <cstring>cacertEdit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QButtonGroup" row="9" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>buttonGroup1</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="title">
+ <string>WEP keys</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QRadioButton" row="0" column="0">
+ <property name="name">
+ <cstring>wep0Radio</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>key 0</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="1" column="0">
+ <property name="name">
+ <cstring>wep1Radio</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>key 1</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="3" column="0">
+ <property name="name">
+ <cstring>wep3Radio</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>key 3</string>
+ </property>
+ </widget>
+ <widget class="QRadioButton" row="2" column="0">
+ <property name="name">
+ <cstring>wep2Radio</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>key 2</string>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="0" column="1">
+ <property name="name">
+ <cstring>wep0Edit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="1" column="1">
+ <property name="name">
+ <cstring>wep1Edit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="2" column="1">
+ <property name="name">
+ <cstring>wep2Edit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ <widget class="QLineEdit" row="3" column="1">
+ <property name="name">
+ <cstring>wep3Edit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="1" column="0">
+ <property name="name">
+ <cstring>spacer5</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>130</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton" row="1" column="1">
+ <property name="name">
+ <cstring>addButton</cstring>
+ </property>
+ <property name="text">
+ <string>Add</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="1" column="2">
+ <property name="name">
+ <cstring>removeButton</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Remove</string>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>authSelect</sender>
+ <signal>activated(int)</signal>
+ <receiver>NetworkConfig</receiver>
+ <slot>authChanged(int)</slot>
+ </connection>
+ <connection>
+ <sender>cancelButton</sender>
+ <signal>clicked()</signal>
+ <receiver>NetworkConfig</receiver>
+ <slot>close()</slot>
+ </connection>
+ <connection>
+ <sender>addButton</sender>
+ <signal>clicked()</signal>
+ <receiver>NetworkConfig</receiver>
+ <slot>addNetwork()</slot>
+ </connection>
+ <connection>
+ <sender>encrSelect</sender>
+ <signal>activated(const QString&amp;)</signal>
+ <receiver>NetworkConfig</receiver>
+ <slot>encrChanged(const QString&amp;)</slot>
+ </connection>
+ <connection>
+ <sender>removeButton</sender>
+ <signal>clicked()</signal>
+ <receiver>NetworkConfig</receiver>
+ <slot>removeNetwork()</slot>
+ </connection>
+</connections>
+<tabstops>
+ <tabstop>ssidEdit</tabstop>
+ <tabstop>idstrEdit</tabstop>
+ <tabstop>authSelect</tabstop>
+ <tabstop>encrSelect</tabstop>
+ <tabstop>pskEdit</tabstop>
+ <tabstop>eapSelect</tabstop>
+ <tabstop>identityEdit</tabstop>
+ <tabstop>passwordEdit</tabstop>
+ <tabstop>cacertEdit</tabstop>
+ <tabstop>wep0Radio</tabstop>
+ <tabstop>wep1Radio</tabstop>
+ <tabstop>wep2Radio</tabstop>
+ <tabstop>wep3Radio</tabstop>
+ <tabstop>wep0Edit</tabstop>
+ <tabstop>wep1Edit</tabstop>
+ <tabstop>wep2Edit</tabstop>
+ <tabstop>wep3Edit</tabstop>
+ <tabstop>addButton</tabstop>
+ <tabstop>removeButton</tabstop>
+ <tabstop>cancelButton</tabstop>
+</tabstops>
+<includes>
+ <include location="global" impldecl="in declaration">qlistview.h</include>
+ <include location="global" impldecl="in implementation">qmessagebox.h</include>
+ <include location="local" impldecl="in implementation">wpagui.h</include>
+ <include location="local" impldecl="in implementation">networkconfig.ui.h</include>
+</includes>
+<forwards>
+ <forward>class WpaGui;</forward>
+</forwards>
+<variables>
+ <variable access="private">WpaGui *wpagui;</variable>
+ <variable access="private">int edit_network_id;</variable>
+ <variable access="private">bool new_network;</variable>
+</variables>
+<slots>
+ <slot>authChanged( int sel )</slot>
+ <slot>addNetwork()</slot>
+ <slot>encrChanged( const QString &amp; sel )</slot>
+ <slot>writeWepKey( int network_id, QLineEdit * edit, int id )</slot>
+ <slot>removeNetwork()</slot>
+</slots>
+<functions>
+ <function access="private" specifier="non virtual">init()</function>
+ <function>paramsFromScanResults( QListViewItem * sel )</function>
+ <function>setWpaGui( WpaGui * _wpagui )</function>
+ <function returnType="int">setNetworkParam( int id, const char * field, const char * value, bool quote )</function>
+ <function access="private">wepEnabled( bool enabled )</function>
+ <function>paramsFromConfig( int network_id )</function>
+ <function>newNetwork()</function>
+ <function access="private">getEapCapa()</function>
+</functions>
+<pixmapinproject/>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/wpa_supplicant/wpa_gui/networkconfig.ui.h b/wpa_supplicant/wpa_gui/networkconfig.ui.h
new file mode 100644
index 0000000..501d5d2
--- /dev/null
+++ b/wpa_supplicant/wpa_gui/networkconfig.ui.h
@@ -0,0 +1,552 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+#include <stdlib.h>
+
+enum {
+ AUTH_NONE = 0,
+ AUTH_IEEE8021X = 1,
+ AUTH_WPA_PSK = 2,
+ AUTH_WPA_EAP = 3,
+ AUTH_WPA2_PSK = 4,
+ AUTH_WPA2_EAP = 5
+};
+
+#define WPA_GUI_KEY_DATA "[key is configured]"
+
+void NetworkConfig::init()
+{
+ wpagui = NULL;
+ new_network = false;
+}
+
+void NetworkConfig::paramsFromScanResults(Q3ListViewItem *sel)
+{
+ new_network = true;
+
+ /* SSID BSSID frequency signal flags */
+ setCaption(sel->text(0));
+ ssidEdit->setText(sel->text(0));
+
+ QString flags = sel->text(4);
+ int auth, encr = 0;
+ if (flags.find("[WPA2-EAP") >= 0)
+ auth = AUTH_WPA2_EAP;
+ else if (flags.find("[WPA-EAP") >= 0)
+ auth = AUTH_WPA_EAP;
+ else if (flags.find("[WPA2-PSK") >= 0)
+ auth = AUTH_WPA2_PSK;
+ else if (flags.find("[WPA-PSK") >= 0)
+ auth = AUTH_WPA_PSK;
+ else
+ auth = AUTH_NONE;
+
+ if (flags.find("-CCMP") >= 0)
+ encr = 1;
+ else if (flags.find("-TKIP") >= 0)
+ encr = 0;
+ else if (flags.find("WEP") >= 0)
+ encr = 1;
+ else
+ encr = 0;
+
+ authSelect->setCurrentItem(auth);
+ authChanged(auth);
+ encrSelect->setCurrentItem(encr);
+
+ getEapCapa();
+}
+
+
+void NetworkConfig::authChanged(int sel)
+{
+ pskEdit->setEnabled(sel == AUTH_WPA_PSK || sel == AUTH_WPA2_PSK);
+ bool eap = sel == AUTH_IEEE8021X || sel == AUTH_WPA_EAP ||
+ sel == AUTH_WPA2_EAP;
+ eapSelect->setEnabled(eap);
+ identityEdit->setEnabled(eap);
+ passwordEdit->setEnabled(eap);
+ cacertEdit->setEnabled(eap);
+
+ while (encrSelect->count())
+ encrSelect->removeItem(0);
+
+ if (sel == AUTH_NONE || sel == AUTH_IEEE8021X) {
+ encrSelect->insertItem("None");
+ encrSelect->insertItem("WEP");
+ encrSelect->setCurrentItem(sel == AUTH_NONE ? 0 : 1);
+ } else {
+ encrSelect->insertItem("TKIP");
+ encrSelect->insertItem("CCMP");
+ encrSelect->setCurrentItem((sel == AUTH_WPA2_PSK ||
+ sel == AUTH_WPA2_EAP) ? 1 : 0);
+ }
+
+ wepEnabled(sel == AUTH_IEEE8021X);
+}
+
+
+void NetworkConfig::addNetwork()
+{
+ char reply[10], cmd[256];
+ size_t reply_len;
+ int id;
+ int psklen = pskEdit->text().length();
+ int auth = authSelect->currentItem();
+
+ if (auth == AUTH_WPA_PSK || auth == AUTH_WPA2_PSK) {
+ if (psklen < 8 || psklen > 64) {
+ QMessageBox::warning(this, "wpa_gui", "WPA-PSK requires a passphrase "
+ "of 8 to 63 characters\n"
+ "or 64 hex digit PSK");
+ return;
+ }
+ }
+
+ if (wpagui == NULL)
+ return;
+
+ memset(reply, 0, sizeof(reply));
+ reply_len = sizeof(reply) - 1;
+
+ if (new_network) {
+ wpagui->ctrlRequest("ADD_NETWORK", reply, &reply_len);
+ if (reply[0] == 'F') {
+ QMessageBox::warning(this, "wpa_gui", "Failed to add network to wpa_supplicant\n"
+ "configuration.");
+ return;
+ }
+ id = atoi(reply);
+ } else {
+ id = edit_network_id;
+ }
+
+ setNetworkParam(id, "ssid", ssidEdit->text().ascii(), true);
+
+ if (idstrEdit->isEnabled())
+ setNetworkParam(id, "id_str", idstrEdit->text().ascii(), true);
+
+ const char *key_mgmt = NULL, *proto = NULL, *pairwise = NULL;
+ switch (auth) {
+ case AUTH_NONE:
+ key_mgmt = "NONE";
+ break;
+ case AUTH_IEEE8021X:
+ key_mgmt = "IEEE8021X";
+ break;
+ case AUTH_WPA_PSK:
+ key_mgmt = "WPA-PSK";
+ proto = "WPA";
+ break;
+ case AUTH_WPA_EAP:
+ key_mgmt = "WPA-EAP";
+ proto = "WPA";
+ break;
+ case AUTH_WPA2_PSK:
+ key_mgmt = "WPA-PSK";
+ proto = "WPA2";
+ break;
+ case AUTH_WPA2_EAP:
+ key_mgmt = "WPA-EAP";
+ proto = "WPA2";
+ break;
+ }
+
+ if (auth == AUTH_WPA_PSK || auth == AUTH_WPA_EAP ||
+ auth == AUTH_WPA2_PSK || auth == AUTH_WPA2_EAP) {
+ int encr = encrSelect->currentItem();
+ if (encr == 0)
+ pairwise = "TKIP";
+ else
+ pairwise = "CCMP";
+ }
+
+ if (proto)
+ setNetworkParam(id, "proto", proto, false);
+ if (key_mgmt)
+ setNetworkParam(id, "key_mgmt", key_mgmt, false);
+ if (pairwise) {
+ setNetworkParam(id, "pairwise", pairwise, false);
+ setNetworkParam(id, "group", "TKIP CCMP WEP104 WEP40", false);
+ }
+ if (pskEdit->isEnabled() &&
+ strcmp(pskEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0)
+ setNetworkParam(id, "psk", pskEdit->text().ascii(), psklen != 64);
+ if (eapSelect->isEnabled())
+ setNetworkParam(id, "eap", eapSelect->currentText().ascii(), false);
+ if (identityEdit->isEnabled())
+ setNetworkParam(id, "identity", identityEdit->text().ascii(), true);
+ if (passwordEdit->isEnabled() &&
+ strcmp(passwordEdit->text().ascii(), WPA_GUI_KEY_DATA) != 0)
+ setNetworkParam(id, "password", passwordEdit->text().ascii(), true);
+ if (cacertEdit->isEnabled())
+ setNetworkParam(id, "ca_cert", cacertEdit->text().ascii(), true);
+ writeWepKey(id, wep0Edit, 0);
+ writeWepKey(id, wep1Edit, 1);
+ writeWepKey(id, wep2Edit, 2);
+ writeWepKey(id, wep3Edit, 3);
+
+ if (wep0Radio->isEnabled() && wep0Radio->isChecked())
+ setNetworkParam(id, "wep_tx_keyidx", "0", false);
+ else if (wep1Radio->isEnabled() && wep1Radio->isChecked())
+ setNetworkParam(id, "wep_tx_keyidx", "1", false);
+ else if (wep2Radio->isEnabled() && wep2Radio->isChecked())
+ setNetworkParam(id, "wep_tx_keyidx", "2", false);
+ else if (wep3Radio->isEnabled() && wep3Radio->isChecked())
+ setNetworkParam(id, "wep_tx_keyidx", "3", false);
+
+ snprintf(cmd, sizeof(cmd), "ENABLE_NETWORK %d", id);
+ reply_len = sizeof(reply);
+ wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (strncmp(reply, "OK", 2) != 0) {
+ QMessageBox::warning(this, "wpa_gui", "Failed to enable network in wpa_supplicant\n"
+ "configuration.");
+ /* Network was added, so continue anyway */
+ }
+ wpagui->triggerUpdate();
+ wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len);
+
+ close();
+}
+
+
+void NetworkConfig::setWpaGui( WpaGui *_wpagui )
+{
+ wpagui = _wpagui;
+}
+
+
+int NetworkConfig::setNetworkParam(int id, const char *field, const char *value, bool quote)
+{
+ char reply[10], cmd[256];
+ size_t reply_len;
+ snprintf(cmd, sizeof(cmd), "SET_NETWORK %d %s %s%s%s",
+ id, field, quote ? "\"" : "", value, quote ? "\"" : "");
+ reply_len = sizeof(reply);
+ wpagui->ctrlRequest(cmd, reply, &reply_len);
+ return strncmp(reply, "OK", 2) == 0 ? 0 : -1;
+}
+
+
+void NetworkConfig::encrChanged( const QString &sel )
+{
+ wepEnabled(sel.find("WEP") == 0);
+}
+
+
+void NetworkConfig::wepEnabled( bool enabled )
+{
+ wep0Edit->setEnabled(enabled);
+ wep1Edit->setEnabled(enabled);
+ wep2Edit->setEnabled(enabled);
+ wep3Edit->setEnabled(enabled);
+ wep0Radio->setEnabled(enabled);
+ wep1Radio->setEnabled(enabled);
+ wep2Radio->setEnabled(enabled);
+ wep3Radio->setEnabled(enabled);
+}
+
+
+void NetworkConfig::writeWepKey( int network_id, QLineEdit *edit, int id )
+{
+ char buf[10];
+ bool hex;
+ const char *txt, *pos;
+ size_t len;
+
+ if (!edit->isEnabled() || edit->text().isEmpty())
+ return;
+
+ /*
+ * Assume hex key if only hex characters are present and length matches
+ * with 40, 104, or 128-bit key
+ */
+ txt = edit->text().ascii();
+ if (strcmp(txt, WPA_GUI_KEY_DATA) == 0)
+ return;
+ len = strlen(txt);
+ if (len == 0)
+ return;
+ pos = txt;
+ hex = true;
+ while (*pos) {
+ if (!((*pos >= '0' && *pos <= '9') || (*pos >= 'a' && *pos <= 'f') ||
+ (*pos >= 'A' && *pos <= 'F'))) {
+ hex = false;
+ break;
+ }
+ pos++;
+ }
+ if (hex && len != 10 && len != 26 && len != 32)
+ hex = false;
+ snprintf(buf, sizeof(buf), "wep_key%d", id);
+ setNetworkParam(network_id, buf, txt, !hex);
+}
+
+
+static int key_value_isset(const char *reply, size_t reply_len)
+{
+ return reply_len > 0 && (reply_len < 4 || memcmp(reply, "FAIL", 4) != 0);
+}
+
+
+void NetworkConfig::paramsFromConfig( int network_id )
+{
+ int i, res;
+
+ edit_network_id = network_id;
+ getEapCapa();
+
+ char reply[1024], cmd[256], *pos;
+ size_t reply_len;
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ssid", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
+ reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ ssidEdit->setText(reply + 1);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d id_str", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
+ reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ idstrEdit->setText(reply + 1);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d proto", network_id);
+ reply_len = sizeof(reply) - 1;
+ int wpa = 0;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
+ reply[reply_len] = '\0';
+ if (strstr(reply, "RSN") || strstr(reply, "WPA2"))
+ wpa = 2;
+ else if (strstr(reply, "WPA"))
+ wpa = 1;
+ }
+
+ int auth = AUTH_NONE, encr = 0;
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d key_mgmt", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
+ reply[reply_len] = '\0';
+ if (strstr(reply, "WPA-EAP"))
+ auth = wpa & 2 ? AUTH_WPA2_EAP : AUTH_WPA_EAP;
+ else if (strstr(reply, "WPA-PSK"))
+ auth = wpa & 2 ? AUTH_WPA2_PSK : AUTH_WPA_PSK;
+ else if (strstr(reply, "IEEE8021X")) {
+ auth = AUTH_IEEE8021X;
+ encr = 1;
+ }
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d pairwise", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0) {
+ reply[reply_len] = '\0';
+ if (strstr(reply, "CCMP") && auth != AUTH_NONE)
+ encr = 1;
+ else if (strstr(reply, "TKIP"))
+ encr = 0;
+ else if (strstr(reply, "WEP"))
+ encr = 1;
+ else
+ encr = 0;
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d psk", network_id);
+ reply_len = sizeof(reply) - 1;
+ res = wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ pskEdit->setText(reply + 1);
+ } else if (res >= 0 && key_value_isset(reply, reply_len)) {
+ pskEdit->setText(WPA_GUI_KEY_DATA);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d identity", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
+ reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ identityEdit->setText(reply + 1);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d password", network_id);
+ reply_len = sizeof(reply) - 1;
+ res = wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (res >= 0 && reply_len >= 2 &&
+ reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ passwordEdit->setText(reply + 1);
+ } else if (res >= 0 && key_value_isset(reply, reply_len)) {
+ passwordEdit->setText(WPA_GUI_KEY_DATA);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d ca_cert", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 2 &&
+ reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ cacertEdit->setText(reply + 1);
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d eap", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) {
+ reply[reply_len] = '\0';
+ for (i = 0; i < eapSelect->count(); i++) {
+ if (eapSelect->text(i).compare(reply) == 0) {
+ eapSelect->setCurrentItem(i);
+ break;
+ }
+ }
+ }
+
+ for (i = 0; i < 4; i++) {
+ QLineEdit *wepEdit;
+ switch (i) {
+ default:
+ case 0:
+ wepEdit = wep0Edit;
+ break;
+ case 1:
+ wepEdit = wep1Edit;
+ break;
+ case 2:
+ wepEdit = wep2Edit;
+ break;
+ case 3:
+ wepEdit = wep3Edit;
+ break;
+ }
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_key%d", network_id, i);
+ reply_len = sizeof(reply) - 1;
+ res = wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (res >= 0 && reply_len >= 2 && reply[0] == '"') {
+ reply[reply_len] = '\0';
+ pos = strchr(reply + 1, '"');
+ if (pos)
+ *pos = '\0';
+ if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
+ encr = 1;
+
+ wepEdit->setText(reply + 1);
+ } else if (res >= 0 && key_value_isset(reply, reply_len)) {
+ if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
+ encr = 1;
+ wepEdit->setText(WPA_GUI_KEY_DATA);
+ }
+ }
+
+ snprintf(cmd, sizeof(cmd), "GET_NETWORK %d wep_tx_keyidx", network_id);
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest(cmd, reply, &reply_len) >= 0 && reply_len >= 1) {
+ reply[reply_len] = '\0';
+ switch (atoi(reply)) {
+ case 0:
+ wep0Radio->setChecked(true);
+ break;
+ case 1:
+ wep1Radio->setChecked(true);
+ break;
+ case 2:
+ wep2Radio->setChecked(true);
+ break;
+ case 3:
+ wep3Radio->setChecked(true);
+ break;
+ }
+ }
+
+ authSelect->setCurrentItem(auth);
+ authChanged(auth);
+ encrSelect->setCurrentItem(encr);
+ if (auth == AUTH_NONE || auth == AUTH_IEEE8021X)
+ wepEnabled(encr == 1);
+
+ removeButton->setEnabled(true);
+ addButton->setText("Save");
+}
+
+
+void NetworkConfig::removeNetwork()
+{
+ char reply[10], cmd[256];
+ size_t reply_len;
+
+ if (QMessageBox::information(this, "wpa_gui",
+ "This will permanently remove the network\n"
+ "from the configuration. Do you really want\n"
+ "to remove this network?", "Yes", "No") != 0)
+ return;
+
+ snprintf(cmd, sizeof(cmd), "REMOVE_NETWORK %d", edit_network_id);
+ reply_len = sizeof(reply);
+ wpagui->ctrlRequest(cmd, reply, &reply_len);
+ if (strncmp(reply, "OK", 2) != 0) {
+ QMessageBox::warning(this, "wpa_gui",
+ "Failed to remove network from wpa_supplicant\n"
+ "configuration.");
+ } else {
+ wpagui->triggerUpdate();
+ wpagui->ctrlRequest("SAVE_CONFIG", reply, &reply_len);
+ }
+
+ close();
+}
+
+
+void NetworkConfig::newNetwork()
+{
+ new_network = true;
+ getEapCapa();
+}
+
+
+void NetworkConfig::getEapCapa()
+{
+ char reply[256];
+ size_t reply_len;
+
+ if (wpagui == NULL)
+ return;
+
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest("GET_CAPABILITY eap", reply, &reply_len) < 0)
+ return;
+ reply[reply_len] = '\0';
+
+ QString res(reply);
+ QStringList types = QStringList::split(QChar(' '), res);
+ eapSelect->insertStringList(types);
+}
diff --git a/wpa_supplicant/wpa_gui/scanresults.ui b/wpa_supplicant/wpa_gui/scanresults.ui
new file mode 100644
index 0000000..66c8b4b
--- /dev/null
+++ b/wpa_supplicant/wpa_gui/scanresults.ui
@@ -0,0 +1,179 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>ScanResults</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>ScanResults</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>452</width>
+ <height>225</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Scan results</string>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QListView">
+ <column>
+ <property name="text">
+ <string>SSID</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>BSSID</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>frequency</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>signal</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>flags</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>scanResultsView</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout24</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer6</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>50</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>scanButton</cstring>
+ </property>
+ <property name="text">
+ <string>Scan</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>closeButton</cstring>
+ </property>
+ <property name="text">
+ <string>Close</string>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>closeButton</sender>
+ <signal>clicked()</signal>
+ <receiver>ScanResults</receiver>
+ <slot>close()</slot>
+ </connection>
+ <connection>
+ <sender>scanButton</sender>
+ <signal>clicked()</signal>
+ <receiver>ScanResults</receiver>
+ <slot>scanRequest()</slot>
+ </connection>
+ <connection>
+ <sender>scanResultsView</sender>
+ <signal>doubleClicked(QListViewItem*)</signal>
+ <receiver>ScanResults</receiver>
+ <slot>bssSelected(QListViewItem*)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">wpa_ctrl.h</include>
+ <include location="local" impldecl="in implementation">wpagui.h</include>
+ <include location="local" impldecl="in implementation">networkconfig.h</include>
+ <include location="local" impldecl="in implementation">scanresults.ui.h</include>
+</includes>
+<forwards>
+ <forward>class WpaGui;</forward>
+</forwards>
+<variables>
+ <variable access="private">WpaGui *wpagui;</variable>
+ <variable access="private">QTimer *timer;</variable>
+</variables>
+<slots>
+ <slot>setWpaGui( WpaGui * _wpagui )</slot>
+ <slot>updateResults()</slot>
+ <slot>scanRequest()</slot>
+ <slot>getResults()</slot>
+ <slot>bssSelected( QListViewItem * sel )</slot>
+</slots>
+<functions>
+ <function access="private" specifier="non virtual">init()</function>
+ <function access="private" specifier="non virtual">destroy()</function>
+</functions>
+<pixmapinproject/>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/wpa_supplicant/wpa_gui/scanresults.ui.h b/wpa_supplicant/wpa_gui/scanresults.ui.h
new file mode 100644
index 0000000..530d2e6
--- /dev/null
+++ b/wpa_supplicant/wpa_gui/scanresults.ui.h
@@ -0,0 +1,101 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+void ScanResults::init()
+{
+ wpagui = NULL;
+}
+
+
+void ScanResults::destroy()
+{
+ delete timer;
+}
+
+
+void ScanResults::setWpaGui(WpaGui *_wpagui)
+{
+ wpagui = _wpagui;
+ updateResults();
+
+ timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), SLOT(getResults()));
+ timer->start(10000, FALSE);
+}
+
+
+void ScanResults::updateResults()
+{
+ char reply[8192];
+ size_t reply_len;
+
+ if (wpagui == NULL)
+ return;
+
+ reply_len = sizeof(reply) - 1;
+ if (wpagui->ctrlRequest("SCAN_RESULTS", reply, &reply_len) < 0)
+ return;
+ reply[reply_len] = '\0';
+
+ scanResultsView->clear();
+
+ QString res(reply);
+ QStringList lines = QStringList::split(QChar('\n'), res);
+ bool first = true;
+ for (QStringList::Iterator it = lines.begin(); it != lines.end(); it++) {
+ if (first) {
+ first = false;
+ continue;
+ }
+
+ QStringList cols = QStringList::split(QChar('\t'), *it, true);
+ QString ssid, bssid, freq, signal, flags;
+ bssid = cols.count() > 0 ? cols[0] : "";
+ freq = cols.count() > 1 ? cols[1] : "";
+ signal = cols.count() > 2 ? cols[2] : "";
+ flags = cols.count() > 3 ? cols[3] : "";
+ ssid = cols.count() > 4 ? cols[4] : "";
+ new Q3ListViewItem(scanResultsView, ssid, bssid, freq, signal, flags);
+ }
+}
+
+
+void ScanResults::scanRequest()
+{
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+
+ if (wpagui == NULL)
+ return;
+
+ wpagui->ctrlRequest("SCAN", reply, &reply_len);
+}
+
+
+void ScanResults::getResults()
+{
+ updateResults();
+}
+
+
+
+
+void ScanResults::bssSelected( Q3ListViewItem * sel )
+{
+ NetworkConfig *nc = new NetworkConfig();
+ if (nc == NULL)
+ return;
+ nc->setWpaGui(wpagui);
+ nc->paramsFromScanResults(sel);
+ nc->show();
+ nc->exec();
+}
diff --git a/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling b/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling
new file mode 100755
index 0000000..e173b00
--- /dev/null
+++ b/wpa_supplicant/wpa_gui/setup-mingw-cross-compiling
@@ -0,0 +1,11 @@
+#!/bin/sh
+
+# qmake seems to be forcing include and lib paths from the original build
+# and I have no idea how to change these. For now, just override the
+# directories in the Makefile.Release file after qmake run.
+
+qmake -spec /q/jm/qt4-win/4.0.0/mkspecs/win32-g++ wpa_gui.pro -o Makefile
+cat Makefile.Release |
+ sed s%qt4/lib%qt4-win/4.0.0/lib%g |
+ sed s%qt4/include%qt4-win/4.0.0/include%g > tmp.Makefile.Release &&
+mv -f tmp.Makefile.Release Makefile.Release
diff --git a/wpa_supplicant/wpa_gui/userdatarequest.ui b/wpa_supplicant/wpa_gui/userdatarequest.ui
new file mode 100644
index 0000000..c3d545f
--- /dev/null
+++ b/wpa_supplicant/wpa_gui/userdatarequest.ui
@@ -0,0 +1,163 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>UserDataRequest</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>UserDataRequest</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>216</width>
+ <height>103</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>Authentication credentials required</string>
+ </property>
+ <property name="sizeGripEnabled">
+ <bool>true</bool>
+ </property>
+ <vbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>queryInfo</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout28</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>queryField</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLineEdit">
+ <property name="name">
+ <cstring>queryEdit</cstring>
+ </property>
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="echoMode">
+ <enum>Password</enum>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ <widget class="QLayoutWidget">
+ <property name="name">
+ <cstring>layout27</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>spacer4</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>20</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonOk</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;OK</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>buttonCancel</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Cancel</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ <property name="autoDefault">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </vbox>
+</widget>
+<connections>
+ <connection>
+ <sender>buttonOk</sender>
+ <signal>clicked()</signal>
+ <receiver>UserDataRequest</receiver>
+ <slot>sendReply()</slot>
+ </connection>
+ <connection>
+ <sender>buttonCancel</sender>
+ <signal>clicked()</signal>
+ <receiver>UserDataRequest</receiver>
+ <slot>reject()</slot>
+ </connection>
+ <connection>
+ <sender>queryEdit</sender>
+ <signal>returnPressed()</signal>
+ <receiver>UserDataRequest</receiver>
+ <slot>sendReply()</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="local" impldecl="in implementation">wpa_ctrl.h</include>
+ <include location="local" impldecl="in implementation">wpagui.h</include>
+ <include location="local" impldecl="in implementation">userdatarequest.ui.h</include>
+</includes>
+<forwards>
+ <forward>class WpaGui;</forward>
+</forwards>
+<variables>
+ <variable access="private">WpaGui *wpagui;</variable>
+ <variable access="private">int networkid;</variable>
+ <variable access="private">QString field;</variable>
+</variables>
+<slots>
+ <slot>sendReply()</slot>
+</slots>
+<functions>
+ <function specifier="non virtual" returnType="int">setParams( WpaGui * _wpagui, const char * reqMsg )</function>
+</functions>
+<pixmapinproject/>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/wpa_supplicant/wpa_gui/userdatarequest.ui.h b/wpa_supplicant/wpa_gui/userdatarequest.ui.h
new file mode 100644
index 0000000..66d4478
--- /dev/null
+++ b/wpa_supplicant/wpa_gui/userdatarequest.ui.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+#include <stdlib.h>
+
+int UserDataRequest::setParams(WpaGui *_wpagui, const char *reqMsg)
+{
+ char *tmp, *pos, *pos2;
+ wpagui = _wpagui;
+ tmp = strdup(reqMsg);
+ if (tmp == NULL)
+ return -1;
+ pos = strchr(tmp, '-');
+ if (pos == NULL) {
+ free(tmp);
+ return -1;
+ }
+ *pos++ = '\0';
+ field = tmp;
+ pos2 = strchr(pos, ':');
+ if (pos2 == NULL) {
+ free(tmp);
+ return -1;
+ }
+ *pos2++ = '\0';
+
+ networkid = atoi(pos);
+ queryInfo->setText(pos2);
+ if (strcmp(tmp, "PASSWORD") == 0) {
+ queryField->setText("Password: ");
+ queryEdit->setEchoMode(QLineEdit::Password);
+ } else if (strcmp(tmp, "NEW_PASSWORD") == 0) {
+ queryField->setText("New password: ");
+ queryEdit->setEchoMode(QLineEdit::Password);
+ } else if (strcmp(tmp, "IDENTITY") == 0)
+ queryField->setText("Identity: ");
+ else if (strcmp(tmp, "PASSPHRASE") == 0) {
+ queryField->setText("Private key passphrase: ");
+ queryEdit->setEchoMode(QLineEdit::Password);
+ } else
+ queryField->setText(field + ":");
+ free(tmp);
+
+ return 0;
+}
+
+
+void UserDataRequest::sendReply()
+{
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+
+ if (wpagui == NULL) {
+ reject();
+ return;
+ }
+
+ QString cmd = QString(WPA_CTRL_RSP) + field + '-' +
+ QString::number(networkid) + ':' +
+ queryEdit->text();
+ wpagui->ctrlRequest(cmd.ascii(), reply, &reply_len);
+ accept();
+}
diff --git a/wpa_supplicant/wpa_gui/wpa_gui.pro b/wpa_supplicant/wpa_gui/wpa_gui.pro
new file mode 100644
index 0000000..6363db9
--- /dev/null
+++ b/wpa_supplicant/wpa_gui/wpa_gui.pro
@@ -0,0 +1,50 @@
+TEMPLATE = app
+LANGUAGE = C++
+
+CONFIG += qt warn_on release
+
+DEFINES += CONFIG_CTRL_IFACE
+
+win32 {
+ LIBS += -lws2_32 -static
+ DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
+ SOURCES += ../../src/utils/os_win32.c
+} else:win32-g++ {
+ # cross compilation to win32
+ LIBS += -lws2_32 -static
+ DEFINES += CONFIG_NATIVE_WINDOWS CONFIG_CTRL_IFACE_NAMED_PIPE
+ SOURCES += ../../src/utils/os_win32.c
+} else {
+ DEFINES += CONFIG_CTRL_IFACE_UNIX
+ SOURCES += ../../src/utils/os_unix.c
+}
+
+INCLUDEPATH += . .. ../../src/utils ../../src/common
+
+HEADERS += wpamsg.h
+
+SOURCES += main.cpp \
+ ../../src/common/wpa_ctrl.c
+
+FORMS = wpagui.ui \
+ eventhistory.ui \
+ scanresults.ui \
+ userdatarequest.ui \
+ networkconfig.ui
+
+
+unix {
+ UI_DIR = .ui
+ MOC_DIR = .moc
+ OBJECTS_DIR = .obj
+}
+
+qtver = $$[QT_VERSION]
+isEmpty( qtver ) {
+ message(Compiling for Qt 3.x)
+ DEFINES += Q3ListViewItem=QListViewItem
+} else {
+ message(Compiling for Qt $$qtver)
+ QT += qt3support
+ CONFIG += uic3
+}
diff --git a/wpa_supplicant/wpa_gui/wpagui.ui b/wpa_supplicant/wpa_gui/wpagui.ui
new file mode 100644
index 0000000..01666a3
--- /dev/null
+++ b/wpa_supplicant/wpa_gui/wpagui.ui
@@ -0,0 +1,471 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>WpaGui</class>
+<widget class="QMainWindow">
+ <property name="name">
+ <cstring>WpaGui</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>279</width>
+ <height>308</height>
+ </rect>
+ </property>
+ <property name="caption">
+ <string>wpa_gui</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel16</cstring>
+ </property>
+ <property name="text">
+ <string>Adapter:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="0" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>adapterSelect</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>textLabel8</cstring>
+ </property>
+ <property name="text">
+ <string>Network:</string>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>networkSelect</cstring>
+ </property>
+ </widget>
+ <widget class="QFrame" row="2" column="0" rowspan="1" colspan="4">
+ <property name="name">
+ <cstring>frame3</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Raised</enum>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Status:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>textLabel2</cstring>
+ </property>
+ <property name="text">
+ <string>Last message:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>textLabel3</cstring>
+ </property>
+ <property name="text">
+ <string>Authentication:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>textLabel4</cstring>
+ </property>
+ <property name="text">
+ <string>Encryption:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>textLabel5</cstring>
+ </property>
+ <property name="text">
+ <string>SSID:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>textLabel6</cstring>
+ </property>
+ <property name="text">
+ <string>BSSID:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="0">
+ <property name="name">
+ <cstring>textLabel7</cstring>
+ </property>
+ <property name="text">
+ <string>IP address:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="1">
+ <property name="name">
+ <cstring>textStatus</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>textLastMessage</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1">
+ <property name="name">
+ <cstring>textAuthentication</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1">
+ <property name="name">
+ <cstring>textEncryption</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="1">
+ <property name="name">
+ <cstring>textSsid</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="1">
+ <property name="name">
+ <cstring>textBssid</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="6" column="1">
+ <property name="name">
+ <cstring>textIpAddress</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <spacer row="3" column="0">
+ <property name="name">
+ <cstring>spacer7</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton" row="3" column="1">
+ <property name="name">
+ <cstring>connectButton</cstring>
+ </property>
+ <property name="text">
+ <string>Connect</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="2">
+ <property name="name">
+ <cstring>disconnectButton</cstring>
+ </property>
+ <property name="text">
+ <string>Disconnect</string>
+ </property>
+ </widget>
+ <widget class="QPushButton" row="3" column="3">
+ <property name="name">
+ <cstring>scanButton</cstring>
+ </property>
+ <property name="text">
+ <string>Scan</string>
+ </property>
+ </widget>
+ </grid>
+</widget>
+<menubar>
+ <property name="name">
+ <cstring>MenuBar</cstring>
+ </property>
+ <item text="&amp;File" name="fileMenu">
+ <separator/>
+ <action name="fileEventHistoryAction"/>
+ <action name="fileAdd_NetworkAction"/>
+ <action name="fileEdit_networkAction"/>
+ <separator/>
+ <action name="fileExitAction"/>
+ </item>
+ <item text="&amp;Help" name="helpMenu">
+ <action name="helpContentsAction"/>
+ <action name="helpIndexAction"/>
+ <separator/>
+ <action name="helpAboutAction"/>
+ </item>
+</menubar>
+<toolbars>
+</toolbars>
+<actions>
+ <action>
+ <property name="name">
+ <cstring>fileExitAction</cstring>
+ </property>
+ <property name="text">
+ <string>Exit</string>
+ </property>
+ <property name="menuText">
+ <string>E&amp;xit</string>
+ </property>
+ <property name="accel">
+ <string>Ctrl+Q</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>helpContentsAction</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Contents</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Contents...</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>helpIndexAction</cstring>
+ </property>
+ <property name="enabled">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string>Index</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Index...</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>helpAboutAction</cstring>
+ </property>
+ <property name="text">
+ <string>About</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;About</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>fileEventHistoryAction</cstring>
+ </property>
+ <property name="text">
+ <string>Event History</string>
+ </property>
+ <property name="menuText">
+ <string>Event &amp;History</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>fileAdd_NetworkAction</cstring>
+ </property>
+ <property name="text">
+ <string>Add Network</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Add Network</string>
+ </property>
+ </action>
+ <action>
+ <property name="name">
+ <cstring>fileEdit_networkAction</cstring>
+ </property>
+ <property name="text">
+ <string>Edit Network</string>
+ </property>
+ <property name="menuText">
+ <string>&amp;Edit Network</string>
+ </property>
+ </action>
+</actions>
+<connections>
+ <connection>
+ <sender>helpIndexAction</sender>
+ <signal>activated()</signal>
+ <receiver>WpaGui</receiver>
+ <slot>helpIndex()</slot>
+ </connection>
+ <connection>
+ <sender>helpContentsAction</sender>
+ <signal>activated()</signal>
+ <receiver>WpaGui</receiver>
+ <slot>helpContents()</slot>
+ </connection>
+ <connection>
+ <sender>helpAboutAction</sender>
+ <signal>activated()</signal>
+ <receiver>WpaGui</receiver>
+ <slot>helpAbout()</slot>
+ </connection>
+ <connection>
+ <sender>fileExitAction</sender>
+ <signal>activated()</signal>
+ <receiver>WpaGui</receiver>
+ <slot>close()</slot>
+ </connection>
+ <connection>
+ <sender>disconnectButton</sender>
+ <signal>clicked()</signal>
+ <receiver>WpaGui</receiver>
+ <slot>disconnect()</slot>
+ </connection>
+ <connection>
+ <sender>scanButton</sender>
+ <signal>clicked()</signal>
+ <receiver>WpaGui</receiver>
+ <slot>scan()</slot>
+ </connection>
+ <connection>
+ <sender>connectButton</sender>
+ <signal>clicked()</signal>
+ <receiver>WpaGui</receiver>
+ <slot>connectB()</slot>
+ </connection>
+ <connection>
+ <sender>fileEventHistoryAction</sender>
+ <signal>activated()</signal>
+ <receiver>WpaGui</receiver>
+ <slot>eventHistory()</slot>
+ </connection>
+ <connection>
+ <sender>networkSelect</sender>
+ <signal>activated(const QString&amp;)</signal>
+ <receiver>WpaGui</receiver>
+ <slot>selectNetwork(const QString&amp;)</slot>
+ </connection>
+ <connection>
+ <sender>fileEdit_networkAction</sender>
+ <signal>activated()</signal>
+ <receiver>WpaGui</receiver>
+ <slot>editNetwork()</slot>
+ </connection>
+ <connection>
+ <sender>fileAdd_NetworkAction</sender>
+ <signal>activated()</signal>
+ <receiver>WpaGui</receiver>
+ <slot>addNetwork()</slot>
+ </connection>
+ <connection>
+ <sender>adapterSelect</sender>
+ <signal>activated(const QString&amp;)</signal>
+ <receiver>WpaGui</receiver>
+ <slot>selectAdapter(const QString&amp;)</slot>
+ </connection>
+</connections>
+<includes>
+ <include location="global" impldecl="in declaration">qtimer.h</include>
+ <include location="global" impldecl="in declaration">qsocketnotifier.h</include>
+ <include location="local" impldecl="in declaration">wpamsg.h</include>
+ <include location="local" impldecl="in declaration">eventhistory.h</include>
+ <include location="local" impldecl="in declaration">scanresults.h</include>
+ <include location="local" impldecl="in implementation">wpa_ctrl.h</include>
+ <include location="global" impldecl="in implementation">dirent.h</include>
+ <include location="global" impldecl="in implementation">qmessagebox.h</include>
+ <include location="global" impldecl="in implementation">qapplication.h</include>
+ <include location="local" impldecl="in implementation">userdatarequest.h</include>
+ <include location="local" impldecl="in implementation">networkconfig.h</include>
+ <include location="local" impldecl="in implementation">wpagui.ui.h</include>
+</includes>
+<forwards>
+ <forward>class UserDataRequest;</forward>
+</forwards>
+<variables>
+ <variable access="private">ScanResults *scanres;</variable>
+ <variable access="private">bool networkMayHaveChanged;</variable>
+ <variable access="private">char *ctrl_iface;</variable>
+ <variable access="private">EventHistory *eh;</variable>
+ <variable access="private">struct wpa_ctrl *ctrl_conn;</variable>
+ <variable access="private">QSocketNotifier *msgNotifier;</variable>
+ <variable access="private">QTimer *timer;</variable>
+ <variable access="private">int pingsToStatusUpdate;</variable>
+ <variable access="private">WpaMsgList msgs;</variable>
+ <variable access="private">char *ctrl_iface_dir;</variable>
+ <variable access="private">struct wpa_ctrl *monitor_conn;</variable>
+ <variable access="private">UserDataRequest *udr;</variable>
+</variables>
+<slots>
+ <slot>parse_argv()</slot>
+ <slot>updateStatus()</slot>
+ <slot>updateNetworks()</slot>
+ <slot>helpIndex()</slot>
+ <slot>helpContents()</slot>
+ <slot>helpAbout()</slot>
+ <slot>disconnect()</slot>
+ <slot>scan()</slot>
+ <slot>eventHistory()</slot>
+ <slot>ping()</slot>
+ <slot>processMsg( char * msg )</slot>
+ <slot>processCtrlReq( const char * req )</slot>
+ <slot>receiveMsgs()</slot>
+ <slot>connectB()</slot>
+ <slot>selectNetwork( const QString &amp; sel )</slot>
+ <slot>editNetwork()</slot>
+ <slot>addNetwork()</slot>
+ <slot>selectAdapter( const QString &amp; sel )</slot>
+</slots>
+<functions>
+ <function access="private" specifier="non virtual">init()</function>
+ <function access="private" specifier="non virtual">destroy()</function>
+ <function access="private" specifier="non virtual" returnType="int">openCtrlConnection( const char * ifname )</function>
+ <function returnType="int">ctrlRequest( const char * cmd, char * buf, size_t * buflen )</function>
+ <function>triggerUpdate()</function>
+</functions>
+<pixmapinproject/>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/wpa_supplicant/wpa_gui/wpagui.ui.h b/wpa_supplicant/wpa_gui/wpagui.ui.h
new file mode 100644
index 0000000..678ff1b
--- /dev/null
+++ b/wpa_supplicant/wpa_gui/wpagui.ui.h
@@ -0,0 +1,730 @@
+/****************************************************************************
+** ui.h extension file, included from the uic-generated form implementation.
+**
+** If you want to add, delete, or rename functions or slots, use
+** Qt Designer to update this file, preserving your code.
+**
+** You should not define a constructor or destructor in this file.
+** Instead, write your code in functions called init() and destroy().
+** These will automatically be called by the form's constructor and
+** destructor.
+*****************************************************************************/
+
+
+#ifdef __MINGW32__
+/* Need to get getopt() */
+#include <unistd.h>
+#endif
+
+#include <stdlib.h>
+
+void WpaGui::init()
+{
+ eh = NULL;
+ scanres = NULL;
+ udr = NULL;
+ ctrl_iface = NULL;
+ ctrl_conn = NULL;
+ monitor_conn = NULL;
+ msgNotifier = NULL;
+ ctrl_iface_dir = strdup("/var/run/wpa_supplicant");
+
+ parse_argv();
+
+ textStatus->setText("connecting to wpa_supplicant");
+ timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), SLOT(ping()));
+ timer->start(1000, FALSE);
+
+ if (openCtrlConnection(ctrl_iface) < 0) {
+ printf("Failed to open control connection to wpa_supplicant.\n");
+ }
+
+ updateStatus();
+ networkMayHaveChanged = true;
+ updateNetworks();
+}
+
+
+void WpaGui::destroy()
+{
+ delete msgNotifier;
+
+ if (monitor_conn) {
+ wpa_ctrl_detach(monitor_conn);
+ wpa_ctrl_close(monitor_conn);
+ monitor_conn = NULL;
+ }
+ if (ctrl_conn) {
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
+ }
+
+ if (eh) {
+ eh->close();
+ delete eh;
+ eh = NULL;
+ }
+
+ if (scanres) {
+ scanres->close();
+ delete scanres;
+ scanres = NULL;
+ }
+
+ if (udr) {
+ udr->close();
+ delete udr;
+ udr = NULL;
+ }
+
+ free(ctrl_iface);
+ ctrl_iface = NULL;
+
+ free(ctrl_iface_dir);
+ ctrl_iface_dir = NULL;
+}
+
+
+void WpaGui::parse_argv()
+{
+ int c;
+ for (;;) {
+ c = getopt(qApp->argc(), qApp->argv(), "i:p:");
+ if (c < 0)
+ break;
+ switch (c) {
+ case 'i':
+ free(ctrl_iface);
+ ctrl_iface = strdup(optarg);
+ break;
+ case 'p':
+ free(ctrl_iface_dir);
+ ctrl_iface_dir = strdup(optarg);
+ break;
+ }
+ }
+}
+
+
+int WpaGui::openCtrlConnection(const char *ifname)
+{
+ char *cfile;
+ int flen;
+ char buf[2048], *pos, *pos2;
+ size_t len;
+
+ if (ifname) {
+ if (ifname != ctrl_iface) {
+ free(ctrl_iface);
+ ctrl_iface = strdup(ifname);
+ }
+ } else {
+#ifdef CONFIG_CTRL_IFACE_UDP
+ free(ctrl_iface);
+ ctrl_iface = strdup("udp");
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#ifdef CONFIG_CTRL_IFACE_UNIX
+ struct dirent *dent;
+ DIR *dir = opendir(ctrl_iface_dir);
+ free(ctrl_iface);
+ ctrl_iface = NULL;
+ if (dir) {
+ while ((dent = readdir(dir))) {
+#ifdef _DIRENT_HAVE_D_TYPE
+ /* Skip the file if it is not a socket.
+ * Also accept DT_UNKNOWN (0) in case
+ * the C library or underlying file
+ * system does not support d_type. */
+ if (dent->d_type != DT_SOCK &&
+ dent->d_type != DT_UNKNOWN)
+ continue;
+#endif /* _DIRENT_HAVE_D_TYPE */
+
+ if (strcmp(dent->d_name, ".") == 0 ||
+ strcmp(dent->d_name, "..") == 0)
+ continue;
+ printf("Selected interface '%s'\n", dent->d_name);
+ ctrl_iface = strdup(dent->d_name);
+ break;
+ }
+ closedir(dir);
+ }
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+ struct wpa_ctrl *ctrl;
+ int ret;
+
+ free(ctrl_iface);
+ ctrl_iface = NULL;
+
+ ctrl = wpa_ctrl_open(NULL);
+ if (ctrl) {
+ len = sizeof(buf) - 1;
+ ret = wpa_ctrl_request(ctrl, "INTERFACES", 10, buf, &len, NULL);
+ if (ret >= 0) {
+ buf[len] = '\0';
+ pos = strchr(buf, '\n');
+ if (pos)
+ *pos = '\0';
+ ctrl_iface = strdup(buf);
+ }
+ wpa_ctrl_close(ctrl);
+ }
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+ }
+
+ if (ctrl_iface == NULL)
+ return -1;
+
+#ifdef CONFIG_CTRL_IFACE_UNIX
+ flen = strlen(ctrl_iface_dir) + strlen(ctrl_iface) + 2;
+ cfile = (char *) malloc(flen);
+ if (cfile == NULL)
+ return -1;
+ snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ctrl_iface);
+#else /* CONFIG_CTRL_IFACE_UNIX */
+ flen = strlen(ctrl_iface) + 1;
+ cfile = (char *) malloc(flen);
+ if (cfile == NULL)
+ return -1;
+ snprintf(cfile, flen, "%s", ctrl_iface);
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+
+ if (ctrl_conn) {
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
+ }
+
+ if (monitor_conn) {
+ delete msgNotifier;
+ msgNotifier = NULL;
+ wpa_ctrl_detach(monitor_conn);
+ wpa_ctrl_close(monitor_conn);
+ monitor_conn = NULL;
+ }
+
+ printf("Trying to connect to '%s'\n", cfile);
+ ctrl_conn = wpa_ctrl_open(cfile);
+ if (ctrl_conn == NULL) {
+ free(cfile);
+ return -1;
+ }
+ monitor_conn = wpa_ctrl_open(cfile);
+ free(cfile);
+ if (monitor_conn == NULL) {
+ wpa_ctrl_close(ctrl_conn);
+ return -1;
+ }
+ if (wpa_ctrl_attach(monitor_conn)) {
+ printf("Failed to attach to wpa_supplicant\n");
+ wpa_ctrl_close(monitor_conn);
+ monitor_conn = NULL;
+ wpa_ctrl_close(ctrl_conn);
+ ctrl_conn = NULL;
+ return -1;
+ }
+
+#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
+ msgNotifier = new QSocketNotifier(wpa_ctrl_get_fd(monitor_conn),
+ QSocketNotifier::Read, this);
+ connect(msgNotifier, SIGNAL(activated(int)), SLOT(receiveMsgs()));
+#endif
+
+ adapterSelect->clear();
+ adapterSelect->insertItem(ctrl_iface);
+ adapterSelect->setCurrentItem(0);
+
+ len = sizeof(buf) - 1;
+ if (wpa_ctrl_request(ctrl_conn, "INTERFACES", 10, buf, &len, NULL) >= 0) {
+ buf[len] = '\0';
+ pos = buf;
+ while (*pos) {
+ pos2 = strchr(pos, '\n');
+ if (pos2)
+ *pos2 = '\0';
+ if (strcmp(pos, ctrl_iface) != 0)
+ adapterSelect->insertItem(pos);
+ if (pos2)
+ pos = pos2 + 1;
+ else
+ break;
+ }
+ }
+
+ return 0;
+}
+
+
+static void wpa_gui_msg_cb(char *msg, size_t)
+{
+ /* This should not happen anymore since two control connections are used. */
+ printf("missed message: %s\n", msg);
+}
+
+
+int WpaGui::ctrlRequest(const char *cmd, char *buf, size_t *buflen)
+{
+ int ret;
+
+ if (ctrl_conn == NULL)
+ return -3;
+ ret = wpa_ctrl_request(ctrl_conn, cmd, strlen(cmd), buf, buflen,
+ wpa_gui_msg_cb);
+ if (ret == -2) {
+ printf("'%s' command timed out.\n", cmd);
+ } else if (ret < 0) {
+ printf("'%s' command failed.\n", cmd);
+ }
+
+ return ret;
+}
+
+
+void WpaGui::updateStatus()
+{
+ char buf[2048], *start, *end, *pos;
+ size_t len;
+
+ pingsToStatusUpdate = 10;
+
+ len = sizeof(buf) - 1;
+ if (ctrl_conn == NULL || ctrlRequest("STATUS", buf, &len) < 0) {
+ textStatus->setText("Could not get status from wpa_supplicant");
+ textAuthentication->clear();
+ textEncryption->clear();
+ textSsid->clear();
+ textBssid->clear();
+ textIpAddress->clear();
+ return;
+ }
+
+ buf[len] = '\0';
+
+ bool auth_updated = false, ssid_updated = false;
+ bool bssid_updated = false, ipaddr_updated = false;
+ bool status_updated = false;
+ char *pairwise_cipher = NULL, *group_cipher = NULL;
+
+ start = buf;
+ while (*start) {
+ bool last = false;
+ end = strchr(start, '\n');
+ if (end == NULL) {
+ last = true;
+ end = start;
+ while (end[0] && end[1])
+ end++;
+ }
+ *end = '\0';
+
+ pos = strchr(start, '=');
+ if (pos) {
+ *pos++ = '\0';
+ if (strcmp(start, "bssid") == 0) {
+ bssid_updated = true;
+ textBssid->setText(pos);
+ } else if (strcmp(start, "ssid") == 0) {
+ ssid_updated = true;
+ textSsid->setText(pos);
+ } else if (strcmp(start, "ip_address") == 0) {
+ ipaddr_updated = true;
+ textIpAddress->setText(pos);
+ } else if (strcmp(start, "wpa_state") == 0) {
+ status_updated = true;
+ textStatus->setText(pos);
+ } else if (strcmp(start, "key_mgmt") == 0) {
+ auth_updated = true;
+ textAuthentication->setText(pos);
+ /* TODO: could add EAP status to this */
+ } else if (strcmp(start, "pairwise_cipher") == 0) {
+ pairwise_cipher = pos;
+ } else if (strcmp(start, "group_cipher") == 0) {
+ group_cipher = pos;
+ }
+ }
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+
+ if (pairwise_cipher || group_cipher) {
+ QString encr;
+ if (pairwise_cipher && group_cipher &&
+ strcmp(pairwise_cipher, group_cipher) != 0) {
+ encr.append(pairwise_cipher);
+ encr.append(" + ");
+ encr.append(group_cipher);
+ } else if (pairwise_cipher) {
+ encr.append(pairwise_cipher);
+ } else {
+ encr.append(group_cipher);
+ encr.append(" [group key only]");
+ }
+ textEncryption->setText(encr);
+ } else
+ textEncryption->clear();
+
+ if (!status_updated)
+ textStatus->clear();
+ if (!auth_updated)
+ textAuthentication->clear();
+ if (!ssid_updated)
+ textSsid->clear();
+ if (!bssid_updated)
+ textBssid->clear();
+ if (!ipaddr_updated)
+ textIpAddress->clear();
+}
+
+
+void WpaGui::updateNetworks()
+{
+ char buf[2048], *start, *end, *id, *ssid, *bssid, *flags;
+ size_t len;
+ int first_active = -1;
+ bool selected = false;
+
+ if (!networkMayHaveChanged)
+ return;
+
+ networkSelect->clear();
+
+ if (ctrl_conn == NULL)
+ return;
+
+ len = sizeof(buf) - 1;
+ if (ctrlRequest("LIST_NETWORKS", buf, &len) < 0)
+ return;
+
+ buf[len] = '\0';
+ start = strchr(buf, '\n');
+ if (start == NULL)
+ return;
+ start++;
+
+ while (*start) {
+ bool last = false;
+ end = strchr(start, '\n');
+ if (end == NULL) {
+ last = true;
+ end = start;
+ while (end[0] && end[1])
+ end++;
+ }
+ *end = '\0';
+
+ id = start;
+ ssid = strchr(id, '\t');
+ if (ssid == NULL)
+ break;
+ *ssid++ = '\0';
+ bssid = strchr(ssid, '\t');
+ if (bssid == NULL)
+ break;
+ *bssid++ = '\0';
+ flags = strchr(bssid, '\t');
+ if (flags == NULL)
+ break;
+ *flags++ = '\0';
+
+ QString network(id);
+ network.append(": ");
+ network.append(ssid);
+ networkSelect->insertItem(network);
+
+ if (strstr(flags, "[CURRENT]")) {
+ networkSelect->setCurrentItem(networkSelect->count() - 1);
+ selected = true;
+ } else if (first_active < 0 && strstr(flags, "[DISABLED]") == NULL)
+ first_active = networkSelect->count() - 1;
+
+ if (last)
+ break;
+ start = end + 1;
+ }
+
+ if (!selected && first_active >= 0)
+ networkSelect->setCurrentItem(first_active);
+
+ networkMayHaveChanged = false;
+}
+
+
+void WpaGui::helpIndex()
+{
+ printf("helpIndex\n");
+}
+
+
+void WpaGui::helpContents()
+{
+ printf("helpContents\n");
+}
+
+
+void WpaGui::helpAbout()
+{
+ QMessageBox::about(this, "wpa_gui for wpa_supplicant",
+ "Copyright (c) 2003-2008,\n"
+ "Jouni Malinen <j@w1.fi>\n"
+ "and contributors.\n"
+ "\n"
+ "This program is free software. You can\n"
+ "distribute it and/or modify it under the terms of\n"
+ "the GNU General Public License version 2.\n"
+ "\n"
+ "Alternatively, this software may be distributed\n"
+ "under the terms of the BSD license.\n"
+ "\n"
+ "This product includes software developed\n"
+ "by the OpenSSL Project for use in the\n"
+ "OpenSSL Toolkit (http://www.openssl.org/)\n");
+}
+
+
+void WpaGui::disconnect()
+{
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+ ctrlRequest("DISCONNECT", reply, &reply_len);
+}
+
+
+void WpaGui::scan()
+{
+ if (scanres) {
+ scanres->close();
+ delete scanres;
+ }
+
+ scanres = new ScanResults();
+ if (scanres == NULL)
+ return;
+ scanres->setWpaGui(this);
+ scanres->show();
+ scanres->exec();
+}
+
+
+void WpaGui::eventHistory()
+{
+ if (eh) {
+ eh->close();
+ delete eh;
+ }
+
+ eh = new EventHistory();
+ if (eh == NULL)
+ return;
+ eh->addEvents(msgs);
+ eh->show();
+ eh->exec();
+}
+
+
+void WpaGui::ping()
+{
+ char buf[10];
+ size_t len;
+
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+ /*
+ * QSocketNotifier cannot be used with Windows named pipes, so use a timer
+ * to check for received messages for now. This could be optimized be doing
+ * something specific to named pipes or Windows events, but it is not clear
+ * what would be the best way of doing that in Qt.
+ */
+ receiveMsgs();
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+
+ if (scanres && !scanres->isVisible()) {
+ delete scanres;
+ scanres = NULL;
+ }
+
+ if (eh && !eh->isVisible()) {
+ delete eh;
+ eh = NULL;
+ }
+
+ if (udr && !udr->isVisible()) {
+ delete udr;
+ udr = NULL;
+ }
+
+ len = sizeof(buf) - 1;
+ if (ctrlRequest("PING", buf, &len) < 0) {
+ printf("PING failed - trying to reconnect\n");
+ if (openCtrlConnection(ctrl_iface) >= 0) {
+ printf("Reconnected successfully\n");
+ pingsToStatusUpdate = 0;
+ }
+ }
+
+ pingsToStatusUpdate--;
+ if (pingsToStatusUpdate <= 0) {
+ updateStatus();
+ updateNetworks();
+ }
+}
+
+
+static int str_match(const char *a, const char *b)
+{
+ return strncmp(a, b, strlen(b)) == 0;
+}
+
+
+void WpaGui::processMsg(char *msg)
+{
+ char *pos = msg, *pos2;
+ int priority = 2;
+
+ if (*pos == '<') {
+ /* skip priority */
+ pos++;
+ priority = atoi(pos);
+ pos = strchr(pos, '>');
+ if (pos)
+ pos++;
+ else
+ pos = msg;
+ }
+
+ WpaMsg wm(pos, priority);
+ if (eh)
+ eh->addEvent(wm);
+ msgs.append(wm);
+ while (msgs.count() > 100)
+ msgs.pop_front();
+
+ /* Update last message with truncated version of the event */
+ if (strncmp(pos, "CTRL-", 5) == 0) {
+ pos2 = strchr(pos, str_match(pos, WPA_CTRL_REQ) ? ':' : ' ');
+ if (pos2)
+ pos2++;
+ else
+ pos2 = pos;
+ } else
+ pos2 = pos;
+ QString lastmsg = pos2;
+ lastmsg.truncate(40);
+ textLastMessage->setText(lastmsg);
+
+ pingsToStatusUpdate = 0;
+ networkMayHaveChanged = true;
+
+ if (str_match(pos, WPA_CTRL_REQ))
+ processCtrlReq(pos + strlen(WPA_CTRL_REQ));
+}
+
+
+void WpaGui::processCtrlReq(const char *req)
+{
+ if (udr) {
+ udr->close();
+ delete udr;
+ }
+ udr = new UserDataRequest();
+ if (udr == NULL)
+ return;
+ if (udr->setParams(this, req) < 0) {
+ delete udr;
+ udr = NULL;
+ return;
+ }
+ udr->show();
+ udr->exec();
+}
+
+
+void WpaGui::receiveMsgs()
+{
+ char buf[256];
+ size_t len;
+
+ while (monitor_conn && wpa_ctrl_pending(monitor_conn) > 0) {
+ len = sizeof(buf) - 1;
+ if (wpa_ctrl_recv(monitor_conn, buf, &len) == 0) {
+ buf[len] = '\0';
+ processMsg(buf);
+ }
+ }
+}
+
+
+void WpaGui::connectB()
+{
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+ ctrlRequest("REASSOCIATE", reply, &reply_len);
+}
+
+
+void WpaGui::selectNetwork( const QString &sel )
+{
+ QString cmd(sel);
+ char reply[10];
+ size_t reply_len = sizeof(reply);
+
+ int pos = cmd.find(':');
+ if (pos < 0) {
+ printf("Invalid selectNetwork '%s'\n", cmd.ascii());
+ return;
+ }
+ cmd.truncate(pos);
+ cmd.prepend("SELECT_NETWORK ");
+ ctrlRequest(cmd.ascii(), reply, &reply_len);
+}
+
+
+void WpaGui::editNetwork()
+{
+ QString sel(networkSelect->currentText());
+ int pos = sel.find(':');
+ if (pos < 0) {
+ printf("Invalid selectNetwork '%s'\n", sel.ascii());
+ return;
+ }
+ sel.truncate(pos);
+
+ NetworkConfig *nc = new NetworkConfig();
+ if (nc == NULL)
+ return;
+ nc->setWpaGui(this);
+
+ nc->paramsFromConfig(sel.toInt());
+ nc->show();
+ nc->exec();
+}
+
+
+void WpaGui::triggerUpdate()
+{
+ updateStatus();
+ networkMayHaveChanged = true;
+ updateNetworks();
+}
+
+
+void WpaGui::addNetwork()
+{
+ NetworkConfig *nc = new NetworkConfig();
+ if (nc == NULL)
+ return;
+ nc->setWpaGui(this);
+ nc->newNetwork();
+ nc->show();
+ nc->exec();
+}
+
+
+void WpaGui::selectAdapter( const QString & sel )
+{
+ if (openCtrlConnection(sel.ascii()) < 0)
+ printf("Failed to open control connection to wpa_supplicant.\n");
+ updateStatus();
+ updateNetworks();
+}
diff --git a/wpa_supplicant/wpa_gui/wpamsg.h b/wpa_supplicant/wpa_gui/wpamsg.h
new file mode 100644
index 0000000..f3fce06
--- /dev/null
+++ b/wpa_supplicant/wpa_gui/wpamsg.h
@@ -0,0 +1,34 @@
+#ifndef WPAMSG_H
+#define WPAMSG_H
+
+class WpaMsg;
+
+#if QT_VERSION >= 0x040000
+#include <QDateTime>
+#include <QLinkedList>
+typedef QLinkedList<WpaMsg> WpaMsgList;
+#else
+#include <qdatetime.h>
+typedef QValueList<WpaMsg> WpaMsgList;
+#endif
+
+class WpaMsg {
+public:
+ WpaMsg() {}
+ WpaMsg(const QString &_msg, int _priority = 2)
+ : msg(_msg), priority(_priority)
+ {
+ timestamp = QDateTime::currentDateTime();
+ }
+
+ QString getMsg() const { return msg; }
+ int getPriority() const { return priority; }
+ QDateTime getTimestamp() const { return timestamp; }
+
+private:
+ QString msg;
+ int priority;
+ QDateTime timestamp;
+};
+
+#endif /* WPAMSG_H */
diff --git a/wpa_supplicant/wpa_priv.c b/wpa_supplicant/wpa_priv.c
index 4a27125..4ff0284 100644
--- a/wpa_supplicant/wpa_priv.c
+++ b/wpa_supplicant/wpa_priv.c
@@ -172,12 +172,12 @@ static void wpa_priv_get_scan_results2(struct wpa_priv_interface *iface,
sizeof(*from));
os_free(buf);
- os_free(res);
+ wpa_scan_results_free(res);
return;
fail:
os_free(buf);
- os_free(res);
+ wpa_scan_results_free(res);
sendto(iface->fd, "", 0, 0, (struct sockaddr *) from, sizeof(*from));
}
diff --git a/wpa_supplicant/wpa_supplicant.c b/wpa_supplicant/wpa_supplicant.c
index c1f95cb..3a5c7cb 100644
--- a/wpa_supplicant/wpa_supplicant.c
+++ b/wpa_supplicant/wpa_supplicant.c
@@ -385,6 +385,9 @@ static void wpa_supplicant_cleanup(struct wpa_supplicant *wpa_s)
ieee80211_sta_deinit(wpa_s);
wpas_wps_deinit(wpa_s);
+
+ wpabuf_free(wpa_s->pending_eapol_rx);
+ wpa_s->pending_eapol_rx = NULL;
}
@@ -418,6 +421,10 @@ void wpa_clear_keys(struct wpa_supplicant *wpa_s, const u8 *addr)
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 1, 0, NULL, 0, NULL, 0);
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 2, 0, NULL, 0, NULL, 0);
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 3, 0, NULL, 0, NULL, 0);
+#ifdef CONFIG_IEEE80211W
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 4, 0, NULL, 0, NULL, 0);
+ wpa_drv_set_key(wpa_s, WPA_ALG_NONE, bcast, 5, 0, NULL, 0, NULL, 0);
+#endif /* CONFIG_IEEE80211W */
if (addr) {
wpa_drv_set_key(wpa_s, WPA_ALG_NONE, addr, 0, 0, NULL, 0, NULL,
0);
@@ -475,6 +482,9 @@ void wpa_supplicant_set_state(struct wpa_supplicant *wpa_s, wpa_states state)
wpa_supplicant_state_txt(wpa_s->wpa_state),
wpa_supplicant_state_txt(state));
+ if (state != WPA_SCANNING)
+ wpa_supplicant_notify_scanning(wpa_s, 0);
+
wpa_supplicant_dbus_notify_state_change(wpa_s, state,
wpa_s->wpa_state);
@@ -1226,7 +1236,6 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
int reason_code)
{
u8 *addr = NULL;
- wpa_supplicant_set_state(wpa_s, WPA_DISCONNECTED);
if (!is_zero_ether_addr(wpa_s->bssid)) {
if (wpa_s->use_client_mlme)
ieee80211_sta_deauthenticate(wpa_s, reason_code);
@@ -1236,11 +1245,10 @@ void wpa_supplicant_deauthenticate(struct wpa_supplicant *wpa_s,
addr = wpa_s->bssid;
}
wpa_clear_keys(wpa_s, addr);
+ wpa_supplicant_mark_disassoc(wpa_s);
wpa_s->current_ssid = NULL;
wpa_sm_set_config(wpa_s->wpa, NULL);
eapol_sm_notify_config(wpa_s->eapol, NULL, NULL);
- eapol_sm_notify_portEnabled(wpa_s->eapol, FALSE);
- eapol_sm_notify_portValid(wpa_s->eapol, FALSE);
}
@@ -1471,12 +1479,14 @@ static int wpa_supplicant_set_driver(struct wpa_supplicant *wpa_s,
if (name == NULL) {
/* default to first driver in the list */
wpa_s->driver = wpa_supplicant_drivers[0];
+ wpa_s->global_drv_priv = wpa_s->global->drv_priv[0];
return 0;
}
for (i = 0; wpa_supplicant_drivers[i]; i++) {
if (os_strcmp(name, wpa_supplicant_drivers[i]->name) == 0) {
wpa_s->driver = wpa_supplicant_drivers[i];
+ wpa_s->global_drv_priv = wpa_s->global->drv_priv[i];
return 0;
}
}
@@ -1494,6 +1504,27 @@ void wpa_supplicant_rx_eapol(void *ctx, const u8 *src_addr,
wpa_printf(MSG_DEBUG, "RX EAPOL from " MACSTR, MAC2STR(src_addr));
wpa_hexdump(MSG_MSGDUMP, "RX EAPOL", buf, len);
+ if (wpa_s->wpa_state < WPA_ASSOCIATED) {
+ /*
+ * There is possible race condition between receiving the
+ * association event and the EAPOL frame since they are coming
+ * through different paths from the driver. In order to avoid
+ * issues in trying to process the EAPOL frame before receiving
+ * association information, lets queue it for processing until
+ * the association event is received.
+ */
+ wpa_printf(MSG_DEBUG, "Not associated - Delay processing of "
+ "received EAPOL frame");
+ wpabuf_free(wpa_s->pending_eapol_rx);
+ wpa_s->pending_eapol_rx = wpabuf_alloc_copy(buf, len);
+ if (wpa_s->pending_eapol_rx) {
+ os_get_time(&wpa_s->pending_eapol_rx_time);
+ os_memcpy(wpa_s->pending_eapol_rx_src, src_addr,
+ ETH_ALEN);
+ }
+ return;
+ }
+
if (wpa_s->key_mgmt == WPA_KEY_MGMT_NONE) {
wpa_printf(MSG_DEBUG, "Ignored received EAPOL frame since "
"no key management is configured");
@@ -1915,6 +1946,8 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
if (wpa_s == NULL)
return NULL;
+ wpa_s->global = global;
+
if (wpa_supplicant_init_iface(wpa_s, iface) ||
wpa_supplicant_init_iface2(wpa_s)) {
wpa_printf(MSG_DEBUG, "Failed to add interface %s",
@@ -1924,15 +1957,13 @@ struct wpa_supplicant * wpa_supplicant_add_iface(struct wpa_global *global,
return NULL;
}
- wpa_s->global = global;
-
/* Register the interface with the dbus control interface */
if (wpas_dbus_register_iface(wpa_s)) {
wpa_supplicant_deinit_iface(wpa_s);
os_free(wpa_s);
return NULL;
}
-
+
wpa_s->next = global->ifaces;
global->ifaces = wpa_s;
diff --git a/wpa_supplicant/wpa_supplicant_i.h b/wpa_supplicant/wpa_supplicant_i.h
index 5e4dcc1..b441cbb 100644
--- a/wpa_supplicant/wpa_supplicant_i.h
+++ b/wpa_supplicant/wpa_supplicant_i.h
@@ -305,6 +305,7 @@ struct wpa_supplicant {
int mgmt_group_cipher;
void *drv_priv; /* private data used by driver_ops */
+ void *global_drv_priv;
struct wpa_ssid *prev_scan_ssid; /* previously scanned SSID;
* NULL = not yet initialized (start
@@ -325,6 +326,7 @@ struct wpa_supplicant {
struct ctrl_iface_priv *ctrl_iface;
wpa_states wpa_state;
+ int scanning;
int new_connection;
int reassociated_connection;
@@ -358,6 +360,10 @@ struct wpa_supplicant {
struct wps_context *wps;
int wps_success; /* WPS success event received */
int blacklist_cleared;
+
+ struct wpabuf *pending_eapol_rx;
+ struct os_time pending_eapol_rx_time;
+ u8 pending_eapol_rx_src[ETH_ALEN];
};
@@ -404,8 +410,11 @@ int wpa_supplicant_scard_init(struct wpa_supplicant *wpa_s,
struct wpa_ssid *ssid);
/* scan.c */
+int wpa_supplicant_enabled_networks(struct wpa_config *conf);
void wpa_supplicant_req_scan(struct wpa_supplicant *wpa_s, int sec, int usec);
void wpa_supplicant_cancel_scan(struct wpa_supplicant *wpa_s);
+void wpa_supplicant_notify_scanning(struct wpa_supplicant *wpa_s,
+ int scanning);
/* events.c */
void wpa_supplicant_mark_disassoc(struct wpa_supplicant *wpa_s);
@@ -415,7 +424,8 @@ 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);
+ 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);
}
diff --git a/wpa_supplicant/wpas_glue.c b/wpa_supplicant/wpas_glue.c
index 2b96aa7..fc72cb8 100644
--- a/wpa_supplicant/wpas_glue.c
+++ b/wpa_supplicant/wpas_glue.c
@@ -402,7 +402,7 @@ static void _wpa_supplicant_disassociate(void *wpa_s, int reason_code)
{
wpa_supplicant_disassociate(wpa_s, reason_code);
/* Schedule a scan to make sure we continue looking for networks */
- wpa_supplicant_req_scan(wpa_s, 0, 0);
+ wpa_supplicant_req_scan(wpa_s, 5, 0);
}
@@ -410,7 +410,7 @@ 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, 0, 0);
+ wpa_supplicant_req_scan(wpa_s, 5, 0);
}
diff --git a/wpa_supplicant/wps_supplicant.c b/wpa_supplicant/wps_supplicant.c
index 9b73601..9422b1b 100644
--- a/wpa_supplicant/wps_supplicant.c
+++ b/wpa_supplicant/wps_supplicant.c
@@ -26,8 +26,10 @@
#include "ctrl_iface_dbus.h"
#include "eap_common/eap_wsc_common.h"
#include "blacklist.h"
+#include "wpa.h"
#include "wps_supplicant.h"
+
#define WPS_PIN_SCAN_IGNORE_SEL_REG 3
static void wpas_wps_timeout(void *eloop_ctx, void *timeout_ctx);
@@ -83,11 +85,109 @@ int wpas_wps_eapol_cb(struct wpa_supplicant *wpa_s)
}
+static void wpas_wps_security_workaround(struct wpa_supplicant *wpa_s,
+ struct wpa_ssid *ssid,
+ const struct wps_credential *cred)
+{
+ struct wpa_driver_capa capa;
+ size_t i;
+ struct wpa_scan_res *bss;
+ const u8 *ie;
+ struct wpa_ie_data adv;
+ int wpa2 = 0, ccmp = 0;
+
+ /*
+ * Many existing WPS APs do not know how to negotiate WPA2 or CCMP in
+ * case they are configured for mixed mode operation (WPA+WPA2 and
+ * TKIP+CCMP). Try to use scan results to figure out whether the AP
+ * actually supports stronger security and select that if the client
+ * has support for it, too.
+ */
+
+ if (wpa_drv_get_capa(wpa_s, &capa))
+ return; /* Unknown what driver supports */
+
+ if (wpa_supplicant_get_scan_results(wpa_s) || wpa_s->scan_res == NULL)
+ return; /* Could not get scan results for checking advertised
+ * parameters */
+
+ for (i = 0; i < wpa_s->scan_res->num; i++) {
+ bss = wpa_s->scan_res->res[i];
+ if (os_memcmp(bss->bssid, cred->mac_addr, ETH_ALEN) != 0)
+ continue;
+ ie = wpa_scan_get_ie(bss, WLAN_EID_SSID);
+ if (ie == NULL)
+ continue;
+ if (ie[1] != ssid->ssid_len || ssid->ssid == NULL ||
+ os_memcmp(ie + 2, ssid->ssid, ssid->ssid_len) != 0)
+ continue;
+
+ wpa_printf(MSG_DEBUG, "WPS: AP found from scan results");
+ break;
+ }
+
+ if (i == wpa_s->scan_res->num) {
+ wpa_printf(MSG_DEBUG, "WPS: The AP was not found from scan "
+ "results - use credential as-is");
+ return;
+ }
+
+ ie = wpa_scan_get_ie(bss, WLAN_EID_RSN);
+ if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0) {
+ wpa2 = 1;
+ if (adv.pairwise_cipher & WPA_CIPHER_CCMP)
+ ccmp = 1;
+ } else {
+ ie = wpa_scan_get_vendor_ie(bss, WPA_IE_VENDOR_TYPE);
+ if (ie && wpa_parse_wpa_ie(ie, 2 + ie[1], &adv) == 0 &&
+ adv.pairwise_cipher & WPA_CIPHER_CCMP)
+ ccmp = 1;
+ }
+
+ if (ie == NULL && (ssid->proto & WPA_PROTO_WPA) &&
+ (ssid->pairwise_cipher & WPA_CIPHER_TKIP)) {
+ /*
+ * TODO: This could be the initial AP configuration and the
+ * Beacon contents could change shortly. Should request a new
+ * scan and delay addition of the network until the updated
+ * scan results are available.
+ */
+ wpa_printf(MSG_DEBUG, "WPS: The AP did not yet advertise WPA "
+ "support - use credential as-is");
+ return;
+ }
+
+ if (ccmp && !(ssid->pairwise_cipher & WPA_CIPHER_CCMP) &&
+ (ssid->pairwise_cipher & WPA_CIPHER_TKIP) &&
+ (capa.key_mgmt & WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK)) {
+ wpa_printf(MSG_DEBUG, "WPS: Add CCMP into the credential "
+ "based on scan results");
+ if (wpa_s->conf->ap_scan == 1)
+ ssid->pairwise_cipher |= WPA_CIPHER_CCMP;
+ else
+ ssid->pairwise_cipher = WPA_CIPHER_CCMP;
+ }
+
+ if (wpa2 && !(ssid->proto & WPA_PROTO_RSN) &&
+ (ssid->proto & WPA_PROTO_WPA) &&
+ (capa.enc & WPA_DRIVER_CAPA_ENC_CCMP)) {
+ wpa_printf(MSG_DEBUG, "WPS: Add WPA2 into the credential "
+ "based on scan results");
+ if (wpa_s->conf->ap_scan == 1)
+ ssid->proto |= WPA_PROTO_RSN;
+ else
+ ssid->proto = WPA_PROTO_RSN;
+ }
+}
+
+
static int wpa_supplicant_wps_cred(void *ctx,
const struct wps_credential *cred)
{
struct wpa_supplicant *wpa_s = ctx;
struct wpa_ssid *ssid = wpa_s->current_ssid;
+ u8 key_idx = 0;
+ u16 auth_type;
if ((wpa_s->conf->wps_cred_processing == 1 ||
wpa_s->conf->wps_cred_processing == 2) && cred->cred_attr) {
@@ -110,13 +210,30 @@ static int wpa_supplicant_wps_cred(void *ctx,
if (wpa_s->conf->wps_cred_processing == 1)
return 0;
- if (cred->auth_type != WPS_AUTH_OPEN &&
- cred->auth_type != WPS_AUTH_SHARED &&
- cred->auth_type != WPS_AUTH_WPAPSK &&
- cred->auth_type != WPS_AUTH_WPA2PSK) {
+ wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
+ wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
+ cred->auth_type);
+ wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
+ wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
+ wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
+ cred->key, cred->key_len);
+ wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
+ MAC2STR(cred->mac_addr));
+
+ auth_type = cred->auth_type;
+ if (auth_type == (WPS_AUTH_WPAPSK | WPS_AUTH_WPA2PSK)) {
+ wpa_printf(MSG_DEBUG, "WPS: Workaround - convert mixed-mode "
+ "auth_type into WPA2PSK");
+ auth_type = WPS_AUTH_WPA2PSK;
+ }
+
+ if (auth_type != WPS_AUTH_OPEN &&
+ auth_type != WPS_AUTH_SHARED &&
+ auth_type != WPS_AUTH_WPAPSK &&
+ auth_type != WPS_AUTH_WPA2PSK) {
wpa_printf(MSG_DEBUG, "WPS: Ignored credentials for "
- "unsupported authentication type %d",
- cred->auth_type);
+ "unsupported authentication type 0x%x",
+ auth_type);
return 0;
}
@@ -151,13 +268,36 @@ static int wpa_supplicant_wps_cred(void *ctx,
case WPS_ENCR_NONE:
break;
case WPS_ENCR_WEP:
- if (cred->key_len > 0 && cred->key_len <= MAX_WEP_KEY_LEN &&
- cred->key_idx < NUM_WEP_KEYS) {
- os_memcpy(ssid->wep_key[cred->key_idx], cred->key,
+ if (cred->key_len <= 0)
+ break;
+ if (cred->key_len != 5 && cred->key_len != 13 &&
+ cred->key_len != 10 && cred->key_len != 26) {
+ wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key length "
+ "%lu", (unsigned long) cred->key_len);
+ return -1;
+ }
+ if (cred->key_idx > NUM_WEP_KEYS) {
+ wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key index %d",
+ cred->key_idx);
+ return -1;
+ }
+ if (cred->key_idx)
+ key_idx = cred->key_idx - 1;
+ if (cred->key_len == 10 || cred->key_len == 26) {
+ if (hexstr2bin((char *) cred->key,
+ ssid->wep_key[key_idx],
+ cred->key_len / 2) < 0) {
+ wpa_printf(MSG_ERROR, "WPS: Invalid WEP Key "
+ "%d", key_idx);
+ return -1;
+ }
+ ssid->wep_key_len[key_idx] = cred->key_len / 2;
+ } else {
+ os_memcpy(ssid->wep_key[key_idx], cred->key,
cred->key_len);
- ssid->wep_key_len[cred->key_idx] = cred->key_len;
- ssid->wep_tx_keyidx = cred->key_idx;
+ ssid->wep_key_len[key_idx] = cred->key_len;
}
+ ssid->wep_tx_keyidx = key_idx;
break;
case WPS_ENCR_TKIP:
ssid->pairwise_cipher = WPA_CIPHER_TKIP;
@@ -167,7 +307,7 @@ static int wpa_supplicant_wps_cred(void *ctx,
break;
}
- switch (cred->auth_type) {
+ switch (auth_type) {
case WPS_AUTH_OPEN:
ssid->auth_alg = WPA_AUTH_ALG_OPEN;
ssid->key_mgmt = WPA_KEY_MGMT_NONE;
@@ -225,6 +365,8 @@ static int wpa_supplicant_wps_cred(void *ctx,
}
}
+ wpas_wps_security_workaround(wpa_s, ssid, cred);
+
#ifndef CONFIG_NO_CONFIG_WRITE
if (wpa_s->conf->update_config &&
wpa_config_write(wpa_s->confname, wpa_s->conf)) {
@@ -277,6 +419,10 @@ static void wpa_supplicant_wps_event(void *ctx, enum wps_event event,
break;
case WPS_EV_PWD_AUTH_FAIL:
break;
+ case WPS_EV_PBC_OVERLAP:
+ break;
+ case WPS_EV_PBC_TIMEOUT:
+ break;
}
}
@@ -343,7 +489,7 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
if (bssid) {
size_t i;
- struct wpa_scan_res *res;
+ int count = 0;
os_memcpy(ssid->bssid, bssid, ETH_ALEN);
ssid->bssid_set = 1;
@@ -355,6 +501,7 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
for (i = 0; i < wpa_s->scan_res->num; i++) {
const u8 *ie;
+ struct wpa_scan_res *res;
res = wpa_s->scan_res->res[i];
if (os_memcmp(bssid, res->bssid, ETH_ALEN) != 0)
@@ -369,7 +516,18 @@ static struct wpa_ssid * wpas_wps_add_network(struct wpa_supplicant *wpa_s,
break;
os_memcpy(ssid->ssid, ie + 2, ie[1]);
ssid->ssid_len = ie[1];
- break;
+ wpa_hexdump_ascii(MSG_DEBUG, "WPS: Picked SSID from "
+ "scan results",
+ ssid->ssid, ssid->ssid_len);
+ count++;
+ }
+
+ if (count > 1) {
+ wpa_printf(MSG_DEBUG, "WPS: More than one SSID found "
+ "for the AP; use wildcard");
+ os_free(ssid->ssid);
+ ssid->ssid = NULL;
+ ssid->ssid_len = 0;
}
}
OpenPOWER on IntegriCloud