aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSam Leffler <sam@FreeBSD.org>2007-07-09 16:15:06 +0000
committerSam Leffler <sam@FreeBSD.org>2007-07-09 16:15:06 +0000
commit75cbf10273fddabf1de109ac241e64defd66eb38 (patch)
treec6f336fc28b042f00efc2373c71fceadfa394e52
parentb449aee71d92a35e5293f3df4f0a564f77fbd02b (diff)
downloadsrc-75cbf10273fddabf1de109ac241e64defd66eb38.tar.gz
src-75cbf10273fddabf1de109ac241e64defd66eb38.zip
Import of hostapd 0.5.8
Notes
Notes: svn path=/vendor/hostapd/dist/; revision=171322
-rw-r--r--contrib/hostapd/COPYING4
-rw-r--r--contrib/hostapd/ChangeLog129
-rw-r--r--contrib/hostapd/FREEBSD-Xlist9
-rw-r--r--contrib/hostapd/FREEBSD-upgrade8
-rw-r--r--contrib/hostapd/Makefile219
-rw-r--r--contrib/hostapd/README23
-rw-r--r--contrib/hostapd/accounting.c60
-rw-r--r--contrib/hostapd/accounting.h28
-rw-r--r--contrib/hostapd/aes.c12
-rw-r--r--contrib/hostapd/aes.h25
-rw-r--r--contrib/hostapd/aes_wrap.c377
-rw-r--r--contrib/hostapd/aes_wrap.h2
-rw-r--r--contrib/hostapd/ap.h64
-rw-r--r--contrib/hostapd/ap_list.c459
-rw-r--r--contrib/hostapd/ap_list.h68
-rw-r--r--contrib/hostapd/beacon.c419
-rw-r--r--contrib/hostapd/beacon.h24
-rw-r--r--contrib/hostapd/build_config.h50
-rw-r--r--contrib/hostapd/common.c479
-rw-r--r--contrib/hostapd/common.h312
-rw-r--r--contrib/hostapd/config.c1288
-rw-r--r--contrib/hostapd/config.h236
-rw-r--r--contrib/hostapd/config_types.h14
-rw-r--r--contrib/hostapd/crypto.c87
-rw-r--r--contrib/hostapd/crypto.h308
-rw-r--r--contrib/hostapd/ctrl_iface.c91
-rw-r--r--contrib/hostapd/ctrl_iface.h14
-rw-r--r--contrib/hostapd/defconfig29
-rw-r--r--contrib/hostapd/defs.h13
-rw-r--r--contrib/hostapd/des.c476
-rw-r--r--contrib/hostapd/doc/code_structure.doxygen5
-rw-r--r--contrib/hostapd/doc/ctrl_iface.doxygen66
-rw-r--r--contrib/hostapd/doc/doxygen.fast233
-rw-r--r--contrib/hostapd/doc/doxygen.full230
-rw-r--r--contrib/hostapd/doc/driver_wrapper.doxygen20
-rw-r--r--contrib/hostapd/doc/eap.doxygen56
-rw-r--r--contrib/hostapd/doc/hostapd.fig264
-rwxr-xr-xcontrib/hostapd/doc/kerneldoc2doxygen.pl129
-rw-r--r--contrib/hostapd/doc/mainpage.doxygen52
-rw-r--r--contrib/hostapd/doc/porting.doxygen5
-rw-r--r--contrib/hostapd/driver.h499
-rw-r--r--contrib/hostapd/driver_test.c742
-rw-r--r--contrib/hostapd/driver_wired.c35
-rw-r--r--contrib/hostapd/eap.c518
-rw-r--r--contrib/hostapd/eap.h38
-rw-r--r--contrib/hostapd/eap_aka.c848
-rw-r--r--contrib/hostapd/eap_defs.h39
-rw-r--r--contrib/hostapd/eap_gpsk.c646
-rw-r--r--contrib/hostapd/eap_gpsk_common.c441
-rw-r--r--contrib/hostapd/eap_gpsk_common.h66
-rw-r--r--contrib/hostapd/eap_gtc.c82
-rw-r--r--contrib/hostapd/eap_i.h84
-rw-r--r--contrib/hostapd/eap_identity.c88
-rw-r--r--contrib/hostapd/eap_md5.c92
-rw-r--r--contrib/hostapd/eap_methods.c273
-rw-r--r--contrib/hostapd/eap_methods.h49
-rw-r--r--contrib/hostapd/eap_mschapv2.c282
-rw-r--r--contrib/hostapd/eap_pax.c105
-rw-r--r--contrib/hostapd/eap_pax_common.c20
-rw-r--r--contrib/hostapd/eap_pax_common.h31
-rw-r--r--contrib/hostapd/eap_peap.c77
-rw-r--r--contrib/hostapd/eap_psk.c108
-rw-r--r--contrib/hostapd/eap_psk_common.c25
-rw-r--r--contrib/hostapd/eap_psk_common.h29
-rw-r--r--contrib/hostapd/eap_sake.c547
-rw-r--r--contrib/hostapd/eap_sake_common.c380
-rw-r--r--contrib/hostapd/eap_sake_common.h104
-rw-r--r--contrib/hostapd/eap_sim.c443
-rw-r--r--contrib/hostapd/eap_sim_common.c316
-rw-r--r--contrib/hostapd/eap_sim_common.h76
-rw-r--r--contrib/hostapd/eap_sim_db.c1284
-rw-r--r--contrib/hostapd/eap_sim_db.h97
-rw-r--r--contrib/hostapd/eap_tls.c83
-rw-r--r--contrib/hostapd/eap_tls_common.c64
-rw-r--r--contrib/hostapd/eap_tls_common.h14
-rw-r--r--contrib/hostapd/eap_tlv.c52
-rw-r--r--contrib/hostapd/eap_ttls.c495
-rw-r--r--contrib/hostapd/eap_ttls.h14
-rw-r--r--contrib/hostapd/eap_vendor_test.c228
-rw-r--r--contrib/hostapd/eapol_sm.c457
-rw-r--r--contrib/hostapd/eapol_sm.h178
-rw-r--r--contrib/hostapd/eapol_version.patch129
-rw-r--r--contrib/hostapd/eloop.c332
-rw-r--r--contrib/hostapd/eloop.h207
-rw-r--r--contrib/hostapd/eloop_none.c390
-rw-r--r--contrib/hostapd/eloop_win.c604
-rw-r--r--contrib/hostapd/hlr_auc_gw.c588
-rw-r--r--contrib/hostapd/hlr_auc_gw.milenage_db9
-rw-r--r--contrib/hostapd/hostap_common.h370
-rw-r--r--contrib/hostapd/hostapd.87
-rw-r--r--contrib/hostapd/hostapd.c1416
-rw-r--r--contrib/hostapd/hostapd.conf384
-rw-r--r--contrib/hostapd/hostapd.eap_user43
-rw-r--r--contrib/hostapd/hostapd.h140
-rw-r--r--contrib/hostapd/hostapd.vlan9
-rw-r--r--contrib/hostapd/hostapd_cli.12
-rw-r--r--contrib/hostapd/hostapd_cli.c31
-rw-r--r--contrib/hostapd/hw_features.c429
-rw-r--r--contrib/hostapd/hw_features.h61
-rw-r--r--contrib/hostapd/iapp.c58
-rw-r--r--contrib/hostapd/iapp.h23
-rw-r--r--contrib/hostapd/ieee802_11.c658
-rw-r--r--contrib/hostapd/ieee802_11.h238
-rw-r--r--contrib/hostapd/ieee802_11_auth.c73
-rw-r--r--contrib/hostapd/ieee802_11_auth.h25
-rw-r--r--contrib/hostapd/ieee802_11h.c34
-rw-r--r--contrib/hostapd/ieee802_11h.h27
-rw-r--r--contrib/hostapd/ieee802_1x.c718
-rw-r--r--contrib/hostapd/ieee802_1x.h60
-rw-r--r--contrib/hostapd/includes.h57
-rw-r--r--contrib/hostapd/l2_packet.h12
-rw-r--r--contrib/hostapd/l2_packet_none.c123
-rw-r--r--contrib/hostapd/md4.c282
-rw-r--r--contrib/hostapd/md5.c53
-rw-r--r--contrib/hostapd/md5.h11
-rw-r--r--contrib/hostapd/milenage.c1053
-rw-r--r--contrib/hostapd/milenage.h26
-rw-r--r--contrib/hostapd/mlme.c176
-rw-r--r--contrib/hostapd/mlme.h40
-rw-r--r--contrib/hostapd/ms_funcs.c245
-rw-r--r--contrib/hostapd/ms_funcs.h13
-rw-r--r--contrib/hostapd/os.h485
-rw-r--r--contrib/hostapd/os_internal.c441
-rw-r--r--contrib/hostapd/os_none.c220
-rw-r--r--contrib/hostapd/os_unix.c212
-rw-r--r--contrib/hostapd/pmksa_cache.c366
-rw-r--r--contrib/hostapd/pmksa_cache.h54
-rw-r--r--contrib/hostapd/preauth.c276
-rw-r--r--contrib/hostapd/preauth.h58
-rw-r--r--contrib/hostapd/radius.c295
-rw-r--r--contrib/hostapd/radius.h48
-rw-r--r--contrib/hostapd/radius_client.c427
-rw-r--r--contrib/hostapd/radius_client.h22
-rw-r--r--contrib/hostapd/radius_server.c368
-rw-r--r--contrib/hostapd/radius_server.h21
-rw-r--r--contrib/hostapd/rc4.c7
-rw-r--r--contrib/hostapd/rc4.h2
-rw-r--r--contrib/hostapd/reconfig.c714
-rw-r--r--contrib/hostapd/sha1.c470
-rw-r--r--contrib/hostapd/sha1.h10
-rw-r--r--contrib/hostapd/sha256.c379
-rw-r--r--contrib/hostapd/sha256.h27
-rw-r--r--contrib/hostapd/sta_info.c298
-rw-r--r--contrib/hostapd/sta_info.h33
-rw-r--r--contrib/hostapd/state_machine.h144
-rw-r--r--contrib/hostapd/tls.h182
-rw-r--r--contrib/hostapd/tls_gnutls.c1370
-rw-r--r--contrib/hostapd/tls_none.c219
-rw-r--r--contrib/hostapd/tls_openssl.c418
-rw-r--r--contrib/hostapd/version.h2
-rw-r--r--contrib/hostapd/vlan_init.c835
-rw-r--r--contrib/hostapd/vlan_init.h31
-rw-r--r--contrib/hostapd/wme.c260
-rw-r--r--contrib/hostapd/wme.h146
-rw-r--r--contrib/hostapd/wpa.c3558
-rw-r--r--contrib/hostapd/wpa.h236
-rw-r--r--contrib/hostapd/wpa_common.h58
-rw-r--r--contrib/hostapd/wpa_ctrl.c296
-rw-r--r--contrib/hostapd/wpa_ctrl.h4
159 files changed, 32275 insertions, 6309 deletions
diff --git a/contrib/hostapd/COPYING b/contrib/hostapd/COPYING
index 60549be514af..14f5453722a8 100644
--- a/contrib/hostapd/COPYING
+++ b/contrib/hostapd/COPYING
@@ -2,7 +2,7 @@
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
@@ -305,7 +305,7 @@ the "copyright" line and a pointer to where the full notice is found.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
diff --git a/contrib/hostapd/ChangeLog b/contrib/hostapd/ChangeLog
index f7bd4102d094..73c63a86522d 100644
--- a/contrib/hostapd/ChangeLog
+++ b/contrib/hostapd/ChangeLog
@@ -1,9 +1,136 @@
ChangeLog for hostapd
-2006-02-08 - v0.4.8
+2007-05-28 - v0.5.8
+ * updated driver_devicescape.c to build with the current
+ wireless-dev.git tree and net/d80211 changes
+ * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+ draft (draft-ietf-emu-eap-gpsk-03.txt)
+ * fixed EAP-MSCHAPv2 server to use a space between S and M parameters
+ in Success Request [Bug 203]
+ * added support for sending EAP-AKA Notifications in error cases
+ * RADIUS server: added support for processing duplicate messages
+ (retransmissions from RADIUS client) by replying with the previous
+ reply
+
+2006-12-31 - v0.5.7
+ * updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48
+ * updated EAP-PSK to use the IANA-allocated EAP type 47
+ * fixed EAP-PSK bit ordering of the Flags field
+ * fixed configuration reloading (SIGHUP) to re-initialize WPA PSKs
+ by reading wpa_psk_file [Bug 181]
+ * fixed EAP-TTLS AVP parser processing for too short AVP lengths
+ * fixed IPv6 connection to RADIUS accounting server
+
+2006-11-24 - v0.5.6
+ * added support for configuring and controlling multiple BSSes per
+ radio interface (bss=<ifname> in hostapd.conf); this is only
+ available with Devicescape and test driver interfaces
+ * fixed PMKSA cache update in the end of successful RSN
+ pre-authentication
+ * added support for dynamic VLAN configuration (i.e., selecting VLAN-ID
+ for each STA based on RADIUS Access-Accept attributes); this requires
+ VLAN support from the kernel driver/802.11 stack and this is
+ currently only available with Devicescape and test driver interfaces
+ * driver_madwifi: fixed configuration of unencrypted modes (plaintext
+ and IEEE 802.1X without WEP)
+ * removed STAKey handshake since PeerKey handshake has replaced it in
+ IEEE 802.11ma and there are no known deployments of STAKey
+ * updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+ draft (draft-ietf-emu-eap-gpsk-01.txt)
+ * added preliminary implementation of IEEE 802.11w/D1.0 (management
+ frame protection)
+ (Note: this requires driver support to work properly.)
+ (Note2: IEEE 802.11w is an unapproved draft and subject to change.)
+ * hlr_auc_gw: added support for GSM-Milenage (for EAP-SIM)
+ * hlr_auc_gw: added support for reading per-IMSI Milenage keys and
+ parameters from a text file to make it possible to implement proper
+ GSM/UMTS authentication server for multiple SIM/USIM cards using
+ EAP-SIM/EAP-AKA
+ * fixed session timeout processing with drivers that do not use
+ ieee802_11.c (e.g., madwifi)
+
+2006-08-27 - v0.5.5
+ * added 'hostapd_cli new_sta <addr>' command for adding a new STA into
+ hostapd (e.g., to initialize wired network authentication based on an
+ external signal)
+ * fixed hostapd to add PMKID KDE into 4-Way Handshake Message 1 when
+ using WPA2 even if PMKSA caching is not used
+ * added -P<pid file> argument for hostapd to write the current process
+ id into a file
+ * added support for RADIUS Authentication Server MIB (RFC 2619)
+
+2006-06-20 - v0.5.4
+ * fixed nt_password_hash build [Bug 144]
+ * added PeerKey handshake implementation for IEEE 802.11e
+ direct link setup (DLS) to replace STAKey handshake
+ * added support for EAP Generalized Pre-Shared Key (EAP-GPSK,
+ draft-clancy-emu-eap-shared-secret-00.txt)
+ * fixed a segmentation fault when RSN pre-authentication was completed
+ successfully [Bug 152]
+
+2006-04-27 - v0.5.3
+ * do not build nt_password_hash and hlr_auc_gw by default to avoid
+ requiring a TLS library for a successful build; these programs can be
+ build with 'make nt_password_hash' and 'make hlr_auc_gw'
+ * added a new configuration option, eapol_version, that can be used to
+ set EAPOL version to 1 (default is 2) to work around broken client
+ implementations that drop EAPOL frames which use version number 2
+ [Bug 89]
+ * added support for EAP-SAKE (no EAP method number allocated yet, so
+ this is using the same experimental type 255 as EAP-PSK)
+ * fixed EAP-MSCHAPv2 message length validation
+
+2006-03-19 - v0.5.2
* fixed stdarg use in hostapd_logger(): if both stdout and syslog
logging was enabled, hostapd could trigger a segmentation fault in
vsyslog on some CPU -- C library combinations
+ * moved HLR/AuC gateway implementation for EAP-SIM/AKA into an external
+ program to make it easier to use for implementing real SS7 gateway;
+ eap_sim_db is not anymore used as a file name for GSM authentication
+ triplets; instead, it is path to UNIX domain socket that will be used
+ to communicate with the external gateway program (e.g., hlr_auc_gw)
+ * added example HLR/AuC gateway implementation, hlr_auc_gw, that uses
+ local information (GSM authentication triplets from a text file and
+ hardcoded AKA authentication data); this can be used to test EAP-SIM
+ and EAP-AKA
+ * added Milenage algorithm (example 3GPP AKA algorithm) to hlr_auc_gw
+ to make it possible to test EAP-AKA with real USIM cards (this is
+ disabled by default; define AKA_USE_MILENAGE when building hlr_auc_gw
+ to enable this)
+ * driver_madwifi: added support for getting station RSN IE from
+ madwifi-ng svn r1453 and newer; this fixes RSN that was apparently
+ broken with earlier change (r1357) in the driver
+ * changed EAP method registration to use a dynamic list of methods
+ instead of a static list generated at build time
+ * fixed WPA message 3/4 not to encrypt Key Data field (WPA IE)
+ [Bug 125]
+ * added ap_max_inactivity configuration parameter
+
+2006-01-29 - v0.5.1
+ * driver_test: added better support for multiple APs and STAs by using
+ a directory with sockets that include MAC address for each device in
+ the name (test_socket=DIR:/tmp/test)
+ * added support for EAP expanded type (vendor specific EAP methods)
+
+2005-12-18 - v0.5.0 (beginning of 0.5.x development releases)
+ * added experimental STAKey handshake implementation for IEEE 802.11e
+ direct link setup (DLS); note: this is disabled by default in both
+ build and runtime configuration (can be enabled with CONFIG_STAKEY=y
+ and stakey=1)
+ * added support for EAP methods to use callbacks to external programs
+ by buffering a pending request and processing it after the EAP method
+ is ready to continue
+ * improved EAP-SIM database interface to allow external request to GSM
+ HLR/AuC without blocking hostapd process
+ * added support for using EAP-SIM pseudonyms and fast re-authentication
+ * added support for EAP-AKA in the integrated EAP authenticator
+ * added support for matching EAP identity prefixes (e.g., "1"*) in EAP
+ user database to allow EAP-SIM/AKA selection without extra roundtrip
+ for EAP-Nak negotiation
+ * added support for storing EAP user password as NtPasswordHash instead
+ of plaintext password when using MSCHAP or MSCHAPv2 for
+ authentication (hash:<16-octet hex value>); added nt_password_hash
+ tool for hashing password to generate NtPasswordHash
2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases)
* driver_wired: fixed EAPOL sending to optionally use PAE group address
diff --git a/contrib/hostapd/FREEBSD-Xlist b/contrib/hostapd/FREEBSD-Xlist
index cba8df0ea7bd..1f544522a1b5 100644
--- a/contrib/hostapd/FREEBSD-Xlist
+++ b/contrib/hostapd/FREEBSD-Xlist
@@ -2,9 +2,16 @@ $FreeBSD$
.cvsignore
driver.c
driver_bsd.c
+driver_devicescape.c
driver_madwifi.c
driver_prism54.c
-l2_packet.c
+l2_packet_freebsd.c
+l2_packet_linux.c
+l2_packet_ndis.c
+l2_packet_pcap.c
+l2_packet_winpcap.c
+nt_password_hash.c
+os_win32.c
prism54.h
priv_netlink.h
wireless_copy.h
diff --git a/contrib/hostapd/FREEBSD-upgrade b/contrib/hostapd/FREEBSD-upgrade
index 5efe2f50c64f..08922051fe55 100644
--- a/contrib/hostapd/FREEBSD-upgrade
+++ b/contrib/hostapd/FREEBSD-upgrade
@@ -6,12 +6,12 @@ WPA/802.1x Authenticator
For the import files and directories were pruned by:
- tar -X FREEBSD-Xlist -zxf hostapd-0.3.7.tar.gz
+ tar -X FREEBSD-Xlist -zxf hostapd-0.5.8.tar.gz
then imported by:
- cvs import -m 'Import of hostapd 0.3.7' \
- src/contrib/hostapd MALINEN v0_3_7
+ cvs import -m 'Import of hostapd 0.5.8' \
+ src/contrib/hostapd MALINEN v0_5_8
To make local changes to hostapd, simply patch and commit to the
main branch (aka HEAD). Never make local changes on the vendor
@@ -21,4 +21,4 @@ All local changes should be submitted to Jouni Malinen for inclusion in
the next vendor release.
sam@FreeBSD.org
-4-June-2005
+7-July-2007
diff --git a/contrib/hostapd/Makefile b/contrib/hostapd/Makefile
index 276baeeed8c5..c98922b31aaf 100644
--- a/contrib/hostapd/Makefile
+++ b/contrib/hostapd/Makefile
@@ -1,6 +1,5 @@
CC=gcc
DIR_WPA_SUPPLICANT=.
-DIR_HOSTAP=.
ifndef CFLAGS
CFLAGS = -MMD -O2 -Wall -g
@@ -11,18 +10,41 @@ endif
CFLAGS += -DHOSTAPD_DUMP_STATE
# Include directories for CVS version
-CFLAGS += -I. -I$(DIR_HOSTAP) -I../utils -I$(DIR_WPA_SUPPLICANT)
+CFLAGS += -I. -I../utils -I$(DIR_WPA_SUPPLICANT)
# 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
-OBJS = hostapd.o eloop.o ieee802_1x.o eapol_sm.o radius.o md5.o rc4.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
+
+ifdef CONFIG_NATIVE_WINDOWS
+CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32
+endif
+
+OBJS = hostapd.o eloop.o ieee802_1x.o eapol_sm.o radius.o md5.o rc4.o md4.o \
common.o ieee802_11.o config.o ieee802_11_auth.o accounting.o \
sta_info.o radius_client.o sha1.o wpa.o aes_wrap.o ctrl_iface.o \
- driver_conf.o
+ driver_conf.o os_$(CONFIG_OS).o preauth.o pmksa_cache.o beacon.o \
+ hw_features.o wme.o ap_list.o reconfig.o \
+ mlme.o vlan_init.o ieee802_11h.o
--include .config
+HOBJS=hlr_auc_gw.o common.o os_$(CONFIG_OS).o milenage.o aes_wrap.o
+
+CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
ifdef CONFIG_IAPP
CFLAGS += -DCONFIG_IAPP
@@ -34,6 +56,15 @@ CFLAGS += -DCONFIG_RSN_PREAUTH
CONFIG_L2_PACKET=y
endif
+ifdef CONFIG_PEERKEY
+CFLAGS += -DCONFIG_PEERKEY
+endif
+
+ifdef CONFIG_IEEE80211W
+CFLAGS += -DCONFIG_IEEE80211W
+NEED_SHA256=y
+endif
+
ifdef CONFIG_DRIVER_HOSTAP
CFLAGS += -DCONFIG_DRIVER_HOSTAP
OBJS += driver.o
@@ -55,6 +86,11 @@ CFLAGS += -DCONFIG_DRIVER_PRISM54
OBJS += driver_prism54.o
endif
+ifdef CONFIG_DRIVER_DEVICESCAPE
+CFLAGS += -DCONFIG_DRIVER_DEVICESCAPE
+OBJS += driver_devicescape.o
+endif
+
ifdef CONFIG_DRIVER_BSD
CFLAGS += -DCONFIG_DRIVER_BSD
OBJS += driver_bsd.o
@@ -70,7 +106,6 @@ endif
ifdef CONFIG_L2_PACKET
ifdef CONFIG_DNET_PCAP
-CFLAGS += -DUSE_DNET_PCAP
ifdef CONFIG_L2_FREEBSD
LIBS += -lpcap
OBJS += $(DIR_WPA_SUPPLICANT)/l2_packet_freebsd.o
@@ -122,9 +157,21 @@ endif
ifdef CONFIG_EAP_SIM
CFLAGS += -DEAP_SIM
-OBJS += eap_sim.o $(DIR_WPA_SUPPLICANT)/eap_sim_common.o
-# Example EAP-SIM interface for GSM authentication. This can be replaced with
-# another file implementating the interface specified in eap_sim_db.h.
+OBJS += eap_sim.o
+CONFIG_EAP_SIM_COMMON=y
+endif
+
+ifdef CONFIG_EAP_AKA
+CFLAGS += -DEAP_AKA
+OBJS += eap_aka.o
+CONFIG_EAP_SIM_COMMON=y
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += $(DIR_WPA_SUPPLICANT)/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 += eap_sim_db.o
endif
@@ -138,6 +185,25 @@ CFLAGS += -DEAP_PSK
OBJS += eap_psk.o $(DIR_WPA_SUPPLICANT)/eap_psk_common.o
endif
+ifdef CONFIG_EAP_SAKE
+CFLAGS += -DEAP_SAKE
+OBJS += eap_sake.o $(DIR_WPA_SUPPLICANT)/eap_sake_common.o
+endif
+
+ifdef CONFIG_EAP_GPSK
+CFLAGS += -DEAP_GPSK
+OBJS += eap_gpsk.o $(DIR_WPA_SUPPLICANT)/eap_gpsk_common.o
+ifdef CONFIG_EAP_GPSK_SHA256
+CFLAGS += -DEAP_GPSK_SHA256
+NEED_SHA256=y
+endif
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+CFLAGS += -DEAP_VENDOR_TEST
+OBJS += eap_vendor_test.o
+endif
+
ifdef CONFIG_EAP_TLV
CFLAGS += -DEAP_TLV
OBJS += eap_tlv.o
@@ -145,15 +211,34 @@ endif
ifdef CONFIG_EAP
CFLAGS += -DEAP_SERVER
-OBJS += eap.o eap_identity.o
+OBJS += eap.o eap_methods.o eap_identity.o
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
endif
ifdef TLS_FUNCS
# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
CFLAGS += -DEAP_TLS_FUNCS
-OBJS += eap_tls_common.o $(DIR_WPA_SUPPLICANT)/tls_openssl.o
+OBJS += eap_tls_common.o
+ifeq ($(CONFIG_TLS), openssl)
+OBJS += $(DIR_WPA_SUPPLICANT)/tls_openssl.o
LIBS += -lssl -lcrypto
LIBS_p += -lcrypto
+LIBS_h += -lcrypto
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+OBJS += $(DIR_WPA_SUPPLICANT)/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
+NEED_CRYPTO=y
else
OBJS += $(DIR_WPA_SUPPLICANT)/tls_none.o
endif
@@ -163,10 +248,60 @@ CFLAGS += -DPKCS12_FUNCS
endif
ifdef MS_FUNCS
+OBJS += $(DIR_WPA_SUPPLICANT)/ms_funcs.o
+NEED_CRYPTO=y
+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
-OBJS += $(DIR_WPA_SUPPLICANT)/ms_funcs.o $(DIR_WPA_SUPPLICANT)/crypto.o
+endif
+ifeq ($(CONFIG_TLS), openssl)
+OBJS += $(DIR_WPA_SUPPLICANT)/crypto.o
+OBJS_p += $(DIR_WPA_SUPPLICANT)/crypto.o
+HOBJS += $(DIR_WPA_SUPPLICANT)/crypto.o
+CONFIG_INTERNAL_SHA256=y
+endif
+ifeq ($(CONFIG_TLS), gnutls)
+OBJS += $(DIR_WPA_SUPPLICANT)/crypto_gnutls.o
+OBJS_p += $(DIR_WPA_SUPPLICANT)/crypto_gnutls.o
+HOBJS += $(DIR_WPA_SUPPLICANT)/crypto_gnutls.o
+CONFIG_INTERNAL_SHA256=y
+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 NEED_SHA256
+OBJS += sha256.o
endif
ifdef CONFIG_RADIUS_SERVER
@@ -178,6 +313,12 @@ ifdef CONFIG_IPV6
CFLAGS += -DCONFIG_IPV6
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
+
ALL=hostapd hostapd_cli
all: verify_config $(ALL)
@@ -201,10 +342,7 @@ driver_conf.c: Makefile .config
rm -f driver_conf.c
echo '/* THIS FILE AUTOMATICALLY GENERATED, DO NOT EDIT! */' \
> driver_conf.c
- echo '#include <stdlib.h>' >> driver_conf.c
- echo '#include <stdio.h>' >> driver_conf.c
- echo '#include <sys/types.h>' >> driver_conf.c
- echo '#include <netinet/in.h>' >> driver_conf.c
+ echo '#include "includes.h"' >> driver_conf.c
echo '#include "hostapd.h"' >> driver_conf.c
echo '#include "driver.h"' >> driver_conf.c
ifdef CONFIG_DRIVER_HOSTAP
@@ -219,6 +357,9 @@ endif
ifdef CONFIG_DRIVER_PRISM54
echo "void prism54_driver_register(void);" >> driver_conf.c
endif
+ifdef CONFIG_DRIVER_DEVICESCAPE
+ echo "void devicescape_driver_register(void);" >> driver_conf.c
+endif
ifdef CONFIG_DRIVER_BSD
echo "void bsd_driver_register(void);" >> driver_conf.c
endif
@@ -238,6 +379,9 @@ endif
ifdef CONFIG_DRIVER_PRISM54
echo "prism54_driver_register();" >> driver_conf.c
endif
+ifdef CONFIG_DRIVER_DEVICESCAPE
+ echo "devicescape_driver_register();" >> driver_conf.c
+endif
ifdef CONFIG_DRIVER_BSD
echo "bsd_driver_register();" >> driver_conf.c
endif
@@ -249,7 +393,48 @@ endif
hostapd_cli: hostapd_cli.o $(DIR_WPA_SUPPLICANT)/wpa_ctrl.o
$(CC) -o hostapd_cli hostapd_cli.o $(DIR_WPA_SUPPLICANT)/wpa_ctrl.o
+NOBJS = nt_password_hash.o $(DIR_WPA_SUPPLICANT)/ms_funcs.o sha1.o rc4.o md5.o
+NOBJS += $(DIR_WPA_SUPPLICANT)/crypto.o 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:
- rm -f core *~ *.o hostapd hostapd_cli *.d driver_conf.c
+ rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw
+ rm -f *.d driver_conf.c
+
+%.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
+ doxygen doc/doxygen.full
+ $(MAKE) -C doc/latex
+ cp doc/latex/refman.pdf hostapd-devel.pdf
+
+docs-fast: docs-pics
+ doxygen doc/doxygen.fast
+
+clean-docs:
+ rm -rf doc/latex doc/html
+ rm -f doc/hosta.d{eps,png} hostapd-devel.pdf
+
+TEST_SRC_MILENAGE = milenage.c aes_wrap.c common.c os_$(CONFIG_OS).c
+test-milenage: $(TEST_SRC_MILENAGE)
+ $(CC) -o test-milenage -Wall -Werror $(TEST_SRC_MILENAGE) \
+ -DTEST_MAIN_MILENAGE -I. -I../wpa_supplicant -DINTERNAL_AES
+ ./test-milenage
+ rm test-milenage
-include $(OBJS:%.o=%.d)
diff --git a/contrib/hostapd/README b/contrib/hostapd/README
index d5354624b5da..541fac428515 100644
--- a/contrib/hostapd/README
+++ b/contrib/hostapd/README
@@ -2,8 +2,7 @@ hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
Authenticator and RADIUS authentication server
================================================================
-Copyright (c) 2002-2006, Jouni Malinen <jkmaline@cc.hut.fi> and
-contributors
+Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is dual-licensed under both the GPL version 2 and BSD
@@ -27,13 +26,13 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
(this copy of the license is in COPYING file)
-Alternatively, this software may be distributed under the terms of BSD
-license:
+Alternatively, this software may be distributed, used, and modified
+under the terms of BSD license:
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
@@ -92,9 +91,9 @@ Current hardware/software requirements:
madwifi driver for cards based on Atheros chip set (ar521x)
(http://sourceforge.net/projects/madwifi/)
- Please note that you will need to modify the hostapd Makefile
- to use correct path for madwifi driver root directory
- (CFLAGS += -I../head line in Makefile).
+ Please note that you will need to add the correct path for
+ madwifi driver root directory in .config (see defconfig file for
+ an example: CFLAGS += -I<path>)
Prism54 driver for Intersil/Conexant Prism GT/Duette/Indigo
(http://www.prism54.org/)
@@ -158,14 +157,6 @@ receives 802.1X (EAPOL) frames from the Supplicant using the wlan#ap
device that is also used with IEEE 802.11 management frames. The
frames to the Supplicant are sent using the same device.
-hostapd includes a minimal colocated Authentication Server for testing
-purposes. It only requests the identity of the Supplicant and
-authorizes any host that is able to send a valid EAP Response
-frame. This can be used for quick testing since it does not require an
-external Authentication Server, but it should not be used for any real
-authentication purposes since no keys are required and anyone can
-authenticate.
-
The normal configuration of the Authenticator would use an external
Authentication Server. hostapd supports RADIUS encapsulation of EAP
packets, so the Authentication Server should be a RADIUS server, like
diff --git a/contrib/hostapd/accounting.c b/contrib/hostapd/accounting.c
index 5ee3d750f9f2..b22347b2ac2e 100644
--- a/contrib/hostapd/accounting.c
+++ b/contrib/hostapd/accounting.c
@@ -1,7 +1,6 @@
/*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / Accounting
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * hostapd / RADIUS Accounting
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -13,18 +12,8 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <sys/ioctl.h>
-#include <signal.h>
+#include "includes.h"
#include <assert.h>
-#include <time.h>
-#include <sys/time.h>
-#include <sys/socket.h>
-
#include "hostapd.h"
#include "radius.h"
@@ -40,7 +29,13 @@
* input/output octets and updates Acct-{Input,Output}-Gigawords. */
#define ACCT_DEFAULT_UPDATE_INTERVAL 300
-static struct radius_msg * accounting_msg(hostapd *hapd, struct sta_info *sta,
+/* from ieee802_1x.c */
+const char *radius_mode_txt(struct hostapd_data *hapd);
+int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta);
+
+
+static struct radius_msg * accounting_msg(struct hostapd_data *hapd,
+ struct sta_info *sta,
int status_type)
{
struct radius_msg *msg;
@@ -131,7 +126,7 @@ static struct radius_msg * accounting_msg(hostapd *hapd, struct sta_info *sta,
}
snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
- MAC2STR(hapd->own_addr), hapd->conf->ssid);
+ MAC2STR(hapd->own_addr), hapd->conf->ssid.ssid);
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
(u8 *) buf, strlen(buf))) {
printf("Could not add Called-Station-Id\n");
@@ -154,7 +149,10 @@ static struct radius_msg * accounting_msg(hostapd *hapd, struct sta_info *sta,
goto fail;
}
- snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
+ snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
+ radius_sta_rate(hapd, sta) / 2,
+ (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
+ radius_mode_txt(hapd));
if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
(u8 *) buf, strlen(buf))) {
printf("Could not add Connect-Info\n");
@@ -211,7 +209,7 @@ static int accounting_sta_update_stats(struct hostapd_data *hapd,
static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
{
- hostapd *hapd = eloop_ctx;
+ struct hostapd_data *hapd = eloop_ctx;
struct sta_info *sta = timeout_ctx;
int interval;
@@ -229,11 +227,11 @@ static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
}
-void accounting_sta_start(hostapd *hapd, struct sta_info *sta)
+void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
{
struct radius_msg *msg;
int interval;
-
+
if (sta->acct_session_started)
return;
@@ -260,7 +258,8 @@ void accounting_sta_start(hostapd *hapd, struct sta_info *sta)
}
-void accounting_sta_report(hostapd *hapd, struct sta_info *sta, int stop)
+void accounting_sta_report(struct hostapd_data *hapd, struct sta_info *sta,
+ int stop)
{
struct radius_msg *msg;
int cause = sta->acct_terminate_cause;
@@ -360,14 +359,14 @@ void accounting_sta_report(hostapd *hapd, struct sta_info *sta, int stop)
}
-void accounting_sta_interim(hostapd *hapd, struct sta_info *sta)
+void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta)
{
if (sta->acct_session_started)
accounting_sta_report(hapd, sta, 0);
}
-void accounting_sta_stop(hostapd *hapd, struct sta_info *sta)
+void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
{
if (sta->acct_session_started) {
accounting_sta_report(hapd, sta, 1);
@@ -435,7 +434,7 @@ static void accounting_report_state(struct hostapd_data *hapd, int on)
}
-int accounting_init(hostapd *hapd)
+int accounting_init(struct hostapd_data *hapd)
{
/* Acct-Session-Id should be unique over reboots. If reliable clock is
* not available, this could be replaced with reboot counter, etc. */
@@ -451,7 +450,18 @@ int accounting_init(hostapd *hapd)
}
-void accounting_deinit(hostapd *hapd)
+void accounting_deinit(struct hostapd_data *hapd)
{
accounting_report_state(hapd, 0);
}
+
+
+int accounting_reconfig(struct hostapd_data *hapd,
+ struct hostapd_config *oldconf)
+{
+ if (!hapd->radius_client_reconfigured)
+ return 0;
+
+ accounting_deinit(hapd);
+ return accounting_init(hapd);
+}
diff --git a/contrib/hostapd/accounting.h b/contrib/hostapd/accounting.h
index 8af3eac59cb5..ee2ee64e3b02 100644
--- a/contrib/hostapd/accounting.h
+++ b/contrib/hostapd/accounting.h
@@ -1,13 +1,27 @@
+/*
+ * hostapd / RADIUS Accounting
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
#ifndef ACCOUNTING_H
#define ACCOUNTING_H
-
-void accounting_sta_start(hostapd *hapd, struct sta_info *sta);
-void accounting_sta_interim(hostapd *hapd, struct sta_info *sta);
-void accounting_sta_stop(hostapd *hapd, struct sta_info *sta);
+void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta);
+void accounting_sta_interim(struct hostapd_data *hapd, struct sta_info *sta);
+void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta);
void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
-int accounting_init(hostapd *hapd);
-void accounting_deinit(hostapd *hapd);
-
+int accounting_init(struct hostapd_data *hapd);
+void accounting_deinit(struct hostapd_data *hapd);
+int accounting_reconfig(struct hostapd_data *hapd,
+ struct hostapd_config *oldconf);
#endif /* ACCOUNTING_H */
diff --git a/contrib/hostapd/aes.c b/contrib/hostapd/aes.c
index ce94778dd62e..1a2459b3e013 100644
--- a/contrib/hostapd/aes.c
+++ b/contrib/hostapd/aes.c
@@ -9,7 +9,7 @@
* cost of reduced throughput (quite small difference on Pentium 4,
* 10-25% when using -O1 or -O2 optimization)
*
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * 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
@@ -21,6 +21,8 @@
* See README and COPYING for more details.
*/
+#include "includes.h"
+
/*
* rijndael-alg-fst.c
*
@@ -1060,7 +1062,7 @@ void * aes_encrypt_init(const u8 *key, size_t len)
u32 *rk;
if (len != 16)
return NULL;
- rk = malloc(4 * 44);
+ rk = os_malloc(4 * 44);
if (rk == NULL)
return NULL;
rijndaelKeySetupEnc(rk, key);
@@ -1076,7 +1078,7 @@ void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
void aes_encrypt_deinit(void *ctx)
{
- free(ctx);
+ os_free(ctx);
}
@@ -1085,7 +1087,7 @@ void * aes_decrypt_init(const u8 *key, size_t len)
u32 *rk;
if (len != 16)
return NULL;
- rk = malloc(4 * 44);
+ rk = os_malloc(4 * 44);
if (rk == NULL)
return NULL;
rijndaelKeySetupDec(rk, key);
@@ -1101,5 +1103,5 @@ void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
void aes_decrypt_deinit(void *ctx)
{
- free(ctx);
+ os_free(ctx);
}
diff --git a/contrib/hostapd/aes.h b/contrib/hostapd/aes.h
new file mode 100644
index 000000000000..6b9f4147afb1
--- /dev/null
+++ b/contrib/hostapd/aes.h
@@ -0,0 +1,25 @@
+/*
+ * AES functions
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef AES_H
+#define AES_H
+
+void * aes_encrypt_init(const u8 *key, size_t len);
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
+void aes_encrypt_deinit(void *ctx);
+void * aes_decrypt_init(const u8 *key, size_t len);
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
+void aes_decrypt_deinit(void *ctx);
+
+#endif /* AES_H */
diff --git a/contrib/hostapd/aes_wrap.c b/contrib/hostapd/aes_wrap.c
index a5925ca2ec47..c52e45af27c5 100644
--- a/contrib/hostapd/aes_wrap.c
+++ b/contrib/hostapd/aes_wrap.c
@@ -7,7 +7,7 @@
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
*
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * 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
@@ -19,17 +19,18 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
+
#include "common.h"
#include "aes_wrap.h"
#include "crypto.h"
-#ifndef EAP_TLS_FUNCS
+#ifdef INTERNAL_AES
#include "aes.c"
-#endif /* EAP_TLS_FUNCS */
+#endif /* INTERNAL_AES */
+
+#ifndef CONFIG_NO_AES_WRAP
/**
* aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
@@ -49,8 +50,8 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
r = cipher + 8;
/* 1) Initialize variables. */
- memset(a, 0xa6, 8);
- memcpy(r, plain, 8 * n);
+ os_memset(a, 0xa6, 8);
+ os_memcpy(r, plain, 8 * n);
ctx = aes_encrypt_init(kek, 16);
if (ctx == NULL)
@@ -66,12 +67,12 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
for (j = 0; j <= 5; j++) {
r = cipher + 8;
for (i = 1; i <= n; i++) {
- memcpy(b, a, 8);
- memcpy(b + 8, r, 8);
+ os_memcpy(b, a, 8);
+ os_memcpy(b + 8, r, 8);
aes_encrypt(ctx, b, b);
- memcpy(a, b, 8);
+ os_memcpy(a, b, 8);
a[7] ^= n * j + i;
- memcpy(r, b + 8, 8);
+ os_memcpy(r, b + 8, 8);
r += 8;
}
}
@@ -86,6 +87,8 @@ int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
return 0;
}
+#endif /* CONFIG_NO_AES_WRAP */
+
/**
* aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
@@ -102,9 +105,9 @@ int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
void *ctx;
/* 1) Initialize variables. */
- memcpy(a, cipher, 8);
+ os_memcpy(a, cipher, 8);
r = plain;
- memcpy(r, cipher + 8, 8 * n);
+ os_memcpy(r, cipher + 8, 8 * n);
ctx = aes_decrypt_init(kek, 16);
if (ctx == NULL)
@@ -120,13 +123,13 @@ int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
for (j = 5; j >= 0; j--) {
r = plain + (n - 1) * 8;
for (i = n; i >= 1; i--) {
- memcpy(b, a, 8);
+ os_memcpy(b, a, 8);
b[7] ^= n * j + i;
- memcpy(b + 8, r, 8);
+ os_memcpy(b + 8, r, 8);
aes_decrypt(ctx, b, b);
- memcpy(a, b, 8);
- memcpy(r, b + 8, 8);
+ os_memcpy(a, b, 8);
+ os_memcpy(r, b + 8, 8);
r -= 8;
}
}
@@ -148,6 +151,8 @@ int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
#define BLOCK_SIZE 16
+#ifndef CONFIG_NO_AES_OMAC1
+
static void gf_mulx(u8 *pad)
{
int i, carry;
@@ -162,8 +167,8 @@ static void gf_mulx(u8 *pad)
/**
- * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128
- * @key: Key for the hash operation
+ * omac1_aes_128 - One-Key CBC MAC (OMAC1) hash with AES-128 (aka AES-CMAC)
+ * @key: 128-bit key for the hash operation
* @data: Data buffer for which a MAC is determined
* @data: Length of data buffer in bytes
* @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
@@ -174,13 +179,12 @@ int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
void *ctx;
u8 cbc[BLOCK_SIZE], pad[BLOCK_SIZE];
const u8 *pos = data;
- int i;
- size_t left = data_len;
+ size_t i, left = data_len;
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
- memset(cbc, 0, BLOCK_SIZE);
+ os_memset(cbc, 0, BLOCK_SIZE);
while (left >= BLOCK_SIZE) {
for (i = 0; i < BLOCK_SIZE; i++)
@@ -190,7 +194,7 @@ int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
left -= BLOCK_SIZE;
}
- memset(pad, 0, BLOCK_SIZE);
+ os_memset(pad, 0, BLOCK_SIZE);
aes_encrypt(ctx, pad, pad);
gf_mulx(pad);
@@ -208,6 +212,8 @@ int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
return 0;
}
+#endif /* CONFIG_NO_AES_OMAC1 */
+
/**
* aes_128_encrypt_block - Perform one AES 128-bit block operation
@@ -228,6 +234,8 @@ int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
}
+#ifndef CONFIG_NO_AES_CTR
+
/**
* aes_128_ctr_encrypt - AES-128 CTR mode encryption
* @key: Key for encryption (16 bytes)
@@ -240,7 +248,7 @@ int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
u8 *data, size_t data_len)
{
void *ctx;
- size_t len, left = data_len;
+ size_t j, len, left = data_len;
int i;
u8 *pos = data;
u8 counter[BLOCK_SIZE], buf[BLOCK_SIZE];
@@ -248,14 +256,14 @@ int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
- memcpy(counter, nonce, BLOCK_SIZE);
+ os_memcpy(counter, nonce, BLOCK_SIZE);
while (left > 0) {
aes_encrypt(ctx, counter, buf);
len = (left < BLOCK_SIZE) ? left : BLOCK_SIZE;
- for (i = 0; i < len; i++)
- pos[i] ^= buf[i];
+ for (j = 0; j < len; j++)
+ pos[j] ^= buf[j];
pos += len;
left -= len;
@@ -269,6 +277,10 @@ int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
return 0;
}
+#endif /* CONFIG_NO_AES_CTR */
+
+
+#ifndef CONFIG_NO_AES_EAX
/**
* aes_128_eax_encrypt - AES-128 EAX mode encryption
@@ -299,26 +311,26 @@ int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
buf_len = hdr_len;
buf_len += 16;
- buf = malloc(buf_len);
+ buf = os_malloc(buf_len);
if (buf == NULL)
return -1;
- memset(buf, 0, 15);
+ os_memset(buf, 0, 15);
buf[15] = 0;
- memcpy(buf + 16, nonce, nonce_len);
+ os_memcpy(buf + 16, nonce, nonce_len);
omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac);
buf[15] = 1;
- memcpy(buf + 16, hdr, hdr_len);
+ os_memcpy(buf + 16, hdr, hdr_len);
omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac);
aes_128_ctr_encrypt(key, nonce_mac, data, data_len);
buf[15] = 2;
- memcpy(buf + 16, data, data_len);
+ os_memcpy(buf + 16, data, data_len);
omac1_aes_128(key, buf, 16 + data_len, data_mac);
- free(buf);
+ os_free(buf);
for (i = 0; i < BLOCK_SIZE; i++)
tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i];
@@ -356,25 +368,25 @@ int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
buf_len = hdr_len;
buf_len += 16;
- buf = malloc(buf_len);
+ buf = os_malloc(buf_len);
if (buf == NULL)
return -1;
- memset(buf, 0, 15);
+ os_memset(buf, 0, 15);
buf[15] = 0;
- memcpy(buf + 16, nonce, nonce_len);
+ os_memcpy(buf + 16, nonce, nonce_len);
omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac);
buf[15] = 1;
- memcpy(buf + 16, hdr, hdr_len);
+ os_memcpy(buf + 16, hdr, hdr_len);
omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac);
buf[15] = 2;
- memcpy(buf + 16, data, data_len);
+ os_memcpy(buf + 16, data, data_len);
omac1_aes_128(key, buf, 16 + data_len, data_mac);
- free(buf);
+ os_free(buf);
for (i = 0; i < BLOCK_SIZE; i++) {
if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]))
@@ -386,6 +398,10 @@ int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
return 0;
}
+#endif /* CONFIG_NO_AES_EAX */
+
+
+#ifndef CONFIG_NO_AES_CBC
/**
* aes_128_cbc_encrypt - AES-128 CBC encryption
@@ -405,14 +421,14 @@ int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
ctx = aes_encrypt_init(key, 16);
if (ctx == NULL)
return -1;
- memcpy(cbc, iv, BLOCK_SIZE);
+ os_memcpy(cbc, iv, BLOCK_SIZE);
blocks = data_len / BLOCK_SIZE;
for (i = 0; i < blocks; i++) {
for (j = 0; j < BLOCK_SIZE; j++)
cbc[j] ^= pos[j];
aes_encrypt(ctx, cbc, cbc);
- memcpy(pos, cbc, BLOCK_SIZE);
+ os_memcpy(pos, cbc, BLOCK_SIZE);
pos += BLOCK_SIZE;
}
aes_encrypt_deinit(ctx);
@@ -438,288 +454,19 @@ int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
ctx = aes_decrypt_init(key, 16);
if (ctx == NULL)
return -1;
- memcpy(cbc, iv, BLOCK_SIZE);
+ os_memcpy(cbc, iv, BLOCK_SIZE);
blocks = data_len / BLOCK_SIZE;
for (i = 0; i < blocks; i++) {
- memcpy(tmp, pos, BLOCK_SIZE);
+ os_memcpy(tmp, pos, BLOCK_SIZE);
aes_decrypt(ctx, pos, pos);
for (j = 0; j < BLOCK_SIZE; j++)
pos[j] ^= cbc[j];
- memcpy(cbc, tmp, BLOCK_SIZE);
+ os_memcpy(cbc, tmp, BLOCK_SIZE);
pos += BLOCK_SIZE;
}
aes_decrypt_deinit(ctx);
return 0;
}
-
-#ifdef TEST_MAIN
-
-#ifdef __i386__
-#define rdtscll(val) \
- __asm__ __volatile__("rdtsc" : "=A" (val))
-
-static void test_aes_perf(void)
-{
- const int num_iters = 10;
- int i;
- unsigned int start, end;
- u8 key[16], pt[16], ct[16];
- void *ctx;
-
- printf("keySetupEnc:");
- for (i = 0; i < num_iters; i++) {
- rdtscll(start);
- ctx = aes_encrypt_init(key, 16);
- rdtscll(end);
- aes_encrypt_deinit(ctx);
- printf(" %d", end - start);
- }
- printf("\n");
-
- printf("Encrypt:");
- ctx = aes_encrypt_init(key, 16);
- for (i = 0; i < num_iters; i++) {
- rdtscll(start);
- aes_encrypt(ctx, pt, ct);
- rdtscll(end);
- printf(" %d", end - start);
- }
- aes_encrypt_deinit(ctx);
- printf("\n");
-}
-#endif /* __i386__ */
-
-
-static int test_eax(void)
-{
- u8 msg[] = { 0xF7, 0xFB };
- u8 key[] = { 0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B,
- 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4 };
- u8 nonce[] = { 0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84,
- 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD };
- u8 hdr[] = { 0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA };
- u8 cipher[] = { 0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D,
- 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79,
- 0x67, 0xE5 };
- u8 data[sizeof(msg)], tag[BLOCK_SIZE];
-
- memcpy(data, msg, sizeof(msg));
- if (aes_128_eax_encrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
- data, sizeof(data), tag)) {
- printf("AES-128 EAX mode encryption failed\n");
- return 1;
- }
- if (memcmp(data, cipher, sizeof(data)) != 0) {
- printf("AES-128 EAX mode encryption returned invalid cipher "
- "text\n");
- return 1;
- }
- if (memcmp(tag, cipher + sizeof(data), BLOCK_SIZE) != 0) {
- printf("AES-128 EAX mode encryption returned invalid tag\n");
- return 1;
- }
-
- if (aes_128_eax_decrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
- data, sizeof(data), tag)) {
- printf("AES-128 EAX mode decryption failed\n");
- return 1;
- }
- if (memcmp(data, msg, sizeof(data)) != 0) {
- printf("AES-128 EAX mode decryption returned invalid plain "
- "text\n");
- return 1;
- }
-
- return 0;
-}
-
-
-static int test_cbc(void)
-{
- struct cbc_test_vector {
- u8 key[16];
- u8 iv[16];
- u8 plain[32];
- u8 cipher[32];
- size_t len;
- } vectors[] = {
- {
- { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
- 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 },
- { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
- 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 },
- "Single block msg",
- { 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8,
- 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a },
- 16
- },
- {
- { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
- 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a },
- { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
- 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 },
- { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
- 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
- 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
- { 0xd2, 0x96, 0xcd, 0x94, 0xc2, 0xcc, 0xcf, 0x8a,
- 0x3a, 0x86, 0x30, 0x28, 0xb5, 0xe1, 0xdc, 0x0a,
- 0x75, 0x86, 0x60, 0x2d, 0x25, 0x3c, 0xff, 0xf9,
- 0x1b, 0x82, 0x66, 0xbe, 0xa6, 0xd6, 0x1a, 0xb1 },
- 32
- }
- };
- int i, ret = 0;
- u8 *buf;
-
- for (i = 0; i < sizeof(vectors) / sizeof(vectors[0]); i++) {
- struct cbc_test_vector *tv = &vectors[i];
- buf = malloc(tv->len);
- if (buf == NULL) {
- ret++;
- break;
- }
- memcpy(buf, tv->plain, tv->len);
- aes_128_cbc_encrypt(tv->key, tv->iv, buf, tv->len);
- if (memcmp(buf, tv->cipher, tv->len) != 0) {
- printf("AES-CBC encrypt %d failed\n", i);
- ret++;
- }
- memcpy(buf, tv->cipher, tv->len);
- aes_128_cbc_decrypt(tv->key, tv->iv, buf, tv->len);
- if (memcmp(buf, tv->plain, tv->len) != 0) {
- printf("AES-CBC decrypt %d failed\n", i);
- ret++;
- }
- free(buf);
- }
-
- return ret;
-}
-
-
-/* OMAC1 AES-128 test vectors from
- * http://csrc.nist.gov/CryptoToolkit/modes/proposedmodes/omac/omac-ad.pdf
- */
-
-struct omac1_test_vector {
- u8 k[16];
- u8 msg[64];
- int msg_len;
- u8 tag[16];
-};
-
-static struct omac1_test_vector test_vectors[] =
-{
- {
- { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
- 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
- { },
- 0,
- { 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
- 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 }
- },
- {
- { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
- 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
- { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
- 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
- 16,
- { 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
- 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c }
- },
- {
- { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
- 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
- { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
- 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
- 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
- 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
- 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 },
- 40,
- { 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
- 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 }
- },
- {
- { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
- 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
- { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
- 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
- 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
- 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
- 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
- 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
- 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
- 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
- 64,
- { 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
- 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe }
- },
-};
-
-
-int main(int argc, char *argv[])
-{
- u8 kek[] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
- };
- u8 plain[] = {
- 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
- 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
- };
- u8 crypt[] = {
- 0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47,
- 0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
- 0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
- };
- u8 result[24];
- int ret = 0, i;
- struct omac1_test_vector *tv;
-
- if (aes_wrap(kek, 2, plain, result)) {
- printf("AES-WRAP-128-128 reported failure\n");
- ret++;
- }
- if (memcmp(result, crypt, 24) != 0) {
- printf("AES-WRAP-128-128 failed\n");
- ret++;
- }
- if (aes_unwrap(kek, 2, crypt, result)) {
- printf("AES-UNWRAP-128-128 reported failure\n");
- ret++;
- }
- if (memcmp(result, plain, 16) != 0) {
- int i;
- printf("AES-UNWRAP-128-128 failed\n");
- ret++;
- for (i = 0; i < 16; i++)
- printf(" %02x", result[i]);
- printf("\n");
- }
-
-#ifdef __i386__
- test_aes_perf();
-#endif /* __i386__ */
-
- for (i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); i++) {
- tv = &test_vectors[i];
- omac1_aes_128(tv->k, tv->msg, tv->msg_len, result);
- if (memcmp(result, tv->tag, 16) != 0) {
- printf("OMAC1-AES-128 test vector %d failed\n", i);
- ret++;
- }
- }
-
- ret += test_eax();
-
- ret += test_cbc();
-
- if (ret)
- printf("FAILED!\n");
-
- return ret;
-}
-#endif /* TEST_MAIN */
+#endif /* CONFIG_NO_AES_CBC */
diff --git a/contrib/hostapd/aes_wrap.h b/contrib/hostapd/aes_wrap.h
index cb1a53967761..1bc6971eff8e 100644
--- a/contrib/hostapd/aes_wrap.h
+++ b/contrib/hostapd/aes_wrap.h
@@ -7,7 +7,7 @@
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
*
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * 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
diff --git a/contrib/hostapd/ap.h b/contrib/hostapd/ap.h
index e874ffd2b237..b73c5b47a6fb 100644
--- a/contrib/hostapd/ap.h
+++ b/contrib/hostapd/ap.h
@@ -1,3 +1,17 @@
+/*
+ * hostapd / Station table data structures
+ * Copyright (c) 2002-2004, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
#ifndef AP_H
#define AP_H
@@ -9,16 +23,13 @@
#define WLAN_STA_PERM BIT(4)
#define WLAN_STA_AUTHORIZED BIT(5)
#define WLAN_STA_PENDING_POLL BIT(6) /* pending activity poll not ACKed */
-#define WLAN_STA_PREAUTH BIT(7)
-
-#define WLAN_RATE_1M BIT(0)
-#define WLAN_RATE_2M BIT(1)
-#define WLAN_RATE_5M5 BIT(2)
-#define WLAN_RATE_11M BIT(3)
-#define WLAN_RATE_COUNT 4
+#define WLAN_STA_SHORT_PREAMBLE BIT(7)
+#define WLAN_STA_PREAUTH BIT(8)
+#define WLAN_STA_WME BIT(9)
+#define WLAN_STA_NONERP BIT(31)
-/* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8,
- * but some pre-standard IEEE 802.11g products use longer elements. */
+/* Maximum number of supported rates (from both Supported Rates and Extended
+ * Supported Rates IEs). */
#define WLAN_SUPP_RATES_MAX 32
@@ -31,7 +42,14 @@ struct sta_info {
u16 capability;
u16 listen_interval; /* or beacon_int for APs */
u8 supported_rates[WLAN_SUPP_RATES_MAX];
- u8 tx_supp_rates;
+ int supported_rates_len;
+
+ unsigned int nonerp_set:1;
+ unsigned int no_short_slot_time_set:1;
+ unsigned int no_short_preamble_set:1;
+
+ u16 auth_alg;
+ u8 previous_ap[6];
enum {
STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
@@ -57,26 +75,15 @@ struct sta_info {
u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */
- int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
- u8 *wpa_ie;
- size_t wpa_ie_len;
struct wpa_state_machine *wpa_sm;
- enum {
- WPA_VERSION_NO_WPA = 0 /* WPA not used */,
- WPA_VERSION_WPA = 1 /* WPA / IEEE 802.11i/D3.0 */,
- WPA_VERSION_WPA2 = 2 /* WPA2 / IEEE 802.11i */
- } wpa;
- int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */
- struct rsn_pmksa_cache *pmksa;
struct rsn_preauth_interface *preauth_iface;
- u8 req_replay_counter[8 /* WPA_REPLAY_COUNTER_LEN */];
- int req_replay_counter_used;
- u32 dot11RSNAStatsTKIPLocalMICFailures;
- u32 dot11RSNAStatsTKIPRemoteMICFailures;
-};
+ struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */
+ struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
+
+ int vlan_id;
+};
-#define MAX_STA_COUNT 1024
/* Maximum number of AIDs to use for STAs; must be 2007 or lower
* (8802.11 limitation) */
@@ -95,5 +102,10 @@ struct sta_info {
#define AP_MAX_INACTIVITY (5 * 60)
#define AP_DISASSOC_DELAY (1)
#define AP_DEAUTH_DELAY (1)
+/* Number of seconds to keep STA entry with Authenticated flag after it has
+ * been disassociated. */
+#define AP_MAX_INACTIVITY_AFTER_DISASSOC (1 * 30)
+/* Number of seconds to keep STA entry after it has been deauthenticated. */
+#define AP_MAX_INACTIVITY_AFTER_DEAUTH (1 * 5)
#endif /* AP_H */
diff --git a/contrib/hostapd/ap_list.c b/contrib/hostapd/ap_list.c
new file mode 100644
index 000000000000..f2d322125fc8
--- /dev/null
+++ b/contrib/hostapd/ap_list.c
@@ -0,0 +1,459 @@
+/*
+ * hostapd / AP table
+ * Copyright 2002-2003, Jouni Malinen <j@w1.fi>
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2006, Devicescape Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "hostapd.h"
+#include "ieee802_11.h"
+#include "eloop.h"
+#include "ap_list.h"
+#include "hw_features.h"
+#include "beacon.h"
+
+
+struct ieee80211_frame_info {
+ u32 version;
+ u32 length;
+ u64 mactime;
+ u64 hosttime;
+ u32 phytype;
+ u32 channel;
+ u32 datarate;
+ u32 antenna;
+ u32 priority;
+ u32 ssi_type;
+ u32 ssi_signal;
+ u32 ssi_noise;
+ u32 preamble;
+ u32 encoding;
+
+ /* Note: this structure is otherwise identical to capture format used
+ * in linux-wlan-ng, but this additional field is used to provide meta
+ * data about the frame to hostapd. This was the easiest method for
+ * providing this information, but this might change in the future. */
+ u32 msg_type;
+} __attribute__ ((packed));
+
+
+enum ieee80211_phytype {
+ ieee80211_phytype_fhss_dot11_97 = 1,
+ ieee80211_phytype_dsss_dot11_97 = 2,
+ ieee80211_phytype_irbaseband = 3,
+ ieee80211_phytype_dsss_dot11_b = 4,
+ ieee80211_phytype_pbcc_dot11_b = 5,
+ ieee80211_phytype_ofdm_dot11_g = 6,
+ ieee80211_phytype_pbcc_dot11_g = 7,
+ ieee80211_phytype_ofdm_dot11_a = 8,
+ ieee80211_phytype_dsss_dot11_turbog = 255,
+ ieee80211_phytype_dsss_dot11_turbo = 256,
+};
+
+
+/* AP list is a double linked list with head->prev pointing to the end of the
+ * list and tail->next = NULL. Entries are moved to the head of the list
+ * whenever a beacon has been received from the AP in question. The tail entry
+ * in this link will thus be the least recently used entry. */
+
+
+static void ap_list_new_ap(struct hostapd_iface *iface, struct ap_info *ap)
+{
+ wpa_printf(MSG_DEBUG, "New AP detected: " MACSTR, MAC2STR(ap->addr));
+
+ /* TODO: could send a notification message to an external program that
+ * would then determine whether a rogue AP has been detected */
+}
+
+
+static void ap_list_expired_ap(struct hostapd_iface *iface, struct ap_info *ap)
+{
+ wpa_printf(MSG_DEBUG, "AP info expired: " MACSTR, MAC2STR(ap->addr));
+
+ /* TODO: could send a notification message to an external program */
+}
+
+
+static int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
+{
+ int i;
+
+ if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
+ ap->phytype != ieee80211_phytype_pbcc_dot11_g ||
+ iface->conf->channel != ap->channel)
+ return 0;
+
+ if (ap->erp != -1 && (ap->erp & ERP_INFO_NON_ERP_PRESENT))
+ return 1;
+
+ for (i = 0; i < WLAN_SUPP_RATES_MAX; i++) {
+ int rate = (ap->supported_rates[i] & 0x7f) * 5;
+ if (rate == 60 || rate == 90 || rate > 110)
+ return 0;
+ }
+
+ return 1;
+}
+
+
+struct ap_info * ap_get_ap(struct hostapd_iface *iface, u8 *ap)
+{
+ struct ap_info *s;
+
+ s = iface->ap_hash[STA_HASH(ap)];
+ while (s != NULL && memcmp(s->addr, ap, ETH_ALEN) != 0)
+ s = s->hnext;
+ return s;
+}
+
+
+static void ap_ap_list_add(struct hostapd_iface *iface, struct ap_info *ap)
+{
+ if (iface->ap_list) {
+ ap->prev = iface->ap_list->prev;
+ iface->ap_list->prev = ap;
+ } else
+ ap->prev = ap;
+ ap->next = iface->ap_list;
+ iface->ap_list = ap;
+}
+
+
+static void ap_ap_list_del(struct hostapd_iface *iface, struct ap_info *ap)
+{
+ if (iface->ap_list == ap)
+ iface->ap_list = ap->next;
+ else
+ ap->prev->next = ap->next;
+
+ if (ap->next)
+ ap->next->prev = ap->prev;
+ else if (iface->ap_list)
+ iface->ap_list->prev = ap->prev;
+}
+
+
+static void ap_ap_iter_list_add(struct hostapd_iface *iface,
+ struct ap_info *ap)
+{
+ if (iface->ap_iter_list) {
+ ap->iter_prev = iface->ap_iter_list->iter_prev;
+ iface->ap_iter_list->iter_prev = ap;
+ } else
+ ap->iter_prev = ap;
+ ap->iter_next = iface->ap_iter_list;
+ iface->ap_iter_list = ap;
+}
+
+
+static void ap_ap_iter_list_del(struct hostapd_iface *iface,
+ struct ap_info *ap)
+{
+ if (iface->ap_iter_list == ap)
+ iface->ap_iter_list = ap->iter_next;
+ else
+ ap->iter_prev->iter_next = ap->iter_next;
+
+ if (ap->iter_next)
+ ap->iter_next->iter_prev = ap->iter_prev;
+ else if (iface->ap_iter_list)
+ iface->ap_iter_list->iter_prev = ap->iter_prev;
+}
+
+
+static void ap_ap_hash_add(struct hostapd_iface *iface, struct ap_info *ap)
+{
+ ap->hnext = iface->ap_hash[STA_HASH(ap->addr)];
+ iface->ap_hash[STA_HASH(ap->addr)] = ap;
+}
+
+
+static void ap_ap_hash_del(struct hostapd_iface *iface, struct ap_info *ap)
+{
+ struct ap_info *s;
+
+ s = iface->ap_hash[STA_HASH(ap->addr)];
+ if (s == NULL) return;
+ if (memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
+ iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
+ return;
+ }
+
+ while (s->hnext != NULL &&
+ memcmp(s->hnext->addr, ap->addr, ETH_ALEN) != 0)
+ s = s->hnext;
+ if (s->hnext != NULL)
+ s->hnext = s->hnext->hnext;
+ else
+ printf("AP: could not remove AP " MACSTR " from hash table\n",
+ MAC2STR(ap->addr));
+}
+
+
+static void ap_free_ap(struct hostapd_iface *iface, struct ap_info *ap)
+{
+ ap_ap_hash_del(iface, ap);
+ ap_ap_list_del(iface, ap);
+ ap_ap_iter_list_del(iface, ap);
+
+ iface->num_ap--;
+ free(ap);
+}
+
+
+static void hostapd_free_aps(struct hostapd_iface *iface)
+{
+ struct ap_info *ap, *prev;
+
+ ap = iface->ap_list;
+
+ while (ap) {
+ prev = ap;
+ ap = ap->next;
+ ap_free_ap(iface, prev);
+ }
+
+ iface->ap_list = NULL;
+}
+
+
+int ap_ap_for_each(struct hostapd_iface *iface,
+ int (*func)(struct ap_info *s, void *data), void *data)
+{
+ struct ap_info *s;
+ int ret = 0;
+
+ s = iface->ap_list;
+
+ while (s) {
+ ret = func(s, data);
+ if (ret)
+ break;
+ s = s->next;
+ }
+
+ return ret;
+}
+
+
+static struct ap_info * ap_ap_add(struct hostapd_iface *iface, u8 *addr)
+{
+ struct ap_info *ap;
+
+ ap = wpa_zalloc(sizeof(struct ap_info));
+ if (ap == NULL)
+ return NULL;
+
+ /* initialize AP info data */
+ memcpy(ap->addr, addr, ETH_ALEN);
+ ap_ap_list_add(iface, ap);
+ iface->num_ap++;
+ ap_ap_hash_add(iface, ap);
+ ap_ap_iter_list_add(iface, ap);
+
+ if (iface->num_ap > iface->conf->ap_table_max_size && ap != ap->prev) {
+ wpa_printf(MSG_DEBUG, "Removing the least recently used AP "
+ MACSTR " from AP table", MAC2STR(ap->prev->addr));
+ if (iface->conf->passive_scan_interval > 0)
+ ap_list_expired_ap(iface, ap->prev);
+ ap_free_ap(iface, ap->prev);
+ }
+
+ return ap;
+}
+
+
+void ap_list_process_beacon(struct hostapd_iface *iface,
+ struct ieee80211_mgmt *mgmt,
+ struct ieee802_11_elems *elems,
+ struct hostapd_frame_info *fi)
+{
+ struct ap_info *ap;
+ int new_ap = 0;
+ size_t len;
+
+ if (iface->conf->ap_table_max_size < 1)
+ return;
+
+ ap = ap_get_ap(iface, mgmt->bssid);
+ if (!ap) {
+ ap = ap_ap_add(iface, mgmt->bssid);
+ if (!ap) {
+ printf("Failed to allocate AP information entry\n");
+ return;
+ }
+ new_ap = 1;
+ }
+
+ ap->beacon_int = le_to_host16(mgmt->u.beacon.beacon_int);
+ ap->capability = le_to_host16(mgmt->u.beacon.capab_info);
+
+ if (elems->ssid) {
+ len = elems->ssid_len;
+ if (len >= sizeof(ap->ssid))
+ len = sizeof(ap->ssid) - 1;
+ memcpy(ap->ssid, elems->ssid, len);
+ ap->ssid[len] = '\0';
+ ap->ssid_len = len;
+ }
+
+ memset(ap->supported_rates, 0, WLAN_SUPP_RATES_MAX);
+ len = 0;
+ if (elems->supp_rates) {
+ len = elems->supp_rates_len;
+ if (len > WLAN_SUPP_RATES_MAX)
+ len = WLAN_SUPP_RATES_MAX;
+ memcpy(ap->supported_rates, elems->supp_rates, len);
+ }
+ if (elems->ext_supp_rates) {
+ int len2;
+ if (len + elems->ext_supp_rates_len > WLAN_SUPP_RATES_MAX)
+ len2 = WLAN_SUPP_RATES_MAX - len;
+ else
+ len2 = elems->ext_supp_rates_len;
+ memcpy(ap->supported_rates + len, elems->ext_supp_rates, len2);
+ }
+
+ ap->wpa = elems->wpa_ie != NULL;
+
+ if (elems->erp_info && elems->erp_info_len == 1)
+ ap->erp = elems->erp_info[0];
+ else
+ ap->erp = -1;
+
+ if (elems->ds_params && elems->ds_params_len == 1)
+ ap->channel = elems->ds_params[0];
+ else if (fi)
+ ap->channel = fi->channel;
+
+ ap->num_beacons++;
+ time(&ap->last_beacon);
+ if (fi) {
+ ap->phytype = fi->phytype;
+ ap->ssi_signal = fi->ssi_signal;
+ ap->datarate = fi->datarate;
+ }
+
+ if (new_ap) {
+ if (iface->conf->passive_scan_interval > 0)
+ ap_list_new_ap(iface, ap);
+ } else if (ap != iface->ap_list) {
+ /* move AP entry into the beginning of the list so that the
+ * oldest entry is always in the end of the list */
+ ap_ap_list_del(iface, ap);
+ ap_ap_list_add(iface, ap);
+ }
+
+ if (!iface->olbc &&
+ ap_list_beacon_olbc(iface, ap)) {
+ struct hostapd_data *hapd = iface->bss[0];
+ iface->olbc = 1;
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
+ "OLBC AP detected: " MACSTR " - enable "
+ "protection\n", MAC2STR(ap->addr));
+ ieee802_11_set_beacons(hapd->iface);
+ }
+}
+
+
+static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
+{
+ struct hostapd_iface *iface = eloop_ctx;
+ time_t now;
+ struct ap_info *ap;
+
+ eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
+
+ if (!iface->ap_list)
+ return;
+
+ time(&now);
+
+ /* FIX: it looks like jkm-Purina ended up in busy loop in this
+ * function. Apparently, something can still cause a loop in the AP
+ * list.. */
+
+ while (iface->ap_list) {
+ ap = iface->ap_list->prev;
+ if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
+ now)
+ break;
+
+ if (iface->conf->passive_scan_interval > 0)
+ ap_list_expired_ap(iface, ap);
+ ap_free_ap(iface, ap);
+ }
+
+ if (iface->olbc) {
+ int olbc = 0;
+ ap = iface->ap_list;
+ while (ap) {
+ if (ap_list_beacon_olbc(iface, ap)) {
+ olbc = 1;
+ break;
+ }
+ ap = ap->next;
+ }
+ if (!olbc) {
+ struct hostapd_data *hapd = iface->bss[0];
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
+ "OLBC not detected anymore\n");
+ iface->olbc = 0;
+ ieee802_11_set_beacons(hapd->iface);
+ }
+ }
+}
+
+
+int ap_list_init(struct hostapd_iface *iface)
+{
+ eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
+ return 0;
+}
+
+
+void ap_list_deinit(struct hostapd_iface *iface)
+{
+ eloop_cancel_timeout(ap_list_timer, iface, NULL);
+ hostapd_free_aps(iface);
+}
+
+
+int ap_list_reconfig(struct hostapd_iface *iface,
+ struct hostapd_config *oldconf)
+{
+ time_t now;
+ struct ap_info *ap;
+
+ if (iface->conf->ap_table_max_size == oldconf->ap_table_max_size &&
+ iface->conf->ap_table_expiration_time ==
+ oldconf->ap_table_expiration_time)
+ return 0;
+
+ time(&now);
+
+ while (iface->ap_list) {
+ ap = iface->ap_list->prev;
+ if (iface->num_ap <= iface->conf->ap_table_max_size &&
+ ap->last_beacon + iface->conf->ap_table_expiration_time >=
+ now)
+ break;
+
+ if (iface->conf->passive_scan_interval > 0)
+ ap_list_expired_ap(iface, iface->ap_list->prev);
+ ap_free_ap(iface, iface->ap_list->prev);
+ }
+
+ return 0;
+}
diff --git a/contrib/hostapd/ap_list.h b/contrib/hostapd/ap_list.h
new file mode 100644
index 000000000000..668d9096341c
--- /dev/null
+++ b/contrib/hostapd/ap_list.h
@@ -0,0 +1,68 @@
+/*
+ * hostapd / AP table
+ * Copyright 2002-2003, Jouni Malinen <j@w1.fi>
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2006, Devicescape Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef AP_LIST_H
+#define AP_LIST_H
+
+struct ap_info {
+ /* Note: next/prev pointers are updated whenever a new beacon is
+ * received because these are used to find the least recently used
+ * entries. iter_next/iter_prev are updated only when adding new BSSes
+ * and when removing old ones. These should be used when iterating
+ * through the table in a manner that allows beacons to be received
+ * during the iteration. */
+ struct ap_info *next; /* next entry in AP list */
+ struct ap_info *prev; /* previous entry in AP list */
+ struct ap_info *hnext; /* next entry in hash table list */
+ struct ap_info *iter_next; /* next entry in AP iteration list */
+ struct ap_info *iter_prev; /* previous entry in AP iteration list */
+ u8 addr[6];
+ u16 beacon_int;
+ u16 capability;
+ u8 supported_rates[WLAN_SUPP_RATES_MAX];
+ u8 ssid[33];
+ size_t ssid_len;
+ int wpa;
+ int erp; /* ERP Info or -1 if ERP info element not present */
+
+ int phytype; /* .11a / .11b / .11g / Atheros Turbo */
+ int channel;
+ int datarate; /* in 100 kbps */
+ int ssi_signal;
+
+ unsigned int num_beacons; /* number of beacon frames received */
+ time_t last_beacon;
+
+ int already_seen; /* whether API call AP-NEW has already fetched
+ * information about this AP */
+};
+
+struct ieee802_11_elems;
+struct hostapd_frame_info;
+
+struct ap_info * ap_get_ap(struct hostapd_iface *iface, u8 *sta);
+int ap_ap_for_each(struct hostapd_iface *iface,
+ int (*func)(struct ap_info *s, void *data), void *data);
+void ap_list_process_beacon(struct hostapd_iface *iface,
+ struct ieee80211_mgmt *mgmt,
+ struct ieee802_11_elems *elems,
+ struct hostapd_frame_info *fi);
+int ap_list_init(struct hostapd_iface *iface);
+void ap_list_deinit(struct hostapd_iface *iface);
+int ap_list_reconfig(struct hostapd_iface *iface,
+ struct hostapd_config *oldconf);
+
+#endif /* AP_LIST_H */
diff --git a/contrib/hostapd/beacon.c b/contrib/hostapd/beacon.c
new file mode 100644
index 000000000000..7af2bc1754e2
--- /dev/null
+++ b/contrib/hostapd/beacon.c
@@ -0,0 +1,419 @@
+/*
+ * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
+ * Copyright (c) 2002-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
+#include "hostapd.h"
+#include "ieee802_11.h"
+#include "wpa.h"
+#include "wme.h"
+#include "beacon.h"
+#include "hw_features.h"
+#include "driver.h"
+#include "sta_info.h"
+#include "ieee802_11h.h"
+
+
+static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
+{
+ u8 erp = 0;
+
+ if (hapd->iface == NULL || hapd->iface->current_mode == NULL ||
+ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+ return 0;
+
+ switch (hapd->iconf->cts_protection_type) {
+ case CTS_PROTECTION_FORCE_ENABLED:
+ erp |= ERP_INFO_NON_ERP_PRESENT | ERP_INFO_USE_PROTECTION;
+ break;
+ case CTS_PROTECTION_FORCE_DISABLED:
+ erp = 0;
+ break;
+ case CTS_PROTECTION_AUTOMATIC:
+ if (hapd->iface->olbc)
+ erp |= ERP_INFO_USE_PROTECTION;
+ /* continue */
+ case CTS_PROTECTION_AUTOMATIC_NO_OLBC:
+ if (hapd->iface->num_sta_non_erp > 0) {
+ erp |= ERP_INFO_NON_ERP_PRESENT |
+ ERP_INFO_USE_PROTECTION;
+ }
+ break;
+ }
+ if (hapd->iface->num_sta_no_short_preamble > 0)
+ erp |= ERP_INFO_BARKER_PREAMBLE_MODE;
+
+ return erp;
+}
+
+
+static u8 * hostapd_eid_ds_params(struct hostapd_data *hapd, u8 *eid)
+{
+ *eid++ = WLAN_EID_DS_PARAMS;
+ *eid++ = 1;
+ *eid++ = hapd->iconf->channel;
+ return eid;
+}
+
+
+static u8 * hostapd_eid_erp_info(struct hostapd_data *hapd, u8 *eid)
+{
+ if (hapd->iface == NULL || hapd->iface->current_mode == NULL ||
+ hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+ return eid;
+
+ /* Set NonERP_present and use_protection bits if there
+ * are any associated NonERP stations. */
+ /* TODO: use_protection bit can be set to zero even if
+ * there are NonERP stations present. This optimization
+ * might be useful if NonERP stations are "quiet".
+ * See 802.11g/D6 E-1 for recommended practice.
+ * In addition, Non ERP present might be set, if AP detects Non ERP
+ * operation on other APs. */
+
+ /* Add ERP Information element */
+ *eid++ = WLAN_EID_ERP_INFO;
+ *eid++ = 1;
+ *eid++ = ieee802_11_erp_info(hapd);
+
+ return eid;
+}
+
+
+static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
+ int max_len)
+{
+ int left;
+ u8 *pos = eid;
+
+ if ((!hapd->iconf->ieee80211d && !hapd->iface->dfs_enable) ||
+ max_len < 6)
+ return eid;
+
+ *pos++ = WLAN_EID_COUNTRY;
+ pos++; /* length will be set later */
+ memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
+ pos += 3;
+ left = max_len - 3;
+
+ if ((pos - eid) & 1) {
+ if (left < 1)
+ return eid;
+ *pos++ = 0; /* pad for 16-bit alignment */
+ left--;
+ }
+
+ eid[1] = (pos - eid) - 2;
+
+ return pos;
+}
+
+
+static u8 * hostapd_eid_power_constraint(struct hostapd_data *hapd, u8 *eid)
+
+{
+ if (!hapd->iface->dfs_enable)
+ return eid;
+ *eid++ = WLAN_EID_PWR_CONSTRAINT;
+ *eid++ = 1;
+ *eid++ = hapd->iface->pwr_const;
+ return eid;
+}
+
+
+static u8 * hostapd_eid_tpc_report(struct hostapd_data *hapd, u8 *eid)
+
+{
+ if (!hapd->iface->dfs_enable)
+ return eid;
+ *eid++ = WLAN_EID_TPC_REPORT;
+ *eid++ = 2;
+ *eid++ = hapd->iface->tx_power; /* TX POWER */
+ *eid++ = 0; /* Link Margin */
+ return eid;
+}
+
+static u8 * hostapd_eid_channel_switch(struct hostapd_data *hapd, u8 *eid)
+
+{
+ if (!hapd->iface->dfs_enable || !hapd->iface->channel_switch)
+ return eid;
+ *eid++ = WLAN_EID_CHANNEL_SWITCH;
+ *eid++ = 3;
+ *eid++ = CHAN_SWITCH_MODE_QUIET;
+ *eid++ = hapd->iface->channel_switch; /* New channel */
+ /* 0 - very soon; 1 - before next TBTT; num - after num beacons */
+ *eid++ = 0;
+ return eid;
+}
+
+
+static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len,
+ struct sta_info *sta)
+{
+ const u8 *ie;
+ size_t ielen;
+
+ ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
+ if (ie == NULL || ielen > len)
+ return eid;
+
+ memcpy(eid, ie, ielen);
+ return eid + ielen;
+}
+
+
+void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
+ size_t len)
+{
+ struct ieee80211_mgmt *resp;
+ struct ieee802_11_elems elems;
+ char *ssid;
+ u8 *pos, *epos;
+ size_t ssid_len;
+ struct sta_info *sta = NULL;
+
+ if (!hapd->iconf->send_probe_response)
+ return;
+
+ if (ieee802_11_parse_elems(hapd, mgmt->u.probe_req.variable,
+ len - (IEEE80211_HDRLEN +
+ sizeof(mgmt->u.probe_req)), &elems,
+ 0)
+ == ParseFailed) {
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_MINIMAL,
+ "Could not parse ProbeReq from " MACSTR "\n",
+ MAC2STR(mgmt->sa));
+ return;
+ }
+
+ ssid = NULL;
+ ssid_len = 0;
+
+ if ((!elems.ssid || !elems.supp_rates)) {
+ printf("STA " MACSTR " sent probe request without SSID or "
+ "supported rates element\n", MAC2STR(mgmt->sa));
+ return;
+ }
+
+ if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0) {
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_MSGDUMPS,
+ "Probe Request from " MACSTR " for broadcast "
+ "SSID ignored\n", MAC2STR(mgmt->sa));
+ return;
+ }
+
+ sta = ap_get_sta(hapd, mgmt->sa);
+
+ if (elems.ssid_len == 0 ||
+ (elems.ssid_len == hapd->conf->ssid.ssid_len &&
+ memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) == 0)) {
+ ssid = hapd->conf->ssid.ssid;
+ ssid_len = hapd->conf->ssid.ssid_len;
+ if (sta)
+ sta->ssid_probe = &hapd->conf->ssid;
+ }
+
+ if (!ssid) {
+ if (HOSTAPD_DEBUG_COND(HOSTAPD_DEBUG_MSGDUMPS)) {
+ printf("Probe Request from " MACSTR " for foreign "
+ "SSID '", MAC2STR(mgmt->sa));
+ ieee802_11_print_ssid(elems.ssid, elems.ssid_len);
+ printf("'\n");
+ }
+ return;
+ }
+
+ /* TODO: verify that supp_rates contains at least one matching rate
+ * with AP configuration */
+#define MAX_PROBERESP_LEN 512
+ resp = wpa_zalloc(MAX_PROBERESP_LEN);
+ if (resp == NULL)
+ return;
+ epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
+
+ resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_PROBE_RESP);
+ memcpy(resp->da, mgmt->sa, ETH_ALEN);
+ memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+
+ memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
+ resp->u.probe_resp.beacon_int =
+ host_to_le16(hapd->iconf->beacon_int);
+
+ /* hardware or low-level driver will setup seq_ctrl and timestamp */
+ resp->u.probe_resp.capab_info =
+ host_to_le16(hostapd_own_capab_info(hapd, sta, 1));
+
+ pos = resp->u.probe_resp.variable;
+ *pos++ = WLAN_EID_SSID;
+ *pos++ = ssid_len;
+ memcpy(pos, ssid, ssid_len);
+ pos += ssid_len;
+
+ /* Supported rates */
+ pos = hostapd_eid_supp_rates(hapd, pos);
+
+ /* DS Params */
+ pos = hostapd_eid_ds_params(hapd, pos);
+
+ pos = hostapd_eid_country(hapd, pos, epos - pos);
+
+ pos = hostapd_eid_power_constraint(hapd, pos);
+ pos = hostapd_eid_tpc_report(hapd, pos);
+
+ /* ERP Information element */
+ pos = hostapd_eid_erp_info(hapd, pos);
+
+ /* Extended supported rates */
+ pos = hostapd_eid_ext_supp_rates(hapd, pos);
+
+ pos = hostapd_eid_wpa(hapd, pos, epos - pos, sta);
+
+ /* Wi-Fi Wireless Multimedia Extensions */
+ if (hapd->conf->wme_enabled)
+ pos = hostapd_eid_wme(hapd, pos);
+
+ if (hostapd_send_mgmt_frame(hapd, resp, pos - (u8 *) resp, 0) < 0)
+ perror("handle_probe_req: send");
+
+ free(resp);
+
+ HOSTAPD_DEBUG(HOSTAPD_DEBUG_MSGDUMPS, "STA " MACSTR
+ " sent probe request for %s SSID\n",
+ MAC2STR(mgmt->sa), elems.ssid_len == 0 ? "broadcast" :
+ "our");
+}
+
+
+void ieee802_11_set_beacon(struct hostapd_data *hapd)
+{
+ struct ieee80211_mgmt *head;
+ u8 *pos, *tail, *tailpos;
+ int preamble;
+ u16 capab_info;
+ size_t head_len, tail_len;
+ int cts_protection = ((ieee802_11_erp_info(hapd) &
+ ERP_INFO_USE_PROTECTION) ? 1 : 0);
+
+#define BEACON_HEAD_BUF_SIZE 256
+#define BEACON_TAIL_BUF_SIZE 256
+ head = wpa_zalloc(BEACON_HEAD_BUF_SIZE);
+ tailpos = tail = malloc(BEACON_TAIL_BUF_SIZE);
+ if (head == NULL || tail == NULL) {
+ printf("Failed to set beacon data\n");
+ free(head);
+ free(tail);
+ return;
+ }
+
+ head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+ WLAN_FC_STYPE_BEACON);
+ head->duration = host_to_le16(0);
+ memset(head->da, 0xff, ETH_ALEN);
+
+ memcpy(head->sa, hapd->own_addr, ETH_ALEN);
+ memcpy(head->bssid, hapd->own_addr, ETH_ALEN);
+ head->u.beacon.beacon_int =
+ host_to_le16(hapd->iconf->beacon_int);
+
+ /* hardware or low-level driver will setup seq_ctrl and timestamp */
+ capab_info = hostapd_own_capab_info(hapd, NULL, 0);
+ head->u.beacon.capab_info = host_to_le16(capab_info);
+ pos = &head->u.beacon.variable[0];
+
+ /* SSID */
+ *pos++ = WLAN_EID_SSID;
+ if (hapd->conf->ignore_broadcast_ssid == 2) {
+ /* clear the data, but keep the correct length of the SSID */
+ *pos++ = hapd->conf->ssid.ssid_len;
+ memset(pos, 0, hapd->conf->ssid.ssid_len);
+ pos += hapd->conf->ssid.ssid_len;
+ } else if (hapd->conf->ignore_broadcast_ssid) {
+ *pos++ = 0; /* empty SSID */
+ } else {
+ *pos++ = hapd->conf->ssid.ssid_len;
+ memcpy(pos, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len);
+ pos += hapd->conf->ssid.ssid_len;
+ }
+
+ /* Supported rates */
+ pos = hostapd_eid_supp_rates(hapd, pos);
+
+ /* DS Params */
+ pos = hostapd_eid_ds_params(hapd, pos);
+
+ head_len = pos - (u8 *) head;
+
+ tailpos = hostapd_eid_country(hapd, tailpos,
+ tail + BEACON_TAIL_BUF_SIZE - tailpos);
+
+ tailpos = hostapd_eid_power_constraint(hapd, tailpos);
+ tailpos = hostapd_eid_channel_switch(hapd, tailpos);
+ tailpos = hostapd_eid_tpc_report(hapd, tailpos);
+
+ /* ERP Information element */
+ tailpos = hostapd_eid_erp_info(hapd, tailpos);
+
+ /* Extended supported rates */
+ tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
+
+ tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
+ tailpos, NULL);
+
+ /* Wi-Fi Wireless Multimedia Extensions */
+ if (hapd->conf->wme_enabled)
+ tailpos = hostapd_eid_wme(hapd, tailpos);
+
+ tail_len = tailpos > tail ? tailpos - tail : 0;
+
+ if (hostapd_set_beacon(hapd->conf->iface, hapd, (u8 *) head, head_len,
+ tail, tail_len))
+ printf("Failed to set beacon head/tail\n");
+
+ free(tail);
+ free(head);
+
+ if (hostapd_set_cts_protect(hapd, cts_protection))
+ printf("Failed to set CTS protect in kernel driver\n");
+
+ if (hapd->iface && hapd->iface->current_mode &&
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
+ hostapd_set_short_slot_time(hapd,
+ hapd->iface->num_sta_no_short_slot_time
+ > 0 ? 0 : 1))
+ printf("Failed to set Short Slot Time option in kernel "
+ "driver\n");
+
+ if (hapd->iface && hapd->iface->num_sta_no_short_preamble == 0 &&
+ hapd->iconf->preamble == SHORT_PREAMBLE)
+ preamble = SHORT_PREAMBLE;
+ else
+ preamble = LONG_PREAMBLE;
+ if (hostapd_set_preamble(hapd, preamble))
+ printf("Could not set preamble for kernel driver\n");
+}
+
+
+void ieee802_11_set_beacons(struct hostapd_iface *iface)
+{
+ size_t i;
+ for (i = 0; i < iface->num_bss; i++)
+ ieee802_11_set_beacon(iface->bss[i]);
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/contrib/hostapd/beacon.h b/contrib/hostapd/beacon.h
new file mode 100644
index 000000000000..18e0da2e89f6
--- /dev/null
+++ b/contrib/hostapd/beacon.h
@@ -0,0 +1,24 @@
+/*
+ * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
+ * Copyright (c) 2002-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef BEACON_H
+#define BEACON_H
+
+void handle_probe_req(struct hostapd_data *hapd, struct ieee80211_mgmt *mgmt,
+ size_t len);
+void ieee802_11_set_beacon(struct hostapd_data *hapd);
+void ieee802_11_set_beacons(struct hostapd_iface *iface);
+
+#endif /* BEACON_H */
diff --git a/contrib/hostapd/build_config.h b/contrib/hostapd/build_config.h
new file mode 100644
index 000000000000..58bcda825345
--- /dev/null
+++ b/contrib/hostapd/build_config.h
@@ -0,0 +1,50 @@
+/*
+ * wpa_supplicant/hostapd - Build time configuration defines
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ *
+ * This header file can be used to define configuration defines that were
+ * originally defined in Makefile. This is mainly meant for IDE use or for
+ * systems that do not have suitable 'make' tool. In these cases, it may be
+ * easier to have a single place for defining all the needed C pre-processor
+ * defines.
+ */
+
+#ifndef BUILD_CONFIG_H
+#define BUILD_CONFIG_H
+
+/* Insert configuration defines, e.g., #define EAP_MD5, here, if needed. */
+
+#ifdef CONFIG_WIN32_DEFAULTS
+#define CONFIG_NATIVE_WINDOWS
+#define CONFIG_ANSI_C_EXTRA
+#define CONFIG_WINPCAP
+#define IEEE8021X_EAPOL
+#define EAP_TLS_FUNCS
+#define PKCS12_FUNCS
+#define PCSC_FUNCS
+#define CONFIG_CTRL_IFACE
+#define CONFIG_CTRL_IFACE_NAMED_PIPE
+#define CONFIG_DRIVER_NDIS
+#define CONFIG_NDIS_EVENTS_INTEGRATED
+#define CONFIG_DEBUG_FILE
+#define EAP_MD5
+#define EAP_TLS
+#define EAP_MSCHAPv2
+#define EAP_PEAP
+#define EAP_TTLS
+#define EAP_GTC
+#define EAP_OTP
+#define EAP_LEAP
+#define _CRT_SECURE_NO_DEPRECATE
+#endif /* CONFIG_WIN32_DEFAULTS */
+
+#endif /* BUILD_CONFIG_H */
diff --git a/contrib/hostapd/common.c b/contrib/hostapd/common.c
index 4b756d8f9292..c8d6f130a960 100644
--- a/contrib/hostapd/common.c
+++ b/contrib/hostapd/common.c
@@ -1,6 +1,6 @@
/*
* wpa_supplicant/hostapd / common helper functions, etc.
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * 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
@@ -12,70 +12,20 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <time.h>
-#include <sys/time.h>
-#ifdef CONFIG_NATIVE_WINDOWS
-#include <winsock2.h>
-#include <wincrypt.h>
-#endif /* CONFIG_NATIVE_WINDOWS */
+#include "includes.h"
#include "common.h"
+#ifdef CONFIG_DEBUG_FILE
+static FILE *out_file = NULL;
+#endif /* CONFIG_DEBUG_FILE */
+int wpa_debug_use_file = 0;
int wpa_debug_level = MSG_INFO;
int wpa_debug_show_keys = 0;
int wpa_debug_timestamp = 0;
-int hostapd_get_rand(u8 *buf, size_t len)
-{
-#ifdef CONFIG_NATIVE_WINDOWS
- 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;
-#else /* CONFIG_NATIVE_WINDOWS */
- FILE *f;
- size_t rc;
-
- f = fopen("/dev/urandom", "r");
- if (f == NULL) {
- printf("Could not open /dev/urandom.\n");
- return -1;
- }
-
- rc = fread(buf, 1, len, f);
- fclose(f);
-
- return rc != len ? -1 : 0;
-#endif /* CONFIG_NATIVE_WINDOWS */
-}
-
-
-void hostapd_hexdump(const char *title, const u8 *buf, size_t len)
-{
- size_t i;
- printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
- for (i = 0; i < len; i++)
- printf(" %02x", buf[i]);
- printf("\n");
-}
-
-
static int hex2num(char c)
{
if (c >= '0' && c <= '9')
@@ -139,7 +89,8 @@ int hwaddr_aton(const char *txt, u8 *addr)
*/
int hexstr2bin(const char *hex, u8 *buf, size_t len)
{
- int i, a;
+ size_t i;
+ int a;
const char *ipos = hex;
u8 *opos = buf;
@@ -154,45 +105,6 @@ int hexstr2bin(const char *hex, u8 *buf, size_t len)
}
-char * rel2abs_path(const char *rel_path)
-{
- char *buf = NULL, *cwd, *ret;
- size_t len = 128, cwd_len, rel_len, ret_len;
-
- if (rel_path[0] == '/')
- return strdup(rel_path);
-
- for (;;) {
- buf = malloc(len);
- if (buf == NULL)
- return NULL;
- cwd = getcwd(buf, len);
- if (cwd == NULL) {
- free(buf);
- if (errno != ERANGE) {
- return NULL;
- }
- len *= 2;
- } else {
- break;
- }
- }
-
- cwd_len = strlen(cwd);
- rel_len = strlen(rel_path);
- ret_len = cwd_len + 1 + rel_len + 1;
- ret = malloc(ret_len);
- if (ret) {
- memcpy(ret, cwd, cwd_len);
- ret[cwd_len] = '/';
- memcpy(ret + cwd_len + 1, rel_path, rel_len);
- ret[ret_len - 1] = '\0';
- }
- free(buf);
- return ret;
-}
-
-
/**
* inc_byte_array - Increment arbitrary length byte array by one
* @counter: Pointer to byte array
@@ -214,40 +126,40 @@ void inc_byte_array(u8 *counter, size_t len)
}
-void print_char(char c)
+void wpa_get_ntp_timestamp(u8 *buf)
{
- if (c >= 32 && c < 127)
- printf("%c", c);
- else
- printf("<%02x>", c);
+ struct os_time now;
+ u32 sec, usec;
+
+ /* 64-bit NTP timestamp (time from 1900-01-01 00:00:00) */
+ os_get_time(&now);
+ sec = host_to_be32(now.sec + 2208988800U); /* Epoch to 1900 */
+ /* Estimate 2^32/10^6 = 4295 - 1/32 - 1/512 */
+ usec = now.usec;
+ usec = host_to_be32(4295 * usec - (usec >> 5) - (usec >> 9));
+ os_memcpy(buf, (u8 *) &sec, 4);
+ os_memcpy(buf + 4, (u8 *) &usec, 4);
}
-void fprint_char(FILE *f, char c)
-{
- if (c >= 32 && c < 127)
- fprintf(f, "%c", c);
- else
- fprintf(f, "<%02x>", c);
-}
-
#ifndef CONFIG_NO_STDOUT_DEBUG
void wpa_debug_print_timestamp(void)
{
- struct timeval tv;
- char buf[16];
+ struct os_time tv;
if (!wpa_debug_timestamp)
return;
- gettimeofday(&tv, NULL);
- if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S",
- localtime((const time_t *) &tv.tv_sec)) <= 0) {
- snprintf(buf, sizeof(buf), "%u", (int) tv.tv_sec);
- }
- printf("%s.%06u: ", buf, (unsigned int) tv.tv_usec);
+ os_get_time(&tv);
+#ifdef CONFIG_DEBUG_FILE
+ if (out_file) {
+ fprintf(out_file, "%ld.%06u: ", (long) tv.sec,
+ (unsigned int) tv.usec);
+ } else
+#endif /* CONFIG_DEBUG_FILE */
+ printf("%ld.%06u: ", (long) tv.sec, (unsigned int) tv.usec);
}
@@ -269,8 +181,17 @@ void wpa_printf(int level, char *fmt, ...)
va_start(ap, fmt);
if (level >= wpa_debug_level) {
wpa_debug_print_timestamp();
+#ifdef CONFIG_DEBUG_FILE
+ if (out_file) {
+ vfprintf(out_file, fmt, ap);
+ fprintf(out_file, "\n");
+ } else {
+#endif /* CONFIG_DEBUG_FILE */
vprintf(fmt, ap);
printf("\n");
+#ifdef CONFIG_DEBUG_FILE
+ }
+#endif /* CONFIG_DEBUG_FILE */
}
va_end(ap);
}
@@ -283,6 +204,21 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
if (level < wpa_debug_level)
return;
wpa_debug_print_timestamp();
+#ifdef CONFIG_DEBUG_FILE
+ if (out_file) {
+ fprintf(out_file, "%s - hexdump(len=%lu):",
+ title, (unsigned long) len);
+ if (buf == NULL) {
+ fprintf(out_file, " [NULL]");
+ } else if (show) {
+ for (i = 0; i < len; i++)
+ fprintf(out_file, " %02x", buf[i]);
+ } else {
+ fprintf(out_file, " [REMOVED]");
+ }
+ fprintf(out_file, "\n");
+ } else {
+#endif /* CONFIG_DEBUG_FILE */
printf("%s - hexdump(len=%lu):", title, (unsigned long) len);
if (buf == NULL) {
printf(" [NULL]");
@@ -293,6 +229,9 @@ static void _wpa_hexdump(int level, const char *title, const u8 *buf,
printf(" [REMOVED]");
}
printf("\n");
+#ifdef CONFIG_DEBUG_FILE
+ }
+#endif /* CONFIG_DEBUG_FILE */
}
void wpa_hexdump(int level, const char *title, const u8 *buf, size_t len)
@@ -310,13 +249,51 @@ void wpa_hexdump_key(int level, const char *title, const u8 *buf, size_t len)
static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
size_t len, int show)
{
- int i, llen;
+ size_t i, llen;
const u8 *pos = buf;
- const int line_len = 16;
+ const size_t line_len = 16;
if (level < wpa_debug_level)
return;
wpa_debug_print_timestamp();
+#ifdef CONFIG_DEBUG_FILE
+ if (out_file) {
+ if (!show) {
+ fprintf(out_file,
+ "%s - hexdump_ascii(len=%lu): [REMOVED]\n",
+ title, (unsigned long) len);
+ return;
+ }
+ if (buf == NULL) {
+ fprintf(out_file,
+ "%s - hexdump_ascii(len=%lu): [NULL]\n",
+ title, (unsigned long) len);
+ return;
+ }
+ fprintf(out_file, "%s - hexdump_ascii(len=%lu):\n",
+ title, (unsigned long) len);
+ while (len) {
+ llen = len > line_len ? line_len : len;
+ fprintf(out_file, " ");
+ for (i = 0; i < llen; i++)
+ fprintf(out_file, " %02x", pos[i]);
+ for (i = llen; i < line_len; i++)
+ fprintf(out_file, " ");
+ fprintf(out_file, " ");
+ for (i = 0; i < llen; i++) {
+ if (isprint(pos[i]))
+ fprintf(out_file, "%c", pos[i]);
+ else
+ fprintf(out_file, "_");
+ }
+ for (i = llen; i < line_len; i++)
+ fprintf(out_file, " ");
+ fprintf(out_file, "\n");
+ pos += llen;
+ len -= llen;
+ }
+ } else {
+#endif /* CONFIG_DEBUG_FILE */
if (!show) {
printf("%s - hexdump_ascii(len=%lu): [REMOVED]\n",
title, (unsigned long) len);
@@ -348,6 +325,9 @@ static void _wpa_hexdump_ascii(int level, const char *title, const u8 *buf,
pos += llen;
len -= llen;
}
+#ifdef CONFIG_DEBUG_FILE
+ }
+#endif /* CONFIG_DEBUG_FILE */
}
@@ -363,26 +343,261 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
_wpa_hexdump_ascii(level, title, buf, len, wpa_debug_show_keys);
}
+
+int wpa_debug_open_file(void)
+{
+#ifdef CONFIG_DEBUG_FILE
+ static int count = 0;
+ char fname[64];
+ if (!wpa_debug_use_file)
+ return 0;
+#ifdef _WIN32
+ os_snprintf(fname, sizeof(fname), "\\Temp\\wpa_supplicant-log-%d.txt",
+ count++);
+#else /* _WIN32 */
+ os_snprintf(fname, sizeof(fname), "/tmp/wpa_supplicant-log-%d.txt",
+ count++);
+#endif /* _WIN32 */
+ out_file = fopen(fname, "w");
+ return out_file == NULL ? -1 : 0;
+#else /* CONFIG_DEBUG_FILE */
+ return 0;
+#endif /* CONFIG_DEBUG_FILE */
+}
+
+
+void wpa_debug_close_file(void)
+{
+#ifdef CONFIG_DEBUG_FILE
+ if (!wpa_debug_use_file)
+ return;
+ fclose(out_file);
+ out_file = NULL;
+#endif /* CONFIG_DEBUG_FILE */
+}
+
#endif /* CONFIG_NO_STDOUT_DEBUG */
-#ifdef CONFIG_NATIVE_WINDOWS
+#ifndef CONFIG_NO_WPA_MSG
+static wpa_msg_cb_func wpa_msg_cb = NULL;
+
+void wpa_msg_register_cb(wpa_msg_cb_func func)
+{
+ wpa_msg_cb = func;
+}
+
+
+void wpa_msg(void *ctx, int level, char *fmt, ...)
+{
+ va_list ap;
+ char *buf;
+ const int buflen = 2048;
+ int len;
-#define EPOCHFILETIME (116444736000000000ULL)
+ buf = os_malloc(buflen);
+ if (buf == NULL) {
+ wpa_printf(MSG_ERROR, "wpa_msg: Failed to allocate message "
+ "buffer");
+ return;
+ }
+ va_start(ap, fmt);
+ len = vsnprintf(buf, buflen, fmt, ap);
+ va_end(ap);
+ wpa_printf(level, "%s", buf);
+ if (wpa_msg_cb)
+ wpa_msg_cb(ctx, level, buf, len);
+ os_free(buf);
+}
+#endif /* CONFIG_NO_WPA_MSG */
-int gettimeofday(struct timeval *tv, struct timezone *tz)
+
+static inline int _wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data,
+ size_t len, int uppercase)
{
- FILETIME ft;
- LARGE_INTEGER li;
- ULONGLONG t;
+ size_t i;
+ char *pos = buf, *end = buf + buf_size;
+ int ret;
+ if (buf_size == 0)
+ return 0;
+ for (i = 0; i < len; i++) {
+ ret = os_snprintf(pos, end - pos, uppercase ? "%02X" : "%02x",
+ data[i]);
+ if (ret < 0 || ret >= end - pos) {
+ end[-1] = '\0';
+ return pos - buf;
+ }
+ pos += ret;
+ }
+ end[-1] = '\0';
+ return pos - buf;
+}
- GetSystemTimeAsFileTime(&ft);
- li.LowPart = ft.dwLowDateTime;
- li.HighPart = ft.dwHighDateTime;
- t = (li.QuadPart - EPOCHFILETIME) / 10;
- tv->tv_sec = (long) (t / 1000000);
- tv->tv_usec = (long) (t % 1000000);
+/**
+ * wpa_snprintf_hex - Print data as a hex string into a buffer
+ * @buf: Memory area to use as the output buffer
+ * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
+ * @data: Data to be printed
+ * @len: Length of data in bytes
+ * Returns: Number of bytes written
+ */
+int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len)
+{
+ return _wpa_snprintf_hex(buf, buf_size, data, len, 0);
+}
- return 0;
+
+/**
+ * wpa_snprintf_hex_uppercase - Print data as a upper case hex string into buf
+ * @buf: Memory area to use as the output buffer
+ * @buf_size: Maximum buffer size in bytes (should be at least 2 * len + 1)
+ * @data: Data to be printed
+ * @len: Length of data in bytes
+ * Returns: Number of bytes written
+ */
+int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
+ size_t len)
+{
+ return _wpa_snprintf_hex(buf, buf_size, data, len, 1);
+}
+
+
+#ifdef CONFIG_ANSI_C_EXTRA
+
+#ifdef _WIN32_WCE
+void perror(const char *s)
+{
+ wpa_printf(MSG_ERROR, "%s: GetLastError: %d",
+ s, (int) GetLastError());
+}
+#endif /* _WIN32_WCE */
+
+
+int optind = 1;
+int optopt;
+char *optarg;
+
+int getopt(int argc, char *const argv[], const char *optstring)
+{
+ static int optchr = 1;
+ char *cp;
+
+ if (optchr == 1) {
+ if (optind >= argc) {
+ /* all arguments processed */
+ return EOF;
+ }
+
+ if (argv[optind][0] != '-' || argv[optind][1] == '\0') {
+ /* no option characters */
+ return EOF;
+ }
+ }
+
+ if (os_strcmp(argv[optind], "--") == 0) {
+ /* no more options */
+ optind++;
+ return EOF;
+ }
+
+ optopt = argv[optind][optchr];
+ cp = os_strchr(optstring, optopt);
+ if (cp == NULL || optopt == ':') {
+ if (argv[optind][++optchr] == '\0') {
+ optchr = 1;
+ optind++;
+ }
+ return '?';
+ }
+
+ if (cp[1] == ':') {
+ /* Argument required */
+ optchr = 1;
+ if (argv[optind][optchr + 1]) {
+ /* No space between option and argument */
+ optarg = &argv[optind++][optchr + 1];
+ } else if (++optind >= argc) {
+ /* option requires an argument */
+ return '?';
+ } else {
+ /* Argument in the next argv */
+ optarg = argv[optind++];
+ }
+ } else {
+ /* No argument */
+ if (argv[optind][++optchr] == '\0') {
+ optchr = 1;
+ optind++;
+ }
+ optarg = NULL;
+ }
+ return *cp;
+}
+#endif /* CONFIG_ANSI_C_EXTRA */
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+/**
+ * wpa_unicode2ascii_inplace - Convert unicode string into ASCII
+ * @str: Pointer to string to convert
+ *
+ * This function converts a unicode string to ASCII using the same
+ * buffer for output. If UNICODE is not set, the buffer is not
+ * modified.
+ */
+void wpa_unicode2ascii_inplace(TCHAR *str)
+{
+#ifdef UNICODE
+ char *dst = (char *) str;
+ while (*str)
+ *dst++ = (char) *str++;
+ *dst = '\0';
+#endif /* UNICODE */
+}
+
+
+TCHAR * wpa_strdup_tchar(const char *str)
+{
+#ifdef UNICODE
+ TCHAR *buf;
+ buf = os_malloc((strlen(str) + 1) * sizeof(TCHAR));
+ if (buf == NULL)
+ return NULL;
+ wsprintf(buf, L"%S", str);
+ return buf;
+#else /* UNICODE */
+ return os_strdup(str);
+#endif /* UNICODE */
}
#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+/**
+ * wpa_ssid_txt - Convert SSID to a printable string
+ * @ssid: SSID (32-octet string)
+ * @ssid_len: Length of ssid in octets
+ * Returns: Pointer to a printable string
+ *
+ * This function can be used to convert SSIDs into printable form. In most
+ * cases, SSIDs do not use unprintable characters, but IEEE 802.11 standard
+ * does not limit the used character set, so anything could be used in an SSID.
+ *
+ * This function uses a static buffer, so only one call can be used at the
+ * time, i.e., this is not re-entrant and the returned buffer must be used
+ * before calling this again.
+ */
+const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len)
+{
+ static char ssid_txt[33];
+ char *pos;
+
+ if (ssid_len > 32)
+ ssid_len = 32;
+ os_memcpy(ssid_txt, ssid, ssid_len);
+ ssid_txt[ssid_len] = '\0';
+ for (pos = ssid_txt; *pos != '\0'; pos++) {
+ if ((u8) *pos < 32 || (u8) *pos >= 127)
+ *pos = '_';
+ }
+ return ssid_txt;
+}
diff --git a/contrib/hostapd/common.h b/contrib/hostapd/common.h
index 4bece7f6ecd9..b200b580d5df 100644
--- a/contrib/hostapd/common.h
+++ b/contrib/hostapd/common.h
@@ -1,6 +1,6 @@
/*
* wpa_supplicant/hostapd / common helper functions, etc.
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * 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
@@ -15,12 +15,14 @@
#ifndef COMMON_H
#define COMMON_H
+#include "os.h"
+
#ifdef __linux__
#include <endian.h>
#include <byteswap.h>
#endif /* __linux__ */
-#if defined(__FreeBSD__) || defined(__NetBSD__)
+#if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__DragonFly__)
#include <sys/types.h>
#include <sys/endian.h>
#define __BYTE_ORDER _BYTE_ORDER
@@ -29,51 +31,22 @@
#define bswap_16 bswap16
#define bswap_32 bswap32
#define bswap_64 bswap64
-#endif /* defined(__FreeBSD__) || defined(__NetBSD__) */
-
-#ifdef CONFIG_NATIVE_WINDOWS
-#include <winsock2.h>
-
-static inline int daemon(int nochdir, int noclose)
-{
- printf("Windows - daemon() not supported yet\n");
- return -1;
-}
-
-static inline void sleep(int seconds)
-{
- Sleep(seconds * 1000);
-}
-
-static inline void usleep(unsigned long usec)
-{
- Sleep(usec / 1000);
-}
-
-#ifndef timersub
-#define timersub(a, b, res) do { \
- (res)->tv_sec = (a)->tv_sec - (b)->tv_sec; \
- (res)->tv_usec = (a)->tv_usec - (b)->tv_usec; \
- if ((res)->tv_usec < 0) { \
- (res)->tv_sec--; \
- (res)->tv_usec += 1000000; \
- } \
-} while (0)
+#endif /* defined(__FreeBSD__) || defined(__NetBSD__) ||
+ * defined(__DragonFly__) */
+
+#ifdef CONFIG_TI_COMPILER
+#define __BIG_ENDIAN 4321
+#define __LITTLE_ENDIAN 1234
+#ifdef __big_endian__
+#define __BYTE_ORDER __BIG_ENDIAN
+#else
+#define __BYTE_ORDER __LITTLE_ENDIAN
#endif
+#endif /* CONFIG_TI_COMPILER */
-struct timezone {
- int tz_minuteswest;
- int tz_dsttime;
-};
-
-int gettimeofday(struct timeval *tv, struct timezone *tz);
-
-static inline long int random(void)
-{
- return rand();
-}
+#ifdef CONFIG_NATIVE_WINDOWS
+#include <winsock.h>
-typedef int gid_t;
typedef int socklen_t;
#ifndef MSG_DONTWAIT
@@ -84,6 +57,10 @@ typedef int socklen_t;
#if defined(__CYGWIN__) || defined(CONFIG_NATIVE_WINDOWS)
+#ifdef _MSC_VER
+#define inline __inline
+#endif /* _MSC_VER */
+
static inline unsigned short wpa_swap_16(unsigned short v)
{
return ((v & 0xff) << 8) | (v >> 8);
@@ -105,6 +82,18 @@ static inline unsigned int wpa_swap_32(unsigned int v)
#else /* __CYGWIN__ */
+#ifndef __BYTE_ORDER
+#ifndef __LITTLE_ENDIAN
+#ifndef __BIG_ENDIAN
+#define __LITTLE_ENDIAN 1234
+#define __BIG_ENDIAN 4321
+#if defined(sparc)
+#define __BYTE_ORDER __BIG_ENDIAN
+#endif
+#endif /* __BIG_ENDIAN */
+#endif /* __LITTLE_ENDIAN */
+#endif /* __BYTE_ORDER */
+
#if __BYTE_ORDER == __LITTLE_ENDIAN
#define le_to_host16(n) (n)
#define host_to_le16(n) (n)
@@ -113,6 +102,10 @@ static inline unsigned int wpa_swap_32(unsigned int v)
#define le_to_host32(n) (n)
#define be_to_host32(n) bswap_32(n)
#define host_to_be32(n) bswap_32(n)
+#define le_to_host64(n) (n)
+#define host_to_le64(n) (n)
+#define be_to_host64(n) bswap_64(n)
+#define host_to_be64(n) bswap_64(n)
#elif __BYTE_ORDER == __BIG_ENDIAN
#define le_to_host16(n) bswap_16(n)
#define host_to_le16(n) bswap_16(n)
@@ -121,6 +114,10 @@ static inline unsigned int wpa_swap_32(unsigned int v)
#define le_to_host32(n) bswap_32(n)
#define be_to_host32(n) (n)
#define host_to_be32(n) (n)
+#define le_to_host64(n) bswap_64(n)
+#define host_to_le64(n) bswap_64(n)
+#define be_to_host64(n) (n)
+#define host_to_be64(n) (n)
#ifndef WORDS_BIGENDIAN
#define WORDS_BIGENDIAN
#endif
@@ -145,12 +142,88 @@ static inline unsigned int wpa_swap_32(unsigned int v)
(a)[0] = ((u16) (val)) & 0xff; \
} while (0)
+#define WPA_GET_BE24(a) ((((u32) (a)[0]) << 16) | (((u32) (a)[1]) << 8) | \
+ ((u32) (a)[2]))
+#define WPA_PUT_BE24(a, val) \
+ do { \
+ (a)[0] = (u8) (((u32) (val)) >> 16); \
+ (a)[1] = (u8) (((u32) (val)) >> 8); \
+ (a)[2] = (u8) (((u32) (val)) & 0xff); \
+ } while (0)
+
+#define WPA_GET_BE32(a) ((((u32) (a)[0]) << 24) | (((u32) (a)[1]) << 16) | \
+ (((u32) (a)[2]) << 8) | ((u32) (a)[3]))
+#define WPA_PUT_BE32(a, val) \
+ do { \
+ (a)[0] = (u8) (((u32) (val)) >> 24); \
+ (a)[1] = (u8) (((u32) (val)) >> 16); \
+ (a)[2] = (u8) (((u32) (val)) >> 8); \
+ (a)[3] = (u8) (((u32) (val)) & 0xff); \
+ } while (0)
+
+#define WPA_PUT_BE64(a, val) \
+ do { \
+ (a)[0] = (u8) (((u64) (val)) >> 56); \
+ (a)[1] = (u8) (((u64) (val)) >> 48); \
+ (a)[2] = (u8) (((u64) (val)) >> 40); \
+ (a)[3] = (u8) (((u64) (val)) >> 32); \
+ (a)[4] = (u8) (((u64) (val)) >> 24); \
+ (a)[5] = (u8) (((u64) (val)) >> 16); \
+ (a)[6] = (u8) (((u64) (val)) >> 8); \
+ (a)[7] = (u8) (((u64) (val)) & 0xff); \
+ } while (0)
+
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
+#ifdef _MSC_VER
+typedef UINT64 u64;
+typedef UINT32 u32;
+typedef UINT16 u16;
+typedef UINT8 u8;
+typedef INT64 s64;
+typedef INT32 s32;
+typedef INT16 s16;
+typedef INT8 s8;
+#define WPA_TYPES_DEFINED
+#endif /* _MSC_VER */
+
+#ifdef __vxworks
+typedef unsigned long long u64;
+typedef UINT32 u32;
+typedef UINT16 u16;
+typedef UINT8 u8;
+typedef long long s64;
+typedef INT32 s32;
+typedef INT16 s16;
+typedef INT8 s8;
+#define WPA_TYPES_DEFINED
+#endif /* __vxworks */
+
+#ifdef CONFIG_TI_COMPILER
+#ifdef _LLONG_AVAILABLE
+typedef unsigned long long u64;
+#else
+/*
+ * TODO: 64-bit variable not available. Using long as a workaround to test the
+ * build, but this will likely not work for all operations.
+ */
+typedef unsigned long u64;
+#endif
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+#define WPA_TYPES_DEFINED
+#endif /* CONFIG_TI_COMPILER */
+
+#ifndef WPA_TYPES_DEFINED
+#ifdef CONFIG_USE_INTTYPES_H
+#include <inttypes.h>
+#else
#include <stdint.h>
+#endif
typedef uint64_t u64;
typedef uint32_t u32;
typedef uint16_t u16;
@@ -159,19 +232,27 @@ typedef int64_t s64;
typedef int32_t s32;
typedef int16_t s16;
typedef int8_t s8;
+#define WPA_TYPES_DEFINED
+#endif /* !WPA_TYPES_DEFINED */
-int hostapd_get_rand(u8 *buf, size_t len);
-void hostapd_hexdump(const char *title, const u8 *buf, size_t len);
+#define hostapd_get_rand os_get_random
int hwaddr_aton(const char *txt, u8 *addr);
int hexstr2bin(const char *hex, u8 *buf, size_t len);
-char * rel2abs_path(const char *rel_path);
void inc_byte_array(u8 *counter, size_t len);
-void print_char(char c);
-void fprint_char(FILE *f, char c);
+void wpa_get_ntp_timestamp(u8 *buf);
+
+
+#ifdef __GNUC__
+#define PRINTF_FORMAT(a,b) __attribute__ ((format (printf, (a), (b))))
+#define STRUCT_PACKED __attribute__ ((packed))
+#else
+#define PRINTF_FORMAT(a,b)
+#define STRUCT_PACKED
+#endif
/* Debugging function - conditional printf and hex dump. Driver wrappers can
- * use these for debugging purposes. */
+ * use these for debugging purposes. */
enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };
@@ -179,13 +260,18 @@ enum { MSG_MSGDUMP, MSG_DEBUG, MSG_INFO, MSG_WARNING, MSG_ERROR };
#define wpa_debug_print_timestamp() do { } while (0)
#define wpa_printf(args...) do { } while (0)
-#define wpa_hexdump(args...) do { } while (0)
-#define wpa_hexdump_key(args...) do { } while (0)
-#define wpa_hexdump_ascii(args...) do { } while (0)
-#define wpa_hexdump_ascii_key(args...) do { } while (0)
+#define wpa_hexdump(l,t,b,le) do { } while (0)
+#define wpa_hexdump_key(l,t,b,le) do { } while (0)
+#define wpa_hexdump_ascii(l,t,b,le) do { } while (0)
+#define wpa_hexdump_ascii_key(l,t,b,le) do { } while (0)
+#define wpa_debug_open_file() do { } while (0)
+#define wpa_debug_close_file() do { } while (0)
#else /* CONFIG_NO_STDOUT_DEBUG */
+int wpa_debug_open_file(void);
+void wpa_debug_close_file(void);
+
/**
* wpa_debug_printf_timestamp - Print timestamp for debug output
*
@@ -207,7 +293,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, ...)
-__attribute__ ((format (printf, 2, 3)));
+PRINTF_FORMAT(2, 3);
/**
* wpa_hexdump - conditional hex dump
@@ -273,6 +359,42 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
#endif /* CONFIG_NO_STDOUT_DEBUG */
+#ifdef CONFIG_NO_WPA_MSG
+#define wpa_msg(args...) do { } while (0)
+#define wpa_msg_register_cb(f) do { } while (0)
+#else /* CONFIG_NO_WPA_MSG */
+/**
+ * wpa_msg - Conditional printf for default target and ctrl_iface monitors
+ * @ctx: Pointer to context data; this is the ctx variable registered
+ * with struct wpa_driver_ops::init()
+ * @level: priority level (MSG_*) of the message
+ * @fmt: printf format string, followed by optional arguments
+ *
+ * This function is used to print conditional debugging and error messages. The
+ * output may be directed to stdout, stderr, and/or syslog based on
+ * configuration. This function is like wpa_printf(), but it also sends the
+ * same message to all attached ctrl_iface monitors.
+ *
+ * Note: New line '\n' is added to the end of the text when printing to stdout.
+ */
+void wpa_msg(void *ctx, int level, char *fmt, ...) PRINTF_FORMAT(3, 4);
+
+typedef void (*wpa_msg_cb_func)(void *ctx, int level, const char *txt,
+ size_t len);
+
+/**
+ * wpa_msg_register_cb - Register callback function for wpa_msg() messages
+ * @func: Callback function (%NULL to unregister)
+ */
+void wpa_msg_register_cb(wpa_msg_cb_func func);
+#endif /* CONFIG_NO_WPA_MSG */
+
+
+int wpa_snprintf_hex(char *buf, size_t buf_size, const u8 *data, size_t len);
+int wpa_snprintf_hex_uppercase(char *buf, size_t buf_size, const u8 *data,
+ size_t len);
+
+
#ifdef EAPOL_TEST
#define WPA_ASSERT(a) \
do { \
@@ -287,4 +409,84 @@ void wpa_hexdump_ascii_key(int level, const char *title, const u8 *buf,
#define WPA_ASSERT(a) do { } while (0)
#endif
+
+#ifdef _MSC_VER
+#undef vsnprintf
+#define vsnprintf _vsnprintf
+#undef close
+#define close closesocket
+#endif /* _MSC_VER */
+
+
+#ifdef CONFIG_ANSI_C_EXTRA
+
+#if !defined(_MSC_VER) || _MSC_VER < 1400
+/* snprintf - used in number of places; sprintf() is _not_ a good replacement
+ * due to possible buffer overflow; see, e.g.,
+ * http://www.ijs.si/software/snprintf/ for portable implementation of
+ * snprintf. */
+int snprintf(char *str, size_t size, const char *format, ...);
+
+/* vsnprintf - only used for wpa_msg() in wpa_supplicant.c */
+int vsnprintf(char *str, size_t size, const char *format, va_list ap);
+#endif /* !defined(_MSC_VER) || _MSC_VER < 1400 */
+
+/* getopt - only used in main.c */
+int getopt(int argc, char *const argv[], const char *optstring);
+extern char *optarg;
+extern int optind;
+
+#ifndef CONFIG_NO_SOCKLEN_T_TYPEDEF
+#ifndef __socklen_t_defined
+typedef int socklen_t;
+#endif
+#endif
+
+/* inline - define as __inline or just define it to be empty, if needed */
+#ifdef CONFIG_NO_INLINE
+#define inline
+#else
+#define inline __inline
+#endif
+
+#ifndef __func__
+#define __func__ "__func__ not defined"
+#endif
+
+#ifndef bswap_16
+#define bswap_16(a) ((((u16) (a) << 8) & 0xff00) | (((u16) (a) >> 8) & 0xff))
+#endif
+
+#ifndef bswap_32
+#define bswap_32(a) ((((u32) (a) << 24) & 0xff000000) | \
+ (((u32) (a) << 8) & 0xff0000) | \
+ (((u32) (a) >> 8) & 0xff00) | \
+ (((u32) (a) >> 24) & 0xff))
+#endif
+
+#ifndef MSG_DONTWAIT
+#define MSG_DONTWAIT 0
+#endif
+
+#ifdef _WIN32_WCE
+void perror(const char *s);
+#endif /* _WIN32_WCE */
+
+#endif /* CONFIG_ANSI_C_EXTRA */
+
+#define wpa_zalloc(s) os_zalloc((s))
+
+#ifdef CONFIG_NATIVE_WINDOWS
+void wpa_unicode2ascii_inplace(TCHAR *str);
+TCHAR * wpa_strdup_tchar(const char *str);
+#else /* CONFIG_NATIVE_WINDOWS */
+#define wpa_unicode2ascii_inplace(s) do { } while (0)
+#define wpa_strdup_tchar(s) strdup((s))
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+const char * wpa_ssid_txt(u8 *ssid, size_t ssid_len);
+
+typedef u32 __be32;
+typedef u64 __be64;
+
#endif /* COMMON_H */
diff --git a/contrib/hostapd/config.c b/contrib/hostapd/config.c
index 016d9b9c959d..d1b2ba3fa5e0 100644
--- a/contrib/hostapd/config.c
+++ b/contrib/hostapd/config.c
@@ -1,7 +1,6 @@
/*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / Configuration file
- * Copyright (c) 2003-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * hostapd / Configuration file
+ * 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
@@ -13,63 +12,230 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <sys/socket.h>
-#include <sys/socket.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
+#include "includes.h"
+#ifndef CONFIG_NATIVE_WINDOWS
#include <grp.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
#include "hostapd.h"
#include "driver.h"
#include "sha1.h"
#include "eap.h"
#include "radius_client.h"
-#include "ieee802_1x.h" /* XXX for EAPOL_VERSION */
+#include "wpa_common.h"
-static struct hostapd_config *hostapd_config_defaults(void)
+#define MAX_STA_COUNT 2007
+
+
+static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
+ const char *fname)
{
- struct hostapd_config *conf;
+ FILE *f;
+ char buf[128], *pos, *pos2;
+ int line = 0, vlan_id;
+ struct hostapd_vlan *vlan;
- conf = malloc(sizeof(*conf) + sizeof(struct hostapd_radius_servers));
- if (conf == NULL) {
+ f = fopen(fname, "r");
+ if (!f) {
+ printf("VLAN file '%s' not readable.\n", fname);
+ return -1;
+ }
+
+ while (fgets(buf, sizeof(buf), f)) {
+ line++;
+
+ if (buf[0] == '#')
+ continue;
+ pos = buf;
+ while (*pos != '\0') {
+ if (*pos == '\n') {
+ *pos = '\0';
+ break;
+ }
+ pos++;
+ }
+ if (buf[0] == '\0')
+ continue;
+
+ if (buf[0] == '*') {
+ vlan_id = VLAN_ID_WILDCARD;
+ pos = buf + 1;
+ } else {
+ vlan_id = strtol(buf, &pos, 10);
+ if (buf == pos || vlan_id < 1 ||
+ vlan_id > MAX_VLAN_ID) {
+ printf("Invalid VLAN ID at line %d in '%s'\n",
+ line, fname);
+ fclose(f);
+ return -1;
+ }
+ }
+
+ while (*pos == ' ' || *pos == '\t')
+ pos++;
+ pos2 = pos;
+ while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0')
+ pos2++;
+ *pos2 = '\0';
+ if (*pos == '\0' || strlen(pos) > IFNAMSIZ) {
+ printf("Invalid VLAN ifname at line %d in '%s'\n",
+ line, fname);
+ fclose(f);
+ return -1;
+ }
+
+ vlan = malloc(sizeof(*vlan));
+ if (vlan == NULL) {
+ printf("Out of memory while reading VLAN interfaces "
+ "from '%s'\n", fname);
+ fclose(f);
+ return -1;
+ }
+
+ memset(vlan, 0, sizeof(*vlan));
+ vlan->vlan_id = vlan_id;
+ strncpy(vlan->ifname, pos, sizeof(vlan->ifname));
+ if (bss->vlan_tail)
+ bss->vlan_tail->next = vlan;
+ else
+ bss->vlan = vlan;
+ bss->vlan_tail = vlan;
+ }
+
+ fclose(f);
+
+ return 0;
+}
+
+
+static void hostapd_config_free_vlan(struct hostapd_bss_config *bss)
+{
+ struct hostapd_vlan *vlan, *prev;
+
+ vlan = bss->vlan;
+ prev = NULL;
+ while (vlan) {
+ prev = vlan;
+ vlan = vlan->next;
+ free(prev);
+ }
+
+ bss->vlan = NULL;
+}
+
+
+/* convert floats with one decimal place to value*10 int, i.e.,
+ * "1.5" will return 15 */
+static int hostapd_config_read_int10(const char *value)
+{
+ int i, d;
+ char *pos;
+
+ i = atoi(value);
+ pos = strchr(value, '.');
+ d = 0;
+ if (pos) {
+ pos++;
+ if (*pos >= '0' && *pos <= '9')
+ d = *pos - '0';
+ }
+
+ return i * 10 + d;
+}
+
+
+static void hostapd_config_defaults_bss(struct hostapd_bss_config *bss)
+{
+ bss->logger_syslog_level = HOSTAPD_LEVEL_INFO;
+ bss->logger_stdout_level = HOSTAPD_LEVEL_INFO;
+ bss->logger_syslog = (unsigned int) -1;
+ bss->logger_stdout = (unsigned int) -1;
+
+ bss->auth_algs = HOSTAPD_AUTH_OPEN | HOSTAPD_AUTH_SHARED_KEY;
+
+ bss->wep_rekeying_period = 300;
+ /* use key0 in individual key and key1 in broadcast key */
+ bss->broadcast_key_idx_min = 1;
+ bss->broadcast_key_idx_max = 2;
+ bss->eap_reauth_period = 3600;
+
+ bss->wpa_group_rekey = 600;
+ bss->wpa_gmk_rekey = 86400;
+ bss->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+ bss->wpa_pairwise = WPA_CIPHER_TKIP;
+ bss->wpa_group = WPA_CIPHER_TKIP;
+
+ bss->max_num_sta = MAX_STA_COUNT;
+
+ bss->dtim_period = 2;
+
+ bss->radius_server_auth_port = 1812;
+ bss->ap_max_inactivity = AP_MAX_INACTIVITY;
+ bss->eapol_version = EAPOL_VERSION;
+}
+
+
+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 =
+ { aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
+ const struct hostapd_wme_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 };
+
+ conf = wpa_zalloc(sizeof(*conf));
+ bss = wpa_zalloc(sizeof(*bss));
+ if (conf == NULL || bss == NULL) {
printf("Failed to allocate memory for configuration data.\n");
+ free(conf);
+ free(bss);
return NULL;
}
- memset(conf, 0, sizeof(*conf) + sizeof(struct hostapd_radius_servers));
- conf->radius = (struct hostapd_radius_servers *) (conf + 1);
/* set default driver based on configuration */
conf->driver = driver_lookup("default");
if (conf->driver == NULL) {
printf("No default driver registered!\n");
free(conf);
+ free(bss);
return NULL;
}
- conf->wep_rekeying_period = 300;
- conf->eap_reauth_period = 3600;
+ bss->radius = wpa_zalloc(sizeof(*bss->radius));
+ if (bss->radius == NULL) {
+ free(conf);
+ free(bss);
+ return NULL;
+ }
+
+ hostapd_config_defaults_bss(bss);
- conf->logger_syslog_level = HOSTAPD_LEVEL_INFO;
- conf->logger_stdout_level = HOSTAPD_LEVEL_INFO;
- conf->logger_syslog = (unsigned int) -1;
- conf->logger_stdout = (unsigned int) -1;
+ conf->num_bss = 1;
+ conf->bss = bss;
- conf->auth_algs = HOSTAPD_AUTH_OPEN | HOSTAPD_AUTH_SHARED_KEY;
- conf->eapol_version = EAPOL_VERSION; /* NB: default version */
+ conf->beacon_int = 100;
+ conf->rts_threshold = -1; /* use driver default: 2347 */
+ conf->fragm_threshold = -1; /* user driver default: 2346 */
+ conf->send_probe_response = 1;
+ conf->bridge_packets = INTERNAL_BRIDGE_DO_NOT_CONTROL;
- conf->wpa_group_rekey = 600;
- conf->wpa_gmk_rekey = 86400;
- conf->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
- conf->wpa_pairwise = WPA_CIPHER_TKIP;
- conf->wpa_group = WPA_CIPHER_TKIP;
+ memcpy(conf->country, "US ", 3);
- conf->radius_server_auth_port = 1812;
+ 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;
return conf;
}
@@ -93,12 +259,19 @@ static int hostapd_parse_ip_addr(const char *txt, struct hostapd_ip_addr *addr)
}
-static int mac_comp(const void *a, const void *b)
+int hostapd_mac_comp(const void *a, const void *b)
{
return memcmp(a, b, sizeof(macaddr));
}
+int hostapd_mac_comp_empty(const void *a)
+{
+ macaddr empty = { 0 };
+ return memcmp(a, empty, sizeof(macaddr));
+}
+
+
static int hostapd_config_read_maclist(const char *fname, macaddr **acl,
int *num)
{
@@ -154,14 +327,14 @@ static int hostapd_config_read_maclist(const char *fname, macaddr **acl,
fclose(f);
- qsort(*acl, *num, sizeof(macaddr), mac_comp);
+ qsort(*acl, *num, sizeof(macaddr), hostapd_mac_comp);
return 0;
}
static int hostapd_config_read_wpa_psk(const char *fname,
- struct hostapd_config *conf)
+ struct hostapd_ssid *ssid)
{
FILE *f;
char buf[128], *pos;
@@ -201,13 +374,12 @@ static int hostapd_config_read_wpa_psk(const char *fname,
break;
}
- psk = malloc(sizeof(*psk));
+ psk = wpa_zalloc(sizeof(*psk));
if (psk == NULL) {
printf("WPA PSK allocation failed\n");
ret = -1;
break;
}
- memset(psk, 0, sizeof(*psk));
if (memcmp(addr, "\x00\x00\x00\x00\x00\x00", ETH_ALEN) == 0)
psk->group = 1;
else
@@ -227,7 +399,7 @@ static int hostapd_config_read_wpa_psk(const char *fname,
if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
ok = 1;
else if (len >= 8 && len < 64) {
- pbkdf2_sha1(pos, conf->ssid, conf->ssid_len,
+ pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
4096, psk->psk, PMK_LEN);
ok = 1;
}
@@ -239,8 +411,8 @@ static int hostapd_config_read_wpa_psk(const char *fname,
break;
}
- psk->next = conf->wpa_psk;
- conf->wpa_psk = psk;
+ psk->next = ssid->wpa_psk;
+ ssid->wpa_psk = psk;
}
fclose(f);
@@ -249,42 +421,45 @@ static int hostapd_config_read_wpa_psk(const char *fname,
}
-int hostapd_setup_wpa_psk(struct hostapd_config *conf)
+int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
{
- if (conf->wpa_passphrase != NULL) {
- if (conf->wpa_psk != NULL) {
+ struct hostapd_ssid *ssid = &conf->ssid;
+
+ if (ssid->wpa_passphrase != NULL) {
+ if (ssid->wpa_psk != NULL) {
printf("Warning: both WPA PSK and passphrase set. "
"Using passphrase.\n");
- free(conf->wpa_psk);
+ free(ssid->wpa_psk);
}
- conf->wpa_psk = malloc(sizeof(struct hostapd_wpa_psk));
- if (conf->wpa_psk == NULL) {
+ ssid->wpa_psk = wpa_zalloc(sizeof(struct hostapd_wpa_psk));
+ if (ssid->wpa_psk == NULL) {
printf("Unable to alloc space for PSK\n");
return -1;
}
wpa_hexdump_ascii(MSG_DEBUG, "SSID",
- (u8 *) conf->ssid, conf->ssid_len);
+ (u8 *) ssid->ssid, ssid->ssid_len);
wpa_hexdump_ascii(MSG_DEBUG, "PSK (ASCII passphrase)",
- (u8 *) conf->wpa_passphrase,
- strlen(conf->wpa_passphrase));
- memset(conf->wpa_psk, 0, sizeof(struct hostapd_wpa_psk));
- pbkdf2_sha1(conf->wpa_passphrase,
- conf->ssid, conf->ssid_len,
- 4096, conf->wpa_psk->psk, PMK_LEN);
+ (u8 *) ssid->wpa_passphrase,
+ strlen(ssid->wpa_passphrase));
+ pbkdf2_sha1(ssid->wpa_passphrase,
+ ssid->ssid, ssid->ssid_len,
+ 4096, ssid->wpa_psk->psk, PMK_LEN);
wpa_hexdump(MSG_DEBUG, "PSK (from passphrase)",
- conf->wpa_psk->psk, PMK_LEN);
- conf->wpa_psk->group = 1;
+ ssid->wpa_psk->psk, PMK_LEN);
+ ssid->wpa_psk->group = 1;
- memset(conf->wpa_passphrase, 0, strlen(conf->wpa_passphrase));
- free(conf->wpa_passphrase);
- conf->wpa_passphrase = 0;
+ memset(ssid->wpa_passphrase, 0,
+ strlen(ssid->wpa_passphrase));
+ free(ssid->wpa_passphrase);
+ ssid->wpa_passphrase = NULL;
}
- if (conf->wpa_psk_file) {
- if (hostapd_config_read_wpa_psk(conf->wpa_psk_file, conf))
+ if (ssid->wpa_psk_file) {
+ if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file,
+ &conf->ssid))
return -1;
- free(conf->wpa_psk_file);
- conf->wpa_psk_file = NULL;
+ free(ssid->wpa_psk_file);
+ ssid->wpa_psk_file = NULL;
}
return 0;
@@ -293,7 +468,7 @@ int hostapd_setup_wpa_psk(struct hostapd_config *conf)
#ifdef EAP_SERVER
static int hostapd_config_read_eap_user(const char *fname,
- struct hostapd_config *conf)
+ struct hostapd_bss_config *conf)
{
FILE *f;
char buf[512], *pos, *start, *pos2;
@@ -334,12 +509,11 @@ static int hostapd_config_read_eap_user(const char *fname,
goto failed;
}
- user = malloc(sizeof(*user));
+ user = wpa_zalloc(sizeof(*user));
if (user == NULL) {
printf("EAP user allocation failed\n");
goto failed;
}
- memset(user, 0, sizeof(*user));
user->force_version = -1;
if (buf[0] == '*') {
@@ -363,6 +537,11 @@ static int hostapd_config_read_eap_user(const char *fname,
}
memcpy(user->identity, start, pos - start);
user->identity_len = pos - start;
+
+ if (pos[0] == '"' && pos[1] == '*') {
+ user->wildcard_prefix = 1;
+ pos++;
+ }
}
pos++;
while (*pos == ' ' || *pos == '\t')
@@ -385,12 +564,17 @@ static int hostapd_config_read_eap_user(const char *fname,
}
num_methods = 0;
while (*start) {
- char *pos2 = strchr(start, ',');
- if (pos2) {
- *pos2++ = '\0';
+ char *pos3 = strchr(start, ',');
+ if (pos3) {
+ *pos3++ = '\0';
}
- user->methods[num_methods] = eap_get_type(start);
- if (user->methods[num_methods] == EAP_TYPE_NONE) {
+ user->methods[num_methods].method =
+ eap_get_type(start, &user->methods[num_methods]
+ .vendor);
+ if (user->methods[num_methods].vendor ==
+ EAP_VENDOR_IETF &&
+ user->methods[num_methods].method == EAP_TYPE_NONE)
+ {
printf("Unsupported EAP type '%s' on line %d "
"in '%s'\n", start, line, fname);
goto failed;
@@ -399,9 +583,9 @@ static int hostapd_config_read_eap_user(const char *fname,
num_methods++;
if (num_methods >= EAP_USER_MAX_METHODS)
break;
- if (pos2 == NULL)
+ if (pos3 == NULL)
break;
- start = pos2;
+ start = pos3;
}
if (num_methods == 0) {
printf("No EAP types configured on line %d in '%s'\n",
@@ -453,6 +637,31 @@ static int hostapd_config_read_eap_user(const char *fname,
user->password_len = pos - start;
pos++;
+ } else if (strncmp(pos, "hash:", 5) == 0) {
+ pos += 5;
+ pos2 = pos;
+ while (*pos2 != '\0' && *pos2 != ' ' &&
+ *pos2 != '\t' && *pos2 != '#')
+ pos2++;
+ if (pos2 - pos != 32) {
+ printf("Invalid password hash on line %d in "
+ "'%s'\n", line, fname);
+ goto failed;
+ }
+ user->password = malloc(16);
+ if (user->password == NULL) {
+ printf("Failed to allocate memory for EAP "
+ "password hash\n");
+ goto failed;
+ }
+ if (hexstr2bin(pos, user->password, 16) < 0) {
+ printf("Invalid hash password on line %d in "
+ "'%s'\n", line, fname);
+ goto failed;
+ }
+ user->password_len = 16;
+ user->password_hash = 1;
+ pos = pos2;
} else {
pos2 = pos;
while (*pos2 != '\0' && *pos2 != ' ' &&
@@ -496,6 +705,7 @@ static int hostapd_config_read_eap_user(const char *fname,
failed:
if (user) {
+ free(user->password);
free(user->identity);
free(user);
}
@@ -562,7 +772,8 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
else if (strcmp(start, "WPA-EAP") == 0)
val |= WPA_KEY_MGMT_IEEE8021X;
else {
- printf("Line %d: invalid key_mgmt '%s'", line, start);
+ printf("Line %d: invalid key_mgmt '%s'\n",
+ line, start);
free(buf);
return -1;
}
@@ -574,7 +785,7 @@ static int hostapd_config_parse_key_mgmt(int line, const char *value)
free(buf);
if (val == 0) {
- printf("Line %d: no key_mgmt values configured.", line);
+ printf("Line %d: no key_mgmt values configured.\n", line);
return -1;
}
@@ -632,23 +843,308 @@ static int hostapd_config_parse_cipher(int line, const char *value)
}
-static int hostapd_config_check(struct hostapd_config *conf)
+static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
+ struct hostapd_config *conf)
{
- if (conf->ieee802_1x && !conf->eap_server &&
- !conf->radius->auth_servers) {
+ if (bss->ieee802_1x && !bss->eap_server &&
+ !bss->radius->auth_servers) {
printf("Invalid IEEE 802.1X configuration (no EAP "
"authenticator configured).\n");
return -1;
}
- if (conf->wpa && (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
- conf->wpa_psk == NULL && conf->wpa_passphrase == NULL &&
- conf->wpa_psk_file == NULL) {
+ if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+ bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
+ bss->ssid.wpa_psk_file == NULL) {
printf("WPA-PSK enabled, but PSK or passphrase is not "
"configured.\n");
return -1;
}
+ if (hostapd_mac_comp_empty(bss->bssid) != 0) {
+ size_t i;
+
+ for (i = 0; i < conf->num_bss; i++) {
+ if ((&conf->bss[i] != bss) &&
+ (hostapd_mac_comp(conf->bss[i].bssid,
+ bss->bssid) == 0)) {
+ printf("Duplicate BSSID " MACSTR
+ " on interface '%s' and '%s'.\n",
+ MAC2STR(bss->bssid),
+ conf->bss[i].iface, bss->iface);
+ return -1;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+static int hostapd_config_check(struct hostapd_config *conf)
+{
+ size_t i;
+
+ for (i = 0; i < conf->num_bss; i++) {
+ if (hostapd_config_check_bss(&conf->bss[i], conf))
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
+ char *val)
+{
+ size_t len = strlen(val);
+
+ if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL)
+ return -1;
+
+ if (val[0] == '"') {
+ if (len < 2 || val[len - 1] != '"')
+ return -1;
+ len -= 2;
+ wep->key[keyidx] = malloc(len);
+ if (wep->key[keyidx] == NULL)
+ return -1;
+ memcpy(wep->key[keyidx], val + 1, len);
+ wep->len[keyidx] = len;
+ } else {
+ if (len & 1)
+ return -1;
+ len /= 2;
+ wep->key[keyidx] = malloc(len);
+ if (wep->key[keyidx] == NULL)
+ return -1;
+ wep->len[keyidx] = len;
+ if (hexstr2bin(val, wep->key[keyidx], len) < 0)
+ return -1;
+ }
+
+ wep->keys_set++;
+
+ return 0;
+}
+
+
+static int hostapd_parse_rates(int **rate_list, char *val)
+{
+ int *list;
+ int count;
+ char *pos, *end;
+
+ free(*rate_list);
+ *rate_list = NULL;
+
+ pos = val;
+ count = 0;
+ while (*pos != '\0') {
+ if (*pos == ' ')
+ count++;
+ pos++;
+ }
+
+ list = malloc(sizeof(int) * (count + 2));
+ if (list == NULL)
+ return -1;
+ pos = val;
+ count = 0;
+ while (*pos != '\0') {
+ end = strchr(pos, ' ');
+ if (end)
+ *end = '\0';
+
+ list[count++] = atoi(pos);
+ if (!end)
+ break;
+ pos = end + 1;
+ }
+ list[count] = -1;
+
+ *rate_list = list;
+ return 0;
+}
+
+
+static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
+{
+ struct hostapd_bss_config *bss;
+
+ if (*ifname == '\0')
+ return -1;
+
+ bss = realloc(conf->bss, (conf->num_bss + 1) *
+ sizeof(struct hostapd_bss_config));
+ if (bss == NULL) {
+ printf("Failed to allocate memory for multi-BSS entry\n");
+ return -1;
+ }
+ conf->bss = bss;
+
+ bss = &(conf->bss[conf->num_bss]);
+ memset(bss, 0, sizeof(*bss));
+ bss->radius = wpa_zalloc(sizeof(*bss->radius));
+ if (bss->radius == NULL) {
+ printf("Failed to allocate memory for multi-BSS RADIUS "
+ "data\n");
+ return -1;
+ }
+
+ conf->num_bss++;
+ conf->last_bss = bss;
+
+ hostapd_config_defaults_bss(bss);
+ snprintf(bss->iface, sizeof(bss->iface), "%s", ifname);
+ memcpy(bss->ssid.vlan, bss->iface, IFNAMSIZ + 1);
+
+ return 0;
+}
+
+
+static int valid_cw(int cw)
+{
+ return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
+ cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023);
+}
+
+
+enum {
+ IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
+ IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
+ IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
+ IEEE80211_TX_QUEUE_DATA3 = 3, /* used for EDCA AC_BK data */
+ IEEE80211_TX_QUEUE_DATA4 = 4,
+ IEEE80211_TX_QUEUE_AFTER_BEACON = 6,
+ IEEE80211_TX_QUEUE_BEACON = 7
+};
+
+static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
+ char *val)
+{
+ int num;
+ char *pos;
+ struct hostapd_tx_queue_params *queue;
+
+ /* skip 'tx_queue_' prefix */
+ pos = name + 9;
+ if (strncmp(pos, "data", 4) == 0 &&
+ pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
+ num = pos[4] - '0';
+ pos += 6;
+ } else if (strncmp(pos, "after_beacon_", 13) == 0) {
+ num = IEEE80211_TX_QUEUE_AFTER_BEACON;
+ pos += 13;
+ } else if (strncmp(pos, "beacon_", 7) == 0) {
+ num = IEEE80211_TX_QUEUE_BEACON;
+ pos += 7;
+ } else {
+ printf("Unknown tx_queue name '%s'\n", pos);
+ return -1;
+ }
+
+ queue = &conf->tx_queue[num];
+
+ if (strcmp(pos, "aifs") == 0) {
+ queue->aifs = atoi(val);
+ if (queue->aifs < 0 || queue->aifs > 255) {
+ printf("Invalid AIFS value %d\n", queue->aifs);
+ return -1;
+ }
+ } else if (strcmp(pos, "cwmin") == 0) {
+ queue->cwmin = atoi(val);
+ if (!valid_cw(queue->cwmin)) {
+ printf("Invalid cwMin value %d\n", queue->cwmin);
+ return -1;
+ }
+ } else if (strcmp(pos, "cwmax") == 0) {
+ queue->cwmax = atoi(val);
+ if (!valid_cw(queue->cwmax)) {
+ printf("Invalid cwMax value %d\n", queue->cwmax);
+ return -1;
+ }
+ } else if (strcmp(pos, "burst") == 0) {
+ queue->burst = hostapd_config_read_int10(val);
+ } else {
+ printf("Unknown tx_queue field '%s'\n", pos);
+ return -1;
+ }
+
+ queue->configured = 1;
+
+ return 0;
+}
+
+
+static int hostapd_config_wme_ac(struct hostapd_config *conf, char *name,
+ char *val)
+{
+ int num, v;
+ char *pos;
+ struct hostapd_wme_ac_params *ac;
+
+ /* skip 'wme_ac_' prefix */
+ pos = name + 7;
+ if (strncmp(pos, "be_", 3) == 0) {
+ num = 0;
+ pos += 3;
+ } else if (strncmp(pos, "bk_", 3) == 0) {
+ num = 1;
+ pos += 3;
+ } else if (strncmp(pos, "vi_", 3) == 0) {
+ num = 2;
+ pos += 3;
+ } else if (strncmp(pos, "vo_", 3) == 0) {
+ num = 3;
+ pos += 3;
+ } else {
+ printf("Unknown wme name '%s'\n", pos);
+ return -1;
+ }
+
+ ac = &conf->wme_ac_params[num];
+
+ if (strcmp(pos, "aifs") == 0) {
+ v = atoi(val);
+ if (v < 1 || v > 255) {
+ printf("Invalid AIFS value %d\n", v);
+ return -1;
+ }
+ ac->aifs = v;
+ } else if (strcmp(pos, "cwmin") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 12) {
+ printf("Invalid cwMin value %d\n", v);
+ return -1;
+ }
+ ac->cwmin = v;
+ } else if (strcmp(pos, "cwmax") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 12) {
+ printf("Invalid cwMax value %d\n", v);
+ return -1;
+ }
+ ac->cwmax = v;
+ } else if (strcmp(pos, "txop_limit") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 0xffff) {
+ printf("Invalid txop value %d\n", v);
+ return -1;
+ }
+ ac->txopLimit = v;
+ } else if (strcmp(pos, "acm") == 0) {
+ v = atoi(val);
+ if (v < 0 || v > 1) {
+ printf("Invalid acm value %d\n", v);
+ return -1;
+ }
+ ac->admission_control_mandatory = v;
+ } else {
+ printf("Unknown wme_ac_ field '%s'\n", pos);
+ return -1;
+ }
+
return 0;
}
@@ -656,14 +1152,12 @@ static int hostapd_config_check(struct hostapd_config *conf)
struct hostapd_config * hostapd_config_read(const char *fname)
{
struct hostapd_config *conf;
+ struct hostapd_bss_config *bss;
FILE *f;
char buf[256], *pos;
int line = 0;
int errors = 0;
- char *accept_mac_file = NULL, *deny_mac_file = NULL;
-#ifdef EAP_SERVER
- char *eap_user_file = NULL;
-#endif /* EAP_SERVER */
+ size_t i;
f = fopen(fname, "r");
if (f == NULL) {
@@ -677,8 +1171,10 @@ struct hostapd_config * hostapd_config_read(const char *fname)
fclose(f);
return NULL;
}
+ bss = conf->last_bss = conf->bss;
while (fgets(buf, sizeof(buf), f)) {
+ bss = conf->last_bss;
line++;
if (buf[0] == '#')
@@ -704,10 +1200,10 @@ struct hostapd_config * hostapd_config_read(const char *fname)
pos++;
if (strcmp(buf, "interface") == 0) {
- snprintf(conf->iface, sizeof(conf->iface), "%s", pos);
+ snprintf(conf->bss[0].iface,
+ sizeof(conf->bss[0].iface), "%s", pos);
} else if (strcmp(buf, "bridge") == 0) {
- snprintf(conf->bridge, sizeof(conf->bridge), "%s",
- pos);
+ snprintf(bss->bridge, sizeof(bss->bridge), "%s", pos);
} else if (strcmp(buf, "driver") == 0) {
conf->driver = driver_lookup(pos);
if (conf->driver == NULL) {
@@ -716,185 +1212,199 @@ struct hostapd_config * hostapd_config_read(const char *fname)
errors++;
}
} else if (strcmp(buf, "debug") == 0) {
- conf->debug = atoi(pos);
+ bss->debug = atoi(pos);
} else if (strcmp(buf, "logger_syslog_level") == 0) {
- conf->logger_syslog_level = atoi(pos);
+ bss->logger_syslog_level = atoi(pos);
} else if (strcmp(buf, "logger_stdout_level") == 0) {
- conf->logger_stdout_level = atoi(pos);
+ bss->logger_stdout_level = atoi(pos);
} else if (strcmp(buf, "logger_syslog") == 0) {
- conf->logger_syslog = atoi(pos);
+ bss->logger_syslog = atoi(pos);
} else if (strcmp(buf, "logger_stdout") == 0) {
- conf->logger_stdout = atoi(pos);
+ bss->logger_stdout = atoi(pos);
} else if (strcmp(buf, "dump_file") == 0) {
- conf->dump_log_name = strdup(pos);
+ bss->dump_log_name = strdup(pos);
} else if (strcmp(buf, "ssid") == 0) {
- conf->ssid_len = strlen(pos);
- if (conf->ssid_len >= HOSTAPD_SSID_LEN ||
- conf->ssid_len < 1) {
+ bss->ssid.ssid_len = strlen(pos);
+ if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
+ bss->ssid.ssid_len < 1) {
printf("Line %d: invalid SSID '%s'\n", line,
pos);
errors++;
+ } else {
+ memcpy(bss->ssid.ssid, pos,
+ bss->ssid.ssid_len);
+ bss->ssid.ssid[bss->ssid.ssid_len] = '\0';
+ bss->ssid.ssid_set = 1;
}
- memcpy(conf->ssid, pos, conf->ssid_len);
- conf->ssid[conf->ssid_len] = '\0';
- conf->ssid_set = 1;
} else if (strcmp(buf, "macaddr_acl") == 0) {
- conf->macaddr_acl = atoi(pos);
- if (conf->macaddr_acl != ACCEPT_UNLESS_DENIED &&
- conf->macaddr_acl != DENY_UNLESS_ACCEPTED &&
- conf->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+ bss->macaddr_acl = atoi(pos);
+ if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
+ bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
+ bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
printf("Line %d: unknown macaddr_acl %d\n",
- line, conf->macaddr_acl);
+ line, bss->macaddr_acl);
}
} else if (strcmp(buf, "accept_mac_file") == 0) {
- accept_mac_file = strdup(pos);
- if (!accept_mac_file) {
- printf("Line %d: allocation failed\n", line);
+ if (hostapd_config_read_maclist(pos, &bss->accept_mac,
+ &bss->num_accept_mac))
+ {
+ printf("Line %d: Failed to read "
+ "accept_mac_file '%s'\n",
+ line, pos);
errors++;
}
} else if (strcmp(buf, "deny_mac_file") == 0) {
- deny_mac_file = strdup(pos);
- if (!deny_mac_file) {
- printf("Line %d: allocation failed\n", line);
+ if (hostapd_config_read_maclist(pos, &bss->deny_mac,
+ &bss->num_deny_mac))
+ {
+ printf("Line %d: Failed to read "
+ "deny_mac_file '%s'\n",
+ line, pos);
errors++;
}
+ } else if (strcmp(buf, "ap_max_inactivity") == 0) {
+ bss->ap_max_inactivity = atoi(pos);
+ } else if (strcmp(buf, "country_code") == 0) {
+ memcpy(conf->country, pos, 2);
+ /* FIX: make this configurable */
+ conf->country[2] = ' ';
+ } else if (strcmp(buf, "ieee80211d") == 0) {
+ conf->ieee80211d = atoi(pos);
+ } else if (strcmp(buf, "ieee80211h") == 0) {
+ conf->ieee80211h = atoi(pos);
} else if (strcmp(buf, "assoc_ap_addr") == 0) {
- if (hwaddr_aton(pos, conf->assoc_ap_addr)) {
+ if (hwaddr_aton(pos, bss->assoc_ap_addr)) {
printf("Line %d: invalid MAC address '%s'\n",
line, pos);
errors++;
}
- conf->assoc_ap = 1;
+ bss->assoc_ap = 1;
} else if (strcmp(buf, "ieee8021x") == 0) {
- conf->ieee802_1x = atoi(pos);
+ bss->ieee802_1x = atoi(pos);
+ } else if (strcmp(buf, "eapol_version") == 0) {
+ bss->eapol_version = atoi(pos);
+ if (bss->eapol_version < 1 ||
+ bss->eapol_version > 2) {
+ printf("Line %d: invalid EAPOL "
+ "version (%d): '%s'.\n",
+ line, bss->eapol_version, pos);
+ errors++;
+ } else
+ wpa_printf(MSG_DEBUG, "eapol_version=%d",
+ bss->eapol_version);
#ifdef EAP_SERVER
} else if (strcmp(buf, "eap_authenticator") == 0) {
- conf->eap_server = atoi(pos);
+ bss->eap_server = atoi(pos);
printf("Line %d: obsolete eap_authenticator used; "
"this has been renamed to eap_server\n", line);
} else if (strcmp(buf, "eap_server") == 0) {
- conf->eap_server = atoi(pos);
+ bss->eap_server = atoi(pos);
} else if (strcmp(buf, "eap_user_file") == 0) {
- free(eap_user_file);
- eap_user_file = strdup(pos);
- if (!eap_user_file) {
- printf("Line %d: allocation failed\n", line);
+ if (hostapd_config_read_eap_user(pos, bss))
errors++;
- }
} else if (strcmp(buf, "ca_cert") == 0) {
- free(conf->ca_cert);
- conf->ca_cert = strdup(pos);
+ free(bss->ca_cert);
+ bss->ca_cert = strdup(pos);
} else if (strcmp(buf, "server_cert") == 0) {
- free(conf->server_cert);
- conf->server_cert = strdup(pos);
+ free(bss->server_cert);
+ bss->server_cert = strdup(pos);
} else if (strcmp(buf, "private_key") == 0) {
- free(conf->private_key);
- conf->private_key = strdup(pos);
+ free(bss->private_key);
+ bss->private_key = strdup(pos);
} else if (strcmp(buf, "private_key_passwd") == 0) {
- free(conf->private_key_passwd);
- conf->private_key_passwd = strdup(pos);
+ free(bss->private_key_passwd);
+ bss->private_key_passwd = strdup(pos);
} else if (strcmp(buf, "check_crl") == 0) {
- conf->check_crl = atoi(pos);
+ bss->check_crl = atoi(pos);
#ifdef EAP_SIM
} else if (strcmp(buf, "eap_sim_db") == 0) {
- free(conf->eap_sim_db);
- conf->eap_sim_db = strdup(pos);
+ free(bss->eap_sim_db);
+ bss->eap_sim_db = strdup(pos);
#endif /* EAP_SIM */
#endif /* EAP_SERVER */
} else if (strcmp(buf, "eap_message") == 0) {
char *term;
- conf->eap_req_id_text = strdup(pos);
- if (conf->eap_req_id_text == NULL) {
+ bss->eap_req_id_text = strdup(pos);
+ if (bss->eap_req_id_text == NULL) {
printf("Line %d: Failed to allocate memory "
"for eap_req_id_text\n", line);
errors++;
continue;
}
- conf->eap_req_id_text_len =
- strlen(conf->eap_req_id_text);
- term = strstr(conf->eap_req_id_text, "\\0");
+ bss->eap_req_id_text_len =
+ strlen(bss->eap_req_id_text);
+ term = strstr(bss->eap_req_id_text, "\\0");
if (term) {
*term++ = '\0';
memmove(term, term + 1,
- conf->eap_req_id_text_len -
- (term - conf->eap_req_id_text) - 1);
- conf->eap_req_id_text_len--;
+ bss->eap_req_id_text_len -
+ (term - bss->eap_req_id_text) - 1);
+ bss->eap_req_id_text_len--;
}
} else if (strcmp(buf, "wep_key_len_broadcast") == 0) {
- conf->default_wep_key_len = atoi(pos);
- if (conf->default_wep_key_len > 13) {
+ bss->default_wep_key_len = atoi(pos);
+ if (bss->default_wep_key_len > 13) {
printf("Line %d: invalid WEP key len %lu "
"(= %lu bits)\n", line,
(unsigned long)
- conf->default_wep_key_len,
+ bss->default_wep_key_len,
(unsigned long)
- conf->default_wep_key_len * 8);
+ bss->default_wep_key_len * 8);
errors++;
}
} else if (strcmp(buf, "wep_key_len_unicast") == 0) {
- conf->individual_wep_key_len = atoi(pos);
- if (conf->individual_wep_key_len < 0 ||
- conf->individual_wep_key_len > 13) {
+ bss->individual_wep_key_len = atoi(pos);
+ if (bss->individual_wep_key_len < 0 ||
+ bss->individual_wep_key_len > 13) {
printf("Line %d: invalid WEP key len %d "
"(= %d bits)\n", line,
- conf->individual_wep_key_len,
- conf->individual_wep_key_len * 8);
+ bss->individual_wep_key_len,
+ bss->individual_wep_key_len * 8);
errors++;
}
} else if (strcmp(buf, "wep_rekey_period") == 0) {
- conf->wep_rekeying_period = atoi(pos);
- if (conf->wep_rekeying_period < 0) {
+ bss->wep_rekeying_period = atoi(pos);
+ if (bss->wep_rekeying_period < 0) {
printf("Line %d: invalid period %d\n",
- line, conf->wep_rekeying_period);
+ line, bss->wep_rekeying_period);
errors++;
}
} else if (strcmp(buf, "eap_reauth_period") == 0) {
- conf->eap_reauth_period = atoi(pos);
- if (conf->eap_reauth_period < 0) {
+ bss->eap_reauth_period = atoi(pos);
+ if (bss->eap_reauth_period < 0) {
printf("Line %d: invalid period %d\n",
- line, conf->eap_reauth_period);
+ line, bss->eap_reauth_period);
errors++;
}
} else if (strcmp(buf, "eapol_key_index_workaround") == 0) {
- conf->eapol_key_index_workaround = atoi(pos);
- } else if (strcmp(buf, "eapol_version") == 0) {
- conf->eapol_version = atoi(pos);
- if (conf->eapol_version < 1 ||
- conf->eapol_version > 2) {
- printf("Line %d: invalid EAPOL "
- "version (%d): '%s'.\n",
- line, conf->eapol_version, pos);
- errors++;
- } else
- wpa_printf(MSG_DEBUG, "eapol_version=%d",
- conf->eapol_version);
+ bss->eapol_key_index_workaround = atoi(pos);
#ifdef CONFIG_IAPP
} else if (strcmp(buf, "iapp_interface") == 0) {
- conf->ieee802_11f = 1;
- snprintf(conf->iapp_iface, sizeof(conf->iapp_iface),
+ bss->ieee802_11f = 1;
+ snprintf(bss->iapp_iface, sizeof(bss->iapp_iface),
"%s", pos);
#endif /* CONFIG_IAPP */
} else if (strcmp(buf, "own_ip_addr") == 0) {
- if (hostapd_parse_ip_addr(pos, &conf->own_ip_addr)) {
+ if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
printf("Line %d: invalid IP address '%s'\n",
line, pos);
errors++;
}
} else if (strcmp(buf, "nas_identifier") == 0) {
- conf->nas_identifier = strdup(pos);
+ bss->nas_identifier = strdup(pos);
} else if (strcmp(buf, "auth_server_addr") == 0) {
if (hostapd_config_read_radius_addr(
- &conf->radius->auth_servers,
- &conf->radius->num_auth_servers, pos, 1812,
- &conf->radius->auth_server)) {
+ &bss->radius->auth_servers,
+ &bss->radius->num_auth_servers, pos, 1812,
+ &bss->radius->auth_server)) {
printf("Line %d: invalid IP address '%s'\n",
line, pos);
errors++;
}
- } else if (conf->radius->auth_server &&
+ } else if (bss->radius->auth_server &&
strcmp(buf, "auth_server_port") == 0) {
- conf->radius->auth_server->port = atoi(pos);
- } else if (conf->radius->auth_server &&
+ bss->radius->auth_server->port = atoi(pos);
+ } else if (bss->radius->auth_server &&
strcmp(buf, "auth_server_shared_secret") == 0) {
int len = strlen(pos);
if (len == 0) {
@@ -903,22 +1413,22 @@ struct hostapd_config * hostapd_config_read(const char *fname)
"allowed.\n", line);
errors++;
}
- conf->radius->auth_server->shared_secret =
+ bss->radius->auth_server->shared_secret =
(u8 *) strdup(pos);
- conf->radius->auth_server->shared_secret_len = len;
+ bss->radius->auth_server->shared_secret_len = len;
} else if (strcmp(buf, "acct_server_addr") == 0) {
if (hostapd_config_read_radius_addr(
- &conf->radius->acct_servers,
- &conf->radius->num_acct_servers, pos, 1813,
- &conf->radius->acct_server)) {
+ &bss->radius->acct_servers,
+ &bss->radius->num_acct_servers, pos, 1813,
+ &bss->radius->acct_server)) {
printf("Line %d: invalid IP address '%s'\n",
line, pos);
errors++;
}
- } else if (conf->radius->acct_server &&
+ } else if (bss->radius->acct_server &&
strcmp(buf, "acct_server_port") == 0) {
- conf->radius->acct_server->port = atoi(pos);
- } else if (conf->radius->acct_server &&
+ bss->radius->acct_server->port = atoi(pos);
+ } else if (bss->radius->acct_server &&
strcmp(buf, "acct_server_shared_secret") == 0) {
int len = strlen(pos);
if (len == 0) {
@@ -927,29 +1437,38 @@ struct hostapd_config * hostapd_config_read(const char *fname)
"allowed.\n", line);
errors++;
}
- conf->radius->acct_server->shared_secret =
+ bss->radius->acct_server->shared_secret =
(u8 *) strdup(pos);
- conf->radius->acct_server->shared_secret_len = len;
+ bss->radius->acct_server->shared_secret_len = len;
} else if (strcmp(buf, "radius_retry_primary_interval") == 0) {
- conf->radius->retry_primary_interval = atoi(pos);
+ bss->radius->retry_primary_interval = atoi(pos);
} else if (strcmp(buf, "radius_acct_interim_interval") == 0) {
- conf->radius->acct_interim_interval = atoi(pos);
+ bss->radius->acct_interim_interval = atoi(pos);
} else if (strcmp(buf, "auth_algs") == 0) {
- conf->auth_algs = atoi(pos);
- if (conf->auth_algs == 0) {
+ bss->auth_algs = atoi(pos);
+ if (bss->auth_algs == 0) {
printf("Line %d: no authentication algorithms "
"allowed\n",
line);
errors++;
}
+ } else if (strcmp(buf, "max_num_sta") == 0) {
+ bss->max_num_sta = atoi(pos);
+ if (bss->max_num_sta < 0 ||
+ bss->max_num_sta > MAX_STA_COUNT) {
+ printf("Line %d: Invalid max_num_sta=%d; "
+ "allowed range 0..%d\n", line,
+ bss->max_num_sta, MAX_STA_COUNT);
+ errors++;
+ }
} else if (strcmp(buf, "wpa") == 0) {
- conf->wpa = atoi(pos);
+ bss->wpa = atoi(pos);
} else if (strcmp(buf, "wpa_group_rekey") == 0) {
- conf->wpa_group_rekey = atoi(pos);
+ bss->wpa_group_rekey = atoi(pos);
} else if (strcmp(buf, "wpa_strict_rekey") == 0) {
- conf->wpa_strict_rekey = atoi(pos);
+ bss->wpa_strict_rekey = atoi(pos);
} else if (strcmp(buf, "wpa_gmk_rekey") == 0) {
- conf->wpa_gmk_rekey = atoi(pos);
+ bss->wpa_gmk_rekey = atoi(pos);
} else if (strcmp(buf, "wpa_passphrase") == 0) {
int len = strlen(pos);
if (len < 8 || len > 63) {
@@ -957,106 +1476,253 @@ struct hostapd_config * hostapd_config_read(const char *fname)
" %d (expected 8..63)\n", line, len);
errors++;
} else {
- free(conf->wpa_passphrase);
- conf->wpa_passphrase = strdup(pos);
+ free(bss->ssid.wpa_passphrase);
+ bss->ssid.wpa_passphrase = strdup(pos);
}
} else if (strcmp(buf, "wpa_psk") == 0) {
- free(conf->wpa_psk);
- conf->wpa_psk = malloc(sizeof(struct hostapd_wpa_psk));
- if (conf->wpa_psk) {
- memset(conf->wpa_psk, 0,
- sizeof(struct hostapd_wpa_psk));
- }
- if (conf->wpa_psk == NULL)
+ free(bss->ssid.wpa_psk);
+ bss->ssid.wpa_psk =
+ wpa_zalloc(sizeof(struct hostapd_wpa_psk));
+ if (bss->ssid.wpa_psk == NULL)
errors++;
- else if (hexstr2bin(pos, conf->wpa_psk->psk, PMK_LEN)
- || pos[PMK_LEN * 2] != '\0') {
+ else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk,
+ PMK_LEN) ||
+ pos[PMK_LEN * 2] != '\0') {
printf("Line %d: Invalid PSK '%s'.\n", line,
pos);
errors++;
} else {
- conf->wpa_psk->group = 1;
+ bss->ssid.wpa_psk->group = 1;
}
} else if (strcmp(buf, "wpa_psk_file") == 0) {
- free(conf->wpa_psk_file);
- conf->wpa_psk_file = strdup(pos);
- if (!conf->wpa_psk_file) {
+ free(bss->ssid.wpa_psk_file);
+ bss->ssid.wpa_psk_file = strdup(pos);
+ if (!bss->ssid.wpa_psk_file) {
printf("Line %d: allocation failed\n", line);
errors++;
}
} else if (strcmp(buf, "wpa_key_mgmt") == 0) {
- conf->wpa_key_mgmt =
+ bss->wpa_key_mgmt =
hostapd_config_parse_key_mgmt(line, pos);
- if (conf->wpa_key_mgmt == -1)
+ if (bss->wpa_key_mgmt == -1)
errors++;
} else if (strcmp(buf, "wpa_pairwise") == 0) {
- conf->wpa_pairwise =
+ bss->wpa_pairwise =
hostapd_config_parse_cipher(line, pos);
- if (conf->wpa_pairwise == -1 ||
- conf->wpa_pairwise == 0)
+ if (bss->wpa_pairwise == -1 ||
+ bss->wpa_pairwise == 0)
errors++;
- else if (conf->wpa_pairwise &
+ else if (bss->wpa_pairwise &
(WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
WPA_CIPHER_WEP104)) {
printf("Line %d: unsupported pairwise "
"cipher suite '%s'\n",
- conf->wpa_pairwise, pos);
+ bss->wpa_pairwise, pos);
errors++;
} else {
- if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
- conf->wpa_group = WPA_CIPHER_TKIP;
+ if (bss->wpa_pairwise & WPA_CIPHER_TKIP)
+ bss->wpa_group = WPA_CIPHER_TKIP;
else
- conf->wpa_group = WPA_CIPHER_CCMP;
+ bss->wpa_group = WPA_CIPHER_CCMP;
}
#ifdef CONFIG_RSN_PREAUTH
} else if (strcmp(buf, "rsn_preauth") == 0) {
- conf->rsn_preauth = atoi(pos);
+ bss->rsn_preauth = atoi(pos);
} else if (strcmp(buf, "rsn_preauth_interfaces") == 0) {
- conf->rsn_preauth_interfaces = strdup(pos);
+ bss->rsn_preauth_interfaces = strdup(pos);
#endif /* CONFIG_RSN_PREAUTH */
+#ifdef CONFIG_PEERKEY
+ } else if (strcmp(buf, "peerkey") == 0) {
+ bss->peerkey = atoi(pos);
+#endif /* CONFIG_PEERKEY */
} else if (strcmp(buf, "ctrl_interface") == 0) {
- free(conf->ctrl_interface);
- conf->ctrl_interface = strdup(pos);
+ free(bss->ctrl_interface);
+ bss->ctrl_interface = strdup(pos);
} else if (strcmp(buf, "ctrl_interface_group") == 0) {
+#ifndef CONFIG_NATIVE_WINDOWS
struct group *grp;
char *endp;
const char *group = pos;
grp = getgrnam(group);
if (grp) {
- conf->ctrl_interface_gid = grp->gr_gid;
- conf->ctrl_interface_gid_set = 1;
+ bss->ctrl_interface_gid = grp->gr_gid;
+ bss->ctrl_interface_gid_set = 1;
wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
" (from group name '%s')",
- conf->ctrl_interface_gid, group);
+ bss->ctrl_interface_gid, group);
continue;
}
/* Group name not found - try to parse this as gid */
- conf->ctrl_interface_gid = strtol(group, &endp, 10);
+ bss->ctrl_interface_gid = strtol(group, &endp, 10);
if (*group == '\0' || *endp != '\0') {
wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
"'%s'", line, group);
errors++;
continue;
}
- conf->ctrl_interface_gid_set = 1;
+ bss->ctrl_interface_gid_set = 1;
wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
- conf->ctrl_interface_gid);
+ bss->ctrl_interface_gid);
+#endif /* CONFIG_NATIVE_WINDOWS */
#ifdef RADIUS_SERVER
} else if (strcmp(buf, "radius_server_clients") == 0) {
- free(conf->radius_server_clients);
- conf->radius_server_clients = strdup(pos);
+ free(bss->radius_server_clients);
+ bss->radius_server_clients = strdup(pos);
} else if (strcmp(buf, "radius_server_auth_port") == 0) {
- conf->radius_server_auth_port = atoi(pos);
+ bss->radius_server_auth_port = atoi(pos);
} else if (strcmp(buf, "radius_server_ipv6") == 0) {
- conf->radius_server_ipv6 = atoi(pos);
+ bss->radius_server_ipv6 = atoi(pos);
#endif /* RADIUS_SERVER */
} else if (strcmp(buf, "test_socket") == 0) {
- free(conf->test_socket);
- conf->test_socket = strdup(pos);
+ free(bss->test_socket);
+ bss->test_socket = strdup(pos);
} else if (strcmp(buf, "use_pae_group_addr") == 0) {
- conf->use_pae_group_addr = atoi(pos);
+ bss->use_pae_group_addr = atoi(pos);
+ } else if (strcmp(buf, "hw_mode") == 0) {
+ if (strcmp(pos, "a") == 0)
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
+ else if (strcmp(pos, "b") == 0)
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
+ else if (strcmp(pos, "g") == 0)
+ conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
+ else {
+ printf("Line %d: unknown hw_mode '%s'\n",
+ line, pos);
+ errors++;
+ }
+ } else if (strcmp(buf, "channel") == 0) {
+ conf->channel = atoi(pos);
+ } else if (strcmp(buf, "beacon_int") == 0) {
+ int val = atoi(pos);
+ /* MIB defines range as 1..65535, but very small values
+ * cause problems with the current implementation.
+ * Since it is unlikely that this small numbers are
+ * useful in real life scenarios, do not allow beacon
+ * period to be set below 15 TU. */
+ if (val < 15 || val > 65535) {
+ printf("Line %d: invalid beacon_int %d "
+ "(expected 15..65535)\n",
+ line, val);
+ errors++;
+ } else
+ conf->beacon_int = val;
+ } else if (strcmp(buf, "dtim_period") == 0) {
+ bss->dtim_period = atoi(pos);
+ if (bss->dtim_period < 1 || bss->dtim_period > 255) {
+ printf("Line %d: invalid dtim_period %d\n",
+ line, bss->dtim_period);
+ errors++;
+ }
+ } else if (strcmp(buf, "rts_threshold") == 0) {
+ conf->rts_threshold = atoi(pos);
+ if (conf->rts_threshold < 0 ||
+ conf->rts_threshold > 2347) {
+ printf("Line %d: invalid rts_threshold %d\n",
+ line, conf->rts_threshold);
+ errors++;
+ }
+ } else if (strcmp(buf, "fragm_threshold") == 0) {
+ conf->fragm_threshold = atoi(pos);
+ if (conf->fragm_threshold < 256 ||
+ conf->fragm_threshold > 2346) {
+ printf("Line %d: invalid fragm_threshold %d\n",
+ line, conf->fragm_threshold);
+ errors++;
+ }
+ } else if (strcmp(buf, "send_probe_response") == 0) {
+ int val = atoi(pos);
+ if (val != 0 && val != 1) {
+ printf("Line %d: invalid send_probe_response "
+ "%d (expected 0 or 1)\n", line, val);
+ } else
+ conf->send_probe_response = val;
+ } else if (strcmp(buf, "supported_rates") == 0) {
+ if (hostapd_parse_rates(&conf->supported_rates, pos)) {
+ printf("Line %d: invalid rate list\n", line);
+ errors++;
+ }
+ } else if (strcmp(buf, "basic_rates") == 0) {
+ if (hostapd_parse_rates(&conf->basic_rates, pos)) {
+ printf("Line %d: invalid rate list\n", line);
+ errors++;
+ }
+ } else if (strcmp(buf, "ignore_broadcast_ssid") == 0) {
+ bss->ignore_broadcast_ssid = atoi(pos);
+ } else if (strcmp(buf, "bridge_packets") == 0) {
+ conf->bridge_packets = atoi(pos);
+ } else if (strcmp(buf, "wep_default_key") == 0) {
+ bss->ssid.wep.idx = atoi(pos);
+ if (bss->ssid.wep.idx > 3) {
+ printf("Invalid wep_default_key index %d\n",
+ bss->ssid.wep.idx);
+ errors++;
+ }
+ } else if (strcmp(buf, "wep_key0") == 0 ||
+ strcmp(buf, "wep_key1") == 0 ||
+ strcmp(buf, "wep_key2") == 0 ||
+ strcmp(buf, "wep_key3") == 0) {
+ if (hostapd_config_read_wep(&bss->ssid.wep,
+ buf[7] - '0', pos)) {
+ printf("Line %d: invalid WEP key '%s'\n",
+ line, buf);
+ errors++;
+ }
+ } else if (strcmp(buf, "dynamic_vlan") == 0) {
+ bss->ssid.dynamic_vlan = atoi(pos);
+ } else if (strcmp(buf, "vlan_file") == 0) {
+ if (hostapd_config_read_vlan_file(bss, pos)) {
+ printf("Line %d: failed to read VLAN file "
+ "'%s'\n", line, pos);
+ errors++;
+ }
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+ } else if (strcmp(buf, "vlan_tagged_interface") == 0) {
+ bss->ssid.vlan_tagged_interface = strdup(pos);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+ } else if (strcmp(buf, "passive_scan_interval") == 0) {
+ conf->passive_scan_interval = atoi(pos);
+ } else if (strcmp(buf, "passive_scan_listen") == 0) {
+ conf->passive_scan_listen = atoi(pos);
+ } else if (strcmp(buf, "passive_scan_mode") == 0) {
+ conf->passive_scan_mode = atoi(pos);
+ } else if (strcmp(buf, "ap_table_max_size") == 0) {
+ conf->ap_table_max_size = atoi(pos);
+ } else if (strcmp(buf, "ap_table_expiration_time") == 0) {
+ conf->ap_table_expiration_time = atoi(pos);
+ } else if (strncmp(buf, "tx_queue_", 9) == 0) {
+ if (hostapd_config_tx_queue(conf, buf, pos)) {
+ printf("Line %d: invalid TX queue item\n",
+ line);
+ errors++;
+ }
+ } else if (strcmp(buf, "wme_enabled") == 0) {
+ bss->wme_enabled = atoi(pos);
+ } else if (strncmp(buf, "wme_ac_", 7) == 0) {
+ if (hostapd_config_wme_ac(conf, buf, pos)) {
+ printf("Line %d: invalid wme ac item\n",
+ line);
+ errors++;
+ }
+ } else if (strcmp(buf, "bss") == 0) {
+ if (hostapd_config_bss(conf, pos)) {
+ printf("Line %d: invalid bss item\n", line);
+ errors++;
+ }
+ } else if (strcmp(buf, "bssid") == 0) {
+ if (bss == conf->bss) {
+ printf("Line %d: bssid item not allowed "
+ "for the default interface\n", line);
+ errors++;
+ } else if (hwaddr_aton(pos, bss->bssid)) {
+ printf("Line %d: invalid bssid item\n", line);
+ errors++;
+ }
+#ifdef CONFIG_IEEE80211W
+ } else if (strcmp(buf, "ieee80211w") == 0) {
+ bss->ieee80211w = atoi(pos);
+#endif /* CONFIG_IEEE80211W */
} else {
printf("Line %d: unknown configuration item '%s'\n",
line, buf);
@@ -1066,23 +1732,30 @@ struct hostapd_config * hostapd_config_read(const char *fname)
fclose(f);
- if (hostapd_config_read_maclist(accept_mac_file, &conf->accept_mac,
- &conf->num_accept_mac))
- errors++;
- free(accept_mac_file);
- if (hostapd_config_read_maclist(deny_mac_file, &conf->deny_mac,
- &conf->num_deny_mac))
- errors++;
- free(deny_mac_file);
-
-#ifdef EAP_SERVER
- if (hostapd_config_read_eap_user(eap_user_file, conf))
- errors++;
- free(eap_user_file);
-#endif /* EAP_SERVER */
+ 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;
+ }
- conf->radius->auth_server = conf->radius->auth_servers;
- conf->radius->acct_server = conf->radius->acct_servers;
+ for (i = 0; i < conf->num_bss; i++) {
+ bss = &conf->bss[i];
+
+ bss->radius->auth_server = bss->radius->auth_servers;
+ bss->radius->acct_server = bss->radius->acct_servers;
+
+ if (bss->wpa && bss->ieee802_1x) {
+ bss->ssid.security_policy = SECURITY_WPA;
+ } else if (bss->wpa) {
+ bss->ssid.security_policy = SECURITY_WPA_PSK;
+ } else if (bss->ieee802_1x) {
+ bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+ bss->ssid.wep.default_len = bss->default_wep_key_len;
+ } else if (bss->ssid.wep.keys_set)
+ bss->ssid.security_policy = SECURITY_STATIC_WEP;
+ else
+ bss->ssid.security_policy = SECURITY_PLAINTEXT;
+ }
if (hostapd_config_check(conf))
errors++;
@@ -1098,6 +1771,20 @@ struct hostapd_config * hostapd_config_read(const char *fname)
}
+int hostapd_wep_key_cmp(struct hostapd_wep_keys *a, struct hostapd_wep_keys *b)
+{
+ int i;
+
+ if (a->idx != b->idx || a->default_len != b->default_len)
+ return 1;
+ for (i = 0; i < NUM_WEP_KEYS; i++)
+ if (a->len[i] != b->len[i] ||
+ memcmp(a->key[i], b->key[i], a->len[i]) != 0)
+ return 1;
+ return 0;
+}
+
+
static void hostapd_config_free_radius(struct hostapd_radius_server *servers,
int num_servers)
{
@@ -1118,7 +1805,17 @@ static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
}
-void hostapd_config_free(struct hostapd_config *conf)
+static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
+{
+ int i;
+ for (i = 0; i < NUM_WEP_KEYS; i++) {
+ free(keys->key[i]);
+ keys->key[i] = NULL;
+ }
+}
+
+
+static void hostapd_config_free_bss(struct hostapd_bss_config *conf)
{
struct hostapd_wpa_psk *psk, *prev;
struct hostapd_eap_user *user, *prev_user;
@@ -1126,15 +1823,18 @@ void hostapd_config_free(struct hostapd_config *conf)
if (conf == NULL)
return;
- psk = conf->wpa_psk;
+ psk = conf->ssid.wpa_psk;
while (psk) {
prev = psk;
psk = psk->next;
free(prev);
}
- free(conf->wpa_passphrase);
- free(conf->wpa_psk_file);
+ free(conf->ssid.wpa_passphrase);
+ free(conf->ssid.wpa_psk_file);
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+ free(conf->ssid.vlan_tagged_interface);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
user = conf->eap_user;
while (user) {
@@ -1161,13 +1861,41 @@ void hostapd_config_free(struct hostapd_config *conf)
free(conf->eap_sim_db);
free(conf->radius_server_clients);
free(conf->test_socket);
+ free(conf->radius);
+ hostapd_config_free_vlan(conf);
+ if (conf->ssid.dyn_vlan_keys) {
+ struct hostapd_ssid *ssid = &conf->ssid;
+ size_t i;
+ for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
+ if (ssid->dyn_vlan_keys[i] == NULL)
+ continue;
+ hostapd_config_free_wep(ssid->dyn_vlan_keys[i]);
+ free(ssid->dyn_vlan_keys[i]);
+ }
+ free(ssid->dyn_vlan_keys);
+ ssid->dyn_vlan_keys = NULL;
+ }
+}
+
+
+void hostapd_config_free(struct hostapd_config *conf)
+{
+ size_t i;
+
+ if (conf == NULL)
+ return;
+
+ for (i = 0; i < conf->num_bss; i++)
+ hostapd_config_free_bss(&conf->bss[i]);
+ free(conf->bss);
+
free(conf);
}
/* Perform a binary search for given MAC address from a pre-sorted list.
* Returns 1 if address is in the list or 0 if not. */
-int hostapd_maclist_found(macaddr *list, int num_entries, u8 *addr)
+int hostapd_maclist_found(macaddr *list, int num_entries, const u8 *addr)
{
int start, end, middle, res;
@@ -1189,13 +1917,40 @@ int hostapd_maclist_found(macaddr *list, int num_entries, u8 *addr)
}
-const u8 * hostapd_get_psk(const struct hostapd_config *conf, const u8 *addr,
- const u8 *prev_psk)
+int hostapd_rate_found(int *list, int rate)
+{
+ int i;
+
+ if (list == NULL)
+ return 0;
+
+ for (i = 0; list[i] >= 0; i++)
+ if (list[i] == rate)
+ return 1;
+
+ return 0;
+}
+
+
+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan, int vlan_id)
+{
+ struct hostapd_vlan *v = vlan;
+ while (v) {
+ if (v->vlan_id == vlan_id || v->vlan_id == VLAN_ID_WILDCARD)
+ return v->ifname;
+ v = v->next;
+ }
+ return NULL;
+}
+
+
+const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
+ const u8 *addr, const u8 *prev_psk)
{
struct hostapd_wpa_psk *psk;
int next_ok = prev_psk == NULL;
- for (psk = conf->wpa_psk; psk != NULL; psk = psk->next) {
+ for (psk = conf->ssid.wpa_psk; psk != NULL; psk = psk->next) {
if (next_ok &&
(psk->group || memcmp(psk->addr, addr, ETH_ALEN) == 0))
return psk->psk;
@@ -1209,7 +1964,7 @@ const u8 * hostapd_get_psk(const struct hostapd_config *conf, const u8 *addr,
const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_config *conf, const u8 *identity,
+hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
size_t identity_len, int phase2)
{
struct hostapd_eap_user *user = conf->eap_user;
@@ -1219,6 +1974,15 @@ hostapd_get_eap_user(const struct hostapd_config *conf, const u8 *identity,
/* Wildcard match */
break;
}
+
+ if (!phase2 && user->wildcard_prefix &&
+ identity_len >= user->identity_len &&
+ memcmp(user->identity, identity, user->identity_len) == 0)
+ {
+ /* Wildcard prefix match */
+ break;
+ }
+
if (user->phase2 == !!phase2 &&
user->identity_len == identity_len &&
memcmp(user->identity, identity, identity_len) == 0)
diff --git a/contrib/hostapd/config.h b/contrib/hostapd/config.h
index 8754a84884aa..fafe8e041106 100644
--- a/contrib/hostapd/config.h
+++ b/contrib/hostapd/config.h
@@ -1,3 +1,17 @@
+/*
+ * hostapd / Configuration file
+ * 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.
+ */
+
#ifndef CONFIG_H
#define CONFIG_H
@@ -7,6 +21,68 @@ typedef u8 macaddr[ETH_ALEN];
struct hostapd_radius_servers;
+#define HOSTAPD_MAX_SSID_LEN 32
+
+#define NUM_WEP_KEYS 4
+struct hostapd_wep_keys {
+ u8 idx;
+ u8 *key[NUM_WEP_KEYS];
+ size_t len[NUM_WEP_KEYS];
+ int keys_set;
+ size_t default_len; /* key length used for dynamic key generation */
+};
+
+typedef enum hostap_security_policy {
+ SECURITY_PLAINTEXT = 0,
+ SECURITY_STATIC_WEP = 1,
+ SECURITY_IEEE_802_1X = 2,
+ SECURITY_WPA_PSK = 3,
+ SECURITY_WPA = 4
+} secpolicy;
+
+struct hostapd_ssid {
+ char ssid[HOSTAPD_MAX_SSID_LEN + 1];
+ size_t ssid_len;
+ int ssid_set;
+
+ char vlan[IFNAMSIZ + 1];
+ secpolicy security_policy;
+
+ struct hostapd_wpa_psk *wpa_psk;
+ char *wpa_passphrase;
+ char *wpa_psk_file;
+
+ struct hostapd_wep_keys wep;
+
+#define DYNAMIC_VLAN_DISABLED 0
+#define DYNAMIC_VLAN_OPTIONAL 1
+#define DYNAMIC_VLAN_REQUIRED 2
+ int dynamic_vlan;
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+ char *vlan_tagged_interface;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+ struct hostapd_wep_keys **dyn_vlan_keys;
+ size_t max_dyn_vlan_keys;
+};
+
+
+#define VLAN_ID_WILDCARD -1
+
+struct hostapd_vlan {
+ struct hostapd_vlan *next;
+ int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
+ char ifname[IFNAMSIZ + 1];
+ int dynamic_vlan;
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+
+#define DVLAN_CLEAN_BR 0x1
+#define DVLAN_CLEAN_VLAN 0x2
+#define DVLAN_CLEAN_VLAN_PORT 0x4
+#define DVLAN_CLEAN_WLAN_PORT 0x8
+ int clean;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+};
+
#define PMK_LEN 32
struct hostapd_wpa_psk {
struct hostapd_wpa_psk *next;
@@ -20,19 +96,46 @@ struct hostapd_eap_user {
struct hostapd_eap_user *next;
u8 *identity;
size_t identity_len;
- u8 methods[EAP_USER_MAX_METHODS];
+ struct {
+ int vendor;
+ u32 method;
+ } methods[EAP_USER_MAX_METHODS];
u8 *password;
size_t password_len;
int phase2;
int force_version;
+ unsigned int wildcard_prefix:1;
+ unsigned int password_hash:1; /* whether password is hashed with
+ * nt_password_hash() */
};
-struct hostapd_config {
+
+#define NUM_TX_QUEUES 8
+
+struct hostapd_tx_queue_params {
+ int aifs;
+ int cwmin;
+ int cwmax;
+ int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
+ int configured;
+};
+
+struct hostapd_wme_ac_params {
+ int cwmin;
+ int cwmax;
+ int aifs;
+ int txopLimit; /* in units of 32us */
+ int admission_control_mandatory;
+};
+
+
+/**
+ * struct hostapd_bss_config - Per-BSS configuration
+ */
+struct hostapd_bss_config {
char iface[IFNAMSIZ + 1];
char bridge[IFNAMSIZ + 1];
- const struct driver_ops *driver;
-
enum {
HOSTAPD_LEVEL_DEBUG_VERBOSE = 0,
HOSTAPD_LEVEL_DEBUG = 1,
@@ -47,6 +150,7 @@ struct hostapd_config {
#define HOSTAPD_MODULE_WPA BIT(3)
#define HOSTAPD_MODULE_DRIVER BIT(4)
#define HOSTAPD_MODULE_IAPP BIT(5)
+#define HOSTAPD_MODULE_MLME BIT(6)
unsigned int logger_syslog; /* module bitfield */
unsigned int logger_stdout; /* module bitfield */
@@ -56,7 +160,12 @@ struct hostapd_config {
HOSTAPD_DEBUG_EXCESSIVE = 4 } debug; /* debug verbosity level */
char *dump_log_name; /* file name for state dump (SIGUSR1) */
+ int max_num_sta; /* maximum number of STAs in station table */
+
+ int dtim_period;
+
int ieee802_1x; /* use IEEE 802.1X */
+ int eapol_version;
int eap_server; /* Use internal EAP server instead of external
* RADIUS server */
struct hostapd_eap_user *eap_user;
@@ -65,19 +174,17 @@ struct hostapd_config {
char *nas_identifier;
struct hostapd_radius_servers *radius;
-#define HOSTAPD_SSID_LEN 32
- char ssid[HOSTAPD_SSID_LEN + 1];
- size_t ssid_len;
- int ssid_set;
+ struct hostapd_ssid ssid;
+
char *eap_req_id_text; /* optional displayable message sent with
* EAP Request-Identity */
size_t eap_req_id_text_len;
int eapol_key_index_workaround;
- int eapol_version;
size_t default_wep_key_len;
int individual_wep_key_len;
int wep_rekeying_period;
+ int broadcast_key_idx_min, broadcast_key_idx_max;
int eap_reauth_period;
int ieee802_11f; /* use IEEE 802.11f (IAPP) */
@@ -105,9 +212,6 @@ struct hostapd_config {
#define HOSTAPD_WPA_VERSION_WPA BIT(0)
#define HOSTAPD_WPA_VERSION_WPA2 BIT(1)
int wpa;
- struct hostapd_wpa_psk *wpa_psk;
- char *wpa_passphrase;
- char *wpa_psk_file;
#define WPA_KEY_MGMT_IEEE8021X BIT(0)
#define WPA_KEY_MGMT_PSK BIT(1)
int wpa_key_mgmt;
@@ -116,6 +220,14 @@ struct hostapd_config {
#define WPA_CIPHER_WEP104 BIT(2)
#define WPA_CIPHER_TKIP BIT(3)
#define WPA_CIPHER_CCMP BIT(4)
+#ifdef CONFIG_IEEE80211W
+#define WPA_CIPHER_AES_128_CMAC BIT(5)
+ enum {
+ NO_IEEE80211W = 0,
+ IEEE80211W_OPTIONAL = 1,
+ IEEE80211W_REQUIRED = 2
+ } ieee80211w;
+#endif /* CONFIG_IEEE80211W */
int wpa_pairwise;
int wpa_group;
int wpa_group_rekey;
@@ -123,6 +235,7 @@ struct hostapd_config {
int wpa_gmk_rekey;
int rsn_preauth;
char *rsn_preauth_interfaces;
+ int peerkey;
char *ctrl_interface; /* directory for UNIX domain sockets */
gid_t ctrl_interface_gid;
@@ -144,17 +257,106 @@ struct hostapd_config {
* address instead of individual address
* (for driver_wired.c).
*/
+
+ int ap_max_inactivity;
+ int ignore_broadcast_ssid;
+
+ int wme_enabled;
+
+ struct hostapd_vlan *vlan, *vlan_tail;
+
+ macaddr bssid;
+};
+
+
+typedef enum {
+ HOSTAPD_MODE_IEEE80211B,
+ HOSTAPD_MODE_IEEE80211G,
+ HOSTAPD_MODE_IEEE80211A,
+ NUM_HOSTAPD_MODES
+} hostapd_hw_mode;
+
+
+/**
+ * struct hostapd_config - Per-radio interface configuration
+ */
+struct hostapd_config {
+ struct hostapd_bss_config *bss, *last_bss;
+ struct hostapd_radius_servers *radius;
+ size_t num_bss;
+
+ u16 beacon_int;
+ int rts_threshold;
+ int fragm_threshold;
+ u8 send_probe_response;
+ u8 channel;
+ hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
+ enum {
+ LONG_PREAMBLE = 0,
+ SHORT_PREAMBLE = 1
+ } preamble;
+ enum {
+ CTS_PROTECTION_AUTOMATIC = 0,
+ CTS_PROTECTION_FORCE_ENABLED = 1,
+ CTS_PROTECTION_FORCE_DISABLED = 2,
+ CTS_PROTECTION_AUTOMATIC_NO_OLBC = 3,
+ } cts_protection_type;
+
+ int *supported_rates;
+ int *basic_rates;
+
+ const struct driver_ops *driver;
+
+ int passive_scan_interval; /* seconds, 0 = disabled */
+ int passive_scan_listen; /* usec */
+ int passive_scan_mode;
+ int ap_table_max_size;
+ int ap_table_expiration_time;
+
+ char country[3]; /* first two octets: country code as described in
+ * ISO/IEC 3166-1. Third octet:
+ * ' ' (ascii 32): all environments
+ * 'O': Outdoor environemnt only
+ * 'I': Indoor environment only
+ */
+
+ int ieee80211d;
+ unsigned int ieee80211h; /* Enable/Disable 80211h */
+
+ struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
+
+ /*
+ * WME 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];
+
+ enum {
+ INTERNAL_BRIDGE_DO_NOT_CONTROL = -1,
+ INTERNAL_BRIDGE_DISABLED = 0,
+ INTERNAL_BRIDGE_ENABLED = 1
+ } bridge_packets;
};
+int hostapd_mac_comp(const void *a, const void *b);
+int hostapd_mac_comp_empty(const void *a);
struct hostapd_config * hostapd_config_read(const char *fname);
void hostapd_config_free(struct hostapd_config *conf);
-int hostapd_maclist_found(macaddr *list, int num_entries, u8 *addr);
-const u8 * hostapd_get_psk(const struct hostapd_config *conf, const u8 *addr,
- const u8 *prev_psk);
-int hostapd_setup_wpa_psk(struct hostapd_config *conf);
+int hostapd_maclist_found(macaddr *list, int num_entries, const u8 *addr);
+int hostapd_rate_found(int *list, int rate);
+int hostapd_wep_key_cmp(struct hostapd_wep_keys *a,
+ struct hostapd_wep_keys *b);
+const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
+ const u8 *addr, const u8 *prev_psk);
+int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
+ int vlan_id);
const struct hostapd_eap_user *
-hostapd_get_eap_user(const struct hostapd_config *conf, const u8 *identity,
+hostapd_get_eap_user(const struct hostapd_bss_config *conf, const u8 *identity,
size_t identity_len, int phase2);
#endif /* CONFIG_H */
diff --git a/contrib/hostapd/config_types.h b/contrib/hostapd/config_types.h
index 12b57cb4acf1..ffcffa3c0cd4 100644
--- a/contrib/hostapd/config_types.h
+++ b/contrib/hostapd/config_types.h
@@ -1,3 +1,17 @@
+/*
+ * hostapd / Shared configuration file defines
+ * 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 CONFIG_TYPES_H
#define CONFIG_TYPES_H
diff --git a/contrib/hostapd/crypto.c b/contrib/hostapd/crypto.c
index b4c81892c66e..c5edd24c4b55 100644
--- a/contrib/hostapd/crypto.c
+++ b/contrib/hostapd/crypto.c
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / wrapper functions for libcrypto
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * 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
@@ -12,9 +12,8 @@
* See README and COPYING for more details.
*/
-#include <string.h>
-#include <sys/types.h>
-
+#include "includes.h"
+#include <openssl/opensslv.h>
#include <openssl/md4.h>
#include <openssl/md5.h>
#include <openssl/sha.h>
@@ -36,7 +35,7 @@
void md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
MD4_CTX ctx;
- int i;
+ size_t i;
MD4_Init(&ctx);
for (i = 0; i < num_elem; i++)
@@ -70,7 +69,7 @@ void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
MD5_CTX ctx;
- int i;
+ size_t i;
MD5_Init(&ctx);
for (i = 0; i < num_elem; i++)
@@ -82,7 +81,7 @@ void md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
{
SHA_CTX ctx;
- int i;
+ size_t i;
SHA1_Init(&ctx);
for (i = 0; i < num_elem; i++)
@@ -91,24 +90,78 @@ void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
}
-void sha1_transform(u8 *state, const u8 data[64])
+static void sha1_transform(u8 *state, const u8 data[64])
{
SHA_CTX context;
- memset(&context, 0, sizeof(context));
- memcpy(&context.h0, state, 5 * 4);
+ os_memset(&context, 0, sizeof(context));
+ os_memcpy(&context.h0, state, 5 * 4);
SHA1_Transform(&context, data);
- memcpy(state, &context.h0, 5 * 4);
+ os_memcpy(state, &context.h0, 5 * 4);
+}
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+ u8 xkey[64];
+ u32 t[5], _t[5];
+ int i, j, m, k;
+ u8 *xpos = x;
+ u32 carry;
+
+ if (seed_len > sizeof(xkey))
+ seed_len = sizeof(xkey);
+
+ /* FIPS 186-2 + change notice 1 */
+
+ os_memcpy(xkey, seed, seed_len);
+ os_memset(xkey + seed_len, 0, 64 - seed_len);
+ t[0] = 0x67452301;
+ t[1] = 0xEFCDAB89;
+ t[2] = 0x98BADCFE;
+ t[3] = 0x10325476;
+ t[4] = 0xC3D2E1F0;
+
+ m = xlen / 40;
+ for (j = 0; j < m; j++) {
+ /* XSEED_j = 0 */
+ for (i = 0; i < 2; i++) {
+ /* XVAL = (XKEY + XSEED_j) mod 2^b */
+
+ /* w_i = G(t, XVAL) */
+ os_memcpy(_t, t, 20);
+ sha1_transform((u8 *) _t, xkey);
+ _t[0] = host_to_be32(_t[0]);
+ _t[1] = host_to_be32(_t[1]);
+ _t[2] = host_to_be32(_t[2]);
+ _t[3] = host_to_be32(_t[3]);
+ _t[4] = host_to_be32(_t[4]);
+ os_memcpy(xpos, _t, 20);
+
+ /* XKEY = (1 + XKEY + w_i) mod 2^b */
+ carry = 1;
+ for (k = 19; k >= 0; k--) {
+ carry += xkey[k] + xpos[k];
+ xkey[k] = carry & 0xff;
+ carry >>= 8;
+ }
+
+ xpos += 20;
+ }
+ /* x_j = w_0|w_1 */
+ }
+
+ return 0;
}
void * aes_encrypt_init(const u8 *key, size_t len)
{
AES_KEY *ak;
- ak = malloc(sizeof(*ak));
+ ak = os_malloc(sizeof(*ak));
if (ak == NULL)
return NULL;
if (AES_set_encrypt_key(key, 8 * len, ak) < 0) {
- free(ak);
+ os_free(ak);
return NULL;
}
return ak;
@@ -123,18 +176,18 @@ void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
void aes_encrypt_deinit(void *ctx)
{
- free(ctx);
+ os_free(ctx);
}
void * aes_decrypt_init(const u8 *key, size_t len)
{
AES_KEY *ak;
- ak = malloc(sizeof(*ak));
+ ak = os_malloc(sizeof(*ak));
if (ak == NULL)
return NULL;
if (AES_set_decrypt_key(key, 8 * len, ak) < 0) {
- free(ak);
+ os_free(ak);
return NULL;
}
return ak;
@@ -149,6 +202,6 @@ void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
void aes_decrypt_deinit(void *ctx)
{
- free(ctx);
+ os_free(ctx);
}
#endif /* EAP_TLS_FUNCS */
diff --git a/contrib/hostapd/crypto.h b/contrib/hostapd/crypto.h
index e664861afe71..00b13b91c48e 100644
--- a/contrib/hostapd/crypto.h
+++ b/contrib/hostapd/crypto.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant / wrapper functions for crypto libraries
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * 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
@@ -56,16 +56,28 @@ void sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
u8 *mac);
/**
- * sha1_transform - Perform one SHA-1 transform step
- * @state: SHA-1 state
- * @data: Input data for the SHA-1 transform
+ * fips186_2-prf - NIST FIPS Publication 186-2 change notice 1 PRF
+ * @seed: Seed/key for the PRF
+ * @seed_len: Seed length in bytes
+ * @x: Buffer for PRF output
+ * @xlen: Output length in bytes
+ * Returns: 0 on success, -1 on failure
*
- * This function is used to implement random number generation specified in
- * NIST FIPS Publication 186-2 for EAP-SIM. This PRF uses a function that is
- * similar to SHA-1, but has different message padding and as such, access to
- * just part of the SHA-1 is needed.
+ * This function implements random number generation specified in NIST FIPS
+ * Publication 186-2 for EAP-SIM. This PRF uses a function that is similar to
+ * SHA-1, but has different message padding.
*/
-void sha1_transform(u8 *state, const u8 data[64]);
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen);
+
+/**
+ * sha256_vector - SHA256 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ */
+void sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+ u8 *mac);
/**
* des_encrypt - Encrypt one block with DES
@@ -120,4 +132,282 @@ void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
void aes_decrypt_deinit(void *ctx);
+enum crypto_hash_alg {
+ CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,
+ CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1
+};
+
+struct crypto_hash;
+
+/**
+ * crypto_hash_init - Initialize hash/HMAC function
+ * @alg: Hash algorithm
+ * @key: Key for keyed hash (e.g., HMAC) or %NULL if not needed
+ * @key_len: Length of the key in bytes
+ * Returns: Pointer to hash context to use with other hash functions or %NULL
+ * on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+ size_t key_len);
+
+/**
+ * crypto_hash_update - Add data to hash calculation
+ * @ctx: Context pointer from crypto_hash_init()
+ * @data: Data buffer to add
+ * @len: Length of the buffer
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len);
+
+/**
+ * crypto_hash_finish - Complete hash calculation
+ * @ctx: Context pointer from crypto_hash_init()
+ * @hash: Buffer for hash value or %NULL if caller is just freeing the hash
+ * context
+ * @len: Pointer to length of the buffer or %NULL if caller is just freeing the
+ * hash context; on return, this is set to the actual length of the hash value
+ * Returns: 0 on success, -1 if buffer is too small (len set to needed length),
+ * or -2 on other failures (including failed crypto_hash_update() operations)
+ *
+ * This function calculates the hash value and frees the context buffer that
+ * was used for hash calculation.
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *hash, size_t *len);
+
+
+enum crypto_cipher_alg {
+ CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES,
+ CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4
+};
+
+struct crypto_cipher;
+
+/**
+ * crypto_cipher_init - Initialize block/stream cipher function
+ * @alg: Cipher algorithm
+ * @iv: Initialization vector for block ciphers or %NULL for stream ciphers
+ * @key: Cipher key
+ * @key_len: Length of key in bytes
+ * Returns: Pointer to cipher context to use with other cipher functions or
+ * %NULL on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+ const u8 *iv, const u8 *key,
+ size_t key_len);
+
+/**
+ * crypto_cipher_encrypt - Cipher encrypt
+ * @ctx: Context pointer from crypto_cipher_init()
+ * @plain: Plaintext to cipher
+ * @crypt: Resulting ciphertext
+ * @len: Length of the plaintext
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+ u8 *crypt, size_t len);
+
+/**
+ * crypto_cipher_decrypt - Cipher decrypt
+ * @ctx: Context pointer from crypto_cipher_init()
+ * @crypt: Ciphertext to decrypt
+ * @plain: Resulting plaintext
+ * @len: Length of the cipher text
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+ u8 *plain, size_t len);
+
+/**
+ * crypto_cipher_decrypt - Free cipher context
+ * @ctx: Context pointer from crypto_cipher_init()
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_cipher_deinit(struct crypto_cipher *ctx);
+
+
+struct crypto_public_key;
+struct crypto_private_key;
+
+/**
+ * crypto_public_key_import - Import an RSA public key
+ * @key: Key buffer (DER encoded RSA public key)
+ * @len: Key buffer length in bytes
+ * Returns: Pointer to the public key or %NULL on failure
+ *
+ * This function can just return %NULL if the crypto library supports X.509
+ * parsing. In that case, crypto_public_key_from_cert() is used to import the
+ * public key from a certificate.
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len);
+
+/**
+ * crypto_private_key_import - Import an RSA private key
+ * @key: Key buffer (DER encoded RSA private key)
+ * @len: Key buffer length in bytes
+ * Returns: Pointer to the private key or %NULL on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_private_key * crypto_private_key_import(const u8 *key,
+ size_t len);
+
+/**
+ * crypto_public_key_from_cert - Import an RSA public key from a certificate
+ * @buf: DER encoded X.509 certificate
+ * @len: Certificate buffer length in bytes
+ * Returns: Pointer to public key or %NULL on failure
+ *
+ * This function can just return %NULL if the crypto library does not support
+ * X.509 parsing. In that case, internal code will be used to parse the
+ * certificate and public key is imported using crypto_public_key_import().
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
+ size_t len);
+
+/**
+ * crypto_public_key_encrypt_pkcs1_v15 - Public key encryption (PKCS #1 v1.5)
+ * @key: Public key
+ * @in: Plaintext buffer
+ * @inlen: Length of plaintext buffer in bytes
+ * @out: Output buffer for encrypted data
+ * @outlen: Length of output buffer in bytes; set to used length on success
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen);
+
+/**
+ * crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1)
+ * @key: Private key from crypto_private_key_import()
+ * @in: Plaintext buffer
+ * @inlen: Length of plaintext buffer in bytes
+ * @out: Output buffer for encrypted (signed) data
+ * @outlen: Length of output buffer in bytes; set to used length on success
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
+ const u8 *in, size_t inlen,
+ u8 *out, size_t *outlen);
+
+/**
+ * crypto_public_key_free - Free public key
+ * @key: Public key
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_public_key_free(struct crypto_public_key *key);
+
+/**
+ * crypto_private_key_free - Free private key
+ * @key: Private key from crypto_private_key_import()
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_private_key_free(struct crypto_private_key *key);
+
+/**
+ * crypto_public_key_decrypt_pkcs1 - Decrypt PKCS #1 signature
+ * @key: Public key
+ * @crypt: Encrypted signature data (using the private key)
+ * @crypt_len: Encrypted signature data length
+ * @plain: Buffer for plaintext (at least crypt_len bytes)
+ * @plain_len: Plaintext length (max buffer size on input, real len on output);
+ * Returns: 0 on success, -1 on failure
+ */
+int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
+ const u8 *crypt, size_t crypt_len,
+ u8 *plain, size_t *plain_len);
+
+/**
+ * crypto_global_init - Initialize crypto wrapper
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_global_init(void);
+
+/**
+ * crypto_global_deinit - Deinitialize crypto wrapper
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_global_deinit(void);
+
+/**
+ * crypto_mod_exp - Modular exponentiation of large integers
+ * @base: Base integer (big endian byte array)
+ * @base_len: Length of base integer in bytes
+ * @power: Power integer (big endian byte array)
+ * @power_len: Length of power integer in bytes
+ * @modulus: Modulus integer (big endian byte array)
+ * @modulus_len: Length of modulus integer in bytes
+ * @result: Buffer for the result
+ * @result_len: Result length (max buffer size on input, real len on output)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function calculates result = base ^ power mod modulus. modules_len is
+ * used as the maximum size of modulus buffer. It is set to the used size on
+ * success.
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_mod_exp(const u8 *base, size_t base_len,
+ const u8 *power, size_t power_len,
+ const u8 *modulus, size_t modulus_len,
+ u8 *result, size_t *result_len);
+
#endif /* CRYPTO_H */
diff --git a/contrib/hostapd/ctrl_iface.c b/contrib/hostapd/ctrl_iface.c
index ff730d4a95d3..9863782ed148 100644
--- a/contrib/hostapd/ctrl_iface.c
+++ b/contrib/hostapd/ctrl_iface.c
@@ -1,7 +1,6 @@
/*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / UNIX domain socket -based control interface
- * Copyright (c) 2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * hostapd / UNIX domain socket -based control interface
+ * Copyright (c) 2004, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -13,17 +12,12 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/socket.h>
+#include "includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
#include <sys/un.h>
-#include <sys/uio.h>
#include <sys/stat.h>
-#include <errno.h>
-#include <netinet/in.h>
#include "hostapd.h"
#include "eloop.h"
@@ -35,6 +29,7 @@
#include "ieee802_11.h"
#include "ctrl_iface.h"
#include "sta_info.h"
+#include "accounting.h"
struct wpa_ctrl_dst {
@@ -52,10 +47,9 @@ static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
{
struct wpa_ctrl_dst *dst;
- dst = malloc(sizeof(*dst));
+ dst = wpa_zalloc(sizeof(*dst));
if (dst == NULL)
return -1;
- memset(dst, 0, sizeof(*dst));
memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
dst->addrlen = fromlen;
dst->debug_level = MSG_INFO;
@@ -122,20 +116,26 @@ static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
struct sta_info *sta,
char *buf, size_t buflen)
{
- int len, res;
+ int len, res, ret;
if (sta == NULL) {
- return snprintf(buf, buflen, "FAIL\n");
+ ret = snprintf(buf, buflen, "FAIL\n");
+ if (ret < 0 || (size_t) ret >= buflen)
+ return 0;
+ return ret;
}
len = 0;
- len += snprintf(buf + len, buflen - len, MACSTR "\n",
- MAC2STR(sta->addr));
+ ret = snprintf(buf + len, buflen - len, MACSTR "\n",
+ MAC2STR(sta->addr));
+ if (ret < 0 || (size_t) ret >= buflen - len)
+ return len;
+ len += ret;
res = ieee802_11_get_mib_sta(hapd, sta, buf + len, buflen - len);
if (res >= 0)
len += res;
- res = wpa_get_mib_sta(hapd, sta, buf + len, buflen - len);
+ res = wpa_get_mib_sta(sta->wpa_sm, buf + len, buflen - len);
if (res >= 0)
len += res;
res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
@@ -158,9 +158,14 @@ static int hostapd_ctrl_iface_sta(struct hostapd_data *hapd,
char *buf, size_t buflen)
{
u8 addr[ETH_ALEN];
+ int ret;
- if (hwaddr_aton(txtaddr, addr))
- return snprintf(buf, buflen, "FAIL\n");
+ if (hwaddr_aton(txtaddr, addr)) {
+ ret = snprintf(buf, buflen, "FAIL\n");
+ if (ret < 0 || (size_t) ret >= buflen)
+ return 0;
+ return ret;
+ }
return hostapd_ctrl_iface_sta_mib(hapd, ap_get_sta(hapd, addr),
buf, buflen);
}
@@ -172,14 +177,46 @@ static int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd,
{
u8 addr[ETH_ALEN];
struct sta_info *sta;
+ int ret;
if (hwaddr_aton(txtaddr, addr) ||
- (sta = ap_get_sta(hapd, addr)) == NULL)
- return snprintf(buf, buflen, "FAIL\n");
+ (sta = ap_get_sta(hapd, addr)) == NULL) {
+ ret = snprintf(buf, buflen, "FAIL\n");
+ if (ret < 0 || (size_t) ret >= buflen)
+ return 0;
+ return ret;
+ }
return hostapd_ctrl_iface_sta_mib(hapd, sta->next, buf, buflen);
}
+static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
+ const char *txtaddr)
+{
+ u8 addr[ETH_ALEN];
+ struct sta_info *sta;
+
+ wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
+
+ if (hwaddr_aton(txtaddr, addr))
+ return -1;
+
+ sta = ap_get_sta(hapd, addr);
+ if (sta)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
+ "notification", MAC2STR(addr));
+ sta = ap_sta_add(hapd, addr);
+ if (sta == NULL)
+ return -1;
+
+ hostapd_new_assoc_sta(hapd, sta, 0);
+ accounting_sta_get_id(hapd, sta);
+ return 0;
+}
+
+
static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
void *sock_ctx)
{
@@ -217,7 +254,7 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
} else if (strcmp(buf, "MIB") == 0) {
reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
if (reply_len >= 0) {
- res = wpa_get_mib(hapd, reply + reply_len,
+ res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
reply_size - reply_len);
if (res < 0)
reply_len = -1;
@@ -260,6 +297,9 @@ static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
buf + 6))
reply_len = -1;
+ } else if (strncmp(buf, "NEW_STA ", 8) == 0) {
+ if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
+ reply_len = -1;
} else {
memcpy(reply, "UNKNOWN COMMAND\n", 16);
reply_len = 16;
@@ -290,6 +330,7 @@ static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
snprintf(buf, len, "%s/%s",
hapd->conf->ctrl_interface, hapd->conf->iface);
+ buf[len - 1] = '\0';
return buf;
}
@@ -454,3 +495,5 @@ void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
dst = next;
}
}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/contrib/hostapd/ctrl_iface.h b/contrib/hostapd/ctrl_iface.h
index ef1a541c94c8..2ac2f3b29931 100644
--- a/contrib/hostapd/ctrl_iface.h
+++ b/contrib/hostapd/ctrl_iface.h
@@ -1,3 +1,17 @@
+/*
+ * hostapd / UNIX domain socket -based control interface
+ * Copyright (c) 2004, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
#ifndef CTRL_IFACE_H
#define CTRL_IFACE_H
diff --git a/contrib/hostapd/defconfig b/contrib/hostapd/defconfig
index e8f4e4fc53ec..8fe4bf9f5bfa 100644
--- a/contrib/hostapd/defconfig
+++ b/contrib/hostapd/defconfig
@@ -22,6 +22,15 @@ CONFIG_DRIVER_HOSTAP=y
# Driver interface for Prism54 driver
#CONFIG_DRIVER_PRISM54=y
+# Driver interface for drivers using Devicescape IEEE 802.11 stack
+#CONFIG_DRIVER_DEVICESCAPE=y
+# Currently, driver_devicescape.c build requires some additional parameters
+# to be able to include some of the kernel header files. Following lines can
+# be used to set these (WIRELESS_DEV must point to the root directory of the
+# wireless-dev.git tree).
+#WIRELESS_DEV=/usr/src/wireless-dev
+#CFLAGS += -I$(WIRELESS_DEV)/net/mac80211
+
# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
#CONFIG_DRIVER_BSD=y
#CFLAGS += -I/usr/local/include
@@ -33,6 +42,15 @@ CONFIG_IAPP=y
# WPA2/IEEE 802.11i RSN pre-authentication
CONFIG_RSN_PREAUTH=y
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
# Integrated EAP server
CONFIG_EAP=y
@@ -57,12 +75,23 @@ CONFIG_EAP_TTLS=y
# EAP-SIM for the integrated EAP server
#CONFIG_EAP_SIM=y
+# EAP-AKA for the integrated EAP server
+#CONFIG_EAP_AKA=y
+
# EAP-PAX for the integrated EAP server
#CONFIG_EAP_PAX=y
# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
#CONFIG_EAP_PSK=y
+# EAP-SAKE for the integrated EAP server
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK for the integrated EAP server
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
# PKCS#12 (PFX) support (used to read private key and certificate file from
# a file that usually has extension .p12 or .pfx)
CONFIG_PKCS12=y
diff --git a/contrib/hostapd/defs.h b/contrib/hostapd/defs.h
index 6f9881d71d03..603fc55c110a 100644
--- a/contrib/hostapd/defs.h
+++ b/contrib/hostapd/defs.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Common definitions
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * 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
@@ -24,7 +24,8 @@
typedef enum { FALSE = 0, TRUE = 1 } Boolean;
-typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP } wpa_alg;
+typedef enum { WPA_ALG_NONE, WPA_ALG_WEP, WPA_ALG_TKIP, WPA_ALG_CCMP,
+ WPA_ALG_IGTK, WPA_ALG_DHV } wpa_alg;
typedef enum { CIPHER_NONE, CIPHER_WEP40, CIPHER_TKIP, CIPHER_CCMP,
CIPHER_WEP104 } wpa_cipher;
typedef enum { KEY_MGMT_802_1X, KEY_MGMT_PSK, KEY_MGMT_NONE,
@@ -128,4 +129,12 @@ typedef enum {
WPA_COMPLETED
} wpa_states;
+#define MLME_SETPROTECTION_PROTECT_TYPE_NONE 0
+#define MLME_SETPROTECTION_PROTECT_TYPE_RX 1
+#define MLME_SETPROTECTION_PROTECT_TYPE_TX 2
+#define MLME_SETPROTECTION_PROTECT_TYPE_RX_TX 3
+
+#define MLME_SETPROTECTION_KEY_TYPE_GROUP 0
+#define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1
+
#endif /* DEFS_H */
diff --git a/contrib/hostapd/des.c b/contrib/hostapd/des.c
new file mode 100644
index 000000000000..8e0d56fc6af1
--- /dev/null
+++ b/contrib/hostapd/des.c
@@ -0,0 +1,476 @@
+/*
+ * DES and 3DES-EDE ciphers
+ *
+ * Modifications to LibTomCrypt implementation:
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+
+
+#ifdef INTERNAL_DES
+
+/*
+ * This implementation is based on a DES implementation included in
+ * LibTomCrypt. The version here is modified to fit in wpa_supplicant/hostapd
+ * coding style.
+ */
+
+/* LibTomCrypt, modular cryptographic library -- Tom St Denis
+ *
+ * LibTomCrypt is a library that provides various cryptographic
+ * algorithms in a highly modular and flexible manner.
+ *
+ * The library is free for all purposes without any express
+ * guarantee it works.
+ *
+ * Tom St Denis, tomstdenis@gmail.com, http://libtomcrypt.com
+ */
+
+/**
+ DES code submitted by Dobes Vandermeer
+*/
+
+#define ROLc(x, y) \
+ ((((unsigned long) (x) << (unsigned long) ((y) & 31)) | \
+ (((unsigned long) (x) & 0xFFFFFFFFUL) >> \
+ (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
+#define RORc(x, y) \
+ (((((unsigned long) (x) & 0xFFFFFFFFUL) >> \
+ (unsigned long) ((y) & 31)) | \
+ ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & \
+ 0xFFFFFFFFUL)
+
+
+static const u32 bytebit[8] =
+{
+ 0200, 0100, 040, 020, 010, 04, 02, 01
+};
+
+static const u32 bigbyte[24] =
+{
+ 0x800000UL, 0x400000UL, 0x200000UL, 0x100000UL,
+ 0x80000UL, 0x40000UL, 0x20000UL, 0x10000UL,
+ 0x8000UL, 0x4000UL, 0x2000UL, 0x1000UL,
+ 0x800UL, 0x400UL, 0x200UL, 0x100UL,
+ 0x80UL, 0x40UL, 0x20UL, 0x10UL,
+ 0x8UL, 0x4UL, 0x2UL, 0x1L
+};
+
+/* Use the key schedule specific in the standard (ANSI X3.92-1981) */
+
+static const u8 pc1[56] = {
+ 56, 48, 40, 32, 24, 16, 8, 0, 57, 49, 41, 33, 25, 17,
+ 9, 1, 58, 50, 42, 34, 26, 18, 10, 2, 59, 51, 43, 35,
+ 62, 54, 46, 38, 30, 22, 14, 6, 61, 53, 45, 37, 29, 21,
+ 13, 5, 60, 52, 44, 36, 28, 20, 12, 4, 27, 19, 11, 3
+};
+
+static const u8 totrot[16] = {
+ 1, 2, 4, 6,
+ 8, 10, 12, 14,
+ 15, 17, 19, 21,
+ 23, 25, 27, 28
+};
+
+static const u8 pc2[48] = {
+ 13, 16, 10, 23, 0, 4, 2, 27, 14, 5, 20, 9,
+ 22, 18, 11, 3, 25, 7, 15, 6, 26, 19, 12, 1,
+ 40, 51, 30, 36, 46, 54, 29, 39, 50, 44, 32, 47,
+ 43, 48, 38, 55, 33, 52, 45, 41, 49, 35, 28, 31
+};
+
+
+static const u32 SP1[64] =
+{
+ 0x01010400UL, 0x00000000UL, 0x00010000UL, 0x01010404UL,
+ 0x01010004UL, 0x00010404UL, 0x00000004UL, 0x00010000UL,
+ 0x00000400UL, 0x01010400UL, 0x01010404UL, 0x00000400UL,
+ 0x01000404UL, 0x01010004UL, 0x01000000UL, 0x00000004UL,
+ 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00010400UL,
+ 0x00010400UL, 0x01010000UL, 0x01010000UL, 0x01000404UL,
+ 0x00010004UL, 0x01000004UL, 0x01000004UL, 0x00010004UL,
+ 0x00000000UL, 0x00000404UL, 0x00010404UL, 0x01000000UL,
+ 0x00010000UL, 0x01010404UL, 0x00000004UL, 0x01010000UL,
+ 0x01010400UL, 0x01000000UL, 0x01000000UL, 0x00000400UL,
+ 0x01010004UL, 0x00010000UL, 0x00010400UL, 0x01000004UL,
+ 0x00000400UL, 0x00000004UL, 0x01000404UL, 0x00010404UL,
+ 0x01010404UL, 0x00010004UL, 0x01010000UL, 0x01000404UL,
+ 0x01000004UL, 0x00000404UL, 0x00010404UL, 0x01010400UL,
+ 0x00000404UL, 0x01000400UL, 0x01000400UL, 0x00000000UL,
+ 0x00010004UL, 0x00010400UL, 0x00000000UL, 0x01010004UL
+};
+
+static const u32 SP2[64] =
+{
+ 0x80108020UL, 0x80008000UL, 0x00008000UL, 0x00108020UL,
+ 0x00100000UL, 0x00000020UL, 0x80100020UL, 0x80008020UL,
+ 0x80000020UL, 0x80108020UL, 0x80108000UL, 0x80000000UL,
+ 0x80008000UL, 0x00100000UL, 0x00000020UL, 0x80100020UL,
+ 0x00108000UL, 0x00100020UL, 0x80008020UL, 0x00000000UL,
+ 0x80000000UL, 0x00008000UL, 0x00108020UL, 0x80100000UL,
+ 0x00100020UL, 0x80000020UL, 0x00000000UL, 0x00108000UL,
+ 0x00008020UL, 0x80108000UL, 0x80100000UL, 0x00008020UL,
+ 0x00000000UL, 0x00108020UL, 0x80100020UL, 0x00100000UL,
+ 0x80008020UL, 0x80100000UL, 0x80108000UL, 0x00008000UL,
+ 0x80100000UL, 0x80008000UL, 0x00000020UL, 0x80108020UL,
+ 0x00108020UL, 0x00000020UL, 0x00008000UL, 0x80000000UL,
+ 0x00008020UL, 0x80108000UL, 0x00100000UL, 0x80000020UL,
+ 0x00100020UL, 0x80008020UL, 0x80000020UL, 0x00100020UL,
+ 0x00108000UL, 0x00000000UL, 0x80008000UL, 0x00008020UL,
+ 0x80000000UL, 0x80100020UL, 0x80108020UL, 0x00108000UL
+};
+
+static const u32 SP3[64] =
+{
+ 0x00000208UL, 0x08020200UL, 0x00000000UL, 0x08020008UL,
+ 0x08000200UL, 0x00000000UL, 0x00020208UL, 0x08000200UL,
+ 0x00020008UL, 0x08000008UL, 0x08000008UL, 0x00020000UL,
+ 0x08020208UL, 0x00020008UL, 0x08020000UL, 0x00000208UL,
+ 0x08000000UL, 0x00000008UL, 0x08020200UL, 0x00000200UL,
+ 0x00020200UL, 0x08020000UL, 0x08020008UL, 0x00020208UL,
+ 0x08000208UL, 0x00020200UL, 0x00020000UL, 0x08000208UL,
+ 0x00000008UL, 0x08020208UL, 0x00000200UL, 0x08000000UL,
+ 0x08020200UL, 0x08000000UL, 0x00020008UL, 0x00000208UL,
+ 0x00020000UL, 0x08020200UL, 0x08000200UL, 0x00000000UL,
+ 0x00000200UL, 0x00020008UL, 0x08020208UL, 0x08000200UL,
+ 0x08000008UL, 0x00000200UL, 0x00000000UL, 0x08020008UL,
+ 0x08000208UL, 0x00020000UL, 0x08000000UL, 0x08020208UL,
+ 0x00000008UL, 0x00020208UL, 0x00020200UL, 0x08000008UL,
+ 0x08020000UL, 0x08000208UL, 0x00000208UL, 0x08020000UL,
+ 0x00020208UL, 0x00000008UL, 0x08020008UL, 0x00020200UL
+};
+
+static const u32 SP4[64] =
+{
+ 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
+ 0x00802080UL, 0x00800081UL, 0x00800001UL, 0x00002001UL,
+ 0x00000000UL, 0x00802000UL, 0x00802000UL, 0x00802081UL,
+ 0x00000081UL, 0x00000000UL, 0x00800080UL, 0x00800001UL,
+ 0x00000001UL, 0x00002000UL, 0x00800000UL, 0x00802001UL,
+ 0x00000080UL, 0x00800000UL, 0x00002001UL, 0x00002080UL,
+ 0x00800081UL, 0x00000001UL, 0x00002080UL, 0x00800080UL,
+ 0x00002000UL, 0x00802080UL, 0x00802081UL, 0x00000081UL,
+ 0x00800080UL, 0x00800001UL, 0x00802000UL, 0x00802081UL,
+ 0x00000081UL, 0x00000000UL, 0x00000000UL, 0x00802000UL,
+ 0x00002080UL, 0x00800080UL, 0x00800081UL, 0x00000001UL,
+ 0x00802001UL, 0x00002081UL, 0x00002081UL, 0x00000080UL,
+ 0x00802081UL, 0x00000081UL, 0x00000001UL, 0x00002000UL,
+ 0x00800001UL, 0x00002001UL, 0x00802080UL, 0x00800081UL,
+ 0x00002001UL, 0x00002080UL, 0x00800000UL, 0x00802001UL,
+ 0x00000080UL, 0x00800000UL, 0x00002000UL, 0x00802080UL
+};
+
+static const u32 SP5[64] =
+{
+ 0x00000100UL, 0x02080100UL, 0x02080000UL, 0x42000100UL,
+ 0x00080000UL, 0x00000100UL, 0x40000000UL, 0x02080000UL,
+ 0x40080100UL, 0x00080000UL, 0x02000100UL, 0x40080100UL,
+ 0x42000100UL, 0x42080000UL, 0x00080100UL, 0x40000000UL,
+ 0x02000000UL, 0x40080000UL, 0x40080000UL, 0x00000000UL,
+ 0x40000100UL, 0x42080100UL, 0x42080100UL, 0x02000100UL,
+ 0x42080000UL, 0x40000100UL, 0x00000000UL, 0x42000000UL,
+ 0x02080100UL, 0x02000000UL, 0x42000000UL, 0x00080100UL,
+ 0x00080000UL, 0x42000100UL, 0x00000100UL, 0x02000000UL,
+ 0x40000000UL, 0x02080000UL, 0x42000100UL, 0x40080100UL,
+ 0x02000100UL, 0x40000000UL, 0x42080000UL, 0x02080100UL,
+ 0x40080100UL, 0x00000100UL, 0x02000000UL, 0x42080000UL,
+ 0x42080100UL, 0x00080100UL, 0x42000000UL, 0x42080100UL,
+ 0x02080000UL, 0x00000000UL, 0x40080000UL, 0x42000000UL,
+ 0x00080100UL, 0x02000100UL, 0x40000100UL, 0x00080000UL,
+ 0x00000000UL, 0x40080000UL, 0x02080100UL, 0x40000100UL
+};
+
+static const u32 SP6[64] =
+{
+ 0x20000010UL, 0x20400000UL, 0x00004000UL, 0x20404010UL,
+ 0x20400000UL, 0x00000010UL, 0x20404010UL, 0x00400000UL,
+ 0x20004000UL, 0x00404010UL, 0x00400000UL, 0x20000010UL,
+ 0x00400010UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
+ 0x00000000UL, 0x00400010UL, 0x20004010UL, 0x00004000UL,
+ 0x00404000UL, 0x20004010UL, 0x00000010UL, 0x20400010UL,
+ 0x20400010UL, 0x00000000UL, 0x00404010UL, 0x20404000UL,
+ 0x00004010UL, 0x00404000UL, 0x20404000UL, 0x20000000UL,
+ 0x20004000UL, 0x00000010UL, 0x20400010UL, 0x00404000UL,
+ 0x20404010UL, 0x00400000UL, 0x00004010UL, 0x20000010UL,
+ 0x00400000UL, 0x20004000UL, 0x20000000UL, 0x00004010UL,
+ 0x20000010UL, 0x20404010UL, 0x00404000UL, 0x20400000UL,
+ 0x00404010UL, 0x20404000UL, 0x00000000UL, 0x20400010UL,
+ 0x00000010UL, 0x00004000UL, 0x20400000UL, 0x00404010UL,
+ 0x00004000UL, 0x00400010UL, 0x20004010UL, 0x00000000UL,
+ 0x20404000UL, 0x20000000UL, 0x00400010UL, 0x20004010UL
+};
+
+static const u32 SP7[64] =
+{
+ 0x00200000UL, 0x04200002UL, 0x04000802UL, 0x00000000UL,
+ 0x00000800UL, 0x04000802UL, 0x00200802UL, 0x04200800UL,
+ 0x04200802UL, 0x00200000UL, 0x00000000UL, 0x04000002UL,
+ 0x00000002UL, 0x04000000UL, 0x04200002UL, 0x00000802UL,
+ 0x04000800UL, 0x00200802UL, 0x00200002UL, 0x04000800UL,
+ 0x04000002UL, 0x04200000UL, 0x04200800UL, 0x00200002UL,
+ 0x04200000UL, 0x00000800UL, 0x00000802UL, 0x04200802UL,
+ 0x00200800UL, 0x00000002UL, 0x04000000UL, 0x00200800UL,
+ 0x04000000UL, 0x00200800UL, 0x00200000UL, 0x04000802UL,
+ 0x04000802UL, 0x04200002UL, 0x04200002UL, 0x00000002UL,
+ 0x00200002UL, 0x04000000UL, 0x04000800UL, 0x00200000UL,
+ 0x04200800UL, 0x00000802UL, 0x00200802UL, 0x04200800UL,
+ 0x00000802UL, 0x04000002UL, 0x04200802UL, 0x04200000UL,
+ 0x00200800UL, 0x00000000UL, 0x00000002UL, 0x04200802UL,
+ 0x00000000UL, 0x00200802UL, 0x04200000UL, 0x00000800UL,
+ 0x04000002UL, 0x04000800UL, 0x00000800UL, 0x00200002UL
+};
+
+static const u32 SP8[64] =
+{
+ 0x10001040UL, 0x00001000UL, 0x00040000UL, 0x10041040UL,
+ 0x10000000UL, 0x10001040UL, 0x00000040UL, 0x10000000UL,
+ 0x00040040UL, 0x10040000UL, 0x10041040UL, 0x00041000UL,
+ 0x10041000UL, 0x00041040UL, 0x00001000UL, 0x00000040UL,
+ 0x10040000UL, 0x10000040UL, 0x10001000UL, 0x00001040UL,
+ 0x00041000UL, 0x00040040UL, 0x10040040UL, 0x10041000UL,
+ 0x00001040UL, 0x00000000UL, 0x00000000UL, 0x10040040UL,
+ 0x10000040UL, 0x10001000UL, 0x00041040UL, 0x00040000UL,
+ 0x00041040UL, 0x00040000UL, 0x10041000UL, 0x00001000UL,
+ 0x00000040UL, 0x10040040UL, 0x00001000UL, 0x00041040UL,
+ 0x10001000UL, 0x00000040UL, 0x10000040UL, 0x10040000UL,
+ 0x10040040UL, 0x10000000UL, 0x00040000UL, 0x10001040UL,
+ 0x00000000UL, 0x10041040UL, 0x00040040UL, 0x10000040UL,
+ 0x10040000UL, 0x10001000UL, 0x10001040UL, 0x00000000UL,
+ 0x10041040UL, 0x00041000UL, 0x00041000UL, 0x00001040UL,
+ 0x00001040UL, 0x00040040UL, 0x10000000UL, 0x10041000UL
+};
+
+
+static void cookey(const u32 *raw1, u32 *keyout)
+{
+ u32 *cook;
+ const u32 *raw0;
+ u32 dough[32];
+ int i;
+
+ cook = dough;
+ for (i = 0; i < 16; i++, raw1++) {
+ raw0 = raw1++;
+ *cook = (*raw0 & 0x00fc0000L) << 6;
+ *cook |= (*raw0 & 0x00000fc0L) << 10;
+ *cook |= (*raw1 & 0x00fc0000L) >> 10;
+ *cook++ |= (*raw1 & 0x00000fc0L) >> 6;
+ *cook = (*raw0 & 0x0003f000L) << 12;
+ *cook |= (*raw0 & 0x0000003fL) << 16;
+ *cook |= (*raw1 & 0x0003f000L) >> 4;
+ *cook++ |= (*raw1 & 0x0000003fL);
+ }
+
+ os_memcpy(keyout, dough, sizeof(dough));
+}
+
+
+static void deskey(const u8 *key, int decrypt, u32 *keyout)
+{
+ u32 i, j, l, m, n, kn[32];
+ u8 pc1m[56], pcr[56];
+
+ for (j = 0; j < 56; j++) {
+ l = (u32) pc1[j];
+ m = l & 7;
+ pc1m[j] = (u8)
+ ((key[l >> 3U] & bytebit[m]) == bytebit[m] ? 1 : 0);
+ }
+
+ for (i = 0; i < 16; i++) {
+ if (decrypt)
+ m = (15 - i) << 1;
+ else
+ m = i << 1;
+ n = m + 1;
+ kn[m] = kn[n] = 0L;
+ for (j = 0; j < 28; j++) {
+ l = j + (u32) totrot[i];
+ if (l < 28)
+ pcr[j] = pc1m[l];
+ else
+ pcr[j] = pc1m[l - 28];
+ }
+ for (/* j = 28 */; j < 56; j++) {
+ l = j + (u32) totrot[i];
+ if (l < 56)
+ pcr[j] = pc1m[l];
+ else
+ pcr[j] = pc1m[l - 28];
+ }
+ for (j = 0; j < 24; j++) {
+ if ((int) pcr[(int) pc2[j]] != 0)
+ kn[m] |= bigbyte[j];
+ if ((int) pcr[(int) pc2[j + 24]] != 0)
+ kn[n] |= bigbyte[j];
+ }
+ }
+
+ cookey(kn, keyout);
+}
+
+
+static void desfunc(u32 *block, const u32 *keys)
+{
+ u32 work, right, leftt;
+ int cur_round;
+
+ leftt = block[0];
+ right = block[1];
+
+ work = ((leftt >> 4) ^ right) & 0x0f0f0f0fL;
+ right ^= work;
+ leftt ^= (work << 4);
+
+ work = ((leftt >> 16) ^ right) & 0x0000ffffL;
+ right ^= work;
+ leftt ^= (work << 16);
+
+ work = ((right >> 2) ^ leftt) & 0x33333333L;
+ leftt ^= work;
+ right ^= (work << 2);
+
+ work = ((right >> 8) ^ leftt) & 0x00ff00ffL;
+ leftt ^= work;
+ right ^= (work << 8);
+
+ right = ROLc(right, 1);
+ work = (leftt ^ right) & 0xaaaaaaaaL;
+
+ leftt ^= work;
+ right ^= work;
+ leftt = ROLc(leftt, 1);
+
+ for (cur_round = 0; cur_round < 8; cur_round++) {
+ work = RORc(right, 4) ^ *keys++;
+ leftt ^= SP7[work & 0x3fL]
+ ^ SP5[(work >> 8) & 0x3fL]
+ ^ SP3[(work >> 16) & 0x3fL]
+ ^ SP1[(work >> 24) & 0x3fL];
+ work = right ^ *keys++;
+ leftt ^= SP8[ work & 0x3fL]
+ ^ SP6[(work >> 8) & 0x3fL]
+ ^ SP4[(work >> 16) & 0x3fL]
+ ^ SP2[(work >> 24) & 0x3fL];
+
+ work = RORc(leftt, 4) ^ *keys++;
+ right ^= SP7[ work & 0x3fL]
+ ^ SP5[(work >> 8) & 0x3fL]
+ ^ SP3[(work >> 16) & 0x3fL]
+ ^ SP1[(work >> 24) & 0x3fL];
+ work = leftt ^ *keys++;
+ right ^= SP8[ work & 0x3fL]
+ ^ SP6[(work >> 8) & 0x3fL]
+ ^ SP4[(work >> 16) & 0x3fL]
+ ^ SP2[(work >> 24) & 0x3fL];
+ }
+
+ right = RORc(right, 1);
+ work = (leftt ^ right) & 0xaaaaaaaaL;
+ leftt ^= work;
+ right ^= work;
+ leftt = RORc(leftt, 1);
+ work = ((leftt >> 8) ^ right) & 0x00ff00ffL;
+ right ^= work;
+ leftt ^= (work << 8);
+ /* -- */
+ work = ((leftt >> 2) ^ right) & 0x33333333L;
+ right ^= work;
+ leftt ^= (work << 2);
+ work = ((right >> 16) ^ leftt) & 0x0000ffffL;
+ leftt ^= work;
+ right ^= (work << 16);
+ work = ((right >> 4) ^ leftt) & 0x0f0f0f0fL;
+ leftt ^= work;
+ right ^= (work << 4);
+
+ block[0] = right;
+ block[1] = leftt;
+}
+
+
+/* wpa_supplicant/hostapd specific wrapper */
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+ u8 pkey[8], next, tmp;
+ int i;
+ u32 ek[32], work[2];
+
+ /* Add parity bits to the key */
+ next = 0;
+ for (i = 0; i < 7; i++) {
+ tmp = key[i];
+ pkey[i] = (tmp >> i) | next | 1;
+ next = tmp << (7 - i);
+ }
+ pkey[i] = next | 1;
+
+ deskey(pkey, 0, ek);
+
+ work[0] = WPA_GET_BE32(clear);
+ work[1] = WPA_GET_BE32(clear + 4);
+ desfunc(work, ek);
+ WPA_PUT_BE32(cypher, work[0]);
+ WPA_PUT_BE32(cypher + 4, work[1]);
+}
+
+
+struct des3_key_s {
+ u32 ek[3][32];
+ u32 dk[3][32];
+};
+
+void des3_key_setup(const u8 *key, struct des3_key_s *dkey)
+{
+ deskey(key, 0, dkey->ek[0]);
+ deskey(key + 8, 1, dkey->ek[1]);
+ deskey(key + 16, 0, dkey->ek[2]);
+
+ deskey(key, 1, dkey->dk[2]);
+ deskey(key + 8, 0, dkey->dk[1]);
+ deskey(key + 16, 1, dkey->dk[0]);
+}
+
+
+void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt)
+{
+ u32 work[2];
+
+ work[0] = WPA_GET_BE32(plain);
+ work[1] = WPA_GET_BE32(plain + 4);
+ desfunc(work, key->ek[0]);
+ desfunc(work, key->ek[1]);
+ desfunc(work, key->ek[2]);
+ WPA_PUT_BE32(crypt, work[0]);
+ WPA_PUT_BE32(crypt + 4, work[1]);
+}
+
+
+void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain)
+{
+ u32 work[2];
+
+ work[0] = WPA_GET_BE32(crypt);
+ work[1] = WPA_GET_BE32(crypt + 4);
+ desfunc(work, key->dk[0]);
+ desfunc(work, key->dk[1]);
+ desfunc(work, key->dk[2]);
+ WPA_PUT_BE32(plain, work[0]);
+ WPA_PUT_BE32(plain + 4, work[1]);
+}
+
+#endif /* INTERNAL_DES */
diff --git a/contrib/hostapd/doc/code_structure.doxygen b/contrib/hostapd/doc/code_structure.doxygen
new file mode 100644
index 000000000000..fdcf725b5d7f
--- /dev/null
+++ b/contrib/hostapd/doc/code_structure.doxygen
@@ -0,0 +1,5 @@
+/**
+\page code_structure Structure of the source code
+
+
+*/
diff --git a/contrib/hostapd/doc/ctrl_iface.doxygen b/contrib/hostapd/doc/ctrl_iface.doxygen
new file mode 100644
index 000000000000..76cfc6a6b79c
--- /dev/null
+++ b/contrib/hostapd/doc/ctrl_iface.doxygen
@@ -0,0 +1,66 @@
+/**
+\page ctrl_iface_page Control interface
+
+hostapd implements a control interface that can be used by
+external programs to control the operations of the hostapd
+daemon and to get status information and event notifications. There is
+a small C library, in a form of a single C file, wpa_ctrl.c, that
+provides helper functions to facilitate the use of the control
+interface. External programs can link this file into them and then use
+the library functions documented in wpa_ctrl.h to interact with
+%wpa_supplicant. This library can also be used with C++. hostapd_cli.c
+is an example program using this library.
+
+There are multiple mechanisms for inter-process communication. For
+example, Linux version of hostapd is using UNIX domain sockets for the
+control interface. The use of the functions defined in wpa_ctrl.h can
+be used to hide the details of the used IPC from external programs.
+
+
+\section using_ctrl_iface Using the control interface
+
+External programs, e.g., a GUI or a configuration utility, that need to
+communicate with hostapd should link in wpa_ctrl.c. This
+allows them to use helper functions to open connection to the control
+interface with wpa_ctrl_open() and to send commands with
+wpa_ctrl_request().
+
+hostapd uses the control interface for two types of communication:
+commands and unsolicited event messages. Commands are a pair of
+messages, a request from the external program and a response from
+hostapd. These can be executed using wpa_ctrl_request().
+Unsolicited event messages are sent by hostapd to the control
+interface connection without specific request from the external program
+for receiving each message. However, the external program needs to
+attach to the control interface with wpa_ctrl_attach() to receive these
+unsolicited messages.
+
+If the control interface connection is used both for commands and
+unsolicited event messages, there is potential for receiving an
+unsolicited message between the command request and response.
+wpa_ctrl_request() caller will need to supply a callback, msg_cb,
+for processing these messages. Often it is easier to open two
+control interface connections by calling wpa_ctrl_open() twice and
+then use one of the connections for commands and the other one for
+unsolicited messages. This way command request/response pairs will
+not be broken by unsolicited messages. wpa_cli is an example of how
+to use only one connection for both purposes and wpa_gui demonstrates
+how to use two separate connections.
+
+Once the control interface connection is not needed anymore, it should
+be closed by calling wpa_ctrl_close(). If the connection was used for
+unsolicited event messages, it should be first detached by calling
+wpa_ctrl_detach().
+
+
+\section ctrl_iface_cmds Control interface commands
+
+Following commands can be used with wpa_ctrl_request():
+
+\subsection ctrl_iface_PING PING
+
+This command can be used to test whether hostapd is replying
+to the control interface commands. The expected reply is \c PONG if the
+connection is open and hostapd is processing commands.
+
+*/
diff --git a/contrib/hostapd/doc/doxygen.fast b/contrib/hostapd/doc/doxygen.fast
new file mode 100644
index 000000000000..44760f4204b3
--- /dev/null
+++ b/contrib/hostapd/doc/doxygen.fast
@@ -0,0 +1,233 @@
+# Doxyfile 1.4.4
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = hostapd
+PROJECT_NUMBER = 0.5.x
+OUTPUT_DIRECTORY = doc
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+SEPARATE_MEMBER_PAGES = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = NO
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = . \
+ ../wpa_supplicant/eap_sim_common.c \
+ ../wpa_supplicant/eap_sim_common.h
+FILE_PATTERNS = *.c *.h *.doxygen
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH = doc
+INPUT_FILTER = doc/kerneldoc2doxygen.pl
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = YES
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = YES
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 3
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = NO
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED = RADIUS_SERVER EAP_SERVER EAP_SIM
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = NO
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = NO
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = NO
diff --git a/contrib/hostapd/doc/doxygen.full b/contrib/hostapd/doc/doxygen.full
new file mode 100644
index 000000000000..619f977303da
--- /dev/null
+++ b/contrib/hostapd/doc/doxygen.full
@@ -0,0 +1,230 @@
+# Doxyfile 1.4.1
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+PROJECT_NAME = hostapd
+PROJECT_NUMBER = 0.5.x
+OUTPUT_DIRECTORY = doc
+CREATE_SUBDIRS = NO
+OUTPUT_LANGUAGE = English
+USE_WINDOWS_ENCODING = NO
+BRIEF_MEMBER_DESC = YES
+REPEAT_BRIEF = YES
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+ALWAYS_DETAILED_SEC = NO
+INLINE_INHERITED_MEMB = NO
+FULL_PATH_NAMES = YES
+STRIP_FROM_PATH =
+STRIP_FROM_INC_PATH =
+SHORT_NAMES = NO
+JAVADOC_AUTOBRIEF = NO
+MULTILINE_CPP_IS_BRIEF = NO
+DETAILS_AT_TOP = NO
+INHERIT_DOCS = YES
+DISTRIBUTE_GROUP_DOC = NO
+TAB_SIZE = 8
+ALIASES =
+OPTIMIZE_OUTPUT_FOR_C = YES
+OPTIMIZE_OUTPUT_JAVA = NO
+SUBGROUPING = YES
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+EXTRACT_ALL = NO
+EXTRACT_PRIVATE = NO
+EXTRACT_STATIC = NO
+EXTRACT_LOCAL_CLASSES = YES
+EXTRACT_LOCAL_METHODS = NO
+HIDE_UNDOC_MEMBERS = NO
+HIDE_UNDOC_CLASSES = NO
+HIDE_FRIEND_COMPOUNDS = NO
+HIDE_IN_BODY_DOCS = NO
+INTERNAL_DOCS = NO
+CASE_SENSE_NAMES = YES
+HIDE_SCOPE_NAMES = NO
+SHOW_INCLUDE_FILES = YES
+INLINE_INFO = YES
+SORT_MEMBER_DOCS = YES
+SORT_BRIEF_DOCS = NO
+SORT_BY_SCOPE_NAME = NO
+GENERATE_TODOLIST = YES
+GENERATE_TESTLIST = YES
+GENERATE_BUGLIST = YES
+GENERATE_DEPRECATEDLIST= YES
+ENABLED_SECTIONS =
+MAX_INITIALIZER_LINES = 30
+SHOW_USED_FILES = YES
+SHOW_DIRECTORIES = NO
+FILE_VERSION_FILTER =
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+QUIET = NO
+WARNINGS = YES
+WARN_IF_UNDOCUMENTED = YES
+WARN_IF_DOC_ERROR = YES
+WARN_NO_PARAMDOC = YES
+WARN_FORMAT = "$file:$line: $text"
+WARN_LOGFILE =
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+INPUT = .
+FILE_PATTERNS = *.c *.h *.doxygen
+RECURSIVE = YES
+EXCLUDE =
+EXCLUDE_SYMLINKS = NO
+EXCLUDE_PATTERNS =
+EXAMPLE_PATH =
+EXAMPLE_PATTERNS = *
+EXAMPLE_RECURSIVE = NO
+IMAGE_PATH = doc
+INPUT_FILTER = kerneldoc2doxygen.pl
+FILTER_PATTERNS =
+FILTER_SOURCE_FILES = YES
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+SOURCE_BROWSER = YES
+INLINE_SOURCES = NO
+STRIP_CODE_COMMENTS = YES
+REFERENCED_BY_RELATION = NO
+REFERENCES_RELATION = NO
+VERBATIM_HEADERS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+ALPHABETICAL_INDEX = YES
+COLS_IN_ALPHA_INDEX = 3
+IGNORE_PREFIX =
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+GENERATE_HTML = YES
+HTML_OUTPUT = html
+HTML_FILE_EXTENSION = .html
+HTML_HEADER =
+HTML_FOOTER =
+HTML_STYLESHEET =
+HTML_ALIGN_MEMBERS = YES
+GENERATE_HTMLHELP = NO
+CHM_FILE =
+HHC_LOCATION =
+GENERATE_CHI = NO
+BINARY_TOC = NO
+TOC_EXPAND = NO
+DISABLE_INDEX = NO
+ENUM_VALUES_PER_LINE = 4
+GENERATE_TREEVIEW = NO
+TREEVIEW_WIDTH = 250
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+GENERATE_LATEX = YES
+LATEX_OUTPUT = latex
+LATEX_CMD_NAME = latex
+MAKEINDEX_CMD_NAME = makeindex
+COMPACT_LATEX = NO
+PAPER_TYPE = a4wide
+EXTRA_PACKAGES =
+LATEX_HEADER =
+PDF_HYPERLINKS = YES
+USE_PDFLATEX = YES
+LATEX_BATCHMODE = NO
+LATEX_HIDE_INDICES = NO
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+GENERATE_RTF = NO
+RTF_OUTPUT = rtf
+COMPACT_RTF = NO
+RTF_HYPERLINKS = NO
+RTF_STYLESHEET_FILE =
+RTF_EXTENSIONS_FILE =
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+GENERATE_MAN = NO
+MAN_OUTPUT = man
+MAN_EXTENSION = .3
+MAN_LINKS = NO
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+GENERATE_XML = NO
+XML_OUTPUT = xml
+XML_SCHEMA =
+XML_DTD =
+XML_PROGRAMLISTING = YES
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+GENERATE_AUTOGEN_DEF = NO
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+GENERATE_PERLMOD = NO
+PERLMOD_LATEX = NO
+PERLMOD_PRETTY = YES
+PERLMOD_MAKEVAR_PREFIX =
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+ENABLE_PREPROCESSING = YES
+MACRO_EXPANSION = NO
+EXPAND_ONLY_PREDEF = NO
+SEARCH_INCLUDES = YES
+INCLUDE_PATH =
+INCLUDE_FILE_PATTERNS =
+PREDEFINED = RADIUS_SERVER EAP_SERVER EAP_SIM
+EXPAND_AS_DEFINED =
+SKIP_FUNCTION_MACROS = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+TAGFILES =
+GENERATE_TAGFILE =
+ALLEXTERNALS = NO
+EXTERNAL_GROUPS = YES
+PERL_PATH = /usr/bin/perl
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+CLASS_DIAGRAMS = NO
+HIDE_UNDOC_RELATIONS = YES
+HAVE_DOT = YES
+CLASS_GRAPH = YES
+COLLABORATION_GRAPH = YES
+GROUP_GRAPHS = YES
+UML_LOOK = NO
+TEMPLATE_RELATIONS = NO
+INCLUDE_GRAPH = YES
+INCLUDED_BY_GRAPH = YES
+CALL_GRAPH = YES
+GRAPHICAL_HIERARCHY = YES
+DIRECTORY_GRAPH = NO
+DOT_IMAGE_FORMAT = png
+DOT_PATH =
+DOTFILE_DIRS =
+MAX_DOT_GRAPH_WIDTH = 1024
+MAX_DOT_GRAPH_HEIGHT = 1024
+MAX_DOT_GRAPH_DEPTH = 1000
+DOT_TRANSPARENT = NO
+DOT_MULTI_TARGETS = NO
+GENERATE_LEGEND = YES
+DOT_CLEANUP = YES
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+SEARCHENGINE = YES
diff --git a/contrib/hostapd/doc/driver_wrapper.doxygen b/contrib/hostapd/doc/driver_wrapper.doxygen
new file mode 100644
index 000000000000..0ad196f2d6b6
--- /dev/null
+++ b/contrib/hostapd/doc/driver_wrapper.doxygen
@@ -0,0 +1,20 @@
+/**
+\page driver_wrapper Driver wrapper implementation (driver.h, drivers.c)
+
+All hardware and driver dependent functionality is in separate C files
+that implement defined wrapper functions. Other parts
+of the hostapd are designed to be hardware, driver, and operating
+system independent.
+
+Driver wrappers need to implement whatever calls are used in the
+target operating system/driver for controlling wireless LAN
+devices. As an example, in case of Linux, these are mostly some glue
+code and ioctl() calls and netlink message parsing for Linux Wireless
+Extensions (WE). Since features required for WPA were added only recently to
+Linux Wireless Extensions (in version 18), some driver specific code is used
+in number of driver interface implementations. These driver dependent parts
+can be replaced with generic code in driver_wext.c once the target driver
+includes full support for WE-18. After that, all Linux drivers, at
+least in theory, could use the same driver wrapper code.
+
+*/
diff --git a/contrib/hostapd/doc/eap.doxygen b/contrib/hostapd/doc/eap.doxygen
new file mode 100644
index 000000000000..f0f135aa9598
--- /dev/null
+++ b/contrib/hostapd/doc/eap.doxygen
@@ -0,0 +1,56 @@
+/**
+\page eap_module EAP server implementation
+
+Extensible Authentication Protocol (EAP) is an authentication framework
+defined in RFC 3748. hostapd uses a separate code module for EAP server
+implementation. This module was designed to use only a minimal set of
+direct function calls (mainly, to debug/event functions) in order for
+it to be usable in other programs. The design of the EAP
+implementation is based loosely on RFC 4137. The state machine is
+defined in this RFC and so is the interface between the server state
+machine and methods. As such, this RFC provides useful information for
+understanding the EAP server implementation in hostapd.
+
+Some of the terminology used in EAP state machine is referring to
+EAPOL (IEEE 802.1X), but there is no strict requirement on the lower
+layer being IEEE 802.1X if EAP module is built for other programs than
+%wpa_supplicant. These terms should be understood to refer to the
+lower layer as defined in RFC 4137.
+
+
+\section adding_eap_methods Adding EAP methods
+
+Each EAP method is implemented as a separate module, usually as one C
+file named eap_<name of the method>.c, e.g., eap_md5.c. All EAP
+methods use the same interface between the server state machine and
+method specific functions. This allows new EAP methods to be added
+without modifying the core EAP state machine implementation.
+
+New EAP methods need to be registered by adding them into the build
+(Makefile) and the EAP method registration list in the
+eap_server_register_methods() function of eap_methods.c. Each EAP
+method should use a build-time configuration option, e.g., EAP_TLS, in
+order to make it possible to select which of the methods are included
+in the build.
+
+EAP methods must implement the interface defined in eap_i.h. struct
+eap_method defines the needed function pointers that each EAP method
+must provide. In addition, the EAP type and name are registered using
+this structure. This interface is based on section 4.4 of RFC 4137.
+
+It is recommended that the EAP methods would use generic helper
+functions, eap_msg_alloc() and eap_hdr_validate() when processing
+messages. This allows code sharing and can avoid missing some of the
+needed validation steps for received packets. In addition, these
+functions make it easier to change between expanded and legacy EAP
+header, if needed.
+
+When adding an EAP method that uses a vendor specific EAP type
+(Expanded Type as defined in RFC 3748, Chapter 5.7), the new method
+must be registered by passing vendor id instead of EAP_VENDOR_IETF to
+eap_server_method_alloc(). These methods must not try to emulate
+expanded types by registering a legacy EAP method for type 254. See
+eap_vendor_test.c for an example of an EAP method implementation that
+is implemented as an expanded type.
+
+*/
diff --git a/contrib/hostapd/doc/hostapd.fig b/contrib/hostapd/doc/hostapd.fig
new file mode 100644
index 000000000000..af3f0be19a9b
--- /dev/null
+++ b/contrib/hostapd/doc/hostapd.fig
@@ -0,0 +1,264 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+Letter
+100.00
+Single
+-2
+1200 2
+6 1875 4050 2925 4350
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 1875 4050 2925 4050 2925 4350 1875 4350 1875 4050
+4 0 0 50 -1 0 12 0.0000 4 180 735 2025 4275 l2_packet\001
+-6
+6 4725 1200 5925 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4725 1200 5925 1200 5925 1500 4725 1500 4725 1200
+4 0 0 50 -1 0 12 0.0000 4 135 1005 4800 1425 GUI frontend\001
+-6
+6 6000 2700 7200 3225
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 6000 2700 7200 2700 7200 3225 6000 3225 6000 2700
+4 0 0 50 -1 0 12 0.0000 4 135 975 6075 2925 WPA/WPA2\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 3150 state machine\001
+-6
+6 6000 4950 7200 5475
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 6000 4950 7200 4950 7200 5475 6000 5475 6000 4950
+4 0 0 50 -1 0 12 0.0000 4 135 360 6075 5175 EAP\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 5400 state machine\001
+-6
+6 4350 3900 5025 4425
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4350 3900 5025 3900 5025 4425 4350 4425 4350 3900
+4 0 0 50 -1 0 12 0.0000 4 105 420 4500 4125 event\001
+4 0 0 50 -1 0 12 0.0000 4 180 315 4500 4350 loop\001
+-6
+6 4275 2550 5100 2850
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4275 2550 5100 2550 5100 2850 4275 2850 4275 2550
+4 0 0 50 -1 0 12 0.0000 4 135 450 4425 2775 ctrl i/f\001
+-6
+6 6000 3900 7200 4425
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 6000 3900 7200 3900 7200 4425 6000 4425 6000 3900
+4 0 0 50 -1 0 12 0.0000 4 135 600 6075 4125 EAPOL\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 4350 state machine\001
+-6
+6 2775 3150 4050 3450
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 2775 3150 4050 3150 4050 3450 2775 3450 2775 3150
+4 0 0 50 -1 0 12 0.0000 4 180 990 2925 3375 configuration\001
+-6
+6 3450 1200 4575 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3450 1200 4575 1200 4575 1500 3450 1500 3450 1200
+4 0 0 50 -1 0 12 0.0000 4 180 870 3600 1425 hostapd_cli\001
+-6
+6 3525 7800 5775 8100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3525 7800 5775 7800 5775 8100 3525 8100 3525 7800
+4 0 0 50 -1 0 12 0.0000 4 135 2145 3600 8025 kernel network device driver\001
+-6
+6 4275 6000 5100 6300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4275 6000 5100 6000 5100 6300 4275 6300 4275 6000
+4 0 0 50 -1 0 12 0.0000 4 135 630 4350 6225 driver i/f\001
+-6
+6 8175 4725 9225 5025
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 4725 9225 4725 9225 5025 8175 5025 8175 4725
+4 0 0 50 -1 0 12 0.0000 4 135 735 8250 4950 EAP-TLS\001
+-6
+6 9300 4725 10350 5025
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9300 4725 10350 4725 10350 5025 9300 5025 9300 4725
+4 0 0 50 -1 0 12 0.0000 4 135 810 9375 4950 EAP-MD5\001
+-6
+6 8175 5100 9225 5400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 5100 9225 5100 9225 5400 8175 5400 8175 5100
+4 0 0 50 -1 0 12 0.0000 4 135 885 8250 5325 EAP-PEAP\001
+-6
+6 9300 5100 10350 5400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9300 5100 10350 5100 10350 5400 9300 5400 9300 5100
+4 0 0 50 -1 0 12 0.0000 4 135 840 9375 5325 EAP-TTLS\001
+-6
+6 8175 5475 9225 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 5475 9225 5475 9225 5775 8175 5775 8175 5475
+4 0 0 50 -1 0 12 0.0000 4 135 780 8250 5700 EAP-GTC\001
+-6
+6 8175 5850 9225 6150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 5850 9225 5850 9225 6150 8175 6150 8175 5850
+4 0 0 50 -1 0 12 0.0000 4 135 750 8250 6075 EAP-SIM\001
+-6
+6 8175 6225 9225 6525
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 6225 9225 6225 9225 6525 8175 6525 8175 6225
+4 0 0 50 -1 0 12 0.0000 4 135 765 8250 6450 EAP-PSK\001
+-6
+6 9300 5850 10350 6150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9300 5850 10350 5850 10350 6150 9300 6150 9300 5850
+4 0 0 50 -1 0 12 0.0000 4 135 825 9375 6075 EAP-AKA\001
+-6
+6 9300 5475 10350 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9300 5475 10350 5475 10350 5775 9300 5775 9300 5475
+4 0 0 50 -1 0 12 0.0000 4 135 795 9375 5700 EAP-PAX\001
+-6
+6 8175 6600 9675 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8175 6600 9675 6600 9675 6900 8175 6900 8175 6600
+4 0 0 50 -1 0 12 0.0000 4 135 1365 8250 6825 EAP-MSCHAPv2\001
+-6
+6 8700 3450 9375 3750
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8700 3450 9375 3450 9375 3750 8700 3750 8700 3450
+4 0 0 50 -1 0 12 0.0000 4 150 480 8775 3675 crypto\001
+-6
+6 9600 3450 10275 3750
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9600 3450 10275 3450 10275 3750 9600 3750 9600 3450
+4 0 0 50 -1 0 12 0.0000 4 135 315 9750 3675 TLS\001
+-6
+6 6000 5775 7200 6300
+6 6000 5775 7200 6300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 6000 5775 7200 5775 7200 6300 6000 6300 6000 5775
+4 0 0 50 -1 0 12 0.0000 4 135 690 6075 6000 RADIUS\001
+-6
+4 0 0 50 -1 0 12 0.0000 4 90 480 6075 6225 server\001
+-6
+6 8100 2250 8925 2775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8100 2250 8925 2250 8925 2775 8100 2775 8100 2250
+4 0 0 50 -1 0 12 0.0000 4 135 690 8175 2475 RADIUS\001
+4 0 0 50 -1 0 12 0.0000 4 135 420 8175 2700 client\001
+-6
+6 3150 5475 4425 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3150 5475 4425 5475 4425 5775 3150 5775 3150 5475
+4 0 0 50 -1 0 12 0.0000 4 135 990 3300 5700 driver events\001
+-6
+6 1950 5550 2625 6075
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 1950 5550 2625 5550 2625 6075 1950 6075 1950 5550
+4 0 0 50 -1 0 12 0.0000 4 135 540 2025 5775 Station\001
+4 0 0 50 -1 0 12 0.0000 4 135 375 2025 6000 table\001
+-6
+6 1875 4725 2925 5250
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 1875 4725 2925 4725 2925 5250 1875 5250 1875 4725
+4 0 0 50 -1 0 12 0.0000 4 135 960 1950 4950 IEEE 802.11\001
+4 0 0 50 -1 0 12 0.0000 4 135 555 1950 5175 MLME\001
+-6
+2 1 1 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
+ 1275 4200 1875 4200
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+ 4500 2550 3900 1500
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+ 4800 2550 5400 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 2925 4200 4350 4200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 5025 3900 6000 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 5025 4200 6000 4200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4650 6000 4650 4425
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6600 4425 6600 4950
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6600 3225 6600 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 7200 5250 8100 5250
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 9075 4425 9075 3750
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 7200 3000 8700 3525
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4650 3900 4650 2850
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 7200 4125 8700 3675
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6000 4350 5025 6000
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6000 3150 4875 6000
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 1500 2100 10800 2100 10800 7500 1500 7500 1500 2100
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 9900 4425 9900 3750
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 1
+ 4350 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4350 3900 4050 3450
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4350 4425 4050 5475
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+ 2250 7200 4200 7800
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+ 7200 7200 5100 7800
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 2775 6900 3675 6900 3675 7200 2775 7200 2775 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 3750 6900 4650 6900 4650 7200 3750 7200 3750 6900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 4
+ 2250 6900 2250 6600 7200 6600 7200 6900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 3225 6900 3225 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4200 6900 4200 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 5175 6900 5175 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6150 6900 6150 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 4650 6600 4650 6300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 1800 6900 2700 6900 2700 7200 1800 7200 1800 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 4725 6900 5625 6900 5625 7200 4725 7200 4725 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 5700 6900 6600 6900 6600 7200 5700 7200 5700 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 6675 6900 7800 6900 7800 7200 6675 7200 6675 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 8100 6975 10425 6975 10425 4425 8100 4425 8100 6975
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 6600 5475 6600 5775
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 5025 4425 6000 5775
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
+ 4800 3900 5925 2550 8100 2550
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 7200 3900 8475 2775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+ 9450 2250 10425 2250 10425 2775 9450 2775 9450 2250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 8925 2475 9450 2475
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 2325 5550 2325 5250
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+ 2925 4950 4350 4275
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 3
+ 2850 4725 5775 2400 8100 2400
+4 0 0 50 -1 0 12 0.0000 4 135 915 375 3975 EAPOL and\001
+4 0 0 50 -1 0 12 0.0000 4 180 630 375 4200 pre-auth\001
+4 0 0 50 -1 0 12 0.0000 4 180 810 375 4425 ethertypes\001
+4 0 0 50 -1 0 12 0.0000 4 135 1050 375 4650 from/to kernel\001
+4 0 0 50 -1 0 12 0.0000 4 135 1920 3675 1875 frontend control interface\001
+4 0 0 50 -1 2 14 0.0000 4 195 720 1637 2371 hostapd\001
+4 0 0 50 -1 0 12 0.0000 4 180 600 3825 7125 prism54\001
+4 0 0 50 -1 0 12 0.0000 4 180 510 1875 7125 hostap\001
+4 0 0 50 -1 0 12 0.0000 4 135 600 2850 7125 madwifi\001
+4 0 0 50 -1 0 12 0.0000 4 135 270 4800 7125 bsd\001
+4 0 0 50 -1 0 12 0.0000 4 105 300 6750 7125 test\001
+4 0 0 50 -1 0 12 0.0000 4 135 420 5775 7125 wired\001
+4 0 0 50 -1 0 12 0.0000 4 135 1050 8700 4650 EAP methods\001
+4 0 0 50 -1 0 12 0.0000 4 135 690 9525 2475 RADIUS\001
+4 0 0 50 -1 0 12 0.0000 4 180 825 9525 2700 accounting\001
diff --git a/contrib/hostapd/doc/kerneldoc2doxygen.pl b/contrib/hostapd/doc/kerneldoc2doxygen.pl
new file mode 100755
index 000000000000..68835a1ddd31
--- /dev/null
+++ b/contrib/hostapd/doc/kerneldoc2doxygen.pl
@@ -0,0 +1,129 @@
+#!/usr/bin/perl -w
+#
+##########################################################################
+# Convert kernel-doc style comments to Doxygen comments.
+##########################################################################
+#
+# This script reads a C source file from stdin, and writes
+# to stdout. Normal usage:
+#
+# $ mv file.c file.c.gtkdoc
+# $ kerneldoc2doxygen.pl <file.c.gtkdoc >file.c
+#
+# Or to do the same thing with multiple files:
+# $ perl -i.gtkdoc kerneldoc2doxygen.pl *.c *.h
+#
+# This script may also be suitable for use as a Doxygen input filter,
+# but that has not been tested.
+#
+# Back up your source files before using this script!!
+#
+##########################################################################
+# Copyright (C) 2003 Jonathan Foster <jon@jon-foster.co.uk>
+# Copyright (C) 2005 Jouni Malinen <j@w1.fi>
+# (modified for kerneldoc format used in wpa_supplicant)
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License version 2 as
+# published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+# or look at http://www.gnu.org/licenses/gpl.html
+##########################################################################
+
+
+##########################################################################
+#
+# This function converts a single comment from gtk-doc to Doxygen format.
+# The parameter does not include the opening or closing lines
+# (i.e. given a comment like this:
+# "/**\n"
+# " * FunctionName:\n"
+# " * @foo: This describes the foo parameter\n"
+# " * @bar: This describes the bar parameter\n"
+# " * @Returns: This describes the return value\n"
+# " *\n"
+# " * This describes the function.\n"
+# " */\n"
+# This function gets:
+# " * FunctionName:\n"
+# " * @foo: This describes the foo parameter\n"
+# " * @bar: This describes the bar parameter\n"
+# " * @Returns: This describes the return value\n"
+# " *\n"
+# " * This describes the function.\n"
+# And it returns:
+# " * This describes the function.\n"
+# " *\n"
+# " * @param foo This describes the foo parameter\n"
+# " * @param bar This describes the bar parameter\n"
+# " * @return This describes the return value\n"
+# )
+#
+sub fixcomment {
+ $t = $_[0];
+
+ # " * func: foo" --> "\brief foo\n"
+ # " * struct bar: foo" --> "\brief foo\n"
+ # If this fails, not a kernel-doc comment ==> return unmodified.
+ ($t =~ s/^[\t ]*\*[\t ]*(struct )?([^ \t\n]*) - ([^\n]*)/\\brief $3\n/s)
+ or return $t;
+
+ # " * Returns: foo" --> "\return foo"
+ $t =~ s/\n[\t ]*\*[\t ]*Returns:/\n\\return/sig;
+
+ # " * @foo: bar" --> "\param foo bar"
+ # Handle two common typos: No ":", or "," instead of ":".
+ $t =~ s/\n[\t ]*\*[\t ]*\@([^ :,]*)[:,]?[\t ]*/\n\\param $1 /sg;
+
+ return $t;
+}
+
+##########################################################################
+# Start of main code
+
+# Read entire stdin into memory - one multi-line string.
+$_ = do { local $/; <> };
+
+s{^/\*\n \*}{/\*\* \\file\n\\brief};
+s{ \* Copyright}{\\par Copyright\nCopyright};
+
+# Fix any comments like "/*************" so they don't match.
+# "/***" ===> "/* *"
+s{/\*\*\*}{/\* \*}gs;
+
+# The main comment-detection code.
+s{
+ ( # $1 = Open comment
+ /\*\* # Open comment
+ (?!\*) # Do not match /*** (redundant due to fixup above).
+ [\t ]*\n? # If 1st line is whitespace, match the lot (including the newline).
+ )
+ (.*?) # $2 = Body of comment (multi-line)
+ ( # $3 = Close comment
+ ( # If possible, match the whitespace before the close-comment
+ (?<=\n) # This part only matches after a newline
+ [\t ]* # Eat whitespace
+ )?
+ \*/ # Close comment
+ )
+ }
+ {
+ $1 . fixcomment($2) . $3
+ }gesx;
+# ^^^^ Modes: g - Global, match all occurances.
+# e - Evaluate the replacement as an expression.
+# s - Single-line - allows the pattern to match across newlines.
+# x - eXtended pattern, ignore embedded whitespace
+# and allow comments.
+
+# Write results to stdout
+print $_;
+
diff --git a/contrib/hostapd/doc/mainpage.doxygen b/contrib/hostapd/doc/mainpage.doxygen
new file mode 100644
index 000000000000..7cf95de584af
--- /dev/null
+++ b/contrib/hostapd/doc/mainpage.doxygen
@@ -0,0 +1,52 @@
+/**
+\mainpage Developers' documentation for hostapd
+
+hostapd includes IEEE 802.11 access point management (authentication /
+association), IEEE 802.1X/WPA/WPA2 Authenticator, EAP server, and
+RADIUS authentication server functionality. It can be build with
+various configuration option, e.g., a standalone AP management
+solution or a RADIUS authentication server with support for number of
+EAP methods.
+
+The goal of this documentation and comments in the source code is to
+give enough information for other developers to understand how hostapd
+has been implemented, how it can be modified, how new drivers can be
+supported, and how hostapd can be ported to other operating
+systems. If any information is missing, feel free to contact Jouni
+Malinen <j@w1.fi> for more information. Contributions as
+patch files are also very welcome at the same address. Please note
+that hostapd is licensed under dual license, GPLv2 or BSD at user's
+choice. All contributions to hostapd are expected to use compatible
+licensing terms.
+
+The source code and read-only access to hostapd CVS repository
+is available from the project home page at
+http://hostap.epitest.fi/hostapd/. This developers' documentation
+is also available as a PDF file from
+http://hostap.epitest.fi/hostapd/hostapd-devel.pdf .
+
+The design goal for hostapd was to use hardware, driver, and
+OS independent, portable C code for all WPA functionality. The source
+code is divided into separate C files as shown on the \ref
+code_structure "code structure page". All hardware/driver specific
+functionality is in separate files that implement a \ref
+driver_wrapper "well-defined driver API". Information about porting
+to different target boards and operating systems is available on
+the \ref porting "porting page".
+
+EAPOL (IEEE 802.1X) state machines are implemented as a separate
+module that interacts with \ref eap_module "EAP server implementation".
+Similarly, RADIUS authentication server is in its own separate module.
+Both IEEE 802.1X and RADIUS authentication server can use EAP server
+functionality.
+
+hostapd implements a \ref ctrl_iface_page "control interface" that can
+be used by external programs to control the operations of the hostapdt
+daemon and to get status information and event notifications. There is
+a small C library that provides helper functions to facilitate the use
+of the control interface. This library can also be used with C++.
+
+\image html hostapd.png "hostapd modules"
+\image latex hostapd.eps "hostapd modules" width=15cm
+
+*/
diff --git a/contrib/hostapd/doc/porting.doxygen b/contrib/hostapd/doc/porting.doxygen
new file mode 100644
index 000000000000..0621791c0be0
--- /dev/null
+++ b/contrib/hostapd/doc/porting.doxygen
@@ -0,0 +1,5 @@
+/**
+\page porting Porting to different target boards and operating systems
+
+
+*/
diff --git a/contrib/hostapd/driver.h b/contrib/hostapd/driver.h
index ed9ecbfdbc8c..4fd262c1ff14 100644
--- a/contrib/hostapd/driver.h
+++ b/contrib/hostapd/driver.h
@@ -1,6 +1,10 @@
#ifndef DRIVER_H
#define DRIVER_H
+enum hostapd_driver_if_type {
+ HOSTAPD_IF_VLAN, HOSTAPD_IF_WDS
+};
+
struct driver_ops {
const char *name; /* as appears in the config file */
@@ -12,6 +16,7 @@ struct driver_ops {
/**
* set_8021x - enable/disable IEEE 802.1X support
+ * @ifname: Interface name (for multi-SSID/VLAN support)
* @priv: driver private data
* @enabled: 1 = enable, 0 = disable
*
@@ -20,7 +25,7 @@ struct driver_ops {
* Configure the kernel driver to enable/disable 802.1X support.
* This may be an empty function if 802.1X support is always enabled.
*/
- int (*set_ieee8021x)(void *priv, int enabled);
+ int (*set_ieee8021x)(const char *ifname, void *priv, int enabled);
/**
* set_privacy - enable/disable privacy
@@ -31,32 +36,111 @@ struct driver_ops {
*
* Configure privacy.
*/
- int (*set_privacy)(void *priv, int enabled);
-
- int (*set_encryption)(void *priv, const char *alg, u8 *addr,
- int idx, u8 *key, size_t key_len);
- int (*get_seqnum)(void *priv, u8 *addr, int idx, u8 *seq);
+ int (*set_privacy)(const char *ifname, void *priv, int enabled);
+
+ int (*set_encryption)(const char *ifname, void *priv, const char *alg,
+ const u8 *addr, int idx,
+ const u8 *key, size_t key_len, int txkey);
+ int (*get_seqnum)(const char *ifname, void *priv, const u8 *addr,
+ int idx, u8 *seq);
+ int (*get_seqnum_igtk)(const char *ifname, void *priv, const u8 *addr,
+ int idx, u8 *seq);
int (*flush)(void *priv);
- int (*set_generic_elem)(void *priv, const u8 *elem, size_t elem_len);
+ int (*set_generic_elem)(const char *ifname, void *priv, const u8 *elem,
+ size_t elem_len);
int (*read_sta_data)(void *priv, struct hostap_sta_driver_data *data,
- u8 *addr);
- int (*send_eapol)(void *priv, u8 *addr, u8 *data, size_t data_len,
- int encrypt);
- int (*set_sta_authorized)(void *driver, u8 *addr, int authorized);
- int (*sta_deauth)(void *priv, u8 *addr, int reason);
- int (*sta_disassoc)(void *priv, u8 *addr, int reason);
- int (*sta_remove)(void *priv, u8 *addr);
- int (*get_ssid)(void *priv, u8 *buf, int len);
- int (*set_ssid)(void *priv, u8 *buf, int len);
+ const u8 *addr);
+ int (*send_eapol)(void *priv, const u8 *addr, const u8 *data,
+ size_t data_len, int encrypt, const u8 *own_addr);
+ int (*sta_deauth)(void *priv, const u8 *addr, int reason);
+ int (*sta_disassoc)(void *priv, const u8 *addr, int reason);
+ int (*sta_remove)(void *priv, const u8 *addr);
+ int (*get_ssid)(const char *ifname, void *priv, u8 *buf, int len);
+ int (*set_ssid)(const char *ifname, void *priv, const u8 *buf,
+ int len);
int (*set_countermeasures)(void *priv, int enabled);
int (*send_mgmt_frame)(void *priv, const void *msg, size_t len,
int flags);
- int (*set_assoc_ap)(void *priv, u8 *addr);
- int (*sta_add)(void *priv, u8 *addr, u16 aid, u16 capability,
- u8 tx_supp_rates);
- int (*get_inact_sec)(void *priv, u8 *addr);
- int (*sta_clear_stats)(void *priv, u8 *addr);
+ int (*set_assoc_ap)(void *priv, const u8 *addr);
+ int (*sta_add)(const char *ifname, void *priv, const u8 *addr, u16 aid,
+ u16 capability, u8 *supp_rates, size_t supp_rates_len,
+ int flags);
+ int (*get_inact_sec)(void *priv, const u8 *addr);
+ int (*sta_clear_stats)(void *priv, const u8 *addr);
+
+ int (*set_freq)(void *priv, int mode, int freq);
+ int (*set_rts)(void *priv, int rts);
+ int (*get_rts)(void *priv, int *rts);
+ int (*set_frag)(void *priv, int frag);
+ int (*get_frag)(void *priv, int *frag);
+ int (*set_retry)(void *priv, int short_retry, int long_retry);
+ int (*get_retry)(void *priv, int *short_retry, int *long_retry);
+
+ int (*sta_set_flags)(void *priv, const u8 *addr,
+ int flags_or, int flags_and);
+ int (*set_rate_sets)(void *priv, int *supp_rates, int *basic_rates,
+ int mode);
+ int (*set_channel_flag)(void *priv, int mode, int chan, int flag,
+ unsigned char power_level,
+ unsigned char antenna_max);
+ int (*set_regulatory_domain)(void *priv, unsigned int rd);
+ int (*set_country)(void *priv, const char *country);
+ int (*set_ieee80211d)(void *priv, int enabled);
+ int (*set_beacon)(const char *ifname, void *priv,
+ u8 *head, size_t head_len,
+ u8 *tail, size_t tail_len);
+
+ /* Configure internal bridge:
+ * 0 = disabled, i.e., client separation is enabled (no bridging of
+ * packets between associated STAs
+ * 1 = enabled, i.e., bridge packets between associated STAs (default)
+ */
+ int (*set_internal_bridge)(void *priv, int value);
+ int (*set_beacon_int)(void *priv, int value);
+ int (*set_dtim_period)(const char *ifname, void *priv, int value);
+ /* Configure broadcast SSID mode:
+ * 0 = include SSID in Beacon frames and reply to Probe Request frames
+ * that use broadcast SSID
+ * 1 = hide SSID from Beacon frames and ignore Probe Request frames for
+ * broadcast SSID
+ */
+ int (*set_broadcast_ssid)(void *priv, int value);
+ int (*set_cts_protect)(void *priv, int value);
+ int (*set_key_tx_rx_threshold)(void *priv, int value);
+ int (*set_preamble)(void *priv, int value);
+ int (*set_short_slot_time)(void *priv, int value);
+ int (*set_tx_queue_params)(void *priv, int queue, int aifs, int cw_min,
+ int cw_max, int burst_time);
+ int (*bss_add)(void *priv, const char *ifname, const u8 *bssid);
+ int (*bss_remove)(void *priv, const char *ifname);
+ int (*valid_bss_mask)(void *priv, const u8 *addr, const u8 *mask);
+ int (*passive_scan)(void *priv, int now, int our_mode_only,
+ int interval, int _listen, int *channel,
+ int *last_rx);
+ struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv,
+ u16 *num_modes,
+ u16 *flags);
+ int (*if_add)(const char *iface, void *priv,
+ enum hostapd_driver_if_type type, char *ifname,
+ const u8 *addr);
+ int (*if_update)(void *priv, enum hostapd_driver_if_type type,
+ char *ifname, const u8 *addr);
+ int (*if_remove)(void *priv, enum hostapd_driver_if_type type,
+ const char *ifname, const u8 *addr);
+ int (*set_sta_vlan)(void *priv, const u8 *addr, const char *ifname,
+ int vlan_id);
+ /**
+ * commit - Optional commit changes handler
+ * @priv: driver private data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This optional handler function can be registered if the driver
+ * interface implementation needs to commit changes (e.g., by setting
+ * network interface up) at the end of initial configuration. If set,
+ * this handler will be called after initial setup has been completed.
+ */
+ int (*commit)(void *priv);
};
static inline int
@@ -94,11 +178,12 @@ hostapd_wireless_event_deinit(struct hostapd_data *hapd)
}
static inline int
-hostapd_set_ieee8021x(struct hostapd_data *hapd, int enabled)
+hostapd_set_ieee8021x(const char *ifname, struct hostapd_data *hapd,
+ int enabled)
{
if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL)
return 0;
- return hapd->driver->set_ieee8021x(hapd->driver, enabled);
+ return hapd->driver->set_ieee8021x(ifname, hapd->driver, enabled);
}
static inline int
@@ -106,25 +191,38 @@ hostapd_set_privacy(struct hostapd_data *hapd, int enabled)
{
if (hapd->driver == NULL || hapd->driver->set_privacy == NULL)
return 0;
- return hapd->driver->set_privacy(hapd->driver, enabled);
+ return hapd->driver->set_privacy(hapd->conf->iface, hapd->driver,
+ enabled);
}
static inline int
-hostapd_set_encryption(struct hostapd_data *hapd, const char *alg, u8 *addr,
- int idx, u8 *key, size_t key_len)
+hostapd_set_encryption(const char *ifname, struct hostapd_data *hapd,
+ const char *alg, const u8 *addr, int idx,
+ u8 *key, size_t key_len, int txkey)
{
if (hapd->driver == NULL || hapd->driver->set_encryption == NULL)
return 0;
- return hapd->driver->set_encryption(hapd->driver, alg, addr, idx, key,
- key_len);
+ return hapd->driver->set_encryption(ifname, hapd->driver, alg, addr,
+ idx, key, key_len, txkey);
}
static inline int
-hostapd_get_seqnum(struct hostapd_data *hapd, u8 *addr, int idx, u8 *seq)
+hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
+ const u8 *addr, int idx, u8 *seq)
{
if (hapd->driver == NULL || hapd->driver->get_seqnum == NULL)
return 0;
- return hapd->driver->get_seqnum(hapd->driver, addr, idx, seq);
+ return hapd->driver->get_seqnum(ifname, hapd->driver, addr, idx, seq);
+}
+
+static inline int
+hostapd_get_seqnum_igtk(const char *ifname, struct hostapd_data *hapd,
+ const u8 *addr, int idx, u8 *seq)
+{
+ if (hapd->driver == NULL || hapd->driver->get_seqnum_igtk == NULL)
+ return -1;
+ return hapd->driver->get_seqnum_igtk(ifname, hapd->driver, addr, idx,
+ seq);
}
static inline int
@@ -141,12 +239,13 @@ hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
{
if (hapd->driver == NULL || hapd->driver->set_generic_elem == NULL)
return 0;
- return hapd->driver->set_generic_elem(hapd->driver, elem, elem_len);
+ return hapd->driver->set_generic_elem(hapd->conf->iface, hapd->driver,
+ elem, elem_len);
}
static inline int
hostapd_read_sta_data(struct hostapd_data *hapd,
- struct hostap_sta_driver_data *data, u8 *addr)
+ struct hostap_sta_driver_data *data, const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL)
return -1;
@@ -154,26 +253,17 @@ hostapd_read_sta_data(struct hostapd_data *hapd,
}
static inline int
-hostapd_send_eapol(struct hostapd_data *hapd, u8 *addr, u8 *data,
+hostapd_send_eapol(struct hostapd_data *hapd, const u8 *addr, const u8 *data,
size_t data_len, int encrypt)
{
if (hapd->driver == NULL || hapd->driver->send_eapol == NULL)
return 0;
return hapd->driver->send_eapol(hapd->driver, addr, data, data_len,
- encrypt);
-}
-
-static inline int
-hostapd_set_sta_authorized(struct hostapd_data *hapd, u8 *addr, int authorized)
-{
- if (hapd->driver == NULL || hapd->driver->set_sta_authorized == NULL)
- return 0;
- return hapd->driver->set_sta_authorized(hapd->driver, addr,
- authorized);
+ encrypt, hapd->own_addr);
}
static inline int
-hostapd_sta_deauth(struct hostapd_data *hapd, u8 *addr, int reason)
+hostapd_sta_deauth(struct hostapd_data *hapd, const u8 *addr, int reason)
{
if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
return 0;
@@ -181,7 +271,7 @@ hostapd_sta_deauth(struct hostapd_data *hapd, u8 *addr, int reason)
}
static inline int
-hostapd_sta_disassoc(struct hostapd_data *hapd, u8 *addr, int reason)
+hostapd_sta_disassoc(struct hostapd_data *hapd, const u8 *addr, int reason)
{
if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
return 0;
@@ -189,7 +279,7 @@ hostapd_sta_disassoc(struct hostapd_data *hapd, u8 *addr, int reason)
}
static inline int
-hostapd_sta_remove(struct hostapd_data *hapd, u8 *addr)
+hostapd_sta_remove(struct hostapd_data *hapd, const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
return 0;
@@ -201,15 +291,17 @@ hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len)
{
if (hapd->driver == NULL || hapd->driver->get_ssid == NULL)
return 0;
- return hapd->driver->get_ssid(hapd->driver, buf, len);
+ return hapd->driver->get_ssid(hapd->conf->iface, hapd->driver, buf,
+ len);
}
static inline int
-hostapd_set_ssid(struct hostapd_data *hapd, u8 *buf, size_t len)
+hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
{
if (hapd->driver == NULL || hapd->driver->set_ssid == NULL)
return 0;
- return hapd->driver->set_ssid(hapd->driver, buf, len);
+ return hapd->driver->set_ssid(hapd->conf->iface, hapd->driver, buf,
+ len);
}
static inline int
@@ -222,14 +314,14 @@ hostapd_send_mgmt_frame(struct hostapd_data *hapd, const void *msg, size_t len,
}
static inline int
-hostapd_set_assoc_ap(struct hostapd_data *hapd, u8 *addr)
+hostapd_set_assoc_ap(struct hostapd_data *hapd, const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->set_assoc_ap == NULL)
return 0;
return hapd->driver->set_assoc_ap(hapd->driver, addr);
}
-static inline int
+static inline int
hostapd_set_countermeasures(struct hostapd_data *hapd, int enabled)
{
if (hapd->driver == NULL || hapd->driver->set_countermeasures == NULL)
@@ -238,34 +330,327 @@ hostapd_set_countermeasures(struct hostapd_data *hapd, int enabled)
}
static inline int
-hostapd_sta_add(struct hostapd_data *hapd, u8 *addr, u16 aid, u16 capability,
- u8 tx_supp_rates)
+hostapd_sta_add(const char *ifname, struct hostapd_data *hapd, const u8 *addr,
+ u16 aid, u16 capability, u8 *supp_rates, size_t supp_rates_len,
+ int flags)
{
if (hapd->driver == NULL || hapd->driver->sta_add == NULL)
return 0;
- return hapd->driver->sta_add(hapd->driver, addr, aid, capability,
- tx_supp_rates);
+ return hapd->driver->sta_add(ifname, hapd->driver, addr, aid,
+ capability, supp_rates, supp_rates_len,
+ flags);
}
static inline int
-hostapd_get_inact_sec(struct hostapd_data *hapd, u8 *addr)
+hostapd_get_inact_sec(struct hostapd_data *hapd, const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL)
return 0;
return hapd->driver->get_inact_sec(hapd->driver, addr);
}
+static inline int
+hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq)
+{
+ if (hapd->driver == NULL || hapd->driver->set_freq == NULL)
+ return 0;
+ return hapd->driver->set_freq(hapd->driver, mode, freq);
+}
+
+static inline int
+hostapd_set_rts(struct hostapd_data *hapd, int rts)
+{
+ if (hapd->driver == NULL || hapd->driver->set_rts == NULL)
+ return 0;
+ return hapd->driver->set_rts(hapd->driver, rts);
+}
+
+static inline int
+hostapd_get_rts(struct hostapd_data *hapd, int *rts)
+{
+ if (hapd->driver == NULL || hapd->driver->get_rts == NULL)
+ return 0;
+ return hapd->driver->get_rts(hapd->driver, rts);
+}
+
+static inline int
+hostapd_set_frag(struct hostapd_data *hapd, int frag)
+{
+ if (hapd->driver == NULL || hapd->driver->set_frag == NULL)
+ return 0;
+ return hapd->driver->set_frag(hapd->driver, frag);
+}
+
+static inline int
+hostapd_get_frag(struct hostapd_data *hapd, int *frag)
+{
+ if (hapd->driver == NULL || hapd->driver->get_frag == NULL)
+ return 0;
+ return hapd->driver->get_frag(hapd->driver, frag);
+}
+
+static inline int
+hostapd_set_retry(struct hostapd_data *hapd, int short_retry, int long_retry)
+{
+ if (hapd->driver == NULL || hapd->driver->set_retry == NULL)
+ return 0;
+ return hapd->driver->set_retry(hapd->driver, short_retry, long_retry);
+}
+
+static inline int
+hostapd_get_retry(struct hostapd_data *hapd, int *short_retry, int *long_retry)
+{
+ if (hapd->driver == NULL || hapd->driver->get_retry == NULL)
+ return 0;
+ return hapd->driver->get_retry(hapd->driver, short_retry, long_retry);
+}
+
+static inline int
+hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
+ int flags_or, int flags_and)
+{
+ if (hapd->driver == NULL || hapd->driver->sta_set_flags == NULL)
+ return 0;
+ return hapd->driver->sta_set_flags(hapd->driver, addr, flags_or,
+ flags_and);
+}
+
+static inline int
+hostapd_set_rate_sets(struct hostapd_data *hapd, int *supp_rates,
+ int *basic_rates, int mode)
+{
+ if (hapd->driver == NULL || hapd->driver->set_rate_sets == NULL)
+ return 0;
+ return hapd->driver->set_rate_sets(hapd->driver, supp_rates,
+ basic_rates, mode);
+}
+
+static inline int
+hostapd_set_channel_flag(struct hostapd_data *hapd, int mode, int chan,
+ int flag, unsigned char power_level,
+ unsigned char antenna_max)
+{
+ if (hapd->driver == NULL || hapd->driver->set_channel_flag == NULL)
+ return 0;
+ return hapd->driver->set_channel_flag(hapd->driver, mode, chan, flag,
+ power_level, antenna_max);
+}
+
+static inline int
+hostapd_set_regulatory_domain(struct hostapd_data *hapd, unsigned int rd)
+{
+ if (hapd->driver == NULL ||
+ hapd->driver->set_regulatory_domain == NULL)
+ return 0;
+ return hapd->driver->set_regulatory_domain(hapd->driver, rd);
+}
+
+static inline int
+hostapd_set_country(struct hostapd_data *hapd, const char *country)
+{
+ if (hapd->driver == NULL ||
+ hapd->driver->set_country == NULL)
+ return 0;
+ return hapd->driver->set_country(hapd->driver, country);
+}
+
+static inline int
+hostapd_set_ieee80211d(struct hostapd_data *hapd, int enabled)
+{
+ if (hapd->driver == NULL ||
+ hapd->driver->set_ieee80211d == NULL)
+ return 0;
+ return hapd->driver->set_ieee80211d(hapd->driver, enabled);
+}
void driver_register(const char *name, const struct driver_ops *ops);
void driver_unregister(const char *name);
const struct driver_ops *driver_lookup(const char *name);
static inline int
-hostapd_sta_clear_stats(struct hostapd_data *hapd, u8 *addr)
+hostapd_sta_clear_stats(struct hostapd_data *hapd, const u8 *addr)
{
if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL)
return 0;
return hapd->driver->sta_clear_stats(hapd->driver, addr);
}
+static inline int
+hostapd_set_beacon(const char *ifname, struct hostapd_data *hapd,
+ u8 *head, size_t head_len,
+ u8 *tail, size_t tail_len)
+{
+ if (hapd->driver == NULL || hapd->driver->set_beacon == NULL)
+ return 0;
+ return hapd->driver->set_beacon(ifname, hapd->driver, head, head_len,
+ tail, tail_len);
+}
+
+static inline int
+hostapd_set_internal_bridge(struct hostapd_data *hapd, int value)
+{
+ if (hapd->driver == NULL || hapd->driver->set_internal_bridge == NULL)
+ return 0;
+ return hapd->driver->set_internal_bridge(hapd->driver, value);
+}
+
+static inline int
+hostapd_set_beacon_int(struct hostapd_data *hapd, int value)
+{
+ if (hapd->driver == NULL || hapd->driver->set_beacon_int == NULL)
+ return 0;
+ return hapd->driver->set_beacon_int(hapd->driver, value);
+}
+
+static inline int
+hostapd_set_dtim_period(struct hostapd_data *hapd, int value)
+{
+ if (hapd->driver == NULL || hapd->driver->set_dtim_period == NULL)
+ return 0;
+ return hapd->driver->set_dtim_period(hapd->conf->iface, hapd->driver,
+ value);
+}
+
+static inline int
+hostapd_set_broadcast_ssid(struct hostapd_data *hapd, int value)
+{
+ if (hapd->driver == NULL || hapd->driver->set_broadcast_ssid == NULL)
+ return 0;
+ return hapd->driver->set_broadcast_ssid(hapd->driver, value);
+}
+
+static inline int
+hostapd_set_cts_protect(struct hostapd_data *hapd, int value)
+{
+ if (hapd->driver == NULL || hapd->driver->set_cts_protect == NULL)
+ return 0;
+ return hapd->driver->set_cts_protect(hapd->driver, value);
+}
+
+static inline int
+hostapd_set_key_tx_rx_threshold(struct hostapd_data *hapd, int value)
+{
+ if (hapd->driver == NULL ||
+ hapd->driver->set_key_tx_rx_threshold == NULL)
+ return 0;
+ return hapd->driver->set_key_tx_rx_threshold(hapd->driver, value);
+}
+
+static inline int
+hostapd_set_preamble(struct hostapd_data *hapd, int value)
+{
+ if (hapd->driver == NULL || hapd->driver->set_preamble == NULL)
+ return 0;
+ return hapd->driver->set_preamble(hapd->driver, value);
+}
+
+static inline int
+hostapd_set_short_slot_time(struct hostapd_data *hapd, int value)
+{
+ if (hapd->driver == NULL || hapd->driver->set_short_slot_time == NULL)
+ return 0;
+ return hapd->driver->set_short_slot_time(hapd->driver, value);
+}
+
+static inline int
+hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
+ int cw_min, int cw_max, int burst_time)
+{
+ if (hapd->driver == NULL || hapd->driver->set_tx_queue_params == NULL)
+ return 0;
+ return hapd->driver->set_tx_queue_params(hapd->driver, queue, aifs,
+ cw_min, cw_max, burst_time);
+}
+
+static inline int
+hostapd_bss_add(struct hostapd_data *hapd, const char *ifname, const u8 *bssid)
+{
+ if (hapd->driver == NULL || hapd->driver->bss_add == NULL)
+ return 0;
+ return hapd->driver->bss_add(hapd->driver, ifname, bssid);
+}
+
+static inline int
+hostapd_bss_remove(struct hostapd_data *hapd, const char *ifname)
+{
+ if (hapd->driver == NULL || hapd->driver->bss_remove == NULL)
+ return 0;
+ return hapd->driver->bss_remove(hapd->driver, ifname);
+}
+
+static inline int
+hostapd_valid_bss_mask(struct hostapd_data *hapd, const u8 *addr,
+ const u8 *mask)
+{
+ if (hapd->driver == NULL || hapd->driver->valid_bss_mask == NULL)
+ return 1;
+ return hapd->driver->valid_bss_mask(hapd->driver, addr, mask);
+}
+
+static inline int
+hostapd_if_add(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
+ char *ifname, const u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->driver->if_add == NULL)
+ return -1;
+ return hapd->driver->if_add(hapd->conf->iface, hapd->driver, type,
+ ifname, addr);
+}
+
+static inline int
+hostapd_if_update(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
+ char *ifname, const u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->driver->if_update == NULL)
+ return -1;
+ return hapd->driver->if_update(hapd->driver, type, ifname, addr);
+}
+
+static inline int
+hostapd_if_remove(struct hostapd_data *hapd, enum hostapd_driver_if_type type,
+ char *ifname, const u8 *addr)
+{
+ if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
+ return -1;
+ return hapd->driver->if_remove(hapd->driver, type, ifname, addr);
+}
+
+static inline int
+hostapd_passive_scan(struct hostapd_data *hapd, int now, int our_mode_only,
+ int interval, int _listen, int *channel,
+ int *last_rx)
+{
+ if (hapd->driver == NULL || hapd->driver->passive_scan == NULL)
+ return -1;
+ return hapd->driver->passive_scan(hapd->driver, now, our_mode_only,
+ interval, _listen, channel, last_rx);
+}
+
+static inline struct hostapd_hw_modes *
+hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
+ u16 *flags)
+{
+ if (hapd->driver == NULL || hapd->driver->get_hw_feature_data == NULL)
+ return NULL;
+ return hapd->driver->get_hw_feature_data(hapd->driver, num_modes,
+ flags);
+}
+
+static inline int
+hostapd_set_sta_vlan(const char *ifname, struct hostapd_data *hapd,
+ const u8 *addr, int vlan_id)
+{
+ if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL)
+ return 0;
+ return hapd->driver->set_sta_vlan(hapd->driver, addr, ifname, vlan_id);
+}
+
+static inline int
+hostapd_driver_commit(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL || hapd->driver->commit == NULL)
+ return 0;
+ return hapd->driver->commit(hapd->driver);
+}
+
#endif /* DRIVER_H */
diff --git a/contrib/hostapd/driver_test.c b/contrib/hostapd/driver_test.c
index 6af9af256262..d0b90d1c9e5f 100644
--- a/contrib/hostapd/driver_test.c
+++ b/contrib/hostapd/driver_test.c
@@ -1,7 +1,6 @@
/*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / Driver interface for development testing
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * hostapd / Driver interface for development testing
+ * 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
@@ -13,18 +12,10 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
+#include "includes.h"
#include <sys/ioctl.h>
-#include <netinet/in.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/socket.h>
#include <sys/un.h>
-#include <sys/uio.h>
+#include <dirent.h>
#include "hostapd.h"
#include "driver.h"
@@ -37,7 +28,8 @@
#include "accounting.h"
#include "radius.h"
#include "l2_packet.h"
-#include "hostap_common.h"
+#include "ieee802_11.h"
+#include "hw_features.h"
struct test_client_socket {
@@ -45,6 +37,18 @@ struct test_client_socket {
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 ssid[32];
+ size_t ssid_len;
+ int privacy;
};
struct test_driver_data {
@@ -52,13 +56,40 @@ struct test_driver_data {
struct hostapd_data *hapd;
struct test_client_socket *cli;
int test_socket;
- u8 *ie;
- size_t ielen;
+ struct test_driver_bss *bss;
+ char *socket_dir;
+ char *own_socket_path;
};
static const struct driver_ops test_driver_ops;
+static void test_driver_free_bss(struct test_driver_bss *bss)
+{
+ free(bss->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)
@@ -67,7 +98,8 @@ test_driver_get_cli(struct test_driver_data *drv, struct sockaddr_un *from,
while (cli) {
if (cli->unlen == fromlen &&
- strncmp(cli->un.sun_path, from->sun_path, fromlen) == 0)
+ strncmp(cli->un.sun_path, from->sun_path,
+ fromlen - sizeof(cli->un.sun_family)) == 0)
return cli;
cli = cli->next;
}
@@ -76,8 +108,9 @@ test_driver_get_cli(struct test_driver_data *drv, struct sockaddr_un *from,
}
-static int test_driver_send_eapol(void *priv, u8 *addr, u8 *data,
- size_t data_len, int encrypt)
+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;
@@ -95,18 +128,21 @@ static int test_driver_send_eapol(void *priv, u8 *addr, u8 *data,
cli = cli->next;
}
- if (!cli)
+ 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, drv->hapd->own_addr, ETH_ALEN);
+ memcpy(eth.h_source, own_addr, ETH_ALEN);
eth.h_proto = htons(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 = data;
+ io[2].iov_base = (u8 *) data;
io[2].iov_len = data_len;
memset(&msg, 0, sizeof(msg));
@@ -118,42 +154,168 @@ static int test_driver_send_eapol(void *priv, u8 *addr, u8 *data,
}
+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=%d "
+ "socket_dir=%p)",
+ __func__, drv->test_socket, 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 buf[512], *pos, *end;
- int i;
-
- pos = buf;
- end = buf + sizeof(buf);
+ int ret;
+ struct test_driver_bss *bss;
wpa_printf(MSG_DEBUG, "test_driver: SCAN");
- /* reply: SCANRESP BSSID SSID IEs */
- pos += snprintf(pos, end - pos, "SCANRESP " MACSTR " ",
- MAC2STR(drv->hapd->own_addr));
- for (i = 0; i < drv->hapd->conf->ssid_len; i++) {
- pos += snprintf(pos, end - pos, "%02x",
- drv->hapd->conf->ssid[i]);
+ 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);
+
+ 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);
}
- pos += snprintf(pos, end - pos, " ");
- for (i = 0; i < drv->ielen; i++) {
- pos += snprintf(pos, end - pos, "%02x",
- drv->ie[i]);
+}
+
+
+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;
}
- sendto(drv->test_socket, buf, pos - buf, 0,
- (struct sockaddr *) from, fromlen);
+ 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, const u8 *addr,
+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 = drv->hapd;
+ 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");
@@ -172,30 +334,26 @@ static int test_driver_new_sta(struct test_driver_data *drv, const u8 *addr,
printf("test_driver: no IE from STA\n");
return -1;
}
- res = wpa_validate_wpa_ie(hapd, sta, ie, ielen,
- ie[0] == WLAN_EID_RSN ?
- HOSTAPD_WPA_VERSION_WPA2 :
- HOSTAPD_WPA_VERSION_WPA);
+ 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);
if (res != WPA_IE_OK) {
printf("WPA/RSN information element rejected? "
"(res %u)\n", res);
return -1;
}
- free(sta->wpa_ie);
- sta->wpa_ie = malloc(ielen);
- if (sta->wpa_ie == NULL)
- return -1;
- memcpy(sta->wpa_ie, ie, ielen);
- sta->wpa_ie_len = ielen;
- } else {
- free(sta->wpa_ie);
- sta->wpa_ie = NULL;
- sta->wpa_ie_len = 0;
}
new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
- sta->flags |= WLAN_STA_ASSOC;
- wpa_sm_event(hapd, sta, WPA_ASSOC);
+ 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);
@@ -210,17 +368,17 @@ static void test_driver_assoc(struct test_driver_data *drv,
char *data)
{
struct test_client_socket *cli;
- u8 ie[256];
- size_t ielen;
+ 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 = malloc(sizeof(*cli));
+ cli = wpa_zalloc(sizeof(*cli));
if (cli == NULL)
return;
- memset(cli, 0, sizeof(*cli));
if (hwaddr_aton(data, cli->addr)) {
printf("test_socket: Invalid MAC address '%s' in ASSOC\n",
data);
@@ -233,7 +391,14 @@ static void test_driver_assoc(struct test_driver_data *drv,
pos2 = strchr(pos, ' ');
ielen = 0;
if (pos2) {
- /* TODO: verify SSID */
+ 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;
@@ -243,19 +408,33 @@ static void test_driver_assoc(struct test_driver_data *drv,
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",
- cli->un.sun_path, cli->unlen);
+ (const u8 *) cli->un.sun_path,
+ cli->unlen - sizeof(cli->un.sun_family));
snprintf(cmd, sizeof(cmd), "ASSOCRESP " MACSTR " 0",
- MAC2STR(drv->hapd->own_addr));
+ MAC2STR(bss->bssid));
sendto(drv->test_socket, cmd, strlen(cmd), 0,
(struct sockaddr *) from, fromlen);
- if (test_driver_new_sta(drv, cli->addr, ie, ielen) < 0) {
+ if (test_driver_new_sta(drv, bss, cli->addr, ie, ielen) < 0) {
wpa_printf(MSG_DEBUG, "test_driver: failed to add new STA");
}
}
@@ -277,10 +456,10 @@ static void test_driver_disassoc(struct test_driver_data *drv,
sta = ap_get_sta(drv->hapd, cli->addr);
if (sta != NULL) {
sta->flags &= ~WLAN_STA_ASSOC;
- wpa_sm_event(drv->hapd, sta, WPA_DISASSOC);
+ wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
sta->acct_terminate_cause =
RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
- ieee802_1x_set_port_enabled(drv->hapd, sta, 0);
+ ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
ap_free_sta(drv->hapd, sta);
}
}
@@ -292,20 +471,64 @@ static void test_driver_eapol(struct test_driver_data *drv,
{
struct test_client_socket *cli;
if (datalen > 14) {
+ u8 *proto = data + 2 * ETH_ALEN;
/* Skip Ethernet header */
+ wpa_printf(MSG_DEBUG, "test_driver: dst=" MACSTR " src="
+ MACSTR " proto=%04x",
+ MAC2STR(data), MAC2STR(data + ETH_ALEN),
+ (proto[0] << 8) | proto[1]);
data += 14;
datalen -= 14;
}
cli = test_driver_get_cli(drv, from, fromlen);
- if (cli)
- ieee802_1x_receive(drv->hapd, cli->addr, data, datalen);
- else {
+ 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_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 = wpa_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;
@@ -331,7 +554,10 @@ static void test_driver_receive_unix(int sock, void *eloop_ctx, void *sock_ctx)
} 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, buf + 6, res - 6);
+ test_driver_eapol(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);
@@ -339,25 +565,40 @@ static void test_driver_receive_unix(int sock, void *eloop_ctx, void *sock_ctx)
}
-static int test_driver_set_generic_elem(void *priv,
+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;
- free(drv->ie);
- drv->ie = malloc(elem_len);
- if (drv->ie) {
- memcpy(drv->ie, elem, elem_len);
- drv->ielen = elem_len;
- return 0;
- } else {
- drv->ielen = 0;
- return -1;
+ for (bss = drv->bss; bss; bss = bss->next) {
+ if (strcmp(bss->ifname, ifname) != 0)
+ continue;
+
+ free(bss->ie);
+
+ if (elem == NULL) {
+ bss->ie = NULL;
+ bss->ielen = 0;
+ return 0;
+ }
+
+ bss->ie = malloc(elem_len);
+ if (bss->ie) {
+ memcpy(bss->ie, elem, elem_len);
+ bss->ielen = elem_len;
+ return 0;
+ } else {
+ bss->ielen = 0;
+ return -1;
+ }
}
+
+ return -1;
}
-static int test_driver_sta_deauth(void *priv, u8 *addr, int reason)
+static int test_driver_sta_deauth(void *priv, const u8 *addr, int reason)
{
struct test_driver_data *drv = priv;
struct test_client_socket *cli;
@@ -380,7 +621,7 @@ static int test_driver_sta_deauth(void *priv, u8 *addr, int reason)
}
-static int test_driver_sta_disassoc(void *priv, u8 *addr, int reason)
+static int test_driver_sta_disassoc(void *priv, const u8 *addr, int reason)
{
struct test_driver_data *drv = priv;
struct test_client_socket *cli;
@@ -403,51 +644,346 @@ static int test_driver_sta_disassoc(void *priv, u8 *addr, int reason)
}
+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 = wpa_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 = wpa_zalloc(sizeof(struct hostapd_channel_data));
+ modes[0].rates = wpa_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 = HOSTAPD_CHAN_W_SCAN |
+ HOSTAPD_CHAN_W_ACTIVE_SCAN;
+ 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 = wpa_zalloc(sizeof(struct hostapd_channel_data));
+ modes[1].rates = wpa_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 = HOSTAPD_CHAN_W_SCAN |
+ HOSTAPD_CHAN_W_ACTIVE_SCAN;
+ 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 = wpa_zalloc(sizeof(struct hostapd_channel_data));
+ modes[2].rates = wpa_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 = HOSTAPD_CHAN_W_SCAN |
+ HOSTAPD_CHAN_W_ACTIVE_SCAN;
+ 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 = wpa_zalloc(sizeof(*bss));
+ if (bss == NULL)
+ return -1;
+
+ strncpy(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)
+{
+ 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",
+ __func__, ifname, MAC2STR(addr), aid, capability, flags);
+ 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 int test_driver_init(struct hostapd_data *hapd)
{
struct test_driver_data *drv;
struct sockaddr_un addr;
- drv = malloc(sizeof(struct test_driver_data));
+ drv = wpa_zalloc(sizeof(struct test_driver_data));
if (drv == NULL) {
printf("Could not allocate memory for test driver data\n");
return -1;
}
+ drv->bss = wpa_zalloc(sizeof(*drv->bss));
+ if (drv->bss == NULL) {
+ printf("Could not allocate memory for test driver BSS data\n");
+ free(drv);
+ return -1;
+ }
- memset(drv, 0, sizeof(*drv));
drv->ops = test_driver_ops;
drv->hapd = hapd;
/* Generate a MAC address to help testing with multiple APs */
hapd->own_addr[0] = 0x02; /* locally administered */
- sha1_prf(hapd->conf->iface, strlen(hapd->conf->iface),
+ sha1_prf((const u8 *) hapd->conf->iface, strlen(hapd->conf->iface),
"hostapd test bssid generation",
- hapd->conf->ssid, hapd->conf->ssid_len,
+ (const u8 *) hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len,
hapd->own_addr + 1, ETH_ALEN - 1);
+ strncpy(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.sun_path)) {
printf("Too long test_socket path\n");
- free(drv);
+ test_driver_free_priv(drv);
return -1;
}
+ 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 {
+ drv->own_socket_path = strdup(hapd->conf->test_socket);
+ }
+ if (drv->own_socket_path == NULL) {
+ test_driver_free_priv(drv);
+ return -1;
+ }
+
drv->test_socket = socket(PF_UNIX, SOCK_DGRAM, 0);
if (drv->test_socket < 0) {
perror("socket(PF_UNIX)");
- free(drv);
+ test_driver_free_priv(drv);
return -1;
}
memset(&addr, 0, sizeof(addr));
addr.sun_family = AF_UNIX;
- strncpy(addr.sun_path, hapd->conf->test_socket,
+ strncpy(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(hapd->conf->test_socket);
- free(drv);
+ unlink(drv->own_socket_path);
+ test_driver_free_priv(drv);
return -1;
}
eloop_register_read_sock(drv->test_socket,
@@ -475,13 +1011,18 @@ static void test_driver_deinit(void *priv)
if (drv->test_socket >= 0) {
eloop_unregister_read_sock(drv->test_socket);
close(drv->test_socket);
- unlink(drv->hapd->conf->test_socket);
+ unlink(drv->own_socket_path);
}
drv->hapd->driver = NULL;
- free(drv->ie);
- free(drv);
+ /* 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);
}
@@ -490,9 +1031,22 @@ static const struct driver_ops test_driver_ops = {
.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,
};
diff --git a/contrib/hostapd/driver_wired.c b/contrib/hostapd/driver_wired.c
index 6ef6b19f53ff..950668183f93 100644
--- a/contrib/hostapd/driver_wired.c
+++ b/contrib/hostapd/driver_wired.c
@@ -1,7 +1,6 @@
/*
- * Host AP (software wireless LAN access point) user space daemon for
- * Host AP kernel driver / Kernel driver communication
- * Copyright (c) 2002-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * hostapd / Kernel driver communication for wired (Ethernet) drivers
+ * Copyright (c) 2002-2005, 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
@@ -14,16 +13,8 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <errno.h>
+#include "includes.h"
#include <sys/ioctl.h>
-#include <netinet/in.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/socket.h>
#ifdef USE_KERNEL_HEADERS
#include <asm/types.h>
@@ -105,7 +96,8 @@ static void wired_possible_new_sta(struct hostapd_data *hapd, u8 *addr)
}
-static void handle_data(struct hostapd_data *hapd, char *buf, size_t len)
+static void handle_data(struct hostapd_data *hapd, unsigned char *buf,
+ size_t len)
{
struct ieee8023_hdr *hdr;
u8 *pos, *sa;
@@ -306,8 +298,9 @@ static int wired_init_sockets(struct wired_driver_data *drv)
}
-static int wired_send_eapol(void *priv, u8 *addr,
- u8 *data, size_t data_len, int encrypt)
+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;
@@ -317,17 +310,16 @@ static int wired_send_eapol(void *priv, u8 *addr,
int res;
len = sizeof(*hdr) + data_len;
- hdr = malloc(len);
+ hdr = wpa_zalloc(len);
if (hdr == NULL) {
printf("malloc() failed for wired_send_eapol(len=%lu)\n",
(unsigned long) len);
return -1;
}
- memset(hdr, 0, len);
memcpy(hdr->dest, drv->use_pae_group_addr ? pae_group_addr : addr,
ETH_ALEN);
- memcpy(hdr->src, drv->hapd->own_addr, ETH_ALEN);
+ memcpy(hdr->src, own_addr, ETH_ALEN);
hdr->ethertype = htons(ETH_P_PAE);
pos = (u8 *) (hdr + 1);
@@ -350,19 +342,20 @@ static int wired_driver_init(struct hostapd_data *hapd)
{
struct wired_driver_data *drv;
- drv = malloc(sizeof(struct wired_driver_data));
+ drv = wpa_zalloc(sizeof(struct wired_driver_data));
if (drv == NULL) {
printf("Could not allocate memory for wired driver data\n");
return -1;
}
- memset(drv, 0, sizeof(*drv));
drv->ops = wired_driver_ops;
drv->hapd = hapd;
drv->use_pae_group_addr = hapd->conf->use_pae_group_addr;
- if (wired_init_sockets(drv))
+ if (wired_init_sockets(drv)) {
+ free(drv);
return -1;
+ }
hapd->driver = &drv->ops;
return 0;
diff --git a/contrib/hostapd/eap.c b/contrib/hostapd/eap.c
index a20147e79e78..da250f04c783 100644
--- a/contrib/hostapd/eap.c
+++ b/contrib/hostapd/eap.c
@@ -1,6 +1,6 @@
/*
- * hostapd / EAP Standalone Authenticator state machine
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * hostapd / EAP Standalone Authenticator state machine (RFC 4137)
+ * 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
@@ -12,103 +12,22 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <netinet/in.h>
-#include <string.h>
-#include <sys/socket.h>
+#include "includes.h"
#include "hostapd.h"
-#include "eloop.h"
#include "sta_info.h"
#include "eap_i.h"
+#include "state_machine.h"
-#define EAP_MAX_AUTH_ROUNDS 50
+#define STATE_MACHINE_DATA struct eap_sm
+#define STATE_MACHINE_DEBUG_PREFIX "EAP"
-extern const struct eap_method eap_method_identity;
-#ifdef EAP_MD5
-extern const struct eap_method eap_method_md5;
-#endif /* EAP_MD5 */
-#ifdef EAP_TLS
-extern const struct eap_method eap_method_tls;
-#endif /* EAP_TLS */
-#ifdef EAP_MSCHAPv2
-extern const struct eap_method eap_method_mschapv2;
-#endif /* EAP_MSCHAPv2 */
-#ifdef EAP_PEAP
-extern const struct eap_method eap_method_peap;
-#endif /* EAP_PEAP */
-#ifdef EAP_TLV
-extern const struct eap_method eap_method_tlv;
-#endif /* EAP_TLV */
-#ifdef EAP_GTC
-extern const struct eap_method eap_method_gtc;
-#endif /* EAP_GTC */
-#ifdef EAP_TTLS
-extern const struct eap_method eap_method_ttls;
-#endif /* EAP_TTLS */
-#ifdef EAP_SIM
-extern const struct eap_method eap_method_sim;
-#endif /* EAP_SIM */
-#ifdef EAP_PAX
-extern const struct eap_method eap_method_pax;
-#endif /* EAP_PAX */
-#ifdef EAP_PSK
-extern const struct eap_method eap_method_psk;
-#endif /* EAP_PSK */
-
-static const struct eap_method *eap_methods[] =
-{
- &eap_method_identity,
-#ifdef EAP_MD5
- &eap_method_md5,
-#endif /* EAP_MD5 */
-#ifdef EAP_TLS
- &eap_method_tls,
-#endif /* EAP_TLS */
-#ifdef EAP_MSCHAPv2
- &eap_method_mschapv2,
-#endif /* EAP_MSCHAPv2 */
-#ifdef EAP_PEAP
- &eap_method_peap,
-#endif /* EAP_PEAP */
-#ifdef EAP_TTLS
- &eap_method_ttls,
-#endif /* EAP_TTLS */
-#ifdef EAP_TLV
- &eap_method_tlv,
-#endif /* EAP_TLV */
-#ifdef EAP_GTC
- &eap_method_gtc,
-#endif /* EAP_GTC */
-#ifdef EAP_SIM
- &eap_method_sim,
-#endif /* EAP_SIM */
-#ifdef EAP_PAX
- &eap_method_pax,
-#endif /* EAP_PAX */
-#ifdef EAP_PSK
- &eap_method_psk,
-#endif /* EAP_PSK */
-};
-#define NUM_EAP_METHODS (sizeof(eap_methods) / sizeof(eap_methods[0]))
-
-
-const struct eap_method * eap_sm_get_eap_methods(int method)
-{
- int i;
- for (i = 0; i < NUM_EAP_METHODS; i++) {
- if (eap_methods[i]->method == method)
- return eap_methods[i];
- }
- return NULL;
-}
+#define EAP_MAX_AUTH_ROUNDS 50
static void eap_user_free(struct eap_user *user);
-/* EAP state machines are described in draft-ietf-eap-statemachine-05.txt */
+/* EAP state machines are described in RFC 4137 */
static int eap_sm_calculateTimeout(struct eap_sm *sm, int retransCount,
int eapSRTT, int eapRTTVAR,
@@ -118,34 +37,11 @@ static u8 * eap_sm_buildSuccess(struct eap_sm *sm, int id, size_t *len);
static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len);
static int eap_sm_nextId(struct eap_sm *sm, int id);
static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len);
-static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm);
+static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor);
static int eap_sm_Policy_getDecision(struct eap_sm *sm);
static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method);
-/* Definitions for clarifying state machine implementation */
-#define SM_STATE(machine, state) \
-static void sm_ ## machine ## _ ## state ## _Enter(struct eap_sm *sm, \
- int global)
-
-#define SM_ENTRY(machine, state) \
-if (!global || sm->machine ## _state != machine ## _ ## state) { \
- sm->changed = TRUE; \
- wpa_printf(MSG_DEBUG, "EAP: " #machine " entering state " #state); \
-} \
-sm->machine ## _state = machine ## _ ## state;
-
-#define SM_ENTER(machine, state) \
-sm_ ## machine ## _ ## state ## _Enter(sm, 0)
-#define SM_ENTER_GLOBAL(machine, state) \
-sm_ ## machine ## _ ## state ## _Enter(sm, 1)
-
-#define SM_STEP(machine) \
-static void sm_ ## machine ## _Step(struct eap_sm *sm)
-
-#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
-
-
static Boolean eapol_get_bool(struct eap_sm *sm, enum eapol_bool_var var)
{
return sm->eapol_cb->get_bool(sm->eapol_ctx, var);
@@ -177,6 +73,19 @@ static void eapol_set_eapKeyData(struct eap_sm *sm,
}
+/**
+ * eap_user_get - Fetch user information from the database
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @identity: Identity (User-Name) of the user
+ * @identity_len: Length of identity in bytes
+ * @phase2: 0 = EAP phase1 user, 1 = EAP phase2 (tunneled) user
+ * Returns: 0 on success, or -1 on failure
+ *
+ * This function is used to fetch user information for EAP. The user will be
+ * selected based on the specified identity. sm->user and
+ * sm->user_eap_method_index are updated for the new user when a matching user
+ * is found. sm->user can be used to get user information (e.g., password).
+ */
int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
int phase2)
{
@@ -189,10 +98,9 @@ int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
eap_user_free(sm->user);
sm->user = NULL;
- user = malloc(sizeof(*user));
+ user = wpa_zalloc(sizeof(*user));
if (user == NULL)
return -1;
- memset(user, 0, sizeof(*user));
if (sm->eapol_cb->get_eap_user(sm->eapol_ctx, identity,
identity_len, phase2, user) != 0) {
@@ -228,9 +136,11 @@ SM_STATE(EAP, INITIALIZE)
/* eapKeyAvailable = FALSE */
eapol_set_bool(sm, EAPOL_eapRestart, FALSE);
- /* This is not defined in draft-ietf-eap-statemachine-05.txt, but
- * method state needs to be reseted here so that it does not remain in
- * success state when re-authentication starts. */
+ /*
+ * This is not defined in RFC 4137, but method state needs to be
+ * reseted here so that it does not remain in success state when
+ * re-authentication starts.
+ */
if (sm->m && sm->eap_method_priv) {
sm->m->reset(sm, sm->eap_method_priv);
sm->eap_method_priv = NULL;
@@ -247,6 +157,7 @@ SM_STATE(EAP, INITIALIZE)
}
}
sm->num_rounds = 0;
+ sm->method_pending = METHOD_PENDING_NONE;
}
@@ -260,7 +171,8 @@ SM_STATE(EAP, PICK_UP_METHOD)
sm->m->reset(sm, sm->eap_method_priv);
sm->eap_method_priv = NULL;
}
- sm->m = eap_sm_get_eap_methods(sm->currentMethod);
+ sm->m = eap_sm_get_eap_methods(EAP_VENDOR_IETF,
+ sm->currentMethod);
if (sm->m && sm->m->initPickUp) {
sm->eap_method_priv = sm->m->initPickUp(sm);
if (sm->eap_method_priv == NULL) {
@@ -397,14 +309,21 @@ SM_STATE(EAP, METHOD_RESPONSE)
SM_STATE(EAP, PROPOSE_METHOD)
{
+ int vendor;
+ EapType type;
+
SM_ENTRY(EAP, PROPOSE_METHOD);
- sm->currentMethod = eap_sm_Policy_getNextMethod(sm);
+ type = eap_sm_Policy_getNextMethod(sm, &vendor);
+ if (vendor == EAP_VENDOR_IETF)
+ sm->currentMethod = type;
+ else
+ sm->currentMethod = EAP_TYPE_EXPANDED;
if (sm->m && sm->eap_method_priv) {
sm->m->reset(sm, sm->eap_method_priv);
sm->eap_method_priv = NULL;
}
- sm->m = eap_sm_get_eap_methods(sm->currentMethod);
+ sm->m = eap_sm_get_eap_methods(vendor, type);
if (sm->m) {
sm->eap_method_priv = sm->m->init(sm);
if (sm->eap_method_priv == NULL) {
@@ -534,7 +453,9 @@ SM_STEP(EAP)
SM_ENTER(EAP, SELECT_ACTION);
else if (sm->rxResp &&
(sm->respMethod == EAP_TYPE_NAK ||
- sm->respMethod == EAP_TYPE_EXPANDED_NAK))
+ (sm->respMethod == EAP_TYPE_EXPANDED &&
+ sm->respVendor == EAP_VENDOR_IETF &&
+ sm->respVendorMethod == EAP_TYPE_NAK)))
SM_ENTER(EAP, NAK);
else
SM_ENTER(EAP, PICK_UP_METHOD);
@@ -568,14 +489,25 @@ SM_STEP(EAP)
case EAP_RECEIVED:
if (sm->rxResp && (sm->respId == sm->currentId) &&
(sm->respMethod == EAP_TYPE_NAK ||
- sm->respMethod == EAP_TYPE_EXPANDED_NAK)
+ (sm->respMethod == EAP_TYPE_EXPANDED &&
+ sm->respVendor == EAP_VENDOR_IETF &&
+ sm->respVendorMethod == EAP_TYPE_NAK))
&& (sm->methodState == METHOD_PROPOSED))
SM_ENTER(EAP, NAK);
else if (sm->rxResp && (sm->respId == sm->currentId) &&
- (sm->respMethod == sm->currentMethod))
+ ((sm->respMethod == sm->currentMethod) ||
+ (sm->respMethod == EAP_TYPE_EXPANDED &&
+ sm->respVendor == EAP_VENDOR_IETF &&
+ sm->respVendorMethod == sm->currentMethod)))
SM_ENTER(EAP, INTEGRITY_CHECK);
- else
+ else {
+ wpa_printf(MSG_DEBUG, "EAP: RECEIVED->DISCARD: "
+ "rxResp=%d respId=%d currentId=%d "
+ "respMethod=%d currentMethod=%d",
+ sm->rxResp, sm->respId, sm->currentId,
+ sm->respMethod, sm->currentMethod);
SM_ENTER(EAP, DISCARD);
+ }
break;
case EAP_DISCARD:
SM_ENTER(EAP, IDLE);
@@ -593,13 +525,48 @@ SM_STEP(EAP)
SM_ENTER(EAP, SEND_REQUEST);
break;
case EAP_METHOD_RESPONSE:
+ /*
+ * Note: Mechanism to allow EAP methods to wait while going
+ * through pending processing is an extension to RFC 4137
+ * which only defines the transits to SELECT_ACTION and
+ * METHOD_REQUEST from this METHOD_RESPONSE state.
+ */
if (sm->methodState == METHOD_END)
SM_ENTER(EAP, SELECT_ACTION);
- else
+ else if (sm->method_pending == METHOD_PENDING_WAIT) {
+ wpa_printf(MSG_DEBUG, "EAP: Method has pending "
+ "processing - wait before proceeding to "
+ "METHOD_REQUEST state");
+ } else if (sm->method_pending == METHOD_PENDING_CONT) {
+ wpa_printf(MSG_DEBUG, "EAP: Method has completed "
+ "pending processing - reprocess pending "
+ "EAP message");
+ sm->method_pending = METHOD_PENDING_NONE;
+ SM_ENTER(EAP, METHOD_RESPONSE);
+ } else
SM_ENTER(EAP, METHOD_REQUEST);
break;
case EAP_PROPOSE_METHOD:
- SM_ENTER(EAP, METHOD_REQUEST);
+ /*
+ * Note: Mechanism to allow EAP methods to wait while going
+ * through pending processing is an extension to RFC 4137
+ * which only defines the transit to METHOD_REQUEST from this
+ * PROPOSE_METHOD state.
+ */
+ if (sm->method_pending == METHOD_PENDING_WAIT) {
+ wpa_printf(MSG_DEBUG, "EAP: Method has pending "
+ "processing - wait before proceeding to "
+ "METHOD_REQUEST state");
+ if (sm->user_eap_method_index > 0)
+ sm->user_eap_method_index--;
+ } else if (sm->method_pending == METHOD_PENDING_CONT) {
+ wpa_printf(MSG_DEBUG, "EAP: Method has completed "
+ "pending processing - reprocess pending "
+ "EAP message");
+ sm->method_pending = METHOD_PENDING_NONE;
+ SM_ENTER(EAP, PROPOSE_METHOD);
+ } else
+ SM_ENTER(EAP, METHOD_REQUEST);
break;
case EAP_NAK:
SM_ENTER(EAP, SELECT_ACTION);
@@ -642,6 +609,8 @@ static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len)
sm->rxResp = FALSE;
sm->respId = -1;
sm->respMethod = EAP_TYPE_NONE;
+ sm->respVendor = EAP_VENDOR_IETF;
+ sm->respVendorMethod = EAP_TYPE_NONE;
if (resp == NULL || len < sizeof(*hdr))
return;
@@ -660,11 +629,26 @@ static void eap_sm_parseEapResp(struct eap_sm *sm, u8 *resp, size_t len)
if (hdr->code == EAP_CODE_RESPONSE)
sm->rxResp = TRUE;
- if (len > sizeof(*hdr))
- sm->respMethod = *((u8 *) (hdr + 1));
+ if (plen > sizeof(*hdr)) {
+ u8 *pos = (u8 *) (hdr + 1);
+ sm->respMethod = *pos++;
+ if (sm->respMethod == EAP_TYPE_EXPANDED) {
+ if (plen < sizeof(*hdr) + 8) {
+ wpa_printf(MSG_DEBUG, "EAP: Ignored truncated "
+ "expanded EAP-Packet (plen=%lu)",
+ (unsigned long) plen);
+ return;
+ }
+ sm->respVendor = WPA_GET_BE24(pos);
+ pos += 3;
+ sm->respVendorMethod = WPA_GET_BE32(pos);
+ }
+ }
wpa_printf(MSG_DEBUG, "EAP: parseEapResp: rxResp=%d respId=%d "
- "respMethod=%d", sm->rxResp, sm->respId, sm->respMethod);
+ "respMethod=%u respVendor=%u respVendorMethod=%u",
+ sm->rxResp, sm->respId, sm->respMethod, sm->respVendor,
+ sm->respVendorMethod);
}
@@ -705,7 +689,7 @@ static u8 * eap_sm_buildFailure(struct eap_sm *sm, int id, size_t *len)
static int eap_sm_nextId(struct eap_sm *sm, int id)
{
if (id < 0) {
- /* RFC 3748 Ch 4.1: recommended to initalize Identifier with a
+ /* RFC 3748 Ch 4.1: recommended to initialize Identifier with a
* random number */
id = rand() & 0xff;
if (id != sm->lastId)
@@ -715,22 +699,40 @@ static int eap_sm_nextId(struct eap_sm *sm, int id)
}
+/**
+ * eap_sm_process_nak - Process EAP-Response/Nak
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @nak_list: Nak list (allowed methods) from the supplicant
+ * @len: Length of nak_list in bytes
+ *
+ * This function is called when EAP-Response/Nak is received from the
+ * supplicant. This can happen for both phase 1 and phase 2 authentications.
+ */
void eap_sm_process_nak(struct eap_sm *sm, u8 *nak_list, size_t len)
{
- int i, j;
+ int i;
+ size_t j;
+
+ if (sm->user == NULL)
+ return;
wpa_printf(MSG_MSGDUMP, "EAP: processing NAK (current EAP method "
"index %d)", sm->user_eap_method_index);
wpa_hexdump(MSG_MSGDUMP, "EAP: configured methods",
- sm->user->methods, EAP_MAX_METHODS);
+ (u8 *) sm->user->methods,
+ EAP_MAX_METHODS * sizeof(sm->user->methods[0]));
wpa_hexdump(MSG_MSGDUMP, "EAP: list of methods supported by the peer",
nak_list, len);
i = sm->user_eap_method_index;
- while (i < EAP_MAX_METHODS && sm->user->methods[i] != EAP_TYPE_NONE) {
+ while (i < EAP_MAX_METHODS &&
+ (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
+ sm->user->methods[i].method != EAP_TYPE_NONE)) {
+ if (sm->user->methods[i].vendor != EAP_VENDOR_IETF)
+ goto not_found;
for (j = 0; j < len; j++) {
- if (nak_list[j] == sm->user->methods[i]) {
+ if (nak_list[j] == sm->user->methods[i].method) {
break;
}
}
@@ -741,14 +743,19 @@ void eap_sm_process_nak(struct eap_sm *sm, u8 *nak_list, size_t len)
continue;
}
+ not_found:
/* not found - remove from the list */
memmove(&sm->user->methods[i], &sm->user->methods[i + 1],
- EAP_MAX_METHODS - i - 1);
- sm->user->methods[EAP_MAX_METHODS - 1] = EAP_TYPE_NONE;
+ (EAP_MAX_METHODS - i - 1) *
+ sizeof(sm->user->methods[0]));
+ sm->user->methods[EAP_MAX_METHODS - 1].vendor =
+ EAP_VENDOR_IETF;
+ sm->user->methods[EAP_MAX_METHODS - 1].method = EAP_TYPE_NONE;
}
wpa_hexdump(MSG_MSGDUMP, "EAP: new list of configured methods",
- sm->user->methods, EAP_MAX_METHODS);
+ (u8 *) sm->user->methods, EAP_MAX_METHODS *
+ sizeof(sm->user->methods[0]));
}
@@ -768,9 +775,10 @@ static void eap_sm_Policy_update(struct eap_sm *sm, u8 *nak_list, size_t len)
}
-static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm)
+static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm, int *vendor)
{
EapType next;
+ int idx = sm->user_eap_method_index;
/* In theory, there should be no problems with starting
* re-authentication with something else than EAP-Request/Identity and
@@ -780,16 +788,21 @@ static EapType eap_sm_Policy_getNextMethod(struct eap_sm *sm)
* Re-auth sets currentId == -1, so that can be used here to select
* whether Identity needs to be requested again. */
if (sm->identity == NULL || sm->currentId == -1) {
+ *vendor = EAP_VENDOR_IETF;
next = EAP_TYPE_IDENTITY;
sm->update_user = TRUE;
- } else if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
- sm->user->methods[sm->user_eap_method_index] !=
- EAP_TYPE_NONE) {
- next = sm->user->methods[sm->user_eap_method_index++];
+ } else if (sm->user && idx < EAP_MAX_METHODS &&
+ (sm->user->methods[idx].vendor != EAP_VENDOR_IETF ||
+ sm->user->methods[idx].method != EAP_TYPE_NONE)) {
+ *vendor = sm->user->methods[idx].vendor;
+ next = sm->user->methods[idx].method;
+ sm->user_eap_method_index++;
} else {
+ *vendor = EAP_VENDOR_IETF;
next = EAP_TYPE_NONE;
}
- wpa_printf(MSG_DEBUG, "EAP: getNextMethod: type %d", next);
+ wpa_printf(MSG_DEBUG, "EAP: getNextMethod: vendor %d type %d",
+ *vendor, next);
return next;
}
@@ -822,7 +835,10 @@ static int eap_sm_Policy_getDecision(struct eap_sm *sm)
}
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
- sm->user->methods[sm->user_eap_method_index] != EAP_TYPE_NONE) {
+ (sm->user->methods[sm->user_eap_method_index].vendor !=
+ EAP_VENDOR_IETF ||
+ sm->user->methods[sm->user_eap_method_index].method !=
+ EAP_TYPE_NONE)) {
wpa_printf(MSG_DEBUG, "EAP: getDecision: another method "
"available -> CONTINUE");
return DECISION_CONTINUE;
@@ -846,6 +862,15 @@ static Boolean eap_sm_Policy_doPickUp(struct eap_sm *sm, EapType method)
}
+/**
+ * eap_sm_step - Step EAP state machine
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * Returns: 1 if EAP state was changed or 0 if not
+ *
+ * This function advances EAP state machine to a new state to match with the
+ * current variables. This should be called whenever variables used by the EAP
+ * state machine have changed.
+ */
int eap_sm_step(struct eap_sm *sm)
{
int res = 0;
@@ -859,17 +884,14 @@ int eap_sm_step(struct eap_sm *sm)
}
-u8 eap_get_type(const char *name)
-{
- int i;
- for (i = 0; i < NUM_EAP_METHODS; i++) {
- if (strcmp(eap_methods[i]->name, name) == 0)
- return eap_methods[i]->method;
- }
- return EAP_TYPE_NONE;
-}
-
-
+/**
+ * eap_set_eapRespData - Set EAP response (eapRespData)
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @eapRespData: EAP-Response payload from the supplicant
+ * @eapRespDataLen: Length of eapRespData in bytes
+ *
+ * This function is called when an EAP-Response is received from a supplicant.
+ */
void eap_set_eapRespData(struct eap_sm *sm, const u8 *eapRespData,
size_t eapRespDataLen)
{
@@ -896,21 +918,29 @@ static void eap_user_free(struct eap_user *user)
}
+/**
+ * eap_sm_init - Allocate and initialize EAP state machine
+ * @eapol_ctx: Context data to be used with eapol_cb calls
+ * @eapol_cb: Pointer to EAPOL callback functions
+ * @conf: EAP configuration
+ * Returns: Pointer to the allocated EAP state machine or %NULL on failure
+ *
+ * This function allocates and initializes an EAP state machine.
+ */
struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
- struct eap_config *eap_conf)
+ struct eap_config *conf)
{
struct eap_sm *sm;
- sm = malloc(sizeof(*sm));
+ sm = wpa_zalloc(sizeof(*sm));
if (sm == NULL)
return NULL;
- memset(sm, 0, sizeof(*sm));
sm->eapol_ctx = eapol_ctx;
sm->eapol_cb = eapol_cb;
sm->MaxRetrans = 10;
- sm->ssl_ctx = eap_conf->ssl_ctx;
- sm->eap_sim_db_priv = eap_conf->eap_sim_db_priv;
- sm->backend_auth = eap_conf->backend_auth;
+ sm->ssl_ctx = conf->ssl_ctx;
+ sm->eap_sim_db_priv = conf->eap_sim_db_priv;
+ sm->backend_auth = conf->backend_auth;
wpa_printf(MSG_DEBUG, "EAP: State machine created");
@@ -918,6 +948,13 @@ struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
}
+/**
+ * eap_sm_deinit - Deinitialize and free an EAP state machine
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * This function deinitializes EAP state machine and frees all allocated
+ * resources.
+ */
void eap_sm_deinit(struct eap_sm *sm)
{
if (sm == NULL)
@@ -935,6 +972,13 @@ void eap_sm_deinit(struct eap_sm *sm)
}
+/**
+ * eap_sm_notify_cached - Notify EAP state machine of cached PMK
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * This function is called when PMKSA caching is used to skip EAP
+ * authentication.
+ */
void eap_sm_notify_cached(struct eap_sm *sm)
{
if (sm == NULL)
@@ -942,3 +986,153 @@ void eap_sm_notify_cached(struct eap_sm *sm)
sm->EAP_state = EAP_SUCCESS;
}
+
+
+/**
+ * eap_sm_pending_cb - EAP state machine callback for a pending EAP request
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ *
+ * This function is called when data for a pending EAP-Request is received.
+ */
+void eap_sm_pending_cb(struct eap_sm *sm)
+{
+ if (sm == NULL)
+ return;
+ wpa_printf(MSG_DEBUG, "EAP: Callback for pending request received");
+ if (sm->method_pending == METHOD_PENDING_WAIT)
+ sm->method_pending = METHOD_PENDING_CONT;
+}
+
+
+/**
+ * eap_sm_method_pending - Query whether EAP method is waiting for pending data
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * Returns: 1 if method is waiting for pending data or 0 if not
+ */
+int eap_sm_method_pending(struct eap_sm *sm)
+{
+ if (sm == NULL)
+ return 0;
+ return sm->method_pending == METHOD_PENDING_WAIT;
+}
+
+
+/**
+ * eap_hdr_validate - Validate EAP header
+ * @vendor: Expected EAP Vendor-Id (0 = IETF)
+ * @eap_type: Expected EAP type number
+ * @msg: EAP frame (starting with EAP header)
+ * @msglen: Length of msg
+ * @plen: Pointer to variable to contain the returned payload length
+ * Returns: Pointer to EAP payload (after type field), or %NULL on failure
+ *
+ * This is a helper function for EAP method implementations. This is usually
+ * called in the beginning of struct eap_method::process() function to verify
+ * that the received EAP request packet has a valid header. This function is
+ * able to process both legacy and expanded EAP headers and in most cases, the
+ * caller can just use the returned payload pointer (into *plen) for processing
+ * the payload regardless of whether the packet used the expanded EAP header or
+ * not.
+ */
+const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+ const u8 *msg, size_t msglen, size_t *plen)
+{
+ const struct eap_hdr *hdr;
+ const u8 *pos;
+ size_t len;
+
+ hdr = (const struct eap_hdr *) msg;
+
+ if (msglen < sizeof(*hdr)) {
+ wpa_printf(MSG_INFO, "EAP: Too short EAP frame");
+ return NULL;
+ }
+
+ len = be_to_host16(hdr->length);
+ if (len < sizeof(*hdr) + 1 || len > msglen) {
+ wpa_printf(MSG_INFO, "EAP: Invalid EAP length");
+ return NULL;
+ }
+
+ pos = (const u8 *) (hdr + 1);
+
+ if (*pos == EAP_TYPE_EXPANDED) {
+ int exp_vendor;
+ u32 exp_type;
+ if (len < sizeof(*hdr) + 8) {
+ wpa_printf(MSG_INFO, "EAP: Invalid expanded EAP "
+ "length");
+ return NULL;
+ }
+ pos++;
+ exp_vendor = WPA_GET_BE24(pos);
+ pos += 3;
+ exp_type = WPA_GET_BE32(pos);
+ pos += 4;
+ if (exp_vendor != vendor || exp_type != (u32) eap_type) {
+ wpa_printf(MSG_INFO, "EAP: Invalid expanded frame "
+ "type");
+ return NULL;
+ }
+
+ *plen = len - sizeof(*hdr) - 8;
+ return pos;
+ } else {
+ if (vendor != EAP_VENDOR_IETF || *pos != eap_type) {
+ wpa_printf(MSG_INFO, "EAP: Invalid frame type");
+ return NULL;
+ }
+ *plen = len - sizeof(*hdr) - 1;
+ return pos + 1;
+ }
+}
+
+
+/**
+ * eap_msg_alloc - Allocate a buffer for an EAP message
+ * @vendor: Vendor-Id (0 = IETF)
+ * @type: EAP type
+ * @len: Buffer for returning message length
+ * @payload_len: Payload length in bytes (data after Type)
+ * @code: Message Code (EAP_CODE_*)
+ * @identifier: Identifier
+ * @payload: Pointer to payload pointer that will be set to point to the
+ * beginning of the payload or %NULL if payload pointer is not needed
+ * Returns: Pointer to the allocated message buffer or %NULL on error
+ *
+ * This function can be used to allocate a buffer for an EAP message and fill
+ * in the EAP header. This function is automatically using expanded EAP header
+ * if the selected Vendor-Id is not IETF. In other words, most EAP methods do
+ * not need to separately select which header type to use when using this
+ * function to allocate the message buffers.
+ */
+struct eap_hdr * eap_msg_alloc(int vendor, EapType type, size_t *len,
+ size_t payload_len, u8 code, u8 identifier,
+ u8 **payload)
+{
+ struct eap_hdr *hdr;
+ u8 *pos;
+
+ *len = sizeof(struct eap_hdr) + (vendor == EAP_VENDOR_IETF ? 1 : 8) +
+ payload_len;
+ hdr = malloc(*len);
+ if (hdr) {
+ hdr->code = code;
+ hdr->identifier = identifier;
+ hdr->length = host_to_be16(*len);
+ pos = (u8 *) (hdr + 1);
+ if (vendor == EAP_VENDOR_IETF) {
+ *pos++ = type;
+ } else {
+ *pos++ = EAP_TYPE_EXPANDED;
+ WPA_PUT_BE24(pos, vendor);
+ pos += 3;
+ WPA_PUT_BE32(pos, type);
+ pos += 4;
+ }
+ if (payload)
+ *payload = pos;
+ }
+
+ return hdr;
+}
diff --git a/contrib/hostapd/eap.h b/contrib/hostapd/eap.h
index c5c62eb57c72..137719189dfa 100644
--- a/contrib/hostapd/eap.h
+++ b/contrib/hostapd/eap.h
@@ -1,16 +1,36 @@
+/*
+ * hostapd / EAP Standalone Authenticator state machine (RFC 4137)
+ * 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.
+ */
+
#ifndef EAP_H
#define EAP_H
#include "defs.h"
#include "eap_defs.h"
+#include "eap_methods.h"
struct eap_sm;
#define EAP_MAX_METHODS 8
struct eap_user {
- u8 methods[EAP_MAX_METHODS];
+ struct {
+ int vendor;
+ u32 method;
+ } methods[EAP_MAX_METHODS];
u8 *password;
size_t password_len;
+ int password_hash; /* whether password is hashed with
+ * nt_password_hash() */
int phase2;
int force_version;
};
@@ -46,10 +66,11 @@ struct eap_sm * eap_sm_init(void *eapol_ctx, struct eapol_callbacks *eapol_cb,
struct eap_config *eap_conf);
void eap_sm_deinit(struct eap_sm *sm);
int eap_sm_step(struct eap_sm *sm);
-u8 eap_get_type(const char *name);
void eap_set_eapRespData(struct eap_sm *sm, const u8 *eapRespData,
size_t eapRespDataLen);
void eap_sm_notify_cached(struct eap_sm *sm);
+void eap_sm_pending_cb(struct eap_sm *sm);
+int eap_sm_method_pending(struct eap_sm *sm);
#else /* EAP_SERVER */
@@ -69,10 +90,6 @@ static inline int eap_sm_step(struct eap_sm *sm)
return 0;
}
-static inline u8 eap_get_type(const char *name)
-{
- return EAP_TYPE_NONE;
-}
static inline void eap_set_eapRespData(struct eap_sm *sm,
const u8 *eapRespData,
@@ -84,6 +101,15 @@ static inline void eap_sm_notify_cached(struct eap_sm *sm)
{
}
+static inline void eap_sm_pending_cb(struct eap_sm *sm)
+{
+}
+
+static inline int eap_sm_method_pending(struct eap_sm *sm)
+{
+ return 0;
+}
+
#endif /* EAP_SERVER */
#endif /* EAP_H */
diff --git a/contrib/hostapd/eap_aka.c b/contrib/hostapd/eap_aka.c
new file mode 100644
index 000000000000..5db4cd3f7260
--- /dev/null
+++ b/contrib/hostapd/eap_aka.c
@@ -0,0 +1,848 @@
+/*
+ * hostapd / EAP-AKA (RFC 4187)
+ * 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 "hostapd.h"
+#include "common.h"
+#include "crypto.h"
+#include "eap_i.h"
+#include "eap_sim_common.h"
+#include "eap_sim_db.h"
+
+
+struct eap_aka_data {
+ u8 mk[EAP_SIM_MK_LEN];
+ u8 nonce_s[EAP_SIM_NONCE_S_LEN];
+ u8 k_aut[EAP_SIM_K_AUT_LEN];
+ u8 k_encr[EAP_SIM_K_ENCR_LEN];
+ u8 msk[EAP_SIM_KEYING_DATA_LEN];
+ u8 emsk[EAP_EMSK_LEN];
+ u8 rand[EAP_AKA_RAND_LEN];
+ u8 autn[EAP_AKA_AUTN_LEN];
+ u8 ck[EAP_AKA_CK_LEN];
+ u8 ik[EAP_AKA_IK_LEN];
+ u8 res[EAP_AKA_RES_MAX_LEN];
+ size_t res_len;
+ enum {
+ IDENTITY, CHALLENGE, REAUTH, NOTIFICATION, SUCCESS, FAILURE
+ } state;
+ char *next_pseudonym;
+ char *next_reauth_id;
+ u16 counter;
+ struct eap_sim_reauth *reauth;
+ int auts_reported; /* whether the current AUTS has been reported to the
+ * eap_sim_db */
+ u16 notification;
+};
+
+
+static void eap_aka_determine_identity(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ int before_identity, int after_reauth);
+
+
+static const char * eap_aka_state_txt(int state)
+{
+ switch (state) {
+ case IDENTITY:
+ return "IDENTITY";
+ case CHALLENGE:
+ return "CHALLENGE";
+ case REAUTH:
+ return "REAUTH";
+ case SUCCESS:
+ return "SUCCESS";
+ case FAILURE:
+ return "FAILURE";
+ case NOTIFICATION:
+ return "NOTIFICATION";
+ default:
+ return "Unknown?!";
+ }
+}
+
+
+static void eap_aka_state(struct eap_aka_data *data, int state)
+{
+ wpa_printf(MSG_DEBUG, "EAP-AKA: %s -> %s",
+ eap_aka_state_txt(data->state),
+ eap_aka_state_txt(state));
+ data->state = state;
+}
+
+
+static void * eap_aka_init(struct eap_sm *sm)
+{
+ struct eap_aka_data *data;
+
+ if (sm->eap_sim_db_priv == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: eap_sim_db not configured");
+ return NULL;
+ }
+
+ data = wpa_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ data->state = IDENTITY;
+ eap_aka_determine_identity(sm, data, 1, 0);
+
+ return data;
+}
+
+
+static void eap_aka_reset(struct eap_sm *sm, void *priv)
+{
+ struct eap_aka_data *data = priv;
+ free(data->next_pseudonym);
+ free(data->next_reauth_id);
+ free(data);
+}
+
+
+static u8 * eap_aka_build_identity(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ int id, size_t *reqDataLen)
+{
+ struct eap_sim_msg *msg;
+
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Identity");
+ msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
+ EAP_AKA_SUBTYPE_IDENTITY);
+ if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
+ sm->identity_len)) {
+ wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
+ eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
+ }
+ return eap_sim_msg_finish(msg, reqDataLen, NULL, NULL, 0);
+}
+
+
+static int eap_aka_build_encr(struct eap_sm *sm, struct eap_aka_data *data,
+ struct eap_sim_msg *msg, u16 counter,
+ const u8 *nonce_s)
+{
+ free(data->next_pseudonym);
+ data->next_pseudonym =
+ eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 1);
+ free(data->next_reauth_id);
+ if (data->counter <= EAP_AKA_MAX_FAST_REAUTHS) {
+ data->next_reauth_id =
+ eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 1);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Max fast re-authentication "
+ "count exceeded - force full authentication");
+ data->next_reauth_id = NULL;
+ }
+
+ if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
+ counter == 0 && nonce_s == NULL)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, " AT_IV");
+ wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
+ eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
+
+ if (counter > 0) {
+ wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", counter);
+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
+ }
+
+ if (nonce_s) {
+ wpa_printf(MSG_DEBUG, " *AT_NONCE_S");
+ eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
+ EAP_SIM_NONCE_S_LEN);
+ }
+
+ if (data->next_pseudonym) {
+ wpa_printf(MSG_DEBUG, " *AT_NEXT_PSEUDONYM (%s)",
+ data->next_pseudonym);
+ eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
+ strlen(data->next_pseudonym),
+ (u8 *) data->next_pseudonym,
+ strlen(data->next_pseudonym));
+ }
+
+ if (data->next_reauth_id) {
+ wpa_printf(MSG_DEBUG, " *AT_NEXT_REAUTH_ID (%s)",
+ data->next_reauth_id);
+ eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
+ strlen(data->next_reauth_id),
+ (u8 *) data->next_reauth_id,
+ strlen(data->next_reauth_id));
+ }
+
+ if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Failed to encrypt "
+ "AT_ENCR_DATA");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+static u8 * eap_aka_build_challenge(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ int id, size_t *reqDataLen)
+{
+ struct eap_sim_msg *msg;
+
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Challenge");
+ msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
+ EAP_AKA_SUBTYPE_CHALLENGE);
+ wpa_printf(MSG_DEBUG, " AT_RAND");
+ eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, data->rand, EAP_AKA_RAND_LEN);
+ eap_sim_msg_add(msg, EAP_SIM_AT_AUTN, 0, data->autn, EAP_AKA_AUTN_LEN);
+
+ if (eap_aka_build_encr(sm, data, msg, 0, NULL)) {
+ eap_sim_msg_free(msg);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, " AT_MAC");
+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+ return eap_sim_msg_finish(msg, reqDataLen, data->k_aut, NULL, 0);
+}
+
+
+static u8 * eap_aka_build_reauth(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ int id, size_t *reqDataLen)
+{
+ struct eap_sim_msg *msg;
+
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Re-authentication");
+
+ if (hostapd_get_rand(data->nonce_s, EAP_SIM_NONCE_S_LEN))
+ return NULL;
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-AKA: NONCE_S",
+ data->nonce_s, EAP_SIM_NONCE_S_LEN);
+
+ eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
+ data->emsk);
+ eap_sim_derive_keys_reauth(data->counter, sm->identity,
+ sm->identity_len, data->nonce_s, data->mk,
+ data->msk, data->emsk);
+
+ msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
+ EAP_AKA_SUBTYPE_REAUTHENTICATION);
+
+ if (eap_aka_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
+ eap_sim_msg_free(msg);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, " AT_MAC");
+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+ return eap_sim_msg_finish(msg, reqDataLen, data->k_aut, NULL, 0);
+}
+
+
+static u8 * eap_aka_build_notification(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ int id, size_t *reqDataLen)
+{
+ struct eap_sim_msg *msg;
+
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Generating Notification");
+ msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_AKA,
+ EAP_AKA_SUBTYPE_NOTIFICATION);
+ wpa_printf(MSG_DEBUG, " AT_NOTIFICATION");
+ eap_sim_msg_add(msg, EAP_SIM_AT_NOTIFICATION, data->notification,
+ NULL, 0);
+ return eap_sim_msg_finish(msg, reqDataLen, NULL, NULL, 0);
+}
+
+
+static u8 * eap_aka_buildReq(struct eap_sm *sm, void *priv, int id,
+ size_t *reqDataLen)
+{
+ struct eap_aka_data *data = priv;
+
+ data->auts_reported = 0;
+ switch (data->state) {
+ case IDENTITY:
+ return eap_aka_build_identity(sm, data, id, reqDataLen);
+ case CHALLENGE:
+ return eap_aka_build_challenge(sm, data, id, reqDataLen);
+ case REAUTH:
+ return eap_aka_build_reauth(sm, data, id, reqDataLen);
+ case NOTIFICATION:
+ return eap_aka_build_notification(sm, data, id, reqDataLen);
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
+ "buildReq", data->state);
+ break;
+ }
+ return NULL;
+}
+
+
+static Boolean eap_aka_check(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_hdr *resp;
+ u8 *pos;
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ if (respDataLen < sizeof(*resp) + 4 || *pos != EAP_TYPE_AKA ||
+ (ntohs(resp->length)) > respDataLen) {
+ wpa_printf(MSG_INFO, "EAP-AKA: Invalid frame");
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static Boolean eap_aka_subtype_ok(struct eap_aka_data *data, u8 subtype)
+{
+ if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR ||
+ subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT)
+ return FALSE;
+
+ switch (data->state) {
+ case IDENTITY:
+ if (subtype != EAP_AKA_SUBTYPE_IDENTITY) {
+ wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
+ "subtype %d", subtype);
+ return TRUE;
+ }
+ break;
+ case CHALLENGE:
+ if (subtype != EAP_AKA_SUBTYPE_CHALLENGE &&
+ subtype != EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
+ wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
+ "subtype %d", subtype);
+ return TRUE;
+ }
+ break;
+ case REAUTH:
+ if (subtype != EAP_AKA_SUBTYPE_REAUTHENTICATION) {
+ wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
+ "subtype %d", subtype);
+ return TRUE;
+ }
+ break;
+ case NOTIFICATION:
+ if (subtype != EAP_AKA_SUBTYPE_NOTIFICATION) {
+ wpa_printf(MSG_INFO, "EAP-AKA: Unexpected response "
+ "subtype %d", subtype);
+ return TRUE;
+ }
+ break;
+ default:
+ wpa_printf(MSG_INFO, "EAP-AKA: Unexpected state (%d) for "
+ "processing a response", data->state);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static void eap_aka_determine_identity(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ int before_identity, int after_reauth)
+{
+ const u8 *identity;
+ size_t identity_len;
+ int res;
+
+ identity = NULL;
+ identity_len = 0;
+
+ if (after_reauth && data->reauth) {
+ identity = data->reauth->identity;
+ identity_len = data->reauth->identity_len;
+ } else if (sm->identity && sm->identity_len > 0 &&
+ sm->identity[0] == EAP_AKA_PERMANENT_PREFIX) {
+ identity = sm->identity;
+ identity_len = sm->identity_len;
+ } else {
+ identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
+ sm->identity,
+ sm->identity_len,
+ &identity_len);
+ if (identity == NULL) {
+ data->reauth = eap_sim_db_get_reauth_entry(
+ sm->eap_sim_db_priv, sm->identity,
+ sm->identity_len);
+ if (data->reauth) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Using fast "
+ "re-authentication");
+ identity = data->reauth->identity;
+ identity_len = data->reauth->identity_len;
+ data->counter = data->reauth->counter;
+ memcpy(data->mk, data->reauth->mk,
+ EAP_SIM_MK_LEN);
+ }
+ }
+ }
+
+ if (identity == NULL ||
+ eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
+ sm->identity_len) < 0) {
+ if (before_identity) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Permanent user name "
+ "not known - send AKA-Identity request");
+ eap_aka_state(data, IDENTITY);
+ return;
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown whether the "
+ "permanent user name is known; try to use "
+ "it");
+ /* eap_sim_db_get_aka_auth() will report failure, if
+ * this identity is not known. */
+ }
+ }
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity",
+ identity, identity_len);
+
+ if (!after_reauth && data->reauth) {
+ eap_aka_state(data, REAUTH);
+ return;
+ }
+
+ res = eap_sim_db_get_aka_auth(sm->eap_sim_db_priv, identity,
+ identity_len, data->rand, data->autn,
+ data->ik, data->ck, data->res,
+ &data->res_len, sm);
+ if (res == EAP_SIM_DB_PENDING) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
+ "not yet available - pending request");
+ sm->method_pending = METHOD_PENDING_WAIT;
+ return;
+ }
+
+ data->reauth = NULL;
+ data->counter = 0; /* reset re-auth counter since this is full auth */
+
+ if (res != 0) {
+ wpa_printf(MSG_INFO, "EAP-AKA: Failed to get AKA "
+ "authentication data for the peer");
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
+ return;
+ }
+ if (sm->method_pending == METHOD_PENDING_WAIT) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: AKA authentication data "
+ "available - abort pending wait");
+ sm->method_pending = METHOD_PENDING_NONE;
+ }
+
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-AKA: Identity for MK derivation",
+ sm->identity, sm->identity_len);
+
+ eap_aka_derive_mk(sm->identity, sm->identity_len, data->ik, data->ck,
+ data->mk);
+ eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
+ data->emsk);
+
+ eap_aka_state(data, CHALLENGE);
+}
+
+
+static void eap_aka_process_identity(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ u8 *respData, size_t respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Identity");
+
+ if (attr->mac || attr->iv || attr->encr_data) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Unexpected attribute "
+ "received in EAP-Response/AKA-Identity");
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
+ return;
+ }
+
+ if (attr->identity) {
+ free(sm->identity);
+ sm->identity = malloc(attr->identity_len);
+ if (sm->identity) {
+ memcpy(sm->identity, attr->identity,
+ attr->identity_len);
+ sm->identity_len = attr->identity_len;
+ }
+ }
+
+ eap_aka_determine_identity(sm, data, 0, 0);
+}
+
+
+static void eap_aka_process_challenge(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ u8 *respData, size_t respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ const u8 *identity;
+ size_t identity_len;
+
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Challenge");
+
+ if (attr->mac == NULL ||
+ eap_sim_verify_mac(data->k_aut, respData, respDataLen, attr->mac,
+ NULL, 0)) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message "
+ "did not include valid AT_MAC");
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
+ return;
+ }
+
+ if (attr->res == NULL || attr->res_len != data->res_len ||
+ memcmp(attr->res, data->res, data->res_len) != 0) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Challenge message did not "
+ "include valid AT_RES");
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Challenge response includes the "
+ "correct AT_MAC");
+ eap_aka_state(data, SUCCESS);
+
+ identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
+ sm->identity_len, &identity_len);
+ if (identity == NULL) {
+ identity = sm->identity;
+ identity_len = sm->identity_len;
+ }
+
+ if (data->next_pseudonym) {
+ eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
+ identity_len,
+ data->next_pseudonym);
+ data->next_pseudonym = NULL;
+ }
+ if (data->next_reauth_id) {
+ eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
+ identity_len,
+ data->next_reauth_id, data->counter + 1,
+ data->mk);
+ data->next_reauth_id = NULL;
+ }
+}
+
+
+static void eap_aka_process_sync_failure(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ u8 *respData, size_t respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Synchronization-Failure");
+
+ if (attr->auts == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Synchronization-Failure "
+ "message did not include valid AT_AUTS");
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
+ return;
+ }
+
+ /* Avoid re-reporting AUTS when processing pending EAP packet by
+ * maintaining a local flag stating whether this AUTS has already been
+ * reported. */
+ if (!data->auts_reported &&
+ eap_sim_db_resynchronize(sm->eap_sim_db_priv, sm->identity,
+ sm->identity_len, attr->auts,
+ data->rand)) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Resynchronization failed");
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
+ return;
+ }
+ data->auts_reported = 1;
+
+ /* Try again after resynchronization */
+ eap_aka_determine_identity(sm, data, 0, 0);
+}
+
+
+static void eap_aka_process_reauth(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ u8 *respData, size_t respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ struct eap_sim_attrs eattr;
+ u8 *decrypted = NULL;
+ const u8 *identity, *id2;
+ size_t identity_len, id2_len;
+
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Processing Reauthentication");
+
+ if (attr->mac == NULL ||
+ eap_sim_verify_mac(data->k_aut, respData, respDataLen, attr->mac,
+ data->nonce_s, EAP_SIM_NONCE_S_LEN)) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
+ "did not include valid AT_MAC");
+ goto fail;
+ }
+
+ if (attr->encr_data == NULL || attr->iv == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Reauthentication "
+ "message did not include encrypted data");
+ goto fail;
+ }
+
+ decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+ attr->encr_data_len, attr->iv, &eattr,
+ 0);
+ if (decrypted == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Failed to parse encrypted "
+ "data from reauthentication message");
+ goto fail;
+ }
+
+ if (eattr.counter != data->counter) {
+ wpa_printf(MSG_WARNING, "EAP-AKA: Re-authentication message "
+ "used incorrect counter %u, expected %u",
+ eattr.counter, data->counter);
+ goto fail;
+ }
+ free(decrypted);
+ decrypted = NULL;
+
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response includes "
+ "the correct AT_MAC");
+
+ if (eattr.counter_too_small) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Re-authentication response "
+ "included AT_COUNTER_TOO_SMALL - starting full "
+ "authentication");
+ eap_aka_determine_identity(sm, data, 0, 1);
+ return;
+ }
+
+ eap_aka_state(data, SUCCESS);
+
+ if (data->reauth) {
+ identity = data->reauth->identity;
+ identity_len = data->reauth->identity_len;
+ } else {
+ identity = sm->identity;
+ identity_len = sm->identity_len;
+ }
+
+ id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
+ identity_len, &id2_len);
+ if (id2) {
+ identity = id2;
+ identity_len = id2_len;
+ }
+
+ if (data->next_pseudonym) {
+ eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
+ identity_len, data->next_pseudonym);
+ data->next_pseudonym = NULL;
+ }
+ if (data->next_reauth_id) {
+ eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
+ identity_len, data->next_reauth_id,
+ data->counter + 1, data->mk);
+ data->next_reauth_id = NULL;
+ } else {
+ eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ data->reauth = NULL;
+ }
+
+ return;
+
+fail:
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
+ eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ data->reauth = NULL;
+ free(decrypted);
+}
+
+
+static void eap_aka_process_client_error(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ u8 *respData, size_t respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Client reported error %d",
+ attr->client_error_code);
+ eap_aka_state(data, FAILURE);
+}
+
+
+static void eap_aka_process_authentication_reject(
+ struct eap_sm *sm, struct eap_aka_data *data,
+ u8 *respData, size_t respDataLen, struct eap_sim_attrs *attr)
+{
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Client rejected authentication");
+ eap_aka_state(data, FAILURE);
+}
+
+
+static void eap_aka_process_notification(struct eap_sm *sm,
+ struct eap_aka_data *data,
+ u8 *respData, size_t respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Client replied to notification");
+ eap_aka_state(data, FAILURE);
+}
+
+
+static void eap_aka_process(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_aka_data *data = priv;
+ struct eap_hdr *resp;
+ u8 *pos, subtype;
+ size_t len;
+ struct eap_sim_attrs attr;
+
+ resp = (struct eap_hdr *) respData;
+ pos = (u8 *) (resp + 1);
+ subtype = pos[1];
+
+ if (eap_aka_subtype_ok(data, subtype)) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unrecognized or unexpected "
+ "EAP-AKA Subtype in EAP Response");
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
+ return;
+ }
+
+ len = be_to_host16(resp->length);
+ pos += 4;
+
+ if (eap_sim_parse_attr(pos, respData + len, &attr, 1, 0)) {
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Failed to parse attributes");
+ data->notification = EAP_SIM_GENERAL_FAILURE_BEFORE_AUTH;
+ eap_aka_state(data, NOTIFICATION);
+ return;
+ }
+
+ if (subtype == EAP_AKA_SUBTYPE_CLIENT_ERROR) {
+ eap_aka_process_client_error(sm, data, respData, len, &attr);
+ return;
+ }
+
+ if (subtype == EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT) {
+ eap_aka_process_authentication_reject(sm, data, respData, len,
+ &attr);
+ return;
+ }
+
+ switch (data->state) {
+ case IDENTITY:
+ eap_aka_process_identity(sm, data, respData, len, &attr);
+ break;
+ case CHALLENGE:
+ if (subtype == EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE) {
+ eap_aka_process_sync_failure(sm, data, respData, len,
+ &attr);
+ } else {
+ eap_aka_process_challenge(sm, data, respData, len,
+ &attr);
+ }
+ break;
+ case REAUTH:
+ eap_aka_process_reauth(sm, data, respData, len, &attr);
+ break;
+ case NOTIFICATION:
+ eap_aka_process_notification(sm, data, respData, len, &attr);
+ break;
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-AKA: Unknown state %d in "
+ "process", data->state);
+ break;
+ }
+}
+
+
+static Boolean eap_aka_isDone(struct eap_sm *sm, void *priv)
+{
+ struct eap_aka_data *data = priv;
+ return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_aka_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_aka_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = malloc(EAP_SIM_KEYING_DATA_LEN);
+ if (key == NULL)
+ return NULL;
+ memcpy(key, data->msk, EAP_SIM_KEYING_DATA_LEN);
+ *len = EAP_SIM_KEYING_DATA_LEN;
+ return key;
+}
+
+
+static u8 * eap_aka_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_aka_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+ memcpy(key, data->emsk, EAP_EMSK_LEN);
+ *len = EAP_EMSK_LEN;
+ return key;
+}
+
+
+static Boolean eap_aka_isSuccess(struct eap_sm *sm, void *priv)
+{
+ struct eap_aka_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+int eap_server_aka_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_AKA, "AKA");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_aka_init;
+ eap->reset = eap_aka_reset;
+ eap->buildReq = eap_aka_buildReq;
+ eap->check = eap_aka_check;
+ eap->process = eap_aka_process;
+ eap->isDone = eap_aka_isDone;
+ eap->getKey = eap_aka_getKey;
+ eap->isSuccess = eap_aka_isSuccess;
+ eap->get_emsk = eap_aka_get_emsk;
+
+ ret = eap_server_method_register(eap);
+ if (ret)
+ eap_server_method_free(eap);
+ return ret;
+}
diff --git a/contrib/hostapd/eap_defs.h b/contrib/hostapd/eap_defs.h
index 9cd44905153d..8ea923a8f9d0 100644
--- a/contrib/hostapd/eap_defs.h
+++ b/contrib/hostapd/eap_defs.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant/hostapd / Shared EAP definitions
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP server/peer: Shared EAP definitions
+ * 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
@@ -17,12 +17,20 @@
/* RFC 3748 - Extensible Authentication Protocol (EAP) */
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
struct eap_hdr {
u8 code;
u8 identifier;
u16 length; /* including code and identifier; network byte order */
/* followed by length-4 octets of data */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,
EAP_CODE_FAILURE = 4 };
@@ -40,17 +48,28 @@ typedef enum {
EAP_TYPE_GTC = 6, /* RFC 3748 */
EAP_TYPE_TLS = 13 /* RFC 2716 */,
EAP_TYPE_LEAP = 17 /* Cisco proprietary */,
- EAP_TYPE_SIM = 18 /* draft-haverinen-pppext-eap-sim-12.txt */,
+ EAP_TYPE_SIM = 18 /* RFC 4186 */,
EAP_TYPE_TTLS = 21 /* draft-ietf-pppext-eap-ttls-02.txt */,
- EAP_TYPE_AKA = 23 /* draft-arkko-pppext-eap-aka-12.txt */,
+ EAP_TYPE_AKA = 23 /* RFC 4187 */,
EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */,
EAP_TYPE_MSCHAPV2 = 26 /* draft-kamath-pppext-eap-mschapv2-00.txt */,
EAP_TYPE_TLV = 33 /* draft-josefsson-pppext-eap-tls-eap-07.txt */,
- EAP_TYPE_FAST = 43 /* draft-cam-winget-eap-fast-00.txt */,
- EAP_TYPE_PAX = 46, /* draft-clancy-eap-pax-04.txt */
- EAP_TYPE_EXPANDED_NAK = 254 /* RFC 3748 */,
- EAP_TYPE_PSK = 255 /* EXPERIMENTAL - type not yet allocated
- * draft-bersani-eap-psk-09 */
+ EAP_TYPE_FAST = 43 /* draft-cam-winget-eap-fast-05.txt */,
+ EAP_TYPE_PAX = 46 /* RFC 4746 */,
+ EAP_TYPE_PSK = 47 /* RFC 4764 */,
+ EAP_TYPE_SAKE = 48 /* RFC 4763 */,
+ EAP_TYPE_EXPANDED = 254 /* RFC 3748 */,
+ EAP_TYPE_GPSK = 255 /* EXPERIMENTAL - type not yet allocated
+ * draft-ietf-emu-eap-gpsk-01.txt */
} EapType;
+
+/* SMI Network Management Private Enterprise Code for vendor specific types */
+enum {
+ EAP_VENDOR_IETF = 0
+};
+
+#define EAP_MSK_LEN 64
+#define EAP_EMSK_LEN 64
+
#endif /* EAP_DEFS_H */
diff --git a/contrib/hostapd/eap_gpsk.c b/contrib/hostapd/eap_gpsk.c
new file mode 100644
index 000000000000..8ab70a1ac3f3
--- /dev/null
+++ b/contrib/hostapd/eap_gpsk.c
@@ -0,0 +1,646 @@
+/*
+ * hostapd / EAP-GPSK (draft-ietf-emu-eap-gpsk-03.txt) server
+ * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "hostapd.h"
+#include "common.h"
+#include "eap_i.h"
+#include "eap_gpsk_common.h"
+
+
+struct eap_gpsk_data {
+ enum { GPSK_1, GPSK_3, SUCCESS, FAILURE } state;
+ u8 rand_server[EAP_GPSK_RAND_LEN];
+ u8 rand_client[EAP_GPSK_RAND_LEN];
+ u8 msk[EAP_MSK_LEN];
+ u8 emsk[EAP_EMSK_LEN];
+ u8 sk[EAP_GPSK_MAX_SK_LEN];
+ size_t sk_len;
+ u8 pk[EAP_GPSK_MAX_PK_LEN];
+ size_t pk_len;
+ u8 *id_client;
+ size_t id_client_len;
+ u8 *id_server;
+ size_t id_server_len;
+#define MAX_NUM_CSUITES 2
+ struct eap_gpsk_csuite csuite_list[MAX_NUM_CSUITES];
+ size_t csuite_count;
+ int vendor; /* CSuite/Vendor */
+ int specifier; /* CSuite/Specifier */
+};
+
+
+static const char * eap_gpsk_state_txt(int state)
+{
+ switch (state) {
+ case GPSK_1:
+ return "GPSK-1";
+ case GPSK_3:
+ return "GPSK-3";
+ case SUCCESS:
+ return "SUCCESS";
+ case FAILURE:
+ return "FAILURE";
+ default:
+ return "?";
+ }
+}
+
+
+static void eap_gpsk_state(struct eap_gpsk_data *data, int state)
+{
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: %s -> %s",
+ eap_gpsk_state_txt(data->state),
+ eap_gpsk_state_txt(state));
+ data->state = state;
+}
+
+
+static void * eap_gpsk_init(struct eap_sm *sm)
+{
+ struct eap_gpsk_data *data;
+
+ data = wpa_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ data->state = GPSK_1;
+
+ /* TODO: add support for configuring ID_Server */
+ data->id_server = (u8 *) strdup("hostapd");
+ if (data->id_server)
+ data->id_server_len = strlen((char *) data->id_server);
+
+ data->csuite_count = 0;
+ if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
+ EAP_GPSK_CIPHER_AES)) {
+ WPA_PUT_BE24(data->csuite_list[data->csuite_count].vendor,
+ EAP_GPSK_VENDOR_IETF);
+ WPA_PUT_BE24(data->csuite_list[data->csuite_count].specifier,
+ EAP_GPSK_CIPHER_AES);
+ data->csuite_count++;
+ }
+ if (eap_gpsk_supported_ciphersuite(EAP_GPSK_VENDOR_IETF,
+ EAP_GPSK_CIPHER_SHA256)) {
+ WPA_PUT_BE24(data->csuite_list[data->csuite_count].vendor,
+ EAP_GPSK_VENDOR_IETF);
+ WPA_PUT_BE24(data->csuite_list[data->csuite_count].specifier,
+ EAP_GPSK_CIPHER_SHA256);
+ data->csuite_count++;
+ }
+
+ return data;
+}
+
+
+static void eap_gpsk_reset(struct eap_sm *sm, void *priv)
+{
+ struct eap_gpsk_data *data = priv;
+ free(data->id_server);
+ free(data->id_client);
+ free(data);
+}
+
+
+static u8 * eap_gpsk_build_gpsk_1(struct eap_sm *sm,
+ struct eap_gpsk_data *data,
+ int id, size_t *reqDataLen)
+{
+ u8 *pos;
+ size_t len;
+ struct eap_hdr *req;
+
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-1");
+
+ if (hostapd_get_rand(data->rand_server, EAP_GPSK_RAND_LEN)) {
+ wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to get random data");
+ eap_gpsk_state(data, FAILURE);
+ return NULL;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "EAP-GPSK: RAND_Server",
+ data->rand_server, EAP_GPSK_RAND_LEN);
+
+ len = 1 + 2 + data->id_server_len + EAP_GPSK_RAND_LEN + 2 +
+ data->csuite_count * sizeof(struct eap_gpsk_csuite);
+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqDataLen,
+ len, EAP_CODE_REQUEST, id, &pos);
+ if (req == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory "
+ "for request/GPSK-1");
+ eap_gpsk_state(data, FAILURE);
+ return NULL;
+ }
+
+ *pos++ = EAP_GPSK_OPCODE_GPSK_1;
+
+ WPA_PUT_BE16(pos, data->id_server_len);
+ pos += 2;
+ if (data->id_server)
+ memcpy(pos, data->id_server, data->id_server_len);
+ pos += data->id_server_len;
+
+ memcpy(pos, data->rand_server, EAP_GPSK_RAND_LEN);
+ pos += EAP_GPSK_RAND_LEN;
+
+ WPA_PUT_BE16(pos, data->csuite_count * sizeof(struct eap_gpsk_csuite));
+ pos += 2;
+ memcpy(pos, data->csuite_list,
+ data->csuite_count * sizeof(struct eap_gpsk_csuite));
+
+ return (u8 *) req;
+}
+
+
+static u8 * eap_gpsk_build_gpsk_3(struct eap_sm *sm,
+ struct eap_gpsk_data *data,
+ int id, size_t *reqDataLen)
+{
+ u8 *pos, *start;
+ size_t len, miclen;
+ struct eap_gpsk_csuite *csuite;
+ struct eap_hdr *req;
+
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Request/GPSK-3");
+
+ miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
+ len = 1 + 2 * EAP_GPSK_RAND_LEN + sizeof(struct eap_gpsk_csuite) + 2 +
+ miclen;
+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GPSK, reqDataLen,
+ len, EAP_CODE_REQUEST, id, &pos);
+ if (req == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-GPSK: Failed to allocate memory "
+ "for request/GPSK-3");
+ eap_gpsk_state(data, FAILURE);
+ return NULL;
+ }
+
+ *pos++ = EAP_GPSK_OPCODE_GPSK_3;
+ start = pos;
+
+ memcpy(pos, data->rand_client, EAP_GPSK_RAND_LEN);
+ pos += EAP_GPSK_RAND_LEN;
+ memcpy(pos, data->rand_server, EAP_GPSK_RAND_LEN);
+ pos += EAP_GPSK_RAND_LEN;
+ csuite = (struct eap_gpsk_csuite *) pos;
+ WPA_PUT_BE24(csuite->vendor, data->vendor);
+ WPA_PUT_BE24(csuite->specifier, data->specifier);
+ pos += sizeof(*csuite);
+
+ /* no PD_Payload_2 */
+ WPA_PUT_BE16(pos, 0);
+ pos += 2;
+
+ if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
+ data->specifier, start, pos - start, pos) < 0)
+ {
+ free(req);
+ eap_gpsk_state(data, FAILURE);
+ return NULL;
+ }
+
+ return (u8 *) req;
+}
+
+
+static u8 * eap_gpsk_buildReq(struct eap_sm *sm, void *priv, int id,
+ size_t *reqDataLen)
+{
+ struct eap_gpsk_data *data = priv;
+
+ switch (data->state) {
+ case GPSK_1:
+ return eap_gpsk_build_gpsk_1(sm, data, id, reqDataLen);
+ case GPSK_3:
+ return eap_gpsk_build_gpsk_3(sm, data, id, reqDataLen);
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown state %d in buildReq",
+ data->state);
+ break;
+ }
+ return NULL;
+}
+
+
+static Boolean eap_gpsk_check(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_gpsk_data *data = priv;
+ const u8 *pos;
+ size_t len;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK,
+ respData, respDataLen, &len);
+ if (pos == NULL || len < 1) {
+ wpa_printf(MSG_INFO, "EAP-GPSK: Invalid frame");
+ return TRUE;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Received frame: opcode=%d", *pos);
+
+ if (data->state == GPSK_1 && *pos == EAP_GPSK_OPCODE_GPSK_2)
+ return FALSE;
+
+ if (data->state == GPSK_3 && *pos == EAP_GPSK_OPCODE_GPSK_4)
+ return FALSE;
+
+ wpa_printf(MSG_INFO, "EAP-GPSK: Unexpected opcode=%d in state=%d",
+ *pos, data->state);
+
+ return TRUE;
+}
+
+
+static void eap_gpsk_process_gpsk_2(struct eap_sm *sm,
+ struct eap_gpsk_data *data,
+ u8 *respData, size_t respDataLen,
+ const u8 *payload, size_t payloadlen)
+{
+ const u8 *pos, *end;
+ u16 alen;
+ const struct eap_gpsk_csuite *csuite;
+ size_t i, miclen;
+ u8 mic[EAP_GPSK_MAX_MIC_LEN];
+
+ if (data->state != GPSK_1)
+ return;
+
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-2");
+
+ pos = payload;
+ end = payload + payloadlen;
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+ "ID_Client length");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ alen = WPA_GET_BE16(pos);
+ pos += 2;
+ if (end - pos < alen) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+ "ID_Client");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ free(data->id_client);
+ data->id_client = malloc(alen);
+ if (data->id_client == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Not enough memory to store "
+ "%d-octet ID_Client", alen);
+ return;
+ }
+ memcpy(data->id_client, pos, alen);
+ data->id_client_len = alen;
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-GPSK: ID_Client",
+ data->id_client, data->id_client_len);
+ pos += alen;
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+ "ID_Server length");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ alen = WPA_GET_BE16(pos);
+ pos += 2;
+ if (end - pos < alen) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+ "ID_Server");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ if (alen != data->id_server_len ||
+ memcmp(pos, data->id_server, alen) != 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: ID_Server in GPSK-1 and "
+ "GPSK-2 did not match");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ pos += alen;
+
+ if (end - pos < EAP_GPSK_RAND_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+ "RAND_Client");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ memcpy(data->rand_client, pos, EAP_GPSK_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Client",
+ data->rand_client, EAP_GPSK_RAND_LEN);
+ pos += EAP_GPSK_RAND_LEN;
+
+ if (end - pos < EAP_GPSK_RAND_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+ "RAND_Server");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ if (memcmp(data->rand_server, pos, EAP_GPSK_RAND_LEN) != 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1 and "
+ "GPSK-2 did not match");
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-1",
+ data->rand_server, EAP_GPSK_RAND_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: RAND_Server in GPSK-2",
+ pos, EAP_GPSK_RAND_LEN);
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ pos += EAP_GPSK_RAND_LEN;
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+ "CSuite_List length");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ alen = WPA_GET_BE16(pos);
+ pos += 2;
+ if (end - pos < alen) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+ "CSuite_List");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ if (alen != data->csuite_count * sizeof(struct eap_gpsk_csuite) ||
+ memcmp(pos, data->csuite_list, alen) != 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_List in GPSK-1 and "
+ "GPSK-2 did not match");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ pos += alen;
+
+ if (end - pos < (int) sizeof(*csuite)) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+ "CSuite_Sel");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ csuite = (const struct eap_gpsk_csuite *) pos;
+ for (i = 0; i < data->csuite_count; i++) {
+ if (memcmp(csuite, &data->csuite_list[i], sizeof(*csuite)) ==
+ 0)
+ break;
+ }
+ if (i == data->csuite_count) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Peer selected unsupported "
+ "ciphersuite %d:%d",
+ WPA_GET_BE24(csuite->vendor),
+ WPA_GET_BE24(csuite->specifier));
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ data->vendor = WPA_GET_BE24(csuite->vendor);
+ data->specifier = WPA_GET_BE24(csuite->specifier);
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: CSuite_Sel %d:%d",
+ data->vendor, data->specifier);
+ pos += sizeof(*csuite);
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+ "PD_Payload_1 length");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ alen = WPA_GET_BE16(pos);
+ pos += 2;
+ if (end - pos < alen) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+ "PD_Payload_1");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
+ pos += alen;
+
+ if (sm->user == NULL || sm->user->password == NULL) {
+ wpa_printf(MSG_INFO, "EAP-GPSK: No PSK/password configured "
+ "for the user");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+
+ if (eap_gpsk_derive_keys(sm->user->password, sm->user->password_len,
+ data->vendor, data->specifier,
+ data->rand_client, data->rand_server,
+ data->id_client, data->id_client_len,
+ data->id_server, data->id_server_len,
+ data->msk, data->emsk,
+ data->sk, &data->sk_len,
+ data->pk, &data->pk_len) < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to derive keys");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+
+ miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
+ if (end - pos < (int) miclen) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
+ "(left=%d miclen=%d)", end - pos, miclen);
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
+ data->specifier, payload, pos - payload, mic)
+ < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ if (memcmp(mic, pos, miclen) != 0) {
+ wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-2");
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ pos += miclen;
+
+ if (pos != end) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %d bytes of extra "
+ "data in the end of GPSK-2", end - pos);
+ }
+
+ eap_gpsk_state(data, GPSK_3);
+}
+
+
+static void eap_gpsk_process_gpsk_4(struct eap_sm *sm,
+ struct eap_gpsk_data *data,
+ u8 *respData, size_t respDataLen,
+ const u8 *payload, size_t payloadlen)
+{
+ const u8 *pos, *end;
+ u16 alen;
+ size_t miclen;
+ u8 mic[EAP_GPSK_MAX_MIC_LEN];
+
+ if (data->state != GPSK_3)
+ return;
+
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Received Response/GPSK-4");
+
+ pos = payload;
+ end = payload + payloadlen;
+
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+ "PD_Payload_1 length");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ alen = WPA_GET_BE16(pos);
+ pos += 2;
+ if (end - pos < alen) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Too short message for "
+ "PD_Payload_1");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: PD_Payload_1", pos, alen);
+ pos += alen;
+
+ miclen = eap_gpsk_mic_len(data->vendor, data->specifier);
+ if (end - pos < (int) miclen) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Message too short for MIC "
+ "(left=%d miclen=%d)", end - pos, miclen);
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ if (eap_gpsk_compute_mic(data->sk, data->sk_len, data->vendor,
+ data->specifier, payload, pos - payload, mic)
+ < 0) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to compute MIC");
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ if (memcmp(mic, pos, miclen) != 0) {
+ wpa_printf(MSG_INFO, "EAP-GPSK: Incorrect MIC in GPSK-4");
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Received MIC", pos, miclen);
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Computed MIC", mic, miclen);
+ eap_gpsk_state(data, FAILURE);
+ return;
+ }
+ pos += miclen;
+
+ if (pos != end) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Ignored %d bytes of extra "
+ "data in the end of GPSK-4", end - pos);
+ }
+
+ eap_gpsk_state(data, SUCCESS);
+}
+
+
+static void eap_gpsk_process(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_gpsk_data *data = priv;
+ const u8 *pos;
+ size_t len;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GPSK,
+ respData, respDataLen, &len);
+ if (pos == NULL || len < 1)
+ return;
+
+ switch (*pos) {
+ case EAP_GPSK_OPCODE_GPSK_2:
+ eap_gpsk_process_gpsk_2(sm, data, respData, respDataLen,
+ pos + 1, len - 1);
+ break;
+ case EAP_GPSK_OPCODE_GPSK_4:
+ eap_gpsk_process_gpsk_4(sm, data, respData, respDataLen,
+ pos + 1, len - 1);
+ break;
+ }
+}
+
+
+static Boolean eap_gpsk_isDone(struct eap_sm *sm, void *priv)
+{
+ struct eap_gpsk_data *data = priv;
+ return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_gpsk_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_gpsk_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = malloc(EAP_MSK_LEN);
+ if (key == NULL)
+ return NULL;
+ memcpy(key, data->msk, EAP_MSK_LEN);
+ *len = EAP_MSK_LEN;
+
+ return key;
+}
+
+
+static u8 * eap_gpsk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_gpsk_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+ memcpy(key, data->emsk, EAP_EMSK_LEN);
+ *len = EAP_EMSK_LEN;
+
+ return key;
+}
+
+
+static Boolean eap_gpsk_isSuccess(struct eap_sm *sm, void *priv)
+{
+ struct eap_gpsk_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+int eap_server_gpsk_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_GPSK, "GPSK");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_gpsk_init;
+ eap->reset = eap_gpsk_reset;
+ eap->buildReq = eap_gpsk_buildReq;
+ eap->check = eap_gpsk_check;
+ eap->process = eap_gpsk_process;
+ eap->isDone = eap_gpsk_isDone;
+ eap->getKey = eap_gpsk_getKey;
+ eap->isSuccess = eap_gpsk_isSuccess;
+ eap->get_emsk = eap_gpsk_get_emsk;
+
+ ret = eap_server_method_register(eap);
+ if (ret)
+ eap_server_method_free(eap);
+ return ret;
+}
diff --git a/contrib/hostapd/eap_gpsk_common.c b/contrib/hostapd/eap_gpsk_common.c
new file mode 100644
index 000000000000..a72b5f3da15f
--- /dev/null
+++ b/contrib/hostapd/eap_gpsk_common.c
@@ -0,0 +1,441 @@
+/*
+ * EAP server/peer: EAP-GPSK shared routines
+ * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_defs.h"
+#include "aes_wrap.h"
+#include "crypto.h"
+#include "sha1.h"
+#include "sha256.h"
+#include "eap_gpsk_common.h"
+
+
+/**
+ * eap_gpsk_supported_ciphersuite - Check whether ciphersuite is supported
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * Returns: 1 if ciphersuite is support, or 0 if not
+ */
+int eap_gpsk_supported_ciphersuite(int vendor, int specifier)
+{
+ if (vendor == EAP_GPSK_VENDOR_IETF &&
+ specifier == EAP_GPSK_CIPHER_AES)
+ return 1;
+#ifdef EAP_GPSK_SHA256
+ if (vendor == EAP_GPSK_VENDOR_IETF &&
+ specifier == EAP_GPSK_CIPHER_SHA256)
+ return 1;
+#endif /* EAP_GPSK_SHA256 */
+ return 0;
+}
+
+
+static int eap_gpsk_gkdf(const u8 *psk /* Y */, size_t psk_len,
+ const u8 *data /* Z */, size_t data_len,
+ u8 *buf, size_t len /* X */)
+{
+ u8 *opos;
+ size_t i, n, hashlen, left, clen;
+ u8 ibuf[2], hash[SHA1_MAC_LEN];
+ const u8 *addr[3];
+ size_t vlen[3];
+
+ hashlen = SHA1_MAC_LEN;
+ /* M_i = Hash-Function (i || Y || Z); */
+ addr[0] = ibuf;
+ vlen[0] = sizeof(ibuf);
+ addr[1] = psk;
+ vlen[1] = psk_len;
+ addr[2] = data;
+ vlen[2] = data_len;
+
+ opos = buf;
+ left = len;
+ n = (len + hashlen - 1) / hashlen;
+ for (i = 1; i <= n; i++) {
+ WPA_PUT_BE16(ibuf, i);
+ sha1_vector(3, addr, vlen, hash);
+ clen = left > hashlen ? hashlen : left;
+ os_memcpy(opos, hash, clen);
+ opos += clen;
+ left -= clen;
+ }
+
+ return 0;
+}
+
+
+static int eap_gpsk_derive_keys_aes(const u8 *psk, size_t psk_len,
+ const u8 *seed, size_t seed_len,
+ u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
+ u8 *pk, size_t *pk_len)
+{
+#define EAP_GPSK_SK_LEN_AES 16
+#define EAP_GPSK_PK_LEN_AES 16
+ u8 zero_string[1], mk[32], *pos, *data;
+ u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_AES +
+ EAP_GPSK_PK_LEN_AES];
+ size_t data_len;
+
+ /*
+ * inputString = RAND_Client || ID_Client || RAND_Server || ID_Server
+ * (= seed)
+ * KS = 16, PL = psk_len, CSuite_Sel = 0x000000 0x000001
+ * MK = GKDF-32 (0x00, PL || PSK || CSuite_Sel || inputString)
+ * MSK = GKDF-160 (MK, inputString)[0..63]
+ * EMSK = GKDF-160 (MK, inputString)[64..127]
+ * SK = GKDF-160 (MK, inputString)[128..143]
+ * PK = GKDF-160 (MK, inputString)[144..159]
+ * MID = GKDF-16(0x00, "Method ID" || EAP_Method_Type || CSuite_Sel ||
+ * inputString)
+ * Hash-Function = SHA-1 (see [RFC3174])
+ * hashlen = 20 octets (160 bits)
+ */
+
+ os_memset(zero_string, 0, sizeof(zero_string));
+
+ data_len = 2 + psk_len + 6 + seed_len;
+ data = os_malloc(data_len);
+ if (data == NULL)
+ return -1;
+ pos = data;
+ WPA_PUT_BE16(pos, psk_len);
+ pos += 2;
+ os_memcpy(pos, psk, psk_len);
+ pos += psk_len;
+ WPA_PUT_BE24(pos, 0); /* CSuite/Vendor = IETF */
+ pos += 3;
+ WPA_PUT_BE24(pos, EAP_GPSK_CIPHER_AES); /* CSuite/Specifier */
+ pos += 3;
+ os_memcpy(pos, seed, seed_len); /* inputString */
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation (AES)",
+ data, data_len);
+
+ if (eap_gpsk_gkdf(zero_string, sizeof(zero_string), data, data_len,
+ mk, sizeof(mk)) < 0) {
+ os_free(data);
+ return -1;
+ }
+ os_free(data);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, sizeof(mk));
+
+ if (eap_gpsk_gkdf(mk, sizeof(mk), seed, seed_len,
+ kdf_out, sizeof(kdf_out)) < 0)
+ return -1;
+
+ pos = kdf_out;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MSK", pos, EAP_MSK_LEN);
+ os_memcpy(msk, pos, EAP_MSK_LEN);
+ pos += EAP_MSK_LEN;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: EMSK", pos, EAP_EMSK_LEN);
+ os_memcpy(emsk, pos, EAP_EMSK_LEN);
+ pos += EAP_EMSK_LEN;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: SK", pos, EAP_GPSK_SK_LEN_AES);
+ os_memcpy(sk, pos, EAP_GPSK_SK_LEN_AES);
+ *sk_len = EAP_GPSK_SK_LEN_AES;
+ pos += EAP_GPSK_SK_LEN_AES;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PK", pos, EAP_GPSK_PK_LEN_AES);
+ os_memcpy(pk, pos, EAP_GPSK_PK_LEN_AES);
+ *pk_len = EAP_GPSK_PK_LEN_AES;
+
+ return 0;
+}
+
+
+#ifdef EAP_GPSK_SHA256
+static int eap_gpsk_gkdf_sha256(const u8 *psk /* Y */, size_t psk_len,
+ const u8 *data /* Z */, size_t data_len,
+ u8 *buf, size_t len /* X */)
+{
+ u8 *opos;
+ size_t i, n, hashlen, left, clen;
+ u8 ibuf[2], hash[SHA256_MAC_LEN];
+ const u8 *addr[3];
+ size_t vlen[3];
+
+ hashlen = SHA256_MAC_LEN;
+ /* M_i = Hash-Function (i || Y || Z); */
+ addr[0] = ibuf;
+ vlen[0] = sizeof(ibuf);
+ addr[1] = psk;
+ vlen[1] = psk_len;
+ addr[2] = data;
+ vlen[2] = data_len;
+
+ opos = buf;
+ left = len;
+ n = (len + hashlen - 1) / hashlen;
+ for (i = 1; i <= n; i++) {
+ WPA_PUT_BE16(ibuf, i);
+ sha256_vector(3, addr, vlen, hash);
+ clen = left > hashlen ? hashlen : left;
+ os_memcpy(opos, hash, clen);
+ opos += clen;
+ left -= clen;
+ }
+
+ return 0;
+}
+
+
+static int eap_gpsk_derive_keys_sha256(const u8 *psk, size_t psk_len,
+ const u8 *seed, size_t seed_len,
+ u8 *msk, u8 *emsk,
+ u8 *sk, size_t *sk_len,
+ u8 *pk, size_t *pk_len)
+{
+#define EAP_GPSK_SK_LEN_SHA256 SHA256_MAC_LEN
+#define EAP_GPSK_PK_LEN_SHA256 SHA256_MAC_LEN
+ u8 mk[SHA256_MAC_LEN], zero_string[1], *pos, *data;
+ u8 kdf_out[EAP_MSK_LEN + EAP_EMSK_LEN + EAP_GPSK_SK_LEN_SHA256 +
+ EAP_GPSK_PK_LEN_SHA256];
+ size_t data_len;
+
+ /*
+ * inputString = RAND_Client || ID_Client || RAND_Server || ID_Server
+ * (= seed)
+ * KS = 32, PL = psk_len, CSuite_Sel = 0x000000 0x000002
+ * MK = GKDF-32 (0x00, PL || PSK || CSuite_Sel || inputString)
+ * MSK = GKDF-192 (MK, inputString)[0..63]
+ * EMSK = GKDF-192 (MK, inputString)[64..127]
+ * SK = GKDF-192 (MK, inputString)[128..159]
+ * PK = GKDF-192 (MK, inputString)[160..191]
+ * MID = GKDF-16(0x00, "Method ID" || EAP_Method_Type || CSuite_Sel ||
+ * inputString)
+ * Hash-Function = SHA256 (see [RFC4634])
+ * hashlen = 32 octets (256 bits)
+ */
+
+ os_memset(zero_string, 0, sizeof(zero_string));
+
+ data_len = 2 + psk_len + 6 + seed_len;
+ data = os_malloc(data_len);
+ if (data == NULL)
+ return -1;
+ pos = data;
+ WPA_PUT_BE16(pos, psk_len);
+ pos += 2;
+ os_memcpy(pos, psk, psk_len);
+ pos += psk_len;
+ WPA_PUT_BE24(pos, 0); /* CSuite/Vendor = IETF */
+ pos += 3;
+ WPA_PUT_BE24(pos, EAP_GPSK_CIPHER_SHA256); /* CSuite/Specifier */
+ pos += 3;
+ os_memcpy(pos, seed, seed_len); /* inputString */
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: Data to MK derivation (SHA256)",
+ data, data_len);
+
+ if (eap_gpsk_gkdf_sha256(zero_string, sizeof(zero_string),
+ data, data_len, mk, sizeof(mk)) < 0) {
+ os_free(data);
+ return -1;
+ }
+ os_free(data);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MK", mk, sizeof(mk));
+
+ if (eap_gpsk_gkdf_sha256(mk, sizeof(mk), seed, seed_len,
+ kdf_out, sizeof(kdf_out)) < 0)
+ return -1;
+
+ pos = kdf_out;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: MSK", pos, EAP_MSK_LEN);
+ os_memcpy(msk, pos, EAP_MSK_LEN);
+ pos += EAP_MSK_LEN;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: EMSK", pos, EAP_EMSK_LEN);
+ os_memcpy(emsk, pos, EAP_EMSK_LEN);
+ pos += EAP_EMSK_LEN;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: SK",
+ pos, EAP_GPSK_SK_LEN_SHA256);
+ os_memcpy(sk, pos, EAP_GPSK_SK_LEN_SHA256);
+ *sk_len = EAP_GPSK_SK_LEN_AES;
+ pos += EAP_GPSK_SK_LEN_AES;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PK",
+ pos, EAP_GPSK_PK_LEN_SHA256);
+ os_memcpy(pk, pos, EAP_GPSK_PK_LEN_SHA256);
+ *pk_len = EAP_GPSK_PK_LEN_SHA256;
+
+ return 0;
+}
+#endif /* EAP_GPSK_SHA256 */
+
+
+/**
+ * eap_gpsk_derive_keys - Derive EAP-GPSK keys
+ * @psk: Pre-shared key (at least 16 bytes if AES is used)
+ * @psk_len: Length of psk in bytes
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * @rand_client: 32-byte RAND_Client
+ * @rand_server: 32-byte RAND_Server
+ * @id_client: ID_Client
+ * @id_client_len: Length of ID_Client
+ * @id_server: ID_Server
+ * @id_server_len: Length of ID_Server
+ * @msk: Buffer for 64-byte MSK
+ * @emsk: Buffer for 64-byte EMSK
+ * @sk: Buffer for SK (at least EAP_GPSK_MAX_SK_LEN bytes)
+ * @sk_len: Buffer for returning length of SK
+ * @pk: Buffer for SK (at least EAP_GPSK_MAX_PK_LEN bytes)
+ * @pk_len: Buffer for returning length of PK
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
+ int specifier,
+ const u8 *rand_client, const u8 *rand_server,
+ const u8 *id_client, size_t id_client_len,
+ const u8 *id_server, size_t id_server_len,
+ u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
+ u8 *pk, size_t *pk_len)
+{
+ u8 *seed, *pos;
+ size_t seed_len;
+ int ret;
+
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Deriving keys (%d:%d)",
+ vendor, specifier);
+
+ if (vendor != EAP_GPSK_VENDOR_IETF)
+ return -1;
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-GPSK: PSK", psk, psk_len);
+
+ /* Seed = RAND_Client || ID_Client || RAND_Server || ID_Server */
+ seed_len = 2 * EAP_GPSK_RAND_LEN + id_server_len + id_client_len;
+ seed = os_malloc(seed_len);
+ if (seed == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Failed to allocate memory "
+ "for key derivation");
+ return -1;
+ }
+
+ pos = seed;
+ os_memcpy(pos, rand_client, EAP_GPSK_RAND_LEN);
+ pos += EAP_GPSK_RAND_LEN;
+ os_memcpy(pos, id_client, id_client_len);
+ pos += id_client_len;
+ os_memcpy(pos, rand_server, EAP_GPSK_RAND_LEN);
+ pos += EAP_GPSK_RAND_LEN;
+ os_memcpy(pos, id_server, id_server_len);
+ pos += id_server_len;
+ wpa_hexdump(MSG_DEBUG, "EAP-GPSK: Seed", seed, seed_len);
+
+ switch (specifier) {
+ case EAP_GPSK_CIPHER_AES:
+ ret = eap_gpsk_derive_keys_aes(psk, psk_len, seed, seed_len,
+ msk, emsk, sk, sk_len,
+ pk, pk_len);
+ break;
+#ifdef EAP_GPSK_SHA256
+ case EAP_GPSK_CIPHER_SHA256:
+ ret = eap_gpsk_derive_keys_sha256(psk, psk_len, seed, seed_len,
+ msk, emsk, sk, sk_len,
+ pk, pk_len);
+ break;
+#endif /* EAP_GPSK_SHA256 */
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in "
+ "key derivation", vendor, specifier);
+ ret = -1;
+ break;
+ }
+
+ os_free(seed);
+
+ return ret;
+}
+
+
+/**
+ * eap_gpsk_mic_len - Get the length of the MIC
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * Returns: MIC length in bytes
+ */
+size_t eap_gpsk_mic_len(int vendor, int specifier)
+{
+ if (vendor != EAP_GPSK_VENDOR_IETF)
+ return 0;
+
+ switch (specifier) {
+ case EAP_GPSK_CIPHER_AES:
+ return 16;
+#ifdef EAP_GPSK_SHA256
+ case EAP_GPSK_CIPHER_SHA256:
+ return 32;
+#endif /* EAP_GPSK_SHA256 */
+ default:
+ return 0;
+ }
+}
+
+
+static int eap_gpsk_compute_mic_aes(const u8 *sk, size_t sk_len,
+ const u8 *data, size_t len, u8 *mic)
+{
+ if (sk_len != 16) {
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Invalid SK length %d for "
+ "AES-CMAC MIC", sk_len);
+ return -1;
+ }
+
+ return omac1_aes_128(sk, data, len, mic);
+}
+
+
+/**
+ * eap_gpsk_compute_mic - Compute EAP-GPSK MIC for an EAP packet
+ * @sk: Session key SK from eap_gpsk_derive_keys()
+ * @sk_len: SK length in bytes from eap_gpsk_derive_keys()
+ * @vendor: CSuite/Vendor
+ * @specifier: CSuite/Specifier
+ * @data: Input data to MIC
+ * @len: Input data length in bytes
+ * @mic: Buffer for the computed MIC, eap_gpsk_mic_len(cipher) bytes
+ * Returns: 0 on success, -1 on failure
+ */
+int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
+ int specifier, const u8 *data, size_t len, u8 *mic)
+{
+ int ret;
+
+ if (vendor != EAP_GPSK_VENDOR_IETF)
+ return -1;
+
+ switch (specifier) {
+ case EAP_GPSK_CIPHER_AES:
+ ret = eap_gpsk_compute_mic_aes(sk, sk_len, data, len, mic);
+ break;
+#ifdef EAP_GPSK_SHA256
+ case EAP_GPSK_CIPHER_SHA256:
+ hmac_sha256(sk, sk_len, data, len, mic);
+ ret = 0;
+ break;
+#endif /* EAP_GPSK_SHA256 */
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-GPSK: Unknown cipher %d:%d used in "
+ "MIC computation", vendor, specifier);
+ ret = -1;
+ break;
+ }
+
+ return ret;
+}
diff --git a/contrib/hostapd/eap_gpsk_common.h b/contrib/hostapd/eap_gpsk_common.h
new file mode 100644
index 000000000000..c806b7f85217
--- /dev/null
+++ b/contrib/hostapd/eap_gpsk_common.h
@@ -0,0 +1,66 @@
+/*
+ * EAP server/peer: EAP-GPSK shared routines
+ * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef EAP_GPSK_COMMON_H
+#define EAP_GPSK_COMMON_H
+
+#define EAP_GPSK_OPCODE_GPSK_1 1
+#define EAP_GPSK_OPCODE_GPSK_2 2
+#define EAP_GPSK_OPCODE_GPSK_3 3
+#define EAP_GPSK_OPCODE_GPSK_4 4
+#define EAP_GPSK_OPCODE_FAIL 5
+#define EAP_GPSK_OPCODE_PROTECTED_FAIL 6
+
+/* Failure-Code in GPSK-Fail and GPSK-Protected-Fail */
+#define EAP_GPSK_FAIL_PSK_NOT_FOUND 0x00000001
+#define EAP_GPSK_FAIL_AUTHENTICATION_FAILURE 0x00000002
+#define EAP_GPSK_FAIL_AUTHORIZATION_FAILURE 0x00000003
+
+#define EAP_GPSK_RAND_LEN 32
+#define EAP_GPSK_MAX_SK_LEN 32
+#define EAP_GPSK_MAX_PK_LEN 32
+#define EAP_GPSK_MAX_MIC_LEN 32
+
+#define EAP_GPSK_VENDOR_IETF 0x000000
+#define EAP_GPSK_CIPHER_RESERVED 0x000000
+#define EAP_GPSK_CIPHER_AES 0x000001
+#define EAP_GPSK_CIPHER_SHA256 0x000002
+
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct eap_gpsk_csuite {
+ u8 vendor[3];
+ u8 specifier[3];
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+int eap_gpsk_supported_ciphersuite(int vendor, int specifier);
+int eap_gpsk_derive_keys(const u8 *psk, size_t psk_len, int vendor,
+ int specifier,
+ const u8 *rand_client, const u8 *rand_server,
+ const u8 *id_client, size_t id_client_len,
+ const u8 *id_server, size_t id_server_len,
+ u8 *msk, u8 *emsk, u8 *sk, size_t *sk_len,
+ u8 *pk, size_t *pk_len);
+size_t eap_gpsk_mic_len(int vendor, int specifier);
+int eap_gpsk_compute_mic(const u8 *sk, size_t sk_len, int vendor,
+ int specifier, const u8 *data, size_t len, u8 *mic);
+
+#endif /* EAP_GPSK_COMMON_H */
diff --git a/contrib/hostapd/eap_gtc.c b/contrib/hostapd/eap_gtc.c
index 674f83735f1f..42e4cd35cd74 100644
--- a/contrib/hostapd/eap_gtc.c
+++ b/contrib/hostapd/eap_gtc.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-GTC (RFC 3748)
- * Copyright (c) 2004, Jouni Malinen <jkmaline@cc.hut.fi>
+ * 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
@@ -12,10 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
#include "hostapd.h"
#include "common.h"
@@ -31,10 +28,9 @@ static void * eap_gtc_init(struct eap_sm *sm)
{
struct eap_gtc_data *data;
- data = malloc(sizeof(*data));
+ data = wpa_zalloc(sizeof(*data));
if (data == NULL)
- return data;
- memset(data, 0, sizeof(*data));
+ return NULL;
data->state = CONTINUE;
return data;
@@ -58,8 +54,8 @@ static u8 * eap_gtc_buildReq(struct eap_sm *sm, void *priv, int id,
size_t msg_len;
msg_len = strlen(msg);
- *reqDataLen = sizeof(*req) + 1 + msg_len;
- req = malloc(*reqDataLen);
+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_GTC, reqDataLen,
+ msg_len, EAP_CODE_REQUEST, id, &pos);
if (req == NULL) {
wpa_printf(MSG_ERROR, "EAP-GTC: Failed to allocate memory for "
"request");
@@ -67,11 +63,6 @@ static u8 * eap_gtc_buildReq(struct eap_sm *sm, void *priv, int id,
return NULL;
}
- req->code = EAP_CODE_REQUEST;
- req->identifier = id;
- req->length = htons(*reqDataLen);
- pos = (u8 *) (req + 1);
- *pos++ = EAP_TYPE_GTC;
memcpy(pos, msg, msg_len);
data->state = CONTINUE;
@@ -83,14 +74,12 @@ static u8 * eap_gtc_buildReq(struct eap_sm *sm, void *priv, int id,
static Boolean eap_gtc_check(struct eap_sm *sm, void *priv,
u8 *respData, size_t respDataLen)
{
- struct eap_hdr *resp;
- u8 *pos;
+ const u8 *pos;
size_t len;
- resp = (struct eap_hdr *) respData;
- pos = (u8 *) (resp + 1);
- if (respDataLen < sizeof(*resp) + 2 || *pos != EAP_TYPE_GTC ||
- (len = ntohs(resp->length)) > respDataLen) {
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC,
+ respData, respDataLen, &len);
+ if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-GTC: Invalid frame");
return TRUE;
}
@@ -103,20 +92,22 @@ static void eap_gtc_process(struct eap_sm *sm, void *priv,
u8 *respData, size_t respDataLen)
{
struct eap_gtc_data *data = priv;
- struct eap_hdr *resp;
- u8 *pos;
+ const u8 *pos;
size_t rlen;
- if (sm->user == NULL || sm->user->password == NULL) {
- wpa_printf(MSG_INFO, "EAP-GTC: Password not configured");
+ if (sm->user == NULL || sm->user->password == NULL ||
+ sm->user->password_hash) {
+ wpa_printf(MSG_INFO, "EAP-GTC: Plaintext password not "
+ "configured");
data->state = FAILURE;
return;
}
- resp = (struct eap_hdr *) respData;
- pos = (u8 *) (resp + 1);
- pos++;
- rlen = ntohs(resp->length) - sizeof(*resp) - 1;
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_GTC,
+ respData, respDataLen, &rlen);
+ if (pos == NULL || rlen < 1)
+ return; /* Should not happen - frame already validated */
+
wpa_hexdump_key(MSG_MSGDUMP, "EAP-GTC: Response", pos, rlen);
if (rlen != sm->user->password_len ||
@@ -144,15 +135,26 @@ static Boolean eap_gtc_isSuccess(struct eap_sm *sm, void *priv)
}
-const struct eap_method eap_method_gtc =
+int eap_server_gtc_register(void)
{
- .method = EAP_TYPE_GTC,
- .name = "GTC",
- .init = eap_gtc_init,
- .reset = eap_gtc_reset,
- .buildReq = eap_gtc_buildReq,
- .check = eap_gtc_check,
- .process = eap_gtc_process,
- .isDone = eap_gtc_isDone,
- .isSuccess = eap_gtc_isSuccess,
-};
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_GTC, "GTC");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_gtc_init;
+ eap->reset = eap_gtc_reset;
+ eap->buildReq = eap_gtc_buildReq;
+ eap->check = eap_gtc_check;
+ eap->process = eap_gtc_process;
+ eap->isDone = eap_gtc_isDone;
+ eap->isSuccess = eap_gtc_isSuccess;
+
+ ret = eap_server_method_register(eap);
+ if (ret)
+ eap_server_method_free(eap);
+ return ret;
+}
diff --git a/contrib/hostapd/eap_i.h b/contrib/hostapd/eap_i.h
index 4e803f905d04..85b2c2d2fac8 100644
--- a/contrib/hostapd/eap_i.h
+++ b/contrib/hostapd/eap_i.h
@@ -1,11 +1,32 @@
+/*
+ * hostapd / EAP Authenticator state machine internal structures (RFC 4137)
+ * 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.
+ */
+
#ifndef EAP_I_H
#define EAP_I_H
#include "eap.h"
-/* draft-ietf-eap-statemachine-05.pdf - EAP Standalone Authenticator */
+/* RFC 4137 - EAP Standalone Authenticator */
+/**
+ * struct eap_method - EAP method interface
+ * This structure defines the EAP method interface. Each method will need to
+ * register its own EAP type, EAP name, and set of function pointers for method
+ * specific operations. This interface is based on section 5.4 of RFC 4137.
+ */
struct eap_method {
+ int vendor;
EapType method;
const char *name;
@@ -25,8 +46,58 @@ struct eap_method {
/* isSuccess is not specified in draft-ietf-eap-statemachine-05.txt,
* but it is useful in implementing Policy.getDecision() */
Boolean (*isSuccess)(struct eap_sm *sm, void *priv);
+
+ /**
+ * free - Free EAP method data
+ * @method: Pointer to the method data registered with
+ * eap_server_method_register().
+ *
+ * This function will be called when the EAP method is being
+ * unregistered. If the EAP method allocated resources during
+ * registration (e.g., allocated struct eap_method), they should be
+ * freed in this function. No other method functions will be called
+ * after this call. If this function is not defined (i.e., function
+ * pointer is %NULL), a default handler is used to release the method
+ * data with free(method). This is suitable for most cases.
+ */
+ void (*free)(struct eap_method *method);
+
+#define EAP_SERVER_METHOD_INTERFACE_VERSION 1
+ /**
+ * version - Version of the EAP server method interface
+ *
+ * The EAP server method implementation should set this variable to
+ * EAP_SERVER_METHOD_INTERFACE_VERSION. This is used to verify that the
+ * EAP method is using supported API version when using dynamically
+ * loadable EAP methods.
+ */
+ int version;
+
+ /**
+ * next - Pointer to the next EAP method
+ *
+ * This variable is used internally in the EAP method registration code
+ * to create a linked list of registered EAP methods.
+ */
+ struct eap_method *next;
+
+ /**
+ * get_emsk - Get EAP method specific keying extended material (EMSK)
+ * @sm: Pointer to EAP state machine allocated with eap_sm_init()
+ * @priv: Pointer to private EAP method data from eap_method::init()
+ * @len: Pointer to a variable to store EMSK length
+ * Returns: EMSK or %NULL if not available
+ *
+ * This function can be used to get the extended keying material from
+ * the EAP method. The key may already be stored in the method-specific
+ * private data or this function may derive the key.
+ */
+ u8 * (*get_emsk)(struct eap_sm *sm, void *priv, size_t *len);
};
+/**
+ * struct eap_sm - EAP server state machine data
+ */
struct eap_sm {
enum {
EAP_DISABLED, EAP_INITIALIZE, EAP_IDLE, EAP_RECEIVED,
@@ -77,6 +148,8 @@ struct eap_sm {
Boolean rxResp;
int respId;
EapType respMethod;
+ int respVendor;
+ u32 respVendorMethod;
Boolean ignore;
enum {
DECISION_SUCCESS, DECISION_FAILURE, DECISION_CONTINUE
@@ -102,11 +175,18 @@ struct eap_sm {
Boolean update_user;
int num_rounds;
+ enum {
+ METHOD_PENDING_NONE, METHOD_PENDING_WAIT, METHOD_PENDING_CONT
+ } method_pending;
};
-const struct eap_method * eap_sm_get_eap_methods(int method);
int eap_user_get(struct eap_sm *sm, const u8 *identity, size_t identity_len,
int phase2);
void eap_sm_process_nak(struct eap_sm *sm, u8 *nak_list, size_t len);
+const u8 * eap_hdr_validate(int vendor, EapType eap_type,
+ const u8 *msg, size_t msglen, size_t *plen);
+struct eap_hdr * eap_msg_alloc(int vendor, EapType type, size_t *len,
+ size_t payload_len, u8 code, u8 identifier,
+ u8 **payload);
#endif /* EAP_I_H */
diff --git a/contrib/hostapd/eap_identity.c b/contrib/hostapd/eap_identity.c
index 54efc47961aa..ab6f26b1fea5 100644
--- a/contrib/hostapd/eap_identity.c
+++ b/contrib/hostapd/eap_identity.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-Identity
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * 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
@@ -12,10 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
#include "hostapd.h"
#include "common.h"
@@ -32,10 +29,9 @@ static void * eap_identity_init(struct eap_sm *sm)
{
struct eap_identity_data *data;
- data = malloc(sizeof(*data));
+ data = wpa_zalloc(sizeof(*data));
if (data == NULL)
- return data;
- memset(data, 0, sizeof(*data));
+ return NULL;
data->state = CONTINUE;
return data;
@@ -61,7 +57,7 @@ static void eap_identity_reset(struct eap_sm *sm, void *priv)
static u8 * eap_identity_buildReq(struct eap_sm *sm, void *priv, int id,
- size_t *reqDataLen)
+ size_t *reqDataLen)
{
struct eap_identity_data *data = priv;
struct eap_hdr *req;
@@ -76,8 +72,8 @@ static u8 * eap_identity_buildReq(struct eap_sm *sm, void *priv, int id,
req_data = NULL;
req_data_len = 0;
}
- *reqDataLen = sizeof(*req) + 1 + req_data_len;
- req = malloc(*reqDataLen);
+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY, reqDataLen,
+ req_data_len, EAP_CODE_REQUEST, id, &pos);
if (req == NULL) {
wpa_printf(MSG_ERROR, "EAP-Identity: Failed to allocate "
"memory for request");
@@ -85,11 +81,6 @@ static u8 * eap_identity_buildReq(struct eap_sm *sm, void *priv, int id,
return NULL;
}
- req->code = EAP_CODE_REQUEST;
- req->identifier = id;
- req->length = htons(*reqDataLen);
- pos = (u8 *) (req + 1);
- *pos++ = EAP_TYPE_IDENTITY;
if (req_data)
memcpy(pos, req_data, req_data_len);
@@ -100,14 +91,12 @@ static u8 * eap_identity_buildReq(struct eap_sm *sm, void *priv, int id,
static Boolean eap_identity_check(struct eap_sm *sm, void *priv,
u8 *respData, size_t respDataLen)
{
- struct eap_hdr *resp;
- u8 *pos;
+ const u8 *pos;
size_t len;
- resp = (struct eap_hdr *) respData;
- pos = (u8 *) (resp + 1);
- if (respDataLen < sizeof(*resp) + 1 || *pos != EAP_TYPE_IDENTITY ||
- (len = ntohs(resp->length)) > respDataLen) {
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
+ respData, respDataLen, &len);
+ if (pos == NULL) {
wpa_printf(MSG_INFO, "EAP-Identity: Invalid frame");
return TRUE;
}
@@ -120,9 +109,8 @@ static void eap_identity_process(struct eap_sm *sm, void *priv,
u8 *respData, size_t respDataLen)
{
struct eap_identity_data *data = priv;
- struct eap_hdr *resp;
- u8 *pos;
- int len;
+ const u8 *pos;
+ size_t len;
if (data->pick_up) {
if (eap_identity_check(sm, data, respData, respDataLen)) {
@@ -134,15 +122,11 @@ static void eap_identity_process(struct eap_sm *sm, void *priv,
data->pick_up = 0;
}
- resp = (struct eap_hdr *) respData;
- len = ntohs(resp->length);
- pos = (u8 *) (resp + 1);
- pos++;
- len -= sizeof(*resp) + 1;
- if (len < 0) {
- data->state = FAILURE;
- return;
- }
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
+ respData, respDataLen, &len);
+ if (pos == NULL)
+ return; /* Should not happen - frame already validated */
+
wpa_hexdump_ascii(MSG_DEBUG, "EAP-Identity: Peer identity", pos, len);
free(sm->identity);
sm->identity = malloc(len);
@@ -170,16 +154,28 @@ static Boolean eap_identity_isSuccess(struct eap_sm *sm, void *priv)
}
-const struct eap_method eap_method_identity =
+int eap_server_identity_register(void)
{
- .method = EAP_TYPE_IDENTITY,
- .name = "Identity",
- .init = eap_identity_init,
- .initPickUp = eap_identity_initPickUp,
- .reset = eap_identity_reset,
- .buildReq = eap_identity_buildReq,
- .check = eap_identity_check,
- .process = eap_identity_process,
- .isDone = eap_identity_isDone,
- .isSuccess = eap_identity_isSuccess,
-};
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_IDENTITY,
+ "Identity");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_identity_init;
+ eap->initPickUp = eap_identity_initPickUp;
+ eap->reset = eap_identity_reset;
+ eap->buildReq = eap_identity_buildReq;
+ eap->check = eap_identity_check;
+ eap->process = eap_identity_process;
+ eap->isDone = eap_identity_isDone;
+ eap->isSuccess = eap_identity_isSuccess;
+
+ ret = eap_server_method_register(eap);
+ if (ret)
+ eap_server_method_free(eap);
+ return ret;
+}
diff --git a/contrib/hostapd/eap_md5.c b/contrib/hostapd/eap_md5.c
index d776c8c82749..234a319b6909 100644
--- a/contrib/hostapd/eap_md5.c
+++ b/contrib/hostapd/eap_md5.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-MD5 server
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * 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
@@ -12,10 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
#include "hostapd.h"
#include "common.h"
@@ -36,10 +33,9 @@ static void * eap_md5_init(struct eap_sm *sm)
{
struct eap_md5_data *data;
- data = malloc(sizeof(*data));
+ data = wpa_zalloc(sizeof(*data));
if (data == NULL)
- return data;
- memset(data, 0, sizeof(*data));
+ return NULL;
data->state = CONTINUE;
return data;
@@ -66,8 +62,8 @@ static u8 * eap_md5_buildReq(struct eap_sm *sm, void *priv, int id,
return NULL;
}
- *reqDataLen = sizeof(*req) + 2 + CHALLENGE_LEN;
- req = malloc(*reqDataLen);
+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MD5, reqDataLen,
+ 1 + CHALLENGE_LEN, EAP_CODE_REQUEST, id, &pos);
if (req == NULL) {
wpa_printf(MSG_ERROR, "EAP-MD5: Failed to allocate memory for "
"request");
@@ -75,11 +71,6 @@ static u8 * eap_md5_buildReq(struct eap_sm *sm, void *priv, int id,
return NULL;
}
- req->code = EAP_CODE_REQUEST;
- req->identifier = id;
- req->length = htons(*reqDataLen);
- pos = (u8 *) (req + 1);
- *pos++ = EAP_TYPE_MD5;
*pos++ = CHALLENGE_LEN;
memcpy(pos, data->challenge, CHALLENGE_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Challenge", pos, CHALLENGE_LEN);
@@ -93,23 +84,19 @@ static u8 * eap_md5_buildReq(struct eap_sm *sm, void *priv, int id,
static Boolean eap_md5_check(struct eap_sm *sm, void *priv,
u8 *respData, size_t respDataLen)
{
- struct eap_hdr *resp;
- u8 *pos;
+ const u8 *pos;
size_t len;
- resp = (struct eap_hdr *) respData;
- pos = (u8 *) (resp + 1);
- if (respDataLen < sizeof(*resp) + 2 || *pos != EAP_TYPE_MD5 ||
- (len = ntohs(resp->length)) > respDataLen) {
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5,
+ respData, respDataLen, &len);
+ if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-MD5: Invalid frame");
return TRUE;
}
- pos++;
- if (*pos != MD5_MAC_LEN ||
- sizeof(*resp) + 2 + MD5_MAC_LEN > len) {
+ if (*pos != MD5_MAC_LEN || 1 + MD5_MAC_LEN > len) {
wpa_printf(MSG_INFO, "EAP-MD5: Invalid response "
- "(response_len=%d respDataLen=%lu",
- *pos, (unsigned long) respDataLen);
+ "(response_len=%d payload_len=%lu",
+ *pos, (unsigned long) len);
return TRUE;
}
@@ -122,22 +109,28 @@ static void eap_md5_process(struct eap_sm *sm, void *priv,
{
struct eap_md5_data *data = priv;
struct eap_hdr *resp;
- u8 *pos;
+ const u8 *pos;
const u8 *addr[3];
- size_t len[3];
+ size_t len[3], plen;
u8 hash[MD5_MAC_LEN];
- if (sm->user == NULL || sm->user->password == NULL) {
- wpa_printf(MSG_INFO, "EAP-MD5: Password not configured");
+ if (sm->user == NULL || sm->user->password == NULL ||
+ sm->user->password_hash) {
+ wpa_printf(MSG_INFO, "EAP-MD5: Plaintext password not "
+ "configured");
data->state = FAILURE;
return;
}
- resp = (struct eap_hdr *) respData;
- pos = (u8 *) (resp + 1);
- pos += 2; /* Skip type and len */
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MD5,
+ respData, respDataLen, &plen);
+ if (pos == NULL || *pos != MD5_MAC_LEN || plen < 1 + MD5_MAC_LEN)
+ return; /* Should not happen - frame already validated */
+
+ pos++; /* Skip response len */
wpa_hexdump(MSG_MSGDUMP, "EAP-MD5: Response", pos, MD5_MAC_LEN);
+ resp = (struct eap_hdr *) respData;
addr[0] = &resp->identifier;
len[0] = 1;
addr[1] = sm->user->password;
@@ -170,15 +163,26 @@ static Boolean eap_md5_isSuccess(struct eap_sm *sm, void *priv)
}
-const struct eap_method eap_method_md5 =
+int eap_server_md5_register(void)
{
- .method = EAP_TYPE_MD5,
- .name = "MD5",
- .init = eap_md5_init,
- .reset = eap_md5_reset,
- .buildReq = eap_md5_buildReq,
- .check = eap_md5_check,
- .process = eap_md5_process,
- .isDone = eap_md5_isDone,
- .isSuccess = eap_md5_isSuccess,
-};
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_MD5, "MD5");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_md5_init;
+ eap->reset = eap_md5_reset;
+ eap->buildReq = eap_md5_buildReq;
+ eap->check = eap_md5_check;
+ eap->process = eap_md5_process;
+ eap->isDone = eap_md5_isDone;
+ eap->isSuccess = eap_md5_isSuccess;
+
+ ret = eap_server_method_register(eap);
+ if (ret)
+ eap_server_method_free(eap);
+ return ret;
+}
diff --git a/contrib/hostapd/eap_methods.c b/contrib/hostapd/eap_methods.c
new file mode 100644
index 000000000000..671d5486c316
--- /dev/null
+++ b/contrib/hostapd/eap_methods.c
@@ -0,0 +1,273 @@
+/*
+ * hostapd / EAP method registration
+ * 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 "hostapd.h"
+#include "eap_i.h"
+#include "eap_methods.h"
+
+
+static struct eap_method *eap_methods;
+
+
+/**
+ * eap_sm_get_eap_methods - Get EAP method based on type number
+ * @vendor: EAP Vendor-Id (0 = IETF)
+ * @method: EAP type number
+ * Returns: Pointer to EAP method or %NULL if not found
+ */
+const struct eap_method * eap_sm_get_eap_methods(int vendor, EapType method)
+{
+ struct eap_method *m;
+ for (m = eap_methods; m; m = m->next) {
+ if (m->vendor == vendor && m->method == method)
+ return m;
+ }
+ return NULL;
+}
+
+
+/**
+ * eap_get_type - Get EAP type for the given EAP method name
+ * @name: EAP method name, e.g., TLS
+ * @vendor: Buffer for returning EAP Vendor-Id
+ * Returns: EAP method type or %EAP_TYPE_NONE if not found
+ *
+ * This function maps EAP type names into EAP type numbers based on the list of
+ * EAP methods included in the build.
+ */
+EapType eap_get_type(const char *name, int *vendor)
+{
+ struct eap_method *m;
+ for (m = eap_methods; m; m = m->next) {
+ if (strcmp(m->name, name) == 0) {
+ *vendor = m->vendor;
+ return m->method;
+ }
+ }
+ *vendor = EAP_VENDOR_IETF;
+ return EAP_TYPE_NONE;
+}
+
+
+/**
+ * eap_server_method_alloc - Allocate EAP server method structure
+ * @version: Version of the EAP server method interface (set to
+ * EAP_SERVER_METHOD_INTERFACE_VERSION)
+ * @vendor: EAP Vendor-ID (EAP_VENDOR_*) (0 = IETF)
+ * @method: EAP type number (EAP_TYPE_*)
+ * name: Name of the method (e.g., "TLS")
+ * Returns: Allocated EAP method structure or %NULL on failure
+ *
+ * The returned structure should be freed with eap_server_method_free() when it
+ * is not needed anymore.
+ */
+struct eap_method * eap_server_method_alloc(int version, int vendor,
+ EapType method, const char *name)
+{
+ struct eap_method *eap;
+ eap = wpa_zalloc(sizeof(*eap));
+ if (eap == NULL)
+ return NULL;
+ eap->version = version;
+ eap->vendor = vendor;
+ eap->method = method;
+ eap->name = name;
+ return eap;
+}
+
+
+/**
+ * eap_server_method_free - Free EAP server method structure
+ * @method: Method structure allocated with eap_server_method_alloc()
+ */
+void eap_server_method_free(struct eap_method *method)
+{
+ free(method);
+}
+
+
+/**
+ * eap_server_method_register - Register an EAP server method
+ * @method: EAP method to register
+ * Returns: 0 on success, -1 on invalid method, or -2 if a matching EAP method
+ * has already been registered
+ *
+ * Each EAP server method needs to call this function to register itself as a
+ * supported EAP method.
+ */
+int eap_server_method_register(struct eap_method *method)
+{
+ struct eap_method *m, *last = NULL;
+
+ if (method == NULL || method->name == NULL ||
+ method->version != EAP_SERVER_METHOD_INTERFACE_VERSION)
+ return -1;
+
+ for (m = eap_methods; m; m = m->next) {
+ if ((m->vendor == method->vendor &&
+ m->method == method->method) ||
+ strcmp(m->name, method->name) == 0)
+ return -2;
+ last = m;
+ }
+
+ if (last)
+ last->next = method;
+ else
+ eap_methods = method;
+
+ return 0;
+}
+
+
+/**
+ * eap_server_register_methods - Register statically linked EAP server methods
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is called at program initialization to register all EAP server
+ * methods that were linked in statically.
+ */
+int eap_server_register_methods(void)
+{
+ int ret = 0;
+
+ if (ret == 0) {
+ int eap_server_identity_register(void);
+ ret = eap_server_identity_register();
+ }
+
+#ifdef EAP_MD5
+ if (ret == 0) {
+ int eap_server_md5_register(void);
+ ret = eap_server_md5_register();
+ }
+#endif /* EAP_MD5 */
+
+#ifdef EAP_TLS
+ if (ret == 0) {
+ int eap_server_tls_register(void);
+ ret = eap_server_tls_register();
+ }
+#endif /* EAP_TLS */
+
+#ifdef EAP_MSCHAPv2
+ if (ret == 0) {
+ int eap_server_mschapv2_register(void);
+ ret = eap_server_mschapv2_register();
+ }
+#endif /* EAP_MSCHAPv2 */
+
+#ifdef EAP_PEAP
+ if (ret == 0) {
+ int eap_server_peap_register(void);
+ ret = eap_server_peap_register();
+ }
+#endif /* EAP_PEAP */
+
+#ifdef EAP_TLV
+ if (ret == 0) {
+ int eap_server_tlv_register(void);
+ ret = eap_server_tlv_register();
+ }
+#endif /* EAP_TLV */
+
+#ifdef EAP_GTC
+ if (ret == 0) {
+ int eap_server_gtc_register(void);
+ ret = eap_server_gtc_register();
+ }
+#endif /* EAP_GTC */
+
+#ifdef EAP_TTLS
+ if (ret == 0) {
+ int eap_server_ttls_register(void);
+ ret = eap_server_ttls_register();
+ }
+#endif /* EAP_TTLS */
+
+#ifdef EAP_SIM
+ if (ret == 0) {
+ int eap_server_sim_register(void);
+ ret = eap_server_sim_register();
+ }
+#endif /* EAP_SIM */
+
+#ifdef EAP_AKA
+ if (ret == 0) {
+ int eap_server_aka_register(void);
+ ret = eap_server_aka_register();
+ }
+#endif /* EAP_AKA */
+
+#ifdef EAP_PAX
+ if (ret == 0) {
+ int eap_server_pax_register(void);
+ ret = eap_server_pax_register();
+ }
+#endif /* EAP_PAX */
+
+#ifdef EAP_PSK
+ if (ret == 0) {
+ int eap_server_psk_register(void);
+ ret = eap_server_psk_register();
+ }
+#endif /* EAP_PSK */
+
+#ifdef EAP_SAKE
+ if (ret == 0) {
+ int eap_server_sake_register(void);
+ ret = eap_server_sake_register();
+ }
+#endif /* EAP_SAKE */
+
+#ifdef EAP_GPSK
+ if (ret == 0) {
+ int eap_server_gpsk_register(void);
+ ret = eap_server_gpsk_register();
+ }
+#endif /* EAP_GPSK */
+
+#ifdef EAP_VENDOR_TEST
+ if (ret == 0) {
+ int eap_server_vendor_test_register(void);
+ ret = eap_server_vendor_test_register();
+ }
+#endif /* EAP_VENDOR_TEST */
+
+ return ret;
+}
+
+
+/**
+ * eap_server_unregister_methods - Unregister EAP server methods
+ *
+ * This function is called at program termination to unregister all EAP server
+ * methods.
+ */
+void eap_server_unregister_methods(void)
+{
+ struct eap_method *m;
+
+ while (eap_methods) {
+ m = eap_methods;
+ eap_methods = eap_methods->next;
+
+ if (m->free)
+ m->free(m);
+ else
+ eap_server_method_free(m);
+ }
+}
diff --git a/contrib/hostapd/eap_methods.h b/contrib/hostapd/eap_methods.h
new file mode 100644
index 000000000000..cec8a570e2a6
--- /dev/null
+++ b/contrib/hostapd/eap_methods.h
@@ -0,0 +1,49 @@
+/*
+ * hostapd / EAP method registration
+ * 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.
+ */
+
+#ifndef EAP_METHODS_H
+#define EAP_METHODS_H
+
+const struct eap_method * eap_sm_get_eap_methods(int vendor, EapType method);
+struct eap_method * eap_server_method_alloc(int version, int vendor,
+ EapType method, const char *name);
+void eap_server_method_free(struct eap_method *method);
+int eap_server_method_register(struct eap_method *method);
+
+#ifdef EAP_SERVER
+
+EapType eap_get_type(const char *name, int *vendor);
+int eap_server_register_methods(void);
+void eap_server_unregister_methods(void);
+
+#else /* EAP_SERVER */
+
+static inline EapType eap_get_type(const char *name, int *vendor)
+{
+ *vendor = EAP_VENDOR_IETF;
+ return EAP_TYPE_NONE;
+}
+
+static inline int eap_server_register_methods(void)
+{
+ return 0;
+}
+
+static inline void eap_server_unregister_methods(void)
+{
+}
+
+#endif /* EAP_SERVER */
+
+#endif /* EAP_METHODS_H */
diff --git a/contrib/hostapd/eap_mschapv2.c b/contrib/hostapd/eap_mschapv2.c
index 5cbf6eb71289..bbd819bbe12b 100644
--- a/contrib/hostapd/eap_mschapv2.c
+++ b/contrib/hostapd/eap_mschapv2.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-MSCHAPv2 (draft-kamath-pppext-eap-mschapv2-00.txt) server
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * 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
@@ -12,10 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
#include "hostapd.h"
#include "common.h"
@@ -24,16 +21,12 @@
struct eap_mschapv2_hdr {
- u8 code;
- u8 identifier;
- u16 length; /* including code, identifier, and length */
- u8 type; /* EAP_TYPE_MSCHAPV2 */
u8 op_code; /* MSCHAPV2_OP_* */
u8 mschapv2_id; /* must be changed for challenges, but not for
* success/failure */
u8 ms_length[2]; /* Note: misaligned; length - 5 */
/* followed by data */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
#define MSCHAPV2_OP_CHALLENGE 1
#define MSCHAPV2_OP_RESPONSE 2
@@ -51,6 +44,7 @@ struct eap_mschapv2_hdr {
#define ERROR_CHANGING_PASSWORD 709
#define PASSWD_CHANGE_CHAL_LEN 16
+#define MSCHAPV2_KEY_LEN 16
#define CHALLENGE_LEN 16
@@ -60,6 +54,8 @@ struct eap_mschapv2_data {
u8 auth_response[20];
enum { CHALLENGE, SUCCESS_REQ, FAILURE_REQ, SUCCESS, FAILURE } state;
u8 resp_mschapv2_id;
+ u8 master_key[16];
+ int master_key_valid;
};
@@ -67,10 +63,9 @@ static void * eap_mschapv2_init(struct eap_sm *sm)
{
struct eap_mschapv2_data *data;
- data = malloc(sizeof(*data));
+ data = wpa_zalloc(sizeof(*data));
if (data == NULL)
- return data;
- memset(data, 0, sizeof(*data));
+ return NULL;
data->state = CHALLENGE;
return data;
@@ -88,9 +83,11 @@ static u8 * eap_mschapv2_build_challenge(struct eap_sm *sm,
struct eap_mschapv2_data *data,
int id, size_t *reqDataLen)
{
- struct eap_mschapv2_hdr *req;
+ struct eap_hdr *req;
+ struct eap_mschapv2_hdr *ms;
u8 *pos;
char *name = "hostapd"; /* TODO: make this configurable */
+ size_t ms_len;
if (hostapd_get_rand(data->auth_challenge, CHALLENGE_LEN)) {
wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to get random "
@@ -99,8 +96,9 @@ static u8 * eap_mschapv2_build_challenge(struct eap_sm *sm,
return NULL;
}
- *reqDataLen = sizeof(*req) + 1 + CHALLENGE_LEN + strlen(name);
- req = malloc(*reqDataLen);
+ ms_len = sizeof(*ms) + 1 + CHALLENGE_LEN + strlen(name);
+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqDataLen,
+ ms_len, EAP_CODE_REQUEST, id, &pos);
if (req == NULL) {
wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
" for request");
@@ -108,15 +106,12 @@ static u8 * eap_mschapv2_build_challenge(struct eap_sm *sm,
return NULL;
}
- req->code = EAP_CODE_REQUEST;
- req->identifier = id;
- req->length = htons(*reqDataLen);
- req->type = EAP_TYPE_MSCHAPV2;
- req->op_code = MSCHAPV2_OP_CHALLENGE;
- req->mschapv2_id = id;
- req->ms_length[0] = (*reqDataLen - 5) >> 8;
- req->ms_length[1] = (*reqDataLen - 5) & 0xff;
- pos = (u8 *) (req + 1);
+ ms = (struct eap_mschapv2_hdr *) pos;
+ ms->op_code = MSCHAPV2_OP_CHALLENGE;
+ ms->mschapv2_id = id;
+ WPA_PUT_BE16(ms->ms_length, ms_len);
+
+ pos = (u8 *) (ms + 1);
*pos++ = CHALLENGE_LEN;
memcpy(pos, data->auth_challenge, CHALLENGE_LEN);
wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Challenge", pos,
@@ -132,15 +127,16 @@ static u8 * eap_mschapv2_build_success_req(struct eap_sm *sm,
struct eap_mschapv2_data *data,
int id, size_t *reqDataLen)
{
- struct eap_mschapv2_hdr *req;
- u8 *pos, *msg, *end;
+ struct eap_hdr *req;
+ struct eap_mschapv2_hdr *ms;
+ u8 *pos, *msg;
char *message = "OK";
- size_t msg_len;
- int i;
+ size_t ms_len;
- msg_len = 2 + 2 * sizeof(data->auth_response) + 3 + strlen(message);
- *reqDataLen = sizeof(*req) + msg_len;
- req = malloc(*reqDataLen + 1);
+ ms_len = sizeof(*ms) + 2 + 2 * sizeof(data->auth_response) + 1 + 2 +
+ strlen(message);
+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqDataLen,
+ ms_len, EAP_CODE_REQUEST, id, &pos);
if (req == NULL) {
wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
" for request");
@@ -148,27 +144,25 @@ static u8 * eap_mschapv2_build_success_req(struct eap_sm *sm,
return NULL;
}
- req->code = EAP_CODE_REQUEST;
- req->identifier = id;
- req->length = htons(*reqDataLen);
- req->type = EAP_TYPE_MSCHAPV2;
- req->op_code = MSCHAPV2_OP_SUCCESS;
- req->mschapv2_id = data->resp_mschapv2_id;
- req->ms_length[0] = (*reqDataLen - 5) >> 8;
- req->ms_length[1] = (*reqDataLen - 5) & 0xff;
-
- msg = pos = (u8 *) (req + 1);
- end = ((u8 *) req) + *reqDataLen + 1;
-
- pos += snprintf((char *) pos, end - pos, "S=");
- for (i = 0; i < sizeof(data->auth_response); i++) {
- pos += snprintf((char *) pos, end - pos, "%02X",
- data->auth_response[i]);
- }
- pos += snprintf((char *) pos, end - pos, " M=%s", message);
+ ms = (struct eap_mschapv2_hdr *) pos;
+ ms->op_code = MSCHAPV2_OP_SUCCESS;
+ ms->mschapv2_id = data->resp_mschapv2_id;
+ WPA_PUT_BE16(ms->ms_length, ms_len);
+
+ msg = pos = (u8 *) (ms + 1);
+ *pos++ = 'S';
+ *pos++ = '=';
+ pos += wpa_snprintf_hex_uppercase((char *) pos,
+ sizeof(data->auth_response) * 2 + 1,
+ data->auth_response,
+ sizeof(data->auth_response));
+ *pos++ = ' ';
+ *pos++ = 'M';
+ *pos++ = '=';
+ memcpy(pos, message, strlen(message));
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Success Request Message",
- msg, msg_len);
+ msg, ms_len - sizeof(*ms));
return (u8 *) req;
}
@@ -178,15 +172,16 @@ static u8 * eap_mschapv2_build_failure_req(struct eap_sm *sm,
struct eap_mschapv2_data *data,
int id, size_t *reqDataLen)
{
- struct eap_mschapv2_hdr *req;
+ struct eap_hdr *req;
+ struct eap_mschapv2_hdr *ms;
u8 *pos;
char *message = "E=691 R=0 C=00000000000000000000000000000000 V=3 "
"M=FAILED";
- size_t msg_len;
+ size_t ms_len;
- msg_len = strlen(message);
- *reqDataLen = sizeof(*req) + msg_len;
- req = malloc(*reqDataLen + 1);
+ ms_len = sizeof(*ms) + strlen(message);
+ req = eap_msg_alloc(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2, reqDataLen,
+ ms_len, EAP_CODE_REQUEST, id, &pos);
if (req == NULL) {
wpa_printf(MSG_ERROR, "EAP-MSCHAPV2: Failed to allocate memory"
" for request");
@@ -194,20 +189,15 @@ static u8 * eap_mschapv2_build_failure_req(struct eap_sm *sm,
return NULL;
}
- req->code = EAP_CODE_REQUEST;
- req->identifier = id;
- req->length = htons(*reqDataLen);
- req->type = EAP_TYPE_MSCHAPV2;
- req->op_code = MSCHAPV2_OP_FAILURE;
- req->mschapv2_id = data->resp_mschapv2_id;
- req->ms_length[0] = (*reqDataLen - 5) >> 8;
- req->ms_length[1] = (*reqDataLen - 5) & 0xff;
+ ms = (struct eap_mschapv2_hdr *) pos;
+ ms->op_code = MSCHAPV2_OP_FAILURE;
+ ms->mschapv2_id = data->resp_mschapv2_id;
+ WPA_PUT_BE16(ms->ms_length, ms_len);
- pos = (u8 *) (req + 1);
- memcpy(pos, message, msg_len);
+ memcpy((u8 *) (ms + 1), message, strlen(message));
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: Failure Request Message",
- (u8 *) message, msg_len);
+ (u8 *) message, strlen(message));
return (u8 *) req;
}
@@ -241,17 +231,17 @@ static Boolean eap_mschapv2_check(struct eap_sm *sm, void *priv,
{
struct eap_mschapv2_data *data = priv;
struct eap_mschapv2_hdr *resp;
- u8 *pos;
+ const u8 *pos;
size_t len;
- resp = (struct eap_mschapv2_hdr *) respData;
- pos = (u8 *) (resp + 1);
- if (respDataLen < 6 || resp->type != EAP_TYPE_MSCHAPV2 ||
- (len = ntohs(resp->length)) > respDataLen) {
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
+ respData, respDataLen, &len);
+ if (pos == NULL || len < 1) {
wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Invalid frame");
return TRUE;
}
+ resp = (struct eap_mschapv2_hdr *) pos;
if (data->state == CHALLENGE &&
resp->op_code != MSCHAPV2_OP_RESPONSE) {
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Expected Response - "
@@ -283,18 +273,23 @@ static void eap_mschapv2_process_response(struct eap_sm *sm,
u8 *respData, size_t respDataLen)
{
struct eap_mschapv2_hdr *resp;
- u8 *pos;
- u8 *peer_challenge, *nt_response, flags, *name;
- size_t name_len;
+ const u8 *pos, *end, *peer_challenge, *nt_response, *name;
+ u8 flags;
+ size_t len, name_len, i;
u8 expected[24];
- int i;
- u8 *username, *user;
+ const u8 *username, *user;
size_t username_len, user_len;
- resp = (struct eap_mschapv2_hdr *) respData;
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
+ respData, respDataLen, &len);
+ if (pos == NULL || len < 1)
+ return; /* Should not happen - frame already validated */
+
+ end = pos + len;
+ resp = (struct eap_mschapv2_hdr *) pos;
pos = (u8 *) (resp + 1);
- if (respDataLen < sizeof(resp) + 1 + 49 ||
+ if (len < sizeof(*resp) + 1 + 49 ||
resp->op_code != MSCHAPV2_OP_RESPONSE ||
pos[0] != 49) {
wpa_hexdump(MSG_DEBUG, "EAP-MSCHAPV2: Invalid response",
@@ -310,7 +305,7 @@ static void eap_mschapv2_process_response(struct eap_sm *sm,
pos += 24;
flags = *pos++;
name = pos;
- name_len = respData + respDataLen - name;
+ name_len = end - name;
wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Peer-Challenge",
peer_challenge, 16);
@@ -355,26 +350,55 @@ static void eap_mschapv2_process_response(struct eap_sm *sm,
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-MSCHAPV2: User name",
username, username_len);
- generate_nt_response(data->auth_challenge, peer_challenge,
- username, username_len,
- sm->user->password, sm->user->password_len,
- expected);
+ if (sm->user->password_hash) {
+ generate_nt_response_pwhash(data->auth_challenge,
+ peer_challenge,
+ username, username_len,
+ sm->user->password,
+ expected);
+ } else {
+ generate_nt_response(data->auth_challenge, peer_challenge,
+ username, username_len,
+ sm->user->password,
+ sm->user->password_len,
+ expected);
+ }
if (memcmp(nt_response, expected, 24) == 0) {
+ const u8 *pw_hash;
+ u8 pw_hash_buf[16], pw_hash_hash[16];
+
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Correct NT-Response");
data->state = SUCCESS_REQ;
-
/* Authenticator response is not really needed yet, but
* calculate it here so that peer_challenge and username need
* not be saved. */
- generate_authenticator_response(sm->user->password,
- sm->user->password_len,
- peer_challenge,
- data->auth_challenge,
- username, username_len,
- nt_response,
- data->auth_response);
+ if (sm->user->password_hash) {
+ pw_hash = sm->user->password;
+ generate_authenticator_response_pwhash(
+ sm->user->password, peer_challenge,
+ data->auth_challenge, username, username_len,
+ nt_response, data->auth_response);
+ } else {
+ nt_password_hash(sm->user->password,
+ sm->user->password_len,
+ pw_hash_buf);
+ pw_hash = pw_hash_buf;
+ generate_authenticator_response(sm->user->password,
+ sm->user->password_len,
+ peer_challenge,
+ data->auth_challenge,
+ username, username_len,
+ nt_response,
+ data->auth_response);
+ }
+
+ hash_nt_password_hash(pw_hash, pw_hash_hash);
+ get_master_key(pw_hash_hash, nt_response, data->master_key);
+ data->master_key_valid = 1;
+ wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived Master Key",
+ data->master_key, MSCHAPV2_KEY_LEN);
} else {
wpa_hexdump(MSG_MSGDUMP, "EAP-MSCHAPV2: Expected NT-Response",
expected, 24);
@@ -389,8 +413,15 @@ static void eap_mschapv2_process_success_resp(struct eap_sm *sm,
u8 *respData, size_t respDataLen)
{
struct eap_mschapv2_hdr *resp;
+ const u8 *pos;
+ size_t len;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
+ respData, respDataLen, &len);
+ if (pos == NULL || len < 1)
+ return; /* Should not happen - frame already validated */
- resp = (struct eap_mschapv2_hdr *) respData;
+ resp = (struct eap_mschapv2_hdr *) pos;
if (resp->op_code == MSCHAPV2_OP_SUCCESS) {
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Success Response"
@@ -409,8 +440,15 @@ static void eap_mschapv2_process_failure_resp(struct eap_sm *sm,
u8 *respData, size_t respDataLen)
{
struct eap_mschapv2_hdr *resp;
+ const u8 *pos;
+ size_t len;
+
+ pos = eap_hdr_validate(EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
+ respData, respDataLen, &len);
+ if (pos == NULL || len < 1)
+ return; /* Should not happen - frame already validated */
- resp = (struct eap_mschapv2_hdr *) respData;
+ resp = (struct eap_mschapv2_hdr *) pos;
if (resp->op_code == MSCHAPV2_OP_FAILURE) {
wpa_printf(MSG_DEBUG, "EAP-MSCHAPV2: Received Failure Response"
@@ -462,6 +500,27 @@ static Boolean eap_mschapv2_isDone(struct eap_sm *sm, void *priv)
}
+static u8 * eap_mschapv2_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_mschapv2_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS || !data->master_key_valid)
+ return NULL;
+
+ *len = 2 * MSCHAPV2_KEY_LEN;
+ key = malloc(*len);
+ if (key == NULL)
+ return NULL;
+ get_asymetric_start_key(data->master_key, key, MSCHAPV2_KEY_LEN, 0, 0);
+ get_asymetric_start_key(data->master_key, key + MSCHAPV2_KEY_LEN,
+ MSCHAPV2_KEY_LEN, 1, 0);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-MSCHAPV2: Derived key", key, *len);
+
+ return key;
+}
+
+
static Boolean eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_mschapv2_data *data = priv;
@@ -469,15 +528,28 @@ static Boolean eap_mschapv2_isSuccess(struct eap_sm *sm, void *priv)
}
-const struct eap_method eap_method_mschapv2 =
+int eap_server_mschapv2_register(void)
{
- .method = EAP_TYPE_MSCHAPV2,
- .name = "MSCHAPV2",
- .init = eap_mschapv2_init,
- .reset = eap_mschapv2_reset,
- .buildReq = eap_mschapv2_buildReq,
- .check = eap_mschapv2_check,
- .process = eap_mschapv2_process,
- .isDone = eap_mschapv2_isDone,
- .isSuccess = eap_mschapv2_isSuccess,
-};
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_MSCHAPV2,
+ "MSCHAPV2");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_mschapv2_init;
+ eap->reset = eap_mschapv2_reset;
+ eap->buildReq = eap_mschapv2_buildReq;
+ eap->check = eap_mschapv2_check;
+ eap->process = eap_mschapv2_process;
+ eap->isDone = eap_mschapv2_isDone;
+ eap->getKey = eap_mschapv2_getKey;
+ eap->isSuccess = eap_mschapv2_isSuccess;
+
+ ret = eap_server_method_register(eap);
+ if (ret)
+ eap_server_method_free(eap);
+ return ret;
+}
diff --git a/contrib/hostapd/eap_pax.c b/contrib/hostapd/eap_pax.c
index 2fbec870c9f1..8daa8d3adb04 100644
--- a/contrib/hostapd/eap_pax.c
+++ b/contrib/hostapd/eap_pax.c
@@ -1,6 +1,6 @@
/*
- * hostapd / EAP-PAX (draft-clancy-eap-pax-04.txt) server
- * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * hostapd / EAP-PAX (RFC 4746) server
+ * 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
@@ -12,10 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
#include "hostapd.h"
#include "common.h"
@@ -24,6 +21,11 @@
/*
* Note: only PAX_STD subprotocol is currently supported
+ *
+ * TODO: Add support with PAX_SEC with the mandatory to implement ciphersuite
+ * (HMAC_SHA1_128, IANA DH Group 14 (2048 bits), RSA-PKCS1-V1_5) and
+ * recommended ciphersuite (HMAC_SHA256_128, IANA DH Group 15 (3072 bits),
+ * RSAES-OAEP).
*/
struct eap_pax_data {
@@ -50,13 +52,12 @@ static void * eap_pax_init(struct eap_sm *sm)
{
struct eap_pax_data *data;
- data = malloc(sizeof(*data));
+ data = wpa_zalloc(sizeof(*data));
if (data == NULL)
- return data;
- memset(data, 0, sizeof(*data));
+ return NULL;
data->state = PAX_STD_1;
/*
- * TODO: make this configurable once EAP_PAX_MAC_AES_CBC_MAC_128 is
+ * TODO: make this configurable once EAP_PAX_HMAC_SHA256_128 is
* supported
*/
data->mac_id = EAP_PAX_MAC_HMAC_SHA1_128;
@@ -161,6 +162,8 @@ static u8 * eap_pax_build_std_3(struct eap_sm *sm,
pos, EAP_PAX_MAC_LEN);
pos += EAP_PAX_MAC_LEN;
+ /* Optional ADE could be added here, if needed */
+
eap_pax_mac(data->mac_id, data->ick, EAP_PAX_ICK_LEN,
(u8 *) req, *reqDataLen - EAP_PAX_ICV_LEN,
NULL, 0, NULL, 0, pos);
@@ -319,7 +322,7 @@ static void eap_pax_process_std_2(struct eap_sm *sm,
pos += EAP_PAX_RAND_LEN;
left -= EAP_PAX_RAND_LEN;
- if (left < 2 || 2 + ((pos[0] << 8) | pos[1]) > left) {
+ if (left < 2 || (size_t) 2 + ((pos[0] << 8) | pos[1]) > left) {
wpa_printf(MSG_INFO, "EAP-PAX: Too short PAX_STD-2 (CID)");
return;
}
@@ -331,7 +334,7 @@ static void eap_pax_process_std_2(struct eap_sm *sm,
"CID");
return;
}
- memcpy (data->cid, pos + 2, data->cid_len);
+ memcpy(data->cid, pos + 2, data->cid_len);
pos += 2 + data->cid_len;
left -= 2 + data->cid_len;
wpa_hexdump_ascii(MSG_MSGDUMP, "EAP-PAX: CID",
@@ -355,13 +358,18 @@ static void eap_pax_process_std_2(struct eap_sm *sm,
}
for (i = 0;
- i < EAP_MAX_METHODS && sm->user->methods[i] != EAP_TYPE_NONE;
+ i < EAP_MAX_METHODS &&
+ (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
+ sm->user->methods[i].method != EAP_TYPE_NONE);
i++) {
- if (sm->user->methods[i] == EAP_TYPE_PAX)
+ if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
+ sm->user->methods[i].method == EAP_TYPE_PAX)
break;
}
- if (sm->user->methods[i] != EAP_TYPE_PAX) {
+ if (i >= EAP_MAX_METHODS ||
+ sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
+ sm->user->methods[i].method != EAP_TYPE_PAX) {
wpa_hexdump_ascii(MSG_DEBUG,
"EAP-PAX: EAP-PAX not enabled for CID",
(u8 *) data->cid, data->cid_len);
@@ -451,7 +459,8 @@ static void eap_pax_process(struct eap_sm *sm, void *priv,
struct eap_pax_hdr *resp;
if (sm->user == NULL || sm->user->password == NULL) {
- wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
+ wpa_printf(MSG_INFO, "EAP-PAX: Plaintext password not "
+ "configured");
data->state = FAILURE;
return;
}
@@ -484,14 +493,36 @@ static u8 * eap_pax_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = malloc(EAP_PAX_MSK_LEN);
+ key = malloc(EAP_MSK_LEN);
if (key == NULL)
return NULL;
- *len = EAP_PAX_MSK_LEN;
+ *len = EAP_MSK_LEN;
eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
"Master Session Key", data->rand.e, 2 * EAP_PAX_RAND_LEN,
- EAP_PAX_MSK_LEN, key);
+ EAP_MSK_LEN, key);
+
+ return key;
+}
+
+
+static u8 * eap_pax_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_pax_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+
+ *len = EAP_EMSK_LEN;
+ eap_pax_kdf(data->mac_id, data->mk, EAP_PAX_MK_LEN,
+ "Extended Master Session Key",
+ data->rand.e, 2 * EAP_PAX_RAND_LEN,
+ EAP_EMSK_LEN, key);
return key;
}
@@ -504,16 +535,28 @@ static Boolean eap_pax_isSuccess(struct eap_sm *sm, void *priv)
}
-const struct eap_method eap_method_pax =
+int eap_server_pax_register(void)
{
- .method = EAP_TYPE_PAX,
- .name = "PAX",
- .init = eap_pax_init,
- .reset = eap_pax_reset,
- .buildReq = eap_pax_buildReq,
- .check = eap_pax_check,
- .process = eap_pax_process,
- .isDone = eap_pax_isDone,
- .getKey = eap_pax_getKey,
- .isSuccess = eap_pax_isSuccess,
-};
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_PAX, "PAX");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_pax_init;
+ eap->reset = eap_pax_reset;
+ eap->buildReq = eap_pax_buildReq;
+ eap->check = eap_pax_check;
+ eap->process = eap_pax_process;
+ eap->isDone = eap_pax_isDone;
+ eap->getKey = eap_pax_getKey;
+ eap->isSuccess = eap_pax_isSuccess;
+ eap->get_emsk = eap_pax_get_emsk;
+
+ ret = eap_server_method_register(eap);
+ if (ret)
+ eap_server_method_free(eap);
+ return ret;
+}
diff --git a/contrib/hostapd/eap_pax_common.c b/contrib/hostapd/eap_pax_common.c
index d8f4016a6a09..80110469dcc3 100644
--- a/contrib/hostapd/eap_pax_common.c
+++ b/contrib/hostapd/eap_pax_common.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-PAX shared routines
- * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP server/peer: EAP-PAX shared routines
+ * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,9 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "sha1.h"
@@ -33,7 +31,7 @@
* @output: Buffer for the derived key
* Returns: 0 on success, -1 failed
*
- * draft-clancy-eap-pax-04.txt, chap. 2.5: PAX-KDF-W(X, Y, Z)
+ * RFC 4746, Section 2.6: PAX-KDF-W(X, Y, Z)
*/
int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
const char *identifier,
@@ -50,12 +48,12 @@ int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
if (identifier == NULL || num_blocks >= 255)
return -1;
- /* TODO: add support for EAP_PAX_MAC_AES_CBC_MAC_128 */
+ /* TODO: add support for EAP_PAX_HMAC_SHA256_128 */
if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128)
return -1;
addr[0] = (const u8 *) identifier;
- len[0] = strlen(identifier);
+ len[0] = os_strlen(identifier);
addr[1] = entropy;
len[1] = entropy_len;
addr[2] = &counter;
@@ -66,7 +64,7 @@ int eap_pax_kdf(u8 mac_id, const u8 *key, size_t key_len,
for (counter = 1; counter <= (u8) num_blocks; counter++) {
size_t clen = left > EAP_PAX_MAC_LEN ? EAP_PAX_MAC_LEN : left;
hmac_sha1_vector(key, key_len, 3, addr, len, mac);
- memcpy(pos, mac, clen);
+ os_memcpy(pos, mac, clen);
pos += clen;
left -= clen;
}
@@ -102,7 +100,7 @@ int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
size_t len[3];
size_t count;
- /* TODO: add support for EAP_PAX_MAC_AES_CBC_MAC_128 */
+ /* TODO: add support for EAP_PAX_HMAC_SHA256_128 */
if (mac_id != EAP_PAX_MAC_HMAC_SHA1_128)
return -1;
@@ -115,7 +113,7 @@ int eap_pax_mac(u8 mac_id, const u8 *key, size_t key_len,
count = (data1 ? 1 : 0) + (data2 ? 1 : 0) + (data3 ? 1 : 0);
hmac_sha1_vector(key, key_len, count, addr, len, hash);
- memcpy(mac, hash, EAP_PAX_MAC_LEN);
+ os_memcpy(mac, hash, EAP_PAX_MAC_LEN);
return 0;
}
diff --git a/contrib/hostapd/eap_pax_common.h b/contrib/hostapd/eap_pax_common.h
index b5ad6af1f2b9..bbad5e4052ff 100644
--- a/contrib/hostapd/eap_pax_common.h
+++ b/contrib/hostapd/eap_pax_common.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-PAX shared routines
- * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP server/peer: EAP-PAX shared routines
+ * 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
@@ -15,6 +15,10 @@
#ifndef EAP_PAX_COMMON_H
#define EAP_PAX_COMMON_H
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
struct eap_pax_hdr {
u8 code;
u8 identifier;
@@ -26,7 +30,11 @@ struct eap_pax_hdr {
u8 dh_group_id;
u8 public_key_id;
/* Followed by variable length payload and ICV */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
/* op_code: */
@@ -45,22 +53,31 @@ enum {
/* flags: */
#define EAP_PAX_FLAGS_MF 0x01
#define EAP_PAX_FLAGS_CE 0x02
+#define EAP_PAX_FLAGS_AI 0x04
/* mac_id: */
#define EAP_PAX_MAC_HMAC_SHA1_128 0x01
-#define EAP_PAX_MAC_AES_CBC_MAC_128 0x02
+#define EAP_PAX_HMAC_SHA256_128 0x02
/* dh_group_id: */
#define EAP_PAX_DH_GROUP_NONE 0x00
-#define EAP_PAX_DH_GROUP_3072_MODP 0x01
+#define EAP_PAX_DH_GROUP_2048_MODP 0x01
+#define EAP_PAX_DH_GROUP_3072_MODP 0x02
+#define EAP_PAX_DH_GROUP_NIST_ECC_P_256 0x03
/* public_key_id: */
#define EAP_PAX_PUBLIC_KEY_NONE 0x00
-#define EAP_PAX_PUBLIC_KEY_RSA_OAEP_2048 0x01
+#define EAP_PAX_PUBLIC_KEY_RSAES_OAEP 0x01
+#define EAP_PAX_PUBLIC_KEY_RSA_PKCS1_V1_5 0x02
+#define EAP_PAX_PUBLIC_KEY_EL_GAMAL_NIST_ECC 0x03
+
+/* ADE type: */
+#define EAP_PAX_ADE_VENDOR_SPECIFIC 0x01
+#define EAP_PAX_ADE_CLIENT_CHANNEL_BINDING 0x02
+#define EAP_PAX_ADE_SERVER_CHANNEL_BINDING 0x03
#define EAP_PAX_RAND_LEN 32
-#define EAP_PAX_MSK_LEN 64
#define EAP_PAX_MAC_LEN 16
#define EAP_PAX_ICV_LEN 16
#define EAP_PAX_AK_LEN 16
diff --git a/contrib/hostapd/eap_peap.c b/contrib/hostapd/eap_peap.c
index 9eb61a6b132f..6ea1f618a1d8 100644
--- a/contrib/hostapd/eap_peap.c
+++ b/contrib/hostapd/eap_peap.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-PEAP (draft-josefsson-pppext-eap-tls-eap-07.txt)
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * 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
@@ -12,10 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
#include "hostapd.h"
#include "common.h"
@@ -132,10 +129,9 @@ static void * eap_peap_init(struct eap_sm *sm)
{
struct eap_peap_data *data;
- data = malloc(sizeof(*data));
+ data = wpa_zalloc(sizeof(*data));
if (data == NULL)
- return data;
- memset(data, 0, sizeof(*data));
+ return NULL;
data->peap_version = EAP_PEAP_VERSION;
data->force_version = -1;
if (sm->user && sm->user->force_version >= 0) {
@@ -293,12 +289,10 @@ static u8 * eap_peap_build_phase2_term(struct eap_sm *sm,
struct eap_hdr *hdr;
req_len = sizeof(*hdr);
- hdr = malloc(req_len);
- if (hdr == NULL) {
+ hdr = wpa_zalloc(req_len);
+ if (hdr == NULL)
return NULL;
- }
- memset(hdr, 0, req_len);
hdr->code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
hdr->identifier = id;
hdr->length = htons(req_len);
@@ -345,12 +339,11 @@ static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
{
struct eap_hdr *resp;
u8 *pos;
- size_t len;
resp = (struct eap_hdr *) respData;
pos = (u8 *) (resp + 1);
if (respDataLen < sizeof(*resp) + 2 || *pos != EAP_TYPE_PEAP ||
- (len = ntohs(resp->length)) > respDataLen) {
+ (ntohs(resp->length)) > respDataLen) {
wpa_printf(MSG_INFO, "EAP-PEAP: Invalid frame");
return TRUE;
}
@@ -360,14 +353,15 @@ static Boolean eap_peap_check(struct eap_sm *sm, void *priv,
static int eap_peap_phase2_init(struct eap_sm *sm, struct eap_peap_data *data,
- u8 eap_type)
+ EapType eap_type)
{
if (data->phase2_priv && data->phase2_method) {
data->phase2_method->reset(sm, data->phase2_priv);
data->phase2_method = NULL;
data->phase2_priv = NULL;
}
- data->phase2_method = eap_sm_get_eap_methods(eap_type);
+ data->phase2_method = eap_sm_get_eap_methods(EAP_VENDOR_IETF,
+ eap_type);
if (!data->phase2_method)
return -1;
@@ -395,17 +389,17 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
hdr = (struct eap_hdr *) in_data;
pos = (u8 *) (hdr + 1);
- left = in_len - sizeof(*hdr);
if (in_len > sizeof(*hdr) && *pos == EAP_TYPE_NAK) {
+ left = in_len - sizeof(*hdr);
wpa_hexdump(MSG_DEBUG, "EAP-PEAP: Phase2 type Nak'ed; "
"allowed types", pos + 1, left - 1);
eap_sm_process_nak(sm, pos + 1, left - 1);
if (sm->user && sm->user_eap_method_index < EAP_MAX_METHODS &&
- sm->user->methods[sm->user_eap_method_index] !=
+ sm->user->methods[sm->user_eap_method_index].method !=
EAP_TYPE_NONE) {
- next_type =
- sm->user->methods[sm->user_eap_method_index++];
+ next_type = sm->user->methods[
+ sm->user_eap_method_index++].method;
wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d",
next_type);
} else {
@@ -447,7 +441,7 @@ static void eap_peap_process_phase2_response(struct eap_sm *sm,
}
eap_peap_state(data, PHASE2_METHOD);
- next_type = sm->user->methods[0];
+ next_type = sm->user->methods[0].method;
sm->user_eap_method_index = 1;
wpa_printf(MSG_DEBUG, "EAP-PEAP: try EAP type %d", next_type);
break;
@@ -480,8 +474,9 @@ static void eap_peap_process_phase2(struct eap_sm *sm,
u8 *in_data, size_t in_len)
{
u8 *in_decrypted;
- int buf_len, len_decrypted, len, res;
+ int len_decrypted, len, res;
struct eap_hdr *hdr;
+ size_t buf_len;
wpa_printf(MSG_DEBUG, "EAP-PEAP: received %lu bytes encrypted data for"
" Phase 2", (unsigned long) in_len);
@@ -540,7 +535,7 @@ static void eap_peap_process_phase2(struct eap_sm *sm,
in_decrypted = (u8 *) nhdr;
}
hdr = (struct eap_hdr *) in_decrypted;
- if (len_decrypted < sizeof(*hdr)) {
+ if (len_decrypted < (int) sizeof(*hdr)) {
free(in_decrypted);
wpa_printf(MSG_INFO, "EAP-PEAP: Too short Phase 2 "
"EAP frame (len=%d)", len_decrypted);
@@ -612,7 +607,6 @@ static void eap_peap_process(struct eap_sm *sm, void *priv,
"use version %d",
peer_version, data->peap_version, peer_version);
data->peap_version = peer_version;
-
}
if (flags & EAP_TLS_FLAGS_LENGTH_INCLUDED) {
if (left < 4) {
@@ -711,16 +705,27 @@ static Boolean eap_peap_isSuccess(struct eap_sm *sm, void *priv)
}
-const struct eap_method eap_method_peap =
+int eap_server_peap_register(void)
{
- .method = EAP_TYPE_PEAP,
- .name = "PEAP",
- .init = eap_peap_init,
- .reset = eap_peap_reset,
- .buildReq = eap_peap_buildReq,
- .check = eap_peap_check,
- .process = eap_peap_process,
- .isDone = eap_peap_isDone,
- .getKey = eap_peap_getKey,
- .isSuccess = eap_peap_isSuccess,
-};
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_PEAP, "PEAP");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_peap_init;
+ eap->reset = eap_peap_reset;
+ eap->buildReq = eap_peap_buildReq;
+ eap->check = eap_peap_check;
+ eap->process = eap_peap_process;
+ eap->isDone = eap_peap_isDone;
+ eap->getKey = eap_peap_getKey;
+ eap->isSuccess = eap_peap_isSuccess;
+
+ ret = eap_server_method_register(eap);
+ if (ret)
+ eap_server_method_free(eap);
+ return ret;
+}
diff --git a/contrib/hostapd/eap_psk.c b/contrib/hostapd/eap_psk.c
index 2f92d0577161..7408a522e328 100644
--- a/contrib/hostapd/eap_psk.c
+++ b/contrib/hostapd/eap_psk.c
@@ -1,6 +1,6 @@
/*
- * hostapd / EAP-PSK (draft-bersani-eap-psk-09.txt) server
- * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * hostapd / EAP-PSK (RFC 4764) server
+ * Copyright (c) 2005-2007, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -15,10 +15,7 @@
* different from WPA-PSK. This file is not needed for WPA-PSK functionality.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
#include "hostapd.h"
#include "common.h"
@@ -34,7 +31,8 @@ struct eap_psk_data {
u8 *id_p, *id_s;
size_t id_p_len, id_s_len;
u8 ak[EAP_PSK_AK_LEN], kdk[EAP_PSK_KDK_LEN], tek[EAP_PSK_TEK_LEN];
- u8 msk[EAP_PSK_MSK_LEN];
+ u8 msk[EAP_MSK_LEN];
+ u8 emsk[EAP_EMSK_LEN];
};
@@ -42,12 +40,11 @@ static void * eap_psk_init(struct eap_sm *sm)
{
struct eap_psk_data *data;
- data = malloc(sizeof(*data));
+ data = wpa_zalloc(sizeof(*data));
if (data == NULL)
- return data;
- memset(data, 0, sizeof(*data));
+ return NULL;
data->state = PSK_1;
- data->id_s = "hostapd";
+ data->id_s = (u8 *) "hostapd";
data->id_s_len = 7;
return data;
@@ -90,7 +87,7 @@ static u8 * eap_psk_build_1(struct eap_sm *sm, struct eap_psk_data *data,
req->identifier = id;
req->length = htons(*reqDataLen);
req->type = EAP_TYPE_PSK;
- req->flags = 0; /* T=0 */
+ req->flags = EAP_PSK_FLAGS_SET_T(0); /* T=0 */
memcpy(req->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
memcpy((u8 *) (req + 1), data->id_s, data->id_s_len);
@@ -120,13 +117,14 @@ static u8 * eap_psk_build_3(struct eap_sm *sm, struct eap_psk_data *data,
req->identifier = id;
req->length = htons(*reqDataLen);
req->type = EAP_TYPE_PSK;
- req->flags = 2; /* T=2 */
+ req->flags = EAP_PSK_FLAGS_SET_T(2); /* T=2 */
memcpy(req->rand_s, data->rand_s, EAP_PSK_RAND_LEN);
/* MAC_S = OMAC1-AES-128(AK, ID_S||RAND_P) */
buflen = data->id_s_len + EAP_PSK_RAND_LEN;
buf = malloc(buflen);
if (buf == NULL) {
+ free(req);
data->state = FAILURE;
return NULL;
}
@@ -135,9 +133,11 @@ static u8 * eap_psk_build_3(struct eap_sm *sm, struct eap_psk_data *data,
omac1_aes_128(data->ak, buf, buflen, req->mac_s);
free(buf);
- eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk);
+ eap_psk_derive_keys(data->kdk, data->rand_p, data->tek, data->msk,
+ data->emsk);
wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: TEK", data->tek, EAP_PSK_TEK_LEN);
- wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_PSK_MSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: MSK", data->msk, EAP_MSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-PSK: EMSK", data->emsk, EAP_EMSK_LEN);
memset(nonce, 0, sizeof(nonce));
pchannel = (u8 *) (req + 1);
@@ -189,7 +189,7 @@ static Boolean eap_psk_check(struct eap_sm *sm, void *priv,
wpa_printf(MSG_INFO, "EAP-PSK: Invalid frame");
return TRUE;
}
- t = resp->flags & 0x03;
+ t = EAP_PSK_FLAGS_GET_T(resp->flags);
wpa_printf(MSG_DEBUG, "EAP-PSK: received frame: T=%d", t);
@@ -254,13 +254,18 @@ static void eap_psk_process_2(struct eap_sm *sm,
}
for (i = 0;
- i < EAP_MAX_METHODS && sm->user->methods[i] != EAP_TYPE_NONE;
+ i < EAP_MAX_METHODS &&
+ (sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
+ sm->user->methods[i].method != EAP_TYPE_NONE);
i++) {
- if (sm->user->methods[i] == EAP_TYPE_PSK)
+ if (sm->user->methods[i].vendor == EAP_VENDOR_IETF &&
+ sm->user->methods[i].method == EAP_TYPE_PSK)
break;
}
- if (sm->user->methods[i] != EAP_TYPE_PSK) {
+ if (i >= EAP_MAX_METHODS ||
+ sm->user->methods[i].vendor != EAP_VENDOR_IETF ||
+ sm->user->methods[i].method != EAP_TYPE_PSK) {
wpa_hexdump_ascii(MSG_DEBUG,
"EAP-PSK: EAP-PSK not enabled for ID_P",
data->id_p, data->id_p_len);
@@ -393,14 +398,15 @@ static void eap_psk_process(struct eap_sm *sm, void *priv,
struct eap_psk_hdr *resp;
if (sm->user == NULL || sm->user->password == NULL) {
- wpa_printf(MSG_INFO, "EAP-MSCHAPV2: Password not configured");
+ wpa_printf(MSG_INFO, "EAP-PSK: Plaintext password not "
+ "configured");
data->state = FAILURE;
return;
}
resp = (struct eap_psk_hdr *) respData;
- switch (resp->flags & 0x03) {
+ switch (EAP_PSK_FLAGS_GET_T(resp->flags)) {
case 1:
eap_psk_process_2(sm, data, respData, respDataLen);
break;
@@ -426,11 +432,29 @@ static u8 * eap_psk_getKey(struct eap_sm *sm, void *priv, size_t *len)
if (data->state != SUCCESS)
return NULL;
- key = malloc(EAP_PSK_MSK_LEN);
+ key = malloc(EAP_MSK_LEN);
if (key == NULL)
return NULL;
- memcpy(key, data->msk, EAP_PSK_MSK_LEN);
- *len = EAP_PSK_MSK_LEN;
+ memcpy(key, data->msk, EAP_MSK_LEN);
+ *len = EAP_MSK_LEN;
+
+ return key;
+}
+
+
+static u8 * eap_psk_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_psk_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+ memcpy(key, data->emsk, EAP_EMSK_LEN);
+ *len = EAP_EMSK_LEN;
return key;
}
@@ -443,16 +467,28 @@ static Boolean eap_psk_isSuccess(struct eap_sm *sm, void *priv)
}
-const struct eap_method eap_method_psk =
+int eap_server_psk_register(void)
{
- .method = EAP_TYPE_PSK,
- .name = "PSK",
- .init = eap_psk_init,
- .reset = eap_psk_reset,
- .buildReq = eap_psk_buildReq,
- .check = eap_psk_check,
- .process = eap_psk_process,
- .isDone = eap_psk_isDone,
- .getKey = eap_psk_getKey,
- .isSuccess = eap_psk_isSuccess,
-};
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_PSK, "PSK");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_psk_init;
+ eap->reset = eap_psk_reset;
+ eap->buildReq = eap_psk_buildReq;
+ eap->check = eap_psk_check;
+ eap->process = eap_psk_process;
+ eap->isDone = eap_psk_isDone;
+ eap->getKey = eap_psk_getKey;
+ eap->isSuccess = eap_psk_isSuccess;
+ eap->get_emsk = eap_psk_get_emsk;
+
+ ret = eap_server_method_register(eap);
+ if (ret)
+ eap_server_method_free(eap);
+ return ret;
+}
diff --git a/contrib/hostapd/eap_psk_common.c b/contrib/hostapd/eap_psk_common.c
index 24de66cf0cb7..8d896ae639d5 100644
--- a/contrib/hostapd/eap_psk_common.c
+++ b/contrib/hostapd/eap_psk_common.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-PSK shared routines
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP server/peer: EAP-PSK shared routines
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,12 +12,11 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "aes_wrap.h"
+#include "eap_defs.h"
#include "eap_psk_common.h"
#define aes_block_size 16
@@ -25,9 +24,9 @@
void eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk)
{
- memset(ak, 0, aes_block_size);
+ os_memset(ak, 0, aes_block_size);
aes_128_encrypt_block(psk, ak, ak);
- memcpy(kdk, ak, aes_block_size);
+ os_memcpy(kdk, ak, aes_block_size);
ak[aes_block_size - 1] ^= 0x01;
kdk[aes_block_size - 1] ^= 0x02;
aes_128_encrypt_block(psk, ak, ak);
@@ -35,7 +34,8 @@ void eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk)
}
-void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk)
+void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk,
+ u8 *emsk)
{
u8 hash[aes_block_size];
u8 counter = 1;
@@ -48,10 +48,17 @@ void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk)
hash[aes_block_size - 1] ^= counter;
counter++;
- for (i = 0; i < EAP_PSK_MSK_LEN / aes_block_size; i++) {
+ for (i = 0; i < EAP_MSK_LEN / aes_block_size; i++) {
hash[aes_block_size - 1] ^= counter;
aes_128_encrypt_block(kdk, hash, &msk[i * aes_block_size]);
hash[aes_block_size - 1] ^= counter;
counter++;
}
+
+ for (i = 0; i < EAP_EMSK_LEN / aes_block_size; i++) {
+ hash[aes_block_size - 1] ^= counter;
+ aes_128_encrypt_block(kdk, hash, &emsk[i * aes_block_size]);
+ hash[aes_block_size - 1] ^= counter;
+ counter++;
+ }
}
diff --git a/contrib/hostapd/eap_psk_common.h b/contrib/hostapd/eap_psk_common.h
index 5dd3a1042da3..e1bdccf5916a 100644
--- a/contrib/hostapd/eap_psk_common.h
+++ b/contrib/hostapd/eap_psk_common.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-PSK shared routines
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP server/peer: EAP-PSK shared routines
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -19,7 +19,6 @@
#define EAP_PSK_RAND_LEN 16
#define EAP_PSK_MAC_LEN 16
#define EAP_PSK_TEK_LEN 16
-#define EAP_PSK_MSK_LEN 64
#define EAP_PSK_PSK_LEN 16
#define EAP_PSK_AK_LEN 16
#define EAP_PSK_KDK_LEN 16
@@ -29,6 +28,13 @@
#define EAP_PSK_R_FLAG_DONE_FAILURE 3
#define EAP_PSK_E_FLAG 0x20
+#define EAP_PSK_FLAGS_GET_T(flags) (((flags) & 0xc0) >> 6)
+#define EAP_PSK_FLAGS_SET_T(t) ((u8) (t) << 6)
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
/* Shared prefix for all EAP-PSK frames */
struct eap_psk_hdr {
u8 code;
@@ -36,7 +42,7 @@ struct eap_psk_hdr {
u16 length; /* including code, identifier, and length */
u8 type; /* EAP_TYPE_PSK */
u8 flags;
-} __attribute__ ((packed));
+} STRUCT_PACKED;
/* EAP-PSK First Message (AS -> Supplicant) */
struct eap_psk_hdr_1 {
@@ -47,7 +53,7 @@ struct eap_psk_hdr_1 {
u8 flags;
u8 rand_s[EAP_PSK_RAND_LEN];
/* Followed by variable length ID_S */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
/* EAP-PSK Second Message (Supplicant -> AS) */
struct eap_psk_hdr_2 {
@@ -60,7 +66,7 @@ struct eap_psk_hdr_2 {
u8 rand_p[EAP_PSK_RAND_LEN];
u8 mac_p[EAP_PSK_MAC_LEN];
/* Followed by variable length ID_P */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
/* EAP-PSK Third Message (AS -> Supplicant) */
struct eap_psk_hdr_3 {
@@ -72,7 +78,7 @@ struct eap_psk_hdr_3 {
u8 rand_s[EAP_PSK_RAND_LEN];
u8 mac_s[EAP_PSK_MAC_LEN];
/* Followed by variable length PCHANNEL */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
/* EAP-PSK Fourth Message (Supplicant -> AS) */
struct eap_psk_hdr_4 {
@@ -83,10 +89,15 @@ struct eap_psk_hdr_4 {
u8 flags;
u8 rand_s[EAP_PSK_RAND_LEN];
/* Followed by variable length PCHANNEL */
-} __attribute__ ((packed));
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
void eap_psk_key_setup(const u8 *psk, u8 *ak, u8 *kdk);
-void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk);
+void eap_psk_derive_keys(const u8 *kdk, const u8 *rand_p, u8 *tek, u8 *msk,
+ u8 *emsk);
#endif /* EAP_PSK_COMMON_H */
diff --git a/contrib/hostapd/eap_sake.c b/contrib/hostapd/eap_sake.c
new file mode 100644
index 000000000000..e031f29fb436
--- /dev/null
+++ b/contrib/hostapd/eap_sake.c
@@ -0,0 +1,547 @@
+/*
+ * hostapd / EAP-SAKE (RFC 4763) server
+ * 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 "hostapd.h"
+#include "common.h"
+#include "eap_i.h"
+#include "eap_sake_common.h"
+
+
+struct eap_sake_data {
+ enum { IDENTITY, CHALLENGE, CONFIRM, SUCCESS, FAILURE } state;
+ u8 rand_s[EAP_SAKE_RAND_LEN];
+ u8 rand_p[EAP_SAKE_RAND_LEN];
+ struct {
+ u8 auth[EAP_SAKE_TEK_AUTH_LEN];
+ u8 cipher[EAP_SAKE_TEK_CIPHER_LEN];
+ } tek;
+ u8 msk[EAP_MSK_LEN];
+ u8 emsk[EAP_EMSK_LEN];
+ u8 session_id;
+ u8 *peerid;
+ size_t peerid_len;
+ u8 *serverid;
+ size_t serverid_len;
+};
+
+
+static const char * eap_sake_state_txt(int state)
+{
+ switch (state) {
+ case IDENTITY:
+ return "IDENTITY";
+ case CHALLENGE:
+ return "CHALLENGE";
+ case CONFIRM:
+ return "CONFIRM";
+ case SUCCESS:
+ return "SUCCESS";
+ case FAILURE:
+ return "FAILURE";
+ default:
+ return "?";
+ }
+}
+
+
+static void eap_sake_state(struct eap_sake_data *data, int state)
+{
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: %s -> %s",
+ eap_sake_state_txt(data->state),
+ eap_sake_state_txt(state));
+ data->state = state;
+}
+
+
+static void * eap_sake_init(struct eap_sm *sm)
+{
+ struct eap_sake_data *data;
+
+ data = wpa_zalloc(sizeof(*data));
+ if (data == NULL)
+ return NULL;
+ data->state = CHALLENGE;
+
+ if (hostapd_get_rand(&data->session_id, 1)) {
+ wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
+ os_free(data);
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Initialized Session ID %d",
+ data->session_id);
+
+ /* TODO: add support for configuring SERVERID */
+ data->serverid = (u8 *) strdup("hostapd");
+ if (data->serverid)
+ data->serverid_len = strlen((char *) data->serverid);
+
+ return data;
+}
+
+
+static void eap_sake_reset(struct eap_sm *sm, void *priv)
+{
+ struct eap_sake_data *data = priv;
+ os_free(data->serverid);
+ os_free(data->peerid);
+ os_free(data);
+}
+
+
+static u8 * eap_sake_build_msg(struct eap_sake_data *data, u8 **payload,
+ int id, size_t *length, u8 subtype)
+{
+ struct eap_sake_hdr *req;
+ u8 *msg;
+
+ *length += sizeof(struct eap_sake_hdr);
+
+ msg = wpa_zalloc(*length);
+ if (msg == NULL) {
+ wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to allocate memory "
+ "request");
+ return NULL;
+ }
+
+ req = (struct eap_sake_hdr *) msg;
+ req->code = EAP_CODE_REQUEST;
+ req->identifier = id;
+ req->length = htons((u16) *length);
+ req->type = EAP_TYPE_SAKE;
+ req->version = EAP_SAKE_VERSION;
+ req->session_id = data->session_id;
+ req->subtype = subtype;
+ *payload = (u8 *) (req + 1);
+
+ return msg;
+}
+
+
+static u8 * eap_sake_build_identity(struct eap_sm *sm,
+ struct eap_sake_data *data,
+ int id, size_t *reqDataLen)
+{
+ u8 *msg, *pos;
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Identity");
+
+ *reqDataLen = 4;
+ if (data->serverid)
+ *reqDataLen += 2 + data->serverid_len;
+ msg = eap_sake_build_msg(data, &pos, id, reqDataLen,
+ EAP_SAKE_SUBTYPE_IDENTITY);
+ if (msg == NULL) {
+ data->state = FAILURE;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_PERM_ID_REQ");
+ *pos++ = EAP_SAKE_AT_PERM_ID_REQ;
+ *pos++ = 4;
+ *pos++ = 0;
+ *pos++ = 0;
+
+ if (data->serverid) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
+ *pos++ = EAP_SAKE_AT_SERVERID;
+ *pos++ = 2 + data->serverid_len;
+ os_memcpy(pos, data->serverid, data->serverid_len);
+ }
+
+ return msg;
+}
+
+
+static u8 * eap_sake_build_challenge(struct eap_sm *sm,
+ struct eap_sake_data *data,
+ int id, size_t *reqDataLen)
+{
+ u8 *msg, *pos;
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Challenge");
+
+ if (hostapd_get_rand(data->rand_s, EAP_SAKE_RAND_LEN)) {
+ wpa_printf(MSG_ERROR, "EAP-SAKE: Failed to get random data");
+ data->state = FAILURE;
+ return NULL;
+ }
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SAKE: RAND_S (server rand)",
+ data->rand_s, EAP_SAKE_RAND_LEN);
+
+ *reqDataLen = 2 + EAP_SAKE_RAND_LEN;
+ if (data->serverid)
+ *reqDataLen += 2 + data->serverid_len;
+ msg = eap_sake_build_msg(data, &pos, id, reqDataLen,
+ EAP_SAKE_SUBTYPE_CHALLENGE);
+ if (msg == NULL) {
+ data->state = FAILURE;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_RAND_S");
+ *pos++ = EAP_SAKE_AT_RAND_S;
+ *pos++ = 2 + EAP_SAKE_RAND_LEN;
+ os_memcpy(pos, data->rand_s, EAP_SAKE_RAND_LEN);
+ pos += EAP_SAKE_RAND_LEN;
+
+ if (data->serverid) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_SERVERID");
+ *pos++ = EAP_SAKE_AT_SERVERID;
+ *pos++ = 2 + data->serverid_len;
+ os_memcpy(pos, data->serverid, data->serverid_len);
+ }
+
+ return msg;
+}
+
+
+static u8 * eap_sake_build_confirm(struct eap_sm *sm,
+ struct eap_sake_data *data,
+ int id, size_t *reqDataLen)
+{
+ u8 *msg, *pos;
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Request/Confirm");
+
+ *reqDataLen = 2 + EAP_SAKE_MIC_LEN;
+ msg = eap_sake_build_msg(data, &pos, id, reqDataLen,
+ EAP_SAKE_SUBTYPE_CONFIRM);
+ if (msg == NULL) {
+ data->state = FAILURE;
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: * AT_MIC_S");
+ *pos++ = EAP_SAKE_AT_MIC_S;
+ *pos++ = 2 + EAP_SAKE_MIC_LEN;
+ if (eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+ data->serverid, data->serverid_len,
+ data->peerid, data->peerid_len, 0,
+ msg, *reqDataLen, pos, pos)) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Failed to compute MIC");
+ data->state = FAILURE;
+ os_free(msg);
+ return NULL;
+ }
+
+ return msg;
+}
+
+
+static u8 * eap_sake_buildReq(struct eap_sm *sm, void *priv, int id,
+ size_t *reqDataLen)
+{
+ struct eap_sake_data *data = priv;
+
+ switch (data->state) {
+ case IDENTITY:
+ return eap_sake_build_identity(sm, data, id, reqDataLen);
+ case CHALLENGE:
+ return eap_sake_build_challenge(sm, data, id, reqDataLen);
+ case CONFIRM:
+ return eap_sake_build_confirm(sm, data, id, reqDataLen);
+ default:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown state %d in buildReq",
+ data->state);
+ break;
+ }
+ return NULL;
+}
+
+
+static Boolean eap_sake_check(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_sake_data *data = priv;
+ struct eap_sake_hdr *resp;
+ size_t len;
+ u8 version, session_id, subtype;
+
+ resp = (struct eap_sake_hdr *) respData;
+ if (respDataLen < sizeof(*resp) ||
+ resp->type != EAP_TYPE_SAKE ||
+ (len = ntohs(resp->length)) > respDataLen ||
+ len < sizeof(*resp)) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Invalid frame");
+ return TRUE;
+ }
+ version = resp->version;
+ session_id = resp->session_id;
+ subtype = resp->subtype;
+
+ if (version != EAP_SAKE_VERSION) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Unknown version %d", version);
+ return TRUE;
+ }
+
+ if (session_id != data->session_id) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Session ID mismatch (%d,%d)",
+ session_id, data->session_id);
+ return TRUE;
+ }
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received frame: subtype=%d", subtype);
+
+ if (data->state == IDENTITY && subtype == EAP_SAKE_SUBTYPE_IDENTITY)
+ return FALSE;
+
+ if (data->state == CHALLENGE && subtype == EAP_SAKE_SUBTYPE_CHALLENGE)
+ return FALSE;
+
+ if (data->state == CONFIRM && subtype == EAP_SAKE_SUBTYPE_CONFIRM)
+ return FALSE;
+
+ if (subtype == EAP_SAKE_SUBTYPE_AUTH_REJECT)
+ return FALSE;
+
+ wpa_printf(MSG_INFO, "EAP-SAKE: Unexpected subtype=%d in state=%d",
+ subtype, data->state);
+
+ return TRUE;
+}
+
+
+static void eap_sake_process_identity(struct eap_sm *sm,
+ struct eap_sake_data *data,
+ u8 *respData, size_t respDataLen,
+ u8 *payload, size_t payloadlen)
+{
+ if (data->state != IDENTITY)
+ return;
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Identity");
+ /* TODO: update identity and select new user data */
+ eap_sake_state(data, CHALLENGE);
+}
+
+
+static void eap_sake_process_challenge(struct eap_sm *sm,
+ struct eap_sake_data *data,
+ u8 *respData, size_t respDataLen,
+ u8 *payload, size_t payloadlen)
+{
+ struct eap_sake_parse_attr attr;
+ u8 mic_p[EAP_SAKE_MIC_LEN];
+
+ if (data->state != CHALLENGE)
+ return;
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Challenge");
+
+ if (eap_sake_parse_attributes(payload, payloadlen, &attr))
+ return;
+
+ if (!attr.rand_p || !attr.mic_p) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Response/Challenge did not "
+ "include AT_RAND_P or AT_MIC_P");
+ return;
+ }
+
+ os_memcpy(data->rand_p, attr.rand_p, EAP_SAKE_RAND_LEN);
+
+ os_free(data->peerid);
+ data->peerid = NULL;
+ data->peerid_len = 0;
+ if (attr.peerid) {
+ data->peerid = os_malloc(attr.peerid_len);
+ if (data->peerid == NULL)
+ return;
+ os_memcpy(data->peerid, attr.peerid, attr.peerid_len);
+ data->peerid_len = attr.peerid_len;
+ }
+
+ if (sm->user == NULL || sm->user->password == NULL ||
+ sm->user->password_len != 2 * EAP_SAKE_ROOT_SECRET_LEN) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Plaintext password with "
+ "%d-byte key not configured",
+ 2 * EAP_SAKE_ROOT_SECRET_LEN);
+ data->state = FAILURE;
+ return;
+ }
+ eap_sake_derive_keys(sm->user->password,
+ sm->user->password + EAP_SAKE_ROOT_SECRET_LEN,
+ data->rand_s, data->rand_p,
+ (u8 *) &data->tek, data->msk, data->emsk);
+
+ eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+ data->serverid, data->serverid_len,
+ data->peerid, data->peerid_len, 1,
+ respData, respDataLen, attr.mic_p, mic_p);
+ if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
+ eap_sake_state(data, FAILURE);
+ return;
+ }
+
+ eap_sake_state(data, CONFIRM);
+}
+
+
+static void eap_sake_process_confirm(struct eap_sm *sm,
+ struct eap_sake_data *data,
+ u8 *respData, size_t respDataLen,
+ u8 *payload, size_t payloadlen)
+{
+ struct eap_sake_parse_attr attr;
+ u8 mic_p[EAP_SAKE_MIC_LEN];
+
+ if (data->state != CONFIRM)
+ return;
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Confirm");
+
+ if (eap_sake_parse_attributes(payload, payloadlen, &attr))
+ return;
+
+ if (!attr.mic_p) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Response/Confirm did not "
+ "include AT_MIC_P");
+ return;
+ }
+
+ eap_sake_compute_mic(data->tek.auth, data->rand_s, data->rand_p,
+ data->serverid, data->serverid_len,
+ data->peerid, data->peerid_len, 1,
+ respData, respDataLen, attr.mic_p, mic_p);
+ if (os_memcmp(attr.mic_p, mic_p, EAP_SAKE_MIC_LEN) != 0) {
+ wpa_printf(MSG_INFO, "EAP-SAKE: Incorrect AT_MIC_P");
+ eap_sake_state(data, FAILURE);
+ } else
+ eap_sake_state(data, SUCCESS);
+}
+
+
+static void eap_sake_process_auth_reject(struct eap_sm *sm,
+ struct eap_sake_data *data,
+ u8 *respData, size_t respDataLen,
+ u8 *payload, size_t payloadlen)
+{
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Received Response/Auth-Reject");
+ eap_sake_state(data, FAILURE);
+}
+
+
+static void eap_sake_process(struct eap_sm *sm, void *priv,
+ u8 *respData, size_t respDataLen)
+{
+ struct eap_sake_data *data = priv;
+ struct eap_sake_hdr *resp;
+ u8 subtype, *pos, *end;
+
+ resp = (struct eap_sake_hdr *) respData;
+ subtype = resp->subtype;
+ pos = (u8 *) (resp + 1);
+ end = respData + ntohs(resp->length);
+
+ wpa_hexdump(MSG_DEBUG, "EAP-SAKE: Received attributes",
+ pos, end - pos);
+
+ switch (subtype) {
+ case EAP_SAKE_SUBTYPE_IDENTITY:
+ eap_sake_process_identity(sm, data, respData, respDataLen, pos,
+ end - pos);
+ break;
+ case EAP_SAKE_SUBTYPE_CHALLENGE:
+ eap_sake_process_challenge(sm, data, respData, respDataLen,
+ pos, end - pos);
+ break;
+ case EAP_SAKE_SUBTYPE_CONFIRM:
+ eap_sake_process_confirm(sm, data, respData, respDataLen, pos,
+ end - pos);
+ break;
+ case EAP_SAKE_SUBTYPE_AUTH_REJECT:
+ eap_sake_process_auth_reject(sm, data, respData, respDataLen,
+ pos, end - pos);
+ break;
+ }
+}
+
+
+static Boolean eap_sake_isDone(struct eap_sm *sm, void *priv)
+{
+ struct eap_sake_data *data = priv;
+ return data->state == SUCCESS || data->state == FAILURE;
+}
+
+
+static u8 * eap_sake_getKey(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sake_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = os_malloc(EAP_MSK_LEN);
+ if (key == NULL)
+ return NULL;
+ os_memcpy(key, data->msk, EAP_MSK_LEN);
+ *len = EAP_MSK_LEN;
+
+ return key;
+}
+
+
+static u8 * eap_sake_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sake_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = os_malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+ os_memcpy(key, data->emsk, EAP_EMSK_LEN);
+ *len = EAP_EMSK_LEN;
+
+ return key;
+}
+
+
+static Boolean eap_sake_isSuccess(struct eap_sm *sm, void *priv)
+{
+ struct eap_sake_data *data = priv;
+ return data->state == SUCCESS;
+}
+
+
+int eap_server_sake_register(void)
+{
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_SAKE, "SAKE");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_sake_init;
+ eap->reset = eap_sake_reset;
+ eap->buildReq = eap_sake_buildReq;
+ eap->check = eap_sake_check;
+ eap->process = eap_sake_process;
+ eap->isDone = eap_sake_isDone;
+ eap->getKey = eap_sake_getKey;
+ eap->isSuccess = eap_sake_isSuccess;
+ eap->get_emsk = eap_sake_get_emsk;
+
+ ret = eap_server_method_register(eap);
+ if (ret)
+ eap_server_method_free(eap);
+ return ret;
+}
diff --git a/contrib/hostapd/eap_sake_common.c b/contrib/hostapd/eap_sake_common.c
new file mode 100644
index 000000000000..4b5476f101c8
--- /dev/null
+++ b/contrib/hostapd/eap_sake_common.c
@@ -0,0 +1,380 @@
+/*
+ * EAP server/peer: EAP-SAKE shared routines
+ * 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 "sha1.h"
+#include "eap_defs.h"
+#include "eap_sake_common.h"
+
+
+static int eap_sake_parse_add_attr(struct eap_sake_parse_attr *attr,
+ const u8 *pos)
+{
+ size_t i;
+
+ switch (pos[0]) {
+ case EAP_SAKE_AT_RAND_S:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_S");
+ if (pos[1] != 2 + EAP_SAKE_RAND_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_S with "
+ "invalid length %d", pos[1]);
+ return -1;
+ }
+ attr->rand_s = pos + 2;
+ break;
+ case EAP_SAKE_AT_RAND_P:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_RAND_P");
+ if (pos[1] != 2 + EAP_SAKE_RAND_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_RAND_P with "
+ "invalid length %d", pos[1]);
+ return -1;
+ }
+ attr->rand_p = pos + 2;
+ break;
+ case EAP_SAKE_AT_MIC_S:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_S");
+ if (pos[1] != 2 + EAP_SAKE_MIC_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_S with "
+ "invalid length %d", pos[1]);
+ return -1;
+ }
+ attr->mic_s = pos + 2;
+ break;
+ case EAP_SAKE_AT_MIC_P:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_MIC_P");
+ if (pos[1] != 2 + EAP_SAKE_MIC_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_MIC_P with "
+ "invalid length %d", pos[1]);
+ return -1;
+ }
+ attr->mic_p = pos + 2;
+ break;
+ case EAP_SAKE_AT_SERVERID:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SERVERID");
+ attr->serverid = pos + 2;
+ attr->serverid_len = pos[1] - 2;
+ break;
+ case EAP_SAKE_AT_PEERID:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PEERID");
+ attr->peerid = pos + 2;
+ attr->peerid_len = pos[1] - 2;
+ break;
+ case EAP_SAKE_AT_SPI_S:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_S");
+ attr->spi_s = pos + 2;
+ attr->spi_s_len = pos[1] - 2;
+ break;
+ case EAP_SAKE_AT_SPI_P:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_SPI_P");
+ attr->spi_p = pos + 2;
+ attr->spi_p_len = pos[1] - 2;
+ break;
+ case EAP_SAKE_AT_ANY_ID_REQ:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ANY_ID_REQ");
+ if (pos[1] != 4) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid AT_ANY_ID_REQ"
+ " length %d", pos[1]);
+ return -1;
+ }
+ attr->any_id_req = pos + 2;
+ break;
+ case EAP_SAKE_AT_PERM_ID_REQ:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PERM_ID_REQ");
+ if (pos[1] != 4) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid "
+ "AT_PERM_ID_REQ length %d", pos[1]);
+ return -1;
+ }
+ attr->perm_id_req = pos + 2;
+ break;
+ case EAP_SAKE_AT_ENCR_DATA:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_ENCR_DATA");
+ attr->encr_data = pos + 2;
+ attr->encr_data_len = pos[1] - 2;
+ break;
+ case EAP_SAKE_AT_IV:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV");
+ attr->iv = pos + 2;
+ attr->iv_len = pos[1] - 2;
+ break;
+ case EAP_SAKE_AT_PADDING:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_PADDING");
+ for (i = 2; i < pos[1]; i++) {
+ if (pos[i]) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_PADDING "
+ "with non-zero pad byte");
+ return -1;
+ }
+ }
+ break;
+ case EAP_SAKE_AT_NEXT_TMPID:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_NEXT_TMPID");
+ attr->next_tmpid = pos + 2;
+ attr->next_tmpid_len = pos[1] - 2;
+ break;
+ case EAP_SAKE_AT_MSK_LIFE:
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Parse: AT_IV");
+ if (pos[1] != 6) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid "
+ "AT_MSK_LIFE length %d", pos[1]);
+ return -1;
+ }
+ attr->msk_life = pos + 2;
+ break;
+ default:
+ if (pos[0] < 128) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Unknown non-skippable"
+ " attribute %d", pos[0]);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Ignoring unknown skippable "
+ "attribute %d", pos[0]);
+ break;
+ }
+
+ if (attr->iv && !attr->encr_data) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: AT_IV included without "
+ "AT_ENCR_DATA");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * eap_sake_parse_attributes - Parse EAP-SAKE attributes
+ * @buf: Packet payload (starting with the first attribute)
+ * @len: Payload length
+ * @attr: Structure to be filled with found attributes
+ * Returns: 0 on success or -1 on failure
+ */
+int eap_sake_parse_attributes(const u8 *buf, size_t len,
+ struct eap_sake_parse_attr *attr)
+{
+ const u8 *pos = buf, *end = buf + len;
+
+ os_memset(attr, 0, sizeof(*attr));
+ while (pos < end) {
+ if (end - pos < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Too short attribute");
+ return -1;
+ }
+
+ if (pos[1] < 2) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Invalid attribute "
+ "length (%d)", pos[1]);
+ return -1;
+ }
+
+ if (pos + pos[1] > end) {
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Attribute underflow");
+ return -1;
+ }
+
+ if (eap_sake_parse_add_attr(attr, pos))
+ return -1;
+
+ pos += pos[1];
+ }
+
+ return 0;
+}
+
+
+/**
+ * eap_sake_kdf - EAP-SAKE Key Derivation Function (KDF)
+ * @key: Key for KDF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the KDF
+ * @data: Extra data (start) to bind into the key
+ * @data_len: Length of the data
+ * @data2: Extra data (end) to bind into the key
+ * @data2_len: Length of the data2
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key (e.g., SMS). This is identical to the PRF used in IEEE 802.11i.
+ */
+static void eap_sake_kdf(const u8 *key, size_t key_len, const char *label,
+ const u8 *data, size_t data_len,
+ const u8 *data2, size_t data2_len,
+ u8 *buf, size_t buf_len)
+{
+ u8 counter = 0;
+ size_t pos, plen;
+ u8 hash[SHA1_MAC_LEN];
+ size_t label_len = os_strlen(label) + 1;
+ const unsigned char *addr[4];
+ size_t len[4];
+
+ addr[0] = (u8 *) label; /* Label | Y */
+ len[0] = label_len;
+ addr[1] = data; /* Msg[start] */
+ len[1] = data_len;
+ addr[2] = data2; /* Msg[end] */
+ len[2] = data2_len;
+ addr[3] = &counter; /* Length */
+ len[3] = 1;
+
+ pos = 0;
+ while (pos < buf_len) {
+ plen = buf_len - pos;
+ if (plen >= SHA1_MAC_LEN) {
+ hmac_sha1_vector(key, key_len, 4, addr, len,
+ &buf[pos]);
+ pos += SHA1_MAC_LEN;
+ } else {
+ hmac_sha1_vector(key, key_len, 4, addr, len,
+ hash);
+ os_memcpy(&buf[pos], hash, plen);
+ break;
+ }
+ counter++;
+ }
+}
+
+
+/**
+ * eap_sake_derive_keys - Derive EAP-SAKE keys
+ * @root_secret_a: 16-byte Root-Secret-A
+ * @root_secret_b: 16-byte Root-Secret-B
+ * @rand_s: 16-byte RAND_S
+ * @rand_p: 16-byte RAND_P
+ * @tek: Buffer for Temporary EAK Keys (TEK-Auth[16] | TEK-Cipher[16])
+ * @msk: Buffer for 64-byte MSK
+ * @emsk: Buffer for 64-byte EMSK
+ *
+ * This function derives EAP-SAKE keys as defined in RFC 4763, section 3.2.6.
+ */
+void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
+ const u8 *rand_s, const u8 *rand_p, u8 *tek, u8 *msk,
+ u8 *emsk)
+{
+ u8 sms_a[EAP_SAKE_SMS_LEN];
+ u8 sms_b[EAP_SAKE_SMS_LEN];
+ u8 key_buf[EAP_MSK_LEN + EAP_EMSK_LEN];
+
+ wpa_printf(MSG_DEBUG, "EAP-SAKE: Deriving keys");
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-A",
+ root_secret_a, EAP_SAKE_ROOT_SECRET_LEN);
+ eap_sake_kdf(root_secret_a, EAP_SAKE_ROOT_SECRET_LEN,
+ "SAKE Master Secret A",
+ rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
+ sms_a, EAP_SAKE_SMS_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-A", sms_a, EAP_SAKE_SMS_LEN);
+ eap_sake_kdf(sms_a, EAP_SAKE_SMS_LEN, "Transient EAP Key",
+ rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
+ tek, EAP_SAKE_TEK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Auth",
+ tek, EAP_SAKE_TEK_AUTH_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: TEK-Cipher",
+ tek + EAP_SAKE_TEK_AUTH_LEN, EAP_SAKE_TEK_CIPHER_LEN);
+
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: Root-Secret-B",
+ root_secret_b, EAP_SAKE_ROOT_SECRET_LEN);
+ eap_sake_kdf(root_secret_b, EAP_SAKE_ROOT_SECRET_LEN,
+ "SAKE Master Secret B",
+ rand_p, EAP_SAKE_RAND_LEN, rand_s, EAP_SAKE_RAND_LEN,
+ sms_b, EAP_SAKE_SMS_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: SMS-B", sms_b, EAP_SAKE_SMS_LEN);
+ eap_sake_kdf(sms_b, EAP_SAKE_SMS_LEN, "Master Session Key",
+ rand_s, EAP_SAKE_RAND_LEN, rand_p, EAP_SAKE_RAND_LEN,
+ key_buf, sizeof(key_buf));
+ os_memcpy(msk, key_buf, EAP_MSK_LEN);
+ os_memcpy(emsk, key_buf + EAP_MSK_LEN, EAP_EMSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: MSK", msk, EAP_MSK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SAKE: EMSK", emsk, EAP_EMSK_LEN);
+}
+
+
+/**
+ * eap_sake_compute_mic - Compute EAP-SAKE MIC for an EAP packet
+ * @tek_auth: 16-byte TEK-Auth
+ * @rand_s: 16-byte RAND_S
+ * @rand_p: 16-byte RAND_P
+ * @serverid: SERVERID
+ * @serverid_len: SERVERID length
+ * @peerid: PEERID
+ * @peerid_len: PEERID length
+ * @peer: MIC calculation for 0 = Server, 1 = Peer message
+ * @eap: EAP packet
+ * @eap_len: EAP packet length
+ * @mic_pos: MIC position in the EAP packet (must be [eap .. eap + eap_len])
+ * @mic: Buffer for the computed 16-byte MIC
+ */
+int eap_sake_compute_mic(const u8 *tek_auth,
+ const u8 *rand_s, const u8 *rand_p,
+ const u8 *serverid, size_t serverid_len,
+ const u8 *peerid, size_t peerid_len,
+ int peer, const u8 *eap, size_t eap_len,
+ const u8 *mic_pos, u8 *mic)
+{
+ u8 _rand[2 * EAP_SAKE_RAND_LEN];
+ u8 *tmp, *pos;
+ size_t tmplen;
+
+ tmplen = serverid_len + 1 + peerid_len + 1 + eap_len;
+ tmp = os_malloc(tmplen);
+ if (tmp == NULL)
+ return -1;
+ pos = tmp;
+ if (peer) {
+ if (peerid) {
+ os_memcpy(pos, peerid, peerid_len);
+ pos += peerid_len;
+ }
+ *pos++ = 0x00;
+ if (serverid) {
+ os_memcpy(pos, serverid, serverid_len);
+ pos += serverid_len;
+ }
+ *pos++ = 0x00;
+
+ os_memcpy(_rand, rand_s, EAP_SAKE_RAND_LEN);
+ os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_p,
+ EAP_SAKE_RAND_LEN);
+ } else {
+ if (serverid) {
+ os_memcpy(pos, serverid, serverid_len);
+ pos += serverid_len;
+ }
+ *pos++ = 0x00;
+ if (peerid) {
+ os_memcpy(pos, peerid, peerid_len);
+ pos += peerid_len;
+ }
+ *pos++ = 0x00;
+
+ os_memcpy(_rand, rand_p, EAP_SAKE_RAND_LEN);
+ os_memcpy(_rand + EAP_SAKE_RAND_LEN, rand_s,
+ EAP_SAKE_RAND_LEN);
+ }
+
+ os_memcpy(pos, eap, eap_len);
+ os_memset(pos + (mic_pos - eap), 0, EAP_SAKE_MIC_LEN);
+
+ eap_sake_kdf(tek_auth, EAP_SAKE_TEK_AUTH_LEN,
+ peer ? "Peer MIC" : "Server MIC",
+ _rand, 2 * EAP_SAKE_RAND_LEN, tmp, tmplen,
+ mic, EAP_SAKE_MIC_LEN);
+
+ os_free(tmp);
+
+ return 0;
+}
diff --git a/contrib/hostapd/eap_sake_common.h b/contrib/hostapd/eap_sake_common.h
new file mode 100644
index 000000000000..ac6e8199d66b
--- /dev/null
+++ b/contrib/hostapd/eap_sake_common.h
@@ -0,0 +1,104 @@
+/*
+ * EAP server/peer: EAP-SAKE shared routines
+ * 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.
+ */
+
+#ifndef EAP_SAKE_COMMON_H
+#define EAP_SAKE_COMMON_H
+
+#define EAP_SAKE_VERSION 2
+
+#define EAP_SAKE_SUBTYPE_CHALLENGE 1
+#define EAP_SAKE_SUBTYPE_CONFIRM 2
+#define EAP_SAKE_SUBTYPE_AUTH_REJECT 3
+#define EAP_SAKE_SUBTYPE_IDENTITY 4
+
+#define EAP_SAKE_AT_RAND_S 1
+#define EAP_SAKE_AT_RAND_P 2
+#define EAP_SAKE_AT_MIC_S 3
+#define EAP_SAKE_AT_MIC_P 4
+#define EAP_SAKE_AT_SERVERID 5
+#define EAP_SAKE_AT_PEERID 6
+#define EAP_SAKE_AT_SPI_S 7
+#define EAP_SAKE_AT_SPI_P 8
+#define EAP_SAKE_AT_ANY_ID_REQ 9
+#define EAP_SAKE_AT_PERM_ID_REQ 10
+#define EAP_SAKE_AT_ENCR_DATA 128
+#define EAP_SAKE_AT_IV 129
+#define EAP_SAKE_AT_PADDING 130
+#define EAP_SAKE_AT_NEXT_TMPID 131
+#define EAP_SAKE_AT_MSK_LIFE 132
+
+#define EAP_SAKE_RAND_LEN 16
+#define EAP_SAKE_MIC_LEN 16
+#define EAP_SAKE_ROOT_SECRET_LEN 16
+#define EAP_SAKE_SMS_LEN 16
+#define EAP_SAKE_TEK_AUTH_LEN 16
+#define EAP_SAKE_TEK_CIPHER_LEN 16
+#define EAP_SAKE_TEK_LEN (EAP_SAKE_TEK_AUTH_LEN + EAP_SAKE_TEK_CIPHER_LEN)
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct eap_sake_hdr {
+ u8 code;
+ u8 identifier;
+ u16 length;
+ u8 type; /* EAP_TYPE_SAKE */
+ u8 version; /* EAP_SAKE_VERSION */
+ u8 session_id;
+ u8 subtype;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+struct eap_sake_parse_attr {
+ const u8 *rand_s;
+ const u8 *rand_p;
+ const u8 *mic_s;
+ const u8 *mic_p;
+ const u8 *serverid;
+ size_t serverid_len;
+ const u8 *peerid;
+ size_t peerid_len;
+ const u8 *spi_s;
+ size_t spi_s_len;
+ const u8 *spi_p;
+ size_t spi_p_len;
+ const u8 *any_id_req;
+ const u8 *perm_id_req;
+ const u8 *encr_data;
+ size_t encr_data_len;
+ const u8 *iv;
+ size_t iv_len;
+ const u8 *next_tmpid;
+ size_t next_tmpid_len;
+ const u8 *msk_life;
+};
+
+int eap_sake_parse_attributes(const u8 *buf, size_t len,
+ struct eap_sake_parse_attr *attr);
+void eap_sake_derive_keys(const u8 *root_secret_a, const u8 *root_secret_b,
+ const u8 *rand_s, const u8 *rand_p,
+ u8 *tek, u8 *msk, u8 *emsk);
+int eap_sake_compute_mic(const u8 *tek_auth,
+ const u8 *rand_s, const u8 *rand_p,
+ const u8 *serverid, size_t serverid_len,
+ const u8 *peerid, size_t peerid_len,
+ int peer, const u8 *eap, size_t eap_len,
+ const u8 *mic_pos, u8 *mic);
+
+#endif /* EAP_SAKE_COMMON_H */
diff --git a/contrib/hostapd/eap_sim.c b/contrib/hostapd/eap_sim.c
index fa60cf54d1c7..8c3c82870036 100644
--- a/contrib/hostapd/eap_sim.c
+++ b/contrib/hostapd/eap_sim.c
@@ -1,6 +1,6 @@
/*
- * hostapd / EAP-SIM (draft-haverinen-pppext-eap-sim-15.txt)
- * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * hostapd / EAP-SIM (RFC 4186)
+ * 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
@@ -12,10 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <netinet/in.h>
+#include "includes.h"
#include "hostapd.h"
#include "common.h"
@@ -25,38 +22,23 @@
#include "eap_sim_db.h"
-#define EAP_SIM_VERSION 1
-
-/* EAP-SIM Subtypes */
-#define EAP_SIM_SUBTYPE_START 10
-#define EAP_SIM_SUBTYPE_CHALLENGE 11
-#define EAP_SIM_SUBTYPE_NOTIFICATION 12
-#define EAP_SIM_SUBTYPE_REAUTHENTICATION 13
-#define EAP_SIM_SUBTYPE_CLIENT_ERROR 14
-
-/* AT_CLIENT_ERROR_CODE error codes */
-#define EAP_SIM_UNABLE_TO_PROCESS_PACKET 0
-#define EAP_SIM_UNSUPPORTED_VERSION 1
-#define EAP_SIM_INSUFFICIENT_NUM_OF_CHAL 2
-#define EAP_SIM_RAND_NOT_FRESH 3
-
-#define KC_LEN 8
-#define SRES_LEN 4
-#define EAP_SIM_MAX_FAST_REAUTHS 1000
-
-#define EAP_SIM_MAX_CHAL 3
-
struct eap_sim_data {
u8 mk[EAP_SIM_MK_LEN];
u8 nonce_mt[EAP_SIM_NONCE_MT_LEN];
+ u8 nonce_s[EAP_SIM_NONCE_S_LEN];
u8 k_aut[EAP_SIM_K_AUT_LEN];
u8 k_encr[EAP_SIM_K_ENCR_LEN];
u8 msk[EAP_SIM_KEYING_DATA_LEN];
- u8 kc[EAP_SIM_MAX_CHAL][KC_LEN];
- u8 sres[EAP_SIM_MAX_CHAL][SRES_LEN];
+ u8 emsk[EAP_EMSK_LEN];
+ u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
+ u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
int num_chal;
- enum { START, CHALLENGE, SUCCESS, FAILURE } state;
+ enum { START, CHALLENGE, REAUTH, SUCCESS, FAILURE } state;
+ char *next_pseudonym;
+ char *next_reauth_id;
+ u16 counter;
+ struct eap_sim_reauth *reauth;
};
@@ -67,6 +49,8 @@ static const char * eap_sim_state_txt(int state)
return "START";
case CHALLENGE:
return "CHALLENGE";
+ case REAUTH:
+ return "REAUTH";
case SUCCESS:
return "SUCCESS";
case FAILURE:
@@ -79,7 +63,7 @@ static const char * eap_sim_state_txt(int state)
static void eap_sim_state(struct eap_sim_data *data, int state)
{
- wpa_printf(MSG_DEBUG, "EAP-SIM %s -> %s",
+ wpa_printf(MSG_DEBUG, "EAP-SIM: %s -> %s",
eap_sim_state_txt(data->state),
eap_sim_state_txt(state));
data->state = state;
@@ -95,10 +79,9 @@ static void * eap_sim_init(struct eap_sm *sm)
return NULL;
}
- data = malloc(sizeof(*data));
+ data = wpa_zalloc(sizeof(*data));
if (data == NULL)
- return data;
- memset(data, 0, sizeof(*data));
+ return NULL;
data->state = START;
return data;
@@ -108,6 +91,8 @@ static void * eap_sim_init(struct eap_sm *sm)
static void eap_sim_reset(struct eap_sm *sm, void *priv)
{
struct eap_sim_data *data = priv;
+ free(data->next_pseudonym);
+ free(data->next_reauth_id);
free(data);
}
@@ -118,12 +103,15 @@ static u8 * eap_sim_build_start(struct eap_sm *sm, struct eap_sim_data *data,
struct eap_sim_msg *msg;
u8 ver[2];
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Start");
msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
EAP_SIM_SUBTYPE_START);
if (eap_sim_db_identity_known(sm->eap_sim_db_priv, sm->identity,
sm->identity_len)) {
+ wpa_printf(MSG_DEBUG, " AT_PERMANENT_ID_REQ");
eap_sim_msg_add(msg, EAP_SIM_AT_PERMANENT_ID_REQ, 0, NULL, 0);
}
+ wpa_printf(MSG_DEBUG, " AT_VERSION_LIST");
ver[0] = 0;
ver[1] = EAP_SIM_VERSION;
eap_sim_msg_add(msg, EAP_SIM_AT_VERSION_LIST, sizeof(ver),
@@ -132,22 +120,128 @@ static u8 * eap_sim_build_start(struct eap_sm *sm, struct eap_sim_data *data,
}
+static int eap_sim_build_encr(struct eap_sm *sm, struct eap_sim_data *data,
+ struct eap_sim_msg *msg, u16 counter,
+ const u8 *nonce_s)
+{
+ free(data->next_pseudonym);
+ data->next_pseudonym =
+ eap_sim_db_get_next_pseudonym(sm->eap_sim_db_priv, 0);
+ free(data->next_reauth_id);
+ if (data->counter <= EAP_SIM_MAX_FAST_REAUTHS) {
+ data->next_reauth_id =
+ eap_sim_db_get_next_reauth_id(sm->eap_sim_db_priv, 0);
+ } else {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Max fast re-authentication "
+ "count exceeded - force full authentication");
+ data->next_reauth_id = NULL;
+ }
+
+ if (data->next_pseudonym == NULL && data->next_reauth_id == NULL &&
+ counter == 0 && nonce_s == NULL)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, " AT_IV");
+ wpa_printf(MSG_DEBUG, " AT_ENCR_DATA");
+ eap_sim_msg_add_encr_start(msg, EAP_SIM_AT_IV, EAP_SIM_AT_ENCR_DATA);
+
+ if (counter > 0) {
+ wpa_printf(MSG_DEBUG, " *AT_COUNTER (%u)", counter);
+ eap_sim_msg_add(msg, EAP_SIM_AT_COUNTER, counter, NULL, 0);
+ }
+
+ if (nonce_s) {
+ wpa_printf(MSG_DEBUG, " *AT_NONCE_S");
+ eap_sim_msg_add(msg, EAP_SIM_AT_NONCE_S, 0, nonce_s,
+ EAP_SIM_NONCE_S_LEN);
+ }
+
+ if (data->next_pseudonym) {
+ wpa_printf(MSG_DEBUG, " *AT_NEXT_PSEUDONYM (%s)",
+ data->next_pseudonym);
+ eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_PSEUDONYM,
+ strlen(data->next_pseudonym),
+ (u8 *) data->next_pseudonym,
+ strlen(data->next_pseudonym));
+ }
+
+ if (data->next_reauth_id) {
+ wpa_printf(MSG_DEBUG, " *AT_NEXT_REAUTH_ID (%s)",
+ data->next_reauth_id);
+ eap_sim_msg_add(msg, EAP_SIM_AT_NEXT_REAUTH_ID,
+ strlen(data->next_reauth_id),
+ (u8 *) data->next_reauth_id,
+ strlen(data->next_reauth_id));
+ }
+
+ if (eap_sim_msg_add_encr_end(msg, data->k_encr, EAP_SIM_AT_PADDING)) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to encrypt "
+ "AT_ENCR_DATA");
+ return -1;
+ }
+
+ return 0;
+}
+
+
static u8 * eap_sim_build_challenge(struct eap_sm *sm,
struct eap_sim_data *data,
int id, size_t *reqDataLen)
{
struct eap_sim_msg *msg;
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Challenge");
msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
EAP_SIM_SUBTYPE_CHALLENGE);
+ wpa_printf(MSG_DEBUG, " AT_RAND");
eap_sim_msg_add(msg, EAP_SIM_AT_RAND, 0, (u8 *) data->rand,
data->num_chal * GSM_RAND_LEN);
+
+ if (eap_sim_build_encr(sm, data, msg, 0, NULL)) {
+ eap_sim_msg_free(msg);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, " AT_MAC");
eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
return eap_sim_msg_finish(msg, reqDataLen, data->k_aut, data->nonce_mt,
EAP_SIM_NONCE_MT_LEN);
}
+static u8 * eap_sim_build_reauth(struct eap_sm *sm,
+ struct eap_sim_data *data,
+ int id, size_t *reqDataLen)
+{
+ struct eap_sim_msg *msg;
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Generating Re-authentication");
+
+ if (hostapd_get_rand(data->nonce_s, EAP_SIM_NONCE_S_LEN))
+ return NULL;
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: NONCE_S",
+ data->nonce_s, EAP_SIM_NONCE_S_LEN);
+
+ eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
+ data->emsk);
+ eap_sim_derive_keys_reauth(data->counter, sm->identity,
+ sm->identity_len, data->nonce_s, data->mk,
+ data->msk, data->emsk);
+
+ msg = eap_sim_msg_init(EAP_CODE_REQUEST, id, EAP_TYPE_SIM,
+ EAP_SIM_SUBTYPE_REAUTHENTICATION);
+
+ if (eap_sim_build_encr(sm, data, msg, data->counter, data->nonce_s)) {
+ eap_sim_msg_free(msg);
+ return NULL;
+ }
+
+ wpa_printf(MSG_DEBUG, " AT_MAC");
+ eap_sim_msg_add_mac(msg, EAP_SIM_AT_MAC);
+ return eap_sim_msg_finish(msg, reqDataLen, data->k_aut, NULL, 0);
+}
+
+
static u8 * eap_sim_buildReq(struct eap_sm *sm, void *priv, int id,
size_t *reqDataLen)
{
@@ -158,6 +252,8 @@ static u8 * eap_sim_buildReq(struct eap_sm *sm, void *priv, int id,
return eap_sim_build_start(sm, data, id, reqDataLen);
case CHALLENGE:
return eap_sim_build_challenge(sm, data, id, reqDataLen);
+ case REAUTH:
+ return eap_sim_build_reauth(sm, data, id, reqDataLen);
default:
wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
"buildReq", data->state);
@@ -173,12 +269,11 @@ static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
struct eap_sim_data *data = priv;
struct eap_hdr *resp;
u8 *pos, subtype;
- size_t len;
resp = (struct eap_hdr *) respData;
pos = (u8 *) (resp + 1);
if (respDataLen < sizeof(*resp) + 4 || *pos != EAP_TYPE_SIM ||
- (len = ntohs(resp->length)) > respDataLen) {
+ (ntohs(resp->length)) > respDataLen) {
wpa_printf(MSG_INFO, "EAP-SIM: Invalid frame");
return TRUE;
}
@@ -202,6 +297,13 @@ static Boolean eap_sim_check(struct eap_sm *sm, void *priv,
return TRUE;
}
break;
+ case REAUTH:
+ if (subtype != EAP_SIM_SUBTYPE_REAUTHENTICATION) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Unexpected response "
+ "subtype %d", subtype);
+ return TRUE;
+ }
+ break;
default:
wpa_printf(MSG_INFO, "EAP-SIM: Unexpected state (%d) for "
"processing a response", data->state);
@@ -218,43 +320,15 @@ static int eap_sim_supported_ver(struct eap_sim_data *data, int version)
}
-static void eap_sim_derive_mk(struct eap_sim_data *data,
- const u8 *identity, size_t identity_len,
- const u8 *nonce_mt, int selected_version,
- int num_chal, const u8 *kc)
-{
- u8 sel_ver[2], ver_list[2];
- const unsigned char *addr[5];
- size_t len[5];
-
- addr[0] = identity;
- addr[1] = kc;
- addr[2] = nonce_mt;
- addr[3] = ver_list;
- addr[4] = sel_ver;
-
- len[0] = identity_len;
- len[1] = num_chal * KC_LEN;
- len[2] = EAP_SIM_NONCE_MT_LEN;
- len[3] = sizeof(ver_list);
- len[4] = sizeof(sel_ver);
-
- ver_list[0] = 0;
- ver_list[1] = EAP_SIM_VERSION;
- sel_ver[0] = selected_version >> 8;
- sel_ver[1] = selected_version & 0xff;
-
- /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
- sha1_vector(5, addr, len, data->mk);
- wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", data->mk, EAP_SIM_MK_LEN);
-}
-
-
static void eap_sim_process_start(struct eap_sm *sm,
struct eap_sim_data *data,
u8 *respData, size_t respDataLen,
struct eap_sim_attrs *attr)
{
+ const u8 *identity;
+ size_t identity_len;
+ u8 ver_list[2];
+
wpa_printf(MSG_DEBUG, "EAP-SIM: Receive start response");
if (attr->nonce_mt == NULL || attr->selected_version < 0) {
@@ -281,8 +355,35 @@ static void eap_sim_process_start(struct eap_sm *sm,
}
}
- if (sm->identity == NULL || sm->identity_len < 1 ||
- sm->identity[0] != '1') {
+ identity = NULL;
+ identity_len = 0;
+
+ if (sm->identity && sm->identity_len > 0 &&
+ sm->identity[0] == EAP_SIM_PERMANENT_PREFIX) {
+ identity = sm->identity;
+ identity_len = sm->identity_len;
+ } else {
+ identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv,
+ sm->identity,
+ sm->identity_len,
+ &identity_len);
+ if (identity == NULL) {
+ data->reauth = eap_sim_db_get_reauth_entry(
+ sm->eap_sim_db_priv, sm->identity,
+ sm->identity_len);
+ if (data->reauth) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Using fast "
+ "re-authentication");
+ identity = data->reauth->identity;
+ identity_len = data->reauth->identity_len;
+ data->counter = data->reauth->counter;
+ memcpy(data->mk, data->reauth->mk,
+ EAP_SIM_MK_LEN);
+ }
+ }
+ }
+
+ if (identity == NULL) {
wpa_printf(MSG_DEBUG, "EAP-SIM: Could not get proper permanent"
" user name");
eap_sim_state(data, FAILURE);
@@ -290,12 +391,26 @@ static void eap_sim_process_start(struct eap_sm *sm,
}
wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity",
- sm->identity, sm->identity_len);
+ identity, identity_len);
+
+ if (data->reauth) {
+ eap_sim_state(data, REAUTH);
+ return;
+ }
+
+ data->counter = 0; /* reset re-auth counter since this is full auth */
+ data->reauth = NULL;
data->num_chal = eap_sim_db_get_gsm_triplets(
- sm->eap_sim_db_priv, sm->identity, sm->identity_len,
+ sm->eap_sim_db_priv, identity, identity_len,
EAP_SIM_MAX_CHAL,
- (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres);
+ (u8 *) data->rand, (u8 *) data->kc, (u8 *) data->sres, sm);
+ if (data->num_chal == EAP_SIM_DB_PENDING) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: GSM authentication triplets "
+ "not yet available - pending request");
+ sm->method_pending = METHOD_PENDING_WAIT;
+ return;
+ }
if (data->num_chal < 2) {
wpa_printf(MSG_INFO, "EAP-SIM: Failed to get GSM "
"authentication triplets for the peer");
@@ -303,11 +418,16 @@ static void eap_sim_process_start(struct eap_sm *sm,
return;
}
+ wpa_hexdump_ascii(MSG_DEBUG, "EAP-SIM: Identity for MK derivation",
+ sm->identity, sm->identity_len);
+
memcpy(data->nonce_mt, attr->nonce_mt, EAP_SIM_NONCE_MT_LEN);
- eap_sim_derive_mk(data, sm->identity, sm->identity_len, attr->nonce_mt,
- attr->selected_version, data->num_chal,
- (u8 *) data->kc);
- eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk);
+ WPA_PUT_BE16(ver_list, EAP_SIM_VERSION);
+ eap_sim_derive_mk(sm->identity, sm->identity_len, attr->nonce_mt,
+ attr->selected_version, ver_list, sizeof(ver_list),
+ data->num_chal, (const u8 *) data->kc, data->mk);
+ eap_sim_derive_keys(data->mk, data->k_encr, data->k_aut, data->msk,
+ data->emsk);
eap_sim_state(data, CHALLENGE);
}
@@ -318,9 +438,13 @@ static void eap_sim_process_challenge(struct eap_sm *sm,
u8 *respData, size_t respDataLen,
struct eap_sim_attrs *attr)
{
+ const u8 *identity;
+ size_t identity_len;
+
if (attr->mac == NULL ||
eap_sim_verify_mac(data->k_aut, respData, respDataLen, attr->mac,
- (u8 *) data->sres, data->num_chal * SRES_LEN)) {
+ (u8 *) data->sres,
+ data->num_chal * EAP_SIM_SRES_LEN)) {
wpa_printf(MSG_WARNING, "EAP-SIM: Challenge message "
"did not include valid AT_MAC");
eap_sim_state(data, FAILURE);
@@ -330,6 +454,113 @@ static void eap_sim_process_challenge(struct eap_sm *sm,
wpa_printf(MSG_DEBUG, "EAP-SIM: Challenge response includes the "
"correct AT_MAC");
eap_sim_state(data, SUCCESS);
+
+ identity = eap_sim_db_get_permanent(sm->eap_sim_db_priv, sm->identity,
+ sm->identity_len, &identity_len);
+ if (identity == NULL) {
+ identity = sm->identity;
+ identity_len = sm->identity_len;
+ }
+
+ if (data->next_pseudonym) {
+ eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
+ identity_len,
+ data->next_pseudonym);
+ data->next_pseudonym = NULL;
+ }
+ if (data->next_reauth_id) {
+ eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
+ identity_len,
+ data->next_reauth_id, data->counter + 1,
+ data->mk);
+ data->next_reauth_id = NULL;
+ }
+}
+
+
+static void eap_sim_process_reauth(struct eap_sm *sm,
+ struct eap_sim_data *data,
+ u8 *respData, size_t respDataLen,
+ struct eap_sim_attrs *attr)
+{
+ struct eap_sim_attrs eattr;
+ u8 *decrypted = NULL;
+ const u8 *identity, *id2;
+ size_t identity_len, id2_len;
+
+ if (attr->mac == NULL ||
+ eap_sim_verify_mac(data->k_aut, respData, respDataLen, attr->mac,
+ data->nonce_s, EAP_SIM_NONCE_S_LEN)) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
+ "did not include valid AT_MAC");
+ goto fail;
+ }
+
+ if (attr->encr_data == NULL || attr->iv == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Reauthentication "
+ "message did not include encrypted data");
+ goto fail;
+ }
+
+ decrypted = eap_sim_parse_encr(data->k_encr, attr->encr_data,
+ attr->encr_data_len, attr->iv, &eattr,
+ 0);
+ if (decrypted == NULL) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Failed to parse encrypted "
+ "data from reauthentication message");
+ goto fail;
+ }
+
+ if (eattr.counter != data->counter) {
+ wpa_printf(MSG_WARNING, "EAP-SIM: Re-authentication message "
+ "used incorrect counter %u, expected %u",
+ eattr.counter, data->counter);
+ goto fail;
+ }
+ free(decrypted);
+ decrypted = NULL;
+
+ wpa_printf(MSG_DEBUG, "EAP-SIM: Re-authentication response includes "
+ "the correct AT_MAC");
+ eap_sim_state(data, SUCCESS);
+
+ if (data->reauth) {
+ identity = data->reauth->identity;
+ identity_len = data->reauth->identity_len;
+ } else {
+ identity = sm->identity;
+ identity_len = sm->identity_len;
+ }
+
+ id2 = eap_sim_db_get_permanent(sm->eap_sim_db_priv, identity,
+ identity_len, &id2_len);
+ if (id2) {
+ identity = id2;
+ identity_len = id2_len;
+ }
+
+ if (data->next_pseudonym) {
+ eap_sim_db_add_pseudonym(sm->eap_sim_db_priv, identity,
+ identity_len, data->next_pseudonym);
+ data->next_pseudonym = NULL;
+ }
+ if (data->next_reauth_id) {
+ eap_sim_db_add_reauth(sm->eap_sim_db_priv, identity,
+ identity_len, data->next_reauth_id,
+ data->counter + 1, data->mk);
+ data->next_reauth_id = NULL;
+ } else {
+ eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ data->reauth = NULL;
+ }
+
+ return;
+
+fail:
+ eap_sim_state(data, FAILURE);
+ eap_sim_db_remove_reauth(sm->eap_sim_db_priv, data->reauth);
+ data->reauth = NULL;
+ free(decrypted);
}
@@ -377,6 +608,9 @@ static void eap_sim_process(struct eap_sm *sm, void *priv,
case CHALLENGE:
eap_sim_process_challenge(sm, data, respData, len, &attr);
break;
+ case REAUTH:
+ eap_sim_process_reauth(sm, data, respData, len, &attr);
+ break;
default:
wpa_printf(MSG_DEBUG, "EAP-SIM: Unknown state %d in "
"process", data->state);
@@ -409,6 +643,23 @@ static u8 * eap_sim_getKey(struct eap_sm *sm, void *priv, size_t *len)
}
+static u8 * eap_sim_get_emsk(struct eap_sm *sm, void *priv, size_t *len)
+{
+ struct eap_sim_data *data = priv;
+ u8 *key;
+
+ if (data->state != SUCCESS)
+ return NULL;
+
+ key = malloc(EAP_EMSK_LEN);
+ if (key == NULL)
+ return NULL;
+ memcpy(key, data->emsk, EAP_EMSK_LEN);
+ *len = EAP_EMSK_LEN;
+ return key;
+}
+
+
static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
{
struct eap_sim_data *data = priv;
@@ -416,16 +667,28 @@ static Boolean eap_sim_isSuccess(struct eap_sm *sm, void *priv)
}
-const struct eap_method eap_method_sim =
+int eap_server_sim_register(void)
{
- .method = EAP_TYPE_SIM,
- .name = "SIM",
- .init = eap_sim_init,
- .reset = eap_sim_reset,
- .buildReq = eap_sim_buildReq,
- .check = eap_sim_check,
- .process = eap_sim_process,
- .isDone = eap_sim_isDone,
- .getKey = eap_sim_getKey,
- .isSuccess = eap_sim_isSuccess,
-};
+ struct eap_method *eap;
+ int ret;
+
+ eap = eap_server_method_alloc(EAP_SERVER_METHOD_INTERFACE_VERSION,
+ EAP_VENDOR_IETF, EAP_TYPE_SIM, "SIM");
+ if (eap == NULL)
+ return -1;
+
+ eap->init = eap_sim_init;
+ eap->reset = eap_sim_reset;
+ eap->buildReq = eap_sim_buildReq;
+ eap->check = eap_sim_check;
+ eap->process = eap_sim_process;
+ eap->isDone = eap_sim_isDone;
+ eap->getKey = eap_sim_getKey;
+ eap->isSuccess = eap_sim_isSuccess;
+ eap->get_emsk = eap_sim_get_emsk;
+
+ ret = eap_server_method_register(eap);
+ if (ret)
+ eap_server_method_free(eap);
+ return ret;
+}
diff --git a/contrib/hostapd/eap_sim_common.c b/contrib/hostapd/eap_sim_common.c
index 75947b7995a0..dc8b2f6f4b10 100644
--- a/contrib/hostapd/eap_sim_common.c
+++ b/contrib/hostapd/eap_sim_common.c
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-SIM/AKA shared routines
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer: EAP-SIM/AKA shared routines
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -12,9 +12,7 @@
* See README and COPYING for more details.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
#include "common.h"
#include "eap_i.h"
@@ -24,80 +22,98 @@
#include "eap_sim_common.h"
-static void eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
+static int eap_sim_prf(const u8 *key, u8 *x, size_t xlen)
{
- u8 xkey[64];
- u32 t[5], _t[5];
- int i, j, m, k;
- u8 *xpos = x;
- u32 carry;
-
- /* FIPS 186-2 + change notice 1 */
-
- memcpy(xkey, key, EAP_SIM_MK_LEN);
- memset(xkey + EAP_SIM_MK_LEN, 0, 64 - EAP_SIM_MK_LEN);
- t[0] = 0x67452301;
- t[1] = 0xEFCDAB89;
- t[2] = 0x98BADCFE;
- t[3] = 0x10325476;
- t[4] = 0xC3D2E1F0;
-
- m = xlen / 40;
- for (j = 0; j < m; j++) {
- /* XSEED_j = 0 */
- for (i = 0; i < 2; i++) {
- /* XVAL = (XKEY + XSEED_j) mod 2^b */
-
- /* w_i = G(t, XVAL) */
- memcpy(_t, t, 20);
- sha1_transform((u8 *) _t, xkey);
- _t[0] = host_to_be32(_t[0]);
- _t[1] = host_to_be32(_t[1]);
- _t[2] = host_to_be32(_t[2]);
- _t[3] = host_to_be32(_t[3]);
- _t[4] = host_to_be32(_t[4]);
- memcpy(xpos, _t, 20);
-
- /* XKEY = (1 + XKEY + w_i) mod 2^b */
- carry = 1;
- for (k = 19; k >= 0; k--) {
- carry += xkey[k] + xpos[k];
- xkey[k] = carry & 0xff;
- carry >>= 8;
- }
+ return fips186_2_prf(key, EAP_SIM_MK_LEN, x, xlen);
+}
- xpos += SHA1_MAC_LEN;
- }
- /* x_j = w_0|w_1 */
- }
+
+void eap_sim_derive_mk(const u8 *identity, size_t identity_len,
+ const u8 *nonce_mt, u16 selected_version,
+ const u8 *ver_list, size_t ver_list_len,
+ int num_chal, const u8 *kc, u8 *mk)
+{
+ u8 sel_ver[2];
+ const unsigned char *addr[5];
+ size_t len[5];
+
+ addr[0] = identity;
+ len[0] = identity_len;
+ addr[1] = kc;
+ len[1] = num_chal * EAP_SIM_KC_LEN;
+ addr[2] = nonce_mt;
+ len[2] = EAP_SIM_NONCE_MT_LEN;
+ addr[3] = ver_list;
+ len[3] = ver_list_len;
+ addr[4] = sel_ver;
+ len[4] = 2;
+
+ WPA_PUT_BE16(sel_ver, selected_version);
+
+ /* MK = SHA1(Identity|n*Kc|NONCE_MT|Version List|Selected Version) */
+ sha1_vector(5, addr, len, mk);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: MK", mk, EAP_SIM_MK_LEN);
+}
+
+
+void eap_aka_derive_mk(const u8 *identity, size_t identity_len,
+ const u8 *ik, const u8 *ck, u8 *mk)
+{
+ const u8 *addr[3];
+ size_t len[3];
+
+ addr[0] = identity;
+ len[0] = identity_len;
+ addr[1] = ik;
+ len[1] = EAP_AKA_IK_LEN;
+ addr[2] = ck;
+ len[2] = EAP_AKA_CK_LEN;
+
+ /* MK = SHA1(Identity|IK|CK) */
+ sha1_vector(3, addr, len, mk);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: IK", ik, EAP_AKA_IK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: CK", ck, EAP_AKA_CK_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-AKA: MK", mk, EAP_SIM_MK_LEN);
}
-void eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk)
+int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk, u8 *emsk)
{
- u8 buf[120], *pos;
- eap_sim_prf(mk, buf, 120);
+ u8 buf[EAP_SIM_K_ENCR_LEN + EAP_SIM_K_AUT_LEN +
+ EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN], *pos;
+ if (eap_sim_prf(mk, buf, sizeof(buf)) < 0) {
+ wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
+ return -1;
+ }
pos = buf;
- memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
+ os_memcpy(k_encr, pos, EAP_SIM_K_ENCR_LEN);
pos += EAP_SIM_K_ENCR_LEN;
- memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
+ os_memcpy(k_aut, pos, EAP_SIM_K_AUT_LEN);
pos += EAP_SIM_K_AUT_LEN;
- memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
+ os_memcpy(msk, pos, EAP_SIM_KEYING_DATA_LEN);
+ pos += EAP_SIM_KEYING_DATA_LEN;
+ os_memcpy(emsk, pos, EAP_EMSK_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_encr",
k_encr, EAP_SIM_K_ENCR_LEN);
wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: K_aut",
- k_aut, EAP_SIM_K_ENCR_LEN);
- wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material",
+ k_aut, EAP_SIM_K_AUT_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
msk, EAP_SIM_KEYING_DATA_LEN);
+ wpa_hexdump_key(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
+ os_memset(buf, 0, sizeof(buf));
+
+ return 0;
}
-void eap_sim_derive_keys_reauth(u16 _counter,
- const u8 *identity, size_t identity_len,
- const u8 *nonce_s, const u8 *mk, u8 *msk)
+int eap_sim_derive_keys_reauth(u16 _counter,
+ const u8 *identity, size_t identity_len,
+ const u8 *nonce_s, const u8 *mk, u8 *msk,
+ u8 *emsk)
{
u8 xkey[SHA1_MAC_LEN];
+ u8 buf[EAP_SIM_KEYING_DATA_LEN + EAP_EMSK_LEN + 32];
u8 counter[2];
const u8 *addr[4];
size_t len[4];
@@ -125,9 +141,22 @@ void eap_sim_derive_keys_reauth(u16 _counter,
sha1_vector(4, addr, len, xkey);
wpa_hexdump(MSG_DEBUG, "EAP-SIM: XKEY'", xkey, SHA1_MAC_LEN);
- eap_sim_prf(xkey, msk, EAP_SIM_KEYING_DATA_LEN);
- wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material",
- msk, EAP_SIM_KEYING_DATA_LEN);
+ if (eap_sim_prf(xkey, buf, sizeof(buf)) < 0) {
+ wpa_printf(MSG_ERROR, "EAP-SIM: Failed to derive keys");
+ return -1;
+ }
+ if (msk) {
+ os_memcpy(msk, buf, EAP_SIM_KEYING_DATA_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: keying material (MSK)",
+ msk, EAP_SIM_KEYING_DATA_LEN);
+ }
+ if (emsk) {
+ os_memcpy(emsk, buf + EAP_SIM_KEYING_DATA_LEN, EAP_EMSK_LEN);
+ wpa_hexdump(MSG_DEBUG, "EAP-SIM: EMSK", emsk, EAP_EMSK_LEN);
+ }
+ os_memset(buf, 0, sizeof(buf));
+
+ return 0;
}
@@ -143,7 +172,7 @@ int eap_sim_verify_mac(const u8 *k_aut, const u8 *req, size_t req_len,
mac > req + req_len - EAP_SIM_MAC_LEN)
return -1;
- tmp = malloc(req_len);
+ tmp = os_malloc(req_len);
if (tmp == NULL)
return -1;
@@ -153,12 +182,19 @@ int eap_sim_verify_mac(const u8 *k_aut, const u8 *req, size_t req_len,
len[1] = extra_len;
/* HMAC-SHA1-128 */
- memcpy(tmp, req, req_len);
- memset(tmp + (mac - req), 0, EAP_SIM_MAC_LEN);
+ os_memcpy(tmp, req, req_len);
+ os_memset(tmp + (mac - req), 0, EAP_SIM_MAC_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - msg", tmp, req_len);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC - extra data",
+ extra, extra_len);
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Verify MAC - K_aut",
+ k_aut, EAP_SIM_K_AUT_LEN);
hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
- free(tmp);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Verify MAC: MAC",
+ hmac, EAP_SIM_MAC_LEN);
+ os_free(tmp);
- return (memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
+ return (os_memcmp(hmac, mac, EAP_SIM_MAC_LEN) == 0) ? 0 : 1;
}
@@ -175,9 +211,16 @@ void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
len[1] = extra_len;
/* HMAC-SHA1-128 */
- memset(mac, 0, EAP_SIM_MAC_LEN);
+ os_memset(mac, 0, EAP_SIM_MAC_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - msg", msg, msg_len);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC - extra data",
+ extra, extra_len);
+ wpa_hexdump_key(MSG_MSGDUMP, "EAP-SIM: Add MAC - K_aut",
+ k_aut, EAP_SIM_K_AUT_LEN);
hmac_sha1_vector(k_aut, EAP_SIM_K_AUT_LEN, 2, addr, len, hmac);
- memcpy(mac, hmac, EAP_SIM_MAC_LEN);
+ os_memcpy(mac, hmac, EAP_SIM_MAC_LEN);
+ wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Add MAC: MAC",
+ mac, EAP_SIM_MAC_LEN);
}
@@ -185,10 +228,9 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end,
struct eap_sim_attrs *attr, int aka, int encr)
{
const u8 *pos = start, *apos;
- size_t alen, plen;
- int list_len, i;
+ size_t alen, plen, i, list_len;
- memset(attr, 0, sizeof(*attr));
+ os_memset(attr, 0, sizeof(*attr));
attr->id_req = NO_ID_REQ;
attr->notification = -1;
attr->counter = -1;
@@ -219,7 +261,7 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end,
apos += 2;
alen -= 2;
if ((!aka && (alen % GSM_RAND_LEN)) ||
- (aka && alen != AKA_RAND_LEN)) {
+ (aka && alen != EAP_AKA_RAND_LEN)) {
wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RAND"
" (len %lu)",
(unsigned long) alen);
@@ -237,7 +279,7 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end,
}
apos += 2;
alen -= 2;
- if (alen != AKA_AUTN_LEN) {
+ if (alen != EAP_AKA_AUTN_LEN) {
wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTN"
" (len %lu)",
(unsigned long) alen);
@@ -316,8 +358,9 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end,
wpa_printf(MSG_DEBUG, "EAP-SIM: AT_VERSION_LIST");
if (list_len < 2 || list_len > alen - 2) {
wpa_printf(MSG_WARNING, "EAP-SIM: Invalid "
- "AT_VERSION_LIST (list_len=%d "
- "attr_len=%lu)", list_len,
+ "AT_VERSION_LIST (list_len=%lu "
+ "attr_len=%lu)",
+ (unsigned long) list_len,
(unsigned long) alen);
return -1;
}
@@ -356,6 +399,22 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end,
wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) AT_COUNTER %d",
attr->counter);
break;
+ case EAP_SIM_AT_COUNTER_TOO_SMALL:
+ if (!encr) {
+ wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
+ "AT_COUNTER_TOO_SMALL");
+ return -1;
+ }
+ if (alen != 2) {
+ wpa_printf(MSG_INFO, "EAP-SIM: (encr) Invalid "
+ "AT_COUNTER_TOO_SMALL (alen=%lu)",
+ (unsigned long) alen);
+ return -1;
+ }
+ wpa_printf(MSG_DEBUG, "EAP-SIM: (encr) "
+ "AT_COUNTER_TOO_SMALL");
+ attr->counter_too_small = 1;
+ break;
case EAP_SIM_AT_NONCE_S:
if (!encr) {
wpa_printf(MSG_ERROR, "EAP-SIM: Unencrypted "
@@ -444,6 +503,35 @@ int eap_sim_parse_attr(const u8 *start, const u8 *end,
attr->next_reauth_id = pos + 4;
attr->next_reauth_id_len = plen;
break;
+ case EAP_SIM_AT_RES:
+ wpa_printf(MSG_DEBUG, "EAP-SIM: AT_RES");
+ apos += 2;
+ alen -= 2;
+ if (!aka || alen < EAP_AKA_MIN_RES_LEN ||
+ alen > EAP_AKA_MAX_RES_LEN) {
+ wpa_printf(MSG_INFO, "EAP-SIM: Invalid AT_RES "
+ "(len %lu)",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->res = apos;
+ attr->res_len = alen;
+ break;
+ case EAP_SIM_AT_AUTS:
+ wpa_printf(MSG_DEBUG, "EAP-AKA: AT_AUTS");
+ if (!aka) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM: "
+ "Unexpected AT_AUTS");
+ return -1;
+ }
+ if (alen != EAP_AKA_AUTS_LEN) {
+ wpa_printf(MSG_INFO, "EAP-AKA: Invalid AT_AUTS"
+ " (len %lu)",
+ (unsigned long) alen);
+ return -1;
+ }
+ attr->auts = apos;
+ break;
default:
if (pos[0] < 128) {
wpa_printf(MSG_INFO, "EAP-SIM: Unrecognized "
@@ -478,10 +566,10 @@ u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
return NULL;
}
- decrypted = malloc(encr_data_len);
+ decrypted = os_malloc(encr_data_len);
if (decrypted == NULL)
return NULL;
- memcpy(decrypted, encr_data, encr_data_len);
+ os_memcpy(decrypted, encr_data, encr_data_len);
aes_128_cbc_decrypt(k_encr, iv, decrypted, encr_data_len);
wpa_hexdump(MSG_MSGDUMP, "EAP-SIM: Decrypted AT_ENCR_DATA",
@@ -491,7 +579,7 @@ u8 * eap_sim_parse_encr(const u8 *k_encr, const u8 *encr_data,
aka, 1)) {
wpa_printf(MSG_INFO, "EAP-SIM: (encr) Failed to parse "
"decrypted AT_ENCR_DATA");
- free(decrypted);
+ os_free(decrypted);
return NULL;
}
@@ -514,17 +602,15 @@ struct eap_sim_msg * eap_sim_msg_init(int code, int id, int type, int subtype)
struct eap_hdr *eap;
u8 *pos;
- msg = malloc(sizeof(*msg));
+ msg = os_zalloc(sizeof(*msg));
if (msg == NULL)
return NULL;
- memset(msg, 0, sizeof(*msg));
- msg->buf = malloc(EAP_SIM_INIT_LEN);
+ msg->buf = os_zalloc(EAP_SIM_INIT_LEN);
if (msg->buf == NULL) {
- free(msg);
+ os_free(msg);
return NULL;
}
- memset(msg->buf, 0, EAP_SIM_INIT_LEN);
msg->buf_len = EAP_SIM_INIT_LEN;
eap = (struct eap_hdr *) msg->buf;
eap->code = code;
@@ -561,7 +647,7 @@ u8 * eap_sim_msg_finish(struct eap_sim_msg *msg, size_t *len, const u8 *k_aut,
*len = msg->used;
buf = msg->buf;
- free(msg);
+ os_free(msg);
return buf;
}
@@ -569,8 +655,8 @@ u8 * eap_sim_msg_finish(struct eap_sim_msg *msg, size_t *len, const u8 *k_aut,
void eap_sim_msg_free(struct eap_sim_msg *msg)
{
if (msg) {
- free(msg->buf);
- free(msg);
+ os_free(msg->buf);
+ os_free(msg);
}
}
@@ -578,7 +664,7 @@ void eap_sim_msg_free(struct eap_sim_msg *msg)
static int eap_sim_msg_resize(struct eap_sim_msg *msg, size_t add_len)
{
if (msg->used + add_len > msg->buf_len) {
- u8 *nbuf = realloc(msg->buf, msg->used + add_len);
+ u8 *nbuf = os_realloc(msg->buf, msg->used + add_len);
if (nbuf == NULL)
return -1;
msg->buf = nbuf;
@@ -605,10 +691,10 @@ u8 * eap_sim_msg_add_full(struct eap_sim_msg *msg, u8 attr,
start = pos = msg->buf + msg->used;
*pos++ = attr;
*pos++ = attr_len / 4;
- memcpy(pos, data, len);
+ os_memcpy(pos, data, len);
if (pad_len) {
pos += len;
- memset(pos, 0, pad_len);
+ os_memset(pos, 0, pad_len);
}
msg->used += attr_len;
return start;
@@ -635,10 +721,10 @@ u8 * eap_sim_msg_add(struct eap_sim_msg *msg, u8 attr, u16 value,
WPA_PUT_BE16(pos, value);
pos += 2;
if (data)
- memcpy(pos, data, len);
+ os_memcpy(pos, data, len);
if (pad_len) {
pos += len;
- memset(pos, 0, pad_len);
+ os_memset(pos, 0, pad_len);
}
msg->used += attr_len;
return start;
@@ -681,7 +767,7 @@ int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
{
size_t encr_len;
- if (k_encr == NULL || msg->iv == 0 || msg->encr == 0)
+ if (msg == NULL || k_encr == NULL || msg->iv == 0 || msg->encr == 0)
return -1;
encr_len = msg->used - msg->encr - 4;
@@ -698,7 +784,7 @@ int eap_sim_msg_add_encr_end(struct eap_sim_msg *msg, u8 *k_encr, int attr_pad)
pos = eap_sim_msg_add(msg, attr_pad, 0, NULL, pad_len - 4);
if (pos == NULL)
return -1;
- memset(pos + 4, 0, pad_len - 4);
+ os_memset(pos + 4, 0, pad_len - 4);
encr_len += pad_len;
}
wpa_printf(MSG_DEBUG, " (AT_ENCR_DATA data len %lu)",
@@ -752,43 +838,3 @@ void eap_sim_report_notification(void *msg_ctx, int notification, int aka)
}
}
}
-
-
-#ifdef TEST_MAIN_EAP_SIM_COMMON
-static int test_eap_sim_prf(void)
-{
- /* http://csrc.nist.gov/encryption/dss/Examples-1024bit.pdf */
- u8 xkey[] = {
- 0xbd, 0x02, 0x9b, 0xbe, 0x7f, 0x51, 0x96, 0x0b,
- 0xcf, 0x9e, 0xdb, 0x2b, 0x61, 0xf0, 0x6f, 0x0f,
- 0xeb, 0x5a, 0x38, 0xb6
- };
- u8 w[] = {
- 0x20, 0x70, 0xb3, 0x22, 0x3d, 0xba, 0x37, 0x2f,
- 0xde, 0x1c, 0x0f, 0xfc, 0x7b, 0x2e, 0x3b, 0x49,
- 0x8b, 0x26, 0x06, 0x14, 0x3c, 0x6c, 0x18, 0xba,
- 0xcb, 0x0f, 0x6c, 0x55, 0xba, 0xbb, 0x13, 0x78,
- 0x8e, 0x20, 0xd7, 0x37, 0xa3, 0x27, 0x51, 0x16
- };
- u8 buf[40];
-
- printf("Testing EAP-SIM PRF (FIPS 186-2 + change notice 1)\n");
- eap_sim_prf(xkey, buf, sizeof(buf));
- if (memcmp(w, buf, sizeof(w) != 0)) {
- printf("eap_sim_prf failed\n");
- return 1;
- }
-
- return 0;
-}
-
-
-int main(int argc, char *argv[])
-{
- int errors = 0;
-
- errors += test_eap_sim_prf();
-
- return errors;
-}
-#endif /* TEST_MAIN_EAP_SIM_COMMON */
diff --git a/contrib/hostapd/eap_sim_common.h b/contrib/hostapd/eap_sim_common.h
index 6715c369c0b6..9c983a864e3e 100644
--- a/contrib/hostapd/eap_sim_common.h
+++ b/contrib/hostapd/eap_sim_common.h
@@ -1,6 +1,6 @@
/*
- * WPA Supplicant / EAP-SIM/AKA shared routines
- * Copyright (c) 2004-2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * EAP peer: EAP-SIM/AKA shared routines
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
@@ -23,16 +23,65 @@
#define EAP_SIM_K_ENCR_LEN 16
#define EAP_SIM_KEYING_DATA_LEN 64
#define EAP_SIM_IV_LEN 16
+#define EAP_SIM_KC_LEN 8
+#define EAP_SIM_SRES_LEN 4
#define GSM_RAND_LEN 16
-#define AKA_RAND_LEN 16
-#define AKA_AUTN_LEN 16
-
-void eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk);
-void eap_sim_derive_keys_reauth(u16 _counter,
- const u8 *identity, size_t identity_len,
- const u8 *nonce_s, const u8 *mk, u8 *msk);
+#define EAP_SIM_VERSION 1
+
+/* EAP-SIM Subtypes */
+#define EAP_SIM_SUBTYPE_START 10
+#define EAP_SIM_SUBTYPE_CHALLENGE 11
+#define EAP_SIM_SUBTYPE_NOTIFICATION 12
+#define EAP_SIM_SUBTYPE_REAUTHENTICATION 13
+#define EAP_SIM_SUBTYPE_CLIENT_ERROR 14
+
+/* AT_CLIENT_ERROR_CODE error codes */
+#define EAP_SIM_UNABLE_TO_PROCESS_PACKET 0
+#define EAP_SIM_UNSUPPORTED_VERSION 1
+#define EAP_SIM_INSUFFICIENT_NUM_OF_CHAL 2
+#define EAP_SIM_RAND_NOT_FRESH 3
+
+#define EAP_SIM_MAX_FAST_REAUTHS 1000
+
+#define EAP_SIM_MAX_CHAL 3
+
+
+/* EAP-AKA Subtypes */
+#define EAP_AKA_SUBTYPE_CHALLENGE 1
+#define EAP_AKA_SUBTYPE_AUTHENTICATION_REJECT 2
+#define EAP_AKA_SUBTYPE_SYNCHRONIZATION_FAILURE 4
+#define EAP_AKA_SUBTYPE_IDENTITY 5
+#define EAP_AKA_SUBTYPE_NOTIFICATION 12
+#define EAP_AKA_SUBTYPE_REAUTHENTICATION 13
+#define EAP_AKA_SUBTYPE_CLIENT_ERROR 14
+
+/* AT_CLIENT_ERROR_CODE error codes */
+#define EAP_AKA_UNABLE_TO_PROCESS_PACKET 0
+
+#define EAP_AKA_RAND_LEN 16
+#define EAP_AKA_AUTN_LEN 16
+#define EAP_AKA_AUTS_LEN 14
+#define EAP_AKA_RES_MAX_LEN 16
+#define EAP_AKA_IK_LEN 16
+#define EAP_AKA_CK_LEN 16
+#define EAP_AKA_MAX_FAST_REAUTHS 1000
+#define EAP_AKA_MIN_RES_LEN 4
+#define EAP_AKA_MAX_RES_LEN 16
+
+void eap_sim_derive_mk(const u8 *identity, size_t identity_len,
+ const u8 *nonce_mt, u16 selected_version,
+ const u8 *ver_list, size_t ver_list_len,
+ int num_chal, const u8 *kc, u8 *mk);
+void eap_aka_derive_mk(const u8 *identity, size_t identity_len,
+ const u8 *ik, const u8 *ck, u8 *mk);
+int eap_sim_derive_keys(const u8 *mk, u8 *k_encr, u8 *k_aut, u8 *msk,
+ u8 *emsk);
+int eap_sim_derive_keys_reauth(u16 _counter,
+ const u8 *identity, size_t identity_len,
+ const u8 *nonce_s, const u8 *mk, u8 *msk,
+ u8 *emsk);
int eap_sim_verify_mac(const u8 *k_aut, const u8 *req, size_t req_len,
const u8 *mac, const u8 *extra, size_t extra_len);
void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
@@ -42,8 +91,8 @@ void eap_sim_add_mac(const u8 *k_aut, u8 *msg, size_t msg_len, u8 *mac,
/* EAP-SIM/AKA Attributes (0..127 non-skippable) */
#define EAP_SIM_AT_RAND 1
#define EAP_SIM_AT_AUTN 2 /* only AKA */
-#define EAP_SIM_AT_RES 3 /* only AKA, only send */
-#define EAP_SIM_AT_AUTS 4 /* only AKA, only send */
+#define EAP_SIM_AT_RES 3 /* only AKA, only peer->server */
+#define EAP_SIM_AT_AUTS 4 /* only AKA, only peer->server */
#define EAP_SIM_AT_PADDING 6 /* only encrypted */
#define EAP_SIM_AT_NONCE_MT 7 /* only SIM, only send */
#define EAP_SIM_AT_PERMANENT_ID_REQ 10
@@ -81,11 +130,12 @@ enum eap_sim_id_req {
struct eap_sim_attrs {
const u8 *rand, *autn, *mac, *iv, *encr_data, *version_list, *nonce_s;
const u8 *next_pseudonym, *next_reauth_id;
- const u8 *nonce_mt, *identity;
+ const u8 *nonce_mt, *identity, *res, *auts;
size_t num_chal, version_list_len, encr_data_len;
- size_t next_pseudonym_len, next_reauth_id_len, identity_len;
+ size_t next_pseudonym_len, next_reauth_id_len, identity_len, res_len;
enum eap_sim_id_req id_req;
int notification, counter, selected_version, client_error_code;
+ int counter_too_small;
};
int eap_sim_parse_attr(const u8 *start, const u8 *end,
diff --git a/contrib/hostapd/eap_sim_db.c b/contrib/hostapd/eap_sim_db.c
index a965fa461d26..93ade144fa4f 100644
--- a/contrib/hostapd/eap_sim_db.c
+++ b/contrib/hostapd/eap_sim_db.c
@@ -1,6 +1,6 @@
/*
* hostapd / EAP-SIM database/authenticator gateway
- * Copyright (c) 2005, Jouni Malinen <jkmaline@cc.hut.fi>
+ * 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
@@ -10,106 +10,555 @@
* license.
*
* See README and COPYING for more details.
- */
-
-/* This is an example implementation of the EAP-SIM database/authentication
- * gateway interface that is expected to be replaced with an implementation of
- * SS7 gateway to GSM authentication center (HLR/AuC) or a local
- * implementation of SIM triplet generator.
*
- * The example implementation here reads triplets from a text file in
- * IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex strings. This
- * is used to simulate an HLR/AuC. As such, it is not very useful for real life
- * authentication, but it is useful both as an example implementation and for
- * EAP-SIM testing.
+ * This is an example implementation of the EAP-SIM/AKA database/authentication
+ * gateway interface that is using an external program as an SS7 gateway to
+ * GSM/UMTS authentication center (HLR/AuC). hlr_auc_gw is an example
+ * implementation of such a gateway program. This eap_sim_db.c takes care of
+ * EAP-SIM/AKA pseudonyms and re-auth identities. It can be used with different
+ * gateway implementations for HLR/AuC access. Alternatively, it can also be
+ * completely replaced if the in-memory database of pseudonyms/re-auth
+ * identities is not suitable for some cases.
*/
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
+#include "includes.h"
+#include <sys/un.h>
#include "common.h"
#include "eap_sim_common.h"
#include "eap_sim_db.h"
+#include "eloop.h"
+struct eap_sim_pseudonym {
+ struct eap_sim_pseudonym *next;
+ u8 *identity;
+ size_t identity_len;
+ char *pseudonym;
+};
-/* TODO: add an alternative callback based version of the interface. This is
- * needed to work better with the single threaded design of hostapd. For this,
- * the EAP data has to be stored somewhere and eap_sim_db is given a context
- * pointer for this and a callback function. The callback function will re-send
- * the EAP data through normal operations which will eventually end up calling
- * eap_sim_db_get_gsm_triplets() again for the same user. This time, eap_sim_db
- * should have the triplets available immediately. */
-
+struct eap_sim_db_pending {
+ struct eap_sim_db_pending *next;
+ u8 imsi[20];
+ size_t imsi_len;
+ enum { PENDING, SUCCESS, FAILURE } state;
+ void *cb_session_ctx;
+ struct os_time timestamp;
+ int aka;
+ union {
+ struct {
+ u8 kc[EAP_SIM_MAX_CHAL][EAP_SIM_KC_LEN];
+ u8 sres[EAP_SIM_MAX_CHAL][EAP_SIM_SRES_LEN];
+ u8 rand[EAP_SIM_MAX_CHAL][GSM_RAND_LEN];
+ int num_chal;
+ } sim;
+ struct {
+ u8 rand[EAP_AKA_RAND_LEN];
+ u8 autn[EAP_AKA_AUTN_LEN];
+ u8 ik[EAP_AKA_IK_LEN];
+ u8 ck[EAP_AKA_CK_LEN];
+ u8 res[EAP_AKA_RES_MAX_LEN];
+ size_t res_len;
+ } aka;
+ } u;
+};
struct eap_sim_db_data {
+ int sock;
char *fname;
+ char *local_sock;
+ void (*get_complete_cb)(void *ctx, void *session_ctx);
+ void *ctx;
+ struct eap_sim_pseudonym *pseudonyms;
+ struct eap_sim_reauth *reauths;
+ struct eap_sim_db_pending *pending;
};
-#define KC_LEN 8
-#define SRES_LEN 4
-#define RAND_LEN 16
+static struct eap_sim_db_pending *
+eap_sim_db_get_pending(struct eap_sim_db_data *data, const u8 *imsi,
+ size_t imsi_len, int aka)
+{
+ struct eap_sim_db_pending *entry, *prev = NULL;
+
+ entry = data->pending;
+ while (entry) {
+ if (entry->aka == aka && entry->imsi_len == imsi_len &&
+ memcmp(entry->imsi, imsi, imsi_len) == 0) {
+ if (prev)
+ prev->next = entry->next;
+ else
+ data->pending = entry->next;
+ break;
+ }
+ prev = entry;
+ entry = entry->next;
+ }
+ return entry;
+}
-/* Initialize EAP-SIM database/authentication gateway interface.
- * Returns pointer to a private data structure. */
-void * eap_sim_db_init(const char *config)
+
+static void eap_sim_db_add_pending(struct eap_sim_db_data *data,
+ struct eap_sim_db_pending *entry)
+{
+ entry->next = data->pending;
+ data->pending = entry;
+}
+
+
+static void eap_sim_db_sim_resp_auth(struct eap_sim_db_data *data,
+ const char *imsi, char *buf)
+{
+ char *start, *end, *pos;
+ struct eap_sim_db_pending *entry;
+ int num_chal;
+
+ /*
+ * SIM-RESP-AUTH <IMSI> Kc(i):SRES(i):RAND(i) ...
+ * SIM-RESP-AUTH <IMSI> FAILURE
+ * (IMSI = ASCII string, Kc/SRES/RAND = hex string)
+ */
+
+ entry = eap_sim_db_get_pending(data, (u8 *) imsi, strlen(imsi), 0);
+ if (entry == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
+ "received message found");
+ return;
+ }
+
+ start = buf;
+ if (strncmp(start, "FAILURE", 7) == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
+ "failure");
+ entry->state = FAILURE;
+ eap_sim_db_add_pending(data, entry);
+ data->get_complete_cb(data->ctx, entry->cb_session_ctx);
+ return;
+ }
+
+ num_chal = 0;
+ while (num_chal < EAP_SIM_MAX_CHAL) {
+ end = strchr(start, ' ');
+ if (end)
+ *end = '\0';
+
+ pos = strchr(start, ':');
+ if (pos == NULL)
+ goto parse_fail;
+ *pos = '\0';
+ if (hexstr2bin(start, entry->u.sim.kc[num_chal],
+ EAP_SIM_KC_LEN))
+ goto parse_fail;
+
+ start = pos + 1;
+ pos = strchr(start, ':');
+ if (pos == NULL)
+ goto parse_fail;
+ *pos = '\0';
+ if (hexstr2bin(start, entry->u.sim.sres[num_chal],
+ EAP_SIM_SRES_LEN))
+ goto parse_fail;
+
+ start = pos + 1;
+ if (hexstr2bin(start, entry->u.sim.rand[num_chal],
+ GSM_RAND_LEN))
+ goto parse_fail;
+
+ num_chal++;
+ if (end == NULL)
+ break;
+ else
+ start = end + 1;
+ }
+ entry->u.sim.num_chal = num_chal;
+
+ entry->state = SUCCESS;
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
+ "successfully - callback");
+ eap_sim_db_add_pending(data, entry);
+ data->get_complete_cb(data->ctx, entry->cb_session_ctx);
+ return;
+
+parse_fail:
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
+ free(entry);
+}
+
+
+static void eap_sim_db_aka_resp_auth(struct eap_sim_db_data *data,
+ const char *imsi, char *buf)
+{
+ char *start, *end;
+ struct eap_sim_db_pending *entry;
+
+ /*
+ * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
+ * AKA-RESP-AUTH <IMSI> FAILURE
+ * (IMSI = ASCII string, RAND/AUTN/IK/CK/RES = hex string)
+ */
+
+ entry = eap_sim_db_get_pending(data, (u8 *) imsi, strlen(imsi), 1);
+ if (entry == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: No pending entry for the "
+ "received message found");
+ return;
+ }
+
+ start = buf;
+ if (strncmp(start, "FAILURE", 7) == 0) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: External server reported "
+ "failure");
+ entry->state = FAILURE;
+ eap_sim_db_add_pending(data, entry);
+ data->get_complete_cb(data->ctx, entry->cb_session_ctx);
+ return;
+ }
+
+ end = strchr(start, ' ');
+ if (end == NULL)
+ goto parse_fail;
+ *end = '\0';
+ if (hexstr2bin(start, entry->u.aka.rand, EAP_AKA_RAND_LEN))
+ goto parse_fail;
+
+ start = end + 1;
+ end = strchr(start, ' ');
+ if (end == NULL)
+ goto parse_fail;
+ *end = '\0';
+ if (hexstr2bin(start, entry->u.aka.autn, EAP_AKA_AUTN_LEN))
+ goto parse_fail;
+
+ start = end + 1;
+ end = strchr(start, ' ');
+ if (end == NULL)
+ goto parse_fail;
+ *end = '\0';
+ if (hexstr2bin(start, entry->u.aka.ik, EAP_AKA_IK_LEN))
+ goto parse_fail;
+
+ start = end + 1;
+ end = strchr(start, ' ');
+ if (end == NULL)
+ goto parse_fail;
+ *end = '\0';
+ if (hexstr2bin(start, entry->u.aka.ck, EAP_AKA_CK_LEN))
+ goto parse_fail;
+
+ start = end + 1;
+ end = strchr(start, ' ');
+ if (end)
+ *end = '\0';
+ else {
+ end = start;
+ while (*end)
+ end++;
+ }
+ entry->u.aka.res_len = (end - start) / 2;
+ if (entry->u.aka.res_len > EAP_AKA_RES_MAX_LEN) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Too long RES");
+ entry->u.aka.res_len = 0;
+ goto parse_fail;
+ }
+ if (hexstr2bin(start, entry->u.aka.res, entry->u.aka.res_len))
+ goto parse_fail;
+
+ entry->state = SUCCESS;
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Authentication data parsed "
+ "successfully - callback");
+ eap_sim_db_add_pending(data, entry);
+ data->get_complete_cb(data->ctx, entry->cb_session_ctx);
+ return;
+
+parse_fail:
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
+ free(entry);
+}
+
+
+static void eap_sim_db_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+ struct eap_sim_db_data *data = eloop_ctx;
+ char buf[1000], *pos, *cmd, *imsi;
+ int res;
+
+ res = recv(sock, buf, sizeof(buf), 0);
+ if (res < 0)
+ return;
+ wpa_hexdump_ascii_key(MSG_MSGDUMP, "EAP-SIM DB: Received from an "
+ "external source", (u8 *) buf, res);
+ if (res == 0)
+ return;
+ if (res >= (int) sizeof(buf))
+ res = sizeof(buf) - 1;
+ buf[res] = '\0';
+
+ if (data->get_complete_cb == NULL) {
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: No get_complete_cb "
+ "registered");
+ return;
+ }
+
+ /* <cmd> <IMSI> ... */
+
+ cmd = buf;
+ pos = strchr(cmd, ' ');
+ if (pos == NULL)
+ goto parse_fail;
+ *pos = '\0';
+ imsi = pos + 1;
+ pos = strchr(imsi, ' ');
+ if (pos == NULL)
+ goto parse_fail;
+ *pos = '\0';
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: External response=%s for IMSI %s",
+ cmd, imsi);
+
+ if (strcmp(cmd, "SIM-RESP-AUTH") == 0)
+ eap_sim_db_sim_resp_auth(data, imsi, pos + 1);
+ else if (strcmp(cmd, "AKA-RESP-AUTH") == 0)
+ eap_sim_db_aka_resp_auth(data, imsi, pos + 1);
+ else
+ wpa_printf(MSG_INFO, "EAP-SIM DB: Unknown external response "
+ "'%s'", cmd);
+ return;
+
+parse_fail:
+ wpa_printf(MSG_DEBUG, "EAP-SIM DB: Failed to parse response string");
+}
+
+
+static int eap_sim_db_open_socket(struct eap_sim_db_data *data)
+{
+ struct sockaddr_un addr;
+ static int counter = 0;
+
+ if (strncmp(data->fname, "unix:", 5) != 0)
+ return -1;
+
+ data->sock = socket(PF_UNIX, SOCK_DGRAM, 0);
+ if (data->sock < 0) {
+ perror("socket(eap_sim_db)");
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof(addr.sun_path),
+ "/tmp/eap_sim_db_%d-%d", getpid(), counter++);
+ data->local_sock = strdup(addr.sun_path);
+ if (bind(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("bind(eap_sim_db)");
+ close(data->sock);
+ data->sock = -1;
+ return -1;
+ }
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sun_family = AF_UNIX;
+ snprintf(addr.sun_path, sizeof(addr.sun_path), "%s", data->fname + 5);
+ if (connect(data->sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+ perror("connect(eap_sim_db)");
+ wpa_hexdump_ascii(MSG_INFO, "HLR/AuC GW socket",
+ (u8 *) addr.sun_path, strlen(addr.sun_path));
+ close(data->sock);
+ data->sock = -1;
+ return -1;
+ }
+
+ eloop_register_read_sock(data->sock, eap_sim_db_receive, data, NULL);
+
+ return 0;
+}
+
+
+static void eap_sim_db_close_socket(struct eap_sim_db_data *data)
+{
+ if (data->sock >= 0) {
+ eloop_unregister_read_sock(data->sock);
+ close(data->sock);
+ data->sock = -1;
+ }
+ if (data->local_sock) {
+ unlink(data->local_sock);
+ free(data->local_sock);
+ data->local_sock = NULL;
+ }
+}
+
+
+/**
+ * eap_sim_db_init - Initialize EAP-SIM DB / authentication gateway interface
+ * @config: Configuration data (e.g., file name)
+ * @get_complete_cb: Callback function for reporting availability of triplets
+ * @ctx: Context pointer for get_complete_cb
+ * Returns: Pointer to a private data structure or %NULL on failure
+ */
+void * eap_sim_db_init(const char *config,
+ void (*get_complete_cb)(void *ctx, void *session_ctx),
+ void *ctx)
{
struct eap_sim_db_data *data;
- data = malloc(sizeof(*data));
- if (data == NULL) {
+ data = wpa_zalloc(sizeof(*data));
+ if (data == NULL)
return NULL;
- }
- memset(data, 0, sizeof(*data));
+ data->sock = -1;
+ data->get_complete_cb = get_complete_cb;
+ data->ctx = ctx;
data->fname = strdup(c