Project import
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..1944d16
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,171 @@
+#
+#    Copyright (c) 2010-2012 Nest Labs, Inc.
+#    All rights reserved.
+#
+#    This document is the property of Nest. It is considered
+#    confidential and proprietary information.
+#
+#    This document may not be reproduced or transmitted in any form,
+#    in whole or in part, without the express written permission of
+#    Nest.
+#
+#    Description:
+#      This file is the make file for wpa_supplicant, a free software
+#      implementation of an IEEE 802.11i security supplicant for
+#      Linux, FreeBSD, NetBSD and Microsoft Windows.
+#
+
+
+include pre.mak
+
+PackageRoot		:= .
+
+PackageName		:= hostap
+
+PackageSeparator	:=
+
+PackageSourceDir	:= $(PackageRoot)/$(PackageName)
+
+PackageBuildSubdir	:= $(BuildDirectory)/wpa_supplicant
+
+PackageConfigDir	:= configs
+PackageProductConfig 	:= $(PackageConfigDir)/$(BuildProduct)/defconfig
+PackageSiteConfig	:= $(PackageConfigDir)/defconfig
+PackageDefaultConfig	:= $(PackageBuildSubdir)/defconfig
+
+PackageSiteConfig	:= $(if $(wildcard $(PackageProductConfig)),$(PackageProductConfig),$(wildcard $(PackageSiteConfig)))
+
+PackageSourceConfig	:= $(if $(PackageSiteConfig),$(PackageSiteConfig),$(PackageDefaultConfig))
+PackageBuildConfig	:= $(PackageBuildSubdir)/.config
+
+PackageBuildMakefile	= $(call GenerateBuildPaths,Makefile)
+
+LicenseSourceFile	:= $(PackageSourceDir)/COPYING
+
+CleanPaths		+= $(PackageLicenseFile)
+
+DbusDir			:= sw/tps/dbus
+DbusIncDirs		:= $(call GenerateResultPaths,$(DbusDir),usr/include/dbus-1.0 usr/lib/dbus-1.0/include)
+DbusLibDir		:= $(call GenerateResultPaths,$(DbusDir),usr/lib)
+
+LinuxDir		:= sw/tps/linux
+LinuxIncDir		:= $(call GenerateResultPaths,$(LinuxDir),include)
+
+NetlinkDir		:= sw/tps/libnl
+NetlinkIncDir		:= $(call GenerateResultPaths,$(NetlinkDir),usr/include)
+NetlinkLibDir		:= $(call GenerateResultPaths,$(NetlinkDir),usr/lib)
+
+OpenSSLDir		:= sw/tps/openssl
+OpenSSLIncDir		:= $(call GenerateResultPaths,$(OpenSSLDir),usr/include)
+OpenSSLLibDir		:= $(call GenerateResultPaths,$(OpenSSLDir),usr/lib)
+
+ZlibDir			:= sw/tps/zlib
+ZlibIncDir      	:= $(call GenerateResultPaths,$(ZlibDir),usr/include)
+ZlibLibDir      	:= $(call GenerateResultPaths,$(ZlibDir),usr/lib)
+
+WpaDbusConfSourcePath	:= $(PackageSourceDir)/wpa_supplicant/dbus/dbus-wpa_supplicant.conf
+WpaDbusConfResultPath	:= $(call GenerateResultPaths,,$(notdir $(WpaDbusConfSourcePath)))
+
+SOURCEDIRS          = hostap configs
+hostap_RULE_TARGET  = $(BuildDirectory)/configure
+configs_RULE_TARGET = $(BuildDirectory)/configure
+
+all: $(PackageDefaultGoal)
+
+# Generate the package license contents.
+
+$(LicenseSourceFile): $(BuildDirectory)/source
+
+$(PackageLicenseFile): $(LicenseSourceFile)
+	$(copy-result)
+
+# We are building this package from version-controlled source, so
+# there is nothing to do for this target goal.
+
+$(PackageSourceDir):
+
+# Prepare the sources.
+
+$(BuildDirectory)/source: | $(PackageSourceDir) $(BuildDirectory)
+	$(Verbose)touch $@
+
+# Patch the sources, if necessary.
+
+$(BuildDirectory)/patch: $(BuildDirectory)/source
+	$(Verbose)touch $@
+
+$(PackageDefaultConfig) $(PackageBuildMakefile) $(PackageBuildSubdir): | $(PackageSourceDir) $(BuildDirectory)
+	$(call create-links,$(CURDIR)/$(PackageSourceDir),$(BuildDirectory))
+
+$(PackageBuildConfig): $(PackageSourceConfig) | $(PackageBuildSubdir)
+	$(copy-result)
+
+# Configure the source for building.
+
+$(BuildDirectory)/configure: $(BuildDirectory)/source $(PackageBuildConfig)
+	$(Verbose)touch $@
+
+# Add in extra required feature based defines
+ifeq ($(BUILD_FEATURE_WIFI_BCM),1)
+EXTRA_PLATFORM_CFLAGS = -DCONFIG_ALWAYS_UP
+endif
+
+# Build the source.
+#
+# We have to unset MAKEFLAGS since they confuse the package build otherwise.
+
+$(BuildDirectory)/build: $(BuildDirectory)/configure
+	$(Verbose)unset MAKEFLAGS && \
+	$(MAKE) $(JOBSFLAG) -C $(PackageBuildSubdir) \
+	INSTALL="$(INSTALL) $(INSTALLFLAGS)" \
+	CC="$(CC)" CXX="$(CXX)" AR=$(AR) NM=$(NM) RANLIB=$(RANLIB) STRIP=$(STRIP) \
+	DBUSCFLAGS="$(call ToolGenerateIncludeArgument,$(DbusIncDirs))" \
+	DBUSLDFLAGS="-L$(DbusLibDir) -ldbus-1" \
+	DBUSVERSION=$(shell cat $(BuildRoot)/$(DbusDir)/dbus.version) \
+	LINUXCFLAGS="$(call ToolGenerateIncludeArgument,$(LinuxIncDir))" \
+	NETLINKCFLAGS="$(call ToolGenerateIncludeArgument,$(NetlinkIncDir))" \
+	NETLINKLDFLAGS="-L$(NetlinkLibDir) -lnl -lnl-genl" \
+	OPENSSLCFLAGS="-I$(OpenSSLIncDir)" \
+	OPENSSLLDFLAGS="-L$(OpenSSLLibDir) -L$(ZlibLibDir) -lz" \
+    EXTRA_PLATFORM_CFLAGS="$(EXTRA_PLATFORM_CFLAGS)" \
+	all
+	$(Verbose)touch $@
+
+# Stage the build to a temporary installation area.
+#
+# We have to unset MAKEFLAGS since they confuse the package build otherwise.
+
+.PHONY: stage
+stage: $(BuildDirectory)/stage-default $(BuildDirectory)/stage-other
+
+$(BuildDirectory)/stage-default: $(BuildDirectory)/build | $(ResultDirectory)
+	$(Verbose)unset MAKEFLAGS && \
+	$(MAKE) $(JOBSFLAG) -C $(PackageBuildSubdir) \
+	INSTALL="$(INSTALL) $(INSTALLFLAGS)" \
+	DBUSCFLAGS="$(call ToolGenerateIncludeArgument,$(DbusIncDirs))" \
+	DBUSLDFLAGS="-L$(DbusLibDir) -ldbus-1" \
+	DBUSVERSION=$(shell cat $(BuildRoot)/$(DbusDir)/dbus.version) \
+	LINUXCFLAGS="$(call ToolGenerateIncludeArgument,$(LinuxIncDir))" \
+	NETLINKCFLAGS="$(call ToolGenerateIncludeArgument,$(NetlinkIncDir))" \
+	NETLINKLDFLAGS="-L$(NetlinkLibDir)" \
+	OPENSSLCFLAGS="-I$(OpenSSLIncDir)" \
+	OPENSSLLDFLAGS="-L$(OpenSSLLibDir) -L$(ZlibLibDir) -lz" \
+	BINDIR=/usr/sbin \
+	LIBDIR=/usr/lib \
+	DESTDIR=$(ResultDirectory) \
+	install
+	$(Verbose)touch $@
+
+$(BuildDirectory)/stage-other: $(WpaDbusConfResultPath)
+	$(Verbose)touch $@
+
+$(WpaDbusConfSourcePath): $(PackageSourceDir)
+
+$(WpaDbusConfResultPath): $(WpaDbusConfSourcePath) | $(ResultDirectory)
+	$(copy-result)
+
+clean:
+	$(Verbose)$(RM) $(RMFLAGS) -r $(BuildDirectory)
+	$(Verbose)$(RM) $(RMFLAGS) -r $(ResultDirectory)
+
+include post.mak
diff --git a/configs/defconfig b/configs/defconfig
new file mode 100644
index 0000000..a082e46
--- /dev/null
+++ b/configs/defconfig
@@ -0,0 +1,509 @@
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cases, these lines should use += in order not
+# to override previous values of the variables.
+
+DBUS_INCLUDE := $(DBUSCFLAGS)
+DBUS_LIBS := $(DBUSLDFLAGS)
+
+CFLAGS += $(OPENSSLCFLAGS) $(NETLINKCFLAGS) $(LINUXCFLAGS) $(EXTRA_PLATFORM_CFLAGS)
+
+wpa_supplicant: LIBS += $(DBUSLDFLAGS) $(OPENSSLLDFLAGS) $(NETLINKLDFLAGS)
+wpa_passphrase: LDFLAGS += $(OPENSSLLDFLAGS)
+
+# Driver interface for Host AP driver
+#CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for Agere driver
+#CONFIG_DRIVER_HERMES=y
+# Change include directories to match with the local setup
+#CFLAGS += -I../../hcf -I../../include -I../../include/hcf
+#CFLAGS += -I../../include/wireless
+
+# Driver interface for madwifi driver
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_MADWIFI=y
+# Set include directory to the madwifi source tree
+#CFLAGS += -I../../madwifi
+
+# Driver interface for ndiswrapper
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_NDISWRAPPER=y
+
+# Driver interface for Atmel driver
+#CONFIG_DRIVER_ATMEL=y
+
+# Driver interface for old Broadcom driver
+# Please note that the newer Broadcom driver ("hybrid Linux driver") supports
+# Linux wireless extensions and does not need (or even work) with the old
+# driver wrapper. Use CONFIG_DRIVER_WEXT=y with that driver.
+#CONFIG_DRIVER_BROADCOM=y
+# Example path for wlioctl.h; change to match your configuration
+#CFLAGS += -I/opt/WRT54GS/release/src/include
+
+# Driver interface for Intel ipw2100/2200 driver
+# Deprecated; use CONFIG_DRIVER_WEXT=y instead.
+#CONFIG_DRIVER_IPW=y
+
+# Driver interface for Ralink driver
+#CONFIG_DRIVER_RALINK=y
+
+# Driver interface for generic Linux wireless extensions
+# Note: WEXT is deprecated in the current Linux kernel version and no new
+# functionality is added to it. nl80211-based interface is the new
+# replacement for WEXT and its use allows wpa_supplicant to properly control
+# the driver to improve existing functionality like roaming and to support new
+# functionality.
+CONFIG_DRIVER_WEXT=y
+
+# Driver interface for Linux drivers using the nl80211 kernel interface
+CONFIG_DRIVER_NL80211=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for Windows NDIS
+#CONFIG_DRIVER_NDIS=y
+#CFLAGS += -I/usr/include/w32api/ddk
+#LIBS += -L/usr/local/lib
+# For native build using mingw
+#CONFIG_NATIVE_WINDOWS=y
+# Additional directories for cross-compilation on Linux host for mingw target
+#CFLAGS += -I/opt/mingw/mingw32/include/ddk
+#LIBS += -L/opt/mingw/mingw32/lib
+#CC=mingw32-gcc
+# By default, driver_ndis uses WinPcap for low-level operations. This can be
+# replaced with the following option which replaces WinPcap calls with NDISUIO.
+# However, this requires that WZC is disabled (net stop wzcsvc) before starting
+# wpa_supplicant.
+# CONFIG_USE_NDISUIO=y
+
+# Driver interface for development testing
+#CONFIG_DRIVER_TEST=y
+
+# Driver interface for wired Ethernet drivers
+CONFIG_DRIVER_WIRED=y
+
+# Driver interface for the Broadcom RoboSwitch family
+#CONFIG_DRIVER_ROBOSWITCH=y
+
+# Driver interface for no driver (e.g., WPS ER only)
+#CONFIG_DRIVER_NONE=y
+
+# Driver interface for Texas Instruments WiLink drivers
+#CONFIG_DRIVER_TIWLAN=y
+
+# Enable support for the Netlink v2.0 library
+CONFIG_LIBNL20=y
+
+# Solaris libraries
+#LIBS += -lsocket -ldlpi -lnsl
+#LIBS_c += -lsocket
+
+# Enable IEEE 802.1X Supplicant (automatically included if any EAP method is
+# included)
+CONFIG_IEEE8021X_EAPOL=y
+
+# EAP-MD5
+CONFIG_EAP_MD5=y
+
+# EAP-MSCHAPv2
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-TLS
+CONFIG_EAP_TLS=y
+
+# EAL-PEAP
+CONFIG_EAP_PEAP=y
+
+# EAP-TTLS
+CONFIG_EAP_TTLS=y
+
+# EAP-FAST
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.8d-tls-extensions.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
+# EAP-GTC
+CONFIG_EAP_GTC=y
+
+# EAP-OTP
+CONFIG_EAP_OTP=y
+
+# EAP-SIM (enable CONFIG_PCSC, if EAP-SIM is used)
+#CONFIG_EAP_SIM=y
+
+# EAP-PSK (experimental; this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-pwd (secure authentication using only a password)
+#CONFIG_EAP_PWD=y
+
+# EAP-PAX
+#CONFIG_EAP_PAX=y
+
+# LEAP
+CONFIG_EAP_LEAP=y
+
+# EAP-AKA (enable CONFIG_PCSC, if EAP-AKA is used)
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' (enable CONFIG_PCSC, if EAP-AKA' is used).
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# Enable USIM simulator (Milenage) for EAP-AKA
+#CONFIG_USIM_SIMULATOR=y
+
+# EAP-SAKE
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-TNC and related Trusted Network Connect support (experimental)
+#CONFIG_EAP_TNC=y
+
+# Wi-Fi Protected Setup (WPS)
+#CONFIG_WPS=y
+# Enable WSC 2.0 support
+#CONFIG_WPS2=y
+# Enable WPS external registrar functionality
+#CONFIG_WPS_ER=y
+# Disable credentials for an open network by default when acting as a WPS
+# registrar.
+#CONFIG_WPS_REG_DISABLE_OPEN=y
+# Enable WPS support with NFC config method
+#CONFIG_WPS_NFC=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# Smartcard support (i.e., private key on a smartcard), e.g., with openssl
+# engine.
+#CONFIG_SMARTCARD=y
+
+# PC/SC interface for smartcards (USIM, GSM SIM)
+# Enable this if EAP-SIM or EAP-AKA is included
+#CONFIG_PCSC=y
+
+# Support HT overrides (disable HT/HT40, mask MCS rates, etc.)
+#CONFIG_HT_OVERRIDES=y
+
+# Development testing
+#CONFIG_EAPOL_TEST=y
+
+# Select control interface backend for external programs, e.g, wpa_cli:
+# unix = UNIX domain sockets (default for Linux/*BSD)
+# udp = UDP sockets using localhost (127.0.0.1)
+# named_pipe = Windows Named Pipe (default for Windows)
+# udp-remote = UDP sockets with remote access (only for tests systems/purpose)
+# y = use default (backwards compatibility)
+# If this option is commented out, control interface is not included in the
+# build.
+CONFIG_CTRL_IFACE=y
+
+# Include support for GNU Readline and History Libraries in wpa_cli.
+# When building a wpa_cli binary for distribution, please note that these
+# libraries are licensed under GPL and as such, BSD license may not apply for
+# the resulting binary.
+#CONFIG_READLINE=y
+
+# Include internal line edit mode in wpa_cli. This can be used as a replacement
+# for GNU Readline to provide limited command line editing and history support.
+#CONFIG_WPA_CLI_EDIT=y
+
+# Remove debugging code that is printing out debug message to stdout.
+# This can be used to reduce the size of the wpa_supplicant considerably
+# if debugging code is not needed. The size reduction can be around 35%
+# (e.g., 90 kB).
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Remove WPA support, e.g., for wired-only IEEE 802.1X supplicant, to save
+# 35-50 kB in code size.
+#CONFIG_NO_WPA=y
+
+# Remove WPA2 support. This allows WPA to be used, but removes WPA2 code to
+# save about 1 kB in code size when building only WPA-Personal (no EAP support)
+# or 6 kB if building for WPA-Enterprise.
+#CONFIG_NO_WPA2=y
+
+# Remove IEEE 802.11i/WPA-Personal ASCII passphrase support
+# This option can be used to reduce code size by removing support for
+# converting ASCII passphrases into PSK. If this functionality is removed, the
+# PSK can only be configured as the 64-octet hexstring (e.g., from
+# wpa_passphrase). This saves about 0.5 kB in code size.
+#CONFIG_NO_WPA_PASSPHRASE=y
+
+# Disable scan result processing (ap_mode=1) to save code size by about 1 kB.
+# This can be used if ap_scan=1 mode is never enabled.
+#CONFIG_NO_SCAN_PROCESSING=y
+
+# Select configuration backend:
+# file = text file (e.g., wpa_supplicant.conf; note: the configuration file
+#	path is given on command line, not here; this option is just used to
+#	select the backend that allows configuration files to be used)
+# winreg = Windows registry (see win_example.reg for an example)
+CONFIG_BACKEND=file
+
+# Remove configuration write functionality (i.e., to allow the configuration
+# file to be updated based on runtime configuration changes). The runtime
+# configuration can still be changed, the changes are just not going to be
+# persistent over restarts. This option can be used to reduce code size by
+# about 3.5 kB.
+#CONFIG_NO_CONFIG_WRITE=y
+
+# Remove support for configuration blobs to reduce code size by about 1.5 kB.
+#CONFIG_NO_CONFIG_BLOBS=y
+
+# Select program entry point implementation:
+# main = UNIX/POSIX like main() function (default)
+# main_winsvc = Windows service (read parameters from registry)
+# main_none = Very basic example (development use only)
+#CONFIG_MAIN=main
+
+# Select wrapper for operatins system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+#CONFIG_OS=unix
+
+# Select event loop implementation
+# eloop = select() loop (default)
+# eloop_win = Windows events and WaitForMultipleObject() loop
+# eloop_none = Empty template
+#CONFIG_ELOOP=eloop
+
+# Should we use poll instead of select? Select is used by default.
+#CONFIG_ELOOP_POLL=y
+
+# Select layer 2 packet implementation
+# linux = Linux packet socket (default)
+# pcap = libpcap/libdnet/WinPcap
+# freebsd = FreeBSD libpcap
+# winpcap = WinPcap with receive thread
+# ndis = Windows NDISUIO (note: requires CONFIG_USE_NDISUIO=y)
+# none = Empty template
+#CONFIG_L2_PACKET=linux
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection), also known as PMF
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS
+# internal = Internal TLSv1 implementation (experimental)
+# none = Empty template
+#CONFIG_TLS=openssl
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
+# can be enabled to get a stronger construction of messages when block ciphers
+# are used. It should be noted that some existing TLS v1.0 -based
+# implementation may not be compatible with TLS v1.1 message (ClientHello is
+# sent prior to negotiating which version will be used)
+#CONFIG_TLSV11=y
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
+# can be enabled to enable use of stronger crypto algorithms. It should be
+# noted that some existing TLS v1.0 -based implementation may not be compatible
+# with TLS v1.2 message (ClientHello is sent prior to negotiating which version
+# will be used)
+#CONFIG_TLSV12=y
+
+# If CONFIG_TLS=internal is used, additional library and include paths are
+# needed for LibTomMath. Alternatively, an integrated, minimal version of
+# LibTomMath can be used. See beginning of libtommath.c for details on benefits
+# and drawbacks of this option.
+#CONFIG_INTERNAL_LIBTOMMATH=y
+#ifndef CONFIG_INTERNAL_LIBTOMMATH
+#LTM_PATH=/usr/src/libtommath-0.39
+#CFLAGS += -I$(LTM_PATH)
+#LIBS += -L$(LTM_PATH)
+#LIBS_p += -L$(LTM_PATH)
+#endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+
+# Include NDIS event processing through WMI into wpa_supplicant/wpasvc.
+# This is only for Windows builds and requires WMI-related header files and
+# WbemUuid.Lib from Platform SDK even when building with MinGW.
+#CONFIG_NDIS_EVENTS_INTEGRATED=y
+#PLATFORMSDKLIB="/opt/Program Files/Microsoft Platform SDK/Lib"
+
+# Add support for old DBus control interface
+# (fi.epitest.hostap.WPASupplicant)
+#CONFIG_CTRL_IFACE_DBUS=y
+
+# Add support for new DBus control interface
+# (fi.w1.hostap.wpa_supplicant1)
+CONFIG_CTRL_IFACE_DBUS_NEW=y
+
+# Add introspection support for new DBus control interface
+#CONFIG_CTRL_IFACE_DBUS_INTRO=y
+
+# Add support for loading EAP methods dynamically as shared libraries.
+# When this option is enabled, each EAP method can be either included
+# statically (CONFIG_EAP_<method>=y) or dynamically (CONFIG_EAP_<method>=dyn).
+# Dynamic EAP methods are build as shared objects (eap_*.so) and they need to
+# be loaded in the beginning of the wpa_supplicant configuration file
+# (see load_dynamic_eap parameter in the example file) before being used in
+# the network blocks.
+#
+# Note that some shared parts of EAP methods are included in the main program
+# and in order to be able to use dynamic EAP methods using these parts, the
+# main program must have been build with the EAP method enabled (=y or =dyn).
+# This means that EAP-TLS/PEAP/TTLS/FAST cannot be added as dynamic libraries
+# unless at least one of them was included in the main build to force inclusion
+# of the shared code. Similarly, at least one of EAP-SIM/AKA must be included
+# in the main build to be able to load these methods dynamically.
+#
+# Please also note that using dynamic libraries will increase the total binary
+# size. Thus, it may not be the best option for targets that have limited
+# amount of memory/flash.
+#CONFIG_DYNAMIC_EAP_METHODS=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Add support for writing debug log to a file (/tmp/wpa_supplicant-log-#.txt)
+CONFIG_DEBUG_FILE=y
+
+# Send debug messages to syslog instead of stdout
+CONFIG_DEBUG_SYSLOG=y
+# Set syslog facility for debug messages
+#CONFIG_DEBUG_SYSLOG_FACILITY=LOG_DAEMON
+
+# Add support for sending all debug messages (regardless of debug verbosity)
+# to the Linux kernel tracing facility. This helps debug the entire stack by
+# making it easy to record everything happening from the driver up into the
+# same file, e.g., using trace-cmd.
+#CONFIG_DEBUG_LINUX_TRACING=y
+
+# Enable privilege separation (see README 'Privilege separation' for details)
+#CONFIG_PRIVSEP=y
+
+# Enable mitigation against certain attacks against TKIP by delaying Michael
+# MIC error reports by a random amount of time between 0 and 60 seconds
+#CONFIG_DELAYED_MIC_ERROR_REPORT=y
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+
+# Enable tracing code when the program receives error signals.
+# Signals include:
+# SIGABRT, SIGSEGV, SIGBUS, SIGILL
+CONFIG_WPA_TRACE_SIGNALS=y
+# For BSD, uncomment these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, uncomment these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# wpa_supplicant depends on strong random number generation being available
+# from the operating system. os_get_random() function is used to fetch random
+# data when needed, e.g., for key generation. On Linux and BSD systems, this
+# works by reading /dev/urandom. It should be noted that the OS entropy pool
+# needs to be properly initialized before wpa_supplicant is started. This is
+# important especially on embedded devices that do not have a hardware random
+# number generator and may by default start up with minimal entropy available
+# for random number generation.
+#
+# As a safety net, wpa_supplicant is by default trying to internally collect
+# additional entropy for generating random data to mix in with the data fetched
+# from the OS. This by itself is not considered to be very strong, but it may
+# help in cases where the system pool is not initialized properly. However, it
+# is very strongly recommended that the system pool is initialized with enough
+# entropy either by using hardware assisted random number generator or by
+# storing state over device reboots.
+#
+# wpa_supplicant can be configured to maintain its own entropy store over
+# restarts to enhance random number generation. This is not perfect, but it is
+# much more secure than using the same sequence of random numbers after every
+# reboot. This can be enabled with -e<entropy file> command line option. The
+# specified file needs to be readable and writable by wpa_supplicant.
+#
+# If the os_get_random() is known to provide strong random data (e.g., on
+# Linux/BSD, the board in question is known to have reliable source of random
+# data from /dev/urandom), the internal wpa_supplicant random pool can be
+# disabled. This will save some in binary size and CPU use. However, this
+# should only be considered for builds that are known to be used on devices
+# that meet the requirements described above.
+#CONFIG_NO_RANDOM_POOL=y
+
+# IEEE 802.11n (High Throughput) support (mainly for AP mode)
+#CONFIG_IEEE80211N=y
+
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+#CONFIG_WNM=y
+
+# Interworking (IEEE 802.11u)
+# This can be used to enable functionality to improve interworking with
+# external networks (GAS/ANQP to learn more about the networks and network
+# selection based on available credentials).
+#CONFIG_INTERWORKING=y
+
+# Hotspot 2.0
+#CONFIG_HS20=y
+
+# AP mode operations with wpa_supplicant
+# This can be used for controlling AP mode operations with wpa_supplicant. It
+# should be noted that this is mainly aimed at simple cases like
+# WPA2-Personal while more complex configurations like WPA2-Enterprise with an
+# external RADIUS server can be supported with hostapd.
+#CONFIG_AP=y
+
+# P2P (Wi-Fi Direct)
+# This can be used to enable P2P support in wpa_supplicant. See README-P2P for
+# more information on P2P operations.
+#CONFIG_P2P=y
+
+# Autoscan
+# This can be used to enable automatic scan support in wpa_supplicant.
+# See wpa_supplicant.conf for more information on autoscan usage.
+#
+# Enabling directly a module will enable autoscan support.
+# For exponential module:
+#CONFIG_AUTOSCAN_EXPONENTIAL=y
+# For periodic module:
+#CONFIG_AUTOSCAN_PERIODIC=y
+
+# Password (and passphrase, etc.) backend for external storage
+# These optional mechanisms can be used to add support for storing passwords
+# and other secrets in external (to wpa_supplicant) location. This allows, for
+# example, operating system specific key storage to be used
+#
+# External password backend for testing purposes (developer use)
+#CONFIG_EXT_PASSWORD_TEST=y
diff --git a/hostap.url b/hostap.url
new file mode 100644
index 0000000..9104556
--- /dev/null
+++ b/hostap.url
@@ -0,0 +1 @@
+git://w1.fi/srv/git/hostap.git
diff --git a/hostap.version b/hostap.version
new file mode 100644
index 0000000..a803fcf
--- /dev/null
+++ b/hostap.version
@@ -0,0 +1 @@
+22760dd94722a61175ff90c59d88c4cda1ed5e23
diff --git a/hostap/Android.mk b/hostap/Android.mk
new file mode 100644
index 0000000..77d72ea
--- /dev/null
+++ b/hostap/Android.mk
@@ -0,0 +1,3 @@
+ifeq ($(WPA_SUPPLICANT_VERSION),VER_0_8_X)
+    include $(call all-subdir-makefiles)
+endif
diff --git a/hostap/CONTRIBUTIONS b/hostap/CONTRIBUTIONS
new file mode 100644
index 0000000..5ac7868
--- /dev/null
+++ b/hostap/CONTRIBUTIONS
@@ -0,0 +1,111 @@
+Contributions to hostap.git
+---------------------------
+
+This software is distributed under a permissive open source license to
+allow it to be used in any projects, whether open source or proprietary.
+Contributions to the project are welcome and it is important to maintain
+clear record of contributions and terms under which they are licensed.
+To help with this, following procedure is used to allow acceptance and
+recording of the terms.
+
+These terms are similar to the process used in Linux kernel development.
+The items (a) through (d) are identical to the Developer's Certificate
+of Origin 1.1. To enable cleaner licensing option to be provided in the
+future, an additional item (e) is included.
+
+Until February 11, 2012, in case of most files in hostap.git, "under the
+open source license indicated in the file" means that the contribution
+is licensed both under GPL v2 and modified BSD license (see below) and
+the choice between these licenses is given to anyone who redistributes
+or uses the software. As such, the contribution has to be licensed under
+both options to allow this choice.
+
+As of February 11, 2012, the project has chosen to use only the BSD
+license option for future distribution. As such, the GPL v2 license
+option is no longer used and the contributions are not required to be
+licensed until GPL v2. In case of most files in hostap.git, "under the
+open source license indicated in the file" means that the contribution
+is licensed under the modified BSD license (see below).
+
+
+The additional item (e) is used to collect explicit approval to license
+the contribution with only the modified BSD license (see below), i.e.,
+without the GPL v2 option. This was done to allow simpler licensing
+terms to be used in the future. It should be noted that the modified BSD
+license is compatible with GNU GPL and as such, this possible move to
+simpler licensing option does not prevent use of this software in
+GPL projects.
+
+
+By making a contribution to this project, I certify that:
+
+(a) The contribution was created in whole or in part by me and I
+    have the right to submit it under the open source license
+    indicated in the file; or
+
+(b) The contribution is based upon previous work that, to the best
+    of my knowledge, is covered under an appropriate open source
+    license and I have the right under that license to submit that
+    work with modifications, whether created in whole or in part
+    by me, under the same open source license (unless I am
+    permitted to submit under a different license), as indicated
+    in the file; or
+
+(c) The contribution was provided directly to me by some other
+    person who certified (a), (b) or (c) and I have not modified
+    it.
+
+(d) I understand and agree that this project and the contribution
+    are public and that a record of the contribution (including all
+    personal information I submit with it, including my sign-off) is
+    maintained indefinitely and may be redistributed consistent with
+    this project or the open source license(s) involved.
+
+Additionally, I certify that:
+
+(e) The contribution can be licensed under the modified BSD license
+    as shown below even in case of files that are currently licensed
+    under other terms.
+
+
+To indicate your acceptance of these terms, please add the following
+line to each contribution you make to the project:
+
+Signed-hostap: Your Name <your@email.example.org>
+
+using your real name. Pseudonyms or anonymous contributions cannot
+unfortunately be accepted.
+
+
+
+Modified BSD license (no advertisement clause):
+
+Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+All Rights Reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name(s) of the above-listed copyright holder(s) nor the
+   names of its contributors may be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/hostap/COPYING b/hostap/COPYING
new file mode 100644
index 0000000..8a98582
--- /dev/null
+++ b/hostap/COPYING
@@ -0,0 +1,22 @@
+wpa_supplicant and hostapd
+--------------------------
+
+Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+All Rights Reserved.
+
+
+See the README file for the current license terms.
+
+This software was previously distributed under BSD/GPL v2 dual license
+terms that allowed either of those license alternatives to be
+selected. As of February 11, 2012, the project has chosen to use only
+the BSD license option for future distribution. As such, the GPL v2
+license option is no longer used. It should be noted that the BSD
+license option (the one with advertisement clause removed) is compatible
+with GPL and as such, does not prevent use of this software in projects
+that use GPL.
+
+Some of the files may still include pointers to GPL version 2 license
+terms. However, such copyright and license notifications are maintained
+only for attribution purposes and any distribution of this software
+after February 11, 2012 is no longer under the GPL v2 option.
diff --git a/hostap/CleanSpec.mk b/hostap/CleanSpec.mk
new file mode 100644
index 0000000..d01a378
--- /dev/null
+++ b/hostap/CleanSpec.mk
@@ -0,0 +1,56 @@
+# Copyright (C) 2007 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# If you don't need to do a full clean build but would like to touch
+# a file or delete some intermediate files, add a clean step to the end
+# of the list.  These steps will only be run once, if they haven't been
+# run before.
+#
+# E.g.:
+#     $(call add-clean-step, touch -c external/sqlite/sqlite3.h)
+#     $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates)
+#
+# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with
+# files that are missing or have been moved.
+#
+# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory.
+# Use $(OUT_DIR) to refer to the "out" directory.
+#
+# If you need to re-do something that's already mentioned, just copy
+# the command and add it to the bottom of the list.  E.g., if a change
+# that you made last week required touching a file and a change you
+# made today requires touching the same file, just copy the old
+# touch step and add it to the end of the list.
+#
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+
+# For example:
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates)
+#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates)
+#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f)
+#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*)
+
+# ************************************************
+# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
+# ************************************************
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/wpa_supplicant_intermediates/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/wpa_cli_intermediates/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/wpa_supplicant_intermediates)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/wpa_supplicant_intermediates/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/wpa_cli_intermediates/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/wpa_supplicant_intermediates/*)
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/EXECUTABLES/hostapd_intermediates/*)
diff --git a/hostap/MODULE_LICENSE_BSD_LIKE b/hostap/MODULE_LICENSE_BSD_LIKE
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/hostap/MODULE_LICENSE_BSD_LIKE
diff --git a/hostap/README b/hostap/README
new file mode 100644
index 0000000..1721a3b
--- /dev/null
+++ b/hostap/README
@@ -0,0 +1,56 @@
+wpa_supplicant and hostapd
+--------------------------
+
+Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+All Rights Reserved.
+
+These programs are licensed under the BSD license (the one with
+advertisement clause removed).
+
+If you are submitting changes to the project, please see CONTRIBUTIONS
+file for more instructions.
+
+
+This package may include either wpa_supplicant, hostapd, or both. See
+README file respective subdirectories (wpa_supplicant/README or
+hostapd/README) for more details.
+
+Source code files were moved around in v0.6.x releases and compared to
+earlier releases, the programs are now built by first going to a
+subdirectory (wpa_supplicant or hostapd) and creating build
+configuration (.config) and running 'make' there (for Linux/BSD/cygwin
+builds).
+
+
+License
+-------
+
+This software may be distributed, used, and modified under the terms of
+BSD license:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name(s) of the above-listed copyright holder(s) nor the
+   names of its contributors may be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/hostap/build_release b/hostap/build_release
new file mode 100755
index 0000000..dddf92b
--- /dev/null
+++ b/hostap/build_release
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+set -e
+
+if [ -z "$1" ]; then
+    echo "build_release <version>"
+    exit 1
+fi
+
+TMP=tmp.build_release
+RELDIR=`pwd`/Release
+VER=$1
+NOW=`date +%Y-%m-%d`
+
+echo "Version: $VER - $NOW"
+
+DATEw=`head -n 3 wpa_supplicant/ChangeLog | tail -n 1 | sed "s/ .*//"`
+DATEh=`head -n 3 hostapd/ChangeLog | tail -n 1 | sed "s/ .*//"`
+
+if [ "$DATEw" != "$NOW" -o "$DATEh" != "$NOW" ]; then
+    echo "NOTE! Date mismatch in ChangeLog: wpa_supplicant $DATEw hostapd $DATEh != $NOW"
+fi
+
+if [ -r $TMP ]; then
+    echo "Temporary directory '$TMP' exists. Remove it before running this."
+    exit 1
+fi
+
+mkdir $TMP
+mkdir -p $RELDIR
+
+git archive --format=tar --prefix=wpa-$VER/ HEAD \
+	README COPYING patches src wpa_supplicant hostapd |
+	gzip > $RELDIR/wpa-$VER.tar.gz
+git archive --format=tar --prefix=hostapd-$VER/ HEAD \
+	README COPYING patches src hostapd |
+	gzip > $RELDIR/hostapd-$VER.tar.gz
+git archive --format=tar --prefix=wpa_supplicant-$VER/ HEAD \
+	README COPYING patches src wpa_supplicant |
+	tar --directory=$TMP -xf -
+
+cd $TMP
+make -C wpa_supplicant-$VER/wpa_supplicant/doc/docbook man
+rm -f wpa_supplicant-$VER/wpa_supplicant/doc/docbook/manpage.{links,refs}
+tar czf $RELDIR/wpa_supplicant-$VER.tar.gz wpa_supplicant-$VER
+cd ..
+rm -r $TMP
diff --git a/hostap/doc/Makefile b/hostap/doc/Makefile
new file mode 100644
index 0000000..4e1c1bd
--- /dev/null
+++ b/hostap/doc/Makefile
@@ -0,0 +1,39 @@
+all: docs
+
+%.eps: %.fig
+	fig2dev -L eps $*.fig $*.eps
+
+%.png: %.fig
+	fig2dev -L png -m 3 $*.fig | pngtopnm | pnmscale 0.4 | pnmtopng \
+		> $*.png
+
+%.png: %.dot
+	dot $*.dot -Tpng -o $*.png
+
+%.eps: %.dot
+	dot $*.dot -Tps -o $*.eps
+
+_wpa_supplicant.png: wpa_supplicant.png
+	cp $< $@
+
+docs-pics: wpa_supplicant.png wpa_supplicant.eps hostapd.png hostapd.eps p2p_sm.png p2p_sm.eps p2p_arch.png p2p_arch.eps p2p_arch2.png p2p_arch2.eps
+
+docs: docs-pics
+	(cd ..; doxygen doc/doxygen.conf; cd doc)
+	$(MAKE) -C latex
+	cp latex/refman.pdf wpa_supplicant-devel.pdf
+
+html: docs-pics _wpa_supplicant.png
+	(cd ..; doxygen doc/doxygen.conf; cd doc)
+
+clean:
+	rm -f *~
+	rm -f wpa_supplicant.eps wpa_supplicant.png
+	rm -f _wpa_supplicant.png
+	rm -f hostapd.eps hostapd.png
+	rm -f p2p_sm.eps p2p_sm.png
+	rm -f p2p_arch.eps p2p_arch.png
+	rm -f p2p_arch2.eps p2p_arch2.png
+	rm -f doxygen.warnings
+	rm -rf html latex
+	rm -f wpa_supplicant-devel.pdf
diff --git a/hostap/doc/code_structure.doxygen b/hostap/doc/code_structure.doxygen
new file mode 100644
index 0000000..26f5f6d
--- /dev/null
+++ b/hostap/doc/code_structure.doxygen
@@ -0,0 +1,322 @@
+/**
+\page code_structure Structure of the source code
+
+[ \ref _wpa_supplicant_core "wpa_supplicant core functionality" |
+\ref generic_helper_func "Generic helper functions" |
+\ref crypto_func "Cryptographic functions" |
+\ref tls_func "TLS library" |
+\ref configuration "Configuration" |
+\ref ctrl_iface "Control interface" |
+\ref wpa_code "WPA supplicant" |
+\ref eap_peer "EAP peer" |
+\ref eapol_supp "EAPOL supplicant" |
+\ref win_port "Windows port" |
+\ref test_programs "Test programs" ]
+
+%wpa_supplicant implementation is divided into number of independent
+modules. Core code includes functionality for controlling the network
+selection, association, and configuration. Independent modules include
+WPA code (key handshake, PMKSA caching, pre-authentication), EAPOL
+state machine, and EAP state machine and methods. In addition, there
+are number of separate files for generic helper functions.
+
+Both WPA and EAPOL/EAP state machines can be used separately in other
+programs than %wpa_supplicant. As an example, the included test
+programs eapol_test and preauth_test are using these modules.
+
+\ref driver_wrapper "Driver interface API" is defined in driver.h and
+all hardware/driver dependent functionality is implemented in
+driver_*.c.
+
+
+\section _wpa_supplicant_core wpa_supplicant core functionality
+
+wpa_supplicant.c
+	Program initialization, main control loop
+
+main.c
+	main() for UNIX-like operating systems and MinGW (Windows); this
+	uses command line arguments to configure wpa_supplicant
+
+events.c
+	Driver event processing; wpa_supplicant_event() and related functions
+
+wpa_supplicant_i.h
+	Internal definitions for %wpa_supplicant core; should not be
+	included into independent modules
+
+
+\section generic_helper_func Generic helper functions
+
+%wpa_supplicant uses generic helper functions some of which are shared
+with with hostapd. The following C files are currently used:
+
+eloop.c and eloop.h
+	Event loop (select() loop with registerable timeouts, socket read
+	callbacks, and signal callbacks)
+
+common.c and common.h
+	Common helper functions
+
+defs.h
+	Definitions shared by multiple files
+
+l2_packet.h, l2_packet_linux.c, and l2_packet_pcap.c
+	Layer 2 (link) access wrapper (includes native Linux implementation
+	and wrappers for libdnet/libpcap). A new l2_packet implementation
+	may need to be added when porting to new operating systems that are
+	not supported by libdnet/libpcap. Makefile can be used to select which
+	l2_packet implementation is included. l2_packet_linux.c uses Linux
+	packet sockets and l2_packet_pcap.c has a more portable version using
+	libpcap and libdnet.
+
+pcsc_funcs.c and pcsc_funcs.h
+	Wrapper for PC/SC lite SIM and smart card readers
+
+priv_netlink.h
+	Private version of netlink definitions from Linux kernel header files;
+	this could be replaced with C library header file once suitable
+	version becomes commonly available
+
+version.h
+	Version number definitions
+
+wireless_copy.h
+	Private version of Linux wireless extensions definitions from kernel
+	header files; this could be replaced with C library header file once
+	suitable version becomes commonly available
+
+
+\section crypto_func Cryptographic functions
+
+md5.c and md5.h
+	MD5 (replaced with a crypto library if TLS support is included)
+	HMAC-MD5 (keyed checksum for message authenticity validation)
+
+rc4.c and rc4.h
+	RC4 (broadcast/default key encryption)
+
+sha1.c and sha1.h
+	SHA-1 (replaced with a crypto library if TLS support is included)
+	HMAC-SHA-1 (keyed checksum for message authenticity validation)
+	PRF-SHA-1 (pseudorandom (key/nonce generation) function)
+	PBKDF2-SHA-1 (ASCII passphrase to shared secret)
+	T-PRF (for EAP-FAST)
+	TLS-PRF (RFC 2246)
+
+sha256.c and sha256.h
+	SHA-256 (replaced with a crypto library if TLS support is included)
+
+aes_wrap.c, aes_wrap.h, aes.c
+	AES (replaced with a crypto library if TLS support is included),
+	AES Key Wrap Algorithm with 128-bit KEK, RFC3394 (broadcast/default
+	key encryption),
+	One-Key CBC MAC (OMAC1) hash with AES-128,
+	AES-128 CTR mode encryption,
+	AES-128 EAX mode encryption/decryption,
+	AES-128 CBC
+
+crypto.h
+	Definition of crypto library wrapper
+
+crypto_openssl.c
+	Wrapper functions for libcrypto (OpenSSL)
+
+crypto_internal.c
+	Wrapper functions for internal crypto implementation
+
+crypto_gnutls.c
+	Wrapper functions for libgcrypt (used by GnuTLS)
+
+ms_funcs.c and ms_funcs.h
+	Helper functions for MSCHAPV2 and LEAP
+
+tls.h
+	Definition of TLS library wrapper
+
+tls_none.c
+	Dummy implementation of TLS library wrapper for cases where TLS
+	functionality is not included.
+
+tls_openssl.c
+	TLS library wrapper for openssl
+
+tls_internal.c
+	TLS library for internal TLS implementation
+
+tls_gnutls.c
+	TLS library wrapper for GnuTLS
+
+
+\section tls_func TLS library
+
+asn1.c and asn1.h
+	ASN.1 DER parsing
+
+bignum.c and bignum.h
+	Big number math
+
+rsa.c and rsa.h
+	RSA
+
+x509v3.c and x509v3.h
+	X.509v3 certificate parsing and processing
+
+tlsv1_client.c, tlsv1_client.h
+	TLSv1 client (RFC 2246)
+
+tlsv1_client_i.h
+	Internal structures for TLSv1 client
+
+tlsv1_client_read.c
+	TLSv1 client: read handshake messages
+
+tlsv1_client_write.c
+	TLSv1 client: write handshake messages
+
+tlsv1_common.c and tlsv1_common.h
+	Common TLSv1 routines and definitions
+
+tlsv1_cred.c and tlsv1_cred.h
+	TLSv1 credentials
+
+tlsv1_record.c and tlsv1_record.h
+	TLSv1 record protocol
+
+
+\section configuration Configuration
+
+config_ssid.h
+	Definition of per network configuration items
+
+config.h
+	Definition of the %wpa_supplicant configuration
+
+config.c
+	Configuration parser and common functions
+
+config_file.c
+	Configuration backend for text files (e.g., wpa_supplicant.conf)
+
+config_winreg.c
+	Configuration backend for Windows registry
+
+
+\section ctrl_iface Control interface
+
+%wpa_supplicant has a \ref ctrl_iface_page "control interface"
+that can be used to get status
+information and manage operations from external programs. An example
+command line interface (wpa_cli) and GUI (wpa_gui) for this interface
+are included in the %wpa_supplicant distribution.
+
+ctrl_iface.c and ctrl_iface.h
+	%wpa_supplicant-side of the control interface
+
+ctrl_iface_unix.c
+	UNIX domain sockets -based control interface backend
+
+ctrl_iface_udp.c
+	UDP sockets -based control interface backend
+
+ctrl_iface_named_pipe.c
+	Windows named pipes -based control interface backend
+
+wpa_ctrl.c and wpa_ctrl.h
+	Library functions for external programs to provide access to the
+	%wpa_supplicant control interface
+
+wpa_cli.c
+	Example program for using %wpa_supplicant control interface
+
+
+\section wpa_code WPA supplicant
+
+wpa.c and wpa.h
+	WPA state machine and 4-Way/Group Key Handshake processing
+
+preauth.c and preauth.h
+	PMKSA caching and pre-authentication (RSN/WPA2)
+
+wpa_i.h
+	Internal definitions for WPA code; not to be included to other modules.
+
+\section eap_peer EAP peer
+
+\ref eap_peer_module "EAP peer implementation" is a separate module that
+can be used by other programs than just %wpa_supplicant.
+
+eap.c and eap.h
+	EAP state machine and method interface
+
+eap_defs.h
+	Common EAP definitions
+
+eap_i.h
+	Internal definitions for EAP state machine and EAP methods; not to be
+	included in other modules
+
+eap_sim_common.c and eap_sim_common.h
+	Common code for EAP-SIM and EAP-AKA
+
+eap_tls_common.c and eap_tls_common.h
+	Common code for EAP-PEAP, EAP-TTLS, and EAP-FAST
+
+eap_tlv.c and eap_tlv.h
+	EAP-TLV code for EAP-PEAP and EAP-FAST
+
+eap_ttls.c and eap_ttls.h
+	EAP-TTLS
+
+eap_pax.c, eap_pax_common.h, eap_pax_common.c
+	EAP-PAX
+
+eap_psk.c, eap_psk_common.h, eap_psk_common.c
+	EAP-PSK (note: this is not needed for WPA-PSK)
+
+eap_sake.c, eap_sake_common.h, eap_sake_common.c
+	EAP-SAKE
+
+eap_gpsk.c, eap_gpsk_common.h, eap_gpsk_common.c
+	EAP-GPSK
+
+eap_aka.c, eap_fast.c, eap_gtc.c, eap_leap.c, eap_md5.c, eap_mschapv2.c,
+eap_otp.c, eap_peap.c, eap_sim.c, eap_tls.c
+	Other EAP method implementations
+
+
+\section eapol_supp EAPOL supplicant
+
+eapol_supp_sm.c and eapol_supp_sm.h
+	EAPOL supplicant state machine and IEEE 802.1X processing
+
+
+\section win_port Windows port
+
+ndis_events.c
+	Code for receiving NdisMIndicateStatus() events and delivering them to
+	%wpa_supplicant driver_ndis.c in more easier to use form
+
+win_if_list.c
+	External program for listing current network interface
+
+
+\section test_programs Test programs
+
+radius_client.c and radius_client.h
+	RADIUS authentication client implementation for eapol_test
+
+radius.c and radius.h
+	RADIUS message processing for eapol_test
+
+eapol_test.c
+	Standalone EAP testing tool with integrated RADIUS authentication
+	client
+
+preauth_test.c
+	Standalone RSN pre-authentication tool
+
+wpa_passphrase.c
+	WPA ASCII passphrase to PSK conversion
+
+*/
diff --git a/hostap/doc/ctrl_iface.doxygen b/hostap/doc/ctrl_iface.doxygen
new file mode 100644
index 0000000..0d06625
--- /dev/null
+++ b/hostap/doc/ctrl_iface.doxygen
@@ -0,0 +1,1054 @@
+/**
+\page ctrl_iface_page %wpa_supplicant control interface
+
+%wpa_supplicant implements a control interface that can be used by
+external programs to control the operations of the %wpa_supplicant
+daemon and to get status information and event notifications. There is
+a small C library, in a form of a single C file, wpa_ctrl.c, that
+provides helper functions to facilitate the use of the control
+interface. External programs can link this file into them and then use
+the library functions documented in wpa_ctrl.h to interact with
+%wpa_supplicant. This library can also be used with C++. wpa_cli.c and
+wpa_gui are example programs using this library.
+
+There are multiple mechanisms for inter-process communication. For
+example, Linux version of %wpa_supplicant is using UNIX domain sockets
+for the control interface and Windows version UDP sockets. The use of
+the functions defined in wpa_ctrl.h can be used to hide the details of
+the used IPC from external programs.
+
+
+\section using_ctrl_iface Using the control interface
+
+External programs, e.g., a GUI or a configuration utility, that need to
+communicate with %wpa_supplicant should link in wpa_ctrl.c. This
+allows them to use helper functions to open connection to the control
+interface with wpa_ctrl_open() and to send commands with
+wpa_ctrl_request().
+
+%wpa_supplicant uses the control interface for two types of communication:
+commands and unsolicited event messages. Commands are a pair of
+messages, a request from the external program and a response from
+%wpa_supplicant. These can be executed using wpa_ctrl_request().
+Unsolicited event messages are sent by %wpa_supplicant to the control
+interface connection without specific request from the external program
+for receiving each message. However, the external program needs to
+attach to the control interface with wpa_ctrl_attach() to receive these
+unsolicited messages.
+
+If the control interface connection is used both for commands and
+unsolicited event messages, there is potential for receiving an
+unsolicited message between the command request and response.
+wpa_ctrl_request() caller will need to supply a callback, msg_cb,
+for processing these messages. Often it is easier to open two
+control interface connections by calling wpa_ctrl_open() twice and
+then use one of the connections for commands and the other one for
+unsolicited messages. This way command request/response pairs will
+not be broken by unsolicited messages. wpa_cli is an example of how
+to use only one connection for both purposes and wpa_gui demonstrates
+how to use two separate connections.
+
+Once the control interface connection is not needed anymore, it should
+be closed by calling wpa_ctrl_close(). If the connection was used for
+unsolicited event messages, it should be first detached by calling
+wpa_ctrl_detach().
+
+
+\section ctrl_iface_cmds Control interface commands
+
+Following commands can be used with wpa_ctrl_request():
+
+\subsection ctrl_iface_PING PING
+
+This command can be used to test whether %wpa_supplicant is replying
+to the control interface commands. The expected reply is \c PONG if the
+connection is open and %wpa_supplicant is processing commands.
+
+
+\subsection ctrl_iface_MIB MIB
+
+Request a list of MIB variables (dot1x, dot11). The output is a text
+block with each line in \c variable=value format. For example:
+
+\verbatim
+dot11RSNAOptionImplemented=TRUE
+dot11RSNAPreauthenticationImplemented=TRUE
+dot11RSNAEnabled=FALSE
+dot11RSNAPreauthenticationEnabled=FALSE
+dot11RSNAConfigVersion=1
+dot11RSNAConfigPairwiseKeysSupported=5
+dot11RSNAConfigGroupCipherSize=128
+dot11RSNAConfigPMKLifetime=43200
+dot11RSNAConfigPMKReauthThreshold=70
+dot11RSNAConfigNumberOfPTKSAReplayCounters=1
+dot11RSNAConfigSATimeout=60
+dot11RSNAAuthenticationSuiteSelected=00-50-f2-2
+dot11RSNAPairwiseCipherSelected=00-50-f2-4
+dot11RSNAGroupCipherSelected=00-50-f2-4
+dot11RSNAPMKIDUsed=
+dot11RSNAAuthenticationSuiteRequested=00-50-f2-2
+dot11RSNAPairwiseCipherRequested=00-50-f2-4
+dot11RSNAGroupCipherRequested=00-50-f2-4
+dot11RSNAConfigNumberOfGTKSAReplayCounters=0
+dot11RSNA4WayHandshakeFailures=0
+dot1xSuppPaeState=5
+dot1xSuppHeldPeriod=60
+dot1xSuppAuthPeriod=30
+dot1xSuppStartPeriod=30
+dot1xSuppMaxStart=3
+dot1xSuppSuppControlledPortStatus=Authorized
+dot1xSuppBackendPaeState=2
+dot1xSuppEapolFramesRx=0
+dot1xSuppEapolFramesTx=440
+dot1xSuppEapolStartFramesTx=2
+dot1xSuppEapolLogoffFramesTx=0
+dot1xSuppEapolRespFramesTx=0
+dot1xSuppEapolReqIdFramesRx=0
+dot1xSuppEapolReqFramesRx=0
+dot1xSuppInvalidEapolFramesRx=0
+dot1xSuppEapLengthErrorFramesRx=0
+dot1xSuppLastEapolFrameVersion=0
+dot1xSuppLastEapolFrameSource=00:00:00:00:00:00
+\endverbatim
+
+
+\subsection ctrl_iface_STATUS STATUS
+
+Request current WPA/EAPOL/EAP status information. The output is a text
+block with each line in \c variable=value format. For example:
+
+\verbatim
+bssid=02:00:01:02:03:04
+ssid=test network
+pairwise_cipher=CCMP
+group_cipher=CCMP
+key_mgmt=WPA-PSK
+wpa_state=COMPLETED
+ip_address=192.168.1.21
+Supplicant PAE state=AUTHENTICATED
+suppPortStatus=Authorized
+EAP state=SUCCESS
+\endverbatim
+
+
+\subsection ctrl_iface_STATUS-VERBOSE STATUS-VERBOSE
+
+Same as STATUS, but with more verbosity (i.e., more \c variable=value pairs).
+
+\verbatim
+bssid=02:00:01:02:03:04
+ssid=test network
+id=0
+pairwise_cipher=CCMP
+group_cipher=CCMP
+key_mgmt=WPA-PSK
+wpa_state=COMPLETED
+ip_address=192.168.1.21
+Supplicant PAE state=AUTHENTICATED
+suppPortStatus=Authorized
+heldPeriod=60
+authPeriod=30
+startPeriod=30
+maxStart=3
+portControl=Auto
+Supplicant Backend state=IDLE
+EAP state=SUCCESS
+reqMethod=0
+methodState=NONE
+decision=COND_SUCC
+ClientTimeout=60
+\endverbatim
+
+
+\subsection ctrl_iface_PMKSA PMKSA
+
+Show PMKSA cache
+
+\verbatim
+Index / AA / PMKID / expiration (in seconds) / opportunistic
+1 / 02:00:01:02:03:04 / 000102030405060708090a0b0c0d0e0f / 41362 / 0
+2 / 02:00:01:33:55:77 / 928389281928383b34afb34ba4212345 / 362 / 1
+\endverbatim
+
+
+\subsection ctrl_iface_SET SET <variable> <value>
+
+Set variables:
+- EAPOL::heldPeriod
+- EAPOL::authPeriod
+- EAPOL::startPeriod
+- EAPOL::maxStart
+- dot11RSNAConfigPMKLifetime
+- dot11RSNAConfigPMKReauthThreshold
+- dot11RSNAConfigSATimeout
+
+Example command:
+\verbatim
+SET EAPOL::heldPeriod 45
+\endverbatim
+
+
+\subsection ctrl_iface_LOGON LOGON
+
+IEEE 802.1X EAPOL state machine logon.
+
+
+\subsection ctrl_iface_LOGOFF LOGOFF
+
+IEEE 802.1X EAPOL state machine logoff.
+
+
+\subsection ctrl_iface_REASSOCIATE REASSOCIATE
+
+Force reassociation.
+
+
+\subsection ctrl_iface_RECONNECT RECONNECT
+
+Connect if disconnected (i.e., like \c REASSOCIATE, but only connect
+if in disconnected state).
+
+
+\subsection ctrl_iface_PREAUTH PREAUTH <BSSID>
+
+Start pre-authentication with the given BSSID.
+
+
+\subsection ctrl_iface_ATTACH ATTACH
+
+Attach the connection as a monitor for unsolicited events. This can
+be done with wpa_ctrl_attach().
+
+
+\subsection ctrl_iface_DETACH DETACH
+
+Detach the connection as a monitor for unsolicited events. This can
+be done with wpa_ctrl_detach().
+
+
+\subsection ctrl_iface_LEVEL LEVEL <debug level>
+
+Change debug level.
+
+
+\subsection ctrl_iface_RECONFIGURE RECONFIGURE
+
+Force %wpa_supplicant to re-read its configuration data.
+
+
+\subsection ctrl_iface_TERMINATE TERMINATE
+
+Terminate %wpa_supplicant process.
+
+
+\subsection ctrl_iface_BSSID BSSID <network id> <BSSID>
+
+Set preferred BSSID for a network. Network id can be received from the
+\c LIST_NETWORKS command output.
+
+
+\subsection ctrl_iface_LIST_NETWORKS LIST_NETWORKS
+
+List configured networks.
+
+\verbatim
+network id / ssid / bssid / flags
+0	example network	any	[CURRENT]
+\endverbatim
+
+(note: fields are separated with tabs)
+
+
+\subsection ctrl_iface_DISCONNECT DISCONNECT
+
+Disconnect and wait for \c REASSOCIATE or \c RECONNECT command before
+connecting.
+
+
+\subsection ctrl_iface_SCAN SCAN
+
+Request a new BSS scan.
+
+
+\subsection ctrl_iface_SCAN_RESULTS SCAN_RESULTS
+
+Get the latest scan results.
+
+\verbatim
+bssid / frequency / signal level / flags / ssid
+00:09:5b:95:e0:4e	2412	208	[WPA-PSK-CCMP]	jkm private
+02:55:24:33:77:a3	2462	187	[WPA-PSK-TKIP]	testing
+00:09:5b:95:e0:4f	2412	209		jkm guest
+\endverbatim
+
+(note: fields are separated with tabs)
+
+
+\subsection ctrl_iface_BSS BSS
+
+Get detailed per-BSS scan results. \c BSS command can be used to
+iterate through scan results one BSS at a time and to fetch all
+information from the found BSSes. This provides access to the same
+data that is available through \c SCAN_RESULTS but in a way that
+avoids problems with large number of scan results not fitting in the
+ctrl_iface messages.
+
+There are two options for selecting the BSS with the \c BSS command:
+"BSS <idx>" requests information for the BSS identified by the index
+(0 .. size-1) in the scan results table and "BSS <BSSID>" requests
+information for the given BSS (based on BSSID in 00:01:02:03:04:05
+format).
+
+BSS information is presented in following format. Please note that new
+fields may be added to this field=value data, so the ctrl_iface user
+should be prepared to ignore values it does not understand.
+
+\verbatim
+bssid=00:09:5b:95:e0:4e
+freq=2412
+beacon_int=0
+capabilities=0x0011
+qual=51
+noise=161
+level=212
+tsf=0000000000000000
+ie=000b6a6b6d2070726976617465010180dd180050f20101000050f20401000050f20401000050f2020000
+ssid=jkm private
+\endverbatim
+
+
+
+\subsection ctrl_iface_SELECT_NETWORK SELECT_NETWORK <network id>
+
+Select a network (disable others). Network id can be received from the
+\c LIST_NETWORKS command output.
+
+
+\subsection ctrl_iface_ENABLE_NETWORK ENABLE_NETWORK <network id>
+
+Enable a network. Network id can be received from the
+\c LIST_NETWORKS command output. Special network id \c all can be
+used to enable all network.
+
+
+\subsection ctrl_iface_DISABLE_NETWORK DISABLE_NETWORK <network id>
+
+Disable a network. Network id can be received from the
+\c LIST_NETWORKS command output. Special network id \c all can be
+used to disable all network.
+
+
+\subsection ctrl_iface_ADD_NETWORK ADD_NETWORK
+
+Add a new network. This command creates a new network with empty
+configuration. The new network is disabled and once it has been
+configured it can be enabled with \c ENABLE_NETWORK command. \c ADD_NETWORK
+returns the network id of the new network or FAIL on failure.
+
+
+\subsection ctrl_iface_REMOVE_NETWORK REMOVE_NETWORK <network id>
+
+Remove a network. Network id can be received from the
+\c LIST_NETWORKS command output. Special network id \c all can be
+used to remove all network.
+
+
+\subsection ctrl_iface_SET_NETWORK SET_NETWORK <network id> <variable> <value>
+
+Set network variables. Network id can be received from the
+\c LIST_NETWORKS command output.
+
+This command uses the same variables and data formats as the
+configuration file. See example wpa_supplicant.conf for more details.
+
+- ssid (network name, SSID)
+- psk (WPA passphrase or pre-shared key)
+- key_mgmt (key management protocol)
+- identity (EAP identity)
+- password (EAP password)
+- ...
+
+
+\subsection ctrl_iface_GET_NETWORK GET_NETWORK <network id> <variable>
+
+Get network variables. Network id can be received from the
+\c LIST_NETWORKS command output.
+
+
+\subsection ctrl_iface_SAVE_CONFIG SAVE_CONFIG
+
+Save the current configuration.
+
+
+\subsection ctrl_iface_P2P_FIND P2P_FIND
+
+Start P2P device discovery. Optional parameter can be used to specify
+the duration for the discovery in seconds (e.g., "P2P_FIND 5"). If the
+duration is not specified, discovery will be started for indefinite
+time, i.e., until it is terminated by P2P_STOP_FIND or P2P_CONNECT (to
+start group formation with a discovered peer).
+
+The default search type is to first run a full scan of all channels
+and then continue scanning only social channels (1, 6, 11). This
+behavior can be changed by specifying a different search type: social
+(e.g., "P2P_FIND 5 type=social") will skip the initial full scan and
+only search social channels; progressive (e.g., "P2P_FIND
+type=progressive") starts with a full scan and then searches
+progressively through all channels one channel at the time with the
+social channel scans. Progressive device discovery can be used to find
+new groups (and groups that were not found during the initial scan,
+e.g., due to the GO being asleep) over time without adding
+considerable extra delay for every Search state round.
+
+
+\subsection ctrl_iface_P2P_STOP_FIND P2P_STOP_FIND
+
+Stop ongoing P2P device discovery or other operation (connect, listen
+mode).
+
+
+\subsection ctrl_iface_P2P_CONNECT P2P_CONNECT
+
+Start P2P group formation with a discovered P2P peer. This includes
+group owner negotiation, group interface setup, provisioning, and
+establishing data connection.
+
+P2P_CONNECT <peer device address> <pbc|pin|PIN#>
+[label|display|keypad] [persistent] [join|auth] [go_intent=<0..15>]
+
+Start P2P group formation with a discovered P2P peer. This includes
+optional group owner negotiation, group interface setup, provisioning,
+and establishing data connection.
+
+The <pbc|pin|PIN#> parameter specifies the WPS provisioning
+method. "pbc" string starts pushbutton method, "pin" string start PIN
+method using an automatically generated PIN (which will be returned as
+the command return code), PIN# means that a pre-selected PIN can be
+used (e.g., 12345670). [label|display|keypad] is used with PIN method
+to specify which PIN is used (label=PIN from local label,
+display=dynamically generated random PIN from local display,
+keypad=PIN entered from peer device label or display). "persistent"
+parameter can be used to request a persistent group to be formed.
+
+"join" indicates that this is a command to join an existing group as a
+client. It skips the GO Negotiation part.
+
+"auth" indicates that the WPS parameters are authorized for the peer
+device without actually starting GO Negotiation (i.e., the peer is
+expected to initiate GO Negotiation). This is mainly for testing
+purposes.
+
+The optional "go_intent" parameter can be used to override the default
+GO Intent value.
+
+
+\subsection ctrl_iface_P2P_LISTEN P2P_LISTEN
+
+Start Listen-only state. Optional parameter can be used to specify the
+duration for the Listen operation in seconds. This command may not
+be of that much use during normal operations and is mainly designed
+for testing. It can also be used to keep the device discoverable
+without having to maintain a group.
+
+
+\subsection ctrl_iface_P2P_GROUP_REMOVE P2P_GROUP_REMOVE
+
+Terminate a P2P group. If a new virtual network interface was used for
+the group, it will also be removed. The network interface name of the
+group interface is used as a parameter for this command.
+
+
+\subsection ctrl_iface_P2P_GROUP_ADD P2P_GROUP_ADD
+
+Set up a P2P group owner manually (i.e., without group owner
+negotiation with a specific peer). This is also known as autonomous
+GO. Optional persistent=<network id> can be used to specify restart of
+a persistent group.
+
+
+\subsection ctrl_iface_P2P_PROV_DISC P2P_PROV_DISC
+
+Send P2P provision discovery request to the specified peer. The
+parameters for this command are the P2P device address of the peer and
+the desired configuration method. For example, "P2P_PROV_DISC
+02:01:02:03:04:05 display" would request the peer to display a PIN for
+us and "P2P_PROV_DISC 02:01:02:03:04:05 keypad" would request the peer
+to enter a PIN that we display.
+
+
+\subsection ctrl_iface_P2P_GET_PASSPHRASE P2P_GET_PASSPHRASE
+
+Get the passphrase for a group (only available when acting as a GO).
+
+
+\subsection ctrl_iface_P2P_SERV_DISC_REQ P2P_SERV_DISC_REQ
+
+Schedule a P2P service discovery request. The parameters for this
+command are the device address of the peer device (or 00:00:00:00:00:00
+for wildcard query that is sent to every discovered P2P peer that
+supports service discovery) and P2P Service Query TLV(s) as hexdump.
+For example, "P2P_SERV_DISC_REQ 00:00:00:00:00:00 02000001" schedules
+a request for listing all supported service discovery protocols and
+requests this to be sent to all discovered peers. The pending requests
+are sent during device discovery (see \ref ctrl_iface_P2P_FIND).
+
+This command returns an identifier for the pending query (e.g.,
+"1f77628") that can be used to cancel the request. Directed requests
+will be automatically removed when the specified peer has replied to
+it.
+
+
+\subsection ctrl_iface_P2P_SERV_DISC_CANCEL_REQ P2P_SERV_DISC_CANCEL_REQ
+
+Cancel a pending P2P service discovery request. This command takes a
+single parameter: identifier for the pending query (the value returned
+by \ref ctrl_iface_P2P_SERV_DISC_REQ), e.g.,
+"P2P_SERV_DISC_CANCEL_REQ 1f77628".
+
+
+\subsection ctrl_iface_P2P_SERV_DISC_RESP P2P_SERV_DISC_RESP
+
+Reply to a service discovery query. This command takes following
+parameters: frequency in MHz, destination address, dialog token,
+response TLV(s). The first three parameters are copied from the
+request event. For example,
+"P2P_SERV_DISC_RESP 2437 02:40:61:c2:f3:b7 1 0300000101".
+
+
+\subsection ctrl_iface_P2P_SERVICE_UPDATE P2P_SERVICE_UPDATE
+
+Indicate that local services have changed. This is used to increment
+the P2P service indicator value so that peers know when previously
+cached information may have changed.
+
+
+\subsection ctrl_iface_P2P_SERV_DISC_EXTERNAL P2P_SERV_DISC_EXTERNAL
+
+Configure external processing of P2P service requests: 0 (default) =
+no external processing of requests (i.e., internal code will reject
+each request), 1 = external processing of requests (external program
+is responsible for replying to service discovery requests with
+\ref ctrl_iface_P2P_SERV_DISC_RESP).
+
+
+\subsection ctrl_iface_P2P_REJECT P2P_REJECT
+
+Reject connection attempt from a peer (specified with a device
+address). This is a mechanism to reject a pending GO Negotiation with
+a peer and request to automatically block any further connection or
+discovery of the peer.
+
+
+\subsection ctrl_iface_P2P_INVITE P2P_INVITE
+
+Invite a peer to join a group or to (re)start a persistent group.
+
+
+\subsection ctrl_iface_P2P_PEER P2P_PEER
+
+Fetch information about a discovered peer. This command takes in an
+argument specifying which peer to select: P2P Device Address of the
+peer, "FIRST" to indicate the first peer in the list, or "NEXT-<P2P
+Device Address>" to indicate the entry following the specified peer
+(to allow for iterating through the list).
+
+
+\subsection ctrl_iface_P2P_EXT_LISTEN P2P_EXT_LISTEN
+
+Enable/disable extended listen timing. Without parameters, this
+command disables extended listen timing. When enabling the feature,
+two parameters are used: availibility period and availability interval
+(both in milliseconds and with range of 1-65535).
+
+
+\section ctrl_iface_interactive Interactive requests
+
+If %wpa_supplicant needs additional information during authentication
+(e.g., password), it will use a specific prefix, \c CTRL-REQ-
+(\a WPA_CTRL_REQ macro) in an unsolicited event message. An external
+program, e.g., a GUI, can provide such information by using
+\c CTRL-RSP- (\a WPA_CTRL_RSP macro) prefix in a command with matching
+field name.
+
+The following fields can be requested in this way from the user:
+- IDENTITY (EAP identity/user name)
+- PASSWORD (EAP password)
+- NEW_PASSWORD (New password if the server is requesting password change)
+- PIN (PIN code for accessing a SIM or smartcard)
+- OTP (one-time password; like password, but the value is used only once)
+- PASSPHRASE (passphrase for a private key file)
+
+\verbatim
+CTRL-REQ-<field name>-<network id>-<human readable text>
+CTRL-RSP-<field name>-<network id>-<value>
+\endverbatim
+
+For example, request from %wpa_supplicant:
+\verbatim
+CTRL-REQ-PASSWORD-1-Password needed for SSID test-network
+\endverbatim
+
+And a matching reply from the GUI:
+\verbatim
+CTRL-RSP-PASSWORD-1-secret
+\endverbatim
+
+
+\subsection ctrl_iface_GET_CAPABILITY GET_CAPABILITY <option> [strict]
+
+Get list of supported functionality (eap, pairwise, group,
+proto). Supported functionality is shown as space separate lists of
+values used in the same format as in %wpa_supplicant configuration.
+If optional argument, 'strict', is added, only the values that the
+driver claims to explicitly support are included. Without this, all
+available capabilities are included if the driver does not provide
+a mechanism for querying capabilities.
+
+Example request/reply pairs:
+
+\verbatim
+GET_CAPABILITY eap
+AKA FAST GTC LEAP MD5 MSCHAPV2 OTP PAX PEAP PSK SIM TLS TTLS
+\endverbatim
+
+\verbatim
+GET_CAPABILITY pairwise
+CCMP TKIP NONE
+\endverbatim
+
+\verbatim
+GET_CAPABILITY pairwise strict
+\endverbatim
+
+\verbatim
+GET_CAPABILITY group
+CCMP TKIP WEP104 WEP40
+\endverbatim
+
+\verbatim
+GET_CAPABILITY key_mgmt
+WPA-PSK WPA-EAP IEEE8021X NONE
+\endverbatim
+
+\verbatim
+GET_CAPABILITY proto
+RSN WPA
+\endverbatim
+
+\verbatim
+GET_CAPABILITY auth_alg
+OPEN SHARED LEAP
+\endverbatim
+
+
+\subsection ctrl_iface_AP_SCAN AP_SCAN <ap_scan value>
+
+Change ap_scan value:
+0 = no scanning,
+1 = %wpa_supplicant requests scans and uses scan results to select the AP,
+2 = %wpa_supplicant does not use scanning and just requests driver to
+associate and take care of AP selection
+
+
+\subsection ctrl_iface_INTERFACES INTERFACES
+
+List configured interfaces.
+
+\verbatim
+wlan0
+eth0
+\endverbatim
+
+
+\section ctrl_iface_events Control interface events
+
+%wpa_supplicant generates number messages based on events like
+connection or a completion of a task. These are available to external
+programs that attach to receive unsolicited messages over the control
+interface with wpa_ctrl_attach().
+
+The event messages will be delivered over the attach control interface
+as text strings that start with the priority level of the message and
+a fixed prefix text as defined in wpa_ctrl.h. After this, optional
+additional information may be included depending on the event
+message. For example, following event message is delivered when new
+scan results are available:
+
+\verbatim
+<2>CTRL-EVENT-SCAN-RESULTS
+\endverbatim
+
+Following priority levels are used:
+- 0 = MSGDUMP
+- 1 = DEBUG
+- 2 = INFO
+- 3 = WARNING
+- 4 = ERROR
+
+By default, any priority level greater than equal to 2 (INFO) are
+delivered over the attached control interface. LEVEL command can be
+used to set the level of messages which will be delivered. It should
+be noted that there are many debug messages that do not include any
+particulat prefix and are subject to change. They may be used for
+debug information, but can usually be ignored by external programs.
+
+In most cases, the external program can skip over the priority field
+in the beginning of the event message and then compare the following
+text to the event strings from wpa_ctrl.h that the program is
+interested in processing.
+
+Following subsections describe the most common event notifications
+generated by %wpa_supplicant.
+
+\subsection ctrl_iface_event_CTRL_REQ CTRL-REQ-
+
+WPA_CTRL_REQ: Request information from a user. See
+\ref ctrl_iface_interactive "Interactive requests" sections for more
+details.
+
+\subsection ctrl_iface_event_CONNECTED CTRL-EVENT-CONNECTED
+
+WPA_EVENT_CONNECTED: Indicate successfully completed authentication
+and that the data connection is now enabled.
+
+\subsection ctrl_iface_event_DISCONNECTED CTRL-EVENT-DISCONNECTED
+
+WPA_EVENT_DISCONNECTED: Disconnected, data connection is not available
+
+\subsection ctrl_iface_event_TERMINATING  CTRL-EVENT-TERMINATING
+
+WPA_EVENT_TERMINATING: %wpa_supplicant is exiting
+
+\subsection ctrl_iface_event_PASSWORD_CHANGED CTRL-EVENT-PASSWORD-CHANGED
+
+WPA_EVENT_PASSWORD_CHANGED: Password change was completed successfully
+
+\subsection ctrl_iface_event_EAP_NOTIFICATION CTRL-EVENT-EAP-NOTIFICATION
+
+WPA_EVENT_EAP_NOTIFICATION: EAP-Request/Notification received
+
+\subsection ctrl_iface_event_EAP_STARTED CTRL-EVENT-EAP-STARTED
+
+WPA_EVENT_EAP_STARTED: EAP authentication started (EAP-Request/Identity
+received)
+
+\subsection ctrl_iface_event_EAP_METHOD CTRL-EVENT-EAP-METHOD
+
+WPA_EVENT_EAP_METHOD: EAP method selected
+
+\subsection ctrl_iface_event_EAP_SUCCESS CTRL-EVENT-EAP-SUCCESS
+
+WPA_EVENT_EAP_SUCCESS: EAP authentication completed successfully
+
+\subsection ctrl_iface_event_EAP_FAILURE CTRL-EVENT-EAP-FAILURE
+
+WPA_EVENT_EAP_FAILURE: EAP authentication failed (EAP-Failure received)
+
+\subsection ctrl_iface_event_SCAN_RESULTS CTRL-EVENT-SCAN-RESULTS
+
+WPA_EVENT_SCAN_RESULTS: New scan results available
+
+\subsection ctrl_iface_event_BSS_ADDED CTRL-EVENT-BSS-ADDED
+
+WPA_EVENT_BSS_ADDED: A new BSS entry was added. The event prefix is
+followed by the BSS entry id and BSSID.
+
+\verbatim
+CTRL-EVENT-BSS-ADDED 34 00:11:22:33:44:55
+\endverbatim
+
+\subsection ctrl_iface_event_BSS_REMOVED CTRL-EVENT-BSS-REMOVED
+
+WPA_EVENT_BSS_REMOVED: A BSS entry was removed. The event prefix is
+followed by BSS entry id and BSSID.
+
+\verbatim
+CTRL-EVENT-BSS-REMOVED 34 00:11:22:33:44:55
+\endverbatim
+
+\subsection ctrl_iface_event_WPS_OVERLAP_DETECTED WPS-OVERLAP-DETECTED
+
+WPS_EVENT_OVERLAP: WPS overlap detected in PBC mode
+
+\subsection ctrl_iface_event_WPS_AP_AVAILABLE_PBC WPS-AP-AVAILABLE-PBC
+
+WPS_EVENT_AP_AVAILABLE_PBC: Available WPS AP with active PBC found in
+scan results.
+
+\subsection ctrl_iface_event_WPS_AP_AVAILABLE_PIN WPS-AP-AVAILABLE-PIN
+
+WPS_EVENT_AP_AVAILABLE_PIN: Available WPS AP with recently selected PIN
+registrar found in scan results.
+
+\subsection ctrl_iface_event_WPS_AP_AVAILABLE WPS-AP-AVAILABLE
+
+WPS_EVENT_AP_AVAILABLE: Available WPS AP found in scan results
+
+\subsection ctrl_iface_event_WPS_CRED_RECEIVED WPS-CRED-RECEIVED
+
+WPS_EVENT_CRED_RECEIVED: A new credential received
+
+\subsection ctrl_iface_event_WPS_M2D WPS-M2D
+
+WPS_EVENT_M2D: M2D received
+
+\subsection ctrl_iface_event_WPS_FAIL
+
+WPS_EVENT_FAIL: WPS registration failed after M2/M2D
+
+\subsection ctrl_iface_event_WPS_SUCCESS WPS-SUCCESS
+
+WPS_EVENT_SUCCESS: WPS registration completed successfully
+
+\subsection ctrl_iface_event_WPS_TIMEOUT WPS-TIMEOUT
+
+WPS_EVENT_TIMEOUT: WPS enrollment attempt timed out and was terminated
+
+\subsection ctrl_iface_event_WPS_ENROLLEE_SEEN WPS-ENROLLEE-SEEN
+
+WPS_EVENT_ENROLLEE_SEEN: WPS Enrollee was detected (used in AP mode).
+The event prefix is followed by MAC addr, UUID-E, pri dev type,
+config methods, dev passwd id, request type, [dev name].
+
+\verbatim
+WPS-ENROLLEE-SEEN 02:00:00:00:01:00
+572cf82f-c957-5653-9b16-b5cfb298abf1 1-0050F204-1 0x80 4 1
+[Wireless Client]
+\endverbatim
+
+\subsection ctrl_iface_event_WPS_ER_AP_ADD WPS-ER-AP-ADD
+
+WPS_EVENT_ER_AP_ADD: WPS ER discovered an AP
+
+\verbatim
+WPS-ER-AP-ADD 87654321-9abc-def0-1234-56789abc0002 02:11:22:33:44:55
+pri_dev_type=6-0050F204-1 wps_state=1 |Very friendly name|Company|
+Long description of the model|WAP|http://w1.fi/|http://w1.fi/hostapd/
+\endverbatim
+
+\subsection ctrl_iface_event_WPS_ER_AP_REMOVE WPS-ER-AP-REMOVE
+
+WPS_EVENT_ER_AP_REMOVE: WPS ER removed an AP entry
+
+\verbatim
+WPS-ER-AP-REMOVE 87654321-9abc-def0-1234-56789abc0002
+\endverbatim
+
+\subsection ctrl_iface_event_WPS_ER_ENROLLEE_ADD WPS-ER-ENROLLEE-ADD
+
+WPS_EVENT_ER_ENROLLEE_ADD: WPS ER discovered a new Enrollee
+
+\verbatim
+WPS-ER-ENROLLEE-ADD 2b7093f1-d6fb-5108-adbb-bea66bb87333
+02:66:a0:ee:17:27 M1=1 config_methods=0x14d dev_passwd_id=0
+pri_dev_type=1-0050F204-1
+|Wireless Client|Company|cmodel|123|12345|
+\endverbatim
+
+\subsection ctrl_iface_event_WPS_ER_ENROLLEE_REMOVE WPS-ER-ENROLLEE-REMOVE
+
+WPS_EVENT_ER_ENROLLEE_REMOVE: WPS ER removed an Enrollee entry
+
+\verbatim
+WPS-ER-ENROLLEE-REMOVE 2b7093f1-d6fb-5108-adbb-bea66bb87333
+02:66:a0:ee:17:27
+\endverbatim
+
+\subsection ctrl_iface_event_WPS_PIN_NEEDED WPS-PIN-NEEDED
+
+WPS_EVENT_PIN_NEEDED: PIN is needed to complete provisioning with an
+Enrollee. This is followed by information about the Enrollee (UUID,
+MAC address, device name, manufacturer, model name, model number,
+serial number, primary device type).
+\verbatim
+WPS-PIN-NEEDED 5a02a5fa-9199-5e7c-bc46-e183d3cb32f7 02:2a:c4:18:5b:f3
+[Wireless Client|Company|cmodel|123|12345|1-0050F204-1]
+\endverbatim
+
+\subsection ctrl_iface_event_WPS_NEW_AP_SETTINGS WPS-NEW-AP-SETTINGS
+
+WPS_EVENT_NEW_AP_SETTINGS: New AP settings were received
+
+\subsection ctrl_iface_event_WPS_REG_SUCCESS WPS-REG-SUCCESS
+
+WPS_EVENT_REG_SUCCESS: WPS provisioning was completed successfully
+(AP/Registrar)
+
+\subsection ctrl_iface_event_WPS_AP_SETUP_LOCKED WPS-AP-SETUP-LOCKED
+
+WPS_EVENT_AP_SETUP_LOCKED: AP changed into setup locked state due to
+multiple failed configuration attempts using the AP PIN.
+
+\subsection ctrl_iface_event_AP_STA_CONNECTED AP-STA-CONNECTED
+
+AP_STA_CONNECTED: A station associated with us (AP mode event). The
+event prefix is followed by the MAC address of the station.
+
+\verbatim
+AP-STA-CONNECTED 02:2a:c4:18:5b:f3
+\endverbatim
+
+\subsection ctrl_iface_event_AP_STA_DISCONNECTED AP-STA-DISCONNECTED
+
+AP_STA_DISCONNECTED: A station disassociated (AP mode event)
+
+\verbatim
+AP-STA-DISCONNECTED 02:2a:c4:18:5b:f3
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_DEVICE_FOUND P2P-DEVICE-FOUND
+
+P2P_EVENT_DEVICE_FOUND: Indication of a discovered P2P device with
+information about that device.
+
+\verbatim
+P2P-DEVICE-FOUND 02:b5:64:63:30:63 p2p_dev_addr=02:b5:64:63:30:63
+pri_dev_type=1-0050f204-1 name='Wireless Client' config_methods=0x84
+dev_capab=0x21 group_capab=0x0
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_GO_NEG_REQUEST P2P-GO-NEG-REQUEST
+
+P2P_EVENT_GO_NEG_REQUEST: A P2P device requested GO negotiation, but we
+were not ready to start the negotiation.
+
+\verbatim
+P2P-GO-NEG-REQUEST 02:40:61:c2:f3:b7 dev_passwd_id=4
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_GO_NEG_SUCCESS P2P-GO-NEG-SUCCESS
+
+P2P_EVENT_GO_NEG_SUCCESS: Indication of successfully complete group
+owner negotiation.
+
+\subsection ctrl_iface_event_P2P_EVENT_GO_NEG_FAILURE P2P-GO-NEG-FAILURE
+
+P2P_EVENT_GO_NEG_FAILURE: Indication of failed group owner negotiation.
+
+\subsection ctrl_iface_event_P2P_EVENT_GROUP_FORMATION_SUCCESS P2P-GROUP-FORMATION-SUCCESS
+
+P2P_EVENT_GROUP_FORMATION_SUCCESS: Indication that P2P group formation
+has been completed successfully.
+
+\subsection ctrl_iface_event_P2P_EVENT_GROUP_FORMATION_FAILURE P2P-GROUP-FORMATION-FAILURE
+
+P2P_EVENT_GROUP_FORMATION_FAILURE: Indication that P2P group formation
+failed (e.g., due to provisioning failure or timeout).
+
+\subsection ctrl_iface_event_P2P_EVENT_GROUP_STARTED P2P-GROUP-STARTED
+
+P2P_EVENT_GROUP_STARTED: Indication of a new P2P group having been
+started. Additional parameters: network interface name for the group,
+role (GO/client), SSID. The passphrase used in the group is also
+indicated here if known (on GO) or PSK (on client). If the group is a
+persistent one, a flag indicating that is included.
+
+\verbatim
+P2P-GROUP-STARTED wlan0-p2p-0 GO ssid="DIRECT-3F Testing"
+passphrase="12345678" go_dev_addr=02:40:61:c2:f3:b7 [PERSISTENT]
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_GROUP_REMOVED P2P-GROUP-REMOVED
+
+P2P_EVENT_GROUP_REMOVED: Indication of a P2P group having been removed.
+Additional parameters: network interface name for the group, role
+(GO/client).
+
+\verbatim
+P2P-GROUP-REMOVED wlan0-p2p-0 GO
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_PROV_DISC_SHOW_PIN P2P-PROV-DISC-SHOW-PIN
+
+P2P_EVENT_PROV_DISC_SHOW_PIN: Request from the peer for us to display
+a PIN that will be entered on the peer. The following parameters are
+included after the event prefix: peer_address PIN. The PIN is a
+random PIN generated for this connection. P2P_CONNECT command can be
+used to accept the request with the same PIN configured for the
+connection.
+
+\verbatim
+P2P-PROV-DISC-SHOW-PIN 02:40:61:c2:f3:b7 12345670
+p2p_dev_addr=02:40:61:c2:f3:b7 pri_dev_type=1-0050F204-1 name='Test'
+config_methods=0x188 dev_capab=0x21 group_capab=0x0
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_PROV_DISC_ENTER_PIN P2P-PROV-DISC-ENTER-PIN
+
+P2P_EVENT_PROV_DISC_ENTER_PIN: Request from the peer for us to enter a
+PIN displayed on the peer. The following parameter is included after
+the event prefix: peer address.
+
+\verbatim
+P2P-PROV-DISC-ENTER-PIN 02:40:61:c2:f3:b7 p2p_dev_addr=02:40:61:c2:f3:b7
+pri_dev_type=1-0050F204-1 name='Test' config_methods=0x188
+dev_capab=0x21 group_capab=0x0
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_PROV_DISC_PBC_REQ P2P-PROV-DISC-PBC-REQ
+
+P2P_EVENT_PROV_DISC_PBC_REQ: Request from the peer for us to connect
+using PBC. The following parameters are included after the event prefix:
+peer_address. P2P_CONNECT command can be used to accept the request.
+
+\verbatim
+P2P-PROV-DISC-PBC-REQ 02:40:61:c2:f3:b7 p2p_dev_addr=02:40:61:c2:f3:b7
+pri_dev_type=1-0050F204-1 name='Test' config_methods=0x188
+dev_capab=0x21 group_capab=0x0
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_PROV_DISC_PBC_RESP P2P-PROV-DISC-PBC-RESP
+
+P2P_EVENT_PROV_DISC_PBC_RESP: The peer accepted our provision discovery
+request to connect using PBC. The following parameters are included
+after the event prefix: peer_address. P2P_CONNECT command can be used to
+start GO Negotiation after this.
+
+\verbatim
+P2P-PROV-DISC-PBC-RESP 02:40:61:c2:f3:b7
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_SERV_DISC_REQ P2P-SERV-DISC-REQ
+
+P2P-SERV-DISC-REQ: Indicate reception of a P2P service discovery
+request. The following parameters are included after the event prefix:
+frequency in MHz, source address, dialog token, Service Update
+Indicator, Service Query TLV(s) as hexdump.
+
+\verbatim
+P2P-SERV-DISC-REQ 2412 02:40:61:c2:f3:b7 0 0 02000001
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_SERV_DISC_RESP P2P-SERV-DISC-RESP
+
+P2P-SERV-DISC-RESP: Indicate reception of a P2P service discovery
+response. The following parameters are included after the event prefix:
+source address, Service Update Indicator, Service Response TLV(s) as
+hexdump.
+
+\verbatim
+P2P-SERV-DISC-RESP 02:40:61:c2:f3:b7 0 0300000101
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_INVITATION_RECEIVED P2P-INVITATION-RECEIVED
+
+P2P-INVITATION-RECEIVED: Indicate reception of a P2P Invitation
+Request. For persistent groups, the parameter after the event prefix
+indicates which network block includes the persistent group data.
+
+\verbatim
+P2P-INVITATION-RECEIVED sa=02:40:61:c2:f3:b7 persistent=0
+\endverbatim
+
+\subsection ctrl_iface_event_P2P_EVENT_INVITATION_RESULT P2P-INVITATION-RESULT
+
+P2P-INVITATION-RESULT: Indicate result of a P2P invitation that was
+requested with \ref ctrl_iface_P2P_INVITE. The parameter
+status=<value> shows the status code returned by the peer (or -1 on
+local failure or timeout).
+
+\verbatim
+P2P-INVITATION-RESULT status=1
+\endverbatim
+
+*/
diff --git a/hostap/doc/dbus.doxygen b/hostap/doc/dbus.doxygen
new file mode 100644
index 0000000..a737ed7
--- /dev/null
+++ b/hostap/doc/dbus.doxygen
@@ -0,0 +1,756 @@
+/**
+\page dbus %wpa_supplicant D-Bus API
+
+This section documents the %wpa_supplicant D-Bus API. Every D-Bus
+interface implemented by %wpa_supplicant is described here including
+their methods, signals, and properties with arguments, returned
+values, and possible errors.
+
+Interfaces:
+- \ref dbus_main
+- \ref dbus_interface
+- \ref dbus_wps
+- \ref dbus_bss
+- \ref dbus_network
+
+
+\section dbus_main fi.w1.wpa_supplicant1
+
+Interface implemented by the main %wpa_supplicant D-Bus object
+registered in the bus with fi.w1.wpa_supplicant1 name.
+
+\subsection dbus_main_methods Methods
+
+    <ul>
+      <li>
+	<h3>CreateInterface ( a{sv} : args ) --> o : interface</h3>
+	<p>Registers a wireless interface in %wpa_supplicant.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>a{sv} : args</dt>
+	  <dd>
+	    A dictionary with arguments used to add the interface to %wpa_supplicant. The dictionary may contain the following entries:
+	    <table>
+	      <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th>
+	      <tr><td>Ifname</td><td>s</td><td>Name of the network interface to control, e.g., wlan0</td><td>Yes</td>
+	      <tr><td>Bridge_ifname</td><td>s</td><td>Name of the bridge interface to control, e.g., br0</td><td>No</td>
+	      <tr><td>Driver</td><td>s</td><td>Driver name which the interface uses, e.g., nl80211</td><td>No</td>
+	    </table>
+	  </dd>
+	</dl>
+	<h4>Returns</h4>
+	<dl>
+	  <dt>o : interface</dt>
+	  <dd>A D-Bus path to object representing created interface</dd>
+	</dl>
+	<h4>Possible errors</h4>
+	<dl>
+	  <dt>fi.w1.wpa_supplicant1.InterfaceExists</dt>
+	  <dd>%wpa_supplicant already controls this interface.</dd>
+	  <dt>fi.w1.wpa_supplicant1.UnknownError</dt>
+	  <dd>Creating interface failed for an unknown reason.</dd>
+	  <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+	  <dd>Invalid entries were found in the passed argument.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>RemoveInterface ( o : interface ) --> nothing</h3>
+	<p>Deregisters a wireless interface from %wpa_supplicant.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>o : interface</dt>
+	  <dd>A D-Bus path to an object representing an interface to remove returned by CreateInterface</dd>
+	</dl>
+	<h4>Possible errors</h4>
+	<dl>
+	  <dt>fi.w1.wpa_supplicant1.InterfaceUnknown</dt>
+	  <dd>Object pointed by the path doesn't exist or doesn't represent an interface.</dd>
+	  <dt>fi.w1.wpa_supplicant1.UnknownError</dt>
+	  <dd>Removing interface failed for an unknown reason.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>GetInterface ( s : ifname ) --> o : interface</h3>
+	<p>Returns a D-Bus path to an object related to an interface which %wpa_supplicant already controls.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>s : ifname</dt>
+	  <dd>Name of the network interface, e.g., wlan0</dd>
+	</dl>
+	<h4>Returns</h4>
+	<dl>
+	  <dt>o : interface</dt>
+	  <dd>A D-Bus path to an object representing an interface</dd>
+	</dl>
+	<h4>Possible errors</h4>
+	<dl>
+	  <dt>fi.w1.wpa_supplicant1.InterfaceUnknown</dt>
+	  <dd>An interface with the passed name in not controlled by %wpa_supplicant.</dd>
+	  <dt>fi.w1.wpa_supplicant1.UnknownError</dt>
+	  <dd>Getting an interface object path failed for an unknown reason.</dd>
+	</dl>
+      </li>
+    </ul>
+
+\subsection dbus_main_properties Properties
+
+    <ul>
+      <li>
+	<h3>DebugLevel - s - (read/write)</h3>
+	<p>Global %wpa_supplicant debugging level. Possible values are
+	"msgdump" (verbose debugging), "debug" (debugging),
+	"info" (informative), "warning" (warnings), and "error" (errors).</p>
+      </li>
+
+      <li>
+	<h3>DebugTimestamp - b - (read/write)</h3>
+	<p>Global %wpa_supplicant debugging parameter. Determines if timestamps are shown in debug logs.</p>
+      </li>
+
+      <li>
+	<h3>DebugShowKeys - b - (read/write)</h3>
+	<p>Global %wpa_supplicant debugging parameter. Determines if secrets are shown in debug logs.</p>
+      </li>
+
+      <li>
+	<h3>Interfaces - ao - (read)</h3>
+	<p>An array with paths to D-Bus objects representing controlled interfaces each.</p>
+      </li>
+
+      <li>
+	<h3>EapMethods - as - (read)</h3>
+	<p>An array with supported EAP methods names.</p>
+      </li>
+    </ul>
+
+\subsection dbus_main_signals Signals
+
+    <ul>
+      <li>
+	<h3>InterfaceAdded ( o : interface, a{sv} : properties )</h3>
+	<p>A new interface was added to %wpa_supplicant.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>o : interface</dt>
+	  <dd>A D-Bus path to an object representing the added interface</dd>
+	</dl>
+	<dl>
+	  <dt>a{sv} : properties</dt>
+	  <dd>A dictionary containing properties of added interface.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>InterfaceRemoved ( o : interface )</h3>
+	<p>An interface was removed from %wpa_supplicant.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>o : interface</dt>
+	  <dd>A D-Bus path to an object representing the removed interface</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>PropertiesChanged ( a{sv} : properties )</h3>
+	<p>Some properties have changed.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>a{sv} : properties</dt>
+	  <dd>A dictionary with pairs of properties names which have changed and theirs new values. Possible dictionary keys are: "DebugParams"</dd>
+	</dl>
+      </li>
+    </ul>
+
+
+\section dbus_interface fi.w1.wpa_supplicant1.Interface
+
+Interface implemented by objects related to network interface added to
+%wpa_supplicant, i.e., returned by
+fi.w1.wpa_supplicant1.CreateInterface.
+
+\subsection dbus_interface_methods Methods
+
+    <ul>
+      <li>
+	<h3>Scan ( a{sv} : args ) --> nothing</h3>
+	<p>Triggers a scan.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>a{sv} : args</dt>
+	  <dd>
+	    A dictionary with arguments describing scan type:
+	    <table>
+	      <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th>
+	      <tr><td>Type</td><td>s</td><td>Type of the scan. Possible values: "active", "passive"</td><td>Yes</td>
+	      <tr><td>SSIDs</td><td>aay</td><td>Array of SSIDs to scan for (applies only if scan type is active)</td><td>No</td>
+	      <tr><td>IEs</td><td>aay</td><td>Information elements to used in active scan (applies only if scan type is active)</td><td>No</td>
+	      <tr><td>Channels</td><td>a(uu)</td><td>Array of frequencies to scan in form of (center, width) in MHz.</td><td>No</td>
+	    </table>
+	  </dd>
+	</dl>
+	<h4>Possible errors</h4>
+	<dl>
+	  <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+	  <dd>Invalid entries were found in the passed argument.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>Disconnect ( ) --> nothing</h3>
+	<p>Disassociates the interface from current network.</p>
+	<h4>Possible errors</h4>
+	<dl>
+	  <dt>fi.w1.wpa_supplicant1.NotConnected</dt>
+	  <dd>Interface is not connected to any network.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>AddNetwork ( a{sv} : args ) --> o : network</h3>
+	<p>Adds a new network to the interface.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>a{sv} : args</dt>
+	  <dd>A dictionary with network configuration. Dictionary entries are equivalent to entries in the "network" block in %wpa_supplicant configuration file. Entry values should be appropriate type to the entry, e.g., an entry with key "frequency" should have value type int.</dd>
+	</dl>
+	<h4>Returns</h4>
+	<dl>
+	  <dt>o : network</dt>
+	  <dd>A D-Bus path to an object representing a configured network</dd>
+	</dl>
+	<h4>Possible errors</h4>
+	<dl>
+	  <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+	  <dd>Invalid entries were found in the passed argument.</dd>
+	  <dt>fi.w1.wpa_supplicant1.UnknownError</dt>
+	  <dd>Adding network failed for an unknown reason.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>RemoveNetwork ( o : network ) --> nothing</h3>
+	<p>Removes a configured network from the interface.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>o : network</dt>
+	  <dd>A D-Bus path to an object representing a configured network returned by fi.w1.wpa_supplicant1.Interface.AddNetwork</dd>
+	</dl>
+	<h4>Possible errors</h4>
+	<dl>
+	  <dt>fi.w1.wpa_supplicant1.NetworkUnknown</dt>
+	  <dd>A passed path doesn't point to any network object.</dd>
+	  <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+	  <dd>A passed path doesn't point to any network object.</dd>
+	  <dt>fi.w1.wpa_supplicant1.UnknownError</dt>
+	  <dd>Removing network failed for an unknown reason.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>SelectNetwork ( o : network ) --> nothing</h3>
+	<p>Attempt association with a configured network.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>o : network</dt>
+	  <dd>A D-Bus path to an object representing a configured network returned by fi.w1.wpa_supplicant1.Interface.AddNetwork</dd>
+	</dl>
+	<h4>Possible errors</h4>
+	<dl>
+	  <dt>fi.w1.wpa_supplicant1.NetworkUnknown</dt>
+	  <dd>A passed path doesn't point to any network object.</dd>
+	  <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+	  <dd>A passed path doesn't point to any network object.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>AddBlob ( s : name, ay : data ) --> nothing</h3>
+	<p>Adds a blob to the interface.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>s : name</dt>
+	  <dd>A name of a blob</dd>
+	  <dt>ay : data</dt>
+	  <dd>A blob data</dd>
+	</dl>
+	<h4>Possible errors</h4>
+	<dl>
+	  <dt>fi.w1.wpa_supplicant1.BlobExists</dt>
+	  <dd>A blob with the specified name already exists.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>RemoveBlob ( s : name ) --> nothing</h3>
+	<p>Removes the blob from the interface.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>s : name</dt>
+	  <dd>A name of the blob to remove</dd>
+	</dl>
+	<h4>Possible errors</h4>
+	<dl>
+	  <dt>fi.w1.wpa_supplicant1.BlobUnknown</dt>
+	  <dd>A blob with the specified name doesn't exist.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>GetBlob ( s : name ) --> ay : data</h3>
+	<p>Returns the blob data of a previously added blob.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>s : name</dt>
+	  <dd>A name of the blob</dd>
+	</dl>
+	<h4>Returns</h4>
+	<dl>
+	  <dt>ay : data</dt>
+	  <dd>A blob data</dd>
+	</dl>
+	<h4>Possible errors</h4>
+	<dl>
+	  <dt>fi.w1.wpa_supplicant1.BlobUnknown</dt>
+	  <dd>A blob with the specified name doesn't exist.</dd>
+	</dl>
+      </li>
+      <li>
+	<h3>AutoScan ( s : arg ) --> nothing</h3>
+	<p>Set autoscan parameters for the interface.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>s : arg</dt>
+	  <dd>Autoscan parameter line or empty to unset autoscan.</dd>
+	</dl>
+	<h4>Possible errors</h4>
+	<dl>
+	  <dt>fi.w1.wpa_supplicant1.NoMemory</dt>
+	  <dd>Needed memory was not possible to get allocated.</dd>
+	  <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+	  <dd>Invalid entries were found in the passed argument.</dd>
+	</dl>
+       </li>
+    </ul>
+
+\subsection dbus_interface_properties Properties
+
+    <ul>
+      <li>
+	<h3>Capabilities - a{sv} - (read)</h3>
+	<p>Capabilities of the interface. Dictionary contains following entries:</p>
+	<table>
+	  <tr><th>Key</th><th>Value type</th><th>Description</th>
+	  <tr><td>Pairwise</td><td>as</td><td>Possible array elements: "ccmp", "tkip", "none"</td>
+	  <tr><td>Group</td><td>as</td><td>Possible array elements: "ccmp", "tkip", "wep104", "wep40"</td>
+	  <tr><td>KeyMgmt</td><td>as</td><td>Possible array elements: "wpa-psk", "wpa-ft-psk", "wpa-psk-sha256", "wpa-eap", "wpa-ft-eap", "wpa-eap-sha256", "ieee8021x", "wpa-none", "wps", "none"</td>
+	  <tr><td>Protocol</td><td>as</td><td>Possible array elements: "rsn", "wpa"</td>
+	  <tr><td>AuthAlg</td><td>as</td><td>Possible array elements: "open", "shared", "leap"</td>
+	  <tr><td>Scan</td><td>as</td><td>Possible array elements: "active", "passive", "ssid"</td>
+	  <tr><td>Modes</td><td>as</td><td>Possible array elements: "infrastructure", "ad-hoc", "ap"</td>
+	</table>
+      </li>
+
+      <li>
+	<h3>State - s - (read)</h3>
+	<p>A state of the interface. Possible values are: return "disconnected", "inactive", "scanning", "authenticating", "associating", "associated", "4way_handshake", "group_handshake", "completed","unknown".</p>
+      </li>
+
+      <li>
+	<h3>Scanning - b - (read)</h3>
+	<p>Determines if the interface is already scanning or not</p>
+      </li>
+
+      <li>
+	<h3>ApScan - u - (read/write)</h3>
+	<p>Identical to ap_scan entry in %wpa_supplicant configuration file. Possible values are 0, 1 or 2.</p>
+      </li>
+
+      <li>
+	<h3>BSSExpireAge - u - (read/write)</h3>
+	<p>Identical to bss_expiration_age entry in %wpa_supplicant configuration file.</p>
+      </li>
+
+      <li>
+	<h3>BSSExpireCount - u - (read/write)</h3>
+	<p>Identical to bss_expiration_scan_count entry in %wpa_supplicant configuration file.</p>
+      </li>
+
+      <li>
+	<h3>Country - s - (read/write)</h3>
+	<p>Identical to country entry in %wpa_supplicant configuration file.</p>
+      </li>
+
+      <li>
+	<h3>Ifname - s - (read)</h3>
+	<p>Name of network interface controlled by the interface, e.g., wlan0.</p>
+      </li>
+
+      <li>
+	<h3>BridgeIfname - s - (read)</h3>
+	<p>Name of bridge network interface controlled by the interface, e.g., br0.</p>
+      </li>
+
+      <li>
+	<h3>Driver - s - (read)</h3>
+	<p>Name of driver used by the interface, e.g., nl80211.</p>
+      </li>
+
+      <li>
+	<h3>CurrentBSS - o - (read)</h3>
+	<p>Path to D-Bus object representing BSS which %wpa_supplicant is associated with, or "/" if is not associated at all.</p>
+      </li>
+
+      <li>
+	<h3>CurrentNetwork - o - (read)</h3>
+	<p>Path to D-Bus object representing configured network which %wpa_supplicant uses at the moment, or "/" if doesn't use any.</p>
+      </li>
+
+      <li>
+	<h3>Blobs - as - (read)</h3>
+	<p>List of blobs names added to the Interface.</p>
+      </li>
+
+      <li>
+	<h3>BSSs - ao - (read)</h3>
+	<p>List of D-Bus objects paths representing BSSs known to the interface, i.e., scan results.</p>
+      </li>
+
+      <li>
+	<h3>Networks - ao - (read)</h3>
+	<p>List of D-Bus objects paths representing configured networks.</p>
+      </li>
+
+      <li>
+	<h3>FastReauth - b - (read/write)</h3>
+	<p>Identical to fast_reauth entry in %wpa_supplicant configuration file.</p>
+      </li>
+
+      <li>
+	<h3>ScanInterval - i - (read/write)</h3>
+	<p>Time (in seconds) between scans for a suitable AP. Must be >= 0.</p>
+      </li>
+    </ul>
+
+\subsection dbus_interface_signals Signals
+
+    <ul>
+      <li>
+	<h3>ScanDone ( b : success )</h3>
+	<p>Scanning finished. </p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>s : success</dt>
+	  <dd>Determines if scanning was successful. If so, results are available.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>BSSAdded ( o : BSS, a{sv} : properties )</h3>
+	<p>Interface became aware of a new BSS.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>o : BSS</dt>
+	  <dd>A D-Bus path to an object representing the new BSS.</dd>
+	</dl>
+	<dl>
+	  <dt>a{sv} : properties</dt>
+	  <dd>A dictionary containing properties of added BSS.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>BSSRemoved ( o : BSS )</h3>
+	<p>BSS disappeared.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>o : BSS</dt>
+	  <dd>A D-Bus path to an object representing the BSS.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>BlobAdded ( s : blobName )</h3>
+	<p>A new blob has been added to the interface.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>s : blobName</dt>
+	  <dd>A name of the added blob.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>BlobRemoved ( s : blobName )</h3>
+	<p>A blob has been removed from the interface.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>s : blobName</dt>
+	  <dd>A name of the removed blob.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>NetworkAdded ( o : network, a{sv} : properties )</h3>
+	<p>A new network has been added to the interface.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>o : network</dt>
+	  <dd>A D-Bus path to an object representing the added network.</dd>
+	</dl>
+	<dl>
+	  <dt>a{sv} : properties</dt>
+	  <dd>A dictionary containing properties of added network.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>NetworkRemoved ( o : network )</h3>
+	<p>The network has been removed from the interface.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>o : network</dt>
+	  <dd>A D-Bus path to an object representing the removed network.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>NetworkSelected ( o : network )</h3>
+	<p>The network has been selected.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>o : network</dt>
+	  <dd>A D-Bus path to an object representing the selected network.</dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>PropertiesChanged ( a{sv} : properties )</h3>
+	<p>Some properties have changed.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>a{sv} : properties</dt>
+	  <dd>A dictionary with pairs of properties names which have changed and theirs new values. Possible dictionary keys are: "ApScan", "Scanning", "State", "CurrentBSS", "CurrentNetwork"</dd>
+	</dl>
+      </li>
+    </ul>
+
+
+\section dbus_wps fi.w1.wpa_supplicant1.Interface.WPS
+
+Interface implemented by objects related to network interface added to
+%wpa_supplicant, i.e., returned by fi.w1.wpa_supplicant1.CreateInterface.
+
+\subsection dbus_wps_methods Methods
+
+    <ul>
+      <li>
+	<h3>Start ( a{sv} : args ) --> a{sv} : output</h3>
+	<p>Starts WPS configuration.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>a{sv} : args</dt>
+	  <dd>
+	    A dictionary with arguments used to start WPS configuration. The dictionary may contain the following entries:
+	    <table>
+	      <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th>
+	      <tr><td>Role</td><td>s</td><td>The device's role. Possible values are "enrollee" and "registrar".</td><td>Yes</td>
+	      <tr><td>Type</td><td>s</td><td>WPS authentication type. Applies only for enrollee role. Possible values are "pin" and "pbc".</td><td>Yes, for enrollee role; otherwise no</td>
+	      <tr><td>Pin</td><td>s</td><td>WPS Pin.</td><td>Yes, for registrar role; otherwise optional</td>
+	      <tr><td>Bssid</td><td>ay</td><td></td><td>No</td>
+	    </table>
+	  </dd>
+	</dl>
+	<h4>Returns</h4>
+	<dl>
+	  <dt>a{sv} : output</dt>
+	  <dd>
+	    <table>
+	      <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th>
+	      <tr><td>Pin</td><td>s</td><td>Newly generated PIN, if not specified for enrollee role and pin authentication type.</td><td>No</td>
+	    </table>
+	  </dd>
+	</dl>
+	<h4>Possible errors</h4>
+	<dl>
+	  <dt>fi.w1.wpa_supplicant1.UnknownError</dt>
+	  <dd>Starting WPS configuration failed for an unknown reason.</dd>
+	  <dt>fi.w1.wpa_supplicant1.InvalidArgs</dt>
+	  <dd>Invalid entries were found in the passed argument.</dd>
+	</dl>
+      </li>
+    </ul>
+
+\subsection dbus_wps_properties Properties
+
+    <ul>
+      <li>
+	<h3>ProcessCredentials - b - (read/write)</h3>
+	<p>Determines if the interface will process the credentials (credentials_processed configuration file parameter).</p>
+      </li>
+    </ul>
+
+\subsection dbus_wps_signals Signals
+
+    <ul>
+      <li>
+	<h3>Event ( s : name, a{sv} : args )</h3>
+	<p>WPS event occurred.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>s : event</dt>
+	  <dd>Event type. Possible values are: "success, "fail" and "m2d"</dd>
+	  <dt>a{sv} : args</dt>
+	  <dd>
+	    Event arguments. Empty for success event, one entry ( "msg" : i ) for fail event and following entries for m2d event:
+	    <table>
+	      <tr><th>config_methods</th><th>Value type</th>
+	      <tr><td>manufacturer</td><td>q</td>
+	      <tr><td>model_name</td><td>ay</td>
+	      <tr><td>model_number</td><td>ay</td>
+	      <tr><td>serial_number</td><td>ay</td>
+	      <tr><td>dev_name</td><td>ay</td>
+	      <tr><td>primary_dev_type</td><td>ay</td>
+	      <tr><td>config_error</td><td>q</td>
+	      <tr><td>dev_password_id</td><td>q</td>
+	    </table>
+	  </dd>
+	</dl>
+      </li>
+
+      <li>
+	<h3>Credentials ( a{sv} : credentials )</h3>
+	<p>WPS credentials. Dictionary contains:</p>
+	<table>
+	  <tr><th>Key</th><th>Value type</th><th>Description</th>
+	  <tr><td>BSSID</td><td>ay</td><td></td>
+	  <tr><td>SSID</td><td>s</td><td></td>
+	  <tr><td>AuthType</td><td>as</td><td>Possible array elements: "open", "shared", "wpa-psk", "wpa-eap", "wpa2-eap", "wpa2-psk"</td>
+	  <tr><td>EncrType</td><td>as</td><td>Possible array elements: "none", "wep", "tkip", "aes"</td>
+	  <tr><td>Key</td><td>ay</td><td>Key data</td>
+	  <tr><td>KeyIndex</td><td>u</td><td>Key index</td>
+	</table>
+      </li>
+
+      <li>
+	<h3>PropertiesChanged ( a{sv} : properties )</h3>
+	<p>Some properties have changed.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>a{sv} : properties</dt>
+	  <dd>A dictionary with pairs of properties names which have changed and theirs new values. Possible dictionary keys are: "ProcessCredentials"</dd>
+	</dl>
+      </li>
+    </ul>
+
+
+\section dbus_bss fi.w1.wpa_supplicant1.BSS
+
+Interface implemented by objects representing a scanned BSSs, i.e.,
+scan results.
+
+\subsection dbus_bss_properties Properties
+
+    <ul>
+      <li>
+	<h3>BSSID - ay - (read)</h3>
+	<p>BSSID of the BSS.</p>
+      </li>
+      <li>
+	<h3>SSID - ay - (read)</h3>
+	<p>SSID of the BSS.</p>
+      </li>
+      <li>
+	<h3>WPA - a{sv} - (read)</h3>
+	<p>WPA information of the BSS. Empty dictionary indicates no WPA support. Dictionary entries are:</p>
+	<table>
+	  <tr><td>KeyMgmt</td><td>as</td><td>Key management suite. Possible array elements: "wpa-psk", "wpa-eap", "wpa-none"</td>
+	  <tr><td>Pairwise</td><td>as</td><td>Pairwise cipher suites. Possible array elements: "ccmp", "tkip"</td>
+	  <tr><td>Group</td><td>s</td><td>Group cipher suite. Possible values are: "ccmp", "tkip", "wep104", "wep40"</td>
+	</table>
+      </li>
+      <li>
+	<h3>RSN - a{sv} - (read)</h3>
+	<p>RSN information of the BSS. Empty dictionary indicates no RSN support. Dictionary entries are:</p>
+	<table>
+	  <tr><td>KeyMgmt</td><td>as</td><td>Key management suite. Possible array elements: "wpa-psk", "wpa-eap", "wpa-ft-psk", "wpa-ft-eap", "wpa-psk-sha256", "wpa-eap-sha256",</td>
+	  <tr><td>Pairwise</td><td>as</td><td>Pairwise cipher suites. Possible array elements: "ccmp", "tkip"</td>
+	  <tr><td>Group</td><td>s</td><td>Group cipher suite. Possible values are: "ccmp", "tkip", "wep104", "wep40"</td>
+	  <tr><td>MgmtGroup</td><td>s</td><td>Mangement frames cipher suite. Possible values are: "aes128cmac"</td>
+	</table>
+      </li>
+      <li>
+	<h3>IEs - ay - (read)</h3>
+	<p>All IEs of the BSS as a chain of TLVs</p>
+      </li>
+      <li>
+	<h3>Privacy - b - (read)</h3>
+	<p>Indicates if BSS supports privacy.</p>
+      </li>
+      <li>
+	<h3>Mode - s - (read)</h3>
+	<p>Describes mode of the BSS. Possible values are: "ad-hoc" and "infrastructure".</p>
+      </li>
+      <li>
+	<h3>Frequency - q - (read)</h3>
+	<p>Frequency of the BSS in MHz.</p>
+      </li>
+      <li>
+	<h3>Rates - au - (read)</h3>
+	<p>Descending ordered array of rates supported by the BSS in bits per second.</p>
+      </li>
+      <li>
+	<h3>Signal - n - (read)</h3>
+	<p>Signal strength of the BSS.</p>
+      </li>
+    </ul>
+
+\subsection dbus_bss_signals Signals
+
+    <ul>
+      <li>
+	<h3>PropertiesChanged ( a{sv} : properties )</h3>
+	<p>Some properties have changed.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>a{sv} : properties</dt>
+	  <dd>A dictionary with pairs of properties names which have changed and theirs new values.</dd>
+	</dl>
+      </li>
+    </ul>
+
+
+\section dbus_network fi.w1.wpa_supplicant1.Network
+
+Interface implemented by objects representing configured networks,
+i.e., returned by fi.w1.wpa_supplicant1.Interface.AddNetwork.
+
+\subsection dbus_network_properties Properties
+
+    <ul>
+      <li>
+	<h3>Enabled - b - (read/write)</h3>
+	<p>Determines if the configured network is enabled or not.</p>
+      </li>
+
+      <li>
+	<h3>Properties - a{sv} - (read)</h3>
+	<p>Properties of the configured network. Dictionary contains entries from "network" block of %wpa_supplicant configuration file. All values are string type, e.g., frequency is "2437", not 2437.
+      </li>
+    </ul>
+
+\subsection dbus_network_signals Signals
+
+    <ul>
+      <li>
+	<h3>PropertiesChanged ( a{sv} : properties )</h3>
+	<p>Some properties have changed.</p>
+	<h4>Arguments</h4>
+	<dl>
+	  <dt>a{sv} : properties</dt>
+	  <dd>A dictionary with pairs of properties names which have changed and theirs new values. Possible dictionary keys are: "Enabled"</dd>
+	</dl>
+      </li>
+    </ul>
+
+*/
diff --git a/hostap/doc/directories.doxygen b/hostap/doc/directories.doxygen
new file mode 100644
index 0000000..7465afe
--- /dev/null
+++ b/hostap/doc/directories.doxygen
@@ -0,0 +1,90 @@
+/**
+
+\dir hostapd hostapd
+
+hostapd-specific code for configuration, control interface, and AP
+management.
+
+
+\dir src/common Common functionality
+
+This module includes IEEE 802.11, IEEE 802.1X, and WPA related
+functionality that is shared between AP and station modes.
+
+
+\dir src/crypto Cryptographical functionality and wrappers
+
+This module defines crypto and tls interfaces to provide portability
+layer for different crypto/TLS libraries. Wrappers for number of
+libraries are also included here. In addition, internal implementation
+of various crypto functions are provided as an alternative for an
+external library and to extend some algorithms.
+
+
+\dir src/drivers Driver wrappers
+
+This directory includes the driver interface definition and all the
+driver wrappers that can be used to interact with different drivers
+without making rest of the software dependent on which particular
+driver is used.
+
+
+\dir src/eap_common Common EAP functionality for server and peer
+
+
+\dir src/eap_peer EAP peer
+
+
+\dir src/eap_server EAP server
+
+
+\dir src/eapol_auth EAPOL authenticator
+
+
+\dir src/eapol_supp EAPOL supplicant
+
+
+\dir src/l2_packet Layer 2 packet interface
+
+This module defines an interface for layer 2 (link layer) packet
+sendinf and receiving. All the wrappers for supported mechanisms are
+also included here. This is used to port packet access for new
+operating systems without having to make rest of the source code
+depend on which OS network stack is used.
+
+
+\dir src/radius RADIUS
+
+RADIUS module includes RADIUS message building and parsing
+functionality and separate RADIUS client and server functions.
+
+
+\dir src/rsn_supp IEEE 802.11 RSN and WPA supplicant
+
+
+\dir src/tls Internal TLS server and client implementation
+
+This module can be used as an alternative to using an external TLS
+library.
+
+
+\dir src/utils Utility functions
+
+Independent set of helper functions that most other components
+use. This includes portability wrappers and helpers for common tasks.
+
+
+\dir src/wps Wi-Fi Protected Setup
+
+This directory includes Wi-Fi Protected Setup functions for Registrar
+(both internal in an AP and an External Registrar and
+Enrollee. Minimal UPnP and HTTP functionality is also provided for the
+functionality needed to implement Wi-Fi Protected Setup.
+
+
+\dir wpa_supplicant %wpa_supplicant
+
+%wpa_supplicant-specific code for configuration, control interface, and
+client management.
+
+*/
diff --git a/hostap/doc/doxygen.conf b/hostap/doc/doxygen.conf
new file mode 100644
index 0000000..b8c40e3
--- /dev/null
+++ b/hostap/doc/doxygen.conf
@@ -0,0 +1,1535 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+#       TAG = value [value, ...]
+# For lists items can also be appended using:
+#       TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING      = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME           = "wpa_supplicant / hostapd"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER         = 2.0
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY       = doc
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS         = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE        = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC      = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF           = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF       =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC    = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB  = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES        = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH        =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH    =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES            = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF      = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF           = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS           = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES  = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE               = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES                =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C  = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA   = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN   = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL   = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING      =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT    = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT        = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT            = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT   = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC   = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING            = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT   = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will roughly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE      = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL            = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE        = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC         = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES  = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS  = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES   = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS     = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES     = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS  = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS      = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS          = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES       = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES       = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES     = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO            = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS       = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS        = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the (brief and detailed) documentation of class members so that constructors and destructors are listed first. If set to NO (the default) the constructors will appear in the respective orders defined by SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES       = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME     = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST      = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST      = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST       = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS       =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES  = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES        = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES       = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES             = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page.
+# This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES        = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER    =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE            =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET                  = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS               = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED   = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR      = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC       = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT            = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE           = doc/doxygen.warnings
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT                  = \
+	doc \
+	hostapd \
+	wpa_supplicant \
+	src/ap \
+	src/common \
+	src/crypto \
+	src/drivers \
+	src/eap_common \
+	src/eapol_auth \
+	src/eapol_supp \
+	src/eap_peer \
+	src/eap_server \
+	src/l2_packet \
+	src/p2p \
+	src/radius \
+	src/rsn_supp \
+	src/tls \
+	src/utils \
+	src/wps
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING         = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS          = *.c *.h *.cpp *.m *.doxygen
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE              = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE                =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS       = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS       =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS        =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH           =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS       =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE      = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH             = doc
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+# If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+# You can download the filter tool from
+# http://w1.fi/tools/kerneldoc2doxygen-hostap.pl
+INPUT_FILTER           = kerneldoc2doxygen-hostap.pl
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis.
+# Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match.
+# The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS        =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES    = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER         = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES         = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS    = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION    = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code.
+# Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS              = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS       = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX     = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX    = 3
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX          =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML          = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT            = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION    = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER            =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER            =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET        =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS     = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS  = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET        = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME        = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID       = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP      = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE               =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION           =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI           = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING     =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC             = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND             = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP           = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE               =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE          =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER     = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME   =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS  =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS  =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION           =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX          = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE   = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW      = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES       = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH         = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE       = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE           = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX         = YES
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT           = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME         = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME     = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX          = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE             = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES         =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER           =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS         = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX           = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE        = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES     = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include source code with syntax highlighting in the LaTeX output. Note that which sources are shown also depends on other settings such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE      = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF           = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT             = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF            = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS         = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE    =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE    =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN           = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT             = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION          = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS              = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML           = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT             = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA             =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD                =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING     = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF   = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD       = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX          = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader.
+# This is useful
+# if you want to understand what is going on.
+# On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY         = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING   = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION        = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF     = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES        = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH           =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS  =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED             = IEEE8021X_EAPOL CONFIG_CTRL_IFACE CONFIG_P2P
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED      =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS   = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+#
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+#
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES               =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE       =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS           = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS        = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH              = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS         = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH            =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS   = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT               = YES
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME           = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE           = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH           =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH            = NO
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH    = NO
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS           = NO
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK               = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS     = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH          = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH      = NO
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH             = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH           = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY    = NO
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH        = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT       = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH               =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS           =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES    = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH    = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT        = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS      = YES
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND        = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP            = YES
diff --git a/hostap/doc/driver_wrapper.doxygen b/hostap/doc/driver_wrapper.doxygen
new file mode 100644
index 0000000..28aea50
--- /dev/null
+++ b/hostap/doc/driver_wrapper.doxygen
@@ -0,0 +1,180 @@
+/**
+\page driver_wrapper Driver wrapper implementation (driver.h, drivers.c)
+
+All hardware and driver dependent functionality is in separate C files
+that implement defined wrapper functions. Other parts
+of the %wpa_supplicant are designed to be hardware, driver, and operating
+system independent.
+
+Driver wrappers need to implement whatever calls are used in the
+target operating system/driver for controlling wireless LAN
+devices. As an example, in case of Linux, these are mostly some glue
+code and ioctl() calls and netlink message parsing for Linux Wireless
+Extensions (WE). Since features required for WPA were added only recently to
+Linux Wireless Extensions (in version 18), some driver specific code is used
+in number of driver interface implementations. These driver dependent parts
+can be replaced with generic code in driver_wext.c once the target driver
+includes full support for WE-18. After that, all Linux drivers, at
+least in theory, could use the same driver wrapper code.
+
+A driver wrapper needs to implement some or all of the functions
+defined in driver.h. These functions are registered by filling struct
+wpa_driver_ops with function pointers. Hardware independent parts of
+%wpa_supplicant will call these functions to control the driver/wlan
+card. In addition, support for driver events is required. The event
+callback function, wpa_supplicant_event(), and its parameters are
+documented in driver.h. In addition, a pointer to the 'struct
+wpa_driver_ops' needs to be registered in drivers.c file.
+
+When porting to other operating systems, the driver wrapper should be
+modified to use the native interface of the target OS. It is possible
+that some extra requirements for the interface between the driver
+wrapper and generic %wpa_supplicant code are discovered during porting
+to a new operating system. These will be addressed on case by case
+basis by modifying the interface and updating the other driver
+wrappers for this. The goal is to avoid changing this interface
+without very good reasons in order to limit the number of changes
+needed to other wrappers and hardware independent parts of
+%wpa_supplicant. When changes are required, recommended way is to
+make them in backwards compatible way that allows existing driver
+interface implementations to be compiled without any modification.
+
+Generic Linux Wireless Extensions functions are implemented in
+driver_wext.c. All Linux driver wrappers can use these when the kernel
+driver supports the generic ioctl()s and wireless events. Driver
+specific functions are implemented in separate C files, e.g.,
+driver_hostap.c. These files need to define struct wpa_driver_ops
+entry that will be used in wpa_supplicant.c when calling driver
+functions. struct wpa_driver_ops entries are registered in drivers.c.
+
+In general, it is likely to be useful to first take a look at couple
+of driver interface examples before starting on implementing a new
+one. driver_hostap.c and driver_wext.c include a complete
+implementation for Linux drivers that use %wpa_supplicant-based control
+of WPA IE and roaming. driver_ndis.c (with help from driver_ndis_.c)
+is an example of a complete interface for Windows NDIS interface for
+drivers that generate WPA IE themselves and decide when to roam. These
+example implementations include full support for all security modes.
+
+
+\section driver_req Driver requirements for WPA
+
+WPA introduces new requirements for the device driver. At least some
+of these need to be implemented in order to provide enough support for
+%wpa_supplicant.
+
+\subsection driver_tkip_ccmp TKIP/CCMP
+
+WPA requires that the pairwise cipher suite (encryption algorithm for
+unicast data packets) is TKIP or CCMP. These are new encryption
+protocols and thus, the driver will need to be modified to support
+them. Depending on the used wlan hardware, some parts of these may be
+implemented by the hardware/firmware.
+
+Specification for both TKIP and CCMP is available from IEEE (IEEE
+802.11i amendment). Fully functional, hardware independent
+implementation of both encryption protocols is also available in Host
+AP driver (driver/modules/hostap_{tkip,ccmp}.c). In addition, Linux 2.6
+kernel tree has generic implementations for WEP, TKIP, and CCMP that can
+be used in Linux drivers.
+
+The driver will also need to provide configuration mechanism to allow
+user space programs to configure TKIP and CCMP. Linux Wireless Extensions
+v18 added support for configuring these algorithms and
+individual/non-default keys. If the target kernel does not include WE-18,
+private ioctls can be used to provide similar functionality.
+
+\subsection driver_roaming Roaming control and scanning support
+
+%wpa_supplicant can optionally control AP selection based on the
+information received from Beacon and/or Probe Response frames
+(ap_scan=1 mode in configuration). This means that the driver should
+support external control for scan process. In case of Linux, use of
+new Wireless Extensions scan support (i.e., 'iwlist wlan0 scan') is
+recommended. The current driver wrapper (driver_wext.c) uses this for
+scan results.
+
+Scan results must also include the WPA information element. Support for
+this was added in WE-18. With older versions, a custom event can be used
+to provide the full WPA IE (including element id and length) as a hex
+string that is included in the scan results.
+
+%wpa_supplicant needs to also be able to request the driver to
+associate with a specific BSS. Current Host AP driver and matching
+driver_hostap.c wrapper uses following sequence for this
+request. Similar/identical mechanism should be usable also with other
+drivers.
+
+- set WPA IE for AssocReq with private ioctl
+- set SSID with SIOCSIWESSID
+- set channel/frequency with SIOCSIWFREQ
+- set BSSID with SIOCSIWAP
+  (this last ioctl will trigger the driver to request association)
+
+\subsection driver_wpa_ie WPA IE generation
+
+%wpa_supplicant selects which cipher suites and key management suites
+are used. Based on this information, it generates a WPA IE. This is
+provided to the driver interface in the associate call. This does not
+match with Windows NDIS drivers which generate the WPA IE
+themselves.
+
+%wpa_supplicant allows Windows NDIS-like behavior by providing the
+selected cipher and key management suites in the associate call. If
+the driver generates its own WPA IE and that differs from the one
+generated by %wpa_supplicant, the driver has to inform %wpa_supplicant
+about the used WPA IE (i.e., the one it used in (Re)Associate
+Request). This notification is done using EVENT_ASSOCINFO event (see
+driver.h). %wpa_supplicant is normally configured to use
+ap_scan=2 mode with drivers that control WPA IE generation and roaming.
+
+\subsection driver_events Driver events
+
+%wpa_supplicant needs to receive event callbacks when certain events
+occur (association, disassociation, Michael MIC failure, scan results
+available, PMKSA caching candidate). These events and the callback
+details are defined in driver.h (wpa_supplicant_event() function
+and enum wpa_event_type).
+
+On Linux, association and disassociation can use existing Wireless
+Extensions event that is reporting new AP with SIOCGIWAP
+event. Similarly, completion of a scan can be reported with SIOCGIWSCAN
+event.
+
+Michael MIC failure event was added in WE-18. Older versions of Wireless
+Extensions will need to use a custom event. Host AP driver used a custom
+event with following contents: MLME-MICHAELMICFAILURE.indication(keyid=#
+broadcast/unicast addr=addr2). This is the recommended format until
+the driver can be moved to use WE-18 mechanism.
+
+\subsection driver_wext_summary Summary of Linux Wireless Extensions use
+
+AP selection depends on ap_scan configuration:
+
+ap_scan=1:
+
+- %wpa_supplicant requests scan with SIOCSIWSCAN
+- driver reports scan complete with wireless event SIOCGIWSCAN
+- %wpa_supplicant reads scan results with SIOCGIWSCAN (multiple call if
+  a larget buffer is needed)
+- %wpa_supplicant decides which AP to use based on scan results
+- %wpa_supplicant configures driver to associate with the selected BSS
+  (SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWFREQ,
+   SIOCSIWESSID, SIOCSIWAP)
+
+ap_scan=2:
+
+- %wpa_supplicant configures driver to associate with an SSID
+  (SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWESSID)
+
+
+After this, both modes use similar steps:
+
+- optionally (or required for drivers that generate WPA/RSN IE for
+  (Re)AssocReq), driver reports association parameters (AssocReq IEs)
+  with wireless event IWEVASSOCREQIE (and optionally IWEVASSOCRESPIE)
+- driver reports association with wireless event SIOCGIWAP
+- %wpa_supplicant takes care of EAPOL frame handling (validating
+  information from associnfo and if needed, from scan results if WPA/RSN
+  IE from the Beacon frame is not reported through associnfo)
+*/
diff --git a/hostap/doc/eap.doxygen b/hostap/doc/eap.doxygen
new file mode 100644
index 0000000..6a24829
--- /dev/null
+++ b/hostap/doc/eap.doxygen
@@ -0,0 +1,87 @@
+/**
+\page eap_peer_module EAP peer implementation
+
+Extensible Authentication Protocol (EAP) is an authentication framework
+defined in RFC 3748. %wpa_supplicant uses a separate code module for EAP
+peer implementation. This module was designed to use only a minimal set
+of direct function calls (mainly, to debug/event functions) in order for
+it to be usable in other programs. The design of the EAP
+implementation is based loosely on RFC 4137. The state machine is
+defined in this RFC and so is the interface between the peer state
+machine and methods. As such, this RFC provides useful information for
+understanding the EAP peer implementation in %wpa_supplicant.
+
+Some of the terminology used in EAP state machine is referring to
+EAPOL (IEEE 802.1X), but there is no strict requirement on the lower
+layer being IEEE 802.1X if EAP module is built for other programs than
+%wpa_supplicant. These terms should be understood to refer to the
+lower layer as defined in RFC 4137.
+
+
+\section adding_eap_methods Adding EAP methods
+
+Each EAP method is implemented as a separate module, usually as one C
+file named eap_<name of the method>.c, e.g., eap_md5.c. All EAP
+methods use the same interface between the peer state machine and
+method specific functions. This allows new EAP methods to be added
+without modifying the core EAP state machine implementation.
+
+New EAP methods need to be registered by adding them into the build
+(Makefile) and the EAP method registration list in the
+eap_peer_register_methods() function of eap_methods.c. Each EAP
+method should use a build-time configuration option, e.g., EAP_TLS, in
+order to make it possible to select which of the methods are included
+in the build.
+
+EAP methods must implement the interface defined in eap_i.h. struct
+eap_method defines the needed function pointers that each EAP method
+must provide. In addition, the EAP type and name are registered using
+this structure. This interface is based on section 4.4 of RFC 4137.
+
+It is recommended that the EAP methods would use generic helper
+functions, eap_msg_alloc() and eap_hdr_validate() when processing
+messages. This allows code sharing and can avoid missing some of the
+needed validation steps for received packets. In addition, these
+functions make it easier to change between expanded and legacy EAP
+header, if needed.
+
+When adding an EAP method that uses a vendor specific EAP type
+(Expanded Type as defined in RFC 3748, Chapter 5.7), the new method
+must be registered by passing vendor id instead of EAP_VENDOR_IETF to
+eap_peer_method_alloc(). These methods must not try to emulate
+expanded types by registering a legacy EAP method for type 254. See
+eap_vendor_test.c for an example of an EAP method implementation that
+is implemented as an expanded type.
+
+
+\section used_eap_library Using EAP implementation as a library
+
+The Git repository has an eap_example directory that contains an
+example showing how EAP peer and server code from %wpa_supplicant and
+hostapd can be used as a library. The example program initializes both
+an EAP server and an EAP peer entities and then runs through an
+EAP-PEAP/MSCHAPv2 authentication.
+
+eap_example_peer.c shows the initialization and glue code needed to
+control the EAP peer implementation. eap_example_server.c does the
+same for EAP server. eap_example.c is an example that ties in both the
+EAP server and client parts to allow an EAP authentication to be
+shown.
+
+In this example, the EAP messages are passed between the server and
+the peer are passed by direct function calls within the same process.
+In practice, server and peer functionalities would likely reside in
+separate devices and the EAP messages would be transmitted between the
+devices based on an external protocol. For example, in IEEE 802.11
+uses IEEE 802.1X EAPOL state machines to control the transmission of
+EAP messages and WiMax supports optional PMK EAP authentication
+mechanism that transmits EAP messages as defined in IEEE 802.16e.
+
+The EAP library links in number of helper functions from src/utils and
+src/crypto directories. Most of these are suitable as-is, but it may
+be desirable to replace the debug output code in src/utils/wpa_debug.c
+by dropping this file from the library and re-implementing the
+functions there in a way that better fits in with the main
+application.
+
+*/
diff --git a/hostap/doc/eap_server.doxygen b/hostap/doc/eap_server.doxygen
new file mode 100644
index 0000000..4aca53d
--- /dev/null
+++ b/hostap/doc/eap_server.doxygen
@@ -0,0 +1,56 @@
+/**
+\page eap_server_module EAP server implementation
+
+Extensible Authentication Protocol (EAP) is an authentication framework
+defined in RFC 3748. hostapd uses a separate code module for EAP server
+implementation. This module was designed to use only a minimal set of
+direct function calls (mainly, to debug/event functions) in order for
+it to be usable in other programs. The design of the EAP
+implementation is based loosely on RFC 4137. The state machine is
+defined in this RFC and so is the interface between the server state
+machine and methods. As such, this RFC provides useful information for
+understanding the EAP server implementation in hostapd.
+
+Some of the terminology used in EAP state machine is referring to
+EAPOL (IEEE 802.1X), but there is no strict requirement on the lower
+layer being IEEE 802.1X if EAP module is built for other programs than
+%wpa_supplicant. These terms should be understood to refer to the
+lower layer as defined in RFC 4137.
+
+
+\section adding_eap_methods Adding EAP methods
+
+Each EAP method is implemented as a separate module, usually as one C
+file named eap_<name of the method>.c, e.g., eap_md5.c. All EAP
+methods use the same interface between the server state machine and
+method specific functions. This allows new EAP methods to be added
+without modifying the core EAP state machine implementation.
+
+New EAP methods need to be registered by adding them into the build
+(Makefile) and the EAP method registration list in the
+eap_server_register_methods() function of eap_methods.c. Each EAP
+method should use a build-time configuration option, e.g., EAP_TLS, in
+order to make it possible to select which of the methods are included
+in the build.
+
+EAP methods must implement the interface defined in eap_i.h. struct
+eap_method defines the needed function pointers that each EAP method
+must provide. In addition, the EAP type and name are registered using
+this structure. This interface is based on section 4.4 of RFC 4137.
+
+It is recommended that the EAP methods would use generic helper
+functions, eap_msg_alloc() and eap_hdr_validate() when processing
+messages. This allows code sharing and can avoid missing some of the
+needed validation steps for received packets. In addition, these
+functions make it easier to change between expanded and legacy EAP
+header, if needed.
+
+When adding an EAP method that uses a vendor specific EAP type
+(Expanded Type as defined in RFC 3748, Chapter 5.7), the new method
+must be registered by passing vendor id instead of EAP_VENDOR_IETF to
+eap_server_method_alloc(). These methods must not try to emulate
+expanded types by registering a legacy EAP method for type 254. See
+eap_vendor_test.c for an example of an EAP method implementation that
+is implemented as an expanded type.
+
+*/
diff --git a/hostap/doc/hostapd.fig b/hostap/doc/hostapd.fig
new file mode 100644
index 0000000..af3f0be
--- /dev/null
+++ b/hostap/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/hostap/doc/hostapd_ctrl_iface.doxygen b/hostap/doc/hostapd_ctrl_iface.doxygen
new file mode 100644
index 0000000..ae778bc
--- /dev/null
+++ b/hostap/doc/hostapd_ctrl_iface.doxygen
@@ -0,0 +1,66 @@
+/**
+\page hostapd_ctrl_iface_page hostapd control interface
+
+hostapd implements a control interface that can be used by
+external programs to control the operations of the hostapd
+daemon and to get status information and event notifications. There is
+a small C library, in a form of a single C file, wpa_ctrl.c, that
+provides helper functions to facilitate the use of the control
+interface. External programs can link this file into them and then use
+the library functions documented in wpa_ctrl.h to interact with
+%wpa_supplicant. This library can also be used with C++. hostapd_cli.c
+is an example program using this library.
+
+There are multiple mechanisms for inter-process communication. For
+example, Linux version of hostapd is using UNIX domain sockets for the
+control interface. The use of the functions defined in wpa_ctrl.h can
+be used to hide the details of the used IPC from external programs.
+
+
+\section using_ctrl_iface Using the control interface
+
+External programs, e.g., a GUI or a configuration utility, that need to
+communicate with hostapd should link in wpa_ctrl.c. This
+allows them to use helper functions to open connection to the control
+interface with wpa_ctrl_open() and to send commands with
+wpa_ctrl_request().
+
+hostapd uses the control interface for two types of communication:
+commands and unsolicited event messages. Commands are a pair of
+messages, a request from the external program and a response from
+hostapd. These can be executed using wpa_ctrl_request().
+Unsolicited event messages are sent by hostapd to the control
+interface connection without specific request from the external program
+for receiving each message. However, the external program needs to
+attach to the control interface with wpa_ctrl_attach() to receive these
+unsolicited messages.
+
+If the control interface connection is used both for commands and
+unsolicited event messages, there is potential for receiving an
+unsolicited message between the command request and response.
+wpa_ctrl_request() caller will need to supply a callback, msg_cb,
+for processing these messages. Often it is easier to open two
+control interface connections by calling wpa_ctrl_open() twice and
+then use one of the connections for commands and the other one for
+unsolicited messages. This way command request/response pairs will
+not be broken by unsolicited messages. wpa_cli is an example of how
+to use only one connection for both purposes and wpa_gui demonstrates
+how to use two separate connections.
+
+Once the control interface connection is not needed anymore, it should
+be closed by calling wpa_ctrl_close(). If the connection was used for
+unsolicited event messages, it should be first detached by calling
+wpa_ctrl_detach().
+
+
+\section ctrl_iface_cmds Control interface commands
+
+Following commands can be used with wpa_ctrl_request():
+
+\subsection ctrl_iface_PING PING
+
+This command can be used to test whether hostapd is replying
+to the control interface commands. The expected reply is \c PONG if the
+connection is open and hostapd is processing commands.
+
+*/
diff --git a/hostap/doc/mainpage.doxygen b/hostap/doc/mainpage.doxygen
new file mode 100644
index 0000000..26dc929
--- /dev/null
+++ b/hostap/doc/mainpage.doxygen
@@ -0,0 +1,95 @@
+/**
+\mainpage Developers' documentation for wpa_supplicant and hostapd
+
+The goal of this documentation and comments in the source code is to
+give enough information for other developers to understand how
+%wpa_supplicant and hostapd have been implemented, how they can be
+modified, how new drivers can be supported, and how the source code
+can be ported to other operating systems. If any information is
+missing, feel free to contact Jouni Malinen <j@w1.fi> for more
+information. Contributions as patch files are also very welcome at the
+same address. Please note that this software is licensed under the
+BSD license (the one with advertisement clause removed). All
+contributions to %wpa_supplicant and hostapd are expected to use
+compatible licensing terms.
+
+The source code and read-only access to the combined %wpa_supplicant
+and hostapd Git repository is available from the project home page at
+http://w1.fi/wpa_supplicant/. This developers' documentation is also
+available as a PDF file from
+http://w1.fi/wpa_supplicant/wpa_supplicant-devel.pdf .
+
+
+\section _wpa_supplicant wpa_supplicant
+
+%wpa_supplicant is a WPA Supplicant for Linux, BSD and Windows with
+support for WPA and WPA2 (IEEE 802.11i / RSN). Supplicant is the IEEE
+802.1X/WPA component that is used in the client stations. It
+implements key negotiation with a WPA Authenticator and it can optionally
+control roaming and IEEE 802.11 authentication/association of the wlan
+driver.
+
+The design goal for %wpa_supplicant was to use hardware, driver, and
+OS independent, portable C code for all WPA functionality. The source
+code is divided into separate C files as shown on the \ref
+code_structure "code structure page". All hardware/driver specific
+functionality is in separate files that implement a \ref
+driver_wrapper "well-defined driver API". Information about porting
+to different target boards and operating systems is available on
+the \ref porting "porting page".
+
+EAPOL (IEEE 802.1X) state machines are implemented as a separate
+module that interacts with \ref eap_peer_module "EAP peer implementation".
+In addition to programs aimed at normal production use,
+%wpa_supplicant source tree includes number of \ref testing_tools
+"testing and development tools" that make it easier to test the
+programs without having to setup a full test setup with wireless
+cards. These tools can also be used to implement automatic test
+suites.
+
+%wpa_supplicant implements a
+\ref ctrl_iface_page "control interface" that can be used by
+external programs to control the operations of the %wpa_supplicant
+daemon and to get status information and event notifications. There is
+a small C library that provides helper functions to facilitate the use of the
+control interface. This library can also be used with C++.
+
+\image html _wpa_supplicant.png "wpa_supplicant modules"
+\image latex _wpa_supplicant.eps "wpa_supplicant modules" width=15cm
+
+
+\section _hostapd hostapd
+
+hostapd includes IEEE 802.11 access point management (authentication /
+association), IEEE 802.1X/WPA/WPA2 Authenticator, EAP server, and
+RADIUS authentication server functionality. It can be build with
+various configuration option, e.g., a standalone AP management
+solution or a RADIUS authentication server with support for number of
+EAP methods.
+
+The design goal for hostapd was to use hardware, driver, and
+OS independent, portable C code for all WPA functionality. The source
+code is divided into separate C files as shown on the \ref
+code_structure "code structure page". All hardware/driver specific
+functionality is in separate files that implement a \ref
+driver_wrapper "well-defined driver API". Information about porting
+to different target boards and operating systems is available on
+the \ref porting "porting page".
+
+EAPOL (IEEE 802.1X) state machines are implemented as a separate
+module that interacts with \ref eap_server_module "EAP server implementation".
+Similarly, RADIUS authentication server is in its own separate module.
+Both IEEE 802.1X and RADIUS authentication server can use EAP server
+functionality.
+
+hostapd implements a \ref hostapd_ctrl_iface_page "control interface"
+that can be used by external programs to control the operations of the
+hostapdt daemon and to get status information and event notifications.
+There is a small C library that provides helper functions to facilitate
+the use of the control interface. This library can also be used with
+C++.
+
+\image html hostapd.png "hostapd modules"
+\image latex hostapd.eps "hostapd modules" width=15cm
+
+*/
diff --git a/hostap/doc/p2p.doxygen b/hostap/doc/p2p.doxygen
new file mode 100644
index 0000000..6b11e56
--- /dev/null
+++ b/hostap/doc/p2p.doxygen
@@ -0,0 +1,498 @@
+/**
+\page p2p Wi-Fi Direct - P2P module
+
+Wi-Fi Direct functionality is implemented any many levels in the WLAN
+stack from low-level driver operations to high-level GUI design. This
+document covers the parts that can be user by %wpa_supplicant. However,
+it should be noted that alternative designs are also possible, so some
+of the functionality may reside in other components in the system.
+
+The driver (or WLAN firmware/hardware) is expected to handle low-level
+operations related to P2P Power Management and channel scheduling. In
+addition, support for virtual network interface and data frame
+processing is done inside the driver. Configuration for these
+low-level operations is defined in the driver interface:
+src/drivers/driver.h. This defines both the commands and events used to
+interact with the driver.
+
+P2P module implements higher layer functionality for management P2P
+groups. It takes care of Device Discovery, Service Discovery, Group
+Owner Negotiation, P2P Invitation. In addition, it maintains
+information about neighboring P2P Devices. This module could be used
+in designs that do not use %wpa_supplicant and it could also reside
+inside the driver/firmware component. P2P module API is defined in
+src/p2p/p2p.h.
+
+Provisioning step of Group Formation is implemented using WPS
+(src/wps/wps.h).
+
+%wpa_supplicant includes code in interact with both the P2P module
+(wpa_supplicant/p2p_supplicant.c) and WPS
+(wpa_supplicant/wps_supplicant.c). The driver operations are passed
+through these files, i.e., core P2P or WPS code does not interact
+directly with the driver interface.
+
+
+\section p2p_arch P2P architecture
+
+P2P functionality affects many areas of the system architecture. This
+section shows couple of examples on the location of main P2P
+components. In the diagrams below, green arrows are used to show
+communication paths from the P2P module to upper layer management
+functionality and all the way to a GUI that user could use to manage
+P2P connections. Blue arrows show the path taken for lower layer
+operations. Glue code is used to bind the P2P module API to the rest
+of the system to provide access both towards upper and lower layer
+functionality.
+
+\subsection p2p_arch_mac80211 P2P architecture with Linux/mac80211/ath9k
+
+An architecture where the P2P module resides inside the
+%wpa_supplicant process is used with Linux mac80211-based drivers,
+e.g., ath9k. The following diagram shows the main components related
+to P2P functionality in such an architecture.
+
+\image html p2p_arch.png "P2P module within wpa_supplicant"
+\image latex p2p_arch.eps "P2P module within wpa_supplicant" width=15cm
+
+\subsection p2p_arch_umac P2P architecture with UMAC
+
+The following diagram shows the main components related to P2P
+functionality in an architecture where the P2P module resides inside
+the kernel IEEE 802.11 stack (UMAC in the figure).
+
+\image html p2p_arch2.png "P2P module in kernel
+\image latex p2p_arch2.eps "P2P module in kernel" width=15cm
+
+
+\section p2p_module P2P module
+
+P2P module manages discovery and group formation with a single state
+machine, i.e., only a single operation per device can be in progress
+at any given time. The following diagram describes the P2P state
+machine. For clarity, it does not include state transitions on
+operation timeouts to the IDLE state. The states that are marked with
+dotted ellipse are listed for clarity to describe the protocol
+functionality for Device Discovery phase, but are not used in the
+implementation (the SEARCH state is used to manage the initial Scan
+and the alternating Listen and Search states within Find).
+
+\image html p2p_sm.png "P2P module state machine"
+\image latex p2p_sm.eps "P2P module state machine" width=15cm
+
+\subsection p2p_module_api P2P module API
+
+P2P module API is defined in src/p2p/p2p.h. The API consists of
+functions for requesting operations and for providing event
+notifications. Similar set of callback functions are configured with
+struct p2p_config to provide callback functions that P2P module can
+use to request operations and to provide event notifications. In
+addition, there are number of generic helper functions that can be
+used for P2P related operations.
+
+These are the main functions for an upper layer management entity to
+request P2P operations:
+- p2p_find()
+- p2p_stop_find()
+- p2p_listen()
+- p2p_connect()
+- p2p_reject()
+- p2p_prov_disc_req()
+- p2p_sd_request()
+- p2p_sd_cancel_request()
+- p2p_sd_response()
+- p2p_sd_service_update()
+- p2p_invite()
+
+These are the main callback functions for P2P module to provide event
+notifications to the upper layer management entity:
+
+- p2p_config::dev_found()
+- p2p_config::go_neg_req_rx()
+- p2p_config::go_neg_completed()
+- p2p_config::sd_request()
+- p2p_config::sd_response()
+- p2p_config::prov_disc_req()
+- p2p_config::prov_disc_resp()
+- p2p_config::invitation_process()
+- p2p_config::invitation_received()
+- p2p_config::invitation_result()
+
+The P2P module uses following functions to request lower layer driver
+operations:
+
+- p2p_config::p2p_scan()
+- p2p_config::send_probe_resp()
+- p2p_config::send_action()
+- p2p_config::send_action_done()
+- p2p_config::start_listen()
+- p2p_config::stop_listen()
+
+Events from lower layer driver operations are delivered to the P2P
+module with following functions:
+
+- p2p_probe_req_rx()
+- p2p_rx_action()
+- p2p_scan_res_handler()
+- p2p_scan_res_handled()
+- p2p_send_action_cb()
+- p2p_listen_cb()
+
+In addition to the per-device state, the P2P module maintains
+per-group state for group owners. This is initialized with a call to
+p2p_group_init() when a group is created and deinitialized with
+p2p_group_deinit(). The upper layer GO management entity uses
+following functions to interact with the P2P per-group state:
+
+- p2p_group_notif_assoc()
+- p2p_group_notif_disassoc()
+- p2p_group_notif_formation_done()
+- p2p_group_match_dev_type()
+
+The P2P module will use following callback function to update P2P IE
+for GO Beacon and Probe Response frames:
+
+- p2p_group_config::ie_update()
+
+
+\section p2p_driver P2P driver operations (low-level interface)
+
+The following driver wrapper functions are needed for P2P in addition
+to the standard station/AP mode operations when the P2P module resides
+within %wpa_supplicant:
+- wpa_driver_ops::if_add()
+- wpa_driver_ops::if_remove()
+- wpa_driver_ops::alloc_interface_addr()
+- wpa_driver_ops::release_interface_addr()
+- wpa_driver_ops::remain_on_channel()
+- wpa_driver_ops::cancel_remain_on_channel()
+- wpa_driver_ops::send_action()
+- wpa_driver_ops::probe_req_report()
+- wpa_driver_ops::disable_11b_rates()
+
+The following driver wrapper events are needed for P2P in addition to
+the standard station/AP mode events when the P2P module resides within
+%wpa_supplicant:
+- wpa_event_type::EVENT_RX_ACTION
+- wpa_event_type::EVENT_REMAIN_ON_CHANNEL
+- wpa_event_type::EVENT_CANCEL_REMAIN_ON_CHANNEL
+- wpa_event_type::EVENT_RX_PROBE_REQ
+
+The following driver wrapper functions are needed for P2P in addition
+to the standard station/AP mode operations when the P2P module resides
+in the driver or firmware:
+- wpa_driver_ops::if_add()
+- wpa_driver_ops::if_remove()
+- wpa_driver_ops::alloc_interface_addr()
+- wpa_driver_ops::release_interface_addr()
+- wpa_driver_ops::disable_11b_rates()
+- wpa_driver_ops::p2p_find()
+- wpa_driver_ops::p2p_stop_find()
+- wpa_driver_ops::p2p_listen()
+- wpa_driver_ops::p2p_connect()
+- wpa_driver_ops::p2p_reject()
+- wpa_driver_ops::wps_success_cb()
+- wpa_driver_ops::p2p_group_formation_failed()
+- wpa_driver_ops::p2p_set_params()
+
+The following driver wrapper events are needed for P2P in addition to
+the standard station/AP mode events when the P2P module resides in the
+driver or firmware:
+- wpa_event_type::EVENT_P2P_DEV_FOUND
+- wpa_event_type::EVENT_P2P_GO_NEG_REQ_RX
+- wpa_event_type::EVENT_P2P_GO_NEG_COMPLETED
+
+
+\section p2p_go_neg P2P device discovery and group formation
+
+This section shows an example sequence of operations that can be used
+to implement P2P device discovery and group formation. The function
+calls are described based on the P2P module API. The exact design for
+the glue code outside the P2P module depends on the architecture used
+in the system.
+
+An upper layer management entity starts P2P device discovery by
+calling p2p_find(). The P2P module start the discovery by requesting a
+full scan to be completed by calling p2p_config::p2p_scan(). Results
+from the scan will be reported by calling p2p_scan_res_handler() and
+after last result, the scan result processing is terminated with a
+call to p2p_scan_res_handled(). The P2P peers that are found during
+the full scan are reported with the p2p_config::dev_found() callback.
+
+After the full scan, P2P module start alternating between Listen and
+Search states until the device discovery operation times out or
+terminated, e.g., with a call to p2p_stop_find().
+
+When going into the Listen state, the P2P module requests the driver
+to be configured to be awake on the listen channel with a call to
+p2p_config::start_listen(). The glue code using the P2P module may
+implement this, e.g., by using remain-on-channel low-level driver
+functionality for off-channel operation. Once the driver is available
+on the requested channel, notification of this is delivered by calling
+p2p_listen_cb(). The Probe Request frames that are received during the
+Listen period are delivered to the P2P module by calling
+p2p_config::p2p_probe_req_rx() and P2P module request a response to
+these to be sent by using p2p_config::send_probe_resp() callback
+function. If a group owner negotiation from another P2P device is
+received during the device discovery phase, that is indicated to the
+upper layer code with the p2p_config::go_neg_req_tx() callback.
+
+The Search state is implemented by using the normal scan interface,
+i.e., the P2P module will call p2p_config::p2p_scan() just like in the
+full scan phase described. Similarly, scan results from the search
+operation will be delivered to the P2P module using the
+p2p_scan_res_handler() and p2p_scan_res_handled() functions.
+
+Once the upper layer management entity has found a peer with which it
+wants to connect by forming a new group, it initiates group owner
+negotiation by calling p2p_connect(). Before doing this, the upper
+layer code is responsible for asking the user to provide the PIN to be
+used during the provisioning step with the peer or the push button
+press for PBC mode. The glue code will need to figure out the intended
+interface address for the group before group owner negotiation can be
+started.
+
+Optional Provision Discovery mechanism can be used to request the peer
+to display a PIN for the local device to enter (and vice versa). Upper
+layer management entity can request the specific mechanism by calling
+p2p_prov_disc_req(). The response to this will be reported with the
+p2p_config::prov_disc_resp() callback. If the peer device started
+Provision Discovery, an accepted request will be reported with the
+p2p_config::prov_disc_req() callback. The P2P module will
+automatically accept the Provision Discovery for display and keypad
+methods, but it is up to the upper layer manegement entity to actually
+generate the PIN and to configure it with following p2p_connect() call
+to actually authorize the connection.
+
+The P2P module will use p2p_config::send_action() callback to request
+lower layer code to transmit an Action frame during group owner
+negotiation. p2p_send_action_cb() is used to report the result of
+transmission. If the peer is not reachable, the P2P module will try to
+find it by alternating between Action frame send and Listen
+states. The Listen state for this phase will be used similarly to the
+Listen state during device discovery as described above.
+
+Once the group owner negotiation has been completed, its results will
+be reported with the p2p_config::go_neg_completed() callback. The
+upper layer management code or the glue code using the P2P module API
+is responsible for creating a new group interface and starting
+provisioning step at this point by configuring WPS Registrar or
+Enrollee functionality based on the reported group owner negotiation
+results. The upper layer code is also responsible for timing out WPS
+provisioning if it cannot be completed in 15 seconds.
+
+Successful completion of the WPS provisioning is reported with a call
+to p2p_wps_success_cb(). The P2P module will clear its group formation
+state at this point and allows new group formation attempts to be
+started. The upper layer management code is responsible for configuring
+the GO to accept associations from devices and the client to connect to
+the GO with the provisioned credentials. GO is also responsible for
+calling p2p_group_notif_formation_done() as described below.
+
+If the WPS provisioning step fails or times out, this is reported with
+a call to p2p_group_formation_failed(). The P2P module will clear its
+group formation state at this point and allows new group formation
+attempts to be started. The upper layer management code is responsible
+for removing the group interface for the failed group.
+
+
+\section p2p_sd P2P service discovery
+
+P2P protocol includes service discovery functionality that can be used
+to discover which services are provided by the peers before forming a
+group. This leverages the Generic Advertisement Service (GAS) protocol
+from IEEE 802.11u and P2P vendor-specific contents inside the Native
+GAS messages.
+
+The P2P module takes care of GAS encapsulation, fragmentation, and
+actual transmission and reception of the Action frames needed for
+service discovery. The user of the P2P module is responsible for
+providing P2P specific Service Request TLV(s) for queries and Service
+Response TLV(s) for responses.
+
+\subsection p2p_sd_query Quering services of peers
+
+Service discovery is implemented by processing pending queries as a
+part of the device discovery phase. p2p_sd_request() function is used
+to schedule service discovery queries to a specific peer or to all
+discovered peers. p2p_sd_cancel_request() can be used to cancel a
+scheduled query. Queries that are specific to a single peer will be
+removed automatically after the response has been received.
+
+After the service discovery queries have been queued, device discovery
+is started with a call to p2p_find(). The pending service discovery
+queries are then sent whenever a peer is discovered during the find
+operation. Responses to the queries will be reported with the
+p2p_config::sd_response() callback.
+
+\subsection p2p_sd_response Replying to service discovery queries from peers
+
+The received service discovery requests will be indicated with the
+p2p_config::sd_request() callback. The response to the query is sent
+by calling p2p_sd_response().
+
+\subsection p2p_sd_indicator Service update indicator
+
+P2P service discovery provides a mechanism to notify peers about
+changes in available services. This works by incrementing Service
+Update Indicator value whenever there is a change in the
+services. This value is included in all SD request and response
+frames. The value received from the peers will be included in the
+p2p_config::sd_request() and p2p_config::sd_response() callbacks. The
+value to be sent to the peers is incremented with a call to
+p2p_sd_service_update() whenever availibility of the local services
+changes.
+
+
+\section p2p_go P2P group owner
+
+This section describes how P2P module can be used for managing
+per-group information in a group owner. The function calls are
+described based on the P2P module API. The exact design for the glue
+code outside the P2P module depends on the architecture used in the
+system.
+
+When a P2P group interface is created in group owner role, per-group
+data is initialized with p2p_group_init(). This call provides a
+pointer to the per-device P2P module context and configures the
+per-group operation. The configured p2p_group_config::ie_update()
+callback is used to set the initial P2P IE for Beacon and Probe
+Response frames in the group owner. The AP mode implementation may use
+this information to add IEs into the frames.
+
+Once the group formation has been completed (or if it is skipped in
+case of manual group setup), p2p_group_notif_formation_done() is
+called. This will allow the P2P module to update the P2P IE for
+Beacon and Probe Response frames.
+
+The SME/MLME code that managements IEEE 802.11 association processing
+needs to inform P2P module whenever a P2P client associates or
+disassociates with the group. This is done by calling
+p2p_group_notif_assoc() and p2p_group_notif_disassoc(). The P2P module
+manages a list of group members and updates the P2P Group Information
+subelement in the P2P IE based on the information from the P2P
+clients. The p2p_group_config::ie_update() callback is used whenever
+the P2P IE in Probe Response frames needs to be changed.
+
+The SME/MLME code that takes care of replying to Probe Request frames
+can use p2p_group_match_dev_type() to check whether the Probe Request
+frame request a reply only from groups that include a specific device
+type in one of the clients or GO. A match will be reported if the
+Probe Request does not request a specific device type, so this
+function can be used to filter or received Probe Request frames and
+only the ones that result in non-zero return value need to be replied.
+
+When the P2P group interface for GO role is removed,
+p2p_group_deinit() is used to deinitialize the per-group P2P module
+state.
+
+
+\section p2p_ctrl_iface P2P control interface
+
+%wpa_supplicant \ref ctrl_iface_page "control interface" can be used
+to manage P2P functionality from an external program (e.g., a GUI or a
+system configuration manager). This interface can be used directly
+through the control interface backend mechanism (e.g., local domain
+sockets on Linux) or with help of wpa_cli (e.g., from a script).
+
+The following P2P-related commands are available:
+- \ref ctrl_iface_P2P_FIND P2P_FIND
+- \ref ctrl_iface_P2P_STOP_FIND P2P_STOP_FIND
+- \ref ctrl_iface_P2P_CONNECT P2P_CONNECT
+- \ref ctrl_iface_P2P_LISTEN P2P_LISTEN
+- \ref ctrl_iface_P2P_GROUP_REMOVE P2P_GROUP_REMOVE
+- \ref ctrl_iface_P2P_GROUP_ADD P2P_GROUP_ADD
+- \ref ctrl_iface_P2P_PROV_DISC P2P_PROV_DISC
+- \ref ctrl_iface_P2P_SERV_DISC_REQ P2P_SERV_DISC_REQ
+- \ref ctrl_iface_P2P_SERV_DISC_CANCEL_REQ P2P_SERV_DISC_CANCEL_REQ
+- \ref ctrl_iface_P2P_SERV_DISC_RESP P2P_SERV_DISC_RESP
+- \ref ctrl_iface_P2P_SERVICE_UPDATE P2P_SERVICE_UPDATE
+- \ref ctrl_iface_P2P_SERV_DISC_EXTERNAL P2P_SERV_DISC_EXTERNAL
+- \ref ctrl_iface_P2P_REJECT P2P_REJECT
+- \ref ctrl_iface_P2P_INVITE P2P_INVITE
+
+The following P2P-related events are used:
+- \ref ctrl_iface_event_P2P_EVENT_DEVICE_FOUND P2P-DEVICE-FOUND
+- \ref ctrl_iface_event_P2P_EVENT_GO_NEG_REQUEST P2P-GO-NEG-REQUEST
+- \ref ctrl_iface_event_P2P_EVENT_GO_NEG_SUCCESS P2P-GO-NEG-SUCCESS
+- \ref ctrl_iface_event_P2P_EVENT_GO_NEG_FAILURE P2P-GO-NEG-FAILURE
+- \ref ctrl_iface_event_P2P_EVENT_GROUP_FORMATION_SUCCESS P2P-GROUP-FORMATION-SUCCESS
+- \ref ctrl_iface_event_P2P_EVENT_GROUP_FORMATION_FAILURE P2P-GROUP-FORMATION-FAILURE
+- \ref ctrl_iface_event_P2P_EVENT_GROUP_STARTED P2P-GROUP-STARTED
+- \ref ctrl_iface_event_P2P_EVENT_GROUP_REMOVED P2P-GROUP-REMOVED
+- \ref ctrl_iface_event_P2P_EVENT_PROV_DISC_SHOW_PIN P2P-PROV-DISC-SHOW-PIN
+- \ref ctrl_iface_event_P2P_EVENT_PROV_DISC_ENTER_PIN P2P-PROV-DISC-ENTER-PIN
+- \ref ctrl_iface_event_P2P_EVENT_SERV_DISC_REQ P2P-SERV-DISC-REQ
+- \ref ctrl_iface_event_P2P_EVENT_SERV_DISC_RESP P2P-SERV-DISC-RESP
+- \ref ctrl_iface_event_P2P_EVENT_INVITATION_RECEIVED P2P-INVITATION-RECEIVED
+- \ref ctrl_iface_event_P2P_EVENT_INVITATION_RESULT P2P-INVITATION-RESULT
+
+
+\subsection p2p_wpa_gui GUI example (wpa_gui)
+
+wpa_gui has an example implementation of a GUI that could be used to
+manage P2P operations. The P2P related functionality is contained
+mostly in wpa_supplicant/wpa_gui-qt4/peers.cpp and it shows how the
+control interface commands and events can be used.
+
+
+\subsection p2p_wpa_cli wpa_cli example
+
+wpa_cli can be used to control %wpa_supplicant in interactive
+mode. The following sessions show examples of commands used for
+device discovery and group formation. The lines starting with "> " are
+commands from the user (followed by command result indication) and
+lines starting with "<2>" are event messages from %wpa_supplicant.
+
+P2P device "Wireless Client":
+
+\verbatim
+> p2p_find
+OK
+> <2>P2P-DEVICE-FOUND 02:40:61:c2:f3:b7 p2p_dev_addr=02:40:61:c2:f3:b7
+pri_dev_type=1-0050F204-1 name='Wireless Client 2' config_methods=0x18c
+dev_capab=0x1 group_capab=0x0
+<2>P2P-GO-NEG-REQUEST 02:40:61:c2:f3:b7
+<2>P2P-GO-NEG-REQUEST 02:40:61:c2:f3:b7
+> p2p_connect 02:40:61:c2:f3:b7 pbc
+OK
+<2>P2P-GO-NEG-SUCCESS 
+<2>P2P-GROUP-FORMATION-SUCCESS 
+<2>P2P-GROUP-STARTED sta0-p2p-0 client DIRECT-vM
+> interface
+Available interfaces:
+sta0-p2p-0
+sta0
+> p2p_group_remove sta0-p2p-0
+<2>P2P-GROUP-REMOVED sta0-p2p-0 client
+OK
+> term
+OK
+\endverbatim
+
+
+P2P device "Wireless Client2" (which ended up operating in GO role):
+
+\verbatim
+> p2p_find
+OK
+<2>P2P-DEVICE-FOUND 02:f0:bc:44:87:62 p2p_dev_addr=02:f0:bc:44:87:62
+pri_dev_type=1-0050F204-1 name='Wireless Client' config_methods=0x18c
+dev_capab=0x1 group_capab=0x0
+> p2p_connect 02:f0:bc:44:87:62 pbc
+OK
+<2>P2P-GO-NEG-SUCCESS 
+<2>P2P-GROUP-FORMATION-SUCCESS 
+<2>P2P-GROUP-STARTED sta1-p2p-0 GO DIRECT-vM
+> interface
+Available interfaces:
+sta1-p2p-0
+sta1
+> p2p_group_remove sta1-p2p-0
+<2>P2P-GROUP-REMOVED sta1-p2p-0 GO
+OK
+> term
+OK
+\endverbatim
+
+*/
diff --git a/hostap/doc/p2p_arch.dot b/hostap/doc/p2p_arch.dot
new file mode 100644
index 0000000..27ae0e2
--- /dev/null
+++ b/hostap/doc/p2p_arch.dot
@@ -0,0 +1,85 @@
+digraph p2p_arch {
+	ranksep=.75;
+	size = "7.5,7.5";
+
+	edge [dir=none];
+
+	subgraph cluster_wpa_gui {
+		label = "wpa_gui";
+
+		status -> Qt;
+		scan -> Qt;
+		network -> Qt;
+		Qt -> peers;
+		Qt -> WPS;
+		Qt -> gui_ctrl;
+
+		gui_ctrl [label="ctrl i/f"];
+	}
+
+	subgraph cluster_wpa_supplicant {
+		label = "wpa_supplicant"
+
+		ctrl_iface [label="ctrl i/f"];
+		authenticator [label="Authenticator"];
+		supplicant [label="Supplicant"];
+		driver_iface [label="driver i/f"];
+		p2p_module [label="P2P\nmodule"];
+		wps_registrar [label="WPS\nRegistrar"];
+		wps_enrollee [label="WPS\nEnrollee"];
+		mgmt_entity [label="Management\nentity"];
+
+		ctrl_iface -> mgmt_entity;
+		p2p_module -> mgmt_entity;
+		wps_registrar -> mgmt_entity;
+		wps_enrollee -> mgmt_entity;
+		mgmt_entity -> authenticator;
+		mgmt_entity -> supplicant;
+		mgmt_entity -> driver_iface;
+
+		{ rank = same; mgmt_entity; p2p_module; }
+	}
+
+	subgraph cluster_wpa_cli {
+		label = "wpa_cli -a"
+
+		wpa_cli_action;
+	}
+
+	subgraph cluster_dnsmasq {
+		label = "dnsmasq"
+
+		dnsmasq;
+	}
+
+	subgraph cluster_dhclient {
+		label = "dhclient"
+
+		dhclient;
+	}
+
+	subgraph cluster_kernel {
+		label = "Linux kernel"
+
+		cfg80211 -> mac80211;
+		netdev -> mac80211;
+		mac80211 -> ath9k;
+	}
+
+	gui_ctrl -> ctrl_iface;
+	wpa_cli_action -> ctrl_iface;
+
+	driver_iface -> cfg80211;
+
+	wpa_cli_action -> dnsmasq;
+	wpa_cli_action -> dhclient;
+
+	dnsmasq -> netdev;
+	dhclient -> netdev;
+
+	edge [color=blue,dir=both];
+	p2p_module -> mgmt_entity -> driver_iface -> cfg80211 -> mac80211 -> ath9k;
+
+	edge [color=green,dir=both];
+	peers -> Qt -> gui_ctrl -> ctrl_iface -> mgmt_entity -> p2p_module;
+}
diff --git a/hostap/doc/p2p_arch2.dot b/hostap/doc/p2p_arch2.dot
new file mode 100644
index 0000000..9c7b4b5
--- /dev/null
+++ b/hostap/doc/p2p_arch2.dot
@@ -0,0 +1,85 @@
+digraph p2p_arch2 {
+	ranksep=.75;
+	size = "7.5,7.5";
+
+	edge [dir=none];
+
+	subgraph cluster_wpa_gui {
+		label = "wpa_gui";
+
+		status -> Qt;
+		scan -> Qt;
+		network -> Qt;
+		Qt -> peers;
+		Qt -> WPS;
+		Qt -> gui_ctrl;
+
+		gui_ctrl [label="ctrl i/f"];
+	}
+
+	subgraph cluster_wpa_supplicant {
+		label = "wpa_supplicant"
+
+		ctrl_iface [label="ctrl i/f"];
+		authenticator [label="Authenticator"];
+		supplicant [label="Supplicant"];
+		driver_iface [label="driver i/f"];
+		wps_registrar [label="WPS\nRegistrar"];
+		wps_enrollee [label="WPS\nEnrollee"];
+		mgmt_entity [label="Management\nentity"];
+
+		ctrl_iface -> mgmt_entity;
+		wps_registrar -> mgmt_entity;
+		wps_enrollee -> mgmt_entity;
+		mgmt_entity -> authenticator;
+		mgmt_entity -> supplicant;
+		mgmt_entity -> driver_iface;
+	}
+
+	subgraph cluster_wpa_cli {
+		label = "wpa_cli -a"
+
+		wpa_cli_action;
+	}
+
+	subgraph cluster_dnsmasq {
+		label = "dnsmasq"
+
+		dnsmasq;
+	}
+
+	subgraph cluster_dhclient {
+		label = "dhclient"
+
+		dhclient;
+	}
+
+	subgraph cluster_kernel {
+		label = "Kernel"
+
+		ioctl -> umac;
+		netdev -> umac;
+		umac -> p2p_module;
+		p2p_module [label="P2P\nmodule"];
+		umac -> driver;
+
+		{ rank = same; umac; p2p_module; }
+	}
+
+	gui_ctrl -> ctrl_iface;
+	wpa_cli_action -> ctrl_iface;
+
+	driver_iface -> ioctl;
+
+	wpa_cli_action -> dnsmasq;
+	wpa_cli_action -> dhclient;
+
+	dnsmasq -> netdev;
+	dhclient -> netdev;
+
+	edge [color=blue,dir=both];
+	p2p_module -> umac -> driver;
+
+	edge [color=green,dir=both];
+	peers -> Qt -> gui_ctrl -> ctrl_iface -> mgmt_entity -> driver_iface -> ioctl -> umac -> p2p_module;
+}
diff --git a/hostap/doc/p2p_sm.dot b/hostap/doc/p2p_sm.dot
new file mode 100644
index 0000000..640caef
--- /dev/null
+++ b/hostap/doc/p2p_sm.dot
@@ -0,0 +1,62 @@
+digraph p2p {
+	ranksep=.75;
+	size = "8.5,7.5";
+
+	start -> IDLE;
+	start [label="Init",shape=none];
+
+	/* Discovery: Scan followed by Find(SEARCH,LISTEN) */
+	subgraph cluster_0 {
+		label="Discovery";
+		color=lightgrey;
+		node [color=blue];
+		/* SCAN and LISTEN currently not used in the implementation */
+		SCAN [style=dotted];
+		LISTEN [style=dotted];
+
+		SCAN -> LISTEN;
+		LISTEN -> SEARCH -> LISTEN [style=dotted];
+		SEARCH -> SD_DURING_FIND [label="Peer SD capab\nand no info", weight=100];
+		SD_DURING_FIND -> SEARCH [label="RX SD Resp\nor timeout", weight=100];
+		SEARCH -> PROV_DISC_DURING_FIND [label="Prov Disc cmd\nand no Resp", weight=100];
+		PROV_DISC_DURING_FIND -> SEARCH [label="RX Prov Disc Resp\nor timeout", weight=100];
+	}
+
+	/* Group Formation */
+	subgraph cluster_1 {
+		label="Group Formation";
+		color=lightgrey;
+		node [color=green];
+
+		CONNECT -> CONNECT_LISTEN [style=dotted,weight=100];
+		CONNECT_LISTEN -> CONNECT [style=dotted,weight=100];
+		CONNECT -> WAIT_PEER_IDLE [label="RX GO Neg Resp\n(info unavail)"];
+		WAIT_PEER_IDLE -> WAIT_PEER_CONNECT [style=dotted,weight=100];
+		WAIT_PEER_CONNECT -> WAIT_PEER_IDLE [style=dotted,weight=100];
+
+		CONNECT -> GO_NEG [label="RX GO Neg Resp\n(success)", weight=10];
+		CONNECT_LISTEN -> GO_NEG [label="RX GO Neg Req or\nTX GO Neg Resp"];
+		WAIT_PEER_CONNECT -> GO_NEG [label="RX GO Neg Req"];
+		GO_NEG -> PROVISIONING [label="TX/RX GO Neg Conf"];
+	}
+
+	PROVISIONING -> IDLE [label="WPS\nsuccess"];
+
+	/* External triggers */
+	IDLE -> SCAN [label="Find cmd",weight=20];
+	IDLE -> CONNECT [label="Connect cmd",weight=20];
+	IDLE -> LISTEN_ONLY [label="Listen cmd"];
+
+	/* Timeouts */
+/*
+	edge [color=red];
+	WAIT_PEER_IDLE -> IDLE [label="timeout", weight=0];
+	WAIT_PEER_CONNECT -> IDLE [label="timeout", weight=0];
+	CONNECT -> IDLE [label="timeout", weight=0];
+	CONNECT_LISTEN -> IDLE [label="timeout", weight=0];
+	GO_NEG -> IDLE [label="timeout", weight=0];
+	PROVISIONING -> IDLE [label="timeout", weight=0];
+	LISTEN_ONLY -> IDLE [label="timeout", weight=0];
+	SEARCH -> IDLE [label="timeout", weight=0];
+*/
+}
diff --git a/hostap/doc/porting.doxygen b/hostap/doc/porting.doxygen
new file mode 100644
index 0000000..7ea6a34
--- /dev/null
+++ b/hostap/doc/porting.doxygen
@@ -0,0 +1,208 @@
+/**
+\page porting Porting to different target boards and operating systems
+
+%wpa_supplicant was designed to be easily portable to different
+hardware (board, CPU) and software (OS, drivers) targets. It is
+already used with number of operating systems and numerous wireless
+card models and drivers. The main %wpa_supplicant repository includes
+support for Linux, FreeBSD, and Windows. In addition, the code has been
+ported to number of other operating systems like VxWorks, PalmOS,
+Windows CE, and Windows Mobile. On the hardware
+side, %wpa_supplicant is used on various systems: desktops, laptops,
+PDAs, and embedded devices with CPUs including x86, PowerPC,
+arm/xscale, and MIPS. Both big and little endian configurations are
+supported.
+
+
+\section ansi_c_extra Extra functions on top of ANSI C
+
+%wpa_supplicant is mostly using ANSI C functions that are available on
+most targets. However, couple of additional functions that are common
+on modern UNIX systems are used. Number of these are listed with
+prototypes in common.h (the \verbatim #ifdef CONFIG_ANSI_C_EXTRA \endverbatim
+block). These functions may need to be implemented or at least defined
+as macros to native functions in the target OS or C library.
+
+Many of the common ANSI C functions are used through a wrapper
+definitions in os.h to allow these to be replaced easily with a
+platform specific version in case standard C libraries are not
+available. In addition, os.h defines couple of common platform
+specific functions that are implemented in os_unix.c for UNIX like
+targets and in os_win32.c for Win32 API. If the target platform does
+not support either of these examples, a new os_*.c file may need to be
+added.
+
+Unless OS_NO_C_LIB_DEFINES is defined, the standard ANSI C and POSIX
+functions are used by defining the os_*() wrappers to use them
+directly in order to avoid extra cost in size and speed. If the target
+platform needs different versions of the functions, os.h can be
+modified to define the suitable macros or alternatively,
+OS_NO_C_LIB_DEFINES may be defined for the build and the wrapper
+functions can then be implemented in a new os_*.c wrapper file.
+
+common.h defines number of helper macros for handling integers of
+different size and byte order. Suitable version of these definitions
+may need to be added for the target platform.
+
+
+\section configuration_backend Configuration backend
+
+%wpa_supplicant implements a configuration interface that allows the
+backend to be easily replaced in order to read configuration data from
+a suitable source depending on the target platform. config.c
+implements the generic code that can be shared with all configuration
+backends. Each backend is implemented in its own config_*.c file.
+
+The included config_file.c backend uses a text file for configuration
+and config_winreg.c uses Windows registry. These files can be used as
+an example for a new configuration backend if the target platform uses
+different mechanism for configuration parameters. In addition,
+config_none.c can be used as an empty starting point for building a
+new configuration backend.
+
+
+\section driver_iface_porting Driver interface
+
+Unless the target OS and driver is already supported, most porting
+projects have to implement a driver wrapper. This may be done by
+adding a new driver interface module or modifying an existing module
+(driver_*.c) if the new target is similar to one of them. \ref
+driver_wrapper "Driver wrapper implementation" describes the details
+of the driver interface and discusses the tasks involved in porting
+this part of %wpa_supplicant.
+
+
+\section l2_packet_porting l2_packet (link layer access)
+
+%wpa_supplicant needs to have access to sending and receiving layer 2
+(link layer) packets with two Ethertypes: EAP-over-LAN (EAPOL) 0x888e
+and RSN pre-authentication 0x88c7. l2_packet.h defines the interfaces
+used for this in the core %wpa_supplicant implementation.
+
+If the target operating system supports a generic mechanism for link
+layer access, that is likely the best mechanism for providing the
+needed functionality for %wpa_supplicant. Linux packet socket is an
+example of such a generic mechanism. If this is not available, a
+separate interface may need to be implemented to the network stack or
+driver. This is usually an intermediate or protocol driver that is
+operating between the device driver and the OS network stack. If such
+a mechanism is not feasible, the interface can also be implemented
+directly in the device driver.
+
+The main %wpa_supplicant repository includes l2_packet implementations
+for Linux using packet sockets (l2_packet_linux.c), more portable
+version using libpcap/libdnet libraries (l2_packet_pcap.c; this
+supports WinPcap, too), and FreeBSD specific version of libpcap
+interface (l2_packet_freebsd.c).
+
+If the target operating system is supported by libpcap (receiving) and
+libdnet (sending), l2_packet_pcap.c can likely be used with minimal or
+no changes. If this is not a case or a proprietary interface for link
+layer is required, a new l2_packet module may need to be
+added. Alternatively, struct wpa_driver_ops::send_eapol() handler can
+be used to override the l2_packet library if the link layer access is
+integrated with the driver interface implementation.
+
+
+\section eloop_porting Event loop
+
+%wpa_supplicant uses a single process/thread model and an event loop
+to provide callbacks on events (registered timeout, received packet,
+signal). eloop.h defines the event loop interface. eloop.c is an
+implementation of such an event loop using select() and sockets. This
+is suitable for most UNIX/POSIX systems. When porting to other
+operating systems, it may be necessary to replace that implementation
+with OS specific mechanisms that provide similar functionality.
+
+
+\section ctrl_iface_porting Control interface
+
+%wpa_supplicant uses a \ref ctrl_iface_page "control interface"
+to allow external processed
+to get status information and to control the operations. Currently,
+this is implemented with socket based communication; both UNIX domain
+sockets and UDP sockets are supported. If the target OS does not
+support sockets, this interface will likely need to be modified to use
+another mechanism like message queues. The control interface is
+optional component, so it is also possible to run %wpa_supplicant
+without porting this part.
+
+The %wpa_supplicant side of the control interface is implemented in
+ctrl_iface.c. Matching client side is implemented as a control
+interface library in wpa_ctrl.c.
+
+
+\section entry_point Program entry point
+
+%wpa_supplicant defines a set of functions that can be used to
+initialize main supplicant processing. Each operating system has a
+mechanism for starting new processing or threads. This is usually a
+function with a specific set of arguments and calling convention. This
+function is responsible on initializing %wpa_supplicant.
+
+main.c includes an entry point for UNIX-like operating system, i.e.,
+main() function that uses command line arguments for setting
+parameters for %wpa_supplicant. When porting to other operating
+systems, similar OS-specific entry point implementation is needed. It
+can be implemented in a new file that is then linked with
+%wpa_supplicant instead of main.o. main.c is also a good example on
+how the initialization process should be done.
+
+The supplicant initialization functions are defined in
+wpa_supplicant_i.h. In most cases, the entry point function should
+start by fetching configuration parameters. After this, a global
+%wpa_supplicant context is initialized with a call to
+wpa_supplicant_init(). After this, existing network interfaces can be
+added with wpa_supplicant_add_iface(). wpa_supplicant_run() is then
+used to start the main event loop. Once this returns at program
+termination time, wpa_supplicant_deinit() is used to release global
+context data.
+
+wpa_supplicant_add_iface() and wpa_supplicant_remove_iface() can be
+used dynamically to add and remove interfaces based on when
+%wpa_supplicant processing is needed for them. This can be done, e.g.,
+when hotplug network adapters are being inserted and ejected. It is
+also possible to do this when a network interface is being
+enabled/disabled if it is desirable that %wpa_supplicant processing
+for the interface is fully enabled/disabled at the same time.
+
+
+\section simple_build Simple build example
+
+One way to start a porting project is to begin with a very simple
+build of %wpa_supplicant with WPA-PSK support and once that is
+building correctly, start adding features.
+
+Following command can be used to build very simple version of
+%wpa_supplicant:
+
+\verbatim
+cc -o wpa_supplicant config.c eloop.c common.c md5.c rc4.c sha1.c \
+	config_none.c l2_packet_none.c tls_none.c wpa.c preauth.c \
+	aes_wrap.c wpa_supplicant.c events.c main_none.c drivers.c
+\endverbatim
+
+The end result is not really very useful since it uses empty functions
+for configuration parsing and layer 2 packet access and does not
+include a driver interface. However, this is a good starting point
+since the build is complete in the sense that all functions are
+present and this is easy to configure to a build system by just
+including the listed C files.
+
+Once this version can be build successfully, the end result can be
+made functional by adding a proper program entry point (main*.c),
+driver interface (driver_*.c and matching CONFIG_DRIVER_* define for
+registration in drivers.c), configuration parser/writer (config_*.c),
+and layer 2 packet access implementation (l2_packet_*.c). After these
+components have been added, the end result should be a working
+WPA/WPA2-PSK enabled supplicant.
+
+After the basic functionality has been verified to work, more features
+can be added by linking in more files and defining C pre-processor
+defines. Currently, the best source of information for what options
+are available and which files needs to be included is in the Makefile
+used for building the supplicant with make. Similar configuration will
+be needed for build systems that either use different type of make
+tool or a GUI-based project configuration.
+
+*/
diff --git a/hostap/doc/testing_tools.doxygen b/hostap/doc/testing_tools.doxygen
new file mode 100644
index 0000000..01db0b6
--- /dev/null
+++ b/hostap/doc/testing_tools.doxygen
@@ -0,0 +1,363 @@
+/**
+\page testing_tools Testing and development tools
+
+[ \ref eapol_test "eapol_test" |
+\ref preauth_test "preauth_test" |
+\ref driver_test "driver_test" |
+\ref unit_tests "Unit tests" |
+\ref wpa_trace "Tracing code" ]
+
+%wpa_supplicant source tree includes number of testing and development
+tools that make it easier to test the programs without having to setup
+a full test setup with wireless cards. In addition, these tools can be
+used to implement automatic tests suites.
+
+\section eapol_test eapol_test - EAP peer and RADIUS client testing
+
+eapol_test is a program that links together the same EAP peer
+implementation that %wpa_supplicant is using and the RADIUS
+authentication client code from hostapd. In addition, it has minimal
+glue code to combine these two components in similar ways to IEEE
+802.1X/EAPOL Authenticator state machines. In other words, it
+integrates IEEE 802.1X Authenticator (normally, an access point) and
+IEEE 802.1X Supplicant (normally, a wireless client) together to
+generate a single program that can be used to test EAP methods without
+having to setup an access point and a wireless client.
+
+The main uses for eapol_test are in interoperability testing of EAP
+methods against RADIUS servers and in development testing for new EAP
+methods. It can be easily used to automate EAP testing for
+interoperability and regression since the program can be run from
+shell scripts without require additional test components apart from a
+RADIUS server. For example, the automated EAP tests described in
+eap_testing.txt are implemented with eapol_test. Similarly, eapol_test
+could be used to implement an automated regression test suite for a
+RADIUS authentication server.
+
+eapol_test uses the same build time configuration file, .config, as
+%wpa_supplicant. This file is used to select which EAP methods are
+included in eapol_test. This program is not built with the default
+Makefile target, so a separate make command needs to be used to
+compile the tool:
+
+\verbatim
+make eapol_test
+\endverbatim
+
+The resulting eapol_test binary has following command like options:
+
+\verbatim
+usage:
+eapol_test [-nWS] -c<conf> [-a<AS IP>] [-p<AS port>] [-s<AS secret>] \
+           [-r<count>] [-t<timeout>] [-C<Connect-Info>] \
+           [-M<client MAC address>]
+eapol_test scard
+eapol_test sim <PIN> <num triplets> [debug]
+
+options:
+  -c<conf> = configuration file
+  -a<AS IP> = IP address of the authentication server, default 127.0.0.1
+  -p<AS port> = UDP port of the authentication server, default 1812
+  -s<AS secret> = shared secret with the authentication server, default 'radius'
+  -r<count> = number of re-authentications
+  -W = wait for a control interface monitor before starting
+  -S = save configuration after authentiation
+  -n = no MPPE keys expected
+  -t<timeout> = sets timeout in seconds (default: 30 s)
+  -C<Connect-Info> = RADIUS Connect-Info (default: CONNECT 11Mbps 802.11b)
+  -M<client MAC address> = Set own MAC address (Calling-Station-Id,
+                           default: 02:00:00:00:00:01)
+\endverbatim
+
+
+As an example,
+\verbatim
+eapol_test -ctest.conf -a127.0.0.1 -p1812 -ssecret -r1
+\endverbatim
+tries to complete EAP authentication based on the network
+configuration from test.conf against the RADIUS server running on the
+local host. A re-authentication is triggered to test fast
+re-authentication. The configuration file uses the same format for
+network blocks as %wpa_supplicant.
+
+
+\section preauth_test preauth_test - WPA2 pre-authentication and EAP peer testing
+
+preauth_test is similar to eapol_test in the sense that in combines
+EAP peer implementation with something else, in this case, with WPA2
+pre-authentication. This tool can be used to test pre-authentication
+based on the code that %wpa_supplicant is using. As such, it tests
+both the %wpa_supplicant implementation and the functionality of an
+access point.
+
+preauth_test is built with:
+
+\verbatim
+make preauth_test
+\endverbatim
+
+and it uses following command line arguments:
+
+\verbatim
+usage: preauth_test <conf> <target MAC address> <ifname>
+\endverbatim
+
+For example,
+\verbatim
+preauth_test test.conf 02:11:22:33:44:55 eth0
+\endverbatim
+would use network configuration from test.conf to try to complete
+pre-authentication with AP using BSSID 02:11:22:33:44:55. The
+pre-authentication packets would be sent using the eth0 interface.
+
+
+\section driver_test driver_test - driver interface for testing wpa_supplicant
+
+%wpa_supplicant was designed to support number of different ways to
+communicate with a network device driver. This design uses \ref
+driver_wrapper "driver interface API" and number of driver interface
+implementations. One of these is driver_test.c, i.e., a test driver
+interface that is actually not using any drivers. Instead, it provides
+a mechanism for running %wpa_supplicant without having to have a
+device driver or wireless LAN hardware for that matter.
+
+driver_test can be used to talk directly with hostapd's driver_test
+component to create a test setup where one or more clients and access
+points can be tested within one test host and without having to have
+multiple wireless cards. This makes it easier to test the core code in
+%wpa_supplicant, and hostapd for that matter. Since driver_test uses
+the same driver API than any other driver interface implementation,
+the core code of %wpa_supplicant and hostapd can be tested with the
+same coverage as one would get when using real wireless cards. The
+only area that is not tested is the driver interface implementation
+(driver_*.c).
+
+Having the possibility to use simulated network components makes it
+much easier to do development testing while adding new features and to
+reproduce reported bugs. As such, it is often easiest to just do most
+of the development and bug fixing without using real hardware. Once
+the driver_test setup has been used to implement a new feature or fix
+a bug, the end result can be verified with wireless LAN cards. In many
+cases, this may even be unnecessary, depending on what area the
+feature/bug is relating to. Of course, changes to driver interfaces
+will still require use of real hardware.
+
+Since multiple components can be run within a single host, testing of
+complex network configuration, e.g., large number of clients
+association with an access point, becomes quite easy. All the tests
+can also be automated without having to resort to complex test setup
+using remote access to multiple computers.
+
+driver_test can be included in the %wpa_supplicant build in the same
+way as any other driver interface, i.e., by adding the following line
+into .config:
+
+\verbatim
+CONFIG_DRIVER_TEST=y
+\endverbatim
+
+When running %wpa_supplicant, the test interface is selected by using
+\a -Dtest command line argument. The interface name (\a -i argument)
+can be selected arbitrarily, i.e., it does not need to match with any
+existing network interface. The interface name is used to generate a
+MAC address, so when using multiple clients, each should use a
+different interface, e.g., \a sta1, \a sta2, and so on.
+
+%wpa_supplicant and hostapd are configured in the same way as they
+would be for normal use. Following example shows a simple test setup
+for WPA-PSK.
+
+hostapd is configured with following psk-test.conf configuration file:
+
+\verbatim
+driver=test
+
+interface=ap1
+logger_stdout=-1
+logger_stdout_level=0
+debug=2
+dump_file=/tmp/hostapd.dump
+
+test_socket=/tmp/Test/ap1
+
+ssid=jkm-test-psk
+
+wpa=1
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=TKIP
+wpa_passphrase=12345678
+\endverbatim
+
+and started with following command:
+
+\verbatim
+hostapd psk-test.conf
+\endverbatim
+
+%wpa_supplicant uses following configuration file:
+
+\verbatim
+driver_param=test_socket=/tmp/Test/ap1
+
+network={
+    ssid="jkm-test-psk"
+    key_mgmt=WPA-PSK
+    psk="12345678"
+}
+\endverbatim
+
+%wpa_supplicant can then be started with following command:
+
+\verbatim
+wpa_supplicant -Dtest -cpsk-test.conf -ista1 -ddK
+\endverbatim
+
+If run without debug information, i.e., with
+
+\verbatim
+wpa_supplicant -Dtest -cpsk-test.conf -ista1
+\endverbatim
+
+%wpa_supplicant completes authentication and prints following events:
+
+\verbatim
+Trying to associate with 02:b8:a6:62:08:5a (SSID='jkm-test-psk' freq=0 MHz)
+Associated with 02:b8:a6:62:08:5a
+WPA: Key negotiation completed with 02:b8:a6:62:08:5a [PTK=TKIP GTK=TKIP]
+CTRL-EVENT-CONNECTED - Connection to 02:b8:a6:62:08:5a completed (auth)
+\endverbatim
+
+If test setup is using multiple clients, it is possible to run
+multiple %wpa_supplicant processes. Alternatively, the support for
+multiple interfaces can be used with just one process to save some
+resources on single-CPU systems. For example, following command runs
+two clients:
+
+\verbatim
+./wpa_supplicant -Dtest -cpsk-test.conf -ista1 \
+	-N -Dtest -cpsk-test.conf -ista2
+\endverbatim
+
+This shows following event log:
+
+\verbatim
+Trying to associate with 02:b8:a6:62:08:5a (SSID='jkm-test-psk' freq=0 MHz)
+Associated with 02:b8:a6:62:08:5a
+WPA: Key negotiation completed with 02:b8:a6:62:08:5a [PTK=TKIP GTK=TKIP]
+CTRL-EVENT-CONNECTED - Connection to 02:b8:a6:62:08:5a completed (auth)
+Trying to associate with 02:b8:a6:62:08:5a (SSID='jkm-test-psk' freq=0 MHz)
+Associated with 02:b8:a6:62:08:5a
+WPA: Key negotiation completed with 02:b8:a6:62:08:5a [PTK=TKIP GTK=TKIP]
+CTRL-EVENT-CONNECTED - Connection to 02:b8:a6:62:08:5a completed (auth)
+\endverbatim
+
+hostapd shows this with following events:
+
+\verbatim
+ap1: STA 02:b5:64:63:30:63 IEEE 802.11: associated
+ap1: STA 02:b5:64:63:30:63 WPA: pairwise key handshake completed (WPA)
+ap1: STA 02:b5:64:63:30:63 WPA: group key handshake completed (WPA)
+ap1: STA 02:2a:c4:18:5b:f3 IEEE 802.11: associated
+ap1: STA 02:2a:c4:18:5b:f3 WPA: pairwise key handshake completed (WPA)
+ap1: STA 02:2a:c4:18:5b:f3 WPA: group key handshake completed (WPA)
+\endverbatim
+
+By default, driver_param is simulating a driver that uses the WPA/RSN
+IE generated by %wpa_supplicant. Driver-generated IE and AssocInfo
+events can be tested by adding \a use_associnfo=1 to the \a driver_param
+line in the configuration file. For example:
+
+\verbatim
+driver_param=test_socket=/tmp/Test/ap1 use_associnfo=1
+\endverbatim
+
+
+\section unit_tests Unit tests
+
+Number of the components (.c files) used in %wpa_supplicant define
+their own unit tests for automated validation of the basic
+functionality. Most of the tests for cryptographic algorithms are
+using standard test vectors to validate functionality. These tests can
+be useful especially when verifying port to a new CPU target.
+
+The test programs are collected in the tests subdirectory. All
+automated unit tests can be run with
+
+\verbatim
+make run-tests
+\endverbatim
+
+This make target builds and runs each test and terminates with zero
+exit code if all tests were completed successfully.
+
+
+\section wpa_trace Tracing code for developer debuggin
+
+%wpa_supplicant and hostapd can be built with tracing code that will
+track and analyze memory allocations and other resource registrations
+and certain API uses. If incorrect use is detected, a backtrace of the
+call location (and/or allocation location) is shown. This can also be
+used to detect certain categories of memory leaks and report them
+automatically when the program is terminated. The report will also
+include information about forgotten eloop events.
+
+The trace code can be enabled with CONFIG_WPA_TRACE=y build
+option. More verbose backtrace information can be generated if libbfd
+is available and the binaries are not stripped of symbol
+information. This is enabled with CONFIG_WPA_TRACE_BFD=y.
+
+For example, a memory leak (forgotten os_free() call) would show up
+like this when the program is terminated:
+
+\verbatim
+MEMLEAK[0x82d200]: len 128
+WPA_TRACE: memleak - START
+[0]: ./wpa_supplicant(os_malloc+0x59) [0x41a5e9]
+     os_malloc() ../src/utils/os_unix.c:359
+[1]: ./wpa_supplicant(os_zalloc+0x16) [0x41a676]
+     os_zalloc() ../src/utils/os_unix.c:418
+[2]: ./wpa_supplicant(wpa_supplicant_init+0x38) [0x48b508]
+     wpa_supplicant_init() wpa_supplicant.c:2315
+[3]: ./wpa_supplicant(main+0x2f3) [0x491073]
+     main() main.c:252
+WPA_TRACE: memleak - END
+MEMLEAK: total 128 bytes
+\endverbatim
+
+Another type of error that can be detected is freeing of memory area
+that was registered for some use and is still be referenced:
+
+\verbatim
+WPA_TRACE: Freeing referenced memory - START
+[2]: ./wpa_supplicant(os_free+0x5c) [0x41a53c]
+     os_free() ../src/utils/os_unix.c:411
+[3]: ./wpa_supplicant(wpa_supplicant_remove_iface+0x30) [0x48b380]
+     wpa_supplicant_remove_iface() wpa_supplicant.c:2259
+[4]: ./wpa_supplicant(wpa_supplicant_deinit+0x20) [0x48b3e0]
+     wpa_supplicant_deinit() wpa_supplicant.c:2430
+[5]: ./wpa_supplicant(main+0x357) [0x4910d7]
+     main() main.c:276
+WPA_TRACE: Freeing referenced memory - END
+WPA_TRACE: Reference registration - START
+[1]: ./wpa_supplicant [0x41c040]
+     eloop_trace_sock_add_ref() ../src/utils/eloop.c:94
+[2]: ./wpa_supplicant(wpa_supplicant_ctrl_iface_deinit+0x17) [0x473247]
+     wpa_supplicant_ctrl_iface_deinit() ctrl_iface_unix.c:436
+[3]: ./wpa_supplicant [0x48b21c]
+     wpa_supplicant_cleanup() wpa_supplicant.c:378
+     wpa_supplicant_deinit_iface() wpa_supplicant.c:2155
+[4]: ./wpa_supplicant(wpa_supplicant_remove_iface+0x30) [0x48b380]
+     wpa_supplicant_remove_iface() wpa_supplicant.c:2259
+[5]: ./wpa_supplicant(wpa_supplicant_deinit+0x20) [0x48b3e0]
+     wpa_supplicant_deinit() wpa_supplicant.c:2430
+[6]: ./wpa_supplicant(main+0x357) [0x4910d7]
+     main() main.c:276
+WPA_TRACE: Reference registration - END
+Aborted
+\endverbatim
+
+This type of error results in showing backtraces for both the location
+where the incorrect freeing happened and the location where the memory
+area was marked referenced.
+
+*/
diff --git a/hostap/doc/wpa_supplicant.fig b/hostap/doc/wpa_supplicant.fig
new file mode 100644
index 0000000..06abfb5
--- /dev/null
+++ b/hostap/doc/wpa_supplicant.fig
@@ -0,0 +1,247 @@
+#FIG 3.2
+Landscape
+Center
+Inches
+Letter  
+100.00
+Single
+-2
+1200 2
+6 1875 4050 2925 4350
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1875 4050 2925 4050 2925 4350 1875 4350 1875 4050
+4 0 0 50 -1 0 12 0.0000 4 180 735 2025 4275 l2_packet\001
+-6
+6 3450 1200 4275 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3450 1200 4275 1200 4275 1500 3450 1500 3450 1200
+4 0 0 50 -1 0 12 0.0000 4 180 585 3600 1425 wpa_cli\001
+-6
+6 4725 1200 5925 1500
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4725 1200 5925 1200 5925 1500 4725 1500 4725 1200
+4 0 0 50 -1 0 12 0.0000 4 135 1005 4800 1425 GUI frontend\001
+-6
+6 6000 2700 7200 3225
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 6000 2700 7200 2700 7200 3225 6000 3225 6000 2700
+4 0 0 50 -1 0 12 0.0000 4 135 975 6075 2925 WPA/WPA2\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 3150 state machine\001
+-6
+6 6000 4950 7200 5475
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 6000 4950 7200 4950 7200 5475 6000 5475 6000 4950
+4 0 0 50 -1 0 12 0.0000 4 135 360 6075 5175 EAP\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 5400 state machine\001
+-6
+6 8700 3000 9375 3300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8700 3000 9375 3000 9375 3300 8700 3300 8700 3000
+4 0 0 50 -1 0 12 0.0000 4 150 480 8775 3225 crypto\001
+-6
+6 4350 3900 5025 4425
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4350 3900 5025 3900 5025 4425 4350 4425 4350 3900
+4 0 0 50 -1 0 12 0.0000 4 105 420 4500 4125 event\001
+4 0 0 50 -1 0 12 0.0000 4 180 315 4500 4350 loop\001
+-6
+6 4275 2550 5100 2850
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4275 2550 5100 2550 5100 2850 4275 2850 4275 2550
+4 0 0 50 -1 0 12 0.0000 4 135 450 4425 2775 ctrl i/f\001
+-6
+6 6000 3900 7200 4425
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 6000 3900 7200 3900 7200 4425 6000 4425 6000 3900
+4 0 0 50 -1 0 12 0.0000 4 135 600 6075 4125 EAPOL\001
+4 0 0 50 -1 0 12 0.0000 4 135 1065 6075 4350 state machine\001
+-6
+6 1800 6000 7800 8100
+6 1800 6000 7800 7200
+6 1800 6900 2700 7200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1800 6900 2700 6900 2700 7200 1800 7200 1800 6900
+4 0 0 50 -1 0 12 0.0000 4 105 375 1875 7125 wext\001
+-6
+6 4725 6900 5625 7200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4725 6900 5625 6900 5625 7200 4725 7200 4725 6900
+4 0 0 50 -1 0 12 0.0000 4 135 555 4800 7125 hermes\001
+-6
+6 6675 6900 7800 7200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 6675 6900 7800 6900 7800 7200 6675 7200 6675 6900
+4 0 0 50 -1 0 12 0.0000 4 180 930 6750 7125 ndiswrapper\001
+-6
+6 5700 6900 6600 7200
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 5700 6900 6600 6900 6600 7200 5700 7200 5700 6900
+4 0 0 50 -1 0 12 0.0000 4 135 420 5775 7125 atmel\001
+-6
+6 4275 6000 5100 6300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 4275 6000 5100 6000 5100 6300 4275 6300 4275 6000
+4 0 0 50 -1 0 12 0.0000 4 135 630 4350 6225 driver i/f\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2775 6900 3675 6900 3675 7200 2775 7200 2775 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3750 6900 4650 6900 4650 7200 3750 7200 3750 6900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 4
+	 2250 6900 2250 6600 7200 6600 7200 6900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 3225 6900 3225 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4200 6900 4200 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5175 6900 5175 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6150 6900 6150 6600
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4650 6600 4650 6300
+4 0 0 50 -1 0 12 0.0000 4 180 510 2850 7125 hostap\001
+4 0 0 50 -1 0 12 0.0000 4 135 600 3825 7125 madwifi\001
+-6
+6 3525 7800 5775 8100
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 3525 7800 5775 7800 5775 8100 3525 8100 3525 7800
+4 0 0 50 -1 0 12 0.0000 4 135 2145 3600 8025 kernel network device driver\001
+-6
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 2250 7200 4200 7800
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 7200 7200 5100 7800
+-6
+6 9600 3000 10275 3300
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 9600 3000 10275 3000 10275 3300 9600 3300 9600 3000
+4 0 0 50 -1 0 12 0.0000 4 135 315 9750 3225 TLS\001
+-6
+6 8100 4425 10425 7350
+6 8175 4725 9225 5025
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8175 4725 9225 4725 9225 5025 8175 5025 8175 4725
+4 0 0 50 -1 0 12 0.0000 4 135 735 8250 4950 EAP-TLS\001
+-6
+6 9300 4725 10350 5025
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 9300 4725 10350 4725 10350 5025 9300 5025 9300 4725
+4 0 0 50 -1 0 12 0.0000 4 135 810 9375 4950 EAP-MD5\001
+-6
+6 8175 5100 9225 5400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8175 5100 9225 5100 9225 5400 8175 5400 8175 5100
+4 0 0 50 -1 0 12 0.0000 4 135 885 8250 5325 EAP-PEAP\001
+-6
+6 9300 5100 10350 5400
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 9300 5100 10350 5100 10350 5400 9300 5400 9300 5100
+4 0 0 50 -1 0 12 0.0000 4 135 840 9375 5325 EAP-TTLS\001
+-6
+6 8175 5475 9225 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8175 5475 9225 5475 9225 5775 8175 5775 8175 5475
+4 0 0 50 -1 0 12 0.0000 4 135 780 8250 5700 EAP-GTC\001
+-6
+6 9300 5475 10350 5775
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 9300 5475 10350 5475 10350 5775 9300 5775 9300 5475
+4 0 0 50 -1 0 12 0.0000 4 135 765 9375 5700 EAP-OTP\001
+-6
+6 8175 5850 9225 6150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8175 5850 9225 5850 9225 6150 8175 6150 8175 5850
+4 0 0 50 -1 0 12 0.0000 4 135 750 8250 6075 EAP-SIM\001
+-6
+6 9300 6225 10350 6525
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 9300 6225 10350 6225 10350 6525 9300 6525 9300 6225
+4 0 0 50 -1 0 12 0.0000 4 135 465 9375 6450 LEAP\001
+-6
+6 8175 6225 9225 6525
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8175 6225 9225 6225 9225 6525 8175 6525 8175 6225
+4 0 0 50 -1 0 12 0.0000 4 135 765 8250 6450 EAP-PSK\001
+-6
+6 9300 5850 10350 6150
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 9300 5850 10350 5850 10350 6150 9300 6150 9300 5850
+4 0 0 50 -1 0 12 0.0000 4 135 825 9375 6075 EAP-AKA\001
+-6
+6 8175 6975 9675 7275
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8175 6975 9675 6975 9675 7275 8175 7275 8175 6975
+4 0 0 50 -1 0 12 0.0000 4 135 1365 8250 7200 EAP-MSCHAPv2\001
+-6
+6 9300 6600 10350 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 9300 6600 10350 6600 10350 6900 9300 6900 9300 6600
+4 0 0 50 -1 0 12 0.0000 4 135 870 9375 6825 EAP-FAST\001
+-6
+6 8175 6600 9225 6900
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8175 6600 9225 6600 9225 6900 8175 6900 8175 6600
+4 0 0 50 -1 0 12 0.0000 4 135 795 8250 6825 EAP-PAX\001
+-6
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 8100 7350 10425 7350 10425 4425 8100 4425 8100 7350
+4 0 0 50 -1 0 12 0.0000 4 135 1050 8700 4650 EAP methods\001
+-6
+6 2775 5025 4050 5325
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2775 5025 4050 5025 4050 5325 2775 5325 2775 5025
+4 0 0 50 -1 0 12 0.0000 4 135 990 2925 5250 driver events\001
+-6
+6 2775 3150 4050 3450
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 2775 3150 4050 3150 4050 3450 2775 3450 2775 3150
+4 0 0 50 -1 0 12 0.0000 4 180 990 2925 3375 configuration\001
+-6
+2 1 1 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
+	 1275 4200 1875 4200
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 4500 2550 3900 1500
+2 1 1 1 0 7 50 -1 -1 4.000 0 0 -1 0 0 2
+	 4800 2550 5400 1500
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 2925 4200 4350 4200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5025 3900 6000 3000
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 5025 4200 6000 4200
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4650 6000 4650 4425
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6600 4425 6600 4950
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6600 3225 6600 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 7200 5250 8100 5250
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 9075 4425 9075 3300
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 7200 3000 8700 3150
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4650 3900 4650 2850
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 7200 4125 8700 3300
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6000 4350 5025 6000
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 6000 3150 4875 6000
+2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
+	 1500 2100 10800 2100 10800 7500 1500 7500 1500 2100
+2 1 0 1 2 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 9900 4425 9900 3300
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 1
+	 4350 3900
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4350 3900 4050 3450
+2 1 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 2
+	 4350 4425 4050 5025
+4 0 0 50 -1 0 12 0.0000 4 135 915 375 3975 EAPOL and\001
+4 0 0 50 -1 0 12 0.0000 4 180 630 375 4200 pre-auth\001
+4 0 0 50 -1 0 12 0.0000 4 180 810 375 4425 ethertypes\001
+4 0 0 50 -1 0 12 0.0000 4 135 1050 375 4650 from/to kernel\001
+4 0 0 50 -1 0 12 0.0000 4 135 1920 3675 1875 frontend control interface\001
+4 0 0 50 -1 2 14 0.0000 4 210 1440 1637 2371 wpa_supplicant\001
diff --git a/hostap/eap_example/Makefile b/hostap/eap_example/Makefile
new file mode 100644
index 0000000..0cc19bd
--- /dev/null
+++ b/hostap/eap_example/Makefile
@@ -0,0 +1,152 @@
+ALL=eap_example
+
+all: $(ALL)
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef RANLIB
+RANLIB=ranlib
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+
+CFLAGS += -I.
+CFLAGS += -I../src
+CFLAGS += -I../src/utils
+
+
+OBJS_both += ../src/utils/libutils.a
+OBJS_both += ../src/crypto/libcrypto.a
+OBJS_both += ../src/tls/libtls.a
+
+OBJS_both += ../src/eap_common/eap_peap_common.o
+OBJS_both += ../src/eap_common/eap_psk_common.o
+OBJS_both += ../src/eap_common/eap_pax_common.o
+OBJS_both += ../src/eap_common/eap_sake_common.o
+OBJS_both += ../src/eap_common/eap_gpsk_common.o
+OBJS_both += ../src/eap_common/chap.o
+
+OBJS_peer += ../src/eap_peer/eap_tls.o
+OBJS_peer += ../src/eap_peer/eap_peap.o
+OBJS_peer += ../src/eap_peer/eap_ttls.o
+OBJS_peer += ../src/eap_peer/eap_md5.o
+OBJS_peer += ../src/eap_peer/eap_mschapv2.o
+OBJS_peer += ../src/eap_peer/mschapv2.o
+OBJS_peer += ../src/eap_peer/eap_otp.o
+OBJS_peer += ../src/eap_peer/eap_gtc.o
+OBJS_peer += ../src/eap_peer/eap_leap.o
+OBJS_peer += ../src/eap_peer/eap_psk.o
+OBJS_peer += ../src/eap_peer/eap_pax.o
+OBJS_peer += ../src/eap_peer/eap_sake.o
+OBJS_peer += ../src/eap_peer/eap_gpsk.o
+OBJS_peer += ../src/eap_peer/eap.o
+OBJS_peer += ../src/eap_common/eap_common.o
+OBJS_peer += ../src/eap_peer/eap_methods.o
+OBJS_peer += ../src/eap_peer/eap_tls_common.o
+
+CFLAGS += -DEAP_TLS
+CFLAGS += -DEAP_PEAP
+CFLAGS += -DEAP_TTLS
+CFLAGS += -DEAP_MD5
+CFLAGS += -DEAP_MSCHAPv2
+CFLAGS += -DEAP_GTC
+CFLAGS += -DEAP_OTP
+CFLAGS += -DEAP_LEAP
+CFLAGS += -DEAP_PSK
+CFLAGS += -DEAP_PAX
+CFLAGS += -DEAP_SAKE
+CFLAGS += -DEAP_GPSK -DEAP_GPSK_SHA256
+
+CFLAGS += -DEAP_SERVER_IDENTITY
+CFLAGS += -DEAP_SERVER_TLS
+CFLAGS += -DEAP_SERVER_PEAP
+CFLAGS += -DEAP_SERVER_TTLS
+CFLAGS += -DEAP_SERVER_MD5
+CFLAGS += -DEAP_SERVER_MSCHAPV2
+CFLAGS += -DEAP_SERVER_GTC
+CFLAGS += -DEAP_SERVER_PSK
+CFLAGS += -DEAP_SERVER_PAX
+CFLAGS += -DEAP_SERVER_SAKE
+CFLAGS += -DEAP_SERVER_GPSK -DEAP_SERVER_GPSK_SHA256
+
+CFLAGS += -DIEEE8021X_EAPOL
+
+
+# Optional components to add EAP server support
+OBJS_server += ../src/eap_server/eap_server_tls.o
+OBJS_server += ../src/eap_server/eap_server_peap.o
+OBJS_server += ../src/eap_server/eap_server_ttls.o
+OBJS_server += ../src/eap_server/eap_server_md5.o
+OBJS_server += ../src/eap_server/eap_server_mschapv2.o
+OBJS_server += ../src/eap_server/eap_server_gtc.o
+OBJS_server += ../src/eap_server/eap_server_psk.o
+OBJS_server += ../src/eap_server/eap_server_pax.o
+OBJS_server += ../src/eap_server/eap_server_sake.o
+OBJS_server += ../src/eap_server/eap_server_gpsk.o
+OBJS_server += ../src/eap_server/eap_server.o
+OBJS_server += ../src/eap_server/eap_server_identity.o
+OBJS_server += ../src/eap_server/eap_server_methods.o
+OBJS_server += ../src/eap_server/eap_server_tls_common.o
+CFLAGS += -DEAP_SERVER
+
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+
+%.o: %.c
+	$(Q)$(CC) -c -o $@ $(CFLAGS) $<
+	@$(E) "  CC " $<
+
+
+OBJS_lib=$(OBJS_both) $(OBJS_peer) $(OBJS_server)
+
+OBJS_ex = eap_example.o eap_example_peer.o eap_example_server.o
+
+
+../src/utils/libutils.a:
+	$(MAKE) -C ../src/utils
+
+../src/crypto/libcrypto.a:
+	$(MAKE) -C ../src/crypto
+
+../src/tls/libtls.a:
+	$(MAKE) -C ../src/tls
+
+
+ifneq ($(CONFIG_SOLIB), yes)
+LIBEAP = libeap.a
+libeap.a: $(OBJS_lib)
+	$(AR) crT libeap.a $(OBJS_lib)
+	$(RANLIB) libeap.a
+
+else
+CFLAGS  += -fPIC -DPIC
+LDFLAGS += -shared
+
+LIBEAP  = libeap.so
+libeap.so: $(OBJS_lib)
+	$(LDO) $(LDFLAGS) $(OBJS_lib) -o $(LIBEAP)
+
+endif
+
+eap_example: $(OBJS_ex) $(LIBEAP)
+	$(LDO) $(LDFLAGS) -o eap_example $(OBJS_ex) -L. -leap $(LIBS)
+
+clean:
+	$(MAKE) -C ../src clean
+	rm -f core *~ *.o *.d libeap.a libeap.so $(ALL)
+
+-include $(OBJS:%.o=%.d)
diff --git a/hostap/eap_example/README b/hostap/eap_example/README
new file mode 100644
index 0000000..0c2921e
--- /dev/null
+++ b/hostap/eap_example/README
@@ -0,0 +1,42 @@
+EAP peer/server library and example program
+Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+
+This software may be distributed under the terms of the BSD license.
+See the parent directory README for more details.
+
+
+The interfaces of the EAP server/peer implementation are based on RFC
+4137 (EAP State Machines). This RFC is coordinated with the state
+machines defined in IEEE 802.1X-2004. hostapd and wpa_supplicant
+include implementation of the IEEE 802.1X EAPOL state machines and the
+interface between them and EAP. However, the EAP implementation can be
+used with other protocols, too, by providing a compatible interface
+which maps the EAPOL<->EAP variables to another protocol.
+
+This directory contains an example showing how EAP peer and server
+code from wpa_supplicant and hostapd can be used as a library. The
+example program initializes both an EAP server and an EAP peer
+entities and then runs through an EAP-PEAP/MSCHAPv2 authentication.
+
+eap_example_peer.c shows the initialization and glue code needed to
+control the EAP peer implementation. eap_example_server.c does the
+same for EAP server. eap_example.c is an example that ties in both the
+EAP server and client parts to allow an EAP authentication to be
+shown.
+
+In this example, the EAP messages are passed between the server and
+the peer are passed by direct function calls within the same process.
+In practice, server and peer functionalities would likely reside in
+separate devices and the EAP messages would be transmitted between the
+devices based on an external protocol. For example, in IEEE 802.11
+uses IEEE 802.1X EAPOL state machines to control the transmission of
+EAP messages and WiMax supports optional PMK EAP authentication
+mechanism that transmits EAP messages as defined in IEEE 802.16e.
+
+
+The EAP library links in number of helper functions from src/utils and
+src/crypto directories. Most of these are suitable as-is, but it may
+be desirable to replace the debug output code in src/utils/wpa_debug.c
+by dropping this file from the library and re-implementing the
+functions there in a way that better fits in with the main
+application.
diff --git a/hostap/eap_example/ca.pem b/hostap/eap_example/ca.pem
new file mode 100644
index 0000000..bfae1cc
--- /dev/null
+++ b/hostap/eap_example/ca.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDBzCCAnCgAwIBAgIJAIb4NS4TdLXUMA0GCSqGSIb3DQEBBQUAMGExCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQ4wDAYDVQQKEwV3MS5maTEQMA4G
+A1UEAxMHVGVzdCBDQTEbMBkGCSqGSIb3DQEJARYMdGVzdGNhQHcxLmZpMB4XDTA3
+MTIwOTAzMTQzN1oXDTE3MTIwNjAzMTQzN1owYTELMAkGA1UEBhMCVVMxEzARBgNV
+BAgTCkNhbGlmb3JuaWExDjAMBgNVBAoTBXcxLmZpMRAwDgYDVQQDEwdUZXN0IENB
+MRswGQYJKoZIhvcNAQkBFgx0ZXN0Y2FAdzEuZmkwgZ8wDQYJKoZIhvcNAQEBBQAD
+gY0AMIGJAoGBAO6GoecRclnILh9FTvqnY/yUZmeJDgC+3/PQiicpMDhAzCkWAmi+
+a1LSnqakNN/GdCy3q053TFLFEzhEHkhhRwY/zzj2vZIcFZESoUhr67CzCpcPmTGa
+AfOzsGPjaH6xYcaOR4RZMfXd/EKfAauHxj3LuCusLL5hK/FwxWhQJNJrAgMBAAGj
+gcYwgcMwHQYDVR0OBBYEFKhJuSLJ6JhcB/dRgB8j0h9mOlpKMIGTBgNVHSMEgYsw
+gYiAFKhJuSLJ6JhcB/dRgB8j0h9mOlpKoWWkYzBhMQswCQYDVQQGEwJVUzETMBEG
+A1UECBMKQ2FsaWZvcm5pYTEOMAwGA1UEChMFdzEuZmkxEDAOBgNVBAMTB1Rlc3Qg
+Q0ExGzAZBgkqhkiG9w0BCQEWDHRlc3RjYUB3MS5maYIJAIb4NS4TdLXUMAwGA1Ud
+EwQFMAMBAf8wDQYJKoZIhvcNAQEFBQADgYEAuU+5Uerq+n8WgiIsiANT3wUoGe2Y
+cnoQi2nVjUHrivgMDufH0tgh1AVfc3wVNNREdGC136qr1KBNqalQx2rKZ76xeNqW
+sQa2LIC2wE7Q7LJsltUcUjPyZHGUhBqWjKsCvlonfNB6JHkEayTEvVvyupgzTsxW
+QuuRdZ0sNv/S8VI=
+-----END CERTIFICATE-----
diff --git a/hostap/eap_example/eap_example.c b/hostap/eap_example/eap_example.c
new file mode 100644
index 0000000..68f3c00
--- /dev/null
+++ b/hostap/eap_example/eap_example.c
@@ -0,0 +1,49 @@
+/*
+ * Example application showing how EAP peer and server code from
+ * wpa_supplicant/hostapd can be used as a library. This example program
+ * initializes both an EAP server and an EAP peer entities and then runs
+ * through an EAP-PEAP/MSCHAPv2 authentication.
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+
+
+int eap_example_peer_init(void);
+void eap_example_peer_deinit(void);
+int eap_example_peer_step(void);
+
+int eap_example_server_init(void);
+void eap_example_server_deinit(void);
+int eap_example_server_step(void);
+
+
+extern int wpa_debug_level;
+
+int main(int argc, char *argv[])
+{
+	int res_s, res_p;
+
+	wpa_debug_level = 0;
+
+	if (eap_example_peer_init() < 0 ||
+	    eap_example_server_init() < 0)
+		return -1;
+
+	do {
+		printf("---[ server ]--------------------------------\n");
+		res_s = eap_example_server_step();
+		printf("---[ peer ]----------------------------------\n");
+		res_p = eap_example_peer_step();
+	} while (res_s || res_p);
+
+	eap_example_peer_deinit();
+	eap_example_server_deinit();
+
+	return 0;
+}
diff --git a/hostap/eap_example/eap_example_peer.c b/hostap/eap_example/eap_example_peer.c
new file mode 100644
index 0000000..bfeafa0
--- /dev/null
+++ b/hostap/eap_example/eap_example_peer.c
@@ -0,0 +1,372 @@
+/*
+ * Example application showing how EAP peer code from wpa_supplicant can be
+ * used as a library.
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_peer/eap.h"
+#include "eap_peer/eap_config.h"
+#include "wpabuf.h"
+
+void eap_example_server_rx(const u8 *data, size_t data_len);
+
+
+struct eap_peer_ctx {
+	Boolean eapSuccess;
+	Boolean eapRestart;
+	Boolean eapFail;
+	Boolean eapResp;
+	Boolean eapNoResp;
+	Boolean eapReq;
+	Boolean portEnabled;
+	Boolean altAccept; /* for EAP */
+	Boolean altReject; /* for EAP */
+
+	struct wpabuf *eapReqData; /* for EAP */
+
+	unsigned int idleWhile; /* for EAP state machine */
+
+	struct eap_peer_config eap_config;
+	struct eap_sm *eap;
+};
+
+
+static struct eap_peer_ctx eap_ctx;
+
+
+static struct eap_peer_config * peer_get_config(void *ctx)
+{
+	struct eap_peer_ctx *peer = ctx;
+	return &peer->eap_config;
+}
+
+
+static Boolean peer_get_bool(void *ctx, enum eapol_bool_var variable)
+{
+	struct eap_peer_ctx *peer = ctx;
+	if (peer == NULL)
+		return FALSE;
+	switch (variable) {
+	case EAPOL_eapSuccess:
+		return peer->eapSuccess;
+	case EAPOL_eapRestart:
+		return peer->eapRestart;
+	case EAPOL_eapFail:
+		return peer->eapFail;
+	case EAPOL_eapResp:
+		return peer->eapResp;
+	case EAPOL_eapNoResp:
+		return peer->eapNoResp;
+	case EAPOL_eapReq:
+		return peer->eapReq;
+	case EAPOL_portEnabled:
+		return peer->portEnabled;
+	case EAPOL_altAccept:
+		return peer->altAccept;
+	case EAPOL_altReject:
+		return peer->altReject;
+	}
+	return FALSE;
+}
+
+
+static void peer_set_bool(void *ctx, enum eapol_bool_var variable,
+			  Boolean value)
+{
+	struct eap_peer_ctx *peer = ctx;
+	if (peer == NULL)
+		return;
+	switch (variable) {
+	case EAPOL_eapSuccess:
+		peer->eapSuccess = value;
+		break;
+	case EAPOL_eapRestart:
+		peer->eapRestart = value;
+		break;
+	case EAPOL_eapFail:
+		peer->eapFail = value;
+		break;
+	case EAPOL_eapResp:
+		peer->eapResp = value;
+		break;
+	case EAPOL_eapNoResp:
+		peer->eapNoResp = value;
+		break;
+	case EAPOL_eapReq:
+		peer->eapReq = value;
+		break;
+	case EAPOL_portEnabled:
+		peer->portEnabled = value;
+		break;
+	case EAPOL_altAccept:
+		peer->altAccept = value;
+		break;
+	case EAPOL_altReject:
+		peer->altReject = value;
+		break;
+	}
+}
+
+
+static unsigned int peer_get_int(void *ctx, enum eapol_int_var variable)
+{
+	struct eap_peer_ctx *peer = ctx;
+	if (peer == NULL)
+		return 0;
+	switch (variable) {
+	case EAPOL_idleWhile:
+		return peer->idleWhile;
+	}
+	return 0;
+}
+
+
+static void peer_set_int(void *ctx, enum eapol_int_var variable,
+			 unsigned int value)
+{
+	struct eap_peer_ctx *peer = ctx;
+	if (peer == NULL)
+		return;
+	switch (variable) {
+	case EAPOL_idleWhile:
+		peer->idleWhile = value;
+		break;
+	}
+}
+
+
+static struct wpabuf * peer_get_eapReqData(void *ctx)
+{
+	struct eap_peer_ctx *peer = ctx;
+	if (peer == NULL || peer->eapReqData == NULL)
+		return NULL;
+
+	return peer->eapReqData;
+}
+
+
+static void peer_set_config_blob(void *ctx, struct wpa_config_blob *blob)
+{
+	printf("TODO: %s\n", __func__);
+}
+
+
+static const struct wpa_config_blob *
+peer_get_config_blob(void *ctx, const char *name)
+{
+	printf("TODO: %s\n", __func__);
+	return NULL;
+}
+
+
+static void peer_notify_pending(void *ctx)
+{
+	printf("TODO: %s\n", __func__);
+}
+
+
+static int eap_peer_register_methods(void)
+{
+	int ret = 0;
+
+#ifdef EAP_MD5
+	if (ret == 0)
+		ret = eap_peer_md5_register();
+#endif /* EAP_MD5 */
+
+#ifdef EAP_TLS
+	if (ret == 0)
+		ret = eap_peer_tls_register();
+#endif /* EAP_TLS */
+
+#ifdef EAP_MSCHAPv2
+	if (ret == 0)
+		ret = eap_peer_mschapv2_register();
+#endif /* EAP_MSCHAPv2 */
+
+#ifdef EAP_PEAP
+	if (ret == 0)
+		ret = eap_peer_peap_register();
+#endif /* EAP_PEAP */
+
+#ifdef EAP_TTLS
+	if (ret == 0)
+		ret = eap_peer_ttls_register();
+#endif /* EAP_TTLS */
+
+#ifdef EAP_GTC
+	if (ret == 0)
+		ret = eap_peer_gtc_register();
+#endif /* EAP_GTC */
+
+#ifdef EAP_OTP
+	if (ret == 0)
+		ret = eap_peer_otp_register();
+#endif /* EAP_OTP */
+
+#ifdef EAP_SIM
+	if (ret == 0)
+		ret = eap_peer_sim_register();
+#endif /* EAP_SIM */
+
+#ifdef EAP_LEAP
+	if (ret == 0)
+		ret = eap_peer_leap_register();
+#endif /* EAP_LEAP */
+
+#ifdef EAP_PSK
+	if (ret == 0)
+		ret = eap_peer_psk_register();
+#endif /* EAP_PSK */
+
+#ifdef EAP_AKA
+	if (ret == 0)
+		ret = eap_peer_aka_register();
+#endif /* EAP_AKA */
+
+#ifdef EAP_AKA_PRIME
+	if (ret == 0)
+		ret = eap_peer_aka_prime_register();
+#endif /* EAP_AKA_PRIME */
+
+#ifdef EAP_FAST
+	if (ret == 0)
+		ret = eap_peer_fast_register();
+#endif /* EAP_FAST */
+
+#ifdef EAP_PAX
+	if (ret == 0)
+		ret = eap_peer_pax_register();
+#endif /* EAP_PAX */
+
+#ifdef EAP_SAKE
+	if (ret == 0)
+		ret = eap_peer_sake_register();
+#endif /* EAP_SAKE */
+
+#ifdef EAP_GPSK
+	if (ret == 0)
+		ret = eap_peer_gpsk_register();
+#endif /* EAP_GPSK */
+
+#ifdef EAP_WSC
+	if (ret == 0)
+		ret = eap_peer_wsc_register();
+#endif /* EAP_WSC */
+
+#ifdef EAP_IKEV2
+	if (ret == 0)
+		ret = eap_peer_ikev2_register();
+#endif /* EAP_IKEV2 */
+
+#ifdef EAP_VENDOR_TEST
+	if (ret == 0)
+		ret = eap_peer_vendor_test_register();
+#endif /* EAP_VENDOR_TEST */
+
+#ifdef EAP_TNC
+	if (ret == 0)
+		ret = eap_peer_tnc_register();
+#endif /* EAP_TNC */
+
+	return ret;
+}
+
+
+static struct eapol_callbacks eap_cb;
+static struct eap_config eap_conf;
+
+int eap_example_peer_init(void)
+{
+	if (eap_peer_register_methods() < 0)
+		return -1;
+
+	os_memset(&eap_ctx, 0, sizeof(eap_ctx));
+
+	eap_ctx.eap_config.identity = (u8 *) os_strdup("user");
+	eap_ctx.eap_config.identity_len = 4;
+	eap_ctx.eap_config.password = (u8 *) os_strdup("password");
+	eap_ctx.eap_config.password_len = 8;
+	eap_ctx.eap_config.ca_cert = (u8 *) os_strdup("ca.pem");
+	eap_ctx.eap_config.fragment_size = 1398;
+
+	os_memset(&eap_cb, 0, sizeof(eap_cb));
+	eap_cb.get_config = peer_get_config;
+	eap_cb.get_bool = peer_get_bool;
+	eap_cb.set_bool = peer_set_bool;
+	eap_cb.get_int = peer_get_int;
+	eap_cb.set_int = peer_set_int;
+	eap_cb.get_eapReqData = peer_get_eapReqData;
+	eap_cb.set_config_blob = peer_set_config_blob;
+	eap_cb.get_config_blob = peer_get_config_blob;
+	eap_cb.notify_pending = peer_notify_pending;
+
+	os_memset(&eap_conf, 0, sizeof(eap_conf));
+	eap_ctx.eap = eap_peer_sm_init(&eap_ctx, &eap_cb, &eap_ctx, &eap_conf);
+	if (eap_ctx.eap == NULL)
+		return -1;
+
+	/* Enable "port" to allow authentication */
+	eap_ctx.portEnabled = TRUE;
+
+	return 0;
+}
+
+
+void eap_example_peer_deinit(void)
+{
+	eap_peer_sm_deinit(eap_ctx.eap);
+	eap_peer_unregister_methods();
+	wpabuf_free(eap_ctx.eapReqData);
+	os_free(eap_ctx.eap_config.identity);
+	os_free(eap_ctx.eap_config.password);
+	os_free(eap_ctx.eap_config.ca_cert);
+}
+
+
+int eap_example_peer_step(void)
+{
+	int res;
+	res = eap_peer_sm_step(eap_ctx.eap);
+
+	if (eap_ctx.eapResp) {
+		struct wpabuf *resp;
+		printf("==> Response\n");
+		eap_ctx.eapResp = FALSE;
+		resp = eap_get_eapRespData(eap_ctx.eap);
+		if (resp) {
+			/* Send EAP response to the server */
+			eap_example_server_rx(wpabuf_head(resp),
+					      wpabuf_len(resp));
+			wpabuf_free(resp);
+		}
+	}
+
+	if (eap_ctx.eapSuccess) {
+		res = 0;
+		if (eap_key_available(eap_ctx.eap)) {
+			const u8 *key;
+			size_t key_len;
+			key = eap_get_eapKeyData(eap_ctx.eap, &key_len);
+			wpa_hexdump(MSG_DEBUG, "EAP keying material",
+				    key, key_len);
+		}
+	}
+
+	return res;
+}
+
+
+void eap_example_peer_rx(const u8 *data, size_t data_len)
+{
+	/* Make received EAP message available to the EAP library */
+	eap_ctx.eapReq = TRUE;
+	wpabuf_free(eap_ctx.eapReqData);
+	eap_ctx.eapReqData = wpabuf_alloc_copy(data, data_len);
+}
diff --git a/hostap/eap_example/eap_example_server.c b/hostap/eap_example/eap_example_server.c
new file mode 100644
index 0000000..7097bca
--- /dev/null
+++ b/hostap/eap_example/eap_example_server.c
@@ -0,0 +1,295 @@
+/*
+ * Example application showing how EAP server code from hostapd can be used as
+ * a library.
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/tls.h"
+#include "eap_server/eap.h"
+#include "wpabuf.h"
+
+void eap_example_peer_rx(const u8 *data, size_t data_len);
+
+
+struct eap_server_ctx {
+	struct eap_eapol_interface *eap_if;
+	struct eap_sm *eap;
+	void *tls_ctx;
+};
+
+static struct eap_server_ctx eap_ctx;
+
+
+static int server_get_eap_user(void *ctx, const u8 *identity,
+			       size_t identity_len, int phase2,
+			       struct eap_user *user)
+{
+	os_memset(user, 0, sizeof(*user));
+
+	if (!phase2) {
+		/* Only allow EAP-PEAP as the Phase 1 method */
+		user->methods[0].vendor = EAP_VENDOR_IETF;
+		user->methods[0].method = EAP_TYPE_PEAP;
+		return 0;
+	}
+
+	if (identity_len != 4 || identity == NULL ||
+	    os_memcmp(identity, "user", 4) != 0) {
+		printf("Unknown user\n");
+		return -1;
+	}
+
+	/* Only allow EAP-MSCHAPv2 as the Phase 2 method */
+	user->methods[0].vendor = EAP_VENDOR_IETF;
+	user->methods[0].method = EAP_TYPE_MSCHAPV2;
+	user->password = (u8 *) os_strdup("password");
+	user->password_len = 8;
+
+	return 0;
+}
+
+
+static const char * server_get_eap_req_id_text(void *ctx, size_t *len)
+{
+	*len = 0;
+	return NULL;
+}
+
+
+static struct eapol_callbacks eap_cb;
+static struct eap_config eap_conf;
+
+static int eap_example_server_init_tls(void)
+{
+	struct tls_config tconf;
+	struct tls_connection_params tparams;
+
+	os_memset(&tconf, 0, sizeof(tconf));
+	eap_ctx.tls_ctx = tls_init(&tconf);
+	if (eap_ctx.tls_ctx == NULL)
+		return -1;
+
+	os_memset(&tparams, 0, sizeof(tparams));
+	tparams.ca_cert = "ca.pem";
+	tparams.client_cert = "server.pem";
+	/* tparams.private_key = "server.key"; */
+	tparams.private_key = "server-key.pem";
+	/* tparams.private_key_passwd = "whatever"; */
+
+	if (tls_global_set_params(eap_ctx.tls_ctx, &tparams)) {
+		printf("Failed to set TLS parameters\n");
+		return -1;
+	}
+
+	if (tls_global_set_verify(eap_ctx.tls_ctx, 0)) {
+		printf("Failed to set check_crl\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int eap_server_register_methods(void)
+{
+	int ret = 0;
+
+#ifdef EAP_SERVER_IDENTITY
+	if (ret == 0)
+		ret = eap_server_identity_register();
+#endif /* EAP_SERVER_IDENTITY */
+
+#ifdef EAP_SERVER_MD5
+	if (ret == 0)
+		ret = eap_server_md5_register();
+#endif /* EAP_SERVER_MD5 */
+
+#ifdef EAP_SERVER_TLS
+	if (ret == 0)
+		ret = eap_server_tls_register();
+#endif /* EAP_SERVER_TLS */
+
+#ifdef EAP_SERVER_MSCHAPV2
+	if (ret == 0)
+		ret = eap_server_mschapv2_register();
+#endif /* EAP_SERVER_MSCHAPV2 */
+
+#ifdef EAP_SERVER_PEAP
+	if (ret == 0)
+		ret = eap_server_peap_register();
+#endif /* EAP_SERVER_PEAP */
+
+#ifdef EAP_SERVER_TLV
+	if (ret == 0)
+		ret = eap_server_tlv_register();
+#endif /* EAP_SERVER_TLV */
+
+#ifdef EAP_SERVER_GTC
+	if (ret == 0)
+		ret = eap_server_gtc_register();
+#endif /* EAP_SERVER_GTC */
+
+#ifdef EAP_SERVER_TTLS
+	if (ret == 0)
+		ret = eap_server_ttls_register();
+#endif /* EAP_SERVER_TTLS */
+
+#ifdef EAP_SERVER_SIM
+	if (ret == 0)
+		ret = eap_server_sim_register();
+#endif /* EAP_SERVER_SIM */
+
+#ifdef EAP_SERVER_AKA
+	if (ret == 0)
+		ret = eap_server_aka_register();
+#endif /* EAP_SERVER_AKA */
+
+#ifdef EAP_SERVER_AKA_PRIME
+	if (ret == 0)
+		ret = eap_server_aka_prime_register();
+#endif /* EAP_SERVER_AKA_PRIME */
+
+#ifdef EAP_SERVER_PAX
+	if (ret == 0)
+		ret = eap_server_pax_register();
+#endif /* EAP_SERVER_PAX */
+
+#ifdef EAP_SERVER_PSK
+	if (ret == 0)
+		ret = eap_server_psk_register();
+#endif /* EAP_SERVER_PSK */
+
+#ifdef EAP_SERVER_SAKE
+	if (ret == 0)
+		ret = eap_server_sake_register();
+#endif /* EAP_SERVER_SAKE */
+
+#ifdef EAP_SERVER_GPSK
+	if (ret == 0)
+		ret = eap_server_gpsk_register();
+#endif /* EAP_SERVER_GPSK */
+
+#ifdef EAP_SERVER_VENDOR_TEST
+	if (ret == 0)
+		ret = eap_server_vendor_test_register();
+#endif /* EAP_SERVER_VENDOR_TEST */
+
+#ifdef EAP_SERVER_FAST
+	if (ret == 0)
+		ret = eap_server_fast_register();
+#endif /* EAP_SERVER_FAST */
+
+#ifdef EAP_SERVER_WSC
+	if (ret == 0)
+		ret = eap_server_wsc_register();
+#endif /* EAP_SERVER_WSC */
+
+#ifdef EAP_SERVER_IKEV2
+	if (ret == 0)
+		ret = eap_server_ikev2_register();
+#endif /* EAP_SERVER_IKEV2 */
+
+#ifdef EAP_SERVER_TNC
+	if (ret == 0)
+		ret = eap_server_tnc_register();
+#endif /* EAP_SERVER_TNC */
+
+	return ret;
+}
+
+
+int eap_example_server_init(void)
+{
+	if (eap_server_register_methods() < 0)
+		return -1;
+
+	os_memset(&eap_ctx, 0, sizeof(eap_ctx));
+
+	if (eap_example_server_init_tls() < 0)
+		return -1;
+
+	os_memset(&eap_cb, 0, sizeof(eap_cb));
+	eap_cb.get_eap_user = server_get_eap_user;
+	eap_cb.get_eap_req_id_text = server_get_eap_req_id_text;
+
+	os_memset(&eap_conf, 0, sizeof(eap_conf));
+	eap_conf.eap_server = 1;
+	eap_conf.ssl_ctx = eap_ctx.tls_ctx;
+
+	eap_ctx.eap = eap_server_sm_init(&eap_ctx, &eap_cb, &eap_conf);
+	if (eap_ctx.eap == NULL)
+		return -1;
+
+	eap_ctx.eap_if = eap_get_interface(eap_ctx.eap);
+
+	/* Enable "port" and request EAP to start authentication. */
+	eap_ctx.eap_if->portEnabled = TRUE;
+	eap_ctx.eap_if->eapRestart = TRUE;
+
+	return 0;
+}
+
+
+void eap_example_server_deinit(void)
+{
+	eap_server_sm_deinit(eap_ctx.eap);
+	eap_server_unregister_methods();
+	tls_deinit(eap_ctx.tls_ctx);
+}
+
+
+int eap_example_server_step(void)
+{
+	int res, process = 0;
+
+	res = eap_server_sm_step(eap_ctx.eap);
+
+	if (eap_ctx.eap_if->eapReq) {
+		printf("==> Request\n");
+		process = 1;
+		eap_ctx.eap_if->eapReq = 0;
+	}
+
+	if (eap_ctx.eap_if->eapSuccess) {
+		printf("==> Success\n");
+		process = 1;
+		res = 0;
+		eap_ctx.eap_if->eapSuccess = 0;
+
+		if (eap_ctx.eap_if->eapKeyAvailable) {
+			wpa_hexdump(MSG_DEBUG, "EAP keying material",
+				    eap_ctx.eap_if->eapKeyData,
+				    eap_ctx.eap_if->eapKeyDataLen);
+		}
+	}
+
+	if (eap_ctx.eap_if->eapFail) {
+		printf("==> Fail\n");
+		process = 1;
+		eap_ctx.eap_if->eapFail = 0;
+	}
+
+	if (process && eap_ctx.eap_if->eapReqData) {
+		/* Send EAP response to the server */
+		eap_example_peer_rx(wpabuf_head(eap_ctx.eap_if->eapReqData),
+				    wpabuf_len(eap_ctx.eap_if->eapReqData));
+	}
+
+	return res;
+}
+
+
+void eap_example_server_rx(const u8 *data, size_t data_len)
+{
+	/* Make received EAP message available to the EAP library */
+	wpabuf_free(eap_ctx.eap_if->eapRespData);
+	eap_ctx.eap_if->eapRespData = wpabuf_alloc_copy(data, data_len);
+	if (eap_ctx.eap_if->eapRespData)
+		eap_ctx.eap_if->eapResp = TRUE;
+}
diff --git a/hostap/eap_example/server-key.pem b/hostap/eap_example/server-key.pem
new file mode 100644
index 0000000..d98c4dd
--- /dev/null
+++ b/hostap/eap_example/server-key.pem
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXAIBAAKBgQDToYuDPmjEWu+/Aj0RVWTSb07sX6dAkPnrTaUjZAG5AhjRqJWz
+zD50kFmVKi+R7GgS5tlGzLUtokdwjuSUAmz8tMXwIwmVeS0HluFDVSi94XbVRczE
++nyoDigg1RGyy1mc3t5RG84bvNatq98OceJag4ngh8L8I4k1qTLRMlyBJwIDAQAB
+AoGAP+v0asDn/h8FeSkg7uJfIJyUNxsxNnRTuHnsXkMvrgTvICyOgw828hhDpqVm
+VuoUCVmG2Tatpsn0UBApBHezGRh0u1syWoGM8fiDvZmoYmhFe5FxKnftg3KNXhDf
+Agk4OxwNNPBXpQFQP+GNxh6Qs7FEkYHLRh/J7vC0+wp3UWECQQDzcTQZXqYPow5M
+uinL819HKfh1n2257w1HGvw8cMCiYbKRyR74Q18TJcxuEyEwnPrg5ZGpMPDKiIOU
+SlgAMLBXAkEA3oxBpRue1Kqb2+Fq6lhZ7PQiZC5F69upIb/wxbk8ByImEl1pUKFW
+rV+YoKujbnj77PmMq1+R0dFkT1ai3zDzsQJBAMa3CUgMMpFhEDMhYyzQJF36rI2W
+7gJwV+5K4MqVXyktho3qFhWhKOKAYDcZ9mWwPjmGKzhocqVgecd6SAsfs1ECQA7r
+xHL3eRy1G6IQaQSxS8YxUCT7XUDFB3/1yITZOIcZ6QeOL8NyLceOA0OyflCn1+w5
+hw7uZ25z5Y/UNTNVquECQEgto3zPneEW06qkEnRz9EbLtWR3nRBS/QGrjOFNUuln
+pNhVUH4RB17Kk35xveUTz4U/Iw/WRfGNjFLHrtR/5xk=
+-----END RSA PRIVATE KEY-----
diff --git a/hostap/eap_example/server.key b/hostap/eap_example/server.key
new file mode 100644
index 0000000..4f32591
--- /dev/null
+++ b/hostap/eap_example/server.key
Binary files differ
diff --git a/hostap/eap_example/server.pem b/hostap/eap_example/server.pem
new file mode 100644
index 0000000..02f6e7b
--- /dev/null
+++ b/hostap/eap_example/server.pem
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC0zCCAjygAwIBAgIJAIb4NS4TdLXVMA0GCSqGSIb3DQEBBQUAMGExCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMQ4wDAYDVQQKEwV3MS5maTEQMA4G
+A1UEAxMHVGVzdCBDQTEbMBkGCSqGSIb3DQEJARYMdGVzdGNhQHcxLmZpMB4XDTA3
+MTIwOTAzMTUwOFoXDTE3MTIwNjAzMTUwOFoweTELMAkGA1UEBhMCVVMxEzARBgNV
+BAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDVNhbiBGcmFuY2lzY28xDjAMBgNVBAoT
+BXcxLmZpMRAwDgYDVQQDEwdUZXN0IEFTMRswGQYJKoZIhvcNAQkBFgx0ZXN0YXNA
+dzEuZmkwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANOhi4M+aMRa778CPRFV
+ZNJvTuxfp0CQ+etNpSNkAbkCGNGolbPMPnSQWZUqL5HsaBLm2UbMtS2iR3CO5JQC
+bPy0xfAjCZV5LQeW4UNVKL3hdtVFzMT6fKgOKCDVEbLLWZze3lEbzhu81q2r3w5x
+4lqDieCHwvwjiTWpMtEyXIEnAgMBAAGjezB5MAkGA1UdEwQCMAAwLAYJYIZIAYb4
+QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBRb
+xGTC3mPimgyGb5vYLLV5wyc9ITAfBgNVHSMEGDAWgBSoSbkiyeiYXAf3UYAfI9If
+ZjpaSjANBgkqhkiG9w0BAQUFAAOBgQA9wVGtroz/rsx1EeALJejW01SAr4kpTxoS
+WP6zuWFb+J/lJd7DeVM6/QBYAwZb0fB6nwSpJJCj6XDRZtN/yLeaTd/rCZrfom4Z
+8gbkWMTXDn2Cea2VnCe5W0gK+4dIj5DD5CpPvgt4lYqlwN0WAih6twd7Q4x/tiiJ
+ejNQzlTHOg==
+-----END CERTIFICATE-----
diff --git a/hostap/hostapd/Android.mk b/hostap/hostapd/Android.mk
new file mode 100644
index 0000000..297a903
--- /dev/null
+++ b/hostap/hostapd/Android.mk
@@ -0,0 +1,842 @@
+# Copyright (C) 2008 The Android Open Source Project
+#
+# This software may be distributed under the terms of the BSD license.
+# See README for more details.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+WPA_BUILD_HOSTAPD := false
+ifneq ($(BOARD_HOSTAPD_DRIVER),)
+  WPA_BUILD_HOSTAPD := true
+  CONFIG_DRIVER_$(BOARD_HOSTAPD_DRIVER) := y
+endif
+
+ifeq ($(WPA_BUILD_HOSTAPD),true)
+
+include $(LOCAL_PATH)/android.config
+
+# To ignore possible wrong network configurations
+L_CFLAGS = -DWPA_IGNORE_CONFIG_ERRORS
+
+L_CFLAGS += -DVERSION_STR_POSTFIX=\"-$(PLATFORM_VERSION)\"
+
+# Set Android log name
+L_CFLAGS += -DANDROID_LOG_NAME=\"hostapd\"
+
+# To force sizeof(enum) = 4
+ifeq ($(TARGET_ARCH),arm)
+L_CFLAGS += -mabi=aapcs-linux
+endif
+
+# To allow non-ASCII characters in SSID
+L_CFLAGS += -DWPA_UNICODE_SSID
+
+# OpenSSL is configured without engines on Android
+L_CFLAGS += -DOPENSSL_NO_ENGINE
+
+INCLUDES = $(LOCAL_PATH)
+INCLUDES += $(LOCAL_PATH)/src
+INCLUDES += $(LOCAL_PATH)/src/utils
+INCLUDES += external/openssl/include
+INCLUDES += frameworks/base/cmds/keystore
+ifdef CONFIG_DRIVER_NL80211
+INCLUDES += external/libnl-headers
+endif
+
+
+ifndef CONFIG_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+L_CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+L_CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32
+endif
+
+OBJS = main.c
+OBJS += config_file.c
+
+OBJS += src/ap/hostapd.c
+OBJS += src/ap/wpa_auth_glue.c
+OBJS += src/ap/drv_callbacks.c
+OBJS += src/ap/ap_drv_ops.c
+OBJS += src/ap/utils.c
+OBJS += src/ap/authsrv.c
+OBJS += src/ap/ieee802_1x.c
+OBJS += src/ap/ap_config.c
+OBJS += src/ap/eap_user_db.c
+OBJS += src/ap/ieee802_11_auth.c
+OBJS += src/ap/sta_info.c
+OBJS += src/ap/wpa_auth.c
+OBJS += src/ap/tkip_countermeasures.c
+OBJS += src/ap/ap_mlme.c
+OBJS += src/ap/wpa_auth_ie.c
+OBJS += src/ap/preauth_auth.c
+OBJS += src/ap/pmksa_cache_auth.c
+OBJS += src/ap/ieee802_11_shared.c
+OBJS += src/ap/beacon.c
+OBJS_d =
+OBJS_p =
+LIBS =
+LIBS_c =
+HOBJS =
+LIBS_h =
+
+NEED_RC4=y
+NEED_AES=y
+NEED_MD5=y
+NEED_SHA1=y
+
+OBJS += src/drivers/drivers.c
+L_CFLAGS += -DHOSTAPD
+
+ifdef CONFIG_WPA_TRACE
+L_CFLAGS += -DWPA_TRACE
+OBJS += src/utils/trace.c
+HOBJS += src/utils/trace.c
+LDFLAGS += -rdynamic
+L_CFLAGS += -funwind-tables
+ifdef CONFIG_WPA_TRACE_BFD
+L_CFLAGS += -DWPA_TRACE_BFD
+LIBS += -lbfd
+LIBS_c += -lbfd
+LIBS_h += -lbfd
+endif
+endif
+
+OBJS += src/utils/eloop.c
+OBJS += src/utils/common.c
+OBJS += src/utils/wpa_debug.c
+OBJS += src/utils/wpabuf.c
+OBJS += src/utils/os_$(CONFIG_OS).c
+OBJS += src/utils/ip_addr.c
+
+OBJS += src/common/ieee802_11_common.c
+OBJS += src/common/wpa_common.c
+
+OBJS += src/eapol_auth/eapol_auth_sm.c
+
+
+ifndef CONFIG_NO_DUMP_STATE
+# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to
+# a file (undefine it, if you want to save in binary size)
+L_CFLAGS += -DHOSTAPD_DUMP_STATE
+OBJS += dump_state.c
+OBJS += src/eapol_auth/eapol_auth_dump.c
+endif
+
+ifdef CONFIG_NO_RADIUS
+L_CFLAGS += -DCONFIG_NO_RADIUS
+CONFIG_NO_ACCOUNTING=y
+else
+OBJS += src/radius/radius.c
+OBJS += src/radius/radius_client.c
+endif
+
+ifdef CONFIG_NO_ACCOUNTING
+L_CFLAGS += -DCONFIG_NO_ACCOUNTING
+else
+OBJS += src/ap/accounting.c
+endif
+
+ifdef CONFIG_NO_VLAN
+L_CFLAGS += -DCONFIG_NO_VLAN
+else
+OBJS += src/ap/vlan_init.c
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+OBJS += src/ap/vlan_util.c
+endif
+L_CFLAGS += -DCONFIG_VLAN_NETLINK
+endif
+endif
+
+ifdef CONFIG_NO_CTRL_IFACE
+L_CFLAGS += -DCONFIG_NO_CTRL_IFACE
+else
+OBJS += ctrl_iface.c
+OBJS += src/ap/ctrl_iface_ap.c
+endif
+
+OBJS += src/crypto/md5.c
+
+L_CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
+
+ifdef CONFIG_IAPP
+L_CFLAGS += -DCONFIG_IAPP
+OBJS += src/ap/iapp.c
+endif
+
+ifdef CONFIG_RSN_PREAUTH
+L_CFLAGS += -DCONFIG_RSN_PREAUTH
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_PEERKEY
+L_CFLAGS += -DCONFIG_PEERKEY
+OBJS += src/ap/peerkey_auth.c
+endif
+
+ifdef CONFIG_IEEE80211W
+L_CFLAGS += -DCONFIG_IEEE80211W
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_IEEE80211R
+L_CFLAGS += -DCONFIG_IEEE80211R
+OBJS += src/ap/wpa_auth_ft.c
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+NEED_AES_UNWRAP=y
+endif
+
+ifdef CONFIG_SAE
+L_CFLAGS += -DCONFIG_SAE
+endif
+
+ifdef CONFIG_IEEE80211N
+L_CFLAGS += -DCONFIG_IEEE80211N
+endif
+
+include $(LOCAL_PATH)/src/drivers/drivers.mk
+
+OBJS += $(DRV_AP_OBJS)
+L_CFLAGS += $(DRV_AP_CFLAGS)
+LDFLAGS += $(DRV_AP_LDFLAGS)
+LIBS += $(DRV_AP_LIBS)
+
+ifdef CONFIG_L2_PACKET
+ifdef CONFIG_DNET_PCAP
+ifdef CONFIG_L2_FREEBSD
+LIBS += -lpcap
+OBJS += src/l2_packet/l2_packet_freebsd.c
+else
+LIBS += -ldnet -lpcap
+OBJS += src/l2_packet/l2_packet_pcap.c
+endif
+else
+OBJS += src/l2_packet/l2_packet_linux.c
+endif
+else
+OBJS += src/l2_packet/l2_packet_none.c
+endif
+
+
+ifdef CONFIG_EAP_MD5
+L_CFLAGS += -DEAP_SERVER_MD5
+OBJS += src/eap_server/eap_server_md5.c
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_TLS
+L_CFLAGS += -DEAP_SERVER_TLS
+OBJS += src/eap_server/eap_server_tls.c
+TLS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_PEAP
+L_CFLAGS += -DEAP_SERVER_PEAP
+OBJS += src/eap_server/eap_server_peap.c
+OBJS += src/eap_common/eap_peap_common.c
+TLS_FUNCS=y
+CONFIG_EAP_MSCHAPV2=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+L_CFLAGS += -DEAP_SERVER_TTLS
+OBJS += src/eap_server/eap_server_ttls.c
+TLS_FUNCS=y
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+L_CFLAGS += -DEAP_SERVER_MSCHAPV2
+OBJS += src/eap_server/eap_server_mschapv2.c
+MS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_GTC
+L_CFLAGS += -DEAP_SERVER_GTC
+OBJS += src/eap_server/eap_server_gtc.c
+endif
+
+ifdef CONFIG_EAP_SIM
+L_CFLAGS += -DEAP_SERVER_SIM
+OBJS += src/eap_server/eap_server_sim.c
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA
+L_CFLAGS += -DEAP_SERVER_AKA
+OBJS += src/eap_server/eap_server_aka.c
+CONFIG_EAP_SIM_COMMON=y
+NEED_SHA256=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA_PRIME
+L_CFLAGS += -DEAP_SERVER_AKA_PRIME
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += src/eap_common/eap_sim_common.c
+# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
+# replaced with another file implementating the interface specified in
+# eap_sim_db.h.
+OBJS += src/eap_server/eap_sim_db.c
+NEED_FIPS186_2_PRF=y
+endif
+
+ifdef CONFIG_EAP_PAX
+L_CFLAGS += -DEAP_SERVER_PAX
+OBJS += src/eap_server/eap_server_pax.c src/eap_common/eap_pax_common.c
+endif
+
+ifdef CONFIG_EAP_PSK
+L_CFLAGS += -DEAP_SERVER_PSK
+OBJS += src/eap_server/eap_server_psk.c src/eap_common/eap_psk_common.c
+NEED_AES_OMAC1=y
+NEED_AES_ENCBLOCK=y
+NEED_AES_EAX=y
+endif
+
+ifdef CONFIG_EAP_SAKE
+L_CFLAGS += -DEAP_SERVER_SAKE
+OBJS += src/eap_server/eap_server_sake.c src/eap_common/eap_sake_common.c
+endif
+
+ifdef CONFIG_EAP_GPSK
+L_CFLAGS += -DEAP_SERVER_GPSK
+OBJS += src/eap_server/eap_server_gpsk.c src/eap_common/eap_gpsk_common.c
+ifdef CONFIG_EAP_GPSK_SHA256
+L_CFLAGS += -DEAP_SERVER_GPSK_SHA256
+endif
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_EAP_PWD
+L_CFLAGS += -DEAP_SERVER_PWD
+OBJS += src/eap_server/eap_server_pwd.c src/eap_common/eap_pwd_common.c
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+L_CFLAGS += -DEAP_SERVER_VENDOR_TEST
+OBJS += src/eap_server/eap_server_vendor_test.c
+endif
+
+ifdef CONFIG_EAP_FAST
+L_CFLAGS += -DEAP_SERVER_FAST
+OBJS += src/eap_server/eap_server_fast.c
+OBJS += src/eap_common/eap_fast_common.c
+TLS_FUNCS=y
+NEED_T_PRF=y
+NEED_AES_UNWRAP=y
+endif
+
+ifdef CONFIG_WPS
+ifdef CONFIG_WPS2
+L_CFLAGS += -DCONFIG_WPS2
+endif
+
+L_CFLAGS += -DCONFIG_WPS -DEAP_SERVER_WSC
+OBJS += src/utils/uuid.c
+OBJS += src/ap/wps_hostapd.c
+OBJS += src/eap_server/eap_server_wsc.c src/eap_common/eap_wsc_common.c
+OBJS += src/wps/wps.c
+OBJS += src/wps/wps_common.c
+OBJS += src/wps/wps_attr_parse.c
+OBJS += src/wps/wps_attr_build.c
+OBJS += src/wps/wps_attr_process.c
+OBJS += src/wps/wps_dev_attr.c
+OBJS += src/wps/wps_enrollee.c
+OBJS += src/wps/wps_registrar.c
+NEED_DH_GROUPS=y
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_AES_CBC=y
+NEED_MODEXP=y
+CONFIG_EAP=y
+
+ifdef CONFIG_WPS_NFC
+L_CFLAGS += -DCONFIG_WPS_NFC
+OBJS += src/wps/ndef.c
+NEED_WPS_OOB=y
+endif
+
+ifdef NEED_WPS_OOB
+L_CFLAGS += -DCONFIG_WPS_OOB
+endif
+
+ifdef CONFIG_WPS_UPNP
+L_CFLAGS += -DCONFIG_WPS_UPNP
+OBJS += src/wps/wps_upnp.c
+OBJS += src/wps/wps_upnp_ssdp.c
+OBJS += src/wps/wps_upnp_web.c
+OBJS += src/wps/wps_upnp_event.c
+OBJS += src/wps/wps_upnp_ap.c
+OBJS += src/wps/upnp_xml.c
+OBJS += src/wps/httpread.c
+OBJS += src/wps/http_client.c
+OBJS += src/wps/http_server.c
+endif
+
+ifdef CONFIG_WPS_STRICT
+L_CFLAGS += -DCONFIG_WPS_STRICT
+OBJS += src/wps/wps_validate.c
+endif
+
+ifdef CONFIG_WPS_TESTING
+L_CFLAGS += -DCONFIG_WPS_TESTING
+endif
+
+endif
+
+ifdef CONFIG_EAP_IKEV2
+L_CFLAGS += -DEAP_SERVER_IKEV2
+OBJS += src/eap_server/eap_server_ikev2.c src/eap_server/ikev2.c
+OBJS += src/eap_common/eap_ikev2_common.c src/eap_common/ikev2_common.c
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_MODEXP=y
+NEED_CIPHER=y
+endif
+
+ifdef CONFIG_EAP_TNC
+L_CFLAGS += -DEAP_SERVER_TNC
+OBJS += src/eap_server/eap_server_tnc.c
+OBJS += src/eap_server/tncs.c
+NEED_BASE64=y
+ifndef CONFIG_DRIVER_BSD
+LIBS += -ldl
+endif
+endif
+
+# Basic EAP functionality is needed for EAPOL
+OBJS += eap_register.c
+OBJS += src/eap_server/eap_server.c
+OBJS += src/eap_common/eap_common.c
+OBJS += src/eap_server/eap_server_methods.c
+OBJS += src/eap_server/eap_server_identity.c
+L_CFLAGS += -DEAP_SERVER_IDENTITY
+
+ifdef CONFIG_EAP
+L_CFLAGS += -DEAP_SERVER
+endif
+
+ifdef CONFIG_PKCS12
+L_CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef MS_FUNCS
+OBJS += src/crypto/ms_funcs.c
+NEED_DES=y
+NEED_MD4=y
+endif
+
+ifdef CHAP
+OBJS += src/eap_common/chap.c
+endif
+
+ifdef TLS_FUNCS
+NEED_DES=y
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
+L_CFLAGS += -DEAP_TLS_FUNCS
+OBJS += src/eap_server/eap_server_tls_common.c
+NEED_TLS_PRF=y
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
+endif
+
+ifeq ($(CONFIG_TLS), openssl)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_openssl.c
+LIBS += -lssl
+endif
+OBJS += src/crypto/crypto_openssl.c
+HOBJS += src/crypto/crypto_openssl.c
+ifdef NEED_FIPS186_2_PRF
+OBJS += src/crypto/fips_prf_openssl.c
+endif
+LIBS += -lcrypto
+LIBS_h += -lcrypto
+endif
+
+ifeq ($(CONFIG_TLS), gnutls)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_gnutls.c
+LIBS += -lgnutls -lgpg-error
+ifdef CONFIG_GNUTLS_EXTRA
+L_CFLAGS += -DCONFIG_GNUTLS_EXTRA
+LIBS += -lgnutls-extra
+endif
+endif
+OBJS += src/crypto/crypto_gnutls.c
+HOBJS += src/crypto/crypto_gnutls.c
+ifdef NEED_FIPS186_2_PRF
+OBJS += src/crypto/fips_prf_gnutls.c
+endif
+LIBS += -lgcrypt
+LIBS_h += -lgcrypt
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), schannel)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_schannel.c
+endif
+OBJS += src/crypto/crypto_cryptoapi.c
+OBJS_p += src/crypto/crypto_cryptoapi.c
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), nss)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_nss.c
+LIBS += -lssl3
+endif
+OBJS += src/crypto/crypto_nss.c
+ifdef NEED_FIPS186_2_PRF
+OBJS += src/crypto/fips_prf_nss.c
+endif
+LIBS += -lnss3
+LIBS_h += -lnss3
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), internal)
+ifndef CONFIG_CRYPTO
+CONFIG_CRYPTO=internal
+endif
+ifdef TLS_FUNCS
+OBJS += src/crypto/crypto_internal-rsa.c
+OBJS += src/crypto/tls_internal.c
+OBJS += src/tls/tlsv1_common.c
+OBJS += src/tls/tlsv1_record.c
+OBJS += src/tls/tlsv1_cred.c
+OBJS += src/tls/tlsv1_server.c
+OBJS += src/tls/tlsv1_server_write.c
+OBJS += src/tls/tlsv1_server_read.c
+OBJS += src/tls/asn1.c
+OBJS += src/tls/rsa.c
+OBJS += src/tls/x509v3.c
+OBJS += src/tls/pkcs1.c
+OBJS += src/tls/pkcs5.c
+OBJS += src/tls/pkcs8.c
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_TLS_PRF=y
+NEED_MODEXP=y
+NEED_CIPHER=y
+L_CFLAGS += -DCONFIG_TLS_INTERNAL
+L_CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+endif
+ifdef NEED_CIPHER
+NEED_DES=y
+OBJS += src/crypto/crypto_internal-cipher.c
+endif
+ifdef NEED_MODEXP
+OBJS += src/crypto/crypto_internal-modexp.c
+OBJS += src/tls/bignum.c
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS += src/crypto/crypto_libtomcrypt.c
+LIBS += -ltomcrypt -ltfm
+LIBS_h += -ltomcrypt -ltfm
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+OBJS += src/crypto/crypto_internal.c
+NEED_AES_DEC=y
+L_CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+L_CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
+L_CFLAGS += -DLTM_FAST
+endif
+else
+LIBS += -ltommath
+LIBS_h += -ltommath
+endif
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_DES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+OBJS += src/crypto/crypto_cryptoapi.c
+OBJS_p += src/crypto/crypto_cryptoapi.c
+L_CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), none)
+ifdef TLS_FUNCS
+OBJS += src/crypto/tls_none.c
+L_CFLAGS += -DEAP_TLS_NONE
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+endif
+OBJS += src/crypto/crypto_none.c
+OBJS_p += src/crypto/crypto_none.c
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+
+ifndef TLS_FUNCS
+OBJS += src/crypto/tls_none.c
+ifeq ($(CONFIG_TLS), internal)
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+AESOBJS = # none so far
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += src/crypto/aes-internal.c src/crypto/aes-internal-enc.c
+endif
+
+AESOBJS += src/crypto/aes-wrap.c
+ifdef NEED_AES_EAX
+AESOBJS += src/crypto/aes-eax.c
+NEED_AES_CTR=y
+endif
+ifdef NEED_AES_CTR
+AESOBJS += src/crypto/aes-ctr.c
+endif
+ifdef NEED_AES_ENCBLOCK
+AESOBJS += src/crypto/aes-encblock.c
+endif
+ifdef NEED_AES_OMAC1
+AESOBJS += src/crypto/aes-omac1.c
+endif
+ifdef NEED_AES_UNWRAP
+NEED_AES_DEC=y
+AESOBJS += src/crypto/aes-unwrap.c
+endif
+ifdef NEED_AES_CBC
+NEED_AES_DEC=y
+AESOBJS += src/crypto/aes-cbc.c
+endif
+ifdef NEED_AES_DEC
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += src/crypto/aes-internal-dec.c
+endif
+endif
+ifdef NEED_AES
+OBJS += $(AESOBJS)
+endif
+
+SHA1OBJS =
+ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
+SHA1OBJS += src/crypto/sha1.c
+endif
+SHA1OBJS += src/crypto/sha1-prf.c
+ifdef CONFIG_INTERNAL_SHA1
+SHA1OBJS += src/crypto/sha1-internal.c
+ifdef NEED_FIPS186_2_PRF
+SHA1OBJS += src/crypto/fips_prf_internal.c
+endif
+endif
+ifneq ($(CONFIG_TLS), openssl)
+SHA1OBJS += src/crypto/sha1-pbkdf2.c
+endif
+ifdef NEED_T_PRF
+SHA1OBJS += src/crypto/sha1-tprf.c
+endif
+ifdef NEED_TLS_PRF
+SHA1OBJS += src/crypto/sha1-tlsprf.c
+endif
+endif
+
+ifdef NEED_SHA1
+OBJS += $(SHA1OBJS)
+endif
+
+ifdef NEED_MD5
+ifdef CONFIG_INTERNAL_MD5
+OBJS += src/crypto/md5-internal.c
+HOBJS += src/crypto/md5-internal.c
+endif
+endif
+
+ifdef NEED_MD4
+ifdef CONFIG_INTERNAL_MD4
+OBJS += src/crypto/md4-internal.c
+endif
+endif
+
+ifdef NEED_DES
+ifdef CONFIG_INTERNAL_DES
+OBJS += src/crypto/des-internal.c
+endif
+endif
+
+ifdef NEED_RC4
+ifdef CONFIG_INTERNAL_RC4
+OBJS += src/crypto/rc4.c
+endif
+endif
+
+ifdef NEED_SHA256
+L_CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
+OBJS += src/crypto/sha256.c
+endif
+OBJS += src/crypto/sha256-prf.c
+ifdef CONFIG_INTERNAL_SHA256
+OBJS += src/crypto/sha256-internal.c
+endif
+ifdef NEED_TLS_PRF_SHA256
+OBJS += ../src/crypto/sha256-tlsprf.c
+endif
+endif
+
+ifdef NEED_DH_GROUPS
+OBJS += src/crypto/dh_groups.c
+endif
+ifdef NEED_DH_GROUPS_ALL
+L_CFLAGS += -DALL_DH_GROUPS
+endif
+ifdef CONFIG_INTERNAL_DH_GROUP5
+ifdef NEED_DH_GROUPS
+OBJS += src/crypto/dh_group5.c
+endif
+endif
+
+ifdef CONFIG_NO_RANDOM_POOL
+L_CFLAGS += -DCONFIG_NO_RANDOM_POOL
+else
+OBJS += src/crypto/random.c
+HOBJS += src/crypto/random.c
+HOBJS += $(SHA1OBJS)
+HOBJS += src/crypto/md5.c
+endif
+
+ifdef CONFIG_RADIUS_SERVER
+L_CFLAGS += -DRADIUS_SERVER
+OBJS += src/radius/radius_server.c
+endif
+
+ifdef CONFIG_IPV6
+L_CFLAGS += -DCONFIG_IPV6
+endif
+
+ifdef CONFIG_DRIVER_RADIUS_ACL
+L_CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
+endif
+
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
+# and vlan interfaces for the vlan feature.
+L_CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
+endif
+
+ifdef NEED_BASE64
+OBJS += src/utils/base64.c
+endif
+
+ifdef NEED_AP_MLME
+OBJS += src/ap/wmm.c
+OBJS += src/ap/ap_list.c
+OBJS += src/ap/ieee802_11.c
+OBJS += src/ap/hw_features.c
+L_CFLAGS += -DNEED_AP_MLME
+endif
+ifdef CONFIG_IEEE80211N
+OBJS += src/ap/ieee802_11_ht.c
+endif
+
+ifdef CONFIG_P2P_MANAGER
+L_CFLAGS += -DCONFIG_P2P_MANAGER
+OBJS += src/ap/p2p_hostapd.c
+endif
+
+OBJS += src/drivers/driver_common.c
+
+ifdef CONFIG_NO_STDOUT_DEBUG
+L_CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
+endif
+
+ifdef CONFIG_DEBUG_FILE
+L_CFLAGS += -DCONFIG_DEBUG_FILE
+endif
+
+ifdef CONFIG_ANDROID_LOG
+L_CFLAGS += -DCONFIG_ANDROID_LOG
+endif
+
+OBJS_c = hostapd_cli.c src/common/wpa_ctrl.c src/utils/os_$(CONFIG_OS).c
+OBJS_c += src/utils/eloop.c
+ifdef CONFIG_WPA_TRACE
+OBJS_c += src/utils/trace.c
+endif
+OBJS_c += src/utils/wpa_debug.c
+ifdef CONFIG_WPA_CLI_EDIT
+OBJS_c += src/utils/edit.c
+else
+OBJS_c += src/utils/edit_simple.c
+endif
+
+########################
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := hostapd_cli
+LOCAL_MODULE_TAGS := debug
+LOCAL_SHARED_LIBRARIES := libc libcutils
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_SRC_FILES := $(OBJS_c)
+LOCAL_C_INCLUDES := $(INCLUDES)
+include $(BUILD_EXECUTABLE)
+
+########################
+include $(CLEAR_VARS)
+LOCAL_MODULE := hostapd
+LOCAL_MODULE_TAGS := optional
+ifdef CONFIG_DRIVER_CUSTOM
+LOCAL_STATIC_LIBRARIES := libCustomWifi
+endif
+ifneq ($(BOARD_HOSTAPD_PRIVATE_LIB),)
+LOCAL_STATIC_LIBRARIES += $(BOARD_HOSTAPD_PRIVATE_LIB)
+endif
+LOCAL_SHARED_LIBRARIES := libc libcutils libcrypto libssl
+ifdef CONFIG_DRIVER_NL80211
+LOCAL_STATIC_LIBRARIES += libnl_2
+endif
+LOCAL_CFLAGS := $(L_CFLAGS)
+LOCAL_SRC_FILES := $(OBJS)
+LOCAL_C_INCLUDES := $(INCLUDES)
+include $(BUILD_EXECUTABLE)
+
+endif # ifeq ($(WPA_BUILD_HOSTAPD),true)
diff --git a/hostap/hostapd/ChangeLog b/hostap/hostapd/ChangeLog
new file mode 100644
index 0000000..6824e5a
--- /dev/null
+++ b/hostap/hostapd/ChangeLog
@@ -0,0 +1,849 @@
+ChangeLog for hostapd
+
+2013-01-12 - v2.0
+	* added AP-STA-DISCONNECTED ctrl_iface event
+	* improved debug logging (human readable event names, interface name
+	  included in more entries)
+	* added number of small changes to make it easier for static analyzers
+	  to understand the implementation
+	* added a workaround for Windows 7 Michael MIC failure reporting and
+	  use of the Secure bit in EAPOL-Key msg 3/4
+	* fixed number of small bugs (see git logs for more details)
+	* changed OpenSSL to read full certificate chain from server_cert file
+	* nl80211: number of updates to use new cfg80211/nl80211 functionality
+	  - replace monitor interface with nl80211 commands
+	  - additional information for driver-based AP SME
+	* EAP-pwd:
+	  - fix KDF for group 21 and zero-padding
+	  - added support for fragmentation
+	  - increased maximum number of hunting-and-pecking iterations
+	* avoid excessive Probe Response retries for broadcast Probe Request
+	  frames (only with drivers using hostapd SME/MLME)
+	* added preliminary support for using TLS v1.2 (CONFIG_TLSV12=y)
+	* fixed WPS operation stopping on dual concurrent AP
+	* added wps_rf_bands configuration parameter for overriding RF Bands
+	  value for WPS
+	* added support for getting per-device PSK from RADIUS Tunnel-Password
+	* added support for libnl 3.2 and newer
+	* increased initial group key handshake retransmit timeout to 500 ms
+	* added a workaround for 4-way handshake to update SNonce even after
+	  having sent EAPOL-Key 3/4 to avoid issues with some supplicant
+	  implementations that can change SNonce for each EAP-Key 2/4
+	* added a workaround for EAPOL-Key 4/4 using incorrect type value in
+	  WPA2 mode (some deployed stations use WPA type in that message)
+	* added a WPS workaround for mixed mode AP Settings with Windows 7
+	* changed WPS AP PIN disabling mechanism to disable the PIN after 10
+	  consecutive failures in addition to using the exponential lockout
+	  period
+	* added support for WFA Hotspot 2.0
+	  - GAS/ANQP advertisement of network information
+	  - disable_dgaf parameter to disable downstream group-addressed
+	    forwarding
+	* simplified licensing terms by selecting the BSD license as the only
+	  alternative
+	* EAP-SIM: fixed re-authentication not to update pseudonym
+	* EAP-SIM: use Notification round before EAP-Failure
+	* EAP-AKA: added support for AT_COUNTER_TOO_SMALL
+	* EAP-AKA: skip AKA/Identity exchange if EAP identity is recognized
+	* EAP-AKA': fixed identity for MK derivation
+	* EAP-AKA': updated to RFC 5448 (username prefixes changed); note: this
+	  breaks interoperability with older versions
+	* EAP-SIM/AKA: allow pseudonym to be used after unknown reauth id
+	* changed ANonce to be a random number instead of Counter-based
+	* added support for canceling WPS operations with hostapd_cli wps_cancel
+	* fixed EAP/WPS to PSK transition on reassociation in cases where
+	  deauthentication is missed
+	* hlr_auc_gw enhancements:
+	  - a new command line parameter -u can be used to enable updating of
+	    SQN in Milenage file
+	  - use 5 bit IND for SQN updates
+	  - SQLite database can now be used to store Milenage information
+	* EAP-SIM/AKA DB: added optional use of SQLite database for pseudonyms
+	  and reauth data
+	* added support for Chargeable-User-Identity (RFC 4372)
+	* added radius_auth_req_attr and radius_acct_req_attr configuration
+	  parameters to allow adding/overriding of RADIUS attributes in
+	  Access-Request and Accounting-Request packets
+	* added support for RADIUS dynamic authorization server (RFC 5176)
+	* added initial support for WNM operations
+	  - BSS max idle period
+	  - WNM-Sleep Mode
+	* added new WPS NFC ctrl_iface mechanism
+	  - removed obsoleted WPS_OOB command (including support for deprecated
+	    UFD config_method)
+	* added FT support for drivers that implement MLME internally
+	* added SA Query support for drivers that implement MLME internally
+	* removed default ACM=1 from AC_VO and AC_VI
+	* changed VENDOR-TEST EAP method to use proper private enterprise number
+	  (this will not interoperate with older versions)
+	* added hostapd.conf parameter vendor_elements to allow arbitrary vendor
+	  specific elements to be added to the Beacon and Probe Response frames
+	* added support for configuring GCMP cipher for IEEE 802.11ad
+	* added support for 256-bit AES with internal TLS implementation
+	* changed EAPOL transmission to use AC_VO if WMM is active
+	* fixed EAP-TLS/PEAP/TTLS/FAST server to validate TLS Message Length
+	  correctly; invalid messages could have caused the hostapd process to
+	  terminate before this fix [CVE-2012-4445]
+	* limit number of active wildcard PINs for WPS Registrar to one to avoid
+	  confusing behavior with multiple wildcard PINs
+	* added a workaround for WPS PBC session overlap detection to avoid
+	  interop issues with deployed station implementations that do not
+	  remove active PBC indication from Probe Request frames properly
+	* added support for using SQLite for the eap_user database
+	* added Acct-Session-Id attribute into Access-Request messages
+	* fixed EAPOL frame transmission to non-QoS STAs with nl80211
+	  (do not send QoS frames if the STA did not negotiate use of QoS for
+	  this association)
+
+2012-05-10 - v1.0
+	* Add channel selection support in hostapd. See hostapd.conf.
+	* Add support for IEEE 802.11v Time Advertisement mechanism with UTC
+	  TSF offset. See hostapd.conf for config info.
+	* Delay STA entry removal until Deauth/Disassoc TX status in AP mode.
+	  This allows the driver to use PS buffering of Deauthentication and
+	  Disassociation frames when the STA is in power save sleep. Only
+	  available with drivers that provide TX status events for Deauth/
+	  Disassoc frames (nl80211).
+	* Allow PMKSA caching to be disabled on the Authenticator. See
+	  hostap.conf config parameter disable_pmksa_caching.
+	* atheros: Add support for IEEE 802.11w configuration.
+	* bsd: Add support for setting HT values in IFM_MMASK.
+	* Allow client isolation to be configured with ap_isolate. Client
+	  isolation can be used to prevent low-level bridging of frames
+	  between associated stations in the BSS. By default, this bridging
+	  is allowed.
+	* Allow coexistance of HT BSSes with WEP/TKIP BSSes.
+	* Add require_ht config parameter, which can be used to configure
+	  hostapd to reject association with any station that does not support
+	  HT PHY.
+	* Add support for writing debug log to a file using "-f" option. Also
+	  add relog CLI command to re-open the log file.
+	* Add bridge handling for WDS STA interfaces. By default they are
+	  added to the configured bridge of the AP interface (if present),
+	  but the user can also specify a separate bridge using cli command
+	  wds_bridge.
+	* hostapd_cli:
+	  - Add wds_bridge command for specifying bridge for WDS STA
+	    interfaces.
+	  - Add relog command for reopening log file.
+	  - Send AP-STA-DISCONNECTED event when an AP disconnects a station
+	    due to inactivity.
+	  - Add wps_config ctrl_interface command for configuring AP. This
+	    command can be used to configure the AP using the internal WPS
+	    registrar. It works in the same way as new AP settings received
+	    from an ER.
+	  - Many WPS/WPS ER commands - see WPS/WPS ER sections for details.
+	  - Add command get version, that returns hostapd version string.
+	* WNM: Add BSS Transition Management Request for ESS Disassoc Imminent.
+	  Use hostapd_cli ess_disassoc (STA addr) (URL) to send the
+	  notification to the STA.
+	* Allow AP mode to disconnect STAs based on low ACK condition (when
+	  the data connection is not working properly, e.g., due to the STA
+	  going outside the range of the AP). Disabled by default, enable by
+	  config option disassoc_low_ack.
+	* Add WPA_IGNORE_CONFIG_ERRORS build option to continue in case of bad
+	  config file.
+	* WPS:
+	  - Send AP Settings as a wrapped Credential attribute to ctrl_iface
+	    in WPS-NEW-AP-SETTINGS.
+	  - Dispatch more WPS events through hostapd ctrl_iface.
+	  - Add mechanism for indicating non-standard WPS errors.
+	  - Change concurrent radio AP to use only one WPS UPnP instance.
+	  - Add wps_check_pin command for processing PIN from user input.
+	    UIs can use this command to process a PIN entered by a user and to
+	    validate the checksum digit (if present).
+	  - Add hostap_cli get_config command to display current AP config.
+	  - Add new hostapd_cli command, wps_ap_pin, to manage AP PIN at
+	    runtime and support dynamic AP PIN management.
+	  - Disable AP PIN after 10 consecutive failures. Slow down attacks
+	    on failures up to 10.
+	  - Allow AP to start in Enrollee mode without AP PIN for probing,
+	    to be compatible with Windows 7.
+	  - Add Config Error into WPS-FAIL events to provide more info
+	    to the user on how to resolve the issue.
+	  - When controlling multiple interfaces:
+	     - apply WPS commands to all interfaces configured to use WPS
+	     - apply WPS config changes to all interfaces that use WPS
+	     - when an attack is detected on any interface, disable AP PIN on
+	       all interfaces
+	* WPS ER:
+	  - Show SetSelectedRegistrar events as ctrl_iface events.
+	  - Add special AP Setup Locked mode to allow read only ER.
+	    ap_setup_locked=2 can now be used to enable a special mode where
+	    WPS ER can learn the current AP settings, but cannot change them.
+	* WPS 2.0: Add support for WPS 2.0 (CONFIG_WPS2)
+	  - Add build option CONFIG_WPS_EXTENSIBILITY_TESTING to enable tool
+	    for testing protocol extensibility.
+	  - Add build option CONFIG_WPS_STRICT to allow disabling of WPS
+	    workarounds.
+	  - Add support for AuthorizedMACs attribute.
+	* TDLS:
+	  - Allow TDLS use or TDLS channel switching in the BSS to be
+	    prohibited in the BSS, using config params tdls_prohibit and
+	    tdls_prohibit_chan_switch.
+	* EAP server: Add support for configuring fragment size (see
+	  fragment_size in hostapd.conf).
+	* wlantest: Add a tool wlantest for IEEE802.11 protocol testing.
+	  wlantest can be used to capture frames from a monitor interface
+	  for realtime capturing or from pcap files for offline analysis.
+	* Interworking: Support added for 802.11u. Enable in .config with
+	  CONFIG_INTERWORKING. See hostapd.conf for config parameters for
+	  interworking.
+	* Android: Add build and runtime support for Android hostapd.
+	* Add a new debug message level for excessive information. Use
+	  -ddd to enable.
+	* TLS: Add support for tls_disable_time_checks=1 in client mode.
+	* Internal TLS:
+	  - Add support for TLS v1.1 (RFC 4346). Enable with build parameter
+	    CONFIG_TLSV11.
+	  - Add domainComponent parser for X.509 names
+	* Reorder some IEs to get closer to IEEE 802.11 standard. Move
+	  WMM into end of Beacon, Probe Resp and (Re)Assoc Resp frames.
+	  Move HT IEs to be later in (Re)Assoc Resp.
+	* Many bugfixes.
+
+2010-04-18 - v0.7.2
+	* fix WPS internal Registrar use when an external Registrar is also
+	  active
+	* bsd: Cleaned up driver wrapper and added various low-level
+	  configuration options
+	* TNC: fixed issues with fragmentation
+	* EAP-TNC: add Flags field into fragment acknowledgement (needed to
+	  interoperate with other implementations; may potentially breaks
+	  compatibility with older wpa_supplicant/hostapd versions)
+	* cleaned up driver wrapper API for multi-BSS operations
+	* nl80211: fix multi-BSS and VLAN operations
+	* fix number of issues with IEEE 802.11r/FT; this version is not
+	  backwards compatible with old versions
+	* add SA Query Request processing in AP mode (IEEE 802.11w)
+	* fix IGTK PN in group rekeying (IEEE 802.11w)
+	* fix WPS PBC session overlap detection to use correct attribute
+	* hostapd_notif_Assoc() can now be called with all IEs to simplify
+	  driver wrappers
+	* work around interoperability issue with some WPS External Registrar
+	  implementations
+	* nl80211: fix WPS IE update
+	* hostapd_cli: add support for action script operations (run a script
+	  on hostapd events)
+	* fix DH padding with internal crypto code (mainly, for WPS)
+	* fix WPS association with both WPS IE and WPA/RSN IE present with
+	  driver wrappers that use hostapd MLME (e.g., nl80211)
+
+2010-01-16 - v0.7.1
+	* cleaned up driver wrapper API (struct wpa_driver_ops); the new API
+	  is not fully backwards compatible, so out-of-tree driver wrappers
+	  will need modifications
+	* cleaned up various module interfaces
+	* merge hostapd and wpa_supplicant developers' documentation into a
+	  single document
+	* fixed HT Capabilities IE with nl80211 drivers
+	* moved generic AP functionality code into src/ap
+	* WPS: handle Selected Registrar as union of info from all Registrars
+	* remove obsolte Prism54.org driver wrapper
+	* added internal debugging mechanism with backtrace support and memory
+	  allocation/freeing validation, etc. tests (CONFIG_WPA_TRACE=y)
+	* EAP-FAST server: piggyback Phase 2 start with the end of Phase 1
+	* WPS: add support for dynamically selecting whether to provision the
+	  PSK as an ASCII passphrase or PSK
+	* added support for WDS (4-address frame) mode with per-station virtual
+	  interfaces (wds_sta=1 in config file; only supported with
+	  driver=nl80211 for now)
+	* fixed WPS Probe Request processing to handle missing required
+	  attribute
+	* fixed PKCS#12 use with OpenSSL 1.0.0
+	* detect bridge interface automatically so that bridge parameter in
+	  hostapd.conf becomes optional (though, it may now be used to
+	  automatically add then WLAN interface into a bridge with
+	  driver=nl80211)
+
+2009-11-21 - v0.7.0
+	* increased hostapd_cli ping interval to 5 seconds and made this
+	  configurable with a new command line options (-G<seconds>)
+	* driver_nl80211: use Linux socket filter to improve performance
+	* added support for external Registrars with WPS (UPnP transport)
+	* 802.11n: scan for overlapping BSSes before starting 20/40 MHz channel
+	* driver_nl80211: fixed STA accounting data collection (TX/RX bytes
+	  reported correctly; TX/RX packets not yet available from kernel)
+	* added support for WPS USBA out-of-band mechanism with USB Flash
+	  Drives (UFD) (CONFIG_WPS_UFD=y)
+	* fixed EAPOL/EAP reauthentication when using an external RADIUS
+	  authentication server
+	* fixed TNC with EAP-TTLS
+	* fixed IEEE 802.11r key derivation function to match with the standard
+	  (note: this breaks interoperability with previous version) [Bug 303]
+	* fixed SHA-256 based key derivation function to match with the
+	  standard when using CCMP (for IEEE 802.11r and IEEE 802.11w)
+	  (note: this breaks interoperability with previous version) [Bug 307]
+	* added number of code size optimizations to remove unnecessary
+	  functionality from the program binary based on build configuration
+	  (part of this automatic; part configurable with CONFIG_NO_* build
+	  options)
+	* use shared driver wrapper files with wpa_supplicant
+	* driver_nl80211: multiple updates to provide support for new Linux
+	  nl80211/mac80211 functionality
+	* updated management frame protection to use IEEE Std 802.11w-2009
+	* fixed number of small WPS issues and added workarounds to
+	  interoperate with common deployed broken implementations
+	* added some IEEE 802.11n co-existence rules to disable 40 MHz channels
+	  or modify primary/secondary channels if needed based on neighboring
+	  networks
+	* added support for NFC out-of-band mechanism with WPS
+	* added preliminary support for IEEE 802.11r RIC processing
+
+2009-01-06 - v0.6.7
+	* added support for Wi-Fi Protected Setup (WPS)
+	  (hostapd can now be configured to act as an integrated WPS Registrar
+	  and provision credentials for WPS Enrollees using PIN and PBC
+	  methods; external wireless Registrar can configure the AP, but
+	  external WLAN Manager Registrars are not supported); WPS support can
+	  be enabled by adding CONFIG_WPS=y into .config and setting the
+	  runtime configuration variables in hostapd.conf (see WPS section in
+	  the example configuration file); new hostapd_cli commands wps_pin and
+	  wps_pbc are used to configure WPS negotiation; see README-WPS for
+	  more details
+	* added IEEE 802.11n HT capability configuration (ht_capab)
+	* added support for generating Country IE based on nl80211 regulatory
+	  information (added if ieee80211d=1 in configuration)
+	* fixed WEP authentication (both Open System and Shared Key) with
+	  mac80211
+	* added support for EAP-AKA' (draft-arkko-eap-aka-kdf)
+	* added support for using driver_test over UDP socket
+	* changed EAP-GPSK to use the IANA assigned EAP method type 51
+	* updated management frame protection to use IEEE 802.11w/D7.0
+	* fixed retransmission of EAP requests if no response is received
+
+2008-11-23 - v0.6.6
+	* added a new configuration option, wpa_ptk_rekey, that can be used to
+	  enforce frequent PTK rekeying, e.g., to mitigate some attacks against
+	  TKIP deficiencies
+	* updated OpenSSL code for EAP-FAST to use an updated version of the
+	  session ticket overriding API that was included into the upstream
+	  OpenSSL 0.9.9 tree on 2008-11-15 (no additional OpenSSL patch is
+	  needed with that version anymore)
+	* changed channel flags configuration to read the information from
+	  the driver (e.g., via driver_nl80211 when using mac80211) instead of
+	  using hostapd as the source of the regulatory information (i.e.,
+	  information from CRDA is now used with mac80211); this allows 5 GHz
+	  channels to be used with hostapd (if allowed in the current
+	  regulatory domain)
+	* fixed EAP-TLS message processing for the last TLS message if it is
+	  large enough to require fragmentation (e.g., if a large Session
+	  Ticket data is included)
+	* fixed listen interval configuration for nl80211 drivers
+
+2008-11-01 - v0.6.5
+	* added support for SHA-256 as X.509 certificate digest when using the
+	  internal X.509/TLSv1 implementation
+	* fixed EAP-FAST PAC-Opaque padding (0.6.4 broke this for some peer
+	  identity lengths)
+	* fixed internal TLSv1 implementation for abbreviated handshake (used
+	  by EAP-FAST server)
+	* added support for setting VLAN ID for STAs based on local MAC ACL
+	  (accept_mac_file) as an alternative for RADIUS server-based
+	  configuration
+	* updated management frame protection to use IEEE 802.11w/D6.0
+	  (adds a new association ping to protect against unauthenticated
+	  authenticate or (re)associate request frames dropping association)
+	* added support for using SHA256-based stronger key derivation for WPA2
+	  (IEEE 802.11w)
+	* added new "driver wrapper" for RADIUS-only configuration
+	  (driver=none in hostapd.conf; CONFIG_DRIVER_NONE=y in .config)
+	* fixed WPA/RSN IE validation to verify that the proto (WPA vs. WPA2)
+	  is enabled in configuration
+	* changed EAP-FAST configuration to use separate fields for A-ID and
+	  A-ID-Info (eap_fast_a_id_info) to allow A-ID to be set to a fixed
+	  16-octet len binary value for better interoperability with some peer
+	  implementations; eap_fast_a_id is now configured as a hex string
+	* driver_nl80211: Updated to match the current Linux mac80211 AP mode
+	  configuration (wireless-testing.git and Linux kernel releases
+	  starting from 2.6.29)
+
+2008-08-10 - v0.6.4
+	* added peer identity into EAP-FAST PAC-Opaque and skip Phase 2
+	  Identity Request if identity is already known
+	* added support for EAP Sequences in EAP-FAST Phase 2
+	* added support for EAP-TNC (Trusted Network Connect)
+	  (this version implements the EAP-TNC method and EAP-TTLS/EAP-FAST
+	  changes needed to run two methods in sequence (IF-T) and the IF-IMV
+	  and IF-TNCCS interfaces from TNCS)
+	* added support for optional cryptobinding with PEAPv0
+	* added fragmentation support for EAP-TNC
+	* added support for fragmenting EAP-TTLS/PEAP/FAST Phase 2 (tunneled)
+	  data
+	* added support for opportunistic key caching (OKC)
+
+2008-02-22 - v0.6.3
+	* fixed Reassociation Response callback processing when using internal
+	  MLME (driver_{hostap,nl80211,test}.c)
+	* updated FT support to use the latest draft, IEEE 802.11r/D9.0
+	* copy optional Proxy-State attributes into RADIUS response when acting
+	  as a RADIUS authentication server
+	* fixed EAPOL state machine to handle a case in which no response is
+	  received from the RADIUS authentication server; previous version
+	  could have triggered a crash in some cases after a timeout
+	* fixed EAP-SIM/AKA realm processing to allow decorated usernames to
+	  be used
+	* added a workaround for EAP-SIM/AKA peers that include incorrect null
+	  termination in the username
+	* fixed EAP-SIM/AKA protected result indication to include AT_COUNTER
+	  attribute in notification messages only when using fast
+	  reauthentication
+	* fixed EAP-SIM Start response processing for fast reauthentication
+	  case
+	* added support for pending EAP processing in EAP-{PEAP,TTLS,FAST}
+	  phase 2 to allow EAP-SIM and EAP-AKA to be used as the Phase 2 method
+
+2008-01-01 - v0.6.2
+	* fixed EAP-SIM and EAP-AKA message parser to validate attribute
+	  lengths properly to avoid potential crash caused by invalid messages
+	* added data structure for storing allocated buffers (struct wpabuf);
+	  this does not affect hostapd usage, but many of the APIs changed
+	  and various interfaces (e.g., EAP) is not compatible with old
+	  versions
+	* added support for protecting EAP-AKA/Identity messages with
+	  AT_CHECKCODE (optional feature in RFC 4187)
+	* added support for protected result indication with AT_RESULT_IND for
+	  EAP-SIM and EAP-AKA (eap_sim_aka_result_ind=1)
+	* added support for configuring EAP-TTLS phase 2 non-EAP methods in
+	  EAP server configuration; previously all four were enabled for every
+	  phase 2 user, now all four are disabled by default and need to be
+	  enabled with new method names TTLS-PAP, TTLS-CHAP, TTLS-MSCHAP,
+	  TTLS-MSCHAPV2
+	* removed old debug printing mechanism and the related 'debug'
+	  parameter in the configuration file; debug verbosity is now set with
+	  -d (or -dd) command line arguments
+	* added support for EAP-IKEv2 (draft-tschofenig-eap-ikev2-15.txt);
+	  only shared key/password authentication is supported in this version
+
+2007-11-24 - v0.6.1
+	* added experimental, integrated TLSv1 server implementation with the
+	  needed X.509/ASN.1/RSA/bignum processing (this can be enabled by
+	  setting CONFIG_TLS=internal and CONFIG_INTERNAL_LIBTOMMATH=y in
+	  .config); this can be useful, e.g., if the target system does not
+	  have a suitable TLS library and a minimal code size is required
+	* added support for EAP-FAST server method to the integrated EAP
+	  server
+	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+	  draft (draft-ietf-emu-eap-gpsk-07.txt)
+	* added a new configuration parameter, rsn_pairwise, to allow different
+	  pairwise cipher suites to be enabled for WPA and RSN/WPA2
+	  (note: if wpa_pairwise differs from rsn_pairwise, the driver will
+	  either need to support this or will have to use the WPA/RSN IEs from
+	  hostapd; currently, the included madwifi and bsd driver interfaces do
+	  not have support for this)
+	* updated FT support to use the latest draft, IEEE 802.11r/D8.0
+
+2007-05-28 - v0.6.0
+	* added experimental IEEE 802.11r/D6.0 support
+	* updated EAP-SAKE to RFC 4763 and the IANA-allocated EAP type 48
+	* updated EAP-PSK to use the IANA-allocated EAP type 47
+	* fixed EAP-PSK bit ordering of the Flags field
+	* fixed configuration reloading (SIGHUP) to re-initialize WPA PSKs
+	  by reading wpa_psk_file [Bug 181]
+	* fixed EAP-TTLS AVP parser processing for too short AVP lengths
+	* fixed IPv6 connection to RADIUS accounting server
+	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+	  draft (draft-ietf-emu-eap-gpsk-04.txt)
+	* hlr_auc_gw: read GSM triplet file into memory and rotate through the
+	  entries instead of only using the same three triplets every time
+	  (this does not work properly with tests using multiple clients, but
+	  provides bit better triplet data for testing a single client; anyway,
+	  if a better quality triplets are needed, GSM-Milenage should be used
+	  instead of hardcoded triplet file)
+	* fixed EAP-MSCHAPv2 server to use a space between S and M parameters
+	  in Success Request [Bug 203]
+	* added support for sending EAP-AKA Notifications in error cases
+	* updated to use IEEE 802.11w/D2.0 for management frame protection
+	  (still experimental)
+	* RADIUS server: added support for processing duplicate messages
+	  (retransmissions from RADIUS client) by replying with the previous
+	  reply
+
+2006-11-24 - v0.5.6
+	* added support for configuring and controlling multiple BSSes per
+	  radio interface (bss=<ifname> in hostapd.conf); this is only
+	  available with Devicescape and test driver interfaces
+	* fixed PMKSA cache update in the end of successful RSN
+	  pre-authentication
+	* added support for dynamic VLAN configuration (i.e., selecting VLAN-ID
+	  for each STA based on RADIUS Access-Accept attributes); this requires
+	  VLAN support from the kernel driver/802.11 stack and this is
+	  currently only available with Devicescape and test driver interfaces
+	* driver_madwifi: fixed configuration of unencrypted modes (plaintext
+	  and IEEE 802.1X without WEP)
+	* removed STAKey handshake since PeerKey handshake has replaced it in
+	  IEEE 802.11ma and there are no known deployments of STAKey
+	* updated EAP Generalized Pre-Shared Key (EAP-GPSK) to use the latest
+	  draft (draft-ietf-emu-eap-gpsk-01.txt)
+	* added preliminary implementation of IEEE 802.11w/D1.0 (management
+	  frame protection)
+	  (Note: this requires driver support to work properly.)
+	  (Note2: IEEE 802.11w is an unapproved draft and subject to change.)
+	* hlr_auc_gw: added support for GSM-Milenage (for EAP-SIM)
+	* hlr_auc_gw: added support for reading per-IMSI Milenage keys and
+	  parameters from a text file to make it possible to implement proper
+	  GSM/UMTS authentication server for multiple SIM/USIM cards using
+	  EAP-SIM/EAP-AKA
+	* fixed session timeout processing with drivers that do not use
+	  ieee802_11.c (e.g., madwifi)
+
+2006-08-27 - v0.5.5
+	* added 'hostapd_cli new_sta <addr>' command for adding a new STA into
+	  hostapd (e.g., to initialize wired network authentication based on an
+	  external signal)
+	* fixed hostapd to add PMKID KDE into 4-Way Handshake Message 1 when
+	  using WPA2 even if PMKSA caching is not used
+	* added -P<pid file> argument for hostapd to write the current process
+	  id into a file
+	* added support for RADIUS Authentication Server MIB (RFC 2619)
+
+2006-06-20 - v0.5.4
+	* fixed nt_password_hash build [Bug 144]
+	* added PeerKey handshake implementation for IEEE 802.11e
+	  direct link setup (DLS) to replace STAKey handshake
+	* added support for EAP Generalized Pre-Shared Key (EAP-GPSK,
+	  draft-clancy-emu-eap-shared-secret-00.txt)
+	* fixed a segmentation fault when RSN pre-authentication was completed
+	  successfully [Bug 152]
+
+2006-04-27 - v0.5.3
+	* do not build nt_password_hash and hlr_auc_gw by default to avoid
+	  requiring a TLS library for a successful build; these programs can be
+	  build with 'make nt_password_hash' and 'make hlr_auc_gw'
+	* added a new configuration option, eapol_version, that can be used to
+	  set EAPOL version to 1 (default is 2) to work around broken client
+	  implementations that drop EAPOL frames which use version number 2
+	  [Bug 89]
+	* added support for EAP-SAKE (no EAP method number allocated yet, so
+	  this is using the same experimental type 255 as EAP-PSK)
+	* fixed EAP-MSCHAPv2 message length validation
+
+2006-03-19 - v0.5.2
+	* fixed stdarg use in hostapd_logger(): if both stdout and syslog
+	  logging was enabled, hostapd could trigger a segmentation fault in
+	  vsyslog on some CPU -- C library combinations
+	* moved HLR/AuC gateway implementation for EAP-SIM/AKA into an external
+	  program to make it easier to use for implementing real SS7 gateway;
+	  eap_sim_db is not anymore used as a file name for GSM authentication
+	  triplets; instead, it is path to UNIX domain socket that will be used
+	  to communicate with the external gateway program (e.g., hlr_auc_gw)
+	* added example HLR/AuC gateway implementation, hlr_auc_gw, that uses
+	  local information (GSM authentication triplets from a text file and
+	  hardcoded AKA authentication data); this can be used to test EAP-SIM
+	  and EAP-AKA
+	* added Milenage algorithm (example 3GPP AKA algorithm) to hlr_auc_gw
+	  to make it possible to test EAP-AKA with real USIM cards (this is
+	  disabled by default; define AKA_USE_MILENAGE when building hlr_auc_gw
+	  to enable this)
+	* driver_madwifi: added support for getting station RSN IE from
+	  madwifi-ng svn r1453 and newer; this fixes RSN that was apparently
+	  broken with earlier change (r1357) in the driver
+	* changed EAP method registration to use a dynamic list of methods
+	  instead of a static list generated at build time
+	* fixed WPA message 3/4 not to encrypt Key Data field (WPA IE)
+	  [Bug 125]
+	* added ap_max_inactivity configuration parameter
+
+2006-01-29 - v0.5.1
+	* driver_test: added better support for multiple APs and STAs by using
+	  a directory with sockets that include MAC address for each device in
+	  the name (test_socket=DIR:/tmp/test)
+	* added support for EAP expanded type (vendor specific EAP methods)
+
+2005-12-18 - v0.5.0 (beginning of 0.5.x development releases)
+	* added experimental STAKey handshake implementation for IEEE 802.11e
+	  direct link setup (DLS); note: this is disabled by default in both
+	  build and runtime configuration (can be enabled with CONFIG_STAKEY=y
+	  and stakey=1)
+	* added support for EAP methods to use callbacks to external programs
+	  by buffering a pending request and processing it after the EAP method
+	  is ready to continue
+	* improved EAP-SIM database interface to allow external request to GSM
+	  HLR/AuC without blocking hostapd process
+	* added support for using EAP-SIM pseudonyms and fast re-authentication
+	* added support for EAP-AKA in the integrated EAP authenticator
+	* added support for matching EAP identity prefixes (e.g., "1"*) in EAP
+	  user database to allow EAP-SIM/AKA selection without extra roundtrip
+	  for EAP-Nak negotiation
+	* added support for storing EAP user password as NtPasswordHash instead
+	  of plaintext password when using MSCHAP or MSCHAPv2 for
+	  authentication (hash:<16-octet hex value>); added nt_password_hash
+	  tool for hashing password to generate NtPasswordHash
+
+2005-11-20 - v0.4.7 (beginning of 0.4.x stable releases)
+	* driver_wired: fixed EAPOL sending to optionally use PAE group address
+	  as the destination instead of supplicant MAC address; this is
+	  disabled by default, but should be enabled with use_pae_group_addr=1
+	  in configuration file if the wired interface is used by only one
+	  device at the time (common switch configuration)
+	* driver_madwifi: configure driver to use TKIP countermeasures in order
+	  to get correct behavior (IEEE 802.11 association failing; previously,
+	  association succeeded, but hostpad forced disassociation immediately)
+	* driver_madwifi: added support for madwifi-ng
+
+2005-10-27 - v0.4.6
+	* added support for replacing user identity from EAP with RADIUS
+	  User-Name attribute from Access-Accept message, if that is included,
+	  for the RADIUS accounting messages (e.g., for EAP-PEAP/TTLS to get
+	  tunneled identity into accounting messages when the RADIUS server
+	  does not support better way of doing this with Class attribute)
+	* driver_madwifi: fixed EAPOL packet receive for configuration where
+	  ath# is part of a bridge interface
+	* added a configuration file and log analyzer script for logwatch
+	* fixed EAPOL state machine step function to process all state
+	  transitions before processing new events; this resolves a race
+	  condition in which EAPOL-Start message could trigger hostapd to send
+	  two EAP-Response/Identity frames to the authentication server
+
+2005-09-25 - v0.4.5
+	* added client CA list to the TLS certificate request in order to make
+	  it easier for the client to select which certificate to use
+	* added experimental support for EAP-PSK
+	* added support for WE-19 (hostap, madwifi)
+
+2005-08-21 - v0.4.4
+	* fixed build without CONFIG_RSN_PREAUTH
+	* fixed FreeBSD build
+
+2005-06-26 - v0.4.3
+	* fixed PMKSA caching to copy User-Name and Class attributes so that
+	  RADIUS accounting gets correct information
+	* start RADIUS accounting only after successful completion of WPA
+	  4-Way Handshake if WPA-PSK is used
+	* fixed PMKSA caching for the case where STA (re)associates without
+	  first disassociating
+
+2005-06-12 - v0.4.2
+	* EAP-PAX is now registered as EAP type 46
+	* fixed EAP-PAX MAC calculation
+	* fixed EAP-PAX CK and ICK key derivation
+	* renamed eap_authenticator configuration variable to eap_server to
+	  better match with RFC 3748 (EAP) terminology
+	* driver_test: added support for testing hostapd with wpa_supplicant
+	  by using test driver interface without any kernel drivers or network
+	  cards
+
+2005-05-22 - v0.4.1
+	* fixed RADIUS server initialization when only auth or acct server
+	  is configured and the other one is left empty
+	* driver_madwifi: added support for RADIUS accounting
+	* driver_madwifi: added preliminary support for compiling against 'BSD'
+	  branch of madwifi CVS tree
+	* driver_madwifi: fixed pairwise key removal to allow WPA reauth
+	  without disassociation
+	* added support for reading additional certificates from PKCS#12 files
+	  and adding them to the certificate chain
+	* fixed RADIUS Class attribute processing to only use Access-Accept
+	  packets to update Class; previously, other RADIUS authentication
+	  packets could have cleared Class attribute
+	* added support for more than one Class attribute in RADIUS packets
+	* added support for verifying certificate revocation list (CRL) when
+	  using integrated EAP authenticator for EAP-TLS; new hostapd.conf
+	  options 'check_crl'; CRL must be included in the ca_cert file for now
+
+2005-04-25 - v0.4.0 (beginning of 0.4.x development releases)
+	* added support for including network information into
+	  EAP-Request/Identity message (ASCII-0 (nul) in eap_message)
+	  (e.g., to implement draft-adrange-eap-network-discovery-07.txt)
+	* fixed a bug which caused some RSN pre-authentication cases to use
+	  freed memory and potentially crash hostapd
+	* fixed private key loading for cases where passphrase is not set
+	* added support for sending TLS alerts and aborting authentication
+	  when receiving a TLS alert
+	* fixed WPA2 to add PMKSA cache entry when using integrated EAP
+	  authenticator
+	* fixed PMKSA caching (EAP authentication was not skipped correctly
+	  with the new state machine changes from IEEE 802.1X draft)
+	* added support for RADIUS over IPv6; own_ip_addr, auth_server_addr,
+	  and acct_server_addr can now be IPv6 addresses (CONFIG_IPV6=y needs
+	  to be added to .config to include IPv6 support); for RADIUS server,
+	  radius_server_ipv6=1 needs to be set in hostapd.conf and addresses
+	  in RADIUS clients file can then use IPv6 format
+	* added experimental support for EAP-PAX
+	* replaced hostapd control interface library (hostapd_ctrl.[ch]) with
+	  the same implementation that wpa_supplicant is using (wpa_ctrl.[ch])
+
+2005-02-12 - v0.3.7 (beginning of 0.3.x stable releases)
+
+2005-01-23 - v0.3.5
+	* added support for configuring a forced PEAP version based on the
+	  Phase 1 identity
+	* fixed PEAPv1 to use tunneled EAP-Success/Failure instead of EAP-TLV
+	  to terminate authentication
+	* fixed EAP identifier duplicate processing with the new IEEE 802.1X
+	  draft
+	* clear accounting data in the driver when starting a new accounting
+	  session
+	* driver_madwifi: filter wireless events based on ifindex to allow more
+	  than one network interface to be used
+	* fixed WPA message 2/4 processing not to cancel timeout for TimeoutEvt
+	  setting if the packet does not pass MIC verification (e.g., due to
+	  incorrect PSK); previously, message 1/4 was not tried again if an
+	  invalid message 2/4 was received
+	* fixed reconfiguration of RADIUS client retransmission timer when
+	  adding a new message to the pending list; previously, timer was not
+	  updated at this point and if there was a pending message with long
+	  time for the next retry, the new message needed to wait that long for
+	  its first retry, too
+
+2005-01-09 - v0.3.4
+	* added support for configuring multiple allowed EAP types for Phase 2
+	  authentication (EAP-PEAP, EAP-TTLS)
+	* fixed EAPOL-Start processing to trigger WPA reauthentication
+	  (previously, only EAPOL authentication was done)
+
+2005-01-02 - v0.3.3
+	* added support for EAP-PEAP in the integrated EAP authenticator
+	* added support for EAP-GTC in the integrated EAP authenticator
+	* added support for configuring list of EAP methods for Phase 1 so that
+	  the integrated EAP authenticator can, e.g., use the wildcard entry
+	  for EAP-TLS and EAP-PEAP
+	* added support for EAP-TTLS in the integrated EAP authenticator
+	* added support for EAP-SIM in the integrated EAP authenticator
+	* added support for using hostapd as a RADIUS authentication server
+	  with the integrated EAP authenticator taking care of EAP
+	  authentication (new hostapd.conf options: radius_server_clients and
+	  radius_server_auth_port); this is not included in default build; use
+	  CONFIG_RADIUS_SERVER=y in .config to include
+
+2004-12-19 - v0.3.2
+	* removed 'daemonize' configuration file option since it has not really
+	  been used at all for more than year
+	* driver_madwifi: fixed group key setup and added get_ssid method
+	* added support for EAP-MSCHAPv2 in the integrated EAP authenticator
+
+2004-12-12 - v0.3.1
+	* added support for integrated EAP-TLS authentication (new hostapd.conf
+	  variables: ca_cert, server_cert, private_key, private_key_passwd);
+	  this enabled dynamic keying (WPA2/WPA/IEEE 802.1X/WEP) without
+	  external RADIUS server
+	* added support for reading PKCS#12 (PFX) files (as a replacement for
+	  PEM/DER) to get certificate and private key (CONFIG_PKCS12)
+
+2004-12-05 - v0.3.0 (beginning of 0.3.x development releases)
+	* added support for Acct-{Input,Output}-Gigawords
+	* added support for Event-Timestamp (in RADIUS Accounting-Requests)
+	* added support for RADIUS Authentication Client MIB (RFC2618)
+	* added support for RADIUS Accounting Client MIB (RFC2620)
+	* made EAP re-authentication period configurable (eap_reauth_period)
+	* fixed EAPOL reauthentication to trigger WPA/WPA2 reauthentication
+	* fixed EAPOL state machine to stop if STA is removed during
+	  eapol_sm_step(); this fixes at least one segfault triggering bug with
+	  IEEE 802.11i pre-authentication
+	* added support for multiple WPA pre-shared keys (e.g., one for each
+	  client MAC address or keys shared by a group of clients);
+	  new hostapd.conf field wpa_psk_file for setting path to a text file
+	  containing PSKs, see hostapd.wpa_psk for an example
+	* added support for multiple driver interfaces to allow hostapd to be
+	  used with other drivers
+	* added wired authenticator driver interface (driver=wired in
+	  hostapd.conf, see wired.conf for example configuration)
+	* added madwifi driver interface (driver=madwifi in hostapd.conf, see
+	  madwifi.conf for example configuration; Note: include files from
+	  madwifi project is needed for building and a configuration file,
+	  .config, needs to be created in hostapd directory with
+	  CONFIG_DRIVER_MADWIFI=y to include this driver interface in hostapd
+	  build)
+	* fixed an alignment issue that could cause SHA-1 to fail on some
+	  platforms (e.g., Intel ixp425 with a compiler that does not 32-bit
+	  align variables)
+	* fixed RADIUS reconnection after an error in sending interim
+	  accounting packets
+	* added hostapd control interface for external programs and an example
+	  CLI, hostapd_cli (like wpa_cli for wpa_supplicant)
+	* started adding dot11, dot1x, radius MIBs ('hostapd_cli mib',
+	  'hostapd_cli sta <addr>')
+	* finished update from IEEE 802.1X-2001 to IEEE 802.1X-REV (now d11)
+	* added support for strict GTK rekeying (wpa_strict_rekey in
+	  hostapd.conf)
+	* updated IAPP to use UDP port 3517 and multicast address 224.0.1.178
+	  (instead of broadcast) for IAPP ADD-notify (moved from draft 3 to
+	  IEEE 802.11F-2003)
+	* added Prism54 driver interface (driver=prism54 in hostapd.conf;
+	  note: .config needs to be created in hostapd directory with
+	  CONFIG_DRIVER_PRISM54=y to include this driver interface in hostapd
+	  build)
+	* dual-licensed hostapd (GPLv2 and BSD licenses)
+	* fixed RADIUS accounting to generate a new session id for cases where
+	  a station reassociates without first being complete deauthenticated
+	* fixed STA disassociation handler to mark next timeout state to
+	  deauthenticate the station, i.e., skip long wait for inactivity poll
+	  and extra disassociation, if the STA disassociates without
+	  deauthenticating
+	* added integrated EAP authenticator that can be used instead of
+	  external RADIUS authentication server; currently, only EAP-MD5 is
+	  supported, so this cannot yet be used for key distribution; the EAP
+	  method interface is generic, though, so adding new EAP methods should
+	  be straightforward; new hostapd.conf variables: 'eap_authenticator'
+	  and 'eap_user_file'; this obsoletes "minimal authentication server"
+	  ('minimal_eap' in hostapd.conf) which is now removed
+	* added support for FreeBSD and driver interface for the BSD net80211
+	  layer (driver=bsd in hostapd.conf and CONFIG_DRIVER_BSD=y in
+	  .config); please note that some of the required kernel mods have not
+	  yet been committed
+
+2004-07-17 - v0.2.4 (beginning of 0.2.x stable releases)
+	* fixed some accounting cases where Accounting-Start was sent when
+	  IEEE 802.1X port was being deauthorized
+
+2004-06-20 - v0.2.3
+	* modified RADIUS client to re-connect the socket in case of certain
+	  error codes that are generated when a network interface state is
+	  changes (e.g., when IP address changes or the interface is set UP)
+	* fixed couple of cases where EAPOL state for a station was freed
+	  twice causing a segfault for hostapd
+	* fixed couple of bugs in processing WPA deauthentication (freed data
+	  was used)
+
+2004-05-31 - v0.2.2
+	* fixed WPA/WPA2 group rekeying to use key index correctly (GN/GM)
+	* fixed group rekeying to send zero TSC in EAPOL-Key messages to fix
+	  cases where STAs dropped multicast frames as replay attacks
+	* added support for copying RADIUS Attribute 'Class' from
+	  authentication messages into accounting messages
+	* send canned EAP failure if RADIUS server sends Access-Reject without
+	  EAP message (previously, Supplicant was not notified in this case)
+	* fixed mixed WPA-PSK and WPA-EAP mode to work with WPA-PSK (i.e., do
+	  not start EAPOL state machines if the STA selected to use WPA-PSK)
+
+2004-05-06 - v0.2.1
+	* added WPA and IEEE 802.11i/RSN (WPA2) Authenticator functionality
+	  - based on IEEE 802.11i/D10.0 but modified to interoperate with WPA
+	    (i.e., IEEE 802.11i/D3.0)
+	  - supports WPA-only, RSN-only, and mixed WPA/RSN mode
+	  - both WPA-PSK and WPA-RADIUS/EAP are supported
+	  - PMKSA caching and pre-authentication
+	  - new hostapd.conf variables: wpa, wpa_psk, wpa_passphrase,
+	    wpa_key_mgmt, wpa_pairwise, wpa_group_rekey, wpa_gmk_rekey,
+	    rsn_preauth, rsn_preauth_interfaces
+	* fixed interim accounting to remove any pending accounting messages
+	  to the STA before sending a new one
+
+2004-02-15 - v0.2.0
+	* added support for Acct-Interim-Interval:
+	  - draft-ietf-radius-acct-interim-01.txt
+	  - use Acct-Interim-Interval attribute from Access-Accept if local
+	    'radius_acct_interim_interval' is not set
+	  - allow different update intervals for each STA
+	* fixed event loop to call signal handlers only after returning from
+	  the real signal handler
+	* reset sta->timeout_next after successful association to make sure
+	  that the previously registered inactivity timer will not remove the
+	  STA immediately (e.g., if STA deauthenticates and re-associates
+	  before the timer is triggered).
+	* added new hostapd.conf variable, nas_identifier, that can be used to
+	  add an optional RADIUS Attribute, NAS-Identifier, into authentication
+	  and accounting messages
+	* added support for Accounting-On and Accounting-Off messages
+	* fixed accounting session handling to send Accounting-Start only once
+	  per session and not to send Accounting-Stop if the session was not
+	  initialized properly
+	* fixed Accounting-Stop statistics in cases where the message was
+	  previously sent after the kernel entry for the STA (and/or IEEE
+	  802.1X data) was removed
+
+
+Note:
+
+Older changes up to and including v0.1.0 are included in the ChangeLog
+of the Host AP driver.
diff --git a/hostap/hostapd/Makefile b/hostap/hostapd/Makefile
new file mode 100644
index 0000000..d8c01e5
--- /dev/null
+++ b/hostap/hostapd/Makefile
@@ -0,0 +1,907 @@
+ifndef CC
+CC=gcc
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+CFLAGS += -I../src
+CFLAGS += -I../src/utils
+
+# Uncomment following line and set the path to your kernel tree include
+# directory if your C library does not include all header files.
+# CFLAGS += -DUSE_KERNEL_HEADERS -I/usr/src/linux/include
+
+-include .config
+
+ifndef CONFIG_OS
+ifdef CONFIG_NATIVE_WINDOWS
+CONFIG_OS=win32
+else
+CONFIG_OS=unix
+endif
+endif
+
+ifeq ($(CONFIG_OS), internal)
+CFLAGS += -DOS_NO_C_LIB_DEFINES
+endif
+
+ifdef CONFIG_NATIVE_WINDOWS
+CFLAGS += -DCONFIG_NATIVE_WINDOWS
+LIBS += -lws2_32
+endif
+
+OBJS += main.o
+OBJS += config_file.o
+
+OBJS += ../src/ap/hostapd.o
+OBJS += ../src/ap/wpa_auth_glue.o
+OBJS += ../src/ap/drv_callbacks.o
+OBJS += ../src/ap/ap_drv_ops.o
+OBJS += ../src/ap/utils.o
+OBJS += ../src/ap/authsrv.o
+OBJS += ../src/ap/ieee802_1x.o
+OBJS += ../src/ap/ap_config.o
+OBJS += ../src/ap/eap_user_db.o
+OBJS += ../src/ap/ieee802_11_auth.o
+OBJS += ../src/ap/sta_info.o
+OBJS += ../src/ap/wpa_auth.o
+OBJS += ../src/ap/tkip_countermeasures.o
+OBJS += ../src/ap/ap_mlme.o
+OBJS += ../src/ap/wpa_auth_ie.o
+OBJS += ../src/ap/preauth_auth.o
+OBJS += ../src/ap/pmksa_cache_auth.o
+OBJS += ../src/ap/ieee802_11_shared.o
+OBJS += ../src/ap/beacon.o
+
+OBJS_c = hostapd_cli.o ../src/common/wpa_ctrl.o ../src/utils/os_$(CONFIG_OS).o
+
+NEED_RC4=y
+NEED_AES=y
+NEED_MD5=y
+NEED_SHA1=y
+
+OBJS += ../src/drivers/drivers.o
+CFLAGS += -DHOSTAPD
+
+ifdef CONFIG_WPA_TRACE
+CFLAGS += -DWPA_TRACE
+OBJS += ../src/utils/trace.o
+HOBJS += ../src/utils/trace.o
+LDFLAGS += -rdynamic
+CFLAGS += -funwind-tables
+ifdef CONFIG_WPA_TRACE_BFD
+CFLAGS += -DWPA_TRACE_BFD
+LIBS += -lbfd
+LIBS_c += -lbfd
+LIBS_h += -lbfd
+endif
+endif
+
+ifndef CONFIG_ELOOP
+CONFIG_ELOOP=eloop
+endif
+OBJS += ../src/utils/$(CONFIG_ELOOP).o
+OBJS_c += ../src/utils/$(CONFIG_ELOOP).o
+OBJS += ../src/utils/common.o
+OBJS += ../src/utils/wpa_debug.o
+OBJS_c += ../src/utils/wpa_debug.o
+OBJS += ../src/utils/wpabuf.o
+OBJS += ../src/utils/os_$(CONFIG_OS).o
+OBJS += ../src/utils/ip_addr.o
+
+OBJS += ../src/common/ieee802_11_common.o
+OBJS += ../src/common/wpa_common.o
+
+OBJS += ../src/eapol_auth/eapol_auth_sm.o
+
+
+ifndef CONFIG_NO_DUMP_STATE
+# define HOSTAPD_DUMP_STATE to include SIGUSR1 handler for dumping state to
+# a file (undefine it, if you want to save in binary size)
+CFLAGS += -DHOSTAPD_DUMP_STATE
+OBJS += dump_state.o
+OBJS += ../src/eapol_auth/eapol_auth_dump.o
+endif
+
+ifdef CONFIG_NO_RADIUS
+CFLAGS += -DCONFIG_NO_RADIUS
+CONFIG_NO_ACCOUNTING=y
+else
+OBJS += ../src/radius/radius.o
+OBJS += ../src/radius/radius_client.o
+OBJS += ../src/radius/radius_das.o
+endif
+
+ifdef CONFIG_NO_ACCOUNTING
+CFLAGS += -DCONFIG_NO_ACCOUNTING
+else
+OBJS += ../src/ap/accounting.o
+endif
+
+ifdef CONFIG_NO_VLAN
+CFLAGS += -DCONFIG_NO_VLAN
+else
+OBJS += ../src/ap/vlan_init.o
+ifdef CONFIG_VLAN_NETLINK
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+OBJS += ../src/ap/vlan_util.o
+endif
+CFLAGS += -DCONFIG_VLAN_NETLINK
+endif
+endif
+
+ifdef CONFIG_NO_CTRL_IFACE
+CFLAGS += -DCONFIG_NO_CTRL_IFACE
+else
+OBJS += ctrl_iface.o
+OBJS += ../src/ap/ctrl_iface_ap.o
+endif
+
+OBJS += ../src/crypto/md5.o
+
+CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
+
+ifdef CONFIG_IAPP
+CFLAGS += -DCONFIG_IAPP
+OBJS += ../src/ap/iapp.o
+endif
+
+ifdef CONFIG_RSN_PREAUTH
+CFLAGS += -DCONFIG_RSN_PREAUTH
+CONFIG_L2_PACKET=y
+endif
+
+ifdef CONFIG_PEERKEY
+CFLAGS += -DCONFIG_PEERKEY
+OBJS += ../src/ap/peerkey_auth.o
+endif
+
+ifdef CONFIG_IEEE80211W
+CFLAGS += -DCONFIG_IEEE80211W
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211R
+OBJS += ../src/ap/wpa_auth_ft.o
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+NEED_AES_UNWRAP=y
+endif
+
+ifdef CONFIG_SAE
+CFLAGS += -DCONFIG_SAE
+endif
+
+ifdef CONFIG_WNM
+CFLAGS += -DCONFIG_WNM
+OBJS += ../src/ap/wnm_ap.o
+endif
+
+ifdef CONFIG_IEEE80211N
+CFLAGS += -DCONFIG_IEEE80211N
+endif
+
+ifdef CONFIG_IEEE80211AC
+CFLAGS += -DCONFIG_IEEE80211AC
+endif
+
+include ../src/drivers/drivers.mak
+OBJS += $(DRV_AP_OBJS)
+CFLAGS += $(DRV_AP_CFLAGS)
+LDFLAGS += $(DRV_AP_LDFLAGS)
+LIBS += $(DRV_AP_LIBS)
+
+ifdef CONFIG_L2_PACKET
+ifdef CONFIG_DNET_PCAP
+ifdef CONFIG_L2_FREEBSD
+LIBS += -lpcap
+OBJS += ../src/l2_packet/l2_packet_freebsd.o
+else
+LIBS += -ldnet -lpcap
+OBJS += ../src/l2_packet/l2_packet_pcap.o
+endif
+else
+OBJS += ../src/l2_packet/l2_packet_linux.o
+endif
+else
+OBJS += ../src/l2_packet/l2_packet_none.o
+endif
+
+
+ifdef CONFIG_EAP_MD5
+CFLAGS += -DEAP_SERVER_MD5
+OBJS += ../src/eap_server/eap_server_md5.o
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_TLS
+CFLAGS += -DEAP_SERVER_TLS
+OBJS += ../src/eap_server/eap_server_tls.o
+TLS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_UNAUTH_TLS
+CFLAGS += -DEAP_SERVER_UNAUTH_TLS
+ifndef CONFIG_EAP_TLS
+OBJS += ../src/eap_server/eap_server_tls.o
+TLS_FUNCS=y
+endif
+endif
+
+ifdef CONFIG_EAP_PEAP
+CFLAGS += -DEAP_SERVER_PEAP
+OBJS += ../src/eap_server/eap_server_peap.o
+OBJS += ../src/eap_common/eap_peap_common.o
+TLS_FUNCS=y
+CONFIG_EAP_MSCHAPV2=y
+endif
+
+ifdef CONFIG_EAP_TTLS
+CFLAGS += -DEAP_SERVER_TTLS
+OBJS += ../src/eap_server/eap_server_ttls.o
+TLS_FUNCS=y
+CHAP=y
+endif
+
+ifdef CONFIG_EAP_MSCHAPV2
+CFLAGS += -DEAP_SERVER_MSCHAPV2
+OBJS += ../src/eap_server/eap_server_mschapv2.o
+MS_FUNCS=y
+endif
+
+ifdef CONFIG_EAP_GTC
+CFLAGS += -DEAP_SERVER_GTC
+OBJS += ../src/eap_server/eap_server_gtc.o
+endif
+
+ifdef CONFIG_EAP_SIM
+CFLAGS += -DEAP_SERVER_SIM
+OBJS += ../src/eap_server/eap_server_sim.o
+CONFIG_EAP_SIM_COMMON=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA
+CFLAGS += -DEAP_SERVER_AKA
+OBJS += ../src/eap_server/eap_server_aka.o
+CONFIG_EAP_SIM_COMMON=y
+NEED_SHA256=y
+NEED_AES_CBC=y
+endif
+
+ifdef CONFIG_EAP_AKA_PRIME
+CFLAGS += -DEAP_SERVER_AKA_PRIME
+endif
+
+ifdef CONFIG_EAP_SIM_COMMON
+OBJS += ../src/eap_common/eap_sim_common.o
+# Example EAP-SIM/AKA interface for GSM/UMTS authentication. This can be
+# replaced with another file implementating the interface specified in
+# eap_sim_db.h.
+OBJS += ../src/eap_server/eap_sim_db.o
+NEED_FIPS186_2_PRF=y
+endif
+
+ifdef CONFIG_EAP_PAX
+CFLAGS += -DEAP_SERVER_PAX
+OBJS += ../src/eap_server/eap_server_pax.o ../src/eap_common/eap_pax_common.o
+endif
+
+ifdef CONFIG_EAP_PSK
+CFLAGS += -DEAP_SERVER_PSK
+OBJS += ../src/eap_server/eap_server_psk.o ../src/eap_common/eap_psk_common.o
+NEED_AES_OMAC1=y
+NEED_AES_ENCBLOCK=y
+NEED_AES_EAX=y
+endif
+
+ifdef CONFIG_EAP_SAKE
+CFLAGS += -DEAP_SERVER_SAKE
+OBJS += ../src/eap_server/eap_server_sake.o ../src/eap_common/eap_sake_common.o
+endif
+
+ifdef CONFIG_EAP_GPSK
+CFLAGS += -DEAP_SERVER_GPSK
+OBJS += ../src/eap_server/eap_server_gpsk.o ../src/eap_common/eap_gpsk_common.o
+ifdef CONFIG_EAP_GPSK_SHA256
+CFLAGS += -DEAP_SERVER_GPSK_SHA256
+endif
+NEED_SHA256=y
+NEED_AES_OMAC1=y
+endif
+
+ifdef CONFIG_EAP_PWD
+CFLAGS += -DEAP_SERVER_PWD
+OBJS += ../src/eap_server/eap_server_pwd.o ../src/eap_common/eap_pwd_common.o
+NEED_SHA256=y
+endif
+
+ifdef CONFIG_EAP_VENDOR_TEST
+CFLAGS += -DEAP_SERVER_VENDOR_TEST
+OBJS += ../src/eap_server/eap_server_vendor_test.o
+endif
+
+ifdef CONFIG_EAP_FAST
+CFLAGS += -DEAP_SERVER_FAST
+OBJS += ../src/eap_server/eap_server_fast.o
+OBJS += ../src/eap_common/eap_fast_common.o
+TLS_FUNCS=y
+NEED_T_PRF=y
+NEED_AES_UNWRAP=y
+endif
+
+ifdef CONFIG_WPS
+ifdef CONFIG_WPS2
+CFLAGS += -DCONFIG_WPS2
+endif
+
+CFLAGS += -DCONFIG_WPS -DEAP_SERVER_WSC
+OBJS += ../src/utils/uuid.o
+OBJS += ../src/ap/wps_hostapd.o
+OBJS += ../src/eap_server/eap_server_wsc.o ../src/eap_common/eap_wsc_common.o
+OBJS += ../src/wps/wps.o
+OBJS += ../src/wps/wps_common.o
+OBJS += ../src/wps/wps_attr_parse.o
+OBJS += ../src/wps/wps_attr_build.o
+OBJS += ../src/wps/wps_attr_process.o
+OBJS += ../src/wps/wps_dev_attr.o
+OBJS += ../src/wps/wps_enrollee.o
+OBJS += ../src/wps/wps_registrar.o
+NEED_DH_GROUPS=y
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_AES_CBC=y
+NEED_MODEXP=y
+CONFIG_EAP=y
+
+ifdef CONFIG_WPS_NFC
+CFLAGS += -DCONFIG_WPS_NFC
+OBJS += ../src/wps/ndef.o
+NEED_WPS_OOB=y
+endif
+
+ifdef NEED_WPS_OOB
+CFLAGS += -DCONFIG_WPS_OOB
+endif
+
+ifdef CONFIG_WPS_UPNP
+CFLAGS += -DCONFIG_WPS_UPNP
+OBJS += ../src/wps/wps_upnp.o
+OBJS += ../src/wps/wps_upnp_ssdp.o
+OBJS += ../src/wps/wps_upnp_web.o
+OBJS += ../src/wps/wps_upnp_event.o
+OBJS += ../src/wps/wps_upnp_ap.o
+OBJS += ../src/wps/upnp_xml.o
+OBJS += ../src/wps/httpread.o
+OBJS += ../src/wps/http_client.o
+OBJS += ../src/wps/http_server.o
+endif
+
+ifdef CONFIG_WPS_STRICT
+CFLAGS += -DCONFIG_WPS_STRICT
+OBJS += ../src/wps/wps_validate.o
+endif
+
+ifdef CONFIG_WPS_TESTING
+CFLAGS += -DCONFIG_WPS_TESTING
+endif
+
+endif
+
+ifdef CONFIG_EAP_IKEV2
+CFLAGS += -DEAP_SERVER_IKEV2
+OBJS += ../src/eap_server/eap_server_ikev2.o ../src/eap_server/ikev2.o
+OBJS += ../src/eap_common/eap_ikev2_common.o ../src/eap_common/ikev2_common.o
+NEED_DH_GROUPS=y
+NEED_DH_GROUPS_ALL=y
+NEED_MODEXP=y
+NEED_CIPHER=y
+endif
+
+ifdef CONFIG_EAP_TNC
+CFLAGS += -DEAP_SERVER_TNC
+OBJS += ../src/eap_server/eap_server_tnc.o
+OBJS += ../src/eap_server/tncs.o
+NEED_BASE64=y
+ifndef CONFIG_DRIVER_BSD
+LIBS += -ldl
+endif
+endif
+
+# Basic EAP functionality is needed for EAPOL
+OBJS += eap_register.o
+OBJS += ../src/eap_server/eap_server.o
+OBJS += ../src/eap_common/eap_common.o
+OBJS += ../src/eap_server/eap_server_methods.o
+OBJS += ../src/eap_server/eap_server_identity.o
+CFLAGS += -DEAP_SERVER_IDENTITY
+
+ifdef CONFIG_EAP
+CFLAGS += -DEAP_SERVER
+endif
+
+ifdef CONFIG_PKCS12
+CFLAGS += -DPKCS12_FUNCS
+endif
+
+ifdef MS_FUNCS
+OBJS += ../src/crypto/ms_funcs.o
+NEED_DES=y
+NEED_MD4=y
+endif
+
+ifdef CHAP
+OBJS += ../src/eap_common/chap.o
+endif
+
+ifdef TLS_FUNCS
+NEED_DES=y
+# Shared TLS functions (needed for EAP_TLS, EAP_PEAP, and EAP_TTLS)
+CFLAGS += -DEAP_TLS_FUNCS
+OBJS += ../src/eap_server/eap_server_tls_common.o
+NEED_TLS_PRF=y
+endif
+
+ifndef CONFIG_TLS
+CONFIG_TLS=openssl
+endif
+
+ifdef CONFIG_TLSV11
+CFLAGS += -DCONFIG_TLSV11
+endif
+
+ifdef CONFIG_TLSV12
+CFLAGS += -DCONFIG_TLSV12
+NEED_SHA256=y
+endif
+
+ifeq ($(CONFIG_TLS), openssl)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_openssl.o
+LIBS += -lssl
+endif
+OBJS += ../src/crypto/crypto_openssl.o
+HOBJS += ../src/crypto/crypto_openssl.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_openssl.o
+endif
+LIBS += -lcrypto
+LIBS_h += -lcrypto
+endif
+
+ifeq ($(CONFIG_TLS), gnutls)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_gnutls.o
+LIBS += -lgnutls -lgpg-error
+endif
+OBJS += ../src/crypto/crypto_gnutls.o
+HOBJS += ../src/crypto/crypto_gnutls.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_gnutls.o
+endif
+LIBS += -lgcrypt
+LIBS_h += -lgcrypt
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), schannel)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_schannel.o
+endif
+OBJS += ../src/crypto/crypto_cryptoapi.o
+OBJS_p += ../src/crypto/crypto_cryptoapi.o
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), nss)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_nss.o
+LIBS += -lssl3
+endif
+OBJS += ../src/crypto/crypto_nss.o
+ifdef NEED_FIPS186_2_PRF
+OBJS += ../src/crypto/fips_prf_nss.o
+endif
+LIBS += -lnss3
+LIBS_h += -lnss3
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+
+ifeq ($(CONFIG_TLS), internal)
+ifndef CONFIG_CRYPTO
+CONFIG_CRYPTO=internal
+endif
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/crypto_internal-rsa.o
+OBJS += ../src/crypto/tls_internal.o
+OBJS += ../src/tls/tlsv1_common.o
+OBJS += ../src/tls/tlsv1_record.o
+OBJS += ../src/tls/tlsv1_cred.o
+OBJS += ../src/tls/tlsv1_server.o
+OBJS += ../src/tls/tlsv1_server_write.o
+OBJS += ../src/tls/tlsv1_server_read.o
+OBJS += ../src/tls/asn1.o
+OBJS += ../src/tls/rsa.o
+OBJS += ../src/tls/x509v3.o
+OBJS += ../src/tls/pkcs1.o
+OBJS += ../src/tls/pkcs5.o
+OBJS += ../src/tls/pkcs8.o
+NEED_SHA256=y
+NEED_BASE64=y
+NEED_TLS_PRF=y
+ifdef CONFIG_TLSV12
+NEED_TLS_PRF_SHA256=y
+endif
+NEED_MODEXP=y
+NEED_CIPHER=y
+CFLAGS += -DCONFIG_TLS_INTERNAL
+CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+endif
+ifdef NEED_CIPHER
+NEED_DES=y
+OBJS += ../src/crypto/crypto_internal-cipher.o
+endif
+ifdef NEED_MODEXP
+OBJS += ../src/crypto/crypto_internal-modexp.o
+OBJS += ../src/tls/bignum.o
+endif
+ifeq ($(CONFIG_CRYPTO), libtomcrypt)
+OBJS += ../src/crypto/crypto_libtomcrypt.o
+LIBS += -ltomcrypt -ltfm
+LIBS_h += -ltomcrypt -ltfm
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), internal)
+OBJS += ../src/crypto/crypto_internal.o
+NEED_AES_DEC=y
+CFLAGS += -DCONFIG_CRYPTO_INTERNAL
+ifdef CONFIG_INTERNAL_LIBTOMMATH
+CFLAGS += -DCONFIG_INTERNAL_LIBTOMMATH
+ifdef CONFIG_INTERNAL_LIBTOMMATH_FAST
+CFLAGS += -DLTM_FAST
+endif
+else
+LIBS += -ltommath
+LIBS_h += -ltommath
+endif
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_DES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD4=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+CONFIG_INTERNAL_DH_GROUP5=y
+endif
+ifeq ($(CONFIG_CRYPTO), cryptoapi)
+OBJS += ../src/crypto/crypto_cryptoapi.o
+OBJS_p += ../src/crypto/crypto_cryptoapi.o
+CFLAGS += -DCONFIG_CRYPTO_CRYPTOAPI
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+ifeq ($(CONFIG_TLS), none)
+ifdef TLS_FUNCS
+OBJS += ../src/crypto/tls_none.o
+CFLAGS += -DEAP_TLS_NONE
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+endif
+OBJS += ../src/crypto/crypto_none.o
+OBJS_p += ../src/crypto/crypto_none.o
+CONFIG_INTERNAL_SHA256=y
+CONFIG_INTERNAL_RC4=y
+endif
+
+ifndef TLS_FUNCS
+OBJS += ../src/crypto/tls_none.o
+ifeq ($(CONFIG_TLS), internal)
+CONFIG_INTERNAL_AES=y
+CONFIG_INTERNAL_SHA1=y
+CONFIG_INTERNAL_MD5=y
+CONFIG_INTERNAL_RC4=y
+endif
+endif
+
+AESOBJS = # none so far
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-enc.o
+endif
+
+AESOBJS += ../src/crypto/aes-wrap.o
+ifdef NEED_AES_EAX
+AESOBJS += ../src/crypto/aes-eax.o
+NEED_AES_CTR=y
+endif
+ifdef NEED_AES_CTR
+AESOBJS += ../src/crypto/aes-ctr.o
+endif
+ifdef NEED_AES_ENCBLOCK
+AESOBJS += ../src/crypto/aes-encblock.o
+endif
+ifdef NEED_AES_OMAC1
+AESOBJS += ../src/crypto/aes-omac1.o
+endif
+ifdef NEED_AES_UNWRAP
+NEED_AES_DEC=y
+AESOBJS += ../src/crypto/aes-unwrap.o
+endif
+ifdef NEED_AES_CBC
+NEED_AES_DEC=y
+AESOBJS += ../src/crypto/aes-cbc.o
+endif
+ifdef NEED_AES_DEC
+ifdef CONFIG_INTERNAL_AES
+AESOBJS += ../src/crypto/aes-internal-dec.o
+endif
+endif
+ifdef NEED_AES
+OBJS += $(AESOBJS)
+endif
+
+ifdef NEED_SHA1
+ifneq ($(CONFIG_TLS), openssl)
+SHA1OBJS += ../src/crypto/sha1.o
+endif
+SHA1OBJS += ../src/crypto/sha1-prf.o
+ifdef CONFIG_INTERNAL_SHA1
+SHA1OBJS += ../src/crypto/sha1-internal.o
+ifdef NEED_FIPS186_2_PRF
+SHA1OBJS += ../src/crypto/fips_prf_internal.o
+endif
+endif
+ifneq ($(CONFIG_TLS), openssl)
+SHA1OBJS += ../src/crypto/sha1-pbkdf2.o
+endif
+ifdef NEED_T_PRF
+SHA1OBJS += ../src/crypto/sha1-tprf.o
+endif
+ifdef NEED_TLS_PRF
+SHA1OBJS += ../src/crypto/sha1-tlsprf.o
+endif
+endif
+
+ifdef NEED_SHA1
+OBJS += $(SHA1OBJS)
+endif
+
+ifdef NEED_MD5
+ifdef CONFIG_INTERNAL_MD5
+OBJS += ../src/crypto/md5-internal.o
+HOBJS += ../src/crypto/md5-internal.o
+endif
+endif
+
+ifdef NEED_MD4
+ifdef CONFIG_INTERNAL_MD4
+OBJS += ../src/crypto/md4-internal.o
+endif
+endif
+
+ifdef NEED_DES
+ifdef CONFIG_INTERNAL_DES
+OBJS += ../src/crypto/des-internal.o
+endif
+endif
+
+ifdef NEED_RC4
+ifdef CONFIG_INTERNAL_RC4
+OBJS += ../src/crypto/rc4.o
+endif
+endif
+
+ifdef NEED_SHA256
+CFLAGS += -DCONFIG_SHA256
+ifneq ($(CONFIG_TLS), openssl)
+OBJS += ../src/crypto/sha256.o
+endif
+OBJS += ../src/crypto/sha256-prf.o
+ifdef CONFIG_INTERNAL_SHA256
+OBJS += ../src/crypto/sha256-internal.o
+endif
+ifdef NEED_TLS_PRF_SHA256
+OBJS += ../src/crypto/sha256-tlsprf.o
+endif
+endif
+
+ifdef NEED_DH_GROUPS
+OBJS += ../src/crypto/dh_groups.o
+endif
+ifdef NEED_DH_GROUPS_ALL
+CFLAGS += -DALL_DH_GROUPS
+endif
+ifdef CONFIG_INTERNAL_DH_GROUP5
+ifdef NEED_DH_GROUPS
+OBJS += ../src/crypto/dh_group5.o
+endif
+endif
+
+ifdef CONFIG_NO_RANDOM_POOL
+CFLAGS += -DCONFIG_NO_RANDOM_POOL
+else
+OBJS += ../src/crypto/random.o
+HOBJS += ../src/crypto/random.o
+HOBJS += ../src/utils/eloop.o
+HOBJS += $(SHA1OBJS)
+HOBJS += ../src/crypto/md5.o
+endif
+
+ifdef CONFIG_RADIUS_SERVER
+CFLAGS += -DRADIUS_SERVER
+OBJS += ../src/radius/radius_server.o
+endif
+
+ifdef CONFIG_IPV6
+CFLAGS += -DCONFIG_IPV6
+endif
+
+ifdef CONFIG_DRIVER_RADIUS_ACL
+CFLAGS += -DCONFIG_DRIVER_RADIUS_ACL
+endif
+
+ifdef CONFIG_FULL_DYNAMIC_VLAN
+# define CONFIG_FULL_DYNAMIC_VLAN to have hostapd manipulate bridges
+# and vlan interfaces for the vlan feature.
+CFLAGS += -DCONFIG_FULL_DYNAMIC_VLAN
+endif
+
+ifdef NEED_BASE64
+OBJS += ../src/utils/base64.o
+endif
+
+ifdef NEED_AP_MLME
+OBJS += ../src/ap/wmm.o
+OBJS += ../src/ap/ap_list.o
+OBJS += ../src/ap/ieee802_11.o
+OBJS += ../src/ap/hw_features.o
+CFLAGS += -DNEED_AP_MLME
+endif
+ifdef CONFIG_IEEE80211N
+OBJS += ../src/ap/ieee802_11_ht.o
+endif
+
+ifdef CONFIG_IEEE80211AC
+OBJS += ../src/ap/ieee802_11_vht.o
+endif
+
+ifdef CONFIG_P2P_MANAGER
+CFLAGS += -DCONFIG_P2P_MANAGER
+OBJS += ../src/ap/p2p_hostapd.o
+endif
+
+ifdef CONFIG_HS20
+CFLAGS += -DCONFIG_HS20
+OBJS += ../src/ap/hs20.o
+CONFIG_INTERWORKING=y
+endif
+
+ifdef CONFIG_INTERWORKING
+CFLAGS += -DCONFIG_INTERWORKING
+OBJS += ../src/common/gas.o
+OBJS += ../src/ap/gas_serv.o
+endif
+
+OBJS += ../src/drivers/driver_common.o
+
+ifdef CONFIG_WPA_CLI_EDIT
+OBJS_c += ../src/utils/edit.o
+else
+OBJS_c += ../src/utils/edit_simple.o
+endif
+
+ifdef CONFIG_NO_STDOUT_DEBUG
+CFLAGS += -DCONFIG_NO_STDOUT_DEBUG
+endif
+
+ifdef CONFIG_DEBUG_FILE
+CFLAGS += -DCONFIG_DEBUG_FILE
+endif
+
+ifdef CONFIG_SQLITE
+CFLAGS += -DCONFIG_SQLITE
+LIBS += -lsqlite3
+LIBS_h += -lsqlite3
+endif
+
+ALL=hostapd hostapd_cli
+
+all: verify_config $(ALL)
+
+Q=@
+E=echo
+ifeq ($(V), 1)
+Q=
+E=true
+endif
+
+%.o: %.c
+	$(Q)$(CC) -c -o $@ $(CFLAGS) $<
+	@$(E) "  CC " $<
+
+verify_config:
+	@if [ ! -r .config ]; then \
+		echo 'Building hostapd requires a configuration file'; \
+		echo '(.config). See README for more instructions. You can'; \
+		echo 'run "cp defconfig .config" to create an example'; \
+		echo 'configuration.'; \
+		exit 1; \
+	fi
+
+install: all
+	mkdir -p $(DESTDIR)/usr/local/bin
+	for i in $(ALL); do cp -f $$i $(DESTDIR)/usr/local/bin/$$i; done
+
+../src/drivers/build.hostapd:
+	@if [ -f ../src/drivers/build.wpa_supplicant ]; then \
+		$(MAKE) -C ../src/drivers clean; \
+	fi
+	@touch ../src/drivers/build.hostapd
+
+BCHECK=../src/drivers/build.hostapd
+
+hostapd: $(BCHECK) $(OBJS)
+	$(Q)$(CC) $(LDFLAGS) -o hostapd $(OBJS) $(LIBS)
+	@$(E) "  LD " $@
+
+ifdef CONFIG_WPA_TRACE
+OBJS_c += ../src/utils/trace.o
+endif
+hostapd_cli: $(OBJS_c)
+	$(Q)$(CC) $(LDFLAGS) -o hostapd_cli $(OBJS_c) $(LIBS_c)
+	@$(E) "  LD " $@
+
+NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o $(SHA1OBJS) ../src/crypto/md5.o
+ifdef NEED_RC4
+ifdef CONFIG_INTERNAL_RC4
+NOBJS += ../src/crypto/rc4.o
+endif
+endif
+ifdef CONFIG_INTERNAL_MD5
+NOBJS += ../src/crypto/md5-internal.o
+endif
+NOBJS += ../src/crypto/crypto_openssl.o ../src/utils/os_$(CONFIG_OS).o
+NOBJS += ../src/utils/wpa_debug.o
+NOBJS += ../src/utils/wpabuf.o
+ifdef CONFIG_WPA_TRACE
+NOBJS += ../src/utils/trace.o
+LIBS_n += -lbfd
+endif
+ifdef TLS_FUNCS
+LIBS_n += -lcrypto
+endif
+
+HOBJS += hlr_auc_gw.o ../src/utils/common.o ../src/utils/wpa_debug.o ../src/utils/os_$(CONFIG_OS).o ../src/utils/wpabuf.o ../src/crypto/milenage.o
+HOBJS += ../src/crypto/aes-encblock.o
+ifdef CONFIG_INTERNAL_AES
+HOBJS += ../src/crypto/aes-internal.o
+HOBJS += ../src/crypto/aes-internal-enc.o
+endif
+
+nt_password_hash: $(NOBJS)
+	$(Q)$(CC) $(LDFLAGS) -o nt_password_hash $(NOBJS) $(LIBS_n)
+	@$(E) "  LD " $@
+
+hlr_auc_gw: $(HOBJS)
+	$(Q)$(CC) $(LDFLAGS) -o hlr_auc_gw $(HOBJS) $(LIBS_h)
+	@$(E) "  LD " $@
+
+clean:
+	$(MAKE) -C ../src clean
+	rm -f core *~ *.o hostapd hostapd_cli nt_password_hash hlr_auc_gw
+	rm -f *.d
+
+-include $(OBJS:%.o=%.d)
diff --git a/hostap/hostapd/README b/hostap/hostapd/README
new file mode 100644
index 0000000..34dad30
--- /dev/null
+++ b/hostap/hostapd/README
@@ -0,0 +1,372 @@
+hostapd - user space IEEE 802.11 AP and IEEE 802.1X/WPA/WPA2/EAP
+	  Authenticator and RADIUS authentication server
+================================================================
+
+Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+All Rights Reserved.
+
+This program is licensed under the BSD license (the one with
+advertisement clause removed).
+
+If you are submitting changes to the project, please see CONTRIBUTIONS
+file for more instructions.
+
+
+
+License
+-------
+
+This software may be distributed, used, and modified under the terms of
+BSD license:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+3. Neither the name(s) of the above-listed copyright holder(s) nor the
+   names of its contributors may be used to endorse or promote products
+   derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+
+Introduction
+============
+
+Originally, hostapd was an optional user space component for Host AP
+driver. It adds more features to the basic IEEE 802.11 management
+included in the kernel driver: using external RADIUS authentication
+server for MAC address based access control, IEEE 802.1X Authenticator
+and dynamic WEP keying, RADIUS accounting, WPA/WPA2 (IEEE 802.11i/RSN)
+Authenticator and dynamic TKIP/CCMP keying.
+
+The current version includes support for other drivers, an integrated
+EAP server (i.e., allow full authentication without requiring
+an external RADIUS authentication server), and RADIUS authentication
+server for EAP authentication.
+
+
+Requirements
+------------
+
+Current hardware/software requirements:
+- drivers:
+	Host AP driver for Prism2/2.5/3.
+	(http://hostap.epitest.fi/)
+	Please note that station firmware version needs to be 1.7.0 or newer
+	to work in WPA mode.
+
+	madwifi driver for cards based on Atheros chip set (ar521x)
+	(http://sourceforge.net/projects/madwifi/)
+	Please note that you will need to add the correct path for
+	madwifi driver root directory in .config (see defconfig file for
+	an example: CFLAGS += -I<path>)
+
+	mac80211-based drivers that support AP mode (with driver=nl80211).
+	This includes drivers for Atheros (ath9k) and Broadcom (b43)
+	chipsets.
+
+	Any wired Ethernet driver for wired IEEE 802.1X authentication
+	(experimental code)
+
+	FreeBSD -current (with some kernel mods that have not yet been
+	committed when hostapd v0.3.0 was released)
+	BSD net80211 layer (e.g., Atheros driver)
+
+
+Build configuration
+-------------------
+
+In order to be able to build hostapd, you will need to create a build
+time configuration file, .config that selects which optional
+components are included. See defconfig file for example configuration
+and list of available options.
+
+
+
+IEEE 802.1X
+===========
+
+IEEE Std 802.1X-2001 is a standard for port-based network access
+control. In case of IEEE 802.11 networks, a "virtual port" is used
+between each associated station and the AP. IEEE 802.11 specifies
+minimal authentication mechanism for stations, whereas IEEE 802.1X
+introduces a extensible mechanism for authenticating and authorizing
+users.
+
+IEEE 802.1X uses elements called Supplicant, Authenticator, Port
+Access Entity, and Authentication Server. Supplicant is a component in
+a station and it performs the authentication with the Authentication
+Server. An access point includes an Authenticator that relays the packets
+between a Supplicant and an Authentication Server. In addition, it has a
+Port Access Entity (PAE) with Authenticator functionality for
+controlling the virtual port authorization, i.e., whether to accept
+packets from or to the station.
+
+IEEE 802.1X uses Extensible Authentication Protocol (EAP). The frames
+between a Supplicant and an Authenticator are sent using EAP over LAN
+(EAPOL) and the Authenticator relays these frames to the Authentication
+Server (and similarly, relays the messages from the Authentication
+Server to the Supplicant). The Authentication Server can be colocated with the
+Authenticator, in which case there is no need for additional protocol
+for EAP frame transmission. However, a more common configuration is to
+use an external Authentication Server and encapsulate EAP frame in the
+frames used by that server. RADIUS is suitable for this, but IEEE
+802.1X would also allow other mechanisms.
+
+Host AP driver includes PAE functionality in the kernel driver. It
+is a relatively simple mechanism for denying normal frames going to
+or coming from an unauthorized port. PAE allows IEEE 802.1X related
+frames to be passed between the Supplicant and the Authenticator even
+on an unauthorized port.
+
+User space daemon, hostapd, includes Authenticator functionality. It
+receives 802.1X (EAPOL) frames from the Supplicant using the wlan#ap
+device that is also used with IEEE 802.11 management frames. The
+frames to the Supplicant are sent using the same device.
+
+The normal configuration of the Authenticator would use an external
+Authentication Server. hostapd supports RADIUS encapsulation of EAP
+packets, so the Authentication Server should be a RADIUS server, like
+FreeRADIUS (http://www.freeradius.org/). The Authenticator in hostapd
+relays the frames between the Supplicant and the Authentication
+Server. It also controls the PAE functionality in the kernel driver by
+controlling virtual port authorization, i.e., station-AP
+connection, based on the IEEE 802.1X state.
+
+When a station would like to use the services of an access point, it
+will first perform IEEE 802.11 authentication. This is normally done
+with open systems authentication, so there is no security. After
+this, IEEE 802.11 association is performed. If IEEE 802.1X is
+configured to be used, the virtual port for the station is set in
+Unauthorized state and only IEEE 802.1X frames are accepted at this
+point. The Authenticator will then ask the Supplicant to authenticate
+with the Authentication Server. After this is completed successfully,
+the virtual port is set to Authorized state and frames from and to the
+station are accepted.
+
+Host AP configuration for IEEE 802.1X
+-------------------------------------
+
+The user space daemon has its own configuration file that can be used to
+define AP options. Distribution package contains an example
+configuration file (hostapd/hostapd.conf) that can be used as a basis
+for configuration. It includes examples of all supported configuration
+options and short description of each option. hostapd should be started
+with full path to the configuration file as the command line argument,
+e.g., './hostapd /etc/hostapd.conf'. If you have more that one wireless
+LAN card, you can use one hostapd process for multiple interfaces by
+giving a list of configuration files (one per interface) in the command
+line.
+
+hostapd includes a minimal co-located IEEE 802.1X server which can be
+used to test IEEE 802.1X authentication. However, it should not be
+used in normal use since it does not provide any security. This can be
+configured by setting ieee8021x and minimal_eap options in the
+configuration file.
+
+An external Authentication Server (RADIUS) is configured with
+auth_server_{addr,port,shared_secret} options. In addition,
+ieee8021x and own_ip_addr must be set for this mode. With such
+configuration, the co-located Authentication Server is not used and EAP
+frames will be relayed using EAPOL between the Supplicant and the
+Authenticator and RADIUS encapsulation between the Authenticator and
+the Authentication Server. Other than this, the functionality is similar
+to the case with the co-located Authentication Server.
+
+Authentication Server and Supplicant
+------------------------------------
+
+Any RADIUS server supporting EAP should be usable as an IEEE 802.1X
+Authentication Server with hostapd Authenticator. FreeRADIUS
+(http://www.freeradius.org/) has been successfully tested with hostapd
+Authenticator and both Xsupplicant (http://www.open1x.org) and Windows
+XP Supplicants. EAP/TLS was used with Xsupplicant and
+EAP/MD5-Challenge with Windows XP.
+
+http://www.missl.cs.umd.edu/wireless/eaptls/ has useful information
+about using EAP/TLS with FreeRADIUS and Xsupplicant (just replace
+Cisco access point with Host AP driver, hostapd daemon, and a Prism2
+card ;-). http://www.freeradius.org/doc/EAP-MD5.html has information
+about using EAP/MD5 with FreeRADIUS, including instructions for WinXP
+configuration. http://www.denobula.com/EAPTLS.pdf has a HOWTO on
+EAP/TLS use with WinXP Supplicant.
+
+Automatic WEP key configuration
+-------------------------------
+
+EAP/TLS generates a session key that can be used to send WEP keys from
+an AP to authenticated stations. The Authenticator in hostapd can be
+configured to automatically select a random default/broadcast key
+(shared by all authenticated stations) with wep_key_len_broadcast
+option (5 for 40-bit WEP or 13 for 104-bit WEP). In addition,
+wep_key_len_unicast option can be used to configure individual unicast
+keys for stations. This requires support for individual keys in the
+station driver.
+
+WEP keys can be automatically updated by configuring rekeying. This
+will improve security of the network since same WEP key will only be
+used for a limited period of time. wep_rekey_period option sets the
+interval for rekeying in seconds.
+
+
+WPA/WPA2
+========
+
+Features
+--------
+
+Supported WPA/IEEE 802.11i features:
+- WPA-PSK ("WPA-Personal")
+- WPA with EAP (e.g., with RADIUS authentication server) ("WPA-Enterprise")
+- key management for CCMP, TKIP, WEP104, WEP40
+- RSN/WPA2 (IEEE 802.11i), including PMKSA caching and pre-authentication
+
+WPA
+---
+
+The original security mechanism of IEEE 802.11 standard was not
+designed to be strong and has proved to be insufficient for most
+networks that require some kind of security. Task group I (Security)
+of IEEE 802.11 working group (http://www.ieee802.org/11/) has worked
+to address the flaws of the base standard and has in practice
+completed its work in May 2004. The IEEE 802.11i amendment to the IEEE
+802.11 standard was approved in June 2004 and this amendment is likely
+to be published in July 2004.
+
+Wi-Fi Alliance (http://www.wi-fi.org/) used a draft version of the
+IEEE 802.11i work (draft 3.0) to define a subset of the security
+enhancements that can be implemented with existing wlan hardware. This
+is called Wi-Fi Protected Access<TM> (WPA). This has now become a
+mandatory component of interoperability testing and certification done
+by Wi-Fi Alliance. Wi-Fi provides information about WPA at its web
+site (http://www.wi-fi.org/OpenSection/protected_access.asp).
+
+IEEE 802.11 standard defined wired equivalent privacy (WEP) algorithm
+for protecting wireless networks. WEP uses RC4 with 40-bit keys,
+24-bit initialization vector (IV), and CRC32 to protect against packet
+forgery. All these choices have proven to be insufficient: key space is
+too small against current attacks, RC4 key scheduling is insufficient
+(beginning of the pseudorandom stream should be skipped), IV space is
+too small and IV reuse makes attacks easier, there is no replay
+protection, and non-keyed authentication does not protect against bit
+flipping packet data.
+
+WPA is an intermediate solution for the security issues. It uses
+Temporal Key Integrity Protocol (TKIP) to replace WEP. TKIP is a
+compromise on strong security and possibility to use existing
+hardware. It still uses RC4 for the encryption like WEP, but with
+per-packet RC4 keys. In addition, it implements replay protection,
+keyed packet authentication mechanism (Michael MIC).
+
+Keys can be managed using two different mechanisms. WPA can either use
+an external authentication server (e.g., RADIUS) and EAP just like
+IEEE 802.1X is using or pre-shared keys without need for additional
+servers. Wi-Fi calls these "WPA-Enterprise" and "WPA-Personal",
+respectively. Both mechanisms will generate a master session key for
+the Authenticator (AP) and Supplicant (client station).
+
+WPA implements a new key handshake (4-Way Handshake and Group Key
+Handshake) for generating and exchanging data encryption keys between
+the Authenticator and Supplicant. This handshake is also used to
+verify that both Authenticator and Supplicant know the master session
+key. These handshakes are identical regardless of the selected key
+management mechanism (only the method for generating master session
+key changes).
+
+
+IEEE 802.11i / WPA2
+-------------------
+
+The design for parts of IEEE 802.11i that were not included in WPA has
+finished (May 2004) and this amendment to IEEE 802.11 was approved in
+June 2004. Wi-Fi Alliance is using the final IEEE 802.11i as a new
+version of WPA called WPA2. This includes, e.g., support for more
+robust encryption algorithm (CCMP: AES in Counter mode with CBC-MAC)
+to replace TKIP and optimizations for handoff (reduced number of
+messages in initial key handshake, pre-authentication, and PMKSA caching).
+
+Some wireless LAN vendors are already providing support for CCMP in
+their WPA products. There is no "official" interoperability
+certification for CCMP and/or mixed modes using both TKIP and CCMP, so
+some interoperability issues can be expected even though many
+combinations seem to be working with equipment from different vendors.
+Testing for WPA2 is likely to start during the second half of 2004.
+
+hostapd configuration for WPA/WPA2
+----------------------------------
+
+TODO
+
+# Enable WPA. Setting this variable configures the AP to require WPA (either
+# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
+# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
+# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
+# RADIUS authentication server must be configured, and WPA-EAP must be included
+# in wpa_key_mgmt.
+# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
+# and/or WPA2 (full IEEE 802.11i/RSN):
+# bit0 = WPA
+# bit1 = IEEE 802.11i/RSN (WPA2)
+#wpa=1
+
+# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
+# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
+# (8..63 characters) that will be converted to PSK. This conversion uses SSID
+# so the PSK changes when ASCII passphrase is used and the SSID is changed.
+#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+#wpa_passphrase=secret passphrase
+
+# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
+# entries are separated with a space.
+#wpa_key_mgmt=WPA-PSK WPA-EAP
+
+# Set of accepted cipher suites (encryption algorithms) for pairwise keys
+# (unicast packets). This is a space separated list of algorithms:
+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i]
+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i]
+# Group cipher suite (encryption algorithm for broadcast and multicast frames)
+# is automatically selected based on this configuration. If only CCMP is
+# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
+# TKIP will be used as the group cipher.
+#wpa_pairwise=TKIP CCMP
+
+# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
+# seconds.
+#wpa_group_rekey=600
+
+# Time interval for rekeying GMK (master key used internally to generate GTKs
+# (in seconds).
+#wpa_gmk_rekey=86400
+
+# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
+# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
+# authentication and key handshake before actually associating with a new AP.
+#rsn_preauth=1
+#
+# Space separated list of interfaces from which pre-authentication frames are
+# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
+# interface that are used for connections to other APs. This could include
+# wired interfaces and WDS links. The normal wireless data interface towards
+# associated stations (e.g., wlan0) should not be added, since
+# pre-authentication is only used with APs other than the currently associated
+# one.
+#rsn_preauth_interfaces=eth0
diff --git a/hostap/hostapd/README-WPS b/hostap/hostapd/README-WPS
new file mode 100644
index 0000000..87a6f91
--- /dev/null
+++ b/hostap/hostapd/README-WPS
@@ -0,0 +1,340 @@
+hostapd and Wi-Fi Protected Setup (WPS)
+=======================================
+
+This document describes how the WPS implementation in hostapd can be
+configured and how an external component on an AP (e.g., web UI) is
+used to enable enrollment of client devices.
+
+
+Introduction to WPS
+-------------------
+
+Wi-Fi Protected Setup (WPS) is a mechanism for easy configuration of a
+wireless network. It allows automated generation of random keys (WPA
+passphrase/PSK) and configuration of an access point and client
+devices. WPS includes number of methods for setting up connections
+with PIN method and push-button configuration (PBC) being the most
+commonly deployed options.
+
+While WPS can enable more home networks to use encryption in the
+wireless network, it should be noted that the use of the PIN and
+especially PBC mechanisms for authenticating the initial key setup is
+not very secure. As such, use of WPS may not be suitable for
+environments that require secure network access without chance for
+allowing outsiders to gain access during the setup phase.
+
+WPS uses following terms to describe the entities participating in the
+network setup:
+- access point: the WLAN access point
+- Registrar: a device that control a network and can authorize
+  addition of new devices); this may be either in the AP ("internal
+  Registrar") or in an external device, e.g., a laptop, ("external
+  Registrar")
+- Enrollee: a device that is being authorized to use the network
+
+It should also be noted that the AP and a client device may change
+roles (i.e., AP acts as an Enrollee and client device as a Registrar)
+when WPS is used to configure the access point.
+
+
+More information about WPS is available from Wi-Fi Alliance:
+http://www.wi-fi.org/wifi-protected-setup
+
+
+hostapd implementation
+----------------------
+
+hostapd includes an optional WPS component that can be used as an
+internal WPS Registrar to manage addition of new WPS enabled clients
+to the network. In addition, WPS Enrollee functionality in hostapd can
+be used to allow external WPS Registrars to configure the access
+point, e.g., for initial network setup. In addition, hostapd can proxy a
+WPS registration between a wireless Enrollee and an external Registrar
+(e.g., Microsoft Vista or Atheros JumpStart) with UPnP.
+
+
+hostapd configuration
+---------------------
+
+WPS is an optional component that needs to be enabled in hostapd build
+configuration (.config). Here is an example configuration that
+includes WPS support and uses madwifi driver interface:
+
+CONFIG_DRIVER_MADWIFI=y
+CFLAGS += -I/usr/src/madwifi-0.9.3
+CONFIG_WPS=y
+CONFIG_WPS2=y
+CONFIG_WPS_UPNP=y
+
+Following parameter can be used to enable support for NFC config method:
+
+CONFIG_WPS_NFC=y
+
+
+Following section shows an example runtime configuration
+(hostapd.conf) that enables WPS:
+
+# Configure the driver and network interface
+driver=madwifi
+interface=ath0
+
+# WPA2-Personal configuration for the AP
+ssid=wps-test
+wpa=2
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=CCMP
+# Default WPA passphrase for legacy (non-WPS) clients
+wpa_passphrase=12345678
+# Enable random per-device PSK generation for WPS clients
+# Please note that the file has to exists for hostapd to start (i.e., create an
+# empty file as a starting point).
+wpa_psk_file=/etc/hostapd.psk
+
+# Enable control interface for PBC/PIN entry
+ctrl_interface=/var/run/hostapd
+
+# Enable internal EAP server for EAP-WSC (part of Wi-Fi Protected Setup)
+eap_server=1
+
+# WPS configuration (AP configured, do not allow external WPS Registrars)
+wps_state=2
+ap_setup_locked=1
+# If UUID is not configured, it will be generated based on local MAC address.
+uuid=87654321-9abc-def0-1234-56789abc0000
+wps_pin_requests=/var/run/hostapd.pin-req
+device_name=Wireless AP
+manufacturer=Company
+model_name=WAP
+model_number=123
+serial_number=12345
+device_type=6-0050F204-1
+os_version=01020300
+config_methods=label display push_button keypad
+
+# if external Registrars are allowed, UPnP support could be added:
+#upnp_iface=br0
+#friendly_name=WPS Access Point
+
+
+External operations
+-------------------
+
+WPS requires either a device PIN code (usually, 8-digit number) or a
+pushbutton event (for PBC) to allow a new WPS Enrollee to join the
+network. hostapd uses the control interface as an input channel for
+these events.
+
+The PIN value used in the commands must be processed by an UI to
+remove non-digit characters and potentially, to verify the checksum
+digit. "hostapd_cli wps_check_pin <PIN>" can be used to do such
+processing. It returns FAIL if the PIN is invalid, or FAIL-CHECKSUM if
+the checksum digit is incorrect, or the processed PIN (non-digit
+characters removed) if the PIN is valid.
+
+When a client device (WPS Enrollee) connects to hostapd (WPS
+Registrar) in order to start PIN mode negotiation for WPS, an
+identifier (Enrollee UUID) is sent. hostapd will need to be configured
+with a device password (PIN) for this Enrollee. This is an operation
+that requires user interaction (assuming there are no pre-configured
+PINs on the AP for a set of Enrollee).
+
+The PIN request with information about the device is appended to the
+wps_pin_requests file (/var/run/hostapd.pin-req in this example). In
+addition, hostapd control interface event is sent as a notification of
+a new device. The AP could use, e.g., a web UI for showing active
+Enrollees to the user and request a PIN for an Enrollee.
+
+The PIN request file has one line for every Enrollee that connected to
+the AP, but for which there was no PIN. Following information is
+provided for each Enrollee (separated with tabulators):
+- timestamp (seconds from 1970-01-01)
+- Enrollee UUID
+- MAC address
+- Device name
+- Manufacturer
+- Model Name
+- Model Number
+- Serial Number
+- Device category
+
+Example line in the /var/run/hostapd.pin-req file:
+1200188391	53b63a98-d29e-4457-a2ed-094d7e6a669c	Intel(R) Centrino(R)	Intel Corporation	Intel(R) Centrino(R)	-	-	1-0050F204-1
+
+Control interface data:
+WPS-PIN-NEEDED [UUID-E|MAC Address|Device Name|Manufacturer|Model Name|Model Number|Serial Number|Device Category]
+For example:
+<2>WPS-PIN-NEEDED [53b63a98-d29e-4457-a2ed-094d7e6a669c|02:12:34:56:78:9a|Device|Manuf|Model|Model Number|Serial Number|1-0050F204-1]
+
+When the user enters a PIN for a pending Enrollee, e.g., on the web
+UI), hostapd needs to be notified of the new PIN over the control
+interface. This can be done either by using the UNIX domain socket
+-based control interface directly (src/common/wpa_ctrl.c provides
+helper functions for using the interface) or by calling hostapd_cli.
+
+Example command to add a PIN (12345670) for an Enrollee:
+
+hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c 12345670
+
+If the UUID-E is not available (e.g., Enrollee waits for the Registrar
+to be selected before connecting), wildcard UUID may be used to allow
+the PIN to be used once with any UUID:
+
+hostapd_cli wps_pin any 12345670
+
+To reduce likelihood of PIN being used with other devices or of
+forgetting an active PIN available for potential attackers, expiration
+time in seconds can be set for the new PIN (value 0 indicates no
+expiration):
+
+hostapd_cli wps_pin any 12345670 300
+
+If the MAC address of the enrollee is known, it should be configured
+to allow the AP to advertise list of authorized enrollees:
+
+hostapd_cli wps_pin 53b63a98-d29e-4457-a2ed-094d7e6a669c \
+	12345670 300 00:11:22:33:44:55
+
+
+After this, the Enrollee can connect to the AP again and complete WPS
+negotiation. At that point, a new, random WPA PSK is generated for the
+client device and the client can then use that key to connect to the
+AP to access the network.
+
+
+If the AP includes a pushbutton, WPS PBC mode can be used. It is
+enabled by pushing a button on both the AP and the client at about the
+same time (2 minute window). hostapd needs to be notified about the AP
+button pushed event over the control interface, e.g., by calling
+hostapd_cli:
+
+hostapd_cli wps_pbc
+
+At this point, the client has two minutes to complete WPS negotiation
+which will generate a new WPA PSK in the same way as the PIN method
+described above.
+
+
+When an external Registrar is used, the AP can act as an Enrollee and
+use its AP PIN. A static AP PIN (e.g., one one a label in the AP
+device) can be configured in hostapd.conf (ap_pin parameter). A more
+secure option is to use hostapd_cli wps_ap_pin command to enable the
+AP PIN only based on user action (and even better security by using a
+random AP PIN for each session, i.e., by using "wps_ap_pin random"
+command with a timeout value). Following commands are available for
+managing the dynamic AP PIN operations:
+
+hostapd_cli wps_ap_pin disable
+- disable AP PIN (i.e., do not allow external Registrars to use it to
+  learn the current AP settings or to reconfigure the AP)
+
+hostapd_cli wps_ap_pin random [timeout]
+- generate a random AP PIN and enable it
+- if the optional timeout parameter is given, the AP PIN will be enabled
+  for the specified number of seconds
+
+hostapd_cli wps_ap_pin get
+- fetch the current AP PIN
+
+hostapd_cli wps_ap_pin set <PIN> [timeout]
+- set the AP PIN and enable it
+- if the optional timeout parameter is given, the AP PIN will be enabled
+  for the specified number of seconds
+
+hostapd_cli get_config
+- display the current configuration
+
+hostapd_cli wps_config <new SSID> <auth> <encr> <new key>
+examples:
+  hostapd_cli wps_config testing WPA2PSK CCMP 12345678
+  hostapd_cli wps_config "no security" OPEN NONE ""
+
+<auth> must be one of the following: OPEN WPAPSK WPA2PSK
+<encr> must be one of the following: NONE WEP TKIP CCMP
+
+
+Credential generation and configuration changes
+-----------------------------------------------
+
+By default, hostapd generates credentials for Enrollees and processing
+AP configuration updates internally. However, it is possible to
+control these operations from external programs, if desired.
+
+The internal credential generation can be disabled with
+skip_cred_build=1 option in the configuration. extra_cred option will
+then need to be used to provide pre-configured Credential attribute(s)
+for hostapd to use. The exact data from this binary file will be sent,
+i.e., it will have to include valid WPS attributes. extra_cred can
+also be used to add additional networks if the Registrar is used to
+configure credentials for multiple networks.
+
+Processing of received configuration updates can be disabled with
+wps_cred_processing=1 option. When this is used, an external program
+is responsible for creating hostapd configuration files and processing
+configuration updates based on messages received from hostapd over
+control interface. This will also include the initial configuration on
+first successful registration if the AP is initially set in
+unconfigured state.
+
+Following control interface messages are sent out for external programs:
+
+WPS-REG-SUCCESS <Enrollee MAC address <UUID-E>
+For example:
+<2>WPS-REG-SUCCESS 02:66:a0:ee:17:27 2b7093f1-d6fb-5108-adbb-bea66bb87333
+
+This can be used to trigger change from unconfigured to configured
+state (random configuration based on the first successful WPS
+registration). In addition, this can be used to update AP UI about the
+status of WPS registration progress.
+
+
+WPS-NEW-AP-SETTINGS <hexdump of AP Setup attributes>
+For example:
+<2>WPS-NEW-AP-SETTINGS 10260001011045000c6a6b6d2d7770732d74657374100300020020100f00020008102700403065346230343536633236366665306433396164313535346131663462663731323433376163666462376633393965353466316631623032306164343438623510200006024231cede15101e000844
+
+This can be used to update the externally stored AP configuration and
+then update hostapd configuration (followed by restarting of hostapd).
+
+
+WPS with NFC
+------------
+
+WPS can be used with NFC-based configuration method. An NFC tag
+containing a password token from the Enrollee can be used to
+authenticate the connection instead of the PIN. In addition, an NFC tag
+with a configuration token can be used to transfer AP settings without
+going through the WPS protocol.
+
+When the AP acts as an Enrollee, a local NFC tag with a password token
+can be used by touching the NFC interface of an external Registrar. The
+wps_nfc_token command is used to manage use of the NFC password token
+from the AP. "wps_nfc_token enable" enables the use of the AP's NFC
+password token (in place of AP PIN) and "wps_nfc_token disable" disables
+the NFC password token.
+
+The NFC password token that is either pre-configured in the
+configuration file (wps_nfc_dev_pw_id, wps_nfc_dh_pubkey,
+wps_nfc_dh_privkey, wps_nfc_dev_pw) or generated dynamically with
+"wps_nfc_token <WPS|NDEF>" command. The nfc_pw_token tool from
+wpa_supplicant can be used to generate NFC password tokens during
+manufacturing (each AP needs to have its own random keys).
+
+The "wps_nfc_config_token <WPS/NDEF>" command can be used to build an
+NFC configuration token. The output value from this command is a hexdump
+of the current AP configuration (WPS parameter requests this to include
+only the WPS attributes; NDEF parameter requests additional NDEF
+encapsulation to be included). This data needs to be written to an NFC
+tag with an external program. Once written, the NFC configuration token
+can be used to touch an NFC interface on a station to provision the
+credentials needed to access the network.
+
+When the NFC device on the AP reads an NFC tag with a MIME media type
+"application/vnd.wfa.wsc", the NDEF message payload (with or without
+NDEF encapsulation) can be delivered to hostapd using the
+following hostapd_cli command:
+
+wps_nfc_tag_read <hexdump of payload>
+
+If the NFC tag contains a password token, the token is added to the
+internal Registrar. This allows station Enrollee from which the password
+token was received to run through WPS protocol to provision the
+credential.
diff --git a/hostap/hostapd/android.config b/hostap/hostapd/android.config
new file mode 100644
index 0000000..f51a5bf
--- /dev/null
+++ b/hostap/hostapd/android.config
@@ -0,0 +1,190 @@
+# Example hostapd build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cass, these lines should use += in order not
+# to override previous values of the variables.
+
+# Driver interface for Host AP driver
+#CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for wired authenticator
+#CONFIG_DRIVER_WIRED=y
+
+# Driver interface for madwifi driver
+#CONFIG_DRIVER_MADWIFI=y
+#CFLAGS += -I../../madwifi # change to the madwifi source directory
+
+# Driver interface for drivers using the nl80211 kernel interface
+#CONFIG_DRIVER_NL80211=y
+# driver_nl80211.c requires a rather new libnl (version 1.1) which may not be
+# shipped with your distribution yet. If that is the case, you need to build
+# newer libnl version and point the hostapd build to use it.
+#LIBNL=/usr/src/libnl
+#CFLAGS += -I$(LIBNL)/include
+#LIBS += -L$(LIBNL)/lib
+CONFIG_LIBNL20=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for no driver (e.g., RADIUS server only)
+#CONFIG_DRIVER_NONE=y
+
+# IEEE 802.11F/IAPP
+#CONFIG_IAPP=y
+
+# WPA2/IEEE 802.11i RSN pre-authentication
+#CONFIG_RSN_PREAUTH=y
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+#CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Integrated EAP server
+#CONFIG_EAP=y
+
+# EAP-MD5 for the integrated EAP server
+#CONFIG_EAP_MD5=y
+
+# EAP-TLS for the integrated EAP server
+#CONFIG_EAP_TLS=y
+
+# EAP-MSCHAPv2 for the integrated EAP server
+#CONFIG_EAP_MSCHAPV2=y
+
+# EAP-PEAP for the integrated EAP server
+#CONFIG_EAP_PEAP=y
+
+# EAP-GTC for the integrated EAP server
+#CONFIG_EAP_GTC=y
+
+# EAP-TTLS for the integrated EAP server
+#CONFIG_EAP_TTLS=y
+
+# EAP-SIM for the integrated EAP server
+#CONFIG_EAP_SIM=y
+
+# EAP-AKA for the integrated EAP server
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' for the integrated EAP server
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# EAP-PAX for the integrated EAP server
+#CONFIG_EAP_PAX=y
+
+# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-SAKE for the integrated EAP server
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK for the integrated EAP server
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-FAST for the integrated EAP server
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
+# Wi-Fi Protected Setup (WPS)
+CONFIG_WPS=y
+# Enable WSC 2.0 support
+CONFIG_WPS2=y
+# Enable UPnP support for external WPS Registrars
+#CONFIG_WPS_UPNP=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# Trusted Network Connect (EAP-TNC)
+#CONFIG_EAP_TNC=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# RADIUS authentication server. This provides access to the integrated EAP
+# server from external hosts using RADIUS.
+#CONFIG_RADIUS_SERVER=y
+
+# Build IPv6 support for RADIUS operations
+CONFIG_IPV6=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Use the hostapd's IEEE 802.11 authentication (ACL), but without
+# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211)
+#CONFIG_DRIVER_RADIUS_ACL=y
+
+# IEEE 802.11n (High Throughput) support
+CONFIG_IEEE80211N=y
+
+# Remove debugging code that is printing out debug messages to stdout.
+# This can be used to reduce the size of the hostapd considerably if debugging
+# code is not needed.
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Add support for writing debug log to Android logcat instead of standard output
+CONFIG_ANDROID_LOG=y
+
+# Remove support for RADIUS accounting
+#CONFIG_NO_ACCOUNTING=y
+
+# Remove support for RADIUS
+CONFIG_NO_RADIUS=y
+
+# Remove support for VLANs
+#CONFIG_NO_VLAN=y
+
+# Remove support for dumping state into a file on SIGUSR1 signal
+# This can be used to reduce binary size at the cost of disabling a debugging
+# option.
+#CONFIG_NO_DUMP_STATE=y
+
+# Select wrapper for operatins system and C library specific functions
+# unix = UNIX/POSIX like systems (default)
+# win32 = Windows systems
+# none = Empty template
+CONFIG_OS=unix
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, comment out these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, comment out these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# Enable AP
+CONFIG_AP=y
diff --git a/hostap/hostapd/config_file.c b/hostap/hostapd/config_file.c
new file mode 100644
index 0000000..0c917a5
--- /dev/null
+++ b/hostap/hostapd/config_file.c
@@ -0,0 +1,3124 @@
+/*
+ * hostapd / Configuration file parser
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <grp.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "utils/common.h"
+#include "utils/uuid.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "eap_server/eap.h"
+#include "radius/radius_client.h"
+#include "ap/wpa_auth.h"
+#include "ap/ap_config.h"
+#include "config_file.h"
+
+
+extern struct wpa_driver_ops *wpa_drivers[];
+
+
+#ifndef CONFIG_NO_VLAN
+static int hostapd_config_read_vlan_file(struct hostapd_bss_config *bss,
+					 const char *fname)
+{
+	FILE *f;
+	char buf[128], *pos, *pos2;
+	int line = 0, vlan_id;
+	struct hostapd_vlan *vlan;
+
+	f = fopen(fname, "r");
+	if (!f) {
+		wpa_printf(MSG_ERROR, "VLAN file '%s' not readable.", fname);
+		return -1;
+	}
+
+	while (fgets(buf, sizeof(buf), f)) {
+		line++;
+
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0') {
+			if (*pos == '\n') {
+				*pos = '\0';
+				break;
+			}
+			pos++;
+		}
+		if (buf[0] == '\0')
+			continue;
+
+		if (buf[0] == '*') {
+			vlan_id = VLAN_ID_WILDCARD;
+			pos = buf + 1;
+		} else {
+			vlan_id = strtol(buf, &pos, 10);
+			if (buf == pos || vlan_id < 1 ||
+			    vlan_id > MAX_VLAN_ID) {
+				wpa_printf(MSG_ERROR, "Invalid VLAN ID at "
+					   "line %d in '%s'", line, fname);
+				fclose(f);
+				return -1;
+			}
+		}
+
+		while (*pos == ' ' || *pos == '\t')
+			pos++;
+		pos2 = pos;
+		while (*pos2 != ' ' && *pos2 != '\t' && *pos2 != '\0')
+			pos2++;
+		*pos2 = '\0';
+		if (*pos == '\0' || os_strlen(pos) > IFNAMSIZ) {
+			wpa_printf(MSG_ERROR, "Invalid VLAN ifname at line %d "
+				   "in '%s'", line, fname);
+			fclose(f);
+			return -1;
+		}
+
+		vlan = os_malloc(sizeof(*vlan));
+		if (vlan == NULL) {
+			wpa_printf(MSG_ERROR, "Out of memory while reading "
+				   "VLAN interfaces from '%s'", fname);
+			fclose(f);
+			return -1;
+		}
+
+		os_memset(vlan, 0, sizeof(*vlan));
+		vlan->vlan_id = vlan_id;
+		os_strlcpy(vlan->ifname, pos, sizeof(vlan->ifname));
+		if (bss->vlan_tail)
+			bss->vlan_tail->next = vlan;
+		else
+			bss->vlan = vlan;
+		bss->vlan_tail = vlan;
+	}
+
+	fclose(f);
+
+	return 0;
+}
+#endif /* CONFIG_NO_VLAN */
+
+
+static int hostapd_acl_comp(const void *a, const void *b)
+{
+	const struct mac_acl_entry *aa = a;
+	const struct mac_acl_entry *bb = b;
+	return os_memcmp(aa->addr, bb->addr, sizeof(macaddr));
+}
+
+
+static int hostapd_config_read_maclist(const char *fname,
+				       struct mac_acl_entry **acl, int *num)
+{
+	FILE *f;
+	char buf[128], *pos;
+	int line = 0;
+	u8 addr[ETH_ALEN];
+	struct mac_acl_entry *newacl;
+	int vlan_id;
+
+	if (!fname)
+		return 0;
+
+	f = fopen(fname, "r");
+	if (!f) {
+		wpa_printf(MSG_ERROR, "MAC list file '%s' not found.", fname);
+		return -1;
+	}
+
+	while (fgets(buf, sizeof(buf), f)) {
+		line++;
+
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0') {
+			if (*pos == '\n') {
+				*pos = '\0';
+				break;
+			}
+			pos++;
+		}
+		if (buf[0] == '\0')
+			continue;
+
+		if (hwaddr_aton(buf, addr)) {
+			wpa_printf(MSG_ERROR, "Invalid MAC address '%s' at "
+				   "line %d in '%s'", buf, line, fname);
+			fclose(f);
+			return -1;
+		}
+
+		vlan_id = 0;
+		pos = buf;
+		while (*pos != '\0' && *pos != ' ' && *pos != '\t')
+			pos++;
+		while (*pos == ' ' || *pos == '\t')
+			pos++;
+		if (*pos != '\0')
+			vlan_id = atoi(pos);
+
+		newacl = os_realloc_array(*acl, *num + 1, sizeof(**acl));
+		if (newacl == NULL) {
+			wpa_printf(MSG_ERROR, "MAC list reallocation failed");
+			fclose(f);
+			return -1;
+		}
+
+		*acl = newacl;
+		os_memcpy((*acl)[*num].addr, addr, ETH_ALEN);
+		(*acl)[*num].vlan_id = vlan_id;
+		(*num)++;
+	}
+
+	fclose(f);
+
+	qsort(*acl, *num, sizeof(**acl), hostapd_acl_comp);
+
+	return 0;
+}
+
+
+#ifdef EAP_SERVER
+static int hostapd_config_read_eap_user(const char *fname,
+					struct hostapd_bss_config *conf)
+{
+	FILE *f;
+	char buf[512], *pos, *start, *pos2;
+	int line = 0, ret = 0, num_methods;
+	struct hostapd_eap_user *user, *tail = NULL;
+
+	if (!fname)
+		return 0;
+
+	if (os_strncmp(fname, "sqlite:", 7) == 0) {
+		os_free(conf->eap_user_sqlite);
+		conf->eap_user_sqlite = os_strdup(fname + 7);
+		return 0;
+	}
+
+	f = fopen(fname, "r");
+	if (!f) {
+		wpa_printf(MSG_ERROR, "EAP user file '%s' not found.", fname);
+		return -1;
+	}
+
+	/* Lines: "user" METHOD,METHOD2 "password" (password optional) */
+	while (fgets(buf, sizeof(buf), f)) {
+		line++;
+
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0') {
+			if (*pos == '\n') {
+				*pos = '\0';
+				break;
+			}
+			pos++;
+		}
+		if (buf[0] == '\0')
+			continue;
+
+		user = NULL;
+
+		if (buf[0] != '"' && buf[0] != '*') {
+			wpa_printf(MSG_ERROR, "Invalid EAP identity (no \" in "
+				   "start) on line %d in '%s'", line, fname);
+			goto failed;
+		}
+
+		user = os_zalloc(sizeof(*user));
+		if (user == NULL) {
+			wpa_printf(MSG_ERROR, "EAP user allocation failed");
+			goto failed;
+		}
+		user->force_version = -1;
+
+		if (buf[0] == '*') {
+			pos = buf;
+		} else {
+			pos = buf + 1;
+			start = pos;
+			while (*pos != '"' && *pos != '\0')
+				pos++;
+			if (*pos == '\0') {
+				wpa_printf(MSG_ERROR, "Invalid EAP identity "
+					   "(no \" in end) on line %d in '%s'",
+					   line, fname);
+				goto failed;
+			}
+
+			user->identity = os_malloc(pos - start);
+			if (user->identity == NULL) {
+				wpa_printf(MSG_ERROR, "Failed to allocate "
+					   "memory for EAP identity");
+				goto failed;
+			}
+			os_memcpy(user->identity, start, pos - start);
+			user->identity_len = pos - start;
+
+			if (pos[0] == '"' && pos[1] == '*') {
+				user->wildcard_prefix = 1;
+				pos++;
+			}
+		}
+		pos++;
+		while (*pos == ' ' || *pos == '\t')
+			pos++;
+
+		if (*pos == '\0') {
+			wpa_printf(MSG_ERROR, "No EAP method on line %d in "
+				   "'%s'", line, fname);
+			goto failed;
+		}
+
+		start = pos;
+		while (*pos != ' ' && *pos != '\t' && *pos != '\0')
+			pos++;
+		if (*pos == '\0') {
+			pos = NULL;
+		} else {
+			*pos = '\0';
+			pos++;
+		}
+		num_methods = 0;
+		while (*start) {
+			char *pos3 = os_strchr(start, ',');
+			if (pos3) {
+				*pos3++ = '\0';
+			}
+			user->methods[num_methods].method =
+				eap_server_get_type(
+					start,
+					&user->methods[num_methods].vendor);
+			if (user->methods[num_methods].vendor ==
+			    EAP_VENDOR_IETF &&
+			    user->methods[num_methods].method == EAP_TYPE_NONE)
+			{
+				if (os_strcmp(start, "TTLS-PAP") == 0) {
+					user->ttls_auth |= EAP_TTLS_AUTH_PAP;
+					goto skip_eap;
+				}
+				if (os_strcmp(start, "TTLS-CHAP") == 0) {
+					user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
+					goto skip_eap;
+				}
+				if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
+					user->ttls_auth |=
+						EAP_TTLS_AUTH_MSCHAP;
+					goto skip_eap;
+				}
+				if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
+					user->ttls_auth |=
+						EAP_TTLS_AUTH_MSCHAPV2;
+					goto skip_eap;
+				}
+				wpa_printf(MSG_ERROR, "Unsupported EAP type "
+					   "'%s' on line %d in '%s'",
+					   start, line, fname);
+				goto failed;
+			}
+
+			num_methods++;
+			if (num_methods >= EAP_MAX_METHODS)
+				break;
+		skip_eap:
+			if (pos3 == NULL)
+				break;
+			start = pos3;
+		}
+		if (num_methods == 0 && user->ttls_auth == 0) {
+			wpa_printf(MSG_ERROR, "No EAP types configured on "
+				   "line %d in '%s'", line, fname);
+			goto failed;
+		}
+
+		if (pos == NULL)
+			goto done;
+
+		while (*pos == ' ' || *pos == '\t')
+			pos++;
+		if (*pos == '\0')
+			goto done;
+
+		if (os_strncmp(pos, "[ver=0]", 7) == 0) {
+			user->force_version = 0;
+			goto done;
+		}
+
+		if (os_strncmp(pos, "[ver=1]", 7) == 0) {
+			user->force_version = 1;
+			goto done;
+		}
+
+		if (os_strncmp(pos, "[2]", 3) == 0) {
+			user->phase2 = 1;
+			goto done;
+		}
+
+		if (*pos == '"') {
+			pos++;
+			start = pos;
+			while (*pos != '"' && *pos != '\0')
+				pos++;
+			if (*pos == '\0') {
+				wpa_printf(MSG_ERROR, "Invalid EAP password "
+					   "(no \" in end) on line %d in '%s'",
+					   line, fname);
+				goto failed;
+			}
+
+			user->password = os_malloc(pos - start);
+			if (user->password == NULL) {
+				wpa_printf(MSG_ERROR, "Failed to allocate "
+					   "memory for EAP password");
+				goto failed;
+			}
+			os_memcpy(user->password, start, pos - start);
+			user->password_len = pos - start;
+
+			pos++;
+		} else if (os_strncmp(pos, "hash:", 5) == 0) {
+			pos += 5;
+			pos2 = pos;
+			while (*pos2 != '\0' && *pos2 != ' ' &&
+			       *pos2 != '\t' && *pos2 != '#')
+				pos2++;
+			if (pos2 - pos != 32) {
+				wpa_printf(MSG_ERROR, "Invalid password hash "
+					   "on line %d in '%s'", line, fname);
+				goto failed;
+			}
+			user->password = os_malloc(16);
+			if (user->password == NULL) {
+				wpa_printf(MSG_ERROR, "Failed to allocate "
+					   "memory for EAP password hash");
+				goto failed;
+			}
+			if (hexstr2bin(pos, user->password, 16) < 0) {
+				wpa_printf(MSG_ERROR, "Invalid hash password "
+					   "on line %d in '%s'", line, fname);
+				goto failed;
+			}
+			user->password_len = 16;
+			user->password_hash = 1;
+			pos = pos2;
+		} else {
+			pos2 = pos;
+			while (*pos2 != '\0' && *pos2 != ' ' &&
+			       *pos2 != '\t' && *pos2 != '#')
+				pos2++;
+			if ((pos2 - pos) & 1) {
+				wpa_printf(MSG_ERROR, "Invalid hex password "
+					   "on line %d in '%s'", line, fname);
+				goto failed;
+			}
+			user->password = os_malloc((pos2 - pos) / 2);
+			if (user->password == NULL) {
+				wpa_printf(MSG_ERROR, "Failed to allocate "
+					   "memory for EAP password");
+				goto failed;
+			}
+			if (hexstr2bin(pos, user->password,
+				       (pos2 - pos) / 2) < 0) {
+				wpa_printf(MSG_ERROR, "Invalid hex password "
+					   "on line %d in '%s'", line, fname);
+				goto failed;
+			}
+			user->password_len = (pos2 - pos) / 2;
+			pos = pos2;
+		}
+
+		while (*pos == ' ' || *pos == '\t')
+			pos++;
+		if (os_strncmp(pos, "[2]", 3) == 0) {
+			user->phase2 = 1;
+		}
+
+	done:
+		if (tail == NULL) {
+			tail = conf->eap_user = user;
+		} else {
+			tail->next = user;
+			tail = user;
+		}
+		continue;
+
+	failed:
+		if (user) {
+			os_free(user->password);
+			os_free(user->identity);
+			os_free(user);
+		}
+		ret = -1;
+		break;
+	}
+
+	fclose(f);
+
+	return ret;
+}
+#endif /* EAP_SERVER */
+
+
+#ifndef CONFIG_NO_RADIUS
+static int
+hostapd_config_read_radius_addr(struct hostapd_radius_server **server,
+				int *num_server, const char *val, int def_port,
+				struct hostapd_radius_server **curr_serv)
+{
+	struct hostapd_radius_server *nserv;
+	int ret;
+	static int server_index = 1;
+
+	nserv = os_realloc_array(*server, *num_server + 1, sizeof(*nserv));
+	if (nserv == NULL)
+		return -1;
+
+	*server = nserv;
+	nserv = &nserv[*num_server];
+	(*num_server)++;
+	(*curr_serv) = nserv;
+
+	os_memset(nserv, 0, sizeof(*nserv));
+	nserv->port = def_port;
+	ret = hostapd_parse_ip_addr(val, &nserv->addr);
+	nserv->index = server_index++;
+
+	return ret;
+}
+
+
+static struct hostapd_radius_attr *
+hostapd_parse_radius_attr(const char *value)
+{
+	const char *pos;
+	char syntax;
+	struct hostapd_radius_attr *attr;
+	size_t len;
+
+	attr = os_zalloc(sizeof(*attr));
+	if (attr == NULL)
+		return NULL;
+
+	attr->type = atoi(value);
+
+	pos = os_strchr(value, ':');
+	if (pos == NULL) {
+		attr->val = wpabuf_alloc(1);
+		if (attr->val == NULL) {
+			os_free(attr);
+			return NULL;
+		}
+		wpabuf_put_u8(attr->val, 0);
+		return attr;
+	}
+
+	pos++;
+	if (pos[0] == '\0' || pos[1] != ':') {
+		os_free(attr);
+		return NULL;
+	}
+	syntax = *pos++;
+	pos++;
+
+	switch (syntax) {
+	case 's':
+		attr->val = wpabuf_alloc_copy(pos, os_strlen(pos));
+		break;
+	case 'x':
+		len = os_strlen(pos);
+		if (len & 1)
+			break;
+		len /= 2;
+		attr->val = wpabuf_alloc(len);
+		if (attr->val == NULL)
+			break;
+		if (hexstr2bin(pos, wpabuf_put(attr->val, len), len) < 0) {
+			wpabuf_free(attr->val);
+			os_free(attr);
+			return NULL;
+		}
+		break;
+	case 'd':
+		attr->val = wpabuf_alloc(4);
+		if (attr->val)
+			wpabuf_put_be32(attr->val, atoi(pos));
+		break;
+	default:
+		os_free(attr);
+		return NULL;
+	}
+
+	if (attr->val == NULL) {
+		os_free(attr);
+		return NULL;
+	}
+
+	return attr;
+}
+
+
+static int hostapd_parse_das_client(struct hostapd_bss_config *bss,
+				    const char *val)
+{
+	char *secret;
+
+	secret = os_strchr(val, ' ');
+	if (secret == NULL)
+		return -1;
+
+	secret++;
+
+	if (hostapd_parse_ip_addr(val, &bss->radius_das_client_addr))
+		return -1;
+
+	os_free(bss->radius_das_shared_secret);
+	bss->radius_das_shared_secret = (u8 *) os_strdup(secret);
+	if (bss->radius_das_shared_secret == NULL)
+		return -1;
+	bss->radius_das_shared_secret_len = os_strlen(secret);
+
+	return 0;
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
+static int hostapd_config_parse_key_mgmt(int line, const char *value)
+{
+	int val = 0, last;
+	char *start, *end, *buf;
+
+	buf = os_strdup(value);
+	if (buf == NULL)
+		return -1;
+	start = buf;
+
+	while (*start != '\0') {
+		while (*start == ' ' || *start == '\t')
+			start++;
+		if (*start == '\0')
+			break;
+		end = start;
+		while (*end != ' ' && *end != '\t' && *end != '\0')
+			end++;
+		last = *end == '\0';
+		*end = '\0';
+		if (os_strcmp(start, "WPA-PSK") == 0)
+			val |= WPA_KEY_MGMT_PSK;
+		else if (os_strcmp(start, "WPA-EAP") == 0)
+			val |= WPA_KEY_MGMT_IEEE8021X;
+#ifdef CONFIG_IEEE80211R
+		else if (os_strcmp(start, "FT-PSK") == 0)
+			val |= WPA_KEY_MGMT_FT_PSK;
+		else if (os_strcmp(start, "FT-EAP") == 0)
+			val |= WPA_KEY_MGMT_FT_IEEE8021X;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+		else if (os_strcmp(start, "WPA-PSK-SHA256") == 0)
+			val |= WPA_KEY_MGMT_PSK_SHA256;
+		else if (os_strcmp(start, "WPA-EAP-SHA256") == 0)
+			val |= WPA_KEY_MGMT_IEEE8021X_SHA256;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+		else if (os_strcmp(start, "SAE") == 0)
+			val |= WPA_KEY_MGMT_SAE;
+		else if (os_strcmp(start, "FT-SAE") == 0)
+			val |= WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
+		else {
+			wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
+				   line, start);
+			os_free(buf);
+			return -1;
+		}
+
+		if (last)
+			break;
+		start = end + 1;
+	}
+
+	os_free(buf);
+	if (val == 0) {
+		wpa_printf(MSG_ERROR, "Line %d: no key_mgmt values "
+			   "configured.", line);
+		return -1;
+	}
+
+	return val;
+}
+
+
+static int hostapd_config_parse_cipher(int line, const char *value)
+{
+	int val = 0, last;
+	char *start, *end, *buf;
+
+	buf = os_strdup(value);
+	if (buf == NULL)
+		return -1;
+	start = buf;
+
+	while (*start != '\0') {
+		while (*start == ' ' || *start == '\t')
+			start++;
+		if (*start == '\0')
+			break;
+		end = start;
+		while (*end != ' ' && *end != '\t' && *end != '\0')
+			end++;
+		last = *end == '\0';
+		*end = '\0';
+		if (os_strcmp(start, "CCMP") == 0)
+			val |= WPA_CIPHER_CCMP;
+		else if (os_strcmp(start, "GCMP") == 0)
+			val |= WPA_CIPHER_GCMP;
+		else if (os_strcmp(start, "TKIP") == 0)
+			val |= WPA_CIPHER_TKIP;
+		else if (os_strcmp(start, "WEP104") == 0)
+			val |= WPA_CIPHER_WEP104;
+		else if (os_strcmp(start, "WEP40") == 0)
+			val |= WPA_CIPHER_WEP40;
+		else if (os_strcmp(start, "NONE") == 0)
+			val |= WPA_CIPHER_NONE;
+		else {
+			wpa_printf(MSG_ERROR, "Line %d: invalid cipher '%s'.",
+				   line, start);
+			os_free(buf);
+			return -1;
+		}
+
+		if (last)
+			break;
+		start = end + 1;
+	}
+	os_free(buf);
+
+	if (val == 0) {
+		wpa_printf(MSG_ERROR, "Line %d: no cipher values configured.",
+			   line);
+		return -1;
+	}
+	return val;
+}
+
+
+static int hostapd_config_read_wep(struct hostapd_wep_keys *wep, int keyidx,
+				   char *val)
+{
+	size_t len = os_strlen(val);
+
+	if (keyidx < 0 || keyidx > 3 || wep->key[keyidx] != NULL)
+		return -1;
+
+	if (val[0] == '"') {
+		if (len < 2 || val[len - 1] != '"')
+			return -1;
+		len -= 2;
+		wep->key[keyidx] = os_malloc(len);
+		if (wep->key[keyidx] == NULL)
+			return -1;
+		os_memcpy(wep->key[keyidx], val + 1, len);
+		wep->len[keyidx] = len;
+	} else {
+		if (len & 1)
+			return -1;
+		len /= 2;
+		wep->key[keyidx] = os_malloc(len);
+		if (wep->key[keyidx] == NULL)
+			return -1;
+		wep->len[keyidx] = len;
+		if (hexstr2bin(val, wep->key[keyidx], len) < 0)
+			return -1;
+	}
+
+	wep->keys_set++;
+
+	return 0;
+}
+
+
+static int hostapd_parse_rates(int **rate_list, char *val)
+{
+	int *list;
+	int count;
+	char *pos, *end;
+
+	os_free(*rate_list);
+	*rate_list = NULL;
+
+	pos = val;
+	count = 0;
+	while (*pos != '\0') {
+		if (*pos == ' ')
+			count++;
+		pos++;
+	}
+
+	list = os_malloc(sizeof(int) * (count + 2));
+	if (list == NULL)
+		return -1;
+	pos = val;
+	count = 0;
+	while (*pos != '\0') {
+		end = os_strchr(pos, ' ');
+		if (end)
+			*end = '\0';
+
+		list[count++] = atoi(pos);
+		if (!end)
+			break;
+		pos = end + 1;
+	}
+	list[count] = -1;
+
+	*rate_list = list;
+	return 0;
+}
+
+
+static int hostapd_config_bss(struct hostapd_config *conf, const char *ifname)
+{
+	struct hostapd_bss_config *bss;
+
+	if (*ifname == '\0')
+		return -1;
+
+	bss = os_realloc_array(conf->bss, conf->num_bss + 1,
+			       sizeof(struct hostapd_bss_config));
+	if (bss == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
+			   "multi-BSS entry");
+		return -1;
+	}
+	conf->bss = bss;
+
+	bss = &(conf->bss[conf->num_bss]);
+	os_memset(bss, 0, sizeof(*bss));
+	bss->radius = os_zalloc(sizeof(*bss->radius));
+	if (bss->radius == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
+			   "multi-BSS RADIUS data");
+		return -1;
+	}
+
+	conf->num_bss++;
+	conf->last_bss = bss;
+
+	hostapd_config_defaults_bss(bss);
+	os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
+	os_memcpy(bss->ssid.vlan, bss->iface, IFNAMSIZ + 1);
+
+	return 0;
+}
+
+
+/* convert floats with one decimal place to value*10 int, i.e.,
+ * "1.5" will return 15 */
+static int hostapd_config_read_int10(const char *value)
+{
+	int i, d;
+	char *pos;
+
+	i = atoi(value);
+	pos = os_strchr(value, '.');
+	d = 0;
+	if (pos) {
+		pos++;
+		if (*pos >= '0' && *pos <= '9')
+			d = *pos - '0';
+	}
+
+	return i * 10 + d;
+}
+
+
+static int valid_cw(int cw)
+{
+	return (cw == 1 || cw == 3 || cw == 7 || cw == 15 || cw == 31 ||
+		cw == 63 || cw == 127 || cw == 255 || cw == 511 || cw == 1023);
+}
+
+
+enum {
+	IEEE80211_TX_QUEUE_DATA0 = 0, /* used for EDCA AC_VO data */
+	IEEE80211_TX_QUEUE_DATA1 = 1, /* used for EDCA AC_VI data */
+	IEEE80211_TX_QUEUE_DATA2 = 2, /* used for EDCA AC_BE data */
+	IEEE80211_TX_QUEUE_DATA3 = 3 /* used for EDCA AC_BK data */
+};
+
+static int hostapd_config_tx_queue(struct hostapd_config *conf, char *name,
+				   char *val)
+{
+	int num;
+	char *pos;
+	struct hostapd_tx_queue_params *queue;
+
+	/* skip 'tx_queue_' prefix */
+	pos = name + 9;
+	if (os_strncmp(pos, "data", 4) == 0 &&
+	    pos[4] >= '0' && pos[4] <= '9' && pos[5] == '_') {
+		num = pos[4] - '0';
+		pos += 6;
+	} else if (os_strncmp(pos, "after_beacon_", 13) == 0 ||
+		   os_strncmp(pos, "beacon_", 7) == 0) {
+		wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
+		return 0;
+	} else {
+		wpa_printf(MSG_ERROR, "Unknown tx_queue name '%s'", pos);
+		return -1;
+	}
+
+	if (num >= NUM_TX_QUEUES) {
+		/* for backwards compatibility, do not trigger failure */
+		wpa_printf(MSG_INFO, "DEPRECATED: '%s' not used", name);
+		return 0;
+	}
+
+	queue = &conf->tx_queue[num];
+
+	if (os_strcmp(pos, "aifs") == 0) {
+		queue->aifs = atoi(val);
+		if (queue->aifs < 0 || queue->aifs > 255) {
+			wpa_printf(MSG_ERROR, "Invalid AIFS value %d",
+				   queue->aifs);
+			return -1;
+		}
+	} else if (os_strcmp(pos, "cwmin") == 0) {
+		queue->cwmin = atoi(val);
+		if (!valid_cw(queue->cwmin)) {
+			wpa_printf(MSG_ERROR, "Invalid cwMin value %d",
+				   queue->cwmin);
+			return -1;
+		}
+	} else if (os_strcmp(pos, "cwmax") == 0) {
+		queue->cwmax = atoi(val);
+		if (!valid_cw(queue->cwmax)) {
+			wpa_printf(MSG_ERROR, "Invalid cwMax value %d",
+				   queue->cwmax);
+			return -1;
+		}
+	} else if (os_strcmp(pos, "burst") == 0) {
+		queue->burst = hostapd_config_read_int10(val);
+	} else {
+		wpa_printf(MSG_ERROR, "Unknown tx_queue field '%s'", pos);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_IEEE80211R
+static int add_r0kh(struct hostapd_bss_config *bss, char *value)
+{
+	struct ft_remote_r0kh *r0kh;
+	char *pos, *next;
+
+	r0kh = os_zalloc(sizeof(*r0kh));
+	if (r0kh == NULL)
+		return -1;
+
+	/* 02:01:02:03:04:05 a.example.com 000102030405060708090a0b0c0d0e0f */
+	pos = value;
+	next = os_strchr(pos, ' ');
+	if (next)
+		*next++ = '\0';
+	if (next == NULL || hwaddr_aton(pos, r0kh->addr)) {
+		wpa_printf(MSG_ERROR, "Invalid R0KH MAC address: '%s'", pos);
+		os_free(r0kh);
+		return -1;
+	}
+
+	pos = next;
+	next = os_strchr(pos, ' ');
+	if (next)
+		*next++ = '\0';
+	if (next == NULL || next - pos > FT_R0KH_ID_MAX_LEN) {
+		wpa_printf(MSG_ERROR, "Invalid R0KH-ID: '%s'", pos);
+		os_free(r0kh);
+		return -1;
+	}
+	r0kh->id_len = next - pos - 1;
+	os_memcpy(r0kh->id, pos, r0kh->id_len);
+
+	pos = next;
+	if (hexstr2bin(pos, r0kh->key, sizeof(r0kh->key))) {
+		wpa_printf(MSG_ERROR, "Invalid R0KH key: '%s'", pos);
+		os_free(r0kh);
+		return -1;
+	}
+
+	r0kh->next = bss->r0kh_list;
+	bss->r0kh_list = r0kh;
+
+	return 0;
+}
+
+
+static int add_r1kh(struct hostapd_bss_config *bss, char *value)
+{
+	struct ft_remote_r1kh *r1kh;
+	char *pos, *next;
+
+	r1kh = os_zalloc(sizeof(*r1kh));
+	if (r1kh == NULL)
+		return -1;
+
+	/* 02:01:02:03:04:05 02:01:02:03:04:05
+	 * 000102030405060708090a0b0c0d0e0f */
+	pos = value;
+	next = os_strchr(pos, ' ');
+	if (next)
+		*next++ = '\0';
+	if (next == NULL || hwaddr_aton(pos, r1kh->addr)) {
+		wpa_printf(MSG_ERROR, "Invalid R1KH MAC address: '%s'", pos);
+		os_free(r1kh);
+		return -1;
+	}
+
+	pos = next;
+	next = os_strchr(pos, ' ');
+	if (next)
+		*next++ = '\0';
+	if (next == NULL || hwaddr_aton(pos, r1kh->id)) {
+		wpa_printf(MSG_ERROR, "Invalid R1KH-ID: '%s'", pos);
+		os_free(r1kh);
+		return -1;
+	}
+
+	pos = next;
+	if (hexstr2bin(pos, r1kh->key, sizeof(r1kh->key))) {
+		wpa_printf(MSG_ERROR, "Invalid R1KH key: '%s'", pos);
+		os_free(r1kh);
+		return -1;
+	}
+
+	r1kh->next = bss->r1kh_list;
+	bss->r1kh_list = r1kh;
+
+	return 0;
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+#ifdef CONFIG_IEEE80211N
+static int hostapd_config_ht_capab(struct hostapd_config *conf,
+				   const char *capab)
+{
+	if (os_strstr(capab, "[LDPC]"))
+		conf->ht_capab |= HT_CAP_INFO_LDPC_CODING_CAP;
+	if (os_strstr(capab, "[HT40-]")) {
+		conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+		conf->secondary_channel = -1;
+	}
+	if (os_strstr(capab, "[HT40+]")) {
+		conf->ht_capab |= HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+		conf->secondary_channel = 1;
+	}
+	if (os_strstr(capab, "[SMPS-STATIC]")) {
+		conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
+		conf->ht_capab |= HT_CAP_INFO_SMPS_STATIC;
+	}
+	if (os_strstr(capab, "[SMPS-DYNAMIC]")) {
+		conf->ht_capab &= ~HT_CAP_INFO_SMPS_MASK;
+		conf->ht_capab |= HT_CAP_INFO_SMPS_DYNAMIC;
+	}
+	if (os_strstr(capab, "[GF]"))
+		conf->ht_capab |= HT_CAP_INFO_GREEN_FIELD;
+	if (os_strstr(capab, "[SHORT-GI-20]"))
+		conf->ht_capab |= HT_CAP_INFO_SHORT_GI20MHZ;
+	if (os_strstr(capab, "[SHORT-GI-40]"))
+		conf->ht_capab |= HT_CAP_INFO_SHORT_GI40MHZ;
+	if (os_strstr(capab, "[TX-STBC]"))
+		conf->ht_capab |= HT_CAP_INFO_TX_STBC;
+	if (os_strstr(capab, "[RX-STBC1]")) {
+		conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
+		conf->ht_capab |= HT_CAP_INFO_RX_STBC_1;
+	}
+	if (os_strstr(capab, "[RX-STBC12]")) {
+		conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
+		conf->ht_capab |= HT_CAP_INFO_RX_STBC_12;
+	}
+	if (os_strstr(capab, "[RX-STBC123]")) {
+		conf->ht_capab &= ~HT_CAP_INFO_RX_STBC_MASK;
+		conf->ht_capab |= HT_CAP_INFO_RX_STBC_123;
+	}
+	if (os_strstr(capab, "[DELAYED-BA]"))
+		conf->ht_capab |= HT_CAP_INFO_DELAYED_BA;
+	if (os_strstr(capab, "[MAX-AMSDU-7935]"))
+		conf->ht_capab |= HT_CAP_INFO_MAX_AMSDU_SIZE;
+	if (os_strstr(capab, "[DSSS_CCK-40]"))
+		conf->ht_capab |= HT_CAP_INFO_DSSS_CCK40MHZ;
+	if (os_strstr(capab, "[PSMP]"))
+		conf->ht_capab |= HT_CAP_INFO_PSMP_SUPP;
+	if (os_strstr(capab, "[LSIG-TXOP-PROT]"))
+		conf->ht_capab |= HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT;
+
+	return 0;
+}
+#endif /* CONFIG_IEEE80211N */
+
+
+#ifdef CONFIG_IEEE80211AC
+static int hostapd_config_vht_capab(struct hostapd_config *conf,
+				    const char *capab)
+{
+	if (os_strstr(capab, "[MAX-MPDU-7991]"))
+		conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_7991;
+	if (os_strstr(capab, "[MAX-MPDU-11454]"))
+		conf->vht_capab |= VHT_CAP_MAX_MPDU_LENGTH_11454;
+	if (os_strstr(capab, "[VHT160]"))
+		conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160MHZ;
+	if (os_strstr(capab, "[VHT160-80PLUS80]"))
+		conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+	if (os_strstr(capab, "[VHT160-80PLUS80]"))
+		conf->vht_capab |= VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ;
+	if (os_strstr(capab, "[RXLDPC]"))
+		conf->vht_capab |= VHT_CAP_RXLDPC;
+	if (os_strstr(capab, "[SHORT-GI-80]"))
+		conf->vht_capab |= VHT_CAP_SHORT_GI_80;
+	if (os_strstr(capab, "[SHORT-GI-160]"))
+		conf->vht_capab |= VHT_CAP_SHORT_GI_160;
+	if (os_strstr(capab, "[TX-STBC-2BY1]"))
+		conf->vht_capab |= VHT_CAP_TXSTBC;
+	if (os_strstr(capab, "[RX-STBC-1]"))
+		conf->vht_capab |= VHT_CAP_RXSTBC_1;
+	if (os_strstr(capab, "[RX-STBC-12]"))
+		conf->vht_capab |= VHT_CAP_RXSTBC_2;
+	if (os_strstr(capab, "[RX-STBC-123]"))
+		conf->vht_capab |= VHT_CAP_RXSTBC_3;
+	if (os_strstr(capab, "[RX-STBC-1234]"))
+		conf->vht_capab |= VHT_CAP_RXSTBC_4;
+	if (os_strstr(capab, "[SU-BEAMFORMER]"))
+		conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
+	if (os_strstr(capab, "[SU-BEAMFORMEE]"))
+		conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+	if (os_strstr(capab, "[BF-ANTENNA-2]") &&
+	    (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
+		conf->vht_capab |= VHT_CAP_BEAMFORMER_ANTENNAS_MAX;
+	if (os_strstr(capab, "[SOUNDING-DIMENSION-2]") &&
+	    (conf->vht_capab & VHT_CAP_MU_BEAMFORMER_CAPABLE))
+		conf->vht_capab |= VHT_CAP_SOUNDING_DIMENTION_MAX;
+	if (os_strstr(capab, "[MU-BEAMFORMER]"))
+		conf->vht_capab |= VHT_CAP_MU_BEAMFORMER_CAPABLE;
+	if (os_strstr(capab, "[MU-BEAMFORMEE]"))
+		conf->vht_capab |= VHT_CAP_MU_BEAMFORMEE_CAPABLE;
+	if (os_strstr(capab, "[VHT-TXOP-PS]"))
+		conf->vht_capab |= VHT_CAP_VHT_TXOP_PS;
+	if (os_strstr(capab, "[HTC-VHT]"))
+		conf->vht_capab |= VHT_CAP_HTC_VHT;
+	if (os_strstr(capab, "[MAX-A-MPDU-LEN-EXP0]"))
+		conf->vht_capab |= VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT;
+	if (os_strstr(capab, "[VHT-LINK-ADAPT2]") &&
+	    (conf->vht_capab & VHT_CAP_HTC_VHT))
+		conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB;
+	if (os_strstr(capab, "[VHT-LINK-ADAPT3]") &&
+	    (conf->vht_capab & VHT_CAP_HTC_VHT))
+		conf->vht_capab |= VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB;
+	if (os_strstr(capab, "[RX-ANTENNA-PATTERN]"))
+		conf->vht_capab |= VHT_CAP_RX_ANTENNA_PATTERN;
+	if (os_strstr(capab, "[TX-ANTENNA-PATTERN]"))
+		conf->vht_capab |= VHT_CAP_TX_ANTENNA_PATTERN;
+	return 0;
+}
+#endif /* CONFIG_IEEE80211AC */
+
+
+static int hostapd_config_check_bss(struct hostapd_bss_config *bss,
+				    struct hostapd_config *conf)
+{
+	if (bss->ieee802_1x && !bss->eap_server &&
+	    !bss->radius->auth_servers) {
+		wpa_printf(MSG_ERROR, "Invalid IEEE 802.1X configuration (no "
+			   "EAP authenticator configured).");
+		return -1;
+	}
+
+	if (bss->wpa && bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+	    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+		wpa_printf(MSG_ERROR, "WPA-PSK using RADIUS enabled, but no "
+			   "RADIUS checking (macaddr_acl=2) enabled.");
+		return -1;
+	}
+
+	if (bss->wpa && (bss->wpa_key_mgmt & WPA_KEY_MGMT_PSK) &&
+	    bss->ssid.wpa_psk == NULL && bss->ssid.wpa_passphrase == NULL &&
+	    bss->ssid.wpa_psk_file == NULL &&
+	    (bss->wpa_psk_radius != PSK_RADIUS_REQUIRED ||
+	     bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH)) {
+		wpa_printf(MSG_ERROR, "WPA-PSK enabled, but PSK or passphrase "
+			   "is not configured.");
+		return -1;
+	}
+
+	if (hostapd_mac_comp_empty(bss->bssid) != 0) {
+		size_t i;
+
+		for (i = 0; i < conf->num_bss; i++) {
+			if ((&conf->bss[i] != bss) &&
+			    (hostapd_mac_comp(conf->bss[i].bssid,
+					      bss->bssid) == 0)) {
+				wpa_printf(MSG_ERROR, "Duplicate BSSID " MACSTR
+					   " on interface '%s' and '%s'.",
+					   MAC2STR(bss->bssid),
+					   conf->bss[i].iface, bss->iface);
+				return -1;
+			}
+		}
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(bss->wpa_key_mgmt) &&
+	    (bss->nas_identifier == NULL ||
+	     os_strlen(bss->nas_identifier) < 1 ||
+	     os_strlen(bss->nas_identifier) > FT_R0KH_ID_MAX_LEN)) {
+		wpa_printf(MSG_ERROR, "FT (IEEE 802.11r) requires "
+			   "nas_identifier to be configured as a 1..48 octet "
+			   "string");
+		return -1;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211N
+	if (conf->ieee80211n && conf->hw_mode == HOSTAPD_MODE_IEEE80211B) {
+		bss->disable_11n = 1;
+		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) in 11b mode is not "
+			   "allowed, disabling HT capabilites");
+	}
+
+	if (conf->ieee80211n &&
+	    bss->ssid.security_policy == SECURITY_STATIC_WEP) {
+		bss->disable_11n = 1;
+		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WEP is not "
+			   "allowed, disabling HT capabilities");
+	}
+
+	if (conf->ieee80211n && bss->wpa &&
+	    !(bss->wpa_pairwise & WPA_CIPHER_CCMP) &&
+	    !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP))) {
+		bss->disable_11n = 1;
+		wpa_printf(MSG_ERROR, "HT (IEEE 802.11n) with WPA/WPA2 "
+			   "requires CCMP/GCMP to be enabled, disabling HT "
+			   "capabilities");
+	}
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_WPS2
+	if (bss->wps_state && bss->ignore_broadcast_ssid) {
+		wpa_printf(MSG_INFO, "WPS: ignore_broadcast_ssid "
+			   "configuration forced WPS to be disabled");
+		bss->wps_state = 0;
+	}
+
+	if (bss->wps_state && bss->ssid.wep.keys_set && bss->wpa == 0) {
+		wpa_printf(MSG_INFO, "WPS: WEP configuration forced WPS to be "
+			   "disabled");
+		bss->wps_state = 0;
+	}
+
+	if (bss->wps_state && bss->wpa &&
+	    (!(bss->wpa & 2) ||
+	     !(bss->rsn_pairwise & WPA_CIPHER_CCMP))) {
+		wpa_printf(MSG_INFO, "WPS: WPA/TKIP configuration without "
+			   "WPA2/CCMP forced WPS to be disabled");
+		bss->wps_state = 0;
+	}
+#endif /* CONFIG_WPS2 */
+
+#ifdef CONFIG_HS20
+	if (bss->hs20 &&
+	    (!(bss->wpa & 2) ||
+	     !(bss->rsn_pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)))) {
+		wpa_printf(MSG_ERROR, "HS 2.0: WPA2-Enterprise/CCMP "
+			   "configuration is required for Hotspot 2.0 "
+			   "functionality");
+		return -1;
+	}
+#endif /* CONFIG_HS20 */
+
+	return 0;
+}
+
+
+static int hostapd_config_check(struct hostapd_config *conf)
+{
+	size_t i;
+
+	if (conf->ieee80211d && (!conf->country[0] || !conf->country[1])) {
+		wpa_printf(MSG_ERROR, "Cannot enable IEEE 802.11d without "
+			   "setting the country_code");
+		return -1;
+	}
+
+	for (i = 0; i < conf->num_bss; i++) {
+		if (hostapd_config_check_bss(&conf->bss[i], conf))
+			return -1;
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_INTERWORKING
+static int parse_roaming_consortium(struct hostapd_bss_config *bss, char *pos,
+				    int line)
+{
+	size_t len = os_strlen(pos);
+	u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
+
+	struct hostapd_roaming_consortium *rc;
+
+	if ((len & 1) || len < 2 * 3 || len / 2 > MAX_ROAMING_CONSORTIUM_LEN ||
+	    hexstr2bin(pos, oi, len / 2)) {
+		wpa_printf(MSG_ERROR, "Line %d: invalid roaming_consortium "
+			   "'%s'", line, pos);
+		return -1;
+	}
+	len /= 2;
+
+	rc = os_realloc_array(bss->roaming_consortium,
+			      bss->roaming_consortium_count + 1,
+			      sizeof(struct hostapd_roaming_consortium));
+	if (rc == NULL)
+		return -1;
+
+	os_memcpy(rc[bss->roaming_consortium_count].oi, oi, len);
+	rc[bss->roaming_consortium_count].len = len;
+
+	bss->roaming_consortium = rc;
+	bss->roaming_consortium_count++;
+
+	return 0;
+}
+
+
+static int parse_lang_string(struct hostapd_lang_string **array,
+			     unsigned int *count, char *pos)
+{
+	char *sep;
+	size_t clen, nlen;
+	struct hostapd_lang_string *ls;
+
+	sep = os_strchr(pos, ':');
+	if (sep == NULL)
+		return -1;
+	*sep++ = '\0';
+
+	clen = os_strlen(pos);
+	if (clen < 2)
+		return -1;
+	nlen = os_strlen(sep);
+	if (nlen > 252)
+		return -1;
+
+	ls = os_realloc_array(*array, *count + 1,
+			      sizeof(struct hostapd_lang_string));
+	if (ls == NULL)
+		return -1;
+
+	*array = ls;
+	ls = &(*array)[*count];
+	(*count)++;
+
+	os_memset(ls->lang, 0, sizeof(ls->lang));
+	os_memcpy(ls->lang, pos, clen);
+	ls->name_len = nlen;
+	os_memcpy(ls->name, sep, nlen);
+
+	return 0;
+}
+
+
+static int parse_venue_name(struct hostapd_bss_config *bss, char *pos,
+			    int line)
+{
+	if (parse_lang_string(&bss->venue_name, &bss->venue_name_count, pos)) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid venue_name '%s'",
+			   line, pos);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int parse_3gpp_cell_net(struct hostapd_bss_config *bss, char *buf,
+			       int line)
+{
+	size_t count;
+	char *pos;
+	u8 *info = NULL, *ipos;
+
+	/* format: <MCC1,MNC1>[;<MCC2,MNC2>][;...] */
+
+	count = 1;
+	for (pos = buf; *pos; pos++) {
+		if ((*pos < '0' && *pos > '9') && *pos != ';' && *pos != ',')
+			goto fail;
+		if (*pos == ';')
+			count++;
+	}
+	if (1 + count * 3 > 0x7f)
+		goto fail;
+
+	info = os_zalloc(2 + 3 + count * 3);
+	if (info == NULL)
+		return -1;
+
+	ipos = info;
+	*ipos++ = 0; /* GUD - Version 1 */
+	*ipos++ = 3 + count * 3; /* User Data Header Length (UDHL) */
+	*ipos++ = 0; /* PLMN List IEI */
+	/* ext(b8) | Length of PLMN List value contents(b7..1) */
+	*ipos++ = 1 + count * 3;
+	*ipos++ = count; /* Number of PLMNs */
+
+	pos = buf;
+	while (pos && *pos) {
+		char *mcc, *mnc;
+		size_t mnc_len;
+
+		mcc = pos;
+		mnc = os_strchr(pos, ',');
+		if (mnc == NULL)
+			goto fail;
+		*mnc++ = '\0';
+		pos = os_strchr(mnc, ';');
+		if (pos)
+			*pos++ = '\0';
+
+		mnc_len = os_strlen(mnc);
+		if (os_strlen(mcc) != 3 || (mnc_len != 2 && mnc_len != 3))
+			goto fail;
+
+		/* BC coded MCC,MNC */
+		/* MCC digit 2 | MCC digit 1 */
+		*ipos++ = ((mcc[1] - '0') << 4) | (mcc[0] - '0');
+		/* MNC digit 3 | MCC digit 3 */
+		*ipos++ = (((mnc_len == 2) ? 0xf0 : ((mnc[2] - '0') << 4))) |
+			(mcc[2] - '0');
+		/* MNC digit 2 | MNC digit 1 */
+		*ipos++ = ((mnc[1] - '0') << 4) | (mnc[0] - '0');
+	}
+
+	os_free(bss->anqp_3gpp_cell_net);
+	bss->anqp_3gpp_cell_net = info;
+	bss->anqp_3gpp_cell_net_len = 2 + 3 + 3 * count;
+	wpa_hexdump(MSG_MSGDUMP, "3GPP Cellular Network information",
+		    bss->anqp_3gpp_cell_net, bss->anqp_3gpp_cell_net_len);
+
+	return 0;
+
+fail:
+	wpa_printf(MSG_ERROR, "Line %d: Invalid anqp_3gpp_cell_net: %s",
+		   line, buf);
+	os_free(info);
+	return -1;
+}
+
+
+static int parse_nai_realm(struct hostapd_bss_config *bss, char *buf, int line)
+{
+	struct hostapd_nai_realm_data *realm;
+	size_t i, j, len;
+	int *offsets;
+	char *pos, *end, *rpos;
+
+	offsets = os_calloc(bss->nai_realm_count * MAX_NAI_REALMS,
+			    sizeof(int));
+	if (offsets == NULL)
+		return -1;
+
+	for (i = 0; i < bss->nai_realm_count; i++) {
+		realm = &bss->nai_realm_data[i];
+		for (j = 0; j < MAX_NAI_REALMS; j++) {
+			offsets[i * MAX_NAI_REALMS + j] =
+				realm->realm[j] ?
+				realm->realm[j] - realm->realm_buf : -1;
+		}
+	}
+
+	realm = os_realloc_array(bss->nai_realm_data, bss->nai_realm_count + 1,
+				 sizeof(struct hostapd_nai_realm_data));
+	if (realm == NULL) {
+		os_free(offsets);
+		return -1;
+	}
+	bss->nai_realm_data = realm;
+
+	/* patch the pointers after realloc */
+	for (i = 0; i < bss->nai_realm_count; i++) {
+		realm = &bss->nai_realm_data[i];
+		for (j = 0; j < MAX_NAI_REALMS; j++) {
+			int offs = offsets[i * MAX_NAI_REALMS + j];
+			if (offs >= 0)
+				realm->realm[j] = realm->realm_buf + offs;
+			else
+				realm->realm[j] = NULL;
+		}
+	}
+	os_free(offsets);
+
+	realm = &bss->nai_realm_data[bss->nai_realm_count];
+	os_memset(realm, 0, sizeof(*realm));
+
+	pos = buf;
+	realm->encoding = atoi(pos);
+	pos = os_strchr(pos, ',');
+	if (pos == NULL)
+		goto fail;
+	pos++;
+
+	end = os_strchr(pos, ',');
+	if (end) {
+		len = end - pos;
+		*end = '\0';
+	} else {
+		len = os_strlen(pos);
+	}
+
+	if (len > MAX_NAI_REALMLEN) {
+		wpa_printf(MSG_ERROR, "Too long a realm string (%d > max %d "
+			   "characters)", (int) len, MAX_NAI_REALMLEN);
+		goto fail;
+	}
+	os_memcpy(realm->realm_buf, pos, len);
+
+	if (end)
+		pos = end + 1;
+	else
+		pos = NULL;
+
+	while (pos && *pos) {
+		struct hostapd_nai_realm_eap *eap;
+
+		if (realm->eap_method_count >= MAX_NAI_EAP_METHODS) {
+			wpa_printf(MSG_ERROR, "Too many EAP methods");
+			goto fail;
+		}
+
+		eap = &realm->eap_method[realm->eap_method_count];
+		realm->eap_method_count++;
+
+		end = os_strchr(pos, ',');
+		if (end == NULL)
+			end = pos + os_strlen(pos);
+
+		eap->eap_method = atoi(pos);
+		for (;;) {
+			pos = os_strchr(pos, '[');
+			if (pos == NULL || pos > end)
+				break;
+			pos++;
+			if (eap->num_auths >= MAX_NAI_AUTH_TYPES) {
+				wpa_printf(MSG_ERROR, "Too many auth params");
+				goto fail;
+			}
+			eap->auth_id[eap->num_auths] = atoi(pos);
+			pos = os_strchr(pos, ':');
+			if (pos == NULL || pos > end)
+				goto fail;
+			pos++;
+			eap->auth_val[eap->num_auths] = atoi(pos);
+			pos = os_strchr(pos, ']');
+			if (pos == NULL || pos > end)
+				goto fail;
+			pos++;
+			eap->num_auths++;
+		}
+
+		if (*end != ',')
+			break;
+
+		pos = end + 1;
+	}
+
+	/* Split realm list into null terminated realms */
+	rpos = realm->realm_buf;
+	i = 0;
+	while (*rpos) {
+		if (i >= MAX_NAI_REALMS) {
+			wpa_printf(MSG_ERROR, "Too many realms");
+			goto fail;
+		}
+		realm->realm[i++] = rpos;
+		rpos = os_strchr(rpos, ';');
+		if (rpos == NULL)
+			break;
+		*rpos++ = '\0';
+	}
+
+	bss->nai_realm_count++;
+
+	return 0;
+
+fail:
+	wpa_printf(MSG_ERROR, "Line %d: invalid nai_realm '%s'", line, buf);
+	return -1;
+}
+
+#endif /* CONFIG_INTERWORKING */
+
+
+#ifdef CONFIG_HS20
+static int hs20_parse_conn_capab(struct hostapd_bss_config *bss, char *buf,
+				 int line)
+{
+	u8 *conn_cap;
+	char *pos;
+
+	if (bss->hs20_connection_capability_len >= 0xfff0)
+		return -1;
+
+	conn_cap = os_realloc(bss->hs20_connection_capability,
+			      bss->hs20_connection_capability_len + 4);
+	if (conn_cap == NULL)
+		return -1;
+
+	bss->hs20_connection_capability = conn_cap;
+	conn_cap += bss->hs20_connection_capability_len;
+	pos = buf;
+	conn_cap[0] = atoi(pos);
+	pos = os_strchr(pos, ':');
+	if (pos == NULL)
+		return -1;
+	pos++;
+	WPA_PUT_LE16(conn_cap + 1, atoi(pos));
+	pos = os_strchr(pos, ':');
+	if (pos == NULL)
+		return -1;
+	pos++;
+	conn_cap[3] = atoi(pos);
+	bss->hs20_connection_capability_len += 4;
+
+	return 0;
+}
+
+
+static int hs20_parse_wan_metrics(struct hostapd_bss_config *bss, char *buf,
+				  int line)
+{
+	u8 *wan_metrics;
+	char *pos;
+
+	/* <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD> */
+
+	wan_metrics = os_zalloc(13);
+	if (wan_metrics == NULL)
+		return -1;
+
+	pos = buf;
+	/* WAN Info */
+	if (hexstr2bin(pos, wan_metrics, 1) < 0)
+		goto fail;
+	pos += 2;
+	if (*pos != ':')
+		goto fail;
+	pos++;
+
+	/* Downlink Speed */
+	WPA_PUT_LE32(wan_metrics + 1, atoi(pos));
+	pos = os_strchr(pos, ':');
+	if (pos == NULL)
+		goto fail;
+	pos++;
+
+	/* Uplink Speed */
+	WPA_PUT_LE32(wan_metrics + 5, atoi(pos));
+	pos = os_strchr(pos, ':');
+	if (pos == NULL)
+		goto fail;
+	pos++;
+
+	/* Downlink Load */
+	wan_metrics[9] = atoi(pos);
+	pos = os_strchr(pos, ':');
+	if (pos == NULL)
+		goto fail;
+	pos++;
+
+	/* Uplink Load */
+	wan_metrics[10] = atoi(pos);
+	pos = os_strchr(pos, ':');
+	if (pos == NULL)
+		goto fail;
+	pos++;
+
+	/* LMD */
+	WPA_PUT_LE16(wan_metrics + 11, atoi(pos));
+
+	os_free(bss->hs20_wan_metrics);
+	bss->hs20_wan_metrics = wan_metrics;
+
+	return 0;
+
+fail:
+	wpa_printf(MSG_ERROR, "Line %d: Invalid hs20_wan_metrics '%s'",
+		   line, pos);
+	os_free(wan_metrics);
+	return -1;
+}
+
+
+static int hs20_parse_oper_friendly_name(struct hostapd_bss_config *bss,
+					 char *pos, int line)
+{
+	if (parse_lang_string(&bss->hs20_oper_friendly_name,
+			      &bss->hs20_oper_friendly_name_count, pos)) {
+		wpa_printf(MSG_ERROR, "Line %d: Invalid "
+			   "hs20_oper_friendly_name '%s'", line, pos);
+		return -1;
+	}
+	return 0;
+}
+#endif /* CONFIG_HS20 */
+
+
+#ifdef CONFIG_WPS_NFC
+static struct wpabuf * hostapd_parse_bin(const char *buf)
+{
+	size_t len;
+	struct wpabuf *ret;
+
+	len = os_strlen(buf);
+	if (len & 0x01)
+		return NULL;
+	len /= 2;
+
+	ret = wpabuf_alloc(len);
+	if (ret == NULL)
+		return NULL;
+
+	if (hexstr2bin(buf, wpabuf_put(ret, len), len)) {
+		wpabuf_free(ret);
+		return NULL;
+	}
+
+	return ret;
+}
+#endif /* CONFIG_WPS_NFC */
+
+
+static int hostapd_config_fill(struct hostapd_config *conf,
+			       struct hostapd_bss_config *bss,
+			       char *buf, char *pos, int line)
+{
+	int errors = 0;
+
+	{
+		if (os_strcmp(buf, "interface") == 0) {
+			os_strlcpy(conf->bss[0].iface, pos,
+				   sizeof(conf->bss[0].iface));
+		} else if (os_strcmp(buf, "bridge") == 0) {
+			os_strlcpy(bss->bridge, pos, sizeof(bss->bridge));
+		} else if (os_strcmp(buf, "wds_bridge") == 0) {
+			os_strlcpy(bss->wds_bridge, pos,
+				   sizeof(bss->wds_bridge));
+		} else if (os_strcmp(buf, "driver") == 0) {
+			int j;
+			/* clear to get error below if setting is invalid */
+			conf->driver = NULL;
+			for (j = 0; wpa_drivers[j]; j++) {
+				if (os_strcmp(pos, wpa_drivers[j]->name) == 0)
+				{
+					conf->driver = wpa_drivers[j];
+					break;
+				}
+			}
+			if (conf->driver == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid/"
+					   "unknown driver '%s'", line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "debug") == 0) {
+			wpa_printf(MSG_DEBUG, "Line %d: DEPRECATED: 'debug' "
+				   "configuration variable is not used "
+				   "anymore", line);
+		} else if (os_strcmp(buf, "logger_syslog_level") == 0) {
+			bss->logger_syslog_level = atoi(pos);
+		} else if (os_strcmp(buf, "logger_stdout_level") == 0) {
+			bss->logger_stdout_level = atoi(pos);
+		} else if (os_strcmp(buf, "logger_syslog") == 0) {
+			bss->logger_syslog = atoi(pos);
+		} else if (os_strcmp(buf, "logger_stdout") == 0) {
+			bss->logger_stdout = atoi(pos);
+		} else if (os_strcmp(buf, "dump_file") == 0) {
+			bss->dump_log_name = os_strdup(pos);
+		} else if (os_strcmp(buf, "ssid") == 0) {
+			bss->ssid.ssid_len = os_strlen(pos);
+			if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
+			    bss->ssid.ssid_len < 1) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
+					   "'%s'", line, pos);
+				errors++;
+			} else {
+				os_memcpy(bss->ssid.ssid, pos,
+					  bss->ssid.ssid_len);
+				bss->ssid.ssid_set = 1;
+			}
+		} else if (os_strcmp(buf, "ssid2") == 0) {
+			size_t slen;
+			char *str = wpa_config_parse_string(pos, &slen);
+			if (str == NULL || slen < 1 ||
+				   slen > HOSTAPD_MAX_SSID_LEN) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid SSID "
+					   "'%s'", line, pos);
+				errors++;
+			} else {
+				os_memcpy(bss->ssid.ssid, str, slen);
+				bss->ssid.ssid_len = slen;
+				bss->ssid.ssid_set = 1;
+			}
+			os_free(str);
+		} else if (os_strcmp(buf, "utf8_ssid") == 0) {
+			bss->ssid.utf8_ssid = atoi(pos) > 0;
+		} else if (os_strcmp(buf, "macaddr_acl") == 0) {
+			bss->macaddr_acl = atoi(pos);
+			if (bss->macaddr_acl != ACCEPT_UNLESS_DENIED &&
+			    bss->macaddr_acl != DENY_UNLESS_ACCEPTED &&
+			    bss->macaddr_acl != USE_EXTERNAL_RADIUS_AUTH) {
+				wpa_printf(MSG_ERROR, "Line %d: unknown "
+					   "macaddr_acl %d",
+					   line, bss->macaddr_acl);
+			}
+		} else if (os_strcmp(buf, "accept_mac_file") == 0) {
+			if (hostapd_config_read_maclist(pos, &bss->accept_mac,
+							&bss->num_accept_mac))
+			{
+				wpa_printf(MSG_ERROR, "Line %d: Failed to "
+					   "read accept_mac_file '%s'",
+					   line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "deny_mac_file") == 0) {
+			if (hostapd_config_read_maclist(pos, &bss->deny_mac,
+							&bss->num_deny_mac)) {
+				wpa_printf(MSG_ERROR, "Line %d: Failed to "
+					   "read deny_mac_file '%s'",
+					   line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wds_sta") == 0) {
+			bss->wds_sta = atoi(pos);
+		} else if (os_strcmp(buf, "ap_isolate") == 0) {
+			bss->isolate = atoi(pos);
+		} else if (os_strcmp(buf, "ap_max_inactivity") == 0) {
+			bss->ap_max_inactivity = atoi(pos);
+		} else if (os_strcmp(buf, "skip_inactivity_poll") == 0) {
+			bss->skip_inactivity_poll = atoi(pos);
+		} else if (os_strcmp(buf, "country_code") == 0) {
+			os_memcpy(conf->country, pos, 2);
+			/* FIX: make this configurable */
+			conf->country[2] = ' ';
+		} else if (os_strcmp(buf, "ieee80211d") == 0) {
+			conf->ieee80211d = atoi(pos);
+        } else if (os_strcmp(buf, "channel_switch_count") == 0) {
+            conf->channel_switch_count = atoi(pos);
+		} else if (os_strcmp(buf, "ieee8021x") == 0) {
+			bss->ieee802_1x = atoi(pos);
+		} else if (os_strcmp(buf, "eapol_version") == 0) {
+			bss->eapol_version = atoi(pos);
+			if (bss->eapol_version < 1 ||
+			    bss->eapol_version > 2) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid EAPOL "
+					   "version (%d): '%s'.",
+					   line, bss->eapol_version, pos);
+				errors++;
+			} else
+				wpa_printf(MSG_DEBUG, "eapol_version=%d",
+					   bss->eapol_version);
+#ifdef EAP_SERVER
+		} else if (os_strcmp(buf, "eap_authenticator") == 0) {
+			bss->eap_server = atoi(pos);
+			wpa_printf(MSG_ERROR, "Line %d: obsolete "
+				   "eap_authenticator used; this has been "
+				   "renamed to eap_server", line);
+		} else if (os_strcmp(buf, "eap_server") == 0) {
+			bss->eap_server = atoi(pos);
+		} else if (os_strcmp(buf, "eap_user_file") == 0) {
+			if (hostapd_config_read_eap_user(pos, bss))
+				errors++;
+		} else if (os_strcmp(buf, "ca_cert") == 0) {
+			os_free(bss->ca_cert);
+			bss->ca_cert = os_strdup(pos);
+		} else if (os_strcmp(buf, "server_cert") == 0) {
+			os_free(bss->server_cert);
+			bss->server_cert = os_strdup(pos);
+		} else if (os_strcmp(buf, "private_key") == 0) {
+			os_free(bss->private_key);
+			bss->private_key = os_strdup(pos);
+		} else if (os_strcmp(buf, "private_key_passwd") == 0) {
+			os_free(bss->private_key_passwd);
+			bss->private_key_passwd = os_strdup(pos);
+		} else if (os_strcmp(buf, "check_crl") == 0) {
+			bss->check_crl = atoi(pos);
+		} else if (os_strcmp(buf, "dh_file") == 0) {
+			os_free(bss->dh_file);
+			bss->dh_file = os_strdup(pos);
+		} else if (os_strcmp(buf, "fragment_size") == 0) {
+			bss->fragment_size = atoi(pos);
+#ifdef EAP_SERVER_FAST
+		} else if (os_strcmp(buf, "pac_opaque_encr_key") == 0) {
+			os_free(bss->pac_opaque_encr_key);
+			bss->pac_opaque_encr_key = os_malloc(16);
+			if (bss->pac_opaque_encr_key == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: No memory for "
+					   "pac_opaque_encr_key", line);
+				errors++;
+			} else if (hexstr2bin(pos, bss->pac_opaque_encr_key,
+					      16)) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "pac_opaque_encr_key", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "eap_fast_a_id") == 0) {
+			size_t idlen = os_strlen(pos);
+			if (idlen & 1) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "eap_fast_a_id", line);
+				errors++;
+			} else {
+				os_free(bss->eap_fast_a_id);
+				bss->eap_fast_a_id = os_malloc(idlen / 2);
+				if (bss->eap_fast_a_id == NULL ||
+				    hexstr2bin(pos, bss->eap_fast_a_id,
+					       idlen / 2)) {
+					wpa_printf(MSG_ERROR, "Line %d: "
+						   "Failed to parse "
+						   "eap_fast_a_id", line);
+					errors++;
+				} else
+					bss->eap_fast_a_id_len = idlen / 2;
+			}
+		} else if (os_strcmp(buf, "eap_fast_a_id_info") == 0) {
+			os_free(bss->eap_fast_a_id_info);
+			bss->eap_fast_a_id_info = os_strdup(pos);
+		} else if (os_strcmp(buf, "eap_fast_prov") == 0) {
+			bss->eap_fast_prov = atoi(pos);
+		} else if (os_strcmp(buf, "pac_key_lifetime") == 0) {
+			bss->pac_key_lifetime = atoi(pos);
+		} else if (os_strcmp(buf, "pac_key_refresh_time") == 0) {
+			bss->pac_key_refresh_time = atoi(pos);
+#endif /* EAP_SERVER_FAST */
+#ifdef EAP_SERVER_SIM
+		} else if (os_strcmp(buf, "eap_sim_db") == 0) {
+			os_free(bss->eap_sim_db);
+			bss->eap_sim_db = os_strdup(pos);
+		} else if (os_strcmp(buf, "eap_sim_aka_result_ind") == 0) {
+			bss->eap_sim_aka_result_ind = atoi(pos);
+#endif /* EAP_SERVER_SIM */
+#ifdef EAP_SERVER_TNC
+		} else if (os_strcmp(buf, "tnc") == 0) {
+			bss->tnc = atoi(pos);
+#endif /* EAP_SERVER_TNC */
+#ifdef EAP_SERVER_PWD
+		} else if (os_strcmp(buf, "pwd_group") == 0) {
+			bss->pwd_group = atoi(pos);
+#endif /* EAP_SERVER_PWD */
+#endif /* EAP_SERVER */
+		} else if (os_strcmp(buf, "eap_message") == 0) {
+			char *term;
+			bss->eap_req_id_text = os_strdup(pos);
+			if (bss->eap_req_id_text == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: Failed to "
+					   "allocate memory for "
+					   "eap_req_id_text", line);
+				errors++;
+				return errors;
+			}
+			bss->eap_req_id_text_len =
+				os_strlen(bss->eap_req_id_text);
+			term = os_strstr(bss->eap_req_id_text, "\\0");
+			if (term) {
+				*term++ = '\0';
+				os_memmove(term, term + 1,
+					   bss->eap_req_id_text_len -
+					   (term - bss->eap_req_id_text) - 1);
+				bss->eap_req_id_text_len--;
+			}
+		} else if (os_strcmp(buf, "wep_key_len_broadcast") == 0) {
+			bss->default_wep_key_len = atoi(pos);
+			if (bss->default_wep_key_len > 13) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
+					   "key len %lu (= %lu bits)", line,
+					   (unsigned long)
+					   bss->default_wep_key_len,
+					   (unsigned long)
+					   bss->default_wep_key_len * 8);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wep_key_len_unicast") == 0) {
+			bss->individual_wep_key_len = atoi(pos);
+			if (bss->individual_wep_key_len < 0 ||
+			    bss->individual_wep_key_len > 13) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
+					   "key len %d (= %d bits)", line,
+					   bss->individual_wep_key_len,
+					   bss->individual_wep_key_len * 8);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wep_rekey_period") == 0) {
+			bss->wep_rekeying_period = atoi(pos);
+			if (bss->wep_rekeying_period < 0) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "period %d",
+					   line, bss->wep_rekeying_period);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "eap_reauth_period") == 0) {
+			bss->eap_reauth_period = atoi(pos);
+			if (bss->eap_reauth_period < 0) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "period %d",
+					   line, bss->eap_reauth_period);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "eapol_key_index_workaround") == 0) {
+			bss->eapol_key_index_workaround = atoi(pos);
+#ifdef CONFIG_IAPP
+		} else if (os_strcmp(buf, "iapp_interface") == 0) {
+			bss->ieee802_11f = 1;
+			os_strlcpy(bss->iapp_iface, pos,
+				   sizeof(bss->iapp_iface));
+#endif /* CONFIG_IAPP */
+		} else if (os_strcmp(buf, "own_ip_addr") == 0) {
+			if (hostapd_parse_ip_addr(pos, &bss->own_ip_addr)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid IP "
+					   "address '%s'", line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "nas_identifier") == 0) {
+			bss->nas_identifier = os_strdup(pos);
+#ifndef CONFIG_NO_RADIUS
+		} else if (os_strcmp(buf, "auth_server_addr") == 0) {
+			if (hostapd_config_read_radius_addr(
+				    &bss->radius->auth_servers,
+				    &bss->radius->num_auth_servers, pos, 1812,
+				    &bss->radius->auth_server)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid IP "
+					   "address '%s'", line, pos);
+				errors++;
+			}
+		} else if (bss->radius->auth_server &&
+			   os_strcmp(buf, "auth_server_port") == 0) {
+			bss->radius->auth_server->port = atoi(pos);
+		} else if (bss->radius->auth_server &&
+			   os_strcmp(buf, "auth_server_shared_secret") == 0) {
+			int len = os_strlen(pos);
+			if (len == 0) {
+				/* RFC 2865, Ch. 3 */
+				wpa_printf(MSG_ERROR, "Line %d: empty shared "
+					   "secret is not allowed.", line);
+				errors++;
+			}
+			bss->radius->auth_server->shared_secret =
+				(u8 *) os_strdup(pos);
+			bss->radius->auth_server->shared_secret_len = len;
+		} else if (os_strcmp(buf, "acct_server_addr") == 0) {
+			if (hostapd_config_read_radius_addr(
+				    &bss->radius->acct_servers,
+				    &bss->radius->num_acct_servers, pos, 1813,
+				    &bss->radius->acct_server)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid IP "
+					   "address '%s'", line, pos);
+				errors++;
+			}
+		} else if (bss->radius->acct_server &&
+			   os_strcmp(buf, "acct_server_port") == 0) {
+			bss->radius->acct_server->port = atoi(pos);
+		} else if (bss->radius->acct_server &&
+			   os_strcmp(buf, "acct_server_shared_secret") == 0) {
+			int len = os_strlen(pos);
+			if (len == 0) {
+				/* RFC 2865, Ch. 3 */
+				wpa_printf(MSG_ERROR, "Line %d: empty shared "
+					   "secret is not allowed.", line);
+				errors++;
+			}
+			bss->radius->acct_server->shared_secret =
+				(u8 *) os_strdup(pos);
+			bss->radius->acct_server->shared_secret_len = len;
+		} else if (os_strcmp(buf, "radius_retry_primary_interval") ==
+			   0) {
+			bss->radius->retry_primary_interval = atoi(pos);
+		} else if (os_strcmp(buf, "radius_acct_interim_interval") == 0)
+		{
+			bss->acct_interim_interval = atoi(pos);
+		} else if (os_strcmp(buf, "radius_request_cui") == 0) {
+			bss->radius_request_cui = atoi(pos);
+		} else if (os_strcmp(buf, "radius_auth_req_attr") == 0) {
+			struct hostapd_radius_attr *attr, *a;
+			attr = hostapd_parse_radius_attr(pos);
+			if (attr == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "radius_auth_req_attr", line);
+				errors++;
+			} else if (bss->radius_auth_req_attr == NULL) {
+				bss->radius_auth_req_attr = attr;
+			} else {
+				a = bss->radius_auth_req_attr;
+				while (a->next)
+					a = a->next;
+				a->next = attr;
+			}
+		} else if (os_strcmp(buf, "radius_acct_req_attr") == 0) {
+			struct hostapd_radius_attr *attr, *a;
+			attr = hostapd_parse_radius_attr(pos);
+			if (attr == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "radius_acct_req_attr", line);
+				errors++;
+			} else if (bss->radius_acct_req_attr == NULL) {
+				bss->radius_acct_req_attr = attr;
+			} else {
+				a = bss->radius_acct_req_attr;
+				while (a->next)
+					a = a->next;
+				a->next = attr;
+			}
+		} else if (os_strcmp(buf, "radius_das_port") == 0) {
+			bss->radius_das_port = atoi(pos);
+		} else if (os_strcmp(buf, "radius_das_client") == 0) {
+			if (hostapd_parse_das_client(bss, pos) < 0) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "DAS client", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "radius_das_time_window") == 0) {
+			bss->radius_das_time_window = atoi(pos);
+		} else if (os_strcmp(buf, "radius_das_require_event_timestamp")
+			   == 0) {
+			bss->radius_das_require_event_timestamp = atoi(pos);
+#endif /* CONFIG_NO_RADIUS */
+		} else if (os_strcmp(buf, "auth_algs") == 0) {
+			bss->auth_algs = atoi(pos);
+			if (bss->auth_algs == 0) {
+				wpa_printf(MSG_ERROR, "Line %d: no "
+					   "authentication algorithms allowed",
+					   line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "max_num_sta") == 0) {
+			bss->max_num_sta = atoi(pos);
+			if (bss->max_num_sta < 0 ||
+			    bss->max_num_sta > MAX_STA_COUNT) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "max_num_sta=%d; allowed range "
+					   "0..%d", line, bss->max_num_sta,
+					   MAX_STA_COUNT);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wpa") == 0) {
+			bss->wpa = atoi(pos);
+		} else if (os_strcmp(buf, "wpa_group_rekey") == 0) {
+			bss->wpa_group_rekey = atoi(pos);
+		} else if (os_strcmp(buf, "wpa_strict_rekey") == 0) {
+			bss->wpa_strict_rekey = atoi(pos);
+		} else if (os_strcmp(buf, "wpa_gmk_rekey") == 0) {
+			bss->wpa_gmk_rekey = atoi(pos);
+		} else if (os_strcmp(buf, "wpa_ptk_rekey") == 0) {
+			bss->wpa_ptk_rekey = atoi(pos);
+		} else if (os_strcmp(buf, "wpa_passphrase") == 0) {
+			int len = os_strlen(pos);
+			if (len < 8 || len > 63) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid WPA "
+					   "passphrase length %d (expected "
+					   "8..63)", line, len);
+				errors++;
+			} else {
+				os_free(bss->ssid.wpa_passphrase);
+				bss->ssid.wpa_passphrase = os_strdup(pos);
+				os_free(bss->ssid.wpa_psk);
+				bss->ssid.wpa_psk = NULL;
+			}
+		} else if (os_strcmp(buf, "wpa_psk") == 0) {
+			os_free(bss->ssid.wpa_psk);
+			bss->ssid.wpa_psk =
+				os_zalloc(sizeof(struct hostapd_wpa_psk));
+			if (bss->ssid.wpa_psk == NULL)
+				errors++;
+			else if (hexstr2bin(pos, bss->ssid.wpa_psk->psk,
+					    PMK_LEN) ||
+				 pos[PMK_LEN * 2] != '\0') {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid PSK "
+					   "'%s'.", line, pos);
+				errors++;
+			} else {
+				bss->ssid.wpa_psk->group = 1;
+				os_free(bss->ssid.wpa_passphrase);
+				bss->ssid.wpa_passphrase = NULL;
+			}
+		} else if (os_strcmp(buf, "wpa_psk_file") == 0) {
+			os_free(bss->ssid.wpa_psk_file);
+			bss->ssid.wpa_psk_file = os_strdup(pos);
+			if (!bss->ssid.wpa_psk_file) {
+				wpa_printf(MSG_ERROR, "Line %d: allocation "
+					   "failed", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wpa_key_mgmt") == 0) {
+			bss->wpa_key_mgmt =
+				hostapd_config_parse_key_mgmt(line, pos);
+			if (bss->wpa_key_mgmt == -1)
+				errors++;
+		} else if (os_strcmp(buf, "wpa_psk_radius") == 0) {
+			bss->wpa_psk_radius = atoi(pos);
+			if (bss->wpa_psk_radius != PSK_RADIUS_IGNORED &&
+			    bss->wpa_psk_radius != PSK_RADIUS_ACCEPTED &&
+			    bss->wpa_psk_radius != PSK_RADIUS_REQUIRED) {
+				wpa_printf(MSG_ERROR, "Line %d: unknown "
+					   "wpa_psk_radius %d",
+					   line, bss->wpa_psk_radius);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wpa_pairwise") == 0) {
+			bss->wpa_pairwise =
+				hostapd_config_parse_cipher(line, pos);
+			if (bss->wpa_pairwise == -1 ||
+			    bss->wpa_pairwise == 0)
+				errors++;
+			else if (bss->wpa_pairwise &
+				 (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
+				  WPA_CIPHER_WEP104)) {
+				wpa_printf(MSG_ERROR, "Line %d: unsupported "
+					   "pairwise cipher suite '%s'",
+					   bss->wpa_pairwise, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "rsn_pairwise") == 0) {
+			bss->rsn_pairwise =
+				hostapd_config_parse_cipher(line, pos);
+			if (bss->rsn_pairwise == -1 ||
+			    bss->rsn_pairwise == 0)
+				errors++;
+			else if (bss->rsn_pairwise &
+				 (WPA_CIPHER_NONE | WPA_CIPHER_WEP40 |
+				  WPA_CIPHER_WEP104)) {
+				wpa_printf(MSG_ERROR, "Line %d: unsupported "
+					   "pairwise cipher suite '%s'",
+					   bss->rsn_pairwise, pos);
+				errors++;
+			}
+#ifdef CONFIG_RSN_PREAUTH
+		} else if (os_strcmp(buf, "rsn_preauth") == 0) {
+			bss->rsn_preauth = atoi(pos);
+		} else if (os_strcmp(buf, "rsn_preauth_interfaces") == 0) {
+			bss->rsn_preauth_interfaces = os_strdup(pos);
+#endif /* CONFIG_RSN_PREAUTH */
+#ifdef CONFIG_PEERKEY
+		} else if (os_strcmp(buf, "peerkey") == 0) {
+			bss->peerkey = atoi(pos);
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211R
+		} else if (os_strcmp(buf, "mobility_domain") == 0) {
+			if (os_strlen(pos) != 2 * MOBILITY_DOMAIN_ID_LEN ||
+			    hexstr2bin(pos, bss->mobility_domain,
+				       MOBILITY_DOMAIN_ID_LEN) != 0) {
+				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+					   "mobility_domain '%s'", line, pos);
+				errors++;
+				return errors;
+			}
+		} else if (os_strcmp(buf, "r1_key_holder") == 0) {
+			if (os_strlen(pos) != 2 * FT_R1KH_ID_LEN ||
+			    hexstr2bin(pos, bss->r1_key_holder,
+				       FT_R1KH_ID_LEN) != 0) {
+				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+					   "r1_key_holder '%s'", line, pos);
+				errors++;
+				return errors;
+			}
+		} else if (os_strcmp(buf, "r0_key_lifetime") == 0) {
+			bss->r0_key_lifetime = atoi(pos);
+		} else if (os_strcmp(buf, "reassociation_deadline") == 0) {
+			bss->reassociation_deadline = atoi(pos);
+		} else if (os_strcmp(buf, "r0kh") == 0) {
+			if (add_r0kh(bss, pos) < 0) {
+				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+					   "r0kh '%s'", line, pos);
+				errors++;
+				return errors;
+			}
+		} else if (os_strcmp(buf, "r1kh") == 0) {
+			if (add_r1kh(bss, pos) < 0) {
+				wpa_printf(MSG_DEBUG, "Line %d: Invalid "
+					   "r1kh '%s'", line, pos);
+				errors++;
+				return errors;
+			}
+		} else if (os_strcmp(buf, "pmk_r1_push") == 0) {
+			bss->pmk_r1_push = atoi(pos);
+		} else if (os_strcmp(buf, "ft_over_ds") == 0) {
+			bss->ft_over_ds = atoi(pos);
+#endif /* CONFIG_IEEE80211R */
+#ifndef CONFIG_NO_CTRL_IFACE
+		} else if (os_strcmp(buf, "ctrl_interface") == 0) {
+			os_free(bss->ctrl_interface);
+			bss->ctrl_interface = os_strdup(pos);
+		} else if (os_strcmp(buf, "ctrl_interface_group") == 0) {
+#ifndef CONFIG_NATIVE_WINDOWS
+			struct group *grp;
+			char *endp;
+			const char *group = pos;
+
+			grp = getgrnam(group);
+			if (grp) {
+				bss->ctrl_interface_gid = grp->gr_gid;
+				bss->ctrl_interface_gid_set = 1;
+				wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d"
+					   " (from group name '%s')",
+					   bss->ctrl_interface_gid, group);
+				return errors;
+			}
+
+			/* Group name not found - try to parse this as gid */
+			bss->ctrl_interface_gid = strtol(group, &endp, 10);
+			if (*group == '\0' || *endp != '\0') {
+				wpa_printf(MSG_DEBUG, "Line %d: Invalid group "
+					   "'%s'", line, group);
+				errors++;
+				return errors;
+			}
+			bss->ctrl_interface_gid_set = 1;
+			wpa_printf(MSG_DEBUG, "ctrl_interface_group=%d",
+				   bss->ctrl_interface_gid);
+#endif /* CONFIG_NATIVE_WINDOWS */
+#endif /* CONFIG_NO_CTRL_IFACE */
+#ifdef RADIUS_SERVER
+		} else if (os_strcmp(buf, "radius_server_clients") == 0) {
+			os_free(bss->radius_server_clients);
+			bss->radius_server_clients = os_strdup(pos);
+		} else if (os_strcmp(buf, "radius_server_auth_port") == 0) {
+			bss->radius_server_auth_port = atoi(pos);
+		} else if (os_strcmp(buf, "radius_server_ipv6") == 0) {
+			bss->radius_server_ipv6 = atoi(pos);
+#endif /* RADIUS_SERVER */
+		} else if (os_strcmp(buf, "test_socket") == 0) {
+			os_free(bss->test_socket);
+			bss->test_socket = os_strdup(pos);
+		} else if (os_strcmp(buf, "use_pae_group_addr") == 0) {
+			bss->use_pae_group_addr = atoi(pos);
+		} else if (os_strcmp(buf, "hw_mode") == 0) {
+			if (os_strcmp(pos, "a") == 0)
+				conf->hw_mode = HOSTAPD_MODE_IEEE80211A;
+			else if (os_strcmp(pos, "b") == 0)
+				conf->hw_mode = HOSTAPD_MODE_IEEE80211B;
+			else if (os_strcmp(pos, "g") == 0)
+				conf->hw_mode = HOSTAPD_MODE_IEEE80211G;
+			else if (os_strcmp(pos, "ad") == 0)
+				conf->hw_mode = HOSTAPD_MODE_IEEE80211AD;
+			else {
+				wpa_printf(MSG_ERROR, "Line %d: unknown "
+					   "hw_mode '%s'", line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wps_rf_bands") == 0) {
+			if (os_strcmp(pos, "a") == 0)
+				bss->wps_rf_bands = WPS_RF_50GHZ;
+			else if (os_strcmp(pos, "g") == 0 ||
+				 os_strcmp(pos, "b") == 0)
+				bss->wps_rf_bands = WPS_RF_24GHZ;
+			else if (os_strcmp(pos, "ag") == 0 ||
+				 os_strcmp(pos, "ga") == 0)
+				bss->wps_rf_bands =
+					WPS_RF_24GHZ | WPS_RF_50GHZ;
+			else {
+				wpa_printf(MSG_ERROR, "Line %d: unknown "
+					   "wps_rf_band '%s'", line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "channel") == 0) {
+			conf->channel = atoi(pos);
+		} else if (os_strcmp(buf, "beacon_int") == 0) {
+			int val = atoi(pos);
+			/* MIB defines range as 1..65535, but very small values
+			 * cause problems with the current implementation.
+			 * Since it is unlikely that this small numbers are
+			 * useful in real life scenarios, do not allow beacon
+			 * period to be set below 15 TU. */
+			if (val < 15 || val > 65535) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "beacon_int %d (expected "
+					   "15..65535)", line, val);
+				errors++;
+			} else
+				conf->beacon_int = val;
+		} else if (os_strcmp(buf, "dtim_period") == 0) {
+			bss->dtim_period = atoi(pos);
+			if (bss->dtim_period < 1 || bss->dtim_period > 255) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "dtim_period %d",
+					   line, bss->dtim_period);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "rts_threshold") == 0) {
+			conf->rts_threshold = atoi(pos);
+			if (conf->rts_threshold < 0 ||
+			    conf->rts_threshold > 2347) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "rts_threshold %d",
+					   line, conf->rts_threshold);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "fragm_threshold") == 0) {
+			conf->fragm_threshold = atoi(pos);
+			if (conf->fragm_threshold < 256 ||
+			    conf->fragm_threshold > 2346) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "fragm_threshold %d",
+					   line, conf->fragm_threshold);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "send_probe_response") == 0) {
+			int val = atoi(pos);
+			if (val != 0 && val != 1) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "send_probe_response %d (expected "
+					   "0 or 1)", line, val);
+			} else
+				conf->send_probe_response = val;
+		} else if (os_strcmp(buf, "supported_rates") == 0) {
+			if (hostapd_parse_rates(&conf->supported_rates, pos)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid rate "
+					   "list", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "basic_rates") == 0) {
+			if (hostapd_parse_rates(&conf->basic_rates, pos)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid rate "
+					   "list", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "preamble") == 0) {
+			if (atoi(pos))
+				conf->preamble = SHORT_PREAMBLE;
+			else
+				conf->preamble = LONG_PREAMBLE;
+		} else if (os_strcmp(buf, "ignore_broadcast_ssid") == 0) {
+			bss->ignore_broadcast_ssid = atoi(pos);
+		} else if (os_strcmp(buf, "wep_default_key") == 0) {
+			bss->ssid.wep.idx = atoi(pos);
+			if (bss->ssid.wep.idx > 3) {
+				wpa_printf(MSG_ERROR, "Invalid "
+					   "wep_default_key index %d",
+					   bss->ssid.wep.idx);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wep_key0") == 0 ||
+			   os_strcmp(buf, "wep_key1") == 0 ||
+			   os_strcmp(buf, "wep_key2") == 0 ||
+			   os_strcmp(buf, "wep_key3") == 0) {
+			if (hostapd_config_read_wep(&bss->ssid.wep,
+						    buf[7] - '0', pos)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid WEP "
+					   "key '%s'", line, buf);
+				errors++;
+			}
+#ifndef CONFIG_NO_VLAN
+		} else if (os_strcmp(buf, "dynamic_vlan") == 0) {
+			bss->ssid.dynamic_vlan = atoi(pos);
+		} else if (os_strcmp(buf, "vlan_file") == 0) {
+			if (hostapd_config_read_vlan_file(bss, pos)) {
+				wpa_printf(MSG_ERROR, "Line %d: failed to "
+					   "read VLAN file '%s'", line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "vlan_naming") == 0) {
+			bss->ssid.vlan_naming = atoi(pos);
+			if (bss->ssid.vlan_naming >= DYNAMIC_VLAN_NAMING_END ||
+			    bss->ssid.vlan_naming < 0) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "naming scheme %d", line,
+                                           bss->ssid.vlan_naming);
+				errors++;
+                        }
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+		} else if (os_strcmp(buf, "vlan_tagged_interface") == 0) {
+			bss->ssid.vlan_tagged_interface = os_strdup(pos);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+#endif /* CONFIG_NO_VLAN */
+		} else if (os_strcmp(buf, "ap_table_max_size") == 0) {
+			conf->ap_table_max_size = atoi(pos);
+		} else if (os_strcmp(buf, "ap_table_expiration_time") == 0) {
+			conf->ap_table_expiration_time = atoi(pos);
+		} else if (os_strncmp(buf, "tx_queue_", 9) == 0) {
+			if (hostapd_config_tx_queue(conf, buf, pos)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid TX "
+					   "queue item", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wme_enabled") == 0 ||
+			   os_strcmp(buf, "wmm_enabled") == 0) {
+			bss->wmm_enabled = atoi(pos);
+		} else if (os_strcmp(buf, "uapsd_advertisement_enabled") == 0) {
+			bss->wmm_uapsd = atoi(pos);
+		} else if (os_strncmp(buf, "wme_ac_", 7) == 0 ||
+			   os_strncmp(buf, "wmm_ac_", 7) == 0) {
+			if (hostapd_config_wmm_ac(conf->wmm_ac_params, buf,
+						  pos)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid WMM "
+					   "ac item", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "bss") == 0) {
+			if (hostapd_config_bss(conf, pos)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid bss "
+					   "item", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "bssid") == 0) {
+			if (hwaddr_aton(pos, bss->bssid)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid bssid "
+					   "item", line);
+				errors++;
+			}
+#ifdef CONFIG_IEEE80211W
+		} else if (os_strcmp(buf, "ieee80211w") == 0) {
+			bss->ieee80211w = atoi(pos);
+		} else if (os_strcmp(buf, "assoc_sa_query_max_timeout") == 0) {
+			bss->assoc_sa_query_max_timeout = atoi(pos);
+			if (bss->assoc_sa_query_max_timeout == 0) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "assoc_sa_query_max_timeout", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "assoc_sa_query_retry_timeout") == 0)
+		{
+			bss->assoc_sa_query_retry_timeout = atoi(pos);
+			if (bss->assoc_sa_query_retry_timeout == 0) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "assoc_sa_query_retry_timeout",
+					   line);
+				errors++;
+			}
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211N
+		} else if (os_strcmp(buf, "ieee80211n") == 0) {
+			conf->ieee80211n = atoi(pos);
+		} else if (os_strcmp(buf, "ht_capab") == 0) {
+			if (hostapd_config_ht_capab(conf, pos) < 0) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "ht_capab", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "require_ht") == 0) {
+			conf->require_ht = atoi(pos);
+#endif /* CONFIG_IEEE80211N */
+#ifdef CONFIG_IEEE80211AC
+		} else if (os_strcmp(buf, "ieee80211ac") == 0) {
+			conf->ieee80211ac = atoi(pos);
+		} else if (os_strcmp(buf, "vht_capab") == 0) {
+			if (hostapd_config_vht_capab(conf, pos) < 0) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "vht_capab", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "require_vht") == 0) {
+			conf->require_vht = atoi(pos);
+		} else if (os_strcmp(buf, "vht_oper_chwidth") == 0) {
+			conf->vht_oper_chwidth = atoi(pos);
+		} else if (os_strcmp(buf, "vht_oper_centr_freq_seg0_idx") == 0)
+		{
+			conf->vht_oper_centr_freq_seg0_idx = atoi(pos);
+		} else if (os_strcmp(buf, "vht_oper_centr_freq_seg1_idx") == 0)
+		{
+			conf->vht_oper_centr_freq_seg1_idx = atoi(pos);
+#endif /* CONFIG_IEEE80211AC */
+		} else if (os_strcmp(buf, "max_listen_interval") == 0) {
+			bss->max_listen_interval = atoi(pos);
+		} else if (os_strcmp(buf, "disable_pmksa_caching") == 0) {
+			bss->disable_pmksa_caching = atoi(pos);
+		} else if (os_strcmp(buf, "okc") == 0) {
+			bss->okc = atoi(pos);
+#ifdef CONFIG_WPS
+		} else if (os_strcmp(buf, "wps_state") == 0) {
+			bss->wps_state = atoi(pos);
+			if (bss->wps_state < 0 || bss->wps_state > 2) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "wps_state", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "ap_setup_locked") == 0) {
+			bss->ap_setup_locked = atoi(pos);
+		} else if (os_strcmp(buf, "uuid") == 0) {
+			if (uuid_str2bin(pos, bss->uuid)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid UUID",
+					   line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wps_pin_requests") == 0) {
+			os_free(bss->wps_pin_requests);
+			bss->wps_pin_requests = os_strdup(pos);
+		} else if (os_strcmp(buf, "device_name") == 0) {
+			if (os_strlen(pos) > 32) {
+				wpa_printf(MSG_ERROR, "Line %d: Too long "
+					   "device_name", line);
+				errors++;
+			}
+			os_free(bss->device_name);
+			bss->device_name = os_strdup(pos);
+		} else if (os_strcmp(buf, "manufacturer") == 0) {
+			if (os_strlen(pos) > 64) {
+				wpa_printf(MSG_ERROR, "Line %d: Too long "
+					   "manufacturer", line);
+				errors++;
+			}
+			os_free(bss->manufacturer);
+			bss->manufacturer = os_strdup(pos);
+		} else if (os_strcmp(buf, "model_name") == 0) {
+			if (os_strlen(pos) > 32) {
+				wpa_printf(MSG_ERROR, "Line %d: Too long "
+					   "model_name", line);
+				errors++;
+			}
+			os_free(bss->model_name);
+			bss->model_name = os_strdup(pos);
+		} else if (os_strcmp(buf, "model_number") == 0) {
+			if (os_strlen(pos) > 32) {
+				wpa_printf(MSG_ERROR, "Line %d: Too long "
+					   "model_number", line);
+				errors++;
+			}
+			os_free(bss->model_number);
+			bss->model_number = os_strdup(pos);
+		} else if (os_strcmp(buf, "serial_number") == 0) {
+			if (os_strlen(pos) > 32) {
+				wpa_printf(MSG_ERROR, "Line %d: Too long "
+					   "serial_number", line);
+				errors++;
+			}
+			os_free(bss->serial_number);
+			bss->serial_number = os_strdup(pos);
+		} else if (os_strcmp(buf, "device_type") == 0) {
+			if (wps_dev_type_str2bin(pos, bss->device_type))
+				errors++;
+		} else if (os_strcmp(buf, "config_methods") == 0) {
+			os_free(bss->config_methods);
+			bss->config_methods = os_strdup(pos);
+		} else if (os_strcmp(buf, "os_version") == 0) {
+			if (hexstr2bin(pos, bss->os_version, 4)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "os_version", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "ap_pin") == 0) {
+			os_free(bss->ap_pin);
+			bss->ap_pin = os_strdup(pos);
+		} else if (os_strcmp(buf, "skip_cred_build") == 0) {
+			bss->skip_cred_build = atoi(pos);
+		} else if (os_strcmp(buf, "extra_cred") == 0) {
+			os_free(bss->extra_cred);
+			bss->extra_cred =
+				(u8 *) os_readfile(pos, &bss->extra_cred_len);
+			if (bss->extra_cred == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: could not "
+					   "read Credentials from '%s'",
+					   line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wps_cred_processing") == 0) {
+			bss->wps_cred_processing = atoi(pos);
+		} else if (os_strcmp(buf, "ap_settings") == 0) {
+			os_free(bss->ap_settings);
+			bss->ap_settings =
+				(u8 *) os_readfile(pos, &bss->ap_settings_len);
+			if (bss->ap_settings == NULL) {
+				wpa_printf(MSG_ERROR, "Line %d: could not "
+					   "read AP Settings from '%s'",
+					   line, pos);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "upnp_iface") == 0) {
+			bss->upnp_iface = os_strdup(pos);
+		} else if (os_strcmp(buf, "friendly_name") == 0) {
+			os_free(bss->friendly_name);
+			bss->friendly_name = os_strdup(pos);
+		} else if (os_strcmp(buf, "manufacturer_url") == 0) {
+			os_free(bss->manufacturer_url);
+			bss->manufacturer_url = os_strdup(pos);
+		} else if (os_strcmp(buf, "model_description") == 0) {
+			os_free(bss->model_description);
+			bss->model_description = os_strdup(pos);
+		} else if (os_strcmp(buf, "model_url") == 0) {
+			os_free(bss->model_url);
+			bss->model_url = os_strdup(pos);
+		} else if (os_strcmp(buf, "upc") == 0) {
+			os_free(bss->upc);
+			bss->upc = os_strdup(pos);
+		} else if (os_strcmp(buf, "pbc_in_m1") == 0) {
+			bss->pbc_in_m1 = atoi(pos);
+#ifdef CONFIG_WPS_NFC
+		} else if (os_strcmp(buf, "wps_nfc_dev_pw_id") == 0) {
+			bss->wps_nfc_dev_pw_id = atoi(pos);
+			if (bss->wps_nfc_dev_pw_id < 0x10 ||
+			    bss->wps_nfc_dev_pw_id > 0xffff) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "wps_nfc_dev_pw_id value", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "wps_nfc_dh_pubkey") == 0) {
+			wpabuf_free(bss->wps_nfc_dh_pubkey);
+			bss->wps_nfc_dh_pubkey = hostapd_parse_bin(pos);
+		} else if (os_strcmp(buf, "wps_nfc_dh_privkey") == 0) {
+			wpabuf_free(bss->wps_nfc_dh_privkey);
+			bss->wps_nfc_dh_privkey = hostapd_parse_bin(pos);
+		} else if (os_strcmp(buf, "wps_nfc_dev_pw") == 0) {
+			wpabuf_free(bss->wps_nfc_dev_pw);
+			bss->wps_nfc_dev_pw = hostapd_parse_bin(pos);
+#endif /* CONFIG_WPS_NFC */
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P_MANAGER
+		} else if (os_strcmp(buf, "manage_p2p") == 0) {
+			int manage = atoi(pos);
+			if (manage)
+				bss->p2p |= P2P_MANAGE;
+			else
+				bss->p2p &= ~P2P_MANAGE;
+		} else if (os_strcmp(buf, "allow_cross_connection") == 0) {
+			if (atoi(pos))
+				bss->p2p |= P2P_ALLOW_CROSS_CONNECTION;
+			else
+				bss->p2p &= ~P2P_ALLOW_CROSS_CONNECTION;
+#endif /* CONFIG_P2P_MANAGER */
+		} else if (os_strcmp(buf, "disassoc_low_ack") == 0) {
+			bss->disassoc_low_ack = atoi(pos);
+		} else if (os_strcmp(buf, "tdls_prohibit") == 0) {
+			int val = atoi(pos);
+			if (val)
+				bss->tdls |= TDLS_PROHIBIT;
+			else
+				bss->tdls &= ~TDLS_PROHIBIT;
+		} else if (os_strcmp(buf, "tdls_prohibit_chan_switch") == 0) {
+			int val = atoi(pos);
+			if (val)
+				bss->tdls |= TDLS_PROHIBIT_CHAN_SWITCH;
+			else
+				bss->tdls &= ~TDLS_PROHIBIT_CHAN_SWITCH;
+#ifdef CONFIG_RSN_TESTING
+		} else if (os_strcmp(buf, "rsn_testing") == 0) {
+			extern int rsn_testing;
+			rsn_testing = atoi(pos);
+#endif /* CONFIG_RSN_TESTING */
+		} else if (os_strcmp(buf, "time_advertisement") == 0) {
+			bss->time_advertisement = atoi(pos);
+		} else if (os_strcmp(buf, "time_zone") == 0) {
+			size_t tz_len = os_strlen(pos);
+			if (tz_len < 4 || tz_len > 255) {
+				wpa_printf(MSG_DEBUG, "Line %d: invalid "
+					   "time_zone", line);
+				errors++;
+				return errors;
+			}
+			os_free(bss->time_zone);
+			bss->time_zone = os_strdup(pos);
+			if (bss->time_zone == NULL)
+				errors++;
+#ifdef CONFIG_WNM
+		} else if (os_strcmp(buf, "wnm_sleep_mode") == 0) {
+			bss->wnm_sleep_mode = atoi(pos);
+		} else if (os_strcmp(buf, "bss_transition") == 0) {
+			bss->bss_transition = atoi(pos);
+#endif /* CONFIG_WNM */
+#ifdef CONFIG_INTERWORKING
+		} else if (os_strcmp(buf, "interworking") == 0) {
+			bss->interworking = atoi(pos);
+		} else if (os_strcmp(buf, "access_network_type") == 0) {
+			bss->access_network_type = atoi(pos);
+			if (bss->access_network_type < 0 ||
+			    bss->access_network_type > 15) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "access_network_type", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "internet") == 0) {
+			bss->internet = atoi(pos);
+		} else if (os_strcmp(buf, "asra") == 0) {
+			bss->asra = atoi(pos);
+		} else if (os_strcmp(buf, "esr") == 0) {
+			bss->esr = atoi(pos);
+		} else if (os_strcmp(buf, "uesa") == 0) {
+			bss->uesa = atoi(pos);
+		} else if (os_strcmp(buf, "venue_group") == 0) {
+			bss->venue_group = atoi(pos);
+			bss->venue_info_set = 1;
+		} else if (os_strcmp(buf, "venue_type") == 0) {
+			bss->venue_type = atoi(pos);
+			bss->venue_info_set = 1;
+		} else if (os_strcmp(buf, "hessid") == 0) {
+			if (hwaddr_aton(pos, bss->hessid)) {
+				wpa_printf(MSG_ERROR, "Line %d: invalid "
+					   "hessid", line);
+				errors++;
+			}
+		} else if (os_strcmp(buf, "roaming_consortium") == 0) {
+			if (parse_roaming_consortium(bss, pos, line) < 0)
+				errors++;
+		} else if (os_strcmp(buf, "venue_name") == 0) {
+			if (parse_venue_name(bss, pos, line) < 0)
+				errors++;
+		} else if (os_strcmp(buf, "network_auth_type") == 0) {
+			u8 auth_type;
+			u16 redirect_url_len;
+			if (hexstr2bin(pos, &auth_type, 1)) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "network_auth_type '%s'",
+					   line, pos);
+				errors++;
+				return errors;
+			}
+			if (auth_type == 0 || auth_type == 2)
+				redirect_url_len = os_strlen(pos + 2);
+			else
+				redirect_url_len = 0;
+			os_free(bss->network_auth_type);
+			bss->network_auth_type =
+				os_malloc(redirect_url_len + 3 + 1);
+			if (bss->network_auth_type == NULL) {
+				errors++;
+				return errors;
+			}
+			*bss->network_auth_type = auth_type;
+			WPA_PUT_LE16(bss->network_auth_type + 1,
+				     redirect_url_len);
+			if (redirect_url_len)
+				os_memcpy(bss->network_auth_type + 3,
+					  pos + 2, redirect_url_len);
+			bss->network_auth_type_len = 3 + redirect_url_len;
+		} else if (os_strcmp(buf, "ipaddr_type_availability") == 0) {
+			if (hexstr2bin(pos, &bss->ipaddr_type_availability, 1))
+			{
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "ipaddr_type_availability '%s'",
+					   line, pos);
+				bss->ipaddr_type_configured = 0;
+				errors++;
+				return errors;
+			}
+			bss->ipaddr_type_configured = 1;
+		} else if (os_strcmp(buf, "domain_name") == 0) {
+			int j, num_domains, domain_len, domain_list_len = 0;
+			char *tok_start, *tok_prev;
+			u8 *domain_list, *domain_ptr;
+
+			domain_list_len = os_strlen(pos) + 1;
+			domain_list = os_malloc(domain_list_len);
+			if (domain_list == NULL) {
+				errors++;
+				return errors;
+			}
+
+			domain_ptr = domain_list;
+			tok_prev = pos;
+			num_domains = 1;
+			while ((tok_prev = os_strchr(tok_prev, ','))) {
+				num_domains++;
+				tok_prev++;
+			}
+			tok_prev = pos;
+			for (j = 0; j < num_domains; j++) {
+				tok_start = os_strchr(tok_prev, ',');
+				if (tok_start) {
+					domain_len = tok_start - tok_prev;
+					*domain_ptr = domain_len;
+					os_memcpy(domain_ptr + 1, tok_prev,
+						  domain_len);
+					domain_ptr += domain_len + 1;
+					tok_prev = ++tok_start;
+				} else {
+					domain_len = os_strlen(tok_prev);
+					*domain_ptr = domain_len;
+					os_memcpy(domain_ptr + 1, tok_prev,
+						  domain_len);
+					domain_ptr += domain_len + 1;
+				}
+			}
+
+			os_free(bss->domain_name);
+			bss->domain_name = domain_list;
+			bss->domain_name_len = domain_list_len;
+		} else if (os_strcmp(buf, "anqp_3gpp_cell_net") == 0) {
+			if (parse_3gpp_cell_net(bss, pos, line) < 0)
+				errors++;
+		} else if (os_strcmp(buf, "nai_realm") == 0) {
+			if (parse_nai_realm(bss, pos, line) < 0)
+				errors++;
+		} else if (os_strcmp(buf, "gas_frag_limit") == 0) {
+			bss->gas_frag_limit = atoi(pos);
+		} else if (os_strcmp(buf, "gas_comeback_delay") == 0) {
+			bss->gas_comeback_delay = atoi(pos);
+#endif /* CONFIG_INTERWORKING */
+#ifdef CONFIG_RADIUS_TEST
+		} else if (os_strcmp(buf, "dump_msk_file") == 0) {
+			os_free(bss->dump_msk_file);
+			bss->dump_msk_file = os_strdup(pos);
+#endif /* CONFIG_RADIUS_TEST */
+#ifdef CONFIG_HS20
+		} else if (os_strcmp(buf, "hs20") == 0) {
+			bss->hs20 = atoi(pos);
+		} else if (os_strcmp(buf, "disable_dgaf") == 0) {
+			bss->disable_dgaf = atoi(pos);
+		} else if (os_strcmp(buf, "hs20_oper_friendly_name") == 0) {
+			if (hs20_parse_oper_friendly_name(bss, pos, line) < 0)
+				errors++;
+		} else if (os_strcmp(buf, "hs20_wan_metrics") == 0) {
+			if (hs20_parse_wan_metrics(bss, pos, line) < 0) {
+				errors++;
+				return errors;
+			}
+		} else if (os_strcmp(buf, "hs20_conn_capab") == 0) {
+			if (hs20_parse_conn_capab(bss, pos, line) < 0) {
+				errors++;
+				return errors;
+			}
+		} else if (os_strcmp(buf, "hs20_operating_class") == 0) {
+			u8 *oper_class;
+			size_t oper_class_len;
+			oper_class_len = os_strlen(pos);
+			if (oper_class_len < 2 || (oper_class_len & 0x01)) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "hs20_operating_class '%s'",
+					   line, pos);
+				errors++;
+				return errors;
+			}
+			oper_class_len /= 2;
+			oper_class = os_malloc(oper_class_len);
+			if (oper_class == NULL) {
+				errors++;
+				return errors;
+			}
+			if (hexstr2bin(pos, oper_class, oper_class_len)) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "hs20_operating_class '%s'",
+					   line, pos);
+				os_free(oper_class);
+				errors++;
+				return errors;
+			}
+			os_free(bss->hs20_operating_class);
+			bss->hs20_operating_class = oper_class;
+			bss->hs20_operating_class_len = oper_class_len;
+#endif /* CONFIG_HS20 */
+		} else if (os_strcmp(buf, "vendor_elements") == 0) {
+			struct wpabuf *elems;
+			size_t len = os_strlen(pos);
+			if (len & 0x01) {
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "vendor_elements '%s'", line, pos);
+				return 1;
+			}
+			len /= 2;
+			if (len == 0) {
+				wpabuf_free(bss->vendor_elements);
+				bss->vendor_elements = NULL;
+				return 0;
+			}
+
+			elems = wpabuf_alloc(len);
+			if (elems == NULL)
+				return 1;
+
+			if (hexstr2bin(pos, wpabuf_put(elems, len), len)) {
+				wpabuf_free(elems);
+				wpa_printf(MSG_ERROR, "Line %d: Invalid "
+					   "vendor_elements '%s'", line, pos);
+				return 1;
+			}
+
+			wpabuf_free(bss->vendor_elements);
+			bss->vendor_elements = elems;
+		} else {
+			wpa_printf(MSG_ERROR, "Line %d: unknown configuration "
+				   "item '%s'", line, buf);
+			errors++;
+		}
+	}
+
+	return errors;
+}
+
+
+static void hostapd_set_security_params(struct hostapd_bss_config *bss)
+{
+	int pairwise;
+
+	if (bss->individual_wep_key_len == 0) {
+		/* individual keys are not use; can use key idx0 for
+		 * broadcast keys */
+		bss->broadcast_key_idx_min = 0;
+	}
+
+	/* Select group cipher based on the enabled pairwise cipher
+	 * suites */
+	pairwise = 0;
+	if (bss->wpa & 1)
+		pairwise |= bss->wpa_pairwise;
+	if (bss->wpa & 2) {
+		if (bss->rsn_pairwise == 0)
+			bss->rsn_pairwise = bss->wpa_pairwise;
+		pairwise |= bss->rsn_pairwise;
+	}
+	if (pairwise & WPA_CIPHER_TKIP)
+		bss->wpa_group = WPA_CIPHER_TKIP;
+	else if ((pairwise & (WPA_CIPHER_CCMP | WPA_CIPHER_GCMP)) ==
+		 WPA_CIPHER_GCMP)
+		bss->wpa_group = WPA_CIPHER_GCMP;
+	else
+		bss->wpa_group = WPA_CIPHER_CCMP;
+
+	bss->radius->auth_server = bss->radius->auth_servers;
+	bss->radius->acct_server = bss->radius->acct_servers;
+
+	if (bss->wpa && bss->ieee802_1x) {
+		bss->ssid.security_policy = SECURITY_WPA;
+	} else if (bss->wpa) {
+		bss->ssid.security_policy = SECURITY_WPA_PSK;
+	} else if (bss->ieee802_1x) {
+		int cipher = WPA_CIPHER_NONE;
+		bss->ssid.security_policy = SECURITY_IEEE_802_1X;
+		bss->ssid.wep.default_len = bss->default_wep_key_len;
+		if (bss->default_wep_key_len)
+			cipher = bss->default_wep_key_len >= 13 ?
+				WPA_CIPHER_WEP104 : WPA_CIPHER_WEP40;
+		bss->wpa_group = cipher;
+		bss->wpa_pairwise = cipher;
+		bss->rsn_pairwise = cipher;
+	} else if (bss->ssid.wep.keys_set) {
+		int cipher = WPA_CIPHER_WEP40;
+		if (bss->ssid.wep.len[0] >= 13)
+			cipher = WPA_CIPHER_WEP104;
+		bss->ssid.security_policy = SECURITY_STATIC_WEP;
+		bss->wpa_group = cipher;
+		bss->wpa_pairwise = cipher;
+		bss->rsn_pairwise = cipher;
+	} else {
+		bss->ssid.security_policy = SECURITY_PLAINTEXT;
+		bss->wpa_group = WPA_CIPHER_NONE;
+		bss->wpa_pairwise = WPA_CIPHER_NONE;
+		bss->rsn_pairwise = WPA_CIPHER_NONE;
+	}
+}
+
+
+/**
+ * hostapd_config_read - Read and parse a configuration file
+ * @fname: Configuration file name (including path, if needed)
+ * Returns: Allocated configuration data structure
+ */
+struct hostapd_config * hostapd_config_read(const char *fname)
+{
+	struct hostapd_config *conf;
+	struct hostapd_bss_config *bss;
+	FILE *f;
+	char buf[512], *pos;
+	int line = 0;
+	int errors = 0;
+	size_t i;
+
+	f = fopen(fname, "r");
+	if (f == NULL) {
+		wpa_printf(MSG_ERROR, "Could not open configuration file '%s' "
+			   "for reading.", fname);
+		return NULL;
+	}
+
+	conf = hostapd_config_defaults();
+	if (conf == NULL) {
+		fclose(f);
+		return NULL;
+	}
+
+	/* set default driver based on configuration */
+	conf->driver = wpa_drivers[0];
+	if (conf->driver == NULL) {
+		wpa_printf(MSG_ERROR, "No driver wrappers registered!");
+		hostapd_config_free(conf);
+		fclose(f);
+		return NULL;
+	}
+
+	bss = conf->last_bss = conf->bss;
+
+	while (fgets(buf, sizeof(buf), f)) {
+		bss = conf->last_bss;
+		line++;
+
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0') {
+			if (*pos == '\n') {
+				*pos = '\0';
+				break;
+			}
+			pos++;
+		}
+		if (buf[0] == '\0')
+			continue;
+
+		pos = os_strchr(buf, '=');
+		if (pos == NULL) {
+			wpa_printf(MSG_ERROR, "Line %d: invalid line '%s'",
+				   line, buf);
+			errors++;
+			continue;
+		}
+		*pos = '\0';
+		pos++;
+		errors += hostapd_config_fill(conf, bss, buf, pos, line);
+	}
+
+	fclose(f);
+
+	for (i = 0; i < conf->num_bss; i++)
+		hostapd_set_security_params(&conf->bss[i]);
+
+	if (hostapd_config_check(conf))
+		errors++;
+
+#ifndef WPA_IGNORE_CONFIG_ERRORS
+	if (errors) {
+		wpa_printf(MSG_ERROR, "%d errors found in configuration file "
+			   "'%s'", errors, fname);
+		hostapd_config_free(conf);
+		conf = NULL;
+	}
+#endif /* WPA_IGNORE_CONFIG_ERRORS */
+
+	return conf;
+}
+
+
+int hostapd_set_iface(struct hostapd_config *conf,
+		      struct hostapd_bss_config *bss, char *field, char *value)
+{
+	int errors;
+	size_t i;
+
+	errors = hostapd_config_fill(conf, bss, field, value, 0);
+	if (errors) {
+		wpa_printf(MSG_INFO, "Failed to set configuration field '%s' "
+			   "to value '%s'", field, value);
+		return -1;
+	}
+
+	for (i = 0; i < conf->num_bss; i++)
+		hostapd_set_security_params(&conf->bss[i]);
+
+	if (hostapd_config_check(conf)) {
+		wpa_printf(MSG_ERROR, "Configuration check failed");
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/hostap/hostapd/config_file.h b/hostap/hostapd/config_file.h
new file mode 100644
index 0000000..fba57b8
--- /dev/null
+++ b/hostap/hostapd/config_file.h
@@ -0,0 +1,17 @@
+/*
+ * hostapd / Configuration file parser
+ * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CONFIG_FILE_H
+#define CONFIG_FILE_H
+
+struct hostapd_config * hostapd_config_read(const char *fname);
+int hostapd_set_iface(struct hostapd_config *conf,
+		      struct hostapd_bss_config *bss, char *field,
+		      char *value);
+
+#endif /* CONFIG_FILE_H */
diff --git a/hostap/hostapd/ctrl_iface.c b/hostap/hostapd/ctrl_iface.c
new file mode 100644
index 0000000..3c9071c
--- /dev/null
+++ b/hostap/hostapd/ctrl_iface.c
@@ -0,0 +1,1453 @@
+/*
+ * hostapd / UNIX domain socket -based control interface
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
+#include <sys/un.h>
+#include <sys/stat.h>
+#include <stddef.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/version.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "radius/radius_client.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "ap/ieee802_1x.h"
+#include "ap/wpa_auth.h"
+#include "ap/ieee802_11.h"
+#include "ap/sta_info.h"
+#include "ap/wps_hostapd.h"
+#include "ap/ctrl_iface_ap.h"
+#include "ap/ap_drv_ops.h"
+#include "wps/wps_defs.h"
+#include "wps/wps.h"
+#include "config_file.h"
+#include "ctrl_iface.h"
+
+
+struct wpa_ctrl_dst {
+	struct wpa_ctrl_dst *next;
+	struct sockaddr_un addr;
+	socklen_t addrlen;
+	int debug_level;
+	int errors;
+};
+
+
+static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+				    const char *buf, size_t len);
+
+
+static int hostapd_ctrl_iface_attach(struct hostapd_data *hapd,
+				     struct sockaddr_un *from,
+				     socklen_t fromlen)
+{
+	struct wpa_ctrl_dst *dst;
+
+	dst = os_zalloc(sizeof(*dst));
+	if (dst == NULL)
+		return -1;
+	os_memcpy(&dst->addr, from, sizeof(struct sockaddr_un));
+	dst->addrlen = fromlen;
+	dst->debug_level = MSG_INFO;
+	dst->next = hapd->ctrl_dst;
+	hapd->ctrl_dst = dst;
+	wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor attached",
+		    (u8 *) from->sun_path,
+		    fromlen - offsetof(struct sockaddr_un, sun_path));
+	return 0;
+}
+
+
+static int hostapd_ctrl_iface_detach(struct hostapd_data *hapd,
+				     struct sockaddr_un *from,
+				     socklen_t fromlen)
+{
+	struct wpa_ctrl_dst *dst, *prev = NULL;
+
+	dst = hapd->ctrl_dst;
+	while (dst) {
+		if (fromlen == dst->addrlen &&
+		    os_memcmp(from->sun_path, dst->addr.sun_path,
+			      fromlen - offsetof(struct sockaddr_un, sun_path))
+		    == 0) {
+			if (prev == NULL)
+				hapd->ctrl_dst = dst->next;
+			else
+				prev->next = dst->next;
+			os_free(dst);
+			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor detached",
+				    (u8 *) from->sun_path,
+				    fromlen -
+				    offsetof(struct sockaddr_un, sun_path));
+			return 0;
+		}
+		prev = dst;
+		dst = dst->next;
+	}
+	return -1;
+}
+
+
+static int hostapd_ctrl_iface_level(struct hostapd_data *hapd,
+				    struct sockaddr_un *from,
+				    socklen_t fromlen,
+				    char *level)
+{
+	struct wpa_ctrl_dst *dst;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE LEVEL %s", level);
+
+	dst = hapd->ctrl_dst;
+	while (dst) {
+		if (fromlen == dst->addrlen &&
+		    os_memcmp(from->sun_path, dst->addr.sun_path,
+			      fromlen - offsetof(struct sockaddr_un, sun_path))
+		    == 0) {
+			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE changed monitor "
+				    "level", (u8 *) from->sun_path, fromlen -
+				    offsetof(struct sockaddr_un, sun_path));
+			dst->debug_level = atoi(level);
+			return 0;
+		}
+		dst = dst->next;
+	}
+
+	return -1;
+}
+
+
+static int hostapd_ctrl_iface_new_sta(struct hostapd_data *hapd,
+				      const char *txtaddr)
+{
+	u8 addr[ETH_ALEN];
+	struct sta_info *sta;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE NEW_STA %s", txtaddr);
+
+	if (hwaddr_aton(txtaddr, addr))
+		return -1;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "Add new STA " MACSTR " based on ctrl_iface "
+		   "notification", MAC2STR(addr));
+	sta = ap_sta_add(hapd, addr);
+	if (sta == NULL)
+		return -1;
+
+	hostapd_new_assoc_sta(hapd, sta, 0);
+	return 0;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+#ifdef NEED_AP_MLME
+static int hostapd_ctrl_iface_sa_query(struct hostapd_data *hapd,
+				       const char *txtaddr)
+{
+	u8 addr[ETH_ALEN];
+	u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE SA_QUERY %s", txtaddr);
+
+	if (hwaddr_aton(txtaddr, addr) ||
+	    os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN) < 0)
+		return -1;
+
+	ieee802_11_send_sa_query_req(hapd, addr, trans_id);
+
+	return 0;
+}
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211W */
+
+
+#ifdef CONFIG_WPS
+static int hostapd_ctrl_iface_wps_pin(struct hostapd_data *hapd, char *txt)
+{
+	char *pin = os_strchr(txt, ' ');
+	char *timeout_txt;
+	int timeout;
+	u8 addr_buf[ETH_ALEN], *addr = NULL;
+	char *pos;
+
+	if (pin == NULL)
+		return -1;
+	*pin++ = '\0';
+
+	timeout_txt = os_strchr(pin, ' ');
+	if (timeout_txt) {
+		*timeout_txt++ = '\0';
+		timeout = atoi(timeout_txt);
+		pos = os_strchr(timeout_txt, ' ');
+		if (pos) {
+			*pos++ = '\0';
+			if (hwaddr_aton(pos, addr_buf) == 0)
+				addr = addr_buf;
+		}
+	} else
+		timeout = 0;
+
+	return hostapd_wps_add_pin(hapd, addr, txt, pin, timeout);
+}
+
+
+static int hostapd_ctrl_iface_wps_check_pin(
+	struct hostapd_data *hapd, char *cmd, char *buf, size_t buflen)
+{
+	char pin[9];
+	size_t len;
+	char *pos;
+	int ret;
+
+	wpa_hexdump_ascii_key(MSG_DEBUG, "WPS_CHECK_PIN",
+			      (u8 *) cmd, os_strlen(cmd));
+	for (pos = cmd, len = 0; *pos != '\0'; pos++) {
+		if (*pos < '0' || *pos > '9')
+			continue;
+		pin[len++] = *pos;
+		if (len == 9) {
+			wpa_printf(MSG_DEBUG, "WPS: Too long PIN");
+			return -1;
+		}
+	}
+	if (len != 4 && len != 8) {
+		wpa_printf(MSG_DEBUG, "WPS: Invalid PIN length %d", (int) len);
+		return -1;
+	}
+	pin[len] = '\0';
+
+	if (len == 8) {
+		unsigned int pin_val;
+		pin_val = atoi(pin);
+		if (!wps_pin_valid(pin_val)) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid checksum digit");
+			ret = os_snprintf(buf, buflen, "FAIL-CHECKSUM\n");
+			if (ret < 0 || (size_t) ret >= buflen)
+				return -1;
+			return ret;
+		}
+	}
+
+	ret = os_snprintf(buf, buflen, "%s", pin);
+	if (ret < 0 || (size_t) ret >= buflen)
+		return -1;
+
+	return ret;
+}
+
+
+#ifdef CONFIG_WPS_NFC
+static int hostapd_ctrl_iface_wps_nfc_tag_read(struct hostapd_data *hapd,
+					       char *pos)
+{
+	size_t len;
+	struct wpabuf *buf;
+	int ret;
+
+	len = os_strlen(pos);
+	if (len & 0x01)
+		return -1;
+	len /= 2;
+
+	buf = wpabuf_alloc(len);
+	if (buf == NULL)
+		return -1;
+	if (hexstr2bin(pos, wpabuf_put(buf, len), len) < 0) {
+		wpabuf_free(buf);
+		return -1;
+	}
+
+	ret = hostapd_wps_nfc_tag_read(hapd, buf);
+	wpabuf_free(buf);
+
+	return ret;
+}
+
+
+static int hostapd_ctrl_iface_wps_nfc_config_token(struct hostapd_data *hapd,
+						   char *cmd, char *reply,
+						   size_t max_len)
+{
+	int ndef;
+	struct wpabuf *buf;
+	int res;
+
+	if (os_strcmp(cmd, "WPS") == 0)
+		ndef = 0;
+	else if (os_strcmp(cmd, "NDEF") == 0)
+		ndef = 1;
+	else
+		return -1;
+
+	buf = hostapd_wps_nfc_config_token(hapd, ndef);
+	if (buf == NULL)
+		return -1;
+
+	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+					 wpabuf_len(buf));
+	reply[res++] = '\n';
+	reply[res] = '\0';
+
+	wpabuf_free(buf);
+
+	return res;
+}
+
+
+static int hostapd_ctrl_iface_wps_nfc_token_gen(struct hostapd_data *hapd,
+						char *reply, size_t max_len,
+						int ndef)
+{
+	struct wpabuf *buf;
+	int res;
+
+	buf = hostapd_wps_nfc_token_gen(hapd, ndef);
+	if (buf == NULL)
+		return -1;
+
+	res = wpa_snprintf_hex_uppercase(reply, max_len, wpabuf_head(buf),
+					 wpabuf_len(buf));
+	reply[res++] = '\n';
+	reply[res] = '\0';
+
+	wpabuf_free(buf);
+
+	return res;
+}
+
+
+static int hostapd_ctrl_iface_wps_nfc_token(struct hostapd_data *hapd,
+					    char *cmd, char *reply,
+					    size_t max_len)
+{
+	if (os_strcmp(cmd, "WPS") == 0)
+		return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
+							    max_len, 0);
+
+	if (os_strcmp(cmd, "NDEF") == 0)
+		return hostapd_ctrl_iface_wps_nfc_token_gen(hapd, reply,
+							    max_len, 1);
+
+	if (os_strcmp(cmd, "enable") == 0)
+		return hostapd_wps_nfc_token_enable(hapd);
+
+	if (os_strcmp(cmd, "disable") == 0) {
+		hostapd_wps_nfc_token_disable(hapd);
+		return 0;
+	}
+
+	return -1;
+}
+#endif /* CONFIG_WPS_NFC */
+
+
+static int hostapd_ctrl_iface_wps_ap_pin(struct hostapd_data *hapd, char *txt,
+					 char *buf, size_t buflen)
+{
+	int timeout = 300;
+	char *pos;
+	const char *pin_txt;
+
+	pos = os_strchr(txt, ' ');
+	if (pos)
+		*pos++ = '\0';
+
+	if (os_strcmp(txt, "disable") == 0) {
+		hostapd_wps_ap_pin_disable(hapd);
+		return os_snprintf(buf, buflen, "OK\n");
+	}
+
+	if (os_strcmp(txt, "random") == 0) {
+		if (pos)
+			timeout = atoi(pos);
+		pin_txt = hostapd_wps_ap_pin_random(hapd, timeout);
+		if (pin_txt == NULL)
+			return -1;
+		return os_snprintf(buf, buflen, "%s", pin_txt);
+	}
+
+	if (os_strcmp(txt, "get") == 0) {
+		pin_txt = hostapd_wps_ap_pin_get(hapd);
+		if (pin_txt == NULL)
+			return -1;
+		return os_snprintf(buf, buflen, "%s", pin_txt);
+	}
+
+	if (os_strcmp(txt, "set") == 0) {
+		char *pin;
+		if (pos == NULL)
+			return -1;
+		pin = pos;
+		pos = os_strchr(pos, ' ');
+		if (pos) {
+			*pos++ = '\0';
+			timeout = atoi(pos);
+		}
+		if (os_strlen(pin) > buflen)
+			return -1;
+		if (hostapd_wps_ap_pin_set(hapd, pin, timeout) < 0)
+			return -1;
+		return os_snprintf(buf, buflen, "%s", pin);
+	}
+
+	return -1;
+}
+
+
+static int hostapd_ctrl_iface_wps_config(struct hostapd_data *hapd, char *txt)
+{
+	char *pos;
+	char *ssid, *auth, *encr = NULL, *key = NULL;
+
+	ssid = txt;
+	pos = os_strchr(txt, ' ');
+	if (!pos)
+		return -1;
+	*pos++ = '\0';
+
+	auth = pos;
+	pos = os_strchr(pos, ' ');
+	if (pos) {
+		*pos++ = '\0';
+		encr = pos;
+		pos = os_strchr(pos, ' ');
+		if (pos) {
+			*pos++ = '\0';
+			key = pos;
+		}
+	}
+
+	return hostapd_wps_config_ap(hapd, ssid, auth, encr, key);
+}
+#endif /* CONFIG_WPS */
+
+
+#ifdef CONFIG_WNM
+
+static int hostapd_ctrl_iface_disassoc_imminent(struct hostapd_data *hapd,
+						const char *cmd)
+{
+	u8 addr[ETH_ALEN];
+	u8 buf[1000], *pos;
+	struct ieee80211_mgmt *mgmt;
+	int disassoc_timer;
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+	if (cmd[17] != ' ')
+		return -1;
+	disassoc_timer = atoi(cmd + 17);
+
+	os_memset(buf, 0, sizeof(buf));
+	mgmt = (struct ieee80211_mgmt *) buf;
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_ACTION);
+	os_memcpy(mgmt->da, addr, ETH_ALEN);
+	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+	mgmt->u.action.category = WLAN_ACTION_WNM;
+	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
+	mgmt->u.action.u.bss_tm_req.req_mode =
+		WNM_BSS_TM_REQ_DISASSOC_IMMINENT;
+	mgmt->u.action.u.bss_tm_req.disassoc_timer =
+		host_to_le16(disassoc_timer);
+	mgmt->u.action.u.bss_tm_req.validity_interval = 0;
+
+	pos = mgmt->u.action.u.bss_tm_req.variable;
+
+	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
+			   "Management Request frame");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int hostapd_ctrl_iface_ess_disassoc(struct hostapd_data *hapd,
+					   const char *cmd)
+{
+	u8 addr[ETH_ALEN];
+	const char *url;
+	u8 buf[1000], *pos;
+	struct ieee80211_mgmt *mgmt;
+	size_t url_len;
+
+	if (hwaddr_aton(cmd, addr))
+		return -1;
+	url = cmd + 17;
+	if (*url != ' ')
+		return -1;
+	url++;
+	url_len = os_strlen(url);
+	if (url_len > 255)
+		return -1;
+
+	os_memset(buf, 0, sizeof(buf));
+	mgmt = (struct ieee80211_mgmt *) buf;
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_ACTION);
+	os_memcpy(mgmt->da, addr, ETH_ALEN);
+	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+	mgmt->u.action.category = WLAN_ACTION_WNM;
+	mgmt->u.action.u.bss_tm_req.action = WNM_BSS_TRANS_MGMT_REQ;
+	mgmt->u.action.u.bss_tm_req.dialog_token = 1;
+	mgmt->u.action.u.bss_tm_req.req_mode =
+		WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT;
+	mgmt->u.action.u.bss_tm_req.disassoc_timer = host_to_le16(0);
+	mgmt->u.action.u.bss_tm_req.validity_interval = 0;
+
+	pos = mgmt->u.action.u.bss_tm_req.variable;
+
+	/* Session Information URL */
+	*pos++ = url_len;
+	os_memcpy(pos, url, url_len);
+	pos += url_len;
+
+	if (hostapd_drv_send_mlme(hapd, buf, pos - buf, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "Failed to send BSS Transition "
+			   "Management Request frame");
+		return -1;
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_WNM */
+
+
+static int hostapd_ctrl_iface_get_config(struct hostapd_data *hapd,
+					 char *buf, size_t buflen)
+{
+	int ret;
+	char *pos, *end;
+
+	pos = buf;
+	end = buf + buflen;
+
+	ret = os_snprintf(pos, end - pos, "bssid=" MACSTR "\n"
+			  "ssid=%s\n",
+			  MAC2STR(hapd->own_addr),
+			  wpa_ssid_txt(hapd->conf->ssid.ssid,
+				       hapd->conf->ssid.ssid_len));
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+#ifdef CONFIG_WPS
+	ret = os_snprintf(pos, end - pos, "wps_state=%s\n",
+			  hapd->conf->wps_state == 0 ? "disabled" :
+			  (hapd->conf->wps_state == 1 ? "not configured" :
+			   "configured"));
+	if (ret < 0 || ret >= end - pos)
+		return pos - buf;
+	pos += ret;
+
+	if (hapd->conf->wps_state && hapd->conf->wpa &&
+	    hapd->conf->ssid.wpa_passphrase) {
+		ret = os_snprintf(pos, end - pos, "passphrase=%s\n",
+				  hapd->conf->ssid.wpa_passphrase);
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (hapd->conf->wps_state && hapd->conf->wpa &&
+	    hapd->conf->ssid.wpa_psk &&
+	    hapd->conf->ssid.wpa_psk->group) {
+		char hex[PMK_LEN * 2 + 1];
+		wpa_snprintf_hex(hex, sizeof(hex),
+				 hapd->conf->ssid.wpa_psk->psk, PMK_LEN);
+		ret = os_snprintf(pos, end - pos, "psk=%s\n", hex);
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+#endif /* CONFIG_WPS */
+
+	if (hapd->conf->wpa && hapd->conf->wpa_key_mgmt) {
+		ret = os_snprintf(pos, end - pos, "key_mgmt=");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+
+		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
+			ret = os_snprintf(pos, end - pos, "WPA-PSK ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+			ret = os_snprintf(pos, end - pos, "WPA-EAP ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+#ifdef CONFIG_IEEE80211R
+		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
+			ret = os_snprintf(pos, end - pos, "FT-PSK ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
+			ret = os_snprintf(pos, end - pos, "FT-EAP ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
+			ret = os_snprintf(pos, end - pos, "WPA-PSK-SHA256 ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		if (hapd->conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+			ret = os_snprintf(pos, end - pos, "WPA-EAP-SHA256 ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+#endif /* CONFIG_IEEE80211W */
+
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if (hapd->conf->wpa && hapd->conf->wpa_group == WPA_CIPHER_CCMP) {
+		ret = os_snprintf(pos, end - pos, "group_cipher=CCMP\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	} else if (hapd->conf->wpa &&
+		   hapd->conf->wpa_group == WPA_CIPHER_GCMP) {
+		ret = os_snprintf(pos, end - pos, "group_cipher=GCMP\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	} else if (hapd->conf->wpa &&
+		   hapd->conf->wpa_group == WPA_CIPHER_TKIP) {
+		ret = os_snprintf(pos, end - pos, "group_cipher=TKIP\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if ((hapd->conf->wpa & WPA_PROTO_RSN) && hapd->conf->rsn_pairwise) {
+		ret = os_snprintf(pos, end - pos, "rsn_pairwise_cipher=");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+
+		if (hapd->conf->rsn_pairwise & WPA_CIPHER_CCMP) {
+			ret = os_snprintf(pos, end - pos, "CCMP ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		if (hapd->conf->rsn_pairwise & WPA_CIPHER_GCMP) {
+			ret = os_snprintf(pos, end - pos, "GCMP ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		if (hapd->conf->rsn_pairwise & WPA_CIPHER_TKIP) {
+			ret = os_snprintf(pos, end - pos, "TKIP ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	if ((hapd->conf->wpa & WPA_PROTO_WPA) && hapd->conf->wpa_pairwise) {
+		ret = os_snprintf(pos, end - pos, "wpa_pairwise_cipher=");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+
+		if (hapd->conf->wpa_pairwise & WPA_CIPHER_CCMP) {
+			ret = os_snprintf(pos, end - pos, "CCMP ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		if (hapd->conf->wpa_pairwise & WPA_CIPHER_GCMP) {
+			ret = os_snprintf(pos, end - pos, "GCMP ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+		if (hapd->conf->wpa_pairwise & WPA_CIPHER_TKIP) {
+			ret = os_snprintf(pos, end - pos, "TKIP ");
+			if (ret < 0 || ret >= end - pos)
+				return pos - buf;
+			pos += ret;
+		}
+
+		ret = os_snprintf(pos, end - pos, "\n");
+		if (ret < 0 || ret >= end - pos)
+			return pos - buf;
+		pos += ret;
+	}
+
+	return pos - buf;
+}
+
+
+static int hostapd_ctrl_iface_set(struct hostapd_data *hapd, char *cmd)
+{
+	char *value;
+	int ret = 0;
+
+	value = os_strchr(cmd, ' ');
+	if (value == NULL)
+		return -1;
+	*value++ = '\0';
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE SET '%s'='%s'", cmd, value);
+	if (0) {
+#ifdef CONFIG_WPS_TESTING
+	} else if (os_strcasecmp(cmd, "wps_version_number") == 0) {
+		long int val;
+		val = strtol(value, NULL, 0);
+		if (val < 0 || val > 0xff) {
+			ret = -1;
+			wpa_printf(MSG_DEBUG, "WPS: Invalid "
+				   "wps_version_number %ld", val);
+		} else {
+			wps_version_number = val;
+			wpa_printf(MSG_DEBUG, "WPS: Testing - force WPS "
+				   "version %u.%u",
+				   (wps_version_number & 0xf0) >> 4,
+				   wps_version_number & 0x0f);
+			hostapd_wps_update_ie(hapd);
+		}
+	} else if (os_strcasecmp(cmd, "wps_testing_dummy_cred") == 0) {
+		wps_testing_dummy_cred = atoi(value);
+		wpa_printf(MSG_DEBUG, "WPS: Testing - dummy_cred=%d",
+			   wps_testing_dummy_cred);
+#endif /* CONFIG_WPS_TESTING */
+#ifdef CONFIG_INTERWORKING
+	} else if (os_strcasecmp(cmd, "gas_frag_limit") == 0) {
+		int val = atoi(value);
+		if (val <= 0)
+			ret = -1;
+		else
+			hapd->gas_frag_limit = val;
+#endif /* CONFIG_INTERWORKING */
+	} else {
+		ret = hostapd_set_iface(hapd->iconf, hapd->conf, cmd, value);
+	}
+
+	return ret;
+}
+
+
+static int hostapd_ctrl_iface_get(struct hostapd_data *hapd, char *cmd,
+				  char *buf, size_t buflen)
+{
+	int res;
+
+	wpa_printf(MSG_DEBUG, "CTRL_IFACE GET '%s'", cmd);
+
+	if (os_strcmp(cmd, "version") == 0) {
+		res = os_snprintf(buf, buflen, "%s", VERSION_STR);
+		if (res < 0 || (unsigned int) res >= buflen)
+			return -1;
+		return res;
+	}
+
+	return -1;
+}
+
+
+static int hostapd_ctrl_iface_enable(struct hostapd_iface *iface)
+{
+	if (hostapd_enable_iface(iface) < 0) {
+		wpa_printf(MSG_ERROR, "Enabling of interface failed");
+		return -1;
+	}
+	return 0;
+}
+
+
+static int hostapd_ctrl_iface_reload(struct hostapd_iface *iface)
+{
+	if (hostapd_reload_iface(iface) < 0) {
+		wpa_printf(MSG_ERROR, "Reloading of interface failed");
+		return -1;
+	}
+	return 0;
+}
+
+
+static int hostapd_ctrl_iface_disable(struct hostapd_iface *iface)
+{
+	if (hostapd_disable_iface(iface) < 0) {
+		wpa_printf(MSG_ERROR, "Disabling of interface failed");
+		return -1;
+	}
+	return 0;
+}
+
+
+static void hostapd_ctrl_iface_receive(int sock, void *eloop_ctx,
+				       void *sock_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	char buf[256];
+	int res;
+	struct sockaddr_un from;
+	socklen_t fromlen = sizeof(from);
+	char *reply;
+	const int reply_size = 4096;
+	int reply_len;
+	int level = MSG_DEBUG;
+
+	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+		       (struct sockaddr *) &from, &fromlen);
+	if (res < 0) {
+		perror("recvfrom(ctrl_iface)");
+		return;
+	}
+	buf[res] = '\0';
+	if (os_strcmp(buf, "PING") == 0)
+		level = MSG_EXCESSIVE;
+	wpa_hexdump_ascii(level, "RX ctrl_iface", (u8 *) buf, res);
+
+	reply = os_malloc(reply_size);
+	if (reply == NULL) {
+		sendto(sock, "FAIL\n", 5, 0, (struct sockaddr *) &from,
+		       fromlen);
+		return;
+	}
+
+	os_memcpy(reply, "OK\n", 3);
+	reply_len = 3;
+
+	if (os_strcmp(buf, "PING") == 0) {
+		os_memcpy(reply, "PONG\n", 5);
+		reply_len = 5;
+	} else if (os_strncmp(buf, "RELOG", 5) == 0) {
+		if (wpa_debug_reopen_file() < 0)
+			reply_len = -1;
+	} else if (os_strcmp(buf, "MIB") == 0) {
+		reply_len = ieee802_11_get_mib(hapd, reply, reply_size);
+		if (reply_len >= 0) {
+			res = wpa_get_mib(hapd->wpa_auth, reply + reply_len,
+					  reply_size - reply_len);
+			if (res < 0)
+				reply_len = -1;
+			else
+				reply_len += res;
+		}
+		if (reply_len >= 0) {
+			res = ieee802_1x_get_mib(hapd, reply + reply_len,
+						 reply_size - reply_len);
+			if (res < 0)
+				reply_len = -1;
+			else
+				reply_len += res;
+		}
+#ifndef CONFIG_NO_RADIUS
+		if (reply_len >= 0) {
+			res = radius_client_get_mib(hapd->radius,
+						    reply + reply_len,
+						    reply_size - reply_len);
+			if (res < 0)
+				reply_len = -1;
+			else
+				reply_len += res;
+		}
+#endif /* CONFIG_NO_RADIUS */
+	} else if (os_strcmp(buf, "STA-FIRST") == 0) {
+		reply_len = hostapd_ctrl_iface_sta_first(hapd, reply,
+							 reply_size);
+	} else if (os_strncmp(buf, "STA ", 4) == 0) {
+		reply_len = hostapd_ctrl_iface_sta(hapd, buf + 4, reply,
+						   reply_size);
+	} else if (os_strncmp(buf, "STA-NEXT ", 9) == 0) {
+		reply_len = hostapd_ctrl_iface_sta_next(hapd, buf + 9, reply,
+							reply_size);
+	} else if (os_strcmp(buf, "ATTACH") == 0) {
+		if (hostapd_ctrl_iface_attach(hapd, &from, fromlen))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "DETACH") == 0) {
+		if (hostapd_ctrl_iface_detach(hapd, &from, fromlen))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "LEVEL ", 6) == 0) {
+		if (hostapd_ctrl_iface_level(hapd, &from, fromlen,
+						    buf + 6))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "NEW_STA ", 8) == 0) {
+		if (hostapd_ctrl_iface_new_sta(hapd, buf + 8))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DEAUTHENTICATE ", 15) == 0) {
+		if (hostapd_ctrl_iface_deauthenticate(hapd, buf + 15))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
+		if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
+			reply_len = -1;
+#ifdef CONFIG_IEEE80211W
+#ifdef NEED_AP_MLME
+	} else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
+		if (hostapd_ctrl_iface_sa_query(hapd, buf + 9))
+			reply_len = -1;
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WPS
+	} else if (os_strncmp(buf, "WPS_PIN ", 8) == 0) {
+		if (hostapd_ctrl_iface_wps_pin(hapd, buf + 8))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_CHECK_PIN ", 14) == 0) {
+		reply_len = hostapd_ctrl_iface_wps_check_pin(
+			hapd, buf + 14, reply, reply_size);
+	} else if (os_strcmp(buf, "WPS_PBC") == 0) {
+		if (hostapd_wps_button_pushed(hapd, NULL))
+			reply_len = -1;
+	} else if (os_strcmp(buf, "WPS_CANCEL") == 0) {
+		if (hostapd_wps_cancel(hapd))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_AP_PIN ", 11) == 0) {
+		reply_len = hostapd_ctrl_iface_wps_ap_pin(hapd, buf + 11,
+							  reply, reply_size);
+	} else if (os_strncmp(buf, "WPS_CONFIG ", 11) == 0) {
+		if (hostapd_ctrl_iface_wps_config(hapd, buf + 11) < 0)
+			reply_len = -1;
+#ifdef CONFIG_WPS_NFC
+	} else if (os_strncmp(buf, "WPS_NFC_TAG_READ ", 17) == 0) {
+		if (hostapd_ctrl_iface_wps_nfc_tag_read(hapd, buf + 17))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "WPS_NFC_CONFIG_TOKEN ", 21) == 0) {
+		reply_len = hostapd_ctrl_iface_wps_nfc_config_token(
+			hapd, buf + 21, reply, reply_size);
+	} else if (os_strncmp(buf, "WPS_NFC_TOKEN ", 14) == 0) {
+		reply_len = hostapd_ctrl_iface_wps_nfc_token(
+			hapd, buf + 14, reply, reply_size);
+#endif /* CONFIG_WPS_NFC */
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_WNM
+	} else if (os_strncmp(buf, "DISASSOC_IMMINENT ", 18) == 0) {
+		if (hostapd_ctrl_iface_disassoc_imminent(hapd, buf + 18))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "ESS_DISASSOC ", 13) == 0) {
+		if (hostapd_ctrl_iface_ess_disassoc(hapd, buf + 13))
+			reply_len = -1;
+#endif /* CONFIG_WNM */
+	} else if (os_strcmp(buf, "GET_CONFIG") == 0) {
+		reply_len = hostapd_ctrl_iface_get_config(hapd, reply,
+							  reply_size);
+	} else if (os_strncmp(buf, "SET ", 4) == 0) {
+		if (hostapd_ctrl_iface_set(hapd, buf + 4))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "GET ", 4) == 0) {
+		reply_len = hostapd_ctrl_iface_get(hapd, buf + 4, reply,
+						   reply_size);
+	} else if (os_strncmp(buf, "ENABLE", 6) == 0) {
+		if (hostapd_ctrl_iface_enable(hapd->iface))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "RELOAD", 6) == 0) {
+		if (hostapd_ctrl_iface_reload(hapd->iface))
+			reply_len = -1;
+	} else if (os_strncmp(buf, "DISABLE", 7) == 0) {
+		if (hostapd_ctrl_iface_disable(hapd->iface))
+			reply_len = -1;
+	} else {
+		os_memcpy(reply, "UNKNOWN COMMAND\n", 16);
+		reply_len = 16;
+	}
+
+	if (reply_len < 0) {
+		os_memcpy(reply, "FAIL\n", 5);
+		reply_len = 5;
+	}
+	sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+	os_free(reply);
+}
+
+
+static char * hostapd_ctrl_iface_path(struct hostapd_data *hapd)
+{
+	char *buf;
+	size_t len;
+
+	if (hapd->conf->ctrl_interface == NULL)
+		return NULL;
+
+	len = os_strlen(hapd->conf->ctrl_interface) +
+		os_strlen(hapd->conf->iface) + 2;
+	buf = os_malloc(len);
+	if (buf == NULL)
+		return NULL;
+
+	os_snprintf(buf, len, "%s/%s",
+		    hapd->conf->ctrl_interface, hapd->conf->iface);
+	buf[len - 1] = '\0';
+	return buf;
+}
+
+
+static void hostapd_ctrl_iface_msg_cb(void *ctx, int level,
+				      const char *txt, size_t len)
+{
+	struct hostapd_data *hapd = ctx;
+	if (hapd == NULL)
+		return;
+	hostapd_ctrl_iface_send(hapd, level, txt, len);
+}
+
+
+int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
+{
+	struct sockaddr_un addr;
+	int s = -1;
+	char *fname = NULL;
+
+	if (hapd->ctrl_sock > -1) {
+		wpa_printf(MSG_DEBUG, "ctrl_iface already exists!");
+		return 0;
+	}
+
+	if (hapd->conf->ctrl_interface == NULL)
+		return 0;
+
+	if (mkdir(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
+		if (errno == EEXIST) {
+			wpa_printf(MSG_DEBUG, "Using existing control "
+				   "interface directory.");
+		} else {
+			perror("mkdir[ctrl_interface]");
+			goto fail;
+		}
+	}
+
+	if (hapd->conf->ctrl_interface_gid_set &&
+	    chown(hapd->conf->ctrl_interface, -1,
+		  hapd->conf->ctrl_interface_gid) < 0) {
+		perror("chown[ctrl_interface]");
+		return -1;
+	}
+
+#ifdef ANDROID
+	/*
+	 * Android is using umask 0077 which would leave the control interface
+	 * directory without group access. This breaks things since Wi-Fi
+	 * framework assumes that this directory can be accessed by other
+	 * applications in the wifi group. Fix this by adding group access even
+	 * if umask value would prevent this.
+	 */
+	if (chmod(hapd->conf->ctrl_interface, S_IRWXU | S_IRWXG) < 0) {
+		wpa_printf(MSG_ERROR, "CTRL: Could not chmod directory: %s",
+			   strerror(errno));
+		/* Try to continue anyway */
+	}
+#endif /* ANDROID */
+
+	if (os_strlen(hapd->conf->ctrl_interface) + 1 +
+	    os_strlen(hapd->conf->iface) >= sizeof(addr.sun_path))
+		goto fail;
+
+	s = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (s < 0) {
+		perror("socket(PF_UNIX)");
+		goto fail;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+#ifdef __FreeBSD__
+	addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
+	addr.sun_family = AF_UNIX;
+	fname = hostapd_ctrl_iface_path(hapd);
+	if (fname == NULL)
+		goto fail;
+	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
+	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
+			   strerror(errno));
+		if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
+				   " allow connections - assuming it was left"
+				   "over from forced program termination");
+			if (unlink(fname) < 0) {
+				perror("unlink[ctrl_iface]");
+				wpa_printf(MSG_ERROR, "Could not unlink "
+					   "existing ctrl_iface socket '%s'",
+					   fname);
+				goto fail;
+			}
+			if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
+			    0) {
+				perror("hostapd-ctrl-iface: bind(PF_UNIX)");
+				goto fail;
+			}
+			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+				   "ctrl_iface socket '%s'", fname);
+		} else {
+			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
+				   "be in use - cannot override it");
+			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+				   "not used anymore", fname);
+			os_free(fname);
+			fname = NULL;
+			goto fail;
+		}
+	}
+
+	if (hapd->conf->ctrl_interface_gid_set &&
+	    chown(fname, -1, hapd->conf->ctrl_interface_gid) < 0) {
+		perror("chown[ctrl_interface/ifname]");
+		goto fail;
+	}
+
+	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+		perror("chmod[ctrl_interface/ifname]");
+		goto fail;
+	}
+	os_free(fname);
+
+	hapd->ctrl_sock = s;
+	eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
+				 NULL);
+	hapd->msg_ctx = hapd;
+	wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
+
+	return 0;
+
+fail:
+	if (s >= 0)
+		close(s);
+	if (fname) {
+		unlink(fname);
+		os_free(fname);
+	}
+	return -1;
+}
+
+
+void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
+{
+	struct wpa_ctrl_dst *dst, *prev;
+
+	if (hapd->ctrl_sock > -1) {
+		char *fname;
+		eloop_unregister_read_sock(hapd->ctrl_sock);
+		close(hapd->ctrl_sock);
+		hapd->ctrl_sock = -1;
+		fname = hostapd_ctrl_iface_path(hapd);
+		if (fname)
+			unlink(fname);
+		os_free(fname);
+
+		if (hapd->conf->ctrl_interface &&
+		    rmdir(hapd->conf->ctrl_interface) < 0) {
+			if (errno == ENOTEMPTY) {
+				wpa_printf(MSG_DEBUG, "Control interface "
+					   "directory not empty - leaving it "
+					   "behind");
+			} else {
+				perror("rmdir[ctrl_interface]");
+			}
+		}
+	}
+
+	dst = hapd->ctrl_dst;
+	while (dst) {
+		prev = dst;
+		dst = dst->next;
+		os_free(prev);
+	}
+}
+
+
+static int hostapd_ctrl_iface_add(struct hapd_interfaces *interfaces,
+				  char *buf)
+{
+	if (hostapd_add_iface(interfaces, buf) < 0) {
+		wpa_printf(MSG_ERROR, "Adding interface %s failed", buf);
+		return -1;
+	}
+	return 0;
+}
+
+
+static int hostapd_ctrl_iface_remove(struct hapd_interfaces *interfaces,
+				     char *buf)
+{
+	if (hostapd_remove_iface(interfaces, buf) < 0) {
+		wpa_printf(MSG_ERROR, "Removing interface %s failed", buf);
+		return -1;
+	}
+	return 0;
+}
+
+
+static void hostapd_global_ctrl_iface_receive(int sock, void *eloop_ctx,
+					      void *sock_ctx)
+{
+	void *interfaces = eloop_ctx;
+	char buf[256];
+	int res;
+	struct sockaddr_un from;
+	socklen_t fromlen = sizeof(from);
+	char reply[24];
+	int reply_len;
+
+	res = recvfrom(sock, buf, sizeof(buf) - 1, 0,
+		       (struct sockaddr *) &from, &fromlen);
+	if (res < 0) {
+		perror("recvfrom(ctrl_iface)");
+		return;
+	}
+	buf[res] = '\0';
+
+	os_memcpy(reply, "OK\n", 3);
+	reply_len = 3;
+
+	if (os_strcmp(buf, "PING") == 0) {
+		os_memcpy(reply, "PONG\n", 5);
+		reply_len = 5;
+	} else if (os_strncmp(buf, "ADD ", 4) == 0) {
+		if (hostapd_ctrl_iface_add(interfaces, buf + 4) < 0)
+			reply_len = -1;
+	} else if (os_strncmp(buf, "REMOVE ", 7) == 0) {
+		if (hostapd_ctrl_iface_remove(interfaces, buf + 7) < 0)
+			reply_len = -1;
+	} else {
+		wpa_printf(MSG_DEBUG, "Unrecognized global ctrl_iface command "
+			   "ignored");
+		reply_len = -1;
+	}
+
+	if (reply_len < 0) {
+		os_memcpy(reply, "FAIL\n", 5);
+		reply_len = 5;
+	}
+
+	sendto(sock, reply, reply_len, 0, (struct sockaddr *) &from, fromlen);
+}
+
+
+static char * hostapd_global_ctrl_iface_path(struct hapd_interfaces *interface)
+{
+	char *buf;
+	size_t len;
+
+	if (interface->global_iface_path == NULL)
+		return NULL;
+
+	len = os_strlen(interface->global_iface_path) +
+		os_strlen(interface->global_iface_name) + 2;
+	buf = os_malloc(len);
+	if (buf == NULL)
+		return NULL;
+
+	os_snprintf(buf, len, "%s/%s", interface->global_iface_path,
+		    interface->global_iface_name);
+	buf[len - 1] = '\0';
+	return buf;
+}
+
+
+int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
+{
+	struct sockaddr_un addr;
+	int s = -1;
+	char *fname = NULL;
+
+	if (interface->global_iface_path == NULL) {
+		wpa_printf(MSG_DEBUG, "ctrl_iface not configured!");
+		return 0;
+	}
+
+	if (mkdir(interface->global_iface_path, S_IRWXU | S_IRWXG) < 0) {
+		if (errno == EEXIST) {
+			wpa_printf(MSG_DEBUG, "Using existing control "
+				   "interface directory.");
+		} else {
+			perror("mkdir[ctrl_interface]");
+			goto fail;
+		}
+	}
+
+	if (os_strlen(interface->global_iface_path) + 1 +
+	    os_strlen(interface->global_iface_name) >= sizeof(addr.sun_path))
+		goto fail;
+
+	s = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (s < 0) {
+		perror("socket(PF_UNIX)");
+		goto fail;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+#ifdef __FreeBSD__
+	addr.sun_len = sizeof(addr);
+#endif /* __FreeBSD__ */
+	addr.sun_family = AF_UNIX;
+	fname = hostapd_global_ctrl_iface_path(interface);
+	if (fname == NULL)
+		goto fail;
+	os_strlcpy(addr.sun_path, fname, sizeof(addr.sun_path));
+	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		wpa_printf(MSG_DEBUG, "ctrl_iface bind(PF_UNIX) failed: %s",
+			   strerror(errno));
+		if (connect(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+			wpa_printf(MSG_DEBUG, "ctrl_iface exists, but does not"
+				   " allow connections - assuming it was left"
+				   "over from forced program termination");
+			if (unlink(fname) < 0) {
+				perror("unlink[ctrl_iface]");
+				wpa_printf(MSG_ERROR, "Could not unlink "
+					   "existing ctrl_iface socket '%s'",
+					   fname);
+				goto fail;
+			}
+			if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) <
+			    0) {
+				perror("bind(PF_UNIX)");
+				goto fail;
+			}
+			wpa_printf(MSG_DEBUG, "Successfully replaced leftover "
+				   "ctrl_iface socket '%s'", fname);
+		} else {
+			wpa_printf(MSG_INFO, "ctrl_iface exists and seems to "
+				   "be in use - cannot override it");
+			wpa_printf(MSG_INFO, "Delete '%s' manually if it is "
+				   "not used anymore", fname);
+			os_free(fname);
+			fname = NULL;
+			goto fail;
+		}
+	}
+
+	if (chmod(fname, S_IRWXU | S_IRWXG) < 0) {
+		perror("chmod[ctrl_interface/ifname]");
+		goto fail;
+	}
+	os_free(fname);
+
+	interface->global_ctrl_sock = s;
+	eloop_register_read_sock(s, hostapd_global_ctrl_iface_receive,
+				 interface, NULL);
+
+	return 0;
+
+fail:
+	if (s >= 0)
+		close(s);
+	if (fname) {
+		unlink(fname);
+		os_free(fname);
+	}
+	return -1;
+}
+
+
+void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interfaces)
+{
+	char *fname = NULL;
+
+	if (interfaces->global_ctrl_sock > -1) {
+		eloop_unregister_read_sock(interfaces->global_ctrl_sock);
+		close(interfaces->global_ctrl_sock);
+		interfaces->global_ctrl_sock = -1;
+		fname = hostapd_global_ctrl_iface_path(interfaces);
+		if (fname) {
+			unlink(fname);
+			os_free(fname);
+		}
+
+		if (interfaces->global_iface_path &&
+		    rmdir(interfaces->global_iface_path) < 0) {
+			if (errno == ENOTEMPTY) {
+				wpa_printf(MSG_DEBUG, "Control interface "
+					   "directory not empty - leaving it "
+					   "behind");
+			} else {
+				perror("rmdir[ctrl_interface]");
+			}
+		}
+		os_free(interfaces->global_iface_path);
+		interfaces->global_iface_path = NULL;
+	}
+}
+
+
+static void hostapd_ctrl_iface_send(struct hostapd_data *hapd, int level,
+				    const char *buf, size_t len)
+{
+	struct wpa_ctrl_dst *dst, *next;
+	struct msghdr msg;
+	int idx;
+	struct iovec io[2];
+	char levelstr[10];
+
+	dst = hapd->ctrl_dst;
+	if (hapd->ctrl_sock < 0 || dst == NULL)
+		return;
+
+	os_snprintf(levelstr, sizeof(levelstr), "<%d>", level);
+	io[0].iov_base = levelstr;
+	io[0].iov_len = os_strlen(levelstr);
+	io[1].iov_base = (char *) buf;
+	io[1].iov_len = len;
+	os_memset(&msg, 0, sizeof(msg));
+	msg.msg_iov = io;
+	msg.msg_iovlen = 2;
+
+	idx = 0;
+	while (dst) {
+		next = dst->next;
+		if (level >= dst->debug_level) {
+			wpa_hexdump(MSG_DEBUG, "CTRL_IFACE monitor send",
+				    (u8 *) dst->addr.sun_path, dst->addrlen -
+				    offsetof(struct sockaddr_un, sun_path));
+			msg.msg_name = &dst->addr;
+			msg.msg_namelen = dst->addrlen;
+			if (sendmsg(hapd->ctrl_sock, &msg, 0) < 0) {
+				int _errno = errno;
+				wpa_printf(MSG_INFO, "CTRL_IFACE monitor[%d]: "
+					   "%d - %s",
+					   idx, errno, strerror(errno));
+				dst->errors++;
+				if (dst->errors > 10 || _errno == ENOENT) {
+					hostapd_ctrl_iface_detach(
+						hapd, &dst->addr,
+						dst->addrlen);
+				}
+			} else
+				dst->errors = 0;
+		}
+		idx++;
+		dst = next;
+	}
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/hostap/hostapd/ctrl_iface.h b/hostap/hostapd/ctrl_iface.h
new file mode 100644
index 0000000..3341a66
--- /dev/null
+++ b/hostap/hostapd/ctrl_iface.h
@@ -0,0 +1,39 @@
+/*
+ * hostapd / UNIX domain socket -based control interface
+ * Copyright (c) 2004, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CTRL_IFACE_H
+#define CTRL_IFACE_H
+
+#ifndef CONFIG_NO_CTRL_IFACE
+int hostapd_ctrl_iface_init(struct hostapd_data *hapd);
+void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd);
+int hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface);
+void hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface);
+#else /* CONFIG_NO_CTRL_IFACE */
+static inline int hostapd_ctrl_iface_init(struct hostapd_data *hapd)
+{
+	return 0;
+}
+
+static inline void hostapd_ctrl_iface_deinit(struct hostapd_data *hapd)
+{
+}
+
+static inline int
+hostapd_global_ctrl_iface_init(struct hapd_interfaces *interface)
+{
+	return 0;
+}
+
+static inline void
+hostapd_global_ctrl_iface_deinit(struct hapd_interfaces *interface)
+{
+}
+#endif /* CONFIG_NO_CTRL_IFACE */
+
+#endif /* CTRL_IFACE_H */
diff --git a/hostap/hostapd/defconfig b/hostap/hostapd/defconfig
new file mode 100644
index 0000000..b5ddca3
--- /dev/null
+++ b/hostap/hostapd/defconfig
@@ -0,0 +1,269 @@
+# Example hostapd build time configuration
+#
+# This file lists the configuration options that are used when building the
+# hostapd binary. All lines starting with # are ignored. Configuration option
+# lines must be commented out complete, if they are not to be included, i.e.,
+# just setting VARIABLE=n is not disabling that variable.
+#
+# This file is included in Makefile, so variables like CFLAGS and LIBS can also
+# be modified from here. In most cass, these lines should use += in order not
+# to override previous values of the variables.
+
+# Driver interface for Host AP driver
+CONFIG_DRIVER_HOSTAP=y
+
+# Driver interface for wired authenticator
+#CONFIG_DRIVER_WIRED=y
+
+# Driver interface for madwifi driver
+#CONFIG_DRIVER_MADWIFI=y
+#CFLAGS += -I../../madwifi # change to the madwifi source directory
+
+# Driver interface for drivers using the nl80211 kernel interface
+CONFIG_DRIVER_NL80211=y
+
+# Driver interface for FreeBSD net80211 layer (e.g., Atheros driver)
+#CONFIG_DRIVER_BSD=y
+#CFLAGS += -I/usr/local/include
+#LIBS += -L/usr/local/lib
+#LIBS_p += -L/usr/local/lib
+#LIBS_c += -L/usr/local/lib
+
+# Driver interface for no driver (e.g., RADIUS server only)
+#CONFIG_DRIVER_NONE=y
+
+# IEEE 802.11F/IAPP
+CONFIG_IAPP=y
+
+# WPA2/IEEE 802.11i RSN pre-authentication
+CONFIG_RSN_PREAUTH=y
+
+# PeerKey handshake for Station to Station Link (IEEE 802.11e DLS)
+CONFIG_PEERKEY=y
+
+# IEEE 802.11w (management frame protection)
+# This version is an experimental implementation based on IEEE 802.11w/D1.0
+# draft and is subject to change since the standard has not yet been finalized.
+# Driver support is also needed for IEEE 802.11w.
+#CONFIG_IEEE80211W=y
+
+# Integrated EAP server
+CONFIG_EAP=y
+
+# EAP-MD5 for the integrated EAP server
+CONFIG_EAP_MD5=y
+
+# EAP-TLS for the integrated EAP server
+CONFIG_EAP_TLS=y
+
+# EAP-MSCHAPv2 for the integrated EAP server
+CONFIG_EAP_MSCHAPV2=y
+
+# EAP-PEAP for the integrated EAP server
+CONFIG_EAP_PEAP=y
+
+# EAP-GTC for the integrated EAP server
+CONFIG_EAP_GTC=y
+
+# EAP-TTLS for the integrated EAP server
+CONFIG_EAP_TTLS=y
+
+# EAP-SIM for the integrated EAP server
+#CONFIG_EAP_SIM=y
+
+# EAP-AKA for the integrated EAP server
+#CONFIG_EAP_AKA=y
+
+# EAP-AKA' for the integrated EAP server
+# This requires CONFIG_EAP_AKA to be enabled, too.
+#CONFIG_EAP_AKA_PRIME=y
+
+# EAP-PAX for the integrated EAP server
+#CONFIG_EAP_PAX=y
+
+# EAP-PSK for the integrated EAP server (this is _not_ needed for WPA-PSK)
+#CONFIG_EAP_PSK=y
+
+# EAP-pwd for the integrated EAP server (secure authentication with a password)
+#CONFIG_EAP_PWD=y
+
+# EAP-SAKE for the integrated EAP server
+#CONFIG_EAP_SAKE=y
+
+# EAP-GPSK for the integrated EAP server
+#CONFIG_EAP_GPSK=y
+# Include support for optional SHA256 cipher suite in EAP-GPSK
+#CONFIG_EAP_GPSK_SHA256=y
+
+# EAP-FAST for the integrated EAP server
+# Note: Default OpenSSL package does not include support for all the
+# functionality needed for EAP-FAST. If EAP-FAST is enabled with OpenSSL,
+# the OpenSSL library must be patched (openssl-0.9.9-session-ticket.patch)
+# to add the needed functions.
+#CONFIG_EAP_FAST=y
+
+# Wi-Fi Protected Setup (WPS)
+#CONFIG_WPS=y
+# Enable WSC 2.0 support
+#CONFIG_WPS2=y
+# Enable UPnP support for external WPS Registrars
+#CONFIG_WPS_UPNP=y
+# Enable WPS support with NFC config method
+#CONFIG_WPS_NFC=y
+
+# EAP-IKEv2
+#CONFIG_EAP_IKEV2=y
+
+# Trusted Network Connect (EAP-TNC)
+#CONFIG_EAP_TNC=y
+
+# PKCS#12 (PFX) support (used to read private key and certificate file from
+# a file that usually has extension .p12 or .pfx)
+CONFIG_PKCS12=y
+
+# RADIUS authentication server. This provides access to the integrated EAP
+# server from external hosts using RADIUS.
+#CONFIG_RADIUS_SERVER=y
+
+# Build IPv6 support for RADIUS operations
+CONFIG_IPV6=y
+
+# IEEE Std 802.11r-2008 (Fast BSS Transition)
+#CONFIG_IEEE80211R=y
+
+# Use the hostapd's IEEE 802.11 authentication (ACL), but without
+# the IEEE 802.11 Management capability (e.g., madwifi or FreeBSD/net80211)
+#CONFIG_DRIVER_RADIUS_ACL=y
+
+# IEEE 802.11n (High Throughput) support
+#CONFIG_IEEE80211N=y
+
+# Wireless Network Management (IEEE Std 802.11v-2011)
+# Note: This is experimental and not complete implementation.
+#CONFIG_WNM=y
+
+# IEEE 802.11ac (Very High Throughput) support
+#CONFIG_IEEE80211AC=y
+
+# Remove debugging code that is printing out debug messages to stdout.
+# This can be used to reduce the size of the hostapd considerably if debugging
+# code is not needed.
+#CONFIG_NO_STDOUT_DEBUG=y
+
+# Add support for writing debug log to a file: -f /tmp/hostapd.log
+# Disabled by default.
+#CONFIG_DEBUG_FILE=y
+
+# Remove support for RADIUS accounting
+#CONFIG_NO_ACCOUNTING=y
+
+# Remove support for RADIUS
+#CONFIG_NO_RADIUS=y
+
+# Remove support for VLANs
+#CONFIG_NO_VLAN=y
+
+# Enable support for fully dynamic VLANs. This enables hostapd to
+# automatically create bridge and VLAN interfaces if necessary.
+#CONFIG_FULL_DYNAMIC_VLAN=y
+
+# Use netlink-based kernel API for VLAN operations instead of ioctl()
+# Note: This requires libnl 3.1 or newer.
+#CONFIG_VLAN_NETLINK=y
+
+# Remove support for dumping state into a file on SIGUSR1 signal
+# This can be used to reduce binary size at the cost of disabling a debugging
+# option.
+#CONFIG_NO_DUMP_STATE=y
+
+# Enable tracing code for developer debugging
+# This tracks use of memory allocations and other registrations and reports
+# incorrect use with a backtrace of call (or allocation) location.
+#CONFIG_WPA_TRACE=y
+# For BSD, comment out these.
+#LIBS += -lexecinfo
+#LIBS_p += -lexecinfo
+#LIBS_c += -lexecinfo
+
+# Use libbfd to get more details for developer debugging
+# This enables use of libbfd to get more detailed symbols for the backtraces
+# generated by CONFIG_WPA_TRACE=y.
+#CONFIG_WPA_TRACE_BFD=y
+# For BSD, comment out these.
+#LIBS += -lbfd -liberty -lz
+#LIBS_p += -lbfd -liberty -lz
+#LIBS_c += -lbfd -liberty -lz
+
+# hostapd depends on strong random number generation being available from the
+# operating system. os_get_random() function is used to fetch random data when
+# needed, e.g., for key generation. On Linux and BSD systems, this works by
+# reading /dev/urandom. It should be noted that the OS entropy pool needs to be
+# properly initialized before hostapd is started. This is important especially
+# on embedded devices that do not have a hardware random number generator and
+# may by default start up with minimal entropy available for random number
+# generation.
+#
+# As a safety net, hostapd is by default trying to internally collect
+# additional entropy for generating random data to mix in with the data
+# fetched from the OS. This by itself is not considered to be very strong, but
+# it may help in cases where the system pool is not initialized properly.
+# However, it is very strongly recommended that the system pool is initialized
+# with enough entropy either by using hardware assisted random number
+# generator or by storing state over device reboots.
+#
+# hostapd can be configured to maintain its own entropy store over restarts to
+# enhance random number generation. This is not perfect, but it is much more
+# secure than using the same sequence of random numbers after every reboot.
+# This can be enabled with -e<entropy file> command line option. The specified
+# file needs to be readable and writable by hostapd.
+#
+# If the os_get_random() is known to provide strong random data (e.g., on
+# Linux/BSD, the board in question is known to have reliable source of random
+# data from /dev/urandom), the internal hostapd random pool can be disabled.
+# This will save some in binary size and CPU use. However, this should only be
+# considered for builds that are known to be used on devices that meet the
+# requirements described above.
+#CONFIG_NO_RANDOM_POOL=y
+
+# Select TLS implementation
+# openssl = OpenSSL (default)
+# gnutls = GnuTLS
+# internal = Internal TLSv1 implementation (experimental)
+# none = Empty template
+#CONFIG_TLS=openssl
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.1)
+# can be enabled to get a stronger construction of messages when block ciphers
+# are used.
+#CONFIG_TLSV11=y
+
+# TLS-based EAP methods require at least TLS v1.0. Newer version of TLS (v1.2)
+# can be enabled to enable use of stronger crypto algorithms.
+#CONFIG_TLSV12=y
+
+# If CONFIG_TLS=internal is used, additional library and include paths are
+# needed for LibTomMath. Alternatively, an integrated, minimal version of
+# LibTomMath can be used. See beginning of libtommath.c for details on benefits
+# and drawbacks of this option.
+#CONFIG_INTERNAL_LIBTOMMATH=y
+#ifndef CONFIG_INTERNAL_LIBTOMMATH
+#LTM_PATH=/usr/src/libtommath-0.39
+#CFLAGS += -I$(LTM_PATH)
+#LIBS += -L$(LTM_PATH)
+#LIBS_p += -L$(LTM_PATH)
+#endif
+# At the cost of about 4 kB of additional binary size, the internal LibTomMath
+# can be configured to include faster routines for exptmod, sqr, and div to
+# speed up DH and RSA calculation considerably
+#CONFIG_INTERNAL_LIBTOMMATH_FAST=y
+
+# Interworking (IEEE 802.11u)
+# This can be used to enable functionality to improve interworking with
+# external networks.
+#CONFIG_INTERWORKING=y
+
+# Hotspot 2.0
+#CONFIG_HS20=y
+
+# Enable SQLite database support in hlr_auc_gw, EAP-SIM DB, and eap_user_file
+#CONFIG_SQLITE=y
diff --git a/hostap/hostapd/dump_state.c b/hostap/hostapd/dump_state.c
new file mode 100644
index 0000000..d33e05f
--- /dev/null
+++ b/hostap/hostapd/dump_state.c
@@ -0,0 +1,180 @@
+/*
+ * hostapd / State dump
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <time.h>
+
+#include "utils/common.h"
+#include "radius/radius_client.h"
+#include "radius/radius_server.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
+#include "eap_server/eap.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "ap/sta_info.h"
+#include "dump_state.h"
+
+
+static void fprint_char(FILE *f, char c)
+{
+	if (c >= 32 && c < 127)
+		fprintf(f, "%c", c);
+	else
+		fprintf(f, "<%02x>", c);
+}
+
+
+static void ieee802_1x_dump_state(FILE *f, const char *prefix,
+				  struct sta_info *sta)
+{
+	struct eapol_state_machine *sm = sta->eapol_sm;
+	if (sm == NULL)
+		return;
+
+	fprintf(f, "%sIEEE 802.1X:\n", prefix);
+
+	if (sm->identity) {
+		size_t i;
+		fprintf(f, "%sidentity=", prefix);
+		for (i = 0; i < sm->identity_len; i++)
+			fprint_char(f, sm->identity[i]);
+		fprintf(f, "\n");
+	}
+
+	fprintf(f, "%slast EAP type: Authentication Server: %d (%s) "
+		"Supplicant: %d (%s)\n", prefix,
+		sm->eap_type_authsrv,
+		eap_server_get_name(0, sm->eap_type_authsrv),
+		sm->eap_type_supp, eap_server_get_name(0, sm->eap_type_supp));
+
+	fprintf(f, "%scached_packets=%s\n", prefix,
+		sm->last_recv_radius ? "[RX RADIUS]" : "");
+
+	eapol_auth_dump_state(f, prefix, sm);
+}
+
+
+/**
+ * hostapd_dump_state - SIGUSR1 handler to dump hostapd state to a text file
+ */
+static void hostapd_dump_state(struct hostapd_data *hapd)
+{
+	FILE *f;
+	time_t now;
+	struct sta_info *sta;
+	int i;
+#ifndef CONFIG_NO_RADIUS
+	char *buf;
+#endif /* CONFIG_NO_RADIUS */
+
+	if (!hapd->conf->dump_log_name) {
+		wpa_printf(MSG_DEBUG, "Dump file not defined - ignoring dump "
+			   "request");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "Dumping hostapd state to '%s'",
+		   hapd->conf->dump_log_name);
+	f = fopen(hapd->conf->dump_log_name, "w");
+	if (f == NULL) {
+		wpa_printf(MSG_WARNING, "Could not open dump file '%s' for "
+			   "writing.", hapd->conf->dump_log_name);
+		return;
+	}
+
+	time(&now);
+	fprintf(f, "hostapd state dump - %s", ctime(&now));
+	fprintf(f, "num_sta=%d num_sta_non_erp=%d "
+		"num_sta_no_short_slot_time=%d\n"
+		"num_sta_no_short_preamble=%d\n",
+		hapd->num_sta, hapd->iface->num_sta_non_erp,
+		hapd->iface->num_sta_no_short_slot_time,
+		hapd->iface->num_sta_no_short_preamble);
+
+	for (sta = hapd->sta_list; sta != NULL; sta = sta->next) {
+		fprintf(f, "\nSTA=" MACSTR "\n", MAC2STR(sta->addr));
+
+		fprintf(f,
+			"  AID=%d flags=0x%x %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s"
+			"\n"
+			"  capability=0x%x listen_interval=%d\n",
+			sta->aid,
+			sta->flags,
+			(sta->flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
+			(sta->flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
+			(sta->flags & WLAN_STA_PS ? "[PS]" : ""),
+			(sta->flags & WLAN_STA_TIM ? "[TIM]" : ""),
+			(sta->flags & WLAN_STA_PERM ? "[PERM]" : ""),
+			(ap_sta_is_authorized(sta) ? "[AUTHORIZED]" : ""),
+			(sta->flags & WLAN_STA_PENDING_POLL ? "[PENDING_POLL" :
+			 ""),
+			(sta->flags & WLAN_STA_SHORT_PREAMBLE ?
+			 "[SHORT_PREAMBLE]" : ""),
+			(sta->flags & WLAN_STA_PREAUTH ? "[PREAUTH]" : ""),
+			(sta->flags & WLAN_STA_WMM ? "[WMM]" : ""),
+			(sta->flags & WLAN_STA_MFP ? "[MFP]" : ""),
+			(sta->flags & WLAN_STA_WPS ? "[WPS]" : ""),
+			(sta->flags & WLAN_STA_MAYBE_WPS ? "[MAYBE_WPS]" : ""),
+			(sta->flags & WLAN_STA_WDS ? "[WDS]" : ""),
+			(sta->flags & WLAN_STA_NONERP ? "[NonERP]" : ""),
+			(sta->flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
+			sta->capability,
+			sta->listen_interval);
+
+		fprintf(f, "  supported_rates=");
+		for (i = 0; i < sta->supported_rates_len; i++)
+			fprintf(f, "%02x ", sta->supported_rates[i]);
+		fprintf(f, "\n");
+
+		fprintf(f,
+			"  timeout_next=%s\n",
+			(sta->timeout_next == STA_NULLFUNC ? "NULLFUNC POLL" :
+			 (sta->timeout_next == STA_DISASSOC ? "DISASSOC" :
+			  "DEAUTH")));
+
+		ieee802_1x_dump_state(f, "  ", sta);
+	}
+
+#ifndef CONFIG_NO_RADIUS
+	buf = os_malloc(4096);
+	if (buf) {
+		int count = radius_client_get_mib(hapd->radius, buf, 4096);
+		if (count < 0)
+			count = 0;
+		else if (count > 4095)
+			count = 4095;
+		buf[count] = '\0';
+		fprintf(f, "%s", buf);
+
+#ifdef RADIUS_SERVER
+		count = radius_server_get_mib(hapd->radius_srv, buf, 4096);
+		if (count < 0)
+			count = 0;
+		else if (count > 4095)
+			count = 4095;
+		buf[count] = '\0';
+		fprintf(f, "%s", buf);
+#endif /* RADIUS_SERVER */
+
+		os_free(buf);
+	}
+#endif /* CONFIG_NO_RADIUS */
+	fclose(f);
+}
+
+
+int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx)
+{
+	size_t i;
+
+	for (i = 0; i < iface->num_bss; i++)
+		hostapd_dump_state(iface->bss[i]);
+
+	return 0;
+}
diff --git a/hostap/hostapd/dump_state.h b/hostap/hostapd/dump_state.h
new file mode 100644
index 0000000..a209d65
--- /dev/null
+++ b/hostap/hostapd/dump_state.h
@@ -0,0 +1,14 @@
+/*
+ * hostapd / State dump
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DUMP_STATE_H
+#define DUMP_STATE_H
+
+int handle_dump_state_iface(struct hostapd_iface *iface, void *ctx);
+
+#endif /* DUMP_STATE_H */
diff --git a/hostap/hostapd/eap_register.c b/hostap/hostapd/eap_register.c
new file mode 100644
index 0000000..0a7ff91
--- /dev/null
+++ b/hostap/hostapd/eap_register.c
@@ -0,0 +1,138 @@
+/*
+ * EAP method registration
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eap_server/eap_methods.h"
+#include "eap_register.h"
+
+
+/**
+ * eap_server_register_methods - Register statically linked EAP server methods
+ * Returns: 0 on success, -1 or -2 on failure
+ *
+ * This function is called at program initialization to register all EAP
+ * methods that were linked in statically.
+ */
+int eap_server_register_methods(void)
+{
+	int ret = 0;
+
+#ifdef EAP_SERVER_IDENTITY
+	if (ret == 0)
+		ret = eap_server_identity_register();
+#endif /* EAP_SERVER_IDENTITY */
+
+#ifdef EAP_SERVER_MD5
+	if (ret == 0)
+		ret = eap_server_md5_register();
+#endif /* EAP_SERVER_MD5 */
+
+#ifdef EAP_SERVER_TLS
+	if (ret == 0)
+		ret = eap_server_tls_register();
+#endif /* EAP_SERVER_TLS */
+
+#ifdef EAP_SERVER_UNAUTH_TLS
+	if (ret == 0)
+		ret = eap_server_unauth_tls_register();
+#endif /* EAP_SERVER_TLS */
+
+#ifdef EAP_SERVER_MSCHAPV2
+	if (ret == 0)
+		ret = eap_server_mschapv2_register();
+#endif /* EAP_SERVER_MSCHAPV2 */
+
+#ifdef EAP_SERVER_PEAP
+	if (ret == 0)
+		ret = eap_server_peap_register();
+#endif /* EAP_SERVER_PEAP */
+
+#ifdef EAP_SERVER_TLV
+	if (ret == 0)
+		ret = eap_server_tlv_register();
+#endif /* EAP_SERVER_TLV */
+
+#ifdef EAP_SERVER_GTC
+	if (ret == 0)
+		ret = eap_server_gtc_register();
+#endif /* EAP_SERVER_GTC */
+
+#ifdef EAP_SERVER_TTLS
+	if (ret == 0)
+		ret = eap_server_ttls_register();
+#endif /* EAP_SERVER_TTLS */
+
+#ifdef EAP_SERVER_SIM
+	if (ret == 0)
+		ret = eap_server_sim_register();
+#endif /* EAP_SERVER_SIM */
+
+#ifdef EAP_SERVER_AKA
+	if (ret == 0)
+		ret = eap_server_aka_register();
+#endif /* EAP_SERVER_AKA */
+
+#ifdef EAP_SERVER_AKA_PRIME
+	if (ret == 0)
+		ret = eap_server_aka_prime_register();
+#endif /* EAP_SERVER_AKA_PRIME */
+
+#ifdef EAP_SERVER_PAX
+	if (ret == 0)
+		ret = eap_server_pax_register();
+#endif /* EAP_SERVER_PAX */
+
+#ifdef EAP_SERVER_PSK
+	if (ret == 0)
+		ret = eap_server_psk_register();
+#endif /* EAP_SERVER_PSK */
+
+#ifdef EAP_SERVER_SAKE
+	if (ret == 0)
+		ret = eap_server_sake_register();
+#endif /* EAP_SERVER_SAKE */
+
+#ifdef EAP_SERVER_GPSK
+	if (ret == 0)
+		ret = eap_server_gpsk_register();
+#endif /* EAP_SERVER_GPSK */
+
+#ifdef EAP_SERVER_VENDOR_TEST
+	if (ret == 0)
+		ret = eap_server_vendor_test_register();
+#endif /* EAP_SERVER_VENDOR_TEST */
+
+#ifdef EAP_SERVER_FAST
+	if (ret == 0)
+		ret = eap_server_fast_register();
+#endif /* EAP_SERVER_FAST */
+
+#ifdef EAP_SERVER_WSC
+	if (ret == 0)
+		ret = eap_server_wsc_register();
+#endif /* EAP_SERVER_WSC */
+
+#ifdef EAP_SERVER_IKEV2
+	if (ret == 0)
+		ret = eap_server_ikev2_register();
+#endif /* EAP_SERVER_IKEV2 */
+
+#ifdef EAP_SERVER_TNC
+	if (ret == 0)
+		ret = eap_server_tnc_register();
+#endif /* EAP_SERVER_TNC */
+
+#ifdef EAP_SERVER_PWD
+	if (ret == 0)
+		ret = eap_server_pwd_register();
+#endif /* EAP_SERVER_PWD */
+
+	return ret;
+}
diff --git a/hostap/hostapd/eap_register.h b/hostap/hostapd/eap_register.h
new file mode 100644
index 0000000..c342351
--- /dev/null
+++ b/hostap/hostapd/eap_register.h
@@ -0,0 +1,14 @@
+/*
+ * EAP method registration
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAP_REGISTER_H
+#define EAP_REGISTER_H
+
+int eap_server_register_methods(void);
+
+#endif /* EAP_REGISTER_H */
diff --git a/hostap/hostapd/eap_testing.txt b/hostap/hostapd/eap_testing.txt
new file mode 100644
index 0000000..04468c3
--- /dev/null
+++ b/hostap/hostapd/eap_testing.txt
@@ -0,0 +1,77 @@
+Interoperability testing of hostapd's IEEE 802.1X/EAPOL authentication
+
+Test matrix
+
++) tested successfully
+F) failed
+-) peer did not support
+?) not tested
+
+XSupplicant --------------------------------.
+Intel PROSet ---------------------------.   |
+Windows XP -------------------------.   |   |
+Mac OS X 10.4 ------------------.   |   |   |
+Nokia S60 ------------------.   |   |   |   |
+wpa_supplicant ---------.   |   |   |   |   |
+			|   |   |   |   |   |
+
+EAP-MD5			+   -   ?   ?   -
+EAP-GTC			+   -   ?   -   -
+EAP-MSCHAPv2		+   -   ?   -   -
+EAP-TLS			+   +   +1  +   +
+EAP-PEAPv0/MSCHAPv2	+   +   +   +   +   +
+EAP-PEAPv0/GTC		+   +   +   -   +
+EAP-PEAPv0/MD5		+   -   +   -   -
+EAP-PEAPv0/TLS		+   F   -   +   +
+EAP-PEAPv0/SIM		+   +   -   -   -
+EAP-PEAPv0/AKA		+   +   -   -   -
+EAP-PEAPv0/PSK		+   -   -   -   -
+EAP-PEAPv0/PAX		+   -   -   -   -
+EAP-PEAPv0/SAKE		+   -   -   -   -
+EAP-PEAPv0/GPSK		+   -   -   -   -
+EAP-PEAPv1/MSCHAPv2	+   +   +   -   +   +
+EAP-PEAPv1/GTC		+   +   +   -   +
+EAP-PEAPv1/MD5		+   -   +   -   -
+EAP-PEAPv1/TLS		+   F   -   -   +
+EAP-PEAPv1/SIM		+   +   -   -   -
+EAP-PEAPv1/AKA		+   +   -   -   -
+EAP-PEAPv1/PSK		+   -   -   -   -
+EAP-PEAPv1/PAX		+   -   -   -   -
+EAP-PEAPv1/SAKE		+   -   -   -   -
+EAP-PEAPv1/GPSK		+   -   -   -   -
+EAP-TTLS/CHAP		+   -   +   -   +   +
+EAP-TTLS/MSCHAP		+   -   +   -   +   +
+EAP-TTLS/MSCHAPv2	+   +   +   -   +   +
+EAP-TTLS/PAP		+   -   +   -   +   +
+EAP-TTLS/EAP-MD5	+   -   -   -   -   +
+EAP-TTLS/EAP-GTC	+   +   -   -   -
+EAP-TTLS/EAP-MSCHAPv2	+   +   -   -   -
+EAP-TTLS/EAP-TLS	+   F   -   -   -
+EAP-TTLS/EAP-SIM	+   +   -   -   -
+EAP-TTLS/EAP-AKA	+   +   -   -   -
+EAP-TTLS + TNC		+   -   -   -   -
+EAP-SIM			+   +   -   -   +
+EAP-AKA			+   +   -   -   -
+EAP-PAX			+   -   -   -   -
+EAP-SAKE		+   -   -   -   -
+EAP-GPSK		+   -   -   -   -
+EAP-FAST/MSCHAPv2(prov)	+   -   F   -   F
+EAP-FAST/GTC(auth)	+   -   +   -   +
+EAP-FAST/MSCHAPv2(aprov)+   -   F   -   F
+EAP-FAST/GTC(aprov)	+   -   F   -   F
+EAP-FAST/MD5(aprov)	+   -   -   -   -
+EAP-FAST/TLS(aprov)	+   -   -   -   -
+EAP-FAST/SIM(aprov)	+   -   -   -   -
+EAP-FAST/AKA(aprov)	+   -   -   -   -
+EAP-FAST/MSCHAPv2(auth)	+   -   +   -   +
+EAP-FAST/MD5(auth)	+   -   +   -   -
+EAP-FAST/TLS(auth)	+   -   -   -   -
+EAP-FAST/SIM(auth)	+   -   -   -   -
+EAP-FAST/AKA(auth)	+   -   -   -   -
+EAP-FAST + TNC		+   -   -   -   -
+EAP-IKEv2		+   -   -   -   -
+EAP-TNC			+   -   -   -   -
+
+1) EAP-TLS itself worked, but peer certificate validation failed at
+   least when using the internal TLS server (peer included incorrect
+   certificates in the chain?)
diff --git a/hostap/hostapd/hlr_auc_gw.c b/hostap/hostapd/hlr_auc_gw.c
new file mode 100644
index 0000000..e04e2e9
--- /dev/null
+++ b/hostap/hostapd/hlr_auc_gw.c
@@ -0,0 +1,1031 @@
+/*
+ * HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
+ * Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This is an example implementation of the EAP-SIM/AKA database/authentication
+ * gateway interface to HLR/AuC. It is expected to be replaced with an
+ * implementation of SS7 gateway to GSM/UMTS authentication center (HLR/AuC) or
+ * a local implementation of SIM triplet and AKA authentication data generator.
+ *
+ * hostapd will send SIM/AKA authentication queries over a UNIX domain socket
+ * to and external program, e.g., this hlr_auc_gw. This interface uses simple
+ * text-based format:
+ *
+ * EAP-SIM / GSM triplet query/response:
+ * SIM-REQ-AUTH <IMSI> <max_chal>
+ * SIM-RESP-AUTH <IMSI> Kc1:SRES1:RAND1 Kc2:SRES2:RAND2 [Kc3:SRES3:RAND3]
+ * SIM-RESP-AUTH <IMSI> FAILURE
+ *
+ * EAP-AKA / UMTS query/response:
+ * AKA-REQ-AUTH <IMSI>
+ * AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES>
+ * AKA-RESP-AUTH <IMSI> FAILURE
+ *
+ * EAP-AKA / UMTS AUTS (re-synchronization):
+ * AKA-AUTS <IMSI> <AUTS> <RAND>
+ *
+ * IMSI and max_chal are sent as an ASCII string,
+ * Kc/SRES/RAND/AUTN/IK/CK/RES/AUTS as hex strings.
+ *
+ * The example implementation here reads GSM authentication triplets from a
+ * text file in IMSI:Kc:SRES:RAND format, IMSI in ASCII, other fields as hex
+ * strings. This is used to simulate an HLR/AuC. As such, it is not very useful
+ * for real life authentication, but it is useful both as an example
+ * implementation and for EAP-SIM/AKA/AKA' testing.
+ *
+ * SQN generation follows the not time-based Profile 2 described in
+ * 3GPP TS 33.102 Annex C.3.2. The length of IND is 5 bits by default, but this
+ * can be changed with a command line options if needed.
+ */
+
+#include "includes.h"
+#include <sys/un.h>
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
+
+#include "common.h"
+#include "crypto/milenage.h"
+#include "crypto/random.h"
+
+static const char *default_socket_path = "/tmp/hlr_auc_gw.sock";
+static const char *socket_path;
+static int serv_sock = -1;
+static char *milenage_file = NULL;
+static int update_milenage = 0;
+static int sqn_changes = 0;
+static int ind_len = 5;
+
+/* GSM triplets */
+struct gsm_triplet {
+	struct gsm_triplet *next;
+	char imsi[20];
+	u8 kc[8];
+	u8 sres[4];
+	u8 _rand[16];
+};
+
+static struct gsm_triplet *gsm_db = NULL, *gsm_db_pos = NULL;
+
+/* OPc and AMF parameters for Milenage (Example algorithms for AKA). */
+struct milenage_parameters {
+	struct milenage_parameters *next;
+	char imsi[20];
+	u8 ki[16];
+	u8 opc[16];
+	u8 amf[2];
+	u8 sqn[6];
+	int set;
+};
+
+static struct milenage_parameters *milenage_db = NULL;
+
+#define EAP_SIM_MAX_CHAL 3
+
+#define EAP_AKA_RAND_LEN 16
+#define EAP_AKA_AUTN_LEN 16
+#define EAP_AKA_AUTS_LEN 14
+#define EAP_AKA_RES_MAX_LEN 16
+#define EAP_AKA_IK_LEN 16
+#define EAP_AKA_CK_LEN 16
+
+
+#ifdef CONFIG_SQLITE
+
+static sqlite3 *sqlite_db = NULL;
+static struct milenage_parameters db_tmp_milenage;
+
+
+static int db_table_exists(sqlite3 *db, const char *name)
+{
+	char cmd[128];
+	os_snprintf(cmd, sizeof(cmd), "SELECT 1 FROM %s;", name);
+	return sqlite3_exec(db, cmd, NULL, NULL, NULL) == SQLITE_OK;
+}
+
+
+static int db_table_create_milenage(sqlite3 *db)
+{
+	char *err = NULL;
+	const char *sql =
+		"CREATE TABLE milenage("
+		"  imsi INTEGER PRIMARY KEY NOT NULL,"
+		"  ki CHAR(32) NOT NULL,"
+		"  opc CHAR(32) NOT NULL,"
+		"  amf CHAR(4) NOT NULL,"
+		"  sqn CHAR(12) NOT NULL"
+		");";
+
+	printf("Adding database table for milenage information\n");
+	if (sqlite3_exec(db, sql, NULL, NULL, &err) != SQLITE_OK) {
+		printf("SQLite error: %s\n", err);
+		sqlite3_free(err);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static sqlite3 * db_open(const char *db_file)
+{
+	sqlite3 *db;
+
+	if (sqlite3_open(db_file, &db)) {
+		printf("Failed to open database %s: %s\n",
+		       db_file, sqlite3_errmsg(db));
+		sqlite3_close(db);
+		return NULL;
+	}
+
+	if (!db_table_exists(db, "milenage") &&
+	    db_table_create_milenage(db) < 0) {
+		sqlite3_close(db);
+		return NULL;
+	}
+
+	return db;
+}
+
+
+static int get_milenage_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+	struct milenage_parameters *m = ctx;
+	int i;
+
+	m->set = 1;
+
+	for (i = 0; i < argc; i++) {
+		if (os_strcmp(col[i], "ki") == 0 && argv[i] &&
+		    hexstr2bin(argv[i], m->ki, sizeof(m->ki))) {
+			printf("Invalid ki value in database\n");
+			return -1;
+		}
+
+		if (os_strcmp(col[i], "opc") == 0 && argv[i] &&
+		    hexstr2bin(argv[i], m->opc, sizeof(m->opc))) {
+			printf("Invalid opcvalue in database\n");
+			return -1;
+		}
+
+		if (os_strcmp(col[i], "amf") == 0 && argv[i] &&
+		    hexstr2bin(argv[i], m->amf, sizeof(m->amf))) {
+			printf("Invalid amf value in database\n");
+			return -1;
+		}
+
+		if (os_strcmp(col[i], "sqn") == 0 && argv[i] &&
+		    hexstr2bin(argv[i], m->sqn, sizeof(m->sqn))) {
+			printf("Invalid sqn value in database\n");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static struct milenage_parameters * db_get_milenage(const char *imsi_txt)
+{
+	char cmd[128];
+	unsigned long long imsi;
+
+	os_memset(&db_tmp_milenage, 0, sizeof(db_tmp_milenage));
+	imsi = atoll(imsi_txt);
+	os_snprintf(db_tmp_milenage.imsi, sizeof(db_tmp_milenage.imsi),
+		    "%llu", imsi);
+	os_snprintf(cmd, sizeof(cmd),
+		    "SELECT ki,opc,amf,sqn FROM milenage WHERE imsi=%llu;",
+		    imsi);
+	if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage,
+			 NULL) != SQLITE_OK)
+		return NULL;
+
+	if (!db_tmp_milenage.set)
+		return NULL;
+	return &db_tmp_milenage;
+}
+
+
+static int db_update_milenage_sqn(struct milenage_parameters *m)
+{
+	char cmd[128], val[13], *pos;
+
+	pos = val;
+	pos += wpa_snprintf_hex(pos, sizeof(val), m->sqn, 6);
+	*pos = '\0';
+	os_snprintf(cmd, sizeof(cmd),
+		    "UPDATE milenage SET sqn='%s' WHERE imsi=%s;",
+		    val, m->imsi);
+	if (sqlite3_exec(sqlite_db, cmd, NULL, NULL, NULL) != SQLITE_OK) {
+		printf("Failed to update SQN in database for IMSI %s\n",
+		       m->imsi);
+		return -1;
+	}
+	return 0;
+}
+
+#endif /* CONFIG_SQLITE */
+
+
+static int open_socket(const char *path)
+{
+	struct sockaddr_un addr;
+	int s;
+
+	s = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (s < 0) {
+		perror("socket(PF_UNIX)");
+		return -1;
+	}
+
+	memset(&addr, 0, sizeof(addr));
+	addr.sun_family = AF_UNIX;
+	os_strlcpy(addr.sun_path, path, sizeof(addr.sun_path));
+	if (bind(s, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+		perror("hlr-auc-gw: bind(PF_UNIX)");
+		close(s);
+		return -1;
+	}
+
+	return s;
+}
+
+
+static int read_gsm_triplets(const char *fname)
+{
+	FILE *f;
+	char buf[200], *pos, *pos2;
+	struct gsm_triplet *g = NULL;
+	int line, ret = 0;
+
+	if (fname == NULL)
+		return -1;
+
+	f = fopen(fname, "r");
+	if (f == NULL) {
+		printf("Could not open GSM tripler data file '%s'\n", fname);
+		return -1;
+	}
+
+	line = 0;
+	while (fgets(buf, sizeof(buf), f)) {
+		line++;
+
+		/* Parse IMSI:Kc:SRES:RAND */
+		buf[sizeof(buf) - 1] = '\0';
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0' && *pos != '\n')
+			pos++;
+		if (*pos == '\n')
+			*pos = '\0';
+		pos = buf;
+		if (*pos == '\0')
+			continue;
+
+		g = os_zalloc(sizeof(*g));
+		if (g == NULL) {
+			ret = -1;
+			break;
+		}
+
+		/* IMSI */
+		pos2 = strchr(pos, ':');
+		if (pos2 == NULL) {
+			printf("%s:%d - Invalid IMSI (%s)\n",
+			       fname, line, pos);
+			ret = -1;
+			break;
+		}
+		*pos2 = '\0';
+		if (strlen(pos) >= sizeof(g->imsi)) {
+			printf("%s:%d - Too long IMSI (%s)\n",
+			       fname, line, pos);
+			ret = -1;
+			break;
+		}
+		os_strlcpy(g->imsi, pos, sizeof(g->imsi));
+		pos = pos2 + 1;
+
+		/* Kc */
+		pos2 = strchr(pos, ':');
+		if (pos2 == NULL) {
+			printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
+			ret = -1;
+			break;
+		}
+		*pos2 = '\0';
+		if (strlen(pos) != 16 || hexstr2bin(pos, g->kc, 8)) {
+			printf("%s:%d - Invalid Kc (%s)\n", fname, line, pos);
+			ret = -1;
+			break;
+		}
+		pos = pos2 + 1;
+
+		/* SRES */
+		pos2 = strchr(pos, ':');
+		if (pos2 == NULL) {
+			printf("%s:%d - Invalid SRES (%s)\n", fname, line,
+			       pos);
+			ret = -1;
+			break;
+		}
+		*pos2 = '\0';
+		if (strlen(pos) != 8 || hexstr2bin(pos, g->sres, 4)) {
+			printf("%s:%d - Invalid SRES (%s)\n", fname, line,
+			       pos);
+			ret = -1;
+			break;
+		}
+		pos = pos2 + 1;
+
+		/* RAND */
+		pos2 = strchr(pos, ':');
+		if (pos2)
+			*pos2 = '\0';
+		if (strlen(pos) != 32 || hexstr2bin(pos, g->_rand, 16)) {
+			printf("%s:%d - Invalid RAND (%s)\n", fname, line,
+			       pos);
+			ret = -1;
+			break;
+		}
+		pos = pos2 + 1;
+
+		g->next = gsm_db;
+		gsm_db = g;
+		g = NULL;
+	}
+	os_free(g);
+
+	fclose(f);
+
+	return ret;
+}
+
+
+static struct gsm_triplet * get_gsm_triplet(const char *imsi)
+{
+	struct gsm_triplet *g = gsm_db_pos;
+
+	while (g) {
+		if (strcmp(g->imsi, imsi) == 0) {
+			gsm_db_pos = g->next;
+			return g;
+		}
+		g = g->next;
+	}
+
+	g = gsm_db;
+	while (g && g != gsm_db_pos) {
+		if (strcmp(g->imsi, imsi) == 0) {
+			gsm_db_pos = g->next;
+			return g;
+		}
+		g = g->next;
+	}
+
+	return NULL;
+}
+
+
+static int read_milenage(const char *fname)
+{
+	FILE *f;
+	char buf[200], *pos, *pos2;
+	struct milenage_parameters *m = NULL;
+	int line, ret = 0;
+
+	if (fname == NULL)
+		return -1;
+
+	f = fopen(fname, "r");
+	if (f == NULL) {
+		printf("Could not open Milenage data file '%s'\n", fname);
+		return -1;
+	}
+
+	line = 0;
+	while (fgets(buf, sizeof(buf), f)) {
+		line++;
+
+		/* Parse IMSI Ki OPc AMF SQN */
+		buf[sizeof(buf) - 1] = '\0';
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0' && *pos != '\n')
+			pos++;
+		if (*pos == '\n')
+			*pos = '\0';
+		pos = buf;
+		if (*pos == '\0')
+			continue;
+
+		m = os_zalloc(sizeof(*m));
+		if (m == NULL) {
+			ret = -1;
+			break;
+		}
+
+		/* IMSI */
+		pos2 = strchr(pos, ' ');
+		if (pos2 == NULL) {
+			printf("%s:%d - Invalid IMSI (%s)\n",
+			       fname, line, pos);
+			ret = -1;
+			break;
+		}
+		*pos2 = '\0';
+		if (strlen(pos) >= sizeof(m->imsi)) {
+			printf("%s:%d - Too long IMSI (%s)\n",
+			       fname, line, pos);
+			ret = -1;
+			break;
+		}
+		os_strlcpy(m->imsi, pos, sizeof(m->imsi));
+		pos = pos2 + 1;
+
+		/* Ki */
+		pos2 = strchr(pos, ' ');
+		if (pos2 == NULL) {
+			printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
+			ret = -1;
+			break;
+		}
+		*pos2 = '\0';
+		if (strlen(pos) != 32 || hexstr2bin(pos, m->ki, 16)) {
+			printf("%s:%d - Invalid Ki (%s)\n", fname, line, pos);
+			ret = -1;
+			break;
+		}
+		pos = pos2 + 1;
+
+		/* OPc */
+		pos2 = strchr(pos, ' ');
+		if (pos2 == NULL) {
+			printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
+			ret = -1;
+			break;
+		}
+		*pos2 = '\0';
+		if (strlen(pos) != 32 || hexstr2bin(pos, m->opc, 16)) {
+			printf("%s:%d - Invalid OPc (%s)\n", fname, line, pos);
+			ret = -1;
+			break;
+		}
+		pos = pos2 + 1;
+
+		/* AMF */
+		pos2 = strchr(pos, ' ');
+		if (pos2 == NULL) {
+			printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
+			ret = -1;
+			break;
+		}
+		*pos2 = '\0';
+		if (strlen(pos) != 4 || hexstr2bin(pos, m->amf, 2)) {
+			printf("%s:%d - Invalid AMF (%s)\n", fname, line, pos);
+			ret = -1;
+			break;
+		}
+		pos = pos2 + 1;
+
+		/* SQN */
+		pos2 = strchr(pos, ' ');
+		if (pos2)
+			*pos2 = '\0';
+		if (strlen(pos) != 12 || hexstr2bin(pos, m->sqn, 6)) {
+			printf("%s:%d - Invalid SEQ (%s)\n", fname, line, pos);
+			ret = -1;
+			break;
+		}
+		pos = pos2 + 1;
+
+		m->next = milenage_db;
+		milenage_db = m;
+		m = NULL;
+	}
+	os_free(m);
+
+	fclose(f);
+
+	return ret;
+}
+
+
+static void update_milenage_file(const char *fname)
+{
+	FILE *f, *f2;
+	char buf[500], *pos;
+	char *end = buf + sizeof(buf);
+	struct milenage_parameters *m;
+	size_t imsi_len;
+
+	f = fopen(fname, "r");
+	if (f == NULL) {
+		printf("Could not open Milenage data file '%s'\n", fname);
+		return;
+	}
+
+	snprintf(buf, sizeof(buf), "%s.new", fname);
+	f2 = fopen(buf, "w");
+	if (f2 == NULL) {
+		printf("Could not write Milenage data file '%s'\n", buf);
+		fclose(f);
+		return;
+	}
+
+	while (fgets(buf, sizeof(buf), f)) {
+		/* IMSI Ki OPc AMF SQN */
+		buf[sizeof(buf) - 1] = '\0';
+
+		pos = strchr(buf, ' ');
+		if (buf[0] == '#' || pos == NULL || pos - buf >= 20)
+			goto no_update;
+
+		imsi_len = pos - buf;
+
+		for (m = milenage_db; m; m = m->next) {
+			if (strncmp(buf, m->imsi, imsi_len) == 0 &&
+			    m->imsi[imsi_len] == '\0')
+				break;
+		}
+
+		if (!m)
+			goto no_update;
+
+		pos = buf;
+		pos += snprintf(pos, end - pos, "%s ", m->imsi);
+		pos += wpa_snprintf_hex(pos, end - pos, m->ki, 16);
+		*pos++ = ' ';
+		pos += wpa_snprintf_hex(pos, end - pos, m->opc, 16);
+		*pos++ = ' ';
+		pos += wpa_snprintf_hex(pos, end - pos, m->amf, 2);
+		*pos++ = ' ';
+		pos += wpa_snprintf_hex(pos, end - pos, m->sqn, 6);
+		*pos++ = '\n';
+
+	no_update:
+		fprintf(f2, "%s", buf);
+	}
+
+	fclose(f2);
+	fclose(f);
+
+	snprintf(buf, sizeof(buf), "%s.bak", fname);
+	if (rename(fname, buf) < 0) {
+		perror("rename");
+		return;
+	}
+
+	snprintf(buf, sizeof(buf), "%s.new", fname);
+	if (rename(buf, fname) < 0) {
+		perror("rename");
+		return;
+	}
+
+}
+
+
+static struct milenage_parameters * get_milenage(const char *imsi)
+{
+	struct milenage_parameters *m = milenage_db;
+
+	while (m) {
+		if (strcmp(m->imsi, imsi) == 0)
+			break;
+		m = m->next;
+	}
+
+#ifdef CONFIG_SQLITE
+	if (!m)
+		m = db_get_milenage(imsi);
+#endif /* CONFIG_SQLITE */
+
+	return m;
+}
+
+
+static void sim_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
+			 char *imsi)
+{
+	int count, max_chal, ret;
+	char *pos;
+	char reply[1000], *rpos, *rend;
+	struct milenage_parameters *m;
+	struct gsm_triplet *g;
+
+	reply[0] = '\0';
+
+	pos = strchr(imsi, ' ');
+	if (pos) {
+		*pos++ = '\0';
+		max_chal = atoi(pos);
+		if (max_chal < 1 || max_chal < EAP_SIM_MAX_CHAL)
+			max_chal = EAP_SIM_MAX_CHAL;
+	} else
+		max_chal = EAP_SIM_MAX_CHAL;
+
+	rend = &reply[sizeof(reply)];
+	rpos = reply;
+	ret = snprintf(rpos, rend - rpos, "SIM-RESP-AUTH %s", imsi);
+	if (ret < 0 || ret >= rend - rpos)
+		return;
+	rpos += ret;
+
+	m = get_milenage(imsi);
+	if (m) {
+		u8 _rand[16], sres[4], kc[8];
+		for (count = 0; count < max_chal; count++) {
+			if (random_get_bytes(_rand, 16) < 0)
+				return;
+			gsm_milenage(m->opc, m->ki, _rand, sres, kc);
+			*rpos++ = ' ';
+			rpos += wpa_snprintf_hex(rpos, rend - rpos, kc, 8);
+			*rpos++ = ':';
+			rpos += wpa_snprintf_hex(rpos, rend - rpos, sres, 4);
+			*rpos++ = ':';
+			rpos += wpa_snprintf_hex(rpos, rend - rpos, _rand, 16);
+		}
+		*rpos = '\0';
+		goto send;
+	}
+
+	count = 0;
+	while (count < max_chal && (g = get_gsm_triplet(imsi))) {
+		if (strcmp(g->imsi, imsi) != 0)
+			continue;
+
+		if (rpos < rend)
+			*rpos++ = ' ';
+		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->kc, 8);
+		if (rpos < rend)
+			*rpos++ = ':';
+		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->sres, 4);
+		if (rpos < rend)
+			*rpos++ = ':';
+		rpos += wpa_snprintf_hex(rpos, rend - rpos, g->_rand, 16);
+		count++;
+	}
+
+	if (count == 0) {
+		printf("No GSM triplets found for %s\n", imsi);
+		ret = snprintf(rpos, rend - rpos, " FAILURE");
+		if (ret < 0 || ret >= rend - rpos)
+			return;
+		rpos += ret;
+	}
+
+send:
+	printf("Send: %s\n", reply);
+	if (sendto(s, reply, rpos - reply, 0,
+		   (struct sockaddr *) from, fromlen) < 0)
+		perror("send");
+}
+
+
+static void inc_sqn(u8 *sqn)
+{
+	u64 val, seq, ind;
+
+	/*
+	 * SQN = SEQ | IND = SEQ1 | SEQ2 | IND
+	 *
+	 * The mechanism used here is not time-based, so SEQ2 is void and
+	 * SQN = SEQ1 | IND. The length of IND is ind_len bits and the length
+	 * of SEQ1 is 48 - ind_len bits.
+	 */
+
+	/* Increment both SEQ and IND by one */
+	val = ((u64) WPA_GET_BE32(sqn) << 16) | ((u64) WPA_GET_BE16(sqn + 4));
+	seq = (val >> ind_len) + 1;
+	ind = (val + 1) & ((1 << ind_len) - 1);
+	val = (seq << ind_len) | ind;
+	WPA_PUT_BE32(sqn, val >> 16);
+	WPA_PUT_BE16(sqn + 4, val & 0xffff);
+}
+
+
+static void aka_req_auth(int s, struct sockaddr_un *from, socklen_t fromlen,
+			 char *imsi)
+{
+	/* AKA-RESP-AUTH <IMSI> <RAND> <AUTN> <IK> <CK> <RES> */
+	char reply[1000], *pos, *end;
+	u8 _rand[EAP_AKA_RAND_LEN];
+	u8 autn[EAP_AKA_AUTN_LEN];
+	u8 ik[EAP_AKA_IK_LEN];
+	u8 ck[EAP_AKA_CK_LEN];
+	u8 res[EAP_AKA_RES_MAX_LEN];
+	size_t res_len;
+	int ret;
+	struct milenage_parameters *m;
+	int failed = 0;
+
+	m = get_milenage(imsi);
+	if (m) {
+		if (random_get_bytes(_rand, EAP_AKA_RAND_LEN) < 0)
+			return;
+		res_len = EAP_AKA_RES_MAX_LEN;
+		inc_sqn(m->sqn);
+#ifdef CONFIG_SQLITE
+		db_update_milenage_sqn(m);
+#endif /* CONFIG_SQLITE */
+		sqn_changes = 1;
+		printf("AKA: Milenage with SQN=%02x%02x%02x%02x%02x%02x\n",
+		       m->sqn[0], m->sqn[1], m->sqn[2],
+		       m->sqn[3], m->sqn[4], m->sqn[5]);
+		milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
+				  autn, ik, ck, res, &res_len);
+	} else {
+		printf("Unknown IMSI: %s\n", imsi);
+#ifdef AKA_USE_FIXED_TEST_VALUES
+		printf("Using fixed test values for AKA\n");
+		memset(_rand, '0', EAP_AKA_RAND_LEN);
+		memset(autn, '1', EAP_AKA_AUTN_LEN);
+		memset(ik, '3', EAP_AKA_IK_LEN);
+		memset(ck, '4', EAP_AKA_CK_LEN);
+		memset(res, '2', EAP_AKA_RES_MAX_LEN);
+		res_len = EAP_AKA_RES_MAX_LEN;
+#else /* AKA_USE_FIXED_TEST_VALUES */
+		failed = 1;
+#endif /* AKA_USE_FIXED_TEST_VALUES */
+	}
+
+	pos = reply;
+	end = &reply[sizeof(reply)];
+	ret = snprintf(pos, end - pos, "AKA-RESP-AUTH %s ", imsi);
+	if (ret < 0 || ret >= end - pos)
+		return;
+	pos += ret;
+	if (failed) {
+		ret = snprintf(pos, end - pos, "FAILURE");
+		if (ret < 0 || ret >= end - pos)
+			return;
+		pos += ret;
+		goto done;
+	}
+	pos += wpa_snprintf_hex(pos, end - pos, _rand, EAP_AKA_RAND_LEN);
+	*pos++ = ' ';
+	pos += wpa_snprintf_hex(pos, end - pos, autn, EAP_AKA_AUTN_LEN);
+	*pos++ = ' ';
+	pos += wpa_snprintf_hex(pos, end - pos, ik, EAP_AKA_IK_LEN);
+	*pos++ = ' ';
+	pos += wpa_snprintf_hex(pos, end - pos, ck, EAP_AKA_CK_LEN);
+	*pos++ = ' ';
+	pos += wpa_snprintf_hex(pos, end - pos, res, res_len);
+
+done:
+	printf("Send: %s\n", reply);
+
+	if (sendto(s, reply, pos - reply, 0, (struct sockaddr *) from,
+		   fromlen) < 0)
+		perror("send");
+}
+
+
+static void aka_auts(int s, struct sockaddr_un *from, socklen_t fromlen,
+		     char *imsi)
+{
+	char *auts, *__rand;
+	u8 _auts[EAP_AKA_AUTS_LEN], _rand[EAP_AKA_RAND_LEN], sqn[6];
+	struct milenage_parameters *m;
+
+	/* AKA-AUTS <IMSI> <AUTS> <RAND> */
+
+	auts = strchr(imsi, ' ');
+	if (auts == NULL)
+		return;
+	*auts++ = '\0';
+
+	__rand = strchr(auts, ' ');
+	if (__rand == NULL)
+		return;
+	*__rand++ = '\0';
+
+	printf("AKA-AUTS: IMSI=%s AUTS=%s RAND=%s\n", imsi, auts, __rand);
+	if (hexstr2bin(auts, _auts, EAP_AKA_AUTS_LEN) ||
+	    hexstr2bin(__rand, _rand, EAP_AKA_RAND_LEN)) {
+		printf("Could not parse AUTS/RAND\n");
+		return;
+	}
+
+	m = get_milenage(imsi);
+	if (m == NULL) {
+		printf("Unknown IMSI: %s\n", imsi);
+		return;
+	}
+
+	if (milenage_auts(m->opc, m->ki, _rand, _auts, sqn)) {
+		printf("AKA-AUTS: Incorrect MAC-S\n");
+	} else {
+		memcpy(m->sqn, sqn, 6);
+		printf("AKA-AUTS: Re-synchronized: "
+		       "SQN=%02x%02x%02x%02x%02x%02x\n",
+		       sqn[0], sqn[1], sqn[2], sqn[3], sqn[4], sqn[5]);
+#ifdef CONFIG_SQLITE
+		db_update_milenage_sqn(m);
+#endif /* CONFIG_SQLITE */
+		sqn_changes = 1;
+	}
+}
+
+
+static int process(int s)
+{
+	char buf[1000];
+	struct sockaddr_un from;
+	socklen_t fromlen;
+	ssize_t res;
+
+	fromlen = sizeof(from);
+	res = recvfrom(s, buf, sizeof(buf), 0, (struct sockaddr *) &from,
+		       &fromlen);
+	if (res < 0) {
+		perror("recvfrom");
+		return -1;
+	}
+
+	if (res == 0)
+		return 0;
+
+	if ((size_t) res >= sizeof(buf))
+		res = sizeof(buf) - 1;
+	buf[res] = '\0';
+
+	printf("Received: %s\n", buf);
+
+	if (strncmp(buf, "SIM-REQ-AUTH ", 13) == 0)
+		sim_req_auth(s, &from, fromlen, buf + 13);
+	else if (strncmp(buf, "AKA-REQ-AUTH ", 13) == 0)
+		aka_req_auth(s, &from, fromlen, buf + 13);
+	else if (strncmp(buf, "AKA-AUTS ", 9) == 0)
+		aka_auts(s, &from, fromlen, buf + 9);
+	else
+		printf("Unknown request: %s\n", buf);
+
+	return 0;
+}
+
+
+static void cleanup(void)
+{
+	struct gsm_triplet *g, *gprev;
+	struct milenage_parameters *m, *prev;
+
+	if (update_milenage && milenage_file && sqn_changes)
+		update_milenage_file(milenage_file);
+
+	g = gsm_db;
+	while (g) {
+		gprev = g;
+		g = g->next;
+		os_free(gprev);
+	}
+
+	m = milenage_db;
+	while (m) {
+		prev = m;
+		m = m->next;
+		os_free(prev);
+	}
+
+	close(serv_sock);
+	unlink(socket_path);
+
+#ifdef CONFIG_SQLITE
+	if (sqlite_db) {
+		sqlite3_close(sqlite_db);
+		sqlite_db = NULL;
+	}
+#endif /* CONFIG_SQLITE */
+}
+
+
+static void handle_term(int sig)
+{
+	printf("Signal %d - terminate\n", sig);
+	exit(0);
+}
+
+
+static void usage(void)
+{
+	printf("HLR/AuC testing gateway for hostapd EAP-SIM/AKA "
+	       "database/authenticator\n"
+	       "Copyright (c) 2005-2007, 2012, Jouni Malinen <j@w1.fi>\n"
+	       "\n"
+	       "usage:\n"
+	       "hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] "
+	       "[-m<milenage file>] \\\n"
+	       "        [-D<DB file>] [-i<IND len in bits>]\n"
+	       "\n"
+	       "options:\n"
+	       "  -h = show this usage help\n"
+	       "  -u = update SQN in Milenage file on exit\n"
+	       "  -s<socket path> = path for UNIX domain socket\n"
+	       "                    (default: %s)\n"
+	       "  -g<triplet file> = path for GSM authentication triplets\n"
+	       "  -m<milenage file> = path for Milenage keys\n"
+	       "  -D<DB file> = path to SQLite database\n"
+	       "  -i<IND len in bits> = IND length for SQN (default: 5)\n",
+	       default_socket_path);
+}
+
+
+int main(int argc, char *argv[])
+{
+	int c;
+	char *gsm_triplet_file = NULL;
+	char *sqlite_db_file = NULL;
+
+	if (os_program_init())
+		return -1;
+
+	socket_path = default_socket_path;
+
+	for (;;) {
+		c = getopt(argc, argv, "D:g:hi:m:s:u");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'D':
+#ifdef CONFIG_SQLITE
+			sqlite_db_file = optarg;
+			break;
+#else /* CONFIG_SQLITE */
+			printf("No SQLite support included in the build\n");
+			return -1;
+#endif /* CONFIG_SQLITE */
+		case 'g':
+			gsm_triplet_file = optarg;
+			break;
+		case 'h':
+			usage();
+			return 0;
+		case 'i':
+			ind_len = atoi(optarg);
+			if (ind_len < 0 || ind_len > 32) {
+				printf("Invalid IND length\n");
+				return -1;
+			}
+			break;
+		case 'm':
+			milenage_file = optarg;
+			break;
+		case 's':
+			socket_path = optarg;
+			break;
+		case 'u':
+			update_milenage = 1;
+			break;
+		default:
+			usage();
+			return -1;
+		}
+	}
+
+	if (!gsm_triplet_file && !milenage_file && !sqlite_db_file) {
+		usage();
+		return -1;
+	}
+
+#ifdef CONFIG_SQLITE
+	if (sqlite_db_file && (sqlite_db = db_open(sqlite_db_file)) == NULL)
+		return -1;
+#endif /* CONFIG_SQLITE */
+
+	if (gsm_triplet_file && read_gsm_triplets(gsm_triplet_file) < 0)
+		return -1;
+
+	if (milenage_file && read_milenage(milenage_file) < 0)
+		return -1;
+
+	serv_sock = open_socket(socket_path);
+	if (serv_sock < 0)
+		return -1;
+
+	printf("Listening for requests on %s\n", socket_path);
+
+	atexit(cleanup);
+	signal(SIGTERM, handle_term);
+	signal(SIGINT, handle_term);
+
+	for (;;)
+		process(serv_sock);
+
+#ifdef CONFIG_SQLITE
+	if (sqlite_db) {
+		sqlite3_close(sqlite_db);
+		sqlite_db = NULL;
+	}
+#endif /* CONFIG_SQLITE */
+
+	os_program_deinit();
+
+	return 0;
+}
diff --git a/hostap/hostapd/hlr_auc_gw.milenage_db b/hostap/hostapd/hlr_auc_gw.milenage_db
new file mode 100644
index 0000000..ecd06d7
--- /dev/null
+++ b/hostap/hostapd/hlr_auc_gw.milenage_db
@@ -0,0 +1,13 @@
+# Parameters for Milenage (Example algorithms for AKA).
+# The example Ki, OPc, and AMF values here are from 3GPP TS 35.208 v6.0.0
+# 4.3.20 Test Set 20. SQN is the last used SQN value.
+# These values can be used for both UMTS (EAP-AKA) and GSM (EAP-SIM)
+# authentication. In case of GSM/EAP-SIM, AMF and SQN values are not used, but
+# dummy values will need to be included in this file.
+
+# IMSI Ki OPc AMF SQN
+232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000
+
+# These values are from Test Set 19 which has the AMF separation bit set to 1
+# and as such, is suitable for EAP-AKA' test.
+555444333222111 5122250214c33e723a5dd523fc145fc0 981d464c7c52eb6e5036234984ad0bcf c3ab 16f3b3f70fc1
diff --git a/hostap/hostapd/hlr_auc_gw.txt b/hostap/hostapd/hlr_auc_gw.txt
new file mode 100644
index 0000000..097bbce
--- /dev/null
+++ b/hostap/hostapd/hlr_auc_gw.txt
@@ -0,0 +1,104 @@
+HLR/AuC testing gateway for hostapd EAP-SIM/AKA database/authenticator
+
+hlr_auc_gw is an example implementation of the EAP-SIM/AKA/AKA'
+database/authentication gateway interface to HLR/AuC. It could be
+replaced with an implementation of SS7 gateway to GSM/UMTS
+authentication center (HLR/AuC). hostapd will send SIM/AKA
+authentication queries over a UNIX domain socket to and external
+program, e.g., hlr_auc_gw.
+
+hlr_auc_gw can be configured with GSM and UMTS authentication data with
+text files: GSM triplet file (see hostapd.sim_db) and Milenage file (see
+hlr_auc_gw.milenage_db). Milenage parameters can be used to generate
+dynamic authentication data for EAP-SIM, EAP-AKA, and EAP-AKA' while the
+GSM triplet data is used for a more static configuration (e.g., triplets
+extracted from a SIM card).
+
+Alternatively, hlr_auc_gw can be built with support for an SQLite
+database for more dynamic operations. This is enabled by adding
+"CONFIG_SQLITE=y" into hostapd/.config before building hlr_auc_gw ("make
+clean; make hlr_auc_gw" in this directory).
+
+hostapd is configured to use hlr_auc_gw with the eap_sim_db parameter in
+hostapd.conf (e.g., "eap_sim_db=unix:/tmp/hlr_auc_gw.sock"). hlr_auc_gw
+is configured with command line parameters:
+
+hlr_auc_gw [-hu] [-s<socket path>] [-g<triplet file>] [-m<milenage file>] \
+        [-D<DB file>] [-i<IND len in bits>]
+
+options:
+  -h = show this usage help
+  -u = update SQN in Milenage file on exit
+  -s<socket path> = path for UNIX domain socket
+                    (default: /tmp/hlr_auc_gw.sock)
+  -g<triplet file> = path for GSM authentication triplets
+  -m<milenage file> = path for Milenage keys
+  -D<DB file> = path to SQLite database
+  -i<IND len in bits> = IND length for SQN (default: 5)
+
+
+The SQLite database can be initialized with sqlite, e.g., by running
+following commands in "sqlite3 /path/to/hlr_auc_gw.db":
+
+CREATE TABLE milenage(
+	imsi INTEGER PRIMARY KEY NOT NULL,
+	ki CHAR(32) NOT NULL,
+	opc CHAR(32) NOT NULL,
+	amf CHAR(4) NOT NULL,
+	sqn CHAR(12) NOT NULL
+);
+INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES(
+	232010000000000,
+	'90dca4eda45b53cf0f12d7c9c3bc6a89',
+	'cb9cccc4b9258e6dca4760379fb82581',
+	'61df',
+	'000000000000'
+);
+INSERT INTO milenage(imsi,ki,opc,amf,sqn) VALUES(
+	555444333222111,
+	'5122250214c33e723a5dd523fc145fc0',
+	'981d464c7c52eb6e5036234984ad0bcf',
+	'c3ab',
+	'16f3b3f70fc1'
+);
+
+
+hostapd (EAP server) can also be configured to store the EAP-SIM/AKA
+pseudonyms and reauth information into a SQLite database. This is
+configured with the db parameter within the eap_sim_db configuration
+option.
+
+
+"hlr_auc_gw -D /path/to/hlr_auc_gw.db" can then be used to fetch
+Milenage parameters based on IMSI from the database. The database can be
+updated dynamically while hlr_auc_gw is running to add/remove/modify
+entries.
+
+
+Example configuration files for hostapd to operate as a RADIUS
+authentication server for EAP-SIM/AKA/AKA':
+
+hostapd.conf:
+
+driver=none
+radius_server_clients=hostapd.radius_clients
+eap_server=1
+eap_user_file=hostapd.eap_user
+eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/eap_sim.db
+eap_sim_aka_result_ind=1
+
+hostapd.radius_clients:
+
+0.0.0.0/0	radius
+
+hostapd.eap_user:
+
+"0"*	AKA
+"1"*	SIM
+"2"*	AKA
+"3"*	SIM
+"4"*	AKA
+"5"*	SIM
+"6"*	AKA'
+"7"*	AKA'
+"8"*	AKA'
diff --git a/hostap/hostapd/hostapd.8 b/hostap/hostapd/hostapd.8
new file mode 100644
index 0000000..b4456bb
--- /dev/null
+++ b/hostap/hostapd/hostapd.8
@@ -0,0 +1,59 @@
+.TH HOSTAPD 8 "April  7, 2005" hostapd hostapd
+.SH NAME
+hostapd \- IEEE 802.11 AP, IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator
+.SH SYNOPSIS
+.B hostapd
+[\-hdBKtv] [\-P <PID file>] <configuration file(s)>
+.SH DESCRIPTION
+This manual page documents briefly the
+.B hostapd
+daemon.
+.PP
+.B hostapd
+is a user space daemon for access point and authentication servers.
+It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
+The current version supports Linux (Host AP, madwifi, mac80211-based drivers) and FreeBSD (net80211).
+
+.B hostapd
+is designed to be a "daemon" program that runs in the background and acts as the backend component controlling authentication.
+.B hostapd
+supports separate frontend programs and an example text-based frontend,
+.BR hostapd_cli ,
+is included with
+.BR hostapd .
+.SH OPTIONS
+A summary of options is included below.
+For a complete description, run
+.BR hostapd
+from the command line.
+.TP
+.B \-h
+Show usage.
+.TP
+.B \-d
+Show more debug messages.
+.TP
+.B \-dd
+Show even more debug messages.
+.TP
+.B \-B
+Run daemon in the background.
+.TP
+.B \-P <PID file>
+Path to PID file.
+.TP
+.B \-K
+Include key data in debug messages.
+.TP
+.B \-t
+Include timestamps in some debug messages.
+.TP
+.B \-v
+Show hostapd version.
+.SH SEE ALSO
+.BR hostapd_cli (1).
+.SH AUTHOR
+hostapd was written by Jouni Malinen <j@w1.fi>. 
+.PP
+This manual page was written by Faidon Liambotis <faidon@cube.gr>,
+for the Debian project (but may be used by others).
diff --git a/hostap/hostapd/hostapd.accept b/hostap/hostapd/hostapd.accept
new file mode 100644
index 0000000..2d2a0a2
--- /dev/null
+++ b/hostap/hostapd/hostapd.accept
@@ -0,0 +1,6 @@
+# List of MAC addresses that are allowed to authenticate (IEEE 802.11)
+# with the AP. Optional VLAN ID can be assigned for clients based on the
+# MAC address if dynamic VLANs (hostapd.conf dynamic_vlan option) are used.
+00:11:22:33:44:55
+00:66:77:88:99:aa
+00:00:22:33:44:55	1
diff --git a/hostap/hostapd/hostapd.conf b/hostap/hostapd/hostapd.conf
new file mode 100644
index 0000000..75b1941
--- /dev/null
+++ b/hostap/hostapd/hostapd.conf
@@ -0,0 +1,1535 @@
+##### hostapd configuration file ##############################################
+# Empty lines and lines starting with # are ignored
+
+# AP netdevice name (without 'ap' postfix, i.e., wlan0 uses wlan0ap for
+# management frames); ath0 for madwifi
+interface=wlan0
+
+# In case of madwifi, atheros, and nl80211 driver interfaces, an additional
+# configuration parameter, bridge, may be used to notify hostapd if the
+# interface is included in a bridge. This parameter is not used with Host AP
+# driver. If the bridge parameter is not set, the drivers will automatically
+# figure out the bridge interface (assuming sysfs is enabled and mounted to
+# /sys) and this parameter may not be needed.
+#
+# For nl80211, this parameter can be used to request the AP interface to be
+# added to the bridge automatically (brctl may refuse to do this before hostapd
+# has been started to change the interface mode). If needed, the bridge
+# interface is also created.
+#bridge=br0
+
+# Driver interface type (hostap/wired/madwifi/test/none/nl80211/bsd);
+# default: hostap). nl80211 is used with all Linux mac80211 drivers.
+# Use driver=none if building hostapd as a standalone RADIUS server that does
+# not control any wireless/wired driver.
+# driver=hostap
+
+# hostapd event logger configuration
+#
+# Two output method: syslog and stdout (only usable if not forking to
+# background).
+#
+# Module bitfield (ORed bitfield of modules that will be logged; -1 = all
+# modules):
+# bit 0 (1) = IEEE 802.11
+# bit 1 (2) = IEEE 802.1X
+# bit 2 (4) = RADIUS
+# bit 3 (8) = WPA
+# bit 4 (16) = driver interface
+# bit 5 (32) = IAPP
+# bit 6 (64) = MLME
+#
+# Levels (minimum value for logged events):
+#  0 = verbose debugging
+#  1 = debugging
+#  2 = informational messages
+#  3 = notification
+#  4 = warning
+#
+logger_syslog=-1
+logger_syslog_level=2
+logger_stdout=-1
+logger_stdout_level=2
+
+# Dump file for state information (on SIGUSR1)
+dump_file=/tmp/hostapd.dump
+
+# Interface for separate control program. If this is specified, hostapd
+# will create this directory and a UNIX domain socket for listening to requests
+# from external programs (CLI/GUI, etc.) for status information and
+# configuration. The socket file will be named based on the interface name, so
+# multiple hostapd processes/interfaces can be run at the same time if more
+# than one interface is used.
+# /var/run/hostapd is the recommended directory for sockets and by default,
+# hostapd_cli will use it when trying to connect with hostapd.
+ctrl_interface=/var/run/hostapd
+
+# Access control for the control interface can be configured by setting the
+# directory to allow only members of a group to use sockets. This way, it is
+# possible to run hostapd as root (since it needs to change network
+# configuration and open raw sockets) and still allow GUI/CLI components to be
+# run as non-root users. However, since the control interface can be used to
+# change the network configuration, this access needs to be protected in many
+# cases. By default, hostapd is configured to use gid 0 (root). If you
+# want to allow non-root users to use the contron interface, add a new group
+# and change this value to match with that group. Add users that should have
+# control interface access to this group.
+#
+# This variable can be a group name or gid.
+#ctrl_interface_group=wheel
+ctrl_interface_group=0
+
+
+##### IEEE 802.11 related configuration #######################################
+
+# SSID to be used in IEEE 802.11 management frames
+ssid=test
+# Alternative formats for configuring SSID
+# (double quoted string, hexdump, printf-escaped string)
+#ssid2="test"
+#ssid2=74657374
+#ssid2=P"hello\nthere"
+
+# UTF-8 SSID: Whether the SSID is to be interpreted using UTF-8 encoding
+#utf8_ssid=1
+
+# Country code (ISO/IEC 3166-1). Used to set regulatory domain.
+# Set as needed to indicate country in which device is operating.
+# This can limit available channels and transmit power.
+#country_code=US
+
+# Enable IEEE 802.11d. This advertises the country_code and the set of allowed
+# channels and transmit power levels based on the regulatory limits. The
+# country_code setting must be configured with the correct country for
+# IEEE 802.11d functions.
+# (default: 0 = disabled)
+#ieee80211d=1
+
+# Operation mode (a = IEEE 802.11a, b = IEEE 802.11b, g = IEEE 802.11g,
+# ad = IEEE 802.11ad (60 GHz); a/g options are used with IEEE 802.11n, too, to
+# specify band)
+# Default: IEEE 802.11b
+hw_mode=g
+
+# Channel number (IEEE 802.11)
+# (default: 0, i.e., not set)
+# Please note that some drivers do not use this value from hostapd and the
+# channel will need to be configured separately with iwconfig.
+channel=1
+
+# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
+beacon_int=100
+
+# DTIM (delivery traffic information message) period (range 1..255):
+# number of beacons between DTIMs (1 = every beacon includes DTIM element)
+# (default: 2)
+dtim_period=2
+
+# Maximum number of stations allowed in station table. New stations will be
+# rejected after the station table is full. IEEE 802.11 has a limit of 2007
+# different association IDs, so this number should not be larger than that.
+# (default: 2007)
+max_num_sta=255
+
+# RTS/CTS threshold; 2347 = disabled (default); range 0..2347
+# If this field is not included in hostapd.conf, hostapd will not control
+# RTS threshold and 'iwconfig wlan# rts <val>' can be used to set it.
+rts_threshold=2347
+
+# Fragmentation threshold; 2346 = disabled (default); range 256..2346
+# If this field is not included in hostapd.conf, hostapd will not control
+# fragmentation threshold and 'iwconfig wlan# frag <val>' can be used to set
+# it.
+fragm_threshold=2346
+
+# Rate configuration
+# Default is to enable all rates supported by the hardware. This configuration
+# item allows this list be filtered so that only the listed rates will be left
+# in the list. If the list is empty, all rates are used. This list can have
+# entries that are not in the list of rates the hardware supports (such entries
+# are ignored). The entries in this list are in 100 kbps, i.e., 11 Mbps = 110.
+# If this item is present, at least one rate have to be matching with the rates
+# hardware supports.
+# default: use the most common supported rate setting for the selected
+# hw_mode (i.e., this line can be removed from configuration file in most
+# cases)
+#supported_rates=10 20 55 110 60 90 120 180 240 360 480 540
+
+# Basic rate set configuration
+# List of rates (in 100 kbps) that are included in the basic rate set.
+# If this item is not included, usually reasonable default set is used.
+#basic_rates=10 20
+#basic_rates=10 20 55 110
+#basic_rates=60 120 240
+
+# Short Preamble
+# This parameter can be used to enable optional use of short preamble for
+# frames sent at 2 Mbps, 5.5 Mbps, and 11 Mbps to improve network performance.
+# This applies only to IEEE 802.11b-compatible networks and this should only be
+# enabled if the local hardware supports use of short preamble. If any of the
+# associated STAs do not support short preamble, use of short preamble will be
+# disabled (and enabled when such STAs disassociate) dynamically.
+# 0 = do not allow use of short preamble (default)
+# 1 = allow use of short preamble
+#preamble=1
+
+# Station MAC address -based authentication
+# Please note that this kind of access control requires a driver that uses
+# hostapd to take care of management frame processing and as such, this can be
+# used with driver=hostap or driver=nl80211, but not with driver=madwifi.
+# 0 = accept unless in deny list
+# 1 = deny unless in accept list
+# 2 = use external RADIUS server (accept/deny lists are searched first)
+macaddr_acl=0
+
+# Accept/deny lists are read from separate files (containing list of
+# MAC addresses, one per line). Use absolute path name to make sure that the
+# files can be read on SIGHUP configuration reloads.
+#accept_mac_file=/etc/hostapd.accept
+#deny_mac_file=/etc/hostapd.deny
+
+# IEEE 802.11 specifies two authentication algorithms. hostapd can be
+# configured to allow both of these or only one. Open system authentication
+# should be used with IEEE 802.1X.
+# Bit fields of allowed authentication algorithms:
+# bit 0 = Open System Authentication
+# bit 1 = Shared Key Authentication (requires WEP)
+auth_algs=3
+
+# Send empty SSID in beacons and ignore probe request frames that do not
+# specify full SSID, i.e., require stations to know SSID.
+# default: disabled (0)
+# 1 = send empty (length=0) SSID in beacon and ignore probe request for
+#     broadcast SSID
+# 2 = clear SSID (ASCII 0), but keep the original length (this may be required
+#     with some clients that do not support empty SSID) and ignore probe
+#     requests for broadcast SSID
+ignore_broadcast_ssid=0
+
+# Additional vendor specfic elements for Beacon and Probe Response frames
+# This parameter can be used to add additional vendor specific element(s) into
+# the end of the Beacon and Probe Response frames. The format for these
+# element(s) is a hexdump of the raw information elements (id+len+payload for
+# one or more elements)
+#vendor_elements=dd0411223301
+
+# TX queue parameters (EDCF / bursting)
+# tx_queue_<queue name>_<param>
+# queues: data0, data1, data2, data3, after_beacon, beacon
+#		(data0 is the highest priority queue)
+# parameters:
+#   aifs: AIFS (default 2)
+#   cwmin: cwMin (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023)
+#   cwmax: cwMax (1, 3, 7, 15, 31, 63, 127, 255, 511, 1023); cwMax >= cwMin
+#   burst: maximum length (in milliseconds with precision of up to 0.1 ms) for
+#          bursting
+#
+# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
+# These parameters are used by the access point when transmitting frames
+# to the clients.
+#
+# Low priority / AC_BK = background
+#tx_queue_data3_aifs=7
+#tx_queue_data3_cwmin=15
+#tx_queue_data3_cwmax=1023
+#tx_queue_data3_burst=0
+# Note: for IEEE 802.11b mode: cWmin=31 cWmax=1023 burst=0
+#
+# Normal priority / AC_BE = best effort
+#tx_queue_data2_aifs=3
+#tx_queue_data2_cwmin=15
+#tx_queue_data2_cwmax=63
+#tx_queue_data2_burst=0
+# Note: for IEEE 802.11b mode: cWmin=31 cWmax=127 burst=0
+#
+# High priority / AC_VI = video
+#tx_queue_data1_aifs=1
+#tx_queue_data1_cwmin=7
+#tx_queue_data1_cwmax=15
+#tx_queue_data1_burst=3.0
+# Note: for IEEE 802.11b mode: cWmin=15 cWmax=31 burst=6.0
+#
+# Highest priority / AC_VO = voice
+#tx_queue_data0_aifs=1
+#tx_queue_data0_cwmin=3
+#tx_queue_data0_cwmax=7
+#tx_queue_data0_burst=1.5
+# Note: for IEEE 802.11b mode: cWmin=7 cWmax=15 burst=3.3
+
+# 802.1D Tag (= UP) to AC mappings
+# WMM specifies following mapping of data frames to different ACs. This mapping
+# can be configured using Linux QoS/tc and sch_pktpri.o module.
+# 802.1D Tag	802.1D Designation	Access Category	WMM Designation
+# 1		BK			AC_BK		Background
+# 2		-			AC_BK		Background
+# 0		BE			AC_BE		Best Effort
+# 3		EE			AC_BE		Best Effort
+# 4		CL			AC_VI		Video
+# 5		VI			AC_VI		Video
+# 6		VO			AC_VO		Voice
+# 7		NC			AC_VO		Voice
+# Data frames with no priority information: AC_BE
+# Management frames: AC_VO
+# PS-Poll frames: AC_BE
+
+# Default WMM parameters (IEEE 802.11 draft; 11-03-0504-03-000e):
+# for 802.11a or 802.11g networks
+# These parameters are sent to WMM clients when they associate.
+# The parameters will be used by WMM clients for frames transmitted to the
+# access point.
+#
+# note - txop_limit is in units of 32microseconds
+# note - acm is admission control mandatory flag. 0 = admission control not
+# required, 1 = mandatory
+# note - here cwMin and cmMax are in exponent form. the actual cw value used
+# will be (2^n)-1 where n is the value given here
+#
+wmm_enabled=1
+#
+# WMM-PS Unscheduled Automatic Power Save Delivery [U-APSD]
+# Enable this flag if U-APSD supported outside hostapd (eg., Firmware/driver)
+#uapsd_advertisement_enabled=1
+#
+# Low priority / AC_BK = background
+wmm_ac_bk_cwmin=4
+wmm_ac_bk_cwmax=10
+wmm_ac_bk_aifs=7
+wmm_ac_bk_txop_limit=0
+wmm_ac_bk_acm=0
+# Note: for IEEE 802.11b mode: cWmin=5 cWmax=10
+#
+# Normal priority / AC_BE = best effort
+wmm_ac_be_aifs=3
+wmm_ac_be_cwmin=4
+wmm_ac_be_cwmax=10
+wmm_ac_be_txop_limit=0
+wmm_ac_be_acm=0
+# Note: for IEEE 802.11b mode: cWmin=5 cWmax=7
+#
+# High priority / AC_VI = video
+wmm_ac_vi_aifs=2
+wmm_ac_vi_cwmin=3
+wmm_ac_vi_cwmax=4
+wmm_ac_vi_txop_limit=94
+wmm_ac_vi_acm=0
+# Note: for IEEE 802.11b mode: cWmin=4 cWmax=5 txop_limit=188
+#
+# Highest priority / AC_VO = voice
+wmm_ac_vo_aifs=2
+wmm_ac_vo_cwmin=2
+wmm_ac_vo_cwmax=3
+wmm_ac_vo_txop_limit=47
+wmm_ac_vo_acm=0
+# Note: for IEEE 802.11b mode: cWmin=3 cWmax=4 burst=102
+
+# Static WEP key configuration
+#
+# The key number to use when transmitting.
+# It must be between 0 and 3, and the corresponding key must be set.
+# default: not set
+#wep_default_key=0
+# The WEP keys to use.
+# A key may be a quoted string or unquoted hexadecimal digits.
+# The key length should be 5, 13, or 16 characters, or 10, 26, or 32
+# digits, depending on whether 40-bit (64-bit), 104-bit (128-bit), or
+# 128-bit (152-bit) WEP is used.
+# Only the default key must be supplied; the others are optional.
+# default: not set
+#wep_key0=123456789a
+#wep_key1="vwxyz"
+#wep_key2=0102030405060708090a0b0c0d
+#wep_key3=".2.4.6.8.0.23"
+
+# Station inactivity limit
+#
+# If a station does not send anything in ap_max_inactivity seconds, an
+# empty data frame is sent to it in order to verify whether it is
+# still in range. If this frame is not ACKed, the station will be
+# disassociated and then deauthenticated. This feature is used to
+# clear station table of old entries when the STAs move out of the
+# range.
+#
+# The station can associate again with the AP if it is still in range;
+# this inactivity poll is just used as a nicer way of verifying
+# inactivity; i.e., client will not report broken connection because
+# disassociation frame is not sent immediately without first polling
+# the STA with a data frame.
+# default: 300 (i.e., 5 minutes)
+#ap_max_inactivity=300
+#
+# The inactivity polling can be disabled to disconnect stations based on
+# inactivity timeout so that idle stations are more likely to be disconnected
+# even if they are still in range of the AP. This can be done by setting
+# skip_inactivity_poll to 1 (default 0).
+#skip_inactivity_poll=0
+
+# Disassociate stations based on excessive transmission failures or other
+# indications of connection loss. This depends on the driver capabilities and
+# may not be available with all drivers.
+#disassoc_low_ack=1
+
+# Maximum allowed Listen Interval (how many Beacon periods STAs are allowed to
+# remain asleep). Default: 65535 (no limit apart from field size)
+#max_listen_interval=100
+
+# WDS (4-address frame) mode with per-station virtual interfaces
+# (only supported with driver=nl80211)
+# This mode allows associated stations to use 4-address frames to allow layer 2
+# bridging to be used.
+#wds_sta=1
+
+# If bridge parameter is set, the WDS STA interface will be added to the same
+# bridge by default. This can be overridden with the wds_bridge parameter to
+# use a separate bridge.
+#wds_bridge=wds-br0
+
+# Client isolation can be used to prevent low-level bridging of frames between
+# associated stations in the BSS. By default, this bridging is allowed.
+#ap_isolate=1
+
+##### IEEE 802.11n related configuration ######################################
+
+# ieee80211n: Whether IEEE 802.11n (HT) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+# Note: You will also need to enable WMM for full HT functionality.
+#ieee80211n=1
+
+# ht_capab: HT capabilities (list of flags)
+# LDPC coding capability: [LDPC] = supported
+# Supported channel width set: [HT40-] = both 20 MHz and 40 MHz with secondary
+#	channel below the primary channel; [HT40+] = both 20 MHz and 40 MHz
+#	with secondary channel below the primary channel
+#	(20 MHz only if neither is set)
+#	Note: There are limits on which channels can be used with HT40- and
+#	HT40+. Following table shows the channels that may be available for
+#	HT40- and HT40+ use per IEEE 802.11n Annex J:
+#	freq		HT40-		HT40+
+#	2.4 GHz		5-13		1-7 (1-9 in Europe/Japan)
+#	5 GHz		40,48,56,64	36,44,52,60
+#	(depending on the location, not all of these channels may be available
+#	for use)
+#	Please note that 40 MHz channels may switch their primary and secondary
+#	channels if needed or creation of 40 MHz channel maybe rejected based
+#	on overlapping BSSes. These changes are done automatically when hostapd
+#	is setting up the 40 MHz channel.
+# Spatial Multiplexing (SM) Power Save: [SMPS-STATIC] or [SMPS-DYNAMIC]
+#	(SMPS disabled if neither is set)
+# HT-greenfield: [GF] (disabled if not set)
+# Short GI for 20 MHz: [SHORT-GI-20] (disabled if not set)
+# Short GI for 40 MHz: [SHORT-GI-40] (disabled if not set)
+# Tx STBC: [TX-STBC] (disabled if not set)
+# Rx STBC: [RX-STBC1] (one spatial stream), [RX-STBC12] (one or two spatial
+#	streams), or [RX-STBC123] (one, two, or three spatial streams); Rx STBC
+#	disabled if none of these set
+# HT-delayed Block Ack: [DELAYED-BA] (disabled if not set)
+# Maximum A-MSDU length: [MAX-AMSDU-7935] for 7935 octets (3839 octets if not
+#	set)
+# DSSS/CCK Mode in 40 MHz: [DSSS_CCK-40] = allowed (not allowed if not set)
+# PSMP support: [PSMP] (disabled if not set)
+# L-SIG TXOP protection support: [LSIG-TXOP-PROT] (disabled if not set)
+#ht_capab=[HT40-][SHORT-GI-20][SHORT-GI-40]
+
+# Require stations to support HT PHY (reject association if they do not)
+#require_ht=1
+
+##### IEEE 802.11ac related configuration #####################################
+
+# ieee80211ac: Whether IEEE 802.11ac (VHT) is enabled
+# 0 = disabled (default)
+# 1 = enabled
+# Note: You will also need to enable WMM for full VHT functionality.
+#ieee80211ac=1
+
+# vht_capab: VHT capabilities (list of flags)
+#
+# vht_max_mpdu_len: [MAX-MPDU-7991] [MAX-MPDU-11454]
+# Indicates maximum MPDU length
+# 0 = 3895 octets (default)
+# 1 = 7991 octets
+# 2 = 11454 octets
+# 3 = reserved
+#
+# supported_chan_width: [VHT160] [VHT160-80PLUS80]
+# Indicates supported Channel widths
+# 0 = 160 MHz & 80+80 channel widths are not supported (default)
+# 1 = 160 MHz channel width is supported
+# 2 = 160 MHz & 80+80 channel widths are supported
+# 3 = reserved
+#
+# Rx LDPC coding capability: [RXLDPC]
+# Indicates support for receiving LDPC coded pkts
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Short GI for 80 MHz: [SHORT-GI-80]
+# Indicates short GI support for reception of packets transmitted with TXVECTOR
+# params format equal to VHT and CBW = 80Mhz
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Short GI for 160 MHz: [SHORT-GI-160]
+# Indicates short GI support for reception of packets transmitted with TXVECTOR
+# params format equal to VHT and CBW = 160Mhz
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Tx STBC: [TX-STBC-2BY1]
+# Indicates support for the transmission of at least 2x1 STBC
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Rx STBC: [RX-STBC-1] [RX-STBC-12] [RX-STBC-123] [RX-STBC-1234]
+# Indicates support for the reception of PPDUs using STBC
+# 0 = Not supported (default)
+# 1 = support of one spatial stream
+# 2 = support of one and two spatial streams
+# 3 = support of one, two and three spatial streams
+# 4 = support of one, two, three and four spatial streams
+# 5,6,7 = reserved
+#
+# SU Beamformer Capable: [SU-BEAMFORMER]
+# Indicates support for operation as a single user beamformer
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# SU Beamformee Capable: [SU-BEAMFORMEE]
+# Indicates support for operation as a single user beamformee
+# 0 = Not supported (default)
+# 1 = Supported
+#
+# Compressed Steering Number of Beamformer Antennas Supported: [BF-ANTENNA-2]
+#   Beamformee's capability indicating the maximum number of beamformer
+#   antennas the beamformee can support when sending compressed beamforming
+#   feedback
+# If SU beamformer capable, set to maximum value minus 1
+# else reserved (default)
+#
+# Number of Sounding Dimensions: [SOUNDING-DIMENSION-2]
+# Beamformer's capability indicating the maximum value of the NUM_STS parameter
+# in the TXVECTOR of a VHT NDP
+# If SU beamformer capable, set to maximum value minus 1
+# else reserved (default)
+#
+# MU Beamformer Capable: [MU-BEAMFORMER]
+# Indicates support for operation as an MU beamformer
+# 0 = Not supported or sent by Non-AP STA (default)
+# 1 = Supported
+#
+# MU Beamformee Capable: [MU-BEAMFORMEE]
+# Indicates support for operation as an MU beamformee
+# 0 = Not supported or sent by AP (default)
+# 1 = Supported
+#
+# VHT TXOP PS: [VHT-TXOP-PS]
+# Indicates whether or not the AP supports VHT TXOP Power Save Mode
+#  or whether or not the STA is in VHT TXOP Power Save mode
+# 0 = VHT AP doesnt support VHT TXOP PS mode (OR) VHT Sta not in VHT TXOP PS
+#  mode
+# 1 = VHT AP supports VHT TXOP PS mode (OR) VHT Sta is in VHT TXOP power save
+#  mode
+#
+# +HTC-VHT Capable: [HTC-VHT]
+# Indicates whether or not the STA supports receiving a VHT variant HT Control
+# field.
+# 0 = Not supported (default)
+# 1 = supported
+#
+# Maximum A-MPDU Length Exponent: [MAX-A-MPDU-LEN-EXP0]..[MAX-A-MPDU-LEN-EXP7]
+# Indicates the maximum length of A-MPDU pre-EOF padding that the STA can recv
+# This field is an integer in the range of 0 to 7.
+# The length defined by this field is equal to
+# 2 pow(13 + Maximum A-MPDU Length Exponent) -1 octets
+#
+# VHT Link Adaptation Capable: [VHT-LINK-ADAPT2] [VHT-LINK-ADAPT3]
+# Indicates whether or not the STA supports link adaptation using VHT variant
+# HT Control field
+# If +HTC-VHTcapable is 1
+#  0 = (no feedback) if the STA does not provide VHT MFB (default)
+#  1 = reserved
+#  2 = (Unsolicited) if the STA provides only unsolicited VHT MFB
+#  3 = (Both) if the STA can provide VHT MFB in response to VHT MRQ and if the
+#      STA provides unsolicited VHT MFB
+# Reserved if +HTC-VHTcapable is 0
+#
+# Rx Antenna Pattern Consistency: [RX-ANTENNA-PATTERN]
+# Indicates the possibility of Rx antenna pattern change
+# 0 = Rx antenna pattern might change during the lifetime of an association
+# 1 = Rx antenna pattern does not change during the lifetime of an association
+#
+# Tx Antenna Pattern Consistency: [TX-ANTENNA-PATTERN]
+# Indicates the possibility of Tx antenna pattern change
+# 0 = Tx antenna pattern might change during the lifetime of an association
+# 1 = Tx antenna pattern does not change during the lifetime of an association
+#vht_capab=[SHORT-GI-80][HTC-VHT]
+#
+# Require stations to support VHT PHY (reject association if they do not)
+#require_vht=1
+
+# 0 = 20 or 40 MHz operating Channel width
+# 1 = 80 MHz channel width
+# 2 = 160 MHz channel width
+# 3 = 80+80 MHz channel width
+#vht_oper_chwidth=1
+#
+# center freq = 5 GHz + (5 * index)
+# So index 42 gives center freq 5.210 GHz
+# which is channel 42 in 5G band
+#
+#vht_oper_centr_freq_seg0_idx=42
+#
+# center freq = 5 GHz + (5 * index)
+# So index 159 gives center freq 5.795 GHz
+# which is channel 159 in 5G band
+#
+#vht_oper_centr_freq_seg1_idx=159
+
+##### IEEE 802.1X-2004 related configuration ##################################
+
+# Require IEEE 802.1X authorization
+#ieee8021x=1
+
+# IEEE 802.1X/EAPOL version
+# hostapd is implemented based on IEEE Std 802.1X-2004 which defines EAPOL
+# version 2. However, there are many client implementations that do not handle
+# the new version number correctly (they seem to drop the frames completely).
+# In order to make hostapd interoperate with these clients, the version number
+# can be set to the older version (1) with this configuration value.
+#eapol_version=2
+
+# Optional displayable message sent with EAP Request-Identity. The first \0
+# in this string will be converted to ASCII-0 (nul). This can be used to
+# separate network info (comma separated list of attribute=value pairs); see,
+# e.g., RFC 4284.
+#eap_message=hello
+#eap_message=hello\0networkid=netw,nasid=foo,portid=0,NAIRealms=example.com
+
+# WEP rekeying (disabled if key lengths are not set or are set to 0)
+# Key lengths for default/broadcast and individual/unicast keys:
+# 5 = 40-bit WEP (also known as 64-bit WEP with 40 secret bits)
+# 13 = 104-bit WEP (also known as 128-bit WEP with 104 secret bits)
+#wep_key_len_broadcast=5
+#wep_key_len_unicast=5
+# Rekeying period in seconds. 0 = do not rekey (i.e., set keys only once)
+#wep_rekey_period=300
+
+# EAPOL-Key index workaround (set bit7) for WinXP Supplicant (needed only if
+# only broadcast keys are used)
+eapol_key_index_workaround=0
+
+# EAP reauthentication period in seconds (default: 3600 seconds; 0 = disable
+# reauthentication).
+#eap_reauth_period=3600
+
+# Use PAE group address (01:80:c2:00:00:03) instead of individual target
+# address when sending EAPOL frames with driver=wired. This is the most common
+# mechanism used in wired authentication, but it also requires that the port
+# is only used by one station.
+#use_pae_group_addr=1
+
+##### Integrated EAP server ###################################################
+
+# Optionally, hostapd can be configured to use an integrated EAP server
+# to process EAP authentication locally without need for an external RADIUS
+# server. This functionality can be used both as a local authentication server
+# for IEEE 802.1X/EAPOL and as a RADIUS server for other devices.
+
+# Use integrated EAP server instead of external RADIUS authentication
+# server. This is also needed if hostapd is configured to act as a RADIUS
+# authentication server.
+eap_server=0
+
+# Path for EAP server user database
+# If SQLite support is included, this can be set to "sqlite:/path/to/sqlite.db"
+# to use SQLite database instead of a text file.
+#eap_user_file=/etc/hostapd.eap_user
+
+# CA certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
+#ca_cert=/etc/hostapd.ca.pem
+
+# Server certificate (PEM or DER file) for EAP-TLS/PEAP/TTLS
+#server_cert=/etc/hostapd.server.pem
+
+# Private key matching with the server certificate for EAP-TLS/PEAP/TTLS
+# This may point to the same file as server_cert if both certificate and key
+# are included in a single file. PKCS#12 (PFX) file (.p12/.pfx) can also be
+# used by commenting out server_cert and specifying the PFX file as the
+# private_key.
+#private_key=/etc/hostapd.server.prv
+
+# Passphrase for private key
+#private_key_passwd=secret passphrase
+
+# Enable CRL verification.
+# Note: hostapd does not yet support CRL downloading based on CDP. Thus, a
+# valid CRL signed by the CA is required to be included in the ca_cert file.
+# This can be done by using PEM format for CA certificate and CRL and
+# concatenating these into one file. Whenever CRL changes, hostapd needs to be
+# restarted to take the new CRL into use.
+# 0 = do not verify CRLs (default)
+# 1 = check the CRL of the user certificate
+# 2 = check all CRLs in the certificate path
+#check_crl=1
+
+# dh_file: File path to DH/DSA parameters file (in PEM format)
+# This is an optional configuration file for setting parameters for an
+# ephemeral DH key exchange. In most cases, the default RSA authentication does
+# not use this configuration. However, it is possible setup RSA to use
+# ephemeral DH key exchange. In addition, ciphers with DSA keys always use
+# ephemeral DH keys. This can be used to achieve forward secrecy. If the file
+# is in DSA parameters format, it will be automatically converted into DH
+# params. This parameter is required if anonymous EAP-FAST is used.
+# You can generate DH parameters file with OpenSSL, e.g.,
+# "openssl dhparam -out /etc/hostapd.dh.pem 1024"
+#dh_file=/etc/hostapd.dh.pem
+
+# Fragment size for EAP methods
+#fragment_size=1400
+
+# Finite cyclic group for EAP-pwd. Number maps to group of domain parameters
+# using the IANA repository for IKE (RFC 2409).
+#pwd_group=19
+
+# Configuration data for EAP-SIM database/authentication gateway interface.
+# This is a text string in implementation specific format. The example
+# implementation in eap_sim_db.c uses this as the UNIX domain socket name for
+# the HLR/AuC gateway (e.g., hlr_auc_gw). In this case, the path uses "unix:"
+# prefix. If hostapd is built with SQLite support (CONFIG_SQLITE=y in .config),
+# database file can be described with an optional db=<path> parameter.
+#eap_sim_db=unix:/tmp/hlr_auc_gw.sock
+#eap_sim_db=unix:/tmp/hlr_auc_gw.sock db=/tmp/hostapd.db
+
+# Encryption key for EAP-FAST PAC-Opaque values. This key must be a secret,
+# random value. It is configured as a 16-octet value in hex format. It can be
+# generated, e.g., with the following command:
+# od -tx1 -v -N16 /dev/random | colrm 1 8 | tr -d ' '
+#pac_opaque_encr_key=000102030405060708090a0b0c0d0e0f
+
+# EAP-FAST authority identity (A-ID)
+# A-ID indicates the identity of the authority that issues PACs. The A-ID
+# should be unique across all issuing servers. In theory, this is a variable
+# length field, but due to some existing implementations requiring A-ID to be
+# 16 octets in length, it is strongly recommended to use that length for the
+# field to provid interoperability with deployed peer implementations. This
+# field is configured in hex format.
+#eap_fast_a_id=101112131415161718191a1b1c1d1e1f
+
+# EAP-FAST authority identifier information (A-ID-Info)
+# This is a user-friendly name for the A-ID. For example, the enterprise name
+# and server name in a human-readable format. This field is encoded as UTF-8.
+#eap_fast_a_id_info=test server
+
+# Enable/disable different EAP-FAST provisioning modes:
+#0 = provisioning disabled
+#1 = only anonymous provisioning allowed
+#2 = only authenticated provisioning allowed
+#3 = both provisioning modes allowed (default)
+#eap_fast_prov=3
+
+# EAP-FAST PAC-Key lifetime in seconds (hard limit)
+#pac_key_lifetime=604800
+
+# EAP-FAST PAC-Key refresh time in seconds (soft limit on remaining hard
+# limit). The server will generate a new PAC-Key when this number of seconds
+# (or fewer) of the lifetime remains.
+#pac_key_refresh_time=86400
+
+# EAP-SIM and EAP-AKA protected success/failure indication using AT_RESULT_IND
+# (default: 0 = disabled).
+#eap_sim_aka_result_ind=1
+
+# Trusted Network Connect (TNC)
+# If enabled, TNC validation will be required before the peer is allowed to
+# connect. Note: This is only used with EAP-TTLS and EAP-FAST. If any other
+# EAP method is enabled, the peer will be allowed to connect without TNC.
+#tnc=1
+
+
+##### IEEE 802.11f - Inter-Access Point Protocol (IAPP) #######################
+
+# Interface to be used for IAPP broadcast packets
+#iapp_interface=eth0
+
+
+##### RADIUS client configuration #############################################
+# for IEEE 802.1X with external Authentication Server, IEEE 802.11
+# authentication with external ACL for MAC addresses, and accounting
+
+# The own IP address of the access point (used as NAS-IP-Address)
+own_ip_addr=127.0.0.1
+
+# Optional NAS-Identifier string for RADIUS messages. When used, this should be
+# a unique to the NAS within the scope of the RADIUS server. For example, a
+# fully qualified domain name can be used here.
+# When using IEEE 802.11r, nas_identifier must be set and must be between 1 and
+# 48 octets long.
+#nas_identifier=ap.example.com
+
+# RADIUS authentication server
+#auth_server_addr=127.0.0.1
+#auth_server_port=1812
+#auth_server_shared_secret=secret
+
+# RADIUS accounting server
+#acct_server_addr=127.0.0.1
+#acct_server_port=1813
+#acct_server_shared_secret=secret
+
+# Secondary RADIUS servers; to be used if primary one does not reply to
+# RADIUS packets. These are optional and there can be more than one secondary
+# server listed.
+#auth_server_addr=127.0.0.2
+#auth_server_port=1812
+#auth_server_shared_secret=secret2
+#
+#acct_server_addr=127.0.0.2
+#acct_server_port=1813
+#acct_server_shared_secret=secret2
+
+# Retry interval for trying to return to the primary RADIUS server (in
+# seconds). RADIUS client code will automatically try to use the next server
+# when the current server is not replying to requests. If this interval is set,
+# primary server will be retried after configured amount of time even if the
+# currently used secondary server is still working.
+#radius_retry_primary_interval=600
+
+
+# Interim accounting update interval
+# If this is set (larger than 0) and acct_server is configured, hostapd will
+# send interim accounting updates every N seconds. Note: if set, this overrides
+# possible Acct-Interim-Interval attribute in Access-Accept message. Thus, this
+# value should not be configured in hostapd.conf, if RADIUS server is used to
+# control the interim interval.
+# This value should not be less 600 (10 minutes) and must not be less than
+# 60 (1 minute).
+#radius_acct_interim_interval=600
+
+# Request Chargeable-User-Identity (RFC 4372)
+# This parameter can be used to configure hostapd to request CUI from the
+# RADIUS server by including Chargeable-User-Identity attribute into
+# Access-Request packets.
+#radius_request_cui=1
+
+# Dynamic VLAN mode; allow RADIUS authentication server to decide which VLAN
+# is used for the stations. This information is parsed from following RADIUS
+# attributes based on RFC 3580 and RFC 2868: Tunnel-Type (value 13 = VLAN),
+# Tunnel-Medium-Type (value 6 = IEEE 802), Tunnel-Private-Group-ID (value
+# VLANID as a string). vlan_file option below must be configured if dynamic
+# VLANs are used. Optionally, the local MAC ACL list (accept_mac_file) can be
+# used to set static client MAC address to VLAN ID mapping.
+# 0 = disabled (default)
+# 1 = option; use default interface if RADIUS server does not include VLAN ID
+# 2 = required; reject authentication if RADIUS server does not include VLAN ID
+#dynamic_vlan=0
+
+# VLAN interface list for dynamic VLAN mode is read from a separate text file.
+# This list is used to map VLAN ID from the RADIUS server to a network
+# interface. Each station is bound to one interface in the same way as with
+# multiple BSSIDs or SSIDs. Each line in this text file is defining a new
+# interface and the line must include VLAN ID and interface name separated by
+# white space (space or tab).
+#vlan_file=/etc/hostapd.vlan
+
+# Interface where 802.1q tagged packets should appear when a RADIUS server is
+# used to determine which VLAN a station is on.  hostapd creates a bridge for
+# each VLAN.  Then hostapd adds a VLAN interface (associated with the interface
+# indicated by 'vlan_tagged_interface') and the appropriate wireless interface
+# to the bridge.
+#vlan_tagged_interface=eth0
+
+# When hostapd creates a VLAN interface on vlan_tagged_interfaces, it needs
+# to know how to name it.
+# 0 = vlan<XXX>, e.g., vlan1
+# 1 = <vlan_tagged_interface>.<XXX>, e.g. eth0.1
+#vlan_naming=0
+
+# Arbitrary RADIUS attributes can be added into Access-Request and
+# Accounting-Request packets by specifying the contents of the attributes with
+# the following configuration parameters. There can be multiple of these to
+# add multiple attributes. These parameters can also be used to override some
+# of the attributes added automatically by hostapd.
+# Format: <attr_id>[:<syntax:value>]
+# attr_id: RADIUS attribute type (e.g., 26 = Vendor-Specific)
+# syntax: s = string (UTF-8), d = integer, x = octet string
+# value: attribute value in format indicated by the syntax
+# If syntax and value parts are omitted, a null value (single 0x00 octet) is
+# used.
+#
+# Additional Access-Request attributes
+# radius_auth_req_attr=<attr_id>[:<syntax:value>]
+# Examples:
+# Operator-Name = "Operator"
+#radius_auth_req_attr=126:s:Operator
+# Service-Type = Framed (2)
+#radius_auth_req_attr=6:d:2
+# Connect-Info = "testing" (this overrides the automatically generated value)
+#radius_auth_req_attr=77:s:testing
+# Same Connect-Info value set as a hexdump
+#radius_auth_req_attr=77:x:74657374696e67
+
+#
+# Additional Accounting-Request attributes
+# radius_acct_req_attr=<attr_id>[:<syntax:value>]
+# Examples:
+# Operator-Name = "Operator"
+#radius_acct_req_attr=126:s:Operator
+
+# Dynamic Authorization Extensions (RFC 5176)
+# This mechanism can be used to allow dynamic changes to user session based on
+# commands from a RADIUS server (or some other disconnect client that has the
+# needed session information). For example, Disconnect message can be used to
+# request an associated station to be disconnected.
+#
+# This is disabled by default. Set radius_das_port to non-zero UDP port
+# number to enable.
+#radius_das_port=3799
+#
+# DAS client (the host that can send Disconnect/CoA requests) and shared secret
+#radius_das_client=192.168.1.123 shared secret here
+#
+# DAS Event-Timestamp time window in seconds
+#radius_das_time_window=300
+#
+# DAS require Event-Timestamp
+#radius_das_require_event_timestamp=1
+
+##### RADIUS authentication server configuration ##############################
+
+# hostapd can be used as a RADIUS authentication server for other hosts. This
+# requires that the integrated EAP server is also enabled and both
+# authentication services are sharing the same configuration.
+
+# File name of the RADIUS clients configuration for the RADIUS server. If this
+# commented out, RADIUS server is disabled.
+#radius_server_clients=/etc/hostapd.radius_clients
+
+# The UDP port number for the RADIUS authentication server
+#radius_server_auth_port=1812
+
+# Use IPv6 with RADIUS server (IPv4 will also be supported using IPv6 API)
+#radius_server_ipv6=1
+
+
+##### WPA/IEEE 802.11i configuration ##########################################
+
+# Enable WPA. Setting this variable configures the AP to require WPA (either
+# WPA-PSK or WPA-RADIUS/EAP based on other configuration). For WPA-PSK, either
+# wpa_psk or wpa_passphrase must be set and wpa_key_mgmt must include WPA-PSK.
+# Instead of wpa_psk / wpa_passphrase, wpa_psk_radius might suffice.
+# For WPA-RADIUS/EAP, ieee8021x must be set (but without dynamic WEP keys),
+# RADIUS authentication server must be configured, and WPA-EAP must be included
+# in wpa_key_mgmt.
+# This field is a bit field that can be used to enable WPA (IEEE 802.11i/D3.0)
+# and/or WPA2 (full IEEE 802.11i/RSN):
+# bit0 = WPA
+# bit1 = IEEE 802.11i/RSN (WPA2) (dot11RSNAEnabled)
+#wpa=1
+
+# WPA pre-shared keys for WPA-PSK. This can be either entered as a 256-bit
+# secret in hex format (64 hex digits), wpa_psk, or as an ASCII passphrase
+# (8..63 characters) that will be converted to PSK. This conversion uses SSID
+# so the PSK changes when ASCII passphrase is used and the SSID is changed.
+# wpa_psk (dot11RSNAConfigPSKValue)
+# wpa_passphrase (dot11RSNAConfigPSKPassPhrase)
+#wpa_psk=0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+#wpa_passphrase=secret passphrase
+
+# Optionally, WPA PSKs can be read from a separate text file (containing list
+# of (PSK,MAC address) pairs. This allows more than one PSK to be configured.
+# Use absolute path name to make sure that the files can be read on SIGHUP
+# configuration reloads.
+#wpa_psk_file=/etc/hostapd.wpa_psk
+
+# Optionally, WPA passphrase can be received from RADIUS authentication server
+# This requires macaddr_acl to be set to 2 (RADIUS)
+# 0 = disabled (default)
+# 1 = optional; use default passphrase/psk if RADIUS server does not include
+#	Tunnel-Password
+# 2 = required; reject authentication if RADIUS server does not include
+#	Tunnel-Password
+#wpa_psk_radius=0
+
+# Set of accepted key management algorithms (WPA-PSK, WPA-EAP, or both). The
+# entries are separated with a space. WPA-PSK-SHA256 and WPA-EAP-SHA256 can be
+# added to enable SHA256-based stronger algorithms.
+# (dot11RSNAConfigAuthenticationSuitesTable)
+#wpa_key_mgmt=WPA-PSK WPA-EAP
+
+# Set of accepted cipher suites (encryption algorithms) for pairwise keys
+# (unicast packets). This is a space separated list of algorithms:
+# CCMP = AES in Counter mode with CBC-MAC [RFC 3610, IEEE 802.11i/D7.0]
+# TKIP = Temporal Key Integrity Protocol [IEEE 802.11i/D7.0]
+# Group cipher suite (encryption algorithm for broadcast and multicast frames)
+# is automatically selected based on this configuration. If only CCMP is
+# allowed as the pairwise cipher, group cipher will also be CCMP. Otherwise,
+# TKIP will be used as the group cipher.
+# (dot11RSNAConfigPairwiseCiphersTable)
+# Pairwise cipher for WPA (v1) (default: TKIP)
+#wpa_pairwise=TKIP CCMP
+# Pairwise cipher for RSN/WPA2 (default: use wpa_pairwise value)
+#rsn_pairwise=CCMP
+
+# Time interval for rekeying GTK (broadcast/multicast encryption keys) in
+# seconds. (dot11RSNAConfigGroupRekeyTime)
+#wpa_group_rekey=600
+
+# Rekey GTK when any STA that possesses the current GTK is leaving the BSS.
+# (dot11RSNAConfigGroupRekeyStrict)
+#wpa_strict_rekey=1
+
+# Time interval for rekeying GMK (master key used internally to generate GTKs
+# (in seconds).
+#wpa_gmk_rekey=86400
+
+# Maximum lifetime for PTK in seconds. This can be used to enforce rekeying of
+# PTK to mitigate some attacks against TKIP deficiencies.
+#wpa_ptk_rekey=600
+
+# Enable IEEE 802.11i/RSN/WPA2 pre-authentication. This is used to speed up
+# roaming be pre-authenticating IEEE 802.1X/EAP part of the full RSN
+# authentication and key handshake before actually associating with a new AP.
+# (dot11RSNAPreauthenticationEnabled)
+#rsn_preauth=1
+#
+# Space separated list of interfaces from which pre-authentication frames are
+# accepted (e.g., 'eth0' or 'eth0 wlan0wds0'. This list should include all
+# interface that are used for connections to other APs. This could include
+# wired interfaces and WDS links. The normal wireless data interface towards
+# associated stations (e.g., wlan0) should not be added, since
+# pre-authentication is only used with APs other than the currently associated
+# one.
+#rsn_preauth_interfaces=eth0
+
+# peerkey: Whether PeerKey negotiation for direct links (IEEE 802.11e) is
+# allowed. This is only used with RSN/WPA2.
+# 0 = disabled (default)
+# 1 = enabled
+#peerkey=1
+
+# ieee80211w: Whether management frame protection (MFP) is enabled
+# 0 = disabled (default)
+# 1 = optional
+# 2 = required
+#ieee80211w=0
+
+# Association SA Query maximum timeout (in TU = 1.024 ms; for MFP)
+# (maximum time to wait for a SA Query response)
+# dot11AssociationSAQueryMaximumTimeout, 1...4294967295
+#assoc_sa_query_max_timeout=1000
+
+# Association SA Query retry timeout (in TU = 1.024 ms; for MFP)
+# (time between two subsequent SA Query requests)
+# dot11AssociationSAQueryRetryTimeout, 1...4294967295
+#assoc_sa_query_retry_timeout=201
+
+# disable_pmksa_caching: Disable PMKSA caching
+# This parameter can be used to disable caching of PMKSA created through EAP
+# authentication. RSN preauthentication may still end up using PMKSA caching if
+# it is enabled (rsn_preauth=1).
+# 0 = PMKSA caching enabled (default)
+# 1 = PMKSA caching disabled
+#disable_pmksa_caching=0
+
+# okc: Opportunistic Key Caching (aka Proactive Key Caching)
+# Allow PMK cache to be shared opportunistically among configured interfaces
+# and BSSes (i.e., all configurations within a single hostapd process).
+# 0 = disabled (default)
+# 1 = enabled
+#okc=1
+
+
+##### IEEE 802.11r configuration ##############################################
+
+# Mobility Domain identifier (dot11FTMobilityDomainID, MDID)
+# MDID is used to indicate a group of APs (within an ESS, i.e., sharing the
+# same SSID) between which a STA can use Fast BSS Transition.
+# 2-octet identifier as a hex string.
+#mobility_domain=a1b2
+
+# PMK-R0 Key Holder identifier (dot11FTR0KeyHolderID)
+# 1 to 48 octet identifier.
+# This is configured with nas_identifier (see RADIUS client section above).
+
+# Default lifetime of the PMK-RO in minutes; range 1..65535
+# (dot11FTR0KeyLifetime)
+#r0_key_lifetime=10000
+
+# PMK-R1 Key Holder identifier (dot11FTR1KeyHolderID)
+# 6-octet identifier as a hex string.
+#r1_key_holder=000102030405
+
+# Reassociation deadline in time units (TUs / 1.024 ms; range 1000..65535)
+# (dot11FTReassociationDeadline)
+#reassociation_deadline=1000
+
+# List of R0KHs in the same Mobility Domain
+# format: <MAC address> <NAS Identifier> <128-bit key as hex string>
+# This list is used to map R0KH-ID (NAS Identifier) to a destination MAC
+# address when requesting PMK-R1 key from the R0KH that the STA used during the
+# Initial Mobility Domain Association.
+#r0kh=02:01:02:03:04:05 r0kh-1.example.com 000102030405060708090a0b0c0d0e0f
+#r0kh=02:01:02:03:04:06 r0kh-2.example.com 00112233445566778899aabbccddeeff
+# And so on.. One line per R0KH.
+
+# List of R1KHs in the same Mobility Domain
+# format: <MAC address> <R1KH-ID> <128-bit key as hex string>
+# This list is used to map R1KH-ID to a destination MAC address when sending
+# PMK-R1 key from the R0KH. This is also the list of authorized R1KHs in the MD
+# that can request PMK-R1 keys.
+#r1kh=02:01:02:03:04:05 02:11:22:33:44:55 000102030405060708090a0b0c0d0e0f
+#r1kh=02:01:02:03:04:06 02:11:22:33:44:66 00112233445566778899aabbccddeeff
+# And so on.. One line per R1KH.
+
+# Whether PMK-R1 push is enabled at R0KH
+# 0 = do not push PMK-R1 to all configured R1KHs (default)
+# 1 = push PMK-R1 to all configured R1KHs whenever a new PMK-R0 is derived
+#pmk_r1_push=1
+
+##### Neighbor table ##########################################################
+# Maximum number of entries kept in AP table (either for neigbor table or for
+# detecting Overlapping Legacy BSS Condition). The oldest entry will be
+# removed when adding a new entry that would make the list grow over this
+# limit. Note! WFA certification for IEEE 802.11g requires that OLBC is
+# enabled, so this field should not be set to 0 when using IEEE 802.11g.
+# default: 255
+#ap_table_max_size=255
+
+# Number of seconds of no frames received after which entries may be deleted
+# from the AP table. Since passive scanning is not usually performed frequently
+# this should not be set to very small value. In addition, there is no
+# guarantee that every scan cycle will receive beacon frames from the
+# neighboring APs.
+# default: 60
+#ap_table_expiration_time=3600
+
+
+##### Wi-Fi Protected Setup (WPS) #############################################
+
+# WPS state
+# 0 = WPS disabled (default)
+# 1 = WPS enabled, not configured
+# 2 = WPS enabled, configured
+#wps_state=2
+
+# AP can be configured into a locked state where new WPS Registrar are not
+# accepted, but previously authorized Registrars (including the internal one)
+# can continue to add new Enrollees.
+#ap_setup_locked=1
+
+# Universally Unique IDentifier (UUID; see RFC 4122) of the device
+# This value is used as the UUID for the internal WPS Registrar. If the AP
+# is also using UPnP, this value should be set to the device's UPnP UUID.
+# If not configured, UUID will be generated based on the local MAC address.
+#uuid=12345678-9abc-def0-1234-56789abcdef0
+
+# Note: If wpa_psk_file is set, WPS is used to generate random, per-device PSKs
+# that will be appended to the wpa_psk_file. If wpa_psk_file is not set, the
+# default PSK (wpa_psk/wpa_passphrase) will be delivered to Enrollees. Use of
+# per-device PSKs is recommended as the more secure option (i.e., make sure to
+# set wpa_psk_file when using WPS with WPA-PSK).
+
+# When an Enrollee requests access to the network with PIN method, the Enrollee
+# PIN will need to be entered for the Registrar. PIN request notifications are
+# sent to hostapd ctrl_iface monitor. In addition, they can be written to a
+# text file that could be used, e.g., to populate the AP administration UI with
+# pending PIN requests. If the following variable is set, the PIN requests will
+# be written to the configured file.
+#wps_pin_requests=/var/run/hostapd_wps_pin_requests
+
+# Device Name
+# User-friendly description of device; up to 32 octets encoded in UTF-8
+#device_name=Wireless AP
+
+# Manufacturer
+# The manufacturer of the device (up to 64 ASCII characters)
+#manufacturer=Company
+
+# Model Name
+# Model of the device (up to 32 ASCII characters)
+#model_name=WAP
+
+# Model Number
+# Additional device description (up to 32 ASCII characters)
+#model_number=123
+
+# Serial Number
+# Serial number of the device (up to 32 characters)
+#serial_number=12345
+
+# Primary Device Type
+# Used format: <categ>-<OUI>-<subcateg>
+# categ = Category as an integer value
+# OUI = OUI and type octet as a 4-octet hex-encoded value; 0050F204 for
+#       default WPS OUI
+# subcateg = OUI-specific Sub Category as an integer value
+# Examples:
+#   1-0050F204-1 (Computer / PC)
+#   1-0050F204-2 (Computer / Server)
+#   5-0050F204-1 (Storage / NAS)
+#   6-0050F204-1 (Network Infrastructure / AP)
+#device_type=6-0050F204-1
+
+# OS Version
+# 4-octet operating system version number (hex string)
+#os_version=01020300
+
+# Config Methods
+# List of the supported configuration methods
+# Available methods: usba ethernet label display ext_nfc_token int_nfc_token
+#	nfc_interface push_button keypad virtual_display physical_display
+#	virtual_push_button physical_push_button
+#config_methods=label virtual_display virtual_push_button keypad
+
+# WPS capability discovery workaround for PBC with Windows 7
+# Windows 7 uses incorrect way of figuring out AP's WPS capabilities by acting
+# as a Registrar and using M1 from the AP. The config methods attribute in that
+# message is supposed to indicate only the configuration method supported by
+# the AP in Enrollee role, i.e., to add an external Registrar. For that case,
+# PBC shall not be used and as such, the PushButton config method is removed
+# from M1 by default. If pbc_in_m1=1 is included in the configuration file,
+# the PushButton config method is left in M1 (if included in config_methods
+# parameter) to allow Windows 7 to use PBC instead of PIN (e.g., from a label
+# in the AP).
+#pbc_in_m1=1
+
+# Static access point PIN for initial configuration and adding Registrars
+# If not set, hostapd will not allow external WPS Registrars to control the
+# access point. The AP PIN can also be set at runtime with hostapd_cli
+# wps_ap_pin command. Use of temporary (enabled by user action) and random
+# AP PIN is much more secure than configuring a static AP PIN here. As such,
+# use of the ap_pin parameter is not recommended if the AP device has means for
+# displaying a random PIN.
+#ap_pin=12345670
+
+# Skip building of automatic WPS credential
+# This can be used to allow the automatically generated Credential attribute to
+# be replaced with pre-configured Credential(s).
+#skip_cred_build=1
+
+# Additional Credential attribute(s)
+# This option can be used to add pre-configured Credential attributes into M8
+# message when acting as a Registrar. If skip_cred_build=1, this data will also
+# be able to override the Credential attribute that would have otherwise been
+# automatically generated based on network configuration. This configuration
+# option points to an external file that much contain the WPS Credential
+# attribute(s) as binary data.
+#extra_cred=hostapd.cred
+
+# Credential processing
+#   0 = process received credentials internally (default)
+#   1 = do not process received credentials; just pass them over ctrl_iface to
+#	external program(s)
+#   2 = process received credentials internally and pass them over ctrl_iface
+#	to external program(s)
+# Note: With wps_cred_processing=1, skip_cred_build should be set to 1 and
+# extra_cred be used to provide the Credential data for Enrollees.
+#
+# wps_cred_processing=1 will disabled automatic updates of hostapd.conf file
+# both for Credential processing and for marking AP Setup Locked based on
+# validation failures of AP PIN. An external program is responsible on updating
+# the configuration appropriately in this case.
+#wps_cred_processing=0
+
+# AP Settings Attributes for M7
+# By default, hostapd generates the AP Settings Attributes for M7 based on the
+# current configuration. It is possible to override this by providing a file
+# with pre-configured attributes. This is similar to extra_cred file format,
+# but the AP Settings attributes are not encapsulated in a Credential
+# attribute.
+#ap_settings=hostapd.ap_settings
+
+# WPS UPnP interface
+# If set, support for external Registrars is enabled.
+#upnp_iface=br0
+
+# Friendly Name (required for UPnP)
+# Short description for end use. Should be less than 64 characters.
+#friendly_name=WPS Access Point
+
+# Manufacturer URL (optional for UPnP)
+#manufacturer_url=http://www.example.com/
+
+# Model Description (recommended for UPnP)
+# Long description for end user. Should be less than 128 characters.
+#model_description=Wireless Access Point
+
+# Model URL (optional for UPnP)
+#model_url=http://www.example.com/model/
+
+# Universal Product Code (optional for UPnP)
+# 12-digit, all-numeric code that identifies the consumer package.
+#upc=123456789012
+
+# WPS RF Bands (a = 5G, b = 2.4G, g = 2.4G, ag = dual band)
+# This value should be set according to RF band(s) supported by the AP if
+# hw_mode is not set. For dual band dual concurrent devices, this needs to be
+# set to ag to allow both RF bands to be advertized.
+#wps_rf_bands=ag
+
+# NFC password token for WPS
+# These parameters can be used to configure a fixed NFC password token for the
+# AP. This can be generated, e.g., with nfc_pw_token from wpa_supplicant. When
+# these parameters are used, the AP is assumed to be deployed with a NFC tag
+# that includes the matching NFC password token (e.g., written based on the
+# NDEF record from nfc_pw_token).
+#
+#wps_nfc_dev_pw_id: Device Password ID (16..65535)
+#wps_nfc_dh_pubkey: Hexdump of DH Public Key
+#wps_nfc_dh_privkey: Hexdump of DH Private Key
+#wps_nfc_dev_pw: Hexdump of Device Password
+
+##### Wi-Fi Direct (P2P) ######################################################
+
+# Enable P2P Device management
+#manage_p2p=1
+
+# Allow cross connection
+#allow_cross_connection=1
+
+#### TDLS (IEEE 802.11z-2010) #################################################
+
+# Prohibit use of TDLS in this BSS
+#tdls_prohibit=1
+
+# Prohibit use of TDLS Channel Switching in this BSS
+#tdls_prohibit_chan_switch=1
+
+##### IEEE 802.11v-2011 #######################################################
+
+# Time advertisement
+# 0 = disabled (default)
+# 2 = UTC time at which the TSF timer is 0
+#time_advertisement=2
+
+# Local time zone as specified in 8.3 of IEEE Std 1003.1-2004:
+# stdoffset[dst[offset][,start[/time],end[/time]]]
+#time_zone=EST5
+
+# WNM-Sleep Mode (extended sleep mode for stations)
+# 0 = disabled (default)
+# 1 = enabled (allow stations to use WNM-Sleep Mode)
+#wnm_sleep_mode=1
+
+# BSS Transition Management
+# 0 = disabled (default)
+# 1 = enabled
+#bss_transition=1
+
+##### IEEE 802.11u-2011 #######################################################
+
+# Enable Interworking service
+#interworking=1
+
+# Access Network Type
+# 0 = Private network
+# 1 = Private network with guest access
+# 2 = Chargeable public network
+# 3 = Free public network
+# 4 = Personal device network
+# 5 = Emergency services only network
+# 14 = Test or experimental
+# 15 = Wildcard
+#access_network_type=0
+
+# Whether the network provides connectivity to the Internet
+# 0 = Unspecified
+# 1 = Network provides connectivity to the Internet
+#internet=1
+
+# Additional Step Required for Access
+# Note: This is only used with open network, i.e., ASRA shall ne set to 0 if
+# RSN is used.
+#asra=0
+
+# Emergency services reachable
+#esr=0
+
+# Unauthenticated emergency service accessible
+#uesa=0
+
+# Venue Info (optional)
+# The available values are defined in IEEE Std 802.11u-2011, 7.3.1.34.
+# Example values (group,type):
+# 0,0 = Unspecified
+# 1,7 = Convention Center
+# 1,13 = Coffee Shop
+# 2,0 = Unspecified Business
+# 7,1  Private Residence
+#venue_group=7
+#venue_type=1
+
+# Homogeneous ESS identifier (optional; dot11HESSID)
+# If set, this shall be identifical to one of the BSSIDs in the homogeneous
+# ESS and this shall be set to the same value across all BSSs in homogeneous
+# ESS.
+#hessid=02:03:04:05:06:07
+
+# Roaming Consortium List
+# Arbitrary number of Roaming Consortium OIs can be configured with each line
+# adding a new OI to the list. The first three entries are available through
+# Beacon and Probe Response frames. Any additional entry will be available only
+# through ANQP queries. Each OI is between 3 and 15 octets and is configured as
+# a hexstring.
+#roaming_consortium=021122
+#roaming_consortium=2233445566
+
+# Venue Name information
+# This parameter can be used to configure one or more Venue Name Duples for
+# Venue Name ANQP information. Each entry has a two or three character language
+# code (ISO-639) separated by colon from the venue name string.
+# Note that venue_group and venue_type have to be set for Venue Name
+# information to be complete.
+#venue_name=eng:Example venue
+#venue_name=fin:Esimerkkipaikka
+
+# Network Authentication Type
+# This parameter indicates what type of network authentication is used in the
+# network.
+# format: <network auth type indicator (1-octet hex str)> [redirect URL]
+# Network Authentication Type Indicator values:
+# 00 = Acceptance of terms and conditions
+# 01 = On-line enrollment supported
+# 02 = http/https redirection
+# 03 = DNS redirection
+#network_auth_type=00
+#network_auth_type=02http://www.example.com/redirect/me/here/
+
+# IP Address Type Availability
+# format: <1-octet encoded value as hex str>
+# (ipv4_type & 0x3f) << 2 | (ipv6_type & 0x3)
+# ipv4_type:
+# 0 = Address type not available
+# 1 = Public IPv4 address available
+# 2 = Port-restricted IPv4 address available
+# 3 = Single NATed private IPv4 address available
+# 4 = Double NATed private IPv4 address available
+# 5 = Port-restricted IPv4 address and single NATed IPv4 address available
+# 6 = Port-restricted IPv4 address and double NATed IPv4 address available
+# 7 = Availability of the address type is not known
+# ipv6_type:
+# 0 = Address type not available
+# 1 = Address type available
+# 2 = Availability of the address type not known
+#ipaddr_type_availability=14
+
+# Domain Name
+# format: <variable-octet str>[,<variable-octet str>]
+#domain_name=example.com,another.example.com,yet-another.example.com
+
+# 3GPP Cellular Network information
+# format: <MCC1,MNC1>[;<MCC2,MNC2>][;...]
+#anqp_3gpp_cell_net=244,91;310,026;234,56
+
+# NAI Realm information
+# One or more realm can be advertised. Each nai_realm line adds a new realm to
+# the set. These parameters provide information for stations using Interworking
+# network selection to allow automatic connection to a network based on
+# credentials.
+# format: <encoding>,<NAI Realm(s)>[,<EAP Method 1>][,<EAP Method 2>][,...]
+# encoding:
+#	0 = Realm formatted in accordance with IETF RFC 4282
+#	1 = UTF-8 formatted character string that is not formatted in
+#	    accordance with IETF RFC 4282
+# NAI Realm(s): Semi-colon delimited NAI Realm(s)
+# EAP Method: <EAP Method>[:<[AuthParam1:Val1]>][<[AuthParam2:Val2]>][...]
+# AuthParam (Table 8-188 in IEEE Std 802.11-2012):
+# ID 2 = Non-EAP Inner Authentication Type
+#	1 = PAP, 2 = CHAP, 3 = MSCHAP, 4 = MSCHAPV2
+# ID 3 = Inner authentication EAP Method Type
+# ID 5 = Credential Type
+#	1 = SIM, 2 = USIM, 3 = NFC Secure Element, 4 = Hardware Token,
+#	5 = Softoken, 6 = Certificate, 7 = username/password, 9 = Anonymous,
+#	10 = Vendor Specific
+#nai_realm=0,example.com;example.net
+# EAP methods EAP-TLS with certificate and EAP-TTLS/MSCHAPv2 with
+# username/password
+#nai_realm=0,example.org,13[5:6],21[2:4][5:7]
+
+##### Hotspot 2.0 #############################################################
+
+# Enable Hotspot 2.0 support
+#hs20=1
+
+# Disable Downstream Group-Addressed Forwarding (DGAF)
+# This can be used to configure a network where no group-addressed frames are
+# allowed. The AP will not forward any group-address frames to the stations and
+# random GTKs are issued for each station to prevent associated stations from
+# forging such frames to other stations in the BSS.
+#disable_dgaf=1
+
+# Operator Friendly Name
+# This parameter can be used to configure one or more Operator Friendly Name
+# Duples. Each entry has a two or three character language code (ISO-639)
+# separated by colon from the operator friendly name string.
+#hs20_oper_friendly_name=eng:Example operator
+#hs20_oper_friendly_name=fin:Esimerkkioperaattori
+
+# Connection Capability
+# This can be used to advertise what type of IP traffic can be sent through the
+# hotspot (e.g., due to firewall allowing/blocking protocols/ports).
+# format: <IP Protocol>:<Port Number>:<Status>
+# IP Protocol: 1 = ICMP, 6 = TCP, 17 = UDP
+# Port Number: 0..65535
+# Status: 0 = Closed, 1 = Open, 2 = Unknown
+# Each hs20_conn_capab line is added to the list of advertised tuples.
+#hs20_conn_capab=1:0:2
+#hs20_conn_capab=6:22:1
+#hs20_conn_capab=17:5060:0
+
+# WAN Metrics
+# format: <WAN Info>:<DL Speed>:<UL Speed>:<DL Load>:<UL Load>:<LMD>
+# WAN Info: B0-B1: Link Status, B2: Symmetric Link, B3: At Capabity
+#    (encoded as two hex digits)
+#    Link Status: 1 = Link up, 2 = Link down, 3 = Link in test state
+# Downlink Speed: Estimate of WAN backhaul link current downlink speed in kbps;
+#	1..4294967295; 0 = unknown
+# Uplink Speed: Estimate of WAN backhaul link current uplink speed in kbps
+#	1..4294967295; 0 = unknown
+# Downlink Load: Current load of downlink WAN connection (scaled to 255 = 100%)
+# Uplink Load: Current load of uplink WAN connection (scaled to 255 = 100%)
+# Load Measurement Duration: Duration for measuring downlink/uplink load in
+# tenths of a second (1..65535); 0 if load cannot be determined
+#hs20_wan_metrics=01:8000:1000:80:240:3000
+
+# Operating Class Indication
+# List of operating classes the BSSes in this ESS use. The Global operating
+# classes in Table E-4 of IEEE Std 802.11-2012 Annex E define the values that
+# can be used in this.
+# format: hexdump of operating class octets
+# for example, operating classes 81 (2.4 GHz channels 1-13) and 115 (5 GHz
+# channels 36-48):
+#hs20_operating_class=5173
+
+##### Multiple BSSID support ##################################################
+#
+# Above configuration is using the default interface (wlan#, or multi-SSID VLAN
+# interfaces). Other BSSIDs can be added by using separator 'bss' with
+# default interface name to be allocated for the data packets of the new BSS.
+#
+# hostapd will generate BSSID mask based on the BSSIDs that are
+# configured. hostapd will verify that dev_addr & MASK == dev_addr. If this is
+# not the case, the MAC address of the radio must be changed before starting
+# hostapd (ifconfig wlan0 hw ether <MAC addr>). If a BSSID is configured for
+# every secondary BSS, this limitation is not applied at hostapd and other
+# masks may be used if the driver supports them (e.g., swap the locally
+# administered bit)
+#
+# BSSIDs are assigned in order to each BSS, unless an explicit BSSID is
+# specified using the 'bssid' parameter.
+# If an explicit BSSID is specified, it must be chosen such that it:
+# - results in a valid MASK that covers it and the dev_addr
+# - is not the same as the MAC address of the radio
+# - is not the same as any other explicitly specified BSSID
+#
+# Please note that hostapd uses some of the values configured for the first BSS
+# as the defaults for the following BSSes. However, it is recommended that all
+# BSSes include explicit configuration of all relevant configuration items.
+#
+#bss=wlan0_0
+#ssid=test2
+# most of the above items can be used here (apart from radio interface specific
+# items, like channel)
+
+#bss=wlan0_1
+#bssid=00:13:10:95:fe:0b
+# ...
diff --git a/hostap/hostapd/hostapd.deny b/hostap/hostapd/hostapd.deny
new file mode 100644
index 0000000..1616678
--- /dev/null
+++ b/hostap/hostapd/hostapd.deny
@@ -0,0 +1,5 @@
+# List of MAC addresses that are not allowed to authenticate (IEEE 802.11)
+# with the AP.
+00:20:30:40:50:60
+00:ab:cd:ef:12:34
+00:00:30:40:50:60
diff --git a/hostap/hostapd/hostapd.eap_user b/hostap/hostapd/hostapd.eap_user
new file mode 100644
index 0000000..12a2c61
--- /dev/null
+++ b/hostap/hostapd/hostapd.eap_user
@@ -0,0 +1,97 @@
+# hostapd user database for integrated EAP server
+
+# Each line must contain an identity, EAP method(s), and an optional password
+# separated with whitespace (space or tab). The identity and password must be
+# double quoted ("user"). Password can alternatively be stored as
+# NtPasswordHash (16-byte MD4 hash of the unicode presentation of the password
+# in unicode) if it is used for MSCHAP or MSCHAPv2 authentication. This means
+# that the plaintext password does not need to be included in the user file.
+# Password hash is stored as hash:<16-octets of hex data> without quotation
+# marks.
+
+# [2] flag in the end of the line can be used to mark users for tunneled phase
+# 2 authentication (e.g., within EAP-PEAP). In these cases, an anonymous
+# identity can be used in the unencrypted phase 1 and the real user identity
+# is transmitted only within the encrypted tunnel in phase 2. If non-anonymous
+# access is needed, two user entries is needed, one for phase 1 and another
+# with the same username for phase 2.
+#
+# EAP-TLS, EAP-PEAP, EAP-TTLS, EAP-FAST, EAP-SIM, and EAP-AKA do not use
+# password option.
+# EAP-MD5, EAP-MSCHAPV2, EAP-GTC, EAP-PAX, EAP-PSK, and EAP-SAKE require a
+# password.
+# EAP-PEAP, EAP-TTLS, and EAP-FAST require Phase 2 configuration.
+#
+# * can be used as a wildcard to match any user identity. The main purposes for
+# this are to set anonymous phase 1 identity for EAP-PEAP and EAP-TTLS and to
+# avoid having to configure every certificate for EAP-TLS authentication. The
+# first matching entry is selected, so * should be used as the last phase 1
+# user entry.
+#
+# "prefix"* can be used to match the given prefix and anything after this. The
+# main purpose for this is to be able to avoid EAP method negotiation when the
+# method is using known prefix in identities (e.g., EAP-SIM and EAP-AKA). This
+# is only allowed for phase 1 identities.
+#
+# Multiple methods can be configured to make the authenticator try them one by
+# one until the peer accepts one. The method names are separated with a
+# comma (,).
+#
+# [ver=0] and [ver=1] flags after EAP type PEAP can be used to force PEAP
+# version based on the Phase 1 identity. Without this flag, the EAP
+# authenticator advertises the highest supported version and select the version
+# based on the first PEAP packet from the supplicant.
+#
+# EAP-TTLS supports both EAP and non-EAP authentication inside the tunnel.
+# Tunneled EAP methods are configured with standard EAP method name and [2]
+# flag. Non-EAP methods can be enabled by following method names: TTLS-PAP,
+# TTLS-CHAP, TTLS-MSCHAP, TTLS-MSCHAPV2. TTLS-PAP and TTLS-CHAP require a
+# plaintext password while TTLS-MSCHAP and TTLS-MSCHAPV2 can use NT password
+# hash.
+
+# Phase 1 users
+"user"		MD5	"password"
+"test user"	MD5	"secret"
+"example user"	TLS
+"DOMAIN\user"	MSCHAPV2	"password"
+"gtc user"	GTC	"password"
+"pax user"	PAX	"unknown"
+"pax.user@example.com"	PAX	0123456789abcdef0123456789abcdef
+"psk user"	PSK	"unknown"
+"psk.user@example.com"	PSK	0123456789abcdef0123456789abcdef
+"sake.user@example.com"	SAKE	0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+"ttls"		TTLS
+"not anonymous"	PEAP
+# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes
+"0"*		AKA,TTLS,TLS,PEAP,SIM
+"1"*		SIM,TTLS,TLS,PEAP,AKA
+"2"*		AKA,TTLS,TLS,PEAP,SIM
+"3"*		SIM,TTLS,TLS,PEAP,AKA
+"4"*		AKA,TTLS,TLS,PEAP,SIM
+"5"*		SIM,TTLS,TLS,PEAP,AKA
+"6"*		AKA'
+"7"*		AKA'
+"8"*		AKA'
+
+# Wildcard for all other identities
+*		PEAP,TTLS,TLS,SIM,AKA
+
+# Phase 2 (tunnelled within EAP-PEAP or EAP-TTLS) users
+"t-md5"		MD5	"password"	[2]
+"DOMAIN\t-mschapv2"	MSCHAPV2	"password"	[2]
+"t-gtc"		GTC	"password"	[2]
+"not anonymous"	MSCHAPV2	"password"	[2]
+"user"		MD5,GTC,MSCHAPV2	"password"	[2]
+"test user"	MSCHAPV2	hash:000102030405060708090a0b0c0d0e0f	[2]
+"ttls-user"	TTLS-PAP,TTLS-CHAP,TTLS-MSCHAP,TTLS-MSCHAPV2	"password"	[2]
+
+# Default to EAP-SIM and EAP-AKA based on fixed identity prefixes in phase 2
+"0"*		AKA	[2]
+"1"*		SIM	[2]
+"2"*		AKA	[2]
+"3"*		SIM	[2]
+"4"*		AKA	[2]
+"5"*		SIM	[2]
+"6"*		AKA'	[2]
+"7"*		AKA'	[2]
+"8"*		AKA'	[2]
diff --git a/hostap/hostapd/hostapd.eap_user_sqlite b/hostap/hostapd/hostapd.eap_user_sqlite
new file mode 100644
index 0000000..f688327
--- /dev/null
+++ b/hostap/hostapd/hostapd.eap_user_sqlite
@@ -0,0 +1,17 @@
+CREATE TABLE users(
+	identity TEXT PRIMARY KEY,
+	methods TEXT,
+	password TEXT,
+	phase2 INTEGER
+);
+
+CREATE TABLE wildcards(
+	identity TEXT PRIMARY KEY,
+	methods TEXT
+);
+
+INSERT INTO users(identity,methods,password,phase2) VALUES ('user','TTLS-MSCHAPV2','password',1);
+INSERT INTO users(identity,methods,password,phase2) VALUES ('DOMAIN\mschapv2 user','TTLS-MSCHAPV2','password',1);
+
+INSERT INTO wildcards(identity,methods) VALUES ('','TTLS,TLS');
+INSERT INTO wildcards(identity,methods) VALUES ('0','AKA');
diff --git a/hostap/hostapd/hostapd.radius_clients b/hostap/hostapd/hostapd.radius_clients
new file mode 100644
index 0000000..3980427
--- /dev/null
+++ b/hostap/hostapd/hostapd.radius_clients
@@ -0,0 +1,4 @@
+# RADIUS client configuration for the RADIUS server
+10.1.2.3	secret passphrase
+192.168.1.0/24	another very secret passphrase
+0.0.0.0/0	radius
diff --git a/hostap/hostapd/hostapd.sim_db b/hostap/hostapd/hostapd.sim_db
new file mode 100644
index 0000000..01c593d
--- /dev/null
+++ b/hostap/hostapd/hostapd.sim_db
@@ -0,0 +1,9 @@
+# Example GSM authentication triplet file for EAP-SIM authenticator
+# IMSI:Kc:SRES:RAND
+# IMSI: ASCII string (numbers)
+# Kc: hex, 8 octets
+# SRES: hex, 4 octets
+# RAND: hex, 16 octets
+234567898765432:A0A1A2A3A4A5A6A7:D1D2D3D4:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+234567898765432:B0B1B2B3B4B5B6B7:E1E2E3E4:BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB
+234567898765432:C0C1C2C3C4C5C6C7:F1F2F3F4:CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC
diff --git a/hostap/hostapd/hostapd.vlan b/hostap/hostapd/hostapd.vlan
new file mode 100644
index 0000000..98254fa
--- /dev/null
+++ b/hostap/hostapd/hostapd.vlan
@@ -0,0 +1,9 @@
+# VLAN ID to network interface mapping
+1	vlan1
+2	vlan2
+3	vlan3
+100	guest
+# Optional wildcard entry matching all VLAN IDs. The first # in the interface
+# name will be replaced with the VLAN ID. The network interfaces are created
+# (and removed) dynamically based on the use.
+*	vlan#
diff --git a/hostap/hostapd/hostapd.wpa_psk b/hostap/hostapd/hostapd.wpa_psk
new file mode 100644
index 0000000..0a9499a
--- /dev/null
+++ b/hostap/hostapd/hostapd.wpa_psk
@@ -0,0 +1,9 @@
+# List of WPA PSKs. Each line, except for empty lines and lines starting
+# with #, must contain a MAC address and PSK separated with a space.
+# Special MAC address 00:00:00:00:00:00 can be used to configure PSKs that
+# anyone can use. PSK can be configured as an ASCII passphrase of 8..63
+# characters or as a 256-bit hex PSK (64 hex digits).
+00:00:00:00:00:00 secret passphrase
+00:11:22:33:44:55 another passphrase
+00:22:33:44:55:66 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef
+00:00:00:00:00:00 another passphrase for all STAs
diff --git a/hostap/hostapd/hostapd_cli.1 b/hostap/hostapd/hostapd_cli.1
new file mode 100644
index 0000000..218ea15
--- /dev/null
+++ b/hostap/hostapd/hostapd_cli.1
@@ -0,0 +1,89 @@
+.TH HOSTAPD_CLI 1 "April  7, 2005" hostapd_cli "hostapd command-line interface"
+.SH NAME
+hostapd_cli \- hostapd command-line interface
+.SH SYNOPSIS
+.B hostapd_cli
+[\-p<path>] [\-i<ifname>] [\-a<path>] [\-hvB] [command..]
+.SH DESCRIPTION
+This manual page documents briefly the
+.B hostapd_cli
+utility.
+.PP
+.B hostapd_cli
+is a command-line interface for the
+.B hostapd
+daemon.
+
+.B hostapd
+is a user space daemon for access point and authentication servers.
+It implements IEEE 802.11 access point management, IEEE 802.1X/WPA/WPA2/EAP Authenticators and RADIUS authentication server.
+For more information about
+.B hostapd
+refer to the
+.BR hostapd (8)
+man page.
+.SH OPTIONS
+A summary of options is included below.
+For a complete description, run
+.BR hostapd_cli
+from the command line.
+.TP
+.B \-p<path>
+Path to find control sockets.
+
+Default: /var/run/hostapd
+.TP
+.B \-i<ifname>
+Interface to listen on.
+
+Default: first interface found in socket path.
+.TP
+.B \-a<path>
+Run in daemon mode executing the action file based on events from hostapd.
+.TP
+.B \-B
+Run a daemon in the background.
+.TP
+.B \-h
+Show usage.
+.TP
+.B \-v
+Show hostapd_cli version.
+.SH COMMANDS
+A summary of commands is included below.
+For a complete description, run
+.BR hostapd_cli
+from the command line.
+.TP
+.B mib
+Get MIB variables (dot1x, dot11, radius).
+.TP
+.B sta <addr>
+Get MIB variables for one station.
+.TP
+.B all_sta
+Get MIB variables for all stations.
+.TP
+.B help
+Get usage help.
+.TP
+.B interface [ifname] 
+Show interfaces/select interface.
+.TP
+.B level <debug level>
+Change debug level.
+.TP
+.B license
+Show full
+.B hostapd_cli
+license.
+.TP
+.B quit
+Exit hostapd_cli.
+.SH SEE ALSO
+.BR hostapd (8).
+.SH AUTHOR
+hostapd_cli was written by Jouni Malinen <j@w1.fi>. 
+.PP
+This manual page was written by Faidon Liambotis <faidon@cube.gr>,
+for the Debian project (but may be used by others).
diff --git a/hostap/hostapd/hostapd_cli.c b/hostap/hostapd/hostapd_cli.c
new file mode 100644
index 0000000..e8e1bb2
--- /dev/null
+++ b/hostap/hostapd/hostapd_cli.c
@@ -0,0 +1,1134 @@
+/*
+ * hostapd - command line interface for hostapd daemon
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <dirent.h>
+
+#include "common/wpa_ctrl.h"
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/edit.h"
+#include "common/version.h"
+
+
+static const char *hostapd_cli_version =
+"hostapd_cli v" VERSION_STR "\n"
+"Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi> and contributors";
+
+
+static const char *hostapd_cli_license =
+"This software may be distributed under the terms of the BSD license.\n"
+"See README for more details.\n";
+
+static const char *hostapd_cli_full_license =
+"This software may be distributed under the terms of the BSD license.\n"
+"\n"
+"Redistribution and use in source and binary forms, with or without\n"
+"modification, are permitted provided that the following conditions are\n"
+"met:\n"
+"\n"
+"1. Redistributions of source code must retain the above copyright\n"
+"   notice, this list of conditions and the following disclaimer.\n"
+"\n"
+"2. Redistributions in binary form must reproduce the above copyright\n"
+"   notice, this list of conditions and the following disclaimer in the\n"
+"   documentation and/or other materials provided with the distribution.\n"
+"\n"
+"3. Neither the name(s) of the above-listed copyright holder(s) nor the\n"
+"   names of its contributors may be used to endorse or promote products\n"
+"   derived from this software without specific prior written permission.\n"
+"\n"
+"THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS\n"
+"\"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT\n"
+"LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR\n"
+"A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT\n"
+"OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n"
+"SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT\n"
+"LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\n"
+"DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\n"
+"THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n"
+"(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n"
+"OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n"
+"\n";
+
+static const char *commands_help =
+"Commands:\n"
+"   mib                  get MIB variables (dot1x, dot11, radius)\n"
+"   sta <addr>           get MIB variables for one station\n"
+"   all_sta              get MIB variables for all stations\n"
+"   new_sta <addr>       add a new station\n"
+"   deauthenticate <addr>  deauthenticate a station\n"
+"   disassociate <addr>  disassociate a station\n"
+#ifdef CONFIG_IEEE80211W
+"   sa_query <addr>      send SA Query to a station\n"
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WPS
+"   wps_pin <uuid> <pin> [timeout] [addr]  add WPS Enrollee PIN\n"
+"   wps_check_pin <PIN>  verify PIN checksum\n"
+"   wps_pbc              indicate button pushed to initiate PBC\n"
+"   wps_cancel           cancel the pending WPS operation\n"
+#ifdef CONFIG_WPS_NFC
+"   wps_nfc_tag_read <hexdump>  report read NFC tag with WPS data\n"
+"   wps_nfc_config_token <WPS/NDEF>  build NFC configuration token\n"
+"   wps_nfc_token <WPS/NDEF/enable/disable>  manager NFC password token\n"
+#endif /* CONFIG_WPS_NFC */
+"   wps_ap_pin <cmd> [params..]  enable/disable AP PIN\n"
+"   wps_config <SSID> <auth> <encr> <key>  configure AP\n"
+#endif /* CONFIG_WPS */
+"   get_config           show current configuration\n"
+"   help                 show this usage help\n"
+"   interface [ifname]   show interfaces/select interface\n"
+"   level <debug level>  change debug level\n"
+"   license              show full hostapd_cli license\n"
+"   quit                 exit hostapd_cli\n";
+
+static struct wpa_ctrl *ctrl_conn;
+static int hostapd_cli_quit = 0;
+static int hostapd_cli_attached = 0;
+static const char *ctrl_iface_dir = "/var/run/hostapd";
+static char *ctrl_ifname = NULL;
+static const char *pid_file = NULL;
+static const char *action_file = NULL;
+static int ping_interval = 5;
+static int interactive = 0;
+
+
+static void usage(void)
+{
+	fprintf(stderr, "%s\n", hostapd_cli_version);
+	fprintf(stderr,
+		"\n"
+		"usage: hostapd_cli [-p<path>] [-i<ifname>] [-hvB] "
+		"[-a<path>] \\\n"
+		"                   [-G<ping interval>] [command..]\n"
+		"\n"
+		"Options:\n"
+		"   -h           help (show this usage text)\n"
+		"   -v           shown version information\n"
+		"   -p<path>     path to find control sockets (default: "
+		"/var/run/hostapd)\n"
+		"   -a<file>     run in daemon mode executing the action file "
+		"based on events\n"
+		"                from hostapd\n"
+		"   -B           run a daemon in the background\n"
+		"   -i<ifname>   Interface to listen on (default: first "
+		"interface found in the\n"
+		"                socket path)\n\n"
+		"%s",
+		commands_help);
+}
+
+
+static struct wpa_ctrl * hostapd_cli_open_connection(const char *ifname)
+{
+	char *cfile;
+	int flen;
+
+	if (ifname == NULL)
+		return NULL;
+
+	flen = strlen(ctrl_iface_dir) + strlen(ifname) + 2;
+	cfile = malloc(flen);
+	if (cfile == NULL)
+		return NULL;
+	snprintf(cfile, flen, "%s/%s", ctrl_iface_dir, ifname);
+
+	ctrl_conn = wpa_ctrl_open(cfile);
+	free(cfile);
+	return ctrl_conn;
+}
+
+
+static void hostapd_cli_close_connection(void)
+{
+	if (ctrl_conn == NULL)
+		return;
+
+	if (hostapd_cli_attached) {
+		wpa_ctrl_detach(ctrl_conn);
+		hostapd_cli_attached = 0;
+	}
+	wpa_ctrl_close(ctrl_conn);
+	ctrl_conn = NULL;
+}
+
+
+static void hostapd_cli_msg_cb(char *msg, size_t len)
+{
+	printf("%s\n", msg);
+}
+
+
+static int _wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd, int print)
+{
+	char buf[4096];
+	size_t len;
+	int ret;
+
+	if (ctrl_conn == NULL) {
+		printf("Not connected to hostapd - command dropped.\n");
+		return -1;
+	}
+	len = sizeof(buf) - 1;
+	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+			       hostapd_cli_msg_cb);
+	if (ret == -2) {
+		printf("'%s' command timed out.\n", cmd);
+		return -2;
+	} else if (ret < 0) {
+		printf("'%s' command failed.\n", cmd);
+		return -1;
+	}
+	if (print) {
+		buf[len] = '\0';
+		printf("%s", buf);
+	}
+	return 0;
+}
+
+
+static inline int wpa_ctrl_command(struct wpa_ctrl *ctrl, char *cmd)
+{
+	return _wpa_ctrl_command(ctrl, cmd, 1);
+}
+
+
+static int hostapd_cli_cmd_ping(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "PING");
+}
+
+
+static int hostapd_cli_cmd_relog(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "RELOG");
+}
+
+
+static int hostapd_cli_cmd_mib(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "MIB");
+}
+
+
+static int hostapd_cli_exec(const char *program, const char *arg1,
+			    const char *arg2)
+{
+	char *cmd;
+	size_t len;
+	int res;
+	int ret = 0;
+
+	len = os_strlen(program) + os_strlen(arg1) + os_strlen(arg2) + 3;
+	cmd = os_malloc(len);
+	if (cmd == NULL)
+		return -1;
+	res = os_snprintf(cmd, len, "%s %s %s", program, arg1, arg2);
+	if (res < 0 || (size_t) res >= len) {
+		os_free(cmd);
+		return -1;
+	}
+	cmd[len - 1] = '\0';
+#ifndef _WIN32_WCE
+	if (system(cmd) < 0)
+		ret = -1;
+#endif /* _WIN32_WCE */
+	os_free(cmd);
+
+	return ret;
+}
+
+
+static void hostapd_cli_action_process(char *msg, size_t len)
+{
+	const char *pos;
+
+	pos = msg;
+	if (*pos == '<') {
+		pos = os_strchr(pos, '>');
+		if (pos)
+			pos++;
+		else
+			pos = msg;
+	}
+
+	hostapd_cli_exec(action_file, ctrl_ifname, pos);
+}
+
+
+static int hostapd_cli_cmd_sta(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char buf[64];
+	if (argc != 1) {
+		printf("Invalid 'sta' command - exactly one argument, STA "
+		       "address, is required.\n");
+		return -1;
+	}
+	snprintf(buf, sizeof(buf), "STA %s", argv[0]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_new_sta(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	char buf[64];
+	if (argc != 1) {
+		printf("Invalid 'new_sta' command - exactly one argument, STA "
+		       "address, is required.\n");
+		return -1;
+	}
+	snprintf(buf, sizeof(buf), "NEW_STA %s", argv[0]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_deauthenticate(struct wpa_ctrl *ctrl, int argc,
+					  char *argv[])
+{
+	char buf[64];
+	if (argc < 1) {
+		printf("Invalid 'deauthenticate' command - exactly one "
+		       "argument, STA address, is required.\n");
+		return -1;
+	}
+	if (argc > 1)
+		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s %s",
+			    argv[0], argv[1]);
+	else
+		os_snprintf(buf, sizeof(buf), "DEAUTHENTICATE %s", argv[0]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_disassociate(struct wpa_ctrl *ctrl, int argc,
+					char *argv[])
+{
+	char buf[64];
+	if (argc < 1) {
+		printf("Invalid 'disassociate' command - exactly one "
+		       "argument, STA address, is required.\n");
+		return -1;
+	}
+	if (argc > 1)
+		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s %s",
+			    argv[0], argv[1]);
+	else
+		os_snprintf(buf, sizeof(buf), "DISASSOCIATE %s", argv[0]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+#ifdef CONFIG_IEEE80211W
+static int hostapd_cli_cmd_sa_query(struct wpa_ctrl *ctrl, int argc,
+				    char *argv[])
+{
+	char buf[64];
+	if (argc != 1) {
+		printf("Invalid 'sa_query' command - exactly one argument, "
+		       "STA address, is required.\n");
+		return -1;
+	}
+	snprintf(buf, sizeof(buf), "SA_QUERY %s", argv[0]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+#endif /* CONFIG_IEEE80211W */
+
+
+#ifdef CONFIG_WPS
+static int hostapd_cli_cmd_wps_pin(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	char buf[256];
+	if (argc < 2) {
+		printf("Invalid 'wps_pin' command - at least two arguments, "
+		       "UUID and PIN, are required.\n");
+		return -1;
+	}
+	if (argc > 3)
+		snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s %s",
+			 argv[0], argv[1], argv[2], argv[3]);
+	else if (argc > 2)
+		snprintf(buf, sizeof(buf), "WPS_PIN %s %s %s",
+			 argv[0], argv[1], argv[2]);
+	else
+		snprintf(buf, sizeof(buf), "WPS_PIN %s %s", argv[0], argv[1]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_wps_check_pin(struct wpa_ctrl *ctrl, int argc,
+					 char *argv[])
+{
+	char cmd[256];
+	int res;
+
+	if (argc != 1 && argc != 2) {
+		printf("Invalid WPS_CHECK_PIN command: needs one argument:\n"
+		       "- PIN to be verified\n");
+		return -1;
+	}
+
+	if (argc == 2)
+		res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s %s",
+				  argv[0], argv[1]);
+	else
+		res = os_snprintf(cmd, sizeof(cmd), "WPS_CHECK_PIN %s",
+				  argv[0]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long WPS_CHECK_PIN command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_wps_pbc(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "WPS_PBC");
+}
+
+
+static int hostapd_cli_cmd_wps_cancel(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "WPS_CANCEL");
+}
+
+
+#ifdef CONFIG_WPS_NFC
+static int hostapd_cli_cmd_wps_nfc_tag_read(struct wpa_ctrl *ctrl, int argc,
+					    char *argv[])
+{
+	int ret;
+	char *buf;
+	size_t buflen;
+
+	if (argc != 1) {
+		printf("Invalid 'wps_nfc_tag_read' command - one argument "
+		       "is required.\n");
+		return -1;
+	}
+
+	buflen = 18 + os_strlen(argv[0]);
+	buf = os_malloc(buflen);
+	if (buf == NULL)
+		return -1;
+	os_snprintf(buf, buflen, "WPS_NFC_TAG_READ %s", argv[0]);
+
+	ret = wpa_ctrl_command(ctrl, buf);
+	os_free(buf);
+
+	return ret;
+}
+
+
+static int hostapd_cli_cmd_wps_nfc_config_token(struct wpa_ctrl *ctrl,
+						int argc, char *argv[])
+{
+	char cmd[64];
+	int res;
+
+	if (argc != 1) {
+		printf("Invalid 'wps_nfc_config_token' command - one argument "
+		       "is required.\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_CONFIG_TOKEN %s",
+			  argv[0]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long WPS_NFC_CONFIG_TOKEN command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_wps_nfc_token(struct wpa_ctrl *ctrl,
+					 int argc, char *argv[])
+{
+	char cmd[64];
+	int res;
+
+	if (argc != 1) {
+		printf("Invalid 'wps_nfc_token' command - one argument is "
+		       "required.\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "WPS_NFC_TOKEN %s", argv[0]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long WPS_NFC_TOKEN command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+#endif /* CONFIG_WPS_NFC */
+
+
+static int hostapd_cli_cmd_wps_ap_pin(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	char buf[64];
+	if (argc < 1) {
+		printf("Invalid 'wps_ap_pin' command - at least one argument "
+		       "is required.\n");
+		return -1;
+	}
+	if (argc > 2)
+		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s %s",
+			 argv[0], argv[1], argv[2]);
+	else if (argc > 1)
+		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s %s",
+			 argv[0], argv[1]);
+	else
+		snprintf(buf, sizeof(buf), "WPS_AP_PIN %s", argv[0]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_wps_config(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	char buf[256];
+	char ssid_hex[2 * 32 + 1];
+	char key_hex[2 * 64 + 1];
+	int i;
+
+	if (argc < 1) {
+		printf("Invalid 'wps_config' command - at least two arguments "
+		       "are required.\n");
+		return -1;
+	}
+
+	ssid_hex[0] = '\0';
+	for (i = 0; i < 32; i++) {
+		if (argv[0][i] == '\0')
+			break;
+		os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
+	}
+
+	key_hex[0] = '\0';
+	if (argc > 3) {
+		for (i = 0; i < 64; i++) {
+			if (argv[3][i] == '\0')
+				break;
+			os_snprintf(&key_hex[i * 2], 3, "%02x",
+				    argv[3][i]);
+		}
+	}
+
+	if (argc > 3)
+		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s %s",
+			 ssid_hex, argv[1], argv[2], key_hex);
+	else if (argc > 2)
+		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s %s",
+			 ssid_hex, argv[1], argv[2]);
+	else
+		snprintf(buf, sizeof(buf), "WPS_CONFIG %s %s",
+			 ssid_hex, argv[1]);
+	return wpa_ctrl_command(ctrl, buf);
+}
+#endif /* CONFIG_WPS */
+
+
+static int hostapd_cli_cmd_disassoc_imminent(struct wpa_ctrl *ctrl, int argc,
+					     char *argv[])
+{
+	char buf[300];
+	int res;
+
+	if (argc < 2) {
+		printf("Invalid 'disassoc_imminent' command - two arguments "
+		       "(STA addr and Disassociation Timer) are needed\n");
+		return -1;
+	}
+
+	res = os_snprintf(buf, sizeof(buf), "DISASSOC_IMMINENT %s %s",
+			  argv[0], argv[1]);
+	if (res < 0 || res >= (int) sizeof(buf))
+		return -1;
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_ess_disassoc(struct wpa_ctrl *ctrl, int argc,
+					char *argv[])
+{
+	char buf[300];
+	int res;
+
+	if (argc < 2) {
+		printf("Invalid 'ess_disassoc' command - two arguments (STA "
+		       "addr and URL) are needed\n");
+		return -1;
+	}
+
+	res = os_snprintf(buf, sizeof(buf), "ESS_DISASSOC %s %s",
+			  argv[0], argv[1]);
+	if (res < 0 || res >= (int) sizeof(buf))
+		return -1;
+	return wpa_ctrl_command(ctrl, buf);
+}
+
+
+static int hostapd_cli_cmd_get_config(struct wpa_ctrl *ctrl, int argc,
+				      char *argv[])
+{
+	return wpa_ctrl_command(ctrl, "GET_CONFIG");
+}
+
+
+static int wpa_ctrl_command_sta(struct wpa_ctrl *ctrl, char *cmd,
+				char *addr, size_t addr_len)
+{
+	char buf[4096], *pos;
+	size_t len;
+	int ret;
+
+	if (ctrl_conn == NULL) {
+		printf("Not connected to hostapd - command dropped.\n");
+		return -1;
+	}
+	len = sizeof(buf) - 1;
+	ret = wpa_ctrl_request(ctrl, cmd, strlen(cmd), buf, &len,
+			       hostapd_cli_msg_cb);
+	if (ret == -2) {
+		printf("'%s' command timed out.\n", cmd);
+		return -2;
+	} else if (ret < 0) {
+		printf("'%s' command failed.\n", cmd);
+		return -1;
+	}
+
+	buf[len] = '\0';
+	if (memcmp(buf, "FAIL", 4) == 0)
+		return -1;
+	printf("%s", buf);
+
+	pos = buf;
+	while (*pos != '\0' && *pos != '\n')
+		pos++;
+	*pos = '\0';
+	os_strlcpy(addr, buf, addr_len);
+	return 0;
+}
+
+
+static int hostapd_cli_cmd_all_sta(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	char addr[32], cmd[64];
+
+	if (wpa_ctrl_command_sta(ctrl, "STA-FIRST", addr, sizeof(addr)))
+		return 0;
+	do {
+		snprintf(cmd, sizeof(cmd), "STA-NEXT %s", addr);
+	} while (wpa_ctrl_command_sta(ctrl, cmd, addr, sizeof(addr)) == 0);
+
+	return -1;
+}
+
+
+static int hostapd_cli_cmd_help(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	printf("%s", commands_help);
+	return 0;
+}
+
+
+static int hostapd_cli_cmd_license(struct wpa_ctrl *ctrl, int argc,
+				   char *argv[])
+{
+	printf("%s\n\n%s\n", hostapd_cli_version, hostapd_cli_full_license);
+	return 0;
+}
+
+
+static int hostapd_cli_cmd_quit(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	hostapd_cli_quit = 1;
+	if (interactive)
+		eloop_terminate();
+	return 0;
+}
+
+
+static int hostapd_cli_cmd_level(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256];
+	if (argc != 1) {
+		printf("Invalid LEVEL command: needs one argument (debug "
+		       "level)\n");
+		return 0;
+	}
+	snprintf(cmd, sizeof(cmd), "LEVEL %s", argv[0]);
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static void hostapd_cli_list_interfaces(struct wpa_ctrl *ctrl)
+{
+	struct dirent *dent;
+	DIR *dir;
+
+	dir = opendir(ctrl_iface_dir);
+	if (dir == NULL) {
+		printf("Control interface directory '%s' could not be "
+		       "openned.\n", ctrl_iface_dir);
+		return;
+	}
+
+	printf("Available interfaces:\n");
+	while ((dent = readdir(dir))) {
+		if (strcmp(dent->d_name, ".") == 0 ||
+		    strcmp(dent->d_name, "..") == 0)
+			continue;
+		printf("%s\n", dent->d_name);
+	}
+	closedir(dir);
+}
+
+
+static int hostapd_cli_cmd_interface(struct wpa_ctrl *ctrl, int argc,
+				     char *argv[])
+{
+	if (argc < 1) {
+		hostapd_cli_list_interfaces(ctrl);
+		return 0;
+	}
+
+	hostapd_cli_close_connection();
+	free(ctrl_ifname);
+	ctrl_ifname = strdup(argv[0]);
+
+	if (hostapd_cli_open_connection(ctrl_ifname)) {
+		printf("Connected to interface '%s.\n", ctrl_ifname);
+		if (wpa_ctrl_attach(ctrl_conn) == 0) {
+			hostapd_cli_attached = 1;
+		} else {
+			printf("Warning: Failed to attach to "
+			       "hostapd.\n");
+		}
+	} else {
+		printf("Could not connect to interface '%s' - re-trying\n",
+			ctrl_ifname);
+	}
+	return 0;
+}
+
+
+static int hostapd_cli_cmd_set(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256];
+	int res;
+
+	if (argc != 2) {
+		printf("Invalid SET command: needs two arguments (variable "
+		       "name and value)\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "SET %s %s", argv[0], argv[1]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long SET command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+static int hostapd_cli_cmd_get(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	char cmd[256];
+	int res;
+
+	if (argc != 1) {
+		printf("Invalid GET command: needs one argument (variable "
+		       "name)\n");
+		return -1;
+	}
+
+	res = os_snprintf(cmd, sizeof(cmd), "GET %s", argv[0]);
+	if (res < 0 || (size_t) res >= sizeof(cmd) - 1) {
+		printf("Too long GET command.\n");
+		return -1;
+	}
+	return wpa_ctrl_command(ctrl, cmd);
+}
+
+
+struct hostapd_cli_cmd {
+	const char *cmd;
+	int (*handler)(struct wpa_ctrl *ctrl, int argc, char *argv[]);
+};
+
+static struct hostapd_cli_cmd hostapd_cli_commands[] = {
+	{ "ping", hostapd_cli_cmd_ping },
+	{ "mib", hostapd_cli_cmd_mib },
+	{ "relog", hostapd_cli_cmd_relog },
+	{ "sta", hostapd_cli_cmd_sta },
+	{ "all_sta", hostapd_cli_cmd_all_sta },
+	{ "new_sta", hostapd_cli_cmd_new_sta },
+	{ "deauthenticate", hostapd_cli_cmd_deauthenticate },
+	{ "disassociate", hostapd_cli_cmd_disassociate },
+#ifdef CONFIG_IEEE80211W
+	{ "sa_query", hostapd_cli_cmd_sa_query },
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WPS
+	{ "wps_pin", hostapd_cli_cmd_wps_pin },
+	{ "wps_check_pin", hostapd_cli_cmd_wps_check_pin },
+	{ "wps_pbc", hostapd_cli_cmd_wps_pbc },
+	{ "wps_cancel", hostapd_cli_cmd_wps_cancel },
+#ifdef CONFIG_WPS_NFC
+	{ "wps_nfc_tag_read", hostapd_cli_cmd_wps_nfc_tag_read },
+	{ "wps_nfc_config_token", hostapd_cli_cmd_wps_nfc_config_token },
+	{ "wps_nfc_token", hostapd_cli_cmd_wps_nfc_token },
+#endif /* CONFIG_WPS_NFC */
+	{ "wps_ap_pin", hostapd_cli_cmd_wps_ap_pin },
+	{ "wps_config", hostapd_cli_cmd_wps_config },
+#endif /* CONFIG_WPS */
+	{ "disassoc_imminent", hostapd_cli_cmd_disassoc_imminent },
+	{ "ess_disassoc", hostapd_cli_cmd_ess_disassoc },
+	{ "get_config", hostapd_cli_cmd_get_config },
+	{ "help", hostapd_cli_cmd_help },
+	{ "interface", hostapd_cli_cmd_interface },
+	{ "level", hostapd_cli_cmd_level },
+	{ "license", hostapd_cli_cmd_license },
+	{ "quit", hostapd_cli_cmd_quit },
+	{ "set", hostapd_cli_cmd_set },
+	{ "get", hostapd_cli_cmd_get },
+	{ NULL, NULL }
+};
+
+
+static void wpa_request(struct wpa_ctrl *ctrl, int argc, char *argv[])
+{
+	struct hostapd_cli_cmd *cmd, *match = NULL;
+	int count;
+
+	count = 0;
+	cmd = hostapd_cli_commands;
+	while (cmd->cmd) {
+		if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) == 0) {
+			match = cmd;
+			if (os_strcasecmp(cmd->cmd, argv[0]) == 0) {
+				/* we have an exact match */
+				count = 1;
+				break;
+			}
+			count++;
+		}
+		cmd++;
+	}
+
+	if (count > 1) {
+		printf("Ambiguous command '%s'; possible commands:", argv[0]);
+		cmd = hostapd_cli_commands;
+		while (cmd->cmd) {
+			if (strncasecmp(cmd->cmd, argv[0], strlen(argv[0])) ==
+			    0) {
+				printf(" %s", cmd->cmd);
+			}
+			cmd++;
+		}
+		printf("\n");
+	} else if (count == 0) {
+		printf("Unknown command '%s'\n", argv[0]);
+	} else {
+		match->handler(ctrl, argc - 1, &argv[1]);
+	}
+}
+
+
+static void hostapd_cli_recv_pending(struct wpa_ctrl *ctrl, int in_read,
+				     int action_monitor)
+{
+	int first = 1;
+	if (ctrl_conn == NULL)
+		return;
+	while (wpa_ctrl_pending(ctrl)) {
+		char buf[256];
+		size_t len = sizeof(buf) - 1;
+		if (wpa_ctrl_recv(ctrl, buf, &len) == 0) {
+			buf[len] = '\0';
+			if (action_monitor)
+				hostapd_cli_action_process(buf, len);
+			else {
+				if (in_read && first)
+					printf("\n");
+				first = 0;
+				printf("%s\n", buf);
+			}
+		} else {
+			printf("Could not read pending message.\n");
+			break;
+		}
+	}
+}
+
+
+#define max_args 10
+
+static int tokenize_cmd(char *cmd, char *argv[])
+{
+	char *pos;
+	int argc = 0;
+
+	pos = cmd;
+	for (;;) {
+		while (*pos == ' ')
+			pos++;
+		if (*pos == '\0')
+			break;
+		argv[argc] = pos;
+		argc++;
+		if (argc == max_args)
+			break;
+		if (*pos == '"') {
+			char *pos2 = os_strrchr(pos, '"');
+			if (pos2)
+				pos = pos2 + 1;
+		}
+		while (*pos != '\0' && *pos != ' ')
+			pos++;
+		if (*pos == ' ')
+			*pos++ = '\0';
+	}
+
+	return argc;
+}
+
+
+static void hostapd_cli_ping(void *eloop_ctx, void *timeout_ctx)
+{
+	if (ctrl_conn && _wpa_ctrl_command(ctrl_conn, "PING", 0)) {
+		printf("Connection to hostapd lost - trying to reconnect\n");
+		hostapd_cli_close_connection();
+	}
+	if (!ctrl_conn) {
+		ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
+		if (ctrl_conn) {
+			printf("Connection to hostapd re-established\n");
+			if (wpa_ctrl_attach(ctrl_conn) == 0) {
+				hostapd_cli_attached = 1;
+			} else {
+				printf("Warning: Failed to attach to "
+				       "hostapd.\n");
+			}
+		}
+	}
+	if (ctrl_conn)
+		hostapd_cli_recv_pending(ctrl_conn, 1, 0);
+	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
+}
+
+
+static void hostapd_cli_eloop_terminate(int sig, void *signal_ctx)
+{
+	eloop_terminate();
+}
+
+
+static void hostapd_cli_edit_cmd_cb(void *ctx, char *cmd)
+{
+	char *argv[max_args];
+	int argc;
+	argc = tokenize_cmd(cmd, argv);
+	if (argc)
+		wpa_request(ctrl_conn, argc, argv);
+}
+
+
+static void hostapd_cli_edit_eof_cb(void *ctx)
+{
+	eloop_terminate();
+}
+
+
+static void hostapd_cli_interactive(void)
+{
+	printf("\nInteractive mode\n\n");
+
+	eloop_register_signal_terminate(hostapd_cli_eloop_terminate, NULL);
+	edit_init(hostapd_cli_edit_cmd_cb, hostapd_cli_edit_eof_cb,
+		  NULL, NULL, NULL, NULL);
+	eloop_register_timeout(ping_interval, 0, hostapd_cli_ping, NULL, NULL);
+
+	eloop_run();
+
+	edit_deinit(NULL, NULL);
+	eloop_cancel_timeout(hostapd_cli_ping, NULL, NULL);
+}
+
+
+static void hostapd_cli_cleanup(void)
+{
+	hostapd_cli_close_connection();
+	if (pid_file)
+		os_daemonize_terminate(pid_file);
+
+	os_program_deinit();
+}
+
+
+static void hostapd_cli_action(struct wpa_ctrl *ctrl)
+{
+	fd_set rfds;
+	int fd, res;
+	struct timeval tv;
+	char buf[256];
+	size_t len;
+
+	fd = wpa_ctrl_get_fd(ctrl);
+
+	while (!hostapd_cli_quit) {
+		FD_ZERO(&rfds);
+		FD_SET(fd, &rfds);
+		tv.tv_sec = ping_interval;
+		tv.tv_usec = 0;
+		res = select(fd + 1, &rfds, NULL, NULL, &tv);
+		if (res < 0 && errno != EINTR) {
+			perror("select");
+			break;
+		}
+
+		if (FD_ISSET(fd, &rfds))
+			hostapd_cli_recv_pending(ctrl, 0, 1);
+		else {
+			len = sizeof(buf) - 1;
+			if (wpa_ctrl_request(ctrl, "PING", 4, buf, &len,
+					     hostapd_cli_action_process) < 0 ||
+			    len < 4 || os_memcmp(buf, "PONG", 4) != 0) {
+				printf("hostapd did not reply to PING "
+				       "command - exiting\n");
+				break;
+			}
+		}
+	}
+}
+
+
+int main(int argc, char *argv[])
+{
+	int warning_displayed = 0;
+	int c;
+	int daemonize = 0;
+
+	if (os_program_init())
+		return -1;
+
+	for (;;) {
+		c = getopt(argc, argv, "a:BhG:i:p:v");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'a':
+			action_file = optarg;
+			break;
+		case 'B':
+			daemonize = 1;
+			break;
+		case 'G':
+			ping_interval = atoi(optarg);
+			break;
+		case 'h':
+			usage();
+			return 0;
+		case 'v':
+			printf("%s\n", hostapd_cli_version);
+			return 0;
+		case 'i':
+			os_free(ctrl_ifname);
+			ctrl_ifname = os_strdup(optarg);
+			break;
+		case 'p':
+			ctrl_iface_dir = optarg;
+			break;
+		default:
+			usage();
+			return -1;
+		}
+	}
+
+	interactive = (argc == optind) && (action_file == NULL);
+
+	if (interactive) {
+		printf("%s\n\n%s\n\n", hostapd_cli_version,
+		       hostapd_cli_license);
+	}
+
+	if (eloop_init())
+		return -1;
+
+	for (;;) {
+		if (ctrl_ifname == NULL) {
+			struct dirent *dent;
+			DIR *dir = opendir(ctrl_iface_dir);
+			if (dir) {
+				while ((dent = readdir(dir))) {
+					if (os_strcmp(dent->d_name, ".") == 0
+					    ||
+					    os_strcmp(dent->d_name, "..") == 0)
+						continue;
+					printf("Selected interface '%s'\n",
+					       dent->d_name);
+					ctrl_ifname = os_strdup(dent->d_name);
+					break;
+				}
+				closedir(dir);
+			}
+		}
+		ctrl_conn = hostapd_cli_open_connection(ctrl_ifname);
+		if (ctrl_conn) {
+			if (warning_displayed)
+				printf("Connection established.\n");
+			break;
+		}
+
+		if (!interactive) {
+			perror("Failed to connect to hostapd - "
+			       "wpa_ctrl_open");
+			return -1;
+		}
+
+		if (!warning_displayed) {
+			printf("Could not connect to hostapd - re-trying\n");
+			warning_displayed = 1;
+		}
+		os_sleep(1, 0);
+		continue;
+	}
+
+	if (interactive || action_file) {
+		if (wpa_ctrl_attach(ctrl_conn) == 0) {
+			hostapd_cli_attached = 1;
+		} else {
+			printf("Warning: Failed to attach to hostapd.\n");
+			if (action_file)
+				return -1;
+		}
+	}
+
+	if (daemonize && os_daemonize(pid_file))
+		return -1;
+
+	if (interactive)
+		hostapd_cli_interactive();
+	else if (action_file)
+		hostapd_cli_action(ctrl_conn);
+	else
+		wpa_request(ctrl_conn, argc - optind, &argv[optind]);
+
+	os_free(ctrl_ifname);
+	eloop_destroy();
+	hostapd_cli_cleanup();
+	return 0;
+}
diff --git a/hostap/hostapd/logwatch/README b/hostap/hostapd/logwatch/README
new file mode 100644
index 0000000..3cba511
--- /dev/null
+++ b/hostap/hostapd/logwatch/README
@@ -0,0 +1,9 @@
+Logwatch is a utility for analyzing system logs and provide a human
+readable summary. This directory has a configuration file and a log
+analyzer script for parsing hostapd system log entries for logwatch.
+These files can be installed by copying them to following locations:
+
+/etc/log.d/conf/services/hostapd.conf
+/etc/log.d/scripts/services/hostapd
+
+More information about logwatch is available from http://www.logwatch.org/
diff --git a/hostap/hostapd/logwatch/hostapd b/hostap/hostapd/logwatch/hostapd
new file mode 100755
index 0000000..97b24ef
--- /dev/null
+++ b/hostap/hostapd/logwatch/hostapd
@@ -0,0 +1,65 @@
+#!/usr/bin/perl -w
+#
+# Logwatch script for hostapd
+#
+# Copyright 2005 Henrik Brix Andersen <brix@gentoo.org>
+# Distributed under the terms of the GNU General Public License v2
+# Alternatively, this file may be distributed under the terms of the BSD License
+
+use strict;
+
+my $debug = $ENV{'LOGWATCH_DEBUG'} || 0;
+my $detail = $ENV{'LOGWATCH_DETAIL_LEVEL'} || 0;
+my $debugcounter = 1;
+
+my %hostapd;
+my @unmatched;
+
+if ($debug >= 5) {
+	print STDERR "\n\nDEBUG: Inside HOSTAPD Filter\n\n";
+}
+
+while (defined(my $line = <STDIN>)) {
+	if ($debug >= 5) {
+		print STDERR "DEBUG($debugcounter): $line";
+		$debugcounter++;
+	}
+    chomp($line);
+
+	if (my ($iface,$mac,$layer,$details) = ($line =~ /(.*?): STA (.*?) (.*?): (.*?)$/i)) {
+		unless ($detail == 10) {
+			# collapse association events
+			$details =~ s/^(associated) .*$/$1/i;
+		}
+		$hostapd{$iface}->{$mac}->{$layer}->{$details}++;
+	} else {
+		push @unmatched, "$line\n";
+	}
+}
+
+if (keys %hostapd) {
+	foreach my $iface (sort keys %hostapd) {
+		print "Interface $iface:\n";
+		foreach my $mac (sort keys %{$hostapd{$iface}}) {
+			print "  Client MAC Address $mac:\n";
+			foreach my $layer (sort keys %{$hostapd{$iface}->{$mac}}) {
+				print "    $layer:\n";
+				foreach my $details (sort keys %{$hostapd{$iface}->{$mac}->{$layer}}) {
+					print "      $details";
+					my $count = $hostapd{$iface}->{$mac}->{$layer}->{$details};
+					if ($count > 1) {
+						print ": " . $count . " Times";
+					}
+					print "\n";
+				}
+			}
+		}
+	}
+}
+
+if ($#unmatched >= 0) {
+    print "\n**Unmatched Entries**\n";
+    print @unmatched;
+}
+
+exit(0);
diff --git a/hostap/hostapd/logwatch/hostapd.conf b/hostap/hostapd/logwatch/hostapd.conf
new file mode 100644
index 0000000..5bebe6a
--- /dev/null
+++ b/hostap/hostapd/logwatch/hostapd.conf
@@ -0,0 +1,10 @@
+# Logwatch configuration for hostapd
+#
+# Copyright 2005 Henrik Brix Andersen <brix@gentoo.org>
+# Distributed under the terms of the GNU General Public License v2
+# Alternatively, this file may be distributed under the terms of the BSD License
+
+Title = "hostapd"
+LogFile = messages
+*OnlyService = hostapd
+*RemoveHeaders
diff --git a/hostap/hostapd/main.c b/hostap/hostapd/main.c
new file mode 100644
index 0000000..56f0002
--- /dev/null
+++ b/hostap/hostapd/main.c
@@ -0,0 +1,657 @@
+/*
+ * hostapd / main()
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#ifndef CONFIG_NATIVE_WINDOWS
+#include <syslog.h>
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/random.h"
+#include "crypto/tls.h"
+#include "common/version.h"
+#include "drivers/driver.h"
+#include "eap_server/eap.h"
+#include "eap_server/tncs.h"
+#include "ap/hostapd.h"
+#include "ap/ap_config.h"
+#include "ap/ap_drv_ops.h"
+#include "config_file.h"
+#include "eap_register.h"
+#include "dump_state.h"
+#include "ctrl_iface.h"
+
+
+extern int wpa_debug_level;
+extern int wpa_debug_show_keys;
+extern int wpa_debug_timestamp;
+
+extern struct wpa_driver_ops *wpa_drivers[];
+
+
+struct hapd_global {
+	void **drv_priv;
+	size_t drv_count;
+};
+
+static struct hapd_global global;
+
+
+#ifndef CONFIG_NO_HOSTAPD_LOGGER
+static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
+			      int level, const char *txt, size_t len)
+{
+	struct hostapd_data *hapd = ctx;
+	char *format, *module_str;
+	int maxlen;
+	int conf_syslog_level, conf_stdout_level;
+	unsigned int conf_syslog, conf_stdout;
+
+	maxlen = len + 100;
+	format = os_malloc(maxlen);
+	if (!format)
+		return;
+
+	if (hapd && hapd->conf) {
+		conf_syslog_level = hapd->conf->logger_syslog_level;
+		conf_stdout_level = hapd->conf->logger_stdout_level;
+		conf_syslog = hapd->conf->logger_syslog;
+		conf_stdout = hapd->conf->logger_stdout;
+	} else {
+		conf_syslog_level = conf_stdout_level = 0;
+		conf_syslog = conf_stdout = (unsigned int) -1;
+	}
+
+	switch (module) {
+	case HOSTAPD_MODULE_IEEE80211:
+		module_str = "IEEE 802.11";
+		break;
+	case HOSTAPD_MODULE_IEEE8021X:
+		module_str = "IEEE 802.1X";
+		break;
+	case HOSTAPD_MODULE_RADIUS:
+		module_str = "RADIUS";
+		break;
+	case HOSTAPD_MODULE_WPA:
+		module_str = "WPA";
+		break;
+	case HOSTAPD_MODULE_DRIVER:
+		module_str = "DRIVER";
+		break;
+	case HOSTAPD_MODULE_IAPP:
+		module_str = "IAPP";
+		break;
+	case HOSTAPD_MODULE_MLME:
+		module_str = "MLME";
+		break;
+	default:
+		module_str = NULL;
+		break;
+	}
+
+	if (hapd && hapd->conf && addr)
+		os_snprintf(format, maxlen, "%s: STA " MACSTR "%s%s: %s",
+			    hapd->conf->iface, MAC2STR(addr),
+			    module_str ? " " : "", module_str, txt);
+	else if (hapd && hapd->conf)
+		os_snprintf(format, maxlen, "%s:%s%s %s",
+			    hapd->conf->iface, module_str ? " " : "",
+			    module_str, txt);
+	else if (addr)
+		os_snprintf(format, maxlen, "STA " MACSTR "%s%s: %s",
+			    MAC2STR(addr), module_str ? " " : "",
+			    module_str, txt);
+	else
+		os_snprintf(format, maxlen, "%s%s%s",
+			    module_str, module_str ? ": " : "", txt);
+
+	if ((conf_stdout & module) && level >= conf_stdout_level) {
+		wpa_debug_print_timestamp();
+		printf("%s\n", format);
+	}
+
+#ifndef CONFIG_NATIVE_WINDOWS
+	if ((conf_syslog & module) && level >= conf_syslog_level) {
+		int priority;
+		switch (level) {
+		case HOSTAPD_LEVEL_DEBUG_VERBOSE:
+		case HOSTAPD_LEVEL_DEBUG:
+			priority = LOG_DEBUG;
+			break;
+		case HOSTAPD_LEVEL_INFO:
+			priority = LOG_INFO;
+			break;
+		case HOSTAPD_LEVEL_NOTICE:
+			priority = LOG_NOTICE;
+			break;
+		case HOSTAPD_LEVEL_WARNING:
+			priority = LOG_WARNING;
+			break;
+		default:
+			priority = LOG_INFO;
+			break;
+		}
+		syslog(priority, "%s", format);
+	}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	os_free(format);
+}
+#endif /* CONFIG_NO_HOSTAPD_LOGGER */
+
+
+/**
+ * hostapd_init - Allocate and initialize per-interface data
+ * @config_file: Path to the configuration file
+ * Returns: Pointer to the allocated interface data or %NULL on failure
+ *
+ * This function is used to allocate main data structures for per-interface
+ * data. The allocated data buffer will be freed by calling
+ * hostapd_cleanup_iface().
+ */
+static struct hostapd_iface * hostapd_init(const char *config_file)
+{
+	struct hostapd_iface *hapd_iface = NULL;
+	struct hostapd_config *conf = NULL;
+	struct hostapd_data *hapd;
+	size_t i;
+
+	hapd_iface = os_zalloc(sizeof(*hapd_iface));
+	if (hapd_iface == NULL)
+		goto fail;
+
+	hapd_iface->config_fname = os_strdup(config_file);
+	if (hapd_iface->config_fname == NULL)
+		goto fail;
+
+	conf = hostapd_config_read(hapd_iface->config_fname);
+	if (conf == NULL)
+		goto fail;
+	hapd_iface->conf = conf;
+
+	hapd_iface->num_bss = conf->num_bss;
+	hapd_iface->bss = os_calloc(conf->num_bss,
+				    sizeof(struct hostapd_data *));
+	if (hapd_iface->bss == NULL)
+		goto fail;
+
+	for (i = 0; i < conf->num_bss; i++) {
+		hapd = hapd_iface->bss[i] =
+			hostapd_alloc_bss_data(hapd_iface, conf,
+					       &conf->bss[i]);
+		if (hapd == NULL)
+			goto fail;
+		hapd->msg_ctx = hapd;
+	}
+
+	return hapd_iface;
+
+fail:
+	if (conf)
+		hostapd_config_free(conf);
+	if (hapd_iface) {
+		os_free(hapd_iface->config_fname);
+		os_free(hapd_iface->bss);
+		os_free(hapd_iface);
+	}
+	return NULL;
+}
+
+
+static int hostapd_driver_init(struct hostapd_iface *iface)
+{
+	struct wpa_init_params params;
+	size_t i;
+	struct hostapd_data *hapd = iface->bss[0];
+	struct hostapd_bss_config *conf = hapd->conf;
+	u8 *b = conf->bssid;
+	struct wpa_driver_capa capa;
+
+	if (hapd->driver == NULL || hapd->driver->hapd_init == NULL) {
+		wpa_printf(MSG_ERROR, "No hostapd driver wrapper available");
+		return -1;
+	}
+
+	/* Initialize the driver interface */
+	if (!(b[0] | b[1] | b[2] | b[3] | b[4] | b[5]))
+		b = NULL;
+
+	os_memset(&params, 0, sizeof(params));
+	for (i = 0; wpa_drivers[i]; i++) {
+		if (wpa_drivers[i] != hapd->driver)
+			continue;
+
+		if (global.drv_priv[i] == NULL &&
+		    wpa_drivers[i]->global_init) {
+			global.drv_priv[i] = wpa_drivers[i]->global_init();
+			if (global.drv_priv[i] == NULL) {
+				wpa_printf(MSG_ERROR, "Failed to initialize "
+					   "driver '%s'",
+					   wpa_drivers[i]->name);
+				return -1;
+			}
+		}
+
+		params.global_priv = global.drv_priv[i];
+		break;
+	}
+	params.bssid = b;
+	params.ifname = hapd->conf->iface;
+	params.ssid = hapd->conf->ssid.ssid;
+	params.ssid_len = hapd->conf->ssid.ssid_len;
+	params.test_socket = hapd->conf->test_socket;
+	params.use_pae_group_addr = hapd->conf->use_pae_group_addr;
+
+	params.num_bridge = hapd->iface->num_bss;
+	params.bridge = os_calloc(hapd->iface->num_bss, sizeof(char *));
+	if (params.bridge == NULL)
+		return -1;
+	for (i = 0; i < hapd->iface->num_bss; i++) {
+		struct hostapd_data *bss = hapd->iface->bss[i];
+		if (bss->conf->bridge[0])
+			params.bridge[i] = bss->conf->bridge;
+	}
+
+	params.own_addr = hapd->own_addr;
+
+	hapd->drv_priv = hapd->driver->hapd_init(hapd, &params);
+	os_free(params.bridge);
+	if (hapd->drv_priv == NULL) {
+		wpa_printf(MSG_ERROR, "%s driver initialization failed.",
+			   hapd->driver->name);
+		hapd->driver = NULL;
+		return -1;
+	}
+
+	if (hapd->driver->get_capa &&
+	    hapd->driver->get_capa(hapd->drv_priv, &capa) == 0) {
+		iface->drv_flags = capa.flags;
+		iface->probe_resp_offloads = capa.probe_resp_offloads;
+	}
+
+	return 0;
+}
+
+
+static struct hostapd_iface *
+hostapd_interface_init(struct hapd_interfaces *interfaces,
+		       const char *config_fname, int debug)
+{
+	struct hostapd_iface *iface;
+	int k;
+
+	wpa_printf(MSG_ERROR, "Configuration file: %s", config_fname);
+	iface = hostapd_init(config_fname);
+	if (!iface)
+		return NULL;
+	iface->interfaces = interfaces;
+
+	for (k = 0; k < debug; k++) {
+		if (iface->bss[0]->conf->logger_stdout_level > 0)
+			iface->bss[0]->conf->logger_stdout_level--;
+	}
+
+	if (iface->conf->bss[0].iface[0] != 0 ||
+	    hostapd_drv_none(iface->bss[0])) {
+		if (hostapd_driver_init(iface) ||
+			hostapd_setup_interface(iface)) {
+			hostapd_interface_deinit_free(iface);
+			return NULL;
+		}
+	}
+
+	return iface;
+}
+
+
+/**
+ * handle_term - SIGINT and SIGTERM handler to terminate hostapd process
+ */
+static void handle_term(int sig, void *signal_ctx)
+{
+	wpa_printf(MSG_DEBUG, "Signal %d received - terminating", sig);
+	eloop_terminate();
+}
+
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
+static int handle_reload_iface(struct hostapd_iface *iface, void *ctx)
+{
+	if (hostapd_reload_config(iface) < 0) {
+		wpa_printf(MSG_WARNING, "Failed to read new configuration "
+			   "file - continuing with old.");
+	}
+	return 0;
+}
+
+
+/**
+ * handle_reload - SIGHUP handler to reload configuration
+ */
+static void handle_reload(int sig, void *signal_ctx)
+{
+	struct hapd_interfaces *interfaces = signal_ctx;
+	wpa_printf(MSG_DEBUG, "Signal %d received - reloading configuration",
+		   sig);
+	hostapd_for_each_interface(interfaces, handle_reload_iface, NULL);
+}
+
+
+static void handle_dump_state(int sig, void *signal_ctx)
+{
+#ifdef HOSTAPD_DUMP_STATE
+	struct hapd_interfaces *interfaces = signal_ctx;
+	hostapd_for_each_interface(interfaces, handle_dump_state_iface, NULL);
+#endif /* HOSTAPD_DUMP_STATE */
+}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static int hostapd_global_init(struct hapd_interfaces *interfaces,
+			       const char *entropy_file)
+{
+	int i;
+
+	os_memset(&global, 0, sizeof(global));
+
+	hostapd_logger_register_cb(hostapd_logger_cb);
+
+	if (eap_server_register_methods()) {
+		wpa_printf(MSG_ERROR, "Failed to register EAP methods");
+		return -1;
+	}
+
+	if (eloop_init()) {
+		wpa_printf(MSG_ERROR, "Failed to initialize event loop");
+		return -1;
+	}
+
+	random_init(entropy_file);
+
+#ifndef CONFIG_NATIVE_WINDOWS
+	eloop_register_signal(SIGHUP, handle_reload, interfaces);
+	eloop_register_signal(SIGUSR1, handle_dump_state, interfaces);
+#endif /* CONFIG_NATIVE_WINDOWS */
+	eloop_register_signal_terminate(handle_term, interfaces);
+
+#ifndef CONFIG_NATIVE_WINDOWS
+	openlog("hostapd", 0, LOG_DAEMON);
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	for (i = 0; wpa_drivers[i]; i++)
+		global.drv_count++;
+	if (global.drv_count == 0) {
+		wpa_printf(MSG_ERROR, "No drivers enabled");
+		return -1;
+	}
+	global.drv_priv = os_calloc(global.drv_count, sizeof(void *));
+	if (global.drv_priv == NULL)
+		return -1;
+
+	return 0;
+}
+
+
+static void hostapd_global_deinit(const char *pid_file)
+{
+	int i;
+
+	for (i = 0; wpa_drivers[i] && global.drv_priv; i++) {
+		if (!global.drv_priv[i])
+			continue;
+		wpa_drivers[i]->global_deinit(global.drv_priv[i]);
+	}
+	os_free(global.drv_priv);
+	global.drv_priv = NULL;
+
+#ifdef EAP_SERVER_TNC
+	tncs_global_deinit();
+#endif /* EAP_SERVER_TNC */
+
+	random_deinit();
+
+	eloop_destroy();
+
+#ifndef CONFIG_NATIVE_WINDOWS
+	closelog();
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	eap_server_unregister_methods();
+
+	os_daemonize_terminate(pid_file);
+}
+
+
+static int hostapd_global_run(struct hapd_interfaces *ifaces, int daemonize,
+			      const char *pid_file)
+{
+#ifdef EAP_SERVER_TNC
+	int tnc = 0;
+	size_t i, k;
+
+	for (i = 0; !tnc && i < ifaces->count; i++) {
+		for (k = 0; k < ifaces->iface[i]->num_bss; k++) {
+			if (ifaces->iface[i]->bss[0]->conf->tnc) {
+				tnc++;
+				break;
+			}
+		}
+	}
+
+	if (tnc && tncs_global_init() < 0) {
+		wpa_printf(MSG_ERROR, "Failed to initialize TNCS");
+		return -1;
+	}
+#endif /* EAP_SERVER_TNC */
+
+	if (daemonize && os_daemonize(pid_file)) {
+		perror("daemon");
+		return -1;
+	}
+
+	eloop_run();
+
+	return 0;
+}
+
+
+static void show_version(void)
+{
+	fprintf(stderr,
+		"hostapd v" VERSION_STR "\n"
+		"User space daemon for IEEE 802.11 AP management,\n"
+		"IEEE 802.1X/WPA/WPA2/EAP/RADIUS Authenticator\n"
+		"Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> "
+		"and contributors\n");
+}
+
+
+static void usage(void)
+{
+	show_version();
+	fprintf(stderr,
+		"\n"
+		"usage: hostapd [-hdBKtv] [-P <PID file>] [-e <entropy file>] "
+		"\\\n"
+		"         [-g <global ctrl_iface>] <configuration file(s)>\n"
+		"\n"
+		"options:\n"
+		"   -h   show this usage\n"
+		"   -d   show more debug messages (-dd for even more)\n"
+		"   -B   run daemon in the background\n"
+		"   -e   entropy file\n"
+		"   -g   global control interface path\n"
+		"   -P   PID file\n"
+		"   -K   include key data in debug messages\n"
+#ifdef CONFIG_DEBUG_FILE
+		"   -f   log output to debug file instead of stdout\n"
+#endif /* CONFIG_DEBUG_FILE */
+		"   -t   include timestamps in some debug messages\n"
+		"   -v   show hostapd version\n");
+
+	exit(1);
+}
+
+
+static const char * hostapd_msg_ifname_cb(void *ctx)
+{
+	struct hostapd_data *hapd = ctx;
+	if (hapd && hapd->iconf && hapd->iconf->bss)
+		return hapd->iconf->bss->iface;
+	return NULL;
+}
+
+
+static int hostapd_get_global_ctrl_iface(struct hapd_interfaces *interfaces,
+					 const char *path)
+{
+	char *pos;
+	os_free(interfaces->global_iface_path);
+	interfaces->global_iface_path = os_strdup(path);
+	if (interfaces->global_iface_path == NULL)
+		return -1;
+	pos = os_strrchr(interfaces->global_iface_path, '/');
+	if (pos == NULL) {
+		os_free(interfaces->global_iface_path);
+		interfaces->global_iface_path = NULL;
+		return -1;
+	}
+
+	*pos = '\0';
+	interfaces->global_iface_name = pos + 1;
+
+	return 0;
+}
+
+
+int main(int argc, char *argv[])
+{
+	struct hapd_interfaces interfaces;
+	int ret = 1;
+	size_t i;
+	int c, debug = 0, daemonize = 0;
+	char *pid_file = NULL;
+	const char *log_file = NULL;
+	const char *entropy_file = NULL;
+
+	if (os_program_init())
+		return -1;
+
+	os_memset(&interfaces, 0, sizeof(interfaces));
+	interfaces.reload_config = hostapd_reload_config;
+	interfaces.config_read_cb = hostapd_config_read;
+	interfaces.for_each_interface = hostapd_for_each_interface;
+	interfaces.ctrl_iface_init = hostapd_ctrl_iface_init;
+	interfaces.ctrl_iface_deinit = hostapd_ctrl_iface_deinit;
+	interfaces.driver_init = hostapd_driver_init;
+	interfaces.global_iface_path = NULL;
+	interfaces.global_iface_name = NULL;
+	interfaces.global_ctrl_sock = -1;
+
+	for (;;) {
+		c = getopt(argc, argv, "Bde:f:hKP:tvg:");
+		if (c < 0)
+			break;
+		switch (c) {
+		case 'h':
+			usage();
+			break;
+		case 'd':
+			debug++;
+			if (wpa_debug_level > 0)
+				wpa_debug_level--;
+			break;
+		case 'B':
+			daemonize++;
+			break;
+		case 'e':
+			entropy_file = optarg;
+			break;
+		case 'f':
+			log_file = optarg;
+			break;
+		case 'K':
+			wpa_debug_show_keys++;
+			break;
+		case 'P':
+			os_free(pid_file);
+			pid_file = os_rel2abs_path(optarg);
+			break;
+		case 't':
+			wpa_debug_timestamp++;
+			break;
+		case 'v':
+			show_version();
+			exit(1);
+			break;
+		case 'g':
+			hostapd_get_global_ctrl_iface(&interfaces, optarg);
+			break;
+
+		default:
+			usage();
+			break;
+		}
+	}
+
+	if (optind == argc && interfaces.global_iface_path == NULL)
+		usage();
+
+	wpa_msg_register_ifname_cb(hostapd_msg_ifname_cb);
+
+	if (log_file)
+		wpa_debug_open_file(log_file);
+
+	interfaces.count = argc - optind;
+	if (interfaces.count) {
+		interfaces.iface = os_calloc(interfaces.count,
+					     sizeof(struct hostapd_iface *));
+		if (interfaces.iface == NULL) {
+			wpa_printf(MSG_ERROR, "malloc failed");
+			return -1;
+		}
+	}
+
+	if (hostapd_global_init(&interfaces, entropy_file))
+		return -1;
+
+	/* Initialize interfaces */
+	for (i = 0; i < interfaces.count; i++) {
+		interfaces.iface[i] = hostapd_interface_init(&interfaces,
+							     argv[optind + i],
+							     debug);
+		if (!interfaces.iface[i])
+			goto out;
+	}
+
+	hostapd_global_ctrl_iface_init(&interfaces);
+
+	if (hostapd_global_run(&interfaces, daemonize, pid_file))
+		goto out;
+
+	ret = 0;
+
+ out:
+	hostapd_global_ctrl_iface_deinit(&interfaces);
+	/* Deinitialize all interfaces */
+	for (i = 0; i < interfaces.count; i++)
+		hostapd_interface_deinit_free(interfaces.iface[i]);
+	os_free(interfaces.iface);
+
+	hostapd_global_deinit(pid_file);
+	os_free(pid_file);
+
+	if (log_file)
+		wpa_debug_close_file();
+
+	os_program_deinit();
+
+	return ret;
+}
diff --git a/hostap/hostapd/nt_password_hash.c b/hostap/hostapd/nt_password_hash.c
new file mode 100644
index 0000000..7064b9c
--- /dev/null
+++ b/hostap/hostapd/nt_password_hash.c
@@ -0,0 +1,47 @@
+/*
+ * hostapd - Plaintext password to NtPasswordHash
+ * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/ms_funcs.h"
+
+
+int main(int argc, char *argv[])
+{
+	unsigned char password_hash[16];
+	size_t i;
+	char *password, buf[64], *pos;
+
+	if (argc > 1)
+		password = argv[1];
+	else {
+		if (fgets(buf, sizeof(buf), stdin) == NULL) {
+			printf("Failed to read password\n");
+			return 1;
+		}
+		buf[sizeof(buf) - 1] = '\0';
+		pos = buf;
+		while (*pos != '\0') {
+			if (*pos == '\r' || *pos == '\n') {
+				*pos = '\0';
+				break;
+			}
+			pos++;
+		}
+		password = buf;
+	}
+
+	if (nt_password_hash((u8 *) password, strlen(password), password_hash))
+		return -1;
+	for (i = 0; i < sizeof(password_hash); i++)
+		printf("%02x", password_hash[i]);
+	printf("\n");
+
+	return 0;
+}
diff --git a/hostap/hostapd/wired.conf b/hostap/hostapd/wired.conf
new file mode 100644
index 0000000..956f8c5
--- /dev/null
+++ b/hostap/hostapd/wired.conf
@@ -0,0 +1,40 @@
+##### hostapd configuration file ##############################################
+# Empty lines and lines starting with # are ignored
+
+# Example configuration file for wired authenticator. See hostapd.conf for
+# more details.
+
+interface=eth0
+driver=wired
+logger_stdout=-1
+logger_stdout_level=1
+debug=2
+dump_file=/tmp/hostapd.dump
+
+ieee8021x=1
+eap_reauth_period=3600
+
+use_pae_group_addr=1
+
+
+##### RADIUS configuration ####################################################
+# for IEEE 802.1X with external Authentication Server, IEEE 802.11
+# authentication with external ACL for MAC addresses, and accounting
+
+# The own IP address of the access point (used as NAS-IP-Address)
+own_ip_addr=127.0.0.1
+
+# Optional NAS-Identifier string for RADIUS messages. When used, this should be
+# a unique to the NAS within the scope of the RADIUS server. For example, a
+# fully qualified domain name can be used here.
+nas_identifier=ap.example.com
+
+# RADIUS authentication server
+auth_server_addr=127.0.0.1
+auth_server_port=1812
+auth_server_shared_secret=radius
+
+# RADIUS accounting server
+acct_server_addr=127.0.0.1
+acct_server_port=1813
+acct_server_shared_secret=radius
diff --git a/hostap/mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf b/hostap/mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf
new file mode 100644
index 0000000..08cde7e
--- /dev/null
+++ b/hostap/mac80211_hwsim/tests/0001-wpa2-psk/hostapd.conf
@@ -0,0 +1,11 @@
+interface=wlan0
+driver=nl80211
+
+hw_mode=g
+channel=1
+ssid=mac80211 test
+
+wpa=2
+wpa_key_mgmt=WPA-PSK
+wpa_pairwise=CCMP
+wpa_passphrase=12345678
diff --git a/hostap/mac80211_hwsim/tests/0001-wpa2-psk/test.txt b/hostap/mac80211_hwsim/tests/0001-wpa2-psk/test.txt
new file mode 100644
index 0000000..05d85a0
--- /dev/null
+++ b/hostap/mac80211_hwsim/tests/0001-wpa2-psk/test.txt
@@ -0,0 +1,7 @@
+# WPA2-Personal (PSK) with CCMP, AP and single client
+
+modprobe mac80211_hwsim
+
+hostapd hostapd.conf
+
+wpa_supplicant -Dwext -iwlan1 -c wpa_supplicant.conf
diff --git a/hostap/mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf b/hostap/mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf
new file mode 100644
index 0000000..299128c
--- /dev/null
+++ b/hostap/mac80211_hwsim/tests/0001-wpa2-psk/wpa_supplicant.conf
@@ -0,0 +1,10 @@
+ctrl_interface=/var/run/wpa_supplicant
+
+network={
+	ssid="mac80211 test"
+	psk="12345678"
+	key_mgmt=WPA-PSK
+	proto=WPA2
+	pairwise=CCMP
+	group=CCMP
+}
diff --git a/hostap/mac80211_hwsim/tests/0002-vlan/hostapd.accept b/hostap/mac80211_hwsim/tests/0002-vlan/hostapd.accept
new file mode 100644
index 0000000..e97a175
--- /dev/null
+++ b/hostap/mac80211_hwsim/tests/0002-vlan/hostapd.accept
@@ -0,0 +1,2 @@
+02:00:00:00:01:00	1
+02:00:00:00:02:00	2
diff --git a/hostap/mac80211_hwsim/tests/0002-vlan/hostapd.conf b/hostap/mac80211_hwsim/tests/0002-vlan/hostapd.conf
new file mode 100644
index 0000000..8698f0e
--- /dev/null
+++ b/hostap/mac80211_hwsim/tests/0002-vlan/hostapd.conf
@@ -0,0 +1,12 @@
+interface=wlan0
+driver=nl80211
+
+hw_mode=g
+channel=1
+ssid=mac80211 test
+
+dynamic_vlan=2
+vlan_file=hostapd.vlan
+
+macaddr_acl=0
+accept_mac_file=hostapd.accept
diff --git a/hostap/mac80211_hwsim/tests/0002-vlan/hostapd.vlan b/hostap/mac80211_hwsim/tests/0002-vlan/hostapd.vlan
new file mode 100644
index 0000000..b3750b2
--- /dev/null
+++ b/hostap/mac80211_hwsim/tests/0002-vlan/hostapd.vlan
@@ -0,0 +1 @@
+*	vlan#
diff --git a/hostap/mac80211_hwsim/tests/0002-vlan/test.txt b/hostap/mac80211_hwsim/tests/0002-vlan/test.txt
new file mode 100644
index 0000000..8c92f1c
--- /dev/null
+++ b/hostap/mac80211_hwsim/tests/0002-vlan/test.txt
@@ -0,0 +1,15 @@
+# Plaintext connection, two clients, different VLANs
+
+modprobe mac80211_hwsim radios=3
+
+hostapd hostapd.conf
+
+ifconfig wlan1 up
+iwconfig wlan1 essid "mac80211 test"
+
+ifconfig wlan2 up
+iwconfig wlan2 essid "mac80211 test"
+
+# Expected results:
+# STA1(wlan1) is bound to vlan1
+# STA2(wlan2) is bound to vlan2
diff --git a/hostap/mac80211_hwsim/tools/Makefile b/hostap/mac80211_hwsim/tools/Makefile
new file mode 100644
index 0000000..ec0d2dc
--- /dev/null
+++ b/hostap/mac80211_hwsim/tools/Makefile
@@ -0,0 +1,11 @@
+all: hwsim_test
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef CFLAGS
+CFLAGS = -O2 -Wall -g
+endif
+
+hwsim_test: hwsim_test.o
diff --git a/hostap/mac80211_hwsim/tools/hwsim_test.c b/hostap/mac80211_hwsim/tools/hwsim_test.c
new file mode 100644
index 0000000..75e5984
--- /dev/null
+++ b/hostap/mac80211_hwsim/tools/hwsim_test.c
@@ -0,0 +1,238 @@
+/*
+ * hwsim_test - Data connectivity test for mac80211_hwsim
+ * Copyright (c) 2009, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <netpacket/packet.h>
+#include <net/ethernet.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+
+#define HWSIM_ETHERTYPE ETHERTYPE_IP
+#define HWSIM_PACKETLEN 1500
+
+static unsigned char addr1[ETH_ALEN], addr2[ETH_ALEN], bcast[ETH_ALEN];
+
+static void tx(int s, const char *ifname, int ifindex,
+	       const unsigned char *src, const unsigned char *dst)
+{
+	char buf[HWSIM_PACKETLEN], *pos;
+	struct ether_header *eth;
+	int i;
+
+	printf("TX: %s(ifindex=%d) " MACSTR " -> " MACSTR "\n",
+	       ifname, ifindex, MAC2STR(src), MAC2STR(dst));
+
+	eth = (struct ether_header *) buf;
+	memcpy(eth->ether_dhost, dst, ETH_ALEN);
+	memcpy(eth->ether_shost, src, ETH_ALEN);
+	eth->ether_type = htons(HWSIM_ETHERTYPE);
+	pos = (char *) (eth + 1);
+	for (i = 0; i < sizeof(buf) - sizeof(*eth); i++)
+		*pos++ = i;
+
+	if (send(s, buf, sizeof(buf), 0) < 0)
+		perror("send");
+}
+
+
+struct rx_result {
+	int rx_unicast1:1;
+	int rx_broadcast1:1;
+	int rx_unicast2:1;
+	int rx_broadcast2:1;
+};
+
+
+static void rx(int s, int iface, const char *ifname, int ifindex,
+	       struct rx_result *res)
+{
+	char buf[HWSIM_PACKETLEN + 1], *pos;
+	struct ether_header *eth;
+	int len, i;
+
+	len = recv(s, buf, sizeof(buf), 0);
+	if (len < 0) {
+		perror("recv");
+		return;
+	}
+	eth = (struct ether_header *) buf;
+
+	printf("RX: %s(ifindex=%d) " MACSTR " -> " MACSTR " (len=%d)\n",
+	       ifname, ifindex,
+	       MAC2STR(eth->ether_shost), MAC2STR(eth->ether_dhost), len);
+
+	if (len != HWSIM_PACKETLEN) {
+		printf("Ignore frame with unexpected RX length\n");
+		return;
+	}
+
+	pos = (char *) (eth + 1);
+	for (i = 0; i < sizeof(buf) - 1 - sizeof(*eth); i++) {
+		if ((unsigned char) *pos != (unsigned char) i) {
+			printf("Ignore frame with unexpected contents\n");
+			printf("i=%d received=0x%x expected=0x%x\n",
+			       i, (unsigned char) *pos, (unsigned char) i);
+			return;
+		}
+		pos++;
+	}
+
+	if (iface == 1 &&
+		   memcmp(eth->ether_dhost, addr1, ETH_ALEN) == 0 &&
+		   memcmp(eth->ether_shost, addr2, ETH_ALEN) == 0)
+		res->rx_unicast1 = 1;
+	else if (iface == 1 &&
+		   memcmp(eth->ether_dhost, bcast, ETH_ALEN) == 0 &&
+		   memcmp(eth->ether_shost, addr2, ETH_ALEN) == 0)
+		res->rx_broadcast1 = 1;
+	else if (iface == 2 &&
+		   memcmp(eth->ether_dhost, addr2, ETH_ALEN) == 0 &&
+		   memcmp(eth->ether_shost, addr1, ETH_ALEN) == 0)
+		res->rx_unicast2 = 1;
+	else if (iface == 2 &&
+		   memcmp(eth->ether_dhost, bcast, ETH_ALEN) == 0 &&
+		   memcmp(eth->ether_shost, addr1, ETH_ALEN) == 0)
+		res->rx_broadcast2 = 1;
+}
+
+
+int main(int argc, char *argv[])
+{
+	int s1 = -1, s2 = -1, ret = -1;
+	struct ifreq ifr;
+	int ifindex1, ifindex2;
+	struct sockaddr_ll ll;
+	fd_set rfds;
+	struct timeval tv;
+	struct rx_result res;
+
+	if (argc != 3) {
+		fprintf(stderr, "usage: hwsim_test <ifname1> <ifname2>\n");
+		return -1;
+	}
+
+	memset(bcast, 0xff, ETH_ALEN);
+
+	s1 = socket(PF_PACKET, SOCK_RAW, htons(HWSIM_ETHERTYPE));
+	if (s1 < 0) {
+		perror("socket");
+		goto fail;
+	}
+
+	s2 = socket(PF_PACKET, SOCK_RAW, htons(HWSIM_ETHERTYPE));
+	if (s2 < 0) {
+		perror("socket");
+		goto fail;
+	}
+
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, argv[1], sizeof(ifr.ifr_name));
+	if (ioctl(s1, SIOCGIFINDEX, &ifr) < 0) {
+		perror("ioctl[SIOCGIFINDEX]");
+		goto fail;
+	}
+	ifindex1 = ifr.ifr_ifindex;
+	if (ioctl(s1, SIOCGIFHWADDR, &ifr) < 0) {
+		perror("ioctl[SIOCGIFHWADDR]");
+		goto fail;
+	}
+	memcpy(addr1, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+	memset(&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, argv[2], sizeof(ifr.ifr_name));
+	if (ioctl(s2, SIOCGIFINDEX, &ifr) < 0) {
+		perror("ioctl[SIOCGIFINDEX]");
+		goto fail;
+	}
+	ifindex2 = ifr.ifr_ifindex;
+	if (ioctl(s2, SIOCGIFHWADDR, &ifr) < 0) {
+		perror("ioctl[SIOCGIFHWADDR]");
+		goto fail;
+	}
+	memcpy(addr2, ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+
+	memset(&ll, 0, sizeof(ll));
+	ll.sll_family = PF_PACKET;
+	ll.sll_ifindex = ifindex1;
+	ll.sll_protocol = htons(HWSIM_ETHERTYPE);
+	if (bind(s1, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+		perror("bind");
+		goto fail;
+	}
+
+	memset(&ll, 0, sizeof(ll));
+	ll.sll_family = PF_PACKET;
+	ll.sll_ifindex = ifindex2;
+	ll.sll_protocol = htons(HWSIM_ETHERTYPE);
+	if (bind(s2, (struct sockaddr *) &ll, sizeof(ll)) < 0) {
+		perror("bind");
+		goto fail;
+	}
+
+	tx(s1, argv[1], ifindex1, addr1, addr2);
+	tx(s1, argv[1], ifindex1, addr1, bcast);
+	tx(s2, argv[2], ifindex2, addr2, addr1);
+	tx(s2, argv[2], ifindex2, addr2, bcast);
+
+	tv.tv_sec = 1;
+	tv.tv_usec = 0;
+
+	memset(&res, 0, sizeof(res));
+	for (;;) {
+		int r;
+		FD_ZERO(&rfds);
+		FD_SET(s1, &rfds);
+		FD_SET(s2, &rfds);
+
+		r = select(s2 + 1, &rfds, NULL, NULL, &tv);
+		if (r < 0) {
+			perror("select");
+			goto fail;
+		}
+
+		if (r == 0)
+			break; /* timeout */
+
+		if (FD_ISSET(s1, &rfds))
+			rx(s1, 1, argv[1], ifindex1, &res);
+		if (FD_ISSET(s2, &rfds))
+			rx(s2, 2, argv[2], ifindex2, &res);
+
+		if (res.rx_unicast1 && res.rx_broadcast1 &&
+		    res.rx_unicast2 && res.rx_broadcast2) {
+			ret = 0;
+			break;
+		}
+	}
+
+	if (ret) {
+		printf("Did not receive all expected frames:\n"
+		       "rx_unicast1=%d rx_broadcast1=%d "
+		       "rx_unicast2=%d rx_broadcast2=%d\n",
+		       res.rx_unicast1, res.rx_broadcast1,
+		       res.rx_unicast2, res.rx_broadcast2);
+	} else {
+		printf("Both unicast and broadcast working in both "
+		       "directions\n");
+	}
+
+fail:
+	close(s1);
+	close(s2);
+
+	return ret;
+}
diff --git a/hostap/patches/openssl-0.9.8-tls-extensions.patch b/hostap/patches/openssl-0.9.8-tls-extensions.patch
new file mode 100644
index 0000000..44490cc
--- /dev/null
+++ b/hostap/patches/openssl-0.9.8-tls-extensions.patch
@@ -0,0 +1,429 @@
+This patch is adding support for TLS hello extensions and externally
+generated pre-shared key material to OpenSSL 0.9.8. This is
+based on the patch from Alexey Kobozev <akobozev@cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+
+
+diff -uprN openssl-0.9.8.orig/include/openssl/ssl.h openssl-0.9.8/include/openssl/ssl.h
+--- openssl-0.9.8.orig/include/openssl/ssl.h	2005-06-10 12:51:16.000000000 -0700
++++ openssl-0.9.8/include/openssl/ssl.h	2005-07-19 20:02:15.000000000 -0700
+@@ -340,6 +340,7 @@ extern "C" {
+  * 'struct ssl_st *' function parameters used to prototype callbacks
+  * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_extension_st TLS_EXTENSION;
+ 
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -361,6 +362,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+ typedef struct ssl_st SSL;
+ typedef struct ssl_ctx_st SSL_CTX;
+ 
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ 	{
+@@ -968,6 +971,15 @@ struct ssl_st
+ 	int first_packet;
+ 	int client_version;	/* what was passed, used for
+ 				 * SSLv3/TLS rollback check */
++
++	/* TLS externsions */
++	TLS_EXTENSION *tls_extension;
++	int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
++	void *tls_extension_cb_arg;
++
++	/* TLS pre-shared secret session resumption */
++	tls_session_secret_cb_fn tls_session_secret_cb;
++	void *tls_session_secret_cb_arg;
+ 	};
+ 
+ #ifdef __cplusplus
+@@ -1533,6 +1545,13 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+ 
++/* TLS extensions functions */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+  * made after this point may be overwritten when the script is next run.
+@@ -1714,6 +1733,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_ENC					 210
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
+ #define SSL_F_WRITE_PENDING				 212
++#define SSL_F_SSL_SET_HELLO_EXTENSION	 213
+ 
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
+diff -uprN openssl-0.9.8.orig/include/openssl/tls1.h openssl-0.9.8/include/openssl/tls1.h
+--- openssl-0.9.8.orig/include/openssl/tls1.h	2003-07-22 05:34:21.000000000 -0700
++++ openssl-0.9.8/include/openssl/tls1.h	2005-07-19 20:02:15.000000000 -0700
+@@ -282,6 +282,14 @@ extern "C" {
+ #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
+ #endif
+ 
++/* TLS extension struct */
++struct tls_extension_st
++{
++	unsigned short type;
++	unsigned short length;
++	void *data;
++};
++
+ #ifdef  __cplusplus
+ }
+ #endif
+diff -uprN openssl-0.9.8.orig/ssl/Makefile openssl-0.9.8/ssl/Makefile
+--- openssl-0.9.8.orig/ssl/Makefile	2005-05-30 16:20:30.000000000 -0700
++++ openssl-0.9.8/ssl/Makefile	2005-07-19 20:02:15.000000000 -0700
+@@ -24,7 +24,7 @@ LIBSRC=	\
+ 	s2_meth.c   s2_srvr.c s2_clnt.c  s2_lib.c  s2_enc.c s2_pkt.c \
+ 	s3_meth.c   s3_srvr.c s3_clnt.c  s3_lib.c  s3_enc.c s3_pkt.c s3_both.c \
+ 	s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c          s23_pkt.c \
+-	t1_meth.c   t1_srvr.c t1_clnt.c  t1_lib.c  t1_enc.c \
++	t1_meth.c   t1_srvr.c t1_clnt.c  t1_lib.c  t1_enc.c                    t1_ext.c \
+ 	d1_meth.c   d1_srvr.c d1_clnt.c  d1_lib.c  d1_pkt.c \
+ 	d1_both.c d1_enc.c \
+ 	ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
+@@ -35,7 +35,7 @@ LIBOBJ= \
+ 	s2_meth.o  s2_srvr.o  s2_clnt.o  s2_lib.o  s2_enc.o s2_pkt.o \
+ 	s3_meth.o  s3_srvr.o  s3_clnt.o  s3_lib.o  s3_enc.o s3_pkt.o s3_both.o \
+ 	s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o          s23_pkt.o \
+-	t1_meth.o   t1_srvr.o t1_clnt.o  t1_lib.o  t1_enc.o \
++	t1_meth.o   t1_srvr.o t1_clnt.o  t1_lib.o  t1_enc.o                    t1_ext.o \
+ 	d1_meth.o   d1_srvr.o d1_clnt.o  d1_lib.o  d1_pkt.o \
+ 	d1_both.o d1_enc.o \
+ 	ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
+@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h ..
+ t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
+ t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
+ t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c
++t1_ext.o: t1_ext.c ssl_locl.h
+diff -uprN openssl-0.9.8.orig/ssl/s3_clnt.c openssl-0.9.8/ssl/s3_clnt.c
+--- openssl-0.9.8.orig/ssl/s3_clnt.c	2005-05-16 03:11:03.000000000 -0700
++++ openssl-0.9.8/ssl/s3_clnt.c	2005-07-19 20:02:15.000000000 -0700
+@@ -606,6 +606,20 @@ int ssl3_client_hello(SSL *s)
+ 			}
+ 		*(p++)=0; /* Add the NULL method */
+ 		
++		/* send client hello extensions if any */
++		if (s->version >= TLS1_VERSION && s->tls_extension)
++		{
++			// set the total extensions length
++			s2n(s->tls_extension->length + 4, p);
++
++			// put the extensions with type and length
++			s2n(s->tls_extension->type, p);
++			s2n(s->tls_extension->length, p);
++			
++			memcpy(p, s->tls_extension->data, s->tls_extension->length);
++			p+=s->tls_extension->length;
++		}
++
+ 		l=(p-d);
+ 		d=buf;
+ 		*(d++)=SSL3_MT_CLIENT_HELLO;
+@@ -628,7 +642,7 @@ int ssl3_get_server_hello(SSL *s)
+ 	STACK_OF(SSL_CIPHER) *sk;
+ 	SSL_CIPHER *c;
+ 	unsigned char *p,*d;
+-	int i,al,ok;
++	int i,al,ok,pre_shared;
+ 	unsigned int j;
+ 	long n;
+ 	SSL_COMP *comp;
+@@ -693,7 +707,24 @@ int ssl3_get_server_hello(SSL *s)
+ 		goto f_err;
+ 		}
+ 
+-	if (j != 0 && j == s->session->session_id_length
++	/* check if we want to resume the session based on external pre-shared secret */
++	pre_shared = 0;
++	if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++	{
++		SSL_CIPHER *pref_cipher=NULL;
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++			NULL, &pref_cipher, s->tls_session_secret_cb_arg))
++		{
++			s->hit=1;
++			s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
++			s->session->session_id_length = j;
++			memcpy(s->session->session_id, p, j);
++			pre_shared = 1;
++		}
++	}
++
++	if ((pre_shared || j != 0) && j == s->session->session_id_length
+ 	    && memcmp(p,s->session->session_id,j) == 0)
+ 	    {
+ 	    if(s->sid_ctx_length != s->session->sid_ctx_length
+diff -uprN openssl-0.9.8.orig/ssl/s3_srvr.c openssl-0.9.8/ssl/s3_srvr.c
+--- openssl-0.9.8.orig/ssl/s3_srvr.c	2005-05-22 17:32:55.000000000 -0700
++++ openssl-0.9.8/ssl/s3_srvr.c	2005-07-19 20:02:15.000000000 -0700
+@@ -955,6 +955,75 @@ int ssl3_get_client_hello(SSL *s)
+ 		}
+ #endif
+ 
++	/* Check for TLS client hello extension here */
++	if (p < (d+n) && s->version >= TLS1_VERSION)
++	{
++		if (s->tls_extension_cb)
++		{
++			TLS_EXTENSION tls_ext;
++			unsigned short ext_total_len;
++			
++			n2s(p, ext_total_len);
++			n2s(p, tls_ext.type);
++			n2s(p, tls_ext.length);
++
++			// sanity check in TLS extension len
++			if (tls_ext.length > (d+n) - p)
++			{
++				// just cut the lenth to packet border
++				tls_ext.length = (d+n) - p;
++			}
++
++			tls_ext.data = p;
++
++			// returns an alert code or 0
++			al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg);
++			if (al != 0)
++			{
++				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR);
++				goto f_err;
++			}
++		}
++	}
++
++	/* Check if we want to use external pre-shared secret for this handshake */
++	/* for not reused session only */
++	if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++	{
++		SSL_CIPHER *pref_cipher=NULL;
++
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, 
++			ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
++		{
++			s->hit=1;
++			s->session->ciphers=ciphers;
++			s->session->verify_result=X509_V_OK;
++			
++			ciphers=NULL;
++			
++			/* check if some cipher was preferred by call back */
++			pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
++			if (pref_cipher == NULL)
++				{
++				al=SSL_AD_HANDSHAKE_FAILURE;
++				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
++				goto f_err;
++				}
++
++			s->session->cipher=pref_cipher;
++
++			if (s->cipher_list)
++				sk_SSL_CIPHER_free(s->cipher_list);
++
++			if (s->cipher_list_by_id)
++				sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++			s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++			s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++		}
++	}
++
+ 	/* Given s->session->ciphers and SSL_get_ciphers, we must
+ 	 * pick a cipher */
+ 
+diff -uprN openssl-0.9.8.orig/ssl/ssl_err.c openssl-0.9.8/ssl/ssl_err.c
+--- openssl-0.9.8.orig/ssl/ssl_err.c	2005-06-10 12:51:16.000000000 -0700
++++ openssl-0.9.8/ssl/ssl_err.c	2005-07-19 20:02:15.000000000 -0700
+@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
+ {ERR_FUNC(SSL_F_TLS1_ENC),	"TLS1_ENC"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING),	"WRITE_PENDING"},
++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
+ {0,NULL}
+ 	};
+ 
+diff -uprN openssl-0.9.8.orig/ssl/ssl.h openssl-0.9.8/ssl/ssl.h
+--- openssl-0.9.8.orig/ssl/ssl.h	2005-06-10 12:51:16.000000000 -0700
++++ openssl-0.9.8/ssl/ssl.h	2005-07-19 20:02:15.000000000 -0700
+@@ -340,6 +340,7 @@ extern "C" {
+  * 'struct ssl_st *' function parameters used to prototype callbacks
+  * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_extension_st TLS_EXTENSION;
+ 
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -361,6 +362,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+ typedef struct ssl_st SSL;
+ typedef struct ssl_ctx_st SSL_CTX;
+ 
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ 	{
+@@ -968,6 +971,15 @@ struct ssl_st
+ 	int first_packet;
+ 	int client_version;	/* what was passed, used for
+ 				 * SSLv3/TLS rollback check */
++
++	/* TLS externsions */
++	TLS_EXTENSION *tls_extension;
++	int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
++	void *tls_extension_cb_arg;
++
++	/* TLS pre-shared secret session resumption */
++	tls_session_secret_cb_fn tls_session_secret_cb;
++	void *tls_session_secret_cb_arg;
+ 	};
+ 
+ #ifdef __cplusplus
+@@ -1533,6 +1545,13 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+ 
++/* TLS extensions functions */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+  * made after this point may be overwritten when the script is next run.
+@@ -1714,6 +1733,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_ENC					 210
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
+ #define SSL_F_WRITE_PENDING				 212
++#define SSL_F_SSL_SET_HELLO_EXTENSION	 213
+ 
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
+diff -uprN openssl-0.9.8.orig/ssl/ssl_sess.c openssl-0.9.8/ssl/ssl_sess.c
+--- openssl-0.9.8.orig/ssl/ssl_sess.c	2005-04-29 13:10:06.000000000 -0700
++++ openssl-0.9.8/ssl/ssl_sess.c	2005-07-19 20:02:15.000000000 -0700
+@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+ 	return(s->session_timeout);
+ 	}
+ 
++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, 
++	STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
++{
++	if (s == NULL) return(0);
++	s->tls_session_secret_cb = tls_session_secret_cb;
++	s->tls_session_secret_cb_arg = arg;
++	return(1);
++}
++
+ typedef struct timeout_param_st
+ 	{
+ 	SSL_CTX *ctx;
+diff -uprN openssl-0.9.8.orig/ssl/t1_ext.c openssl-0.9.8/ssl/t1_ext.c
+--- openssl-0.9.8.orig/ssl/t1_ext.c	1969-12-31 16:00:00.000000000 -0800
++++ openssl-0.9.8/ssl/t1_ext.c	2005-07-19 20:03:29.000000000 -0700
+@@ -0,0 +1,48 @@
++
++#include <stdio.h>
++#include "ssl_locl.h"
++
++
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
++{
++	if(s->version >= TLS1_VERSION)
++	{
++		if(s->tls_extension)
++		{
++			OPENSSL_free(s->tls_extension);
++			s->tls_extension = NULL;
++		}
++
++		if(ext_data)
++		{
++			s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
++			if(!s->tls_extension)
++			{
++				SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
++				return 0;
++			}
++
++			s->tls_extension->type = ext_type;
++			s->tls_extension->length = ext_len;
++			s->tls_extension->data = s->tls_extension + 1;
++			memcpy(s->tls_extension->data, ext_data, ext_len);
++		}
++
++		return 1;
++	}
++
++	return 0;
++}
++
++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg)
++{
++	if(s->version >= TLS1_VERSION)
++	{
++		s->tls_extension_cb = cb;
++		s->tls_extension_cb_arg = arg;
++
++		return 1;
++	}
++
++	return 0;
++}
+diff -uprN openssl-0.9.8.orig/ssl/t1_lib.c openssl-0.9.8/ssl/t1_lib.c
+--- openssl-0.9.8.orig/ssl/t1_lib.c	2005-04-26 09:02:40.000000000 -0700
++++ openssl-0.9.8/ssl/t1_lib.c	2005-07-19 20:02:15.000000000 -0700
+@@ -131,6 +131,10 @@ int tls1_new(SSL *s)
+ 
+ void tls1_free(SSL *s)
+ 	{
++	if(s->tls_extension)
++	{
++		OPENSSL_free(s->tls_extension);
++	}
+ 	ssl3_free(s);
+ 	}
+ 
+diff -uprN openssl-0.9.8.orig/ssl/tls1.h openssl-0.9.8/ssl/tls1.h
+--- openssl-0.9.8.orig/ssl/tls1.h	2003-07-22 05:34:21.000000000 -0700
++++ openssl-0.9.8/ssl/tls1.h	2005-07-19 20:02:15.000000000 -0700
+@@ -282,6 +282,14 @@ extern "C" {
+ #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
+ #endif
+ 
++/* TLS extension struct */
++struct tls_extension_st
++{
++	unsigned short type;
++	unsigned short length;
++	void *data;
++};
++
+ #ifdef  __cplusplus
+ }
+ #endif
+diff -uprN openssl-0.9.8.orig/util/ssleay.num openssl-0.9.8/util/ssleay.num
+--- openssl-0.9.8.orig/util/ssleay.num	2005-05-08 17:22:02.000000000 -0700
++++ openssl-0.9.8/util/ssleay.num	2005-07-19 20:02:15.000000000 -0700
+@@ -226,3 +226,6 @@ DTLSv1_server_method                    
+ SSL_COMP_get_compression_methods        276	EXIST:!VMS:FUNCTION:COMP
+ SSL_COMP_get_compress_methods           276	EXIST:VMS:FUNCTION:COMP
+ SSL_SESSION_get_id                      277	EXIST::FUNCTION:
++SSL_set_hello_extension			278	EXIST::FUNCTION:
++SSL_set_hello_extension_cb		279	EXIST::FUNCTION:
++SSL_set_session_secret_cb		280	EXIST::FUNCTION:
diff --git a/hostap/patches/openssl-0.9.8d-tls-extensions.patch b/hostap/patches/openssl-0.9.8d-tls-extensions.patch
new file mode 100644
index 0000000..eec6db8
--- /dev/null
+++ b/hostap/patches/openssl-0.9.8d-tls-extensions.patch
@@ -0,0 +1,429 @@
+This patch is adding support for TLS hello extensions and externally
+generated pre-shared key material to OpenSSL 0.9.8d. This is
+based on the patch from Alexey Kobozev <akobozev@cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+
+
+diff -uprN openssl-0.9.8d.orig/include/openssl/ssl.h openssl-0.9.8d/include/openssl/ssl.h
+--- openssl-0.9.8d.orig/include/openssl/ssl.h	2006-06-14 06:52:49.000000000 -0700
++++ openssl-0.9.8d/include/openssl/ssl.h	2006-12-10 08:20:02.000000000 -0800
+@@ -345,6 +345,7 @@ extern "C" {
+  * 'struct ssl_st *' function parameters used to prototype callbacks
+  * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_extension_st TLS_EXTENSION;
+ 
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+ typedef struct ssl_st SSL;
+ typedef struct ssl_ctx_st SSL_CTX;
+ 
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ 	{
+@@ -973,6 +976,15 @@ struct ssl_st
+ 	int first_packet;
+ 	int client_version;	/* what was passed, used for
+ 				 * SSLv3/TLS rollback check */
++
++	/* TLS externsions */
++	TLS_EXTENSION *tls_extension;
++	int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
++	void *tls_extension_cb_arg;
++
++	/* TLS pre-shared secret session resumption */
++	tls_session_secret_cb_fn tls_session_secret_cb;
++	void *tls_session_secret_cb_arg;
+ 	};
+ 
+ #ifdef __cplusplus
+@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+ 
++/* TLS extensions functions */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+  * made after this point may be overwritten when the script is next run.
+@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_ENC					 210
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
+ #define SSL_F_WRITE_PENDING				 212
++#define SSL_F_SSL_SET_HELLO_EXTENSION	 213
+ 
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
+diff -uprN openssl-0.9.8d.orig/include/openssl/tls1.h openssl-0.9.8d/include/openssl/tls1.h
+--- openssl-0.9.8d.orig/include/openssl/tls1.h	2006-06-14 10:52:01.000000000 -0700
++++ openssl-0.9.8d/include/openssl/tls1.h	2006-12-10 08:20:02.000000000 -0800
+@@ -296,6 +296,14 @@ extern "C" {
+ #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
+ #endif
+ 
++/* TLS extension struct */
++struct tls_extension_st
++{
++	unsigned short type;
++	unsigned short length;
++	void *data;
++};
++
+ #ifdef  __cplusplus
+ }
+ #endif
+diff -uprN openssl-0.9.8d.orig/ssl/Makefile openssl-0.9.8d/ssl/Makefile
+--- openssl-0.9.8d.orig/ssl/Makefile	2006-02-03 17:49:35.000000000 -0800
++++ openssl-0.9.8d/ssl/Makefile	2006-12-10 08:20:02.000000000 -0800
+@@ -24,7 +24,7 @@ LIBSRC=	\
+ 	s2_meth.c   s2_srvr.c s2_clnt.c  s2_lib.c  s2_enc.c s2_pkt.c \
+ 	s3_meth.c   s3_srvr.c s3_clnt.c  s3_lib.c  s3_enc.c s3_pkt.c s3_both.c \
+ 	s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c          s23_pkt.c \
+-	t1_meth.c   t1_srvr.c t1_clnt.c  t1_lib.c  t1_enc.c \
++	t1_meth.c   t1_srvr.c t1_clnt.c  t1_lib.c  t1_enc.c                    t1_ext.c \
+ 	d1_meth.c   d1_srvr.c d1_clnt.c  d1_lib.c  d1_pkt.c \
+ 	d1_both.c d1_enc.c \
+ 	ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
+@@ -35,7 +35,7 @@ LIBOBJ= \
+ 	s2_meth.o  s2_srvr.o  s2_clnt.o  s2_lib.o  s2_enc.o s2_pkt.o \
+ 	s3_meth.o  s3_srvr.o  s3_clnt.o  s3_lib.o  s3_enc.o s3_pkt.o s3_both.o \
+ 	s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o          s23_pkt.o \
+-	t1_meth.o   t1_srvr.o t1_clnt.o  t1_lib.o  t1_enc.o \
++	t1_meth.o   t1_srvr.o t1_clnt.o  t1_lib.o  t1_enc.o                    t1_ext.o \
+ 	d1_meth.o   d1_srvr.o d1_clnt.o  d1_lib.o  d1_pkt.o \
+ 	d1_both.o d1_enc.o \
+ 	ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
+@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h ..
+ t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
+ t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
+ t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c
++t1_ext.o: t1_ext.c ssl_locl.h
+diff -uprN openssl-0.9.8d.orig/ssl/s3_clnt.c openssl-0.9.8d/ssl/s3_clnt.c
+--- openssl-0.9.8d.orig/ssl/s3_clnt.c	2005-12-12 23:41:46.000000000 -0800
++++ openssl-0.9.8d/ssl/s3_clnt.c	2006-12-10 08:20:02.000000000 -0800
+@@ -601,6 +601,20 @@ int ssl3_client_hello(SSL *s)
+ #endif
+ 		*(p++)=0; /* Add the NULL method */
+ 		
++		/* send client hello extensions if any */
++		if (s->version >= TLS1_VERSION && s->tls_extension)
++		{
++			// set the total extensions length
++			s2n(s->tls_extension->length + 4, p);
++
++			// put the extensions with type and length
++			s2n(s->tls_extension->type, p);
++			s2n(s->tls_extension->length, p);
++			
++			memcpy(p, s->tls_extension->data, s->tls_extension->length);
++			p+=s->tls_extension->length;
++		}
++
+ 		l=(p-d);
+ 		d=buf;
+ 		*(d++)=SSL3_MT_CLIENT_HELLO;
+@@ -623,7 +637,7 @@ int ssl3_get_server_hello(SSL *s)
+ 	STACK_OF(SSL_CIPHER) *sk;
+ 	SSL_CIPHER *c;
+ 	unsigned char *p,*d;
+-	int i,al,ok;
++	int i,al,ok,pre_shared;
+ 	unsigned int j;
+ 	long n;
+ #ifndef OPENSSL_NO_COMP
+@@ -690,7 +704,24 @@ int ssl3_get_server_hello(SSL *s)
+ 		goto f_err;
+ 		}
+ 
+-	if (j != 0 && j == s->session->session_id_length
++	/* check if we want to resume the session based on external pre-shared secret */
++	pre_shared = 0;
++	if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++	{
++		SSL_CIPHER *pref_cipher=NULL;
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++			NULL, &pref_cipher, s->tls_session_secret_cb_arg))
++		{
++			s->hit=1;
++			s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
++			s->session->session_id_length = j;
++			memcpy(s->session->session_id, p, j);
++			pre_shared = 1;
++		}
++	}
++
++	if ((pre_shared || j != 0) && j == s->session->session_id_length
+ 	    && memcmp(p,s->session->session_id,j) == 0)
+ 	    {
+ 	    if(s->sid_ctx_length != s->session->sid_ctx_length
+diff -uprN openssl-0.9.8d.orig/ssl/s3_srvr.c openssl-0.9.8d/ssl/s3_srvr.c
+--- openssl-0.9.8d.orig/ssl/s3_srvr.c	2006-09-28 04:29:03.000000000 -0700
++++ openssl-0.9.8d/ssl/s3_srvr.c	2006-12-10 08:20:02.000000000 -0800
+@@ -943,6 +943,75 @@ int ssl3_get_client_hello(SSL *s)
+ 		}
+ #endif
+ 
++	/* Check for TLS client hello extension here */
++	if (p < (d+n) && s->version >= TLS1_VERSION)
++	{
++		if (s->tls_extension_cb)
++		{
++			TLS_EXTENSION tls_ext;
++			unsigned short ext_total_len;
++			
++			n2s(p, ext_total_len);
++			n2s(p, tls_ext.type);
++			n2s(p, tls_ext.length);
++
++			// sanity check in TLS extension len
++			if (tls_ext.length > (d+n) - p)
++			{
++				// just cut the lenth to packet border
++				tls_ext.length = (d+n) - p;
++			}
++
++			tls_ext.data = p;
++
++			// returns an alert code or 0
++			al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg);
++			if (al != 0)
++			{
++				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR);
++				goto f_err;
++			}
++		}
++	}
++
++	/* Check if we want to use external pre-shared secret for this handshake */
++	/* for not reused session only */
++	if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++	{
++		SSL_CIPHER *pref_cipher=NULL;
++
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, 
++			ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
++		{
++			s->hit=1;
++			s->session->ciphers=ciphers;
++			s->session->verify_result=X509_V_OK;
++			
++			ciphers=NULL;
++			
++			/* check if some cipher was preferred by call back */
++			pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
++			if (pref_cipher == NULL)
++				{
++				al=SSL_AD_HANDSHAKE_FAILURE;
++				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
++				goto f_err;
++				}
++
++			s->session->cipher=pref_cipher;
++
++			if (s->cipher_list)
++				sk_SSL_CIPHER_free(s->cipher_list);
++
++			if (s->cipher_list_by_id)
++				sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++			s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++			s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++		}
++	}
++
+ 	/* Given s->session->ciphers and SSL_get_ciphers, we must
+ 	 * pick a cipher */
+ 
+diff -uprN openssl-0.9.8d.orig/ssl/ssl.h openssl-0.9.8d/ssl/ssl.h
+--- openssl-0.9.8d.orig/ssl/ssl.h	2006-06-14 06:52:49.000000000 -0700
++++ openssl-0.9.8d/ssl/ssl.h	2006-12-10 08:20:02.000000000 -0800
+@@ -345,6 +345,7 @@ extern "C" {
+  * 'struct ssl_st *' function parameters used to prototype callbacks
+  * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_extension_st TLS_EXTENSION;
+ 
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+ typedef struct ssl_st SSL;
+ typedef struct ssl_ctx_st SSL_CTX;
+ 
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ 	{
+@@ -973,6 +976,15 @@ struct ssl_st
+ 	int first_packet;
+ 	int client_version;	/* what was passed, used for
+ 				 * SSLv3/TLS rollback check */
++
++	/* TLS externsions */
++	TLS_EXTENSION *tls_extension;
++	int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
++	void *tls_extension_cb_arg;
++
++	/* TLS pre-shared secret session resumption */
++	tls_session_secret_cb_fn tls_session_secret_cb;
++	void *tls_session_secret_cb_arg;
+ 	};
+ 
+ #ifdef __cplusplus
+@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+ 
++/* TLS extensions functions */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+  * made after this point may be overwritten when the script is next run.
+@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_ENC					 210
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
+ #define SSL_F_WRITE_PENDING				 212
++#define SSL_F_SSL_SET_HELLO_EXTENSION	 213
+ 
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
+diff -uprN openssl-0.9.8d.orig/ssl/ssl_err.c openssl-0.9.8d/ssl/ssl_err.c
+--- openssl-0.9.8d.orig/ssl/ssl_err.c	2006-01-08 13:52:46.000000000 -0800
++++ openssl-0.9.8d/ssl/ssl_err.c	2006-12-10 08:20:02.000000000 -0800
+@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
+ {ERR_FUNC(SSL_F_TLS1_ENC),	"TLS1_ENC"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING),	"WRITE_PENDING"},
++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
+ {0,NULL}
+ 	};
+ 
+diff -uprN openssl-0.9.8d.orig/ssl/ssl_sess.c openssl-0.9.8d/ssl/ssl_sess.c
+--- openssl-0.9.8d.orig/ssl/ssl_sess.c	2005-12-30 15:51:57.000000000 -0800
++++ openssl-0.9.8d/ssl/ssl_sess.c	2006-12-10 08:20:02.000000000 -0800
+@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+ 	return(s->session_timeout);
+ 	}
+ 
++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, 
++	STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
++{
++	if (s == NULL) return(0);
++	s->tls_session_secret_cb = tls_session_secret_cb;
++	s->tls_session_secret_cb_arg = arg;
++	return(1);
++}
++
+ typedef struct timeout_param_st
+ 	{
+ 	SSL_CTX *ctx;
+diff -uprN openssl-0.9.8d.orig/ssl/t1_ext.c openssl-0.9.8d/ssl/t1_ext.c
+--- openssl-0.9.8d.orig/ssl/t1_ext.c	1969-12-31 16:00:00.000000000 -0800
++++ openssl-0.9.8d/ssl/t1_ext.c	2006-12-10 08:20:02.000000000 -0800
+@@ -0,0 +1,48 @@
++
++#include <stdio.h>
++#include "ssl_locl.h"
++
++
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
++{
++	if(s->version >= TLS1_VERSION)
++	{
++		if(s->tls_extension)
++		{
++			OPENSSL_free(s->tls_extension);
++			s->tls_extension = NULL;
++		}
++
++		if(ext_data)
++		{
++			s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
++			if(!s->tls_extension)
++			{
++				SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
++				return 0;
++			}
++
++			s->tls_extension->type = ext_type;
++			s->tls_extension->length = ext_len;
++			s->tls_extension->data = s->tls_extension + 1;
++			memcpy(s->tls_extension->data, ext_data, ext_len);
++		}
++
++		return 1;
++	}
++
++	return 0;
++}
++
++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg)
++{
++	if(s->version >= TLS1_VERSION)
++	{
++		s->tls_extension_cb = cb;
++		s->tls_extension_cb_arg = arg;
++
++		return 1;
++	}
++
++	return 0;
++}
+diff -uprN openssl-0.9.8d.orig/ssl/t1_lib.c openssl-0.9.8d/ssl/t1_lib.c
+--- openssl-0.9.8d.orig/ssl/t1_lib.c	2005-08-05 16:52:07.000000000 -0700
++++ openssl-0.9.8d/ssl/t1_lib.c	2006-12-10 08:20:02.000000000 -0800
+@@ -97,6 +97,10 @@ int tls1_new(SSL *s)
+ 
+ void tls1_free(SSL *s)
+ 	{
++	if(s->tls_extension)
++	{
++		OPENSSL_free(s->tls_extension);
++	}
+ 	ssl3_free(s);
+ 	}
+ 
+diff -uprN openssl-0.9.8d.orig/ssl/tls1.h openssl-0.9.8d/ssl/tls1.h
+--- openssl-0.9.8d.orig/ssl/tls1.h	2006-06-14 10:52:01.000000000 -0700
++++ openssl-0.9.8d/ssl/tls1.h	2006-12-10 08:20:02.000000000 -0800
+@@ -296,6 +296,14 @@ extern "C" {
+ #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
+ #endif
+ 
++/* TLS extension struct */
++struct tls_extension_st
++{
++	unsigned short type;
++	unsigned short length;
++	void *data;
++};
++
+ #ifdef  __cplusplus
+ }
+ #endif
+diff -uprN openssl-0.9.8d.orig/util/ssleay.num openssl-0.9.8d/util/ssleay.num
+--- openssl-0.9.8d.orig/util/ssleay.num	2005-05-08 17:22:02.000000000 -0700
++++ openssl-0.9.8d/util/ssleay.num	2006-12-10 08:20:02.000000000 -0800
+@@ -226,3 +226,6 @@ DTLSv1_server_method                    
+ SSL_COMP_get_compression_methods        276	EXIST:!VMS:FUNCTION:COMP
+ SSL_COMP_get_compress_methods           276	EXIST:VMS:FUNCTION:COMP
+ SSL_SESSION_get_id                      277	EXIST::FUNCTION:
++SSL_set_hello_extension			278	EXIST::FUNCTION:
++SSL_set_hello_extension_cb		279	EXIST::FUNCTION:
++SSL_set_session_secret_cb		280	EXIST::FUNCTION:
diff --git a/hostap/patches/openssl-0.9.8e-tls-extensions.patch b/hostap/patches/openssl-0.9.8e-tls-extensions.patch
new file mode 100644
index 0000000..ede053f
--- /dev/null
+++ b/hostap/patches/openssl-0.9.8e-tls-extensions.patch
@@ -0,0 +1,353 @@
+This patch is adding support for TLS hello extensions and externally
+generated pre-shared key material to OpenSSL 0.9.8e. This is
+based on the patch from Alexey Kobozev <akobozev@cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+
+
+diff -uprN openssl-0.9.8e.orig/ssl/Makefile openssl-0.9.8e/ssl/Makefile
+--- openssl-0.9.8e.orig/ssl/Makefile	2006-02-03 17:49:35.000000000 -0800
++++ openssl-0.9.8e/ssl/Makefile	2007-03-22 20:23:19.000000000 -0700
+@@ -24,7 +24,7 @@ LIBSRC=	\
+ 	s2_meth.c   s2_srvr.c s2_clnt.c  s2_lib.c  s2_enc.c s2_pkt.c \
+ 	s3_meth.c   s3_srvr.c s3_clnt.c  s3_lib.c  s3_enc.c s3_pkt.c s3_both.c \
+ 	s23_meth.c s23_srvr.c s23_clnt.c s23_lib.c          s23_pkt.c \
+-	t1_meth.c   t1_srvr.c t1_clnt.c  t1_lib.c  t1_enc.c \
++	t1_meth.c   t1_srvr.c t1_clnt.c  t1_lib.c  t1_enc.c                    t1_ext.c \
+ 	d1_meth.c   d1_srvr.c d1_clnt.c  d1_lib.c  d1_pkt.c \
+ 	d1_both.c d1_enc.c \
+ 	ssl_lib.c ssl_err2.c ssl_cert.c ssl_sess.c \
+@@ -35,7 +35,7 @@ LIBOBJ= \
+ 	s2_meth.o  s2_srvr.o  s2_clnt.o  s2_lib.o  s2_enc.o s2_pkt.o \
+ 	s3_meth.o  s3_srvr.o  s3_clnt.o  s3_lib.o  s3_enc.o s3_pkt.o s3_both.o \
+ 	s23_meth.o s23_srvr.o s23_clnt.o s23_lib.o          s23_pkt.o \
+-	t1_meth.o   t1_srvr.o t1_clnt.o  t1_lib.o  t1_enc.o \
++	t1_meth.o   t1_srvr.o t1_clnt.o  t1_lib.o  t1_enc.o                    t1_ext.o \
+ 	d1_meth.o   d1_srvr.o d1_clnt.o  d1_lib.o  d1_pkt.o \
+ 	d1_both.o d1_enc.o \
+ 	ssl_lib.o ssl_err2.o ssl_cert.o ssl_sess.o \
+@@ -968,3 +968,4 @@ t1_srvr.o: ../include/openssl/ssl23.h ..
+ t1_srvr.o: ../include/openssl/stack.h ../include/openssl/symhacks.h
+ t1_srvr.o: ../include/openssl/tls1.h ../include/openssl/x509.h
+ t1_srvr.o: ../include/openssl/x509_vfy.h ssl_locl.h t1_srvr.c
++t1_ext.o: t1_ext.c ssl_locl.h
+diff -uprN openssl-0.9.8e.orig/ssl/s3_clnt.c openssl-0.9.8e/ssl/s3_clnt.c
+--- openssl-0.9.8e.orig/ssl/s3_clnt.c	2006-09-28 05:23:15.000000000 -0700
++++ openssl-0.9.8e/ssl/s3_clnt.c	2007-03-22 20:23:19.000000000 -0700
+@@ -601,6 +601,20 @@ int ssl3_client_hello(SSL *s)
+ #endif
+ 		*(p++)=0; /* Add the NULL method */
+ 		
++		/* send client hello extensions if any */
++		if (s->version >= TLS1_VERSION && s->tls_extension)
++		{
++			// set the total extensions length
++			s2n(s->tls_extension->length + 4, p);
++
++			// put the extensions with type and length
++			s2n(s->tls_extension->type, p);
++			s2n(s->tls_extension->length, p);
++			
++			memcpy(p, s->tls_extension->data, s->tls_extension->length);
++			p+=s->tls_extension->length;
++		}
++
+ 		l=(p-d);
+ 		d=buf;
+ 		*(d++)=SSL3_MT_CLIENT_HELLO;
+@@ -623,7 +637,7 @@ int ssl3_get_server_hello(SSL *s)
+ 	STACK_OF(SSL_CIPHER) *sk;
+ 	SSL_CIPHER *c;
+ 	unsigned char *p,*d;
+-	int i,al,ok;
++	int i,al,ok,pre_shared;
+ 	unsigned int j;
+ 	long n;
+ #ifndef OPENSSL_NO_COMP
+@@ -690,7 +704,24 @@ int ssl3_get_server_hello(SSL *s)
+ 		goto f_err;
+ 		}
+ 
+-	if (j != 0 && j == s->session->session_id_length
++	/* check if we want to resume the session based on external pre-shared secret */
++	pre_shared = 0;
++	if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++	{
++		SSL_CIPHER *pref_cipher=NULL;
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++			NULL, &pref_cipher, s->tls_session_secret_cb_arg))
++		{
++			s->hit=1;
++			s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
++			s->session->session_id_length = j;
++			memcpy(s->session->session_id, p, j);
++			pre_shared = 1;
++		}
++	}
++
++	if ((pre_shared || j != 0) && j == s->session->session_id_length
+ 	    && memcmp(p,s->session->session_id,j) == 0)
+ 	    {
+ 	    if(s->sid_ctx_length != s->session->sid_ctx_length
+diff -uprN openssl-0.9.8e.orig/ssl/s3_srvr.c openssl-0.9.8e/ssl/s3_srvr.c
+--- openssl-0.9.8e.orig/ssl/s3_srvr.c	2007-02-07 12:36:40.000000000 -0800
++++ openssl-0.9.8e/ssl/s3_srvr.c	2007-03-22 20:23:19.000000000 -0700
+@@ -945,6 +945,75 @@ int ssl3_get_client_hello(SSL *s)
+ 		}
+ #endif
+ 
++	/* Check for TLS client hello extension here */
++	if (p < (d+n) && s->version >= TLS1_VERSION)
++	{
++		if (s->tls_extension_cb)
++		{
++			TLS_EXTENSION tls_ext;
++			unsigned short ext_total_len;
++			
++			n2s(p, ext_total_len);
++			n2s(p, tls_ext.type);
++			n2s(p, tls_ext.length);
++
++			// sanity check in TLS extension len
++			if (tls_ext.length > (d+n) - p)
++			{
++				// just cut the lenth to packet border
++				tls_ext.length = (d+n) - p;
++			}
++
++			tls_ext.data = p;
++
++			// returns an alert code or 0
++			al = s->tls_extension_cb(s, &tls_ext, s->tls_extension_cb_arg);
++			if (al != 0)
++			{
++				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_PEER_ERROR);
++				goto f_err;
++			}
++		}
++	}
++
++	/* Check if we want to use external pre-shared secret for this handshake */
++	/* for not reused session only */
++	if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++	{
++		SSL_CIPHER *pref_cipher=NULL;
++
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, 
++			ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
++		{
++			s->hit=1;
++			s->session->ciphers=ciphers;
++			s->session->verify_result=X509_V_OK;
++			
++			ciphers=NULL;
++			
++			/* check if some cipher was preferred by call back */
++			pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
++			if (pref_cipher == NULL)
++				{
++				al=SSL_AD_HANDSHAKE_FAILURE;
++				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
++				goto f_err;
++				}
++
++			s->session->cipher=pref_cipher;
++
++			if (s->cipher_list)
++				sk_SSL_CIPHER_free(s->cipher_list);
++
++			if (s->cipher_list_by_id)
++				sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++			s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++			s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++		}
++	}
++
+ 	/* Given s->session->ciphers and SSL_get_ciphers, we must
+ 	 * pick a cipher */
+ 
+diff -uprN openssl-0.9.8e.orig/ssl/ssl.h openssl-0.9.8e/ssl/ssl.h
+--- openssl-0.9.8e.orig/ssl/ssl.h	2007-02-19 09:55:07.000000000 -0800
++++ openssl-0.9.8e/ssl/ssl.h	2007-03-22 20:23:19.000000000 -0700
+@@ -345,6 +345,7 @@ extern "C" {
+  * 'struct ssl_st *' function parameters used to prototype callbacks
+  * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_extension_st TLS_EXTENSION;
+ 
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -366,6 +367,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+ typedef struct ssl_st SSL;
+ typedef struct ssl_ctx_st SSL_CTX;
+ 
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ 	{
+@@ -973,6 +976,15 @@ struct ssl_st
+ 	int first_packet;
+ 	int client_version;	/* what was passed, used for
+ 				 * SSLv3/TLS rollback check */
++
++	/* TLS externsions */
++	TLS_EXTENSION *tls_extension;
++	int (*tls_extension_cb)(SSL *s, TLS_EXTENSION *tls_ext, void *arg);
++	void *tls_extension_cb_arg;
++
++	/* TLS pre-shared secret session resumption */
++	tls_session_secret_cb_fn tls_session_secret_cb;
++	void *tls_session_secret_cb_arg;
+ 	};
+ 
+ #ifdef __cplusplus
+@@ -1538,6 +1550,13 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+ 
++/* TLS extensions functions */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+  * made after this point may be overwritten when the script is next run.
+@@ -1719,6 +1738,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_ENC					 210
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
+ #define SSL_F_WRITE_PENDING				 212
++#define SSL_F_SSL_SET_HELLO_EXTENSION	 213
+ 
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
+diff -uprN openssl-0.9.8e.orig/ssl/ssl_err.c openssl-0.9.8e/ssl/ssl_err.c
+--- openssl-0.9.8e.orig/ssl/ssl_err.c	2006-11-21 12:14:46.000000000 -0800
++++ openssl-0.9.8e/ssl/ssl_err.c	2007-03-22 20:23:19.000000000 -0700
+@@ -242,6 +242,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
+ {ERR_FUNC(SSL_F_TLS1_ENC),	"TLS1_ENC"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING),	"WRITE_PENDING"},
++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
+ {0,NULL}
+ 	};
+ 
+diff -uprN openssl-0.9.8e.orig/ssl/ssl_sess.c openssl-0.9.8e/ssl/ssl_sess.c
+--- openssl-0.9.8e.orig/ssl/ssl_sess.c	2007-02-10 02:40:24.000000000 -0800
++++ openssl-0.9.8e/ssl/ssl_sess.c	2007-03-22 20:23:19.000000000 -0700
+@@ -656,6 +656,15 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+ 	return(s->session_timeout);
+ 	}
+ 
++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, 
++	STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
++{
++	if (s == NULL) return(0);
++	s->tls_session_secret_cb = tls_session_secret_cb;
++	s->tls_session_secret_cb_arg = arg;
++	return(1);
++}
++
+ typedef struct timeout_param_st
+ 	{
+ 	SSL_CTX *ctx;
+diff -uprN openssl-0.9.8e.orig/ssl/t1_ext.c openssl-0.9.8e/ssl/t1_ext.c
+--- openssl-0.9.8e.orig/ssl/t1_ext.c	1969-12-31 16:00:00.000000000 -0800
++++ openssl-0.9.8e/ssl/t1_ext.c	2007-03-22 20:23:19.000000000 -0700
+@@ -0,0 +1,48 @@
++
++#include <stdio.h>
++#include "ssl_locl.h"
++
++
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
++{
++	if(s->version >= TLS1_VERSION)
++	{
++		if(s->tls_extension)
++		{
++			OPENSSL_free(s->tls_extension);
++			s->tls_extension = NULL;
++		}
++
++		if(ext_data)
++		{
++			s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
++			if(!s->tls_extension)
++			{
++				SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
++				return 0;
++			}
++
++			s->tls_extension->type = ext_type;
++			s->tls_extension->length = ext_len;
++			s->tls_extension->data = s->tls_extension + 1;
++			memcpy(s->tls_extension->data, ext_data, ext_len);
++		}
++
++		return 1;
++	}
++
++	return 0;
++}
++
++int SSL_set_hello_extension_cb(SSL *s, int (*cb)(SSL *, TLS_EXTENSION *, void *), void *arg)
++{
++	if(s->version >= TLS1_VERSION)
++	{
++		s->tls_extension_cb = cb;
++		s->tls_extension_cb_arg = arg;
++
++		return 1;
++	}
++
++	return 0;
++}
+diff -uprN openssl-0.9.8e.orig/ssl/t1_lib.c openssl-0.9.8e/ssl/t1_lib.c
+--- openssl-0.9.8e.orig/ssl/t1_lib.c	2007-01-21 08:07:25.000000000 -0800
++++ openssl-0.9.8e/ssl/t1_lib.c	2007-03-22 20:23:19.000000000 -0700
+@@ -97,6 +97,10 @@ int tls1_new(SSL *s)
+ 
+ void tls1_free(SSL *s)
+ 	{
++	if(s->tls_extension)
++	{
++		OPENSSL_free(s->tls_extension);
++	}
+ 	ssl3_free(s);
+ 	}
+ 
+diff -uprN openssl-0.9.8e.orig/ssl/tls1.h openssl-0.9.8e/ssl/tls1.h
+--- openssl-0.9.8e.orig/ssl/tls1.h	2006-06-14 10:52:01.000000000 -0700
++++ openssl-0.9.8e/ssl/tls1.h	2007-03-22 20:23:19.000000000 -0700
+@@ -296,6 +296,14 @@ extern "C" {
+ #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
+ #endif
+ 
++/* TLS extension struct */
++struct tls_extension_st
++{
++	unsigned short type;
++	unsigned short length;
++	void *data;
++};
++
+ #ifdef  __cplusplus
+ }
+ #endif
+diff -uprN openssl-0.9.8e.orig/util/ssleay.num openssl-0.9.8e/util/ssleay.num
+--- openssl-0.9.8e.orig/util/ssleay.num	2006-11-30 05:04:43.000000000 -0800
++++ openssl-0.9.8e/util/ssleay.num	2007-03-22 20:24:07.000000000 -0700
+@@ -238,3 +238,6 @@ SSL_CTX_set_info_callback               
+ SSL_CTX_sess_get_new_cb                 287	EXIST::FUNCTION:
+ SSL_CTX_get_client_cert_cb              288	EXIST::FUNCTION:
+ SSL_CTX_sess_get_remove_cb              289	EXIST::FUNCTION:
++SSL_set_hello_extension			290	EXIST::FUNCTION:
++SSL_set_hello_extension_cb		291	EXIST::FUNCTION:
++SSL_set_session_secret_cb		292	EXIST::FUNCTION:
diff --git a/hostap/patches/openssl-0.9.8g-tls-extensions.patch b/hostap/patches/openssl-0.9.8g-tls-extensions.patch
new file mode 100644
index 0000000..8ccbfaa
--- /dev/null
+++ b/hostap/patches/openssl-0.9.8g-tls-extensions.patch
@@ -0,0 +1,330 @@
+This patch adds support for TLS SessionTicket extension (RFC 5077) for
+the parts used by EAP-FAST (RFC 4851).
+
+This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+OpenSSL 0.9.8g does not enable TLS extension support by default, so it
+will need to be enabled by adding enable-tlsext to config script
+command line.
+
+
+diff -upr openssl-0.9.8g.orig/ssl/s3_clnt.c openssl-0.9.8g/ssl/s3_clnt.c
+--- openssl-0.9.8g.orig/ssl/s3_clnt.c	2007-08-31 03:28:51.000000000 +0300
++++ openssl-0.9.8g/ssl/s3_clnt.c	2008-04-15 17:11:46.000000000 +0300
+@@ -727,6 +727,20 @@ int ssl3_get_server_hello(SSL *s)
+ 		goto f_err;
+ 		}
+ 
++#ifndef OPENSSL_NO_TLSEXT
++	/* check if we want to resume the session based on external pre-shared secret */
++	if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++	{
++		SSL_CIPHER *pref_cipher=NULL;
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++			NULL, &pref_cipher, s->tls_session_secret_cb_arg))
++		{
++			s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
++		}
++	}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ 	if (j != 0 && j == s->session->session_id_length
+ 	    && memcmp(p,s->session->session_id,j) == 0)
+ 	    {
+diff -upr openssl-0.9.8g.orig/ssl/s3_srvr.c openssl-0.9.8g/ssl/s3_srvr.c
+--- openssl-0.9.8g.orig/ssl/s3_srvr.c	2007-09-30 21:55:59.000000000 +0300
++++ openssl-0.9.8g/ssl/s3_srvr.c	2008-04-15 17:10:37.000000000 +0300
+@@ -928,6 +928,59 @@ int ssl3_get_client_hello(SSL *s)
+ 			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+ 			goto err;
+ 		}
++
++	/* Check if we want to use external pre-shared secret for this
++	 * handshake for not reused session only. We need to generate
++	 * server_random before calling tls_session_secret_cb in order to allow
++	 * SessionTicket processing to use it in key derivation. */
++	{
++		unsigned long Time;
++		unsigned char *pos;
++		Time=(unsigned long)time(NULL);			/* Time */
++		pos=s->s3->server_random;
++		l2n(Time,pos);
++		if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
++		{
++			al=SSL_AD_INTERNAL_ERROR;
++			goto f_err;
++		}
++	}
++
++	if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++	{
++		SSL_CIPHER *pref_cipher=NULL;
++
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, 
++			ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
++		{
++			s->hit=1;
++			s->session->ciphers=ciphers;
++			s->session->verify_result=X509_V_OK;
++			
++			ciphers=NULL;
++			
++			/* check if some cipher was preferred by call back */
++			pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
++			if (pref_cipher == NULL)
++				{
++				al=SSL_AD_HANDSHAKE_FAILURE;
++				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
++				goto f_err;
++				}
++
++			s->session->cipher=pref_cipher;
++
++			if (s->cipher_list)
++				sk_SSL_CIPHER_free(s->cipher_list);
++
++			if (s->cipher_list_by_id)
++				sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++			s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++			s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++		}
++	}
+ #endif
+ 	/* Worst case, we will use the NULL compression, but if we have other
+ 	 * options, we will now look for them.  We have i-1 compression
+@@ -1066,16 +1119,22 @@ int ssl3_send_server_hello(SSL *s)
+ 	unsigned char *buf;
+ 	unsigned char *p,*d;
+ 	int i,sl;
+-	unsigned long l,Time;
++	unsigned long l;
++#ifdef OPENSSL_NO_TLSEXT
++	unsigned long Time;
++#endif
+ 
+ 	if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+ 		{
+ 		buf=(unsigned char *)s->init_buf->data;
++#ifdef OPENSSL_NO_TLSEXT
+ 		p=s->s3->server_random;
++		/* Generate server_random if it was not needed previously */
+ 		Time=(unsigned long)time(NULL);			/* Time */
+ 		l2n(Time,p);
+ 		if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
+ 			return -1;
++#endif
+ 		/* Do the message type and length last */
+ 		d=p= &(buf[4]);
+ 
+diff -upr openssl-0.9.8g.orig/ssl/ssl.h openssl-0.9.8g/ssl/ssl.h
+--- openssl-0.9.8g.orig/ssl/ssl.h	2007-10-19 10:42:38.000000000 +0300
++++ openssl-0.9.8g/ssl/ssl.h	2008-04-15 17:10:37.000000000 +0300
+@@ -342,6 +342,7 @@ extern "C" {
+  * 'struct ssl_st *' function parameters used to prototype callbacks
+  * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_extension_st TLS_EXTENSION;
+ 
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -363,6 +364,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+ typedef struct ssl_st SSL;
+ typedef struct ssl_ctx_st SSL_CTX;
+ 
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ 	{
+@@ -1004,6 +1007,14 @@ struct ssl_st
+ 	                       */
+ 	/* RFC4507 session ticket expected to be received or sent */
+ 	int tlsext_ticket_expected;
++
++	/* TLS extensions */
++	TLS_EXTENSION *tls_extension;
++
++	/* TLS pre-shared secret session resumption */
++	tls_session_secret_cb_fn tls_session_secret_cb;
++	void *tls_session_secret_cb_arg;
++
+ 	SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
+ #define session_ctx initial_ctx
+ #else
+@@ -1589,6 +1600,12 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+ 
++/* TLS extensions functions */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+  * made after this point may be overwritten when the script is next run.
+@@ -1778,6 +1795,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_ENC					 210
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
+ #define SSL_F_WRITE_PENDING				 212
++#define SSL_F_SSL_SET_HELLO_EXTENSION			 213
+ 
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
+diff -upr openssl-0.9.8g.orig/ssl/ssl_err.c openssl-0.9.8g/ssl/ssl_err.c
+--- openssl-0.9.8g.orig/ssl/ssl_err.c	2007-10-11 17:36:59.000000000 +0300
++++ openssl-0.9.8g/ssl/ssl_err.c	2008-04-15 17:10:37.000000000 +0300
+@@ -250,6 +250,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
+ {ERR_FUNC(SSL_F_TLS1_ENC),	"TLS1_ENC"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING),	"WRITE_PENDING"},
++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
+ {0,NULL}
+ 	};
+ 
+diff -upr openssl-0.9.8g.orig/ssl/ssl_sess.c openssl-0.9.8g/ssl/ssl_sess.c
+--- openssl-0.9.8g.orig/ssl/ssl_sess.c	2007-10-19 10:36:34.000000000 +0300
++++ openssl-0.9.8g/ssl/ssl_sess.c	2008-04-15 17:10:37.000000000 +0300
+@@ -704,6 +704,52 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+ 	return(s->session_timeout);
+ 	}
+ 
++#ifndef OPENSSL_NO_TLSEXT
++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, 
++	STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
++{
++	if (s == NULL) return(0);
++	s->tls_session_secret_cb = tls_session_secret_cb;
++	s->tls_session_secret_cb_arg = arg;
++	return(1);
++}
++
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
++{
++	if(s->version >= TLS1_VERSION)
++	{
++		if(s->tls_extension)
++		{
++			OPENSSL_free(s->tls_extension);
++			s->tls_extension = NULL;
++		}
++
++		s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
++		if(!s->tls_extension)
++		{
++			SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
++			return 0;
++		}
++
++		s->tls_extension->type = ext_type;
++
++		if(ext_data)
++		{
++			s->tls_extension->length = ext_len;
++			s->tls_extension->data = s->tls_extension + 1;
++			memcpy(s->tls_extension->data, ext_data, ext_len);
++		} else {
++			s->tls_extension->length = 0;
++			s->tls_extension->data = NULL;
++		}
++
++		return 1;
++	}
++
++	return 0;
++}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ typedef struct timeout_param_st
+ 	{
+ 	SSL_CTX *ctx;
+diff -upr openssl-0.9.8g.orig/ssl/t1_lib.c openssl-0.9.8g/ssl/t1_lib.c
+--- openssl-0.9.8g.orig/ssl/t1_lib.c	2007-10-19 10:44:10.000000000 +0300
++++ openssl-0.9.8g/ssl/t1_lib.c	2008-04-15 17:10:37.000000000 +0300
+@@ -105,6 +105,12 @@ int tls1_new(SSL *s)
+ 
+ void tls1_free(SSL *s)
+ 	{
++#ifndef OPENSSL_NO_TLSEXT
++	if(s->tls_extension)
++	{
++		OPENSSL_free(s->tls_extension);
++	}
++#endif
+ 	ssl3_free(s);
+ 	}
+ 
+@@ -174,8 +180,24 @@ unsigned char *ssl_add_clienthello_tlsex
+ 		int ticklen;
+ 		if (s->session && s->session->tlsext_tick)
+ 			ticklen = s->session->tlsext_ticklen;
++		else if (s->session && s->tls_extension &&
++			s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
++			s->tls_extension->data)
++		{
++			ticklen = s->tls_extension->length;
++			s->session->tlsext_tick = OPENSSL_malloc(ticklen);
++			if (!s->session->tlsext_tick)
++				return NULL;
++			memcpy(s->session->tlsext_tick, s->tls_extension->data,
++			       ticklen);
++			s->session->tlsext_ticklen = ticklen;
++		}
+ 		else
+ 			ticklen = 0;
++		if (ticklen == 0 && s->tls_extension &&
++		    s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
++		    s->tls_extension->data == NULL)
++			goto skip_ext;
+ 		/* Check for enough room 2 for extension type, 2 for len
+  		 * rest for ticket
+   		 */
+@@ -189,6 +211,7 @@ unsigned char *ssl_add_clienthello_tlsex
+ 			ret += ticklen;
+ 			}
+ 		}
++		skip_ext:
+ 
+ 	if ((extdatalen = ret-p-2)== 0) 
+ 		return p;
+@@ -543,6 +566,8 @@ int tls1_process_ticket(SSL *s, unsigned
+ 				s->tlsext_ticket_expected = 1;
+ 				return 0;	/* Cache miss */
+ 				}
++			if (s->tls_session_secret_cb)
++				return 0;
+ 			return tls_decrypt_ticket(s, p, size, session_id, len,
+ 									ret);
+ 			}
+diff -upr openssl-0.9.8g.orig/ssl/tls1.h openssl-0.9.8g/ssl/tls1.h
+--- openssl-0.9.8g.orig/ssl/tls1.h	2007-08-28 04:12:44.000000000 +0300
++++ openssl-0.9.8g/ssl/tls1.h	2008-04-15 17:10:37.000000000 +0300
+@@ -365,6 +365,14 @@ SSL_CTX_ctrl(ctx,SSL_CTRL_SET_TLSEXT_SER
+ #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
+ #endif
+ 
++/* TLS extension struct */
++struct tls_extension_st
++{
++	unsigned short type;
++	unsigned short length;
++	void *data;
++};
++
+ #ifdef  __cplusplus
+ }
+ #endif
+diff -upr openssl-0.9.8g.orig/util/ssleay.num openssl-0.9.8g/util/ssleay.num
+--- openssl-0.9.8g.orig/util/ssleay.num	2007-08-13 01:31:16.000000000 +0300
++++ openssl-0.9.8g/util/ssleay.num	2008-04-15 17:10:37.000000000 +0300
+@@ -241,3 +241,5 @@ SSL_CTX_sess_get_remove_cb              
+ SSL_set_SSL_CTX                         290	EXIST::FUNCTION:
+ SSL_get_servername                      291	EXIST::FUNCTION:TLSEXT
+ SSL_get_servername_type                 292	EXIST::FUNCTION:TLSEXT
++SSL_set_hello_extension			305	EXIST::FUNCTION:TLSEXT
++SSL_set_session_secret_cb		306	EXIST::FUNCTION:TLSEXT
diff --git a/hostap/patches/openssl-0.9.8h-tls-extensions.patch b/hostap/patches/openssl-0.9.8h-tls-extensions.patch
new file mode 100644
index 0000000..c68f227
--- /dev/null
+++ b/hostap/patches/openssl-0.9.8h-tls-extensions.patch
@@ -0,0 +1,344 @@
+This patch adds support for TLS SessionTicket extension (RFC 5077) for
+the parts used by EAP-FAST (RFC 4851).
+
+This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+OpenSSL 0.9.8h does not enable TLS extension support by default, so it
+will need to be enabled by adding enable-tlsext to config script
+command line.
+
+
+diff -upr openssl-0.9.8h.orig/ssl/s3_clnt.c openssl-0.9.8h/ssl/s3_clnt.c
+--- openssl-0.9.8h.orig/ssl/s3_clnt.c	2008-05-28 10:29:27.000000000 +0300
++++ openssl-0.9.8h/ssl/s3_clnt.c	2008-05-29 10:44:25.000000000 +0300
+@@ -752,6 +752,20 @@ int ssl3_get_server_hello(SSL *s)
+ 		goto f_err;
+ 		}
+ 
++#ifndef OPENSSL_NO_TLSEXT
++	/* check if we want to resume the session based on external pre-shared secret */
++	if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++	{
++		SSL_CIPHER *pref_cipher=NULL;
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++			NULL, &pref_cipher, s->tls_session_secret_cb_arg))
++		{
++			s->session->cipher=pref_cipher ? pref_cipher : ssl_get_cipher_by_char(s,p+j);
++		}
++	}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ 	if (j != 0 && j == s->session->session_id_length
+ 	    && memcmp(p,s->session->session_id,j) == 0)
+ 	    {
+@@ -2693,11 +2707,8 @@ static int ssl3_check_finished(SSL *s)
+ 	{
+ 	int ok;
+ 	long n;
+-	/* If we have no ticket or session ID is non-zero length (a match of
+-	 * a non-zero session length would never reach here) it cannot be a
+-	 * resumed session.
+-	 */
+-	if (!s->session->tlsext_tick || s->session->session_id_length)
++	/* If we have no ticket it cannot be a resumed session. */
++	if (!s->session->tlsext_tick)
+ 		return 1;
+ 	/* this function is called when we really expect a Certificate
+ 	 * message, so permit appropriate message length */
+diff -upr openssl-0.9.8h.orig/ssl/s3_srvr.c openssl-0.9.8h/ssl/s3_srvr.c
+--- openssl-0.9.8h.orig/ssl/s3_srvr.c	2008-04-30 19:11:32.000000000 +0300
++++ openssl-0.9.8h/ssl/s3_srvr.c	2008-05-28 18:49:34.000000000 +0300
+@@ -959,6 +959,59 @@ int ssl3_get_client_hello(SSL *s)
+ 			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+ 			goto err;
+ 		}
++
++	/* Check if we want to use external pre-shared secret for this
++	 * handshake for not reused session only. We need to generate
++	 * server_random before calling tls_session_secret_cb in order to allow
++	 * SessionTicket processing to use it in key derivation. */
++	{
++		unsigned long Time;
++		unsigned char *pos;
++		Time=(unsigned long)time(NULL);			/* Time */
++		pos=s->s3->server_random;
++		l2n(Time,pos);
++		if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
++		{
++			al=SSL_AD_INTERNAL_ERROR;
++			goto f_err;
++		}
++	}
++
++	if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++	{
++		SSL_CIPHER *pref_cipher=NULL;
++
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, 
++			ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
++		{
++			s->hit=1;
++			s->session->ciphers=ciphers;
++			s->session->verify_result=X509_V_OK;
++			
++			ciphers=NULL;
++			
++			/* check if some cipher was preferred by call back */
++			pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
++			if (pref_cipher == NULL)
++				{
++				al=SSL_AD_HANDSHAKE_FAILURE;
++				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
++				goto f_err;
++				}
++
++			s->session->cipher=pref_cipher;
++
++			if (s->cipher_list)
++				sk_SSL_CIPHER_free(s->cipher_list);
++
++			if (s->cipher_list_by_id)
++				sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++			s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++			s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++		}
++	}
+ #endif
+ 	/* Worst case, we will use the NULL compression, but if we have other
+ 	 * options, we will now look for them.  We have i-1 compression
+@@ -1097,16 +1150,22 @@ int ssl3_send_server_hello(SSL *s)
+ 	unsigned char *buf;
+ 	unsigned char *p,*d;
+ 	int i,sl;
+-	unsigned long l,Time;
++	unsigned long l;
++#ifdef OPENSSL_NO_TLSEXT
++	unsigned long Time;
++#endif
+ 
+ 	if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+ 		{
+ 		buf=(unsigned char *)s->init_buf->data;
++#ifdef OPENSSL_NO_TLSEXT
+ 		p=s->s3->server_random;
++		/* Generate server_random if it was not needed previously */
+ 		Time=(unsigned long)time(NULL);			/* Time */
+ 		l2n(Time,p);
+ 		if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
+ 			return -1;
++#endif
+ 		/* Do the message type and length last */
+ 		d=p= &(buf[4]);
+ 
+diff -upr openssl-0.9.8h.orig/ssl/ssl.h openssl-0.9.8h/ssl/ssl.h
+--- openssl-0.9.8h.orig/ssl/ssl.h	2008-04-30 19:11:32.000000000 +0300
++++ openssl-0.9.8h/ssl/ssl.h	2008-05-28 18:49:34.000000000 +0300
+@@ -343,6 +343,7 @@ extern "C" {
+  * 'struct ssl_st *' function parameters used to prototype callbacks
+  * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_extension_st TLS_EXTENSION;
+ 
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -364,6 +365,8 @@ DECLARE_STACK_OF(SSL_CIPHER)
+ typedef struct ssl_st SSL;
+ typedef struct ssl_ctx_st SSL_CTX;
+ 
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ 	{
+@@ -1027,6 +1030,14 @@ struct ssl_st
+ 
+ 	/* RFC4507 session ticket expected to be received or sent */
+ 	int tlsext_ticket_expected;
++
++	/* TLS extensions */
++	TLS_EXTENSION *tls_extension;
++
++	/* TLS pre-shared secret session resumption */
++	tls_session_secret_cb_fn tls_session_secret_cb;
++	void *tls_session_secret_cb_arg;
++
+ 	SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
+ #define session_ctx initial_ctx
+ #else
+@@ -1625,6 +1636,12 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+ 
++/* TLS extensions functions */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+  * made after this point may be overwritten when the script is next run.
+@@ -1815,6 +1832,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_ENC					 210
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
+ #define SSL_F_WRITE_PENDING				 212
++#define SSL_F_SSL_SET_HELLO_EXTENSION			 213
+ 
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
+diff -upr openssl-0.9.8h.orig/ssl/ssl_err.c openssl-0.9.8h/ssl/ssl_err.c
+--- openssl-0.9.8h.orig/ssl/ssl_err.c	2007-10-12 03:00:30.000000000 +0300
++++ openssl-0.9.8h/ssl/ssl_err.c	2008-05-28 18:49:34.000000000 +0300
+@@ -251,6 +251,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
+ {ERR_FUNC(SSL_F_TLS1_ENC),	"TLS1_ENC"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING),	"WRITE_PENDING"},
++{ERR_FUNC(SSL_F_SSL_SET_HELLO_EXTENSION), "SSL_set_hello_extension"},
+ {0,NULL}
+ 	};
+ 
+diff -upr openssl-0.9.8h.orig/ssl/ssl_sess.c openssl-0.9.8h/ssl/ssl_sess.c
+--- openssl-0.9.8h.orig/ssl/ssl_sess.c	2007-10-17 20:30:15.000000000 +0300
++++ openssl-0.9.8h/ssl/ssl_sess.c	2008-05-28 18:49:34.000000000 +0300
+@@ -704,6 +704,52 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+ 	return(s->session_timeout);
+ 	}
+ 
++#ifndef OPENSSL_NO_TLSEXT
++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len, 
++	STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
++{
++	if (s == NULL) return(0);
++	s->tls_session_secret_cb = tls_session_secret_cb;
++	s->tls_session_secret_cb_arg = arg;
++	return(1);
++}
++
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
++{
++	if(s->version >= TLS1_VERSION)
++	{
++		if(s->tls_extension)
++		{
++			OPENSSL_free(s->tls_extension);
++			s->tls_extension = NULL;
++		}
++
++		s->tls_extension = OPENSSL_malloc(sizeof(TLS_EXTENSION) + ext_len);
++		if(!s->tls_extension)
++		{
++			SSLerr(SSL_F_SSL_SET_HELLO_EXTENSION, ERR_R_MALLOC_FAILURE);
++			return 0;
++		}
++
++		s->tls_extension->type = ext_type;
++
++		if(ext_data)
++		{
++			s->tls_extension->length = ext_len;
++			s->tls_extension->data = s->tls_extension + 1;
++			memcpy(s->tls_extension->data, ext_data, ext_len);
++		} else {
++			s->tls_extension->length = 0;
++			s->tls_extension->data = NULL;
++		}
++
++		return 1;
++	}
++
++	return 0;
++}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ typedef struct timeout_param_st
+ 	{
+ 	SSL_CTX *ctx;
+diff -upr openssl-0.9.8h.orig/ssl/t1_lib.c openssl-0.9.8h/ssl/t1_lib.c
+--- openssl-0.9.8h.orig/ssl/t1_lib.c	2008-05-28 10:26:33.000000000 +0300
++++ openssl-0.9.8h/ssl/t1_lib.c	2008-05-28 18:49:34.000000000 +0300
+@@ -106,6 +106,12 @@ int tls1_new(SSL *s)
+ 
+ void tls1_free(SSL *s)
+ 	{
++#ifndef OPENSSL_NO_TLSEXT
++	if(s->tls_extension)
++	{
++		OPENSSL_free(s->tls_extension);
++	}
++#endif
+ 	ssl3_free(s);
+ 	}
+ 
+@@ -175,8 +181,24 @@ unsigned char *ssl_add_clienthello_tlsex
+ 		int ticklen;
+ 		if (s->session && s->session->tlsext_tick)
+ 			ticklen = s->session->tlsext_ticklen;
++		else if (s->session && s->tls_extension &&
++			s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
++			s->tls_extension->data)
++		{
++			ticklen = s->tls_extension->length;
++			s->session->tlsext_tick = OPENSSL_malloc(ticklen);
++			if (!s->session->tlsext_tick)
++				return NULL;
++			memcpy(s->session->tlsext_tick, s->tls_extension->data,
++			       ticklen);
++			s->session->tlsext_ticklen = ticklen;
++		}
+ 		else
+ 			ticklen = 0;
++		if (ticklen == 0 && s->tls_extension &&
++		    s->tls_extension->type == TLSEXT_TYPE_session_ticket &&
++		    s->tls_extension->data == NULL)
++			goto skip_ext;
+ 		/* Check for enough room 2 for extension type, 2 for len
+  		 * rest for ticket
+   		 */
+@@ -190,6 +212,7 @@ unsigned char *ssl_add_clienthello_tlsex
+ 			ret += ticklen;
+ 			}
+ 		}
++		skip_ext:
+ 
+ 	if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
+ 		{
+@@ -774,6 +797,8 @@ int tls1_process_ticket(SSL *s, unsigned
+ 				s->tlsext_ticket_expected = 1;
+ 				return 0;	/* Cache miss */
+ 				}
++			if (s->tls_session_secret_cb)
++				return 0;
+ 			return tls_decrypt_ticket(s, p, size, session_id, len,
+ 									ret);
+ 			}
+diff -upr openssl-0.9.8h.orig/ssl/tls1.h openssl-0.9.8h/ssl/tls1.h
+--- openssl-0.9.8h.orig/ssl/tls1.h	2008-04-30 19:11:33.000000000 +0300
++++ openssl-0.9.8h/ssl/tls1.h	2008-05-28 18:49:34.000000000 +0300
+@@ -398,6 +398,14 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
+ #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
+ #endif
+ 
++/* TLS extension struct */
++struct tls_extension_st
++{
++	unsigned short type;
++	unsigned short length;
++	void *data;
++};
++
+ #ifdef  __cplusplus
+ }
+ #endif
+diff -upr openssl-0.9.8h.orig/util/ssleay.num openssl-0.9.8h/util/ssleay.num
+--- openssl-0.9.8h.orig/util/ssleay.num	2007-08-13 01:31:16.000000000 +0300
++++ openssl-0.9.8h/util/ssleay.num	2008-05-28 18:49:34.000000000 +0300
+@@ -241,3 +241,5 @@ SSL_CTX_sess_get_remove_cb              
+ SSL_set_SSL_CTX                         290	EXIST::FUNCTION:
+ SSL_get_servername                      291	EXIST::FUNCTION:TLSEXT
+ SSL_get_servername_type                 292	EXIST::FUNCTION:TLSEXT
++SSL_set_hello_extension			305	EXIST::FUNCTION:TLSEXT
++SSL_set_session_secret_cb		306	EXIST::FUNCTION:TLSEXT
diff --git a/hostap/patches/openssl-0.9.8i-tls-extensions.patch b/hostap/patches/openssl-0.9.8i-tls-extensions.patch
new file mode 100644
index 0000000..90bff54
--- /dev/null
+++ b/hostap/patches/openssl-0.9.8i-tls-extensions.patch
@@ -0,0 +1,404 @@
+This patch adds support for TLS SessionTicket extension (RFC 5077) for
+the parts used by EAP-FAST (RFC 4851).
+
+This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+OpenSSL 0.9.8i does not enable TLS extension support by default, so it
+will need to be enabled by adding enable-tlsext to config script
+command line.
+
+
+Index: openssl-0.9.8i/ssl/s3_clnt.c
+===================================================================
+--- openssl-0.9.8i.orig/ssl/s3_clnt.c	2008-06-16 19:56:41.000000000 +0300
++++ openssl-0.9.8i/ssl/s3_clnt.c	2008-11-23 20:39:40.000000000 +0200
+@@ -759,6 +759,21 @@
+ 		goto f_err;
+ 		}
+ 
++#ifndef OPENSSL_NO_TLSEXT
++	/* check if we want to resume the session based on external pre-shared secret */
++	if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++		{
++		SSL_CIPHER *pref_cipher=NULL;
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++			NULL, &pref_cipher, s->tls_session_secret_cb_arg))
++			{
++			s->session->cipher=pref_cipher ?
++				pref_cipher : ssl_get_cipher_by_char(s,p+j);
++			}
++		}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ 	if (j != 0 && j == s->session->session_id_length
+ 	    && memcmp(p,s->session->session_id,j) == 0)
+ 	    {
+@@ -2701,11 +2716,8 @@
+ 	{
+ 	int ok;
+ 	long n;
+-	/* If we have no ticket or session ID is non-zero length (a match of
+-	 * a non-zero session length would never reach here) it cannot be a
+-	 * resumed session.
+-	 */
+-	if (!s->session->tlsext_tick || s->session->session_id_length)
++	/* If we have no ticket it cannot be a resumed session. */
++	if (!s->session->tlsext_tick)
+ 		return 1;
+ 	/* this function is called when we really expect a Certificate
+ 	 * message, so permit appropriate message length */
+Index: openssl-0.9.8i/ssl/s3_srvr.c
+===================================================================
+--- openssl-0.9.8i.orig/ssl/s3_srvr.c	2008-09-14 21:16:09.000000000 +0300
++++ openssl-0.9.8i/ssl/s3_srvr.c	2008-11-23 20:37:40.000000000 +0200
+@@ -959,6 +959,59 @@
+ 			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+ 			goto err;
+ 		}
++
++	/* Check if we want to use external pre-shared secret for this
++	 * handshake for not reused session only. We need to generate
++	 * server_random before calling tls_session_secret_cb in order to allow
++	 * SessionTicket processing to use it in key derivation. */
++	{
++		unsigned long Time;
++		unsigned char *pos;
++		Time=(unsigned long)time(NULL);			/* Time */
++		pos=s->s3->server_random;
++		l2n(Time,pos);
++		if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
++			{
++			al=SSL_AD_INTERNAL_ERROR;
++			goto f_err;
++			}
++	}
++
++	if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++		{
++		SSL_CIPHER *pref_cipher=NULL;
++
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, 
++			ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
++			{
++			s->hit=1;
++			s->session->ciphers=ciphers;
++			s->session->verify_result=X509_V_OK;
++			
++			ciphers=NULL;
++			
++			/* check if some cipher was preferred by call back */
++			pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
++			if (pref_cipher == NULL)
++				{
++				al=SSL_AD_HANDSHAKE_FAILURE;
++				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
++				goto f_err;
++				}
++
++			s->session->cipher=pref_cipher;
++
++			if (s->cipher_list)
++				sk_SSL_CIPHER_free(s->cipher_list);
++
++			if (s->cipher_list_by_id)
++				sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++			s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++			s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++			}
++		}
+ #endif
+ 	/* Worst case, we will use the NULL compression, but if we have other
+ 	 * options, we will now look for them.  We have i-1 compression
+@@ -1097,16 +1150,22 @@
+ 	unsigned char *buf;
+ 	unsigned char *p,*d;
+ 	int i,sl;
+-	unsigned long l,Time;
++	unsigned long l;
++#ifdef OPENSSL_NO_TLSEXT
++	unsigned long Time;
++#endif
+ 
+ 	if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+ 		{
+ 		buf=(unsigned char *)s->init_buf->data;
++#ifdef OPENSSL_NO_TLSEXT
+ 		p=s->s3->server_random;
++		/* Generate server_random if it was not needed previously */
+ 		Time=(unsigned long)time(NULL);			/* Time */
+ 		l2n(Time,p);
+ 		if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
+ 			return -1;
++#endif
+ 		/* Do the message type and length last */
+ 		d=p= &(buf[4]);
+ 
+Index: openssl-0.9.8i/ssl/ssl_err.c
+===================================================================
+--- openssl-0.9.8i.orig/ssl/ssl_err.c	2008-08-13 22:44:44.000000000 +0300
++++ openssl-0.9.8i/ssl/ssl_err.c	2008-11-23 20:33:43.000000000 +0200
+@@ -253,6 +253,7 @@
+ {ERR_FUNC(SSL_F_TLS1_ENC),	"TLS1_ENC"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING),	"WRITE_PENDING"},
++{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
+ {0,NULL}
+ 	};
+ 
+Index: openssl-0.9.8i/ssl/ssl.h
+===================================================================
+--- openssl-0.9.8i.orig/ssl/ssl.h	2008-08-13 22:44:44.000000000 +0300
++++ openssl-0.9.8i/ssl/ssl.h	2008-11-23 20:35:41.000000000 +0200
+@@ -344,6 +344,7 @@
+  * 'struct ssl_st *' function parameters used to prototype callbacks
+  * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
+ 
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -362,6 +363,9 @@
+ 
+ DECLARE_STACK_OF(SSL_CIPHER)
+ 
++typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg);
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ 	{
+@@ -1034,6 +1038,18 @@
+ 
+ 	/* RFC4507 session ticket expected to be received or sent */
+ 	int tlsext_ticket_expected;
++
++	/* TLS Session Ticket extension override */
++	TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
++
++	/* TLS Session Ticket extension callback */
++	tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
++	void *tls_session_ticket_ext_cb_arg;
++
++	/* TLS pre-shared secret session resumption */
++	tls_session_secret_cb_fn tls_session_secret_cb;
++	void *tls_session_secret_cb_arg;
++
+ 	SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
+ #define session_ctx initial_ctx
+ #else
+@@ -1632,6 +1648,15 @@
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+ 
++/* TLS extensions functions */
++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
++
++int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
++				  void *arg);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+  * made after this point may be overwritten when the script is next run.
+@@ -1824,6 +1849,7 @@
+ #define SSL_F_TLS1_ENC					 210
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
+ #define SSL_F_WRITE_PENDING				 212
++#define SSL_F_SSL_SET_SESSION_TICKET_EXT		 213
+ 
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
+Index: openssl-0.9.8i/ssl/ssl_sess.c
+===================================================================
+--- openssl-0.9.8i.orig/ssl/ssl_sess.c	2008-06-04 21:35:27.000000000 +0300
++++ openssl-0.9.8i/ssl/ssl_sess.c	2008-11-23 20:32:24.000000000 +0200
+@@ -707,6 +707,61 @@
+ 	return(s->session_timeout);
+ 	}
+ 
++#ifndef OPENSSL_NO_TLSEXT
++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
++	STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
++	{
++	if (s == NULL) return(0);
++	s->tls_session_secret_cb = tls_session_secret_cb;
++	s->tls_session_secret_cb_arg = arg;
++	return(1);
++	}
++
++int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
++				  void *arg)
++	{
++	if (s == NULL) return(0);
++	s->tls_session_ticket_ext_cb = cb;
++	s->tls_session_ticket_ext_cb_arg = arg;
++	return(1);
++	}
++
++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
++	{
++	if (s->version >= TLS1_VERSION)
++		{
++		if (s->tlsext_session_ticket)
++			{
++			OPENSSL_free(s->tlsext_session_ticket);
++			s->tlsext_session_ticket = NULL;
++			}
++
++		s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
++		if (!s->tlsext_session_ticket)
++			{
++			SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
++			return 0;
++			}
++
++		if (ext_data)
++			{
++			s->tlsext_session_ticket->length = ext_len;
++			s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
++			memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
++			}
++		else
++			{
++			s->tlsext_session_ticket->length = 0;
++			s->tlsext_session_ticket->data = NULL;
++			}
++
++		return 1;
++		}
++
++	return 0;
++	}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ typedef struct timeout_param_st
+ 	{
+ 	SSL_CTX *ctx;
+Index: openssl-0.9.8i/ssl/t1_lib.c
+===================================================================
+--- openssl-0.9.8i.orig/ssl/t1_lib.c	2008-09-04 01:13:04.000000000 +0300
++++ openssl-0.9.8i/ssl/t1_lib.c	2008-11-23 20:31:20.000000000 +0200
+@@ -106,6 +106,12 @@
+ 
+ void tls1_free(SSL *s)
+ 	{
++#ifndef OPENSSL_NO_TLSEXT
++	if (s->tlsext_session_ticket)
++		{
++		OPENSSL_free(s->tlsext_session_ticket);
++		}
++#endif
+ 	ssl3_free(s);
+ 	}
+ 
+@@ -175,8 +181,23 @@
+ 		int ticklen;
+ 		if (s->session && s->session->tlsext_tick)
+ 			ticklen = s->session->tlsext_ticklen;
++		else if (s->session && s->tlsext_session_ticket &&
++			 s->tlsext_session_ticket->data)
++			{
++			ticklen = s->tlsext_session_ticket->length;
++			s->session->tlsext_tick = OPENSSL_malloc(ticklen);
++			if (!s->session->tlsext_tick)
++				return NULL;
++			memcpy(s->session->tlsext_tick,
++			       s->tlsext_session_ticket->data,
++			       ticklen);
++			s->session->tlsext_ticklen = ticklen;
++			}
+ 		else
+ 			ticklen = 0;
++		if (ticklen == 0 && s->tlsext_session_ticket &&
++		    s->tlsext_session_ticket->data == NULL)
++			goto skip_ext;
+ 		/* Check for enough room 2 for extension type, 2 for len
+  		 * rest for ticket
+   		 */
+@@ -190,6 +211,7 @@
+ 			ret += ticklen;
+ 			}
+ 		}
++		skip_ext:
+ 
+ 	if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp)
+ 		{
+@@ -407,6 +429,15 @@
+ 				}
+ 
+ 			}
++		else if (type == TLSEXT_TYPE_session_ticket)
++			{
++			if (s->tls_session_ticket_ext_cb &&
++			    !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
++				{
++				*al = TLS1_AD_INTERNAL_ERROR;
++				return 0;
++				}
++			}
+ 		else if (type == TLSEXT_TYPE_status_request
+ 						&& s->ctx->tlsext_status_cb)
+ 			{
+@@ -553,6 +584,12 @@
+ 			}
+ 		else if (type == TLSEXT_TYPE_session_ticket)
+ 			{
++			if (s->tls_session_ticket_ext_cb &&
++			    !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
++				{
++				*al = TLS1_AD_INTERNAL_ERROR;
++				return 0;
++				}
+ 			if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
+ 				|| (size > 0))
+ 				{
+@@ -776,6 +813,15 @@
+ 				s->tlsext_ticket_expected = 1;
+ 				return 0;	/* Cache miss */
+ 				}
++			if (s->tls_session_secret_cb)
++				{
++				/* Indicate cache miss here and instead of
++				 * generating the session from ticket now,
++				 * trigger abbreviated handshake based on
++				 * external mechanism to calculate the master
++				 * secret later. */
++				return 0;
++				}
+ 			return tls_decrypt_ticket(s, p, size, session_id, len,
+ 									ret);
+ 			}
+Index: openssl-0.9.8i/ssl/tls1.h
+===================================================================
+--- openssl-0.9.8i.orig/ssl/tls1.h	2008-04-30 19:11:33.000000000 +0300
++++ openssl-0.9.8i/ssl/tls1.h	2008-11-23 20:22:38.000000000 +0200
+@@ -398,6 +398,13 @@
+ #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
+ #endif
+ 
++/* TLS extension struct */
++struct tls_session_ticket_ext_st
++	{
++	unsigned short length;
++	void *data;
++	};
++
+ #ifdef  __cplusplus
+ }
+ #endif
+Index: openssl-0.9.8i/util/ssleay.num
+===================================================================
+--- openssl-0.9.8i.orig/util/ssleay.num	2008-06-05 13:57:21.000000000 +0300
++++ openssl-0.9.8i/util/ssleay.num	2008-11-23 20:22:05.000000000 +0200
+@@ -242,3 +242,5 @@
+ SSL_get_servername                      291	EXIST::FUNCTION:TLSEXT
+ SSL_get_servername_type                 292	EXIST::FUNCTION:TLSEXT
+ SSL_CTX_set_client_cert_engine          293	EXIST::FUNCTION:ENGINE
++SSL_set_session_ticket_ext		306	EXIST::FUNCTION:TLSEXT
++SSL_set_session_secret_cb		307	EXIST::FUNCTION:TLSEXT
diff --git a/hostap/patches/openssl-0.9.8x-tls-extensions.patch b/hostap/patches/openssl-0.9.8x-tls-extensions.patch
new file mode 100644
index 0000000..d1c0dbe
--- /dev/null
+++ b/hostap/patches/openssl-0.9.8x-tls-extensions.patch
@@ -0,0 +1,396 @@
+This patch adds support for TLS SessionTicket extension (RFC 5077) for
+the parts used by EAP-FAST (RFC 4851).
+
+This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+OpenSSL 0.9.8x does not enable TLS extension support by default, so it
+will need to be enabled by adding enable-tlsext to config script
+command line.
+
+
+diff -upr openssl-0.9.8x.orig/ssl/s3_clnt.c openssl-0.9.8x/ssl/s3_clnt.c
+--- openssl-0.9.8x.orig/ssl/s3_clnt.c	2011-12-26 21:38:28.000000000 +0200
++++ openssl-0.9.8x/ssl/s3_clnt.c	2012-07-07 10:46:31.501140621 +0300
+@@ -757,6 +757,21 @@ int ssl3_get_server_hello(SSL *s)
+ 		goto f_err;
+ 		}
+ 
++#ifndef OPENSSL_NO_TLSEXT
++	/* check if we want to resume the session based on external pre-shared secret */
++	if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++		{
++		SSL_CIPHER *pref_cipher=NULL;
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if (s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++			NULL, &pref_cipher, s->tls_session_secret_cb_arg))
++			{
++			s->session->cipher=pref_cipher ?
++				pref_cipher : ssl_get_cipher_by_char(s,p+j);
++			}
++		}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ 	if (j != 0 && j == s->session->session_id_length
+ 	    && memcmp(p,s->session->session_id,j) == 0)
+ 	    {
+@@ -2725,11 +2740,8 @@ int ssl3_check_finished(SSL *s)
+ 	{
+ 	int ok;
+ 	long n;
+-	/* If we have no ticket or session ID is non-zero length (a match of
+-	 * a non-zero session length would never reach here) it cannot be a
+-	 * resumed session.
+-	 */
+-	if (!s->session->tlsext_tick || s->session->session_id_length)
++	/* If we have no ticket it cannot be a resumed session. */
++	if (!s->session->tlsext_tick)
+ 		return 1;
+ 	/* this function is called when we really expect a Certificate
+ 	 * message, so permit appropriate message length */
+diff -upr openssl-0.9.8x.orig/ssl/s3_srvr.c openssl-0.9.8x/ssl/s3_srvr.c
+--- openssl-0.9.8x.orig/ssl/s3_srvr.c	2012-02-16 17:21:17.000000000 +0200
++++ openssl-0.9.8x/ssl/s3_srvr.c	2012-07-07 10:46:31.501140621 +0300
+@@ -1009,6 +1009,59 @@ int ssl3_get_client_hello(SSL *s)
+ 			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+ 			goto err;
+ 		}
++
++	/* Check if we want to use external pre-shared secret for this
++	 * handshake for not reused session only. We need to generate
++	 * server_random before calling tls_session_secret_cb in order to allow
++	 * SessionTicket processing to use it in key derivation. */
++	{
++		unsigned long Time;
++		unsigned char *pos;
++		Time=(unsigned long)time(NULL);			/* Time */
++		pos=s->s3->server_random;
++		l2n(Time,pos);
++		if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
++			{
++			al=SSL_AD_INTERNAL_ERROR;
++			goto f_err;
++			}
++	}
++
++	if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++		{
++		SSL_CIPHER *pref_cipher=NULL;
++
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length, 
++			ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
++			{
++			s->hit=1;
++			s->session->ciphers=ciphers;
++			s->session->verify_result=X509_V_OK;
++			
++			ciphers=NULL;
++			
++			/* check if some cipher was preferred by call back */
++			pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
++			if (pref_cipher == NULL)
++				{
++				al=SSL_AD_HANDSHAKE_FAILURE;
++				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
++				goto f_err;
++				}
++
++			s->session->cipher=pref_cipher;
++
++			if (s->cipher_list)
++				sk_SSL_CIPHER_free(s->cipher_list);
++
++			if (s->cipher_list_by_id)
++				sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++			s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++			s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++			}
++		}
+ #endif
+ 	/* Worst case, we will use the NULL compression, but if we have other
+ 	 * options, we will now look for them.  We have i-1 compression
+@@ -1147,16 +1200,22 @@ int ssl3_send_server_hello(SSL *s)
+ 	unsigned char *buf;
+ 	unsigned char *p,*d;
+ 	int i,sl;
+-	unsigned long l,Time;
++	unsigned long l;
++#ifdef OPENSSL_NO_TLSEXT
++	unsigned long Time;
++#endif
+ 
+ 	if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+ 		{
+ 		buf=(unsigned char *)s->init_buf->data;
++#ifdef OPENSSL_NO_TLSEXT
+ 		p=s->s3->server_random;
++		/* Generate server_random if it was not needed previously */
+ 		Time=(unsigned long)time(NULL);			/* Time */
+ 		l2n(Time,p);
+ 		if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
+ 			return -1;
++#endif
+ 		/* Do the message type and length last */
+ 		d=p= &(buf[4]);
+ 
+diff -upr openssl-0.9.8x.orig/ssl/ssl_err.c openssl-0.9.8x/ssl/ssl_err.c
+--- openssl-0.9.8x.orig/ssl/ssl_err.c	2012-03-12 16:50:55.000000000 +0200
++++ openssl-0.9.8x/ssl/ssl_err.c	2012-07-07 10:46:31.501140621 +0300
+@@ -264,6 +264,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
+ {ERR_FUNC(SSL_F_TLS1_ENC),	"TLS1_ENC"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING),	"WRITE_PENDING"},
++{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
+ {0,NULL}
+ 	};
+ 
+diff -upr openssl-0.9.8x.orig/ssl/ssl.h openssl-0.9.8x/ssl/ssl.h
+--- openssl-0.9.8x.orig/ssl/ssl.h	2012-03-12 16:50:55.000000000 +0200
++++ openssl-0.9.8x/ssl/ssl.h	2012-07-07 10:46:31.501140621 +0300
+@@ -344,6 +344,7 @@ extern "C" {
+  * 'struct ssl_st *' function parameters used to prototype callbacks
+  * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
+ 
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -362,6 +363,9 @@ typedef struct ssl_cipher_st
+ 
+ DECLARE_STACK_OF(SSL_CIPHER)
+ 
++typedef int (*tls_session_ticket_ext_cb_fn)(SSL *s, const unsigned char *data, int len, void *arg);
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ 	{
+@@ -1050,6 +1054,18 @@ struct ssl_st
+ 
+ 	/* RFC4507 session ticket expected to be received or sent */
+ 	int tlsext_ticket_expected;
++
++	/* TLS Session Ticket extension override */
++	TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
++
++	/* TLS Session Ticket extension callback */
++	tls_session_ticket_ext_cb_fn tls_session_ticket_ext_cb;
++	void *tls_session_ticket_ext_cb_arg;
++
++	/* TLS pre-shared secret session resumption */
++	tls_session_secret_cb_fn tls_session_secret_cb;
++	void *tls_session_secret_cb_arg;
++
+ 	SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
+ #define session_ctx initial_ctx
+ #else
+@@ -1663,6 +1679,15 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+ 
++/* TLS extensions functions */
++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
++
++int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
++				  void *arg);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+  * made after this point may be overwritten when the script is next run.
+@@ -1866,6 +1891,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_ENC					 210
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
+ #define SSL_F_WRITE_PENDING				 212
++#define SSL_F_SSL_SET_SESSION_TICKET_EXT		 213
+ 
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
+diff -upr openssl-0.9.8x.orig/ssl/ssl_sess.c openssl-0.9.8x/ssl/ssl_sess.c
+--- openssl-0.9.8x.orig/ssl/ssl_sess.c	2010-02-01 18:48:40.000000000 +0200
++++ openssl-0.9.8x/ssl/ssl_sess.c	2012-07-07 10:46:31.501140621 +0300
+@@ -712,6 +712,61 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+ 	return(s->session_timeout);
+ 	}
+ 
++#ifndef OPENSSL_NO_TLSEXT
++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
++	STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
++	{
++	if (s == NULL) return(0);
++	s->tls_session_secret_cb = tls_session_secret_cb;
++	s->tls_session_secret_cb_arg = arg;
++	return(1);
++	}
++
++int SSL_set_session_ticket_ext_cb(SSL *s, tls_session_ticket_ext_cb_fn cb,
++				  void *arg)
++	{
++	if (s == NULL) return(0);
++	s->tls_session_ticket_ext_cb = cb;
++	s->tls_session_ticket_ext_cb_arg = arg;
++	return(1);
++	}
++
++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
++	{
++	if (s->version >= TLS1_VERSION)
++		{
++		if (s->tlsext_session_ticket)
++			{
++			OPENSSL_free(s->tlsext_session_ticket);
++			s->tlsext_session_ticket = NULL;
++			}
++
++		s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
++		if (!s->tlsext_session_ticket)
++			{
++			SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
++			return 0;
++			}
++
++		if (ext_data)
++			{
++			s->tlsext_session_ticket->length = ext_len;
++			s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
++			memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
++			}
++		else
++			{
++			s->tlsext_session_ticket->length = 0;
++			s->tlsext_session_ticket->data = NULL;
++			}
++
++		return 1;
++		}
++
++	return 0;
++	}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ typedef struct timeout_param_st
+ 	{
+ 	SSL_CTX *ctx;
+diff -upr openssl-0.9.8x.orig/ssl/t1_lib.c openssl-0.9.8x/ssl/t1_lib.c
+--- openssl-0.9.8x.orig/ssl/t1_lib.c	2012-01-04 16:25:10.000000000 +0200
++++ openssl-0.9.8x/ssl/t1_lib.c	2012-07-07 10:47:31.153140501 +0300
+@@ -106,6 +106,12 @@ int tls1_new(SSL *s)
+ 
+ void tls1_free(SSL *s)
+ 	{
++#ifndef OPENSSL_NO_TLSEXT
++	if (s->tlsext_session_ticket)
++		{
++		OPENSSL_free(s->tlsext_session_ticket);
++		}
++#endif
+ 	ssl3_free(s);
+ 	}
+ 
+@@ -206,8 +212,23 @@ unsigned char *ssl_add_clienthello_tlsex
+ 		int ticklen;
+ 		if (!s->new_session && s->session && s->session->tlsext_tick)
+ 			ticklen = s->session->tlsext_ticklen;
++		else if (s->session && s->tlsext_session_ticket &&
++			 s->tlsext_session_ticket->data)
++			{
++			ticklen = s->tlsext_session_ticket->length;
++			s->session->tlsext_tick = OPENSSL_malloc(ticklen);
++			if (!s->session->tlsext_tick)
++				return NULL;
++			memcpy(s->session->tlsext_tick,
++			       s->tlsext_session_ticket->data,
++			       ticklen);
++			s->session->tlsext_ticklen = ticklen;
++			}
+ 		else
+ 			ticklen = 0;
++		if (ticklen == 0 && s->tlsext_session_ticket &&
++		    s->tlsext_session_ticket->data == NULL)
++			goto skip_ext;
+ 		/* Check for enough room 2 for extension type, 2 for len
+  		 * rest for ticket
+   		 */
+@@ -221,6 +242,7 @@ unsigned char *ssl_add_clienthello_tlsex
+ 			ret += ticklen;
+ 			}
+ 		}
++		skip_ext:
+ 
+ 	if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
+ 	    s->version != DTLS1_VERSION)
+@@ -486,6 +508,15 @@ int ssl_parse_clienthello_tlsext(SSL *s,
+ 				return 0;
+ 			renegotiate_seen = 1;
+ 			}
++		else if (type == TLSEXT_TYPE_session_ticket)
++			{
++			if (s->tls_session_ticket_ext_cb &&
++			    !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
++				{
++				*al = TLS1_AD_INTERNAL_ERROR;
++				return 0;
++				}
++			}
+ 		else if (type == TLSEXT_TYPE_status_request &&
+ 		         s->version != DTLS1_VERSION && s->ctx->tlsext_status_cb)
+ 			{
+@@ -663,6 +694,12 @@ int ssl_parse_serverhello_tlsext(SSL *s,
+ 			}
+ 		else if (type == TLSEXT_TYPE_session_ticket)
+ 			{
++			if (s->tls_session_ticket_ext_cb &&
++			    !s->tls_session_ticket_ext_cb(s, data, size, s->tls_session_ticket_ext_cb_arg))
++				{
++				*al = TLS1_AD_INTERNAL_ERROR;
++				return 0;
++				}
+ 			if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
+ 				|| (size > 0))
+ 				{
+@@ -920,6 +957,15 @@ int tls1_process_ticket(SSL *s, unsigned
+ 				s->tlsext_ticket_expected = 1;
+ 				return 0;	/* Cache miss */
+ 				}
++			if (s->tls_session_secret_cb)
++				{
++				/* Indicate cache miss here and instead of
++				 * generating the session from ticket now,
++				 * trigger abbreviated handshake based on
++				 * external mechanism to calculate the master
++				 * secret later. */
++				return 0;
++				}
+ 			return tls_decrypt_ticket(s, p, size, session_id, len,
+ 									ret);
+ 			}
+diff -upr openssl-0.9.8x.orig/ssl/tls1.h openssl-0.9.8x/ssl/tls1.h
+--- openssl-0.9.8x.orig/ssl/tls1.h	2009-11-08 16:51:54.000000000 +0200
++++ openssl-0.9.8x/ssl/tls1.h	2012-07-07 10:46:31.501140621 +0300
+@@ -401,6 +401,13 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
+ #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
+ #endif
+ 
++/* TLS extension struct */
++struct tls_session_ticket_ext_st
++	{
++	unsigned short length;
++	void *data;
++	};
++
+ #ifdef  __cplusplus
+ }
+ #endif
+diff -upr openssl-0.9.8x.orig/util/ssleay.num openssl-0.9.8x/util/ssleay.num
+--- openssl-0.9.8x.orig/util/ssleay.num	2008-06-05 13:57:21.000000000 +0300
++++ openssl-0.9.8x/util/ssleay.num	2012-07-07 10:46:31.505140623 +0300
+@@ -242,3 +242,5 @@ SSL_set_SSL_CTX
+ SSL_get_servername                      291	EXIST::FUNCTION:TLSEXT
+ SSL_get_servername_type                 292	EXIST::FUNCTION:TLSEXT
+ SSL_CTX_set_client_cert_engine          293	EXIST::FUNCTION:ENGINE
++SSL_set_session_ticket_ext		306	EXIST::FUNCTION:TLSEXT
++SSL_set_session_secret_cb		307	EXIST::FUNCTION:TLSEXT
diff --git a/hostap/patches/openssl-0.9.9-session-ticket.patch b/hostap/patches/openssl-0.9.9-session-ticket.patch
new file mode 100644
index 0000000..3afa639
--- /dev/null
+++ b/hostap/patches/openssl-0.9.9-session-ticket.patch
@@ -0,0 +1,374 @@
+This patch adds support for TLS SessionTicket extension (RFC 5077) for
+the parts used by EAP-FAST (RFC 4851).
+
+This is based on the patch from Alexey Kobozev <akobozev@cisco.com>
+(sent to openssl-dev mailing list on Tue, 07 Jun 2005 15:40:58 +0300).
+
+NOTE: This patch (without SSL_set_hello_extension() wrapper) was
+merged into the upstream OpenSSL 0.9.9 tree and as such, an external
+patch for EAP-FAST support is not needed anymore.
+
+
+
+Index: openssl-SNAP-20081111/ssl/s3_clnt.c
+===================================================================
+--- openssl-SNAP-20081111.orig/ssl/s3_clnt.c
++++ openssl-SNAP-20081111/ssl/s3_clnt.c
+@@ -788,6 +788,23 @@ int ssl3_get_server_hello(SSL *s)
+ 		goto f_err;
+ 		}
+ 
++#ifndef OPENSSL_NO_TLSEXT
++	/* check if we want to resume the session based on external pre-shared secret */
++	if (s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++		{
++		SSL_CIPHER *pref_cipher=NULL;
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if (s->tls_session_secret_cb(s, s->session->master_key,
++					     &s->session->master_key_length,
++					     NULL, &pref_cipher,
++					     s->tls_session_secret_cb_arg))
++			{
++			s->session->cipher = pref_cipher ?
++				pref_cipher : ssl_get_cipher_by_char(s, p+j);
++			}
++		}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ 	if (j != 0 && j == s->session->session_id_length
+ 	    && memcmp(p,s->session->session_id,j) == 0)
+ 	    {
+@@ -2927,11 +2944,8 @@ static int ssl3_check_finished(SSL *s)
+ 	{
+ 	int ok;
+ 	long n;
+-	/* If we have no ticket or session ID is non-zero length (a match of
+-	 * a non-zero session length would never reach here) it cannot be a
+-	 * resumed session.
+-	 */
+-	if (!s->session->tlsext_tick || s->session->session_id_length)
++	/* If we have no ticket it cannot be a resumed session. */
++	if (!s->session->tlsext_tick)
+ 		return 1;
+ 	/* this function is called when we really expect a Certificate
+ 	 * message, so permit appropriate message length */
+Index: openssl-SNAP-20081111/ssl/s3_srvr.c
+===================================================================
+--- openssl-SNAP-20081111.orig/ssl/s3_srvr.c
++++ openssl-SNAP-20081111/ssl/s3_srvr.c
+@@ -1010,6 +1010,59 @@ int ssl3_get_client_hello(SSL *s)
+ 			SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_CLIENTHELLO_TLSEXT);
+ 			goto err;
+ 		}
++
++	/* Check if we want to use external pre-shared secret for this
++	 * handshake for not reused session only. We need to generate
++	 * server_random before calling tls_session_secret_cb in order to allow
++	 * SessionTicket processing to use it in key derivation. */
++	{
++		unsigned long Time;
++		unsigned char *pos;
++		Time=(unsigned long)time(NULL);			/* Time */
++		pos=s->s3->server_random;
++		l2n(Time,pos);
++		if (RAND_pseudo_bytes(pos,SSL3_RANDOM_SIZE-4) <= 0)
++			{
++			al=SSL_AD_INTERNAL_ERROR;
++			goto f_err;
++			}
++	}
++
++	if (!s->hit && s->version >= TLS1_VERSION && s->tls_session_secret_cb)
++		{
++		SSL_CIPHER *pref_cipher=NULL;
++
++		s->session->master_key_length=sizeof(s->session->master_key);
++		if(s->tls_session_secret_cb(s, s->session->master_key, &s->session->master_key_length,
++			ciphers, &pref_cipher, s->tls_session_secret_cb_arg))
++			{
++			s->hit=1;
++			s->session->ciphers=ciphers;
++			s->session->verify_result=X509_V_OK;
++
++			ciphers=NULL;
++
++			/* check if some cipher was preferred by call back */
++			pref_cipher=pref_cipher ? pref_cipher : ssl3_choose_cipher(s, s->session->ciphers, SSL_get_ciphers(s));
++			if (pref_cipher == NULL)
++				{
++				al=SSL_AD_HANDSHAKE_FAILURE;
++				SSLerr(SSL_F_SSL3_GET_CLIENT_HELLO,SSL_R_NO_SHARED_CIPHER);
++				goto f_err;
++				}
++
++			s->session->cipher=pref_cipher;
++
++			if (s->cipher_list)
++				sk_SSL_CIPHER_free(s->cipher_list);
++
++			if (s->cipher_list_by_id)
++				sk_SSL_CIPHER_free(s->cipher_list_by_id);
++
++			s->cipher_list = sk_SSL_CIPHER_dup(s->session->ciphers);
++			s->cipher_list_by_id = sk_SSL_CIPHER_dup(s->session->ciphers);
++			}
++		}
+ #endif
+ 
+ 	/* Worst case, we will use the NULL compression, but if we have other
+@@ -1134,16 +1187,22 @@ int ssl3_send_server_hello(SSL *s)
+ 	unsigned char *buf;
+ 	unsigned char *p,*d;
+ 	int i,sl;
+-	unsigned long l,Time;
++	unsigned long l;
++#ifdef OPENSSL_NO_TLSEXT
++	unsigned long Time;
++#endif
+ 
+ 	if (s->state == SSL3_ST_SW_SRVR_HELLO_A)
+ 		{
+ 		buf=(unsigned char *)s->init_buf->data;
++#ifdef OPENSSL_NO_TLSEXT
+ 		p=s->s3->server_random;
++		/* Generate server_random if it was not needed previously */
+ 		Time=(unsigned long)time(NULL);			/* Time */
+ 		l2n(Time,p);
+ 		if (RAND_pseudo_bytes(p,SSL3_RANDOM_SIZE-4) <= 0)
+ 			return -1;
++#endif
+ 		/* Do the message type and length last */
+ 		d=p= &(buf[4]);
+ 
+Index: openssl-SNAP-20081111/ssl/ssl_err.c
+===================================================================
+--- openssl-SNAP-20081111.orig/ssl/ssl_err.c
++++ openssl-SNAP-20081111/ssl/ssl_err.c
+@@ -263,6 +263,7 @@ static ERR_STRING_DATA SSL_str_functs[]=
+ {ERR_FUNC(SSL_F_TLS1_PRF),	"tls1_prf"},
+ {ERR_FUNC(SSL_F_TLS1_SETUP_KEY_BLOCK),	"TLS1_SETUP_KEY_BLOCK"},
+ {ERR_FUNC(SSL_F_WRITE_PENDING),	"WRITE_PENDING"},
++{ERR_FUNC(SSL_F_SSL_SET_SESSION_TICKET_EXT), "SSL_set_session_ticket_ext"},
+ {0,NULL}
+ 	};
+ 
+Index: openssl-SNAP-20081111/ssl/ssl.h
+===================================================================
+--- openssl-SNAP-20081111.orig/ssl/ssl.h
++++ openssl-SNAP-20081111/ssl/ssl.h
+@@ -355,6 +355,7 @@ extern "C" {
+  * 'struct ssl_st *' function parameters used to prototype callbacks
+  * in SSL_CTX. */
+ typedef struct ssl_st *ssl_crock_st;
++typedef struct tls_session_ticket_ext_st TLS_SESSION_TICKET_EXT;
+ 
+ /* used to hold info on the particular ciphers used */
+ typedef struct ssl_cipher_st
+@@ -378,6 +379,8 @@ typedef struct ssl_cipher_st
+ 
+ DECLARE_STACK_OF(SSL_CIPHER)
+ 
++typedef int (*tls_session_secret_cb_fn)(SSL *s, void *secret, int *secret_len, STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg);
++
+ /* Used to hold functions for SSLv2 or SSLv3/TLSv1 functions */
+ typedef struct ssl_method_st
+ 	{
+@@ -1145,6 +1148,13 @@ struct ssl_st
+ 	void *tlsext_opaque_prf_input;
+ 	size_t tlsext_opaque_prf_input_len;
+ 
++	/* TLS Session Ticket extension override */
++	TLS_SESSION_TICKET_EXT *tlsext_session_ticket;
++
++	/* TLS pre-shared secret session resumption */
++	tls_session_secret_cb_fn tls_session_secret_cb;
++	void *tls_session_secret_cb_arg;
++
+ 	SSL_CTX * initial_ctx; /* initial ctx, used to store sessions */
+ #define session_ctx initial_ctx
+ #else
+@@ -1746,6 +1756,16 @@ void *SSL_COMP_get_compression_methods(v
+ int SSL_COMP_add_compression_method(int id,void *cm);
+ #endif
+ 
++/* NOTE: This function will be removed; it is only here for backwards
++ * compatibility for the API during testing. */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len);
++
++/* TLS extensions functions */
++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len);
++
++/* Pre-shared secret session resumption functions */
++int SSL_set_session_secret_cb(SSL *s, tls_session_secret_cb_fn tls_session_secret_cb, void *arg);
++
+ /* BEGIN ERROR CODES */
+ /* The following lines are auto generated by the script mkerr.pl. Any changes
+  * made after this point may be overwritten when the script is next run.
+@@ -1948,6 +1968,7 @@ void ERR_load_SSL_strings(void);
+ #define SSL_F_TLS1_PRF					 284
+ #define SSL_F_TLS1_SETUP_KEY_BLOCK			 211
+ #define SSL_F_WRITE_PENDING				 212
++#define SSL_F_SSL_SET_SESSION_TICKET_EXT		 213
+ 
+ /* Reason codes. */
+ #define SSL_R_APP_DATA_IN_HANDSHAKE			 100
+Index: openssl-SNAP-20081111/ssl/ssl_sess.c
+===================================================================
+--- openssl-SNAP-20081111.orig/ssl/ssl_sess.c
++++ openssl-SNAP-20081111/ssl/ssl_sess.c
+@@ -834,6 +834,62 @@ long SSL_CTX_get_timeout(const SSL_CTX *
+ 	return(s->session_timeout);
+ 	}
+ 
++#ifndef OPENSSL_NO_TLSEXT
++int SSL_set_session_secret_cb(SSL *s, int (*tls_session_secret_cb)(SSL *s, void *secret, int *secret_len,
++	STACK_OF(SSL_CIPHER) *peer_ciphers, SSL_CIPHER **cipher, void *arg), void *arg)
++	{
++	if (s == NULL) return(0);
++	s->tls_session_secret_cb = tls_session_secret_cb;
++	s->tls_session_secret_cb_arg = arg;
++	return(1);
++	}
++
++int SSL_set_session_ticket_ext(SSL *s, void *ext_data, int ext_len)
++	{
++	if (s->version >= TLS1_VERSION)
++		{
++		if (s->tlsext_session_ticket)
++			{
++			OPENSSL_free(s->tlsext_session_ticket);
++			s->tlsext_session_ticket = NULL;
++			}
++
++		s->tlsext_session_ticket = OPENSSL_malloc(sizeof(TLS_SESSION_TICKET_EXT) + ext_len);
++		if (!s->tlsext_session_ticket)
++			{
++			SSLerr(SSL_F_SSL_SET_SESSION_TICKET_EXT, ERR_R_MALLOC_FAILURE);
++			return 0;
++			}
++
++		if (ext_data)
++			{
++			s->tlsext_session_ticket->length = ext_len;
++			s->tlsext_session_ticket->data = s->tlsext_session_ticket + 1;
++			memcpy(s->tlsext_session_ticket->data, ext_data, ext_len);
++			}
++		else
++			{
++			s->tlsext_session_ticket->length = 0;
++			s->tlsext_session_ticket->data = NULL;
++			}
++
++		return 1;
++		}
++
++	return 0;
++	}
++
++/* NOTE: This function will be removed; it is only here for backwards
++ * compatibility for the API during testing. */
++int SSL_set_hello_extension(SSL *s, int ext_type, void *ext_data, int ext_len)
++	{
++	if (ext_type != TLSEXT_TYPE_session_ticket)
++		return 0;
++
++	return SSL_set_session_ticket_ext(s, ext_data, ext_len);
++	}
++#endif /* OPENSSL_NO_TLSEXT */
++
+ typedef struct timeout_param_st
+ 	{
+ 	SSL_CTX *ctx;
+Index: openssl-SNAP-20081111/ssl/t1_lib.c
+===================================================================
+--- openssl-SNAP-20081111.orig/ssl/t1_lib.c
++++ openssl-SNAP-20081111/ssl/t1_lib.c
+@@ -154,6 +154,12 @@ int tls1_new(SSL *s)
+ 
+ void tls1_free(SSL *s)
+ 	{
++#ifndef OPENSSL_NO_TLSEXT
++	if (s->tlsext_session_ticket)
++		{
++		OPENSSL_free(s->tlsext_session_ticket);
++		}
++#endif /* OPENSSL_NO_TLSEXT */
+ 	ssl3_free(s);
+ 	}
+ 
+@@ -357,8 +363,23 @@ unsigned char *ssl_add_clienthello_tlsex
+ 		int ticklen;
+ 		if (s->session && s->session->tlsext_tick)
+ 			ticklen = s->session->tlsext_ticklen;
++		else if (s->session && s->tlsext_session_ticket &&
++			 s->tlsext_session_ticket->data)
++			{
++			ticklen = s->tlsext_session_ticket->length;
++			s->session->tlsext_tick = OPENSSL_malloc(ticklen);
++			if (!s->session->tlsext_tick)
++				return NULL;
++			memcpy(s->session->tlsext_tick,
++			       s->tlsext_session_ticket->data,
++			       ticklen);
++			s->session->tlsext_ticklen = ticklen;
++			}
+ 		else
+ 			ticklen = 0;
++		if (ticklen == 0 && s->tlsext_session_ticket &&
++		    s->tlsext_session_ticket->data == NULL)
++			goto skip_ext;
+ 		/* Check for enough room 2 for extension type, 2 for len
+  		 * rest for ticket
+   		 */
+@@ -371,6 +392,7 @@ unsigned char *ssl_add_clienthello_tlsex
+ 			ret += ticklen;
+ 			}
+ 		}
++		skip_ext:
+ 
+ #ifdef TLSEXT_TYPE_opaque_prf_input
+ 	if (s->s3->client_opaque_prf_input != NULL)
+@@ -1435,6 +1457,15 @@ int tls1_process_ticket(SSL *s, unsigned
+ 				s->tlsext_ticket_expected = 1;
+ 				return 0;	/* Cache miss */
+ 				}
++			if (s->tls_session_secret_cb)
++				{
++				/* Indicate cache miss here and instead of
++				 * generating the session from ticket now,
++				 * trigger abbreviated handshake based on
++				 * external mechanism to calculate the master
++				 * secret later. */
++				return 0;
++				}
+ 			return tls_decrypt_ticket(s, p, size, session_id, len,
+ 									ret);
+ 			}
+Index: openssl-SNAP-20081111/ssl/tls1.h
+===================================================================
+--- openssl-SNAP-20081111.orig/ssl/tls1.h
++++ openssl-SNAP-20081111/ssl/tls1.h
+@@ -512,6 +512,13 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_T
+ #define TLS_MD_MASTER_SECRET_CONST    "\x6d\x61\x73\x74\x65\x72\x20\x73\x65\x63\x72\x65\x74"  /*master secret*/
+ #endif
+ 
++/* TLS Session Ticket extension struct */
++struct tls_session_ticket_ext_st
++	{
++	unsigned short length;
++	void *data;
++	};
++
+ #ifdef  __cplusplus
+ }
+ #endif
+Index: openssl-SNAP-20081111/util/ssleay.num
+===================================================================
+--- openssl-SNAP-20081111.orig/util/ssleay.num
++++ openssl-SNAP-20081111/util/ssleay.num
+@@ -254,3 +254,5 @@ PEM_read_bio_SSL_SESSION                
+ SSL_CTX_set_psk_server_callback         303	EXIST::FUNCTION:PSK
+ SSL_get_psk_identity                    304	EXIST::FUNCTION:PSK
+ PEM_write_SSL_SESSION                   305	EXIST:!WIN16:FUNCTION:
++SSL_set_session_ticket_ext		306	EXIST::FUNCTION:TLSEXT
++SSL_set_session_secret_cb		307	EXIST::FUNCTION:TLSEXT
diff --git a/hostap/radius_example/Makefile b/hostap/radius_example/Makefile
new file mode 100644
index 0000000..92e992c
--- /dev/null
+++ b/hostap/radius_example/Makefile
@@ -0,0 +1,45 @@
+ALL=radius_example
+
+all: $(ALL)
+
+ifndef CC
+CC=gcc
+endif
+
+ifndef LDO
+LDO=$(CC)
+endif
+
+ifndef CFLAGS
+CFLAGS = -MMD -O2 -Wall -g
+endif
+
+CFLAGS += -I.
+CFLAGS += -I../src
+CFLAGS += -I../src/utils
+
+LIBS = ../src/radius/libradius.a
+LIBS += ../src/crypto/libcrypto.a
+LIBS += ../src/utils/libutils.a
+
+../src/utils/libutils.a:
+	$(MAKE) -C ../src/utils
+
+../src/crypto/libcrypto.a:
+	$(MAKE) -C ../src/crypto
+
+../src/radius/libradius.a:
+	$(MAKE) -C ../src/radius
+
+#CLAGS += -DCONFIG_IPV6
+
+OBJS_ex = radius_example.o
+
+radius_example: $(OBJS_ex) $(LIBS)
+	$(LDO) $(LDFLAGS) -o radius_example $(OBJS_ex) $(LIBS)
+
+clean:
+	$(MAKE) -C ../src clean
+	rm -f core *~ *.o *.d $(ALL)
+
+-include $(OBJS:%.o=%.d)
diff --git a/hostap/radius_example/README b/hostap/radius_example/README
new file mode 100644
index 0000000..ec458e3
--- /dev/null
+++ b/hostap/radius_example/README
@@ -0,0 +1,35 @@
+Example application using RADIUS client as a library
+Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+
+This software may be distributed under the terms of the BSD license.
+See the parent directory README for more details.
+
+
+This directory contains an example showing how the RADIUS client
+functionality from hostapd can be used as a library in another
+program. The example program initializes the RADIUS client and send a
+Access-Request using User-Name and User-Password attributes. A reply
+from the RADIUS authentication server will be processed and it is used
+as a trigger to terminate the example program.
+
+The RADIUS library links in couple of helper functions from src/utils and
+src/crypto directories. Most of these are suitable as-is, but it may
+be desirable to replace the debug output code in src/utils/wpa_debug.c
+by dropping this file from the library and re-implementing the
+functions there in a way that better fits in with the main
+application.
+
+RADIUS client implementation takes care of receiving messages,
+timeouts, and retransmissions of packets. Consequently, it requires
+functionality for registering timeouts and received packet
+notifications. This is implemented using the generic event loop
+implementation (see src/utils/eloop.h).
+
+The main application may either use the included event loop
+implementation or alternatively, implement eloop_* wrapper functions
+to use whatever event loop design is used in the main program. This
+would involve removing src/utils/eloop.o from the library and
+implementing following functions defines in src/utils/eloop.h:
+eloop_register_timeout(), eloop_cancel_timeout(),
+eloop_register_read_sock(), eloop_unregister_read_sock(), and
+eloop_terminated().
diff --git a/hostap/radius_example/radius_example.c b/hostap/radius_example/radius_example.c
new file mode 100644
index 0000000..cb0e154
--- /dev/null
+++ b/hostap/radius_example/radius_example.c
@@ -0,0 +1,155 @@
+/*
+ * Example application using RADIUS client as a library
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "eloop.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+
+extern int wpa_debug_level;
+
+struct radius_ctx {
+	struct radius_client_data *radius;
+	struct hostapd_radius_servers conf;
+	u8 radius_identifier;
+	struct in_addr own_ip_addr;
+};
+
+
+static void hostapd_logger_cb(void *ctx, const u8 *addr, unsigned int module,
+			      int level, const char *txt, size_t len)
+{
+	printf("%s\n", txt);
+}
+
+
+/* Process the RADIUS frames from Authentication Server */
+static RadiusRxResult receive_auth(struct radius_msg *msg,
+				   struct radius_msg *req,
+				   const u8 *shared_secret,
+				   size_t shared_secret_len,
+				   void *data)
+{
+	/* struct radius_ctx *ctx = data; */
+	printf("Received RADIUS Authentication message; code=%d\n",
+	       radius_msg_get_hdr(msg)->code);
+
+	/* We're done for this example, so request eloop to terminate. */
+	eloop_terminate();
+
+	return RADIUS_RX_PROCESSED;
+}
+
+
+static void start_example(void *eloop_ctx, void *timeout_ctx)
+{
+	struct radius_ctx *ctx = eloop_ctx;
+	struct radius_msg *msg;
+
+	printf("Sending a RADIUS authentication message\n");
+
+	ctx->radius_identifier = radius_client_get_id(ctx->radius);
+	msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
+			     ctx->radius_identifier);
+	if (msg == NULL) {
+		printf("Could not create net RADIUS packet\n");
+		return;
+	}
+
+	radius_msg_make_authenticator(msg, (u8 *) ctx, sizeof(*ctx));
+
+	if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
+				 (u8 *) "user", 4)) {
+		printf("Could not add User-Name\n");
+		radius_msg_free(msg);
+		return;
+	}
+
+	if (!radius_msg_add_attr_user_password(
+		    msg, (u8 *) "password", 8,
+		    ctx->conf.auth_server->shared_secret,
+		    ctx->conf.auth_server->shared_secret_len)) {
+		printf("Could not add User-Password\n");
+		radius_msg_free(msg);
+		return;
+	}
+
+	if (!radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
+				 (u8 *) &ctx->own_ip_addr, 4)) {
+		printf("Could not add NAS-IP-Address\n");
+		radius_msg_free(msg);
+		return;
+	}
+
+	if (radius_client_send(ctx->radius, msg, RADIUS_AUTH, NULL) < 0)
+		radius_msg_free(msg);
+}
+
+
+int main(int argc, char *argv[])
+{
+	struct radius_ctx ctx;
+	struct hostapd_radius_server *srv;
+
+	if (os_program_init())
+		return -1;
+
+	hostapd_logger_register_cb(hostapd_logger_cb);
+
+	os_memset(&ctx, 0, sizeof(ctx));
+	inet_aton("127.0.0.1", &ctx.own_ip_addr);
+
+	if (eloop_init()) {
+		printf("Failed to initialize event loop\n");
+		return -1;
+	}
+
+	srv = os_zalloc(sizeof(*srv));
+	if (srv == NULL)
+		return -1;
+
+	srv->addr.af = AF_INET;
+	srv->port = 1812;
+	if (hostapd_parse_ip_addr("127.0.0.1", &srv->addr) < 0) {
+		printf("Failed to parse IP address\n");
+		return -1;
+	}
+	srv->shared_secret = (u8 *) os_strdup("radius");
+	srv->shared_secret_len = 6;
+
+	ctx.conf.auth_server = ctx.conf.auth_servers = srv;
+	ctx.conf.num_auth_servers = 1;
+	ctx.conf.msg_dumps = 1;
+
+	ctx.radius = radius_client_init(&ctx, &ctx.conf);
+	if (ctx.radius == NULL) {
+		printf("Failed to initialize RADIUS client\n");
+		return -1;
+	}
+
+	if (radius_client_register(ctx.radius, RADIUS_AUTH, receive_auth,
+				   &ctx) < 0) {
+		printf("Failed to register RADIUS authentication handler\n");
+		return -1;
+	}
+
+	eloop_register_timeout(0, 0, start_example, &ctx, NULL);
+
+	eloop_run();
+
+	radius_client_deinit(ctx.radius);
+	os_free(srv->shared_secret);
+	os_free(srv);
+
+	eloop_destroy();
+	os_program_deinit();
+
+	return 0;
+}
diff --git a/hostap/src/Makefile b/hostap/src/Makefile
new file mode 100644
index 0000000..d73a175
--- /dev/null
+++ b/hostap/src/Makefile
@@ -0,0 +1,11 @@
+SUBDIRS=ap common crypto drivers eapol_auth eapol_supp eap_common eap_peer eap_server l2_packet p2p radius rsn_supp tls utils wps
+
+all:
+	for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d; done
+
+clean:
+	for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d clean; done
+	rm -f *~
+
+install:
+	for d in $(SUBDIRS); do [ -d $$d ] && $(MAKE) -C $$d install; done
diff --git a/hostap/src/ap/Makefile b/hostap/src/ap/Makefile
new file mode 100644
index 0000000..9c41962
--- /dev/null
+++ b/hostap/src/ap/Makefile
@@ -0,0 +1,8 @@
+all:
+	@echo Nothing to be made.
+
+clean:
+	rm -f *~ *.o *.d
+
+install:
+	@echo Nothing to be made.
diff --git a/hostap/src/ap/accounting.c b/hostap/src/ap/accounting.c
new file mode 100644
index 0000000..9540531
--- /dev/null
+++ b/hostap/src/ap/accounting.c
@@ -0,0 +1,476 @@
+/*
+ * hostapd / RADIUS Accounting
+ * Copyright (c) 2002-2009, 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "drivers/driver.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+#include "hostapd.h"
+#include "ieee802_1x.h"
+#include "ap_config.h"
+#include "sta_info.h"
+#include "ap_drv_ops.h"
+#include "accounting.h"
+
+
+/* Default interval in seconds for polling TX/RX octets from the driver if
+ * STA is not using interim accounting. This detects wrap arounds for
+ * input/output octets and updates Acct-{Input,Output}-Gigawords. */
+#define ACCT_DEFAULT_UPDATE_INTERVAL 300
+
+static void accounting_sta_interim(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;
+	char buf[128];
+	u8 *val;
+	size_t len;
+	int i;
+	struct wpabuf *b;
+
+	msg = radius_msg_new(RADIUS_CODE_ACCOUNTING_REQUEST,
+			     radius_client_get_id(hapd->radius));
+	if (msg == NULL) {
+		printf("Could not create net RADIUS packet\n");
+		return NULL;
+	}
+
+	if (sta) {
+		radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
+
+		os_snprintf(buf, sizeof(buf), "%08X-%08X",
+			    sta->acct_session_id_hi, sta->acct_session_id_lo);
+		if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
+					 (u8 *) buf, os_strlen(buf))) {
+			printf("Could not add Acct-Session-Id\n");
+			goto fail;
+		}
+	} else {
+		radius_msg_make_authenticator(msg, (u8 *) hapd, sizeof(*hapd));
+	}
+
+	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_STATUS_TYPE,
+				       status_type)) {
+		printf("Could not add Acct-Status-Type\n");
+		goto fail;
+	}
+
+	if (!hostapd_config_get_radius_attr(hapd->conf->radius_acct_req_attr,
+					    RADIUS_ATTR_ACCT_AUTHENTIC) &&
+	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_AUTHENTIC,
+				       hapd->conf->ieee802_1x ?
+				       RADIUS_ACCT_AUTHENTIC_RADIUS :
+				       RADIUS_ACCT_AUTHENTIC_LOCAL)) {
+		printf("Could not add Acct-Authentic\n");
+		goto fail;
+	}
+
+	if (sta) {
+		/* Use 802.1X identity if available */
+		val = ieee802_1x_get_identity(sta->eapol_sm, &len);
+
+		/* Use RADIUS ACL identity if 802.1X provides no identity */
+		if (!val && sta->identity) {
+			val = (u8 *) sta->identity;
+			len = os_strlen(sta->identity);
+		}
+
+		/* Use STA MAC if neither 802.1X nor RADIUS ACL provided
+		 * identity */
+		if (!val) {
+			os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT,
+				    MAC2STR(sta->addr));
+			val = (u8 *) buf;
+			len = os_strlen(buf);
+		}
+
+		if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, val,
+					 len)) {
+			printf("Could not add User-Name\n");
+			goto fail;
+		}
+	}
+
+	if (add_common_radius_attr(hapd, hapd->conf->radius_acct_req_attr, sta,
+				   msg) < 0)
+		goto fail;
+
+	if (sta) {
+		for (i = 0; ; i++) {
+			val = ieee802_1x_get_radius_class(sta->eapol_sm, &len,
+							  i);
+			if (val == NULL)
+				break;
+
+			if (!radius_msg_add_attr(msg, RADIUS_ATTR_CLASS,
+						 val, len)) {
+				printf("Could not add Class\n");
+				goto fail;
+			}
+		}
+
+		b = ieee802_1x_get_radius_cui(sta->eapol_sm);
+		if (b &&
+		    !radius_msg_add_attr(msg,
+					 RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+					 wpabuf_head(b), wpabuf_len(b))) {
+			wpa_printf(MSG_ERROR, "Could not add CUI");
+			goto fail;
+		}
+
+		if (!b && sta->radius_cui &&
+		    !radius_msg_add_attr(msg,
+					 RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+					 (u8 *) sta->radius_cui,
+					 os_strlen(sta->radius_cui))) {
+			wpa_printf(MSG_ERROR, "Could not add CUI from ACL");
+			goto fail;
+		}
+	}
+
+	return msg;
+
+ fail:
+	radius_msg_free(msg);
+	return NULL;
+}
+
+
+static int accounting_sta_update_stats(struct hostapd_data *hapd,
+				       struct sta_info *sta,
+				       struct hostap_sta_driver_data *data)
+{
+	if (hostapd_drv_read_sta_data(hapd, data, sta->addr))
+		return -1;
+
+	if (sta->last_rx_bytes > data->rx_bytes)
+		sta->acct_input_gigawords++;
+	if (sta->last_tx_bytes > data->tx_bytes)
+		sta->acct_output_gigawords++;
+	sta->last_rx_bytes = data->rx_bytes;
+	sta->last_tx_bytes = data->tx_bytes;
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+		       HOSTAPD_LEVEL_DEBUG, "updated TX/RX stats: "
+		       "Acct-Input-Octets=%lu Acct-Input-Gigawords=%u "
+		       "Acct-Output-Octets=%lu Acct-Output-Gigawords=%u",
+		       sta->last_rx_bytes, sta->acct_input_gigawords,
+		       sta->last_tx_bytes, sta->acct_output_gigawords);
+
+	return 0;
+}
+
+
+static void accounting_interim_update(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+	int interval;
+
+	if (sta->acct_interim_interval) {
+		accounting_sta_interim(hapd, sta);
+		interval = sta->acct_interim_interval;
+	} else {
+		struct hostap_sta_driver_data data;
+		accounting_sta_update_stats(hapd, sta, &data);
+		interval = ACCT_DEFAULT_UPDATE_INTERVAL;
+	}
+
+	eloop_register_timeout(interval, 0, accounting_interim_update,
+			       hapd, sta);
+}
+
+
+/**
+ * accounting_sta_start - Start STA accounting
+ * @hapd: hostapd BSS data
+ * @sta: The station
+ */
+void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	struct radius_msg *msg;
+	struct os_time t;
+	int interval;
+
+	if (sta->acct_session_started)
+		return;
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+		       HOSTAPD_LEVEL_INFO,
+		       "starting accounting session %08X-%08X",
+		       sta->acct_session_id_hi, sta->acct_session_id_lo);
+
+	os_get_time(&t);
+	sta->acct_session_start = t.sec;
+	sta->last_rx_bytes = sta->last_tx_bytes = 0;
+	sta->acct_input_gigawords = sta->acct_output_gigawords = 0;
+	hostapd_drv_sta_clear_stats(hapd, sta->addr);
+
+	if (!hapd->conf->radius->acct_server)
+		return;
+
+	if (sta->acct_interim_interval)
+		interval = sta->acct_interim_interval;
+	else
+		interval = ACCT_DEFAULT_UPDATE_INTERVAL;
+	eloop_register_timeout(interval, 0, accounting_interim_update,
+			       hapd, sta);
+
+	msg = accounting_msg(hapd, sta, RADIUS_ACCT_STATUS_TYPE_START);
+	if (msg &&
+	    radius_client_send(hapd->radius, msg, RADIUS_ACCT, sta->addr) < 0)
+		radius_msg_free(msg);
+
+	sta->acct_session_started = 1;
+}
+
+
+static void accounting_sta_report(struct hostapd_data *hapd,
+				  struct sta_info *sta, int stop)
+{
+	struct radius_msg *msg;
+	int cause = sta->acct_terminate_cause;
+	struct hostap_sta_driver_data data;
+	struct os_time now;
+	u32 gigawords;
+
+	if (!hapd->conf->radius->acct_server)
+		return;
+
+	msg = accounting_msg(hapd, sta,
+			     stop ? RADIUS_ACCT_STATUS_TYPE_STOP :
+			     RADIUS_ACCT_STATUS_TYPE_INTERIM_UPDATE);
+	if (!msg) {
+		printf("Could not create RADIUS Accounting message\n");
+		return;
+	}
+
+	os_get_time(&now);
+	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_SESSION_TIME,
+				       now.sec - sta->acct_session_start)) {
+		printf("Could not add Acct-Session-Time\n");
+		goto fail;
+	}
+
+	if (accounting_sta_update_stats(hapd, sta, &data) == 0) {
+		if (!radius_msg_add_attr_int32(msg,
+					       RADIUS_ATTR_ACCT_INPUT_PACKETS,
+					       data.rx_packets)) {
+			printf("Could not add Acct-Input-Packets\n");
+			goto fail;
+		}
+		if (!radius_msg_add_attr_int32(msg,
+					       RADIUS_ATTR_ACCT_OUTPUT_PACKETS,
+					       data.tx_packets)) {
+			printf("Could not add Acct-Output-Packets\n");
+			goto fail;
+		}
+		if (!radius_msg_add_attr_int32(msg,
+					       RADIUS_ATTR_ACCT_INPUT_OCTETS,
+					       data.rx_bytes)) {
+			printf("Could not add Acct-Input-Octets\n");
+			goto fail;
+		}
+		gigawords = sta->acct_input_gigawords;
+#if __WORDSIZE == 64
+		gigawords += data.rx_bytes >> 32;
+#endif
+		if (gigawords &&
+		    !radius_msg_add_attr_int32(
+			    msg, RADIUS_ATTR_ACCT_INPUT_GIGAWORDS,
+			    gigawords)) {
+			printf("Could not add Acct-Input-Gigawords\n");
+			goto fail;
+		}
+		if (!radius_msg_add_attr_int32(msg,
+					       RADIUS_ATTR_ACCT_OUTPUT_OCTETS,
+					       data.tx_bytes)) {
+			printf("Could not add Acct-Output-Octets\n");
+			goto fail;
+		}
+		gigawords = sta->acct_output_gigawords;
+#if __WORDSIZE == 64
+		gigawords += data.tx_bytes >> 32;
+#endif
+		if (gigawords &&
+		    !radius_msg_add_attr_int32(
+			    msg, RADIUS_ATTR_ACCT_OUTPUT_GIGAWORDS,
+			    gigawords)) {
+			printf("Could not add Acct-Output-Gigawords\n");
+			goto fail;
+		}
+	}
+
+	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_EVENT_TIMESTAMP,
+				       now.sec)) {
+		printf("Could not add Event-Timestamp\n");
+		goto fail;
+	}
+
+	if (eloop_terminated())
+		cause = RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_REBOOT;
+
+	if (stop && cause &&
+	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
+				       cause)) {
+		printf("Could not add Acct-Terminate-Cause\n");
+		goto fail;
+	}
+
+	if (radius_client_send(hapd->radius, msg,
+			       stop ? RADIUS_ACCT : RADIUS_ACCT_INTERIM,
+			       sta->addr) < 0)
+		goto fail;
+	return;
+
+ fail:
+	radius_msg_free(msg);
+}
+
+
+/**
+ * accounting_sta_interim - Send a interim STA accounting report
+ * @hapd: hostapd BSS data
+ * @sta: The station
+ */
+static void accounting_sta_interim(struct hostapd_data *hapd,
+				   struct sta_info *sta)
+{
+	if (sta->acct_session_started)
+		accounting_sta_report(hapd, sta, 0);
+}
+
+
+/**
+ * accounting_sta_stop - Stop STA accounting
+ * @hapd: hostapd BSS data
+ * @sta: The station
+ */
+void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	if (sta->acct_session_started) {
+		accounting_sta_report(hapd, sta, 1);
+		eloop_cancel_timeout(accounting_interim_update, hapd, sta);
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+			       HOSTAPD_LEVEL_INFO,
+			       "stopped accounting session %08X-%08X",
+			       sta->acct_session_id_hi,
+			       sta->acct_session_id_lo);
+		sta->acct_session_started = 0;
+	}
+}
+
+
+void accounting_sta_get_id(struct hostapd_data *hapd,
+				  struct sta_info *sta)
+{
+	sta->acct_session_id_lo = hapd->acct_session_id_lo++;
+	if (hapd->acct_session_id_lo == 0) {
+		hapd->acct_session_id_hi++;
+	}
+	sta->acct_session_id_hi = hapd->acct_session_id_hi;
+}
+
+
+/**
+ * accounting_receive - Process the RADIUS frames from Accounting Server
+ * @msg: RADIUS response message
+ * @req: RADIUS request message
+ * @shared_secret: RADIUS shared secret
+ * @shared_secret_len: Length of shared_secret in octets
+ * @data: Context data (struct hostapd_data *)
+ * Returns: Processing status
+ */
+static RadiusRxResult
+accounting_receive(struct radius_msg *msg, struct radius_msg *req,
+		   const u8 *shared_secret, size_t shared_secret_len,
+		   void *data)
+{
+	if (radius_msg_get_hdr(msg)->code != RADIUS_CODE_ACCOUNTING_RESPONSE) {
+		printf("Unknown RADIUS message code\n");
+		return RADIUS_RX_UNKNOWN;
+	}
+
+	if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
+		printf("Incoming RADIUS packet did not have correct "
+		       "Authenticator - dropped\n");
+		return RADIUS_RX_INVALID_AUTHENTICATOR;
+	}
+
+	return RADIUS_RX_PROCESSED;
+}
+
+
+static void accounting_report_state(struct hostapd_data *hapd, int on)
+{
+	struct radius_msg *msg;
+
+	if (!hapd->conf->radius->acct_server || hapd->radius == NULL)
+		return;
+
+	/* Inform RADIUS server that accounting will start/stop so that the
+	 * server can close old accounting sessions. */
+	msg = accounting_msg(hapd, NULL,
+			     on ? RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_ON :
+			     RADIUS_ACCT_STATUS_TYPE_ACCOUNTING_OFF);
+	if (!msg)
+		return;
+
+	if (!radius_msg_add_attr_int32(msg, RADIUS_ATTR_ACCT_TERMINATE_CAUSE,
+				       RADIUS_ACCT_TERMINATE_CAUSE_NAS_REBOOT))
+	{
+		printf("Could not add Acct-Terminate-Cause\n");
+		radius_msg_free(msg);
+		return;
+	}
+
+	if (radius_client_send(hapd->radius, msg, RADIUS_ACCT, NULL) < 0)
+		radius_msg_free(msg);
+}
+
+
+/**
+ * accounting_init: Initialize accounting
+ * @hapd: hostapd BSS data
+ * Returns: 0 on success, -1 on failure
+ */
+int accounting_init(struct hostapd_data *hapd)
+{
+	struct os_time now;
+
+	/* Acct-Session-Id should be unique over reboots. If reliable clock is
+	 * not available, this could be replaced with reboot counter, etc. */
+	os_get_time(&now);
+	hapd->acct_session_id_hi = now.sec;
+
+	if (radius_client_register(hapd->radius, RADIUS_ACCT,
+				   accounting_receive, hapd))
+		return -1;
+
+	accounting_report_state(hapd, 1);
+
+	return 0;
+}
+
+
+/**
+ * accounting_deinit: Deinitilize accounting
+ * @hapd: hostapd BSS data
+ */
+void accounting_deinit(struct hostapd_data *hapd)
+{
+	accounting_report_state(hapd, 0);
+}
diff --git a/hostap/src/ap/accounting.h b/hostap/src/ap/accounting.h
new file mode 100644
index 0000000..dcc54ee
--- /dev/null
+++ b/hostap/src/ap/accounting.h
@@ -0,0 +1,44 @@
+/*
+ * hostapd / RADIUS Accounting
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef ACCOUNTING_H
+#define ACCOUNTING_H
+
+#ifdef CONFIG_NO_ACCOUNTING
+static inline void accounting_sta_get_id(struct hostapd_data *hapd,
+					 struct sta_info *sta)
+{
+}
+
+static inline void accounting_sta_start(struct hostapd_data *hapd,
+					struct sta_info *sta)
+{
+}
+
+static inline void accounting_sta_stop(struct hostapd_data *hapd,
+				       struct sta_info *sta)
+{
+}
+
+static inline int accounting_init(struct hostapd_data *hapd)
+{
+	return 0;
+}
+
+static inline void accounting_deinit(struct hostapd_data *hapd)
+{
+}
+#else /* CONFIG_NO_ACCOUNTING */
+void accounting_sta_get_id(struct hostapd_data *hapd, struct sta_info *sta);
+void accounting_sta_start(struct hostapd_data *hapd, struct sta_info *sta);
+void accounting_sta_stop(struct hostapd_data *hapd, struct sta_info *sta);
+int accounting_init(struct hostapd_data *hapd);
+void accounting_deinit(struct hostapd_data *hapd);
+#endif /* CONFIG_NO_ACCOUNTING */
+
+#endif /* ACCOUNTING_H */
diff --git a/hostap/src/ap/ap_config.c b/hostap/src/ap/ap_config.c
new file mode 100644
index 0000000..25d26e5
--- /dev/null
+++ b/hostap/src/ap/ap_config.c
@@ -0,0 +1,625 @@
+/*
+ * hostapd / Configuration helper functions
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "crypto/sha1.h"
+#include "radius/radius_client.h"
+#include "common/ieee802_11_defs.h"
+#include "common/eapol_common.h"
+#include "eap_common/eap_wsc_common.h"
+#include "eap_server/eap.h"
+#include "wpa_auth.h"
+#include "sta_info.h"
+#include "ap_config.h"
+
+
+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;
+		os_free(prev);
+	}
+
+	bss->vlan = NULL;
+}
+
+
+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 = WPA_AUTH_ALG_OPEN | WPA_AUTH_ALG_SHARED;
+
+	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->rsn_pairwise = 0;
+
+	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;
+
+	bss->max_listen_interval = 65535;
+
+	bss->pwd_group = 19; /* ECC: GF(p=256) */
+
+#ifdef CONFIG_IEEE80211W
+	bss->assoc_sa_query_max_timeout = 1000;
+	bss->assoc_sa_query_retry_timeout = 201;
+#endif /* CONFIG_IEEE80211W */
+#ifdef EAP_SERVER_FAST
+	 /* both anonymous and authenticated provisioning */
+	bss->eap_fast_prov = 3;
+	bss->pac_key_lifetime = 7 * 24 * 60 * 60;
+	bss->pac_key_refresh_time = 1 * 24 * 60 * 60;
+#endif /* EAP_SERVER_FAST */
+
+	/* Set to -1 as defaults depends on HT in setup */
+	bss->wmm_enabled = -1;
+
+#ifdef CONFIG_IEEE80211R
+	bss->ft_over_ds = 1;
+#endif /* CONFIG_IEEE80211R */
+
+	bss->radius_das_time_window = 300;
+}
+
+
+struct hostapd_config * hostapd_config_defaults(void)
+{
+#define ecw2cw(ecw) ((1 << (ecw)) - 1)
+
+	struct hostapd_config *conf;
+	struct hostapd_bss_config *bss;
+	const int aCWmin = 4, aCWmax = 10;
+	const struct hostapd_wmm_ac_params ac_bk =
+		{ aCWmin, aCWmax, 7, 0, 0 }; /* background traffic */
+	const struct hostapd_wmm_ac_params ac_be =
+		{ aCWmin, aCWmax, 3, 0, 0 }; /* best effort traffic */
+	const struct hostapd_wmm_ac_params ac_vi = /* video traffic */
+		{ aCWmin - 1, aCWmin, 2, 3000 / 32, 0 };
+	const struct hostapd_wmm_ac_params ac_vo = /* voice traffic */
+		{ aCWmin - 2, aCWmin - 1, 2, 1500 / 32, 0 };
+	const struct hostapd_tx_queue_params txq_bk =
+		{ 7, ecw2cw(aCWmin), ecw2cw(aCWmax), 0 };
+	const struct hostapd_tx_queue_params txq_be =
+		{ 3, ecw2cw(aCWmin), 4 * (ecw2cw(aCWmin) + 1) - 1, 0};
+	const struct hostapd_tx_queue_params txq_vi =
+		{ 1, (ecw2cw(aCWmin) + 1) / 2 - 1, ecw2cw(aCWmin), 30};
+	const struct hostapd_tx_queue_params txq_vo =
+		{ 1, (ecw2cw(aCWmin) + 1) / 4 - 1,
+		  (ecw2cw(aCWmin) + 1) / 2 - 1, 15};
+
+#undef ecw2cw
+
+	conf = os_zalloc(sizeof(*conf));
+	bss = os_zalloc(sizeof(*bss));
+	if (conf == NULL || bss == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to allocate memory for "
+			   "configuration data.");
+		os_free(conf);
+		os_free(bss);
+		return NULL;
+	}
+
+	bss->radius = os_zalloc(sizeof(*bss->radius));
+	if (bss->radius == NULL) {
+		os_free(conf);
+		os_free(bss);
+		return NULL;
+	}
+
+	hostapd_config_defaults_bss(bss);
+
+	conf->num_bss = 1;
+	conf->bss = bss;
+
+	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->wmm_ac_params[0] = ac_be;
+	conf->wmm_ac_params[1] = ac_bk;
+	conf->wmm_ac_params[2] = ac_vi;
+	conf->wmm_ac_params[3] = ac_vo;
+
+	conf->tx_queue[0] = txq_vo;
+	conf->tx_queue[1] = txq_vi;
+	conf->tx_queue[2] = txq_be;
+	conf->tx_queue[3] = txq_bk;
+
+	conf->ht_capab = HT_CAP_INFO_SMPS_DISABLED;
+
+	conf->ap_table_max_size = 255;
+	conf->ap_table_expiration_time = 60;
+
+	return conf;
+}
+
+
+int hostapd_mac_comp(const void *a, const void *b)
+{
+	return os_memcmp(a, b, sizeof(macaddr));
+}
+
+
+int hostapd_mac_comp_empty(const void *a)
+{
+	macaddr empty = { 0 };
+	return os_memcmp(a, empty, sizeof(macaddr));
+}
+
+
+static int hostapd_config_read_wpa_psk(const char *fname,
+				       struct hostapd_ssid *ssid)
+{
+	FILE *f;
+	char buf[128], *pos;
+	int line = 0, ret = 0, len, ok;
+	u8 addr[ETH_ALEN];
+	struct hostapd_wpa_psk *psk;
+
+	if (!fname)
+		return 0;
+
+	f = fopen(fname, "r");
+	if (!f) {
+		wpa_printf(MSG_ERROR, "WPA PSK file '%s' not found.", fname);
+		return -1;
+	}
+
+	while (fgets(buf, sizeof(buf), f)) {
+		line++;
+
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0') {
+			if (*pos == '\n') {
+				*pos = '\0';
+				break;
+			}
+			pos++;
+		}
+		if (buf[0] == '\0')
+			continue;
+
+		if (hwaddr_aton(buf, addr)) {
+			wpa_printf(MSG_ERROR, "Invalid MAC address '%s' on "
+				   "line %d in '%s'", buf, line, fname);
+			ret = -1;
+			break;
+		}
+
+		psk = os_zalloc(sizeof(*psk));
+		if (psk == NULL) {
+			wpa_printf(MSG_ERROR, "WPA PSK allocation failed");
+			ret = -1;
+			break;
+		}
+		if (is_zero_ether_addr(addr))
+			psk->group = 1;
+		else
+			os_memcpy(psk->addr, addr, ETH_ALEN);
+
+		pos = buf + 17;
+		if (*pos == '\0') {
+			wpa_printf(MSG_ERROR, "No PSK on line %d in '%s'",
+				   line, fname);
+			os_free(psk);
+			ret = -1;
+			break;
+		}
+		pos++;
+
+		ok = 0;
+		len = os_strlen(pos);
+		if (len == 64 && hexstr2bin(pos, psk->psk, PMK_LEN) == 0)
+			ok = 1;
+		else if (len >= 8 && len < 64) {
+			pbkdf2_sha1(pos, ssid->ssid, ssid->ssid_len,
+				    4096, psk->psk, PMK_LEN);
+			ok = 1;
+		}
+		if (!ok) {
+			wpa_printf(MSG_ERROR, "Invalid PSK '%s' on line %d in "
+				   "'%s'", pos, line, fname);
+			os_free(psk);
+			ret = -1;
+			break;
+		}
+
+		psk->next = ssid->wpa_psk;
+		ssid->wpa_psk = psk;
+	}
+
+	fclose(f);
+
+	return ret;
+}
+
+
+static int hostapd_derive_psk(struct hostapd_ssid *ssid)
+{
+	ssid->wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
+	if (ssid->wpa_psk == NULL) {
+		wpa_printf(MSG_ERROR, "Unable to alloc space for PSK");
+		return -1;
+	}
+	wpa_hexdump_ascii(MSG_DEBUG, "SSID",
+			  (u8 *) ssid->ssid, ssid->ssid_len);
+	wpa_hexdump_ascii_key(MSG_DEBUG, "PSK (ASCII passphrase)",
+			      (u8 *) ssid->wpa_passphrase,
+			      os_strlen(ssid->wpa_passphrase));
+	pbkdf2_sha1(ssid->wpa_passphrase,
+		    ssid->ssid, ssid->ssid_len,
+		    4096, ssid->wpa_psk->psk, PMK_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "PSK (from passphrase)",
+			ssid->wpa_psk->psk, PMK_LEN);
+	return 0;
+}
+
+
+int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf)
+{
+	struct hostapd_ssid *ssid = &conf->ssid;
+
+	if (ssid->wpa_passphrase != NULL) {
+		if (ssid->wpa_psk != NULL) {
+			wpa_printf(MSG_DEBUG, "Using pre-configured WPA PSK "
+				   "instead of passphrase");
+		} else {
+			wpa_printf(MSG_DEBUG, "Deriving WPA PSK based on "
+				   "passphrase");
+			if (hostapd_derive_psk(ssid) < 0)
+				return -1;
+		}
+		ssid->wpa_psk->group = 1;
+	}
+
+	if (ssid->wpa_psk_file) {
+		if (hostapd_config_read_wpa_psk(ssid->wpa_psk_file,
+						&conf->ssid))
+			return -1;
+	}
+
+	return 0;
+}
+
+
+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] ||
+		    os_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)
+{
+	int i;
+
+	for (i = 0; i < num_servers; i++) {
+		os_free(servers[i].shared_secret);
+	}
+	os_free(servers);
+}
+
+
+struct hostapd_radius_attr *
+hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type)
+{
+	for (; attr; attr = attr->next) {
+		if (attr->type == type)
+			return attr;
+	}
+	return NULL;
+}
+
+
+static void hostapd_config_free_radius_attr(struct hostapd_radius_attr *attr)
+{
+	struct hostapd_radius_attr *prev;
+
+	while (attr) {
+		prev = attr;
+		attr = attr->next;
+		wpabuf_free(prev->val);
+		os_free(prev);
+	}
+}
+
+
+static void hostapd_config_free_eap_user(struct hostapd_eap_user *user)
+{
+	os_free(user->identity);
+	os_free(user->password);
+	os_free(user);
+}
+
+
+static void hostapd_config_free_wep(struct hostapd_wep_keys *keys)
+{
+	int i;
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		os_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;
+
+	if (conf == NULL)
+		return;
+
+	psk = conf->ssid.wpa_psk;
+	while (psk) {
+		prev = psk;
+		psk = psk->next;
+		os_free(prev);
+	}
+
+	os_free(conf->ssid.wpa_passphrase);
+	os_free(conf->ssid.wpa_psk_file);
+	hostapd_config_free_wep(&conf->ssid.wep);
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	os_free(conf->ssid.vlan_tagged_interface);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+	user = conf->eap_user;
+	while (user) {
+		prev_user = user;
+		user = user->next;
+		hostapd_config_free_eap_user(prev_user);
+	}
+	os_free(conf->eap_user_sqlite);
+
+	os_free(conf->dump_log_name);
+	os_free(conf->eap_req_id_text);
+	os_free(conf->accept_mac);
+	os_free(conf->deny_mac);
+	os_free(conf->nas_identifier);
+	hostapd_config_free_radius(conf->radius->auth_servers,
+				   conf->radius->num_auth_servers);
+	hostapd_config_free_radius(conf->radius->acct_servers,
+				   conf->radius->num_acct_servers);
+	hostapd_config_free_radius_attr(conf->radius_auth_req_attr);
+	hostapd_config_free_radius_attr(conf->radius_acct_req_attr);
+	os_free(conf->rsn_preauth_interfaces);
+	os_free(conf->ctrl_interface);
+	os_free(conf->ca_cert);
+	os_free(conf->server_cert);
+	os_free(conf->private_key);
+	os_free(conf->private_key_passwd);
+	os_free(conf->dh_file);
+	os_free(conf->pac_opaque_encr_key);
+	os_free(conf->eap_fast_a_id);
+	os_free(conf->eap_fast_a_id_info);
+	os_free(conf->eap_sim_db);
+	os_free(conf->radius_server_clients);
+	os_free(conf->test_socket);
+	os_free(conf->radius);
+	os_free(conf->radius_das_shared_secret);
+	hostapd_config_free_vlan(conf);
+	if (conf->ssid.dyn_vlan_keys) {
+		struct hostapd_ssid *ssid = &conf->ssid;
+		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]);
+			os_free(ssid->dyn_vlan_keys[i]);
+		}
+		os_free(ssid->dyn_vlan_keys);
+		ssid->dyn_vlan_keys = NULL;
+	}
+
+	os_free(conf->time_zone);
+
+#ifdef CONFIG_IEEE80211R
+	{
+		struct ft_remote_r0kh *r0kh, *r0kh_prev;
+		struct ft_remote_r1kh *r1kh, *r1kh_prev;
+
+		r0kh = conf->r0kh_list;
+		conf->r0kh_list = NULL;
+		while (r0kh) {
+			r0kh_prev = r0kh;
+			r0kh = r0kh->next;
+			os_free(r0kh_prev);
+		}
+
+		r1kh = conf->r1kh_list;
+		conf->r1kh_list = NULL;
+		while (r1kh) {
+			r1kh_prev = r1kh;
+			r1kh = r1kh->next;
+			os_free(r1kh_prev);
+		}
+	}
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_WPS
+	os_free(conf->wps_pin_requests);
+	os_free(conf->device_name);
+	os_free(conf->manufacturer);
+	os_free(conf->model_name);
+	os_free(conf->model_number);
+	os_free(conf->serial_number);
+	os_free(conf->config_methods);
+	os_free(conf->ap_pin);
+	os_free(conf->extra_cred);
+	os_free(conf->ap_settings);
+	os_free(conf->upnp_iface);
+	os_free(conf->friendly_name);
+	os_free(conf->manufacturer_url);
+	os_free(conf->model_description);
+	os_free(conf->model_url);
+	os_free(conf->upc);
+	wpabuf_free(conf->wps_nfc_dh_pubkey);
+	wpabuf_free(conf->wps_nfc_dh_privkey);
+	wpabuf_free(conf->wps_nfc_dev_pw);
+#endif /* CONFIG_WPS */
+
+	os_free(conf->roaming_consortium);
+	os_free(conf->venue_name);
+	os_free(conf->nai_realm_data);
+	os_free(conf->network_auth_type);
+	os_free(conf->anqp_3gpp_cell_net);
+	os_free(conf->domain_name);
+
+#ifdef CONFIG_RADIUS_TEST
+	os_free(conf->dump_msk_file);
+#endif /* CONFIG_RADIUS_TEST */
+
+#ifdef CONFIG_HS20
+	os_free(conf->hs20_oper_friendly_name);
+	os_free(conf->hs20_wan_metrics);
+	os_free(conf->hs20_connection_capability);
+	os_free(conf->hs20_operating_class);
+#endif /* CONFIG_HS20 */
+
+	wpabuf_free(conf->vendor_elements);
+}
+
+
+/**
+ * hostapd_config_free - Free hostapd configuration
+ * @conf: Configuration data from hostapd_config_read().
+ */
+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]);
+	os_free(conf->bss);
+	os_free(conf->supported_rates);
+	os_free(conf->basic_rates);
+
+	os_free(conf);
+}
+
+
+/**
+ * hostapd_maclist_found - Find a MAC address from a list
+ * @list: MAC address list
+ * @num_entries: Number of addresses in the list
+ * @addr: Address to search for
+ * @vlan_id: Buffer for returning VLAN ID or %NULL if not needed
+ * Returns: 1 if address is in the list or 0 if not.
+ *
+ * Perform a binary search for given MAC address from a pre-sorted list.
+ */
+int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
+			  const u8 *addr, int *vlan_id)
+{
+	int start, end, middle, res;
+
+	start = 0;
+	end = num_entries - 1;
+
+	while (start <= end) {
+		middle = (start + end) / 2;
+		res = os_memcmp(list[middle].addr, addr, ETH_ALEN);
+		if (res == 0) {
+			if (vlan_id)
+				*vlan_id = list[middle].vlan_id;
+			return 1;
+		}
+		if (res < 0)
+			start = middle + 1;
+		else
+			end = middle - 1;
+	}
+
+	return 0;
+}
+
+
+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->ssid.wpa_psk; psk != NULL; psk = psk->next) {
+		if (next_ok &&
+		    (psk->group || os_memcmp(psk->addr, addr, ETH_ALEN) == 0))
+			return psk->psk;
+
+		if (psk->psk == prev_psk)
+			next_ok = 1;
+	}
+
+	return NULL;
+}
diff --git a/hostap/src/ap/ap_config.h b/hostap/src/ap/ap_config.h
new file mode 100644
index 0000000..120d0e9
--- /dev/null
+++ b/hostap/src/ap/ap_config.h
@@ -0,0 +1,542 @@
+/*
+ * hostapd / Configuration definitions and helpers functions
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HOSTAPD_CONFIG_H
+#define HOSTAPD_CONFIG_H
+
+#include "common/defs.h"
+#include "ip_addr.h"
+#include "common/wpa_common.h"
+#include "common/ieee802_11_common.h"
+#include "wps/wps.h"
+
+#define MAX_STA_COUNT 2007
+#define MAX_VLAN_ID 4094
+
+typedef u8 macaddr[ETH_ALEN];
+
+struct mac_acl_entry {
+	macaddr addr;
+	int vlan_id;
+};
+
+struct hostapd_radius_servers;
+struct ft_remote_r0kh;
+struct ft_remote_r1kh;
+
+#define HOSTAPD_MAX_SSID_LEN 32
+
+#define NUM_WEP_KEYS 4
+struct hostapd_wep_keys {
+	u8 idx;
+	u8 *key[NUM_WEP_KEYS];
+	size_t len[NUM_WEP_KEYS];
+	int keys_set;
+	size_t default_len; /* key length used for dynamic key generation */
+};
+
+typedef enum hostap_security_policy {
+	SECURITY_PLAINTEXT = 0,
+	SECURITY_STATIC_WEP = 1,
+	SECURITY_IEEE_802_1X = 2,
+	SECURITY_WPA_PSK = 3,
+	SECURITY_WPA = 4
+} secpolicy;
+
+struct hostapd_ssid {
+	u8 ssid[HOSTAPD_MAX_SSID_LEN];
+	size_t ssid_len;
+	unsigned int ssid_set:1;
+	unsigned int utf8_ssid:1;
+
+	char vlan[IFNAMSIZ + 1];
+	secpolicy security_policy;
+
+	struct hostapd_wpa_psk *wpa_psk;
+	char *wpa_passphrase;
+	char *wpa_psk_file;
+
+	struct hostapd_wep_keys wep;
+
+#define DYNAMIC_VLAN_DISABLED 0
+#define DYNAMIC_VLAN_OPTIONAL 1
+#define DYNAMIC_VLAN_REQUIRED 2
+	int dynamic_vlan;
+#define DYNAMIC_VLAN_NAMING_WITHOUT_DEVICE 0
+#define DYNAMIC_VLAN_NAMING_WITH_DEVICE 1
+#define DYNAMIC_VLAN_NAMING_END 2
+	int vlan_naming;
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	char *vlan_tagged_interface;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+	struct hostapd_wep_keys **dyn_vlan_keys;
+	size_t max_dyn_vlan_keys;
+};
+
+
+#define VLAN_ID_WILDCARD -1
+
+struct hostapd_vlan {
+	struct hostapd_vlan *next;
+	int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
+	char ifname[IFNAMSIZ + 1];
+	int dynamic_vlan;
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+
+#define DVLAN_CLEAN_BR 	0x1
+#define DVLAN_CLEAN_VLAN	0x2
+#define DVLAN_CLEAN_VLAN_PORT	0x4
+#define DVLAN_CLEAN_WLAN_PORT	0x8
+	int clean;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+};
+
+#define PMK_LEN 32
+struct hostapd_sta_wpa_psk_short {
+	struct hostapd_sta_wpa_psk_short *next;
+	u8 psk[PMK_LEN];
+};
+
+struct hostapd_wpa_psk {
+	struct hostapd_wpa_psk *next;
+	int group;
+	u8 psk[PMK_LEN];
+	u8 addr[ETH_ALEN];
+};
+
+struct hostapd_eap_user {
+	struct hostapd_eap_user *next;
+	u8 *identity;
+	size_t identity_len;
+	struct {
+		int vendor;
+		u32 method;
+	} methods[EAP_MAX_METHODS];
+	u8 *password;
+	size_t password_len;
+	int phase2;
+	int force_version;
+	unsigned int wildcard_prefix:1;
+	unsigned int password_hash:1; /* whether password is hashed with
+				       * nt_password_hash() */
+	int ttls_auth; /* EAP_TTLS_AUTH_* bitfield */
+};
+
+struct hostapd_radius_attr {
+	u8 type;
+	struct wpabuf *val;
+	struct hostapd_radius_attr *next;
+};
+
+
+#define NUM_TX_QUEUES 4
+
+struct hostapd_tx_queue_params {
+	int aifs;
+	int cwmin;
+	int cwmax;
+	int burst; /* maximum burst time in 0.1 ms, i.e., 10 = 1 ms */
+};
+
+
+#define MAX_ROAMING_CONSORTIUM_LEN 15
+
+struct hostapd_roaming_consortium {
+	u8 len;
+	u8 oi[MAX_ROAMING_CONSORTIUM_LEN];
+};
+
+struct hostapd_lang_string {
+	u8 lang[3];
+	u8 name_len;
+	u8 name[252];
+};
+
+#define MAX_NAI_REALMS 10
+#define MAX_NAI_REALMLEN 255
+#define MAX_NAI_EAP_METHODS 5
+#define MAX_NAI_AUTH_TYPES 4
+struct hostapd_nai_realm_data {
+	u8 encoding;
+	char realm_buf[MAX_NAI_REALMLEN + 1];
+	char *realm[MAX_NAI_REALMS];
+	u8 eap_method_count;
+	struct hostapd_nai_realm_eap {
+		u8 eap_method;
+		u8 num_auths;
+		u8 auth_id[MAX_NAI_AUTH_TYPES];
+		u8 auth_val[MAX_NAI_AUTH_TYPES];
+	} eap_method[MAX_NAI_EAP_METHODS];
+};
+
+/**
+ * struct hostapd_bss_config - Per-BSS configuration
+ */
+struct hostapd_bss_config {
+	char iface[IFNAMSIZ + 1];
+	char bridge[IFNAMSIZ + 1];
+	char wds_bridge[IFNAMSIZ + 1];
+
+	enum hostapd_logger_level logger_syslog_level, logger_stdout_level;
+
+	unsigned int logger_syslog; /* module bitfield */
+	unsigned int logger_stdout; /* module bitfield */
+
+	char *dump_log_name; /* file name for state dump (SIGUSR1) */
+
+	int max_num_sta; /* maximum number of STAs in station table */
+
+	int dtim_period;
+
+	int ieee802_1x; /* use IEEE 802.1X */
+	int eapol_version;
+	int eap_server; /* Use internal EAP server instead of external
+			 * RADIUS server */
+	struct hostapd_eap_user *eap_user;
+	char *eap_user_sqlite;
+	char *eap_sim_db;
+	struct hostapd_ip_addr own_ip_addr;
+	char *nas_identifier;
+	struct hostapd_radius_servers *radius;
+	int acct_interim_interval;
+	int radius_request_cui;
+	struct hostapd_radius_attr *radius_auth_req_attr;
+	struct hostapd_radius_attr *radius_acct_req_attr;
+	int radius_das_port;
+	unsigned int radius_das_time_window;
+	int radius_das_require_event_timestamp;
+	struct hostapd_ip_addr radius_das_client_addr;
+	u8 *radius_das_shared_secret;
+	size_t radius_das_shared_secret_len;
+
+	struct hostapd_ssid ssid;
+
+	char *eap_req_id_text; /* optional displayable message sent with
+				* EAP Request-Identity */
+	size_t eap_req_id_text_len;
+	int eapol_key_index_workaround;
+
+	size_t default_wep_key_len;
+	int individual_wep_key_len;
+	int wep_rekeying_period;
+	int broadcast_key_idx_min, broadcast_key_idx_max;
+	int eap_reauth_period;
+
+	int ieee802_11f; /* use IEEE 802.11f (IAPP) */
+	char iapp_iface[IFNAMSIZ + 1]; /* interface used with IAPP broadcast
+					* frames */
+
+	enum {
+		ACCEPT_UNLESS_DENIED = 0,
+		DENY_UNLESS_ACCEPTED = 1,
+		USE_EXTERNAL_RADIUS_AUTH = 2
+	} macaddr_acl;
+	struct mac_acl_entry *accept_mac;
+	int num_accept_mac;
+	struct mac_acl_entry *deny_mac;
+	int num_deny_mac;
+	int wds_sta;
+	int isolate;
+
+	int auth_algs; /* bitfield of allowed IEEE 802.11 authentication
+			* algorithms, WPA_AUTH_ALG_{OPEN,SHARED,LEAP} */
+
+	int wpa; /* bitfield of WPA_PROTO_WPA, WPA_PROTO_RSN */
+	int wpa_key_mgmt;
+#ifdef CONFIG_IEEE80211W
+	enum mfp_options ieee80211w;
+	/* dot11AssociationSAQueryMaximumTimeout (in TUs) */
+	unsigned int assoc_sa_query_max_timeout;
+	/* dot11AssociationSAQueryRetryTimeout (in TUs) */
+	int assoc_sa_query_retry_timeout;
+#endif /* CONFIG_IEEE80211W */
+	enum {
+		PSK_RADIUS_IGNORED = 0,
+		PSK_RADIUS_ACCEPTED = 1,
+		PSK_RADIUS_REQUIRED = 2
+	} wpa_psk_radius;
+	int wpa_pairwise;
+	int wpa_group;
+	int wpa_group_rekey;
+	int wpa_strict_rekey;
+	int wpa_gmk_rekey;
+	int wpa_ptk_rekey;
+	int rsn_pairwise;
+	int rsn_preauth;
+	char *rsn_preauth_interfaces;
+	int peerkey;
+
+#ifdef CONFIG_IEEE80211R
+	/* IEEE 802.11r - Fast BSS Transition */
+	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
+	u8 r1_key_holder[FT_R1KH_ID_LEN];
+	u32 r0_key_lifetime;
+	u32 reassociation_deadline;
+	struct ft_remote_r0kh *r0kh_list;
+	struct ft_remote_r1kh *r1kh_list;
+	int pmk_r1_push;
+	int ft_over_ds;
+#endif /* CONFIG_IEEE80211R */
+
+	char *ctrl_interface; /* directory for UNIX domain sockets */
+#ifndef CONFIG_NATIVE_WINDOWS
+	gid_t ctrl_interface_gid;
+#endif /* CONFIG_NATIVE_WINDOWS */
+	int ctrl_interface_gid_set;
+
+	char *ca_cert;
+	char *server_cert;
+	char *private_key;
+	char *private_key_passwd;
+	int check_crl;
+	char *dh_file;
+	u8 *pac_opaque_encr_key;
+	u8 *eap_fast_a_id;
+	size_t eap_fast_a_id_len;
+	char *eap_fast_a_id_info;
+	int eap_fast_prov;
+	int pac_key_lifetime;
+	int pac_key_refresh_time;
+	int eap_sim_aka_result_ind;
+	int tnc;
+	int fragment_size;
+	u16 pwd_group;
+
+	char *radius_server_clients;
+	int radius_server_auth_port;
+	int radius_server_ipv6;
+
+	char *test_socket; /* UNIX domain socket path for driver_test */
+
+	int use_pae_group_addr; /* Whether to send EAPOL frames to PAE group
+				 * address instead of individual address
+				 * (for driver_wired.c).
+				 */
+
+	int ap_max_inactivity;
+	int ignore_broadcast_ssid;
+
+	int wmm_enabled;
+	int wmm_uapsd;
+
+	struct hostapd_vlan *vlan, *vlan_tail;
+
+	macaddr bssid;
+
+	/*
+	 * Maximum listen interval that STAs can use when associating with this
+	 * BSS. If a STA tries to use larger value, the association will be
+	 * denied with status code 51.
+	 */
+	u16 max_listen_interval;
+
+	int disable_pmksa_caching;
+	int okc; /* Opportunistic Key Caching */
+
+	int wps_state;
+#ifdef CONFIG_WPS
+	int ap_setup_locked;
+	u8 uuid[16];
+	char *wps_pin_requests;
+	char *device_name;
+	char *manufacturer;
+	char *model_name;
+	char *model_number;
+	char *serial_number;
+	u8 device_type[WPS_DEV_TYPE_LEN];
+	char *config_methods;
+	u8 os_version[4];
+	char *ap_pin;
+	int skip_cred_build;
+	u8 *extra_cred;
+	size_t extra_cred_len;
+	int wps_cred_processing;
+	u8 *ap_settings;
+	size_t ap_settings_len;
+	char *upnp_iface;
+	char *friendly_name;
+	char *manufacturer_url;
+	char *model_description;
+	char *model_url;
+	char *upc;
+	struct wpabuf *wps_vendor_ext[MAX_WPS_VENDOR_EXTENSIONS];
+	int wps_nfc_dev_pw_id;
+	struct wpabuf *wps_nfc_dh_pubkey;
+	struct wpabuf *wps_nfc_dh_privkey;
+	struct wpabuf *wps_nfc_dev_pw;
+#endif /* CONFIG_WPS */
+	int pbc_in_m1;
+
+#define P2P_ENABLED BIT(0)
+#define P2P_GROUP_OWNER BIT(1)
+#define P2P_GROUP_FORMATION BIT(2)
+#define P2P_MANAGE BIT(3)
+#define P2P_ALLOW_CROSS_CONNECTION BIT(4)
+	int p2p;
+
+	int disassoc_low_ack;
+	int skip_inactivity_poll;
+
+#define TDLS_PROHIBIT BIT(0)
+#define TDLS_PROHIBIT_CHAN_SWITCH BIT(1)
+	int tdls;
+	int disable_11n;
+	int disable_11ac;
+
+	/* IEEE 802.11v */
+	int time_advertisement;
+	char *time_zone;
+	int wnm_sleep_mode;
+	int bss_transition;
+
+	/* IEEE 802.11u - Interworking */
+	int interworking;
+	int access_network_type;
+	int internet;
+	int asra;
+	int esr;
+	int uesa;
+	int venue_info_set;
+	u8 venue_group;
+	u8 venue_type;
+	u8 hessid[ETH_ALEN];
+
+	/* IEEE 802.11u - Roaming Consortium list */
+	unsigned int roaming_consortium_count;
+	struct hostapd_roaming_consortium *roaming_consortium;
+
+	/* IEEE 802.11u - Venue Name duples */
+	unsigned int venue_name_count;
+	struct hostapd_lang_string *venue_name;
+
+	/* IEEE 802.11u - Network Authentication Type */
+	u8 *network_auth_type;
+	size_t network_auth_type_len;
+
+	/* IEEE 802.11u - IP Address Type Availability */
+	u8 ipaddr_type_availability;
+	u8 ipaddr_type_configured;
+
+	/* IEEE 802.11u - 3GPP Cellular Network */
+	u8 *anqp_3gpp_cell_net;
+	size_t anqp_3gpp_cell_net_len;
+
+	/* IEEE 802.11u - Domain Name */
+	u8 *domain_name;
+	size_t domain_name_len;
+
+	unsigned int nai_realm_count;
+	struct hostapd_nai_realm_data *nai_realm_data;
+
+	u16 gas_comeback_delay;
+	int gas_frag_limit;
+
+#ifdef CONFIG_HS20
+	int hs20;
+	int disable_dgaf;
+	unsigned int hs20_oper_friendly_name_count;
+	struct hostapd_lang_string *hs20_oper_friendly_name;
+	u8 *hs20_wan_metrics;
+	u8 *hs20_connection_capability;
+	size_t hs20_connection_capability_len;
+	u8 *hs20_operating_class;
+	u8 hs20_operating_class_len;
+#endif /* CONFIG_HS20 */
+
+	u8 wps_rf_bands; /* RF bands for WPS (WPS_RF_*) */
+
+#ifdef CONFIG_RADIUS_TEST
+	char *dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
+
+	struct wpabuf *vendor_elements;
+};
+
+
+/**
+ * struct hostapd_config - Per-radio interface configuration
+ */
+struct hostapd_config {
+	struct hostapd_bss_config *bss, *last_bss;
+	size_t num_bss;
+
+	u16 beacon_int;
+	int rts_threshold;
+	int fragm_threshold;
+	u8 send_probe_response;
+	u8 channel;
+	enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
+	enum {
+		LONG_PREAMBLE = 0,
+		SHORT_PREAMBLE = 1
+	} preamble;
+
+	int *supported_rates;
+	int *basic_rates;
+
+	const struct wpa_driver_ops *driver;
+
+	int ap_table_max_size;
+	int ap_table_expiration_time;
+
+	char country[3]; /* first two octets: country code as described in
+			  * ISO/IEC 3166-1. Third octet:
+			  * ' ' (ascii 32): all environments
+			  * 'O': Outdoor environemnt only
+			  * 'I': Indoor environment only
+			  */
+
+	int ieee80211d;
+
+	/* AP/GO channel switch count */
+	int channel_switch_count;
+
+	struct hostapd_tx_queue_params tx_queue[NUM_TX_QUEUES];
+
+	/*
+	 * WMM AC parameters, in same order as 802.1D, i.e.
+	 * 0 = BE (best effort)
+	 * 1 = BK (background)
+	 * 2 = VI (video)
+	 * 3 = VO (voice)
+	 */
+	struct hostapd_wmm_ac_params wmm_ac_params[4];
+
+	int ht_op_mode_fixed;
+	u16 ht_capab;
+	int ieee80211n;
+	int secondary_channel;
+	int require_ht;
+	u32 vht_capab;
+	int ieee80211ac;
+	int require_vht;
+	u8 vht_oper_chwidth;
+	u8 vht_oper_centr_freq_seg0_idx;
+	u8 vht_oper_centr_freq_seg1_idx;
+};
+
+
+int hostapd_mac_comp(const void *a, const void *b);
+int hostapd_mac_comp_empty(const void *a);
+struct hostapd_config * hostapd_config_defaults(void);
+void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
+void hostapd_config_free(struct hostapd_config *conf);
+int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
+			  const u8 *addr, int *vlan_id);
+int hostapd_rate_found(int *list, int rate);
+int hostapd_wep_key_cmp(struct hostapd_wep_keys *a,
+			struct hostapd_wep_keys *b);
+const u8 * hostapd_get_psk(const struct hostapd_bss_config *conf,
+			   const u8 *addr, const u8 *prev_psk);
+int hostapd_setup_wpa_psk(struct hostapd_bss_config *conf);
+const char * hostapd_get_vlan_id_ifname(struct hostapd_vlan *vlan,
+					int vlan_id);
+struct hostapd_radius_attr *
+hostapd_config_get_radius_attr(struct hostapd_radius_attr *attr, u8 type);
+
+#endif /* HOSTAPD_CONFIG_H */
diff --git a/hostap/src/ap/ap_drv_ops.c b/hostap/src/ap/ap_drv_ops.c
new file mode 100644
index 0000000..556b3b8
--- /dev/null
+++ b/hostap/src/ap/ap_drv_ops.c
@@ -0,0 +1,664 @@
+/*
+ * hostapd - Driver operations
+ * Copyright (c) 2009-2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "drivers/driver.h"
+#include "common/ieee802_11_defs.h"
+#include "wps/wps.h"
+#include "p2p/p2p.h"
+#include "hostapd.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "ap_config.h"
+#include "p2p_hostapd.h"
+#include "hs20.h"
+#include "ap_drv_ops.h"
+
+
+u32 hostapd_sta_flags_to_drv(u32 flags)
+{
+	int res = 0;
+	if (flags & WLAN_STA_AUTHORIZED)
+		res |= WPA_STA_AUTHORIZED;
+	if (flags & WLAN_STA_WMM)
+		res |= WPA_STA_WMM;
+	if (flags & WLAN_STA_SHORT_PREAMBLE)
+		res |= WPA_STA_SHORT_PREAMBLE;
+	if (flags & WLAN_STA_MFP)
+		res |= WPA_STA_MFP;
+	return res;
+}
+
+
+int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
+			       struct wpabuf **beacon_ret,
+			       struct wpabuf **proberesp_ret,
+			       struct wpabuf **assocresp_ret)
+{
+	struct wpabuf *beacon = NULL, *proberesp = NULL, *assocresp = NULL;
+	u8 buf[200], *pos;
+
+	*beacon_ret = *proberesp_ret = *assocresp_ret = NULL;
+
+	pos = buf;
+	pos = hostapd_eid_time_adv(hapd, pos);
+	if (pos != buf) {
+		if (wpabuf_resize(&beacon, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(beacon, buf, pos - buf);
+	}
+	pos = hostapd_eid_time_zone(hapd, pos);
+	if (pos != buf) {
+		if (wpabuf_resize(&proberesp, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(proberesp, buf, pos - buf);
+	}
+
+	pos = buf;
+	pos = hostapd_eid_ext_capab(hapd, pos);
+	if (pos != buf) {
+		if (wpabuf_resize(&assocresp, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(assocresp, buf, pos - buf);
+	}
+	pos = hostapd_eid_interworking(hapd, pos);
+	pos = hostapd_eid_adv_proto(hapd, pos);
+	pos = hostapd_eid_roaming_consortium(hapd, pos);
+	if (pos != buf) {
+		if (wpabuf_resize(&beacon, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(beacon, buf, pos - buf);
+
+		if (wpabuf_resize(&proberesp, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(proberesp, buf, pos - buf);
+	}
+
+	if (hapd->wps_beacon_ie) {
+		if (wpabuf_resize(&beacon, wpabuf_len(hapd->wps_beacon_ie)) <
+		    0)
+			goto fail;
+		wpabuf_put_buf(beacon, hapd->wps_beacon_ie);
+	}
+
+	if (hapd->wps_probe_resp_ie) {
+		if (wpabuf_resize(&proberesp,
+				  wpabuf_len(hapd->wps_probe_resp_ie)) < 0)
+			goto fail;
+		wpabuf_put_buf(proberesp, hapd->wps_probe_resp_ie);
+	}
+
+#ifdef CONFIG_P2P
+	if (hapd->p2p_beacon_ie) {
+		if (wpabuf_resize(&beacon, wpabuf_len(hapd->p2p_beacon_ie)) <
+		    0)
+			goto fail;
+		wpabuf_put_buf(beacon, hapd->p2p_beacon_ie);
+	}
+
+	if (hapd->p2p_probe_resp_ie) {
+		if (wpabuf_resize(&proberesp,
+				  wpabuf_len(hapd->p2p_probe_resp_ie)) < 0)
+			goto fail;
+		wpabuf_put_buf(proberesp, hapd->p2p_probe_resp_ie);
+	}
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_P2P_MANAGER
+	if (hapd->conf->p2p & P2P_MANAGE) {
+		if (wpabuf_resize(&beacon, 100) == 0) {
+			u8 *start, *p;
+			start = wpabuf_put(beacon, 0);
+			p = hostapd_eid_p2p_manage(hapd, start);
+			wpabuf_put(beacon, p - start);
+		}
+
+		if (wpabuf_resize(&proberesp, 100) == 0) {
+			u8 *start, *p;
+			start = wpabuf_put(proberesp, 0);
+			p = hostapd_eid_p2p_manage(hapd, start);
+			wpabuf_put(proberesp, p - start);
+		}
+	}
+#endif /* CONFIG_P2P_MANAGER */
+
+#ifdef CONFIG_WPS2
+	if (hapd->conf->wps_state) {
+		struct wpabuf *a = wps_build_assoc_resp_ie();
+		if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
+			wpabuf_put_buf(assocresp, a);
+		wpabuf_free(a);
+	}
+#endif /* CONFIG_WPS2 */
+
+#ifdef CONFIG_P2P_MANAGER
+	if (hapd->conf->p2p & P2P_MANAGE) {
+		if (wpabuf_resize(&assocresp, 100) == 0) {
+			u8 *start, *p;
+			start = wpabuf_put(assocresp, 0);
+			p = hostapd_eid_p2p_manage(hapd, start);
+			wpabuf_put(assocresp, p - start);
+		}
+	}
+#endif /* CONFIG_P2P_MANAGER */
+
+#ifdef CONFIG_WIFI_DISPLAY
+	if (hapd->p2p_group) {
+		struct wpabuf *a;
+		a = p2p_group_assoc_resp_ie(hapd->p2p_group, P2P_SC_SUCCESS);
+		if (a && wpabuf_resize(&assocresp, wpabuf_len(a)) == 0)
+			wpabuf_put_buf(assocresp, a);
+		wpabuf_free(a);
+	}
+#endif /* CONFIG_WIFI_DISPLAY */
+
+#ifdef CONFIG_HS20
+	pos = buf;
+	pos = hostapd_eid_hs20_indication(hapd, pos);
+	if (pos != buf) {
+		if (wpabuf_resize(&beacon, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(beacon, buf, pos - buf);
+
+		if (wpabuf_resize(&proberesp, pos - buf) != 0)
+			goto fail;
+		wpabuf_put_data(proberesp, buf, pos - buf);
+	}
+#endif /* CONFIG_HS20 */
+
+	*beacon_ret = beacon;
+	*proberesp_ret = proberesp;
+	*assocresp_ret = assocresp;
+
+	return 0;
+
+fail:
+	wpabuf_free(beacon);
+	wpabuf_free(proberesp);
+	wpabuf_free(assocresp);
+	return -1;
+}
+
+
+void hostapd_free_ap_extra_ies(struct hostapd_data *hapd,
+			       struct wpabuf *beacon,
+			       struct wpabuf *proberesp,
+			       struct wpabuf *assocresp)
+{
+	wpabuf_free(beacon);
+	wpabuf_free(proberesp);
+	wpabuf_free(assocresp);
+}
+
+
+int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
+{
+	struct wpabuf *beacon, *proberesp, *assocresp;
+	int ret;
+
+	if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
+		return 0;
+
+	if (hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp) <
+	    0)
+		return -1;
+
+	ret = hapd->driver->set_ap_wps_ie(hapd->drv_priv, beacon, proberesp,
+					  assocresp);
+
+	hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
+
+	return ret;
+}
+
+
+int hostapd_set_authorized(struct hostapd_data *hapd,
+			   struct sta_info *sta, int authorized)
+{
+	if (authorized) {
+		return hostapd_sta_set_flags(hapd, sta->addr,
+					     hostapd_sta_flags_to_drv(
+						     sta->flags),
+					     WPA_STA_AUTHORIZED, ~0);
+	}
+
+	return hostapd_sta_set_flags(hapd, sta->addr,
+				     hostapd_sta_flags_to_drv(sta->flags),
+				     0, ~WPA_STA_AUTHORIZED);
+}
+
+
+int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	int set_flags, total_flags, flags_and, flags_or;
+	total_flags = hostapd_sta_flags_to_drv(sta->flags);
+	set_flags = WPA_STA_SHORT_PREAMBLE | WPA_STA_WMM | WPA_STA_MFP;
+	if (((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
+	     sta->auth_alg == WLAN_AUTH_FT) &&
+	    sta->flags & WLAN_STA_AUTHORIZED)
+		set_flags |= WPA_STA_AUTHORIZED;
+	flags_or = total_flags & set_flags;
+	flags_and = total_flags | ~set_flags;
+	return hostapd_sta_set_flags(hapd, sta->addr, total_flags,
+				     flags_or, flags_and);
+}
+
+
+int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
+			      int enabled)
+{
+	struct wpa_bss_params params;
+	os_memset(&params, 0, sizeof(params));
+	params.ifname = ifname;
+	params.enabled = enabled;
+	if (enabled) {
+		params.wpa = hapd->conf->wpa;
+		params.ieee802_1x = hapd->conf->ieee802_1x;
+		params.wpa_group = hapd->conf->wpa_group;
+		params.wpa_pairwise = hapd->conf->wpa_pairwise;
+		params.wpa_key_mgmt = hapd->conf->wpa_key_mgmt;
+		params.rsn_preauth = hapd->conf->rsn_preauth;
+#ifdef CONFIG_IEEE80211W
+		params.ieee80211w = hapd->conf->ieee80211w;
+#endif /* CONFIG_IEEE80211W */
+	}
+	return hostapd_set_ieee8021x(hapd, &params);
+}
+
+
+int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname)
+{
+	char force_ifname[IFNAMSIZ];
+	u8 if_addr[ETH_ALEN];
+	return hostapd_if_add(hapd, WPA_IF_AP_VLAN, ifname, hapd->own_addr,
+			      NULL, NULL, force_ifname, if_addr, NULL);
+}
+
+
+int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname)
+{
+	return hostapd_if_remove(hapd, WPA_IF_AP_VLAN, ifname);
+}
+
+
+int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
+			int val)
+{
+	const char *bridge = NULL;
+
+	if (hapd->driver == NULL || hapd->driver->set_wds_sta == NULL)
+		return 0;
+	if (hapd->conf->wds_bridge[0])
+		bridge = hapd->conf->wds_bridge;
+	else if (hapd->conf->bridge[0])
+		bridge = hapd->conf->bridge;
+	return hapd->driver->set_wds_sta(hapd->drv_priv, addr, aid, val,
+					 bridge);
+}
+
+
+int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
+			 u16 auth_alg)
+{
+	if (hapd->driver == NULL || hapd->driver->add_sta_node == NULL)
+		return 0;
+	return hapd->driver->add_sta_node(hapd->drv_priv, addr, auth_alg);
+}
+
+
+int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
+		     u16 seq, u16 status, const u8 *ie, size_t len)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_auth == NULL)
+		return 0;
+	return hapd->driver->sta_auth(hapd->drv_priv, hapd->own_addr, addr,
+				      seq, status, ie, len);
+}
+
+
+int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
+		      int reassoc, u16 status, const u8 *ie, size_t len)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_assoc == NULL)
+		return 0;
+	return hapd->driver->sta_assoc(hapd->drv_priv, hapd->own_addr, addr,
+				       reassoc, status, ie, len);
+}
+
+
+int hostapd_sta_add(struct hostapd_data *hapd,
+		    const u8 *addr, u16 aid, u16 capability,
+		    const u8 *supp_rates, size_t supp_rates_len,
+		    u16 listen_interval,
+		    const struct ieee80211_ht_capabilities *ht_capab,
+		    u32 flags, u8 qosinfo)
+{
+	struct hostapd_sta_add_params params;
+
+	if (hapd->driver == NULL)
+		return 0;
+	if (hapd->driver->sta_add == NULL)
+		return 0;
+
+	os_memset(&params, 0, sizeof(params));
+	params.addr = addr;
+	params.aid = aid;
+	params.capability = capability;
+	params.supp_rates = supp_rates;
+	params.supp_rates_len = supp_rates_len;
+	params.listen_interval = listen_interval;
+	params.ht_capabilities = ht_capab;
+	params.flags = hostapd_sta_flags_to_drv(flags);
+	params.qosinfo = qosinfo;
+	return hapd->driver->sta_add(hapd->drv_priv, &params);
+}
+
+
+int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
+		      u8 *tspec_ie, size_t tspec_ielen)
+{
+	if (hapd->driver == NULL || hapd->driver->add_tspec == NULL)
+		return 0;
+	return hapd->driver->add_tspec(hapd->drv_priv, addr, tspec_ie,
+				       tspec_ielen);
+}
+
+
+int 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->drv_priv, enabled);
+}
+
+
+int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
+			     size_t elem_len)
+{
+	if (hapd->driver == NULL || hapd->driver->set_generic_elem == NULL)
+		return 0;
+	return hapd->driver->set_generic_elem(hapd->drv_priv, elem, elem_len);
+}
+
+
+int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len)
+{
+	if (hapd->driver == NULL || hapd->driver->hapd_get_ssid == NULL)
+		return 0;
+	return hapd->driver->hapd_get_ssid(hapd->drv_priv, buf, len);
+}
+
+
+int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len)
+{
+	if (hapd->driver == NULL || hapd->driver->hapd_set_ssid == NULL)
+		return 0;
+	return hapd->driver->hapd_set_ssid(hapd->drv_priv, buf, len);
+}
+
+
+int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
+		   const char *ifname, const u8 *addr, void *bss_ctx,
+		   void **drv_priv, char *force_ifname, u8 *if_addr,
+		   const char *bridge)
+{
+	if (hapd->driver == NULL || hapd->driver->if_add == NULL)
+		return -1;
+	return hapd->driver->if_add(hapd->drv_priv, type, ifname, addr,
+				    bss_ctx, drv_priv, force_ifname, if_addr,
+				    bridge);
+}
+
+
+int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
+		      const char *ifname)
+{
+	if (hapd->driver == NULL || hapd->driver->if_remove == NULL)
+		return -1;
+	return hapd->driver->if_remove(hapd->drv_priv, type, ifname);
+}
+
+
+int hostapd_set_ieee8021x(struct hostapd_data *hapd,
+			  struct wpa_bss_params *params)
+{
+	if (hapd->driver == NULL || hapd->driver->set_ieee8021x == NULL)
+		return 0;
+	return hapd->driver->set_ieee8021x(hapd->drv_priv, params);
+}
+
+
+int 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(ifname, hapd->drv_priv, addr, idx,
+					seq);
+}
+
+
+int hostapd_flush(struct hostapd_data *hapd)
+{
+	if (hapd->driver == NULL || hapd->driver->flush == NULL)
+		return 0;
+	return hapd->driver->flush(hapd->drv_priv);
+}
+
+
+int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
+		     int channel, int ht_enabled, int sec_channel_offset)
+{
+	struct hostapd_freq_params data;
+	if (hapd->driver == NULL)
+		return 0;
+	if (hapd->driver->set_freq == NULL)
+		return 0;
+	os_memset(&data, 0, sizeof(data));
+	data.mode = mode;
+	data.freq = freq;
+	data.channel = channel;
+	data.ht_enabled = ht_enabled;
+	data.sec_channel_offset = sec_channel_offset;
+	return hapd->driver->set_freq(hapd->drv_priv, &data);
+}
+
+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->drv_priv, rts);
+}
+
+
+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->drv_priv, frag);
+}
+
+
+int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
+			  int total_flags, 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->drv_priv, addr, total_flags,
+					   flags_or, flags_and);
+}
+
+
+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->drv_priv, country);
+}
+
+
+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->drv_priv, queue, aifs,
+						 cw_min, cw_max, burst_time);
+}
+
+
+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->drv_priv, num_modes,
+						 flags);
+}
+
+
+int hostapd_driver_commit(struct hostapd_data *hapd)
+{
+	if (hapd->driver == NULL || hapd->driver->commit == NULL)
+		return 0;
+	return hapd->driver->commit(hapd->drv_priv);
+}
+
+
+int hostapd_drv_none(struct hostapd_data *hapd)
+{
+	return hapd->driver && os_strcmp(hapd->driver->name, "none") == 0;
+}
+
+
+int hostapd_driver_scan(struct hostapd_data *hapd,
+			struct wpa_driver_scan_params *params)
+{
+	if (hapd->driver && hapd->driver->scan2)
+		return hapd->driver->scan2(hapd->drv_priv, params);
+	return -1;
+}
+
+
+struct wpa_scan_results * hostapd_driver_get_scan_results(
+	struct hostapd_data *hapd)
+{
+	if (hapd->driver && hapd->driver->get_scan_results2)
+		return hapd->driver->get_scan_results2(hapd->drv_priv);
+	return NULL;
+}
+
+
+int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
+			   int duration)
+{
+	if (hapd->driver && hapd->driver->set_noa)
+		return hapd->driver->set_noa(hapd->drv_priv, count, start,
+					     duration);
+	return -1;
+}
+
+
+int hostapd_drv_set_key(const char *ifname, struct hostapd_data *hapd,
+			enum wpa_alg alg, const u8 *addr,
+			int key_idx, int set_tx,
+			const u8 *seq, size_t seq_len,
+			const u8 *key, size_t key_len)
+{
+	if (hapd->driver == NULL || hapd->driver->set_key == NULL)
+		return 0;
+	return hapd->driver->set_key(ifname, hapd->drv_priv, alg, addr,
+				     key_idx, set_tx, seq, seq_len, key,
+				     key_len);
+}
+
+
+int hostapd_drv_send_mlme(struct hostapd_data *hapd,
+			  const void *msg, size_t len, int noack)
+{
+	if (hapd->driver == NULL || hapd->driver->send_mlme == NULL)
+		return 0;
+	return hapd->driver->send_mlme(hapd->drv_priv, msg, len, noack);
+}
+
+
+int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
+			   const u8 *addr, int reason)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_deauth == NULL)
+		return 0;
+	return hapd->driver->sta_deauth(hapd->drv_priv, hapd->own_addr, addr,
+					reason);
+}
+
+
+int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
+			     const u8 *addr, int reason)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_disassoc == NULL)
+		return 0;
+	return hapd->driver->sta_disassoc(hapd->drv_priv, hapd->own_addr, addr,
+					  reason);
+}
+
+
+int hostapd_drv_wnm_oper(struct hostapd_data *hapd, enum wnm_oper oper,
+			 const u8 *peer, u8 *buf, u16 *buf_len)
+{
+	if (hapd->driver == NULL || hapd->driver->wnm_oper == NULL)
+		return 0;
+	return hapd->driver->wnm_oper(hapd->drv_priv, oper, peer, buf,
+				      buf_len);
+}
+
+
+int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
+			    unsigned int wait, const u8 *dst, const u8 *data,
+			    size_t len)
+{
+	if (hapd->driver == NULL || hapd->driver->send_action == NULL)
+		return 0;
+	return hapd->driver->send_action(hapd->drv_priv, freq, wait, dst,
+					 hapd->own_addr, hapd->own_addr, data,
+					 len, 0);
+}
+
+int hostapd_channel_switch(struct hostapd_data *hapd, int freq, int flags,
+			   u8 tx_block, u8 post_switch_block_tx)
+{
+	struct hostapd_channel_switch params;
+
+	if (!hapd->driver || !hapd->driver->hapd_channel_switch)
+		return 0;
+
+	if (flags & HOSTAPD_CHAN_RADAR) {
+		wpa_printf(MSG_ERROR, "Can't switch to radar channel, "
+			   "DFS functionality is not supported");
+		return -1;
+	}
+
+	if (hapd->iface->conf->secondary_channel) {
+		wpa_printf(MSG_ERROR, "Channel switch is not supported "
+			   "with HT40");
+		return -1;
+	}
+
+	params.freq = freq;
+	params.tx_block = tx_block;
+	params.post_switch_block_tx = post_switch_block_tx;
+	params.ch_switch_count =
+	        (hapd->iconf->channel_switch_count > hapd->conf->dtim_period) ?
+	        hapd->iconf->channel_switch_count : hapd->conf->dtim_period * 2;
+
+	return hapd->driver->hapd_channel_switch(hapd->drv_priv, &params);
+}
diff --git a/hostap/src/ap/ap_drv_ops.h b/hostap/src/ap/ap_drv_ops.h
new file mode 100644
index 0000000..389b39a
--- /dev/null
+++ b/hostap/src/ap/ap_drv_ops.h
@@ -0,0 +1,219 @@
+/*
+ * hostapd - Driver operations
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AP_DRV_OPS
+#define AP_DRV_OPS
+
+enum wpa_driver_if_type;
+struct wpa_bss_params;
+struct wpa_driver_scan_params;
+struct ieee80211_ht_capabilities;
+
+u32 hostapd_sta_flags_to_drv(u32 flags);
+int hostapd_build_ap_extra_ies(struct hostapd_data *hapd,
+			       struct wpabuf **beacon,
+			       struct wpabuf **proberesp,
+			       struct wpabuf **assocresp);
+void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
+			       struct wpabuf *proberesp,
+			       struct wpabuf *assocresp);
+int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
+int hostapd_set_authorized(struct hostapd_data *hapd,
+			   struct sta_info *sta, int authorized);
+int hostapd_set_sta_flags(struct hostapd_data *hapd, struct sta_info *sta);
+int hostapd_set_drv_ieee8021x(struct hostapd_data *hapd, const char *ifname,
+			      int enabled);
+int hostapd_vlan_if_add(struct hostapd_data *hapd, const char *ifname);
+int hostapd_vlan_if_remove(struct hostapd_data *hapd, const char *ifname);
+int hostapd_set_wds_sta(struct hostapd_data *hapd, const u8 *addr, int aid,
+			int val);
+int hostapd_sta_add(struct hostapd_data *hapd,
+		    const u8 *addr, u16 aid, u16 capability,
+		    const u8 *supp_rates, size_t supp_rates_len,
+		    u16 listen_interval,
+		    const struct ieee80211_ht_capabilities *ht_capab,
+		    u32 flags, u8 qosinfo);
+int hostapd_set_privacy(struct hostapd_data *hapd, int enabled);
+int hostapd_set_generic_elem(struct hostapd_data *hapd, const u8 *elem,
+			     size_t elem_len);
+int hostapd_get_ssid(struct hostapd_data *hapd, u8 *buf, size_t len);
+int hostapd_set_ssid(struct hostapd_data *hapd, const u8 *buf, size_t len);
+int hostapd_if_add(struct hostapd_data *hapd, enum wpa_driver_if_type type,
+		   const char *ifname, const u8 *addr, void *bss_ctx,
+		   void **drv_priv, char *force_ifname, u8 *if_addr,
+		   const char *bridge);
+int hostapd_if_remove(struct hostapd_data *hapd, enum wpa_driver_if_type type,
+		      const char *ifname);
+int hostapd_set_ieee8021x(struct hostapd_data *hapd,
+			  struct wpa_bss_params *params);
+int hostapd_get_seqnum(const char *ifname, struct hostapd_data *hapd,
+		       const u8 *addr, int idx, u8 *seq);
+int hostapd_flush(struct hostapd_data *hapd);
+int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
+		     int channel, int ht_enabled, int sec_channel_offset);
+int hostapd_set_rts(struct hostapd_data *hapd, int rts);
+int hostapd_set_frag(struct hostapd_data *hapd, int frag);
+int hostapd_sta_set_flags(struct hostapd_data *hapd, u8 *addr,
+			  int total_flags, int flags_or, int flags_and);
+int hostapd_set_country(struct hostapd_data *hapd, const char *country);
+int hostapd_set_tx_queue_params(struct hostapd_data *hapd, int queue, int aifs,
+				int cw_min, int cw_max, int burst_time);
+struct hostapd_hw_modes *
+hostapd_get_hw_feature_data(struct hostapd_data *hapd, u16 *num_modes,
+			    u16 *flags);
+int hostapd_driver_commit(struct hostapd_data *hapd);
+int hostapd_drv_none(struct hostapd_data *hapd);
+int hostapd_driver_scan(struct hostapd_data *hapd,
+			struct wpa_driver_scan_params *params);
+struct wpa_scan_results * hostapd_driver_get_scan_results(
+	struct hostapd_data *hapd);
+int hostapd_driver_set_noa(struct hostapd_data *hapd, u8 count, int start,
+			   int duration);
+int hostapd_drv_set_key(const char *ifname,
+			struct hostapd_data *hapd,
+			enum wpa_alg alg, const u8 *addr,
+			int key_idx, int set_tx,
+			const u8 *seq, size_t seq_len,
+			const u8 *key, size_t key_len);
+int hostapd_drv_send_mlme(struct hostapd_data *hapd,
+			  const void *msg, size_t len, int noack);
+int hostapd_drv_sta_deauth(struct hostapd_data *hapd,
+			   const u8 *addr, int reason);
+int hostapd_drv_sta_disassoc(struct hostapd_data *hapd,
+			     const u8 *addr, int reason);
+int hostapd_drv_send_action(struct hostapd_data *hapd, unsigned int freq,
+			    unsigned int wait, const u8 *dst, const u8 *data,
+			    size_t len);
+int hostapd_add_sta_node(struct hostapd_data *hapd, const u8 *addr,
+			 u16 auth_alg);
+int hostapd_sta_auth(struct hostapd_data *hapd, const u8 *addr,
+		     u16 seq, u16 status, const u8 *ie, size_t len);
+int hostapd_sta_assoc(struct hostapd_data *hapd, const u8 *addr,
+		      int reassoc, u16 status, const u8 *ie, size_t len);
+int hostapd_add_tspec(struct hostapd_data *hapd, const u8 *addr,
+		      u8 *tspec_ie, size_t tspec_ielen);
+int hostapd_channel_switch(struct hostapd_data *hapd, int freq, int flags,
+			   u8 tx_block, u8 post_switch_block_tx);
+ 
+
+
+#include "drivers/driver.h"
+
+int hostapd_drv_wnm_oper(struct hostapd_data *hapd,
+			 enum wnm_oper oper, const u8 *peer,
+			 u8 *buf, u16 *buf_len);
+
+static inline int hostapd_drv_set_countermeasures(struct hostapd_data *hapd,
+						  int enabled)
+{
+	if (hapd->driver == NULL ||
+	    hapd->driver->hapd_set_countermeasures == NULL)
+		return 0;
+	return hapd->driver->hapd_set_countermeasures(hapd->drv_priv, enabled);
+}
+
+static inline int hostapd_drv_set_sta_vlan(const char *ifname,
+					   struct hostapd_data *hapd,
+					   const u8 *addr, int vlan_id)
+{
+	if (hapd->driver == NULL || hapd->driver->set_sta_vlan == NULL)
+		return 0;
+	return hapd->driver->set_sta_vlan(hapd->drv_priv, addr, ifname,
+					  vlan_id);
+}
+
+static inline int hostapd_drv_get_inact_sec(struct hostapd_data *hapd,
+					    const u8 *addr)
+{
+	if (hapd->driver == NULL || hapd->driver->get_inact_sec == NULL)
+		return 0;
+	return hapd->driver->get_inact_sec(hapd->drv_priv, addr);
+}
+
+static inline int hostapd_drv_sta_remove(struct hostapd_data *hapd,
+					 const u8 *addr)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_remove == NULL)
+		return 0;
+	return hapd->driver->sta_remove(hapd->drv_priv, addr);
+}
+
+static inline int hostapd_drv_hapd_send_eapol(struct hostapd_data *hapd,
+					      const u8 *addr, const u8 *data,
+					      size_t data_len, int encrypt,
+					      u32 flags)
+{
+	if (hapd->driver == NULL || hapd->driver->hapd_send_eapol == NULL)
+		return 0;
+	return hapd->driver->hapd_send_eapol(hapd->drv_priv, addr, data,
+					     data_len, encrypt,
+					     hapd->own_addr, flags);
+}
+
+static inline int hostapd_drv_read_sta_data(
+	struct hostapd_data *hapd, struct hostap_sta_driver_data *data,
+	const u8 *addr)
+{
+	if (hapd->driver == NULL || hapd->driver->read_sta_data == NULL)
+		return -1;
+	return hapd->driver->read_sta_data(hapd->drv_priv, data, addr);
+}
+
+static inline int hostapd_drv_sta_clear_stats(struct hostapd_data *hapd,
+					      const u8 *addr)
+{
+	if (hapd->driver == NULL || hapd->driver->sta_clear_stats == NULL)
+		return 0;
+	return hapd->driver->sta_clear_stats(hapd->drv_priv, addr);
+}
+
+static inline int hostapd_drv_set_ap(struct hostapd_data *hapd,
+				     struct wpa_driver_ap_params *params)
+{
+	if (hapd->driver == NULL || hapd->driver->set_ap == NULL)
+		return 0;
+	return hapd->driver->set_ap(hapd->drv_priv, params);
+}
+
+static inline int hostapd_drv_set_radius_acl_auth(struct hostapd_data *hapd,
+						  const u8 *mac, int accepted,
+						  u32 session_timeout)
+{
+	if (hapd->driver == NULL || hapd->driver->set_radius_acl_auth == NULL)
+		return 0;
+	return hapd->driver->set_radius_acl_auth(hapd->drv_priv, mac, accepted,
+						 session_timeout);
+}
+
+static inline int hostapd_drv_set_radius_acl_expire(struct hostapd_data *hapd,
+						    const u8 *mac)
+{
+	if (hapd->driver == NULL ||
+	    hapd->driver->set_radius_acl_expire == NULL)
+		return 0;
+	return hapd->driver->set_radius_acl_expire(hapd->drv_priv, mac);
+}
+
+static inline int hostapd_drv_set_authmode(struct hostapd_data *hapd,
+					   int auth_algs)
+{
+	if (hapd->driver == NULL || hapd->driver->set_authmode == NULL)
+		return 0;
+	return hapd->driver->set_authmode(hapd->drv_priv, auth_algs);
+}
+
+static inline void hostapd_drv_poll_client(struct hostapd_data *hapd,
+					   const u8 *own_addr, const u8 *addr,
+					   int qos)
+{
+	if (hapd->driver == NULL || hapd->driver->poll_client == NULL)
+		return;
+	hapd->driver->poll_client(hapd->drv_priv, own_addr, addr, qos);
+}
+
+#endif /* AP_DRV_OPS */
diff --git a/hostap/src/ap/ap_list.c b/hostap/src/ap/ap_list.c
new file mode 100644
index 0000000..18090ca
--- /dev/null
+++ b/hostap/src/ap/ap_list.c
@@ -0,0 +1,377 @@
+/*
+ * hostapd / AP table
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2006, Devicescape Software, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "drivers/driver.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "beacon.h"
+#include "ap_list.h"
+
+
+/* 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 int ap_list_beacon_olbc(struct hostapd_iface *iface, struct ap_info *ap)
+{
+	int i;
+
+	if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G ||
+	    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, const u8 *ap)
+{
+	struct ap_info *s;
+
+	s = iface->ap_hash[STA_HASH(ap)];
+	while (s != NULL && os_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 (os_memcmp(s->addr, ap->addr, ETH_ALEN) == 0) {
+		iface->ap_hash[STA_HASH(ap->addr)] = s->hnext;
+		return;
+	}
+
+	while (s->hnext != NULL &&
+	       os_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--;
+	os_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, const u8 *addr)
+{
+	struct ap_info *ap;
+
+	ap = os_zalloc(sizeof(struct ap_info));
+	if (ap == NULL)
+		return NULL;
+
+	/* initialize AP info data */
+	os_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));
+		ap_free_ap(iface, ap->prev);
+	}
+
+	return ap;
+}
+
+
+void ap_list_process_beacon(struct hostapd_iface *iface,
+			    const struct ieee80211_mgmt *mgmt,
+			    struct ieee802_11_elems *elems,
+			    struct hostapd_frame_info *fi)
+{
+	struct ap_info *ap;
+	struct os_time now;
+	int new_ap = 0;
+	size_t len;
+	int set_beacon = 0;
+
+	if (iface->conf->ap_table_max_size < 1)
+		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;
+		os_memcpy(ap->ssid, elems->ssid, len);
+		ap->ssid[len] = '\0';
+		ap->ssid_len = len;
+	}
+
+	merge_byte_arrays(ap->supported_rates, WLAN_SUPP_RATES_MAX,
+			  elems->supp_rates, elems->supp_rates_len,
+			  elems->ext_supp_rates, elems->ext_supp_rates_len);
+
+	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;
+
+	if (elems->ht_capabilities)
+		ap->ht_support = 1;
+	else
+		ap->ht_support = 0;
+
+	ap->num_beacons++;
+	os_get_time(&now);
+	ap->last_beacon = now.sec;
+	if (fi)
+		ap->datarate = fi->datarate;
+
+	if (!new_ap && 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)) {
+		iface->olbc = 1;
+		wpa_printf(MSG_DEBUG, "OLBC AP detected: " MACSTR " - enable "
+			   "protection", MAC2STR(ap->addr));
+		set_beacon++;
+	}
+
+#ifdef CONFIG_IEEE80211N
+	if (!iface->olbc_ht && !ap->ht_support) {
+		iface->olbc_ht = 1;
+		hostapd_ht_operation_update(iface);
+		wpa_printf(MSG_DEBUG, "OLBC HT AP detected: " MACSTR
+			   " - enable protection", MAC2STR(ap->addr));
+		set_beacon++;
+	}
+#endif /* CONFIG_IEEE80211N */
+
+	if (set_beacon)
+		ieee802_11_update_beacons(iface);
+}
+
+
+static void ap_list_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_iface *iface = eloop_ctx;
+	struct os_time now;
+	struct ap_info *ap;
+	int set_beacon = 0;
+
+	eloop_register_timeout(10, 0, ap_list_timer, iface, NULL);
+
+	if (!iface->ap_list)
+		return;
+
+	os_get_time(&now);
+
+	while (iface->ap_list) {
+		ap = iface->ap_list->prev;
+		if (ap->last_beacon + iface->conf->ap_table_expiration_time >=
+		    now.sec)
+			break;
+
+		ap_free_ap(iface, ap);
+	}
+
+	if (iface->olbc || iface->olbc_ht) {
+		int olbc = 0;
+		int olbc_ht = 0;
+
+		ap = iface->ap_list;
+		while (ap && (olbc == 0 || olbc_ht == 0)) {
+			if (ap_list_beacon_olbc(iface, ap))
+				olbc = 1;
+			if (!ap->ht_support)
+				olbc_ht = 1;
+			ap = ap->next;
+		}
+		if (!olbc && iface->olbc) {
+			wpa_printf(MSG_DEBUG, "OLBC not detected anymore");
+			iface->olbc = 0;
+			set_beacon++;
+		}
+#ifdef CONFIG_IEEE80211N
+		if (!olbc_ht && iface->olbc_ht) {
+			wpa_printf(MSG_DEBUG, "OLBC HT not detected anymore");
+			iface->olbc_ht = 0;
+			hostapd_ht_operation_update(iface);
+			set_beacon++;
+		}
+#endif /* CONFIG_IEEE80211N */
+	}
+
+	if (set_beacon)
+		ieee802_11_update_beacons(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);
+}
diff --git a/hostap/src/ap/ap_list.h b/hostap/src/ap/ap_list.h
new file mode 100644
index 0000000..f0b4125
--- /dev/null
+++ b/hostap/src/ap/ap_list.h
@@ -0,0 +1,71 @@
+/*
+ * hostapd / AP table
+ * Copyright (c) 2002-2003, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2006, Devicescape Software, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README 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 channel;
+	int datarate; /* in 100 kbps */
+
+	int ht_support;
+
+	unsigned int num_beacons; /* number of beacon frames received */
+	os_time_t last_beacon;
+
+	int already_seen; /* whether API call AP-NEW has already fetched
+			   * information about this AP */
+};
+
+struct ieee802_11_elems;
+struct hostapd_frame_info;
+
+struct ap_info * ap_get_ap(struct hostapd_iface *iface, const u8 *sta);
+int ap_ap_for_each(struct hostapd_iface *iface,
+		   int (*func)(struct ap_info *s, void *data), void *data);
+void ap_list_process_beacon(struct hostapd_iface *iface,
+			    const struct ieee80211_mgmt *mgmt,
+			    struct ieee802_11_elems *elems,
+			    struct hostapd_frame_info *fi);
+#ifdef NEED_AP_MLME
+int ap_list_init(struct hostapd_iface *iface);
+void ap_list_deinit(struct hostapd_iface *iface);
+#else /* NEED_AP_MLME */
+static inline int ap_list_init(struct hostapd_iface *iface)
+{
+	return 0;
+}
+
+static inline void ap_list_deinit(struct hostapd_iface *iface)
+{
+}
+#endif /* NEED_AP_MLME */
+
+#endif /* AP_LIST_H */
diff --git a/hostap/src/ap/ap_mlme.c b/hostap/src/ap/ap_mlme.c
new file mode 100644
index 0000000..a959694
--- /dev/null
+++ b/hostap/src/ap/ap_mlme.c
@@ -0,0 +1,178 @@
+/*
+ * hostapd / IEEE 802.11 MLME
+ * Copyright 2003-2006, Jouni Malinen <j@w1.fi>
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "ieee802_11.h"
+#include "wpa_auth.h"
+#include "sta_info.h"
+#include "ap_mlme.h"
+
+
+#ifndef CONFIG_NO_HOSTAPD_LOGGER
+static const char * mlme_auth_alg_str(int alg)
+{
+	switch (alg) {
+	case WLAN_AUTH_OPEN:
+		return "OPEN_SYSTEM";
+	case WLAN_AUTH_SHARED_KEY:
+		return "SHARED_KEY";
+	case WLAN_AUTH_FT:
+		return "FT";
+	}
+
+	return "unknown";
+}
+#endif /* CONFIG_NO_HOSTAPD_LOGGER */
+
+
+/**
+ * mlme_authenticate_indication - Report the establishment of an authentication
+ * relationship with a specific peer MAC entity
+ * @hapd: BSS data
+ * @sta: peer STA data
+ *
+ * MLME calls this function as a result of the establishment of an
+ * authentication relationship with a specific peer MAC entity that
+ * resulted from an authentication procedure that was initiated by
+ * that specific peer MAC entity.
+ *
+ * PeerSTAAddress = sta->addr
+ * AuthenticationType = sta->auth_alg (WLAN_AUTH_OPEN / WLAN_AUTH_SHARED_KEY)
+ */
+void mlme_authenticate_indication(struct hostapd_data *hapd,
+				  struct sta_info *sta)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-AUTHENTICATE.indication(" MACSTR ", %s)",
+		       MAC2STR(sta->addr), mlme_auth_alg_str(sta->auth_alg));
+	if (sta->auth_alg != WLAN_AUTH_FT && !(sta->flags & WLAN_STA_MFP))
+		mlme_deletekeys_request(hapd, sta);
+}
+
+
+/**
+ * mlme_deauthenticate_indication - Report the invalidation of an
+ * authentication relationship with a specific peer MAC entity
+ * @hapd: BSS data
+ * @sta: Peer STA data
+ * @reason_code: ReasonCode from Deauthentication frame
+ *
+ * MLME calls this function as a result of the invalidation of an
+ * authentication relationship with a specific peer MAC entity.
+ *
+ * PeerSTAAddress = sta->addr
+ */
+void mlme_deauthenticate_indication(struct hostapd_data *hapd,
+				    struct sta_info *sta, u16 reason_code)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-DEAUTHENTICATE.indication(" MACSTR ", %d)",
+		       MAC2STR(sta->addr), reason_code);
+	mlme_deletekeys_request(hapd, sta);
+}
+
+
+/**
+ * mlme_associate_indication - Report the establishment of an association with
+ * a specific peer MAC entity
+ * @hapd: BSS data
+ * @sta: peer STA data
+ *
+ * MLME calls this function as a result of the establishment of an
+ * association with a specific peer MAC entity that resulted from an
+ * association procedure that was initiated by that specific peer MAC entity.
+ *
+ * PeerSTAAddress = sta->addr
+ */
+void mlme_associate_indication(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-ASSOCIATE.indication(" MACSTR ")",
+		       MAC2STR(sta->addr));
+	if (sta->auth_alg != WLAN_AUTH_FT)
+		mlme_deletekeys_request(hapd, sta);
+}
+
+
+/**
+ * mlme_reassociate_indication - Report the establishment of an reassociation
+ * with a specific peer MAC entity
+ * @hapd: BSS data
+ * @sta: peer STA data
+ *
+ * MLME calls this function as a result of the establishment of an
+ * reassociation with a specific peer MAC entity that resulted from a
+ * reassociation procedure that was initiated by that specific peer MAC entity.
+ *
+ * PeerSTAAddress = sta->addr
+ *
+ * sta->previous_ap contains the "Current AP" information from ReassocReq.
+ */
+void mlme_reassociate_indication(struct hostapd_data *hapd,
+				 struct sta_info *sta)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-REASSOCIATE.indication(" MACSTR ")",
+		       MAC2STR(sta->addr));
+	if (sta->auth_alg != WLAN_AUTH_FT)
+		mlme_deletekeys_request(hapd, sta);
+}
+
+
+/**
+ * mlme_disassociate_indication - Report disassociation with a specific peer
+ * MAC entity
+ * @hapd: BSS data
+ * @sta: Peer STA data
+ * @reason_code: ReasonCode from Disassociation frame
+ *
+ * MLME calls this function as a result of the invalidation of an association
+ * relationship with a specific peer MAC entity.
+ *
+ * PeerSTAAddress = sta->addr
+ */
+void mlme_disassociate_indication(struct hostapd_data *hapd,
+				  struct sta_info *sta, u16 reason_code)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-DISASSOCIATE.indication(" MACSTR ", %d)",
+		       MAC2STR(sta->addr), reason_code);
+	mlme_deletekeys_request(hapd, sta);
+}
+
+
+void mlme_michaelmicfailure_indication(struct hostapd_data *hapd,
+				       const u8 *addr)
+{
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-MichaelMICFailure.indication(" MACSTR ")",
+		       MAC2STR(addr));
+}
+
+
+void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_MLME,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "MLME-DELETEKEYS.request(" MACSTR ")",
+		       MAC2STR(sta->addr));
+
+	if (sta->wpa_sm)
+		wpa_remove_ptk(sta->wpa_sm);
+}
diff --git a/hostap/src/ap/ap_mlme.h b/hostap/src/ap/ap_mlme.h
new file mode 100644
index 0000000..e7fd69d
--- /dev/null
+++ b/hostap/src/ap/ap_mlme.h
@@ -0,0 +1,34 @@
+/*
+ * hostapd / IEEE 802.11 MLME
+ * Copyright 2003, Jouni Malinen <j@w1.fi>
+ * Copyright 2003-2004, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MLME_H
+#define MLME_H
+
+void mlme_authenticate_indication(struct hostapd_data *hapd,
+				  struct sta_info *sta);
+
+void mlme_deauthenticate_indication(struct hostapd_data *hapd,
+				    struct sta_info *sta, u16 reason_code);
+
+void mlme_associate_indication(struct hostapd_data *hapd,
+			       struct sta_info *sta);
+
+void mlme_reassociate_indication(struct hostapd_data *hapd,
+				 struct sta_info *sta);
+
+void mlme_disassociate_indication(struct hostapd_data *hapd,
+				  struct sta_info *sta, u16 reason_code);
+
+void mlme_michaelmicfailure_indication(struct hostapd_data *hapd,
+				       const u8 *addr);
+
+void mlme_deletekeys_request(struct hostapd_data *hapd, struct sta_info *sta);
+
+#endif /* MLME_H */
diff --git a/hostap/src/ap/authsrv.c b/hostap/src/ap/authsrv.c
new file mode 100644
index 0000000..d66d97e
--- /dev/null
+++ b/hostap/src/ap/authsrv.c
@@ -0,0 +1,211 @@
+/*
+ * Authentication server setup
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "crypto/tls.h"
+#include "eap_server/eap.h"
+#include "eap_server/eap_sim_db.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "radius/radius_server.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "sta_info.h"
+#include "authsrv.h"
+
+
+#if defined(EAP_SERVER_SIM) || defined(EAP_SERVER_AKA)
+#define EAP_SIM_DB
+#endif /* EAP_SERVER_SIM || EAP_SERVER_AKA */
+
+
+#ifdef EAP_SIM_DB
+static int hostapd_sim_db_cb_sta(struct hostapd_data *hapd,
+				 struct sta_info *sta, void *ctx)
+{
+	if (eapol_auth_eap_pending_cb(sta->eapol_sm, ctx) == 0)
+		return 1;
+	return 0;
+}
+
+
+static void hostapd_sim_db_cb(void *ctx, void *session_ctx)
+{
+	struct hostapd_data *hapd = ctx;
+	if (ap_for_each_sta(hapd, hostapd_sim_db_cb_sta, session_ctx) == 0) {
+#ifdef RADIUS_SERVER
+		radius_server_eap_pending_cb(hapd->radius_srv, session_ctx);
+#endif /* RADIUS_SERVER */
+	}
+}
+#endif /* EAP_SIM_DB */
+
+
+#ifdef RADIUS_SERVER
+
+static int hostapd_radius_get_eap_user(void *ctx, const u8 *identity,
+				       size_t identity_len, int phase2,
+				       struct eap_user *user)
+{
+	const struct hostapd_eap_user *eap_user;
+	int i;
+
+	eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
+	if (eap_user == NULL)
+		return -1;
+
+	if (user == NULL)
+		return 0;
+
+	os_memset(user, 0, sizeof(*user));
+	for (i = 0; i < EAP_MAX_METHODS; i++) {
+		user->methods[i].vendor = eap_user->methods[i].vendor;
+		user->methods[i].method = eap_user->methods[i].method;
+	}
+
+	if (eap_user->password) {
+		user->password = os_malloc(eap_user->password_len);
+		if (user->password == NULL)
+			return -1;
+		os_memcpy(user->password, eap_user->password,
+			  eap_user->password_len);
+		user->password_len = eap_user->password_len;
+		user->password_hash = eap_user->password_hash;
+	}
+	user->force_version = eap_user->force_version;
+	user->ttls_auth = eap_user->ttls_auth;
+
+	return 0;
+}
+
+
+static int hostapd_setup_radius_srv(struct hostapd_data *hapd)
+{
+	struct radius_server_conf srv;
+	struct hostapd_bss_config *conf = hapd->conf;
+	os_memset(&srv, 0, sizeof(srv));
+	srv.client_file = conf->radius_server_clients;
+	srv.auth_port = conf->radius_server_auth_port;
+	srv.conf_ctx = hapd;
+	srv.eap_sim_db_priv = hapd->eap_sim_db_priv;
+	srv.ssl_ctx = hapd->ssl_ctx;
+	srv.msg_ctx = hapd->msg_ctx;
+	srv.pac_opaque_encr_key = conf->pac_opaque_encr_key;
+	srv.eap_fast_a_id = conf->eap_fast_a_id;
+	srv.eap_fast_a_id_len = conf->eap_fast_a_id_len;
+	srv.eap_fast_a_id_info = conf->eap_fast_a_id_info;
+	srv.eap_fast_prov = conf->eap_fast_prov;
+	srv.pac_key_lifetime = conf->pac_key_lifetime;
+	srv.pac_key_refresh_time = conf->pac_key_refresh_time;
+	srv.eap_sim_aka_result_ind = conf->eap_sim_aka_result_ind;
+	srv.tnc = conf->tnc;
+	srv.wps = hapd->wps;
+	srv.ipv6 = conf->radius_server_ipv6;
+	srv.get_eap_user = hostapd_radius_get_eap_user;
+	srv.eap_req_id_text = conf->eap_req_id_text;
+	srv.eap_req_id_text_len = conf->eap_req_id_text_len;
+	srv.pwd_group = conf->pwd_group;
+#ifdef CONFIG_RADIUS_TEST
+	srv.dump_msk_file = conf->dump_msk_file;
+#endif /* CONFIG_RADIUS_TEST */
+
+	hapd->radius_srv = radius_server_init(&srv);
+	if (hapd->radius_srv == NULL) {
+		wpa_printf(MSG_ERROR, "RADIUS server initialization failed.");
+		return -1;
+	}
+
+	return 0;
+}
+
+#endif /* RADIUS_SERVER */
+
+
+int authsrv_init(struct hostapd_data *hapd)
+{
+#ifdef EAP_TLS_FUNCS
+	if (hapd->conf->eap_server &&
+	    (hapd->conf->ca_cert || hapd->conf->server_cert ||
+	     hapd->conf->dh_file)) {
+		struct tls_connection_params params;
+
+		hapd->ssl_ctx = tls_init(NULL);
+		if (hapd->ssl_ctx == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to initialize TLS");
+			authsrv_deinit(hapd);
+			return -1;
+		}
+
+		os_memset(&params, 0, sizeof(params));
+		params.ca_cert = hapd->conf->ca_cert;
+		params.client_cert = hapd->conf->server_cert;
+		params.private_key = hapd->conf->private_key;
+		params.private_key_passwd = hapd->conf->private_key_passwd;
+		params.dh_file = hapd->conf->dh_file;
+
+		if (tls_global_set_params(hapd->ssl_ctx, &params)) {
+			wpa_printf(MSG_ERROR, "Failed to set TLS parameters");
+			authsrv_deinit(hapd);
+			return -1;
+		}
+
+		if (tls_global_set_verify(hapd->ssl_ctx,
+					  hapd->conf->check_crl)) {
+			wpa_printf(MSG_ERROR, "Failed to enable check_crl");
+			authsrv_deinit(hapd);
+			return -1;
+		}
+	}
+#endif /* EAP_TLS_FUNCS */
+
+#ifdef EAP_SIM_DB
+	if (hapd->conf->eap_sim_db) {
+		hapd->eap_sim_db_priv =
+			eap_sim_db_init(hapd->conf->eap_sim_db,
+					hostapd_sim_db_cb, hapd);
+		if (hapd->eap_sim_db_priv == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to initialize EAP-SIM "
+				   "database interface");
+			authsrv_deinit(hapd);
+			return -1;
+		}
+	}
+#endif /* EAP_SIM_DB */
+
+#ifdef RADIUS_SERVER
+	if (hapd->conf->radius_server_clients &&
+	    hostapd_setup_radius_srv(hapd))
+		return -1;
+#endif /* RADIUS_SERVER */
+
+	return 0;
+}
+
+
+void authsrv_deinit(struct hostapd_data *hapd)
+{
+#ifdef RADIUS_SERVER
+	radius_server_deinit(hapd->radius_srv);
+	hapd->radius_srv = NULL;
+#endif /* RADIUS_SERVER */
+
+#ifdef EAP_TLS_FUNCS
+	if (hapd->ssl_ctx) {
+		tls_deinit(hapd->ssl_ctx);
+		hapd->ssl_ctx = NULL;
+	}
+#endif /* EAP_TLS_FUNCS */
+
+#ifdef EAP_SIM_DB
+	if (hapd->eap_sim_db_priv) {
+		eap_sim_db_deinit(hapd->eap_sim_db_priv);
+		hapd->eap_sim_db_priv = NULL;
+	}
+#endif /* EAP_SIM_DB */
+}
diff --git a/hostap/src/ap/authsrv.h b/hostap/src/ap/authsrv.h
new file mode 100644
index 0000000..2f4ed34
--- /dev/null
+++ b/hostap/src/ap/authsrv.h
@@ -0,0 +1,15 @@
+/*
+ * Authentication server setup
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AUTHSRV_H
+#define AUTHSRV_H
+
+int authsrv_init(struct hostapd_data *hapd);
+void authsrv_deinit(struct hostapd_data *hapd);
+
+#endif /* AUTHSRV_H */
diff --git a/hostap/src/ap/beacon.c b/hostap/src/ap/beacon.c
new file mode 100644
index 0000000..3f39b38
--- /dev/null
+++ b/hostap/src/ap/beacon.c
@@ -0,0 +1,819 @@
+/*
+ * hostapd / IEEE 802.11 Management: Beacon and Probe Request/Response
+ * Copyright (c) 2002-2004, Instant802 Networks, Inc.
+ * Copyright (c) 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "drivers/driver.h"
+#include "wps/wps_defs.h"
+#include "p2p/p2p.h"
+#include "hostapd.h"
+#include "ieee802_11.h"
+#include "wpa_auth.h"
+#include "wmm.h"
+#include "ap_config.h"
+#include "sta_info.h"
+#include "p2p_hostapd.h"
+#include "ap_drv_ops.h"
+#include "beacon.h"
+#include "hw_features.h"
+#include "hs20.h"
+
+
+#ifdef NEED_AP_MLME
+
+static u8 ieee802_11_erp_info(struct hostapd_data *hapd)
+{
+	u8 erp = 0;
+
+	if (hapd->iface->current_mode == NULL ||
+	    hapd->iface->current_mode->mode != HOSTAPD_MODE_IEEE80211G)
+		return 0;
+
+	if (hapd->iface->olbc)
+		erp |= ERP_INFO_USE_PROTECTION;
+	if (hapd->iface->num_sta_non_erp > 0) {
+		erp |= ERP_INFO_NON_ERP_PRESENT |
+			ERP_INFO_USE_PROTECTION;
+	}
+	if (hapd->iface->num_sta_no_short_preamble > 0 ||
+	    hapd->iconf->preamble == LONG_PREAMBLE)
+		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->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_add(u8 *pos, u8 *end, int chan_spacing,
+				    struct hostapd_channel_data *start,
+				    struct hostapd_channel_data *prev)
+{
+	if (end - pos < 3)
+		return pos;
+
+	/* first channel number */
+	*pos++ = start->chan;
+	/* number of channels */
+	*pos++ = (prev->chan - start->chan) / chan_spacing + 1;
+	/* maximum transmit power level */
+	*pos++ = start->max_tx_power;
+
+	return pos;
+}
+
+
+static u8 * hostapd_eid_country(struct hostapd_data *hapd, u8 *eid,
+				int max_len)
+{
+	u8 *pos = eid;
+	u8 *end = eid + max_len;
+	int i;
+	struct hostapd_hw_modes *mode;
+	struct hostapd_channel_data *start, *prev;
+	int chan_spacing = 1;
+
+	if (!hapd->iconf->ieee80211d || max_len < 6 ||
+	    hapd->iface->current_mode == NULL)
+		return eid;
+
+	*pos++ = WLAN_EID_COUNTRY;
+	pos++; /* length will be set later */
+	os_memcpy(pos, hapd->iconf->country, 3); /* e.g., 'US ' */
+	pos += 3;
+
+	mode = hapd->iface->current_mode;
+	if (mode->mode == HOSTAPD_MODE_IEEE80211A)
+		chan_spacing = 4;
+
+	start = prev = NULL;
+	for (i = 0; i < mode->num_channels; i++) {
+		struct hostapd_channel_data *chan = &mode->channels[i];
+		if (chan->flag & HOSTAPD_CHAN_DISABLED)
+			continue;
+		if (start && prev &&
+		    prev->chan + chan_spacing == chan->chan &&
+		    start->max_tx_power == chan->max_tx_power) {
+			prev = chan;
+			continue; /* can use same entry */
+		}
+
+		if (start) {
+			pos = hostapd_eid_country_add(pos, end, chan_spacing,
+						      start, prev);
+			start = NULL;
+		}
+
+		/* Start new group */
+		start = prev = chan;
+	}
+
+	if (start) {
+		pos = hostapd_eid_country_add(pos, end, chan_spacing,
+					      start, prev);
+	}
+
+	if ((pos - eid) & 1) {
+		if (end - pos < 1)
+			return eid;
+		*pos++ = 0; /* pad for 16-bit alignment */
+	}
+
+	eid[1] = (pos - eid) - 2;
+
+	return pos;
+}
+
+static u8 *hostapd_eid_csa(struct hostapd_data *hapd, u8 *eid)
+{
+	int current_ch_flag = 0;
+
+	if (!hapd->next_channel)
+		return eid;
+
+	current_ch_flag = hostapd_hw_get_channel_flag(hapd,
+						      hapd->iconf->channel);
+
+	*eid++ = WLAN_EID_CHANNEL_SWITCH;
+	*eid++ = 3; /* IE length */
+	/* STAs should cease transmit if the switch is due to radar */
+	*eid++ = (current_ch_flag & HOSTAPD_CHAN_RADAR) ? 1 : 0;
+	*eid++ = (u8)hapd->next_channel->chan;
+	*eid++ = (hapd->iconf->channel_switch_count > hapd->conf->dtim_period) ?
+		(u8)hapd->iconf->channel_switch_count :
+		hapd->conf->dtim_period * 2;
+	return eid;
+}
+
+static u8 * hostapd_eid_wpa(struct hostapd_data *hapd, u8 *eid, size_t len)
+{
+	const u8 *ie;
+	size_t ielen;
+
+	ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &ielen);
+	if (ie == NULL || ielen > len)
+		return eid;
+
+	os_memcpy(eid, ie, ielen);
+	return eid + ielen;
+}
+
+
+static u8 * hostapd_gen_probe_resp(struct hostapd_data *hapd,
+				   struct sta_info *sta,
+				   const struct ieee80211_mgmt *req,
+				   int is_p2p, size_t *resp_len)
+{
+	struct ieee80211_mgmt *resp;
+	u8 *pos, *epos;
+	size_t buflen;
+
+#define MAX_PROBERESP_LEN 768
+	buflen = MAX_PROBERESP_LEN;
+#ifdef CONFIG_WPS
+	if (hapd->wps_probe_resp_ie)
+		buflen += wpabuf_len(hapd->wps_probe_resp_ie);
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+	if (hapd->p2p_probe_resp_ie)
+		buflen += wpabuf_len(hapd->p2p_probe_resp_ie);
+#endif /* CONFIG_P2P */
+	if (hapd->conf->vendor_elements)
+		buflen += wpabuf_len(hapd->conf->vendor_elements);
+	resp = os_zalloc(buflen);
+	if (resp == NULL)
+		return NULL;
+
+	epos = ((u8 *) resp) + MAX_PROBERESP_LEN;
+
+	resp->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_PROBE_RESP);
+	if (req)
+		os_memcpy(resp->da, req->sa, ETH_ALEN);
+	os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+
+	os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
+	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++ = hapd->conf->ssid.ssid_len;
+	os_memcpy(pos, hapd->conf->ssid.ssid, hapd->conf->ssid.ssid_len);
+	pos += hapd->conf->ssid.ssid_len;
+
+	/* Supported rates */
+	pos = hostapd_eid_supp_rates(hapd, pos);
+
+	/* DS Params */
+	pos = hostapd_eid_ds_params(hapd, pos);
+
+	pos = hostapd_eid_country(hapd, pos, epos - pos);
+
+	/* ERP Information element */
+	pos = hostapd_eid_erp_info(hapd, pos);
+
+	/* Extended supported rates */
+	pos = hostapd_eid_ext_supp_rates(hapd, pos);
+
+	/* RSN, MDIE, WPA */
+	pos = hostapd_eid_wpa(hapd, pos, epos - pos);
+
+#ifdef CONFIG_IEEE80211N
+	pos = hostapd_eid_ht_capabilities(hapd, pos);
+	pos = hostapd_eid_ht_operation(hapd, pos);
+#endif /* CONFIG_IEEE80211N */
+
+	pos = hostapd_eid_ext_capab(hapd, pos);
+
+	pos = hostapd_eid_time_adv(hapd, pos);
+	pos = hostapd_eid_time_zone(hapd, pos);
+
+	pos = hostapd_eid_interworking(hapd, pos);
+	pos = hostapd_eid_adv_proto(hapd, pos);
+	pos = hostapd_eid_roaming_consortium(hapd, pos);
+
+#ifdef CONFIG_IEEE80211AC
+	pos = hostapd_eid_vht_capabilities(hapd, pos);
+	pos = hostapd_eid_vht_operation(hapd, pos);
+#endif /* CONFIG_IEEE80211AC */
+
+	/* Wi-Fi Alliance WMM */
+	pos = hostapd_eid_wmm(hapd, pos);
+
+#ifdef CONFIG_WPS
+	if (hapd->conf->wps_state && hapd->wps_probe_resp_ie) {
+		os_memcpy(pos, wpabuf_head(hapd->wps_probe_resp_ie),
+			  wpabuf_len(hapd->wps_probe_resp_ie));
+		pos += wpabuf_len(hapd->wps_probe_resp_ie);
+	}
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+	if ((hapd->conf->p2p & P2P_ENABLED) && is_p2p &&
+	    hapd->p2p_probe_resp_ie) {
+		os_memcpy(pos, wpabuf_head(hapd->p2p_probe_resp_ie),
+			  wpabuf_len(hapd->p2p_probe_resp_ie));
+		pos += wpabuf_len(hapd->p2p_probe_resp_ie);
+	}
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_P2P_MANAGER
+	if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
+	    P2P_MANAGE)
+		pos = hostapd_eid_p2p_manage(hapd, pos);
+#endif /* CONFIG_P2P_MANAGER */
+
+#ifdef CONFIG_HS20
+	pos = hostapd_eid_hs20_indication(hapd, pos);
+#endif /* CONFIG_HS20 */
+
+	if (hapd->conf->vendor_elements) {
+		os_memcpy(pos, wpabuf_head(hapd->conf->vendor_elements),
+			  wpabuf_len(hapd->conf->vendor_elements));
+		pos += wpabuf_len(hapd->conf->vendor_elements);
+	}
+
+	*resp_len = pos - (u8 *) resp;
+	return (u8 *) resp;
+}
+
+
+enum ssid_match_result {
+	NO_SSID_MATCH,
+	EXACT_SSID_MATCH,
+	WILDCARD_SSID_MATCH
+};
+
+static enum ssid_match_result ssid_match(struct hostapd_data *hapd,
+					 const u8 *ssid, size_t ssid_len,
+					 const u8 *ssid_list,
+					 size_t ssid_list_len)
+{
+	const u8 *pos, *end;
+	int wildcard = 0;
+
+	if (ssid_len == 0)
+		wildcard = 1;
+	if (ssid_len == hapd->conf->ssid.ssid_len &&
+	    os_memcmp(ssid, hapd->conf->ssid.ssid, ssid_len) == 0)
+		return EXACT_SSID_MATCH;
+
+	if (ssid_list == NULL)
+		return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
+
+	pos = ssid_list;
+	end = ssid_list + ssid_list_len;
+	while (pos + 1 <= end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[1] == 0)
+			wildcard = 1;
+		if (pos[1] == hapd->conf->ssid.ssid_len &&
+		    os_memcmp(pos + 2, hapd->conf->ssid.ssid, pos[1]) == 0)
+			return EXACT_SSID_MATCH;
+		pos += 2 + pos[1];
+	}
+
+	return wildcard ? WILDCARD_SSID_MATCH : NO_SSID_MATCH;
+}
+
+
+void handle_probe_req(struct hostapd_data *hapd,
+		      const struct ieee80211_mgmt *mgmt, size_t len,
+		      int ssi_signal)
+{
+	u8 *resp;
+	struct ieee802_11_elems elems;
+	const u8 *ie;
+	size_t ie_len;
+	struct sta_info *sta = NULL;
+	size_t i, resp_len;
+	int noack;
+	enum ssid_match_result res;
+
+	ie = mgmt->u.probe_req.variable;
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req))
+		return;
+	ie_len = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.probe_req));
+
+	for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++)
+		if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
+					    mgmt->sa, mgmt->da, mgmt->bssid,
+					    ie, ie_len, ssi_signal) > 0)
+			return;
+
+	if (!hapd->iconf->send_probe_response)
+		return;
+
+	if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
+		wpa_printf(MSG_DEBUG, "Could not parse ProbeReq from " MACSTR,
+			   MAC2STR(mgmt->sa));
+		return;
+	}
+
+	if ((!elems.ssid || !elems.supp_rates)) {
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " sent probe request "
+			   "without SSID or supported rates element",
+			   MAC2STR(mgmt->sa));
+		return;
+	}
+
+#ifdef CONFIG_P2P
+	if (hapd->p2p && elems.wps_ie) {
+		struct wpabuf *wps;
+		wps = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
+		if (wps && !p2p_group_match_dev_type(hapd->p2p_group, wps)) {
+			wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request "
+				   "due to mismatch with Requested Device "
+				   "Type");
+			wpabuf_free(wps);
+			return;
+		}
+		wpabuf_free(wps);
+	}
+
+	if (hapd->p2p && elems.p2p) {
+		struct wpabuf *p2p;
+		p2p = ieee802_11_vendor_ie_concat(ie, ie_len, P2P_IE_VENDOR_TYPE);
+		if (p2p && !p2p_group_match_dev_id(hapd->p2p_group, p2p)) {
+			wpa_printf(MSG_MSGDUMP, "P2P: Ignore Probe Request "
+				   "due to mismatch with Device ID");
+			wpabuf_free(p2p);
+			return;
+		}
+		wpabuf_free(p2p);
+	}
+#endif /* CONFIG_P2P */
+
+	if (hapd->conf->ignore_broadcast_ssid && elems.ssid_len == 0 &&
+	    elems.ssid_list_len == 0) {
+		wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR " for "
+			   "broadcast SSID ignored", MAC2STR(mgmt->sa));
+		return;
+	}
+
+	sta = ap_get_sta(hapd, mgmt->sa);
+
+#ifdef CONFIG_P2P
+	if ((hapd->conf->p2p & P2P_GROUP_OWNER) &&
+	    elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
+	    os_memcmp(elems.ssid, P2P_WILDCARD_SSID,
+		      P2P_WILDCARD_SSID_LEN) == 0) {
+		/* Process P2P Wildcard SSID like Wildcard SSID */
+		elems.ssid_len = 0;
+	}
+#endif /* CONFIG_P2P */
+
+	res = ssid_match(hapd, elems.ssid, elems.ssid_len,
+			 elems.ssid_list, elems.ssid_list_len);
+	if (res != NO_SSID_MATCH) {
+		if (sta)
+			sta->ssid_probe = &hapd->conf->ssid;
+	} else {
+		if (!(mgmt->da[0] & 0x01)) {
+			char ssid_txt[33];
+			ieee802_11_print_ssid(ssid_txt, elems.ssid,
+					      elems.ssid_len);
+			wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
+				   " for foreign SSID '%s' (DA " MACSTR ")%s",
+				   MAC2STR(mgmt->sa), ssid_txt,
+				   MAC2STR(mgmt->da),
+				   elems.ssid_list ? " (SSID list)" : "");
+		}
+		return;
+	}
+
+#ifdef CONFIG_INTERWORKING
+	if (elems.interworking && elems.interworking_len >= 1) {
+		u8 ant = elems.interworking[0] & 0x0f;
+		if (ant != INTERWORKING_ANT_WILDCARD &&
+		    ant != hapd->conf->access_network_type) {
+			wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
+				   " for mismatching ANT %u ignored",
+				   MAC2STR(mgmt->sa), ant);
+			return;
+		}
+	}
+
+	if (elems.interworking &&
+	    (elems.interworking_len == 7 || elems.interworking_len == 9)) {
+		const u8 *hessid;
+		if (elems.interworking_len == 7)
+			hessid = elems.interworking + 1;
+		else
+			hessid = elems.interworking + 1 + 2;
+		if (!is_broadcast_ether_addr(hessid) &&
+		    os_memcmp(hessid, hapd->conf->hessid, ETH_ALEN) != 0) {
+			wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
+				   " for mismatching HESSID " MACSTR
+				   " ignored",
+				   MAC2STR(mgmt->sa), MAC2STR(hessid));
+			return;
+		}
+	}
+#endif /* CONFIG_INTERWORKING */
+
+	/* TODO: verify that supp_rates contains at least one matching rate
+	 * with AP configuration */
+
+	resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL,
+				      &resp_len);
+	if (resp == NULL)
+		return;
+
+	/*
+	 * If this is a broadcast probe request, apply no ack policy to avoid
+	 * excessive retries.
+	 */
+	noack = !!(res == WILDCARD_SSID_MATCH &&
+		   is_broadcast_ether_addr(mgmt->da));
+
+	if (hostapd_drv_send_mlme(hapd, resp, resp_len, noack) < 0)
+		perror("handle_probe_req: send");
+
+	os_free(resp);
+
+	wpa_printf(MSG_EXCESSIVE, "STA " MACSTR " sent probe request for %s "
+		   "SSID", MAC2STR(mgmt->sa),
+		   elems.ssid_len == 0 ? "broadcast" : "our");
+}
+
+
+static u8 * hostapd_probe_resp_offloads(struct hostapd_data *hapd,
+					size_t *resp_len)
+{
+	/* check probe response offloading caps and print warnings */
+	if (!(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD))
+		return NULL;
+
+#ifdef CONFIG_WPS
+	if (hapd->conf->wps_state && hapd->wps_probe_resp_ie &&
+	    (!(hapd->iface->probe_resp_offloads &
+	       (WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS |
+		WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2))))
+		wpa_printf(MSG_WARNING, "Device is trying to offload WPS "
+			   "Probe Response while not supporting this");
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+	if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_probe_resp_ie &&
+	    !(hapd->iface->probe_resp_offloads &
+	      WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P))
+		wpa_printf(MSG_WARNING, "Device is trying to offload P2P "
+			   "Probe Response while not supporting this");
+#endif  /* CONFIG_P2P */
+
+	if (hapd->conf->interworking &&
+	    !(hapd->iface->probe_resp_offloads &
+	      WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING))
+		wpa_printf(MSG_WARNING, "Device is trying to offload "
+			   "Interworking Probe Response while not supporting "
+			   "this");
+
+	/* Generate a Probe Response template for the non-P2P case */
+	return hostapd_gen_probe_resp(hapd, NULL, NULL, 0, resp_len);
+}
+
+#endif /* NEED_AP_MLME */
+
+
+void ieee802_11_set_beacon(struct hostapd_data *hapd)
+{
+	struct ieee80211_mgmt *head = NULL;
+	u8 *tail = NULL;
+	size_t head_len = 0, tail_len = 0;
+	u8 *resp = NULL;
+	size_t resp_len = 0;
+	struct wpa_driver_ap_params params;
+	struct wpabuf *beacon, *proberesp, *assocresp;
+#ifdef NEED_AP_MLME
+	u16 capab_info;
+	u8 *pos, *tailpos;
+#endif /* NEED_AP_MLME */
+
+	hapd->beacon_set_done = 1;
+
+#ifdef NEED_AP_MLME
+
+#define BEACON_HEAD_BUF_SIZE 256
+#define BEACON_TAIL_BUF_SIZE 512
+	head = os_zalloc(BEACON_HEAD_BUF_SIZE);
+	tail_len = BEACON_TAIL_BUF_SIZE;
+#ifdef CONFIG_WPS
+	if (hapd->conf->wps_state && hapd->wps_beacon_ie)
+		tail_len += wpabuf_len(hapd->wps_beacon_ie);
+#endif /* CONFIG_WPS */
+#ifdef CONFIG_P2P
+	if (hapd->p2p_beacon_ie)
+		tail_len += wpabuf_len(hapd->p2p_beacon_ie);
+#endif /* CONFIG_P2P */
+	if (hapd->conf->vendor_elements)
+		tail_len += wpabuf_len(hapd->conf->vendor_elements);
+	tailpos = tail = os_malloc(tail_len);
+	if (head == NULL || tail == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to set beacon data");
+		os_free(head);
+		os_free(tail);
+		return;
+	}
+
+	head->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_BEACON);
+	head->duration = host_to_le16(0);
+	os_memset(head->da, 0xff, ETH_ALEN);
+
+	os_memcpy(head->sa, hapd->own_addr, ETH_ALEN);
+	os_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;
+		os_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;
+		os_memcpy(pos, hapd->conf->ssid.ssid,
+			  hapd->conf->ssid.ssid_len);
+		pos += hapd->conf->ssid.ssid_len;
+	}
+
+	/* Supported rates */
+	pos = hostapd_eid_supp_rates(hapd, pos);
+
+	/* 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);
+
+    /* Channel Switch Announcement */
+    tailpos = hostapd_eid_csa(hapd, tailpos);
+    
+	/* ERP Information element */
+	tailpos = hostapd_eid_erp_info(hapd, tailpos);
+
+	/* Extended supported rates */
+	tailpos = hostapd_eid_ext_supp_rates(hapd, tailpos);
+
+	/* RSN, MDIE, WPA */
+	tailpos = hostapd_eid_wpa(hapd, tailpos, tail + BEACON_TAIL_BUF_SIZE -
+				  tailpos);
+
+#ifdef CONFIG_IEEE80211N
+	tailpos = hostapd_eid_ht_capabilities(hapd, tailpos);
+	tailpos = hostapd_eid_ht_operation(hapd, tailpos);
+#endif /* CONFIG_IEEE80211N */
+
+	tailpos = hostapd_eid_ext_capab(hapd, tailpos);
+
+	/*
+	 * TODO: Time Advertisement element should only be included in some
+	 * DTIM Beacon frames.
+	 */
+	tailpos = hostapd_eid_time_adv(hapd, tailpos);
+
+	tailpos = hostapd_eid_interworking(hapd, tailpos);
+	tailpos = hostapd_eid_adv_proto(hapd, tailpos);
+	tailpos = hostapd_eid_roaming_consortium(hapd, tailpos);
+
+#ifdef CONFIG_IEEE80211AC
+	tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+	tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+#endif /* CONFIG_IEEE80211AC */
+
+	/* Wi-Fi Alliance WMM */
+	tailpos = hostapd_eid_wmm(hapd, tailpos);
+
+#ifdef CONFIG_WPS
+	if (hapd->conf->wps_state && hapd->wps_beacon_ie) {
+		os_memcpy(tailpos, wpabuf_head(hapd->wps_beacon_ie),
+			  wpabuf_len(hapd->wps_beacon_ie));
+		tailpos += wpabuf_len(hapd->wps_beacon_ie);
+	}
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+	if ((hapd->conf->p2p & P2P_ENABLED) && hapd->p2p_beacon_ie) {
+		os_memcpy(tailpos, wpabuf_head(hapd->p2p_beacon_ie),
+			  wpabuf_len(hapd->p2p_beacon_ie));
+		tailpos += wpabuf_len(hapd->p2p_beacon_ie);
+	}
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_P2P_MANAGER
+	if ((hapd->conf->p2p & (P2P_MANAGE | P2P_ENABLED | P2P_GROUP_OWNER)) ==
+	    P2P_MANAGE)
+		tailpos = hostapd_eid_p2p_manage(hapd, tailpos);
+#endif /* CONFIG_P2P_MANAGER */
+
+#ifdef CONFIG_HS20
+	tailpos = hostapd_eid_hs20_indication(hapd, tailpos);
+#endif /* CONFIG_HS20 */
+
+	if (hapd->conf->vendor_elements) {
+		os_memcpy(tailpos, wpabuf_head(hapd->conf->vendor_elements),
+			  wpabuf_len(hapd->conf->vendor_elements));
+		tailpos += wpabuf_len(hapd->conf->vendor_elements);
+	}
+
+	tail_len = tailpos > tail ? tailpos - tail : 0;
+
+	resp = hostapd_probe_resp_offloads(hapd, &resp_len);
+#endif /* NEED_AP_MLME */
+
+	os_memset(&params, 0, sizeof(params));
+	params.head = (u8 *) head;
+	params.head_len = head_len;
+	params.tail = tail;
+	params.tail_len = tail_len;
+	params.proberesp = resp;
+	params.proberesp_len = resp_len;
+	params.dtim_period = hapd->conf->dtim_period;
+	params.beacon_int = hapd->iconf->beacon_int;
+	params.basic_rates = hapd->iface->basic_rates;
+	params.ssid = hapd->conf->ssid.ssid;
+	params.ssid_len = hapd->conf->ssid.ssid_len;
+	params.pairwise_ciphers = hapd->conf->rsn_pairwise ?
+		hapd->conf->rsn_pairwise : hapd->conf->wpa_pairwise;
+	params.group_cipher = hapd->conf->wpa_group;
+	params.key_mgmt_suites = hapd->conf->wpa_key_mgmt;
+	params.auth_algs = hapd->conf->auth_algs;
+	params.wpa_version = hapd->conf->wpa;
+	params.privacy = hapd->conf->ssid.wep.keys_set || hapd->conf->wpa ||
+		(hapd->conf->ieee802_1x &&
+		 (hapd->conf->default_wep_key_len ||
+		  hapd->conf->individual_wep_key_len));
+	switch (hapd->conf->ignore_broadcast_ssid) {
+	case 0:
+		params.hide_ssid = NO_SSID_HIDING;
+		break;
+	case 1:
+		params.hide_ssid = HIDDEN_SSID_ZERO_LEN;
+		break;
+	case 2:
+		params.hide_ssid = HIDDEN_SSID_ZERO_CONTENTS;
+		break;
+	}
+	hostapd_build_ap_extra_ies(hapd, &beacon, &proberesp, &assocresp);
+	params.beacon_ies = beacon;
+	params.proberesp_ies = proberesp;
+	params.assocresp_ies = assocresp;
+	params.isolate = hapd->conf->isolate;
+#ifdef NEED_AP_MLME
+	params.cts_protect = !!(ieee802_11_erp_info(hapd) &
+				ERP_INFO_USE_PROTECTION);
+	params.preamble = hapd->iface->num_sta_no_short_preamble == 0 &&
+		hapd->iconf->preamble == SHORT_PREAMBLE;
+	if (hapd->iface->current_mode &&
+	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+		params.short_slot_time =
+			hapd->iface->num_sta_no_short_slot_time > 0 ? 0 : 1;
+	else
+		params.short_slot_time = -1;
+	if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
+		params.ht_opmode = -1;
+	else
+		params.ht_opmode = hapd->iface->ht_op_mode;
+#endif /* NEED_AP_MLME */
+	params.interworking = hapd->conf->interworking;
+	if (hapd->conf->interworking &&
+	    !is_zero_ether_addr(hapd->conf->hessid))
+		params.hessid = hapd->conf->hessid;
+	params.access_network_type = hapd->conf->access_network_type;
+	params.ap_max_inactivity = hapd->conf->ap_max_inactivity;
+#ifdef CONFIG_HS20
+	params.disable_dgaf = hapd->conf->disable_dgaf;
+#endif /* CONFIG_HS20 */
+	if (hostapd_drv_set_ap(hapd, &params))
+		wpa_printf(MSG_ERROR, "Failed to set beacon parameters");
+	hostapd_free_ap_extra_ies(hapd, beacon, proberesp, assocresp);
+
+	os_free(tail);
+	os_free(head);
+	os_free(resp);
+}
+
+
+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]);
+}
+
+
+/* only update beacons if started */
+void ieee802_11_update_beacons(struct hostapd_iface *iface)
+{
+	size_t i;
+	for (i = 0; i < iface->num_bss; i++)
+		if (iface->bss[i]->beacon_set_done)
+			ieee802_11_set_beacon(iface->bss[i]);
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/hostap/src/ap/beacon.h b/hostap/src/ap/beacon.h
new file mode 100644
index 0000000..37f10d2
--- /dev/null
+++ b/hostap/src/ap/beacon.h
@@ -0,0 +1,28 @@
+/*
+ * 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
+
+struct ieee80211_mgmt;
+
+void handle_probe_req(struct hostapd_data *hapd,
+		      const struct ieee80211_mgmt *mgmt, size_t len,
+		      int ssi_signal);
+void ieee802_11_set_beacon(struct hostapd_data *hapd);
+void ieee802_11_set_beacons(struct hostapd_iface *iface);
+void ieee802_11_update_beacons(struct hostapd_iface *iface);
+
+#endif /* BEACON_H */
diff --git a/hostap/src/ap/ctrl_iface_ap.c b/hostap/src/ap/ctrl_iface_ap.c
new file mode 100644
index 0000000..c55d3fe
--- /dev/null
+++ b/hostap/src/ap/ctrl_iface_ap.c
@@ -0,0 +1,297 @@
+/*
+ * Control interface for shared AP commands
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "ieee802_1x.h"
+#include "wpa_auth.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "wps_hostapd.h"
+#include "p2p_hostapd.h"
+#include "ctrl_iface_ap.h"
+#include "ap_drv_ops.h"
+
+
+static int hostapd_get_sta_conn_time(struct sta_info *sta,
+				     char *buf, size_t buflen)
+{
+	struct os_time now, age;
+	int len = 0, ret;
+
+	if (!sta->connected_time.sec)
+		return 0;
+
+	os_get_time(&now);
+	os_time_sub(&now, &sta->connected_time, &age);
+
+	ret = os_snprintf(buf + len, buflen - len, "connected_time=%u\n",
+			  (unsigned int) age.sec);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	return len;
+}
+
+
+static int hostapd_ctrl_iface_sta_mib(struct hostapd_data *hapd,
+				      struct sta_info *sta,
+				      char *buf, size_t buflen)
+{
+	int len, res, ret;
+
+	if (sta == NULL) {
+		ret = os_snprintf(buf, buflen, "FAIL\n");
+		if (ret < 0 || (size_t) ret >= buflen)
+			return 0;
+		return ret;
+	}
+
+	len = 0;
+	ret = os_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(sta->wpa_sm, buf + len, buflen - len);
+	if (res >= 0)
+		len += res;
+	res = ieee802_1x_get_mib_sta(hapd, sta, buf + len, buflen - len);
+	if (res >= 0)
+		len += res;
+	res = hostapd_wps_get_mib_sta(hapd, sta->addr, buf + len,
+				      buflen - len);
+	if (res >= 0)
+		len += res;
+	res = hostapd_p2p_get_mib_sta(hapd, sta, buf + len, buflen - len);
+	if (res >= 0)
+		len += res;
+
+	res = hostapd_get_sta_conn_time(sta, buf + len, buflen - len);
+	if (res >= 0)
+		len += res;
+
+	return len;
+}
+
+
+int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
+				 char *buf, size_t buflen)
+{
+	return hostapd_ctrl_iface_sta_mib(hapd, hapd->sta_list, buf, buflen);
+}
+
+
+int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
+			   char *buf, size_t buflen)
+{
+	u8 addr[ETH_ALEN];
+	int ret;
+
+	if (hwaddr_aton(txtaddr, addr)) {
+		ret = os_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);
+}
+
+
+int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
+				char *buf, size_t buflen)
+{
+	u8 addr[ETH_ALEN];
+	struct sta_info *sta;
+	int ret;
+
+	if (hwaddr_aton(txtaddr, addr) ||
+	    (sta = ap_get_sta(hapd, addr)) == NULL) {
+		ret = os_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);
+}
+
+
+#ifdef CONFIG_P2P_MANAGER
+static int p2p_manager_disconnect(struct hostapd_data *hapd, u16 stype,
+				  u8 minor_reason_code, const u8 *addr)
+{
+	struct ieee80211_mgmt *mgmt;
+	int ret;
+	u8 *pos;
+
+	if (hapd->driver->send_frame == NULL)
+		return -1;
+
+	mgmt = os_zalloc(sizeof(*mgmt) + 100);
+	if (mgmt == NULL)
+		return -1;
+
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "P2P: Disconnect STA " MACSTR
+		" with minor reason code %u (stype=%u)",
+		MAC2STR(addr), minor_reason_code, stype);
+
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT, stype);
+	os_memcpy(mgmt->da, addr, ETH_ALEN);
+	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+	if (stype == WLAN_FC_STYPE_DEAUTH) {
+		mgmt->u.deauth.reason_code =
+			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+		pos = (u8 *) (&mgmt->u.deauth.reason_code + 1);
+	} else {
+		mgmt->u.disassoc.reason_code =
+			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+		pos = (u8 *) (&mgmt->u.disassoc.reason_code + 1);
+	}
+
+	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
+	*pos++ = 4 + 3 + 1;
+	WPA_PUT_BE24(pos, OUI_WFA);
+	pos += 3;
+	*pos++ = P2P_OUI_TYPE;
+
+	*pos++ = P2P_ATTR_MINOR_REASON_CODE;
+	WPA_PUT_LE16(pos, 1);
+	pos += 2;
+	*pos++ = minor_reason_code;
+
+	ret = hapd->driver->send_frame(hapd->drv_priv, (u8 *) mgmt,
+				       pos - (u8 *) mgmt, 1);
+	os_free(mgmt);
+
+	return ret < 0 ? -1 : 0;
+}
+#endif /* CONFIG_P2P_MANAGER */
+
+
+int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
+				      const char *txtaddr)
+{
+	u8 addr[ETH_ALEN];
+	struct sta_info *sta;
+	const char *pos;
+
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DEAUTHENTICATE %s",
+		txtaddr);
+
+	if (hwaddr_aton(txtaddr, addr))
+		return -1;
+
+	pos = os_strstr(txtaddr, " test=");
+	if (pos) {
+		struct ieee80211_mgmt mgmt;
+		int encrypt;
+		if (hapd->driver->send_frame == NULL)
+			return -1;
+		pos += 6;
+		encrypt = atoi(pos);
+		os_memset(&mgmt, 0, sizeof(mgmt));
+		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+						  WLAN_FC_STYPE_DEAUTH);
+		os_memcpy(mgmt.da, addr, ETH_ALEN);
+		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+		mgmt.u.deauth.reason_code =
+			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
+					     IEEE80211_HDRLEN +
+					     sizeof(mgmt.u.deauth),
+					     encrypt) < 0)
+			return -1;
+		return 0;
+	}
+
+#ifdef CONFIG_P2P_MANAGER
+	pos = os_strstr(txtaddr, " p2p=");
+	if (pos) {
+		return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DEAUTH,
+					      atoi(pos + 5), addr);
+	}
+#endif /* CONFIG_P2P_MANAGER */
+
+	hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+	sta = ap_get_sta(hapd, addr);
+	if (sta)
+		ap_sta_deauthenticate(hapd, sta,
+				      WLAN_REASON_PREV_AUTH_NOT_VALID);
+	else if (addr[0] == 0xff)
+		hostapd_free_stas(hapd);
+
+	return 0;
+}
+
+
+int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
+				    const char *txtaddr)
+{
+	u8 addr[ETH_ALEN];
+	struct sta_info *sta;
+	const char *pos;
+
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "CTRL_IFACE DISASSOCIATE %s",
+		txtaddr);
+
+	if (hwaddr_aton(txtaddr, addr))
+		return -1;
+
+	pos = os_strstr(txtaddr, " test=");
+	if (pos) {
+		struct ieee80211_mgmt mgmt;
+		int encrypt;
+		if (hapd->driver->send_frame == NULL)
+			return -1;
+		pos += 6;
+		encrypt = atoi(pos);
+		os_memset(&mgmt, 0, sizeof(mgmt));
+		mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+						  WLAN_FC_STYPE_DISASSOC);
+		os_memcpy(mgmt.da, addr, ETH_ALEN);
+		os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+		os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+		mgmt.u.disassoc.reason_code =
+			host_to_le16(WLAN_REASON_PREV_AUTH_NOT_VALID);
+		if (hapd->driver->send_frame(hapd->drv_priv, (u8 *) &mgmt,
+					     IEEE80211_HDRLEN +
+					     sizeof(mgmt.u.deauth),
+					     encrypt) < 0)
+			return -1;
+		return 0;
+	}
+
+#ifdef CONFIG_P2P_MANAGER
+	pos = os_strstr(txtaddr, " p2p=");
+	if (pos) {
+		return p2p_manager_disconnect(hapd, WLAN_FC_STYPE_DISASSOC,
+					      atoi(pos + 5), addr);
+	}
+#endif /* CONFIG_P2P_MANAGER */
+
+	hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+	sta = ap_get_sta(hapd, addr);
+	if (sta)
+		ap_sta_disassociate(hapd, sta,
+				    WLAN_REASON_PREV_AUTH_NOT_VALID);
+	else if (addr[0] == 0xff)
+		hostapd_free_stas(hapd);
+
+	return 0;
+}
diff --git a/hostap/src/ap/ctrl_iface_ap.h b/hostap/src/ap/ctrl_iface_ap.h
new file mode 100644
index 0000000..e83f894
--- /dev/null
+++ b/hostap/src/ap/ctrl_iface_ap.h
@@ -0,0 +1,23 @@
+/*
+ * Control interface for shared AP commands
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef CTRL_IFACE_AP_H
+#define CTRL_IFACE_AP_H
+
+int hostapd_ctrl_iface_sta_first(struct hostapd_data *hapd,
+				 char *buf, size_t buflen);
+int hostapd_ctrl_iface_sta(struct hostapd_data *hapd, const char *txtaddr,
+			   char *buf, size_t buflen);
+int hostapd_ctrl_iface_sta_next(struct hostapd_data *hapd, const char *txtaddr,
+				char *buf, size_t buflen);
+int hostapd_ctrl_iface_deauthenticate(struct hostapd_data *hapd,
+				      const char *txtaddr);
+int hostapd_ctrl_iface_disassociate(struct hostapd_data *hapd,
+				    const char *txtaddr);
+
+#endif /* CTRL_IFACE_AP_H */
diff --git a/hostap/src/ap/drv_callbacks.c b/hostap/src/ap/drv_callbacks.c
new file mode 100644
index 0000000..e537005
--- /dev/null
+++ b/hostap/src/ap/drv_callbacks.c
@@ -0,0 +1,866 @@
+/*
+ * hostapd / Callback functions for driver wrappers
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "radius/radius.h"
+#include "drivers/driver.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "crypto/random.h"
+#include "p2p/p2p.h"
+#include "wps/wps.h"
+#include "wnm_ap.h"
+#include "hostapd.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "accounting.h"
+#include "tkip_countermeasures.h"
+#include "ieee802_1x.h"
+#include "wpa_auth.h"
+#include "wps_hostapd.h"
+#include "ap_drv_ops.h"
+#include "ap_config.h"
+#include "hw_features.h"
+#include "beacon.h"
+
+
+int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
+			const u8 *req_ies, size_t req_ies_len, int reassoc)
+{
+	struct sta_info *sta;
+	int new_assoc, res;
+	struct ieee802_11_elems elems;
+	const u8 *ie;
+	size_t ielen;
+#ifdef CONFIG_IEEE80211R
+	u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
+	u8 *p = buf;
+#endif /* CONFIG_IEEE80211R */
+	u16 reason = WLAN_REASON_UNSPECIFIED;
+	u16 status = WLAN_STATUS_SUCCESS;
+
+	if (addr == NULL) {
+		/*
+		 * This could potentially happen with unexpected event from the
+		 * driver wrapper. This was seen at least in one case where the
+		 * driver ended up being set to station mode while hostapd was
+		 * running, so better make sure we stop processing such an
+		 * event here.
+		 */
+		wpa_printf(MSG_DEBUG, "hostapd_notif_assoc: Skip event with "
+			   "no address");
+		return -1;
+	}
+	random_add_randomness(addr, ETH_ALEN);
+
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "associated");
+
+	ieee802_11_parse_elems(req_ies, req_ies_len, &elems, 0);
+	if (elems.wps_ie) {
+		ie = elems.wps_ie - 2;
+		ielen = elems.wps_ie_len + 2;
+		wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)AssocReq");
+	} else if (elems.rsn_ie) {
+		ie = elems.rsn_ie - 2;
+		ielen = elems.rsn_ie_len + 2;
+		wpa_printf(MSG_DEBUG, "STA included RSN IE in (Re)AssocReq");
+	} else if (elems.wpa_ie) {
+		ie = elems.wpa_ie - 2;
+		ielen = elems.wpa_ie_len + 2;
+		wpa_printf(MSG_DEBUG, "STA included WPA IE in (Re)AssocReq");
+	} else {
+		ie = NULL;
+		ielen = 0;
+		wpa_printf(MSG_DEBUG, "STA did not include WPS/RSN/WPA IE in "
+			   "(Re)AssocReq");
+	}
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta) {
+		accounting_sta_stop(hapd, sta);
+
+		/*
+		 * Make sure that the previously registered inactivity timer
+		 * will not remove the STA immediately.
+		 */
+		sta->timeout_next = STA_NULLFUNC;
+	} else {
+		sta = ap_sta_add(hapd, addr);
+		if (sta == NULL) {
+			hostapd_drv_sta_disassoc(hapd, addr,
+						 WLAN_REASON_DISASSOC_AP_BUSY);
+			return -1;
+		}
+	}
+	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
+
+#ifdef CONFIG_P2P
+	if (elems.p2p) {
+		wpabuf_free(sta->p2p_ie);
+		sta->p2p_ie = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
+							  P2P_IE_VENDOR_TYPE);
+	}
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_HS20
+	wpabuf_free(sta->hs20_ie);
+	if (elems.hs20 && elems.hs20_len > 4) {
+		sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
+						 elems.hs20_len - 4);
+	} else
+		sta->hs20_ie = NULL;
+#endif /* CONFIG_HS20 */
+
+	if (hapd->conf->wpa) {
+		if (ie == NULL || ielen == 0) {
+#ifdef CONFIG_WPS
+			if (hapd->conf->wps_state) {
+				wpa_printf(MSG_DEBUG, "STA did not include "
+					   "WPA/RSN IE in (Re)Association "
+					   "Request - possible WPS use");
+				sta->flags |= WLAN_STA_MAYBE_WPS;
+				goto skip_wpa_check;
+			}
+#endif /* CONFIG_WPS */
+
+			wpa_printf(MSG_DEBUG, "No WPA/RSN IE from STA");
+			return -1;
+		}
+#ifdef CONFIG_WPS
+		if (hapd->conf->wps_state && ie[0] == 0xdd && ie[1] >= 4 &&
+		    os_memcmp(ie + 2, "\x00\x50\xf2\x04", 4) == 0) {
+			struct wpabuf *wps;
+			sta->flags |= WLAN_STA_WPS;
+			wps = ieee802_11_vendor_ie_concat(ie, ielen,
+							  WPS_IE_VENDOR_TYPE);
+			if (wps) {
+				if (wps_is_20(wps)) {
+					wpa_printf(MSG_DEBUG, "WPS: STA "
+						   "supports WPS 2.0");
+					sta->flags |= WLAN_STA_WPS2;
+				}
+				wpabuf_free(wps);
+			}
+			goto skip_wpa_check;
+		}
+#endif /* CONFIG_WPS */
+
+		if (sta->wpa_sm == NULL)
+			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+							sta->addr);
+		if (sta->wpa_sm == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to initialize WPA state "
+				   "machine");
+			return -1;
+		}
+		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+					  ie, ielen,
+					  elems.mdie, elems.mdie_len);
+		if (res != WPA_IE_OK) {
+			wpa_printf(MSG_DEBUG, "WPA/RSN information element "
+				   "rejected? (res %u)", res);
+			wpa_hexdump(MSG_DEBUG, "IE", ie, ielen);
+			if (res == WPA_INVALID_GROUP) {
+				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+			} else if (res == WPA_INVALID_PAIRWISE) {
+				reason = WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID;
+				status = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+			} else if (res == WPA_INVALID_AKMP) {
+				reason = WLAN_REASON_AKMP_NOT_VALID;
+				status = WLAN_STATUS_AKMP_NOT_VALID;
+			}
+#ifdef CONFIG_IEEE80211W
+			else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION) {
+				reason = WLAN_REASON_INVALID_IE;
+				status = WLAN_STATUS_INVALID_IE;
+			} else if (res == WPA_INVALID_MGMT_GROUP_CIPHER) {
+				reason = WLAN_REASON_GROUP_CIPHER_NOT_VALID;
+				status = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+			}
+#endif /* CONFIG_IEEE80211W */
+			else {
+				reason = WLAN_REASON_INVALID_IE;
+				status = WLAN_STATUS_INVALID_IE;
+			}
+			goto fail;
+		}
+#ifdef CONFIG_IEEE80211W
+		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+		    sta->sa_query_count > 0)
+			ap_check_sa_query_timeout(hapd, sta);
+		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+		    (sta->auth_alg != WLAN_AUTH_FT)) {
+			/*
+			 * STA has already been associated with MFP and SA
+			 * Query timeout has not been reached. Reject the
+			 * association attempt temporarily and start SA Query,
+			 * if one is not pending.
+			 */
+
+			if (sta->sa_query_count == 0)
+				ap_sta_start_sa_query(hapd, sta);
+
+#ifdef CONFIG_IEEE80211R
+			status = WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
+
+			p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
+
+			hostapd_sta_assoc(hapd, addr, reassoc, status, buf,
+					  p - buf);
+#endif /* CONFIG_IEEE80211R */
+			return 0;
+		}
+
+		if (wpa_auth_uses_mfp(sta->wpa_sm))
+			sta->flags |= WLAN_STA_MFP;
+		else
+			sta->flags &= ~WLAN_STA_MFP;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_IEEE80211R
+		if (sta->auth_alg == WLAN_AUTH_FT) {
+			status = wpa_ft_validate_reassoc(sta->wpa_sm, req_ies,
+							 req_ies_len);
+			if (status != WLAN_STATUS_SUCCESS) {
+				if (status == WLAN_STATUS_INVALID_PMKID)
+					reason = WLAN_REASON_INVALID_IE;
+				if (status == WLAN_STATUS_INVALID_MDIE)
+					reason = WLAN_REASON_INVALID_IE;
+				if (status == WLAN_STATUS_INVALID_FTIE)
+					reason = WLAN_REASON_INVALID_IE;
+				goto fail;
+			}
+		}
+#endif /* CONFIG_IEEE80211R */
+	} else if (hapd->conf->wps_state) {
+#ifdef CONFIG_WPS
+		struct wpabuf *wps;
+		if (req_ies)
+			wps = ieee802_11_vendor_ie_concat(req_ies, req_ies_len,
+							  WPS_IE_VENDOR_TYPE);
+		else
+			wps = NULL;
+#ifdef CONFIG_WPS_STRICT
+		if (wps && wps_validate_assoc_req(wps) < 0) {
+			reason = WLAN_REASON_INVALID_IE;
+			status = WLAN_STATUS_INVALID_IE;
+			wpabuf_free(wps);
+			goto fail;
+		}
+#endif /* CONFIG_WPS_STRICT */
+		if (wps) {
+			sta->flags |= WLAN_STA_WPS;
+			if (wps_is_20(wps)) {
+				wpa_printf(MSG_DEBUG, "WPS: STA supports "
+					   "WPS 2.0");
+				sta->flags |= WLAN_STA_WPS2;
+			}
+		} else
+			sta->flags |= WLAN_STA_MAYBE_WPS;
+		wpabuf_free(wps);
+#endif /* CONFIG_WPS */
+	}
+#ifdef CONFIG_WPS
+skip_wpa_check:
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_IEEE80211R
+	p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, buf, sizeof(buf),
+					sta->auth_alg, req_ies, req_ies_len);
+
+	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
+#else /* CONFIG_IEEE80211R */
+	/* Keep compiler silent about unused variables */
+	if (status) {
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	new_assoc = (sta->flags & WLAN_STA_ASSOC) == 0;
+	sta->flags |= WLAN_STA_AUTH | WLAN_STA_ASSOC;
+
+	if (reassoc && (sta->auth_alg == WLAN_AUTH_FT))
+		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
+	else
+		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
+
+	hostapd_new_assoc_sta(hapd, sta, !new_assoc);
+
+	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+
+#ifdef CONFIG_P2P
+	if (req_ies) {
+		p2p_group_notif_assoc(hapd->p2p_group, sta->addr,
+				      req_ies, req_ies_len);
+	}
+#endif /* CONFIG_P2P */
+
+	return 0;
+
+fail:
+#ifdef CONFIG_IEEE80211R
+	hostapd_sta_assoc(hapd, addr, reassoc, status, buf, p - buf);
+#endif /* CONFIG_IEEE80211R */
+	hostapd_drv_sta_disassoc(hapd, sta->addr, reason);
+	ap_free_sta(hapd, sta);
+	return -1;
+}
+
+
+void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct sta_info *sta;
+
+	if (addr == NULL) {
+		/*
+		 * This could potentially happen with unexpected event from the
+		 * driver wrapper. This was seen at least in one case where the
+		 * driver ended up reporting a station mode event while hostapd
+		 * was running, so better make sure we stop processing such an
+		 * event here.
+		 */
+		wpa_printf(MSG_DEBUG, "hostapd_notif_disassoc: Skip event "
+			   "with no address");
+		return;
+	}
+
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "disassociated");
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL) {
+		wpa_printf(MSG_DEBUG, "Disassociation notification for "
+			   "unknown STA " MACSTR, MAC2STR(addr));
+		return;
+	}
+
+	ap_sta_set_authorized(hapd, sta, 0);
+	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
+	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+	ap_free_sta(hapd, sta);
+}
+
+
+void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+
+	if (!sta || !hapd->conf->disassoc_low_ack)
+		return;
+
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "disconnected due to excessive "
+		       "missing ACKs");
+	hostapd_drv_sta_disassoc(hapd, addr, WLAN_REASON_DISASSOC_LOW_ACK);
+	if (sta)
+		ap_sta_disassociate(hapd, sta, WLAN_REASON_DISASSOC_LOW_ACK);
+}
+
+
+void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
+			     int offset)
+{
+#ifdef NEED_AP_MLME
+	int channel;
+
+	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "driver had channel switch: "
+		       "freq=%d, ht=%d, offset=%d", freq, ht, offset);
+
+	//hapd->iface->freq = freq;
+
+	channel = hostapd_hw_get_channel(hapd, freq);
+	if (!channel) {
+		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_WARNING, "driver switched to "
+			       "bad channel!");
+		return;
+	}
+
+	hapd->iconf->channel = channel;
+	hapd->iconf->ieee80211n = ht;
+	hapd->iconf->secondary_channel = offset;
+
+	if (hapd->iface->freq == freq)
+	        return;
+
+	hapd->iface->freq = freq;
+
+	if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, freq,
+			     hapd->iconf->channel,
+			     hapd->iconf->ieee80211n,
+			     hapd->iconf->secondary_channel)) {
+		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_WARNING,
+			       "failed to update the freq !");
+		return;
+	}
+
+	hapd->next_channel = NULL;
+
+	/* update the DS IE */
+	ieee802_11_set_beacon(hapd);
+
+	wpa_printf(MSG_DEBUG, "AP/GO moved to channel %d", channel);
+
+#endif /* NEED_AP_MLME */
+}
+
+
+int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
+			 const u8 *bssid, const u8 *ie, size_t ie_len,
+			 int ssi_signal)
+{
+	size_t i;
+	int ret = 0;
+
+	if (sa == NULL || ie == NULL)
+		return -1;
+
+	random_add_randomness(sa, ETH_ALEN);
+	for (i = 0; hapd->probereq_cb && i < hapd->num_probereq_cb; i++) {
+		if (hapd->probereq_cb[i].cb(hapd->probereq_cb[i].ctx,
+					    sa, da, bssid, ie, ie_len,
+					    ssi_signal) > 0) {
+			ret = 1;
+			break;
+		}
+	}
+	return ret;
+}
+
+
+#ifdef HOSTAPD
+
+#ifdef CONFIG_IEEE80211R
+static void hostapd_notify_auth_ft_finish(void *ctx, const u8 *dst,
+					  const u8 *bssid,
+					  u16 auth_transaction, u16 status,
+					  const u8 *ies, size_t ies_len)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, dst);
+	if (sta == NULL)
+		return;
+
+	hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
+	sta->flags |= WLAN_STA_AUTH;
+
+	hostapd_sta_auth(hapd, dst, auth_transaction, status, ies, ies_len);
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+static void hostapd_notif_auth(struct hostapd_data *hapd,
+			       struct auth_info *rx_auth)
+{
+	struct sta_info *sta;
+	u16 status = WLAN_STATUS_SUCCESS;
+	u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
+	size_t resp_ies_len = 0;
+
+	sta = ap_get_sta(hapd, rx_auth->peer);
+	if (!sta) {
+		sta = ap_sta_add(hapd, rx_auth->peer);
+		if (sta == NULL) {
+			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto fail;
+		}
+	}
+	sta->flags &= ~WLAN_STA_PREAUTH;
+	ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
+#ifdef CONFIG_IEEE80211R
+	if (rx_auth->auth_type == WLAN_AUTH_FT && hapd->wpa_auth) {
+		sta->auth_alg = WLAN_AUTH_FT;
+		if (sta->wpa_sm == NULL)
+			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+							sta->addr);
+		if (sta->wpa_sm == NULL) {
+			wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
+				   "state machine");
+			status = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto fail;
+		}
+		wpa_ft_process_auth(sta->wpa_sm, rx_auth->bssid,
+				    rx_auth->auth_transaction, rx_auth->ies,
+				    rx_auth->ies_len,
+				    hostapd_notify_auth_ft_finish, hapd);
+		return;
+	}
+#endif /* CONFIG_IEEE80211R */
+fail:
+	hostapd_sta_auth(hapd, rx_auth->peer, rx_auth->auth_transaction + 1,
+			 status, resp_ies, resp_ies_len);
+}
+
+
+static void hostapd_action_rx(struct hostapd_data *hapd,
+			      struct rx_action *action)
+{
+	struct sta_info *sta;
+
+        wpa_printf(MSG_DEBUG, "RX_ACTION cat %d action plen %d",
+		   action->category, (int) action->len);
+
+	sta = ap_get_sta(hapd, action->sa);
+	if (sta == NULL) {
+		wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
+		return;
+	}
+#ifdef CONFIG_IEEE80211R
+	if (action->category == WLAN_ACTION_FT) {
+		wpa_printf(MSG_DEBUG, "%s: FT_ACTION length %d",
+			   __func__, (int) action->len);
+		wpa_ft_action_rx(sta->wpa_sm, action->data, action->len);
+	}
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (action->category == WLAN_ACTION_SA_QUERY && action->len >= 4) {
+		wpa_printf(MSG_DEBUG, "%s: SA_QUERY_ACTION length %d",
+			   __func__, (int) action->len);
+		ieee802_11_sa_query_action(hapd, action->sa,
+					   *(action->data + 1),
+					   action->data + 2);
+	}
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WNM
+	if (action->category == WLAN_ACTION_WNM) {
+		wpa_printf(MSG_DEBUG, "%s: WNM_ACTION length %d",
+			   __func__, (int) action->len);
+		ieee802_11_rx_wnm_action_ap(hapd, action);
+	}
+#endif /* CONFIG_WNM */
+}
+
+
+#ifdef NEED_AP_MLME
+
+#define HAPD_BROADCAST ((struct hostapd_data *) -1)
+
+static struct hostapd_data * get_hapd_bssid(struct hostapd_iface *iface,
+					    const u8 *bssid)
+{
+	size_t i;
+
+	if (bssid == NULL)
+		return NULL;
+	if (bssid[0] == 0xff && bssid[1] == 0xff && bssid[2] == 0xff &&
+	    bssid[3] == 0xff && bssid[4] == 0xff && bssid[5] == 0xff)
+		return HAPD_BROADCAST;
+
+	for (i = 0; i < iface->num_bss; i++) {
+		if (os_memcmp(bssid, iface->bss[i]->own_addr, ETH_ALEN) == 0)
+			return iface->bss[i];
+	}
+
+	return NULL;
+}
+
+
+static void hostapd_rx_from_unknown_sta(struct hostapd_data *hapd,
+					const u8 *bssid, const u8 *addr,
+					int wds)
+{
+	hapd = get_hapd_bssid(hapd->iface, bssid);
+	if (hapd == NULL || hapd == HAPD_BROADCAST)
+		return;
+
+	ieee802_11_rx_from_unknown(hapd, addr, wds);
+}
+
+
+static void hostapd_mgmt_rx(struct hostapd_data *hapd, struct rx_mgmt *rx_mgmt)
+{
+	struct hostapd_iface *iface = hapd->iface;
+	const struct ieee80211_hdr *hdr;
+	const u8 *bssid;
+	struct hostapd_frame_info fi;
+
+	hdr = (const struct ieee80211_hdr *) rx_mgmt->frame;
+	bssid = get_hdr_bssid(hdr, rx_mgmt->frame_len);
+	if (bssid == NULL)
+		return;
+
+	hapd = get_hapd_bssid(iface, bssid);
+	if (hapd == NULL) {
+		u16 fc;
+		fc = le_to_host16(hdr->frame_control);
+
+		/*
+		 * Drop frames to unknown BSSIDs except for Beacon frames which
+		 * could be used to update neighbor information.
+		 */
+		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
+			hapd = iface->bss[0];
+		else
+			return;
+	}
+
+	os_memset(&fi, 0, sizeof(fi));
+	fi.datarate = rx_mgmt->datarate;
+	fi.ssi_signal = rx_mgmt->ssi_signal;
+
+	if (hapd == HAPD_BROADCAST) {
+		size_t i;
+		for (i = 0; i < iface->num_bss; i++)
+			ieee802_11_mgmt(iface->bss[i], rx_mgmt->frame,
+					rx_mgmt->frame_len, &fi);
+	} else
+		ieee802_11_mgmt(hapd, rx_mgmt->frame, rx_mgmt->frame_len, &fi);
+
+	random_add_randomness(&fi, sizeof(fi));
+}
+
+
+static void hostapd_rx_action(struct hostapd_data *hapd,
+			      struct rx_action *rx_action)
+{
+	struct rx_mgmt rx_mgmt;
+	u8 *buf;
+	struct ieee80211_hdr *hdr;
+
+	wpa_printf(MSG_DEBUG, "EVENT_RX_ACTION DA=" MACSTR " SA=" MACSTR
+		   " BSSID=" MACSTR " category=%u",
+		   MAC2STR(rx_action->da), MAC2STR(rx_action->sa),
+		   MAC2STR(rx_action->bssid), rx_action->category);
+	wpa_hexdump(MSG_MSGDUMP, "Received action frame contents",
+		    rx_action->data, rx_action->len);
+
+	buf = os_zalloc(24 + 1 + rx_action->len);
+	if (buf == NULL)
+		return;
+	hdr = (struct ieee80211_hdr *) buf;
+	hdr->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_ACTION);
+	if (rx_action->category == WLAN_ACTION_SA_QUERY) {
+		/*
+		 * Assume frame was protected; it would have been dropped if
+		 * not.
+		 */
+		hdr->frame_control |= host_to_le16(WLAN_FC_ISWEP);
+	}
+	os_memcpy(hdr->addr1, rx_action->da, ETH_ALEN);
+	os_memcpy(hdr->addr2, rx_action->sa, ETH_ALEN);
+	os_memcpy(hdr->addr3, rx_action->bssid, ETH_ALEN);
+	buf[24] = rx_action->category;
+	os_memcpy(buf + 24 + 1, rx_action->data, rx_action->len);
+	os_memset(&rx_mgmt, 0, sizeof(rx_mgmt));
+	rx_mgmt.frame = buf;
+	rx_mgmt.frame_len = 24 + 1 + rx_action->len;
+	hostapd_mgmt_rx(hapd, &rx_mgmt);
+	os_free(buf);
+}
+
+
+static void hostapd_mgmt_tx_cb(struct hostapd_data *hapd, const u8 *buf,
+			       size_t len, u16 stype, int ok)
+{
+	struct ieee80211_hdr *hdr;
+	hdr = (struct ieee80211_hdr *) buf;
+	hapd = get_hapd_bssid(hapd->iface, get_hdr_bssid(hdr, len));
+	if (hapd == NULL || hapd == HAPD_BROADCAST)
+		return;
+	ieee802_11_mgmt_cb(hapd, buf, len, stype, ok);
+}
+
+#endif /* NEED_AP_MLME */
+
+
+static int hostapd_event_new_sta(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+	if (sta)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "Data frame from unknown STA " MACSTR
+		   " - adding a new STA", MAC2STR(addr));
+	sta = ap_sta_add(hapd, addr);
+	if (sta) {
+		hostapd_new_assoc_sta(hapd, sta, 0);
+	} else {
+		wpa_printf(MSG_DEBUG, "Failed to add STA entry for " MACSTR,
+			   MAC2STR(addr));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void hostapd_event_eapol_rx(struct hostapd_data *hapd, const u8 *src,
+				   const u8 *data, size_t data_len)
+{
+	struct hostapd_iface *iface = hapd->iface;
+	struct sta_info *sta;
+	size_t j;
+
+	for (j = 0; j < iface->num_bss; j++) {
+		if ((sta = ap_get_sta(iface->bss[j], src))) {
+			if (sta->flags & WLAN_STA_ASSOC) {
+				hapd = iface->bss[j];
+				break;
+			}
+		}
+	}
+
+	ieee802_1x_receive(hapd, src, data, data_len);
+}
+
+
+void wpa_supplicant_event(void *ctx, enum wpa_event_type event,
+			  union wpa_event_data *data)
+{
+	struct hostapd_data *hapd = ctx;
+#ifndef CONFIG_NO_STDOUT_DEBUG
+	int level = MSG_DEBUG;
+
+	if (event == EVENT_RX_MGMT && data->rx_mgmt.frame &&
+	    data->rx_mgmt.frame_len >= 24) {
+		const struct ieee80211_hdr *hdr;
+		u16 fc;
+		hdr = (const struct ieee80211_hdr *) data->rx_mgmt.frame;
+		fc = le_to_host16(hdr->frame_control);
+		if (WLAN_FC_GET_TYPE(fc) == WLAN_FC_TYPE_MGMT &&
+		    WLAN_FC_GET_STYPE(fc) == WLAN_FC_STYPE_BEACON)
+			level = MSG_EXCESSIVE;
+	}
+
+	wpa_dbg(hapd->msg_ctx, level, "Event %s (%d) received",
+		event_to_string(event), event);
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+	switch (event) {
+	case EVENT_MICHAEL_MIC_FAILURE:
+		michael_mic_failure(hapd, data->michael_mic_failure.src, 1);
+		break;
+	case EVENT_SCAN_RESULTS:
+		if (hapd->iface->scan_cb)
+			hapd->iface->scan_cb(hapd->iface);
+		break;
+#ifdef CONFIG_IEEE80211R
+	case EVENT_FT_RRB_RX:
+		wpa_ft_rrb_rx(hapd->wpa_auth, data->ft_rrb_rx.src,
+			      data->ft_rrb_rx.data, data->ft_rrb_rx.data_len);
+		break;
+#endif /* CONFIG_IEEE80211R */
+	case EVENT_WPS_BUTTON_PUSHED:
+		hostapd_wps_button_pushed(hapd, NULL);
+		break;
+#ifdef NEED_AP_MLME
+	case EVENT_TX_STATUS:
+		switch (data->tx_status.type) {
+		case WLAN_FC_TYPE_MGMT:
+			hostapd_mgmt_tx_cb(hapd, data->tx_status.data,
+					   data->tx_status.data_len,
+					   data->tx_status.stype,
+					   data->tx_status.ack);
+			break;
+		case WLAN_FC_TYPE_DATA:
+			hostapd_tx_status(hapd, data->tx_status.dst,
+					  data->tx_status.data,
+					  data->tx_status.data_len,
+					  data->tx_status.ack);
+			break;
+		}
+		break;
+	case EVENT_EAPOL_TX_STATUS:
+		hostapd_eapol_tx_status(hapd, data->eapol_tx_status.dst,
+					data->eapol_tx_status.data,
+					data->eapol_tx_status.data_len,
+					data->eapol_tx_status.ack);
+		break;
+	case EVENT_DRIVER_CLIENT_POLL_OK:
+		hostapd_client_poll_ok(hapd, data->client_poll.addr);
+		break;
+	case EVENT_RX_FROM_UNKNOWN:
+		hostapd_rx_from_unknown_sta(hapd, data->rx_from_unknown.bssid,
+					    data->rx_from_unknown.addr,
+					    data->rx_from_unknown.wds);
+		break;
+	case EVENT_RX_MGMT:
+		hostapd_mgmt_rx(hapd, &data->rx_mgmt);
+		break;
+#endif /* NEED_AP_MLME */
+	case EVENT_RX_PROBE_REQ:
+		if (data->rx_probe_req.sa == NULL ||
+		    data->rx_probe_req.ie == NULL)
+			break;
+		hostapd_probe_req_rx(hapd, data->rx_probe_req.sa,
+				     data->rx_probe_req.da,
+				     data->rx_probe_req.bssid,
+				     data->rx_probe_req.ie,
+				     data->rx_probe_req.ie_len,
+				     data->rx_probe_req.ssi_signal);
+		break;
+	case EVENT_NEW_STA:
+		hostapd_event_new_sta(hapd, data->new_sta.addr);
+		break;
+	case EVENT_EAPOL_RX:
+		hostapd_event_eapol_rx(hapd, data->eapol_rx.src,
+				       data->eapol_rx.data,
+				       data->eapol_rx.data_len);
+		break;
+	case EVENT_ASSOC:
+		hostapd_notif_assoc(hapd, data->assoc_info.addr,
+				    data->assoc_info.req_ies,
+				    data->assoc_info.req_ies_len,
+				    data->assoc_info.reassoc);
+		break;
+	case EVENT_DISASSOC:
+		if (data)
+			hostapd_notif_disassoc(hapd, data->disassoc_info.addr);
+		break;
+	case EVENT_DEAUTH:
+		if (data)
+			hostapd_notif_disassoc(hapd, data->deauth_info.addr);
+		break;
+	case EVENT_STATION_LOW_ACK:
+		if (!data)
+			break;
+		hostapd_event_sta_low_ack(hapd, data->low_ack.addr);
+		break;
+	case EVENT_RX_ACTION:
+		if (data->rx_action.da == NULL || data->rx_action.sa == NULL ||
+		    data->rx_action.bssid == NULL)
+			break;
+#ifdef NEED_AP_MLME
+		hostapd_rx_action(hapd, &data->rx_action);
+#endif /* NEED_AP_MLME */
+		hostapd_action_rx(hapd, &data->rx_action);
+		break;
+	case EVENT_AUTH:
+		hostapd_notif_auth(hapd, &data->auth);
+		break;
+	case EVENT_CH_SWITCH:
+		if (!data)
+			break;
+		hostapd_event_ch_switch(hapd, data->ch_switch.freq,
+					data->ch_switch.ht_enabled,
+					data->ch_switch.ch_offset);
+		break;
+	case EVENT_REQ_CH_SW:
+		if (!data)
+			break;
+		ieee802_11_start_channel_switch(hapd, data->ch_switch.freq,
+						FALSE);
+	default:
+		wpa_printf(MSG_DEBUG, "Unknown event %d", event);
+		break;
+	}
+}
+
+#endif /* HOSTAPD */
diff --git a/hostap/src/ap/eap_user_db.c b/hostap/src/ap/eap_user_db.c
new file mode 100644
index 0000000..79d50e5
--- /dev/null
+++ b/hostap/src/ap/eap_user_db.c
@@ -0,0 +1,270 @@
+/*
+ * hostapd / EAP user database
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#ifdef CONFIG_SQLITE
+#include <sqlite3.h>
+#endif /* CONFIG_SQLITE */
+
+#include "common.h"
+#include "eap_common/eap_wsc_common.h"
+#include "eap_server/eap_methods.h"
+#include "eap_server/eap.h"
+#include "ap_config.h"
+#include "hostapd.h"
+
+#ifdef CONFIG_SQLITE
+
+static void set_user_methods(struct hostapd_eap_user *user, const char *methods)
+{
+	char *buf, *start;
+	int num_methods;
+
+	buf = os_strdup(methods);
+	if (buf == NULL)
+		return;
+
+	os_memset(&user->methods, 0, sizeof(user->methods));
+	num_methods = 0;
+	start = buf;
+	while (*start) {
+		char *pos3 = os_strchr(start, ',');
+		if (pos3)
+			*pos3++ = '\0';
+		user->methods[num_methods].method =
+			eap_server_get_type(start,
+					    &user->methods[num_methods].vendor);
+		if (user->methods[num_methods].vendor == EAP_VENDOR_IETF &&
+		    user->methods[num_methods].method == EAP_TYPE_NONE) {
+			if (os_strcmp(start, "TTLS-PAP") == 0) {
+				user->ttls_auth |= EAP_TTLS_AUTH_PAP;
+				goto skip_eap;
+			}
+			if (os_strcmp(start, "TTLS-CHAP") == 0) {
+				user->ttls_auth |= EAP_TTLS_AUTH_CHAP;
+				goto skip_eap;
+			}
+			if (os_strcmp(start, "TTLS-MSCHAP") == 0) {
+				user->ttls_auth |= EAP_TTLS_AUTH_MSCHAP;
+				goto skip_eap;
+			}
+			if (os_strcmp(start, "TTLS-MSCHAPV2") == 0) {
+				user->ttls_auth |= EAP_TTLS_AUTH_MSCHAPV2;
+				goto skip_eap;
+			}
+			wpa_printf(MSG_INFO, "DB: Unsupported EAP type '%s'",
+				   start);
+			os_free(buf);
+			return;
+		}
+
+		num_methods++;
+		if (num_methods >= EAP_MAX_METHODS)
+			break;
+	skip_eap:
+		if (pos3 == NULL)
+			break;
+		start = pos3;
+	}
+
+	os_free(buf);
+}
+
+
+static int get_user_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+	struct hostapd_eap_user *user = ctx;
+	int i;
+
+	for (i = 0; i < argc; i++) {
+		if (os_strcmp(col[i], "password") == 0 && argv[i]) {
+			os_free(user->password);
+			user->password_len = os_strlen(argv[i]);
+			user->password = (u8 *) os_strdup(argv[i]);
+			user->next = (void *) 1;
+		} else if (os_strcmp(col[i], "methods") == 0 && argv[i]) {
+			set_user_methods(user, argv[i]);
+		}
+	}
+
+	return 0;
+}
+
+
+static int get_wildcard_cb(void *ctx, int argc, char *argv[], char *col[])
+{
+	struct hostapd_eap_user *user = ctx;
+	int i, id = -1, methods = -1;
+	size_t len;
+
+	for (i = 0; i < argc; i++) {
+		if (os_strcmp(col[i], "identity") == 0 && argv[i])
+			id = i;
+		else if (os_strcmp(col[i], "methods") == 0 && argv[i])
+			methods = i;
+	}
+
+	if (id < 0 || methods < 0)
+		return 0;
+
+	len = os_strlen(argv[id]);
+	if (len <= user->identity_len &&
+	    os_memcmp(argv[id], user->identity, len) == 0 &&
+	    (user->password == NULL || len > user->password_len)) {
+		os_free(user->password);
+		user->password_len = os_strlen(argv[id]);
+		user->password = (u8 *) os_strdup(argv[id]);
+		user->next = (void *) 1;
+		set_user_methods(user, argv[methods]);
+	}
+
+	return 0;
+}
+
+
+static const struct hostapd_eap_user *
+eap_user_sqlite_get(struct hostapd_data *hapd, const u8 *identity,
+		    size_t identity_len, int phase2)
+{
+	sqlite3 *db;
+	struct hostapd_eap_user *user = NULL;
+	char id_str[256], cmd[300];
+	size_t i;
+
+	if (identity_len >= sizeof(id_str))
+		return NULL;
+	os_memcpy(id_str, identity, identity_len);
+	id_str[identity_len] = '\0';
+	for (i = 0; i < identity_len; i++) {
+		if (id_str[i] >= 'a' && id_str[i] <= 'z')
+			continue;
+		if (id_str[i] >= 'A' && id_str[i] <= 'Z')
+			continue;
+		if (id_str[i] >= '0' && id_str[i] <= '9')
+			continue;
+		if (id_str[i] == '-' || id_str[i] == '_' || id_str[i] == '.' ||
+		    id_str[i] == ',' || id_str[i] == '@' || id_str[i] == '\\' ||
+		    id_str[i] == '!' || id_str[i] == '#' || id_str[i] == '%' ||
+		    id_str[i] == '=' || id_str[i] == ' ')
+			continue;
+		wpa_printf(MSG_INFO, "DB: Unsupported character in identity");
+		return NULL;
+	}
+
+	os_free(hapd->tmp_eap_user.identity);
+	os_free(hapd->tmp_eap_user.password);
+	os_memset(&hapd->tmp_eap_user, 0, sizeof(hapd->tmp_eap_user));
+	hapd->tmp_eap_user.phase2 = phase2;
+	hapd->tmp_eap_user.identity = os_zalloc(identity_len + 1);
+	if (hapd->tmp_eap_user.identity == NULL)
+		return NULL;
+	os_memcpy(hapd->tmp_eap_user.identity, identity, identity_len);
+
+	if (sqlite3_open(hapd->conf->eap_user_sqlite, &db)) {
+		wpa_printf(MSG_INFO, "DB: Failed to open database %s: %s",
+			   hapd->conf->eap_user_sqlite, sqlite3_errmsg(db));
+		sqlite3_close(db);
+		return NULL;
+	}
+
+	os_snprintf(cmd, sizeof(cmd),
+		    "SELECT password,methods FROM users WHERE "
+		    "identity='%s' AND phase2=%d;", id_str, phase2);
+	wpa_printf(MSG_DEBUG, "DB: %s", cmd);
+	if (sqlite3_exec(db, cmd, get_user_cb, &hapd->tmp_eap_user, NULL) !=
+	    SQLITE_OK) {
+		wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL operation");
+	} else if (hapd->tmp_eap_user.next)
+		user = &hapd->tmp_eap_user;
+
+	if (user == NULL && !phase2) {
+		os_snprintf(cmd, sizeof(cmd),
+			    "SELECT identity,methods FROM wildcards;");
+		wpa_printf(MSG_DEBUG, "DB: %s", cmd);
+		if (sqlite3_exec(db, cmd, get_wildcard_cb, &hapd->tmp_eap_user,
+				 NULL) != SQLITE_OK) {
+			wpa_printf(MSG_DEBUG, "DB: Failed to complete SQL "
+				   "operation");
+		} else if (hapd->tmp_eap_user.next) {
+			user = &hapd->tmp_eap_user;
+			os_free(user->identity);
+			user->identity = user->password;
+			user->identity_len = user->password_len;
+			user->password = NULL;
+			user->password_len = 0;
+		}
+	}
+
+	sqlite3_close(db);
+
+	return user;
+}
+
+#endif /* CONFIG_SQLITE */
+
+
+const struct hostapd_eap_user *
+hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
+		     size_t identity_len, int phase2)
+{
+	const struct hostapd_bss_config *conf = hapd->conf;
+	struct hostapd_eap_user *user = conf->eap_user;
+
+#ifdef CONFIG_WPS
+	if (conf->wps_state && identity_len == WSC_ID_ENROLLEE_LEN &&
+	    os_memcmp(identity, WSC_ID_ENROLLEE, WSC_ID_ENROLLEE_LEN) == 0) {
+		static struct hostapd_eap_user wsc_enrollee;
+		os_memset(&wsc_enrollee, 0, sizeof(wsc_enrollee));
+		wsc_enrollee.methods[0].method = eap_server_get_type(
+			"WSC", &wsc_enrollee.methods[0].vendor);
+		return &wsc_enrollee;
+	}
+
+	if (conf->wps_state && identity_len == WSC_ID_REGISTRAR_LEN &&
+	    os_memcmp(identity, WSC_ID_REGISTRAR, WSC_ID_REGISTRAR_LEN) == 0) {
+		static struct hostapd_eap_user wsc_registrar;
+		os_memset(&wsc_registrar, 0, sizeof(wsc_registrar));
+		wsc_registrar.methods[0].method = eap_server_get_type(
+			"WSC", &wsc_registrar.methods[0].vendor);
+		wsc_registrar.password = (u8 *) conf->ap_pin;
+		wsc_registrar.password_len = conf->ap_pin ?
+			os_strlen(conf->ap_pin) : 0;
+		return &wsc_registrar;
+	}
+#endif /* CONFIG_WPS */
+
+	while (user) {
+		if (!phase2 && user->identity == NULL) {
+			/* Wildcard match */
+			break;
+		}
+
+		if (user->phase2 == !!phase2 && user->wildcard_prefix &&
+		    identity_len >= user->identity_len &&
+		    os_memcmp(user->identity, identity, user->identity_len) ==
+		    0) {
+			/* Wildcard prefix match */
+			break;
+		}
+
+		if (user->phase2 == !!phase2 &&
+		    user->identity_len == identity_len &&
+		    os_memcmp(user->identity, identity, identity_len) == 0)
+			break;
+		user = user->next;
+	}
+
+#ifdef CONFIG_SQLITE
+	if (user == NULL && conf->eap_user_sqlite) {
+		return eap_user_sqlite_get(hapd, identity, identity_len,
+					   phase2);
+	}
+#endif /* CONFIG_SQLITE */
+
+	return user;
+}
diff --git a/hostap/src/ap/gas_serv.c b/hostap/src/ap/gas_serv.c
new file mode 100644
index 0000000..851c183
--- /dev/null
+++ b/hostap/src/ap/gas_serv.c
@@ -0,0 +1,1172 @@
+/*
+ * Generic advertisement service (GAS) server
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/gas.h"
+#include "utils/eloop.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "sta_info.h"
+#include "gas_serv.h"
+
+
+static struct gas_dialog_info *
+gas_dialog_create(struct hostapd_data *hapd, const u8 *addr, u8 dialog_token)
+{
+	struct sta_info *sta;
+	struct gas_dialog_info *dia = NULL;
+	int i, j;
+
+	sta = ap_get_sta(hapd, addr);
+	if (!sta) {
+		/*
+		 * We need a STA entry to be able to maintain state for
+		 * the GAS query.
+		 */
+		wpa_printf(MSG_DEBUG, "ANQP: Add a temporary STA entry for "
+			   "GAS query");
+		sta = ap_sta_add(hapd, addr);
+		if (!sta) {
+			wpa_printf(MSG_DEBUG, "Failed to add STA " MACSTR
+				   " for GAS query", MAC2STR(addr));
+			return NULL;
+		}
+		sta->flags |= WLAN_STA_GAS;
+		/*
+		 * The default inactivity is 300 seconds. We don't need
+		 * it to be that long.
+		 */
+		ap_sta_session_timeout(hapd, sta, 5);
+	}
+
+	if (sta->gas_dialog == NULL) {
+		sta->gas_dialog = os_zalloc(GAS_DIALOG_MAX *
+					    sizeof(struct gas_dialog_info));
+		if (sta->gas_dialog == NULL)
+			return NULL;
+	}
+
+	for (i = sta->gas_dialog_next, j = 0; j < GAS_DIALOG_MAX; i++, j++) {
+		if (i == GAS_DIALOG_MAX)
+			i = 0;
+		if (sta->gas_dialog[i].valid)
+			continue;
+		dia = &sta->gas_dialog[i];
+		dia->valid = 1;
+		dia->index = i;
+		dia->dialog_token = dialog_token;
+		sta->gas_dialog_next = (++i == GAS_DIALOG_MAX) ? 0 : i;
+		return dia;
+	}
+
+	wpa_msg(hapd->msg_ctx, MSG_ERROR, "ANQP: Could not create dialog for "
+		MACSTR " dialog_token %u. Consider increasing "
+		"GAS_DIALOG_MAX.", MAC2STR(addr), dialog_token);
+
+	return NULL;
+}
+
+
+struct gas_dialog_info *
+gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
+		     u8 dialog_token)
+{
+	struct sta_info *sta;
+	int i;
+
+	sta = ap_get_sta(hapd, addr);
+	if (!sta) {
+		wpa_printf(MSG_DEBUG, "ANQP: could not find STA " MACSTR,
+			   MAC2STR(addr));
+		return NULL;
+	}
+	for (i = 0; sta->gas_dialog && i < GAS_DIALOG_MAX; i++) {
+		if (sta->gas_dialog[i].dialog_token != dialog_token ||
+		    !sta->gas_dialog[i].valid)
+			continue;
+		return &sta->gas_dialog[i];
+	}
+	wpa_printf(MSG_DEBUG, "ANQP: Could not find dialog for "
+		   MACSTR " dialog_token %u", MAC2STR(addr), dialog_token);
+	return NULL;
+}
+
+
+void gas_serv_dialog_clear(struct gas_dialog_info *dia)
+{
+	wpabuf_free(dia->sd_resp);
+	os_memset(dia, 0, sizeof(*dia));
+}
+
+
+static void gas_serv_free_dialogs(struct hostapd_data *hapd,
+				  const u8 *sta_addr)
+{
+	struct sta_info *sta;
+	int i;
+
+	sta = ap_get_sta(hapd, sta_addr);
+	if (sta == NULL || sta->gas_dialog == NULL)
+		return;
+
+	for (i = 0; i < GAS_DIALOG_MAX; i++) {
+		if (sta->gas_dialog[i].valid)
+			return;
+	}
+
+	os_free(sta->gas_dialog);
+	sta->gas_dialog = NULL;
+}
+
+
+#ifdef CONFIG_HS20
+static void anqp_add_hs_capab_list(struct hostapd_data *hapd,
+				   struct wpabuf *buf)
+{
+	u8 *len;
+
+	len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+	wpabuf_put_be24(buf, OUI_WFA);
+	wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+	wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
+	wpabuf_put_u8(buf, 0); /* Reserved */
+	wpabuf_put_u8(buf, HS20_STYPE_CAPABILITY_LIST);
+	if (hapd->conf->hs20_oper_friendly_name)
+		wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
+	if (hapd->conf->hs20_wan_metrics)
+		wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
+	if (hapd->conf->hs20_connection_capability)
+		wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
+	if (hapd->conf->nai_realm_data)
+		wpabuf_put_u8(buf, HS20_STYPE_NAI_HOME_REALM_QUERY);
+	if (hapd->conf->hs20_operating_class)
+		wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
+	gas_anqp_set_element_len(buf, len);
+}
+#endif /* CONFIG_HS20 */
+
+
+static void anqp_add_capab_list(struct hostapd_data *hapd,
+				struct wpabuf *buf)
+{
+	u8 *len;
+
+	len = gas_anqp_add_element(buf, ANQP_CAPABILITY_LIST);
+	wpabuf_put_le16(buf, ANQP_CAPABILITY_LIST);
+	if (hapd->conf->venue_name)
+		wpabuf_put_le16(buf, ANQP_VENUE_NAME);
+	if (hapd->conf->network_auth_type)
+		wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
+	if (hapd->conf->roaming_consortium)
+		wpabuf_put_le16(buf, ANQP_ROAMING_CONSORTIUM);
+	if (hapd->conf->ipaddr_type_configured)
+		wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
+	if (hapd->conf->nai_realm_data)
+		wpabuf_put_le16(buf, ANQP_NAI_REALM);
+	if (hapd->conf->anqp_3gpp_cell_net)
+		wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
+	if (hapd->conf->domain_name)
+		wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
+#ifdef CONFIG_HS20
+	anqp_add_hs_capab_list(hapd, buf);
+#endif /* CONFIG_HS20 */
+	gas_anqp_set_element_len(buf, len);
+}
+
+
+static void anqp_add_venue_name(struct hostapd_data *hapd, struct wpabuf *buf)
+{
+	if (hapd->conf->venue_name) {
+		u8 *len;
+		unsigned int i;
+		len = gas_anqp_add_element(buf, ANQP_VENUE_NAME);
+		wpabuf_put_u8(buf, hapd->conf->venue_group);
+		wpabuf_put_u8(buf, hapd->conf->venue_type);
+		for (i = 0; i < hapd->conf->venue_name_count; i++) {
+			struct hostapd_lang_string *vn;
+			vn = &hapd->conf->venue_name[i];
+			wpabuf_put_u8(buf, 3 + vn->name_len);
+			wpabuf_put_data(buf, vn->lang, 3);
+			wpabuf_put_data(buf, vn->name, vn->name_len);
+		}
+		gas_anqp_set_element_len(buf, len);
+	}
+}
+
+
+static void anqp_add_network_auth_type(struct hostapd_data *hapd,
+				       struct wpabuf *buf)
+{
+	if (hapd->conf->network_auth_type) {
+		wpabuf_put_le16(buf, ANQP_NETWORK_AUTH_TYPE);
+		wpabuf_put_le16(buf, hapd->conf->network_auth_type_len);
+		wpabuf_put_data(buf, hapd->conf->network_auth_type,
+				hapd->conf->network_auth_type_len);
+	}
+}
+
+
+static void anqp_add_roaming_consortium(struct hostapd_data *hapd,
+					struct wpabuf *buf)
+{
+	unsigned int i;
+	u8 *len;
+
+	len = gas_anqp_add_element(buf, ANQP_ROAMING_CONSORTIUM);
+	for (i = 0; i < hapd->conf->roaming_consortium_count; i++) {
+		struct hostapd_roaming_consortium *rc;
+		rc = &hapd->conf->roaming_consortium[i];
+		wpabuf_put_u8(buf, rc->len);
+		wpabuf_put_data(buf, rc->oi, rc->len);
+	}
+	gas_anqp_set_element_len(buf, len);
+}
+
+
+static void anqp_add_ip_addr_type_availability(struct hostapd_data *hapd,
+					       struct wpabuf *buf)
+{
+	if (hapd->conf->ipaddr_type_configured) {
+		wpabuf_put_le16(buf, ANQP_IP_ADDR_TYPE_AVAILABILITY);
+		wpabuf_put_le16(buf, 1);
+		wpabuf_put_u8(buf, hapd->conf->ipaddr_type_availability);
+	}
+}
+
+
+static void anqp_add_nai_realm_eap(struct wpabuf *buf,
+				   struct hostapd_nai_realm_data *realm)
+{
+	unsigned int i, j;
+
+	wpabuf_put_u8(buf, realm->eap_method_count);
+
+	for (i = 0; i < realm->eap_method_count; i++) {
+		struct hostapd_nai_realm_eap *eap = &realm->eap_method[i];
+		wpabuf_put_u8(buf, 2 + (3 * eap->num_auths));
+		wpabuf_put_u8(buf, eap->eap_method);
+		wpabuf_put_u8(buf, eap->num_auths);
+		for (j = 0; j < eap->num_auths; j++) {
+			wpabuf_put_u8(buf, eap->auth_id[j]);
+			wpabuf_put_u8(buf, 1);
+			wpabuf_put_u8(buf, eap->auth_val[j]);
+		}
+	}
+}
+
+
+static void anqp_add_nai_realm_data(struct wpabuf *buf,
+				    struct hostapd_nai_realm_data *realm,
+				    unsigned int realm_idx)
+{
+	u8 *realm_data_len;
+
+	wpa_printf(MSG_DEBUG, "realm=%s, len=%d", realm->realm[realm_idx],
+		   (int) os_strlen(realm->realm[realm_idx]));
+	realm_data_len = wpabuf_put(buf, 2);
+	wpabuf_put_u8(buf, realm->encoding);
+	wpabuf_put_u8(buf, os_strlen(realm->realm[realm_idx]));
+	wpabuf_put_str(buf, realm->realm[realm_idx]);
+	anqp_add_nai_realm_eap(buf, realm);
+	gas_anqp_set_element_len(buf, realm_data_len);
+}
+
+
+static int hs20_add_nai_home_realm_matches(struct hostapd_data *hapd,
+					   struct wpabuf *buf,
+					   const u8 *home_realm,
+					   size_t home_realm_len)
+{
+	unsigned int i, j, k;
+	u8 num_realms, num_matching = 0, encoding, realm_len, *realm_list_len;
+	struct hostapd_nai_realm_data *realm;
+	const u8 *pos, *realm_name, *end;
+	struct {
+		unsigned int realm_data_idx;
+		unsigned int realm_idx;
+	} matches[10];
+
+	pos = home_realm;
+	end = pos + home_realm_len;
+	if (pos + 1 > end) {
+		wpa_hexdump(MSG_DEBUG, "Too short NAI Home Realm Query",
+			    home_realm, home_realm_len);
+		return -1;
+	}
+	num_realms = *pos++;
+
+	for (i = 0; i < num_realms && num_matching < 10; i++) {
+		if (pos + 2 > end) {
+			wpa_hexdump(MSG_DEBUG,
+				    "Truncated NAI Home Realm Query",
+				    home_realm, home_realm_len);
+			return -1;
+		}
+		encoding = *pos++;
+		realm_len = *pos++;
+		if (pos + realm_len > end) {
+			wpa_hexdump(MSG_DEBUG,
+				    "Truncated NAI Home Realm Query",
+				    home_realm, home_realm_len);
+			return -1;
+		}
+		realm_name = pos;
+		for (j = 0; j < hapd->conf->nai_realm_count &&
+			     num_matching < 10; j++) {
+			const u8 *rpos, *rend;
+			realm = &hapd->conf->nai_realm_data[j];
+			if (encoding != realm->encoding)
+				continue;
+
+			rpos = realm_name;
+			while (rpos < realm_name + realm_len &&
+			       num_matching < 10) {
+				for (rend = rpos;
+				     rend < realm_name + realm_len; rend++) {
+					if (*rend == ';')
+						break;
+				}
+				for (k = 0; k < MAX_NAI_REALMS &&
+					     realm->realm[k] &&
+					     num_matching < 10; k++) {
+					if ((int) os_strlen(realm->realm[k]) !=
+					    rend - rpos ||
+					    os_strncmp((char *) rpos,
+						       realm->realm[k],
+						       rend - rpos) != 0)
+						continue;
+					matches[num_matching].realm_data_idx =
+						j;
+					matches[num_matching].realm_idx = k;
+					num_matching++;
+				}
+				rpos = rend + 1;
+			}
+		}
+		pos += realm_len;
+	}
+
+	realm_list_len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
+	wpabuf_put_le16(buf, num_matching);
+
+	/*
+	 * There are two ways to format. 1. each realm in a NAI Realm Data unit
+	 * 2. all realms that share the same EAP methods in a NAI Realm Data
+	 * unit. The first format is likely to be bigger in size than the
+	 * second, but may be easier to parse and process by the receiver.
+	 */
+	for (i = 0; i < num_matching; i++) {
+		wpa_printf(MSG_DEBUG, "realm_idx %d, realm_data_idx %d",
+			   matches[i].realm_data_idx, matches[i].realm_idx);
+		realm = &hapd->conf->nai_realm_data[matches[i].realm_data_idx];
+		anqp_add_nai_realm_data(buf, realm, matches[i].realm_idx);
+	}
+	gas_anqp_set_element_len(buf, realm_list_len);
+	return 0;
+}
+
+
+static void anqp_add_nai_realm(struct hostapd_data *hapd, struct wpabuf *buf,
+			       const u8 *home_realm, size_t home_realm_len,
+			       int nai_realm, int nai_home_realm)
+{
+	if (nai_realm && hapd->conf->nai_realm_data) {
+		u8 *len;
+		unsigned int i, j;
+		len = gas_anqp_add_element(buf, ANQP_NAI_REALM);
+		wpabuf_put_le16(buf, hapd->conf->nai_realm_count);
+		for (i = 0; i < hapd->conf->nai_realm_count; i++) {
+			u8 *realm_data_len, *realm_len;
+			struct hostapd_nai_realm_data *realm;
+
+			realm = &hapd->conf->nai_realm_data[i];
+			realm_data_len = wpabuf_put(buf, 2);
+			wpabuf_put_u8(buf, realm->encoding);
+			realm_len = wpabuf_put(buf, 1);
+			for (j = 0; realm->realm[j]; j++) {
+				if (j > 0)
+					wpabuf_put_u8(buf, ';');
+				wpabuf_put_str(buf, realm->realm[j]);
+			}
+			*realm_len = (u8 *) wpabuf_put(buf, 0) - realm_len - 1;
+			anqp_add_nai_realm_eap(buf, realm);
+			gas_anqp_set_element_len(buf, realm_data_len);
+		}
+		gas_anqp_set_element_len(buf, len);
+	} else if (nai_home_realm && hapd->conf->nai_realm_data) {
+		hs20_add_nai_home_realm_matches(hapd, buf, home_realm,
+						home_realm_len);
+	}
+}
+
+
+static void anqp_add_3gpp_cellular_network(struct hostapd_data *hapd,
+					   struct wpabuf *buf)
+{
+	if (hapd->conf->anqp_3gpp_cell_net) {
+		wpabuf_put_le16(buf, ANQP_3GPP_CELLULAR_NETWORK);
+		wpabuf_put_le16(buf,
+				hapd->conf->anqp_3gpp_cell_net_len);
+		wpabuf_put_data(buf, hapd->conf->anqp_3gpp_cell_net,
+				hapd->conf->anqp_3gpp_cell_net_len);
+	}
+}
+
+
+static void anqp_add_domain_name(struct hostapd_data *hapd, struct wpabuf *buf)
+{
+	if (hapd->conf->domain_name) {
+		wpabuf_put_le16(buf, ANQP_DOMAIN_NAME);
+		wpabuf_put_le16(buf, hapd->conf->domain_name_len);
+		wpabuf_put_data(buf, hapd->conf->domain_name,
+				hapd->conf->domain_name_len);
+	}
+}
+
+
+#ifdef CONFIG_HS20
+
+static void anqp_add_operator_friendly_name(struct hostapd_data *hapd,
+					    struct wpabuf *buf)
+{
+	if (hapd->conf->hs20_oper_friendly_name) {
+		u8 *len;
+		unsigned int i;
+		len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+		wpabuf_put_be24(buf, OUI_WFA);
+		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+		wpabuf_put_u8(buf, HS20_STYPE_OPERATOR_FRIENDLY_NAME);
+		wpabuf_put_u8(buf, 0); /* Reserved */
+		for (i = 0; i < hapd->conf->hs20_oper_friendly_name_count; i++)
+		{
+			struct hostapd_lang_string *vn;
+			vn = &hapd->conf->hs20_oper_friendly_name[i];
+			wpabuf_put_u8(buf, 3 + vn->name_len);
+			wpabuf_put_data(buf, vn->lang, 3);
+			wpabuf_put_data(buf, vn->name, vn->name_len);
+		}
+		gas_anqp_set_element_len(buf, len);
+	}
+}
+
+
+static void anqp_add_wan_metrics(struct hostapd_data *hapd,
+				 struct wpabuf *buf)
+{
+	if (hapd->conf->hs20_wan_metrics) {
+		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+		wpabuf_put_be24(buf, OUI_WFA);
+		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+		wpabuf_put_u8(buf, HS20_STYPE_WAN_METRICS);
+		wpabuf_put_u8(buf, 0); /* Reserved */
+		wpabuf_put_data(buf, hapd->conf->hs20_wan_metrics, 13);
+		gas_anqp_set_element_len(buf, len);
+	}
+}
+
+
+static void anqp_add_connection_capability(struct hostapd_data *hapd,
+					   struct wpabuf *buf)
+{
+	if (hapd->conf->hs20_connection_capability) {
+		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+		wpabuf_put_be24(buf, OUI_WFA);
+		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+		wpabuf_put_u8(buf, HS20_STYPE_CONNECTION_CAPABILITY);
+		wpabuf_put_u8(buf, 0); /* Reserved */
+		wpabuf_put_data(buf, hapd->conf->hs20_connection_capability,
+				hapd->conf->hs20_connection_capability_len);
+		gas_anqp_set_element_len(buf, len);
+	}
+}
+
+
+static void anqp_add_operating_class(struct hostapd_data *hapd,
+				     struct wpabuf *buf)
+{
+	if (hapd->conf->hs20_operating_class) {
+		u8 *len = gas_anqp_add_element(buf, ANQP_VENDOR_SPECIFIC);
+		wpabuf_put_be24(buf, OUI_WFA);
+		wpabuf_put_u8(buf, HS20_ANQP_OUI_TYPE);
+		wpabuf_put_u8(buf, HS20_STYPE_OPERATING_CLASS);
+		wpabuf_put_u8(buf, 0); /* Reserved */
+		wpabuf_put_data(buf, hapd->conf->hs20_operating_class,
+				hapd->conf->hs20_operating_class_len);
+		gas_anqp_set_element_len(buf, len);
+	}
+}
+
+#endif /* CONFIG_HS20 */
+
+
+static struct wpabuf *
+gas_serv_build_gas_resp_payload(struct hostapd_data *hapd,
+				unsigned int request,
+				struct gas_dialog_info *di,
+				const u8 *home_realm, size_t home_realm_len)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(1400);
+	if (buf == NULL)
+		return NULL;
+
+	if (request & ANQP_REQ_CAPABILITY_LIST)
+		anqp_add_capab_list(hapd, buf);
+	if (request & ANQP_REQ_VENUE_NAME)
+		anqp_add_venue_name(hapd, buf);
+	if (request & ANQP_REQ_NETWORK_AUTH_TYPE)
+		anqp_add_network_auth_type(hapd, buf);
+	if (request & ANQP_REQ_ROAMING_CONSORTIUM)
+		anqp_add_roaming_consortium(hapd, buf);
+	if (request & ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY)
+		anqp_add_ip_addr_type_availability(hapd, buf);
+	if (request & (ANQP_REQ_NAI_REALM | ANQP_REQ_NAI_HOME_REALM))
+		anqp_add_nai_realm(hapd, buf, home_realm, home_realm_len,
+				   request & ANQP_REQ_NAI_REALM,
+				   request & ANQP_REQ_NAI_HOME_REALM);
+	if (request & ANQP_REQ_3GPP_CELLULAR_NETWORK)
+		anqp_add_3gpp_cellular_network(hapd, buf);
+	if (request & ANQP_REQ_DOMAIN_NAME)
+		anqp_add_domain_name(hapd, buf);
+
+#ifdef CONFIG_HS20
+	if (request & ANQP_REQ_HS_CAPABILITY_LIST)
+		anqp_add_hs_capab_list(hapd, buf);
+	if (request & ANQP_REQ_OPERATOR_FRIENDLY_NAME)
+		anqp_add_operator_friendly_name(hapd, buf);
+	if (request & ANQP_REQ_WAN_METRICS)
+		anqp_add_wan_metrics(hapd, buf);
+	if (request & ANQP_REQ_CONNECTION_CAPABILITY)
+		anqp_add_connection_capability(hapd, buf);
+	if (request & ANQP_REQ_OPERATING_CLASS)
+		anqp_add_operating_class(hapd, buf);
+#endif /* CONFIG_HS20 */
+
+	return buf;
+}
+
+
+static void gas_serv_clear_cached_ies(void *eloop_data, void *user_ctx)
+{
+	struct gas_dialog_info *dia = eloop_data;
+
+	wpa_printf(MSG_DEBUG, "GAS: Timeout triggered, clearing dialog for "
+		   "dialog token %d", dia->dialog_token);
+
+	gas_serv_dialog_clear(dia);
+}
+
+
+struct anqp_query_info {
+	unsigned int request;
+	unsigned int remote_request;
+	const u8 *home_realm_query;
+	size_t home_realm_query_len;
+	u16 remote_delay;
+};
+
+
+static void set_anqp_req(unsigned int bit, const char *name, int local,
+			 unsigned int remote, u16 remote_delay,
+			 struct anqp_query_info *qi)
+{
+	qi->request |= bit;
+	if (local) {
+		wpa_printf(MSG_DEBUG, "ANQP: %s (local)", name);
+	} else if (bit & remote) {
+		wpa_printf(MSG_DEBUG, "ANQP: %s (remote)", name);
+		qi->remote_request |= bit;
+		if (remote_delay > qi->remote_delay)
+			qi->remote_delay = remote_delay;
+	} else {
+		wpa_printf(MSG_DEBUG, "ANQP: %s not available", name);
+	}
+}
+
+
+static void rx_anqp_query_list_id(struct hostapd_data *hapd, u16 info_id,
+				  struct anqp_query_info *qi)
+{
+	switch (info_id) {
+	case ANQP_CAPABILITY_LIST:
+		set_anqp_req(ANQP_REQ_CAPABILITY_LIST, "Capability List", 1, 0,
+			     0, qi);
+		break;
+	case ANQP_VENUE_NAME:
+		set_anqp_req(ANQP_REQ_VENUE_NAME, "Venue Name",
+			     hapd->conf->venue_name != NULL, 0, 0, qi);
+		break;
+	case ANQP_NETWORK_AUTH_TYPE:
+		set_anqp_req(ANQP_REQ_NETWORK_AUTH_TYPE, "Network Auth Type",
+			     hapd->conf->network_auth_type != NULL,
+			     0, 0, qi);
+		break;
+	case ANQP_ROAMING_CONSORTIUM:
+		set_anqp_req(ANQP_REQ_ROAMING_CONSORTIUM, "Roaming Consortium",
+			     hapd->conf->roaming_consortium != NULL, 0, 0, qi);
+		break;
+	case ANQP_IP_ADDR_TYPE_AVAILABILITY:
+		set_anqp_req(ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY,
+			     "IP Addr Type Availability",
+			     hapd->conf->ipaddr_type_configured,
+			     0, 0, qi);
+		break;
+	case ANQP_NAI_REALM:
+		set_anqp_req(ANQP_REQ_NAI_REALM, "NAI Realm",
+			     hapd->conf->nai_realm_data != NULL,
+			     0, 0, qi);
+		break;
+	case ANQP_3GPP_CELLULAR_NETWORK:
+		set_anqp_req(ANQP_REQ_3GPP_CELLULAR_NETWORK,
+			     "3GPP Cellular Network",
+			     hapd->conf->anqp_3gpp_cell_net != NULL,
+			     0, 0, qi);
+		break;
+	case ANQP_DOMAIN_NAME:
+		set_anqp_req(ANQP_REQ_DOMAIN_NAME, "Domain Name",
+			     hapd->conf->domain_name != NULL,
+			     0, 0, qi);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "ANQP: Unsupported Info Id %u",
+			   info_id);
+		break;
+	}
+}
+
+
+static void rx_anqp_query_list(struct hostapd_data *hapd,
+			       const u8 *pos, const u8 *end,
+			       struct anqp_query_info *qi)
+{
+	wpa_printf(MSG_DEBUG, "ANQP: %u Info IDs requested in Query list",
+		   (unsigned int) (end - pos) / 2);
+
+	while (pos + 2 <= end) {
+		rx_anqp_query_list_id(hapd, WPA_GET_LE16(pos), qi);
+		pos += 2;
+	}
+}
+
+
+#ifdef CONFIG_HS20
+
+static void rx_anqp_hs_query_list(struct hostapd_data *hapd, u8 subtype,
+				  struct anqp_query_info *qi)
+{
+	switch (subtype) {
+	case HS20_STYPE_CAPABILITY_LIST:
+		set_anqp_req(ANQP_REQ_HS_CAPABILITY_LIST, "HS Capability List",
+			     1, 0, 0, qi);
+		break;
+	case HS20_STYPE_OPERATOR_FRIENDLY_NAME:
+		set_anqp_req(ANQP_REQ_OPERATOR_FRIENDLY_NAME,
+			     "Operator Friendly Name",
+			     hapd->conf->hs20_oper_friendly_name != NULL,
+			     0, 0, qi);
+		break;
+	case HS20_STYPE_WAN_METRICS:
+		set_anqp_req(ANQP_REQ_WAN_METRICS, "WAN Metrics",
+			     hapd->conf->hs20_wan_metrics != NULL,
+			     0, 0, qi);
+		break;
+	case HS20_STYPE_CONNECTION_CAPABILITY:
+		set_anqp_req(ANQP_REQ_CONNECTION_CAPABILITY,
+			     "Connection Capability",
+			     hapd->conf->hs20_connection_capability != NULL,
+			     0, 0, qi);
+		break;
+	case HS20_STYPE_OPERATING_CLASS:
+		set_anqp_req(ANQP_REQ_OPERATING_CLASS, "Operating Class",
+			     hapd->conf->hs20_operating_class != NULL,
+			     0, 0, qi);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 subtype %u",
+			   subtype);
+		break;
+	}
+}
+
+
+static void rx_anqp_hs_nai_home_realm(struct hostapd_data *hapd,
+				      const u8 *pos, const u8 *end,
+				      struct anqp_query_info *qi)
+{
+	qi->request |= ANQP_REQ_NAI_HOME_REALM;
+	qi->home_realm_query = pos;
+	qi->home_realm_query_len = end - pos;
+	if (hapd->conf->nai_realm_data != NULL) {
+		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query "
+			   "(local)");
+	} else {
+		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 NAI Home Realm Query not "
+			   "available");
+	}
+}
+
+
+static void rx_anqp_vendor_specific(struct hostapd_data *hapd,
+				    const u8 *pos, const u8 *end,
+				    struct anqp_query_info *qi)
+{
+	u32 oui;
+	u8 subtype;
+
+	if (pos + 4 > end) {
+		wpa_printf(MSG_DEBUG, "ANQP: Too short vendor specific ANQP "
+			   "Query element");
+		return;
+	}
+
+	oui = WPA_GET_BE24(pos);
+	pos += 3;
+	if (oui != OUI_WFA) {
+		wpa_printf(MSG_DEBUG, "ANQP: Unsupported vendor OUI %06x",
+			   oui);
+		return;
+	}
+
+	if (*pos != HS20_ANQP_OUI_TYPE) {
+		wpa_printf(MSG_DEBUG, "ANQP: Unsupported WFA vendor type %u",
+			   *pos);
+		return;
+	}
+	pos++;
+
+	if (pos + 1 >= end)
+		return;
+
+	subtype = *pos++;
+	pos++; /* Reserved */
+	switch (subtype) {
+	case HS20_STYPE_QUERY_LIST:
+		wpa_printf(MSG_DEBUG, "ANQP: HS 2.0 Query List");
+		while (pos < end) {
+			rx_anqp_hs_query_list(hapd, *pos, qi);
+			pos++;
+		}
+		break;
+	case HS20_STYPE_NAI_HOME_REALM_QUERY:
+		rx_anqp_hs_nai_home_realm(hapd, pos, end, qi);
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "ANQP: Unsupported HS 2.0 query subtype "
+			   "%u", subtype);
+		break;
+	}
+}
+
+#endif /* CONFIG_HS20 */
+
+
+static void gas_serv_req_local_processing(struct hostapd_data *hapd,
+					  const u8 *sa, u8 dialog_token,
+					  struct anqp_query_info *qi)
+{
+	struct wpabuf *buf, *tx_buf;
+
+	buf = gas_serv_build_gas_resp_payload(hapd, qi->request, NULL,
+					      qi->home_realm_query,
+					      qi->home_realm_query_len);
+	wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Locally generated ANQP responses",
+			buf);
+	if (!buf)
+		return;
+
+	if (wpabuf_len(buf) > hapd->gas_frag_limit ||
+	    hapd->conf->gas_comeback_delay) {
+		struct gas_dialog_info *di;
+		u16 comeback_delay = 1;
+
+		if (hapd->conf->gas_comeback_delay) {
+			/* Testing - allow overriding of the delay value */
+			comeback_delay = hapd->conf->gas_comeback_delay;
+		}
+
+		wpa_printf(MSG_DEBUG, "ANQP: Too long response to fit in "
+			   "initial response - use GAS comeback");
+		di = gas_dialog_create(hapd, sa, dialog_token);
+		if (!di) {
+			wpa_printf(MSG_INFO, "ANQP: Could not create dialog "
+				   "for " MACSTR " (dialog token %u)",
+				   MAC2STR(sa), dialog_token);
+			wpabuf_free(buf);
+			return;
+		}
+		di->sd_resp = buf;
+		di->sd_resp_pos = 0;
+		tx_buf = gas_anqp_build_initial_resp_buf(
+			dialog_token, WLAN_STATUS_SUCCESS, comeback_delay,
+			NULL);
+	} else {
+		wpa_printf(MSG_DEBUG, "ANQP: Initial response (no comeback)");
+		tx_buf = gas_anqp_build_initial_resp_buf(
+			dialog_token, WLAN_STATUS_SUCCESS, 0, buf);
+		wpabuf_free(buf);
+	}
+	if (!tx_buf)
+		return;
+
+	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+	wpabuf_free(tx_buf);
+}
+
+
+static void gas_serv_rx_gas_initial_req(struct hostapd_data *hapd,
+					const u8 *sa,
+					const u8 *data, size_t len)
+{
+	const u8 *pos = data;
+	const u8 *end = data + len;
+	const u8 *next;
+	u8 dialog_token;
+	u16 slen;
+	struct anqp_query_info qi;
+	const u8 *adv_proto;
+
+	if (len < 1 + 2)
+		return;
+
+	os_memset(&qi, 0, sizeof(qi));
+
+	dialog_token = *pos++;
+	wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+		"GAS: GAS Initial Request from " MACSTR " (dialog token %u) ",
+		MAC2STR(sa), dialog_token);
+
+	if (*pos != WLAN_EID_ADV_PROTO) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+			"GAS: Unexpected IE in GAS Initial Request: %u", *pos);
+		return;
+	}
+	adv_proto = pos++;
+
+	slen = *pos++;
+	next = pos + slen;
+	if (next > end || slen < 2) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+			"GAS: Invalid IE in GAS Initial Request");
+		return;
+	}
+	pos++; /* skip QueryRespLenLimit and PAME-BI */
+
+	if (*pos != ACCESS_NETWORK_QUERY_PROTOCOL) {
+		struct wpabuf *buf;
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+			"GAS: Unsupported GAS advertisement protocol id %u",
+			*pos);
+		if (sa[0] & 0x01)
+			return; /* Invalid source address - drop silently */
+		buf = gas_build_initial_resp(
+			dialog_token, WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED,
+			0, 2 + slen + 2);
+		if (buf == NULL)
+			return;
+		wpabuf_put_data(buf, adv_proto, 2 + slen);
+		wpabuf_put_le16(buf, 0); /* Query Response Length */
+		hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+					wpabuf_head(buf), wpabuf_len(buf));
+		wpabuf_free(buf);
+		return;
+	}
+
+	pos = next;
+	/* Query Request */
+	if (pos + 2 > end)
+		return;
+	slen = WPA_GET_LE16(pos);
+	pos += 2;
+	if (pos + slen > end)
+		return;
+	end = pos + slen;
+
+	/* ANQP Query Request */
+	while (pos < end) {
+		u16 info_id, elen;
+
+		if (pos + 4 > end)
+			return;
+
+		info_id = WPA_GET_LE16(pos);
+		pos += 2;
+		elen = WPA_GET_LE16(pos);
+		pos += 2;
+
+		if (pos + elen > end) {
+			wpa_printf(MSG_DEBUG, "ANQP: Invalid Query Request");
+			return;
+		}
+
+		switch (info_id) {
+		case ANQP_QUERY_LIST:
+			rx_anqp_query_list(hapd, pos, pos + elen, &qi);
+			break;
+#ifdef CONFIG_HS20
+		case ANQP_VENDOR_SPECIFIC:
+			rx_anqp_vendor_specific(hapd, pos, pos + elen, &qi);
+			break;
+#endif /* CONFIG_HS20 */
+		default:
+			wpa_printf(MSG_DEBUG, "ANQP: Unsupported Query "
+				   "Request element %u", info_id);
+			break;
+		}
+
+		pos += elen;
+	}
+
+	gas_serv_req_local_processing(hapd, sa, dialog_token, &qi);
+}
+
+
+void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
+			      struct gas_dialog_info *dialog)
+{
+	struct wpabuf *buf, *tx_buf;
+	u8 dialog_token = dialog->dialog_token;
+	size_t frag_len;
+
+	if (dialog->sd_resp == NULL) {
+		buf = gas_serv_build_gas_resp_payload(hapd,
+						      dialog->all_requested,
+						      dialog, NULL, 0);
+		wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
+			buf);
+		if (!buf)
+			goto tx_gas_response_done;
+		dialog->sd_resp = buf;
+		dialog->sd_resp_pos = 0;
+	}
+	frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
+	if (frag_len > hapd->gas_frag_limit || dialog->comeback_delay ||
+	    hapd->conf->gas_comeback_delay) {
+		u16 comeback_delay_tus = dialog->comeback_delay +
+			GAS_SERV_COMEBACK_DELAY_FUDGE;
+		u32 comeback_delay_secs, comeback_delay_usecs;
+
+		if (hapd->conf->gas_comeback_delay) {
+			/* Testing - allow overriding of the delay value */
+			comeback_delay_tus = hapd->conf->gas_comeback_delay;
+		}
+
+		wpa_printf(MSG_DEBUG, "GAS: Response frag_len %u (frag limit "
+			   "%u) and comeback delay %u, "
+			   "requesting comebacks", (unsigned int) frag_len,
+			   (unsigned int) hapd->gas_frag_limit,
+			   dialog->comeback_delay);
+		tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
+							 WLAN_STATUS_SUCCESS,
+							 comeback_delay_tus,
+							 NULL);
+		if (tx_buf) {
+			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+				"GAS: Tx GAS Initial Resp (comeback = 10TU)");
+			hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
+						dst,
+						wpabuf_head(tx_buf),
+						wpabuf_len(tx_buf));
+		}
+		wpabuf_free(tx_buf);
+
+		/* start a timer of 1.5 * comeback-delay */
+		comeback_delay_tus = comeback_delay_tus +
+			(comeback_delay_tus / 2);
+		comeback_delay_secs = (comeback_delay_tus * 1024) / 1000000;
+		comeback_delay_usecs = (comeback_delay_tus * 1024) -
+			(comeback_delay_secs * 1000000);
+		eloop_register_timeout(comeback_delay_secs,
+				       comeback_delay_usecs,
+				       gas_serv_clear_cached_ies, dialog,
+				       NULL);
+		goto tx_gas_response_done;
+	}
+
+	buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
+				dialog->sd_resp_pos, frag_len);
+	if (buf == NULL) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Buffer allocation "
+			"failed");
+		goto tx_gas_response_done;
+	}
+	tx_buf = gas_anqp_build_initial_resp_buf(dialog_token,
+						 WLAN_STATUS_SUCCESS, 0, buf);
+	wpabuf_free(buf);
+	if (tx_buf == NULL)
+		goto tx_gas_response_done;
+	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Initial "
+		"Response (frag_id %d frag_len %d)",
+		dialog->sd_frag_id, (int) frag_len);
+	dialog->sd_frag_id++;
+
+	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, dst,
+				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+	wpabuf_free(tx_buf);
+tx_gas_response_done:
+	gas_serv_clear_cached_ies(dialog, NULL);
+}
+
+
+static void gas_serv_rx_gas_comeback_req(struct hostapd_data *hapd,
+					 const u8 *sa,
+					 const u8 *data, size_t len)
+{
+	struct gas_dialog_info *dialog;
+	struct wpabuf *buf, *tx_buf;
+	u8 dialog_token;
+	size_t frag_len;
+	int more = 0;
+
+	wpa_hexdump(MSG_DEBUG, "GAS: RX GAS Comeback Request", data, len);
+	if (len < 1)
+		return;
+	dialog_token = *data;
+	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Dialog Token: %u",
+		dialog_token);
+
+	dialog = gas_serv_dialog_find(hapd, sa, dialog_token);
+	if (!dialog) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: No pending SD "
+			"response fragment for " MACSTR " dialog token %u",
+			MAC2STR(sa), dialog_token);
+
+		if (sa[0] & 0x01)
+			return; /* Invalid source address - drop silently */
+		tx_buf = gas_anqp_build_comeback_resp_buf(
+			dialog_token, WLAN_STATUS_NO_OUTSTANDING_GAS_REQ, 0, 0,
+			0, NULL);
+		if (tx_buf == NULL)
+			return;
+		goto send_resp;
+	}
+
+	if (dialog->sd_resp == NULL) {
+		wpa_printf(MSG_DEBUG, "GAS: Remote request 0x%x received 0x%x",
+			   dialog->requested, dialog->received);
+		if ((dialog->requested & dialog->received) !=
+		    dialog->requested) {
+			wpa_printf(MSG_DEBUG, "GAS: Did not receive response "
+				   "from remote processing");
+			gas_serv_dialog_clear(dialog);
+			tx_buf = gas_anqp_build_comeback_resp_buf(
+				dialog_token,
+				WLAN_STATUS_GAS_RESP_NOT_RECEIVED, 0, 0, 0,
+				NULL);
+			if (tx_buf == NULL)
+				return;
+			goto send_resp;
+		}
+
+		buf = gas_serv_build_gas_resp_payload(hapd,
+						      dialog->all_requested,
+						      dialog, NULL, 0);
+		wpa_hexdump_buf(MSG_MSGDUMP, "ANQP: Generated ANQP responses",
+			buf);
+		if (!buf)
+			goto rx_gas_comeback_req_done;
+		dialog->sd_resp = buf;
+		dialog->sd_resp_pos = 0;
+	}
+	frag_len = wpabuf_len(dialog->sd_resp) - dialog->sd_resp_pos;
+	if (frag_len > hapd->gas_frag_limit) {
+		frag_len = hapd->gas_frag_limit;
+		more = 1;
+	}
+	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: resp frag_len %u",
+		(unsigned int) frag_len);
+	buf = wpabuf_alloc_copy(wpabuf_head_u8(dialog->sd_resp) +
+				dialog->sd_resp_pos, frag_len);
+	if (buf == NULL) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Failed to allocate "
+			"buffer");
+		goto rx_gas_comeback_req_done;
+	}
+	tx_buf = gas_anqp_build_comeback_resp_buf(dialog_token,
+						  WLAN_STATUS_SUCCESS,
+						  dialog->sd_frag_id,
+						  more, 0, buf);
+	wpabuf_free(buf);
+	if (tx_buf == NULL)
+		goto rx_gas_comeback_req_done;
+	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: Tx GAS Comeback Response "
+		"(frag_id %d more=%d frag_len=%d)",
+		dialog->sd_frag_id, more, (int) frag_len);
+	dialog->sd_frag_id++;
+	dialog->sd_resp_pos += frag_len;
+
+	if (more) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: %d more bytes remain "
+			"to be sent",
+			(int) (wpabuf_len(dialog->sd_resp) -
+			       dialog->sd_resp_pos));
+	} else {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "GAS: All fragments of "
+			"SD response sent");
+		gas_serv_dialog_clear(dialog);
+		gas_serv_free_dialogs(hapd, sa);
+	}
+
+send_resp:
+	hostapd_drv_send_action(hapd, hapd->iface->freq, 0, sa,
+				wpabuf_head(tx_buf), wpabuf_len(tx_buf));
+	wpabuf_free(tx_buf);
+	return;
+
+rx_gas_comeback_req_done:
+	gas_serv_clear_cached_ies(dialog, NULL);
+}
+
+
+static void gas_serv_rx_public_action(void *ctx, const u8 *buf, size_t len,
+				      int freq)
+{
+	struct hostapd_data *hapd = ctx;
+	const struct ieee80211_mgmt *mgmt;
+	size_t hdr_len;
+	const u8 *sa, *data;
+
+	mgmt = (const struct ieee80211_mgmt *) buf;
+	hdr_len = (const u8 *) &mgmt->u.action.u.vs_public_action.action - buf;
+	if (hdr_len > len)
+		return;
+	if (mgmt->u.action.category != WLAN_ACTION_PUBLIC)
+		return;
+	sa = mgmt->sa;
+	len -= hdr_len;
+	data = &mgmt->u.action.u.public_action.action;
+	switch (data[0]) {
+	case WLAN_PA_GAS_INITIAL_REQ:
+		gas_serv_rx_gas_initial_req(hapd, sa, data + 1, len - 1);
+		break;
+	case WLAN_PA_GAS_COMEBACK_REQ:
+		gas_serv_rx_gas_comeback_req(hapd, sa, data + 1, len - 1);
+		break;
+	}
+}
+
+
+int gas_serv_init(struct hostapd_data *hapd)
+{
+	hapd->public_action_cb = gas_serv_rx_public_action;
+	hapd->public_action_cb_ctx = hapd;
+	hapd->gas_frag_limit = 1400;
+	if (hapd->conf->gas_frag_limit > 0)
+		hapd->gas_frag_limit = hapd->conf->gas_frag_limit;
+	return 0;
+}
+
+
+void gas_serv_deinit(struct hostapd_data *hapd)
+{
+}
diff --git a/hostap/src/ap/gas_serv.h b/hostap/src/ap/gas_serv.h
new file mode 100644
index 0000000..4213cf6
--- /dev/null
+++ b/hostap/src/ap/gas_serv.h
@@ -0,0 +1,71 @@
+/*
+ * Generic advertisement service (GAS) server
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef GAS_SERV_H
+#define GAS_SERV_H
+
+#define ANQP_REQ_CAPABILITY_LIST \
+	(1 << (ANQP_CAPABILITY_LIST - ANQP_QUERY_LIST))
+#define ANQP_REQ_VENUE_NAME \
+	(1 << (ANQP_VENUE_NAME - ANQP_QUERY_LIST))
+#define ANQP_REQ_NETWORK_AUTH_TYPE \
+	(1 << (ANQP_NETWORK_AUTH_TYPE - ANQP_QUERY_LIST))
+#define ANQP_REQ_ROAMING_CONSORTIUM \
+	(1 << (ANQP_ROAMING_CONSORTIUM - ANQP_QUERY_LIST))
+#define ANQP_REQ_IP_ADDR_TYPE_AVAILABILITY \
+	(1 << (ANQP_IP_ADDR_TYPE_AVAILABILITY - ANQP_QUERY_LIST))
+#define ANQP_REQ_NAI_REALM \
+	(1 << (ANQP_NAI_REALM - ANQP_QUERY_LIST))
+#define ANQP_REQ_3GPP_CELLULAR_NETWORK \
+	(1 << (ANQP_3GPP_CELLULAR_NETWORK - ANQP_QUERY_LIST))
+#define ANQP_REQ_DOMAIN_NAME \
+	(1 << (ANQP_DOMAIN_NAME - ANQP_QUERY_LIST))
+#define ANQP_REQ_HS_CAPABILITY_LIST \
+	(0x10000 << HS20_STYPE_CAPABILITY_LIST)
+#define ANQP_REQ_OPERATOR_FRIENDLY_NAME \
+	(0x10000 << HS20_STYPE_OPERATOR_FRIENDLY_NAME)
+#define ANQP_REQ_WAN_METRICS \
+	(0x10000 << HS20_STYPE_WAN_METRICS)
+#define ANQP_REQ_CONNECTION_CAPABILITY \
+	(0x10000 << HS20_STYPE_CONNECTION_CAPABILITY)
+#define ANQP_REQ_NAI_HOME_REALM \
+	(0x10000 << HS20_STYPE_NAI_HOME_REALM_QUERY)
+#define ANQP_REQ_OPERATING_CLASS \
+	(0x10000 << HS20_STYPE_OPERATING_CLASS)
+
+/* To account for latencies between hostapd and external ANQP processor */
+#define GAS_SERV_COMEBACK_DELAY_FUDGE 10
+#define GAS_SERV_MIN_COMEBACK_DELAY 100 /* in TU */
+
+struct gas_dialog_info {
+	u8 valid;
+	u8 index;
+	struct wpabuf *sd_resp; /* Fragmented response */
+	u8 dialog_token;
+	size_t sd_resp_pos; /* Offset in sd_resp */
+	u8 sd_frag_id;
+	u16 comeback_delay;
+
+	unsigned int requested;
+	unsigned int received;
+	unsigned int all_requested;
+};
+
+struct hostapd_data;
+
+void gas_serv_tx_gas_response(struct hostapd_data *hapd, const u8 *dst,
+			      struct gas_dialog_info *dialog);
+struct gas_dialog_info *
+gas_serv_dialog_find(struct hostapd_data *hapd, const u8 *addr,
+		     u8 dialog_token);
+void gas_serv_dialog_clear(struct gas_dialog_info *dialog);
+
+int gas_serv_init(struct hostapd_data *hapd);
+void gas_serv_deinit(struct hostapd_data *hapd);
+
+#endif /* GAS_SERV_H */
diff --git a/hostap/src/ap/hostapd.c b/hostap/src/ap/hostapd.c
new file mode 100644
index 0000000..da2b76e
--- /dev/null
+++ b/hostap/src/ap/hostapd.c
@@ -0,0 +1,1434 @@
+/*
+ * hostapd / Initialization and configuration
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "radius/radius_client.h"
+#include "radius/radius_das.h"
+#include "drivers/driver.h"
+#include "hostapd.h"
+#include "authsrv.h"
+#include "sta_info.h"
+#include "accounting.h"
+#include "ap_list.h"
+#include "beacon.h"
+#include "iapp.h"
+#include "ieee802_1x.h"
+#include "ieee802_11_auth.h"
+#include "vlan_init.h"
+#include "wpa_auth.h"
+#include "wps_hostapd.h"
+#include "hw_features.h"
+#include "wpa_auth_glue.h"
+#include "ap_drv_ops.h"
+#include "ap_config.h"
+#include "p2p_hostapd.h"
+#include "gas_serv.h"
+
+
+static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason);
+static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd);
+static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd);
+
+extern int wpa_debug_level;
+extern struct wpa_driver_ops *wpa_drivers[];
+
+
+int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
+			       int (*cb)(struct hostapd_iface *iface,
+					 void *ctx), void *ctx)
+{
+	size_t i;
+	int ret;
+
+	for (i = 0; i < interfaces->count; i++) {
+		ret = cb(interfaces->iface[i], ctx);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+
+static void hostapd_reload_bss(struct hostapd_data *hapd)
+{
+#ifndef CONFIG_NO_RADIUS
+	radius_client_reconfig(hapd->radius, hapd->conf->radius);
+#endif /* CONFIG_NO_RADIUS */
+
+	if (hostapd_setup_wpa_psk(hapd->conf)) {
+		wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
+			   "after reloading configuration");
+	}
+
+	if (hapd->conf->ieee802_1x || hapd->conf->wpa)
+		hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1);
+	else
+		hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
+
+	if (hapd->conf->wpa && hapd->wpa_auth == NULL) {
+		hostapd_setup_wpa(hapd);
+		if (hapd->wpa_auth)
+			wpa_init_keys(hapd->wpa_auth);
+	} else if (hapd->conf->wpa) {
+		const u8 *wpa_ie;
+		size_t wpa_ie_len;
+		hostapd_reconfig_wpa(hapd);
+		wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len);
+		if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len))
+			wpa_printf(MSG_ERROR, "Failed to configure WPA IE for "
+				   "the kernel driver.");
+	} else if (hapd->wpa_auth) {
+		wpa_deinit(hapd->wpa_auth);
+		hapd->wpa_auth = NULL;
+		hostapd_set_privacy(hapd, 0);
+		hostapd_setup_encryption(hapd->conf->iface, hapd);
+		hostapd_set_generic_elem(hapd, (u8 *) "", 0);
+	}
+
+	ieee802_11_set_beacon(hapd);
+	hostapd_update_wps(hapd);
+
+	if (hapd->conf->ssid.ssid_set &&
+	    hostapd_set_ssid(hapd, hapd->conf->ssid.ssid,
+			     hapd->conf->ssid.ssid_len)) {
+		wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
+		/* try to continue */
+	}
+	wpa_printf(MSG_DEBUG, "Reconfigured interface %s", hapd->conf->iface);
+}
+
+
+int hostapd_reload_config(struct hostapd_iface *iface)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+	struct hostapd_config *newconf, *oldconf;
+	size_t j;
+
+	if (iface->interfaces == NULL ||
+	    iface->interfaces->config_read_cb == NULL)
+		return -1;
+	newconf = iface->interfaces->config_read_cb(iface->config_fname);
+	if (newconf == NULL)
+		return -1;
+
+	/*
+	 * Deauthenticate all stations since the new configuration may not
+	 * allow them to use the BSS anymore.
+	 */
+	for (j = 0; j < iface->num_bss; j++) {
+		hostapd_flush_old_stations(iface->bss[j],
+					   WLAN_REASON_PREV_AUTH_NOT_VALID);
+		hostapd_broadcast_wep_clear(iface->bss[j]);
+
+#ifndef CONFIG_NO_RADIUS
+		/* TODO: update dynamic data based on changed configuration
+		 * items (e.g., open/close sockets, etc.) */
+		radius_client_flush(iface->bss[j]->radius, 0);
+#endif /* CONFIG_NO_RADIUS */
+	}
+
+	oldconf = hapd->iconf;
+	iface->conf = newconf;
+
+	for (j = 0; j < iface->num_bss; j++) {
+		hapd = iface->bss[j];
+		hapd->iconf = newconf;
+		hapd->conf = &newconf->bss[j];
+		hostapd_reload_bss(hapd);
+	}
+
+	hostapd_config_free(oldconf);
+
+
+	return 0;
+}
+
+
+static void hostapd_broadcast_key_clear_iface(struct hostapd_data *hapd,
+					      char *ifname)
+{
+	int i;
+
+	for (i = 0; i < NUM_WEP_KEYS; i++) {
+		if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE, NULL, i,
+					0, NULL, 0, NULL, 0)) {
+			wpa_printf(MSG_DEBUG, "Failed to clear default "
+				   "encryption keys (ifname=%s keyidx=%d)",
+				   ifname, i);
+		}
+	}
+#ifdef CONFIG_IEEE80211W
+	if (hapd->conf->ieee80211w) {
+		for (i = NUM_WEP_KEYS; i < NUM_WEP_KEYS + 2; i++) {
+			if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_NONE,
+						NULL, i, 0, NULL,
+						0, NULL, 0)) {
+				wpa_printf(MSG_DEBUG, "Failed to clear "
+					   "default mgmt encryption keys "
+					   "(ifname=%s keyidx=%d)", ifname, i);
+			}
+		}
+	}
+#endif /* CONFIG_IEEE80211W */
+}
+
+
+static int hostapd_broadcast_wep_clear(struct hostapd_data *hapd)
+{
+	hostapd_broadcast_key_clear_iface(hapd, hapd->conf->iface);
+	return 0;
+}
+
+
+static int hostapd_broadcast_wep_set(struct hostapd_data *hapd)
+{
+	int errors = 0, idx;
+	struct hostapd_ssid *ssid = &hapd->conf->ssid;
+
+	idx = ssid->wep.idx;
+	if (ssid->wep.default_len &&
+	    hostapd_drv_set_key(hapd->conf->iface,
+				hapd, WPA_ALG_WEP, broadcast_ether_addr, idx,
+				1, NULL, 0, ssid->wep.key[idx],
+				ssid->wep.len[idx])) {
+		wpa_printf(MSG_WARNING, "Could not set WEP encryption.");
+		errors++;
+	}
+
+	if (ssid->dyn_vlan_keys) {
+		size_t i;
+		for (i = 0; i <= ssid->max_dyn_vlan_keys; i++) {
+			const char *ifname;
+			struct hostapd_wep_keys *key = ssid->dyn_vlan_keys[i];
+			if (key == NULL)
+				continue;
+			ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan,
+							    i);
+			if (ifname == NULL)
+				continue;
+
+			idx = key->idx;
+			if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP,
+						broadcast_ether_addr, idx, 1,
+						NULL, 0, key->key[idx],
+						key->len[idx])) {
+				wpa_printf(MSG_WARNING, "Could not set "
+					   "dynamic VLAN WEP encryption.");
+				errors++;
+			}
+		}
+	}
+
+	return errors;
+}
+
+
+static void hostapd_free_hapd_data(struct hostapd_data *hapd)
+{
+	iapp_deinit(hapd->iapp);
+	hapd->iapp = NULL;
+	accounting_deinit(hapd);
+	hostapd_deinit_wpa(hapd);
+	vlan_deinit(hapd);
+	hostapd_acl_deinit(hapd);
+#ifndef CONFIG_NO_RADIUS
+	radius_client_deinit(hapd->radius);
+	hapd->radius = NULL;
+	radius_das_deinit(hapd->radius_das);
+	hapd->radius_das = NULL;
+#endif /* CONFIG_NO_RADIUS */
+
+	hostapd_deinit_wps(hapd);
+
+	authsrv_deinit(hapd);
+
+	if (hapd->interface_added &&
+	    hostapd_if_remove(hapd, WPA_IF_AP_BSS, hapd->conf->iface)) {
+		wpa_printf(MSG_WARNING, "Failed to remove BSS interface %s",
+			   hapd->conf->iface);
+	}
+
+	os_free(hapd->probereq_cb);
+	hapd->probereq_cb = NULL;
+
+#ifdef CONFIG_P2P
+	wpabuf_free(hapd->p2p_beacon_ie);
+	hapd->p2p_beacon_ie = NULL;
+	wpabuf_free(hapd->p2p_probe_resp_ie);
+	hapd->p2p_probe_resp_ie = NULL;
+#endif /* CONFIG_P2P */
+
+	wpabuf_free(hapd->time_adv);
+
+#ifdef CONFIG_INTERWORKING
+	gas_serv_deinit(hapd);
+#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_SQLITE
+	os_free(hapd->tmp_eap_user.identity);
+	os_free(hapd->tmp_eap_user.password);
+#endif /* CONFIG_SQLITE */
+}
+
+
+/**
+ * hostapd_cleanup - Per-BSS cleanup (deinitialization)
+ * @hapd: Pointer to BSS data
+ *
+ * This function is used to free all per-BSS data structures and resources.
+ * This gets called in a loop for each BSS between calls to
+ * hostapd_cleanup_iface_pre() and hostapd_cleanup_iface() when an interface
+ * is deinitialized. Most of the modules that are initialized in
+ * hostapd_setup_bss() are deinitialized here.
+ */
+static void hostapd_cleanup(struct hostapd_data *hapd)
+{
+	if (hapd->iface->interfaces &&
+	    hapd->iface->interfaces->ctrl_iface_deinit)
+		hapd->iface->interfaces->ctrl_iface_deinit(hapd);
+	hostapd_free_hapd_data(hapd);
+}
+
+
+/**
+ * hostapd_cleanup_iface_pre - Preliminary per-interface cleanup
+ * @iface: Pointer to interface data
+ *
+ * This function is called before per-BSS data structures are deinitialized
+ * with hostapd_cleanup().
+ */
+static void hostapd_cleanup_iface_pre(struct hostapd_iface *iface)
+{
+}
+
+
+static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
+{
+	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
+	iface->hw_features = NULL;
+	os_free(iface->current_rates);
+	iface->current_rates = NULL;
+	os_free(iface->basic_rates);
+	iface->basic_rates = NULL;
+	ap_list_deinit(iface);
+}
+
+
+/**
+ * hostapd_cleanup_iface - Complete per-interface cleanup
+ * @iface: Pointer to interface data
+ *
+ * This function is called after per-BSS data structures are deinitialized
+ * with hostapd_cleanup().
+ */
+static void hostapd_cleanup_iface(struct hostapd_iface *iface)
+{
+	hostapd_cleanup_iface_partial(iface);
+	hostapd_config_free(iface->conf);
+	iface->conf = NULL;
+
+	os_free(iface->config_fname);
+	os_free(iface->bss);
+	os_free(iface);
+}
+
+
+static void hostapd_clear_wep(struct hostapd_data *hapd)
+{
+	if (hapd->drv_priv) {
+		hostapd_set_privacy(hapd, 0);
+		hostapd_broadcast_wep_clear(hapd);
+	}
+}
+
+
+static int hostapd_setup_encryption(char *iface, struct hostapd_data *hapd)
+{
+	int i;
+
+	hostapd_broadcast_wep_set(hapd);
+
+	if (hapd->conf->ssid.wep.default_len) {
+		hostapd_set_privacy(hapd, 1);
+		return 0;
+	}
+
+	/*
+	 * When IEEE 802.1X is not enabled, the driver may need to know how to
+	 * set authentication algorithms for static WEP.
+	 */
+	hostapd_drv_set_authmode(hapd, hapd->conf->auth_algs);
+
+	for (i = 0; i < 4; i++) {
+		if (hapd->conf->ssid.wep.key[i] &&
+		    hostapd_drv_set_key(iface, hapd, WPA_ALG_WEP, NULL, i,
+					i == hapd->conf->ssid.wep.idx, NULL, 0,
+					hapd->conf->ssid.wep.key[i],
+					hapd->conf->ssid.wep.len[i])) {
+			wpa_printf(MSG_WARNING, "Could not set WEP "
+				   "encryption.");
+			return -1;
+		}
+		if (hapd->conf->ssid.wep.key[i] &&
+		    i == hapd->conf->ssid.wep.idx)
+			hostapd_set_privacy(hapd, 1);
+	}
+
+	return 0;
+}
+
+
+static int hostapd_flush_old_stations(struct hostapd_data *hapd, u16 reason)
+{
+	int ret = 0;
+	u8 addr[ETH_ALEN];
+
+	if (hostapd_drv_none(hapd) || hapd->drv_priv == NULL)
+		return 0;
+
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Flushing old station entries");
+	if (hostapd_flush(hapd)) {
+		wpa_msg(hapd->msg_ctx, MSG_WARNING, "Could not connect to "
+			"kernel driver");
+		ret = -1;
+	}
+	wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "Deauthenticate all stations");
+	os_memset(addr, 0xff, ETH_ALEN);
+	hostapd_drv_sta_deauth(hapd, addr, reason);
+	hostapd_free_stas(hapd);
+
+	return ret;
+}
+
+
+/**
+ * hostapd_validate_bssid_configuration - Validate BSSID configuration
+ * @iface: Pointer to interface data
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to validate that the configured BSSIDs are valid.
+ */
+static int hostapd_validate_bssid_configuration(struct hostapd_iface *iface)
+{
+	u8 mask[ETH_ALEN] = { 0 };
+	struct hostapd_data *hapd = iface->bss[0];
+	unsigned int i = iface->conf->num_bss, bits = 0, j;
+	int auto_addr = 0;
+
+	if (hostapd_drv_none(hapd))
+		return 0;
+
+	/* Generate BSSID mask that is large enough to cover the BSSIDs. */
+
+	/* Determine the bits necessary to cover the number of BSSIDs. */
+	for (i--; i; i >>= 1)
+		bits++;
+
+	/* Determine the bits necessary to any configured BSSIDs,
+	   if they are higher than the number of BSSIDs. */
+	for (j = 0; j < iface->conf->num_bss; j++) {
+		if (hostapd_mac_comp_empty(iface->conf->bss[j].bssid) == 0) {
+			if (j)
+				auto_addr++;
+			continue;
+		}
+
+		for (i = 0; i < ETH_ALEN; i++) {
+			mask[i] |=
+				iface->conf->bss[j].bssid[i] ^
+				hapd->own_addr[i];
+		}
+	}
+
+	if (!auto_addr)
+		goto skip_mask_ext;
+
+	for (i = 0; i < ETH_ALEN && mask[i] == 0; i++)
+		;
+	j = 0;
+	if (i < ETH_ALEN) {
+		j = (5 - i) * 8;
+
+		while (mask[i] != 0) {
+			mask[i] >>= 1;
+			j++;
+		}
+	}
+
+	if (bits < j)
+		bits = j;
+
+	if (bits > 40) {
+		wpa_printf(MSG_ERROR, "Too many bits in the BSSID mask (%u)",
+			   bits);
+		return -1;
+	}
+
+	os_memset(mask, 0xff, ETH_ALEN);
+	j = bits / 8;
+	for (i = 5; i > 5 - j; i--)
+		mask[i] = 0;
+	j = bits % 8;
+	while (j--)
+		mask[i] <<= 1;
+
+skip_mask_ext:
+	wpa_printf(MSG_DEBUG, "BSS count %lu, BSSID mask " MACSTR " (%d bits)",
+		   (unsigned long) iface->conf->num_bss, MAC2STR(mask), bits);
+
+	if (!auto_addr)
+		return 0;
+
+	for (i = 0; i < ETH_ALEN; i++) {
+		if ((hapd->own_addr[i] & mask[i]) != hapd->own_addr[i]) {
+			wpa_printf(MSG_ERROR, "Invalid BSSID mask " MACSTR
+				   " for start address " MACSTR ".",
+				   MAC2STR(mask), MAC2STR(hapd->own_addr));
+			wpa_printf(MSG_ERROR, "Start address must be the "
+				   "first address in the block (i.e., addr "
+				   "AND mask == addr).");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static int mac_in_conf(struct hostapd_config *conf, const void *a)
+{
+	size_t i;
+
+	for (i = 0; i < conf->num_bss; i++) {
+		if (hostapd_mac_comp(conf->bss[i].bssid, a) == 0) {
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+
+#ifndef CONFIG_NO_RADIUS
+
+static int hostapd_das_nas_mismatch(struct hostapd_data *hapd,
+				    struct radius_das_attrs *attr)
+{
+	/* TODO */
+	return 0;
+}
+
+
+static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
+					      struct radius_das_attrs *attr)
+{
+	struct sta_info *sta = NULL;
+	char buf[128];
+
+	if (attr->sta_addr)
+		sta = ap_get_sta(hapd, attr->sta_addr);
+
+	if (sta == NULL && attr->acct_session_id &&
+	    attr->acct_session_id_len == 17) {
+		for (sta = hapd->sta_list; sta; sta = sta->next) {
+			os_snprintf(buf, sizeof(buf), "%08X-%08X",
+				    sta->acct_session_id_hi,
+				    sta->acct_session_id_lo);
+			if (os_memcmp(attr->acct_session_id, buf, 17) == 0)
+				break;
+		}
+	}
+
+	if (sta == NULL && attr->cui) {
+		for (sta = hapd->sta_list; sta; sta = sta->next) {
+			struct wpabuf *cui;
+			cui = ieee802_1x_get_radius_cui(sta->eapol_sm);
+			if (cui && wpabuf_len(cui) == attr->cui_len &&
+			    os_memcmp(wpabuf_head(cui), attr->cui,
+				      attr->cui_len) == 0)
+				break;
+		}
+	}
+
+	if (sta == NULL && attr->user_name) {
+		for (sta = hapd->sta_list; sta; sta = sta->next) {
+			u8 *identity;
+			size_t identity_len;
+			identity = ieee802_1x_get_identity(sta->eapol_sm,
+							   &identity_len);
+			if (identity &&
+			    identity_len == attr->user_name_len &&
+			    os_memcmp(identity, attr->user_name, identity_len)
+			    == 0)
+				break;
+		}
+	}
+
+	return sta;
+}
+
+
+static enum radius_das_res
+hostapd_das_disconnect(void *ctx, struct radius_das_attrs *attr)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	if (hostapd_das_nas_mismatch(hapd, attr))
+		return RADIUS_DAS_NAS_MISMATCH;
+
+	sta = hostapd_das_find_sta(hapd, attr);
+	if (sta == NULL)
+		return RADIUS_DAS_SESSION_NOT_FOUND;
+
+	hostapd_drv_sta_deauth(hapd, sta->addr,
+			       WLAN_REASON_PREV_AUTH_NOT_VALID);
+	ap_sta_deauthenticate(hapd, sta, WLAN_REASON_PREV_AUTH_NOT_VALID);
+
+	return RADIUS_DAS_SUCCESS;
+}
+
+#endif /* CONFIG_NO_RADIUS */
+
+
+/**
+ * hostapd_setup_bss - Per-BSS setup (initialization)
+ * @hapd: Pointer to BSS data
+ * @first: Whether this BSS is the first BSS of an interface
+ *
+ * This function is used to initialize all per-BSS data structures and
+ * resources. This gets called in a loop for each BSS when an interface is
+ * initialized. Most of the modules that are initialized here will be
+ * deinitialized in hostapd_cleanup().
+ */
+static int hostapd_setup_bss(struct hostapd_data *hapd, int first)
+{
+	struct hostapd_bss_config *conf = hapd->conf;
+	u8 ssid[HOSTAPD_MAX_SSID_LEN + 1];
+	int ssid_len, set_ssid;
+	char force_ifname[IFNAMSIZ];
+	u8 if_addr[ETH_ALEN];
+
+	if (!first) {
+		if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0) {
+			/* Allocate the next available BSSID. */
+			do {
+				inc_byte_array(hapd->own_addr, ETH_ALEN);
+			} while (mac_in_conf(hapd->iconf, hapd->own_addr));
+		} else {
+			/* Allocate the configured BSSID. */
+			os_memcpy(hapd->own_addr, hapd->conf->bssid, ETH_ALEN);
+
+			if (hostapd_mac_comp(hapd->own_addr,
+					     hapd->iface->bss[0]->own_addr) ==
+			    0) {
+				wpa_printf(MSG_ERROR, "BSS '%s' may not have "
+					   "BSSID set to the MAC address of "
+					   "the radio", hapd->conf->iface);
+				return -1;
+			}
+		}
+
+		hapd->interface_added = 1;
+		if (hostapd_if_add(hapd->iface->bss[0], WPA_IF_AP_BSS,
+				   hapd->conf->iface, hapd->own_addr, hapd,
+				   &hapd->drv_priv, force_ifname, if_addr,
+				   hapd->conf->bridge[0] ? hapd->conf->bridge :
+				   NULL)) {
+			wpa_printf(MSG_ERROR, "Failed to add BSS (BSSID="
+				   MACSTR ")", MAC2STR(hapd->own_addr));
+			return -1;
+		}
+	}
+
+	if (conf->wmm_enabled < 0)
+		conf->wmm_enabled = hapd->iconf->ieee80211n;
+
+	hostapd_flush_old_stations(hapd, WLAN_REASON_PREV_AUTH_NOT_VALID);
+	hostapd_set_privacy(hapd, 0);
+
+	hostapd_broadcast_wep_clear(hapd);
+	if (hostapd_setup_encryption(hapd->conf->iface, hapd))
+		return -1;
+
+	/*
+	 * Fetch the SSID from the system and use it or,
+	 * if one was specified in the config file, verify they
+	 * match.
+	 */
+	ssid_len = hostapd_get_ssid(hapd, ssid, sizeof(ssid));
+	if (ssid_len < 0) {
+		wpa_printf(MSG_ERROR, "Could not read SSID from system");
+		return -1;
+	}
+	if (conf->ssid.ssid_set) {
+		/*
+		 * If SSID is specified in the config file and it differs
+		 * from what is being used then force installation of the
+		 * new SSID.
+		 */
+		set_ssid = (conf->ssid.ssid_len != (size_t) ssid_len ||
+			    os_memcmp(conf->ssid.ssid, ssid, ssid_len) != 0);
+	} else {
+		/*
+		 * No SSID in the config file; just use the one we got
+		 * from the system.
+		 */
+		set_ssid = 0;
+		conf->ssid.ssid_len = ssid_len;
+		os_memcpy(conf->ssid.ssid, ssid, conf->ssid.ssid_len);
+	}
+
+	if (!hostapd_drv_none(hapd)) {
+		wpa_printf(MSG_ERROR, "Using interface %s with hwaddr " MACSTR
+			   " and ssid \"%s\"",
+			   hapd->conf->iface, MAC2STR(hapd->own_addr),
+			   wpa_ssid_txt(hapd->conf->ssid.ssid,
+					hapd->conf->ssid.ssid_len));
+	}
+
+	if (hostapd_setup_wpa_psk(conf)) {
+		wpa_printf(MSG_ERROR, "WPA-PSK setup failed.");
+		return -1;
+	}
+
+	/* Set SSID for the kernel driver (to be used in beacon and probe
+	 * response frames) */
+	if (set_ssid && hostapd_set_ssid(hapd, conf->ssid.ssid,
+					 conf->ssid.ssid_len)) {
+		wpa_printf(MSG_ERROR, "Could not set SSID for kernel driver");
+		return -1;
+	}
+
+	if (wpa_debug_level == MSG_MSGDUMP)
+		conf->radius->msg_dumps = 1;
+#ifndef CONFIG_NO_RADIUS
+	hapd->radius = radius_client_init(hapd, conf->radius);
+	if (hapd->radius == NULL) {
+		wpa_printf(MSG_ERROR, "RADIUS client initialization failed.");
+		return -1;
+	}
+
+	if (hapd->conf->radius_das_port) {
+		struct radius_das_conf das_conf;
+		os_memset(&das_conf, 0, sizeof(das_conf));
+		das_conf.port = hapd->conf->radius_das_port;
+		das_conf.shared_secret = hapd->conf->radius_das_shared_secret;
+		das_conf.shared_secret_len =
+			hapd->conf->radius_das_shared_secret_len;
+		das_conf.client_addr = &hapd->conf->radius_das_client_addr;
+		das_conf.time_window = hapd->conf->radius_das_time_window;
+		das_conf.require_event_timestamp =
+			hapd->conf->radius_das_require_event_timestamp;
+		das_conf.ctx = hapd;
+		das_conf.disconnect = hostapd_das_disconnect;
+		hapd->radius_das = radius_das_init(&das_conf);
+		if (hapd->radius_das == NULL) {
+			wpa_printf(MSG_ERROR, "RADIUS DAS initialization "
+				   "failed.");
+			return -1;
+		}
+	}
+#endif /* CONFIG_NO_RADIUS */
+
+	if (hostapd_acl_init(hapd)) {
+		wpa_printf(MSG_ERROR, "ACL initialization failed.");
+		return -1;
+	}
+	if (hostapd_init_wps(hapd, conf))
+		return -1;
+
+	if (authsrv_init(hapd) < 0)
+		return -1;
+
+	if (ieee802_1x_init(hapd)) {
+		wpa_printf(MSG_ERROR, "IEEE 802.1X initialization failed.");
+		return -1;
+	}
+
+	if (hapd->conf->wpa && hostapd_setup_wpa(hapd))
+		return -1;
+
+	if (accounting_init(hapd)) {
+		wpa_printf(MSG_ERROR, "Accounting initialization failed.");
+		return -1;
+	}
+
+	if (hapd->conf->ieee802_11f &&
+	    (hapd->iapp = iapp_init(hapd, hapd->conf->iapp_iface)) == NULL) {
+		wpa_printf(MSG_ERROR, "IEEE 802.11F (IAPP) initialization "
+			   "failed.");
+		return -1;
+	}
+
+#ifdef CONFIG_INTERWORKING
+	if (gas_serv_init(hapd)) {
+		wpa_printf(MSG_ERROR, "GAS server initialization failed");
+		return -1;
+	}
+#endif /* CONFIG_INTERWORKING */
+
+	if (hapd->iface->interfaces &&
+	    hapd->iface->interfaces->ctrl_iface_init &&
+	    hapd->iface->interfaces->ctrl_iface_init(hapd)) {
+		wpa_printf(MSG_ERROR, "Failed to setup control interface");
+		return -1;
+	}
+
+	if (!hostapd_drv_none(hapd) && vlan_init(hapd)) {
+		wpa_printf(MSG_ERROR, "VLAN initialization failed.");
+		return -1;
+	}
+
+	ieee802_11_set_beacon(hapd);
+
+	if (hapd->wpa_auth && wpa_init_keys(hapd->wpa_auth) < 0)
+		return -1;
+
+	if (hapd->driver && hapd->driver->set_operstate)
+		hapd->driver->set_operstate(hapd->drv_priv, 1);
+
+	return 0;
+}
+
+
+static void hostapd_tx_queue_params(struct hostapd_iface *iface)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+	int i;
+	struct hostapd_tx_queue_params *p;
+
+	for (i = 0; i < NUM_TX_QUEUES; i++) {
+		p = &iface->conf->tx_queue[i];
+
+		if (hostapd_set_tx_queue_params(hapd, i, p->aifs, p->cwmin,
+						p->cwmax, p->burst)) {
+			wpa_printf(MSG_DEBUG, "Failed to set TX queue "
+				   "parameters for queue %d.", i);
+			/* Continue anyway */
+		}
+	}
+}
+
+
+static int setup_interface(struct hostapd_iface *iface)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+	size_t i;
+	char country[4];
+
+	/*
+	 * Make sure that all BSSes get configured with a pointer to the same
+	 * driver interface.
+	 */
+	for (i = 1; i < iface->num_bss; i++) {
+		iface->bss[i]->driver = hapd->driver;
+		iface->bss[i]->drv_priv = hapd->drv_priv;
+	}
+
+	if (hostapd_validate_bssid_configuration(iface))
+		return -1;
+
+	if (hapd->iconf->country[0] && hapd->iconf->country[1]) {
+		os_memcpy(country, hapd->iconf->country, 3);
+		country[3] = '\0';
+		if (hostapd_set_country(hapd, country) < 0) {
+			wpa_printf(MSG_ERROR, "Failed to set country code");
+			return -1;
+		}
+	}
+
+	if (hostapd_get_hw_features(iface)) {
+		/* Not all drivers support this yet, so continue without hw
+		 * feature data. */
+	} else {
+		int ret = hostapd_select_hw_mode(iface);
+		if (ret < 0) {
+			wpa_printf(MSG_ERROR, "Could not select hw_mode and "
+				   "channel. (%d)", ret);
+			return -1;
+		}
+		ret = hostapd_check_ht_capab(iface);
+		if (ret < 0)
+			return -1;
+		if (ret == 1) {
+			wpa_printf(MSG_DEBUG, "Interface initialization will "
+				   "be completed in a callback");
+			return 0;
+		}
+	}
+	return hostapd_setup_interface_complete(iface, 0);
+}
+
+
+int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+	size_t j;
+	u8 *prev_addr;
+
+	if (err) {
+		wpa_printf(MSG_ERROR, "Interface initialization failed");
+		eloop_terminate();
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "Completing interface initialization");
+	if (hapd->iconf->channel) {
+		iface->freq = hostapd_hw_get_freq(hapd, hapd->iconf->channel);
+		wpa_printf(MSG_DEBUG, "Mode: %s  Channel: %d  "
+			   "Frequency: %d MHz",
+			   hostapd_hw_mode_txt(hapd->iconf->hw_mode),
+			   hapd->iconf->channel, iface->freq);
+
+		if (hostapd_set_freq(hapd, hapd->iconf->hw_mode, iface->freq,
+				     hapd->iconf->channel,
+				     hapd->iconf->ieee80211n,
+				     hapd->iconf->secondary_channel)) {
+			wpa_printf(MSG_ERROR, "Could not set channel for "
+				   "kernel driver");
+			return -1;
+		}
+	}
+
+	if (iface->current_mode) {
+		if (hostapd_prepare_rates(iface, iface->current_mode)) {
+			wpa_printf(MSG_ERROR, "Failed to prepare rates "
+				   "table.");
+			hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_WARNING,
+				       "Failed to prepare rates table.");
+			return -1;
+		}
+	}
+
+	if (hapd->iconf->rts_threshold > -1 &&
+	    hostapd_set_rts(hapd, hapd->iconf->rts_threshold)) {
+		wpa_printf(MSG_ERROR, "Could not set RTS threshold for "
+			   "kernel driver");
+		return -1;
+	}
+
+	if (hapd->iconf->fragm_threshold > -1 &&
+	    hostapd_set_frag(hapd, hapd->iconf->fragm_threshold)) {
+		wpa_printf(MSG_ERROR, "Could not set fragmentation threshold "
+			   "for kernel driver");
+		return -1;
+	}
+
+	prev_addr = hapd->own_addr;
+
+	for (j = 0; j < iface->num_bss; j++) {
+		hapd = iface->bss[j];
+		if (j)
+			os_memcpy(hapd->own_addr, prev_addr, ETH_ALEN);
+		if (hostapd_setup_bss(hapd, j == 0))
+			return -1;
+		if (hostapd_mac_comp_empty(hapd->conf->bssid) == 0)
+			prev_addr = hapd->own_addr;
+	}
+
+	hostapd_tx_queue_params(iface);
+
+	ap_list_init(iface);
+
+	if (hostapd_driver_commit(hapd) < 0) {
+		wpa_printf(MSG_ERROR, "%s: Failed to commit driver "
+			   "configuration", __func__);
+		return -1;
+	}
+
+	/*
+	 * WPS UPnP module can be initialized only when the "upnp_iface" is up.
+	 * If "interface" and "upnp_iface" are the same (e.g., non-bridge
+	 * mode), the interface is up only after driver_commit, so initialize
+	 * WPS after driver_commit.
+	 */
+	for (j = 0; j < iface->num_bss; j++) {
+		if (hostapd_init_wps_complete(iface->bss[j]))
+			return -1;
+	}
+
+	if (hapd->setup_complete_cb)
+		hapd->setup_complete_cb(hapd->setup_complete_cb_ctx);
+
+	wpa_printf(MSG_DEBUG, "%s: Setup of interface done.",
+		   iface->bss[0]->conf->iface);
+
+	return 0;
+}
+
+
+/**
+ * hostapd_setup_interface - Setup of an interface
+ * @iface: Pointer to interface data.
+ * Returns: 0 on success, -1 on failure
+ *
+ * Initializes the driver interface, validates the configuration,
+ * and sets driver parameters based on the configuration.
+ * Flushes old stations, sets the channel, encryption,
+ * beacons, and WDS links based on the configuration.
+ */
+int hostapd_setup_interface(struct hostapd_iface *iface)
+{
+	int ret;
+
+	ret = setup_interface(iface);
+	if (ret) {
+		wpa_printf(MSG_ERROR, "%s: Unable to setup interface.",
+			   iface->bss[0]->conf->iface);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * hostapd_alloc_bss_data - Allocate and initialize per-BSS data
+ * @hapd_iface: Pointer to interface data
+ * @conf: Pointer to per-interface configuration
+ * @bss: Pointer to per-BSS configuration for this BSS
+ * Returns: Pointer to allocated BSS data
+ *
+ * This function is used to allocate per-BSS data structure. This data will be
+ * freed after hostapd_cleanup() is called for it during interface
+ * deinitialization.
+ */
+struct hostapd_data *
+hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
+		       struct hostapd_config *conf,
+		       struct hostapd_bss_config *bss)
+{
+	struct hostapd_data *hapd;
+
+	hapd = os_zalloc(sizeof(*hapd));
+	if (hapd == NULL)
+		return NULL;
+
+	hapd->new_assoc_sta_cb = hostapd_new_assoc_sta;
+	hapd->iconf = conf;
+	hapd->conf = bss;
+	hapd->iface = hapd_iface;
+	hapd->driver = hapd->iconf->driver;
+	hapd->ctrl_sock = -1;
+
+	return hapd;
+}
+
+
+void hostapd_interface_deinit(struct hostapd_iface *iface)
+{
+	size_t j;
+
+	if (iface == NULL)
+		return;
+
+	hostapd_cleanup_iface_pre(iface);
+	for (j = 0; j < iface->num_bss; j++) {
+		struct hostapd_data *hapd = iface->bss[j];
+		hostapd_free_stas(hapd);
+		hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+		hostapd_clear_wep(hapd);
+		hostapd_cleanup(hapd);
+	}
+}
+
+
+void hostapd_interface_free(struct hostapd_iface *iface)
+{
+	size_t j;
+	for (j = 0; j < iface->num_bss; j++)
+		os_free(iface->bss[j]);
+	hostapd_cleanup_iface(iface);
+}
+
+
+#ifdef HOSTAPD
+
+void hostapd_interface_deinit_free(struct hostapd_iface *iface)
+{
+	const struct wpa_driver_ops *driver;
+	void *drv_priv;
+	if (iface == NULL)
+		return;
+	driver = iface->bss[0]->driver;
+	drv_priv = iface->bss[0]->drv_priv;
+	hostapd_interface_deinit(iface);
+	if (driver && driver->hapd_deinit && drv_priv)
+		driver->hapd_deinit(drv_priv);
+	hostapd_interface_free(iface);
+}
+
+
+int hostapd_enable_iface(struct hostapd_iface *hapd_iface)
+{
+	if (hapd_iface->bss[0]->drv_priv != NULL) {
+		wpa_printf(MSG_ERROR, "Interface %s already enabled",
+			   hapd_iface->conf->bss[0].iface);
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "Enable interface %s",
+		   hapd_iface->conf->bss[0].iface);
+
+	if (hapd_iface->interfaces == NULL ||
+	    hapd_iface->interfaces->driver_init == NULL ||
+	    hapd_iface->interfaces->driver_init(hapd_iface) ||
+	    hostapd_setup_interface(hapd_iface)) {
+		hostapd_interface_deinit_free(hapd_iface);
+		return -1;
+	}
+	return 0;
+}
+
+
+int hostapd_reload_iface(struct hostapd_iface *hapd_iface)
+{
+	size_t j;
+
+	wpa_printf(MSG_DEBUG, "Reload interface %s",
+		   hapd_iface->conf->bss[0].iface);
+	for (j = 0; j < hapd_iface->num_bss; j++) {
+		hostapd_flush_old_stations(hapd_iface->bss[j],
+					   WLAN_REASON_PREV_AUTH_NOT_VALID);
+
+#ifndef CONFIG_NO_RADIUS
+		/* TODO: update dynamic data based on changed configuration
+		 * items (e.g., open/close sockets, etc.) */
+		radius_client_flush(hapd_iface->bss[j]->radius, 0);
+#endif  /* CONFIG_NO_RADIUS */
+
+		hostapd_reload_bss(hapd_iface->bss[j]);
+	}
+	return 0;
+}
+
+
+int hostapd_disable_iface(struct hostapd_iface *hapd_iface)
+{
+	size_t j;
+	struct hostapd_bss_config *bss;
+	const struct wpa_driver_ops *driver;
+	void *drv_priv;
+
+	if (hapd_iface == NULL)
+		return -1;
+	bss = hapd_iface->bss[0]->conf;
+	driver = hapd_iface->bss[0]->driver;
+	drv_priv = hapd_iface->bss[0]->drv_priv;
+
+	/* whatever hostapd_interface_deinit does */
+	for (j = 0; j < hapd_iface->num_bss; j++) {
+		struct hostapd_data *hapd = hapd_iface->bss[j];
+		hostapd_free_stas(hapd);
+		hostapd_flush_old_stations(hapd, WLAN_REASON_DEAUTH_LEAVING);
+		hostapd_clear_wep(hapd);
+		hostapd_free_hapd_data(hapd);
+	}
+
+	if (driver && driver->hapd_deinit && drv_priv) {
+		driver->hapd_deinit(drv_priv);
+		hapd_iface->bss[0]->drv_priv = NULL;
+	}
+
+	/* From hostapd_cleanup_iface: These were initialized in
+	 * hostapd_setup_interface and hostapd_setup_interface_complete
+	 */
+	hostapd_cleanup_iface_partial(hapd_iface);
+	bss->wpa = 0;
+	bss->wpa_key_mgmt = -1;
+	bss->wpa_pairwise = -1;
+
+	wpa_printf(MSG_DEBUG, "Interface %s disabled", bss->iface);
+	return 0;
+}
+
+
+static struct hostapd_iface *
+hostapd_iface_alloc(struct hapd_interfaces *interfaces)
+{
+	struct hostapd_iface **iface, *hapd_iface;
+
+	iface = os_realloc_array(interfaces->iface, interfaces->count + 1,
+				 sizeof(struct hostapd_iface *));
+	if (iface == NULL)
+		return NULL;
+	interfaces->iface = iface;
+	hapd_iface = interfaces->iface[interfaces->count] =
+		os_zalloc(sizeof(*hapd_iface));
+	if (hapd_iface == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
+			   "the interface", __func__);
+		return NULL;
+	}
+	interfaces->count++;
+	hapd_iface->interfaces = interfaces;
+
+	return hapd_iface;
+}
+
+
+static struct hostapd_config *
+hostapd_config_alloc(struct hapd_interfaces *interfaces, const char *ifname,
+		     const char *ctrl_iface)
+{
+	struct hostapd_bss_config *bss;
+	struct hostapd_config *conf;
+
+	/* Allocates memory for bss and conf */
+	conf = hostapd_config_defaults();
+	if (conf == NULL) {
+		 wpa_printf(MSG_ERROR, "%s: Failed to allocate memory for "
+				"configuration", __func__);
+		return NULL;
+	}
+
+	conf->driver = wpa_drivers[0];
+	if (conf->driver == NULL) {
+		wpa_printf(MSG_ERROR, "No driver wrappers registered!");
+		hostapd_config_free(conf);
+		return NULL;
+	}
+
+	bss = conf->last_bss = conf->bss;
+
+	os_strlcpy(bss->iface, ifname, sizeof(bss->iface));
+	bss->ctrl_interface = os_strdup(ctrl_iface);
+	if (bss->ctrl_interface == NULL) {
+		hostapd_config_free(conf);
+		return NULL;
+	}
+
+	/* Reading configuration file skipped, will be done in SET!
+	 * From reading the configuration till the end has to be done in
+	 * SET
+	 */
+	return conf;
+}
+
+
+static struct hostapd_iface * hostapd_data_alloc(
+	struct hapd_interfaces *interfaces, struct hostapd_config *conf)
+{
+	size_t i;
+	struct hostapd_iface *hapd_iface =
+		interfaces->iface[interfaces->count - 1];
+	struct hostapd_data *hapd;
+
+	hapd_iface->conf = conf;
+	hapd_iface->num_bss = conf->num_bss;
+
+	hapd_iface->bss = os_zalloc(conf->num_bss *
+				    sizeof(struct hostapd_data *));
+	if (hapd_iface->bss == NULL)
+		return NULL;
+
+	for (i = 0; i < conf->num_bss; i++) {
+		hapd = hapd_iface->bss[i] =
+			hostapd_alloc_bss_data(hapd_iface, conf,
+					       &conf->bss[i]);
+		if (hapd == NULL)
+			return NULL;
+		hapd->msg_ctx = hapd;
+	}
+
+	hapd_iface->interfaces = interfaces;
+
+	return hapd_iface;
+}
+
+
+int hostapd_add_iface(struct hapd_interfaces *interfaces, char *buf)
+{
+	struct hostapd_config *conf = NULL;
+	struct hostapd_iface *hapd_iface = NULL;
+	char *ptr;
+	size_t i;
+
+	ptr = os_strchr(buf, ' ');
+	if (ptr == NULL)
+		return -1;
+	*ptr++ = '\0';
+
+	for (i = 0; i < interfaces->count; i++) {
+		if (!os_strcmp(interfaces->iface[i]->conf->bss[0].iface,
+			       buf)) {
+			wpa_printf(MSG_INFO, "Cannot add interface - it "
+				   "already exists");
+			return -1;
+		}
+	}
+
+	hapd_iface = hostapd_iface_alloc(interfaces);
+	if (hapd_iface == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
+			   "for interface", __func__);
+		goto fail;
+	}
+
+	conf = hostapd_config_alloc(interfaces, buf, ptr);
+	if (conf == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
+			   "for configuration", __func__);
+		goto fail;
+	}
+
+	hapd_iface = hostapd_data_alloc(interfaces, conf);
+	if (hapd_iface == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
+			   "for hostapd", __func__);
+		goto fail;
+	}
+
+	if (hapd_iface->interfaces &&
+	    hapd_iface->interfaces->ctrl_iface_init &&
+	    hapd_iface->interfaces->ctrl_iface_init(hapd_iface->bss[0])) {
+		wpa_printf(MSG_ERROR, "%s: Failed to setup control "
+			   "interface", __func__);
+		goto fail;
+	}
+	wpa_printf(MSG_INFO, "Add interface '%s'", conf->bss[0].iface);
+
+	return 0;
+
+fail:
+	if (conf)
+		hostapd_config_free(conf);
+	if (hapd_iface) {
+		os_free(hapd_iface->bss[interfaces->count]);
+		os_free(hapd_iface);
+	}
+	return -1;
+}
+
+
+int hostapd_remove_iface(struct hapd_interfaces *interfaces, char *buf)
+{
+	struct hostapd_iface *hapd_iface;
+	size_t i, k = 0;
+
+	for (i = 0; i < interfaces->count; i++) {
+		hapd_iface = interfaces->iface[i];
+		if (hapd_iface == NULL)
+			return -1;
+		if (!os_strcmp(hapd_iface->conf->bss[0].iface, buf)) {
+			wpa_printf(MSG_INFO, "Remove interface '%s'", buf);
+			hostapd_interface_deinit_free(hapd_iface);
+			k = i;
+			while (k < (interfaces->count - 1)) {
+				interfaces->iface[k] =
+					interfaces->iface[k + 1];
+				k++;
+			}
+			interfaces->count--;
+			return 0;
+		}
+	}
+	return -1;
+}
+
+#endif /* HOSTAPD */
+
+
+/**
+ * hostapd_new_assoc_sta - Notify that a new station associated with the AP
+ * @hapd: Pointer to BSS data
+ * @sta: Pointer to the associated STA data
+ * @reassoc: 1 to indicate this was a re-association; 0 = first association
+ *
+ * This function will be called whenever a station associates with the AP. It
+ * can be called from ieee802_11.c for drivers that export MLME to hostapd and
+ * from drv_callbacks.c based on driver events for drivers that take care of
+ * management frames (IEEE 802.11 authentication and association) internally.
+ */
+void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			   int reassoc)
+{
+	if (hapd->tkip_countermeasures) {
+		hostapd_drv_sta_deauth(hapd, sta->addr,
+				       WLAN_REASON_MICHAEL_MIC_FAILURE);
+		return;
+	}
+
+	hostapd_prune_associations(hapd, sta->addr);
+
+	/* IEEE 802.11F (IAPP) */
+	if (hapd->conf->ieee802_11f)
+		iapp_new_station(hapd->iapp, sta);
+
+#ifdef CONFIG_P2P
+	if (sta->p2p_ie == NULL && !sta->no_p2p_set) {
+		sta->no_p2p_set = 1;
+		hapd->num_sta_no_p2p++;
+		if (hapd->num_sta_no_p2p == 1)
+			hostapd_p2p_non_p2p_sta_connected(hapd);
+	}
+#endif /* CONFIG_P2P */
+
+	/* Start accounting here, if IEEE 802.1X and WPA are not used.
+	 * IEEE 802.1X/WPA code will start accounting after the station has
+	 * been authorized. */
+	if (!hapd->conf->ieee802_1x && !hapd->conf->wpa) {
+		os_get_time(&sta->connected_time);
+		accounting_sta_start(hapd, sta);
+	}
+
+	/* Start IEEE 802.1X authentication process for new stations */
+	ieee802_1x_new_station(hapd, sta);
+	if (reassoc) {
+		if (sta->auth_alg != WLAN_AUTH_FT &&
+		    !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)))
+			wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH);
+	} else
+		wpa_auth_sta_associated(hapd->wpa_auth, sta->wpa_sm);
+
+	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+		   "for " MACSTR " (%d seconds - ap_max_inactivity)",
+		   __func__, MAC2STR(sta->addr),
+		   hapd->conf->ap_max_inactivity);
+	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+	eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
+			       ap_handle_timer, hapd, sta);
+}
+
+struct
+hostapd_channel_data *hostapd_get_valid_channel(struct hostapd_data *hapd,
+						int req_freq)
+{
+	struct hostapd_hw_modes *mode;
+	struct hostapd_channel_data *chan;
+	int i, channel_idx = 0;
+
+	wpa_printf(MSG_DEBUG, "Selecting next channel");
+
+	if (hapd->iface->current_mode == NULL)
+		return NULL;
+
+	mode = hapd->iface->current_mode;
+
+	for (i = 0; i < mode->num_channels; i++) {
+		chan = &mode->channels[i];
+
+		if (chan->flag & (HOSTAPD_CHAN_DISABLED | HOSTAPD_CHAN_RADAR))
+			continue;
+		channel_idx++;
+
+		/* request specific channel */
+		if (req_freq && (req_freq == chan->freq))
+			return chan;
+	}
+
+	wpa_printf(MSG_WARNING, "Could't get requested channel");
+	return NULL;
+}
diff --git a/hostap/src/ap/hostapd.h b/hostap/src/ap/hostapd.h
new file mode 100644
index 0000000..28cae7e
--- /dev/null
+++ b/hostap/src/ap/hostapd.h
@@ -0,0 +1,315 @@
+/*
+ * hostapd / Initialization and configuration
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HOSTAPD_H
+#define HOSTAPD_H
+
+#include "common/defs.h"
+#include "ap_config.h"
+
+struct wpa_driver_ops;
+struct wpa_ctrl_dst;
+struct radius_server_data;
+struct upnp_wps_device_sm;
+struct hostapd_data;
+struct sta_info;
+struct hostap_sta_driver_data;
+struct ieee80211_ht_capabilities;
+struct full_dynamic_vlan;
+enum wps_event;
+union wps_event_data;
+
+struct hostapd_iface;
+
+struct hapd_interfaces {
+	int (*reload_config)(struct hostapd_iface *iface);
+	struct hostapd_config * (*config_read_cb)(const char *config_fname);
+	int (*ctrl_iface_init)(struct hostapd_data *hapd);
+	void (*ctrl_iface_deinit)(struct hostapd_data *hapd);
+	int (*for_each_interface)(struct hapd_interfaces *interfaces,
+				  int (*cb)(struct hostapd_iface *iface,
+					    void *ctx), void *ctx);
+	int (*driver_init)(struct hostapd_iface *iface);
+
+	size_t count;
+	int global_ctrl_sock;
+	char *global_iface_path;
+	char *global_iface_name;
+	struct hostapd_iface **iface;
+};
+
+
+struct hostapd_probereq_cb {
+	int (*cb)(void *ctx, const u8 *sa, const u8 *da, const u8 *bssid,
+		  const u8 *ie, size_t ie_len, int ssi_signal);
+	void *ctx;
+};
+
+#define HOSTAPD_RATE_BASIC 0x00000001
+
+struct hostapd_rate_data {
+	int rate; /* rate in 100 kbps */
+	int flags; /* HOSTAPD_RATE_ flags */
+};
+
+struct hostapd_frame_info {
+	u32 channel;
+	u32 datarate;
+	int ssi_signal; /* dBm */
+};
+
+
+/**
+ * struct hostapd_data - hostapd per-BSS data structure
+ */
+struct hostapd_data {
+	struct hostapd_iface *iface;
+	struct hostapd_config *iconf;
+	struct hostapd_bss_config *conf;
+	int interface_added; /* virtual interface added for this BSS */
+
+	u8 own_addr[ETH_ALEN];
+
+	int num_sta; /* number of entries in sta_list */
+	struct sta_info *sta_list; /* STA info list head */
+#define STA_HASH_SIZE 256
+#define STA_HASH(sta) (sta[5])
+	struct sta_info *sta_hash[STA_HASH_SIZE];
+
+	/*
+	 * Bitfield for indicating which AIDs are allocated. Only AID values
+	 * 1-2007 are used and as such, the bit at index 0 corresponds to AID
+	 * 1.
+	 */
+#define AID_WORDS ((2008 + 31) / 32)
+	u32 sta_aid[AID_WORDS];
+
+	const struct wpa_driver_ops *driver;
+	void *drv_priv;
+
+	void (*new_assoc_sta_cb)(struct hostapd_data *hapd,
+				 struct sta_info *sta, int reassoc);
+
+	void *msg_ctx; /* ctx for wpa_msg() calls */
+	void *msg_ctx_parent; /* parent interface ctx for wpa_msg() calls */
+
+	struct radius_client_data *radius;
+	u32 acct_session_id_hi, acct_session_id_lo;
+	struct radius_das_data *radius_das;
+
+	struct iapp_data *iapp;
+
+	struct hostapd_cached_radius_acl *acl_cache;
+	struct hostapd_acl_query_data *acl_queries;
+
+	struct wpa_authenticator *wpa_auth;
+	struct eapol_authenticator *eapol_auth;
+
+	struct rsn_preauth_interface *preauth_iface;
+	time_t michael_mic_failure;
+	int michael_mic_failures;
+	int tkip_countermeasures;
+
+	int ctrl_sock;
+	struct wpa_ctrl_dst *ctrl_dst;
+
+	void *ssl_ctx;
+	void *eap_sim_db_priv;
+	struct radius_server_data *radius_srv;
+
+	int parameter_set_count;
+
+	/* Time Advertisement */
+	u8 time_update_counter;
+	struct wpabuf *time_adv;
+
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	struct full_dynamic_vlan *full_dynamic_vlan;
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+	struct l2_packet_data *l2;
+	struct wps_context *wps;
+
+	int beacon_set_done;
+	struct wpabuf *wps_beacon_ie;
+	struct wpabuf *wps_probe_resp_ie;
+#ifdef CONFIG_WPS
+	unsigned int ap_pin_failures;
+	unsigned int ap_pin_failures_consecutive;
+	struct upnp_wps_device_sm *wps_upnp;
+	unsigned int ap_pin_lockout_time;
+#endif /* CONFIG_WPS */
+
+	struct hostapd_probereq_cb *probereq_cb;
+	size_t num_probereq_cb;
+
+	void (*public_action_cb)(void *ctx, const u8 *buf, size_t len,
+				 int freq);
+	void *public_action_cb_ctx;
+
+	int (*vendor_action_cb)(void *ctx, const u8 *buf, size_t len,
+				int freq);
+	void *vendor_action_cb_ctx;
+
+	void (*wps_reg_success_cb)(void *ctx, const u8 *mac_addr,
+				   const u8 *uuid_e);
+	void *wps_reg_success_cb_ctx;
+
+	void (*wps_event_cb)(void *ctx, enum wps_event event,
+			     union wps_event_data *data);
+	void *wps_event_cb_ctx;
+
+	void (*sta_authorized_cb)(void *ctx, const u8 *mac_addr,
+				  int authorized, const u8 *p2p_dev_addr);
+	void *sta_authorized_cb_ctx;
+
+	void (*setup_complete_cb)(void *ctx);
+	void *setup_complete_cb_ctx;
+
+	struct hostapd_channel_data *next_channel;
+
+#ifdef CONFIG_P2P
+	struct p2p_data *p2p;
+	struct p2p_group *p2p_group;
+	struct wpabuf *p2p_beacon_ie;
+	struct wpabuf *p2p_probe_resp_ie;
+
+	/* Number of non-P2P association stations */
+	int num_sta_no_p2p;
+
+	/* Periodic NoA (used only when no non-P2P clients in the group) */
+	int noa_enabled;
+	int noa_start;
+	int noa_duration;
+#endif /* CONFIG_P2P */
+#ifdef CONFIG_INTERWORKING
+	size_t gas_frag_limit;
+#endif /* CONFIG_INTERWORKING */
+
+#ifdef CONFIG_SQLITE
+	struct hostapd_eap_user tmp_eap_user;
+#endif /* CONFIG_SQLITE */
+};
+
+
+/**
+ * struct hostapd_iface - hostapd per-interface data structure
+ */
+struct hostapd_iface {
+	struct hapd_interfaces *interfaces;
+	void *owner;
+	char *config_fname;
+	struct hostapd_config *conf;
+
+	size_t num_bss;
+	struct hostapd_data **bss;
+
+	int num_ap; /* number of entries in ap_list */
+	struct ap_info *ap_list; /* AP info list head */
+	struct ap_info *ap_hash[STA_HASH_SIZE];
+	struct ap_info *ap_iter_list;
+
+	unsigned int drv_flags;
+
+	/*
+	 * A bitmap of supported protocols for probe response offload. See
+	 * struct wpa_driver_capa in driver.h
+	 */
+	unsigned int probe_resp_offloads;
+
+	struct hostapd_hw_modes *hw_features;
+	int num_hw_features;
+	struct hostapd_hw_modes *current_mode;
+	/* Rates that are currently used (i.e., filtered copy of
+	 * current_mode->channels */
+	int num_rates;
+	struct hostapd_rate_data *current_rates;
+	int *basic_rates;
+	int freq;
+
+	u16 hw_flags;
+
+	/* Number of associated Non-ERP stations (i.e., stations using 802.11b
+	 * in 802.11g BSS) */
+	int num_sta_non_erp;
+
+	/* Number of associated stations that do not support Short Slot Time */
+	int num_sta_no_short_slot_time;
+
+	/* Number of associated stations that do not support Short Preamble */
+	int num_sta_no_short_preamble;
+
+	int olbc; /* Overlapping Legacy BSS Condition */
+
+	/* Number of HT associated stations that do not support greenfield */
+	int num_sta_ht_no_gf;
+
+	/* Number of associated non-HT stations */
+	int num_sta_no_ht;
+
+	/* Number of HT associated stations 20 MHz */
+	int num_sta_ht_20mhz;
+
+	/* Overlapping BSS information */
+	int olbc_ht;
+
+	u16 ht_op_mode;
+	void (*scan_cb)(struct hostapd_iface *iface);
+};
+
+/* hostapd.c */
+int hostapd_for_each_interface(struct hapd_interfaces *interfaces,
+			       int (*cb)(struct hostapd_iface *iface,
+					 void *ctx), void *ctx);
+int hostapd_reload_config(struct hostapd_iface *iface);
+struct hostapd_data *
+hostapd_alloc_bss_data(struct hostapd_iface *hapd_iface,
+		       struct hostapd_config *conf,
+		       struct hostapd_bss_config *bss);
+int hostapd_setup_interface(struct hostapd_iface *iface);
+int hostapd_setup_interface_complete(struct hostapd_iface *iface, int err);
+void hostapd_interface_deinit(struct hostapd_iface *iface);
+void hostapd_interface_free(struct hostapd_iface *iface);
+void hostapd_new_assoc_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			   int reassoc);
+void hostapd_interface_deinit_free(struct hostapd_iface *iface);
+int hostapd_enable_iface(struct hostapd_iface *hapd_iface);
+int hostapd_reload_iface(struct hostapd_iface *hapd_iface);
+int hostapd_disable_iface(struct hostapd_iface *hapd_iface);
+int hostapd_add_iface(struct hapd_interfaces *ifaces, char *buf);
+int hostapd_remove_iface(struct hapd_interfaces *ifaces, char *buf);
+
+struct
+hostapd_channel_data *hostapd_get_valid_channel(struct hostapd_data *hapd,
+                      int req_freq);
+
+/* utils.c */
+int hostapd_register_probereq_cb(struct hostapd_data *hapd,
+				 int (*cb)(void *ctx, const u8 *sa,
+					   const u8 *da, const u8 *bssid,
+					   const u8 *ie, size_t ie_len,
+					   int ssi_signal),
+				 void *ctx);
+void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr);
+
+/* drv_callbacks.c (TODO: move to somewhere else?) */
+int hostapd_notif_assoc(struct hostapd_data *hapd, const u8 *addr,
+			const u8 *ie, size_t ielen, int reassoc);
+void hostapd_notif_disassoc(struct hostapd_data *hapd, const u8 *addr);
+void hostapd_event_sta_low_ack(struct hostapd_data *hapd, const u8 *addr);
+int hostapd_probe_req_rx(struct hostapd_data *hapd, const u8 *sa, const u8 *da,
+			 const u8 *bssid, const u8 *ie, size_t ie_len,
+			 int ssi_signal);
+void hostapd_event_ch_switch(struct hostapd_data *hapd, int freq, int ht,
+			     int offset);
+
+const struct hostapd_eap_user *
+hostapd_get_eap_user(struct hostapd_data *hapd, const u8 *identity,
+		     size_t identity_len, int phase2);
+
+#endif /* HOSTAPD_H */
diff --git a/hostap/src/ap/hs20.c b/hostap/src/ap/hs20.c
new file mode 100644
index 0000000..45d518b
--- /dev/null
+++ b/hostap/src/ap/hs20.c
@@ -0,0 +1,31 @@
+/*
+ * Hotspot 2.0 AP ANQP processing
+ * Copyright (c) 2009, Atheros Communications, Inc.
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "hs20.h"
+
+
+u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid)
+{
+	if (!hapd->conf->hs20)
+		return eid;
+	*eid++ = WLAN_EID_VENDOR_SPECIFIC;
+	*eid++ = 5;
+	WPA_PUT_BE24(eid, OUI_WFA);
+	eid += 3;
+	*eid++ = HS20_INDICATION_OUI_TYPE;
+	/* Hotspot Configuration: DGAF Enabled */
+	*eid++ = hapd->conf->disable_dgaf ? 0x01 : 0x00;
+	return eid;
+}
diff --git a/hostap/src/ap/hs20.h b/hostap/src/ap/hs20.h
new file mode 100644
index 0000000..98698ce
--- /dev/null
+++ b/hostap/src/ap/hs20.h
@@ -0,0 +1,16 @@
+/*
+ * Hotspot 2.0 AP ANQP processing
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HS20_H
+#define HS20_H
+
+struct hostapd_data;
+
+u8 * hostapd_eid_hs20_indication(struct hostapd_data *hapd, u8 *eid);
+
+#endif /* HS20_H */
diff --git a/hostap/src/ap/hw_features.c b/hostap/src/ap/hw_features.c
new file mode 100644
index 0000000..7a88df5
--- /dev/null
+++ b/hostap/src/ap/hw_features.c
@@ -0,0 +1,819 @@
+/*
+ * hostapd / Hardware feature query and different modes
+ * Copyright 2002-2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "drivers/driver.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "hw_features.h"
+
+
+void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
+			      size_t num_hw_features)
+{
+	size_t i;
+
+	if (hw_features == NULL)
+		return;
+
+	for (i = 0; i < num_hw_features; i++) {
+		os_free(hw_features[i].channels);
+		os_free(hw_features[i].rates);
+	}
+
+	os_free(hw_features);
+}
+
+
+int hostapd_get_hw_features(struct hostapd_iface *iface)
+{
+	struct hostapd_data *hapd = iface->bss[0];
+	int ret = 0, i, j;
+	u16 num_modes, flags;
+	struct hostapd_hw_modes *modes;
+
+	if (hostapd_drv_none(hapd))
+		return -1;
+	modes = hostapd_get_hw_feature_data(hapd, &num_modes, &flags);
+	if (modes == NULL) {
+		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Fetching hardware channel/rate support not "
+			       "supported.");
+		return -1;
+	}
+
+	iface->hw_flags = flags;
+
+	hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
+	iface->hw_features = modes;
+	iface->num_hw_features = num_modes;
+
+	for (i = 0; i < num_modes; i++) {
+		struct hostapd_hw_modes *feature = &modes[i];
+		/* set flag for channels we can use in current regulatory
+		 * domain */
+		for (j = 0; j < feature->num_channels; j++) {
+			/*
+			 * Disable all channels that are marked not to allow
+			 * IBSS operation or active scanning. In addition,
+			 * disable all channels that require radar detection,
+			 * since that (in addition to full DFS) is not yet
+			 * supported.
+			 */
+			if (feature->channels[j].flag &
+			    (HOSTAPD_CHAN_NO_IBSS |
+			     HOSTAPD_CHAN_PASSIVE_SCAN |
+			     HOSTAPD_CHAN_RADAR))
+				feature->channels[j].flag |=
+					HOSTAPD_CHAN_DISABLED;
+			if (feature->channels[j].flag & HOSTAPD_CHAN_DISABLED)
+				continue;
+			wpa_printf(MSG_MSGDUMP, "Allowed channel: mode=%d "
+				   "chan=%d freq=%d MHz max_tx_power=%d dBm",
+				   feature->mode,
+				   feature->channels[j].chan,
+				   feature->channels[j].freq,
+				   feature->channels[j].max_tx_power);
+		}
+	}
+
+	return ret;
+}
+
+
+int hostapd_prepare_rates(struct hostapd_iface *iface,
+			  struct hostapd_hw_modes *mode)
+{
+	int i, num_basic_rates = 0;
+	int basic_rates_a[] = { 60, 120, 240, -1 };
+	int basic_rates_b[] = { 10, 20, -1 };
+	int basic_rates_g[] = { 10, 20, 55, 110, -1 };
+	int *basic_rates;
+
+	if (iface->conf->basic_rates)
+		basic_rates = iface->conf->basic_rates;
+	else switch (mode->mode) {
+	case HOSTAPD_MODE_IEEE80211A:
+		basic_rates = basic_rates_a;
+		break;
+	case HOSTAPD_MODE_IEEE80211B:
+		basic_rates = basic_rates_b;
+		break;
+	case HOSTAPD_MODE_IEEE80211G:
+		basic_rates = basic_rates_g;
+		break;
+	case HOSTAPD_MODE_IEEE80211AD:
+		return 0; /* No basic rates for 11ad */
+	default:
+		return -1;
+	}
+
+	i = 0;
+	while (basic_rates[i] >= 0)
+		i++;
+	if (i)
+		i++; /* -1 termination */
+	os_free(iface->basic_rates);
+	iface->basic_rates = os_malloc(i * sizeof(int));
+	if (iface->basic_rates)
+		os_memcpy(iface->basic_rates, basic_rates, i * sizeof(int));
+
+	os_free(iface->current_rates);
+	iface->num_rates = 0;
+
+	iface->current_rates =
+		os_calloc(mode->num_rates, sizeof(struct hostapd_rate_data));
+	if (!iface->current_rates) {
+		wpa_printf(MSG_ERROR, "Failed to allocate memory for rate "
+			   "table.");
+		return -1;
+	}
+
+	for (i = 0; i < mode->num_rates; i++) {
+		struct hostapd_rate_data *rate;
+
+		if (iface->conf->supported_rates &&
+		    !hostapd_rate_found(iface->conf->supported_rates,
+					mode->rates[i]))
+			continue;
+
+		rate = &iface->current_rates[iface->num_rates];
+		rate->rate = mode->rates[i];
+		if (hostapd_rate_found(basic_rates, rate->rate)) {
+			rate->flags |= HOSTAPD_RATE_BASIC;
+			num_basic_rates++;
+		}
+		wpa_printf(MSG_DEBUG, "RATE[%d] rate=%d flags=0x%x",
+			   iface->num_rates, rate->rate, rate->flags);
+		iface->num_rates++;
+	}
+
+	if ((iface->num_rates == 0 || num_basic_rates == 0) &&
+	    (!iface->conf->ieee80211n || !iface->conf->require_ht)) {
+		wpa_printf(MSG_ERROR, "No rates remaining in supported/basic "
+			   "rate sets (%d,%d).",
+			   iface->num_rates, num_basic_rates);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_IEEE80211N
+static int ieee80211n_allowed_ht40_channel_pair(struct hostapd_iface *iface)
+{
+	int sec_chan, ok, j, first;
+	int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 149, 157,
+			  184, 192 };
+	size_t k;
+
+	if (!iface->conf->secondary_channel)
+		return 1; /* HT40 not used */
+
+	sec_chan = iface->conf->channel + iface->conf->secondary_channel * 4;
+	wpa_printf(MSG_DEBUG, "HT40: control channel: %d  "
+		   "secondary channel: %d",
+		   iface->conf->channel, sec_chan);
+
+	/* Verify that HT40 secondary channel is an allowed 20 MHz
+	 * channel */
+	ok = 0;
+	for (j = 0; j < iface->current_mode->num_channels; j++) {
+		struct hostapd_channel_data *chan =
+			&iface->current_mode->channels[j];
+		if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+		    chan->chan == sec_chan) {
+			ok = 1;
+			break;
+		}
+	}
+	if (!ok) {
+		wpa_printf(MSG_ERROR, "HT40 secondary channel %d not allowed",
+			   sec_chan);
+		return 0;
+	}
+
+	/*
+	 * Verify that HT40 primary,secondary channel pair is allowed per
+	 * IEEE 802.11n Annex J. This is only needed for 5 GHz band since
+	 * 2.4 GHz rules allow all cases where the secondary channel fits into
+	 * the list of allowed channels (already checked above).
+	 */
+	if (iface->current_mode->mode != HOSTAPD_MODE_IEEE80211A)
+		return 1;
+
+	if (iface->conf->secondary_channel > 0)
+		first = iface->conf->channel;
+	else
+		first = sec_chan;
+
+	ok = 0;
+	for (k = 0; k < sizeof(allowed) / sizeof(allowed[0]); k++) {
+		if (first == allowed[k]) {
+			ok = 1;
+			break;
+		}
+	}
+	if (!ok) {
+		wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
+			   iface->conf->channel,
+			   iface->conf->secondary_channel);
+		return 0;
+	}
+
+	return 1;
+}
+
+
+static void ieee80211n_switch_pri_sec(struct hostapd_iface *iface)
+{
+	if (iface->conf->secondary_channel > 0) {
+		iface->conf->channel += 4;
+		iface->conf->secondary_channel = -1;
+	} else {
+		iface->conf->channel -= 4;
+		iface->conf->secondary_channel = 1;
+	}
+}
+
+
+static void ieee80211n_get_pri_sec_chan(struct wpa_scan_res *bss,
+					int *pri_chan, int *sec_chan)
+{
+	struct ieee80211_ht_operation *oper;
+	struct ieee802_11_elems elems;
+
+	*pri_chan = *sec_chan = 0;
+
+	ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
+	if (elems.ht_operation &&
+	    elems.ht_operation_len >= sizeof(*oper)) {
+		oper = (struct ieee80211_ht_operation *) elems.ht_operation;
+		*pri_chan = oper->control_chan;
+		if (oper->ht_param & HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH) {
+			int sec = oper->ht_param &
+				HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK;
+			if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE)
+				*sec_chan = *pri_chan + 4;
+			else if (sec == HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW)
+				*sec_chan = *pri_chan - 4;
+		}
+	}
+}
+
+
+static int ieee80211n_check_40mhz_5g(struct hostapd_iface *iface,
+				     struct wpa_scan_results *scan_res)
+{
+	int pri_chan, sec_chan, pri_freq, sec_freq, pri_bss, sec_bss;
+	int bss_pri_chan, bss_sec_chan;
+	size_t i;
+	int match;
+
+	pri_chan = iface->conf->channel;
+	sec_chan = iface->conf->secondary_channel * 4;
+	pri_freq = hostapd_hw_get_freq(iface->bss[0], pri_chan);
+	if (iface->conf->secondary_channel > 0)
+		sec_freq = pri_freq + 20;
+	else
+		sec_freq = pri_freq - 20;
+
+	/*
+	 * Switch PRI/SEC channels if Beacons were detected on selected SEC
+	 * channel, but not on selected PRI channel.
+	 */
+	pri_bss = sec_bss = 0;
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *bss = scan_res->res[i];
+		if (bss->freq == pri_freq)
+			pri_bss++;
+		else if (bss->freq == sec_freq)
+			sec_bss++;
+	}
+	if (sec_bss && !pri_bss) {
+		wpa_printf(MSG_INFO, "Switch own primary and secondary "
+			   "channel to get secondary channel with no Beacons "
+			   "from other BSSes");
+		ieee80211n_switch_pri_sec(iface);
+	}
+
+	/*
+	 * Match PRI/SEC channel with any existing HT40 BSS on the same
+	 * channels that we are about to use (if already mixed order in
+	 * existing BSSes, use own preference).
+	 */
+	match = 0;
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *bss = scan_res->res[i];
+		ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan, &bss_sec_chan);
+		if (pri_chan == bss_pri_chan &&
+		    sec_chan == bss_sec_chan) {
+			match = 1;
+			break;
+		}
+	}
+	if (!match) {
+		for (i = 0; i < scan_res->num; i++) {
+			struct wpa_scan_res *bss = scan_res->res[i];
+			ieee80211n_get_pri_sec_chan(bss, &bss_pri_chan,
+						    &bss_sec_chan);
+			if (pri_chan == bss_sec_chan &&
+			    sec_chan == bss_pri_chan) {
+				wpa_printf(MSG_INFO, "Switch own primary and "
+					   "secondary channel due to BSS "
+					   "overlap with " MACSTR,
+					   MAC2STR(bss->bssid));
+				ieee80211n_switch_pri_sec(iface);
+				break;
+			}
+		}
+	}
+
+	return 1;
+}
+
+
+static int ieee80211n_check_40mhz_2g4(struct hostapd_iface *iface,
+				      struct wpa_scan_results *scan_res)
+{
+	int pri_freq, sec_freq;
+	int affected_start, affected_end;
+	size_t i;
+
+	pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+	if (iface->conf->secondary_channel > 0)
+		sec_freq = pri_freq + 20;
+	else
+		sec_freq = pri_freq - 20;
+	affected_start = (pri_freq + sec_freq) / 2 - 25;
+	affected_end = (pri_freq + sec_freq) / 2 + 25;
+	wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
+		   affected_start, affected_end);
+	for (i = 0; i < scan_res->num; i++) {
+		struct wpa_scan_res *bss = scan_res->res[i];
+		int pri = bss->freq;
+		int sec = pri;
+		int sec_chan, pri_chan;
+
+		ieee80211n_get_pri_sec_chan(bss, &pri_chan, &sec_chan);
+
+		if (sec_chan) {
+			if (sec_chan < pri_chan)
+				sec = pri - 20;
+			else
+				sec = pri + 20;
+		}
+
+		if ((pri < affected_start || pri > affected_end) &&
+		    (sec < affected_start || sec > affected_end))
+			continue; /* not within affected channel range */
+
+		wpa_printf(MSG_DEBUG, "Neighboring BSS: " MACSTR
+			   " freq=%d pri=%d sec=%d",
+			   MAC2STR(bss->bssid), bss->freq, pri_chan, sec_chan);
+
+		if (sec_chan) {
+			if (pri_freq != pri || sec_freq != sec) {
+				wpa_printf(MSG_DEBUG, "40 MHz pri/sec "
+					   "mismatch with BSS " MACSTR
+					   " <%d,%d> (chan=%d%c) vs. <%d,%d>",
+					   MAC2STR(bss->bssid),
+					   pri, sec, pri_chan,
+					   sec > pri ? '+' : '-',
+					   pri_freq, sec_freq);
+				return 0;
+			}
+		}
+
+		/* TODO: 40 MHz intolerant */
+	}
+
+	return 1;
+}
+
+
+static void ieee80211n_check_scan(struct hostapd_iface *iface)
+{
+	struct wpa_scan_results *scan_res;
+	int oper40;
+	int res;
+
+	/* Check list of neighboring BSSes (from scan) to see whether 40 MHz is
+	 * allowed per IEEE Std 802.11-2012, 10.15.3.2 */
+
+	iface->scan_cb = NULL;
+
+	scan_res = hostapd_driver_get_scan_results(iface->bss[0]);
+	if (scan_res == NULL) {
+		hostapd_setup_interface_complete(iface, 1);
+		return;
+	}
+
+	if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211A)
+		oper40 = ieee80211n_check_40mhz_5g(iface, scan_res);
+	else
+		oper40 = ieee80211n_check_40mhz_2g4(iface, scan_res);
+	wpa_scan_results_free(scan_res);
+
+	if (!oper40) {
+		wpa_printf(MSG_INFO, "20/40 MHz operation not permitted on "
+			   "channel pri=%d sec=%d based on overlapping BSSes",
+			   iface->conf->channel,
+			   iface->conf->channel +
+			   iface->conf->secondary_channel * 4);
+		iface->conf->secondary_channel = 0;
+		iface->conf->ht_capab &= ~HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET;
+	}
+
+	res = ieee80211n_allowed_ht40_channel_pair(iface);
+	hostapd_setup_interface_complete(iface, !res);
+}
+
+
+static void ieee80211n_scan_channels_2g4(struct hostapd_iface *iface,
+					 struct wpa_driver_scan_params *params)
+{
+	/* Scan only the affected frequency range */
+	int pri_freq, sec_freq;
+	int affected_start, affected_end;
+	int i, pos;
+	struct hostapd_hw_modes *mode;
+
+	if (iface->current_mode == NULL)
+		return;
+
+	pri_freq = hostapd_hw_get_freq(iface->bss[0], iface->conf->channel);
+	if (iface->conf->secondary_channel > 0)
+		sec_freq = pri_freq + 20;
+	else
+		sec_freq = pri_freq - 20;
+	affected_start = (pri_freq + sec_freq) / 2 - 25;
+	affected_end = (pri_freq + sec_freq) / 2 + 25;
+	wpa_printf(MSG_DEBUG, "40 MHz affected channel range: [%d,%d] MHz",
+		   affected_start, affected_end);
+
+	mode = iface->current_mode;
+	params->freqs = os_calloc(mode->num_channels + 1, sizeof(int));
+	if (params->freqs == NULL)
+		return;
+	pos = 0;
+
+	for (i = 0; i < mode->num_channels; i++) {
+		struct hostapd_channel_data *chan = &mode->channels[i];
+		if (chan->flag & HOSTAPD_CHAN_DISABLED)
+			continue;
+		if (chan->freq < affected_start ||
+		    chan->freq > affected_end)
+			continue;
+		params->freqs[pos++] = chan->freq;
+	}
+}
+
+
+static int ieee80211n_check_40mhz(struct hostapd_iface *iface)
+{
+	struct wpa_driver_scan_params params;
+
+	if (!iface->conf->secondary_channel)
+		return 0; /* HT40 not used */
+
+	wpa_printf(MSG_DEBUG, "Scan for neighboring BSSes prior to enabling "
+		   "40 MHz channel");
+	os_memset(&params, 0, sizeof(params));
+	if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+		ieee80211n_scan_channels_2g4(iface, &params);
+	if (hostapd_driver_scan(iface->bss[0], &params) < 0) {
+		wpa_printf(MSG_ERROR, "Failed to request a scan of "
+			   "neighboring BSSes");
+		os_free(params.freqs);
+		return -1;
+	}
+	os_free(params.freqs);
+
+	iface->scan_cb = ieee80211n_check_scan;
+	return 1;
+}
+
+
+static int ieee80211n_supported_ht_capab(struct hostapd_iface *iface)
+{
+	u16 hw = iface->current_mode->ht_capab;
+	u16 conf = iface->conf->ht_capab;
+
+	if ((conf & HT_CAP_INFO_LDPC_CODING_CAP) &&
+	    !(hw & HT_CAP_INFO_LDPC_CODING_CAP)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [LDPC]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+	    !(hw & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [HT40*]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_SMPS_MASK) != (hw & HT_CAP_INFO_SMPS_MASK) &&
+	    (conf & HT_CAP_INFO_SMPS_MASK) != HT_CAP_INFO_SMPS_DISABLED) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [SMPS-*]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_GREEN_FIELD) &&
+	    !(hw & HT_CAP_INFO_GREEN_FIELD)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [GF]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_SHORT_GI20MHZ) &&
+	    !(hw & HT_CAP_INFO_SHORT_GI20MHZ)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [SHORT-GI-20]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_SHORT_GI40MHZ) &&
+	    !(hw & HT_CAP_INFO_SHORT_GI40MHZ)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [SHORT-GI-40]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_TX_STBC) && !(hw & HT_CAP_INFO_TX_STBC)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [TX-STBC]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_RX_STBC_MASK) >
+	    (hw & HT_CAP_INFO_RX_STBC_MASK)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [RX-STBC*]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_DELAYED_BA) &&
+	    !(hw & HT_CAP_INFO_DELAYED_BA)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [DELAYED-BA]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_MAX_AMSDU_SIZE) &&
+	    !(hw & HT_CAP_INFO_MAX_AMSDU_SIZE)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [MAX-AMSDU-7935]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_DSSS_CCK40MHZ) &&
+	    !(hw & HT_CAP_INFO_DSSS_CCK40MHZ)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [DSSS_CCK-40]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_PSMP_SUPP) && !(hw & HT_CAP_INFO_PSMP_SUPP)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [PSMP]");
+		return 0;
+	}
+
+	if ((conf & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT) &&
+	    !(hw & HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT)) {
+		wpa_printf(MSG_ERROR, "Driver does not support configured "
+			   "HT capability [LSIG-TXOP-PROT]");
+		return 0;
+	}
+
+	return 1;
+}
+
+#endif /* CONFIG_IEEE80211N */
+
+
+int hostapd_check_ht_capab(struct hostapd_iface *iface)
+{
+#ifdef CONFIG_IEEE80211N
+	int ret;
+	if (!iface->conf->ieee80211n)
+		return 0;
+	if (!ieee80211n_supported_ht_capab(iface))
+		return -1;
+	ret = ieee80211n_check_40mhz(iface);
+	if (ret)
+		return ret;
+	if (!ieee80211n_allowed_ht40_channel_pair(iface))
+		return -1;
+#endif /* CONFIG_IEEE80211N */
+
+	return 0;
+}
+
+
+/**
+ * hostapd_select_hw_mode - Select the hardware mode
+ * @iface: Pointer to interface data.
+ * Returns: 0 on success, < 0 on failure
+ *
+ * Sets up the hardware mode, channel, rates, and passive scanning
+ * based on the configuration.
+ */
+int hostapd_select_hw_mode(struct hostapd_iface *iface)
+{
+	int i, j, ok;
+
+	if (iface->num_hw_features < 1)
+		return -1;
+
+	iface->current_mode = NULL;
+	for (i = 0; i < iface->num_hw_features; i++) {
+		struct hostapd_hw_modes *mode = &iface->hw_features[i];
+		if (mode->mode == iface->conf->hw_mode) {
+			iface->current_mode = mode;
+			break;
+		}
+	}
+
+	if (iface->current_mode == NULL) {
+		wpa_printf(MSG_ERROR, "Hardware does not support configured "
+			   "mode");
+		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_WARNING,
+			       "Hardware does not support configured mode "
+			       "(%d) (hw_mode in hostapd.conf)",
+			       (int) iface->conf->hw_mode);
+		return -2;
+	}
+
+	ok = 0;
+	for (j = 0; j < iface->current_mode->num_channels; j++) {
+		struct hostapd_channel_data *chan =
+			&iface->current_mode->channels[j];
+		if (chan->chan == iface->conf->channel) {
+			if (chan->flag & HOSTAPD_CHAN_DISABLED) {
+				wpa_printf(MSG_ERROR,
+					   "channel [%i] (%i) is disabled for "
+					   "use in AP mode, flags: 0x%x%s%s%s",
+					   j, chan->chan, chan->flag,
+					   chan->flag & HOSTAPD_CHAN_NO_IBSS ?
+					   " NO-IBSS" : "",
+					   chan->flag &
+					   HOSTAPD_CHAN_PASSIVE_SCAN ?
+					   " PASSIVE-SCAN" : "",
+					   chan->flag & HOSTAPD_CHAN_RADAR ?
+					   " RADAR" : "");
+			} else {
+				ok = 1;
+				break;
+			}
+		}
+	}
+	if (ok && iface->conf->secondary_channel) {
+		int sec_ok = 0;
+		int sec_chan = iface->conf->channel +
+			iface->conf->secondary_channel * 4;
+		for (j = 0; j < iface->current_mode->num_channels; j++) {
+			struct hostapd_channel_data *chan =
+				&iface->current_mode->channels[j];
+			if (!(chan->flag & HOSTAPD_CHAN_DISABLED) &&
+			    (chan->chan == sec_chan)) {
+				sec_ok = 1;
+				break;
+			}
+		}
+		if (!sec_ok) {
+			hostapd_logger(iface->bss[0], NULL,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_WARNING,
+				       "Configured HT40 secondary channel "
+				       "(%d) not found from the channel list "
+				       "of current mode (%d) %s",
+				       sec_chan, iface->current_mode->mode,
+				       hostapd_hw_mode_txt(
+					       iface->current_mode->mode));
+			ok = 0;
+		}
+	}
+	if (iface->conf->channel == 0) {
+		/* TODO: could request a scan of neighboring BSSes and select
+		 * the channel automatically */
+		wpa_printf(MSG_ERROR, "Channel not configured "
+			   "(hw_mode/channel in hostapd.conf)");
+		return -3;
+	}
+	if (ok == 0 && iface->conf->channel != 0) {
+		hostapd_logger(iface->bss[0], NULL,
+			       HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_WARNING,
+			       "Configured channel (%d) not found from the "
+			       "channel list of current mode (%d) %s",
+			       iface->conf->channel,
+			       iface->current_mode->mode,
+			       hostapd_hw_mode_txt(iface->current_mode->mode));
+		iface->current_mode = NULL;
+	}
+
+	if (iface->current_mode == NULL) {
+		hostapd_logger(iface->bss[0], NULL, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_WARNING,
+			       "Hardware does not support configured channel");
+		return -4;
+	}
+
+	return 0;
+}
+
+
+const char * hostapd_hw_mode_txt(int mode)
+{
+	switch (mode) {
+	case HOSTAPD_MODE_IEEE80211A:
+		return "IEEE 802.11a";
+	case HOSTAPD_MODE_IEEE80211B:
+		return "IEEE 802.11b";
+	case HOSTAPD_MODE_IEEE80211G:
+		return "IEEE 802.11g";
+	case HOSTAPD_MODE_IEEE80211AD:
+		return "IEEE 802.11ad";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
+{
+	int i;
+
+	if (!hapd->iface->current_mode)
+		return 0;
+
+	for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
+		struct hostapd_channel_data *ch =
+			&hapd->iface->current_mode->channels[i];
+		if (ch->chan == chan)
+			return ch->freq;
+	}
+
+	return 0;
+}
+
+
+int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq)
+{
+	int i;
+
+	if (!hapd->iface->current_mode)
+		return 0;
+
+	for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
+		struct hostapd_channel_data *ch =
+			&hapd->iface->current_mode->channels[i];
+		if (ch->freq == freq)
+			return ch->chan;
+	}
+
+	return 0;
+}
+
+int hostapd_hw_get_channel_flag(struct hostapd_data *hapd, int chan)
+{
+	int i;
+
+	if (!hapd->iface->current_mode)
+		return 0;
+
+	for (i = 0; i < hapd->iface->current_mode->num_channels; i++) {
+		struct hostapd_channel_data *ch =
+			&hapd->iface->current_mode->channels[i];
+		if (ch->chan == chan)
+			return ch->flag;
+	}
+
+	return 0;
+}
diff --git a/hostap/src/ap/hw_features.h b/hostap/src/ap/hw_features.h
new file mode 100644
index 0000000..b8e287b
--- /dev/null
+++ b/hostap/src/ap/hw_features.h
@@ -0,0 +1,72 @@
+/*
+ * hostapd / Hardware feature query and different modes
+ * Copyright 2002-2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2008-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published 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 HW_FEATURES_H
+#define HW_FEATURES_H
+
+#ifdef NEED_AP_MLME
+void hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
+			      size_t num_hw_features);
+int hostapd_get_hw_features(struct hostapd_iface *iface);
+int hostapd_select_hw_mode(struct hostapd_iface *iface);
+const char * hostapd_hw_mode_txt(int mode);
+int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan);
+int hostapd_hw_get_channel(struct hostapd_data *hapd, int freq);
+int hostapd_check_ht_capab(struct hostapd_iface *iface);
+int hostapd_prepare_rates(struct hostapd_iface *iface,
+			  struct hostapd_hw_modes *mode);
+int hostapd_hw_get_channel_flag(struct hostapd_data *hapd, int chan);
+#else /* NEED_AP_MLME */
+static inline void
+hostapd_free_hw_features(struct hostapd_hw_modes *hw_features,
+			 size_t num_hw_features)
+{
+}
+
+static inline int hostapd_get_hw_features(struct hostapd_iface *iface)
+{
+	return -1;
+}
+
+static inline int hostapd_select_hw_mode(struct hostapd_iface *iface)
+{
+	return -100;
+}
+
+static inline const char * hostapd_hw_mode_txt(int mode)
+{
+	return NULL;
+}
+
+static inline int hostapd_hw_get_freq(struct hostapd_data *hapd, int chan)
+{
+	return -1;
+}
+
+static inline int hostapd_check_ht_capab(struct hostapd_iface *iface)
+{
+	return 0;
+}
+
+static inline int hostapd_prepare_rates(struct hostapd_iface *iface,
+					struct hostapd_hw_modes *mode)
+{
+	return 0;
+}
+
+#endif /* NEED_AP_MLME */
+
+#endif /* HW_FEATURES_H */
diff --git a/hostap/src/ap/iapp.c b/hostap/src/ap/iapp.c
new file mode 100644
index 0000000..be55c69
--- /dev/null
+++ b/hostap/src/ap/iapp.c
@@ -0,0 +1,529 @@
+/*
+ * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * Note: IEEE 802.11F-2003 was a experimental use specification. It has expired
+ * and IEEE has withdrawn it. In other words, it is likely better to look at
+ * using some other mechanism for AP-to-AP communication than extending the
+ * implementation here.
+ */
+
+/* TODO:
+ * Level 1: no administrative or security support
+ *	(e.g., static BSSID to IP address mapping in each AP)
+ * Level 2: support for dynamic mapping of BSSID to IP address
+ * Level 3: support for encryption and authentication of IAPP messages
+ * - add support for MOVE-notify and MOVE-response (this requires support for
+ *   finding out IP address for previous AP using RADIUS)
+ * - add support for Send- and ACK-Security-Block to speedup IEEE 802.1X during
+ *   reassociation to another AP
+ * - implement counters etc. for IAPP MIB
+ * - verify endianness of fields in IAPP messages; are they big-endian as
+ *   used here?
+ * - RADIUS connection for AP registration and BSSID to IP address mapping
+ * - TCP connection for IAPP MOVE, CACHE
+ * - broadcast ESP for IAPP ADD-notify
+ * - ESP for IAPP MOVE messages
+ * - security block sending/processing
+ * - IEEE 802.11 context transfer
+ */
+
+#include "utils/includes.h"
+#include <net/if.h>
+#include <sys/ioctl.h>
+#ifdef USE_KERNEL_HEADERS
+#include <linux/if_packet.h>
+#else /* USE_KERNEL_HEADERS */
+#include <netpacket/packet.h>
+#endif /* USE_KERNEL_HEADERS */
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "iapp.h"
+
+
+#define IAPP_MULTICAST "224.0.1.178"
+#define IAPP_UDP_PORT 3517
+#define IAPP_TCP_PORT 3517
+
+struct iapp_hdr {
+	u8 version;
+	u8 command;
+	be16 identifier;
+	be16 length;
+	/* followed by length-6 octets of data */
+} __attribute__ ((packed));
+
+#define IAPP_VERSION 0
+
+enum IAPP_COMMAND {
+	IAPP_CMD_ADD_notify = 0,
+	IAPP_CMD_MOVE_notify = 1,
+	IAPP_CMD_MOVE_response = 2,
+	IAPP_CMD_Send_Security_Block = 3,
+	IAPP_CMD_ACK_Security_Block = 4,
+	IAPP_CMD_CACHE_notify = 5,
+	IAPP_CMD_CACHE_response = 6,
+};
+
+
+/* ADD-notify - multicast UDP on the local LAN */
+struct iapp_add_notify {
+	u8 addr_len; /* ETH_ALEN */
+	u8 reserved;
+	u8 mac_addr[ETH_ALEN];
+	be16 seq_num;
+} __attribute__ ((packed));
+
+
+/* Layer 2 Update frame (802.2 Type 1 LLC XID Update response) */
+struct iapp_layer2_update {
+	u8 da[ETH_ALEN]; /* broadcast */
+	u8 sa[ETH_ALEN]; /* STA addr */
+	be16 len; /* 6 */
+	u8 dsap; /* null DSAP address */
+	u8 ssap; /* null SSAP address, CR=Response */
+	u8 control;
+	u8 xid_info[3];
+} __attribute__ ((packed));
+
+
+/* MOVE-notify - unicast TCP */
+struct iapp_move_notify {
+	u8 addr_len; /* ETH_ALEN */
+	u8 reserved;
+	u8 mac_addr[ETH_ALEN];
+	u16 seq_num;
+	u16 ctx_block_len;
+	/* followed by ctx_block_len bytes */
+} __attribute__ ((packed));
+
+
+/* MOVE-response - unicast TCP */
+struct iapp_move_response {
+	u8 addr_len; /* ETH_ALEN */
+	u8 status;
+	u8 mac_addr[ETH_ALEN];
+	u16 seq_num;
+	u16 ctx_block_len;
+	/* followed by ctx_block_len bytes */
+} __attribute__ ((packed));
+
+enum {
+	IAPP_MOVE_SUCCESSFUL = 0,
+	IAPP_MOVE_DENIED = 1,
+	IAPP_MOVE_STALE_MOVE = 2,
+};
+
+
+/* CACHE-notify */
+struct iapp_cache_notify {
+	u8 addr_len; /* ETH_ALEN */
+	u8 reserved;
+	u8 mac_addr[ETH_ALEN];
+	u16 seq_num;
+	u8 current_ap[ETH_ALEN];
+	u16 ctx_block_len;
+	/* ctx_block_len bytes of context block followed by 16-bit context
+	 * timeout */
+} __attribute__ ((packed));
+
+
+/* CACHE-response - unicast TCP */
+struct iapp_cache_response {
+	u8 addr_len; /* ETH_ALEN */
+	u8 status;
+	u8 mac_addr[ETH_ALEN];
+	u16 seq_num;
+} __attribute__ ((packed));
+
+enum {
+	IAPP_CACHE_SUCCESSFUL = 0,
+	IAPP_CACHE_STALE_CACHE = 1,
+};
+
+
+/* Send-Security-Block - unicast TCP */
+struct iapp_send_security_block {
+	u8 iv[8];
+	u16 sec_block_len;
+	/* followed by sec_block_len bytes of security block */
+} __attribute__ ((packed));
+
+
+/* ACK-Security-Block - unicast TCP */
+struct iapp_ack_security_block {
+	u8 iv[8];
+	u8 new_ap_ack_authenticator[48];
+} __attribute__ ((packed));
+
+
+struct iapp_data {
+	struct hostapd_data *hapd;
+	u16 identifier; /* next IAPP identifier */
+	struct in_addr own, multicast;
+	int udp_sock;
+	int packet_sock;
+};
+
+
+static void iapp_send_add(struct iapp_data *iapp, u8 *mac_addr, u16 seq_num)
+{
+	char buf[128];
+	struct iapp_hdr *hdr;
+	struct iapp_add_notify *add;
+	struct sockaddr_in addr;
+
+	/* Send IAPP ADD-notify to remove possible association from other APs
+	 */
+
+	hdr = (struct iapp_hdr *) buf;
+	hdr->version = IAPP_VERSION;
+	hdr->command = IAPP_CMD_ADD_notify;
+	hdr->identifier = host_to_be16(iapp->identifier++);
+	hdr->length = host_to_be16(sizeof(*hdr) + sizeof(*add));
+
+	add = (struct iapp_add_notify *) (hdr + 1);
+	add->addr_len = ETH_ALEN;
+	add->reserved = 0;
+	os_memcpy(add->mac_addr, mac_addr, ETH_ALEN);
+
+	add->seq_num = host_to_be16(seq_num);
+	
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sin_family = AF_INET;
+	addr.sin_addr.s_addr = iapp->multicast.s_addr;
+	addr.sin_port = htons(IAPP_UDP_PORT);
+	if (sendto(iapp->udp_sock, buf, (char *) (add + 1) - buf, 0,
+		   (struct sockaddr *) &addr, sizeof(addr)) < 0)
+		perror("sendto[IAPP-ADD]");
+}
+
+
+static void iapp_send_layer2_update(struct iapp_data *iapp, u8 *addr)
+{
+	struct iapp_layer2_update msg;
+
+	/* Send Level 2 Update Frame to update forwarding tables in layer 2
+	 * bridge devices */
+
+	/* 802.2 Type 1 Logical Link Control (LLC) Exchange Identifier (XID)
+	 * Update response frame; IEEE Std 802.2-1998, 5.4.1.2.1 */
+
+	os_memset(msg.da, 0xff, ETH_ALEN);
+	os_memcpy(msg.sa, addr, ETH_ALEN);
+	msg.len = host_to_be16(6);
+	msg.dsap = 0; /* NULL DSAP address */
+	msg.ssap = 0x01; /* NULL SSAP address, CR Bit: Response */
+	msg.control = 0xaf; /* XID response lsb.1111F101.
+			     * F=0 (no poll command; unsolicited frame) */
+	msg.xid_info[0] = 0x81; /* XID format identifier */
+	msg.xid_info[1] = 1; /* LLC types/classes: Type 1 LLC */
+	msg.xid_info[2] = 1 << 1; /* XID sender's receive window size (RW)
+				   * FIX: what is correct RW with 802.11? */
+
+	if (send(iapp->packet_sock, &msg, sizeof(msg), 0) < 0)
+		perror("send[L2 Update]");
+}
+
+
+/**
+ * iapp_new_station - IAPP processing for a new STA
+ * @iapp: IAPP data
+ * @sta: The associated station
+ */
+void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta)
+{
+	struct ieee80211_mgmt *assoc;
+	u16 seq;
+
+	if (iapp == NULL)
+		return;
+
+	assoc = sta->last_assoc_req;
+	seq = assoc ? WLAN_GET_SEQ_SEQ(le_to_host16(assoc->seq_ctrl)) : 0;
+
+	/* IAPP-ADD.request(MAC Address, Sequence Number, Timeout) */
+	hostapd_logger(iapp->hapd, sta->addr, HOSTAPD_MODULE_IAPP,
+		       HOSTAPD_LEVEL_DEBUG, "IAPP-ADD.request(seq=%d)", seq);
+	iapp_send_layer2_update(iapp, sta->addr);
+	iapp_send_add(iapp, sta->addr, seq);
+
+	if (assoc && WLAN_FC_GET_STYPE(le_to_host16(assoc->frame_control)) ==
+	    WLAN_FC_STYPE_REASSOC_REQ) {
+		/* IAPP-MOVE.request(MAC Address, Sequence Number, Old AP,
+		 *                   Context Block, Timeout)
+		 */
+		/* TODO: Send IAPP-MOVE to the old AP; Map Old AP BSSID to
+		 * IP address */
+	}
+}
+
+
+static void iapp_process_add_notify(struct iapp_data *iapp,
+				    struct sockaddr_in *from,
+				    struct iapp_hdr *hdr, int len)
+{
+	struct iapp_add_notify *add = (struct iapp_add_notify *) (hdr + 1);
+	struct sta_info *sta;
+
+	if (len != sizeof(*add)) {
+		printf("Invalid IAPP-ADD packet length %d (expected %lu)\n",
+		       len, (unsigned long) sizeof(*add));
+		return;
+	}
+
+	sta = ap_get_sta(iapp->hapd, add->mac_addr);
+
+	/* IAPP-ADD.indication(MAC Address, Sequence Number) */
+	hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
+		       HOSTAPD_LEVEL_INFO,
+		       "Received IAPP ADD-notify (seq# %d) from %s:%d%s",
+		       be_to_host16(add->seq_num),
+		       inet_ntoa(from->sin_addr), ntohs(from->sin_port),
+		       sta ? "" : " (STA not found)");
+
+	if (!sta)
+		return;
+
+	/* TODO: could use seq_num to try to determine whether last association
+	 * to this AP is newer than the one advertised in IAPP-ADD. Although,
+	 * this is not really a reliable verification. */
+
+	hostapd_logger(iapp->hapd, add->mac_addr, HOSTAPD_MODULE_IAPP,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "Removing STA due to IAPP ADD-notify");
+	ap_sta_disconnect(iapp->hapd, sta, NULL, 0);
+}
+
+
+/**
+ * iapp_receive_udp - Process IAPP UDP frames
+ * @sock: File descriptor for the socket
+ * @eloop_ctx: IAPP data (struct iapp_data *)
+ * @sock_ctx: Not used
+ */
+static void iapp_receive_udp(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	struct iapp_data *iapp = eloop_ctx;
+	int len, hlen;
+	unsigned char buf[128];
+	struct sockaddr_in from;
+	socklen_t fromlen;
+	struct iapp_hdr *hdr;
+
+	/* Handle incoming IAPP frames (over UDP/IP) */
+
+	fromlen = sizeof(from);
+	len = recvfrom(iapp->udp_sock, buf, sizeof(buf), 0,
+		       (struct sockaddr *) &from, &fromlen);
+	if (len < 0) {
+		perror("recvfrom");
+		return;
+	}
+
+	if (from.sin_addr.s_addr == iapp->own.s_addr)
+		return; /* ignore own IAPP messages */
+
+	hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "Received %d byte IAPP frame from %s%s\n",
+		       len, inet_ntoa(from.sin_addr),
+		       len < (int) sizeof(*hdr) ? " (too short)" : "");
+
+	if (len < (int) sizeof(*hdr))
+		return;
+
+	hdr = (struct iapp_hdr *) buf;
+	hlen = be_to_host16(hdr->length);
+	hostapd_logger(iapp->hapd, NULL, HOSTAPD_MODULE_IAPP,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "RX: version=%d command=%d id=%d len=%d\n",
+		       hdr->version, hdr->command,
+		       be_to_host16(hdr->identifier), hlen);
+	if (hdr->version != IAPP_VERSION) {
+		printf("Dropping IAPP frame with unknown version %d\n",
+		       hdr->version);
+		return;
+	}
+	if (hlen > len) {
+		printf("Underflow IAPP frame (hlen=%d len=%d)\n", hlen, len);
+		return;
+	}
+	if (hlen < len) {
+		printf("Ignoring %d extra bytes from IAPP frame\n",
+		       len - hlen);
+		len = hlen;
+	}
+
+	switch (hdr->command) {
+	case IAPP_CMD_ADD_notify:
+		iapp_process_add_notify(iapp, &from, hdr, hlen - sizeof(*hdr));
+		break;
+	case IAPP_CMD_MOVE_notify:
+		/* TODO: MOVE is using TCP; so move this to TCP handler once it
+		 * is implemented.. */
+		/* IAPP-MOVE.indication(MAC Address, New BSSID,
+		 * Sequence Number, AP Address, Context Block) */
+		/* TODO: process */
+		break;
+	default:
+		printf("Unknown IAPP command %d\n", hdr->command);
+		break;
+	}
+}
+
+
+struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface)
+{
+	struct ifreq ifr;
+	struct sockaddr_ll addr;
+	int ifindex;
+	struct sockaddr_in *paddr, uaddr;
+	struct iapp_data *iapp;
+	struct ip_mreqn mreq;
+
+	iapp = os_zalloc(sizeof(*iapp));
+	if (iapp == NULL)
+		return NULL;
+	iapp->hapd = hapd;
+	iapp->udp_sock = iapp->packet_sock = -1;
+
+	/* TODO:
+	 * open socket for sending and receiving IAPP frames over TCP
+	 */
+
+	iapp->udp_sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (iapp->udp_sock < 0) {
+		perror("socket[PF_INET,SOCK_DGRAM]");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, iface, sizeof(ifr.ifr_name));
+	if (ioctl(iapp->udp_sock, SIOCGIFINDEX, &ifr) != 0) {
+		perror("ioctl(SIOCGIFINDEX)");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+	ifindex = ifr.ifr_ifindex;
+
+	if (ioctl(iapp->udp_sock, SIOCGIFADDR, &ifr) != 0) {
+		perror("ioctl(SIOCGIFADDR)");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
+	if (paddr->sin_family != AF_INET) {
+		printf("Invalid address family %i (SIOCGIFADDR)\n",
+		       paddr->sin_family);
+		iapp_deinit(iapp);
+		return NULL;
+	}
+	iapp->own.s_addr = paddr->sin_addr.s_addr;
+
+	if (ioctl(iapp->udp_sock, SIOCGIFBRDADDR, &ifr) != 0) {
+		perror("ioctl(SIOCGIFBRDADDR)");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+	paddr = (struct sockaddr_in *) &ifr.ifr_addr;
+	if (paddr->sin_family != AF_INET) {
+		printf("Invalid address family %i (SIOCGIFBRDADDR)\n",
+		       paddr->sin_family);
+		iapp_deinit(iapp);
+		return NULL;
+	}
+	inet_aton(IAPP_MULTICAST, &iapp->multicast);
+
+	os_memset(&uaddr, 0, sizeof(uaddr));
+	uaddr.sin_family = AF_INET;
+	uaddr.sin_port = htons(IAPP_UDP_PORT);
+	if (bind(iapp->udp_sock, (struct sockaddr *) &uaddr,
+		 sizeof(uaddr)) < 0) {
+		perror("bind[UDP]");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+
+	os_memset(&mreq, 0, sizeof(mreq));
+	mreq.imr_multiaddr = iapp->multicast;
+	mreq.imr_address.s_addr = INADDR_ANY;
+	mreq.imr_ifindex = 0;
+	if (setsockopt(iapp->udp_sock, SOL_IP, IP_ADD_MEMBERSHIP, &mreq,
+		       sizeof(mreq)) < 0) {
+		perror("setsockopt[UDP,IP_ADD_MEMBERSHIP]");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+
+	iapp->packet_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+	if (iapp->packet_sock < 0) {
+		perror("socket[PF_PACKET,SOCK_RAW]");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+
+	os_memset(&addr, 0, sizeof(addr));
+	addr.sll_family = AF_PACKET;
+	addr.sll_ifindex = ifindex;
+	if (bind(iapp->packet_sock, (struct sockaddr *) &addr,
+		 sizeof(addr)) < 0) {
+		perror("bind[PACKET]");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+
+	if (eloop_register_read_sock(iapp->udp_sock, iapp_receive_udp,
+				     iapp, NULL)) {
+		printf("Could not register read socket for IAPP.\n");
+		iapp_deinit(iapp);
+		return NULL;
+	}
+
+	printf("IEEE 802.11F (IAPP) using interface %s\n", iface);
+
+	/* TODO: For levels 2 and 3: send RADIUS Initiate-Request, receive
+	 * RADIUS Initiate-Accept or Initiate-Reject. IAPP port should actually
+	 * be openned only after receiving Initiate-Accept. If Initiate-Reject
+	 * is received, IAPP is not started. */
+
+	return iapp;
+}
+
+
+void iapp_deinit(struct iapp_data *iapp)
+{
+	struct ip_mreqn mreq;
+
+	if (iapp == NULL)
+		return;
+
+	if (iapp->udp_sock >= 0) {
+		os_memset(&mreq, 0, sizeof(mreq));
+		mreq.imr_multiaddr = iapp->multicast;
+		mreq.imr_address.s_addr = INADDR_ANY;
+		mreq.imr_ifindex = 0;
+		if (setsockopt(iapp->udp_sock, SOL_IP, IP_DROP_MEMBERSHIP,
+			       &mreq, sizeof(mreq)) < 0) {
+			perror("setsockopt[UDP,IP_DEL_MEMBERSHIP]");
+		}
+
+		eloop_unregister_read_sock(iapp->udp_sock);
+		close(iapp->udp_sock);
+	}
+	if (iapp->packet_sock >= 0) {
+		eloop_unregister_read_sock(iapp->packet_sock);
+		close(iapp->packet_sock);
+	}
+	os_free(iapp);
+}
diff --git a/hostap/src/ap/iapp.h b/hostap/src/ap/iapp.h
new file mode 100644
index 0000000..c221183
--- /dev/null
+++ b/hostap/src/ap/iapp.h
@@ -0,0 +1,39 @@
+/*
+ * hostapd / IEEE 802.11F-2003 Inter-Access Point Protocol (IAPP)
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IAPP_H
+#define IAPP_H
+
+struct iapp_data;
+
+#ifdef CONFIG_IAPP
+
+void iapp_new_station(struct iapp_data *iapp, struct sta_info *sta);
+struct iapp_data * iapp_init(struct hostapd_data *hapd, const char *iface);
+void iapp_deinit(struct iapp_data *iapp);
+
+#else /* CONFIG_IAPP */
+
+static inline void iapp_new_station(struct iapp_data *iapp,
+				    struct sta_info *sta)
+{
+}
+
+static inline struct iapp_data * iapp_init(struct hostapd_data *hapd,
+					   const char *iface)
+{
+	return NULL;
+}
+
+static inline void iapp_deinit(struct iapp_data *iapp)
+{
+}
+
+#endif /* CONFIG_IAPP */
+
+#endif /* IAPP_H */
diff --git a/hostap/src/ap/ieee802_11.c b/hostap/src/ap/ieee802_11.c
new file mode 100644
index 0000000..82004fd
--- /dev/null
+++ b/hostap/src/ap/ieee802_11.c
@@ -0,0 +1,2105 @@
+/*
+ * hostapd / IEEE 802.11 Management
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#ifndef CONFIG_NATIVE_WINDOWS
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/crypto.h"
+#include "drivers/driver.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "common/wpa_ctrl.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+#include "p2p/p2p.h"
+#include "wps/wps.h"
+#include "hostapd.h"
+#include "beacon.h"
+#include "ieee802_11_auth.h"
+#include "sta_info.h"
+#include "ieee802_1x.h"
+#include "wpa_auth.h"
+#include "wmm.h"
+#include "ap_list.h"
+#include "accounting.h"
+#include "ap_config.h"
+#include "ap_mlme.h"
+#include "p2p_hostapd.h"
+#include "ap_drv_ops.h"
+#include "wnm_ap.h"
+#include "ieee802_11.h"
+
+
+u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+	int i, num, count;
+
+	if (hapd->iface->current_rates == NULL)
+		return eid;
+
+	*pos++ = WLAN_EID_SUPP_RATES;
+	num = hapd->iface->num_rates;
+	if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
+		num++;
+	if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
+		num++;
+	if (num > 8) {
+		/* rest of the rates are encoded in Extended supported
+		 * rates element */
+		num = 8;
+	}
+
+	*pos++ = num;
+	count = 0;
+	for (i = 0, count = 0; i < hapd->iface->num_rates && count < num;
+	     i++) {
+		count++;
+		*pos = hapd->iface->current_rates[i].rate / 5;
+		if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
+			*pos |= 0x80;
+		pos++;
+	}
+
+	if (hapd->iconf->ieee80211n && hapd->iconf->require_ht && count < 8) {
+		count++;
+		*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
+	}
+
+	if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht && count < 8) {
+		count++;
+		*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
+	}
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+	int i, num, count;
+
+	if (hapd->iface->current_rates == NULL)
+		return eid;
+
+	num = hapd->iface->num_rates;
+	if (hapd->iconf->ieee80211n && hapd->iconf->require_ht)
+		num++;
+	if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht)
+		num++;
+	if (num <= 8)
+		return eid;
+	num -= 8;
+
+	*pos++ = WLAN_EID_EXT_SUPP_RATES;
+	*pos++ = num;
+	count = 0;
+	for (i = 0, count = 0; i < hapd->iface->num_rates && count < num + 8;
+	     i++) {
+		count++;
+		if (count <= 8)
+			continue; /* already in SuppRates IE */
+		*pos = hapd->iface->current_rates[i].rate / 5;
+		if (hapd->iface->current_rates[i].flags & HOSTAPD_RATE_BASIC)
+			*pos |= 0x80;
+		pos++;
+	}
+
+	if (hapd->iconf->ieee80211n && hapd->iconf->require_ht) {
+		count++;
+		if (count > 8)
+			*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_HT_PHY;
+	}
+
+	if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht) {
+		count++;
+		if (count > 8)
+			*pos++ = 0x80 | BSS_MEMBERSHIP_SELECTOR_VHT_PHY;
+	}
+
+	return pos;
+}
+
+
+u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
+			   int probe)
+{
+	int capab = WLAN_CAPABILITY_ESS;
+	int privacy;
+
+	if (hapd->iface->num_sta_no_short_preamble == 0 &&
+	    hapd->iconf->preamble == SHORT_PREAMBLE)
+		capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
+
+	privacy = hapd->conf->ssid.wep.keys_set;
+
+	if (hapd->conf->ieee802_1x &&
+	    (hapd->conf->default_wep_key_len ||
+	     hapd->conf->individual_wep_key_len))
+		privacy = 1;
+
+	if (hapd->conf->wpa)
+		privacy = 1;
+
+	if (sta) {
+		int policy, def_klen;
+		if (probe && sta->ssid_probe) {
+			policy = sta->ssid_probe->security_policy;
+			def_klen = sta->ssid_probe->wep.default_len;
+		} else {
+			policy = sta->ssid->security_policy;
+			def_klen = sta->ssid->wep.default_len;
+		}
+		privacy = policy != SECURITY_PLAINTEXT;
+		if (policy == SECURITY_IEEE_802_1X && def_klen == 0)
+			privacy = 0;
+	}
+
+	if (privacy)
+		capab |= WLAN_CAPABILITY_PRIVACY;
+
+	if (hapd->iface->current_mode &&
+	    hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G &&
+	    hapd->iface->num_sta_no_short_slot_time == 0)
+		capab |= WLAN_CAPABILITY_SHORT_SLOT_TIME;
+
+	return capab;
+}
+
+
+void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len)
+{
+	int i;
+	if (len > HOSTAPD_MAX_SSID_LEN)
+		len = HOSTAPD_MAX_SSID_LEN;
+	for (i = 0; i < len; i++) {
+		if (ssid[i] >= 32 && ssid[i] < 127)
+			buf[i] = ssid[i];
+		else
+			buf[i] = '.';
+	}
+	buf[len] = '\0';
+}
+
+
+static u16 auth_shared_key(struct hostapd_data *hapd, struct sta_info *sta,
+			   u16 auth_transaction, const u8 *challenge,
+			   int iswep)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "authentication (shared key, transaction %d)",
+		       auth_transaction);
+
+	if (auth_transaction == 1) {
+		if (!sta->challenge) {
+			/* Generate a pseudo-random challenge */
+			u8 key[8];
+			struct os_time now;
+			int r;
+			sta->challenge = os_zalloc(WLAN_AUTH_CHALLENGE_LEN);
+			if (sta->challenge == NULL)
+				return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+			os_get_time(&now);
+			r = os_random();
+			os_memcpy(key, &now.sec, 4);
+			os_memcpy(key + 4, &r, 4);
+			rc4_skip(key, sizeof(key), 0,
+				 sta->challenge, WLAN_AUTH_CHALLENGE_LEN);
+		}
+		return 0;
+	}
+
+	if (auth_transaction != 3)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+	/* Transaction 3 */
+	if (!iswep || !sta->challenge || !challenge ||
+	    os_memcmp(sta->challenge, challenge, WLAN_AUTH_CHALLENGE_LEN)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO,
+			       "shared key authentication - invalid "
+			       "challenge-response");
+		return WLAN_STATUS_CHALLENGE_FAIL;
+	}
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "authentication OK (shared key)");
+#ifdef IEEE80211_REQUIRE_AUTH_ACK
+	/* Station will be marked authenticated if it ACKs the
+	 * authentication reply. */
+#else
+	sta->flags |= WLAN_STA_AUTH;
+	wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+#endif
+	os_free(sta->challenge);
+	sta->challenge = NULL;
+
+	return 0;
+}
+
+
+static void send_auth_reply(struct hostapd_data *hapd,
+			    const u8 *dst, const u8 *bssid,
+			    u16 auth_alg, u16 auth_transaction, u16 resp,
+			    const u8 *ies, size_t ies_len)
+{
+	struct ieee80211_mgmt *reply;
+	u8 *buf;
+	size_t rlen;
+
+	rlen = IEEE80211_HDRLEN + sizeof(reply->u.auth) + ies_len;
+	buf = os_zalloc(rlen);
+	if (buf == NULL)
+		return;
+
+	reply = (struct ieee80211_mgmt *) buf;
+	reply->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					    WLAN_FC_STYPE_AUTH);
+	os_memcpy(reply->da, dst, ETH_ALEN);
+	os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(reply->bssid, bssid, ETH_ALEN);
+
+	reply->u.auth.auth_alg = host_to_le16(auth_alg);
+	reply->u.auth.auth_transaction = host_to_le16(auth_transaction);
+	reply->u.auth.status_code = host_to_le16(resp);
+
+	if (ies && ies_len)
+		os_memcpy(reply->u.auth.variable, ies, ies_len);
+
+	wpa_printf(MSG_DEBUG, "authentication reply: STA=" MACSTR
+		   " auth_alg=%d auth_transaction=%d resp=%d (IE len=%lu)",
+		   MAC2STR(dst), auth_alg, auth_transaction,
+		   resp, (unsigned long) ies_len);
+	if (hostapd_drv_send_mlme(hapd, reply, rlen, 0) < 0)
+		perror("send_auth_reply: send");
+
+	os_free(buf);
+}
+
+
+#ifdef CONFIG_IEEE80211R
+static void handle_auth_ft_finish(void *ctx, const u8 *dst, const u8 *bssid,
+				  u16 auth_transaction, u16 status,
+				  const u8 *ies, size_t ies_len)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	send_auth_reply(hapd, dst, bssid, WLAN_AUTH_FT, auth_transaction,
+			status, ies, ies_len);
+
+	if (status != WLAN_STATUS_SUCCESS)
+		return;
+
+	sta = ap_get_sta(hapd, dst);
+	if (sta == NULL)
+		return;
+
+	hostapd_logger(hapd, dst, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG, "authentication OK (FT)");
+	sta->flags |= WLAN_STA_AUTH;
+	mlme_authenticate_indication(hapd, sta);
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+#ifdef CONFIG_SAE
+
+static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
+					     struct sta_info *sta)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(2);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_le16(buf, 19); /* Finite Cyclic Group */
+	/* TODO: Anti-Clogging Token (if requested) */
+	/* TODO: Scalar */
+	/* TODO: Element */
+
+	return buf;
+}
+
+
+static struct wpabuf * auth_build_sae_confirm(struct hostapd_data *hapd,
+					      struct sta_info *sta)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(2);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_le16(buf, sta->sae_send_confirm);
+	sta->sae_send_confirm++;
+	/* TODO: Confirm */
+
+	return buf;
+}
+
+
+static u16 handle_sae_commit(struct hostapd_data *hapd, struct sta_info *sta,
+			     const u8 *data, size_t len)
+{
+	wpa_hexdump(MSG_DEBUG, "SAE commit fields", data, len);
+
+	/* Check Finite Cyclic Group */
+	if (len < 2)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	if (WPA_GET_LE16(data) != 19) {
+		wpa_printf(MSG_DEBUG, "SAE: Unsupported Finite Cyclic Group %u",
+			   WPA_GET_LE16(data));
+		return WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED;
+	}
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 handle_sae_confirm(struct hostapd_data *hapd, struct sta_info *sta,
+			      const u8 *data, size_t len)
+{
+	u16 rc;
+
+	wpa_hexdump(MSG_DEBUG, "SAE confirm fields", data, len);
+
+	if (len < 2)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	rc = WPA_GET_LE16(data);
+	wpa_printf(MSG_DEBUG, "SAE: peer-send-confirm %u", rc);
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+static void handle_auth_sae(struct hostapd_data *hapd, struct sta_info *sta,
+			    const struct ieee80211_mgmt *mgmt, size_t len,
+			    u8 auth_transaction)
+{
+	u16 resp = WLAN_STATUS_SUCCESS;
+	struct wpabuf *data;
+
+	if (auth_transaction == 1) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "start SAE authentication (RX commit)");
+		resp = handle_sae_commit(hapd, sta, mgmt->u.auth.variable,
+					 ((u8 *) mgmt) + len -
+					 mgmt->u.auth.variable);
+		if (resp == WLAN_STATUS_SUCCESS)
+			sta->sae_state = SAE_COMMIT;
+	} else if (auth_transaction == 2) {
+		if (sta->sae_state != SAE_COMMIT) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "SAE confirm before commit");
+			resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+		}
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "SAE authentication (RX confirm)");
+		resp = handle_sae_confirm(hapd, sta, mgmt->u.auth.variable,
+					  ((u8 *) mgmt) + len -
+					  mgmt->u.auth.variable);
+		if (resp == WLAN_STATUS_SUCCESS) {
+			sta->flags |= WLAN_STA_AUTH;
+			wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+			sta->auth_alg = WLAN_AUTH_SAE;
+			mlme_authenticate_indication(hapd, sta);
+		}
+	} else {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "unexpected SAE authentication transaction %u",
+			       auth_transaction);
+		resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+	}
+
+	sta->auth_alg = WLAN_AUTH_SAE;
+
+	if (resp == WLAN_STATUS_SUCCESS) {
+		if (auth_transaction == 1)
+			data = auth_build_sae_commit(hapd, sta);
+		else
+			data = auth_build_sae_confirm(hapd, sta);
+		if (data == NULL)
+			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+	} else
+		data = NULL;
+
+	send_auth_reply(hapd, mgmt->sa, mgmt->bssid, WLAN_AUTH_SAE,
+			auth_transaction, resp,
+			data ? wpabuf_head(data) : (u8 *) "",
+			data ? wpabuf_len(data) : 0);
+	wpabuf_free(data);
+}
+#endif /* CONFIG_SAE */
+
+
+static void handle_auth(struct hostapd_data *hapd,
+			const struct ieee80211_mgmt *mgmt, size_t len)
+{
+	u16 auth_alg, auth_transaction, status_code;
+	u16 resp = WLAN_STATUS_SUCCESS;
+	struct sta_info *sta = NULL;
+	int res;
+	u16 fc;
+	const u8 *challenge = NULL;
+	u32 session_timeout, acct_interim_interval;
+	int vlan_id = 0;
+	struct hostapd_sta_wpa_psk_short *psk = NULL;
+	u8 resp_ies[2 + WLAN_AUTH_CHALLENGE_LEN];
+	size_t resp_ies_len = 0;
+	char *identity = NULL;
+	char *radius_cui = NULL;
+
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
+		printf("handle_auth - too short payload (len=%lu)\n",
+		       (unsigned long) len);
+		return;
+	}
+
+	auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
+	auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
+	status_code = le_to_host16(mgmt->u.auth.status_code);
+	fc = le_to_host16(mgmt->frame_control);
+
+	if (len >= IEEE80211_HDRLEN + sizeof(mgmt->u.auth) +
+	    2 + WLAN_AUTH_CHALLENGE_LEN &&
+	    mgmt->u.auth.variable[0] == WLAN_EID_CHALLENGE &&
+	    mgmt->u.auth.variable[1] == WLAN_AUTH_CHALLENGE_LEN)
+		challenge = &mgmt->u.auth.variable[2];
+
+	wpa_printf(MSG_DEBUG, "authentication: STA=" MACSTR " auth_alg=%d "
+		   "auth_transaction=%d status_code=%d wep=%d%s",
+		   MAC2STR(mgmt->sa), auth_alg, auth_transaction,
+		   status_code, !!(fc & WLAN_FC_ISWEP),
+		   challenge ? " challenge" : "");
+
+	if (hapd->tkip_countermeasures) {
+		resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
+		goto fail;
+	}
+
+	if (!(((hapd->conf->auth_algs & WPA_AUTH_ALG_OPEN) &&
+	       auth_alg == WLAN_AUTH_OPEN) ||
+#ifdef CONFIG_IEEE80211R
+	      (hapd->conf->wpa && wpa_key_mgmt_ft(hapd->conf->wpa_key_mgmt) &&
+	       auth_alg == WLAN_AUTH_FT) ||
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+	      (hapd->conf->wpa && wpa_key_mgmt_sae(hapd->conf->wpa_key_mgmt) &&
+	       auth_alg == WLAN_AUTH_SAE) ||
+#endif /* CONFIG_SAE */
+	      ((hapd->conf->auth_algs & WPA_AUTH_ALG_SHARED) &&
+	       auth_alg == WLAN_AUTH_SHARED_KEY))) {
+		printf("Unsupported authentication algorithm (%d)\n",
+		       auth_alg);
+		resp = WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
+		goto fail;
+	}
+
+	if (!(auth_transaction == 1 || auth_alg == WLAN_AUTH_SAE ||
+	      (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 3))) {
+		printf("Unknown authentication transaction number (%d)\n",
+		       auth_transaction);
+		resp = WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION;
+		goto fail;
+	}
+
+	if (os_memcmp(mgmt->sa, hapd->own_addr, ETH_ALEN) == 0) {
+		printf("Station " MACSTR " not allowed to authenticate.\n",
+		       MAC2STR(mgmt->sa));
+		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto fail;
+	}
+
+	res = hostapd_allowed_address(hapd, mgmt->sa, (u8 *) mgmt, len,
+				      &session_timeout,
+				      &acct_interim_interval, &vlan_id,
+				      &psk, &identity, &radius_cui);
+
+	if (res == HOSTAPD_ACL_REJECT) {
+		printf("Station " MACSTR " not allowed to authenticate.\n",
+		       MAC2STR(mgmt->sa));
+		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto fail;
+	}
+	if (res == HOSTAPD_ACL_PENDING) {
+		wpa_printf(MSG_DEBUG, "Authentication frame from " MACSTR
+			   " waiting for an external authentication",
+			   MAC2STR(mgmt->sa));
+		/* Authentication code will re-send the authentication frame
+		 * after it has received (and cached) information from the
+		 * external source. */
+		return;
+	}
+
+	sta = ap_sta_add(hapd, mgmt->sa);
+	if (!sta) {
+		resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+		goto fail;
+	}
+
+	if (vlan_id > 0) {
+		if (hostapd_get_vlan_id_ifname(hapd->conf->vlan,
+					       vlan_id) == NULL) {
+			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+				       HOSTAPD_LEVEL_INFO, "Invalid VLAN ID "
+				       "%d received from RADIUS server",
+				       vlan_id);
+			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto fail;
+		}
+		sta->vlan_id = vlan_id;
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_RADIUS,
+			       HOSTAPD_LEVEL_INFO, "VLAN ID %d", sta->vlan_id);
+	}
+
+	hostapd_free_psk_list(sta->psk);
+	if (hapd->conf->wpa_psk_radius != PSK_RADIUS_IGNORED) {
+		sta->psk = psk;
+		psk = NULL;
+	} else {
+		sta->psk = NULL;
+	}
+
+	sta->identity = identity;
+	identity = NULL;
+	sta->radius_cui = radius_cui;
+	radius_cui = NULL;
+
+	sta->flags &= ~WLAN_STA_PREAUTH;
+	ieee802_1x_notify_pre_auth(sta->eapol_sm, 0);
+
+	if (hapd->conf->acct_interim_interval == 0 && acct_interim_interval)
+		sta->acct_interim_interval = acct_interim_interval;
+	if (res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
+		ap_sta_session_timeout(hapd, sta, session_timeout);
+	else
+		ap_sta_no_session_timeout(hapd, sta);
+
+	switch (auth_alg) {
+	case WLAN_AUTH_OPEN:
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "authentication OK (open system)");
+#ifdef IEEE80211_REQUIRE_AUTH_ACK
+		/* Station will be marked authenticated if it ACKs the
+		 * authentication reply. */
+#else
+		sta->flags |= WLAN_STA_AUTH;
+		wpa_auth_sm_event(sta->wpa_sm, WPA_AUTH);
+		sta->auth_alg = WLAN_AUTH_OPEN;
+		mlme_authenticate_indication(hapd, sta);
+#endif
+		break;
+	case WLAN_AUTH_SHARED_KEY:
+		resp = auth_shared_key(hapd, sta, auth_transaction, challenge,
+				       fc & WLAN_FC_ISWEP);
+		sta->auth_alg = WLAN_AUTH_SHARED_KEY;
+		mlme_authenticate_indication(hapd, sta);
+		if (sta->challenge && auth_transaction == 1) {
+			resp_ies[0] = WLAN_EID_CHALLENGE;
+			resp_ies[1] = WLAN_AUTH_CHALLENGE_LEN;
+			os_memcpy(resp_ies + 2, sta->challenge,
+				  WLAN_AUTH_CHALLENGE_LEN);
+			resp_ies_len = 2 + WLAN_AUTH_CHALLENGE_LEN;
+		}
+		break;
+#ifdef CONFIG_IEEE80211R
+	case WLAN_AUTH_FT:
+		sta->auth_alg = WLAN_AUTH_FT;
+		if (sta->wpa_sm == NULL)
+			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+							sta->addr);
+		if (sta->wpa_sm == NULL) {
+			wpa_printf(MSG_DEBUG, "FT: Failed to initialize WPA "
+				   "state machine");
+			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+			goto fail;
+		}
+		wpa_ft_process_auth(sta->wpa_sm, mgmt->bssid,
+				    auth_transaction, mgmt->u.auth.variable,
+				    len - IEEE80211_HDRLEN -
+				    sizeof(mgmt->u.auth),
+				    handle_auth_ft_finish, hapd);
+		/* handle_auth_ft_finish() callback will complete auth. */
+		return;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_SAE
+	case WLAN_AUTH_SAE:
+		handle_auth_sae(hapd, sta, mgmt, len, auth_transaction);
+		return;
+#endif /* CONFIG_SAE */
+	}
+
+ fail:
+	os_free(identity);
+	os_free(radius_cui);
+	hostapd_free_psk_list(psk);
+
+	send_auth_reply(hapd, mgmt->sa, mgmt->bssid, auth_alg,
+			auth_transaction + 1, resp, resp_ies, resp_ies_len);
+}
+
+
+static int hostapd_get_aid(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	int i, j = 32, aid;
+
+	/* get a unique AID */
+	if (sta->aid > 0) {
+		wpa_printf(MSG_DEBUG, "  old AID %d", sta->aid);
+		return 0;
+	}
+
+	for (i = 0; i < AID_WORDS; i++) {
+		if (hapd->sta_aid[i] == (u32) -1)
+			continue;
+		for (j = 0; j < 32; j++) {
+			if (!(hapd->sta_aid[i] & BIT(j)))
+				break;
+		}
+		if (j < 32)
+			break;
+	}
+	if (j == 32)
+		return -1;
+	aid = i * 32 + j + 1;
+	if (aid > 2007)
+		return -1;
+
+	sta->aid = aid;
+	hapd->sta_aid[i] |= BIT(j);
+	wpa_printf(MSG_DEBUG, "  new AID %d", sta->aid);
+	return 0;
+}
+
+
+static u16 check_ssid(struct hostapd_data *hapd, struct sta_info *sta,
+		      const u8 *ssid_ie, size_t ssid_ie_len)
+{
+	if (ssid_ie == NULL)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+	if (ssid_ie_len != hapd->conf->ssid.ssid_len ||
+	    os_memcmp(ssid_ie, hapd->conf->ssid.ssid, ssid_ie_len) != 0) {
+		char ssid_txt[33];
+		ieee802_11_print_ssid(ssid_txt, ssid_ie, ssid_ie_len);
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO,
+			       "Station tried to associate with unknown SSID "
+			       "'%s'", ssid_txt);
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 check_wmm(struct hostapd_data *hapd, struct sta_info *sta,
+		     const u8 *wmm_ie, size_t wmm_ie_len)
+{
+	sta->flags &= ~WLAN_STA_WMM;
+	sta->qosinfo = 0;
+	if (wmm_ie && hapd->conf->wmm_enabled) {
+		struct wmm_information_element *wmm;
+
+		if (!hostapd_eid_wmm_valid(hapd, wmm_ie, wmm_ie_len)) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_WPA,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "invalid WMM element in association "
+				       "request");
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		}
+
+		sta->flags |= WLAN_STA_WMM;
+		wmm = (struct wmm_information_element *) wmm_ie;
+		sta->qosinfo = wmm->qos_info;
+	}
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 copy_supp_rates(struct hostapd_data *hapd, struct sta_info *sta,
+			   struct ieee802_11_elems *elems)
+{
+	if (!elems->supp_rates) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "No supported rates element in AssocReq");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	if (elems->supp_rates_len + elems->ext_supp_rates_len >
+	    sizeof(sta->supported_rates)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Invalid supported rates element length %d+%d",
+			       elems->supp_rates_len,
+			       elems->ext_supp_rates_len);
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	sta->supported_rates_len = merge_byte_arrays(
+		sta->supported_rates, sizeof(sta->supported_rates),
+		elems->supp_rates, elems->supp_rates_len,
+		elems->ext_supp_rates, elems->ext_supp_rates_len);
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+static u16 check_assoc_ies(struct hostapd_data *hapd, struct sta_info *sta,
+			   const u8 *ies, size_t ies_len, int reassoc)
+{
+	struct ieee802_11_elems elems;
+	u16 resp;
+	const u8 *wpa_ie;
+	size_t wpa_ie_len;
+
+	if (ieee802_11_parse_elems(ies, ies_len, &elems, 1) == ParseFailed) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "Station sent an invalid "
+			       "association request");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	resp = check_ssid(hapd, sta, elems.ssid, elems.ssid_len);
+	if (resp != WLAN_STATUS_SUCCESS)
+		return resp;
+	resp = check_wmm(hapd, sta, elems.wmm, elems.wmm_len);
+	if (resp != WLAN_STATUS_SUCCESS)
+		return resp;
+	resp = copy_supp_rates(hapd, sta, &elems);
+	if (resp != WLAN_STATUS_SUCCESS)
+		return resp;
+#ifdef CONFIG_IEEE80211N
+	resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities,
+				 elems.ht_capabilities_len);
+	if (resp != WLAN_STATUS_SUCCESS)
+		return resp;
+	if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
+	    !(sta->flags & WLAN_STA_HT)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "Station does not support "
+			       "mandatory HT PHY - reject association");
+		return WLAN_STATUS_ASSOC_DENIED_NO_HT;
+	}
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_IEEE80211AC
+	resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities,
+				  elems.vht_capabilities_len);
+	if (resp != WLAN_STATUS_SUCCESS)
+		return resp;
+	if (hapd->iconf->ieee80211ac && hapd->iconf->require_vht &&
+	    !(sta->flags & WLAN_STA_VHT)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "Station does not support "
+			       "mandatory VHT PHY - reject association");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+#endif /* CONFIG_IEEE80211AC */
+
+	if ((hapd->conf->wpa & WPA_PROTO_RSN) && elems.rsn_ie) {
+		wpa_ie = elems.rsn_ie;
+		wpa_ie_len = elems.rsn_ie_len;
+	} else if ((hapd->conf->wpa & WPA_PROTO_WPA) &&
+		   elems.wpa_ie) {
+		wpa_ie = elems.wpa_ie;
+		wpa_ie_len = elems.wpa_ie_len;
+	} else {
+		wpa_ie = NULL;
+		wpa_ie_len = 0;
+	}
+
+#ifdef CONFIG_WPS
+	sta->flags &= ~(WLAN_STA_WPS | WLAN_STA_MAYBE_WPS | WLAN_STA_WPS2);
+	if (hapd->conf->wps_state && elems.wps_ie) {
+		wpa_printf(MSG_DEBUG, "STA included WPS IE in (Re)Association "
+			   "Request - assume WPS is used");
+		sta->flags |= WLAN_STA_WPS;
+		wpabuf_free(sta->wps_ie);
+		sta->wps_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
+							  WPS_IE_VENDOR_TYPE);
+		if (sta->wps_ie && wps_is_20(sta->wps_ie)) {
+			wpa_printf(MSG_DEBUG, "WPS: STA supports WPS 2.0");
+			sta->flags |= WLAN_STA_WPS2;
+		}
+		wpa_ie = NULL;
+		wpa_ie_len = 0;
+		if (sta->wps_ie && wps_validate_assoc_req(sta->wps_ie) < 0) {
+			wpa_printf(MSG_DEBUG, "WPS: Invalid WPS IE in "
+				   "(Re)Association Request - reject");
+			return WLAN_STATUS_INVALID_IE;
+		}
+	} else if (hapd->conf->wps_state && wpa_ie == NULL) {
+		wpa_printf(MSG_DEBUG, "STA did not include WPA/RSN IE in "
+			   "(Re)Association Request - possible WPS use");
+		sta->flags |= WLAN_STA_MAYBE_WPS;
+	} else
+#endif /* CONFIG_WPS */
+	if (hapd->conf->wpa && wpa_ie == NULL) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO,
+			       "No WPA/RSN IE in association request");
+		return WLAN_STATUS_INVALID_IE;
+	}
+
+	if (hapd->conf->wpa && wpa_ie) {
+		int res;
+		wpa_ie -= 2;
+		wpa_ie_len += 2;
+		if (sta->wpa_sm == NULL)
+			sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth,
+							sta->addr);
+		if (sta->wpa_sm == NULL) {
+			wpa_printf(MSG_WARNING, "Failed to initialize WPA "
+				   "state machine");
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+		}
+		res = wpa_validate_wpa_ie(hapd->wpa_auth, sta->wpa_sm,
+					  wpa_ie, wpa_ie_len,
+					  elems.mdie, elems.mdie_len);
+		if (res == WPA_INVALID_GROUP)
+			resp = WLAN_STATUS_GROUP_CIPHER_NOT_VALID;
+		else if (res == WPA_INVALID_PAIRWISE)
+			resp = WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID;
+		else if (res == WPA_INVALID_AKMP)
+			resp = WLAN_STATUS_AKMP_NOT_VALID;
+		else if (res == WPA_ALLOC_FAIL)
+			resp = WLAN_STATUS_UNSPECIFIED_FAILURE;
+#ifdef CONFIG_IEEE80211W
+		else if (res == WPA_MGMT_FRAME_PROTECTION_VIOLATION)
+			resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+		else if (res == WPA_INVALID_MGMT_GROUP_CIPHER)
+			resp = WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION;
+#endif /* CONFIG_IEEE80211W */
+		else if (res == WPA_INVALID_MDIE)
+			resp = WLAN_STATUS_INVALID_MDIE;
+		else if (res != WPA_IE_OK)
+			resp = WLAN_STATUS_INVALID_IE;
+		if (resp != WLAN_STATUS_SUCCESS)
+			return resp;
+#ifdef CONFIG_IEEE80211W
+		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+		    sta->sa_query_count > 0)
+			ap_check_sa_query_timeout(hapd, sta);
+		if ((sta->flags & WLAN_STA_MFP) && !sta->sa_query_timed_out &&
+		    (!reassoc || sta->auth_alg != WLAN_AUTH_FT)) {
+			/*
+			 * STA has already been associated with MFP and SA
+			 * Query timeout has not been reached. Reject the
+			 * association attempt temporarily and start SA Query,
+			 * if one is not pending.
+			 */
+
+			if (sta->sa_query_count == 0)
+				ap_sta_start_sa_query(hapd, sta);
+
+			return WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY;
+		}
+
+		if (wpa_auth_uses_mfp(sta->wpa_sm))
+			sta->flags |= WLAN_STA_MFP;
+		else
+			sta->flags &= ~WLAN_STA_MFP;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_IEEE80211R
+		if (sta->auth_alg == WLAN_AUTH_FT) {
+			if (!reassoc) {
+				wpa_printf(MSG_DEBUG, "FT: " MACSTR " tried "
+					   "to use association (not "
+					   "re-association) with FT auth_alg",
+					   MAC2STR(sta->addr));
+				return WLAN_STATUS_UNSPECIFIED_FAILURE;
+			}
+
+			resp = wpa_ft_validate_reassoc(sta->wpa_sm, ies,
+						       ies_len);
+			if (resp != WLAN_STATUS_SUCCESS)
+				return resp;
+		}
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_SAE
+		if (wpa_auth_uses_sae(sta->wpa_sm) &&
+		    sta->auth_alg != WLAN_AUTH_SAE) {
+			wpa_printf(MSG_DEBUG, "SAE: " MACSTR " tried to use "
+				   "SAE AKM after non-SAE auth_alg %u",
+				   MAC2STR(sta->addr), sta->auth_alg);
+			return WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG;
+		}
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_IEEE80211N
+		if ((sta->flags & (WLAN_STA_HT | WLAN_STA_VHT)) &&
+		    wpa_auth_get_pairwise(sta->wpa_sm) == WPA_CIPHER_TKIP) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_INFO,
+				       "Station tried to use TKIP with HT "
+				       "association");
+			return WLAN_STATUS_CIPHER_REJECTED_PER_POLICY;
+		}
+#endif /* CONFIG_IEEE80211N */
+	} else
+		wpa_auth_sta_no_wpa(sta->wpa_sm);
+
+#ifdef CONFIG_P2P
+	if (elems.p2p) {
+		wpabuf_free(sta->p2p_ie);
+		sta->p2p_ie = ieee802_11_vendor_ie_concat(ies, ies_len,
+							  P2P_IE_VENDOR_TYPE);
+
+	} else {
+		wpabuf_free(sta->p2p_ie);
+		sta->p2p_ie = NULL;
+	}
+
+	p2p_group_notif_assoc(hapd->p2p_group, sta->addr, ies, ies_len);
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_HS20
+	wpabuf_free(sta->hs20_ie);
+	if (elems.hs20 && elems.hs20_len > 4) {
+		sta->hs20_ie = wpabuf_alloc_copy(elems.hs20 + 4,
+						 elems.hs20_len - 4);
+	} else
+		sta->hs20_ie = NULL;
+#endif /* CONFIG_HS20 */
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+static void send_deauth(struct hostapd_data *hapd, const u8 *addr,
+			u16 reason_code)
+{
+	int send_len;
+	struct ieee80211_mgmt reply;
+
+	os_memset(&reply, 0, sizeof(reply));
+	reply.frame_control =
+		IEEE80211_FC(WLAN_FC_TYPE_MGMT, WLAN_FC_STYPE_DEAUTH);
+	os_memcpy(reply.da, addr, ETH_ALEN);
+	os_memcpy(reply.sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(reply.bssid, hapd->own_addr, ETH_ALEN);
+
+	send_len = IEEE80211_HDRLEN + sizeof(reply.u.deauth);
+	reply.u.deauth.reason_code = host_to_le16(reason_code);
+
+	if (hostapd_drv_send_mlme(hapd, &reply, send_len, 0) < 0)
+		wpa_printf(MSG_INFO, "Failed to send deauth: %s",
+			   strerror(errno));
+}
+
+
+static void send_assoc_resp(struct hostapd_data *hapd, struct sta_info *sta,
+			    u16 status_code, int reassoc, const u8 *ies,
+			    size_t ies_len)
+{
+	int send_len;
+	u8 buf[sizeof(struct ieee80211_mgmt) + 1024];
+	struct ieee80211_mgmt *reply;
+	u8 *p;
+
+	os_memset(buf, 0, sizeof(buf));
+	reply = (struct ieee80211_mgmt *) buf;
+	reply->frame_control =
+		IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+			     (reassoc ? WLAN_FC_STYPE_REASSOC_RESP :
+			      WLAN_FC_STYPE_ASSOC_RESP));
+	os_memcpy(reply->da, sta->addr, ETH_ALEN);
+	os_memcpy(reply->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(reply->bssid, hapd->own_addr, ETH_ALEN);
+
+	send_len = IEEE80211_HDRLEN;
+	send_len += sizeof(reply->u.assoc_resp);
+	reply->u.assoc_resp.capab_info =
+		host_to_le16(hostapd_own_capab_info(hapd, sta, 0));
+	reply->u.assoc_resp.status_code = host_to_le16(status_code);
+	reply->u.assoc_resp.aid = host_to_le16((sta ? sta->aid : 0)
+					       | BIT(14) | BIT(15));
+	/* Supported rates */
+	p = hostapd_eid_supp_rates(hapd, reply->u.assoc_resp.variable);
+	/* Extended supported rates */
+	p = hostapd_eid_ext_supp_rates(hapd, p);
+
+#ifdef CONFIG_IEEE80211R
+	if (status_code == WLAN_STATUS_SUCCESS) {
+		/* IEEE 802.11r: Mobility Domain Information, Fast BSS
+		 * Transition Information, RSN, [RIC Response] */
+		p = wpa_sm_write_assoc_resp_ies(sta->wpa_sm, p,
+						buf + sizeof(buf) - p,
+						sta->auth_alg, ies, ies_len);
+	}
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211W
+	if (status_code == WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY)
+		p = hostapd_eid_assoc_comeback_time(hapd, sta, p);
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_IEEE80211N
+	p = hostapd_eid_ht_capabilities(hapd, p);
+	p = hostapd_eid_ht_operation(hapd, p);
+#endif /* CONFIG_IEEE80211N */
+
+#ifdef CONFIG_IEEE80211AC
+	p = hostapd_eid_vht_capabilities(hapd, p);
+	p = hostapd_eid_vht_operation(hapd, p);
+#endif /* CONFIG_IEEE80211AC */
+
+	p = hostapd_eid_ext_capab(hapd, p);
+	p = hostapd_eid_bss_max_idle_period(hapd, p);
+
+	if (sta->flags & WLAN_STA_WMM)
+		p = hostapd_eid_wmm(hapd, p);
+
+#ifdef CONFIG_WPS
+	if ((sta->flags & WLAN_STA_WPS) ||
+	    ((sta->flags & WLAN_STA_MAYBE_WPS) && hapd->conf->wpa)) {
+		struct wpabuf *wps = wps_build_assoc_resp_ie();
+		if (wps) {
+			os_memcpy(p, wpabuf_head(wps), wpabuf_len(wps));
+			p += wpabuf_len(wps);
+			wpabuf_free(wps);
+		}
+	}
+#endif /* CONFIG_WPS */
+
+#ifdef CONFIG_P2P
+	if (sta->p2p_ie) {
+		struct wpabuf *p2p_resp_ie;
+		enum p2p_status_code status;
+		switch (status_code) {
+		case WLAN_STATUS_SUCCESS:
+			status = P2P_SC_SUCCESS;
+			break;
+		case WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
+			status = P2P_SC_FAIL_LIMIT_REACHED;
+			break;
+		default:
+			status = P2P_SC_FAIL_INVALID_PARAMS;
+			break;
+		}
+		p2p_resp_ie = p2p_group_assoc_resp_ie(hapd->p2p_group, status);
+		if (p2p_resp_ie) {
+			os_memcpy(p, wpabuf_head(p2p_resp_ie),
+				  wpabuf_len(p2p_resp_ie));
+			p += wpabuf_len(p2p_resp_ie);
+			wpabuf_free(p2p_resp_ie);
+		}
+	}
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_P2P_MANAGER
+	if (hapd->conf->p2p & P2P_MANAGE)
+		p = hostapd_eid_p2p_manage(hapd, p);
+#endif /* CONFIG_P2P_MANAGER */
+
+	send_len += p - reply->u.assoc_resp.variable;
+
+	if (hostapd_drv_send_mlme(hapd, reply, send_len, 0) < 0)
+		wpa_printf(MSG_INFO, "Failed to send assoc resp: %s",
+			   strerror(errno));
+}
+
+
+static void handle_assoc(struct hostapd_data *hapd,
+			 const struct ieee80211_mgmt *mgmt, size_t len,
+			 int reassoc)
+{
+	u16 capab_info, listen_interval;
+	u16 resp = WLAN_STATUS_SUCCESS;
+	const u8 *pos;
+	int left, i;
+	struct sta_info *sta;
+
+	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_req) :
+				      sizeof(mgmt->u.assoc_req))) {
+		printf("handle_assoc(reassoc=%d) - too short payload (len=%lu)"
+		       "\n", reassoc, (unsigned long) len);
+		return;
+	}
+
+	if (reassoc) {
+		capab_info = le_to_host16(mgmt->u.reassoc_req.capab_info);
+		listen_interval = le_to_host16(
+			mgmt->u.reassoc_req.listen_interval);
+		wpa_printf(MSG_DEBUG, "reassociation request: STA=" MACSTR
+			   " capab_info=0x%02x listen_interval=%d current_ap="
+			   MACSTR,
+			   MAC2STR(mgmt->sa), capab_info, listen_interval,
+			   MAC2STR(mgmt->u.reassoc_req.current_ap));
+		left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.reassoc_req));
+		pos = mgmt->u.reassoc_req.variable;
+	} else {
+		capab_info = le_to_host16(mgmt->u.assoc_req.capab_info);
+		listen_interval = le_to_host16(
+			mgmt->u.assoc_req.listen_interval);
+		wpa_printf(MSG_DEBUG, "association request: STA=" MACSTR
+			   " capab_info=0x%02x listen_interval=%d",
+			   MAC2STR(mgmt->sa), capab_info, listen_interval);
+		left = len - (IEEE80211_HDRLEN + sizeof(mgmt->u.assoc_req));
+		pos = mgmt->u.assoc_req.variable;
+	}
+
+	sta = ap_get_sta(hapd, mgmt->sa);
+#ifdef CONFIG_IEEE80211R
+	if (sta && sta->auth_alg == WLAN_AUTH_FT &&
+	    (sta->flags & WLAN_STA_AUTH) == 0) {
+		wpa_printf(MSG_DEBUG, "FT: Allow STA " MACSTR " to associate "
+			   "prior to authentication since it is using "
+			   "over-the-DS FT", MAC2STR(mgmt->sa));
+	} else
+#endif /* CONFIG_IEEE80211R */
+	if (sta == NULL || (sta->flags & WLAN_STA_AUTH) == 0) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "Station tried to "
+			       "associate before authentication "
+			       "(aid=%d flags=0x%x)",
+			       sta ? sta->aid : -1,
+			       sta ? sta->flags : 0);
+		send_deauth(hapd, mgmt->sa,
+			    WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA);
+		return;
+	}
+
+	if (hapd->tkip_countermeasures) {
+		resp = WLAN_REASON_MICHAEL_MIC_FAILURE;
+		goto fail;
+	}
+
+	if (listen_interval > hapd->conf->max_listen_interval) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Too large Listen Interval (%d)",
+			       listen_interval);
+		resp = WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE;
+		goto fail;
+	}
+
+	/* followed by SSID and Supported rates; and HT capabilities if 802.11n
+	 * is used */
+	resp = check_assoc_ies(hapd, sta, pos, left, reassoc);
+	if (resp != WLAN_STATUS_SUCCESS)
+		goto fail;
+
+	if (hostapd_get_aid(hapd, sta) < 0) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "No room for more AIDs");
+		resp = WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA;
+		goto fail;
+	}
+
+	sta->capability = capab_info;
+	sta->listen_interval = listen_interval;
+
+	if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G)
+		sta->flags |= WLAN_STA_NONERP;
+	for (i = 0; i < sta->supported_rates_len; i++) {
+		if ((sta->supported_rates[i] & 0x7f) > 22) {
+			sta->flags &= ~WLAN_STA_NONERP;
+			break;
+		}
+	}
+	if (sta->flags & WLAN_STA_NONERP && !sta->nonerp_set) {
+		sta->nonerp_set = 1;
+		hapd->iface->num_sta_non_erp++;
+		if (hapd->iface->num_sta_non_erp == 1)
+			ieee802_11_set_beacons(hapd->iface);
+	}
+
+	if (!(sta->capability & WLAN_CAPABILITY_SHORT_SLOT_TIME) &&
+	    !sta->no_short_slot_time_set) {
+		sta->no_short_slot_time_set = 1;
+		hapd->iface->num_sta_no_short_slot_time++;
+		if (hapd->iface->current_mode->mode ==
+		    HOSTAPD_MODE_IEEE80211G &&
+		    hapd->iface->num_sta_no_short_slot_time == 1)
+			ieee802_11_set_beacons(hapd->iface);
+	}
+
+	if (sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE)
+		sta->flags |= WLAN_STA_SHORT_PREAMBLE;
+	else
+		sta->flags &= ~WLAN_STA_SHORT_PREAMBLE;
+
+	if (!(sta->capability & WLAN_CAPABILITY_SHORT_PREAMBLE) &&
+	    !sta->no_short_preamble_set) {
+		sta->no_short_preamble_set = 1;
+		hapd->iface->num_sta_no_short_preamble++;
+		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+		    && hapd->iface->num_sta_no_short_preamble == 1)
+			ieee802_11_set_beacons(hapd->iface);
+	}
+
+#ifdef CONFIG_IEEE80211N
+	update_ht_state(hapd, sta);
+#endif /* CONFIG_IEEE80211N */
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "association OK (aid %d)", sta->aid);
+	/* Station will be marked associated, after it acknowledges AssocResp
+	 */
+	sta->flags |= WLAN_STA_ASSOC_REQ_OK;
+
+#ifdef CONFIG_IEEE80211W
+	if ((sta->flags & WLAN_STA_MFP) && sta->sa_query_timed_out) {
+		wpa_printf(MSG_DEBUG, "Allowing %sassociation after timed out "
+			   "SA Query procedure", reassoc ? "re" : "");
+		/* TODO: Send a protected Disassociate frame to the STA using
+		 * the old key and Reason Code "Previous Authentication no
+		 * longer valid". Make sure this is only sent protected since
+		 * unprotected frame would be received by the STA that is now
+		 * trying to associate.
+		 */
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	if (reassoc) {
+		os_memcpy(sta->previous_ap, mgmt->u.reassoc_req.current_ap,
+			  ETH_ALEN);
+	}
+
+	if (sta->last_assoc_req)
+		os_free(sta->last_assoc_req);
+	sta->last_assoc_req = os_malloc(len);
+	if (sta->last_assoc_req)
+		os_memcpy(sta->last_assoc_req, mgmt, len);
+
+	/* Make sure that the previously registered inactivity timer will not
+	 * remove the STA immediately. */
+	sta->timeout_next = STA_NULLFUNC;
+
+ fail:
+	send_assoc_resp(hapd, sta, resp, reassoc, pos, left);
+}
+
+
+static void handle_disassoc(struct hostapd_data *hapd,
+			    const struct ieee80211_mgmt *mgmt, size_t len)
+{
+	struct sta_info *sta;
+
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.disassoc)) {
+		printf("handle_disassoc - too short payload (len=%lu)\n",
+		       (unsigned long) len);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "disassocation: STA=" MACSTR " reason_code=%d",
+		   MAC2STR(mgmt->sa),
+		   le_to_host16(mgmt->u.disassoc.reason_code));
+
+	sta = ap_get_sta(hapd, mgmt->sa);
+	if (sta == NULL) {
+		printf("Station " MACSTR " trying to disassociate, but it "
+		       "is not associated.\n", MAC2STR(mgmt->sa));
+		return;
+	}
+
+	ap_sta_set_authorized(hapd, sta, 0);
+	sta->flags &= ~(WLAN_STA_ASSOC | WLAN_STA_ASSOC_REQ_OK);
+	wpa_auth_sm_event(sta->wpa_sm, WPA_DISASSOC);
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "disassociated");
+	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+	/* Stop Accounting and IEEE 802.1X sessions, but leave the STA
+	 * authenticated. */
+	accounting_sta_stop(hapd, sta);
+	ieee802_1x_free_station(sta);
+	hostapd_drv_sta_remove(hapd, sta->addr);
+
+	if (sta->timeout_next == STA_NULLFUNC ||
+	    sta->timeout_next == STA_DISASSOC) {
+		sta->timeout_next = STA_DEAUTH;
+		eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+		eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
+				       hapd, sta);
+	}
+
+	mlme_disassociate_indication(
+		hapd, sta, le_to_host16(mgmt->u.disassoc.reason_code));
+}
+
+
+static void handle_deauth(struct hostapd_data *hapd,
+			  const struct ieee80211_mgmt *mgmt, size_t len)
+{
+	struct sta_info *sta;
+
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.deauth)) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "handle_deauth - too short "
+			"payload (len=%lu)", (unsigned long) len);
+		return;
+	}
+
+	wpa_msg(hapd->msg_ctx, MSG_DEBUG, "deauthentication: STA=" MACSTR
+		" reason_code=%d",
+		MAC2STR(mgmt->sa), le_to_host16(mgmt->u.deauth.reason_code));
+
+	sta = ap_get_sta(hapd, mgmt->sa);
+	if (sta == NULL) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR " trying "
+			"to deauthenticate, but it is not authenticated",
+			MAC2STR(mgmt->sa));
+		return;
+	}
+
+	ap_sta_set_authorized(hapd, sta, 0);
+	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC |
+			WLAN_STA_ASSOC_REQ_OK);
+	wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG, "deauthenticated");
+	mlme_deauthenticate_indication(
+		hapd, sta, le_to_host16(mgmt->u.deauth.reason_code));
+	sta->acct_terminate_cause = RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+	ap_free_sta(hapd, sta);
+}
+
+
+static void handle_beacon(struct hostapd_data *hapd,
+			  const struct ieee80211_mgmt *mgmt, size_t len,
+			  struct hostapd_frame_info *fi)
+{
+	struct ieee802_11_elems elems;
+
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.beacon)) {
+		printf("handle_beacon - too short payload (len=%lu)\n",
+		       (unsigned long) len);
+		return;
+	}
+
+	(void) ieee802_11_parse_elems(mgmt->u.beacon.variable,
+				      len - (IEEE80211_HDRLEN +
+					     sizeof(mgmt->u.beacon)), &elems,
+				      0);
+
+	ap_list_process_beacon(hapd->iface, mgmt, &elems, fi);
+}
+
+
+#ifdef CONFIG_IEEE80211W
+
+static void hostapd_sa_query_action(struct hostapd_data *hapd,
+				    const struct ieee80211_mgmt *mgmt,
+				    size_t len)
+{
+	const u8 *end;
+
+	end = mgmt->u.action.u.sa_query_resp.trans_id +
+		WLAN_SA_QUERY_TR_ID_LEN;
+	if (((u8 *) mgmt) + len < end) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: Too short SA Query Action "
+			   "frame (len=%lu)", (unsigned long) len);
+		return;
+	}
+
+	ieee802_11_sa_query_action(hapd, mgmt->sa,
+				   mgmt->u.action.u.sa_query_resp.action,
+				   mgmt->u.action.u.sa_query_resp.trans_id);
+}
+
+
+static int robust_action_frame(u8 category)
+{
+	return category != WLAN_ACTION_PUBLIC &&
+		category != WLAN_ACTION_HT;
+}
+#endif /* CONFIG_IEEE80211W */
+
+
+#ifdef CONFIG_WNM
+static void hostapd_wnm_action(struct hostapd_data *hapd, struct sta_info *sta,
+			       const struct ieee80211_mgmt *mgmt,
+			       size_t len)
+{
+	struct rx_action action;
+	if (len < IEEE80211_HDRLEN + 2)
+		return;
+	os_memset(&action, 0, sizeof(action));
+	action.da = mgmt->da;
+	action.sa = mgmt->sa;
+	action.bssid = mgmt->bssid;
+	action.category = mgmt->u.action.category;
+	action.data = (const u8 *) &mgmt->u.action.u.wnm_sleep_req.action;
+	action.len = len - IEEE80211_HDRLEN - 1;
+	action.freq = hapd->iface->freq;
+	ieee802_11_rx_wnm_action_ap(hapd, &action);
+}
+#endif /* CONFIG_WNM */
+
+
+static void handle_action(struct hostapd_data *hapd,
+			  const struct ieee80211_mgmt *mgmt, size_t len)
+{
+	struct sta_info *sta;
+	sta = ap_get_sta(hapd, mgmt->sa);
+
+	if (len < IEEE80211_HDRLEN + 1) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "handle_action - too short payload (len=%lu)",
+			       (unsigned long) len);
+		return;
+	}
+
+	if (mgmt->u.action.category != WLAN_ACTION_PUBLIC &&
+	    (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignored Action "
+			   "frame (category=%u) from unassociated STA " MACSTR,
+			   MAC2STR(mgmt->sa), mgmt->u.action.category);
+		return;
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (sta && (sta->flags & WLAN_STA_MFP) &&
+	    !(mgmt->frame_control & host_to_le16(WLAN_FC_ISWEP) &&
+	      robust_action_frame(mgmt->u.action.category))) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Dropped unprotected Robust Action frame from "
+			       "an MFP STA");
+		return;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	switch (mgmt->u.action.category) {
+#ifdef CONFIG_IEEE80211R
+	case WLAN_ACTION_FT:
+		if (wpa_ft_action_rx(sta->wpa_sm, (u8 *) &mgmt->u.action,
+				     len - IEEE80211_HDRLEN))
+			break;
+		return;
+#endif /* CONFIG_IEEE80211R */
+	case WLAN_ACTION_WMM:
+		hostapd_wmm_action(hapd, mgmt, len);
+		return;
+#ifdef CONFIG_IEEE80211W
+	case WLAN_ACTION_SA_QUERY:
+		hostapd_sa_query_action(hapd, mgmt, len);
+		return;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_WNM
+	case WLAN_ACTION_WNM:
+		hostapd_wnm_action(hapd, sta, mgmt, len);
+		return;
+#endif /* CONFIG_WNM */
+	case WLAN_ACTION_PUBLIC:
+		if (hapd->public_action_cb) {
+			hapd->public_action_cb(hapd->public_action_cb_ctx,
+					       (u8 *) mgmt, len,
+					       hapd->iface->freq);
+			return;
+		}
+		break;
+	case WLAN_ACTION_VENDOR_SPECIFIC:
+		if (hapd->vendor_action_cb) {
+			if (hapd->vendor_action_cb(hapd->vendor_action_cb_ctx,
+						   (u8 *) mgmt, len,
+						   hapd->iface->freq) == 0)
+				return;
+		}
+		break;
+	}
+
+	hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "handle_action - unknown action category %d or invalid "
+		       "frame",
+		       mgmt->u.action.category);
+	if (!(mgmt->da[0] & 0x01) && !(mgmt->u.action.category & 0x80) &&
+	    !(mgmt->sa[0] & 0x01)) {
+		struct ieee80211_mgmt *resp;
+
+		/*
+		 * IEEE 802.11-REVma/D9.0 - 7.3.1.11
+		 * Return the Action frame to the source without change
+		 * except that MSB of the Category set to 1.
+		 */
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: Return unknown Action "
+			   "frame back to sender");
+		resp = os_malloc(len);
+		if (resp == NULL)
+			return;
+		os_memcpy(resp, mgmt, len);
+		os_memcpy(resp->da, resp->sa, ETH_ALEN);
+		os_memcpy(resp->sa, hapd->own_addr, ETH_ALEN);
+		os_memcpy(resp->bssid, hapd->own_addr, ETH_ALEN);
+		resp->u.action.category |= 0x80;
+
+		if (hostapd_drv_send_mlme(hapd, resp, len, 0) < 0) {
+			wpa_printf(MSG_ERROR, "IEEE 802.11: Failed to send "
+				   "Action frame");
+		}
+		os_free(resp);
+	}
+}
+
+
+/**
+ * ieee802_11_mgmt - process incoming IEEE 802.11 management frames
+ * @hapd: hostapd BSS data structure (the BSS to which the management frame was
+ * sent to)
+ * @buf: management frame data (starting from IEEE 802.11 header)
+ * @len: length of frame data in octets
+ * @fi: meta data about received frame (signal level, etc.)
+ *
+ * Process all incoming IEEE 802.11 management frames. This will be called for
+ * each frame received from the kernel driver through wlan#ap interface. In
+ * addition, it can be called to re-inserted pending frames (e.g., when using
+ * external RADIUS server as an MAC ACL).
+ */
+void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
+		     struct hostapd_frame_info *fi)
+{
+	struct ieee80211_mgmt *mgmt;
+	int broadcast;
+	u16 fc, stype;
+
+	if (len < 24)
+		return;
+
+	mgmt = (struct ieee80211_mgmt *) buf;
+	fc = le_to_host16(mgmt->frame_control);
+	stype = WLAN_FC_GET_STYPE(fc);
+
+	if (stype == WLAN_FC_STYPE_BEACON) {
+		handle_beacon(hapd, mgmt, len, fi);
+		return;
+	}
+
+	broadcast = mgmt->bssid[0] == 0xff && mgmt->bssid[1] == 0xff &&
+		mgmt->bssid[2] == 0xff && mgmt->bssid[3] == 0xff &&
+		mgmt->bssid[4] == 0xff && mgmt->bssid[5] == 0xff;
+
+	if (!broadcast &&
+#ifdef CONFIG_P2P
+	    /* Invitation responses can be sent with the peer MAC as BSSID */
+	    !((hapd->conf->p2p & P2P_GROUP_OWNER) &&
+	      stype == WLAN_FC_STYPE_ACTION) &&
+#endif /* CONFIG_P2P */
+	    os_memcmp(mgmt->bssid, hapd->own_addr, ETH_ALEN) != 0) {
+		printf("MGMT: BSSID=" MACSTR " not our address\n",
+		       MAC2STR(mgmt->bssid));
+		return;
+	}
+
+
+	if (stype == WLAN_FC_STYPE_PROBE_REQ) {
+		handle_probe_req(hapd, mgmt, len, fi->ssi_signal);
+		return;
+	}
+
+	if (os_memcmp(mgmt->da, hapd->own_addr, ETH_ALEN) != 0) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "MGMT: DA=" MACSTR " not our address",
+			       MAC2STR(mgmt->da));
+		return;
+	}
+
+	switch (stype) {
+	case WLAN_FC_STYPE_AUTH:
+		wpa_printf(MSG_DEBUG, "mgmt::auth");
+		handle_auth(hapd, mgmt, len);
+		break;
+	case WLAN_FC_STYPE_ASSOC_REQ:
+		wpa_printf(MSG_DEBUG, "mgmt::assoc_req");
+		handle_assoc(hapd, mgmt, len, 0);
+		break;
+	case WLAN_FC_STYPE_REASSOC_REQ:
+		wpa_printf(MSG_DEBUG, "mgmt::reassoc_req");
+		handle_assoc(hapd, mgmt, len, 1);
+		break;
+	case WLAN_FC_STYPE_DISASSOC:
+		wpa_printf(MSG_DEBUG, "mgmt::disassoc");
+		handle_disassoc(hapd, mgmt, len);
+		break;
+	case WLAN_FC_STYPE_DEAUTH:
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "mgmt::deauth");
+		handle_deauth(hapd, mgmt, len);
+		break;
+	case WLAN_FC_STYPE_ACTION:
+		wpa_printf(MSG_DEBUG, "mgmt::action");
+		handle_action(hapd, mgmt, len);
+		break;
+	default:
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "unknown mgmt frame subtype %d", stype);
+		break;
+	}
+}
+
+
+static void handle_auth_cb(struct hostapd_data *hapd,
+			   const struct ieee80211_mgmt *mgmt,
+			   size_t len, int ok)
+{
+	u16 auth_alg, auth_transaction, status_code;
+	struct sta_info *sta;
+
+	if (!ok) {
+		hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_NOTICE,
+			       "did not acknowledge authentication response");
+		return;
+	}
+
+	if (len < IEEE80211_HDRLEN + sizeof(mgmt->u.auth)) {
+		printf("handle_auth_cb - too short payload (len=%lu)\n",
+		       (unsigned long) len);
+		return;
+	}
+
+	auth_alg = le_to_host16(mgmt->u.auth.auth_alg);
+	auth_transaction = le_to_host16(mgmt->u.auth.auth_transaction);
+	status_code = le_to_host16(mgmt->u.auth.status_code);
+
+	sta = ap_get_sta(hapd, mgmt->da);
+	if (!sta) {
+		printf("handle_auth_cb: STA " MACSTR " not found\n",
+		       MAC2STR(mgmt->da));
+		return;
+	}
+
+	if (status_code == WLAN_STATUS_SUCCESS &&
+	    ((auth_alg == WLAN_AUTH_OPEN && auth_transaction == 2) ||
+	     (auth_alg == WLAN_AUTH_SHARED_KEY && auth_transaction == 4))) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "authenticated");
+		sta->flags |= WLAN_STA_AUTH;
+	}
+}
+
+
+static void handle_assoc_cb(struct hostapd_data *hapd,
+			    const struct ieee80211_mgmt *mgmt,
+			    size_t len, int reassoc, int ok)
+{
+	u16 status;
+	struct sta_info *sta;
+	int new_assoc = 1;
+	struct ieee80211_ht_capabilities ht_cap;
+
+	if (len < IEEE80211_HDRLEN + (reassoc ? sizeof(mgmt->u.reassoc_resp) :
+				      sizeof(mgmt->u.assoc_resp))) {
+		printf("handle_assoc_cb(reassoc=%d) - too short payload "
+		       "(len=%lu)\n", reassoc, (unsigned long) len);
+		return;
+	}
+
+	sta = ap_get_sta(hapd, mgmt->da);
+	if (!sta) {
+		printf("handle_assoc_cb: STA " MACSTR " not found\n",
+		       MAC2STR(mgmt->da));
+		return;
+	}
+
+	if (!ok) {
+		hostapd_logger(hapd, mgmt->da, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "did not acknowledge association response");
+		sta->flags &= ~WLAN_STA_ASSOC_REQ_OK;
+		return;
+	}
+
+	if (reassoc)
+		status = le_to_host16(mgmt->u.reassoc_resp.status_code);
+	else
+		status = le_to_host16(mgmt->u.assoc_resp.status_code);
+
+	if (status != WLAN_STATUS_SUCCESS)
+		goto fail;
+
+	/* Stop previous accounting session, if one is started, and allocate
+	 * new session id for the new session. */
+	accounting_sta_stop(hapd, sta);
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO,
+		       "associated (aid %d)",
+		       sta->aid);
+
+	if (sta->flags & WLAN_STA_ASSOC)
+		new_assoc = 0;
+	sta->flags |= WLAN_STA_ASSOC;
+	if ((!hapd->conf->ieee802_1x && !hapd->conf->wpa) ||
+	    sta->auth_alg == WLAN_AUTH_FT) {
+		/*
+		 * Open, static WEP, or FT protocol; no separate authorization
+		 * step.
+		 */
+		ap_sta_set_authorized(hapd, sta, 1);
+	}
+
+	if (reassoc)
+		mlme_reassociate_indication(hapd, sta);
+	else
+		mlme_associate_indication(hapd, sta);
+
+#ifdef CONFIG_IEEE80211W
+	sta->sa_query_timed_out = 0;
+#endif /* CONFIG_IEEE80211W */
+
+	/*
+	 * Remove the STA entry in order to make sure the STA PS state gets
+	 * cleared and configuration gets updated in case of reassociation back
+	 * to the same AP.
+	 */
+	hostapd_drv_sta_remove(hapd, sta->addr);
+
+#ifdef CONFIG_IEEE80211N
+	if (sta->flags & WLAN_STA_HT)
+		hostapd_get_ht_capab(hapd, sta->ht_capabilities, &ht_cap);
+#endif /* CONFIG_IEEE80211N */
+
+	if (hostapd_sta_add(hapd, sta->addr, sta->aid, sta->capability,
+			    sta->supported_rates, sta->supported_rates_len,
+			    sta->listen_interval,
+			    sta->flags & WLAN_STA_HT ? &ht_cap : NULL,
+			    sta->flags, sta->qosinfo)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_NOTICE,
+			       "Could not add STA to kernel driver");
+
+		ap_sta_disconnect(hapd, sta, sta->addr,
+				  WLAN_REASON_DISASSOC_AP_BUSY);
+
+		goto fail;
+	}
+
+	if (sta->flags & WLAN_STA_WDS)
+		hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 1);
+
+	if (sta->eapol_sm == NULL) {
+		/*
+		 * This STA does not use RADIUS server for EAP authentication,
+		 * so bind it to the selected VLAN interface now, since the
+		 * interface selection is not going to change anymore.
+		 */
+		if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
+			goto fail;
+	} else if (sta->vlan_id) {
+		/* VLAN ID already set (e.g., by PMKSA caching), so bind STA */
+		if (ap_sta_bind_vlan(hapd, sta, 0) < 0)
+			goto fail;
+	}
+
+	hostapd_set_sta_flags(hapd, sta);
+
+	if (sta->auth_alg == WLAN_AUTH_FT)
+		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC_FT);
+	else
+		wpa_auth_sm_event(sta->wpa_sm, WPA_ASSOC);
+	hapd->new_assoc_sta_cb(hapd, sta, !new_assoc);
+
+	ieee802_1x_notify_port_enabled(sta->eapol_sm, 1);
+
+ fail:
+	/* Copy of the association request is not needed anymore */
+	if (sta->last_assoc_req) {
+		os_free(sta->last_assoc_req);
+		sta->last_assoc_req = NULL;
+	}
+}
+
+
+static void handle_deauth_cb(struct hostapd_data *hapd,
+			     const struct ieee80211_mgmt *mgmt,
+			     size_t len, int ok)
+{
+	struct sta_info *sta;
+	if (mgmt->da[0] & 0x01)
+		return;
+	sta = ap_get_sta(hapd, mgmt->da);
+	if (!sta) {
+		wpa_printf(MSG_DEBUG, "handle_deauth_cb: STA " MACSTR
+			   " not found", MAC2STR(mgmt->da));
+		return;
+	}
+	if (ok)
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged deauth",
+			   MAC2STR(sta->addr));
+	else
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
+			   "deauth", MAC2STR(sta->addr));
+
+	ap_sta_deauth_cb(hapd, sta);
+}
+
+
+static void handle_disassoc_cb(struct hostapd_data *hapd,
+			       const struct ieee80211_mgmt *mgmt,
+			       size_t len, int ok)
+{
+	struct sta_info *sta;
+	if (mgmt->da[0] & 0x01)
+		return;
+	sta = ap_get_sta(hapd, mgmt->da);
+	if (!sta) {
+		wpa_printf(MSG_DEBUG, "handle_disassoc_cb: STA " MACSTR
+			   " not found", MAC2STR(mgmt->da));
+		return;
+	}
+	if (ok)
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " acknowledged disassoc",
+			   MAC2STR(sta->addr));
+	else
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " did not acknowledge "
+			   "disassoc", MAC2STR(sta->addr));
+
+	ap_sta_disassoc_cb(hapd, sta);
+}
+
+
+/**
+ * ieee802_11_mgmt_cb - Process management frame TX status callback
+ * @hapd: hostapd BSS data structure (the BSS from which the management frame
+ * was sent from)
+ * @buf: management frame data (starting from IEEE 802.11 header)
+ * @len: length of frame data in octets
+ * @stype: management frame subtype from frame control field
+ * @ok: Whether the frame was ACK'ed
+ */
+void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
+			u16 stype, int ok)
+{
+	const struct ieee80211_mgmt *mgmt;
+	mgmt = (const struct ieee80211_mgmt *) buf;
+
+	switch (stype) {
+	case WLAN_FC_STYPE_AUTH:
+		wpa_printf(MSG_DEBUG, "mgmt::auth cb");
+		handle_auth_cb(hapd, mgmt, len, ok);
+		break;
+	case WLAN_FC_STYPE_ASSOC_RESP:
+		wpa_printf(MSG_DEBUG, "mgmt::assoc_resp cb");
+		handle_assoc_cb(hapd, mgmt, len, 0, ok);
+		break;
+	case WLAN_FC_STYPE_REASSOC_RESP:
+		wpa_printf(MSG_DEBUG, "mgmt::reassoc_resp cb");
+		handle_assoc_cb(hapd, mgmt, len, 1, ok);
+		break;
+	case WLAN_FC_STYPE_PROBE_RESP:
+		wpa_printf(MSG_EXCESSIVE, "mgmt::proberesp cb");
+		break;
+	case WLAN_FC_STYPE_DEAUTH:
+		wpa_printf(MSG_DEBUG, "mgmt::deauth cb");
+		handle_deauth_cb(hapd, mgmt, len, ok);
+		break;
+	case WLAN_FC_STYPE_DISASSOC:
+		wpa_printf(MSG_DEBUG, "mgmt::disassoc cb");
+		handle_disassoc_cb(hapd, mgmt, len, ok);
+		break;
+	case WLAN_FC_STYPE_ACTION:
+		wpa_printf(MSG_DEBUG, "mgmt::action cb");
+		break;
+	default:
+		printf("unknown mgmt cb frame subtype %d\n", stype);
+		break;
+	}
+}
+
+
+int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
+{
+	/* TODO */
+	return 0;
+}
+
+
+int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			   char *buf, size_t buflen)
+{
+	/* TODO */
+	return 0;
+}
+
+
+void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
+		       const u8 *buf, size_t len, int ack)
+{
+	struct sta_info *sta;
+	struct hostapd_iface *iface = hapd->iface;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL && iface->num_bss > 1) {
+		size_t j;
+		for (j = 0; j < iface->num_bss; j++) {
+			hapd = iface->bss[j];
+			sta = ap_get_sta(hapd, addr);
+			if (sta)
+				break;
+		}
+	}
+	if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC))
+		return;
+	if (sta->flags & WLAN_STA_PENDING_POLL) {
+		wpa_printf(MSG_DEBUG, "STA " MACSTR " %s pending "
+			   "activity poll", MAC2STR(sta->addr),
+			   ack ? "ACKed" : "did not ACK");
+		if (ack)
+			sta->flags &= ~WLAN_STA_PENDING_POLL;
+	}
+
+	ieee802_1x_tx_status(hapd, sta, buf, len, ack);
+}
+
+
+void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
+			     const u8 *data, size_t len, int ack)
+{
+	struct sta_info *sta;
+	struct hostapd_iface *iface = hapd->iface;
+
+	sta = ap_get_sta(hapd, dst);
+	if (sta == NULL && iface->num_bss > 1) {
+		size_t j;
+		for (j = 0; j < iface->num_bss; j++) {
+			hapd = iface->bss[j];
+			sta = ap_get_sta(hapd, dst);
+			if (sta)
+				break;
+		}
+	}
+	if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
+		wpa_printf(MSG_DEBUG, "Ignore TX status for Data frame to STA "
+			   MACSTR " that is not currently associated",
+			   MAC2STR(dst));
+		return;
+	}
+
+	ieee802_1x_eapol_tx_status(hapd, sta, data, len, ack);
+}
+
+
+void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct sta_info *sta;
+	struct hostapd_iface *iface = hapd->iface;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL && iface->num_bss > 1) {
+		size_t j;
+		for (j = 0; j < iface->num_bss; j++) {
+			hapd = iface->bss[j];
+			sta = ap_get_sta(hapd, addr);
+			if (sta)
+				break;
+		}
+	}
+	if (sta == NULL)
+		return;
+	if (!(sta->flags & WLAN_STA_PENDING_POLL))
+		return;
+
+	wpa_printf(MSG_DEBUG, "STA " MACSTR " ACKed pending "
+		   "activity poll", MAC2STR(sta->addr));
+	sta->flags &= ~WLAN_STA_PENDING_POLL;
+}
+
+
+void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
+				int wds)
+{
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, src);
+	if (sta && (sta->flags & WLAN_STA_ASSOC)) {
+		if (!hapd->conf->wds_sta)
+			return;
+
+		if (wds && !(sta->flags & WLAN_STA_WDS)) {
+			wpa_printf(MSG_DEBUG, "Enable 4-address WDS mode for "
+				   "STA " MACSTR " (aid %u)",
+				   MAC2STR(sta->addr), sta->aid);
+			sta->flags |= WLAN_STA_WDS;
+			hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 1);
+		}
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "Data/PS-poll frame from not associated STA "
+		   MACSTR, MAC2STR(src));
+	if (src[0] & 0x01) {
+		/* Broadcast bit set in SA?! Ignore the frame silently. */
+		return;
+	}
+
+	if (sta && (sta->flags & WLAN_STA_ASSOC_REQ_OK)) {
+		wpa_printf(MSG_DEBUG, "Association Response to the STA has "
+			   "already been sent, but no TX status yet known - "
+			   "ignore Class 3 frame issue with " MACSTR,
+			   MAC2STR(src));
+		return;
+	}
+
+	if (sta && (sta->flags & WLAN_STA_AUTH))
+		hostapd_drv_sta_disassoc(
+			hapd, src,
+			WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+	else
+		hostapd_drv_sta_deauth(
+			hapd, src,
+			WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA);
+}
+
+int ieee802_11_start_channel_switch(struct hostapd_data *hapd,
+				    int freq, u8 radar_detected)
+{
+	struct hostapd_channel_data *next_channel;
+
+	next_channel = hostapd_get_valid_channel(hapd, freq);
+	if (!next_channel)
+		return -1;
+
+	hapd->next_channel = next_channel;
+	u8 radar_on_next_channel =
+		(next_channel->flag & HOSTAPD_CHAN_RADAR) ? 1 : 0;
+	wpa_printf(MSG_INFO, "switching to %sch. #%d, freq %d",
+		   radar_on_next_channel ? "(DFS) " : "",
+		   next_channel->chan, next_channel->freq);
+
+	/* Add CSA */
+	ieee802_11_set_beacon(hapd);
+
+	if (hostapd_channel_switch(hapd, next_channel->freq,
+				   next_channel->flag,
+				   radar_detected,
+				   radar_on_next_channel)) {
+		wpa_printf(MSG_ERROR, "Channel switch failed");
+		return -1;
+	}
+	return 0;
+}
+
+
+#endif /* CONFIG_NATIVE_WINDOWS */
diff --git a/hostap/src/ap/ieee802_11.h b/hostap/src/ap/ieee802_11.h
new file mode 100644
index 0000000..1e5800d
--- /dev/null
+++ b/hostap/src/ap/ieee802_11.h
@@ -0,0 +1,81 @@
+/*
+ * hostapd / IEEE 802.11 Management
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_11_H
+#define IEEE802_11_H
+
+struct hostapd_iface;
+struct hostapd_data;
+struct sta_info;
+struct hostapd_frame_info;
+struct ieee80211_ht_capabilities;
+
+void ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
+		     struct hostapd_frame_info *fi);
+void ieee802_11_mgmt_cb(struct hostapd_data *hapd, const u8 *buf, size_t len,
+			u16 stype, int ok);
+void ieee802_11_print_ssid(char *buf, const u8 *ssid, u8 len);
+#ifdef NEED_AP_MLME
+int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
+int ieee802_11_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			   char *buf, size_t buflen);
+#else /* NEED_AP_MLME */
+static inline int ieee802_11_get_mib(struct hostapd_data *hapd, char *buf,
+				     size_t buflen)
+{
+	return 0;
+}
+
+static inline int ieee802_11_get_mib_sta(struct hostapd_data *hapd,
+					 struct sta_info *sta,
+					 char *buf, size_t buflen)
+{
+	return 0;
+}
+#endif /* NEED_AP_MLME */
+u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
+			   int probe);
+u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_supp_rates(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_ext_supp_rates(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid);
+int hostapd_ht_operation_update(struct hostapd_iface *iface);
+void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
+				  const u8 *addr, const u8 *trans_id);
+void hostapd_get_ht_capab(struct hostapd_data *hapd,
+			  struct ieee80211_ht_capabilities *ht_cap,
+			  struct ieee80211_ht_capabilities *neg_ht_cap);
+u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+		      const u8 *ht_capab, size_t ht_capab_len);
+void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
+u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+		       const u8 *vht_capab, size_t vht_capab_len);
+void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
+		       const u8 *buf, size_t len, int ack);
+void hostapd_eapol_tx_status(struct hostapd_data *hapd, const u8 *dst,
+			     const u8 *data, size_t len, int ack);
+void ieee802_11_rx_from_unknown(struct hostapd_data *hapd, const u8 *src,
+				int wds);
+u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
+				     struct sta_info *sta, u8 *eid);
+void ieee802_11_sa_query_action(struct hostapd_data *hapd,
+				const u8 *sa, const u8 action_type,
+				const u8 *trans_id);
+u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid);
+u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid);
+int hostapd_update_time_adv(struct hostapd_data *hapd);
+void hostapd_client_poll_ok(struct hostapd_data *hapd, const u8 *addr);
+u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid);
+
+#endif /* IEEE802_11_H */
diff --git a/hostap/src/ap/ieee802_11_auth.c b/hostap/src/ap/ieee802_11_auth.c
new file mode 100644
index 0000000..c311e55
--- /dev/null
+++ b/hostap/src/ap/ieee802_11_auth.c
@@ -0,0 +1,643 @@
+/*
+ * hostapd / IEEE 802.11 authentication (ACL)
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * Access control list for IEEE 802.11 authentication can uses statically
+ * configured ACL from configuration files or an external RADIUS server.
+ * Results from external RADIUS queries are cached to allow faster
+ * authentication frame processing.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/sha1.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "ieee802_11.h"
+#include "ieee802_1x.h"
+#include "ieee802_11_auth.h"
+
+#define RADIUS_ACL_TIMEOUT 30
+
+
+struct hostapd_cached_radius_acl {
+	os_time_t timestamp;
+	macaddr addr;
+	int accepted; /* HOSTAPD_ACL_* */
+	struct hostapd_cached_radius_acl *next;
+	u32 session_timeout;
+	u32 acct_interim_interval;
+	int vlan_id;
+	struct hostapd_sta_wpa_psk_short *psk;
+	char *identity;
+	char *radius_cui;
+};
+
+
+struct hostapd_acl_query_data {
+	os_time_t timestamp;
+	u8 radius_id;
+	macaddr addr;
+	u8 *auth_msg; /* IEEE 802.11 authentication frame from station */
+	size_t auth_msg_len;
+	struct hostapd_acl_query_data *next;
+};
+
+
+#ifndef CONFIG_NO_RADIUS
+static void hostapd_acl_cache_free_entry(struct hostapd_cached_radius_acl *e)
+{
+	os_free(e->identity);
+	os_free(e->radius_cui);
+	hostapd_free_psk_list(e->psk);
+	os_free(e);
+}
+
+
+static void hostapd_acl_cache_free(struct hostapd_cached_radius_acl *acl_cache)
+{
+	struct hostapd_cached_radius_acl *prev;
+
+	while (acl_cache) {
+		prev = acl_cache;
+		acl_cache = acl_cache->next;
+		hostapd_acl_cache_free_entry(prev);
+	}
+}
+
+
+static void copy_psk_list(struct hostapd_sta_wpa_psk_short **psk,
+			  struct hostapd_sta_wpa_psk_short *src)
+{
+	struct hostapd_sta_wpa_psk_short **copy_to;
+	struct hostapd_sta_wpa_psk_short *copy_from;
+
+	/* Copy PSK linked list */
+	copy_to = psk;
+	copy_from = src;
+	while (copy_from && copy_to) {
+		*copy_to = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
+		if (*copy_to == NULL)
+			break;
+		os_memcpy(*copy_to, copy_from,
+			  sizeof(struct hostapd_sta_wpa_psk_short));
+		copy_from = copy_from->next;
+		copy_to = &((*copy_to)->next);
+	}
+	if (copy_to)
+		*copy_to = NULL;
+}
+
+
+static int hostapd_acl_cache_get(struct hostapd_data *hapd, const u8 *addr,
+				 u32 *session_timeout,
+				 u32 *acct_interim_interval, int *vlan_id,
+				 struct hostapd_sta_wpa_psk_short **psk,
+				 char **identity, char **radius_cui)
+{
+	struct hostapd_cached_radius_acl *entry;
+	struct os_time now;
+
+	os_get_time(&now);
+
+	for (entry = hapd->acl_cache; entry; entry = entry->next) {
+		if (os_memcmp(entry->addr, addr, ETH_ALEN) != 0)
+			continue;
+
+		if (now.sec - entry->timestamp > RADIUS_ACL_TIMEOUT)
+			return -1; /* entry has expired */
+		if (entry->accepted == HOSTAPD_ACL_ACCEPT_TIMEOUT)
+			if (session_timeout)
+				*session_timeout = entry->session_timeout;
+		if (acct_interim_interval)
+			*acct_interim_interval =
+				entry->acct_interim_interval;
+		if (vlan_id)
+			*vlan_id = entry->vlan_id;
+		copy_psk_list(psk, entry->psk);
+		if (identity) {
+			if (entry->identity)
+				*identity = os_strdup(entry->identity);
+			else
+				*identity = NULL;
+		}
+		if (radius_cui) {
+			if (entry->radius_cui)
+				*radius_cui = os_strdup(entry->radius_cui);
+			else
+				*radius_cui = NULL;
+		}
+		return entry->accepted;
+	}
+
+	return -1;
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
+static void hostapd_acl_query_free(struct hostapd_acl_query_data *query)
+{
+	if (query == NULL)
+		return;
+	os_free(query->auth_msg);
+	os_free(query);
+}
+
+
+#ifndef CONFIG_NO_RADIUS
+static int hostapd_radius_acl_query(struct hostapd_data *hapd, const u8 *addr,
+				    struct hostapd_acl_query_data *query)
+{
+	struct radius_msg *msg;
+	char buf[128];
+
+	query->radius_id = radius_client_get_id(hapd->radius);
+	msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, query->radius_id);
+	if (msg == NULL)
+		return -1;
+
+	radius_msg_make_authenticator(msg, addr, ETH_ALEN);
+
+	os_snprintf(buf, sizeof(buf), RADIUS_ADDR_FORMAT, MAC2STR(addr));
+	if (!radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, (u8 *) buf,
+				 os_strlen(buf))) {
+		wpa_printf(MSG_DEBUG, "Could not add User-Name");
+		goto fail;
+	}
+
+	if (!radius_msg_add_attr_user_password(
+		    msg, (u8 *) buf, os_strlen(buf),
+		    hapd->conf->radius->auth_server->shared_secret,
+		    hapd->conf->radius->auth_server->shared_secret_len)) {
+		wpa_printf(MSG_DEBUG, "Could not add User-Password");
+		goto fail;
+	}
+
+	if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr,
+				   NULL, msg) < 0)
+		goto fail;
+
+	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
+		    MAC2STR(addr));
+	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+				 (u8 *) buf, os_strlen(buf))) {
+		wpa_printf(MSG_DEBUG, "Could not add Calling-Station-Id");
+		goto fail;
+	}
+
+	os_snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
+	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+				 (u8 *) buf, os_strlen(buf))) {
+		wpa_printf(MSG_DEBUG, "Could not add Connect-Info");
+		goto fail;
+	}
+
+	if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, addr) < 0)
+		goto fail;
+	return 0;
+
+ fail:
+	radius_msg_free(msg);
+	return -1;
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
+/**
+ * hostapd_allowed_address - Check whether a specified STA can be authenticated
+ * @hapd: hostapd BSS data
+ * @addr: MAC address of the STA
+ * @msg: Authentication message
+ * @len: Length of msg in octets
+ * @session_timeout: Buffer for returning session timeout (from RADIUS)
+ * @acct_interim_interval: Buffer for returning account interval (from RADIUS)
+ * @vlan_id: Buffer for returning VLAN ID
+ * @psk: Linked list buffer for returning WPA PSK
+ * @identity: Buffer for returning identity (from RADIUS)
+ * @radius_cui: Buffer for returning CUI (from RADIUS)
+ * Returns: HOSTAPD_ACL_ACCEPT, HOSTAPD_ACL_REJECT, or HOSTAPD_ACL_PENDING
+ *
+ * The caller is responsible for freeing the returned *identity and *radius_cui
+ * values with os_free().
+ */
+int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
+			    const u8 *msg, size_t len, u32 *session_timeout,
+			    u32 *acct_interim_interval, int *vlan_id,
+			    struct hostapd_sta_wpa_psk_short **psk,
+			    char **identity, char **radius_cui)
+{
+	if (session_timeout)
+		*session_timeout = 0;
+	if (acct_interim_interval)
+		*acct_interim_interval = 0;
+	if (vlan_id)
+		*vlan_id = 0;
+	if (psk)
+		*psk = NULL;
+	if (identity)
+		*identity = NULL;
+	if (radius_cui)
+		*radius_cui = NULL;
+
+	if (hostapd_maclist_found(hapd->conf->accept_mac,
+				  hapd->conf->num_accept_mac, addr, vlan_id))
+		return HOSTAPD_ACL_ACCEPT;
+
+	if (hostapd_maclist_found(hapd->conf->deny_mac,
+				  hapd->conf->num_deny_mac, addr, vlan_id))
+		return HOSTAPD_ACL_REJECT;
+
+	if (hapd->conf->macaddr_acl == ACCEPT_UNLESS_DENIED)
+		return HOSTAPD_ACL_ACCEPT;
+	if (hapd->conf->macaddr_acl == DENY_UNLESS_ACCEPTED)
+		return HOSTAPD_ACL_REJECT;
+
+	if (hapd->conf->macaddr_acl == USE_EXTERNAL_RADIUS_AUTH) {
+#ifdef CONFIG_NO_RADIUS
+		return HOSTAPD_ACL_REJECT;
+#else /* CONFIG_NO_RADIUS */
+		struct hostapd_acl_query_data *query;
+		struct os_time t;
+
+		/* Check whether ACL cache has an entry for this station */
+		int res = hostapd_acl_cache_get(hapd, addr, session_timeout,
+						acct_interim_interval,
+						vlan_id, psk,
+						identity, radius_cui);
+		if (res == HOSTAPD_ACL_ACCEPT ||
+		    res == HOSTAPD_ACL_ACCEPT_TIMEOUT)
+			return res;
+		if (res == HOSTAPD_ACL_REJECT)
+			return HOSTAPD_ACL_REJECT;
+
+		query = hapd->acl_queries;
+		while (query) {
+			if (os_memcmp(query->addr, addr, ETH_ALEN) == 0) {
+				/* pending query in RADIUS retransmit queue;
+				 * do not generate a new one */
+				if (identity) {
+					os_free(*identity);
+					*identity = NULL;
+				}
+				if (radius_cui) {
+					os_free(*radius_cui);
+					*radius_cui = NULL;
+				}
+				return HOSTAPD_ACL_PENDING;
+			}
+			query = query->next;
+		}
+
+		if (!hapd->conf->radius->auth_server)
+			return HOSTAPD_ACL_REJECT;
+
+		/* No entry in the cache - query external RADIUS server */
+		query = os_zalloc(sizeof(*query));
+		if (query == NULL) {
+			wpa_printf(MSG_ERROR, "malloc for query data failed");
+			return HOSTAPD_ACL_REJECT;
+		}
+		os_get_time(&t);
+		query->timestamp = t.sec;
+		os_memcpy(query->addr, addr, ETH_ALEN);
+		if (hostapd_radius_acl_query(hapd, addr, query)) {
+			wpa_printf(MSG_DEBUG, "Failed to send Access-Request "
+				   "for ACL query.");
+			hostapd_acl_query_free(query);
+			return HOSTAPD_ACL_REJECT;
+		}
+
+		query->auth_msg = os_malloc(len);
+		if (query->auth_msg == NULL) {
+			wpa_printf(MSG_ERROR, "Failed to allocate memory for "
+				   "auth frame.");
+			hostapd_acl_query_free(query);
+			return HOSTAPD_ACL_REJECT;
+		}
+		os_memcpy(query->auth_msg, msg, len);
+		query->auth_msg_len = len;
+		query->next = hapd->acl_queries;
+		hapd->acl_queries = query;
+
+		/* Queued data will be processed in hostapd_acl_recv_radius()
+		 * when RADIUS server replies to the sent Access-Request. */
+		return HOSTAPD_ACL_PENDING;
+#endif /* CONFIG_NO_RADIUS */
+	}
+
+	return HOSTAPD_ACL_REJECT;
+}
+
+
+#ifndef CONFIG_NO_RADIUS
+static void hostapd_acl_expire_cache(struct hostapd_data *hapd, os_time_t now)
+{
+	struct hostapd_cached_radius_acl *prev, *entry, *tmp;
+
+	prev = NULL;
+	entry = hapd->acl_cache;
+
+	while (entry) {
+		if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
+			wpa_printf(MSG_DEBUG, "Cached ACL entry for " MACSTR
+				   " has expired.", MAC2STR(entry->addr));
+			if (prev)
+				prev->next = entry->next;
+			else
+				hapd->acl_cache = entry->next;
+			hostapd_drv_set_radius_acl_expire(hapd, entry->addr);
+			tmp = entry;
+			entry = entry->next;
+			hostapd_acl_cache_free_entry(tmp);
+			continue;
+		}
+
+		prev = entry;
+		entry = entry->next;
+	}
+}
+
+
+static void hostapd_acl_expire_queries(struct hostapd_data *hapd,
+				       os_time_t now)
+{
+	struct hostapd_acl_query_data *prev, *entry, *tmp;
+
+	prev = NULL;
+	entry = hapd->acl_queries;
+
+	while (entry) {
+		if (now - entry->timestamp > RADIUS_ACL_TIMEOUT) {
+			wpa_printf(MSG_DEBUG, "ACL query for " MACSTR
+				   " has expired.", MAC2STR(entry->addr));
+			if (prev)
+				prev->next = entry->next;
+			else
+				hapd->acl_queries = entry->next;
+
+			tmp = entry;
+			entry = entry->next;
+			hostapd_acl_query_free(tmp);
+			continue;
+		}
+
+		prev = entry;
+		entry = entry->next;
+	}
+}
+
+
+/**
+ * hostapd_acl_expire - ACL cache expiration callback
+ * @eloop_ctx: struct hostapd_data *
+ * @timeout_ctx: Not used
+ */
+static void hostapd_acl_expire(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct os_time now;
+
+	os_get_time(&now);
+	hostapd_acl_expire_cache(hapd, now.sec);
+	hostapd_acl_expire_queries(hapd, now.sec);
+
+	eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
+}
+
+
+static void decode_tunnel_passwords(struct hostapd_data *hapd,
+				    const u8 *shared_secret,
+				    size_t shared_secret_len,
+				    struct radius_msg *msg,
+				    struct radius_msg *req,
+				    struct hostapd_cached_radius_acl *cache)
+{
+	int passphraselen;
+	char *passphrase, *strpassphrase;
+	size_t i;
+	struct hostapd_sta_wpa_psk_short *psk;
+
+	/*
+	 * Decode all tunnel passwords as PSK and save them into a linked list.
+	 */
+	for (i = 0; ; i++) {
+		passphrase = radius_msg_get_tunnel_password(
+			msg, &passphraselen, shared_secret, shared_secret_len,
+			req, i);
+		/*
+		 * Passphrase is NULL iff there is no i-th Tunnel-Password
+		 * attribute in msg.
+		 */
+		if (passphrase == NULL)
+			break;
+		/*
+		 * passphrase does not contain the NULL termination.
+		 * Add it here as pbkdf2_sha1() requires it.
+		 */
+		strpassphrase = os_zalloc(passphraselen + 1);
+		psk = os_zalloc(sizeof(struct hostapd_sta_wpa_psk_short));
+		if (strpassphrase && psk) {
+			os_memcpy(strpassphrase, passphrase, passphraselen);
+			pbkdf2_sha1(strpassphrase,
+				    hapd->conf->ssid.ssid,
+				    hapd->conf->ssid.ssid_len, 4096,
+				    psk->psk, PMK_LEN);
+			psk->next = cache->psk;
+			cache->psk = psk;
+			psk = NULL;
+		}
+		os_free(strpassphrase);
+		os_free(psk);
+		os_free(passphrase);
+	}
+}
+
+
+/**
+ * hostapd_acl_recv_radius - Process incoming RADIUS Authentication messages
+ * @msg: RADIUS response message
+ * @req: RADIUS request message
+ * @shared_secret: RADIUS shared secret
+ * @shared_secret_len: Length of shared_secret in octets
+ * @data: Context data (struct hostapd_data *)
+ * Returns: RADIUS_RX_PROCESSED if RADIUS message was a reply to ACL query (and
+ * was processed here) or RADIUS_RX_UNKNOWN if not.
+ */
+static RadiusRxResult
+hostapd_acl_recv_radius(struct radius_msg *msg, struct radius_msg *req,
+			const u8 *shared_secret, size_t shared_secret_len,
+			void *data)
+{
+	struct hostapd_data *hapd = data;
+	struct hostapd_acl_query_data *query, *prev;
+	struct hostapd_cached_radius_acl *cache;
+	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
+	struct os_time t;
+
+	query = hapd->acl_queries;
+	prev = NULL;
+	while (query) {
+		if (query->radius_id == hdr->identifier)
+			break;
+		prev = query;
+		query = query->next;
+	}
+	if (query == NULL)
+		return RADIUS_RX_UNKNOWN;
+
+	wpa_printf(MSG_DEBUG, "Found matching Access-Request for RADIUS "
+		   "message (id=%d)", query->radius_id);
+
+	if (radius_msg_verify(msg, shared_secret, shared_secret_len, req, 0)) {
+		wpa_printf(MSG_INFO, "Incoming RADIUS packet did not have "
+			   "correct authenticator - dropped\n");
+		return RADIUS_RX_INVALID_AUTHENTICATOR;
+	}
+
+	if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
+	    hdr->code != RADIUS_CODE_ACCESS_REJECT) {
+		wpa_printf(MSG_DEBUG, "Unknown RADIUS message code %d to ACL "
+			   "query", hdr->code);
+		return RADIUS_RX_UNKNOWN;
+	}
+
+	/* Insert Accept/Reject info into ACL cache */
+	cache = os_zalloc(sizeof(*cache));
+	if (cache == NULL) {
+		wpa_printf(MSG_DEBUG, "Failed to add ACL cache entry");
+		goto done;
+	}
+	os_get_time(&t);
+	cache->timestamp = t.sec;
+	os_memcpy(cache->addr, query->addr, sizeof(cache->addr));
+	if (hdr->code == RADIUS_CODE_ACCESS_ACCEPT) {
+		u8 *buf;
+		size_t len;
+
+		if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
+					      &cache->session_timeout) == 0)
+			cache->accepted = HOSTAPD_ACL_ACCEPT_TIMEOUT;
+		else
+			cache->accepted = HOSTAPD_ACL_ACCEPT;
+
+		if (radius_msg_get_attr_int32(
+			    msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
+			    &cache->acct_interim_interval) == 0 &&
+		    cache->acct_interim_interval < 60) {
+			wpa_printf(MSG_DEBUG, "Ignored too small "
+				   "Acct-Interim-Interval %d for STA " MACSTR,
+				   cache->acct_interim_interval,
+				   MAC2STR(query->addr));
+			cache->acct_interim_interval = 0;
+		}
+
+		cache->vlan_id = radius_msg_get_vlanid(msg);
+
+		decode_tunnel_passwords(hapd, shared_secret, shared_secret_len,
+					msg, req, cache);
+
+		if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME,
+					    &buf, &len, NULL) == 0) {
+			cache->identity = os_zalloc(len + 1);
+			if (cache->identity)
+				os_memcpy(cache->identity, buf, len);
+		}
+		if (radius_msg_get_attr_ptr(
+			    msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+			    &buf, &len, NULL) == 0) {
+			cache->radius_cui = os_zalloc(len + 1);
+			if (cache->radius_cui)
+				os_memcpy(cache->radius_cui, buf, len);
+		}
+
+		if (hapd->conf->wpa_psk_radius == PSK_RADIUS_REQUIRED &&
+		    !cache->psk)
+			cache->accepted = HOSTAPD_ACL_REJECT;
+	} else
+		cache->accepted = HOSTAPD_ACL_REJECT;
+	cache->next = hapd->acl_cache;
+	hapd->acl_cache = cache;
+
+#ifdef CONFIG_DRIVER_RADIUS_ACL
+	hostapd_drv_set_radius_acl_auth(hapd, query->addr, cache->accepted,
+					cache->session_timeout);
+#else /* CONFIG_DRIVER_RADIUS_ACL */
+#ifdef NEED_AP_MLME
+	/* Re-send original authentication frame for 802.11 processing */
+	wpa_printf(MSG_DEBUG, "Re-sending authentication frame after "
+		   "successful RADIUS ACL query");
+	ieee802_11_mgmt(hapd, query->auth_msg, query->auth_msg_len, NULL);
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_DRIVER_RADIUS_ACL */
+
+ done:
+	if (prev == NULL)
+		hapd->acl_queries = query->next;
+	else
+		prev->next = query->next;
+
+	hostapd_acl_query_free(query);
+
+	return RADIUS_RX_PROCESSED;
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
+/**
+ * hostapd_acl_init: Initialize IEEE 802.11 ACL
+ * @hapd: hostapd BSS data
+ * Returns: 0 on success, -1 on failure
+ */
+int hostapd_acl_init(struct hostapd_data *hapd)
+{
+#ifndef CONFIG_NO_RADIUS
+	if (radius_client_register(hapd->radius, RADIUS_AUTH,
+				   hostapd_acl_recv_radius, hapd))
+		return -1;
+
+	eloop_register_timeout(10, 0, hostapd_acl_expire, hapd, NULL);
+#endif /* CONFIG_NO_RADIUS */
+
+	return 0;
+}
+
+
+/**
+ * hostapd_acl_deinit - Deinitialize IEEE 802.11 ACL
+ * @hapd: hostapd BSS data
+ */
+void hostapd_acl_deinit(struct hostapd_data *hapd)
+{
+	struct hostapd_acl_query_data *query, *prev;
+
+#ifndef CONFIG_NO_RADIUS
+	eloop_cancel_timeout(hostapd_acl_expire, hapd, NULL);
+
+	hostapd_acl_cache_free(hapd->acl_cache);
+#endif /* CONFIG_NO_RADIUS */
+
+	query = hapd->acl_queries;
+	while (query) {
+		prev = query;
+		query = query->next;
+		hostapd_acl_query_free(prev);
+	}
+}
+
+
+void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk)
+{
+	while (psk) {
+		struct hostapd_sta_wpa_psk_short *prev = psk;
+		psk = psk->next;
+		os_free(prev);
+	}
+}
diff --git a/hostap/src/ap/ieee802_11_auth.h b/hostap/src/ap/ieee802_11_auth.h
new file mode 100644
index 0000000..2bc1065
--- /dev/null
+++ b/hostap/src/ap/ieee802_11_auth.h
@@ -0,0 +1,28 @@
+/*
+ * hostapd / IEEE 802.11 authentication (ACL)
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_11_AUTH_H
+#define IEEE802_11_AUTH_H
+
+enum {
+	HOSTAPD_ACL_REJECT = 0,
+	HOSTAPD_ACL_ACCEPT = 1,
+	HOSTAPD_ACL_PENDING = 2,
+	HOSTAPD_ACL_ACCEPT_TIMEOUT = 3
+};
+
+int hostapd_allowed_address(struct hostapd_data *hapd, const u8 *addr,
+			    const u8 *msg, size_t len, u32 *session_timeout,
+			    u32 *acct_interim_interval, int *vlan_id,
+			    struct hostapd_sta_wpa_psk_short **psk,
+			    char **identity, char **radius_cui);
+int hostapd_acl_init(struct hostapd_data *hapd);
+void hostapd_acl_deinit(struct hostapd_data *hapd);
+void hostapd_free_psk_list(struct hostapd_sta_wpa_psk_short *psk);
+
+#endif /* IEEE802_11_AUTH_H */
diff --git a/hostap/src/ap/ieee802_11_ht.c b/hostap/src/ap/ieee802_11_ht.c
new file mode 100644
index 0000000..6c3696f
--- /dev/null
+++ b/hostap/src/ap/ieee802_11_ht.c
@@ -0,0 +1,273 @@
+/*
+ * hostapd / IEEE 802.11n HT
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2008, Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "sta_info.h"
+#include "beacon.h"
+#include "ieee802_11.h"
+
+
+u8 * hostapd_eid_ht_capabilities(struct hostapd_data *hapd, u8 *eid)
+{
+	struct ieee80211_ht_capabilities *cap;
+	u8 *pos = eid;
+
+	if (!hapd->iconf->ieee80211n || !hapd->iface->current_mode ||
+	    hapd->conf->disable_11n)
+		return eid;
+
+	*pos++ = WLAN_EID_HT_CAP;
+	*pos++ = sizeof(*cap);
+
+	cap = (struct ieee80211_ht_capabilities *) pos;
+	os_memset(cap, 0, sizeof(*cap));
+	cap->ht_capabilities_info = host_to_le16(hapd->iconf->ht_capab);
+	cap->a_mpdu_params = hapd->iface->current_mode->a_mpdu_params;
+	os_memcpy(cap->supported_mcs_set, hapd->iface->current_mode->mcs_set,
+		  16);
+
+	/* TODO: ht_extended_capabilities (now fully disabled) */
+	/* TODO: tx_bf_capability_info (now fully disabled) */
+	/* TODO: asel_capabilities (now fully disabled) */
+
+ 	pos += sizeof(*cap);
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_ht_operation(struct hostapd_data *hapd, u8 *eid)
+{
+	struct ieee80211_ht_operation *oper;
+	u8 *pos = eid;
+
+	if (!hapd->iconf->ieee80211n || hapd->conf->disable_11n)
+		return eid;
+
+	*pos++ = WLAN_EID_HT_OPERATION;
+	*pos++ = sizeof(*oper);
+
+	oper = (struct ieee80211_ht_operation *) pos;
+	os_memset(oper, 0, sizeof(*oper));
+
+	oper->control_chan = hapd->iconf->channel;
+	oper->operation_mode = host_to_le16(hapd->iface->ht_op_mode);
+	if (hapd->iconf->secondary_channel == 1)
+		oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE |
+			HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
+	if (hapd->iconf->secondary_channel == -1)
+		oper->ht_param |= HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW |
+			HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH;
+
+	pos += sizeof(*oper);
+
+	return pos;
+}
+
+
+/*
+op_mode
+Set to 0 (HT pure) under the followign conditions
+	- all STAs in the BSS are 20/40 MHz HT in 20/40 MHz BSS or
+	- all STAs in the BSS are 20 MHz HT in 20 MHz BSS
+Set to 1 (HT non-member protection) if there may be non-HT STAs
+	in both the primary and the secondary channel
+Set to 2 if only HT STAs are associated in BSS,
+	however and at least one 20 MHz HT STA is associated
+Set to 3 (HT mixed mode) when one or more non-HT STAs are associated
+*/
+int hostapd_ht_operation_update(struct hostapd_iface *iface)
+{
+	u16 cur_op_mode, new_op_mode;
+	int op_mode_changes = 0;
+
+	if (!iface->conf->ieee80211n || iface->conf->ht_op_mode_fixed)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "%s current operation mode=0x%X",
+		   __func__, iface->ht_op_mode);
+
+	if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT)
+	    && iface->num_sta_ht_no_gf) {
+		iface->ht_op_mode |=
+			HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+		op_mode_changes++;
+	} else if ((iface->ht_op_mode &
+		    HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT) &&
+		   iface->num_sta_ht_no_gf == 0) {
+		iface->ht_op_mode &=
+			~HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT;
+		op_mode_changes++;
+	}
+
+	if (!(iface->ht_op_mode & HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+	    (iface->num_sta_no_ht || iface->olbc_ht)) {
+		iface->ht_op_mode |= HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+		op_mode_changes++;
+	} else if ((iface->ht_op_mode &
+		    HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT) &&
+		   (iface->num_sta_no_ht == 0 && !iface->olbc_ht)) {
+		iface->ht_op_mode &=
+			~HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT;
+		op_mode_changes++;
+	}
+
+	new_op_mode = 0;
+	if (iface->num_sta_no_ht)
+		new_op_mode = OP_MODE_MIXED;
+	else if ((iface->conf->ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)
+		 && iface->num_sta_ht_20mhz)
+		new_op_mode = OP_MODE_20MHZ_HT_STA_ASSOCED;
+	else if (iface->olbc_ht)
+		new_op_mode = OP_MODE_MAY_BE_LEGACY_STAS;
+	else
+		new_op_mode = OP_MODE_PURE;
+
+	cur_op_mode = iface->ht_op_mode & HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+	if (cur_op_mode != new_op_mode) {
+		iface->ht_op_mode &= ~HT_INFO_OPERATION_MODE_OP_MODE_MASK;
+		iface->ht_op_mode |= new_op_mode;
+		op_mode_changes++;
+	}
+
+	wpa_printf(MSG_DEBUG, "%s new operation mode=0x%X changes=%d",
+		   __func__, iface->ht_op_mode, op_mode_changes);
+
+	return op_mode_changes;
+}
+
+
+u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+		      const u8 *ht_capab, size_t ht_capab_len)
+{
+	/* Disable HT caps for STAs associated to no-HT BSSes. */
+	if (!ht_capab ||
+	    ht_capab_len < sizeof(struct ieee80211_ht_capabilities) ||
+	    hapd->conf->disable_11n) {
+		sta->flags &= ~WLAN_STA_HT;
+		os_free(sta->ht_capabilities);
+		sta->ht_capabilities = NULL;
+		return WLAN_STATUS_SUCCESS;
+	}
+
+	if (sta->ht_capabilities == NULL) {
+		sta->ht_capabilities =
+			os_zalloc(sizeof(struct ieee80211_ht_capabilities));
+		if (sta->ht_capabilities == NULL)
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	sta->flags |= WLAN_STA_HT;
+	os_memcpy(sta->ht_capabilities, ht_capab,
+		  sizeof(struct ieee80211_ht_capabilities));
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+static void update_sta_ht(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	u16 ht_capab;
+
+	ht_capab = le_to_host16(sta->ht_capabilities->ht_capabilities_info);
+	wpa_printf(MSG_DEBUG, "HT: STA " MACSTR " HT Capabilities Info: "
+		   "0x%04x", MAC2STR(sta->addr), ht_capab);
+	if ((ht_capab & HT_CAP_INFO_GREEN_FIELD) == 0) {
+		if (!sta->no_ht_gf_set) {
+			sta->no_ht_gf_set = 1;
+			hapd->iface->num_sta_ht_no_gf++;
+		}
+		wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no greenfield, num "
+			   "of non-gf stations %d",
+			   __func__, MAC2STR(sta->addr),
+			   hapd->iface->num_sta_ht_no_gf);
+	}
+	if ((ht_capab & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) == 0) {
+		if (!sta->ht_20mhz_set) {
+			sta->ht_20mhz_set = 1;
+			hapd->iface->num_sta_ht_20mhz++;
+		}
+		wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - 20 MHz HT, num of "
+			   "20MHz HT STAs %d",
+			   __func__, MAC2STR(sta->addr),
+			   hapd->iface->num_sta_ht_20mhz);
+	}
+}
+
+
+static void update_sta_no_ht(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	if (!sta->no_ht_set) {
+		sta->no_ht_set = 1;
+		hapd->iface->num_sta_no_ht++;
+	}
+	if (hapd->iconf->ieee80211n) {
+		wpa_printf(MSG_DEBUG, "%s STA " MACSTR " - no HT, num of "
+			   "non-HT stations %d",
+			   __func__, MAC2STR(sta->addr),
+			   hapd->iface->num_sta_no_ht);
+	}
+}
+
+
+void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	if ((sta->flags & WLAN_STA_HT) && sta->ht_capabilities)
+		update_sta_ht(hapd, sta);
+	else
+		update_sta_no_ht(hapd, sta);
+
+	if (hostapd_ht_operation_update(hapd->iface) > 0)
+		ieee802_11_set_beacons(hapd->iface);
+}
+
+
+void hostapd_get_ht_capab(struct hostapd_data *hapd,
+			  struct ieee80211_ht_capabilities *ht_cap,
+			  struct ieee80211_ht_capabilities *neg_ht_cap)
+{
+	u16 cap;
+
+	if (ht_cap == NULL)
+		return;
+	os_memcpy(neg_ht_cap, ht_cap, sizeof(*neg_ht_cap));
+	cap = le_to_host16(neg_ht_cap->ht_capabilities_info);
+
+	/*
+	 * Mask out HT features we don't support, but don't overwrite
+	 * non-symmetric features like STBC and SMPS. Just because
+	 * we're not in dynamic SMPS mode the STA might still be.
+	 */
+	cap &= (hapd->iconf->ht_capab | HT_CAP_INFO_RX_STBC_MASK |
+		HT_CAP_INFO_TX_STBC | HT_CAP_INFO_SMPS_MASK);
+
+	/*
+	 * STBC needs to be handled specially
+	 * if we don't support RX STBC, mask out TX STBC in the STA's HT caps
+	 * if we don't support TX STBC, mask out RX STBC in the STA's HT caps
+	 */
+	if (!(hapd->iconf->ht_capab & HT_CAP_INFO_RX_STBC_MASK))
+		cap &= ~HT_CAP_INFO_TX_STBC;
+	if (!(hapd->iconf->ht_capab & HT_CAP_INFO_TX_STBC))
+		cap &= ~HT_CAP_INFO_RX_STBC_MASK;
+
+	neg_ht_cap->ht_capabilities_info = host_to_le16(cap);
+}
diff --git a/hostap/src/ap/ieee802_11_shared.c b/hostap/src/ap/ieee802_11_shared.c
new file mode 100644
index 0000000..76f78a7
--- /dev/null
+++ b/hostap/src/ap/ieee802_11_shared.c
@@ -0,0 +1,458 @@
+/*
+ * hostapd / IEEE 802.11 Management
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "ieee802_11.h"
+
+
+#ifdef CONFIG_IEEE80211W
+
+u8 * hostapd_eid_assoc_comeback_time(struct hostapd_data *hapd,
+				     struct sta_info *sta, u8 *eid)
+{
+	u8 *pos = eid;
+	u32 timeout, tu;
+	struct os_time now, passed;
+
+	*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+	*pos++ = 5;
+	*pos++ = WLAN_TIMEOUT_ASSOC_COMEBACK;
+	os_get_time(&now);
+	os_time_sub(&now, &sta->sa_query_start, &passed);
+	tu = (passed.sec * 1000000 + passed.usec) / 1024;
+	if (hapd->conf->assoc_sa_query_max_timeout > tu)
+		timeout = hapd->conf->assoc_sa_query_max_timeout - tu;
+	else
+		timeout = 0;
+	if (timeout < hapd->conf->assoc_sa_query_max_timeout)
+		timeout++; /* add some extra time for local timers */
+	WPA_PUT_LE32(pos, timeout);
+	pos += 4;
+
+	return pos;
+}
+
+
+/* MLME-SAQuery.request */
+void ieee802_11_send_sa_query_req(struct hostapd_data *hapd,
+				  const u8 *addr, const u8 *trans_id)
+{
+	struct ieee80211_mgmt mgmt;
+	u8 *end;
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Request to "
+		   MACSTR, MAC2STR(addr));
+	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+	os_memset(&mgmt, 0, sizeof(mgmt));
+	mgmt.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_ACTION);
+	os_memcpy(mgmt.da, addr, ETH_ALEN);
+	os_memcpy(mgmt.sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt.bssid, hapd->own_addr, ETH_ALEN);
+	mgmt.u.action.category = WLAN_ACTION_SA_QUERY;
+	mgmt.u.action.u.sa_query_req.action = WLAN_SA_QUERY_REQUEST;
+	os_memcpy(mgmt.u.action.u.sa_query_req.trans_id, trans_id,
+		  WLAN_SA_QUERY_TR_ID_LEN);
+	end = mgmt.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
+	if (hostapd_drv_send_mlme(hapd, &mgmt, end - (u8 *) &mgmt, 0) < 0)
+		perror("ieee802_11_send_sa_query_req: send");
+}
+
+
+static void ieee802_11_send_sa_query_resp(struct hostapd_data *hapd,
+					  const u8 *sa, const u8 *trans_id)
+{
+	struct sta_info *sta;
+	struct ieee80211_mgmt resp;
+	u8 *end;
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Request from "
+		   MACSTR, MAC2STR(sa));
+	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+	sta = ap_get_sta(hapd, sa);
+	if (sta == NULL || !(sta->flags & WLAN_STA_ASSOC)) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: Ignore SA Query Request "
+			   "from unassociated STA " MACSTR, MAC2STR(sa));
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.11: Sending SA Query Response to "
+		   MACSTR, MAC2STR(sa));
+
+	os_memset(&resp, 0, sizeof(resp));
+	resp.frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					  WLAN_FC_STYPE_ACTION);
+	os_memcpy(resp.da, sa, ETH_ALEN);
+	os_memcpy(resp.sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(resp.bssid, hapd->own_addr, ETH_ALEN);
+	resp.u.action.category = WLAN_ACTION_SA_QUERY;
+	resp.u.action.u.sa_query_req.action = WLAN_SA_QUERY_RESPONSE;
+	os_memcpy(resp.u.action.u.sa_query_req.trans_id, trans_id,
+		  WLAN_SA_QUERY_TR_ID_LEN);
+	end = resp.u.action.u.sa_query_req.trans_id + WLAN_SA_QUERY_TR_ID_LEN;
+	if (hostapd_drv_send_mlme(hapd, &resp, end - (u8 *) &resp, 0) < 0)
+		perror("ieee80211_mgmt_sa_query_request: send");
+}
+
+
+void ieee802_11_sa_query_action(struct hostapd_data *hapd, const u8 *sa,
+				const u8 action_type, const u8 *trans_id)
+{
+	struct sta_info *sta;
+	int i;
+
+	if (action_type == WLAN_SA_QUERY_REQUEST) {
+		ieee802_11_send_sa_query_resp(hapd, sa, trans_id);
+		return;
+	}
+
+	if (action_type != WLAN_SA_QUERY_RESPONSE) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: Unexpected SA Query "
+			   "Action %d", action_type);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.11: Received SA Query Response from "
+		   MACSTR, MAC2STR(sa));
+	wpa_hexdump(MSG_DEBUG, "IEEE 802.11: SA Query Transaction ID",
+		    trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+	/* MLME-SAQuery.confirm */
+
+	sta = ap_get_sta(hapd, sa);
+	if (sta == NULL || sta->sa_query_trans_id == NULL) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching STA with "
+			   "pending SA Query request found");
+		return;
+	}
+
+	for (i = 0; i < sta->sa_query_count; i++) {
+		if (os_memcmp(sta->sa_query_trans_id +
+			      i * WLAN_SA_QUERY_TR_ID_LEN,
+			      trans_id, WLAN_SA_QUERY_TR_ID_LEN) == 0)
+			break;
+	}
+
+	if (i >= sta->sa_query_count) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.11: No matching SA Query "
+			   "transaction identifier found");
+		return;
+	}
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "Reply to pending SA Query received");
+	ap_sta_stop_sa_query(hapd, sta);
+}
+
+#endif /* CONFIG_IEEE80211W */
+
+
+u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+	u8 len = 0;
+
+	if (hapd->conf->tdls & (TDLS_PROHIBIT | TDLS_PROHIBIT_CHAN_SWITCH))
+		len = 5;
+	if (len < 4 && hapd->conf->interworking)
+		len = 4;
+	if (len < 3 && hapd->conf->wnm_sleep_mode)
+		len = 3;
+	if (len < 7 && hapd->conf->ssid.utf8_ssid)
+		len = 7;
+#ifdef CONFIG_WNM
+	if (len < 4)
+		len = 4;
+#endif /* CONFIG_WNM */
+	if (len == 0)
+		return eid;
+
+	*pos++ = WLAN_EID_EXT_CAPAB;
+	*pos++ = len;
+	*pos++ = 0x00;
+	*pos++ = 0x00;
+
+	*pos = 0x00;
+	if (hapd->conf->wnm_sleep_mode)
+		*pos |= 0x02; /* Bit 17 - WNM-Sleep Mode */
+	if (hapd->conf->bss_transition)
+		*pos |= 0x08; /* Bit 19 - BSS Transition */
+	pos++;
+
+	if (len < 4)
+		return pos;
+	*pos = 0x00;
+#ifdef CONFIG_WNM
+	*pos |= 0x02; /* Bit 25 - SSID List */
+#endif /* CONFIG_WNM */
+	if (hapd->conf->time_advertisement == 2)
+		*pos |= 0x08; /* Bit 27 - UTC TSF Offset */
+	if (hapd->conf->interworking)
+		*pos |= 0x80; /* Bit 31 - Interworking */
+	pos++;
+
+	if (len < 5)
+		return pos;
+	*pos = 0x00;
+	if (hapd->conf->tdls & TDLS_PROHIBIT)
+		*pos |= 0x40; /* Bit 38 - TDLS Prohibited */
+	if (hapd->conf->tdls & TDLS_PROHIBIT_CHAN_SWITCH)
+		*pos |= 0x80; /* Bit 39 - TDLS Channel Switching Prohibited */
+	pos++;
+
+	if (len < 6)
+		return pos;
+	*pos = 0x00;
+	pos++;
+
+	if (len < 7)
+		return pos;
+	*pos = 0x00;
+	if (hapd->conf->ssid.utf8_ssid)
+		*pos |= 0x01; /* Bit 48 - UTF-8 SSID */
+	pos++;
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_interworking(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+	u8 *len;
+
+	if (!hapd->conf->interworking)
+		return eid;
+
+	*pos++ = WLAN_EID_INTERWORKING;
+	len = pos++;
+
+	*pos = hapd->conf->access_network_type;
+	if (hapd->conf->internet)
+		*pos |= INTERWORKING_ANO_INTERNET;
+	if (hapd->conf->asra)
+		*pos |= INTERWORKING_ANO_ASRA;
+	if (hapd->conf->esr)
+		*pos |= INTERWORKING_ANO_ESR;
+	if (hapd->conf->uesa)
+		*pos |= INTERWORKING_ANO_UESA;
+	pos++;
+
+	if (hapd->conf->venue_info_set) {
+		*pos++ = hapd->conf->venue_group;
+		*pos++ = hapd->conf->venue_type;
+	}
+
+	if (!is_zero_ether_addr(hapd->conf->hessid)) {
+		os_memcpy(pos, hapd->conf->hessid, ETH_ALEN);
+		pos += ETH_ALEN;
+	}
+
+	*len = pos - len - 1;
+#endif /* CONFIG_INTERWORKING */
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_adv_proto(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+
+	/* TODO: Separate configuration for ANQP? */
+	if (!hapd->conf->interworking)
+		return eid;
+
+	*pos++ = WLAN_EID_ADV_PROTO;
+	*pos++ = 2;
+	*pos++ = 0x7F; /* Query Response Length Limit | PAME-BI */
+	*pos++ = ACCESS_NETWORK_QUERY_PROTOCOL;
+#endif /* CONFIG_INTERWORKING */
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_roaming_consortium(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+#ifdef CONFIG_INTERWORKING
+	u8 *len;
+	unsigned int i, count;
+
+	if (!hapd->conf->interworking ||
+	    hapd->conf->roaming_consortium == NULL ||
+	    hapd->conf->roaming_consortium_count == 0)
+		return eid;
+
+	*pos++ = WLAN_EID_ROAMING_CONSORTIUM;
+	len = pos++;
+
+	/* Number of ANQP OIs (in addition to the max 3 listed here) */
+	if (hapd->conf->roaming_consortium_count > 3 + 255)
+		*pos++ = 255;
+	else if (hapd->conf->roaming_consortium_count > 3)
+		*pos++ = hapd->conf->roaming_consortium_count - 3;
+	else
+		*pos++ = 0;
+
+	/* OU #1 and #2 Lengths */
+	*pos = hapd->conf->roaming_consortium[0].len;
+	if (hapd->conf->roaming_consortium_count > 1)
+		*pos |= hapd->conf->roaming_consortium[1].len << 4;
+	pos++;
+
+	if (hapd->conf->roaming_consortium_count > 3)
+		count = 3;
+	else
+		count = hapd->conf->roaming_consortium_count;
+
+	for (i = 0; i < count; i++) {
+		os_memcpy(pos, hapd->conf->roaming_consortium[i].oi,
+			  hapd->conf->roaming_consortium[i].len);
+		pos += hapd->conf->roaming_consortium[i].len;
+	}
+
+	*len = pos - len - 1;
+#endif /* CONFIG_INTERWORKING */
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_time_adv(struct hostapd_data *hapd, u8 *eid)
+{
+	if (hapd->conf->time_advertisement != 2)
+		return eid;
+
+	if (hapd->time_adv == NULL &&
+	    hostapd_update_time_adv(hapd) < 0)
+		return eid;
+
+	if (hapd->time_adv == NULL)
+		return eid;
+
+	os_memcpy(eid, wpabuf_head(hapd->time_adv),
+		  wpabuf_len(hapd->time_adv));
+	eid += wpabuf_len(hapd->time_adv);
+
+	return eid;
+}
+
+
+u8 * hostapd_eid_time_zone(struct hostapd_data *hapd, u8 *eid)
+{
+	size_t len;
+
+	if (hapd->conf->time_advertisement != 2)
+		return eid;
+
+	len = os_strlen(hapd->conf->time_zone);
+
+	*eid++ = WLAN_EID_TIME_ZONE;
+	*eid++ = len;
+	os_memcpy(eid, hapd->conf->time_zone, len);
+	eid += len;
+
+	return eid;
+}
+
+
+int hostapd_update_time_adv(struct hostapd_data *hapd)
+{
+	const int elen = 2 + 1 + 10 + 5 + 1;
+	struct os_time t;
+	struct os_tm tm;
+	u8 *pos;
+
+	if (hapd->conf->time_advertisement != 2)
+		return 0;
+
+	if (os_get_time(&t) < 0 || os_gmtime(t.sec, &tm) < 0)
+		return -1;
+
+	if (!hapd->time_adv) {
+		hapd->time_adv = wpabuf_alloc(elen);
+		if (hapd->time_adv == NULL)
+			return -1;
+		pos = wpabuf_put(hapd->time_adv, elen);
+	} else
+		pos = wpabuf_mhead_u8(hapd->time_adv);
+
+	*pos++ = WLAN_EID_TIME_ADVERTISEMENT;
+	*pos++ = 1 + 10 + 5 + 1;
+
+	*pos++ = 2; /* UTC time at which the TSF timer is 0 */
+
+	/* Time Value at TSF 0 */
+	/* FIX: need to calculate this based on the current TSF value */
+	WPA_PUT_LE16(pos, tm.year); /* Year */
+	pos += 2;
+	*pos++ = tm.month; /* Month */
+	*pos++ = tm.day; /* Day of month */
+	*pos++ = tm.hour; /* Hours */
+	*pos++ = tm.min; /* Minutes */
+	*pos++ = tm.sec; /* Seconds */
+	WPA_PUT_LE16(pos, 0); /* Milliseconds (not used) */
+	pos += 2;
+	*pos++ = 0; /* Reserved */
+
+	/* Time Error */
+	/* TODO: fill in an estimate on the error */
+	*pos++ = 0;
+	*pos++ = 0;
+	*pos++ = 0;
+	*pos++ = 0;
+	*pos++ = 0;
+
+	*pos++ = hapd->time_update_counter++;
+
+	return 0;
+}
+
+
+u8 * hostapd_eid_bss_max_idle_period(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+
+#ifdef CONFIG_WNM
+	if (hapd->conf->ap_max_inactivity > 0) {
+		unsigned int val;
+		*pos++ = WLAN_EID_BSS_MAX_IDLE_PERIOD;
+		*pos++ = 3;
+		val = hapd->conf->ap_max_inactivity;
+		if (val > 68000)
+			val = 68000;
+		val *= 1000;
+		val /= 1024;
+		if (val == 0)
+			val = 1;
+		if (val > 65535)
+			val = 65535;
+		WPA_PUT_LE16(pos, val);
+		pos += 2;
+		*pos++ = 0x00; /* TODO: Protected Keep-Alive Required */
+	}
+#endif /* CONFIG_WNM */
+
+	return pos;
+}
diff --git a/hostap/src/ap/ieee802_11_vht.c b/hostap/src/ap/ieee802_11_vht.c
new file mode 100644
index 0000000..b21c2b7
--- /dev/null
+++ b/hostap/src/ap/ieee802_11_vht.c
@@ -0,0 +1,110 @@
+/*
+ * hostapd / IEEE 802.11ac VHT
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of BSD license
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "drivers/driver.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "sta_info.h"
+#include "beacon.h"
+#include "ieee802_11.h"
+
+
+u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
+{
+	struct ieee80211_vht_capabilities *cap;
+	u8 *pos = eid;
+
+	if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode ||
+	    hapd->conf->disable_11ac)
+		return eid;
+
+	*pos++ = WLAN_EID_VHT_CAP;
+	*pos++ = sizeof(*cap);
+
+	cap = (struct ieee80211_vht_capabilities *) pos;
+	os_memset(cap, 0, sizeof(*cap));
+	cap->vht_capabilities_info = host_to_le32(
+		hapd->iface->current_mode->vht_capab);
+
+	/* Supported MCS set comes from hw */
+	os_memcpy(cap->vht_supported_mcs_set,
+	          hapd->iface->current_mode->vht_mcs_set, 8);
+
+	pos += sizeof(*cap);
+
+	return pos;
+}
+
+
+u8 * hostapd_eid_vht_operation(struct hostapd_data *hapd, u8 *eid)
+{
+	struct ieee80211_vht_operation *oper;
+	u8 *pos = eid;
+
+	if (!hapd->iconf->ieee80211ac || hapd->conf->disable_11ac)
+		return eid;
+
+	*pos++ = WLAN_EID_VHT_OPERATION;
+	*pos++ = sizeof(*oper);
+
+	oper = (struct ieee80211_vht_operation *) pos;
+	os_memset(oper, 0, sizeof(*oper));
+
+	/*
+	 * center freq = 5 GHz + (5 * index)
+	 * So index 42 gives center freq 5.210 GHz
+	 * which is channel 42 in 5G band
+	 */
+	oper->vht_op_info_chan_center_freq_seg0_idx =
+		hapd->iconf->vht_oper_centr_freq_seg0_idx;
+	oper->vht_op_info_chan_center_freq_seg1_idx =
+		hapd->iconf->vht_oper_centr_freq_seg1_idx;
+
+	oper->vht_op_info_chwidth = hapd->iconf->vht_oper_chwidth;
+
+	/* VHT Basic MCS set comes from hw */
+	/* Hard code 1 stream, MCS0-7 is a min Basic VHT MCS rates */
+	oper->vht_basic_mcs_set = host_to_le16(0xfffc);
+	pos += sizeof(*oper);
+
+	return pos;
+}
+
+
+u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
+		       const u8 *vht_capab, size_t vht_capab_len)
+{
+	/* Disable VHT caps for STAs associated to no-VHT BSSes. */
+	if (!vht_capab ||
+	    vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
+	    hapd->conf->disable_11ac) {
+		sta->flags &= ~WLAN_STA_VHT;
+		os_free(sta->vht_capabilities);
+		sta->vht_capabilities = NULL;
+		return WLAN_STATUS_SUCCESS;
+	}
+
+	if (sta->vht_capabilities == NULL) {
+		sta->vht_capabilities =
+			os_zalloc(sizeof(struct ieee80211_vht_capabilities));
+		if (sta->vht_capabilities == NULL)
+			return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	sta->flags |= WLAN_STA_VHT;
+	os_memcpy(sta->vht_capabilities, vht_capab,
+		  sizeof(struct ieee80211_vht_capabilities));
+
+	return WLAN_STATUS_SUCCESS;
+}
diff --git a/hostap/src/ap/ieee802_1x.c b/hostap/src/ap/ieee802_1x.c
new file mode 100644
index 0000000..d9c21a8
--- /dev/null
+++ b/hostap/src/ap/ieee802_1x.c
@@ -0,0 +1,2242 @@
+/*
+ * hostapd / IEEE 802.1X-2004 Authenticator
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/md5.h"
+#include "crypto/crypto.h"
+#include "crypto/random.h"
+#include "common/ieee802_11_defs.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+#include "eap_server/eap.h"
+#include "eap_common/eap_wsc_common.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
+#include "p2p/p2p.h"
+#include "hostapd.h"
+#include "accounting.h"
+#include "sta_info.h"
+#include "wpa_auth.h"
+#include "preauth_auth.h"
+#include "pmksa_cache_auth.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "ieee802_1x.h"
+
+
+static void ieee802_1x_finished(struct hostapd_data *hapd,
+				struct sta_info *sta, int success);
+
+
+static void ieee802_1x_send(struct hostapd_data *hapd, struct sta_info *sta,
+			    u8 type, const u8 *data, size_t datalen)
+{
+	u8 *buf;
+	struct ieee802_1x_hdr *xhdr;
+	size_t len;
+	int encrypt = 0;
+
+	len = sizeof(*xhdr) + datalen;
+	buf = os_zalloc(len);
+	if (buf == NULL) {
+		wpa_printf(MSG_ERROR, "malloc() failed for "
+			   "ieee802_1x_send(len=%lu)",
+			   (unsigned long) len);
+		return;
+	}
+
+	xhdr = (struct ieee802_1x_hdr *) buf;
+	xhdr->version = hapd->conf->eapol_version;
+	xhdr->type = type;
+	xhdr->length = host_to_be16(datalen);
+
+	if (datalen > 0 && data != NULL)
+		os_memcpy(xhdr + 1, data, datalen);
+
+	if (wpa_auth_pairwise_set(sta->wpa_sm))
+		encrypt = 1;
+	if (sta->flags & WLAN_STA_PREAUTH) {
+		rsn_preauth_send(hapd, sta, buf, len);
+	} else {
+		hostapd_drv_hapd_send_eapol(
+			hapd, sta->addr, buf, len,
+			encrypt, hostapd_sta_flags_to_drv(sta->flags));
+	}
+
+	os_free(buf);
+}
+
+
+void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
+				   struct sta_info *sta, int authorized)
+{
+	int res;
+
+	if (sta->flags & WLAN_STA_PREAUTH)
+		return;
+
+	if (authorized) {
+		ap_sta_set_authorized(hapd, sta, 1);
+		res = hostapd_set_authorized(hapd, sta, 1);
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_DEBUG, "authorizing port");
+	} else {
+		ap_sta_set_authorized(hapd, sta, 0);
+		res = hostapd_set_authorized(hapd, sta, 0);
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_DEBUG, "unauthorizing port");
+	}
+
+	if (res && errno != ENOENT) {
+		printf("Could not set station " MACSTR " flags for kernel "
+		       "driver (errno=%d).\n", MAC2STR(sta->addr), errno);
+	}
+
+	if (authorized) {
+		os_get_time(&sta->connected_time);
+		accounting_sta_start(hapd, sta);
+	}
+}
+
+
+static void ieee802_1x_tx_key_one(struct hostapd_data *hapd,
+				  struct sta_info *sta,
+				  int idx, int broadcast,
+				  u8 *key_data, size_t key_len)
+{
+	u8 *buf, *ekey;
+	struct ieee802_1x_hdr *hdr;
+	struct ieee802_1x_eapol_key *key;
+	size_t len, ekey_len;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+
+	if (sm == NULL)
+		return;
+
+	len = sizeof(*key) + key_len;
+	buf = os_zalloc(sizeof(*hdr) + len);
+	if (buf == NULL)
+		return;
+
+	hdr = (struct ieee802_1x_hdr *) buf;
+	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
+	key->type = EAPOL_KEY_TYPE_RC4;
+	WPA_PUT_BE16(key->key_length, key_len);
+	wpa_get_ntp_timestamp(key->replay_counter);
+
+	if (random_get_bytes(key->key_iv, sizeof(key->key_iv))) {
+		wpa_printf(MSG_ERROR, "Could not get random numbers");
+		os_free(buf);
+		return;
+	}
+
+	key->key_index = idx | (broadcast ? 0 : BIT(7));
+	if (hapd->conf->eapol_key_index_workaround) {
+		/* According to some information, WinXP Supplicant seems to
+		 * interpret bit7 as an indication whether the key is to be
+		 * activated, so make it possible to enable workaround that
+		 * sets this bit for all keys. */
+		key->key_index |= BIT(7);
+	}
+
+	/* Key is encrypted using "Key-IV + MSK[0..31]" as the RC4-key and
+	 * MSK[32..63] is used to sign the message. */
+	if (sm->eap_if->eapKeyData == NULL || sm->eap_if->eapKeyDataLen < 64) {
+		wpa_printf(MSG_ERROR, "No eapKeyData available for encrypting "
+			   "and signing EAPOL-Key");
+		os_free(buf);
+		return;
+	}
+	os_memcpy((u8 *) (key + 1), key_data, key_len);
+	ekey_len = sizeof(key->key_iv) + 32;
+	ekey = os_malloc(ekey_len);
+	if (ekey == NULL) {
+		wpa_printf(MSG_ERROR, "Could not encrypt key");
+		os_free(buf);
+		return;
+	}
+	os_memcpy(ekey, key->key_iv, sizeof(key->key_iv));
+	os_memcpy(ekey + sizeof(key->key_iv), sm->eap_if->eapKeyData, 32);
+	rc4_skip(ekey, ekey_len, 0, (u8 *) (key + 1), key_len);
+	os_free(ekey);
+
+	/* This header is needed here for HMAC-MD5, but it will be regenerated
+	 * in ieee802_1x_send() */
+	hdr->version = hapd->conf->eapol_version;
+	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
+	hdr->length = host_to_be16(len);
+	hmac_md5(sm->eap_if->eapKeyData + 32, 32, buf, sizeof(*hdr) + len,
+		 key->key_signature);
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key to " MACSTR
+		   " (%s index=%d)", MAC2STR(sm->addr),
+		   broadcast ? "broadcast" : "unicast", idx);
+	ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len);
+	if (sta->eapol_sm)
+		sta->eapol_sm->dot1xAuthEapolFramesTx++;
+	os_free(buf);
+}
+
+
+#ifndef CONFIG_NO_VLAN
+static struct hostapd_wep_keys *
+ieee802_1x_group_alloc(struct hostapd_data *hapd, const char *ifname)
+{
+	struct hostapd_wep_keys *key;
+
+	key = os_zalloc(sizeof(*key));
+	if (key == NULL)
+		return NULL;
+
+	key->default_len = hapd->conf->default_wep_key_len;
+
+	if (key->idx >= hapd->conf->broadcast_key_idx_max ||
+	    key->idx < hapd->conf->broadcast_key_idx_min)
+		key->idx = hapd->conf->broadcast_key_idx_min;
+	else
+		key->idx++;
+
+	if (!key->key[key->idx])
+		key->key[key->idx] = os_malloc(key->default_len);
+	if (key->key[key->idx] == NULL ||
+	    random_get_bytes(key->key[key->idx], key->default_len)) {
+		printf("Could not generate random WEP key (dynamic VLAN).\n");
+		os_free(key->key[key->idx]);
+		key->key[key->idx] = NULL;
+		os_free(key);
+		return NULL;
+	}
+	key->len[key->idx] = key->default_len;
+
+	wpa_printf(MSG_DEBUG, "%s: Default WEP idx %d for dynamic VLAN\n",
+		   ifname, key->idx);
+	wpa_hexdump_key(MSG_DEBUG, "Default WEP key (dynamic VLAN)",
+			key->key[key->idx], key->len[key->idx]);
+
+	if (hostapd_drv_set_key(ifname, hapd, WPA_ALG_WEP,
+				broadcast_ether_addr, key->idx, 1,
+				NULL, 0, key->key[key->idx],
+				key->len[key->idx]))
+		printf("Could not set dynamic VLAN WEP encryption key.\n");
+
+	hostapd_set_drv_ieee8021x(hapd, ifname, 1);
+
+	return key;
+}
+
+
+static struct hostapd_wep_keys *
+ieee802_1x_get_group(struct hostapd_data *hapd, struct hostapd_ssid *ssid,
+		     size_t vlan_id)
+{
+	const char *ifname;
+
+	if (vlan_id == 0)
+		return &ssid->wep;
+
+	if (vlan_id <= ssid->max_dyn_vlan_keys && ssid->dyn_vlan_keys &&
+	    ssid->dyn_vlan_keys[vlan_id])
+		return ssid->dyn_vlan_keys[vlan_id];
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Creating new group "
+		   "state machine for VLAN ID %lu",
+		   (unsigned long) vlan_id);
+
+	ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
+	if (ifname == NULL) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Unknown VLAN ID %lu - "
+			   "cannot create group key state machine",
+			   (unsigned long) vlan_id);
+		return NULL;
+	}
+
+	if (ssid->dyn_vlan_keys == NULL) {
+		int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]);
+		ssid->dyn_vlan_keys = os_zalloc(size);
+		if (ssid->dyn_vlan_keys == NULL)
+			return NULL;
+		ssid->max_dyn_vlan_keys = vlan_id;
+	}
+
+	if (ssid->max_dyn_vlan_keys < vlan_id) {
+		struct hostapd_wep_keys **na;
+		int size = (vlan_id + 1) * sizeof(ssid->dyn_vlan_keys[0]);
+		na = os_realloc(ssid->dyn_vlan_keys, size);
+		if (na == NULL)
+			return NULL;
+		ssid->dyn_vlan_keys = na;
+		os_memset(&ssid->dyn_vlan_keys[ssid->max_dyn_vlan_keys + 1], 0,
+			  (vlan_id - ssid->max_dyn_vlan_keys) *
+			  sizeof(ssid->dyn_vlan_keys[0]));
+		ssid->max_dyn_vlan_keys = vlan_id;
+	}
+
+	ssid->dyn_vlan_keys[vlan_id] = ieee802_1x_group_alloc(hapd, ifname);
+
+	return ssid->dyn_vlan_keys[vlan_id];
+}
+#endif /* CONFIG_NO_VLAN */
+
+
+void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	struct eapol_authenticator *eapol = hapd->eapol_auth;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+#ifndef CONFIG_NO_VLAN
+	struct hostapd_wep_keys *key = NULL;
+	int vlan_id;
+#endif /* CONFIG_NO_VLAN */
+
+	if (sm == NULL || !sm->eap_if->eapKeyData)
+		return;
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Sending EAPOL-Key(s) to " MACSTR,
+		   MAC2STR(sta->addr));
+
+#ifndef CONFIG_NO_VLAN
+	vlan_id = sta->vlan_id;
+	if (vlan_id < 0 || vlan_id > MAX_VLAN_ID)
+		vlan_id = 0;
+
+	if (vlan_id) {
+		key = ieee802_1x_get_group(hapd, sta->ssid, vlan_id);
+		if (key && key->key[key->idx])
+			ieee802_1x_tx_key_one(hapd, sta, key->idx, 1,
+					      key->key[key->idx],
+					      key->len[key->idx]);
+	} else
+#endif /* CONFIG_NO_VLAN */
+	if (eapol->default_wep_key) {
+		ieee802_1x_tx_key_one(hapd, sta, eapol->default_wep_key_idx, 1,
+				      eapol->default_wep_key,
+				      hapd->conf->default_wep_key_len);
+	}
+
+	if (hapd->conf->individual_wep_key_len > 0) {
+		u8 *ikey;
+		ikey = os_malloc(hapd->conf->individual_wep_key_len);
+		if (ikey == NULL ||
+		    random_get_bytes(ikey, hapd->conf->individual_wep_key_len))
+		{
+			wpa_printf(MSG_ERROR, "Could not generate random "
+				   "individual WEP key.");
+			os_free(ikey);
+			return;
+		}
+
+		wpa_hexdump_key(MSG_DEBUG, "Individual WEP key",
+				ikey, hapd->conf->individual_wep_key_len);
+
+		ieee802_1x_tx_key_one(hapd, sta, 0, 0, ikey,
+				      hapd->conf->individual_wep_key_len);
+
+		/* TODO: set encryption in TX callback, i.e., only after STA
+		 * has ACKed EAPOL-Key frame */
+		if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
+					sta->addr, 0, 1, NULL, 0, ikey,
+					hapd->conf->individual_wep_key_len)) {
+			wpa_printf(MSG_ERROR, "Could not set individual WEP "
+				   "encryption.");
+		}
+
+		os_free(ikey);
+	}
+}
+
+
+const char *radius_mode_txt(struct hostapd_data *hapd)
+{
+	switch (hapd->iface->conf->hw_mode) {
+	case HOSTAPD_MODE_IEEE80211AD:
+		return "802.11ad";
+	case HOSTAPD_MODE_IEEE80211A:
+		return "802.11a";
+	case HOSTAPD_MODE_IEEE80211G:
+		return "802.11g";
+	case HOSTAPD_MODE_IEEE80211B:
+	default:
+		return "802.11b";
+	}
+}
+
+
+int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	int i;
+	u8 rate = 0;
+
+	for (i = 0; i < sta->supported_rates_len; i++)
+		if ((sta->supported_rates[i] & 0x7f) > rate)
+			rate = sta->supported_rates[i] & 0x7f;
+
+	return rate;
+}
+
+
+#ifndef CONFIG_NO_RADIUS
+static void ieee802_1x_learn_identity(struct hostapd_data *hapd,
+				      struct eapol_state_machine *sm,
+				      const u8 *eap, size_t len)
+{
+	const u8 *identity;
+	size_t identity_len;
+
+	if (len <= sizeof(struct eap_hdr) ||
+	    eap[sizeof(struct eap_hdr)] != EAP_TYPE_IDENTITY)
+		return;
+
+	identity = eap_get_identity(sm->eap, &identity_len);
+	if (identity == NULL)
+		return;
+
+	/* Save station identity for future RADIUS packets */
+	os_free(sm->identity);
+	sm->identity = os_malloc(identity_len + 1);
+	if (sm->identity == NULL) {
+		sm->identity_len = 0;
+		return;
+	}
+
+	os_memcpy(sm->identity, identity, identity_len);
+	sm->identity_len = identity_len;
+	sm->identity[identity_len] = '\0';
+	hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
+		       HOSTAPD_LEVEL_DEBUG, "STA identity '%s'", sm->identity);
+	sm->dot1xAuthEapolRespIdFramesRx++;
+}
+
+
+static int add_common_radius_sta_attr(struct hostapd_data *hapd,
+				      struct hostapd_radius_attr *req_attr,
+				      struct sta_info *sta,
+				      struct radius_msg *msg)
+{
+	char buf[128];
+
+	if (!hostapd_config_get_radius_attr(req_attr,
+					    RADIUS_ATTR_NAS_PORT) &&
+	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid)) {
+		wpa_printf(MSG_ERROR, "Could not add NAS-Port");
+		return -1;
+	}
+
+	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT,
+		    MAC2STR(sta->addr));
+	buf[sizeof(buf) - 1] = '\0';
+	if (!radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID,
+				 (u8 *) buf, os_strlen(buf))) {
+		wpa_printf(MSG_ERROR, "Could not add Calling-Station-Id");
+		return -1;
+	}
+
+	if (sta->flags & WLAN_STA_PREAUTH) {
+		os_strlcpy(buf, "IEEE 802.11i Pre-Authentication",
+			   sizeof(buf));
+	} else {
+		os_snprintf(buf, sizeof(buf), "CONNECT %d%sMbps %s",
+			    radius_sta_rate(hapd, sta) / 2,
+			    (radius_sta_rate(hapd, sta) & 1) ? ".5" : "",
+			    radius_mode_txt(hapd));
+		buf[sizeof(buf) - 1] = '\0';
+	}
+	if (!hostapd_config_get_radius_attr(req_attr,
+					    RADIUS_ATTR_CONNECT_INFO) &&
+	    !radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO,
+				 (u8 *) buf, os_strlen(buf))) {
+		wpa_printf(MSG_ERROR, "Could not add Connect-Info");
+		return -1;
+	}
+
+	if (sta->acct_session_id_hi || sta->acct_session_id_lo) {
+		os_snprintf(buf, sizeof(buf), "%08X-%08X",
+			    sta->acct_session_id_hi, sta->acct_session_id_lo);
+		if (!radius_msg_add_attr(msg, RADIUS_ATTR_ACCT_SESSION_ID,
+					 (u8 *) buf, os_strlen(buf))) {
+			wpa_printf(MSG_ERROR, "Could not add Acct-Session-Id");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+int add_common_radius_attr(struct hostapd_data *hapd,
+			   struct hostapd_radius_attr *req_attr,
+			   struct sta_info *sta,
+			   struct radius_msg *msg)
+{
+	char buf[128];
+	struct hostapd_radius_attr *attr;
+
+	if (!hostapd_config_get_radius_attr(req_attr,
+					    RADIUS_ATTR_NAS_IP_ADDRESS) &&
+	    hapd->conf->own_ip_addr.af == AF_INET &&
+	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS,
+				 (u8 *) &hapd->conf->own_ip_addr.u.v4, 4)) {
+		wpa_printf(MSG_ERROR, "Could not add NAS-IP-Address");
+		return -1;
+	}
+
+#ifdef CONFIG_IPV6
+	if (!hostapd_config_get_radius_attr(req_attr,
+					    RADIUS_ATTR_NAS_IPV6_ADDRESS) &&
+	    hapd->conf->own_ip_addr.af == AF_INET6 &&
+	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IPV6_ADDRESS,
+				 (u8 *) &hapd->conf->own_ip_addr.u.v6, 16)) {
+		wpa_printf(MSG_ERROR, "Could not add NAS-IPv6-Address");
+		return -1;
+	}
+#endif /* CONFIG_IPV6 */
+
+	if (!hostapd_config_get_radius_attr(req_attr,
+					    RADIUS_ATTR_NAS_IDENTIFIER) &&
+	    hapd->conf->nas_identifier &&
+	    !radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IDENTIFIER,
+				 (u8 *) hapd->conf->nas_identifier,
+				 os_strlen(hapd->conf->nas_identifier))) {
+		wpa_printf(MSG_ERROR, "Could not add NAS-Identifier");
+		return -1;
+	}
+
+	os_snprintf(buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT ":%s",
+		    MAC2STR(hapd->own_addr),
+		    wpa_ssid_txt(hapd->conf->ssid.ssid,
+				 hapd->conf->ssid.ssid_len));
+	buf[sizeof(buf) - 1] = '\0';
+	if (!hostapd_config_get_radius_attr(req_attr,
+					    RADIUS_ATTR_CALLED_STATION_ID) &&
+	    !radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID,
+				 (u8 *) buf, os_strlen(buf))) {
+		wpa_printf(MSG_ERROR, "Could not add Called-Station-Id");
+		return -1;
+	}
+
+	if (!hostapd_config_get_radius_attr(req_attr,
+					    RADIUS_ATTR_NAS_PORT_TYPE) &&
+	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE,
+				       RADIUS_NAS_PORT_TYPE_IEEE_802_11)) {
+		wpa_printf(MSG_ERROR, "Could not add NAS-Port-Type");
+		return -1;
+	}
+
+	if (sta && add_common_radius_sta_attr(hapd, req_attr, sta, msg) < 0)
+		return -1;
+
+	for (attr = req_attr; attr; attr = attr->next) {
+		if (!radius_msg_add_attr(msg, attr->type,
+					 wpabuf_head(attr->val),
+					 wpabuf_len(attr->val))) {
+			wpa_printf(MSG_ERROR, "Could not add RADIUS "
+				   "attribute");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static void ieee802_1x_encapsulate_radius(struct hostapd_data *hapd,
+					  struct sta_info *sta,
+					  const u8 *eap, size_t len)
+{
+	struct radius_msg *msg;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+
+	if (sm == NULL)
+		return;
+
+	ieee802_1x_learn_identity(hapd, sm, eap, len);
+
+	wpa_printf(MSG_DEBUG, "Encapsulating EAP message into a RADIUS "
+		   "packet");
+
+	sm->radius_identifier = radius_client_get_id(hapd->radius);
+	msg = radius_msg_new(RADIUS_CODE_ACCESS_REQUEST,
+			     sm->radius_identifier);
+	if (msg == NULL) {
+		printf("Could not create net RADIUS packet\n");
+		return;
+	}
+
+	radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(*sta));
+
+	if (sm->identity &&
+	    !radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME,
+				 sm->identity, sm->identity_len)) {
+		printf("Could not add User-Name\n");
+		goto fail;
+	}
+
+	if (add_common_radius_attr(hapd, hapd->conf->radius_auth_req_attr, sta,
+				   msg) < 0)
+		goto fail;
+
+	/* TODO: should probably check MTU from driver config; 2304 is max for
+	 * IEEE 802.11, but use 1400 to avoid problems with too large packets
+	 */
+	if (!hostapd_config_get_radius_attr(hapd->conf->radius_auth_req_attr,
+					    RADIUS_ATTR_FRAMED_MTU) &&
+	    !radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400)) {
+		printf("Could not add Framed-MTU\n");
+		goto fail;
+	}
+
+	if (eap && !radius_msg_add_eap(msg, eap, len)) {
+		printf("Could not add EAP-Message\n");
+		goto fail;
+	}
+
+	/* State attribute must be copied if and only if this packet is
+	 * Access-Request reply to the previous Access-Challenge */
+	if (sm->last_recv_radius &&
+	    radius_msg_get_hdr(sm->last_recv_radius)->code ==
+	    RADIUS_CODE_ACCESS_CHALLENGE) {
+		int res = radius_msg_copy_attr(msg, sm->last_recv_radius,
+					       RADIUS_ATTR_STATE);
+		if (res < 0) {
+			printf("Could not copy State attribute from previous "
+			       "Access-Challenge\n");
+			goto fail;
+		}
+		if (res > 0) {
+			wpa_printf(MSG_DEBUG, "Copied RADIUS State Attribute");
+		}
+	}
+
+	if (hapd->conf->radius_request_cui) {
+		const u8 *cui;
+		size_t cui_len;
+		/* Add previously learned CUI or nul CUI to request CUI */
+		if (sm->radius_cui) {
+			cui = wpabuf_head(sm->radius_cui);
+			cui_len = wpabuf_len(sm->radius_cui);
+		} else {
+			cui = (const u8 *) "\0";
+			cui_len = 1;
+		}
+		if (!radius_msg_add_attr(msg,
+					 RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+					 cui, cui_len)) {
+			wpa_printf(MSG_ERROR, "Could not add CUI");
+			goto fail;
+		}
+	}
+
+	if (radius_client_send(hapd->radius, msg, RADIUS_AUTH, sta->addr) < 0)
+		goto fail;
+
+	return;
+
+ fail:
+	radius_msg_free(msg);
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
+static void handle_eap_response(struct hostapd_data *hapd,
+				struct sta_info *sta, struct eap_hdr *eap,
+				size_t len)
+{
+	u8 type, *data;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+	if (sm == NULL)
+		return;
+
+	data = (u8 *) (eap + 1);
+
+	if (len < sizeof(*eap) + 1) {
+		printf("handle_eap_response: too short response data\n");
+		return;
+	}
+
+	sm->eap_type_supp = type = data[0];
+
+	hostapd_logger(hapd, sm->addr, HOSTAPD_MODULE_IEEE8021X,
+		       HOSTAPD_LEVEL_DEBUG, "received EAP packet (code=%d "
+		       "id=%d len=%d) from STA: EAP Response-%s (%d)",
+		       eap->code, eap->identifier, be_to_host16(eap->length),
+		       eap_server_get_name(0, type), type);
+
+	sm->dot1xAuthEapolRespFramesRx++;
+
+	wpabuf_free(sm->eap_if->eapRespData);
+	sm->eap_if->eapRespData = wpabuf_alloc_copy(eap, len);
+	sm->eapolEap = TRUE;
+}
+
+
+/* Process incoming EAP packet from Supplicant */
+static void handle_eap(struct hostapd_data *hapd, struct sta_info *sta,
+		       u8 *buf, size_t len)
+{
+	struct eap_hdr *eap;
+	u16 eap_len;
+
+	if (len < sizeof(*eap)) {
+		printf("   too short EAP packet\n");
+		return;
+	}
+
+	eap = (struct eap_hdr *) buf;
+
+	eap_len = be_to_host16(eap->length);
+	wpa_printf(MSG_DEBUG, "EAP: code=%d identifier=%d length=%d",
+		   eap->code, eap->identifier, eap_len);
+	if (eap_len < sizeof(*eap)) {
+		wpa_printf(MSG_DEBUG, "   Invalid EAP length");
+		return;
+	} else if (eap_len > len) {
+		wpa_printf(MSG_DEBUG, "   Too short frame to contain this EAP "
+			   "packet");
+		return;
+	} else if (eap_len < len) {
+		wpa_printf(MSG_DEBUG, "   Ignoring %lu extra bytes after EAP "
+			   "packet", (unsigned long) len - eap_len);
+	}
+
+	switch (eap->code) {
+	case EAP_CODE_REQUEST:
+		wpa_printf(MSG_DEBUG, " (request)");
+		return;
+	case EAP_CODE_RESPONSE:
+		wpa_printf(MSG_DEBUG, " (response)");
+		handle_eap_response(hapd, sta, eap, eap_len);
+		break;
+	case EAP_CODE_SUCCESS:
+		wpa_printf(MSG_DEBUG, " (success)");
+		return;
+	case EAP_CODE_FAILURE:
+		wpa_printf(MSG_DEBUG, " (failure)");
+		return;
+	default:
+		wpa_printf(MSG_DEBUG, " (unknown code)");
+		return;
+	}
+}
+
+
+static struct eapol_state_machine *
+ieee802_1x_alloc_eapol_sm(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	int flags = 0;
+	if (sta->flags & WLAN_STA_PREAUTH)
+		flags |= EAPOL_SM_PREAUTH;
+	if (sta->wpa_sm) {
+		flags |= EAPOL_SM_USES_WPA;
+		if (wpa_auth_sta_get_pmksa(sta->wpa_sm))
+			flags |= EAPOL_SM_FROM_PMKSA_CACHE;
+	}
+	return eapol_auth_alloc(hapd->eapol_auth, sta->addr, flags,
+				sta->wps_ie, sta->p2p_ie, sta,
+				sta->identity, sta->radius_cui);
+}
+
+
+/**
+ * ieee802_1x_receive - Process the EAPOL frames from the Supplicant
+ * @hapd: hostapd BSS data
+ * @sa: Source address (sender of the EAPOL frame)
+ * @buf: EAPOL frame
+ * @len: Length of buf in octets
+ *
+ * This function is called for each incoming EAPOL frame from the interface
+ */
+void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
+			size_t len)
+{
+	struct sta_info *sta;
+	struct ieee802_1x_hdr *hdr;
+	struct ieee802_1x_eapol_key *key;
+	u16 datalen;
+	struct rsn_pmksa_cache_entry *pmksa;
+	int key_mgmt;
+
+	if (!hapd->conf->ieee802_1x && !hapd->conf->wpa &&
+	    !hapd->conf->wps_state)
+		return;
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.1X: %lu bytes from " MACSTR,
+		   (unsigned long) len, MAC2STR(sa));
+	sta = ap_get_sta(hapd, sa);
+	if (!sta || (!(sta->flags & (WLAN_STA_ASSOC | WLAN_STA_PREAUTH)) &&
+		     !(hapd->iface->drv_flags & WPA_DRIVER_FLAGS_WIRED))) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.1X data frame from not "
+			   "associated/Pre-authenticating STA");
+		return;
+	}
+
+	if (len < sizeof(*hdr)) {
+		printf("   too short IEEE 802.1X packet\n");
+		return;
+	}
+
+	hdr = (struct ieee802_1x_hdr *) buf;
+	datalen = be_to_host16(hdr->length);
+	wpa_printf(MSG_DEBUG, "   IEEE 802.1X: version=%d type=%d length=%d",
+		   hdr->version, hdr->type, datalen);
+
+	if (len - sizeof(*hdr) < datalen) {
+		printf("   frame too short for this IEEE 802.1X packet\n");
+		if (sta->eapol_sm)
+			sta->eapol_sm->dot1xAuthEapLengthErrorFramesRx++;
+		return;
+	}
+	if (len - sizeof(*hdr) > datalen) {
+		wpa_printf(MSG_DEBUG, "   ignoring %lu extra octets after "
+			   "IEEE 802.1X packet",
+			   (unsigned long) len - sizeof(*hdr) - datalen);
+	}
+
+	if (sta->eapol_sm) {
+		sta->eapol_sm->dot1xAuthLastEapolFrameVersion = hdr->version;
+		sta->eapol_sm->dot1xAuthEapolFramesRx++;
+	}
+
+	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
+	if (datalen >= sizeof(struct ieee802_1x_eapol_key) &&
+	    hdr->type == IEEE802_1X_TYPE_EAPOL_KEY &&
+	    (key->type == EAPOL_KEY_TYPE_WPA ||
+	     key->type == EAPOL_KEY_TYPE_RSN)) {
+		wpa_receive(hapd->wpa_auth, sta->wpa_sm, (u8 *) hdr,
+			    sizeof(*hdr) + datalen);
+		return;
+	}
+
+	if (!hapd->conf->ieee802_1x &&
+	    !(sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
+			   "802.1X not enabled and WPS not used");
+		return;
+	}
+
+	key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
+	if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore EAPOL message - "
+			   "STA is using PSK");
+		return;
+	}
+
+	if (!sta->eapol_sm) {
+		sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
+		if (!sta->eapol_sm)
+			return;
+
+#ifdef CONFIG_WPS
+		if (!hapd->conf->ieee802_1x) {
+			u32 wflags = sta->flags & (WLAN_STA_WPS |
+						   WLAN_STA_WPS2 |
+						   WLAN_STA_MAYBE_WPS);
+			if (wflags == WLAN_STA_MAYBE_WPS ||
+			    wflags == (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) {
+				/*
+				 * Delay EAPOL frame transmission until a
+				 * possible WPS STA initiates the handshake
+				 * with EAPOL-Start. Only allow the wait to be
+				 * skipped if the STA is known to support WPS
+				 * 2.0.
+				 */
+				wpa_printf(MSG_DEBUG, "WPS: Do not start "
+					   "EAPOL until EAPOL-Start is "
+					   "received");
+				sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
+			}
+		}
+#endif /* CONFIG_WPS */
+
+		sta->eapol_sm->eap_if->portEnabled = TRUE;
+	}
+
+	/* since we support version 1, we can ignore version field and proceed
+	 * as specified in version 1 standard [IEEE Std 802.1X-2001, 7.5.5] */
+	/* TODO: actually, we are not version 1 anymore.. However, Version 2
+	 * does not change frame contents, so should be ok to process frames
+	 * more or less identically. Some changes might be needed for
+	 * verification of fields. */
+
+	switch (hdr->type) {
+	case IEEE802_1X_TYPE_EAP_PACKET:
+		handle_eap(hapd, sta, (u8 *) (hdr + 1), datalen);
+		break;
+
+	case IEEE802_1X_TYPE_EAPOL_START:
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_DEBUG, "received EAPOL-Start "
+			       "from STA");
+		sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
+		pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
+		if (pmksa) {
+			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+				       HOSTAPD_LEVEL_DEBUG, "cached PMKSA "
+				       "available - ignore it since "
+				       "STA sent EAPOL-Start");
+			wpa_auth_sta_clear_pmksa(sta->wpa_sm, pmksa);
+		}
+		sta->eapol_sm->eapolStart = TRUE;
+		sta->eapol_sm->dot1xAuthEapolStartFramesRx++;
+		eap_server_clear_identity(sta->eapol_sm->eap);
+		wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
+		break;
+
+	case IEEE802_1X_TYPE_EAPOL_LOGOFF:
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_DEBUG, "received EAPOL-Logoff "
+			       "from STA");
+		sta->acct_terminate_cause =
+			RADIUS_ACCT_TERMINATE_CAUSE_USER_REQUEST;
+		accounting_sta_stop(hapd, sta);
+		sta->eapol_sm->eapolLogoff = TRUE;
+		sta->eapol_sm->dot1xAuthEapolLogoffFramesRx++;
+		eap_server_clear_identity(sta->eapol_sm->eap);
+		break;
+
+	case IEEE802_1X_TYPE_EAPOL_KEY:
+		wpa_printf(MSG_DEBUG, "   EAPOL-Key");
+		if (!ap_sta_is_authorized(sta)) {
+			wpa_printf(MSG_DEBUG, "   Dropped key data from "
+				   "unauthorized Supplicant");
+			break;
+		}
+		break;
+
+	case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT:
+		wpa_printf(MSG_DEBUG, "   EAPOL-Encapsulated-ASF-Alert");
+		/* TODO: implement support for this; show data */
+		break;
+
+	default:
+		wpa_printf(MSG_DEBUG, "   unknown IEEE 802.1X packet type");
+		sta->eapol_sm->dot1xAuthInvalidEapolFramesRx++;
+		break;
+	}
+
+	eapol_auth_step(sta->eapol_sm);
+}
+
+
+/**
+ * ieee802_1x_new_station - Start IEEE 802.1X authentication
+ * @hapd: hostapd BSS data
+ * @sta: The station
+ *
+ * This function is called to start IEEE 802.1X authentication when a new
+ * station completes IEEE 802.11 association.
+ */
+void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	struct rsn_pmksa_cache_entry *pmksa;
+	int reassoc = 1;
+	int force_1x = 0;
+	int key_mgmt;
+
+#ifdef CONFIG_WPS
+	if (hapd->conf->wps_state && hapd->conf->wpa &&
+	    (sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS))) {
+		/*
+		 * Need to enable IEEE 802.1X/EAPOL state machines for possible
+		 * WPS handshake even if IEEE 802.1X/EAPOL is not used for
+		 * authentication in this BSS.
+		 */
+		force_1x = 1;
+	}
+#endif /* CONFIG_WPS */
+
+	if (!force_1x && !hapd->conf->ieee802_1x) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - "
+			   "802.1X not enabled or forced for WPS");
+		/*
+		 * Clear any possible EAPOL authenticator state to support
+		 * reassociation change from WPS to PSK.
+		 */
+		ieee802_1x_free_station(sta);
+		return;
+	}
+
+	key_mgmt = wpa_auth_sta_key_mgmt(sta->wpa_sm);
+	if (key_mgmt != -1 && wpa_key_mgmt_wpa_psk(key_mgmt)) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Ignore STA - using PSK");
+		/*
+		 * Clear any possible EAPOL authenticator state to support
+		 * reassociation change from WPA-EAP to PSK.
+		 */
+		ieee802_1x_free_station(sta);
+		return;
+	}
+
+	if (sta->eapol_sm == NULL) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_DEBUG, "start authentication");
+		sta->eapol_sm = ieee802_1x_alloc_eapol_sm(hapd, sta);
+		if (sta->eapol_sm == NULL) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE8021X,
+				       HOSTAPD_LEVEL_INFO,
+				       "failed to allocate state machine");
+			return;
+		}
+		reassoc = 0;
+	}
+
+#ifdef CONFIG_WPS
+	sta->eapol_sm->flags &= ~EAPOL_SM_WAIT_START;
+	if (!hapd->conf->ieee802_1x && !(sta->flags & WLAN_STA_WPS2)) {
+		/*
+		 * Delay EAPOL frame transmission until a possible WPS STA
+		 * initiates the handshake with EAPOL-Start. Only allow the
+		 * wait to be skipped if the STA is known to support WPS 2.0.
+		 */
+		wpa_printf(MSG_DEBUG, "WPS: Do not start EAPOL until "
+			   "EAPOL-Start is received");
+		sta->eapol_sm->flags |= EAPOL_SM_WAIT_START;
+	}
+#endif /* CONFIG_WPS */
+
+	sta->eapol_sm->eap_if->portEnabled = TRUE;
+
+#ifdef CONFIG_IEEE80211R
+	if (sta->auth_alg == WLAN_AUTH_FT) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "PMK from FT - skip IEEE 802.1X/EAP");
+		/* Setup EAPOL state machines to already authenticated state
+		 * because of existing FT information from R0KH. */
+		sta->eapol_sm->keyRun = TRUE;
+		sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+		sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
+		sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
+		sta->eapol_sm->authSuccess = TRUE;
+		sta->eapol_sm->authFail = FALSE;
+		if (sta->eapol_sm->eap)
+			eap_sm_notify_cached(sta->eapol_sm->eap);
+		/* TODO: get vlan_id from R0KH using RRB message */
+		return;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	pmksa = wpa_auth_sta_get_pmksa(sta->wpa_sm);
+	if (pmksa) {
+		int old_vlanid;
+
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "PMK from PMKSA cache - skip IEEE 802.1X/EAP");
+		/* Setup EAPOL state machines to already authenticated state
+		 * because of existing PMKSA information in the cache. */
+		sta->eapol_sm->keyRun = TRUE;
+		sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+		sta->eapol_sm->auth_pae_state = AUTH_PAE_AUTHENTICATING;
+		sta->eapol_sm->be_auth_state = BE_AUTH_SUCCESS;
+		sta->eapol_sm->authSuccess = TRUE;
+		sta->eapol_sm->authFail = FALSE;
+		if (sta->eapol_sm->eap)
+			eap_sm_notify_cached(sta->eapol_sm->eap);
+		old_vlanid = sta->vlan_id;
+		pmksa_cache_to_eapol_data(pmksa, sta->eapol_sm);
+		if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+			sta->vlan_id = 0;
+		ap_sta_bind_vlan(hapd, sta, old_vlanid);
+	} else {
+		if (reassoc) {
+			/*
+			 * Force EAPOL state machines to start
+			 * re-authentication without having to wait for the
+			 * Supplicant to send EAPOL-Start.
+			 */
+			sta->eapol_sm->reAuthenticate = TRUE;
+		}
+		eapol_auth_step(sta->eapol_sm);
+	}
+}
+
+
+void ieee802_1x_free_station(struct sta_info *sta)
+{
+	struct eapol_state_machine *sm = sta->eapol_sm;
+
+	if (sm == NULL)
+		return;
+
+	sta->eapol_sm = NULL;
+
+#ifndef CONFIG_NO_RADIUS
+	radius_msg_free(sm->last_recv_radius);
+	radius_free_class(&sm->radius_class);
+	wpabuf_free(sm->radius_cui);
+#endif /* CONFIG_NO_RADIUS */
+
+	os_free(sm->identity);
+	eapol_auth_free(sm);
+}
+
+
+#ifndef CONFIG_NO_RADIUS
+static void ieee802_1x_decapsulate_radius(struct hostapd_data *hapd,
+					  struct sta_info *sta)
+{
+	struct wpabuf *eap;
+	const struct eap_hdr *hdr;
+	int eap_type = -1;
+	char buf[64];
+	struct radius_msg *msg;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+
+	if (sm == NULL || sm->last_recv_radius == NULL) {
+		if (sm)
+			sm->eap_if->aaaEapNoReq = TRUE;
+		return;
+	}
+
+	msg = sm->last_recv_radius;
+
+	eap = radius_msg_get_eap(msg);
+	if (eap == NULL) {
+		/* RFC 3579, Chap. 2.6.3:
+		 * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
+		 * attribute */
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_WARNING, "could not extract "
+			       "EAP-Message from RADIUS message");
+		sm->eap_if->aaaEapNoReq = TRUE;
+		return;
+	}
+
+	if (wpabuf_len(eap) < sizeof(*hdr)) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_WARNING, "too short EAP packet "
+			       "received from authentication server");
+		wpabuf_free(eap);
+		sm->eap_if->aaaEapNoReq = TRUE;
+		return;
+	}
+
+	if (wpabuf_len(eap) > sizeof(*hdr))
+		eap_type = (wpabuf_head_u8(eap))[sizeof(*hdr)];
+
+	hdr = wpabuf_head(eap);
+	switch (hdr->code) {
+	case EAP_CODE_REQUEST:
+		if (eap_type >= 0)
+			sm->eap_type_authsrv = eap_type;
+		os_snprintf(buf, sizeof(buf), "EAP-Request-%s (%d)",
+			    eap_type >= 0 ? eap_server_get_name(0, eap_type) :
+			    "??",
+			    eap_type);
+		break;
+	case EAP_CODE_RESPONSE:
+		os_snprintf(buf, sizeof(buf), "EAP Response-%s (%d)",
+			    eap_type >= 0 ? eap_server_get_name(0, eap_type) :
+			    "??",
+			    eap_type);
+		break;
+	case EAP_CODE_SUCCESS:
+		os_strlcpy(buf, "EAP Success", sizeof(buf));
+		break;
+	case EAP_CODE_FAILURE:
+		os_strlcpy(buf, "EAP Failure", sizeof(buf));
+		break;
+	default:
+		os_strlcpy(buf, "unknown EAP code", sizeof(buf));
+		break;
+	}
+	buf[sizeof(buf) - 1] = '\0';
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+		       HOSTAPD_LEVEL_DEBUG, "decapsulated EAP packet (code=%d "
+		       "id=%d len=%d) from RADIUS server: %s",
+		       hdr->code, hdr->identifier, be_to_host16(hdr->length),
+		       buf);
+	sm->eap_if->aaaEapReq = TRUE;
+
+	wpabuf_free(sm->eap_if->aaaEapReqData);
+	sm->eap_if->aaaEapReqData = eap;
+}
+
+
+static void ieee802_1x_get_keys(struct hostapd_data *hapd,
+				struct sta_info *sta, struct radius_msg *msg,
+				struct radius_msg *req,
+				const u8 *shared_secret,
+				size_t shared_secret_len)
+{
+	struct radius_ms_mppe_keys *keys;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+	if (sm == NULL)
+		return;
+
+	keys = radius_msg_get_ms_keys(msg, req, shared_secret,
+				      shared_secret_len);
+
+	if (keys && keys->send && keys->recv) {
+		size_t len = keys->send_len + keys->recv_len;
+		wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Send-Key",
+				keys->send, keys->send_len);
+		wpa_hexdump_key(MSG_DEBUG, "MS-MPPE-Recv-Key",
+				keys->recv, keys->recv_len);
+
+		os_free(sm->eap_if->aaaEapKeyData);
+		sm->eap_if->aaaEapKeyData = os_malloc(len);
+		if (sm->eap_if->aaaEapKeyData) {
+			os_memcpy(sm->eap_if->aaaEapKeyData, keys->recv,
+				  keys->recv_len);
+			os_memcpy(sm->eap_if->aaaEapKeyData + keys->recv_len,
+				  keys->send, keys->send_len);
+			sm->eap_if->aaaEapKeyDataLen = len;
+			sm->eap_if->aaaEapKeyAvailable = TRUE;
+		}
+	}
+
+	if (keys) {
+		os_free(keys->send);
+		os_free(keys->recv);
+		os_free(keys);
+	}
+}
+
+
+static void ieee802_1x_store_radius_class(struct hostapd_data *hapd,
+					  struct sta_info *sta,
+					  struct radius_msg *msg)
+{
+	u8 *class;
+	size_t class_len;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+	int count, i;
+	struct radius_attr_data *nclass;
+	size_t nclass_count;
+
+	if (!hapd->conf->radius->acct_server || hapd->radius == NULL ||
+	    sm == NULL)
+		return;
+
+	radius_free_class(&sm->radius_class);
+	count = radius_msg_count_attr(msg, RADIUS_ATTR_CLASS, 1);
+	if (count <= 0)
+		return;
+
+	nclass = os_calloc(count, sizeof(struct radius_attr_data));
+	if (nclass == NULL)
+		return;
+
+	nclass_count = 0;
+
+	class = NULL;
+	for (i = 0; i < count; i++) {
+		do {
+			if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CLASS,
+						    &class, &class_len,
+						    class) < 0) {
+				i = count;
+				break;
+			}
+		} while (class_len < 1);
+
+		nclass[nclass_count].data = os_malloc(class_len);
+		if (nclass[nclass_count].data == NULL)
+			break;
+
+		os_memcpy(nclass[nclass_count].data, class, class_len);
+		nclass[nclass_count].len = class_len;
+		nclass_count++;
+	}
+
+	sm->radius_class.attr = nclass;
+	sm->radius_class.count = nclass_count;
+	wpa_printf(MSG_DEBUG, "IEEE 802.1X: Stored %lu RADIUS Class "
+		   "attributes for " MACSTR,
+		   (unsigned long) sm->radius_class.count,
+		   MAC2STR(sta->addr));
+}
+
+
+/* Update sta->identity based on User-Name attribute in Access-Accept */
+static void ieee802_1x_update_sta_identity(struct hostapd_data *hapd,
+					   struct sta_info *sta,
+					   struct radius_msg *msg)
+{
+	u8 *buf, *identity;
+	size_t len;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+
+	if (sm == NULL)
+		return;
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_USER_NAME, &buf, &len,
+				    NULL) < 0)
+		return;
+
+	identity = os_malloc(len + 1);
+	if (identity == NULL)
+		return;
+
+	os_memcpy(identity, buf, len);
+	identity[len] = '\0';
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+		       HOSTAPD_LEVEL_DEBUG, "old identity '%s' updated with "
+		       "User-Name from Access-Accept '%s'",
+		       sm->identity ? (char *) sm->identity : "N/A",
+		       (char *) identity);
+
+	os_free(sm->identity);
+	sm->identity = identity;
+	sm->identity_len = len;
+}
+
+
+/* Update CUI based on Chargeable-User-Identity attribute in Access-Accept */
+static void ieee802_1x_update_sta_cui(struct hostapd_data *hapd,
+				      struct sta_info *sta,
+				      struct radius_msg *msg)
+{
+	struct eapol_state_machine *sm = sta->eapol_sm;
+	struct wpabuf *cui;
+	u8 *buf;
+	size_t len;
+
+	if (sm == NULL)
+		return;
+
+	if (radius_msg_get_attr_ptr(msg, RADIUS_ATTR_CHARGEABLE_USER_IDENTITY,
+				    &buf, &len, NULL) < 0)
+		return;
+
+	cui = wpabuf_alloc_copy(buf, len);
+	if (cui == NULL)
+		return;
+
+	wpabuf_free(sm->radius_cui);
+	sm->radius_cui = cui;
+}
+
+
+struct sta_id_search {
+	u8 identifier;
+	struct eapol_state_machine *sm;
+};
+
+
+static int ieee802_1x_select_radius_identifier(struct hostapd_data *hapd,
+					       struct sta_info *sta,
+					       void *ctx)
+{
+	struct sta_id_search *id_search = ctx;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+
+	if (sm && sm->radius_identifier >= 0 &&
+	    sm->radius_identifier == id_search->identifier) {
+		id_search->sm = sm;
+		return 1;
+	}
+	return 0;
+}
+
+
+static struct eapol_state_machine *
+ieee802_1x_search_radius_identifier(struct hostapd_data *hapd, u8 identifier)
+{
+	struct sta_id_search id_search;
+	id_search.identifier = identifier;
+	id_search.sm = NULL;
+	ap_for_each_sta(hapd, ieee802_1x_select_radius_identifier, &id_search);
+	return id_search.sm;
+}
+
+
+/**
+ * ieee802_1x_receive_auth - Process RADIUS frames from Authentication Server
+ * @msg: RADIUS response message
+ * @req: RADIUS request message
+ * @shared_secret: RADIUS shared secret
+ * @shared_secret_len: Length of shared_secret in octets
+ * @data: Context data (struct hostapd_data *)
+ * Returns: Processing status
+ */
+static RadiusRxResult
+ieee802_1x_receive_auth(struct radius_msg *msg, struct radius_msg *req,
+			const u8 *shared_secret, size_t shared_secret_len,
+			void *data)
+{
+	struct hostapd_data *hapd = data;
+	struct sta_info *sta;
+	u32 session_timeout = 0, termination_action, acct_interim_interval;
+	int session_timeout_set, old_vlanid = 0;
+	struct eapol_state_machine *sm;
+	int override_eapReq = 0;
+	struct radius_hdr *hdr = radius_msg_get_hdr(msg);
+
+	sm = ieee802_1x_search_radius_identifier(hapd, hdr->identifier);
+	if (sm == NULL) {
+		wpa_printf(MSG_DEBUG, "IEEE 802.1X: Could not find matching "
+			   "station for this RADIUS message");
+		return RADIUS_RX_UNKNOWN;
+	}
+	sta = sm->sta;
+
+	/* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
+	 * present when packet contains an EAP-Message attribute */
+	if (hdr->code == RADIUS_CODE_ACCESS_REJECT &&
+	    radius_msg_get_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL,
+				0) < 0 &&
+	    radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0) {
+		wpa_printf(MSG_DEBUG, "Allowing RADIUS Access-Reject without "
+			   "Message-Authenticator since it does not include "
+			   "EAP-Message");
+	} else if (radius_msg_verify(msg, shared_secret, shared_secret_len,
+				     req, 1)) {
+		printf("Incoming RADIUS packet did not have correct "
+		       "Message-Authenticator - dropped\n");
+		return RADIUS_RX_INVALID_AUTHENTICATOR;
+	}
+
+	if (hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
+	    hdr->code != RADIUS_CODE_ACCESS_REJECT &&
+	    hdr->code != RADIUS_CODE_ACCESS_CHALLENGE) {
+		printf("Unknown RADIUS message code\n");
+		return RADIUS_RX_UNKNOWN;
+	}
+
+	sm->radius_identifier = -1;
+	wpa_printf(MSG_DEBUG, "RADIUS packet matching with station " MACSTR,
+		   MAC2STR(sta->addr));
+
+	radius_msg_free(sm->last_recv_radius);
+	sm->last_recv_radius = msg;
+
+	session_timeout_set =
+		!radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT,
+					   &session_timeout);
+	if (radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION,
+				      &termination_action))
+		termination_action = RADIUS_TERMINATION_ACTION_DEFAULT;
+
+	if (hapd->conf->acct_interim_interval == 0 &&
+	    hdr->code == RADIUS_CODE_ACCESS_ACCEPT &&
+	    radius_msg_get_attr_int32(msg, RADIUS_ATTR_ACCT_INTERIM_INTERVAL,
+				      &acct_interim_interval) == 0) {
+		if (acct_interim_interval < 60) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE8021X,
+				       HOSTAPD_LEVEL_INFO,
+				       "ignored too small "
+				       "Acct-Interim-Interval %d",
+				       acct_interim_interval);
+		} else
+			sta->acct_interim_interval = acct_interim_interval;
+	}
+
+
+	switch (hdr->code) {
+	case RADIUS_CODE_ACCESS_ACCEPT:
+		if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+			sta->vlan_id = 0;
+#ifndef CONFIG_NO_VLAN
+		else {
+			old_vlanid = sta->vlan_id;
+			sta->vlan_id = radius_msg_get_vlanid(msg);
+		}
+		if (sta->vlan_id > 0 &&
+		    hostapd_get_vlan_id_ifname(hapd->conf->vlan,
+					       sta->vlan_id)) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_RADIUS,
+				       HOSTAPD_LEVEL_INFO,
+				       "VLAN ID %d", sta->vlan_id);
+		} else if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_REQUIRED) {
+			sta->eapol_sm->authFail = TRUE;
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE8021X,
+				       HOSTAPD_LEVEL_INFO, "authentication "
+				       "server did not include required VLAN "
+				       "ID in Access-Accept");
+			break;
+		}
+#endif /* CONFIG_NO_VLAN */
+
+		if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0)
+			break;
+
+		/* RFC 3580, Ch. 3.17 */
+		if (session_timeout_set && termination_action ==
+		    RADIUS_TERMINATION_ACTION_RADIUS_REQUEST) {
+			sm->reAuthPeriod = session_timeout;
+		} else if (session_timeout_set)
+			ap_sta_session_timeout(hapd, sta, session_timeout);
+
+		sm->eap_if->aaaSuccess = TRUE;
+		override_eapReq = 1;
+		ieee802_1x_get_keys(hapd, sta, msg, req, shared_secret,
+				    shared_secret_len);
+		ieee802_1x_store_radius_class(hapd, sta, msg);
+		ieee802_1x_update_sta_identity(hapd, sta, msg);
+		ieee802_1x_update_sta_cui(hapd, sta, msg);
+		if (sm->eap_if->eapKeyAvailable &&
+		    wpa_auth_pmksa_add(sta->wpa_sm, sm->eapol_key_crypt,
+				       session_timeout_set ?
+				       (int) session_timeout : -1, sm) == 0) {
+			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "Added PMKSA cache entry");
+		}
+		break;
+	case RADIUS_CODE_ACCESS_REJECT:
+		sm->eap_if->aaaFail = TRUE;
+		override_eapReq = 1;
+		break;
+	case RADIUS_CODE_ACCESS_CHALLENGE:
+		sm->eap_if->aaaEapReq = TRUE;
+		if (session_timeout_set) {
+			/* RFC 2869, Ch. 2.3.2; RFC 3580, Ch. 3.17 */
+			sm->eap_if->aaaMethodTimeout = session_timeout;
+			hostapd_logger(hapd, sm->addr,
+				       HOSTAPD_MODULE_IEEE8021X,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "using EAP timeout of %d seconds (from "
+				       "RADIUS)",
+				       sm->eap_if->aaaMethodTimeout);
+		} else {
+			/*
+			 * Use dynamic retransmission behavior per EAP
+			 * specification.
+			 */
+			sm->eap_if->aaaMethodTimeout = 0;
+		}
+		break;
+	}
+
+	ieee802_1x_decapsulate_radius(hapd, sta);
+	if (override_eapReq)
+		sm->eap_if->aaaEapReq = FALSE;
+
+	eapol_auth_step(sm);
+
+	return RADIUS_RX_QUEUED;
+}
+#endif /* CONFIG_NO_RADIUS */
+
+
+void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	struct eapol_state_machine *sm = sta->eapol_sm;
+	if (sm == NULL)
+		return;
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+		       HOSTAPD_LEVEL_DEBUG, "aborting authentication");
+
+#ifndef CONFIG_NO_RADIUS
+	radius_msg_free(sm->last_recv_radius);
+	sm->last_recv_radius = NULL;
+#endif /* CONFIG_NO_RADIUS */
+
+	if (sm->eap_if->eapTimeout) {
+		/*
+		 * Disconnect the STA since it did not reply to the last EAP
+		 * request and we cannot continue EAP processing (EAP-Failure
+		 * could only be sent if the EAP peer actually replied).
+		 */
+		wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "EAP Timeout, STA " MACSTR,
+			MAC2STR(sta->addr));
+
+		sm->eap_if->portEnabled = FALSE;
+		ap_sta_disconnect(hapd, sta, sta->addr,
+				  WLAN_REASON_PREV_AUTH_NOT_VALID);
+	}
+}
+
+
+static int ieee802_1x_rekey_broadcast(struct hostapd_data *hapd)
+{
+	struct eapol_authenticator *eapol = hapd->eapol_auth;
+
+	if (hapd->conf->default_wep_key_len < 1)
+		return 0;
+
+	os_free(eapol->default_wep_key);
+	eapol->default_wep_key = os_malloc(hapd->conf->default_wep_key_len);
+	if (eapol->default_wep_key == NULL ||
+	    random_get_bytes(eapol->default_wep_key,
+			     hapd->conf->default_wep_key_len)) {
+		printf("Could not generate random WEP key.\n");
+		os_free(eapol->default_wep_key);
+		eapol->default_wep_key = NULL;
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "IEEE 802.1X: New default WEP key",
+			eapol->default_wep_key,
+			hapd->conf->default_wep_key_len);
+
+	return 0;
+}
+
+
+static int ieee802_1x_sta_key_available(struct hostapd_data *hapd,
+					struct sta_info *sta, void *ctx)
+{
+	if (sta->eapol_sm) {
+		sta->eapol_sm->eap_if->eapKeyAvailable = TRUE;
+		eapol_auth_step(sta->eapol_sm);
+	}
+	return 0;
+}
+
+
+static void ieee802_1x_rekey(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct eapol_authenticator *eapol = hapd->eapol_auth;
+
+	if (eapol->default_wep_key_idx >= 3)
+		eapol->default_wep_key_idx =
+			hapd->conf->individual_wep_key_len > 0 ? 1 : 0;
+	else
+		eapol->default_wep_key_idx++;
+
+	wpa_printf(MSG_DEBUG, "IEEE 802.1X: New default WEP key index %d",
+		   eapol->default_wep_key_idx);
+		      
+	if (ieee802_1x_rekey_broadcast(hapd)) {
+		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_WARNING, "failed to generate a "
+			       "new broadcast key");
+		os_free(eapol->default_wep_key);
+		eapol->default_wep_key = NULL;
+		return;
+	}
+
+	/* TODO: Could setup key for RX here, but change default TX keyid only
+	 * after new broadcast key has been sent to all stations. */
+	if (hostapd_drv_set_key(hapd->conf->iface, hapd, WPA_ALG_WEP,
+				broadcast_ether_addr,
+				eapol->default_wep_key_idx, 1, NULL, 0,
+				eapol->default_wep_key,
+				hapd->conf->default_wep_key_len)) {
+		hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_WARNING, "failed to configure a "
+			       "new broadcast key");
+		os_free(eapol->default_wep_key);
+		eapol->default_wep_key = NULL;
+		return;
+	}
+
+	ap_for_each_sta(hapd, ieee802_1x_sta_key_available, NULL);
+
+	if (hapd->conf->wep_rekeying_period > 0) {
+		eloop_register_timeout(hapd->conf->wep_rekeying_period, 0,
+				       ieee802_1x_rekey, hapd, NULL);
+	}
+}
+
+
+static void ieee802_1x_eapol_send(void *ctx, void *sta_ctx, u8 type,
+				  const u8 *data, size_t datalen)
+{
+#ifdef CONFIG_WPS
+	struct sta_info *sta = sta_ctx;
+
+	if ((sta->flags & (WLAN_STA_WPS | WLAN_STA_MAYBE_WPS)) ==
+	    WLAN_STA_MAYBE_WPS) {
+		const u8 *identity;
+		size_t identity_len;
+		struct eapol_state_machine *sm = sta->eapol_sm;
+
+		identity = eap_get_identity(sm->eap, &identity_len);
+		if (identity &&
+		    ((identity_len == WSC_ID_ENROLLEE_LEN &&
+		      os_memcmp(identity, WSC_ID_ENROLLEE,
+				WSC_ID_ENROLLEE_LEN) == 0) ||
+		     (identity_len == WSC_ID_REGISTRAR_LEN &&
+		      os_memcmp(identity, WSC_ID_REGISTRAR,
+				WSC_ID_REGISTRAR_LEN) == 0))) {
+			wpa_printf(MSG_DEBUG, "WPS: WLAN_STA_MAYBE_WPS -> "
+				   "WLAN_STA_WPS");
+			sta->flags |= WLAN_STA_WPS;
+		}
+	}
+#endif /* CONFIG_WPS */
+
+	ieee802_1x_send(ctx, sta_ctx, type, data, datalen);
+}
+
+
+static void ieee802_1x_aaa_send(void *ctx, void *sta_ctx,
+				const u8 *data, size_t datalen)
+{
+#ifndef CONFIG_NO_RADIUS
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = sta_ctx;
+
+	ieee802_1x_encapsulate_radius(hapd, sta, data, datalen);
+#endif /* CONFIG_NO_RADIUS */
+}
+
+
+static void _ieee802_1x_finished(void *ctx, void *sta_ctx, int success,
+				 int preauth)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = sta_ctx;
+	if (preauth)
+		rsn_preauth_finished(hapd, sta, success);
+	else
+		ieee802_1x_finished(hapd, sta, success);
+}
+
+
+static int ieee802_1x_get_eap_user(void *ctx, const u8 *identity,
+				   size_t identity_len, int phase2,
+				   struct eap_user *user)
+{
+	struct hostapd_data *hapd = ctx;
+	const struct hostapd_eap_user *eap_user;
+	int i;
+
+	eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
+	if (eap_user == NULL)
+		return -1;
+
+	os_memset(user, 0, sizeof(*user));
+	user->phase2 = phase2;
+	for (i = 0; i < EAP_MAX_METHODS; i++) {
+		user->methods[i].vendor = eap_user->methods[i].vendor;
+		user->methods[i].method = eap_user->methods[i].method;
+	}
+
+	if (eap_user->password) {
+		user->password = os_malloc(eap_user->password_len);
+		if (user->password == NULL)
+			return -1;
+		os_memcpy(user->password, eap_user->password,
+			  eap_user->password_len);
+		user->password_len = eap_user->password_len;
+		user->password_hash = eap_user->password_hash;
+	}
+	user->force_version = eap_user->force_version;
+	user->ttls_auth = eap_user->ttls_auth;
+
+	return 0;
+}
+
+
+static int ieee802_1x_sta_entry_alive(void *ctx, const u8 *addr)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL || sta->eapol_sm == NULL)
+		return 0;
+	return 1;
+}
+
+
+static void ieee802_1x_logger(void *ctx, const u8 *addr,
+			      eapol_logger_level level, const char *txt)
+{
+#ifndef CONFIG_NO_HOSTAPD_LOGGER
+	struct hostapd_data *hapd = ctx;
+	int hlevel;
+
+	switch (level) {
+	case EAPOL_LOGGER_WARNING:
+		hlevel = HOSTAPD_LEVEL_WARNING;
+		break;
+	case EAPOL_LOGGER_INFO:
+		hlevel = HOSTAPD_LEVEL_INFO;
+		break;
+	case EAPOL_LOGGER_DEBUG:
+	default:
+		hlevel = HOSTAPD_LEVEL_DEBUG;
+		break;
+	}
+
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE8021X, hlevel, "%s",
+		       txt);
+#endif /* CONFIG_NO_HOSTAPD_LOGGER */
+}
+
+
+static void ieee802_1x_set_port_authorized(void *ctx, void *sta_ctx,
+					   int authorized)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = sta_ctx;
+	ieee802_1x_set_sta_authorized(hapd, sta, authorized);
+}
+
+
+static void _ieee802_1x_abort_auth(void *ctx, void *sta_ctx)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = sta_ctx;
+	ieee802_1x_abort_auth(hapd, sta);
+}
+
+
+static void _ieee802_1x_tx_key(void *ctx, void *sta_ctx)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = sta_ctx;
+	ieee802_1x_tx_key(hapd, sta);
+}
+
+
+static void ieee802_1x_eapol_event(void *ctx, void *sta_ctx,
+				   enum eapol_event type)
+{
+	/* struct hostapd_data *hapd = ctx; */
+	struct sta_info *sta = sta_ctx;
+	switch (type) {
+	case EAPOL_AUTH_SM_CHANGE:
+		wpa_auth_sm_notify(sta->wpa_sm);
+		break;
+	case EAPOL_AUTH_REAUTHENTICATE:
+		wpa_auth_sm_event(sta->wpa_sm, WPA_REAUTH_EAPOL);
+		break;
+	}
+}
+
+
+int ieee802_1x_init(struct hostapd_data *hapd)
+{
+	int i;
+	struct eapol_auth_config conf;
+	struct eapol_auth_cb cb;
+
+	os_memset(&conf, 0, sizeof(conf));
+	conf.ctx = hapd;
+	conf.eap_reauth_period = hapd->conf->eap_reauth_period;
+	conf.wpa = hapd->conf->wpa;
+	conf.individual_wep_key_len = hapd->conf->individual_wep_key_len;
+	conf.eap_server = hapd->conf->eap_server;
+	conf.ssl_ctx = hapd->ssl_ctx;
+	conf.msg_ctx = hapd->msg_ctx;
+	conf.eap_sim_db_priv = hapd->eap_sim_db_priv;
+	conf.eap_req_id_text = hapd->conf->eap_req_id_text;
+	conf.eap_req_id_text_len = hapd->conf->eap_req_id_text_len;
+	conf.pac_opaque_encr_key = hapd->conf->pac_opaque_encr_key;
+	conf.eap_fast_a_id = hapd->conf->eap_fast_a_id;
+	conf.eap_fast_a_id_len = hapd->conf->eap_fast_a_id_len;
+	conf.eap_fast_a_id_info = hapd->conf->eap_fast_a_id_info;
+	conf.eap_fast_prov = hapd->conf->eap_fast_prov;
+	conf.pac_key_lifetime = hapd->conf->pac_key_lifetime;
+	conf.pac_key_refresh_time = hapd->conf->pac_key_refresh_time;
+	conf.eap_sim_aka_result_ind = hapd->conf->eap_sim_aka_result_ind;
+	conf.tnc = hapd->conf->tnc;
+	conf.wps = hapd->wps;
+	conf.fragment_size = hapd->conf->fragment_size;
+	conf.pwd_group = hapd->conf->pwd_group;
+	conf.pbc_in_m1 = hapd->conf->pbc_in_m1;
+
+	os_memset(&cb, 0, sizeof(cb));
+	cb.eapol_send = ieee802_1x_eapol_send;
+	cb.aaa_send = ieee802_1x_aaa_send;
+	cb.finished = _ieee802_1x_finished;
+	cb.get_eap_user = ieee802_1x_get_eap_user;
+	cb.sta_entry_alive = ieee802_1x_sta_entry_alive;
+	cb.logger = ieee802_1x_logger;
+	cb.set_port_authorized = ieee802_1x_set_port_authorized;
+	cb.abort_auth = _ieee802_1x_abort_auth;
+	cb.tx_key = _ieee802_1x_tx_key;
+	cb.eapol_event = ieee802_1x_eapol_event;
+
+	hapd->eapol_auth = eapol_auth_init(&conf, &cb);
+	if (hapd->eapol_auth == NULL)
+		return -1;
+
+	if ((hapd->conf->ieee802_1x || hapd->conf->wpa) &&
+	    hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 1))
+		return -1;
+
+#ifndef CONFIG_NO_RADIUS
+	if (radius_client_register(hapd->radius, RADIUS_AUTH,
+				   ieee802_1x_receive_auth, hapd))
+		return -1;
+#endif /* CONFIG_NO_RADIUS */
+
+	if (hapd->conf->default_wep_key_len) {
+		for (i = 0; i < 4; i++)
+			hostapd_drv_set_key(hapd->conf->iface, hapd,
+					    WPA_ALG_NONE, NULL, i, 0, NULL, 0,
+					    NULL, 0);
+
+		ieee802_1x_rekey(hapd, NULL);
+
+		if (hapd->eapol_auth->default_wep_key == NULL)
+			return -1;
+	}
+
+	return 0;
+}
+
+
+void ieee802_1x_deinit(struct hostapd_data *hapd)
+{
+	eloop_cancel_timeout(ieee802_1x_rekey, hapd, NULL);
+
+	if (hapd->driver != NULL &&
+	    (hapd->conf->ieee802_1x || hapd->conf->wpa))
+		hostapd_set_drv_ieee8021x(hapd, hapd->conf->iface, 0);
+
+	eapol_auth_deinit(hapd->eapol_auth);
+	hapd->eapol_auth = NULL;
+}
+
+
+int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+			 const u8 *buf, size_t len, int ack)
+{
+	struct ieee80211_hdr *hdr;
+	u8 *pos;
+	const unsigned char rfc1042_hdr[ETH_ALEN] =
+		{ 0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00 };
+
+	if (sta == NULL)
+		return -1;
+	if (len < sizeof(*hdr) + sizeof(rfc1042_hdr) + 2)
+		return 0;
+
+	hdr = (struct ieee80211_hdr *) buf;
+	pos = (u8 *) (hdr + 1);
+	if (os_memcmp(pos, rfc1042_hdr, sizeof(rfc1042_hdr)) != 0)
+		return 0;
+	pos += sizeof(rfc1042_hdr);
+	if (WPA_GET_BE16(pos) != ETH_P_PAE)
+		return 0;
+	pos += 2;
+
+	return ieee802_1x_eapol_tx_status(hapd, sta, pos, buf + len - pos,
+					  ack);
+}
+
+
+int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+			       const u8 *buf, int len, int ack)
+{
+	const struct ieee802_1x_hdr *xhdr =
+		(const struct ieee802_1x_hdr *) buf;
+	const u8 *pos = buf + sizeof(*xhdr);
+	struct ieee802_1x_eapol_key *key;
+
+	if (len < (int) sizeof(*xhdr))
+		return 0;
+	wpa_printf(MSG_DEBUG, "IEEE 802.1X: " MACSTR " TX status - version=%d "
+		   "type=%d length=%d - ack=%d",
+		   MAC2STR(sta->addr), xhdr->version, xhdr->type,
+		   be_to_host16(xhdr->length), ack);
+
+	if (xhdr->type != IEEE802_1X_TYPE_EAPOL_KEY)
+		return 0;
+
+	if (pos + sizeof(struct wpa_eapol_key) <= buf + len) {
+		const struct wpa_eapol_key *wpa;
+		wpa = (const struct wpa_eapol_key *) pos;
+		if (wpa->type == EAPOL_KEY_TYPE_RSN ||
+		    wpa->type == EAPOL_KEY_TYPE_WPA)
+			wpa_auth_eapol_key_tx_status(hapd->wpa_auth,
+						     sta->wpa_sm, ack);
+	}
+
+	/* EAPOL EAP-Packet packets are eventually re-sent by either Supplicant
+	 * or Authenticator state machines, but EAPOL-Key packets are not
+	 * retransmitted in case of failure. Try to re-send failed EAPOL-Key
+	 * packets couple of times because otherwise STA keys become
+	 * unsynchronized with AP. */
+	if (!ack && pos + sizeof(*key) <= buf + len) {
+		key = (struct ieee802_1x_eapol_key *) pos;
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE8021X,
+			       HOSTAPD_LEVEL_DEBUG, "did not Ack EAPOL-Key "
+			       "frame (%scast index=%d)",
+			       key->key_index & BIT(7) ? "uni" : "broad",
+			       key->key_index & ~BIT(7));
+		/* TODO: re-send EAPOL-Key couple of times (with short delay
+		 * between them?). If all attempt fail, report error and
+		 * deauthenticate STA so that it will get new keys when
+		 * authenticating again (e.g., after returning in range).
+		 * Separate limit/transmit state needed both for unicast and
+		 * broadcast keys(?) */
+	}
+	/* TODO: could move unicast key configuration from ieee802_1x_tx_key()
+	 * to here and change the key only if the EAPOL-Key packet was Acked.
+	 */
+
+	return 1;
+}
+
+
+u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len)
+{
+	if (sm == NULL || sm->identity == NULL)
+		return NULL;
+
+	*len = sm->identity_len;
+	return sm->identity;
+}
+
+
+u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
+				 int idx)
+{
+	if (sm == NULL || sm->radius_class.attr == NULL ||
+	    idx >= (int) sm->radius_class.count)
+		return NULL;
+
+	*len = sm->radius_class.attr[idx].len;
+	return sm->radius_class.attr[idx].data;
+}
+
+
+struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm)
+{
+	if (sm == NULL)
+		return NULL;
+	return sm->radius_cui;
+}
+
+
+const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len)
+{
+	*len = 0;
+	if (sm == NULL)
+		return NULL;
+
+	*len = sm->eap_if->eapKeyDataLen;
+	return sm->eap_if->eapKeyData;
+}
+
+
+void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
+				    int enabled)
+{
+	if (sm == NULL)
+		return;
+	sm->eap_if->portEnabled = enabled ? TRUE : FALSE;
+	eapol_auth_step(sm);
+}
+
+
+void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
+				  int valid)
+{
+	if (sm == NULL)
+		return;
+	sm->portValid = valid ? TRUE : FALSE;
+	eapol_auth_step(sm);
+}
+
+
+void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth)
+{
+	if (sm == NULL)
+		return;
+	if (pre_auth)
+		sm->flags |= EAPOL_SM_PREAUTH;
+	else
+		sm->flags &= ~EAPOL_SM_PREAUTH;
+}
+
+
+static const char * bool_txt(Boolean bool)
+{
+	return bool ? "TRUE" : "FALSE";
+}
+
+
+int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen)
+{
+	/* TODO */
+	return 0;
+}
+
+
+int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			   char *buf, size_t buflen)
+{
+	int len = 0, ret;
+	struct eapol_state_machine *sm = sta->eapol_sm;
+	struct os_time t;
+
+	if (sm == NULL)
+		return 0;
+
+	ret = os_snprintf(buf + len, buflen - len,
+			  "dot1xPaePortNumber=%d\n"
+			  "dot1xPaePortProtocolVersion=%d\n"
+			  "dot1xPaePortCapabilities=1\n"
+			  "dot1xPaePortInitialize=%d\n"
+			  "dot1xPaePortReauthenticate=FALSE\n",
+			  sta->aid,
+			  EAPOL_VERSION,
+			  sm->initialize);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	/* dot1xAuthConfigTable */
+	ret = os_snprintf(buf + len, buflen - len,
+			  "dot1xAuthPaeState=%d\n"
+			  "dot1xAuthBackendAuthState=%d\n"
+			  "dot1xAuthAdminControlledDirections=%d\n"
+			  "dot1xAuthOperControlledDirections=%d\n"
+			  "dot1xAuthAuthControlledPortStatus=%d\n"
+			  "dot1xAuthAuthControlledPortControl=%d\n"
+			  "dot1xAuthQuietPeriod=%u\n"
+			  "dot1xAuthServerTimeout=%u\n"
+			  "dot1xAuthReAuthPeriod=%u\n"
+			  "dot1xAuthReAuthEnabled=%s\n"
+			  "dot1xAuthKeyTxEnabled=%s\n",
+			  sm->auth_pae_state + 1,
+			  sm->be_auth_state + 1,
+			  sm->adminControlledDirections,
+			  sm->operControlledDirections,
+			  sm->authPortStatus,
+			  sm->portControl,
+			  sm->quietPeriod,
+			  sm->serverTimeout,
+			  sm->reAuthPeriod,
+			  bool_txt(sm->reAuthEnabled),
+			  bool_txt(sm->keyTxEnabled));
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	/* dot1xAuthStatsTable */
+	ret = os_snprintf(buf + len, buflen - len,
+			  "dot1xAuthEapolFramesRx=%u\n"
+			  "dot1xAuthEapolFramesTx=%u\n"
+			  "dot1xAuthEapolStartFramesRx=%u\n"
+			  "dot1xAuthEapolLogoffFramesRx=%u\n"
+			  "dot1xAuthEapolRespIdFramesRx=%u\n"
+			  "dot1xAuthEapolRespFramesRx=%u\n"
+			  "dot1xAuthEapolReqIdFramesTx=%u\n"
+			  "dot1xAuthEapolReqFramesTx=%u\n"
+			  "dot1xAuthInvalidEapolFramesRx=%u\n"
+			  "dot1xAuthEapLengthErrorFramesRx=%u\n"
+			  "dot1xAuthLastEapolFrameVersion=%u\n"
+			  "dot1xAuthLastEapolFrameSource=" MACSTR "\n",
+			  sm->dot1xAuthEapolFramesRx,
+			  sm->dot1xAuthEapolFramesTx,
+			  sm->dot1xAuthEapolStartFramesRx,
+			  sm->dot1xAuthEapolLogoffFramesRx,
+			  sm->dot1xAuthEapolRespIdFramesRx,
+			  sm->dot1xAuthEapolRespFramesRx,
+			  sm->dot1xAuthEapolReqIdFramesTx,
+			  sm->dot1xAuthEapolReqFramesTx,
+			  sm->dot1xAuthInvalidEapolFramesRx,
+			  sm->dot1xAuthEapLengthErrorFramesRx,
+			  sm->dot1xAuthLastEapolFrameVersion,
+			  MAC2STR(sm->addr));
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	/* dot1xAuthDiagTable */
+	ret = os_snprintf(buf + len, buflen - len,
+			  "dot1xAuthEntersConnecting=%u\n"
+			  "dot1xAuthEapLogoffsWhileConnecting=%u\n"
+			  "dot1xAuthEntersAuthenticating=%u\n"
+			  "dot1xAuthAuthSuccessesWhileAuthenticating=%u\n"
+			  "dot1xAuthAuthTimeoutsWhileAuthenticating=%u\n"
+			  "dot1xAuthAuthFailWhileAuthenticating=%u\n"
+			  "dot1xAuthAuthEapStartsWhileAuthenticating=%u\n"
+			  "dot1xAuthAuthEapLogoffWhileAuthenticating=%u\n"
+			  "dot1xAuthAuthReauthsWhileAuthenticated=%u\n"
+			  "dot1xAuthAuthEapStartsWhileAuthenticated=%u\n"
+			  "dot1xAuthAuthEapLogoffWhileAuthenticated=%u\n"
+			  "dot1xAuthBackendResponses=%u\n"
+			  "dot1xAuthBackendAccessChallenges=%u\n"
+			  "dot1xAuthBackendOtherRequestsToSupplicant=%u\n"
+			  "dot1xAuthBackendAuthSuccesses=%u\n"
+			  "dot1xAuthBackendAuthFails=%u\n",
+			  sm->authEntersConnecting,
+			  sm->authEapLogoffsWhileConnecting,
+			  sm->authEntersAuthenticating,
+			  sm->authAuthSuccessesWhileAuthenticating,
+			  sm->authAuthTimeoutsWhileAuthenticating,
+			  sm->authAuthFailWhileAuthenticating,
+			  sm->authAuthEapStartsWhileAuthenticating,
+			  sm->authAuthEapLogoffWhileAuthenticating,
+			  sm->authAuthReauthsWhileAuthenticated,
+			  sm->authAuthEapStartsWhileAuthenticated,
+			  sm->authAuthEapLogoffWhileAuthenticated,
+			  sm->backendResponses,
+			  sm->backendAccessChallenges,
+			  sm->backendOtherRequestsToSupplicant,
+			  sm->backendAuthSuccesses,
+			  sm->backendAuthFails);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	/* dot1xAuthSessionStatsTable */
+	os_get_time(&t);
+	ret = os_snprintf(buf + len, buflen - len,
+			  /* TODO: dot1xAuthSessionOctetsRx */
+			  /* TODO: dot1xAuthSessionOctetsTx */
+			  /* TODO: dot1xAuthSessionFramesRx */
+			  /* TODO: dot1xAuthSessionFramesTx */
+			  "dot1xAuthSessionId=%08X-%08X\n"
+			  "dot1xAuthSessionAuthenticMethod=%d\n"
+			  "dot1xAuthSessionTime=%u\n"
+			  "dot1xAuthSessionTerminateCause=999\n"
+			  "dot1xAuthSessionUserName=%s\n",
+			  sta->acct_session_id_hi, sta->acct_session_id_lo,
+			  (wpa_key_mgmt_wpa_ieee8021x(
+				   wpa_auth_sta_key_mgmt(sta->wpa_sm))) ?
+			  1 : 2,
+			  (unsigned int) (t.sec - sta->acct_session_start),
+			  sm->identity);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	return len;
+}
+
+
+static void ieee802_1x_finished(struct hostapd_data *hapd,
+				struct sta_info *sta, int success)
+{
+	const u8 *key;
+	size_t len;
+	/* TODO: get PMKLifetime from WPA parameters */
+	static const int dot11RSNAConfigPMKLifetime = 43200;
+
+	key = ieee802_1x_get_key(sta->eapol_sm, &len);
+	if (success && key && len >= PMK_LEN &&
+	    wpa_auth_pmksa_add(sta->wpa_sm, key, dot11RSNAConfigPMKLifetime,
+			       sta->eapol_sm) == 0) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "Added PMKSA cache entry (IEEE 802.1X)");
+	}
+
+	if (!success) {
+		/*
+		 * Many devices require deauthentication after WPS provisioning
+		 * and some may not be be able to do that themselves, so
+		 * disconnect the client here. In addition, this may also
+		 * benefit IEEE 802.1X/EAPOL authentication cases, too since
+		 * the EAPOL PAE state machine would remain in HELD state for
+		 * considerable amount of time and some EAP methods, like
+		 * EAP-FAST with anonymous provisioning, may require another
+		 * EAPOL authentication to be started to complete connection.
+		 */
+		wpa_dbg(hapd->msg_ctx, MSG_DEBUG, "IEEE 802.1X: Force "
+			"disconnection after EAP-Failure");
+		/* Add a small sleep to increase likelihood of previously
+		 * requested EAP-Failure TX getting out before this should the
+		 * driver reorder operations.
+		 */
+		os_sleep(0, 10000);
+		ap_sta_disconnect(hapd, sta, sta->addr,
+				  WLAN_REASON_IEEE_802_1X_AUTH_FAILED);
+	}
+}
diff --git a/hostap/src/ap/ieee802_1x.h b/hostap/src/ap/ieee802_1x.h
new file mode 100644
index 0000000..e1df940
--- /dev/null
+++ b/hostap/src/ap/ieee802_1x.h
@@ -0,0 +1,61 @@
+/*
+ * hostapd / IEEE 802.1X-2004 Authenticator
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_1X_H
+#define IEEE802_1X_H
+
+struct hostapd_data;
+struct sta_info;
+struct eapol_state_machine;
+struct hostapd_config;
+struct hostapd_bss_config;
+struct hostapd_radius_attr;
+struct radius_msg;
+
+
+void ieee802_1x_receive(struct hostapd_data *hapd, const u8 *sa, const u8 *buf,
+			size_t len);
+void ieee802_1x_new_station(struct hostapd_data *hapd, struct sta_info *sta);
+void ieee802_1x_free_station(struct sta_info *sta);
+
+void ieee802_1x_tx_key(struct hostapd_data *hapd, struct sta_info *sta);
+void ieee802_1x_abort_auth(struct hostapd_data *hapd, struct sta_info *sta);
+void ieee802_1x_set_sta_authorized(struct hostapd_data *hapd,
+				   struct sta_info *sta, int authorized);
+void ieee802_1x_dump_state(FILE *f, const char *prefix, struct sta_info *sta);
+int ieee802_1x_init(struct hostapd_data *hapd);
+void ieee802_1x_deinit(struct hostapd_data *hapd);
+int ieee802_1x_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+			 const u8 *buf, size_t len, int ack);
+int ieee802_1x_eapol_tx_status(struct hostapd_data *hapd, struct sta_info *sta,
+			       const u8 *data, int len, int ack);
+u8 * ieee802_1x_get_identity(struct eapol_state_machine *sm, size_t *len);
+u8 * ieee802_1x_get_radius_class(struct eapol_state_machine *sm, size_t *len,
+				 int idx);
+struct wpabuf * ieee802_1x_get_radius_cui(struct eapol_state_machine *sm);
+const u8 * ieee802_1x_get_key(struct eapol_state_machine *sm, size_t *len);
+void ieee802_1x_notify_port_enabled(struct eapol_state_machine *sm,
+				    int enabled);
+void ieee802_1x_notify_port_valid(struct eapol_state_machine *sm,
+				  int valid);
+void ieee802_1x_notify_pre_auth(struct eapol_state_machine *sm, int pre_auth);
+int ieee802_1x_get_mib(struct hostapd_data *hapd, char *buf, size_t buflen);
+int ieee802_1x_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			   char *buf, size_t buflen);
+void hostapd_get_ntp_timestamp(u8 *buf);
+char *eap_type_text(u8 type);
+
+const char *radius_mode_txt(struct hostapd_data *hapd);
+int radius_sta_rate(struct hostapd_data *hapd, struct sta_info *sta);
+
+int add_common_radius_attr(struct hostapd_data *hapd,
+			   struct hostapd_radius_attr *req_attr,
+			   struct sta_info *sta,
+			   struct radius_msg *msg);
+
+#endif /* IEEE802_1X_H */
diff --git a/hostap/src/ap/p2p_hostapd.c b/hostap/src/ap/p2p_hostapd.c
new file mode 100644
index 0000000..795d313
--- /dev/null
+++ b/hostap/src/ap/p2p_hostapd.c
@@ -0,0 +1,114 @@
+/*
+ * hostapd / P2P integration
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "p2p/p2p.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "sta_info.h"
+#include "p2p_hostapd.h"
+
+
+#ifdef CONFIG_P2P
+
+int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			    char *buf, size_t buflen)
+{
+	if (sta->p2p_ie == NULL)
+		return 0;
+
+	return p2p_ie_text(sta->p2p_ie, buf, buf + buflen);
+}
+
+
+int hostapd_p2p_set_noa(struct hostapd_data *hapd, u8 count, int start,
+			int duration)
+{
+	wpa_printf(MSG_DEBUG, "P2P: Set NoA parameters: count=%u start=%d "
+		   "duration=%d", count, start, duration);
+
+	if (count == 0) {
+		hapd->noa_enabled = 0;
+		hapd->noa_start = 0;
+		hapd->noa_duration = 0;
+	}
+
+	if (count != 255) {
+		wpa_printf(MSG_DEBUG, "P2P: Non-periodic NoA - set "
+			   "NoA parameters");
+		return hostapd_driver_set_noa(hapd, count, start, duration);
+	}
+
+	hapd->noa_enabled = 1;
+	hapd->noa_start = start;
+	hapd->noa_duration = duration;
+
+	if (hapd->num_sta_no_p2p == 0) {
+		wpa_printf(MSG_DEBUG, "P2P: No legacy STAs connected - update "
+			   "periodic NoA parameters");
+		return hostapd_driver_set_noa(hapd, count, start, duration);
+	}
+
+	wpa_printf(MSG_DEBUG, "P2P: Legacy STA(s) connected - do not enable "
+		   "periodic NoA");
+
+	return 0;
+}
+
+
+void hostapd_p2p_non_p2p_sta_connected(struct hostapd_data *hapd)
+{
+	wpa_printf(MSG_DEBUG, "P2P: First non-P2P device connected");
+
+	if (hapd->noa_enabled) {
+		wpa_printf(MSG_DEBUG, "P2P: Disable periodic NoA");
+		hostapd_driver_set_noa(hapd, 0, 0, 0);
+	}
+}
+
+
+void hostapd_p2p_non_p2p_sta_disconnected(struct hostapd_data *hapd)
+{
+	wpa_printf(MSG_DEBUG, "P2P: Last non-P2P device disconnected");
+
+	if (hapd->noa_enabled) {
+		wpa_printf(MSG_DEBUG, "P2P: Enable periodic NoA");
+		hostapd_driver_set_noa(hapd, 255, hapd->noa_start,
+				       hapd->noa_duration);
+	}
+}
+
+#endif /* CONFIG_P2P */
+
+
+#ifdef CONFIG_P2P_MANAGER
+u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 bitmap;
+	*eid++ = WLAN_EID_VENDOR_SPECIFIC;
+	*eid++ = 4 + 3 + 1;
+	WPA_PUT_BE24(eid, OUI_WFA);
+	eid += 3;
+	*eid++ = P2P_OUI_TYPE;
+
+	*eid++ = P2P_ATTR_MANAGEABILITY;
+	WPA_PUT_LE16(eid, 1);
+	eid += 2;
+	bitmap = P2P_MAN_DEVICE_MANAGEMENT;
+	if (hapd->conf->p2p & P2P_ALLOW_CROSS_CONNECTION)
+		bitmap |= P2P_MAN_CROSS_CONNECTION_PERMITTED;
+	bitmap |= P2P_MAN_COEXISTENCE_OPTIONAL;
+	*eid++ = bitmap;
+
+	return eid;
+}
+#endif /* CONFIG_P2P_MANAGER */
diff --git a/hostap/src/ap/p2p_hostapd.h b/hostap/src/ap/p2p_hostapd.h
new file mode 100644
index 0000000..0e3921c
--- /dev/null
+++ b/hostap/src/ap/p2p_hostapd.h
@@ -0,0 +1,35 @@
+/*
+ * hostapd / P2P integration
+ * Copyright (c) 2009-2010, Atheros Communications
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef P2P_HOSTAPD_H
+#define P2P_HOSTAPD_H
+
+#ifdef CONFIG_P2P
+
+int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd, struct sta_info *sta,
+			    char *buf, size_t buflen);
+int hostapd_p2p_set_noa(struct hostapd_data *hapd, u8 count, int start,
+			int duration);
+void hostapd_p2p_non_p2p_sta_connected(struct hostapd_data *hapd);
+void hostapd_p2p_non_p2p_sta_disconnected(struct hostapd_data *hapd);
+
+
+#else /* CONFIG_P2P */
+
+static inline int hostapd_p2p_get_mib_sta(struct hostapd_data *hapd,
+					  struct sta_info *sta,
+					  char *buf, size_t buflen)
+{
+	return 0;
+}
+
+#endif /* CONFIG_P2P */
+
+u8 * hostapd_eid_p2p_manage(struct hostapd_data *hapd, u8 *eid);
+
+#endif /* P2P_HOSTAPD_H */
diff --git a/hostap/src/ap/peerkey_auth.c b/hostap/src/ap/peerkey_auth.c
new file mode 100644
index 0000000..ba5c606
--- /dev/null
+++ b/hostap/src/ap/peerkey_auth.c
@@ -0,0 +1,396 @@
+/*
+ * hostapd - PeerKey for Direct Link Setup (DLS)
+ * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "wpa_auth.h"
+#include "wpa_auth_i.h"
+#include "wpa_auth_ie.h"
+
+#ifdef CONFIG_PEERKEY
+
+static void wpa_stsl_step(void *eloop_ctx, void *timeout_ctx)
+{
+#if 0
+	struct wpa_authenticator *wpa_auth = eloop_ctx;
+	struct wpa_stsl_negotiation *neg = timeout_ctx;
+#endif
+
+	/* TODO: ? */
+}
+
+
+struct wpa_stsl_search {
+	const u8 *addr;
+	struct wpa_state_machine *sm;
+};
+
+
+static int wpa_stsl_select_sta(struct wpa_state_machine *sm, void *ctx)
+{
+	struct wpa_stsl_search *search = ctx;
+	if (os_memcmp(search->addr, sm->addr, ETH_ALEN) == 0) {
+		search->sm = sm;
+		return 1;
+	}
+	return 0;
+}
+
+
+static void wpa_smk_send_error(struct wpa_authenticator *wpa_auth,
+			       struct wpa_state_machine *sm, const u8 *peer,
+			       u16 mui, u16 error_type)
+{
+	u8 kde[2 + RSN_SELECTOR_LEN + ETH_ALEN +
+	       2 + RSN_SELECTOR_LEN + sizeof(struct rsn_error_kde)];
+	u8 *pos;
+	struct rsn_error_kde error;
+
+	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+			"Sending SMK Error");
+
+	pos = kde;
+
+	if (peer) {
+		pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN,
+				  NULL, 0);
+	}
+
+	error.mui = host_to_be16(mui);
+	error.error_type = host_to_be16(error_type);
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_ERROR,
+			  (u8 *) &error, sizeof(error), NULL, 0);
+
+	__wpa_send_eapol(wpa_auth, sm,
+			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+			 WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_ERROR,
+			 NULL, NULL, kde, pos - kde, 0, 0, 0);
+}
+
+
+void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
+		struct wpa_state_machine *sm, struct wpa_eapol_key *key)
+{
+	struct wpa_eapol_ie_parse kde;
+	struct wpa_stsl_search search;
+	u8 *buf, *pos;
+	size_t buf_len;
+
+	if (wpa_parse_kde_ies((const u8 *) (key + 1),
+			      WPA_GET_BE16(key->key_data_length), &kde) < 0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M1");
+		return;
+	}
+
+	if (kde.rsn_ie == NULL || kde.mac_addr == NULL ||
+	    kde.mac_addr_len < ETH_ALEN) {
+		wpa_printf(MSG_INFO, "RSN: No RSN IE or MAC address KDE in "
+			   "SMK M1");
+		return;
+	}
+
+	/* Initiator = sm->addr; Peer = kde.mac_addr */
+
+	search.addr = kde.mac_addr;
+	search.sm = NULL;
+	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
+	    0 || search.sm == NULL) {
+		wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
+			   " aborted - STA not associated anymore",
+			   MAC2STR(kde.mac_addr));
+		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
+				   STK_ERR_STA_NR);
+		/* FIX: wpa_stsl_remove(wpa_auth, neg); */
+		return;
+	}
+
+	buf_len = kde.rsn_ie_len + 2 + RSN_SELECTOR_LEN + ETH_ALEN;
+	buf = os_malloc(buf_len);
+	if (buf == NULL)
+		return;
+	/* Initiator RSN IE */
+	os_memcpy(buf, kde.rsn_ie, kde.rsn_ie_len);
+	pos = buf + kde.rsn_ie_len;
+	/* Initiator MAC Address */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, sm->addr, ETH_ALEN,
+			  NULL, 0);
+
+	/* SMK M2:
+	 * EAPOL-Key(S=1, M=1, A=1, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
+	 *           MIC=MIC, DataKDs=(RSNIE_I, MAC_I KDE)
+	 */
+
+	wpa_auth_logger(wpa_auth, search.sm->addr, LOGGER_DEBUG,
+			"Sending SMK M2");
+
+	__wpa_send_eapol(wpa_auth, search.sm,
+			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+			 WPA_KEY_INFO_ACK | WPA_KEY_INFO_SMK_MESSAGE,
+			 NULL, key->key_nonce, buf, pos - buf, 0, 0, 0);
+
+	os_free(buf);
+}
+
+
+static void wpa_send_smk_m4(struct wpa_authenticator *wpa_auth,
+			    struct wpa_state_machine *sm,
+			    struct wpa_eapol_key *key,
+			    struct wpa_eapol_ie_parse *kde,
+			    const u8 *smk)
+{
+	u8 *buf, *pos;
+	size_t buf_len;
+	u32 lifetime;
+
+	/* SMK M4:
+	 * EAPOL-Key(S=1, M=1, A=0, I=1, K=0, SM=1, KeyRSC=0, Nonce=PNonce,
+	 *           MIC=MIC, DataKDs=(MAC_I KDE, INonce KDE, SMK KDE,
+	 *           Lifetime KDE)
+	 */
+
+	buf_len = 2 + RSN_SELECTOR_LEN + ETH_ALEN +
+		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
+		2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
+		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
+	pos = buf = os_malloc(buf_len);
+	if (buf == NULL)
+		return;
+
+	/* Initiator MAC Address */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, kde->mac_addr, ETH_ALEN,
+			  NULL, 0);
+
+	/* Initiator Nonce */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, kde->nonce, WPA_NONCE_LEN,
+			  NULL, 0);
+
+	/* SMK with PNonce */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
+			  key->key_nonce, WPA_NONCE_LEN);
+
+	/* Lifetime */
+	lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
+			  (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
+
+	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			"Sending SMK M4");
+
+	__wpa_send_eapol(wpa_auth, sm,
+			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+			 WPA_KEY_INFO_INSTALL | WPA_KEY_INFO_SMK_MESSAGE,
+			 NULL, key->key_nonce, buf, pos - buf, 0, 1, 0);
+
+	os_free(buf);
+}
+
+
+static void wpa_send_smk_m5(struct wpa_authenticator *wpa_auth,
+			    struct wpa_state_machine *sm,
+			    struct wpa_eapol_key *key,
+			    struct wpa_eapol_ie_parse *kde,
+			    const u8 *smk, const u8 *peer)
+{
+	u8 *buf, *pos;
+	size_t buf_len;
+	u32 lifetime;
+
+	/* SMK M5:
+	 * EAPOL-Key(S=1, M=1, A=0, I=0, K=0, SM=1, KeyRSC=0, Nonce=INonce,
+	 *           MIC=MIC, DataKDs=(RSNIE_P, MAC_P KDE, PNonce, SMK KDE,
+	 *                             Lifetime KDE))
+	 */
+
+	buf_len = kde->rsn_ie_len +
+		2 + RSN_SELECTOR_LEN + ETH_ALEN +
+		2 + RSN_SELECTOR_LEN + WPA_NONCE_LEN +
+		2 + RSN_SELECTOR_LEN + PMK_LEN + WPA_NONCE_LEN +
+		2 + RSN_SELECTOR_LEN + sizeof(lifetime);
+	pos = buf = os_malloc(buf_len);
+	if (buf == NULL)
+		return;
+
+	/* Peer RSN IE */
+	os_memcpy(buf, kde->rsn_ie, kde->rsn_ie_len);
+	pos = buf + kde->rsn_ie_len;
+
+	/* Peer MAC Address */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_MAC_ADDR, peer, ETH_ALEN, NULL, 0);
+
+	/* PNonce */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_NONCE, key->key_nonce,
+			  WPA_NONCE_LEN, NULL, 0);
+
+	/* SMK and INonce */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_SMK, smk, PMK_LEN,
+			  kde->nonce, WPA_NONCE_LEN);
+
+	/* Lifetime */
+	lifetime = htonl(43200); /* dot11RSNAConfigSMKLifetime */
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_LIFETIME,
+			  (u8 *) &lifetime, sizeof(lifetime), NULL, 0);
+
+	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			"Sending SMK M5");
+
+	__wpa_send_eapol(wpa_auth, sm,
+			 WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+			 WPA_KEY_INFO_SMK_MESSAGE,
+			 NULL, kde->nonce, buf, pos - buf, 0, 1, 0);
+
+	os_free(buf);
+}
+
+
+void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
+		struct wpa_state_machine *sm, struct wpa_eapol_key *key)
+{
+	struct wpa_eapol_ie_parse kde;
+	struct wpa_stsl_search search;
+	u8 smk[32], buf[ETH_ALEN + 8 + 2 * WPA_NONCE_LEN], *pos;
+
+	if (wpa_parse_kde_ies((const u8 *) (key + 1),
+			      WPA_GET_BE16(key->key_data_length), &kde) < 0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK M3");
+		return;
+	}
+
+	if (kde.rsn_ie == NULL ||
+	    kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
+	    kde.nonce == NULL || kde.nonce_len < WPA_NONCE_LEN) {
+		wpa_printf(MSG_INFO, "RSN: No RSN IE, MAC address KDE, or "
+			   "Nonce KDE in SMK M3");
+		return;
+	}
+
+	/* Peer = sm->addr; Initiator = kde.mac_addr;
+	 * Peer Nonce = key->key_nonce; Initiator Nonce = kde.nonce */
+
+	search.addr = kde.mac_addr;
+	search.sm = NULL;
+	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
+	    0 || search.sm == NULL) {
+		wpa_printf(MSG_DEBUG, "RSN: SMK handshake with " MACSTR
+			   " aborted - STA not associated anymore",
+			   MAC2STR(kde.mac_addr));
+		wpa_smk_send_error(wpa_auth, sm, kde.mac_addr, STK_MUI_SMK,
+				   STK_ERR_STA_NR);
+		/* FIX: wpa_stsl_remove(wpa_auth, neg); */
+		return;
+	}
+
+	if (random_get_bytes(smk, PMK_LEN)) {
+		wpa_printf(MSG_DEBUG, "RSN: Failed to generate SMK");
+		return;
+	}
+
+	/* SMK = PRF-256(Random number, "SMK Derivation",
+	 *               AA || Time || INonce || PNonce)
+	 */
+	os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
+	pos = buf + ETH_ALEN;
+	wpa_get_ntp_timestamp(pos);
+	pos += 8;
+	os_memcpy(pos, kde.nonce, WPA_NONCE_LEN);
+	pos += WPA_NONCE_LEN;
+	os_memcpy(pos, key->key_nonce, WPA_NONCE_LEN);
+#ifdef CONFIG_IEEE80211W
+	sha256_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
+		   smk, PMK_LEN);
+#else /* CONFIG_IEEE80211W */
+	sha1_prf(smk, PMK_LEN, "SMK Derivation", buf, sizeof(buf),
+		 smk, PMK_LEN);
+#endif /* CONFIG_IEEE80211W */
+
+	wpa_hexdump_key(MSG_DEBUG, "RSN: SMK", smk, PMK_LEN);
+
+	wpa_send_smk_m4(wpa_auth, sm, key, &kde, smk);
+	wpa_send_smk_m5(wpa_auth, search.sm, key, &kde, smk, sm->addr);
+
+	/* Authenticator does not need SMK anymore and it is required to forget
+	 * it. */
+	os_memset(smk, 0, sizeof(*smk));
+}
+
+
+void wpa_smk_error(struct wpa_authenticator *wpa_auth,
+		   struct wpa_state_machine *sm, struct wpa_eapol_key *key)
+{
+	struct wpa_eapol_ie_parse kde;
+	struct wpa_stsl_search search;
+	struct rsn_error_kde error;
+	u16 mui, error_type;
+
+	if (wpa_parse_kde_ies((const u8 *) (key + 1),
+			      WPA_GET_BE16(key->key_data_length), &kde) < 0) {
+		wpa_printf(MSG_INFO, "RSN: Failed to parse KDEs in SMK Error");
+		return;
+	}
+
+	if (kde.mac_addr == NULL || kde.mac_addr_len < ETH_ALEN ||
+	    kde.error == NULL || kde.error_len < sizeof(error)) {
+		wpa_printf(MSG_INFO, "RSN: No MAC address or Error KDE in "
+			   "SMK Error");
+		return;
+	}
+
+	search.addr = kde.mac_addr;
+	search.sm = NULL;
+	if (wpa_auth_for_each_sta(wpa_auth, wpa_stsl_select_sta, &search) ==
+	    0 || search.sm == NULL) {
+		wpa_printf(MSG_DEBUG, "RSN: Peer STA " MACSTR " not "
+			   "associated for SMK Error message from " MACSTR,
+			   MAC2STR(kde.mac_addr), MAC2STR(sm->addr));
+		return;
+	}
+
+	os_memcpy(&error, kde.error, sizeof(error));
+	mui = be_to_host16(error.mui);
+	error_type = be_to_host16(error.error_type);
+	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+			 "STA reported SMK Error: Peer " MACSTR
+			 " MUI %d Error Type %d",
+			 MAC2STR(kde.mac_addr), mui, error_type);
+
+	wpa_smk_send_error(wpa_auth, search.sm, sm->addr, mui, error_type);
+}
+
+
+int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
+		    struct wpa_stsl_negotiation *neg)
+{
+	struct wpa_stsl_negotiation *pos, *prev;
+
+	if (wpa_auth == NULL)
+		return -1;
+	pos = wpa_auth->stsl_negotiations;
+	prev = NULL;
+	while (pos) {
+		if (pos == neg) {
+			if (prev)
+				prev->next = pos->next;
+			else
+				wpa_auth->stsl_negotiations = pos->next;
+
+			eloop_cancel_timeout(wpa_stsl_step, wpa_auth, pos);
+			os_free(pos);
+			return 0;
+		}
+		prev = pos;
+		pos = pos->next;
+	}
+
+	return -1;
+}
+
+#endif /* CONFIG_PEERKEY */
diff --git a/hostap/src/ap/pmksa_cache_auth.c b/hostap/src/ap/pmksa_cache_auth.c
new file mode 100644
index 0000000..d27fd30
--- /dev/null
+++ b/hostap/src/ap/pmksa_cache_auth.c
@@ -0,0 +1,430 @@
+/*
+ * hostapd - PMKSA cache for IEEE 802.11i RSN
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
+#include "sta_info.h"
+#include "ap_config.h"
+#include "pmksa_cache_auth.h"
+
+
+static const int pmksa_cache_max_entries = 1024;
+static const int dot11RSNAConfigPMKLifetime = 43200;
+
+struct rsn_pmksa_cache {
+#define PMKID_HASH_SIZE 128
+#define PMKID_HASH(pmkid) (unsigned int) ((pmkid)[0] & 0x7f)
+	struct rsn_pmksa_cache_entry *pmkid[PMKID_HASH_SIZE];
+	struct rsn_pmksa_cache_entry *pmksa;
+	int pmksa_count;
+
+	void (*free_cb)(struct rsn_pmksa_cache_entry *entry, void *ctx);
+	void *ctx;
+};
+
+
+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa);
+
+
+static void _pmksa_cache_free_entry(struct rsn_pmksa_cache_entry *entry)
+{
+	if (entry == NULL)
+		return;
+	os_free(entry->identity);
+	wpabuf_free(entry->cui);
+#ifndef CONFIG_NO_RADIUS
+	radius_free_class(&entry->radius_class);
+#endif /* CONFIG_NO_RADIUS */
+	os_free(entry);
+}
+
+
+static void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
+				   struct rsn_pmksa_cache_entry *entry)
+{
+	struct rsn_pmksa_cache_entry *pos, *prev;
+
+	pmksa->pmksa_count--;
+	pmksa->free_cb(entry, pmksa->ctx);
+	pos = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
+	prev = NULL;
+	while (pos) {
+		if (pos == entry) {
+			if (prev != NULL) {
+				prev->hnext = pos->hnext;
+			} else {
+				pmksa->pmkid[PMKID_HASH(entry->pmkid)] =
+					pos->hnext;
+			}
+			break;
+		}
+		prev = pos;
+		pos = pos->hnext;
+	}
+
+	pos = pmksa->pmksa;
+	prev = NULL;
+	while (pos) {
+		if (pos == entry) {
+			if (prev != NULL)
+				prev->next = pos->next;
+			else
+				pmksa->pmksa = pos->next;
+			break;
+		}
+		prev = pos;
+		pos = pos->next;
+	}
+	_pmksa_cache_free_entry(entry);
+}
+
+
+static void pmksa_cache_expire(void *eloop_ctx, void *timeout_ctx)
+{
+	struct rsn_pmksa_cache *pmksa = eloop_ctx;
+	struct os_time now;
+
+	os_get_time(&now);
+	while (pmksa->pmksa && pmksa->pmksa->expiration <= now.sec) {
+		wpa_printf(MSG_DEBUG, "RSN: expired PMKSA cache entry for "
+			   MACSTR, MAC2STR(pmksa->pmksa->spa));
+		pmksa_cache_free_entry(pmksa, pmksa->pmksa);
+	}
+
+	pmksa_cache_set_expiration(pmksa);
+}
+
+
+static void pmksa_cache_set_expiration(struct rsn_pmksa_cache *pmksa)
+{
+	int sec;
+	struct os_time now;
+
+	eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
+	if (pmksa->pmksa == NULL)
+		return;
+	os_get_time(&now);
+	sec = pmksa->pmksa->expiration - now.sec;
+	if (sec < 0)
+		sec = 0;
+	eloop_register_timeout(sec + 1, 0, pmksa_cache_expire, pmksa, NULL);
+}
+
+
+static void pmksa_cache_from_eapol_data(struct rsn_pmksa_cache_entry *entry,
+					struct eapol_state_machine *eapol)
+{
+	if (eapol == NULL)
+		return;
+
+	if (eapol->identity) {
+		entry->identity = os_malloc(eapol->identity_len);
+		if (entry->identity) {
+			entry->identity_len = eapol->identity_len;
+			os_memcpy(entry->identity, eapol->identity,
+				  eapol->identity_len);
+		}
+	}
+
+	if (eapol->radius_cui)
+		entry->cui = wpabuf_dup(eapol->radius_cui);
+
+#ifndef CONFIG_NO_RADIUS
+	radius_copy_class(&entry->radius_class, &eapol->radius_class);
+#endif /* CONFIG_NO_RADIUS */
+
+	entry->eap_type_authsrv = eapol->eap_type_authsrv;
+	entry->vlan_id = ((struct sta_info *) eapol->sta)->vlan_id;
+}
+
+
+void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
+			       struct eapol_state_machine *eapol)
+{
+	if (entry == NULL || eapol == NULL)
+		return;
+
+	if (entry->identity) {
+		os_free(eapol->identity);
+		eapol->identity = os_malloc(entry->identity_len);
+		if (eapol->identity) {
+			eapol->identity_len = entry->identity_len;
+			os_memcpy(eapol->identity, entry->identity,
+				  entry->identity_len);
+		}
+		wpa_hexdump_ascii(MSG_DEBUG, "STA identity from PMKSA",
+				  eapol->identity, eapol->identity_len);
+	}
+
+	if (entry->cui) {
+		wpabuf_free(eapol->radius_cui);
+		eapol->radius_cui = wpabuf_dup(entry->cui);
+	}
+
+#ifndef CONFIG_NO_RADIUS
+	radius_free_class(&eapol->radius_class);
+	radius_copy_class(&eapol->radius_class, &entry->radius_class);
+#endif /* CONFIG_NO_RADIUS */
+	if (eapol->radius_class.attr) {
+		wpa_printf(MSG_DEBUG, "Copied %lu Class attribute(s) from "
+			   "PMKSA", (unsigned long) eapol->radius_class.count);
+	}
+
+	eapol->eap_type_authsrv = entry->eap_type_authsrv;
+	((struct sta_info *) eapol->sta)->vlan_id = entry->vlan_id;
+}
+
+
+static void pmksa_cache_link_entry(struct rsn_pmksa_cache *pmksa,
+				   struct rsn_pmksa_cache_entry *entry)
+{
+	struct rsn_pmksa_cache_entry *pos, *prev;
+
+	/* Add the new entry; order by expiration time */
+	pos = pmksa->pmksa;
+	prev = NULL;
+	while (pos) {
+		if (pos->expiration > entry->expiration)
+			break;
+		prev = pos;
+		pos = pos->next;
+	}
+	if (prev == NULL) {
+		entry->next = pmksa->pmksa;
+		pmksa->pmksa = entry;
+	} else {
+		entry->next = prev->next;
+		prev->next = entry;
+	}
+	entry->hnext = pmksa->pmkid[PMKID_HASH(entry->pmkid)];
+	pmksa->pmkid[PMKID_HASH(entry->pmkid)] = entry;
+
+	pmksa->pmksa_count++;
+	if (prev == NULL)
+		pmksa_cache_set_expiration(pmksa);
+	wpa_printf(MSG_DEBUG, "RSN: added PMKSA cache entry for " MACSTR,
+		   MAC2STR(entry->spa));
+	wpa_hexdump(MSG_DEBUG, "RSN: added PMKID", entry->pmkid, PMKID_LEN);
+}
+
+
+/**
+ * pmksa_cache_auth_add - Add a PMKSA cache entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ * @pmk: The new pairwise master key
+ * @pmk_len: PMK length in bytes, usually PMK_LEN (32)
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @session_timeout: Session timeout
+ * @eapol: Pointer to EAPOL state machine data
+ * @akmp: WPA_KEY_MGMT_* used in key derivation
+ * Returns: Pointer to the added PMKSA cache entry or %NULL on error
+ *
+ * This function create a PMKSA entry for a new PMK and adds it to the PMKSA
+ * cache. If an old entry is already in the cache for the same Supplicant,
+ * this entry will be replaced with the new entry. PMKID will be calculated
+ * based on the PMK.
+ */
+struct rsn_pmksa_cache_entry *
+pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
+		     const u8 *pmk, size_t pmk_len,
+		const u8 *aa, const u8 *spa, int session_timeout,
+		struct eapol_state_machine *eapol, int akmp)
+{
+	struct rsn_pmksa_cache_entry *entry, *pos;
+	struct os_time now;
+
+	if (pmk_len > PMK_LEN)
+		return NULL;
+
+	entry = os_zalloc(sizeof(*entry));
+	if (entry == NULL)
+		return NULL;
+	os_memcpy(entry->pmk, pmk, pmk_len);
+	entry->pmk_len = pmk_len;
+	rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
+		  wpa_key_mgmt_sha256(akmp));
+	os_get_time(&now);
+	entry->expiration = now.sec;
+	if (session_timeout > 0)
+		entry->expiration += session_timeout;
+	else
+		entry->expiration += dot11RSNAConfigPMKLifetime;
+	entry->akmp = akmp;
+	os_memcpy(entry->spa, spa, ETH_ALEN);
+	pmksa_cache_from_eapol_data(entry, eapol);
+
+	/* Replace an old entry for the same STA (if found) with the new entry
+	 */
+	pos = pmksa_cache_auth_get(pmksa, spa, NULL);
+	if (pos)
+		pmksa_cache_free_entry(pmksa, pos);
+
+	if (pmksa->pmksa_count >= pmksa_cache_max_entries && pmksa->pmksa) {
+		/* Remove the oldest entry to make room for the new entry */
+		wpa_printf(MSG_DEBUG, "RSN: removed the oldest PMKSA cache "
+			   "entry (for " MACSTR ") to make room for new one",
+			   MAC2STR(pmksa->pmksa->spa));
+		pmksa_cache_free_entry(pmksa, pmksa->pmksa);
+	}
+
+	pmksa_cache_link_entry(pmksa, entry);
+
+	return entry;
+}
+
+
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
+		    const struct rsn_pmksa_cache_entry *old_entry,
+		    const u8 *aa, const u8 *pmkid)
+{
+	struct rsn_pmksa_cache_entry *entry;
+
+	entry = os_zalloc(sizeof(*entry));
+	if (entry == NULL)
+		return NULL;
+	os_memcpy(entry->pmkid, pmkid, PMKID_LEN);
+	os_memcpy(entry->pmk, old_entry->pmk, old_entry->pmk_len);
+	entry->pmk_len = old_entry->pmk_len;
+	entry->expiration = old_entry->expiration;
+	entry->akmp = old_entry->akmp;
+	os_memcpy(entry->spa, old_entry->spa, ETH_ALEN);
+	entry->opportunistic = 1;
+	if (old_entry->identity) {
+		entry->identity = os_malloc(old_entry->identity_len);
+		if (entry->identity) {
+			entry->identity_len = old_entry->identity_len;
+			os_memcpy(entry->identity, old_entry->identity,
+				  old_entry->identity_len);
+		}
+	}
+	if (old_entry->cui)
+		entry->cui = wpabuf_dup(old_entry->cui);
+#ifndef CONFIG_NO_RADIUS
+	radius_copy_class(&entry->radius_class, &old_entry->radius_class);
+#endif /* CONFIG_NO_RADIUS */
+	entry->eap_type_authsrv = old_entry->eap_type_authsrv;
+	entry->vlan_id = old_entry->vlan_id;
+	entry->opportunistic = 1;
+
+	pmksa_cache_link_entry(pmksa, entry);
+
+	return entry;
+}
+
+
+/**
+ * pmksa_cache_auth_deinit - Free all entries in PMKSA cache
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ */
+void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa)
+{
+	struct rsn_pmksa_cache_entry *entry, *prev;
+	int i;
+
+	if (pmksa == NULL)
+		return;
+
+	entry = pmksa->pmksa;
+	while (entry) {
+		prev = entry;
+		entry = entry->next;
+		_pmksa_cache_free_entry(prev);
+	}
+	eloop_cancel_timeout(pmksa_cache_expire, pmksa, NULL);
+	for (i = 0; i < PMKID_HASH_SIZE; i++)
+		pmksa->pmkid[i] = NULL;
+	os_free(pmksa);
+}
+
+
+/**
+ * pmksa_cache_auth_get - Fetch a PMKSA cache entry
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ * @spa: Supplicant address or %NULL to match any
+ * @pmkid: PMKID or %NULL to match any
+ * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
+ */
+struct rsn_pmksa_cache_entry *
+pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
+		     const u8 *spa, const u8 *pmkid)
+{
+	struct rsn_pmksa_cache_entry *entry;
+
+	if (pmkid)
+		entry = pmksa->pmkid[PMKID_HASH(pmkid)];
+	else
+		entry = pmksa->pmksa;
+	while (entry) {
+		if ((spa == NULL ||
+		     os_memcmp(entry->spa, spa, ETH_ALEN) == 0) &&
+		    (pmkid == NULL ||
+		     os_memcmp(entry->pmkid, pmkid, PMKID_LEN) == 0))
+			return entry;
+		entry = pmkid ? entry->hnext : entry->next;
+	}
+	return NULL;
+}
+
+
+/**
+ * pmksa_cache_get_okc - Fetch a PMKSA cache entry using OKC
+ * @pmksa: Pointer to PMKSA cache data from pmksa_cache_auth_init()
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @pmkid: PMKID
+ * Returns: Pointer to PMKSA cache entry or %NULL if no match was found
+ *
+ * Use opportunistic key caching (OKC) to find a PMK for a supplicant.
+ */
+struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
+	struct rsn_pmksa_cache *pmksa, const u8 *aa, const u8 *spa,
+	const u8 *pmkid)
+{
+	struct rsn_pmksa_cache_entry *entry;
+	u8 new_pmkid[PMKID_LEN];
+
+	entry = pmksa->pmksa;
+	while (entry) {
+		if (os_memcmp(entry->spa, spa, ETH_ALEN) != 0)
+			continue;
+		rsn_pmkid(entry->pmk, entry->pmk_len, aa, spa, new_pmkid,
+			  wpa_key_mgmt_sha256(entry->akmp));
+		if (os_memcmp(new_pmkid, pmkid, PMKID_LEN) == 0)
+			return entry;
+		entry = entry->next;
+	}
+	return NULL;
+}
+
+
+/**
+ * pmksa_cache_auth_init - Initialize PMKSA cache
+ * @free_cb: Callback function to be called when a PMKSA cache entry is freed
+ * @ctx: Context pointer for free_cb function
+ * Returns: Pointer to PMKSA cache data or %NULL on failure
+ */
+struct rsn_pmksa_cache *
+pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+				      void *ctx), void *ctx)
+{
+	struct rsn_pmksa_cache *pmksa;
+
+	pmksa = os_zalloc(sizeof(*pmksa));
+	if (pmksa) {
+		pmksa->free_cb = free_cb;
+		pmksa->ctx = ctx;
+	}
+
+	return pmksa;
+}
diff --git a/hostap/src/ap/pmksa_cache_auth.h b/hostap/src/ap/pmksa_cache_auth.h
new file mode 100644
index 0000000..d473f3f
--- /dev/null
+++ b/hostap/src/ap/pmksa_cache_auth.h
@@ -0,0 +1,59 @@
+/*
+ * hostapd - PMKSA cache for IEEE 802.11i RSN
+ * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PMKSA_CACHE_H
+#define PMKSA_CACHE_H
+
+#include "radius/radius.h"
+
+/**
+ * struct rsn_pmksa_cache_entry - PMKSA cache entry
+ */
+struct rsn_pmksa_cache_entry {
+	struct rsn_pmksa_cache_entry *next, *hnext;
+	u8 pmkid[PMKID_LEN];
+	u8 pmk[PMK_LEN];
+	size_t pmk_len;
+	os_time_t expiration;
+	int akmp; /* WPA_KEY_MGMT_* */
+	u8 spa[ETH_ALEN];
+
+	u8 *identity;
+	size_t identity_len;
+	struct wpabuf *cui;
+	struct radius_class_data radius_class;
+	u8 eap_type_authsrv;
+	int vlan_id;
+	int opportunistic;
+};
+
+struct rsn_pmksa_cache;
+
+struct rsn_pmksa_cache *
+pmksa_cache_auth_init(void (*free_cb)(struct rsn_pmksa_cache_entry *entry,
+				      void *ctx), void *ctx);
+void pmksa_cache_auth_deinit(struct rsn_pmksa_cache *pmksa);
+struct rsn_pmksa_cache_entry *
+pmksa_cache_auth_get(struct rsn_pmksa_cache *pmksa,
+		     const u8 *spa, const u8 *pmkid);
+struct rsn_pmksa_cache_entry * pmksa_cache_get_okc(
+	struct rsn_pmksa_cache *pmksa, const u8 *spa, const u8 *aa,
+	const u8 *pmkid);
+struct rsn_pmksa_cache_entry *
+pmksa_cache_auth_add(struct rsn_pmksa_cache *pmksa,
+		     const u8 *pmk, size_t pmk_len,
+		     const u8 *aa, const u8 *spa, int session_timeout,
+		     struct eapol_state_machine *eapol, int akmp);
+struct rsn_pmksa_cache_entry *
+pmksa_cache_add_okc(struct rsn_pmksa_cache *pmksa,
+		    const struct rsn_pmksa_cache_entry *old_entry,
+		    const u8 *aa, const u8 *pmkid);
+void pmksa_cache_to_eapol_data(struct rsn_pmksa_cache_entry *entry,
+			       struct eapol_state_machine *eapol);
+
+#endif /* PMKSA_CACHE_H */
diff --git a/hostap/src/ap/preauth_auth.c b/hostap/src/ap/preauth_auth.c
new file mode 100644
index 0000000..3e0c800
--- /dev/null
+++ b/hostap/src/ap/preauth_auth.c
@@ -0,0 +1,273 @@
+/*
+ * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#ifdef CONFIG_RSN_PREAUTH
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "l2_packet/l2_packet.h"
+#include "common/wpa_common.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ieee802_1x.h"
+#include "sta_info.h"
+#include "wpa_auth.h"
+#include "preauth_auth.h"
+
+#ifndef ETH_P_PREAUTH
+#define ETH_P_PREAUTH 0x88C7 /* IEEE 802.11i pre-authentication */
+#endif /* ETH_P_PREAUTH */
+
+static const int dot11RSNAConfigPMKLifetime = 43200;
+
+struct rsn_preauth_interface {
+	struct rsn_preauth_interface *next;
+	struct hostapd_data *hapd;
+	struct l2_packet_data *l2;
+	char *ifname;
+	int ifindex;
+};
+
+
+static void rsn_preauth_receive(void *ctx, const u8 *src_addr,
+				const u8 *buf, size_t len)
+{
+	struct rsn_preauth_interface *piface = ctx;
+	struct hostapd_data *hapd = piface->hapd;
+	struct ieee802_1x_hdr *hdr;
+	struct sta_info *sta;
+	struct l2_ethhdr *ethhdr;
+
+	wpa_printf(MSG_DEBUG, "RSN: receive pre-auth packet "
+		   "from interface '%s'", piface->ifname);
+	if (len < sizeof(*ethhdr) + sizeof(*hdr)) {
+		wpa_printf(MSG_DEBUG, "RSN: too short pre-auth packet "
+			   "(len=%lu)", (unsigned long) len);
+		return;
+	}
+
+	ethhdr = (struct l2_ethhdr *) buf;
+	hdr = (struct ieee802_1x_hdr *) (ethhdr + 1);
+
+	if (os_memcmp(ethhdr->h_dest, hapd->own_addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "RSN: pre-auth for foreign address "
+			   MACSTR, MAC2STR(ethhdr->h_dest));
+		return;
+	}
+
+	sta = ap_get_sta(hapd, ethhdr->h_source);
+	if (sta && (sta->flags & WLAN_STA_ASSOC)) {
+		wpa_printf(MSG_DEBUG, "RSN: pre-auth for already association "
+			   "STA " MACSTR, MAC2STR(sta->addr));
+		return;
+	}
+	if (!sta && hdr->type == IEEE802_1X_TYPE_EAPOL_START) {
+		sta = ap_sta_add(hapd, ethhdr->h_source);
+		if (sta == NULL)
+			return;
+		sta->flags = WLAN_STA_PREAUTH;
+
+		ieee802_1x_new_station(hapd, sta);
+		if (sta->eapol_sm == NULL) {
+			ap_free_sta(hapd, sta);
+			sta = NULL;
+		} else {
+			sta->eapol_sm->radius_identifier = -1;
+			sta->eapol_sm->portValid = TRUE;
+			sta->eapol_sm->flags |= EAPOL_SM_PREAUTH;
+		}
+	}
+	if (sta == NULL)
+		return;
+	sta->preauth_iface = piface;
+	ieee802_1x_receive(hapd, ethhdr->h_source, (u8 *) (ethhdr + 1),
+			   len - sizeof(*ethhdr));
+}
+
+
+static int rsn_preauth_iface_add(struct hostapd_data *hapd, const char *ifname)
+{
+	struct rsn_preauth_interface *piface;
+
+	wpa_printf(MSG_DEBUG, "RSN pre-auth interface '%s'", ifname);
+
+	piface = os_zalloc(sizeof(*piface));
+	if (piface == NULL)
+		return -1;
+	piface->hapd = hapd;
+
+	piface->ifname = os_strdup(ifname);
+	if (piface->ifname == NULL) {
+		goto fail1;
+	}
+
+	piface->l2 = l2_packet_init(piface->ifname, NULL, ETH_P_PREAUTH,
+				    rsn_preauth_receive, piface, 1);
+	if (piface->l2 == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to open register layer 2 access "
+			   "to ETH_P_PREAUTH");
+		goto fail2;
+	}
+
+	piface->next = hapd->preauth_iface;
+	hapd->preauth_iface = piface;
+	return 0;
+
+fail2:
+	os_free(piface->ifname);
+fail1:
+	os_free(piface);
+	return -1;
+}
+
+
+void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
+{
+	struct rsn_preauth_interface *piface, *prev;
+
+	piface = hapd->preauth_iface;
+	hapd->preauth_iface = NULL;
+	while (piface) {
+		prev = piface;
+		piface = piface->next;
+		l2_packet_deinit(prev->l2);
+		os_free(prev->ifname);
+		os_free(prev);
+	}
+}
+
+
+int rsn_preauth_iface_init(struct hostapd_data *hapd)
+{
+	char *tmp, *start, *end;
+
+	if (hapd->conf->rsn_preauth_interfaces == NULL)
+		return 0;
+
+	tmp = os_strdup(hapd->conf->rsn_preauth_interfaces);
+	if (tmp == NULL)
+		return -1;
+	start = tmp;
+	for (;;) {
+		while (*start == ' ')
+			start++;
+		if (*start == '\0')
+			break;
+		end = os_strchr(start, ' ');
+		if (end)
+			*end = '\0';
+
+		if (rsn_preauth_iface_add(hapd, start)) {
+			rsn_preauth_iface_deinit(hapd);
+			os_free(tmp);
+			return -1;
+		}
+
+		if (end)
+			start = end + 1;
+		else
+			break;
+	}
+	os_free(tmp);
+	return 0;
+}
+
+
+static void rsn_preauth_finished_cb(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+	wpa_printf(MSG_DEBUG, "RSN: Removing pre-authentication STA entry for "
+		   MACSTR, MAC2STR(sta->addr));
+	ap_free_sta(hapd, sta);
+}
+
+
+void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
+			  int success)
+{
+	const u8 *key;
+	size_t len;
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+		       HOSTAPD_LEVEL_INFO, "pre-authentication %s",
+		       success ? "succeeded" : "failed");
+
+	key = ieee802_1x_get_key(sta->eapol_sm, &len);
+	if (len > PMK_LEN)
+		len = PMK_LEN;
+	if (success && key) {
+		if (wpa_auth_pmksa_add_preauth(hapd->wpa_auth, key, len,
+					       sta->addr,
+					       dot11RSNAConfigPMKLifetime,
+					       sta->eapol_sm) == 0) {
+			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "added PMKSA cache entry (pre-auth)");
+		} else {
+			hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_WPA,
+				       HOSTAPD_LEVEL_DEBUG,
+				       "failed to add PMKSA cache entry "
+				       "(pre-auth)");
+		}
+	}
+
+	/*
+	 * Finish STA entry removal from timeout in order to avoid freeing
+	 * STA data before the caller has finished processing.
+	 */
+	eloop_register_timeout(0, 0, rsn_preauth_finished_cb, hapd, sta);
+}
+
+
+void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
+		      u8 *buf, size_t len)
+{
+	struct rsn_preauth_interface *piface;
+	struct l2_ethhdr *ethhdr;
+
+	piface = hapd->preauth_iface;
+	while (piface) {
+		if (piface == sta->preauth_iface)
+			break;
+		piface = piface->next;
+	}
+
+	if (piface == NULL) {
+		wpa_printf(MSG_DEBUG, "RSN: Could not find pre-authentication "
+			   "interface for " MACSTR, MAC2STR(sta->addr));
+		return;
+	}
+
+	ethhdr = os_malloc(sizeof(*ethhdr) + len);
+	if (ethhdr == NULL)
+		return;
+
+	os_memcpy(ethhdr->h_dest, sta->addr, ETH_ALEN);
+	os_memcpy(ethhdr->h_source, hapd->own_addr, ETH_ALEN);
+	ethhdr->h_proto = host_to_be16(ETH_P_PREAUTH);
+	os_memcpy(ethhdr + 1, buf, len);
+
+	if (l2_packet_send(piface->l2, sta->addr, ETH_P_PREAUTH, (u8 *) ethhdr,
+			   sizeof(*ethhdr) + len) < 0) {
+		wpa_printf(MSG_ERROR, "Failed to send preauth packet using "
+			   "l2_packet_send\n");
+	}
+	os_free(ethhdr);
+}
+
+
+void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	eloop_cancel_timeout(rsn_preauth_finished_cb, hapd, sta);
+}
+
+#endif /* CONFIG_RSN_PREAUTH */
diff --git a/hostap/src/ap/preauth_auth.h b/hostap/src/ap/preauth_auth.h
new file mode 100644
index 0000000..69fb356
--- /dev/null
+++ b/hostap/src/ap/preauth_auth.h
@@ -0,0 +1,52 @@
+/*
+ * hostapd - Authenticator for IEEE 802.11i RSN pre-authentication
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PREAUTH_H
+#define PREAUTH_H
+
+#ifdef CONFIG_RSN_PREAUTH
+
+int rsn_preauth_iface_init(struct hostapd_data *hapd);
+void rsn_preauth_iface_deinit(struct hostapd_data *hapd);
+void rsn_preauth_finished(struct hostapd_data *hapd, struct sta_info *sta,
+			  int success);
+void rsn_preauth_send(struct hostapd_data *hapd, struct sta_info *sta,
+		      u8 *buf, size_t len);
+void rsn_preauth_free_station(struct hostapd_data *hapd, struct sta_info *sta);
+
+#else /* CONFIG_RSN_PREAUTH */
+
+static inline int rsn_preauth_iface_init(struct hostapd_data *hapd)
+{
+	return 0;
+}
+
+static inline void rsn_preauth_iface_deinit(struct hostapd_data *hapd)
+{
+}
+
+static inline void rsn_preauth_finished(struct hostapd_data *hapd,
+					struct sta_info *sta,
+					int success)
+{
+}
+
+static inline void rsn_preauth_send(struct hostapd_data *hapd,
+				    struct sta_info *sta,
+				    u8 *buf, size_t len)
+{
+}
+
+static inline void rsn_preauth_free_station(struct hostapd_data *hapd,
+					    struct sta_info *sta)
+{
+}
+
+#endif /* CONFIG_RSN_PREAUTH */
+
+#endif /* PREAUTH_H */
diff --git a/hostap/src/ap/sta_info.c b/hostap/src/ap/sta_info.c
new file mode 100644
index 0000000..97cd013
--- /dev/null
+++ b/hostap/src/ap/sta_info.c
@@ -0,0 +1,971 @@
+/*
+ * hostapd / Station table
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "common/wpa_ctrl.h"
+#include "radius/radius.h"
+#include "radius/radius_client.h"
+#include "drivers/driver.h"
+#include "p2p/p2p.h"
+#include "hostapd.h"
+#include "accounting.h"
+#include "ieee802_1x.h"
+#include "ieee802_11.h"
+#include "ieee802_11_auth.h"
+#include "wpa_auth.h"
+#include "preauth_auth.h"
+#include "ap_config.h"
+#include "beacon.h"
+#include "ap_mlme.h"
+#include "vlan_init.h"
+#include "p2p_hostapd.h"
+#include "ap_drv_ops.h"
+#include "gas_serv.h"
+#include "sta_info.h"
+
+static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
+				       struct sta_info *sta);
+static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx);
+static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx);
+static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx);
+#ifdef CONFIG_IEEE80211W
+static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx);
+#endif /* CONFIG_IEEE80211W */
+static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta);
+
+int ap_for_each_sta(struct hostapd_data *hapd,
+		    int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
+			      void *ctx),
+		    void *ctx)
+{
+	struct sta_info *sta;
+
+	for (sta = hapd->sta_list; sta; sta = sta->next) {
+		if (cb(hapd, sta, ctx))
+			return 1;
+	}
+
+	return 0;
+}
+
+
+struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta)
+{
+	struct sta_info *s;
+
+	s = hapd->sta_hash[STA_HASH(sta)];
+	while (s != NULL && os_memcmp(s->addr, sta, 6) != 0)
+		s = s->hnext;
+	return s;
+}
+
+
+static void ap_sta_list_del(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	struct sta_info *tmp;
+
+	if (hapd->sta_list == sta) {
+		hapd->sta_list = sta->next;
+		return;
+	}
+
+	tmp = hapd->sta_list;
+	while (tmp != NULL && tmp->next != sta)
+		tmp = tmp->next;
+	if (tmp == NULL) {
+		wpa_printf(MSG_DEBUG, "Could not remove STA " MACSTR " from "
+			   "list.", MAC2STR(sta->addr));
+	} else
+		tmp->next = sta->next;
+}
+
+
+void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	sta->hnext = hapd->sta_hash[STA_HASH(sta->addr)];
+	hapd->sta_hash[STA_HASH(sta->addr)] = sta;
+}
+
+
+static void ap_sta_hash_del(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	struct sta_info *s;
+
+	s = hapd->sta_hash[STA_HASH(sta->addr)];
+	if (s == NULL) return;
+	if (os_memcmp(s->addr, sta->addr, 6) == 0) {
+		hapd->sta_hash[STA_HASH(sta->addr)] = s->hnext;
+		return;
+	}
+
+	while (s->hnext != NULL &&
+	       os_memcmp(s->hnext->addr, sta->addr, ETH_ALEN) != 0)
+		s = s->hnext;
+	if (s->hnext != NULL)
+		s->hnext = s->hnext->hnext;
+	else
+		wpa_printf(MSG_DEBUG, "AP: could not remove STA " MACSTR
+			   " from hash table", MAC2STR(sta->addr));
+}
+
+
+void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	int set_beacon = 0;
+
+	accounting_sta_stop(hapd, sta);
+
+	/* just in case */
+	ap_sta_set_authorized(hapd, sta, 0);
+
+	if (sta->flags & WLAN_STA_WDS)
+		hostapd_set_wds_sta(hapd, sta->addr, sta->aid, 0);
+
+	if (!(sta->flags & WLAN_STA_PREAUTH))
+		hostapd_drv_sta_remove(hapd, sta->addr);
+
+	ap_sta_hash_del(hapd, sta);
+	ap_sta_list_del(hapd, sta);
+
+	if (sta->aid > 0)
+		hapd->sta_aid[(sta->aid - 1) / 32] &=
+			~BIT((sta->aid - 1) % 32);
+
+	hapd->num_sta--;
+	if (sta->nonerp_set) {
+		sta->nonerp_set = 0;
+		hapd->iface->num_sta_non_erp--;
+		if (hapd->iface->num_sta_non_erp == 0)
+			set_beacon++;
+	}
+
+	if (sta->no_short_slot_time_set) {
+		sta->no_short_slot_time_set = 0;
+		hapd->iface->num_sta_no_short_slot_time--;
+		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+		    && hapd->iface->num_sta_no_short_slot_time == 0)
+			set_beacon++;
+	}
+
+	if (sta->no_short_preamble_set) {
+		sta->no_short_preamble_set = 0;
+		hapd->iface->num_sta_no_short_preamble--;
+		if (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G
+		    && hapd->iface->num_sta_no_short_preamble == 0)
+			set_beacon++;
+	}
+
+	if (sta->no_ht_gf_set) {
+		sta->no_ht_gf_set = 0;
+		hapd->iface->num_sta_ht_no_gf--;
+	}
+
+	if (sta->no_ht_set) {
+		sta->no_ht_set = 0;
+		hapd->iface->num_sta_no_ht--;
+	}
+
+	if (sta->ht_20mhz_set) {
+		sta->ht_20mhz_set = 0;
+		hapd->iface->num_sta_ht_20mhz--;
+	}
+
+#ifdef CONFIG_P2P
+	if (sta->no_p2p_set) {
+		sta->no_p2p_set = 0;
+		hapd->num_sta_no_p2p--;
+		if (hapd->num_sta_no_p2p == 0)
+			hostapd_p2p_non_p2p_sta_disconnected(hapd);
+	}
+#endif /* CONFIG_P2P */
+
+#if defined(NEED_AP_MLME) && defined(CONFIG_IEEE80211N)
+	if (hostapd_ht_operation_update(hapd->iface) > 0)
+		set_beacon++;
+#endif /* NEED_AP_MLME && CONFIG_IEEE80211N */
+
+	if (set_beacon)
+		ieee802_11_set_beacons(hapd->iface);
+
+	wpa_printf(MSG_DEBUG, "%s: cancel ap_handle_timer for " MACSTR,
+		   __func__, MAC2STR(sta->addr));
+	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
+	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+
+	ieee802_1x_free_station(sta);
+	wpa_auth_sta_deinit(sta->wpa_sm);
+	rsn_preauth_free_station(hapd, sta);
+#ifndef CONFIG_NO_RADIUS
+	radius_client_flush_auth(hapd->radius, sta->addr);
+#endif /* CONFIG_NO_RADIUS */
+
+	os_free(sta->last_assoc_req);
+	os_free(sta->challenge);
+
+#ifdef CONFIG_IEEE80211W
+	os_free(sta->sa_query_trans_id);
+	eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_P2P
+	p2p_group_notif_disassoc(hapd->p2p_group, sta->addr);
+#endif /* CONFIG_P2P */
+
+#ifdef CONFIG_INTERWORKING
+	if (sta->gas_dialog) {
+		int i;
+		for (i = 0; i < GAS_DIALOG_MAX; i++)
+			gas_serv_dialog_clear(&sta->gas_dialog[i]);
+		os_free(sta->gas_dialog);
+	}
+#endif /* CONFIG_INTERWORKING */
+
+	wpabuf_free(sta->wps_ie);
+	wpabuf_free(sta->p2p_ie);
+	wpabuf_free(sta->hs20_ie);
+
+	os_free(sta->ht_capabilities);
+	hostapd_free_psk_list(sta->psk);
+	os_free(sta->identity);
+	os_free(sta->radius_cui);
+
+	os_free(sta);
+}
+
+
+void hostapd_free_stas(struct hostapd_data *hapd)
+{
+	struct sta_info *sta, *prev;
+
+	sta = hapd->sta_list;
+
+	while (sta) {
+		prev = sta;
+		if (sta->flags & WLAN_STA_AUTH) {
+			mlme_deauthenticate_indication(
+				hapd, sta, WLAN_REASON_UNSPECIFIED);
+		}
+		sta = sta->next;
+		wpa_printf(MSG_DEBUG, "Removing station " MACSTR,
+			   MAC2STR(prev->addr));
+		ap_free_sta(hapd, prev);
+	}
+}
+
+
+/**
+ * ap_handle_timer - Per STA timer handler
+ * @eloop_ctx: struct hostapd_data *
+ * @timeout_ctx: struct sta_info *
+ *
+ * This function is called to check station activity and to remove inactive
+ * stations.
+ */
+void ap_handle_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+	unsigned long next_time = 0;
+
+	wpa_printf(MSG_DEBUG, "%s: " MACSTR " flags=0x%x timeout_next=%d",
+		   __func__, MAC2STR(sta->addr), sta->flags,
+		   sta->timeout_next);
+	if (sta->timeout_next == STA_REMOVE) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
+			       "local deauth request");
+		ap_free_sta(hapd, sta);
+		return;
+	}
+
+	if ((sta->flags & WLAN_STA_ASSOC) &&
+	    (sta->timeout_next == STA_NULLFUNC ||
+	     sta->timeout_next == STA_DISASSOC)) {
+		int inactive_sec;
+		/*
+		 * Add random value to timeout so that we don't end up bouncing
+		 * all stations at the same time if we have lots of associated
+		 * stations that are idle (but keep re-associating).
+		 */
+		int fuzz = os_random() % 20;
+		inactive_sec = hostapd_drv_get_inact_sec(hapd, sta->addr);
+		if (inactive_sec == -1) {
+			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+				"Check inactivity: Could not "
+				"get station info from kernel driver for "
+				MACSTR, MAC2STR(sta->addr));
+			/*
+			 * The driver may not support this functionality.
+			 * Anyway, try again after the next inactivity timeout,
+			 * but do not disconnect the station now.
+			 */
+			next_time = hapd->conf->ap_max_inactivity + fuzz;
+		} else if (inactive_sec < hapd->conf->ap_max_inactivity &&
+			   sta->flags & WLAN_STA_ASSOC) {
+			/* station activity detected; reset timeout state */
+			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+				"Station " MACSTR " has been active %is ago",
+				MAC2STR(sta->addr), inactive_sec);
+			sta->timeout_next = STA_NULLFUNC;
+			next_time = hapd->conf->ap_max_inactivity + fuzz -
+				inactive_sec;
+		} else {
+			wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+				"Station " MACSTR " has been "
+				"inactive too long: %d sec, max allowed: %d",
+				MAC2STR(sta->addr), inactive_sec,
+				hapd->conf->ap_max_inactivity);
+
+			if (hapd->conf->skip_inactivity_poll)
+				sta->timeout_next = STA_DISASSOC;
+		}
+	}
+
+	if ((sta->flags & WLAN_STA_ASSOC) &&
+	    sta->timeout_next == STA_DISASSOC &&
+	    !(sta->flags & WLAN_STA_PENDING_POLL) &&
+	    !hapd->conf->skip_inactivity_poll) {
+		wpa_msg(hapd->msg_ctx, MSG_DEBUG, "Station " MACSTR
+			" has ACKed data poll", MAC2STR(sta->addr));
+		/* data nullfunc frame poll did not produce TX errors; assume
+		 * station ACKed it */
+		sta->timeout_next = STA_NULLFUNC;
+		next_time = hapd->conf->ap_max_inactivity;
+	}
+
+	if (next_time) {
+		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+			   "for " MACSTR " (%lu seconds)",
+			   __func__, MAC2STR(sta->addr), next_time);
+		eloop_register_timeout(next_time, 0, ap_handle_timer, hapd,
+				       sta);
+		return;
+	}
+
+	if (sta->timeout_next == STA_NULLFUNC &&
+	    (sta->flags & WLAN_STA_ASSOC)) {
+		wpa_printf(MSG_DEBUG, "  Polling STA");
+		sta->flags |= WLAN_STA_PENDING_POLL;
+		hostapd_drv_poll_client(hapd, hapd->own_addr, sta->addr,
+					sta->flags & WLAN_STA_WMM);
+	} else if (sta->timeout_next != STA_REMOVE) {
+		int deauth = sta->timeout_next == STA_DEAUTH;
+
+		wpa_dbg(hapd->msg_ctx, MSG_DEBUG,
+			"Timeout, sending %s info to STA " MACSTR,
+			deauth ? "deauthentication" : "disassociation",
+			MAC2STR(sta->addr));
+
+		if (deauth) {
+			hostapd_drv_sta_deauth(
+				hapd, sta->addr,
+				WLAN_REASON_PREV_AUTH_NOT_VALID);
+		} else {
+			hostapd_drv_sta_disassoc(
+				hapd, sta->addr,
+				WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
+		}
+	}
+
+	switch (sta->timeout_next) {
+	case STA_NULLFUNC:
+		sta->timeout_next = STA_DISASSOC;
+		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+			   "for " MACSTR " (%d seconds - AP_DISASSOC_DELAY)",
+			   __func__, MAC2STR(sta->addr), AP_DISASSOC_DELAY);
+		eloop_register_timeout(AP_DISASSOC_DELAY, 0, ap_handle_timer,
+				       hapd, sta);
+		break;
+	case STA_DISASSOC:
+		ap_sta_set_authorized(hapd, sta, 0);
+		sta->flags &= ~WLAN_STA_ASSOC;
+		ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+		if (!sta->acct_terminate_cause)
+			sta->acct_terminate_cause =
+				RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
+		accounting_sta_stop(hapd, sta);
+		ieee802_1x_free_station(sta);
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "disassociated due to "
+			       "inactivity");
+		sta->timeout_next = STA_DEAUTH;
+		wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+			   "for " MACSTR " (%d seconds - AP_DEAUTH_DELAY)",
+			   __func__, MAC2STR(sta->addr), AP_DEAUTH_DELAY);
+		eloop_register_timeout(AP_DEAUTH_DELAY, 0, ap_handle_timer,
+				       hapd, sta);
+		mlme_disassociate_indication(
+			hapd, sta, WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY);
+		break;
+	case STA_DEAUTH:
+	case STA_REMOVE:
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
+			       "inactivity (timer DEAUTH/REMOVE)");
+		if (!sta->acct_terminate_cause)
+			sta->acct_terminate_cause =
+				RADIUS_ACCT_TERMINATE_CAUSE_IDLE_TIMEOUT;
+		mlme_deauthenticate_indication(
+			hapd, sta,
+			WLAN_REASON_PREV_AUTH_NOT_VALID);
+		ap_free_sta(hapd, sta);
+		break;
+	}
+}
+
+
+static void ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+	u8 addr[ETH_ALEN];
+
+	if (!(sta->flags & WLAN_STA_AUTH)) {
+		if (sta->flags & WLAN_STA_GAS) {
+			wpa_printf(MSG_DEBUG, "GAS: Remove temporary STA "
+				   "entry " MACSTR, MAC2STR(sta->addr));
+			ap_free_sta(hapd, sta);
+		}
+		return;
+	}
+
+	mlme_deauthenticate_indication(hapd, sta,
+				       WLAN_REASON_PREV_AUTH_NOT_VALID);
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "deauthenticated due to "
+		       "session timeout");
+	sta->acct_terminate_cause =
+		RADIUS_ACCT_TERMINATE_CAUSE_SESSION_TIMEOUT;
+	os_memcpy(addr, sta->addr, ETH_ALEN);
+	ap_free_sta(hapd, sta);
+	hostapd_drv_sta_deauth(hapd, addr, WLAN_REASON_PREV_AUTH_NOT_VALID);
+}
+
+
+void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
+			    u32 session_timeout)
+{
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG, "setting session timeout to %d "
+		       "seconds", session_timeout);
+	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
+	eloop_register_timeout(session_timeout, 0, ap_handle_session_timer,
+			       hapd, sta);
+}
+
+
+void ap_sta_no_session_timeout(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	eloop_cancel_timeout(ap_handle_session_timer, hapd, sta);
+}
+
+
+struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta)
+		return sta;
+
+	wpa_printf(MSG_DEBUG, "  New STA");
+	if (hapd->num_sta >= hapd->conf->max_num_sta) {
+		/* FIX: might try to remove some old STAs first? */
+		wpa_printf(MSG_DEBUG, "no more room for new STAs (%d/%d)",
+			   hapd->num_sta, hapd->conf->max_num_sta);
+		return NULL;
+	}
+
+	sta = os_zalloc(sizeof(struct sta_info));
+	if (sta == NULL) {
+		wpa_printf(MSG_ERROR, "malloc failed");
+		return NULL;
+	}
+	sta->acct_interim_interval = hapd->conf->acct_interim_interval;
+	accounting_sta_get_id(hapd, sta);
+
+	/* initialize STA info data */
+	wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
+		   "for " MACSTR " (%d seconds - ap_max_inactivity)",
+		   __func__, MAC2STR(addr),
+		   hapd->conf->ap_max_inactivity);
+	eloop_register_timeout(hapd->conf->ap_max_inactivity, 0,
+			       ap_handle_timer, hapd, sta);
+	os_memcpy(sta->addr, addr, ETH_ALEN);
+	sta->next = hapd->sta_list;
+	hapd->sta_list = sta;
+	hapd->num_sta++;
+	ap_sta_hash_add(hapd, sta);
+	sta->ssid = &hapd->conf->ssid;
+	ap_sta_remove_in_other_bss(hapd, sta);
+
+	return sta;
+}
+
+
+static int ap_sta_remove(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+
+	wpa_printf(MSG_DEBUG, "Removing STA " MACSTR " from kernel driver",
+		   MAC2STR(sta->addr));
+	if (hostapd_drv_sta_remove(hapd, sta->addr) &&
+	    sta->flags & WLAN_STA_ASSOC) {
+		wpa_printf(MSG_DEBUG, "Could not remove station " MACSTR
+			   " from kernel driver.", MAC2STR(sta->addr));
+		return -1;
+	}
+	return 0;
+}
+
+
+static void ap_sta_remove_in_other_bss(struct hostapd_data *hapd,
+				       struct sta_info *sta)
+{
+	struct hostapd_iface *iface = hapd->iface;
+	size_t i;
+
+	for (i = 0; i < iface->num_bss; i++) {
+		struct hostapd_data *bss = iface->bss[i];
+		struct sta_info *sta2;
+		/* bss should always be set during operation, but it may be
+		 * NULL during reconfiguration. Assume the STA is not
+		 * associated to another BSS in that case to avoid NULL pointer
+		 * dereferences. */
+		if (bss == hapd || bss == NULL)
+			continue;
+		sta2 = ap_get_sta(bss, sta->addr);
+		if (!sta2)
+			continue;
+
+		ap_sta_disconnect(bss, sta2, sta2->addr,
+				  WLAN_REASON_PREV_AUTH_NOT_VALID);
+	}
+}
+
+
+static void ap_sta_disassoc_cb_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+
+	ap_sta_remove(hapd, sta);
+	mlme_disassociate_indication(hapd, sta, sta->disassoc_reason);
+}
+
+
+void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
+			 u16 reason)
+{
+	wpa_printf(MSG_DEBUG, "%s: disassociate STA " MACSTR,
+		   hapd->conf->iface, MAC2STR(sta->addr));
+	sta->flags &= ~WLAN_STA_ASSOC;
+	ap_sta_set_authorized(hapd, sta, 0);
+	sta->timeout_next = STA_DEAUTH;
+	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+		   "for " MACSTR " (%d seconds - "
+		   "AP_MAX_INACTIVITY_AFTER_DISASSOC)",
+		   __func__, MAC2STR(sta->addr),
+		   AP_MAX_INACTIVITY_AFTER_DISASSOC);
+	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DISASSOC, 0,
+			       ap_handle_timer, hapd, sta);
+	accounting_sta_stop(hapd, sta);
+	ieee802_1x_free_station(sta);
+
+	sta->disassoc_reason = reason;
+	sta->flags |= WLAN_STA_PENDING_DISASSOC_CB;
+	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+	eloop_register_timeout(hapd->iface->drv_flags &
+			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+			       ap_sta_disassoc_cb_timeout, hapd, sta);
+}
+
+
+static void ap_sta_deauth_cb_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+
+	ap_sta_remove(hapd, sta);
+	mlme_deauthenticate_indication(hapd, sta, sta->deauth_reason);
+}
+
+
+void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
+			   u16 reason)
+{
+	wpa_printf(MSG_DEBUG, "%s: deauthenticate STA " MACSTR,
+		   hapd->conf->iface, MAC2STR(sta->addr));
+	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+	ap_sta_set_authorized(hapd, sta, 0);
+	sta->timeout_next = STA_REMOVE;
+	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+		   "for " MACSTR " (%d seconds - "
+		   "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
+		   __func__, MAC2STR(sta->addr),
+		   AP_MAX_INACTIVITY_AFTER_DEAUTH);
+	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
+			       ap_handle_timer, hapd, sta);
+	accounting_sta_stop(hapd, sta);
+	ieee802_1x_free_station(sta);
+
+	sta->deauth_reason = reason;
+	sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
+	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+	eloop_register_timeout(hapd->iface->drv_flags &
+			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+			       ap_sta_deauth_cb_timeout, hapd, sta);
+}
+
+
+#ifdef CONFIG_WPS
+int ap_sta_wps_cancel(struct hostapd_data *hapd,
+		      struct sta_info *sta, void *ctx)
+{
+	if (sta && (sta->flags & WLAN_STA_WPS)) {
+		ap_sta_deauthenticate(hapd, sta,
+				      WLAN_REASON_PREV_AUTH_NOT_VALID);
+		wpa_printf(MSG_DEBUG, "WPS: %s: Deauth sta=" MACSTR,
+			   __func__, MAC2STR(sta->addr));
+		return 1;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_WPS */
+
+
+int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
+		     int old_vlanid)
+{
+#ifndef CONFIG_NO_VLAN
+	const char *iface;
+	struct hostapd_vlan *vlan = NULL;
+	int ret;
+
+	/*
+	 * Do not proceed furthur if the vlan id remains same. We do not want
+	 * duplicate dynamic vlan entries.
+	 */
+	if (sta->vlan_id == old_vlanid)
+		return 0;
+
+	/*
+	 * During 1x reauth, if the vlan id changes, then remove the old id and
+	 * proceed furthur to add the new one.
+	 */
+	if (old_vlanid > 0)
+		vlan_remove_dynamic(hapd, old_vlanid);
+
+	iface = hapd->conf->iface;
+	if (sta->ssid->vlan[0])
+		iface = sta->ssid->vlan;
+
+	if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+		sta->vlan_id = 0;
+	else if (sta->vlan_id > 0) {
+		vlan = hapd->conf->vlan;
+		while (vlan) {
+			if (vlan->vlan_id == sta->vlan_id ||
+			    vlan->vlan_id == VLAN_ID_WILDCARD) {
+				iface = vlan->ifname;
+				break;
+			}
+			vlan = vlan->next;
+		}
+	}
+
+	if (sta->vlan_id > 0 && vlan == NULL) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG, "could not find VLAN for "
+			       "binding station to (vlan_id=%d)",
+			       sta->vlan_id);
+		return -1;
+	} else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) {
+		vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id);
+		if (vlan == NULL) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG, "could not add "
+				       "dynamic VLAN interface for vlan_id=%d",
+				       sta->vlan_id);
+			return -1;
+		}
+
+		iface = vlan->ifname;
+		if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG, "could not "
+				       "configure encryption for dynamic VLAN "
+				       "interface for vlan_id=%d",
+				       sta->vlan_id);
+		}
+
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
+			       "interface '%s'", iface);
+	} else if (vlan && vlan->vlan_id == sta->vlan_id) {
+		if (sta->vlan_id > 0) {
+			vlan->dynamic_vlan++;
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG, "updated existing "
+				       "dynamic VLAN interface '%s'", iface);
+		}
+
+		/*
+		 * Update encryption configuration for statically generated
+		 * VLAN interface. This is only used for static WEP
+		 * configuration for the case where hostapd did not yet know
+		 * which keys are to be used when the interface was added.
+		 */
+		if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
+			hostapd_logger(hapd, sta->addr,
+				       HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_DEBUG, "could not "
+				       "configure encryption for VLAN "
+				       "interface for vlan_id=%d",
+				       sta->vlan_id);
+		}
+	}
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG, "binding station to interface "
+		       "'%s'", iface);
+
+	if (wpa_auth_sta_set_vlan(sta->wpa_sm, sta->vlan_id) < 0)
+		wpa_printf(MSG_INFO, "Failed to update VLAN-ID for WPA");
+
+	ret = hostapd_drv_set_sta_vlan(iface, hapd, sta->addr, sta->vlan_id);
+	if (ret < 0) {
+		hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
+			       "entry to vlan_id=%d", sta->vlan_id);
+	}
+	return ret;
+#else /* CONFIG_NO_VLAN */
+	return 0;
+#endif /* CONFIG_NO_VLAN */
+}
+
+
+#ifdef CONFIG_IEEE80211W
+
+int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	u32 tu;
+	struct os_time now, passed;
+	os_get_time(&now);
+	os_time_sub(&now, &sta->sa_query_start, &passed);
+	tu = (passed.sec * 1000000 + passed.usec) / 1024;
+	if (hapd->conf->assoc_sa_query_max_timeout < tu) {
+		hostapd_logger(hapd, sta->addr,
+			       HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "association SA Query timed out");
+		sta->sa_query_timed_out = 1;
+		os_free(sta->sa_query_trans_id);
+		sta->sa_query_trans_id = NULL;
+		sta->sa_query_count = 0;
+		eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
+		return 1;
+	}
+
+	return 0;
+}
+
+
+static void ap_sa_query_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	struct sta_info *sta = timeout_ctx;
+	unsigned int timeout, sec, usec;
+	u8 *trans_id, *nbuf;
+
+	if (sta->sa_query_count > 0 &&
+	    ap_check_sa_query_timeout(hapd, sta))
+		return;
+
+	nbuf = os_realloc_array(sta->sa_query_trans_id,
+				sta->sa_query_count + 1,
+				WLAN_SA_QUERY_TR_ID_LEN);
+	if (nbuf == NULL)
+		return;
+	if (sta->sa_query_count == 0) {
+		/* Starting a new SA Query procedure */
+		os_get_time(&sta->sa_query_start);
+	}
+	trans_id = nbuf + sta->sa_query_count * WLAN_SA_QUERY_TR_ID_LEN;
+	sta->sa_query_trans_id = nbuf;
+	sta->sa_query_count++;
+
+	os_get_random(trans_id, WLAN_SA_QUERY_TR_ID_LEN);
+
+	timeout = hapd->conf->assoc_sa_query_retry_timeout;
+	sec = ((timeout / 1000) * 1024) / 1000;
+	usec = (timeout % 1000) * 1024;
+	eloop_register_timeout(sec, usec, ap_sa_query_timer, hapd, sta);
+
+	hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "association SA Query attempt %d", sta->sa_query_count);
+
+	ieee802_11_send_sa_query_req(hapd, sta->addr, trans_id);
+}
+
+
+void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	ap_sa_query_timer(hapd, sta);
+}
+
+
+void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	eloop_cancel_timeout(ap_sa_query_timer, hapd, sta);
+	os_free(sta->sa_query_trans_id);
+	sta->sa_query_trans_id = NULL;
+	sta->sa_query_count = 0;
+}
+
+#endif /* CONFIG_IEEE80211W */
+
+
+void ap_sta_set_authorized(struct hostapd_data *hapd, struct sta_info *sta,
+			   int authorized)
+{
+	const u8 *dev_addr = NULL;
+#ifdef CONFIG_P2P
+	u8 addr[ETH_ALEN];
+#endif /* CONFIG_P2P */
+
+	if (!!authorized == !!(sta->flags & WLAN_STA_AUTHORIZED))
+		return;
+
+#ifdef CONFIG_P2P
+	if (hapd->p2p_group == NULL) {
+		if (sta->p2p_ie != NULL &&
+		    p2p_parse_dev_addr_in_p2p_ie(sta->p2p_ie, addr) == 0)
+			dev_addr = addr;
+	} else
+		dev_addr = p2p_group_get_dev_addr(hapd->p2p_group, sta->addr);
+#endif /* CONFIG_P2P */
+
+	if (authorized) {
+		if (dev_addr)
+			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
+				MACSTR " p2p_dev_addr=" MACSTR,
+				MAC2STR(sta->addr), MAC2STR(dev_addr));
+		else
+			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_CONNECTED
+				MACSTR, MAC2STR(sta->addr));
+		if (hapd->msg_ctx_parent &&
+		    hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
+			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+				AP_STA_CONNECTED MACSTR " p2p_dev_addr="
+				MACSTR,
+				MAC2STR(sta->addr), MAC2STR(dev_addr));
+		else if (hapd->msg_ctx_parent &&
+			 hapd->msg_ctx_parent != hapd->msg_ctx)
+			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+				AP_STA_CONNECTED MACSTR, MAC2STR(sta->addr));
+
+		sta->flags |= WLAN_STA_AUTHORIZED;
+	} else {
+		if (dev_addr)
+			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
+				MACSTR " p2p_dev_addr=" MACSTR,
+				MAC2STR(sta->addr), MAC2STR(dev_addr));
+		else
+			wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_DISCONNECTED
+				MACSTR, MAC2STR(sta->addr));
+		if (hapd->msg_ctx_parent &&
+		    hapd->msg_ctx_parent != hapd->msg_ctx && dev_addr)
+			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+				AP_STA_DISCONNECTED MACSTR " p2p_dev_addr="
+				MACSTR, MAC2STR(sta->addr), MAC2STR(dev_addr));
+		else if (hapd->msg_ctx_parent &&
+			 hapd->msg_ctx_parent != hapd->msg_ctx)
+			wpa_msg(hapd->msg_ctx_parent, MSG_INFO,
+				AP_STA_DISCONNECTED MACSTR,
+				MAC2STR(sta->addr));
+		sta->flags &= ~WLAN_STA_AUTHORIZED;
+	}
+
+	if (hapd->sta_authorized_cb)
+		hapd->sta_authorized_cb(hapd->sta_authorized_cb_ctx,
+					sta->addr, authorized, dev_addr);
+}
+
+
+void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
+		       const u8 *addr, u16 reason)
+{
+
+	if (sta == NULL && addr)
+		sta = ap_get_sta(hapd, addr);
+
+	if (addr)
+		hostapd_drv_sta_deauth(hapd, addr, reason);
+
+	if (sta == NULL)
+		return;
+	ap_sta_set_authorized(hapd, sta, 0);
+	wpa_auth_sm_event(sta->wpa_sm, WPA_DEAUTH);
+	ieee802_1x_notify_port_enabled(sta->eapol_sm, 0);
+	sta->flags &= ~(WLAN_STA_AUTH | WLAN_STA_ASSOC);
+	wpa_printf(MSG_DEBUG, "%s: reschedule ap_handle_timer timeout "
+		   "for " MACSTR " (%d seconds - "
+		   "AP_MAX_INACTIVITY_AFTER_DEAUTH)",
+		   __func__, MAC2STR(sta->addr),
+		   AP_MAX_INACTIVITY_AFTER_DEAUTH);
+	eloop_cancel_timeout(ap_handle_timer, hapd, sta);
+	eloop_register_timeout(AP_MAX_INACTIVITY_AFTER_DEAUTH, 0,
+			       ap_handle_timer, hapd, sta);
+	sta->timeout_next = STA_REMOVE;
+
+	sta->deauth_reason = reason;
+	sta->flags |= WLAN_STA_PENDING_DEAUTH_CB;
+	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+	eloop_register_timeout(hapd->iface->drv_flags &
+			       WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS ? 2 : 0, 0,
+			       ap_sta_deauth_cb_timeout, hapd, sta);
+}
+
+
+void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	if (!(sta->flags & WLAN_STA_PENDING_DEAUTH_CB)) {
+		wpa_printf(MSG_DEBUG, "Ignore deauth cb for test frame");
+		return;
+	}
+	sta->flags &= ~WLAN_STA_PENDING_DEAUTH_CB;
+	eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
+	ap_sta_deauth_cb_timeout(hapd, sta);
+}
+
+
+void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta)
+{
+	if (!(sta->flags & WLAN_STA_PENDING_DISASSOC_CB)) {
+		wpa_printf(MSG_DEBUG, "Ignore disassoc cb for test frame");
+		return;
+	}
+	sta->flags &= ~WLAN_STA_PENDING_DISASSOC_CB;
+	eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+	ap_sta_disassoc_cb_timeout(hapd, sta);
+}
diff --git a/hostap/src/ap/sta_info.h b/hostap/src/ap/sta_info.h
new file mode 100644
index 0000000..d5e92fa
--- /dev/null
+++ b/hostap/src/ap/sta_info.h
@@ -0,0 +1,194 @@
+/*
+ * hostapd / Station table
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef STA_INFO_H
+#define STA_INFO_H
+
+/* STA flags */
+#define WLAN_STA_AUTH BIT(0)
+#define WLAN_STA_ASSOC BIT(1)
+#define WLAN_STA_PS BIT(2)
+#define WLAN_STA_TIM BIT(3)
+#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_SHORT_PREAMBLE BIT(7)
+#define WLAN_STA_PREAUTH BIT(8)
+#define WLAN_STA_WMM BIT(9)
+#define WLAN_STA_MFP BIT(10)
+#define WLAN_STA_HT BIT(11)
+#define WLAN_STA_WPS BIT(12)
+#define WLAN_STA_MAYBE_WPS BIT(13)
+#define WLAN_STA_WDS BIT(14)
+#define WLAN_STA_ASSOC_REQ_OK BIT(15)
+#define WLAN_STA_WPS2 BIT(16)
+#define WLAN_STA_GAS BIT(17)
+#define WLAN_STA_VHT BIT(18)
+#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
+#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
+#define WLAN_STA_NONERP BIT(31)
+
+/* Maximum number of supported rates (from both Supported Rates and Extended
+ * Supported Rates IEs). */
+#define WLAN_SUPP_RATES_MAX 32
+
+
+struct sta_info {
+	struct sta_info *next; /* next entry in sta list */
+	struct sta_info *hnext; /* next entry in hash table list */
+	u8 addr[6];
+	u16 aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
+	u32 flags; /* Bitfield of WLAN_STA_* */
+	u16 capability;
+	u16 listen_interval; /* or beacon_int for APs */
+	u8 supported_rates[WLAN_SUPP_RATES_MAX];
+	int supported_rates_len;
+	u8 qosinfo; /* Valid when WLAN_STA_WMM is set */
+
+	unsigned int nonerp_set:1;
+	unsigned int no_short_slot_time_set:1;
+	unsigned int no_short_preamble_set:1;
+	unsigned int no_ht_gf_set:1;
+	unsigned int no_ht_set:1;
+	unsigned int ht_20mhz_set:1;
+	unsigned int no_p2p_set:1;
+
+	u16 auth_alg;
+	u8 previous_ap[6];
+
+	enum {
+		STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH, STA_REMOVE
+	} timeout_next;
+
+	u16 deauth_reason;
+	u16 disassoc_reason;
+
+	/* IEEE 802.1X related data */
+	struct eapol_state_machine *eapol_sm;
+
+	/* IEEE 802.11f (IAPP) related data */
+	struct ieee80211_mgmt *last_assoc_req;
+
+	u32 acct_session_id_hi;
+	u32 acct_session_id_lo;
+	time_t acct_session_start;
+	int acct_session_started;
+	int acct_terminate_cause; /* Acct-Terminate-Cause */
+	int acct_interim_interval; /* Acct-Interim-Interval */
+
+	unsigned long last_rx_bytes;
+	unsigned long last_tx_bytes;
+	u32 acct_input_gigawords; /* Acct-Input-Gigawords */
+	u32 acct_output_gigawords; /* Acct-Output-Gigawords */
+
+	u8 *challenge; /* IEEE 802.11 Shared Key Authentication Challenge */
+
+	struct wpa_state_machine *wpa_sm;
+	struct rsn_preauth_interface *preauth_iface;
+
+	struct hostapd_ssid *ssid; /* SSID selection based on (Re)AssocReq */
+	struct hostapd_ssid *ssid_probe; /* SSID selection based on ProbeReq */
+
+	int vlan_id;
+	 /* PSKs from RADIUS authentication server */
+	struct hostapd_sta_wpa_psk_short *psk;
+
+	char *identity; /* User-Name from RADIUS */
+	char *radius_cui; /* Chargeable-User-Identity from RADIUS */
+
+	struct ieee80211_ht_capabilities *ht_capabilities;
+	struct ieee80211_vht_capabilities *vht_capabilities;
+
+#ifdef CONFIG_IEEE80211W
+	int sa_query_count; /* number of pending SA Query requests;
+			     * 0 = no SA Query in progress */
+	int sa_query_timed_out;
+	u8 *sa_query_trans_id; /* buffer of WLAN_SA_QUERY_TR_ID_LEN *
+				* sa_query_count octets of pending SA Query
+				* transaction identifiers */
+	struct os_time sa_query_start;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_INTERWORKING
+#define GAS_DIALOG_MAX 8 /* Max concurrent dialog number */
+	struct gas_dialog_info *gas_dialog;
+	u8 gas_dialog_next;
+#endif /* CONFIG_INTERWORKING */
+
+	struct wpabuf *wps_ie; /* WPS IE from (Re)Association Request */
+	struct wpabuf *p2p_ie; /* P2P IE from (Re)Association Request */
+	struct wpabuf *hs20_ie; /* HS 2.0 IE from (Re)Association Request */
+
+	struct os_time connected_time;
+
+#ifdef CONFIG_SAE
+	enum { SAE_INIT, SAE_COMMIT, SAE_CONFIRM } sae_state;
+	u16 sae_send_confirm;
+#endif /* CONFIG_SAE */
+};
+
+
+/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY has
+ * passed since last received frame from the station, a nullfunc data frame is
+ * sent to the station. If this frame is not acknowledged and no other frames
+ * have been received, the station will be disassociated after
+ * AP_DISASSOC_DELAY seconds. Similarly, the station will be deauthenticated
+ * after AP_DEAUTH_DELAY seconds has passed after disassociation. */
+#define AP_MAX_INACTIVITY (5 * 60)
+#define AP_DISASSOC_DELAY (1)
+#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)
+
+
+struct hostapd_data;
+
+int ap_for_each_sta(struct hostapd_data *hapd,
+		    int (*cb)(struct hostapd_data *hapd, struct sta_info *sta,
+			      void *ctx),
+		    void *ctx);
+struct sta_info * ap_get_sta(struct hostapd_data *hapd, const u8 *sta);
+void ap_sta_hash_add(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_free_sta(struct hostapd_data *hapd, struct sta_info *sta);
+void hostapd_free_stas(struct hostapd_data *hapd);
+void ap_handle_timer(void *eloop_ctx, void *timeout_ctx);
+void ap_sta_session_timeout(struct hostapd_data *hapd, struct sta_info *sta,
+			    u32 session_timeout);
+void ap_sta_no_session_timeout(struct hostapd_data *hapd,
+			       struct sta_info *sta);
+struct sta_info * ap_sta_add(struct hostapd_data *hapd, const u8 *addr);
+void ap_sta_disassociate(struct hostapd_data *hapd, struct sta_info *sta,
+			 u16 reason);
+void ap_sta_deauthenticate(struct hostapd_data *hapd, struct sta_info *sta,
+			   u16 reason);
+#ifdef CONFIG_WPS
+int ap_sta_wps_cancel(struct hostapd_data *hapd,
+		      struct sta_info *sta, void *ctx);
+#endif /* CONFIG_WPS */
+int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
+		     int old_vlanid);
+void ap_sta_start_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_sta_stop_sa_query(struct hostapd_data *hapd, struct sta_info *sta);
+int ap_check_sa_query_timeout(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_sta_disconnect(struct hostapd_data *hapd, struct sta_info *sta,
+		       const u8 *addr, u16 reason);
+
+void ap_sta_set_authorized(struct hostapd_data *hapd,
+			   struct sta_info *sta, int authorized);
+static inline int ap_sta_is_authorized(struct sta_info *sta)
+{
+	return sta->flags & WLAN_STA_AUTHORIZED;
+}
+
+void ap_sta_deauth_cb(struct hostapd_data *hapd, struct sta_info *sta);
+void ap_sta_disassoc_cb(struct hostapd_data *hapd, struct sta_info *sta);
+
+#endif /* STA_INFO_H */
diff --git a/hostap/src/ap/tkip_countermeasures.c b/hostap/src/ap/tkip_countermeasures.c
new file mode 100644
index 0000000..4a2ea06
--- /dev/null
+++ b/hostap/src/ap/tkip_countermeasures.c
@@ -0,0 +1,105 @@
+/*
+ * hostapd / TKIP countermeasures
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "common/ieee802_11_defs.h"
+#include "radius/radius.h"
+#include "hostapd.h"
+#include "sta_info.h"
+#include "ap_mlme.h"
+#include "wpa_auth.h"
+#include "ap_drv_ops.h"
+#include "tkip_countermeasures.h"
+
+
+static void ieee80211_tkip_countermeasures_stop(void *eloop_ctx,
+						void *timeout_ctx)
+{
+	struct hostapd_data *hapd = eloop_ctx;
+	hapd->tkip_countermeasures = 0;
+	hostapd_drv_set_countermeasures(hapd, 0);
+	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "TKIP countermeasures ended");
+}
+
+
+static void ieee80211_tkip_countermeasures_start(struct hostapd_data *hapd)
+{
+	struct sta_info *sta;
+
+	hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_INFO, "TKIP countermeasures initiated");
+
+	wpa_auth_countermeasures_start(hapd->wpa_auth);
+	hapd->tkip_countermeasures = 1;
+	hostapd_drv_set_countermeasures(hapd, 1);
+	wpa_gtk_rekey(hapd->wpa_auth);
+	eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
+	eloop_register_timeout(60, 0, ieee80211_tkip_countermeasures_stop,
+			       hapd, NULL);
+	while ((sta = hapd->sta_list)) {
+		sta->acct_terminate_cause =
+			RADIUS_ACCT_TERMINATE_CAUSE_ADMIN_RESET;
+		if (sta->flags & WLAN_STA_AUTH) {
+			mlme_deauthenticate_indication(
+				hapd, sta,
+				WLAN_REASON_MICHAEL_MIC_FAILURE);
+		}
+		hostapd_drv_sta_deauth(hapd, sta->addr,
+				       WLAN_REASON_MICHAEL_MIC_FAILURE);
+		ap_free_sta(hapd, sta);
+	}
+}
+
+
+void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd)
+{
+	eloop_cancel_timeout(ieee80211_tkip_countermeasures_stop, hapd, NULL);
+}
+
+
+int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local)
+{
+	struct os_time now;
+	int ret = 0;
+
+	if (addr && local) {
+		struct sta_info *sta = ap_get_sta(hapd, addr);
+		if (sta != NULL) {
+			wpa_auth_sta_local_mic_failure_report(sta->wpa_sm);
+			hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+				       HOSTAPD_LEVEL_INFO,
+				       "Michael MIC failure detected in "
+				       "received frame");
+			mlme_michaelmicfailure_indication(hapd, addr);
+		} else {
+			wpa_printf(MSG_DEBUG,
+				   "MLME-MICHAELMICFAILURE.indication "
+				   "for not associated STA (" MACSTR
+				   ") ignored", MAC2STR(addr));
+			return ret;
+		}
+	}
+
+	os_get_time(&now);
+	if (now.sec > hapd->michael_mic_failure + 60) {
+		hapd->michael_mic_failures = 1;
+	} else {
+		hapd->michael_mic_failures++;
+		if (hapd->michael_mic_failures > 1) {
+			ieee80211_tkip_countermeasures_start(hapd);
+			ret = 1;
+		}
+	}
+	hapd->michael_mic_failure = now.sec;
+
+	return ret;
+}
diff --git a/hostap/src/ap/tkip_countermeasures.h b/hostap/src/ap/tkip_countermeasures.h
new file mode 100644
index 0000000..d3eaed3
--- /dev/null
+++ b/hostap/src/ap/tkip_countermeasures.h
@@ -0,0 +1,15 @@
+/*
+ * hostapd / TKIP countermeasures
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TKIP_COUNTERMEASURES_H
+#define TKIP_COUNTERMEASURES_H
+
+int michael_mic_failure(struct hostapd_data *hapd, const u8 *addr, int local);
+void ieee80211_tkip_countermeasures_deinit(struct hostapd_data *hapd);
+
+#endif /* TKIP_COUNTERMEASURES_H */
diff --git a/hostap/src/ap/utils.c b/hostap/src/ap/utils.c
new file mode 100644
index 0000000..931968c
--- /dev/null
+++ b/hostap/src/ap/utils.c
@@ -0,0 +1,85 @@
+/*
+ * AP mode helper functions
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "common/ieee802_11_defs.h"
+#include "sta_info.h"
+#include "hostapd.h"
+
+
+int hostapd_register_probereq_cb(struct hostapd_data *hapd,
+				 int (*cb)(void *ctx, const u8 *sa,
+					   const u8 *da, const u8 *bssid,
+					   const u8 *ie, size_t ie_len,
+					   int ssi_signal),
+				 void *ctx)
+{
+	struct hostapd_probereq_cb *n;
+
+	n = os_realloc_array(hapd->probereq_cb, hapd->num_probereq_cb + 1,
+			     sizeof(struct hostapd_probereq_cb));
+	if (n == NULL)
+		return -1;
+
+	hapd->probereq_cb = n;
+	n = &hapd->probereq_cb[hapd->num_probereq_cb];
+	hapd->num_probereq_cb++;
+
+	n->cb = cb;
+	n->ctx = ctx;
+
+	return 0;
+}
+
+
+struct prune_data {
+	struct hostapd_data *hapd;
+	const u8 *addr;
+};
+
+static int prune_associations(struct hostapd_iface *iface, void *ctx)
+{
+	struct prune_data *data = ctx;
+	struct sta_info *osta;
+	struct hostapd_data *ohapd;
+	size_t j;
+
+	for (j = 0; j < iface->num_bss; j++) {
+		ohapd = iface->bss[j];
+		if (ohapd == data->hapd)
+			continue;
+		osta = ap_get_sta(ohapd, data->addr);
+		if (!osta)
+			continue;
+
+		ap_sta_disassociate(ohapd, osta, WLAN_REASON_UNSPECIFIED);
+	}
+
+	return 0;
+}
+
+/**
+ * hostapd_prune_associations - Remove extraneous associations
+ * @hapd: Pointer to BSS data for the most recent association
+ * @addr: Associated STA address
+ *
+ * This function looks through all radios and BSS's for previous
+ * (stale) associations of STA. If any are found they are removed.
+ */
+void hostapd_prune_associations(struct hostapd_data *hapd, const u8 *addr)
+{
+	struct prune_data data;
+	data.hapd = hapd;
+	data.addr = addr;
+	if (hapd->iface->interfaces &&
+	    hapd->iface->interfaces->for_each_interface)
+		hapd->iface->interfaces->for_each_interface(
+			hapd->iface->interfaces, prune_associations, &data);
+}
diff --git a/hostap/src/ap/vlan_init.c b/hostap/src/ap/vlan_init.c
new file mode 100644
index 0000000..7b1a9e6
--- /dev/null
+++ b/hostap/src/ap/vlan_init.c
@@ -0,0 +1,934 @@
+/*
+ * hostapd / VLAN initialization
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "vlan_init.h"
+#include "vlan_util.h"
+
+
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+
+#include <net/if.h>
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <linux/if_vlan.h>
+#include <linux/if_bridge.h>
+
+#include "drivers/priv_netlink.h"
+#include "utils/eloop.h"
+
+
+struct full_dynamic_vlan {
+	int s; /* socket on which to listen for new/removed interfaces. */
+};
+
+
+static int ifconfig_helper(const char *if_name, int up)
+{
+	int fd;
+	struct ifreq ifr;
+
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+			   "failed: %s", __func__, strerror(errno));
+		return -1;
+	}
+
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, if_name, IFNAMSIZ);
+
+	if (ioctl(fd, SIOCGIFFLAGS, &ifr) != 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCGIFFLAGS) failed "
+			   "for interface %s: %s",
+			   __func__, if_name, strerror(errno));
+		close(fd);
+		return -1;
+	}
+
+	if (up)
+		ifr.ifr_flags |= IFF_UP;
+	else
+		ifr.ifr_flags &= ~IFF_UP;
+
+	if (ioctl(fd, SIOCSIFFLAGS, &ifr) != 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: ioctl(SIOCSIFFLAGS) failed "
+			   "for interface %s (up=%d): %s",
+			   __func__, if_name, up, strerror(errno));
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}
+
+
+static int ifconfig_up(const char *if_name)
+{
+	wpa_printf(MSG_DEBUG, "VLAN: Set interface %s up", if_name);
+	return ifconfig_helper(if_name, 1);
+}
+
+
+static int ifconfig_down(const char *if_name)
+{
+	wpa_printf(MSG_DEBUG, "VLAN: Set interface %s down", if_name);
+	return ifconfig_helper(if_name, 0);
+}
+
+
+/*
+ * These are only available in recent linux headers (without the leading
+ * underscore).
+ */
+#define _GET_VLAN_REALDEV_NAME_CMD	8
+#define _GET_VLAN_VID_CMD		9
+
+/* This value should be 256 ONLY. If it is something else, then hostapd
+ * might crash!, as this value has been hard-coded in 2.4.x kernel
+ * bridging code.
+ */
+#define MAX_BR_PORTS      		256
+
+static int br_delif(const char *br_name, const char *if_name)
+{
+	int fd;
+	struct ifreq ifr;
+	unsigned long args[2];
+	int if_index;
+
+	wpa_printf(MSG_DEBUG, "VLAN: br_delif(%s, %s)", br_name, if_name);
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+			   "failed: %s", __func__, strerror(errno));
+		return -1;
+	}
+
+	if_index = if_nametoindex(if_name);
+
+	if (if_index == 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
+			   "interface index for '%s'",
+			   __func__, if_name);
+		close(fd);
+		return -1;
+	}
+
+	args[0] = BRCTL_DEL_IF;
+	args[1] = if_index;
+
+	os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+	ifr.ifr_data = (__caddr_t) args;
+
+	if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0 && errno != EINVAL) {
+		/* No error if interface already removed. */
+		wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
+			   "BRCTL_DEL_IF] failed for br_name=%s if_name=%s: "
+			   "%s", __func__, br_name, if_name, strerror(errno));
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}
+
+
+/*
+	Add interface 'if_name' to the bridge 'br_name'
+
+	returns -1 on error
+	returns 1 if the interface is already part of the bridge
+	returns 0 otherwise
+*/
+static int br_addif(const char *br_name, const char *if_name)
+{
+	int fd;
+	struct ifreq ifr;
+	unsigned long args[2];
+	int if_index;
+
+	wpa_printf(MSG_DEBUG, "VLAN: br_addif(%s, %s)", br_name, if_name);
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+			   "failed: %s", __func__, strerror(errno));
+		return -1;
+	}
+
+	if_index = if_nametoindex(if_name);
+
+	if (if_index == 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: Failure determining "
+			   "interface index for '%s'",
+			   __func__, if_name);
+		close(fd);
+		return -1;
+	}
+
+	args[0] = BRCTL_ADD_IF;
+	args[1] = if_index;
+
+	os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+	ifr.ifr_data = (__caddr_t) args;
+
+	if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+		if (errno == EBUSY) {
+			/* The interface is already added. */
+			close(fd);
+			return 1;
+		}
+
+		wpa_printf(MSG_ERROR, "VLAN: %s: ioctl[SIOCDEVPRIVATE,"
+			   "BRCTL_ADD_IF] failed for br_name=%s if_name=%s: "
+			   "%s", __func__, br_name, if_name, strerror(errno));
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}
+
+
+static int br_delbr(const char *br_name)
+{
+	int fd;
+	unsigned long arg[2];
+
+	wpa_printf(MSG_DEBUG, "VLAN: br_delbr(%s)", br_name);
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+			   "failed: %s", __func__, strerror(errno));
+		return -1;
+	}
+
+	arg[0] = BRCTL_DEL_BRIDGE;
+	arg[1] = (unsigned long) br_name;
+
+	if (ioctl(fd, SIOCGIFBR, arg) < 0 && errno != ENXIO) {
+		/* No error if bridge already removed. */
+		wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_DEL_BRIDGE failed for "
+			   "%s: %s", __func__, br_name, strerror(errno));
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}
+
+
+/*
+	Add a bridge with the name 'br_name'.
+
+	returns -1 on error
+	returns 1 if the bridge already exists
+	returns 0 otherwise
+*/
+static int br_addbr(const char *br_name)
+{
+	int fd;
+	unsigned long arg[4];
+	struct ifreq ifr;
+
+	wpa_printf(MSG_DEBUG, "VLAN: br_addbr(%s)", br_name);
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+			   "failed: %s", __func__, strerror(errno));
+		return -1;
+	}
+
+	arg[0] = BRCTL_ADD_BRIDGE;
+	arg[1] = (unsigned long) br_name;
+
+	if (ioctl(fd, SIOCGIFBR, arg) < 0) {
+ 		if (errno == EEXIST) {
+			/* The bridge is already added. */
+			close(fd);
+			return 1;
+		} else {
+			wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_ADD_BRIDGE "
+				   "failed for %s: %s",
+				   __func__, br_name, strerror(errno));
+			close(fd);
+			return -1;
+		}
+	}
+
+	/* Decrease forwarding delay to avoid EAPOL timeouts. */
+	os_memset(&ifr, 0, sizeof(ifr));
+	os_strlcpy(ifr.ifr_name, br_name, IFNAMSIZ);
+	arg[0] = BRCTL_SET_BRIDGE_FORWARD_DELAY;
+	arg[1] = 1;
+	arg[2] = 0;
+	arg[3] = 0;
+	ifr.ifr_data = (char *) &arg;
+	if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: "
+			   "BRCTL_SET_BRIDGE_FORWARD_DELAY (1 sec) failed for "
+			   "%s: %s", __func__, br_name, strerror(errno));
+		/* Continue anyway */
+	}
+
+	close(fd);
+	return 0;
+}
+
+
+static int br_getnumports(const char *br_name)
+{
+	int fd;
+	int i;
+	int port_cnt = 0;
+	unsigned long arg[4];
+	int ifindices[MAX_BR_PORTS];
+	struct ifreq ifr;
+
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+			   "failed: %s", __func__, strerror(errno));
+		return -1;
+	}
+
+	arg[0] = BRCTL_GET_PORT_LIST;
+	arg[1] = (unsigned long) ifindices;
+	arg[2] = MAX_BR_PORTS;
+	arg[3] = 0;
+
+	os_memset(ifindices, 0, sizeof(ifindices));
+	os_strlcpy(ifr.ifr_name, br_name, sizeof(ifr.ifr_name));
+	ifr.ifr_data = (__caddr_t) arg;
+
+	if (ioctl(fd, SIOCDEVPRIVATE, &ifr) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: BRCTL_GET_PORT_LIST "
+			   "failed for %s: %s",
+			   __func__, br_name, strerror(errno));
+		close(fd);
+		return -1;
+	}
+
+	for (i = 1; i < MAX_BR_PORTS; i++) {
+		if (ifindices[i] > 0) {
+			port_cnt++;
+		}
+	}
+
+	close(fd);
+	return port_cnt;
+}
+
+
+#ifndef CONFIG_VLAN_NETLINK
+
+int vlan_rem(const char *if_name)
+{
+	int fd;
+	struct vlan_ioctl_args if_request;
+
+	wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(%s)", if_name);
+	if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
+		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+			   if_name);
+		return -1;
+	}
+
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+			   "failed: %s", __func__, strerror(errno));
+		return -1;
+	}
+
+	os_memset(&if_request, 0, sizeof(if_request));
+
+	os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
+	if_request.cmd = DEL_VLAN_CMD;
+
+	if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: DEL_VLAN_CMD failed for %s: "
+			   "%s", __func__, if_name, strerror(errno));
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}
+
+
+/*
+	Add a vlan interface with VLAN ID 'vid' and tagged interface
+	'if_name'.
+
+	returns -1 on error
+	returns 1 if the interface already exists
+	returns 0 otherwise
+*/
+int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
+{
+	int fd;
+	struct vlan_ioctl_args if_request;
+
+	wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d)",
+		   if_name, vid);
+	ifconfig_up(if_name);
+
+	if ((os_strlen(if_name) + 1) > sizeof(if_request.device1)) {
+		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+			   if_name);
+		return -1;
+	}
+
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+			   "failed: %s", __func__, strerror(errno));
+		return -1;
+	}
+
+	os_memset(&if_request, 0, sizeof(if_request));
+
+	/* Determine if a suitable vlan device already exists. */
+
+	os_snprintf(if_request.device1, sizeof(if_request.device1), "vlan%d",
+		    vid);
+
+	if_request.cmd = _GET_VLAN_VID_CMD;
+
+	if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0) {
+
+		if (if_request.u.VID == vid) {
+			if_request.cmd = _GET_VLAN_REALDEV_NAME_CMD;
+
+			if (ioctl(fd, SIOCSIFVLAN, &if_request) == 0 &&
+			    os_strncmp(if_request.u.device2, if_name,
+				       sizeof(if_request.u.device2)) == 0) {
+				close(fd);
+				wpa_printf(MSG_DEBUG, "VLAN: vlan_add: "
+					   "if_name %s exists already",
+					   if_request.device1);
+				return 1;
+			}
+		}
+	}
+
+	/* A suitable vlan device does not already exist, add one. */
+
+	os_memset(&if_request, 0, sizeof(if_request));
+	os_strlcpy(if_request.device1, if_name, sizeof(if_request.device1));
+	if_request.u.VID = vid;
+	if_request.cmd = ADD_VLAN_CMD;
+
+	if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: ADD_VLAN_CMD failed for %s: "
+			   "%s",
+			   __func__, if_request.device1, strerror(errno));
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}
+
+
+static int vlan_set_name_type(unsigned int name_type)
+{
+	int fd;
+	struct vlan_ioctl_args if_request;
+
+	wpa_printf(MSG_DEBUG, "VLAN: vlan_set_name_type(name_type=%u)",
+		   name_type);
+	if ((fd = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: socket(AF_INET,SOCK_STREAM) "
+			   "failed: %s", __func__, strerror(errno));
+		return -1;
+	}
+
+	os_memset(&if_request, 0, sizeof(if_request));
+
+	if_request.u.name_type = name_type;
+	if_request.cmd = SET_VLAN_NAME_TYPE_CMD;
+	if (ioctl(fd, SIOCSIFVLAN, &if_request) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: SET_VLAN_NAME_TYPE_CMD "
+			   "name_type=%u failed: %s",
+			   __func__, name_type, strerror(errno));
+		close(fd);
+		return -1;
+	}
+
+	close(fd);
+	return 0;
+}
+
+#endif /* CONFIG_VLAN_NETLINK */
+
+
+static void vlan_newlink(char *ifname, struct hostapd_data *hapd)
+{
+	char vlan_ifname[IFNAMSIZ];
+	char br_name[IFNAMSIZ];
+	struct hostapd_vlan *vlan = hapd->conf->vlan;
+	char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+	int vlan_naming = hapd->conf->ssid.vlan_naming;
+
+	wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
+
+	while (vlan) {
+		if (os_strcmp(ifname, vlan->ifname) == 0) {
+
+			os_snprintf(br_name, sizeof(br_name), "brvlan%d",
+				    vlan->vlan_id);
+
+			if (!br_addbr(br_name))
+				vlan->clean |= DVLAN_CLEAN_BR;
+
+			ifconfig_up(br_name);
+
+			if (tagged_interface) {
+				if (vlan_naming ==
+				    DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+					os_snprintf(vlan_ifname,
+						    sizeof(vlan_ifname),
+						    "%s.%d", tagged_interface,
+						    vlan->vlan_id);
+				else
+					os_snprintf(vlan_ifname,
+						    sizeof(vlan_ifname),
+						    "vlan%d", vlan->vlan_id);
+
+				ifconfig_up(tagged_interface);
+				if (!vlan_add(tagged_interface, vlan->vlan_id,
+					      vlan_ifname))
+					vlan->clean |= DVLAN_CLEAN_VLAN;
+
+				if (!br_addif(br_name, vlan_ifname))
+					vlan->clean |= DVLAN_CLEAN_VLAN_PORT;
+
+				ifconfig_up(vlan_ifname);
+			}
+
+			if (!br_addif(br_name, ifname))
+				vlan->clean |= DVLAN_CLEAN_WLAN_PORT;
+
+			ifconfig_up(ifname);
+
+			break;
+		}
+		vlan = vlan->next;
+	}
+}
+
+
+static void vlan_dellink(char *ifname, struct hostapd_data *hapd)
+{
+	char vlan_ifname[IFNAMSIZ];
+	char br_name[IFNAMSIZ];
+	struct hostapd_vlan *first, *prev, *vlan = hapd->conf->vlan;
+	char *tagged_interface = hapd->conf->ssid.vlan_tagged_interface;
+	int vlan_naming = hapd->conf->ssid.vlan_naming;
+
+	wpa_printf(MSG_DEBUG, "VLAN: vlan_dellink(%s)", ifname);
+
+	first = prev = vlan;
+
+	while (vlan) {
+		if (os_strcmp(ifname, vlan->ifname) == 0) {
+			os_snprintf(br_name, sizeof(br_name), "brvlan%d",
+				    vlan->vlan_id);
+
+			if (vlan->clean & DVLAN_CLEAN_WLAN_PORT)
+				br_delif(br_name, vlan->ifname);
+
+			if (tagged_interface) {
+				if (vlan_naming ==
+				    DYNAMIC_VLAN_NAMING_WITH_DEVICE)
+					os_snprintf(vlan_ifname,
+						    sizeof(vlan_ifname),
+						    "%s.%d", tagged_interface,
+						    vlan->vlan_id);
+				else
+					os_snprintf(vlan_ifname,
+						    sizeof(vlan_ifname),
+						    "vlan%d", vlan->vlan_id);
+				if (vlan->clean & DVLAN_CLEAN_VLAN_PORT)
+					br_delif(br_name, vlan_ifname);
+				ifconfig_down(vlan_ifname);
+
+				if (vlan->clean & DVLAN_CLEAN_VLAN)
+					vlan_rem(vlan_ifname);
+			}
+
+			if ((vlan->clean & DVLAN_CLEAN_BR) &&
+			    br_getnumports(br_name) == 0) {
+				ifconfig_down(br_name);
+				br_delbr(br_name);
+			}
+
+			if (vlan == first) {
+				hapd->conf->vlan = vlan->next;
+			} else {
+				prev->next = vlan->next;
+			}
+			os_free(vlan);
+
+			break;
+		}
+		prev = vlan;
+		vlan = vlan->next;
+	}
+}
+
+
+static void
+vlan_read_ifnames(struct nlmsghdr *h, size_t len, int del,
+		  struct hostapd_data *hapd)
+{
+	struct ifinfomsg *ifi;
+	int attrlen, nlmsg_len, rta_len;
+	struct rtattr *attr;
+
+	if (len < sizeof(*ifi))
+		return;
+
+	ifi = NLMSG_DATA(h);
+
+	nlmsg_len = NLMSG_ALIGN(sizeof(struct ifinfomsg));
+
+	attrlen = h->nlmsg_len - nlmsg_len;
+	if (attrlen < 0)
+		return;
+
+	attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+
+	rta_len = RTA_ALIGN(sizeof(struct rtattr));
+	while (RTA_OK(attr, attrlen)) {
+		char ifname[IFNAMSIZ + 1];
+
+		if (attr->rta_type == IFLA_IFNAME) {
+			int n = attr->rta_len - rta_len;
+			if (n < 0)
+				break;
+
+			os_memset(ifname, 0, sizeof(ifname));
+
+			if ((size_t) n > sizeof(ifname))
+				n = sizeof(ifname);
+			os_memcpy(ifname, ((char *) attr) + rta_len, n);
+
+			if (del)
+				vlan_dellink(ifname, hapd);
+			else
+				vlan_newlink(ifname, hapd);
+		}
+
+		attr = RTA_NEXT(attr, attrlen);
+	}
+}
+
+
+static void vlan_event_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	char buf[8192];
+	int left;
+	struct sockaddr_nl from;
+	socklen_t fromlen;
+	struct nlmsghdr *h;
+	struct hostapd_data *hapd = eloop_ctx;
+
+	fromlen = sizeof(from);
+	left = recvfrom(sock, buf, sizeof(buf), MSG_DONTWAIT,
+			(struct sockaddr *) &from, &fromlen);
+	if (left < 0) {
+		if (errno != EINTR && errno != EAGAIN)
+			wpa_printf(MSG_ERROR, "VLAN: %s: recvfrom failed: %s",
+				   __func__, strerror(errno));
+		return;
+	}
+
+	h = (struct nlmsghdr *) buf;
+	while (left >= (int) sizeof(*h)) {
+		int len, plen;
+
+		len = h->nlmsg_len;
+		plen = len - sizeof(*h);
+		if (len > left || plen < 0) {
+			wpa_printf(MSG_DEBUG, "VLAN: Malformed netlink "
+				   "message: len=%d left=%d plen=%d",
+				   len, left, plen);
+			break;
+		}
+
+		switch (h->nlmsg_type) {
+		case RTM_NEWLINK:
+			vlan_read_ifnames(h, plen, 0, hapd);
+			break;
+		case RTM_DELLINK:
+			vlan_read_ifnames(h, plen, 1, hapd);
+			break;
+		}
+
+		len = NLMSG_ALIGN(len);
+		left -= len;
+		h = (struct nlmsghdr *) ((char *) h + len);
+	}
+
+	if (left > 0) {
+		wpa_printf(MSG_DEBUG, "VLAN: %s: %d extra bytes in the end of "
+			   "netlink message", __func__, left);
+	}
+}
+
+
+static struct full_dynamic_vlan *
+full_dynamic_vlan_init(struct hostapd_data *hapd)
+{
+	struct sockaddr_nl local;
+	struct full_dynamic_vlan *priv;
+
+	priv = os_zalloc(sizeof(*priv));
+	if (priv == NULL)
+		return NULL;
+
+#ifndef CONFIG_VLAN_NETLINK
+	vlan_set_name_type(hapd->conf->ssid.vlan_naming ==
+			   DYNAMIC_VLAN_NAMING_WITH_DEVICE ?
+			   VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD :
+			   VLAN_NAME_TYPE_PLUS_VID_NO_PAD);
+#endif /* CONFIG_VLAN_NETLINK */
+
+	priv->s = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
+	if (priv->s < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: socket(PF_NETLINK,SOCK_RAW,"
+			   "NETLINK_ROUTE) failed: %s",
+			   __func__, strerror(errno));
+		os_free(priv);
+		return NULL;
+	}
+
+	os_memset(&local, 0, sizeof(local));
+	local.nl_family = AF_NETLINK;
+	local.nl_groups = RTMGRP_LINK;
+	if (bind(priv->s, (struct sockaddr *) &local, sizeof(local)) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: %s: bind(netlink) failed: %s",
+			   __func__, strerror(errno));
+		close(priv->s);
+		os_free(priv);
+		return NULL;
+	}
+
+	if (eloop_register_read_sock(priv->s, vlan_event_receive, hapd, NULL))
+	{
+		close(priv->s);
+		os_free(priv);
+		return NULL;
+	}
+
+	return priv;
+}
+
+
+static void full_dynamic_vlan_deinit(struct full_dynamic_vlan *priv)
+{
+	if (priv == NULL)
+		return;
+	eloop_unregister_read_sock(priv->s);
+	close(priv->s);
+	os_free(priv);
+}
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+
+int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
+			      struct hostapd_ssid *mssid, const char *dyn_vlan)
+{
+        int i;
+
+        if (dyn_vlan == NULL)
+		return 0;
+
+	/* Static WEP keys are set here; IEEE 802.1X and WPA uses their own
+	 * functions for setting up dynamic broadcast keys. */
+	for (i = 0; i < 4; i++) {
+		if (mssid->wep.key[i] &&
+		    hostapd_drv_set_key(dyn_vlan, hapd, WPA_ALG_WEP, NULL, i,
+					i == mssid->wep.idx, NULL, 0,
+					mssid->wep.key[i], mssid->wep.len[i]))
+		{
+			wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
+				   "encryption for dynamic VLAN");
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+static int vlan_dynamic_add(struct hostapd_data *hapd,
+			    struct hostapd_vlan *vlan)
+{
+	while (vlan) {
+		if (vlan->vlan_id != VLAN_ID_WILDCARD) {
+			if (hostapd_vlan_if_add(hapd, vlan->ifname)) {
+				if (errno != EEXIST) {
+					wpa_printf(MSG_ERROR, "VLAN: Could "
+						   "not add VLAN %s: %s",
+						   vlan->ifname,
+						   strerror(errno));
+					return -1;
+				}
+			}
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+			ifconfig_up(vlan->ifname);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+		}
+
+		vlan = vlan->next;
+	}
+
+	return 0;
+}
+
+
+static void vlan_dynamic_remove(struct hostapd_data *hapd,
+				struct hostapd_vlan *vlan)
+{
+	struct hostapd_vlan *next;
+
+	while (vlan) {
+		next = vlan->next;
+
+		if (vlan->vlan_id != VLAN_ID_WILDCARD &&
+		    hostapd_vlan_if_remove(hapd, vlan->ifname)) {
+			wpa_printf(MSG_ERROR, "VLAN: Could not remove VLAN "
+				   "iface: %s: %s",
+				   vlan->ifname, strerror(errno));
+		}
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+		if (vlan->clean)
+			vlan_dellink(vlan->ifname, hapd);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+		vlan = next;
+	}
+}
+
+
+int vlan_init(struct hostapd_data *hapd)
+{
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	hapd->full_dynamic_vlan = full_dynamic_vlan_init(hapd);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+	if (vlan_dynamic_add(hapd, hapd->conf->vlan))
+		return -1;
+
+        return 0;
+}
+
+
+void vlan_deinit(struct hostapd_data *hapd)
+{
+	vlan_dynamic_remove(hapd, hapd->conf->vlan);
+
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	full_dynamic_vlan_deinit(hapd->full_dynamic_vlan);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+}
+
+
+struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
+				       struct hostapd_vlan *vlan,
+				       int vlan_id)
+{
+	struct hostapd_vlan *n;
+	char *ifname, *pos;
+
+	if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
+	    vlan->vlan_id != VLAN_ID_WILDCARD)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d ifname=%s)",
+		   __func__, vlan_id, vlan->ifname);
+	ifname = os_strdup(vlan->ifname);
+	if (ifname == NULL)
+		return NULL;
+	pos = os_strchr(ifname, '#');
+	if (pos == NULL) {
+		os_free(ifname);
+		return NULL;
+	}
+	*pos++ = '\0';
+
+	n = os_zalloc(sizeof(*n));
+	if (n == NULL) {
+		os_free(ifname);
+		return NULL;
+	}
+
+	n->vlan_id = vlan_id;
+	n->dynamic_vlan = 1;
+
+	os_snprintf(n->ifname, sizeof(n->ifname), "%s%d%s", ifname, vlan_id,
+		    pos);
+	os_free(ifname);
+
+	if (hostapd_vlan_if_add(hapd, n->ifname)) {
+		os_free(n);
+		return NULL;
+	}
+
+	n->next = hapd->conf->vlan;
+	hapd->conf->vlan = n;
+
+#ifdef CONFIG_FULL_DYNAMIC_VLAN
+	ifconfig_up(n->ifname);
+#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+
+	return n;
+}
+
+
+int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
+{
+	struct hostapd_vlan *vlan;
+
+	if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
+		return 1;
+
+	wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id);
+
+	vlan = hapd->conf->vlan;
+	while (vlan) {
+		if (vlan->vlan_id == vlan_id && vlan->dynamic_vlan > 0) {
+			vlan->dynamic_vlan--;
+			break;
+		}
+		vlan = vlan->next;
+	}
+
+	if (vlan == NULL)
+		return 1;
+
+	if (vlan->dynamic_vlan == 0)
+		hostapd_vlan_if_remove(hapd, vlan->ifname);
+
+	return 0;
+}
diff --git a/hostap/src/ap/vlan_init.h b/hostap/src/ap/vlan_init.h
new file mode 100644
index 0000000..382d5de
--- /dev/null
+++ b/hostap/src/ap/vlan_init.h
@@ -0,0 +1,59 @@
+/*
+ * hostapd / VLAN initialization
+ * Copyright 2003, Instant802 Networks, Inc.
+ * Copyright 2005, 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 VLAN_INIT_H
+#define VLAN_INIT_H
+
+#ifndef CONFIG_NO_VLAN
+int vlan_init(struct hostapd_data *hapd);
+void vlan_deinit(struct hostapd_data *hapd);
+struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
+				       struct hostapd_vlan *vlan,
+				       int vlan_id);
+int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id);
+int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
+			      struct hostapd_ssid *mssid,
+			      const char *dyn_vlan);
+#else /* CONFIG_NO_VLAN */
+static inline int vlan_init(struct hostapd_data *hapd)
+{
+	return 0;
+}
+
+static inline void vlan_deinit(struct hostapd_data *hapd)
+{
+}
+
+static inline struct hostapd_vlan * vlan_add_dynamic(struct hostapd_data *hapd,
+						     struct hostapd_vlan *vlan,
+						     int vlan_id)
+{
+	return NULL;
+}
+
+static inline int vlan_remove_dynamic(struct hostapd_data *hapd, int vlan_id)
+{
+	return -1;
+}
+
+static inline int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
+					    struct hostapd_ssid *mssid,
+					    const char *dyn_vlan)
+{
+	return -1;
+}
+#endif /* CONFIG_NO_VLAN */
+
+#endif /* VLAN_INIT_H */
diff --git a/hostap/src/ap/vlan_util.c b/hostap/src/ap/vlan_util.c
new file mode 100644
index 0000000..cc54051
--- /dev/null
+++ b/hostap/src/ap/vlan_util.c
@@ -0,0 +1,177 @@
+/*
+ * hostapd / VLAN netlink api
+ * Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+#include <sys/ioctl.h>
+#include <linux/sockios.h>
+#include <linux/if_vlan.h>
+#include <netlink/genl/genl.h>
+#include <netlink/genl/family.h>
+#include <netlink/genl/ctrl.h>
+#include <netlink/route/link.h>
+#include <netlink/route/link/vlan.h>
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "hostapd.h"
+#include "vlan_util.h"
+
+/*
+ * Add a vlan interface with name 'vlan_if_name', VLAN ID 'vid' and
+ * tagged interface 'if_name'.
+ *
+ * returns -1 on error
+ * returns 1 if the interface already exists
+ * returns 0 otherwise
+*/
+int vlan_add(const char *if_name, int vid, const char *vlan_if_name)
+{
+	int ret = -1;
+	struct nl_sock *handle = NULL;
+	struct nl_cache *cache = NULL;
+	struct rtnl_link *rlink = NULL;
+	int if_idx = 0;
+
+	wpa_printf(MSG_DEBUG, "VLAN: vlan_add(if_name=%s, vid=%d, "
+		   "vlan_if_name=%s)", if_name, vid, vlan_if_name);
+
+	if ((os_strlen(if_name) + 1) > IFNAMSIZ) {
+		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+			   if_name);
+		return -1;
+	}
+
+	if ((os_strlen(vlan_if_name) + 1) > IFNAMSIZ) {
+		wpa_printf(MSG_ERROR, "VLAN: Interface name too long: '%s'",
+			   vlan_if_name);
+		return -1;
+	}
+
+	handle = nl_socket_alloc();
+	if (!handle) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
+		goto vlan_add_error;
+	}
+
+	if (nl_connect(handle, NETLINK_ROUTE) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
+		goto vlan_add_error;
+	}
+
+	if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
+		cache = NULL;
+		wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
+		goto vlan_add_error;
+	}
+
+	if (!(if_idx = rtnl_link_name2i(cache, if_name))) {
+		/* link does not exist */
+		wpa_printf(MSG_ERROR, "VLAN: interface %s does not exist",
+			   if_name);
+		goto vlan_add_error;
+	}
+
+	if ((rlink = rtnl_link_get_by_name(cache, vlan_if_name))) {
+		/* link does exist */
+		rtnl_link_put(rlink);
+		rlink = NULL;
+		wpa_printf(MSG_ERROR, "VLAN: interface %s already exists",
+			   vlan_if_name);
+		ret = 1;
+		goto vlan_add_error;
+	}
+
+	rlink = rtnl_link_alloc();
+	if (!rlink) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to allocate new link");
+		goto vlan_add_error;
+	}
+
+	if (rtnl_link_set_type(rlink, "vlan") < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to set link type");
+		goto vlan_add_error;
+	}
+
+	rtnl_link_set_link(rlink, if_idx);
+	rtnl_link_set_name(rlink, vlan_if_name);
+
+	if (rtnl_link_vlan_set_id(rlink, vid) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to set link vlan id");
+		goto vlan_add_error;
+	}
+
+	if (rtnl_link_add(handle, rlink, NLM_F_CREATE) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to create link %s for "
+			   "vlan %d on %s (%d)",
+			   vlan_if_name, vid, if_name, if_idx);
+		goto vlan_add_error;
+	}
+
+	ret = 0;
+
+vlan_add_error:
+	if (rlink)
+		rtnl_link_put(rlink);
+	if (cache)
+		nl_cache_free(cache);
+	if (handle)
+		nl_socket_free(handle);
+	return ret;
+}
+
+
+int vlan_rem(const char *if_name)
+{
+	int ret = -1;
+	struct nl_sock *handle = NULL;
+	struct nl_cache *cache = NULL;
+	struct rtnl_link *rlink = NULL;
+
+	wpa_printf(MSG_DEBUG, "VLAN: vlan_rem(if_name=%s)", if_name);
+
+	handle = nl_socket_alloc();
+	if (!handle) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to open netlink socket");
+		goto vlan_rem_error;
+	}
+
+	if (nl_connect(handle, NETLINK_ROUTE) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to connect to netlink");
+		goto vlan_rem_error;
+	}
+
+	if (rtnl_link_alloc_cache(handle, AF_UNSPEC, &cache) < 0) {
+		cache = NULL;
+		wpa_printf(MSG_ERROR, "VLAN: failed to alloc cache");
+		goto vlan_rem_error;
+	}
+
+	if (!(rlink = rtnl_link_get_by_name(cache, if_name))) {
+		/* link does not exist */
+		wpa_printf(MSG_ERROR, "VLAN: interface %s does not exists",
+			   if_name);
+		goto vlan_rem_error;
+	}
+
+	if (rtnl_link_delete(handle, rlink) < 0) {
+		wpa_printf(MSG_ERROR, "VLAN: failed to remove link %s",
+			   if_name);
+		goto vlan_rem_error;
+	}
+
+	ret = 0;
+
+vlan_rem_error:
+	if (rlink)
+		rtnl_link_put(rlink);
+	if (cache)
+		nl_cache_free(cache);
+	if (handle)
+		nl_socket_free(handle);
+	return ret;
+}
diff --git a/hostap/src/ap/vlan_util.h b/hostap/src/ap/vlan_util.h
new file mode 100644
index 0000000..bef5a16
--- /dev/null
+++ b/hostap/src/ap/vlan_util.h
@@ -0,0 +1,15 @@
+/*
+ * hostapd / VLAN netlink api
+ * Copyright (c) 2012, Michael Braun <michael-dev@fami-braun.de>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef VLAN_UTIL_H
+#define VLAN_UTIL_H
+
+int vlan_add(const char *if_name, int vid, const char *vlan_if_name);
+int vlan_rem(const char *if_name);
+
+#endif /* VLAN_UTIL_H */
diff --git a/hostap/src/ap/wmm.c b/hostap/src/ap/wmm.c
new file mode 100644
index 0000000..d21c82f
--- /dev/null
+++ b/hostap/src/ap/wmm.c
@@ -0,0 +1,330 @@
+/*
+ * hostapd / WMM (Wi-Fi Multimedia)
+ * Copyright 2002-2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "hostapd.h"
+#include "ieee802_11.h"
+#include "sta_info.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "wmm.h"
+
+
+/* TODO: maintain separate sequence and fragment numbers for each AC
+ * TODO: IGMP snooping to track which multicasts to forward - and use QOS-DATA
+ * if only WMM stations are receiving a certain group */
+
+
+static inline u8 wmm_aci_aifsn(int aifsn, int acm, int aci)
+{
+	u8 ret;
+	ret = (aifsn << WMM_AC_AIFNS_SHIFT) & WMM_AC_AIFSN_MASK;
+	if (acm)
+		ret |= WMM_AC_ACM;
+	ret |= (aci << WMM_AC_ACI_SHIFT) & WMM_AC_ACI_MASK;
+	return ret;
+}
+
+
+static inline u8 wmm_ecw(int ecwmin, int ecwmax)
+{
+	return ((ecwmin << WMM_AC_ECWMIN_SHIFT) & WMM_AC_ECWMIN_MASK) |
+		((ecwmax << WMM_AC_ECWMAX_SHIFT) & WMM_AC_ECWMAX_MASK);
+}
+
+
+/*
+ * Add WMM Parameter Element to Beacon, Probe Response, and (Re)Association
+ * Response frames.
+ */
+u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid)
+{
+	u8 *pos = eid;
+	struct wmm_parameter_element *wmm =
+		(struct wmm_parameter_element *) (pos + 2);
+	int e;
+
+	if (!hapd->conf->wmm_enabled)
+		return eid;
+	eid[0] = WLAN_EID_VENDOR_SPECIFIC;
+	wmm->oui[0] = 0x00;
+	wmm->oui[1] = 0x50;
+	wmm->oui[2] = 0xf2;
+	wmm->oui_type = WMM_OUI_TYPE;
+	wmm->oui_subtype = WMM_OUI_SUBTYPE_PARAMETER_ELEMENT;
+	wmm->version = WMM_VERSION;
+	wmm->qos_info = hapd->parameter_set_count & 0xf;
+
+	if (hapd->conf->wmm_uapsd &&
+	    (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_UAPSD))
+		wmm->qos_info |= 0x80;
+
+	wmm->reserved = 0;
+
+	/* fill in a parameter set record for each AC */
+	for (e = 0; e < 4; e++) {
+		struct wmm_ac_parameter *ac = &wmm->ac[e];
+		struct hostapd_wmm_ac_params *acp =
+			&hapd->iconf->wmm_ac_params[e];
+
+		ac->aci_aifsn = wmm_aci_aifsn(acp->aifs,
+					      acp->admission_control_mandatory,
+					      e);
+		ac->cw = wmm_ecw(acp->cwmin, acp->cwmax);
+		ac->txop_limit = host_to_le16(acp->txop_limit);
+	}
+
+	pos = (u8 *) (wmm + 1);
+	eid[1] = pos - eid - 2; /* element length */
+
+	return pos;
+}
+
+
+/*
+ * This function is called when a station sends an association request with
+ * WMM info element. The function returns 1 on success or 0 on any error in WMM
+ * element. eid does not include Element ID and Length octets.
+ */
+int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid, size_t len)
+{
+	struct wmm_information_element *wmm;
+
+	wpa_hexdump(MSG_MSGDUMP, "WMM IE", eid, len);
+
+	if (len < sizeof(struct wmm_information_element)) {
+		wpa_printf(MSG_DEBUG, "Too short WMM IE (len=%lu)",
+			   (unsigned long) len);
+		return 0;
+	}
+
+	wmm = (struct wmm_information_element *) eid;
+	wpa_printf(MSG_DEBUG, "Validating WMM IE: OUI %02x:%02x:%02x  "
+		   "OUI type %d  OUI sub-type %d  version %d  QoS info 0x%x",
+		   wmm->oui[0], wmm->oui[1], wmm->oui[2], wmm->oui_type,
+		   wmm->oui_subtype, wmm->version, wmm->qos_info);
+	if (wmm->oui_subtype != WMM_OUI_SUBTYPE_INFORMATION_ELEMENT ||
+	    wmm->version != WMM_VERSION) {
+		wpa_printf(MSG_DEBUG, "Unsupported WMM IE Subtype/Version");
+		return 0;
+	}
+
+	return 1;
+}
+
+
+static void wmm_send_action(struct hostapd_data *hapd, const u8 *addr,
+			    const struct wmm_tspec_element *tspec,
+			    u8 action_code, u8 dialogue_token, u8 status_code)
+{
+	u8 buf[256];
+	struct ieee80211_mgmt *m = (struct ieee80211_mgmt *) buf;
+	struct wmm_tspec_element *t = (struct wmm_tspec_element *)
+		m->u.action.u.wmm_action.variable;
+	int len;
+
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "action response - reason %d", status_code);
+	os_memset(buf, 0, sizeof(buf));
+	m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					WLAN_FC_STYPE_ACTION);
+	os_memcpy(m->da, addr, ETH_ALEN);
+	os_memcpy(m->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
+	m->u.action.category = WLAN_ACTION_WMM;
+	m->u.action.u.wmm_action.action_code = action_code;
+	m->u.action.u.wmm_action.dialog_token = dialogue_token;
+	m->u.action.u.wmm_action.status_code = status_code;
+	os_memcpy(t, tspec, sizeof(struct wmm_tspec_element));
+	len = ((u8 *) (t + 1)) - buf;
+
+	if (hostapd_drv_send_mlme(hapd, m, len, 0) < 0)
+		perror("wmm_send_action: send");
+}
+
+
+int wmm_process_tspec(struct wmm_tspec_element *tspec)
+{
+	int medium_time, pps, duration;
+	int up, psb, dir, tid;
+	u16 val, surplus;
+
+	up = (tspec->ts_info[1] >> 3) & 0x07;
+	psb = (tspec->ts_info[1] >> 2) & 0x01;
+	dir = (tspec->ts_info[0] >> 5) & 0x03;
+	tid = (tspec->ts_info[0] >> 1) & 0x0f;
+	wpa_printf(MSG_DEBUG, "WMM: TS Info: UP=%d PSB=%d Direction=%d TID=%d",
+		   up, psb, dir, tid);
+	val = le_to_host16(tspec->nominal_msdu_size);
+	wpa_printf(MSG_DEBUG, "WMM: Nominal MSDU Size: %d%s",
+		   val & 0x7fff, val & 0x8000 ? " (fixed)" : "");
+	wpa_printf(MSG_DEBUG, "WMM: Mean Data Rate: %u bps",
+		   le_to_host32(tspec->mean_data_rate));
+	wpa_printf(MSG_DEBUG, "WMM: Minimum PHY Rate: %u bps",
+		   le_to_host32(tspec->minimum_phy_rate));
+	val = le_to_host16(tspec->surplus_bandwidth_allowance);
+	wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance: %u.%04u",
+		   val >> 13, 10000 * (val & 0x1fff) / 0x2000);
+
+	val = le_to_host16(tspec->nominal_msdu_size);
+	if (val == 0) {
+		wpa_printf(MSG_DEBUG, "WMM: Invalid Nominal MSDU Size (0)");
+		return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
+	}
+	/* pps = Ceiling((Mean Data Rate / 8) / Nominal MSDU Size) */
+	pps = ((le_to_host32(tspec->mean_data_rate) / 8) + val - 1) / val;
+	wpa_printf(MSG_DEBUG, "WMM: Packets-per-second estimate for TSPEC: %d",
+		   pps);
+
+	if (le_to_host32(tspec->minimum_phy_rate) < 1000000) {
+		wpa_printf(MSG_DEBUG, "WMM: Too small Minimum PHY Rate");
+		return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
+	}
+
+	duration = (le_to_host16(tspec->nominal_msdu_size) & 0x7fff) * 8 /
+		(le_to_host32(tspec->minimum_phy_rate) / 1000000) +
+		50 /* FIX: proper SIFS + ACK duration */;
+
+	/* unsigned binary number with an implicit binary point after the
+	 * leftmost 3 bits, i.e., 0x2000 = 1.0 */
+	surplus = le_to_host16(tspec->surplus_bandwidth_allowance);
+	if (surplus <= 0x2000) {
+		wpa_printf(MSG_DEBUG, "WMM: Surplus Bandwidth Allowance not "
+			   "greater than unity");
+		return WMM_ADDTS_STATUS_INVALID_PARAMETERS;
+	}
+
+	medium_time = surplus * pps * duration / 0x2000;
+	wpa_printf(MSG_DEBUG, "WMM: Estimated medium time: %u", medium_time);
+
+	/*
+	 * TODO: store list of granted (and still active) TSPECs and check
+	 * whether there is available medium time for this request. For now,
+	 * just refuse requests that would by themselves take very large
+	 * portion of the available bandwidth.
+	 */
+	if (medium_time > 750000) {
+		wpa_printf(MSG_DEBUG, "WMM: Refuse TSPEC request for over "
+			   "75%% of available bandwidth");
+		return WMM_ADDTS_STATUS_REFUSED;
+	}
+
+	/* Convert to 32 microseconds per second unit */
+	tspec->medium_time = host_to_le16(medium_time / 32);
+
+	return WMM_ADDTS_STATUS_ADMISSION_ACCEPTED;
+}
+
+
+static void wmm_addts_req(struct hostapd_data *hapd,
+			  const struct ieee80211_mgmt *mgmt,
+			  struct wmm_tspec_element *tspec, size_t len)
+{
+	const u8 *end = ((const u8 *) mgmt) + len;
+	int res;
+
+	if ((const u8 *) (tspec + 1) > end) {
+		wpa_printf(MSG_DEBUG, "WMM: TSPEC overflow in ADDTS Request");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "WMM: ADDTS Request (Dialog Token %d) for TSPEC "
+		   "from " MACSTR,
+		   mgmt->u.action.u.wmm_action.dialog_token,
+		   MAC2STR(mgmt->sa));
+
+	res = wmm_process_tspec(tspec);
+	wpa_printf(MSG_DEBUG, "WMM: ADDTS processing result: %d", res);
+
+	wmm_send_action(hapd, mgmt->sa, tspec, WMM_ACTION_CODE_ADDTS_RESP,
+			mgmt->u.action.u.wmm_action.dialog_token, res);
+}
+
+
+void hostapd_wmm_action(struct hostapd_data *hapd,
+			const struct ieee80211_mgmt *mgmt, size_t len)
+{
+	int action_code;
+	int left = len - IEEE80211_HDRLEN - 4;
+	const u8 *pos = ((const u8 *) mgmt) + IEEE80211_HDRLEN + 4;
+	struct ieee802_11_elems elems;
+	struct sta_info *sta = ap_get_sta(hapd, mgmt->sa);
+
+	/* check that the request comes from a valid station */
+	if (!sta ||
+	    (sta->flags & (WLAN_STA_ASSOC | WLAN_STA_WMM)) !=
+	    (WLAN_STA_ASSOC | WLAN_STA_WMM)) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "wmm action received is not from associated wmm"
+			       " station");
+		/* TODO: respond with action frame refused status code */
+		return;
+	}
+
+	/* extract the tspec info element */
+	if (ieee802_11_parse_elems(pos, left, &elems, 1) == ParseFailed) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "hostapd_wmm_action - could not parse wmm "
+			       "action");
+		/* TODO: respond with action frame invalid parameters status
+		 * code */
+		return;
+	}
+
+	if (!elems.wmm_tspec ||
+	    elems.wmm_tspec_len != (sizeof(struct wmm_tspec_element) - 2)) {
+		hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+			       HOSTAPD_LEVEL_DEBUG,
+			       "hostapd_wmm_action - missing or wrong length "
+			       "tspec");
+		/* TODO: respond with action frame invalid parameters status
+		 * code */
+		return;
+	}
+
+	/* TODO: check the request is for an AC with ACM set, if not, refuse
+	 * request */
+
+	action_code = mgmt->u.action.u.wmm_action.action_code;
+	switch (action_code) {
+	case WMM_ACTION_CODE_ADDTS_REQ:
+		wmm_addts_req(hapd, mgmt, (struct wmm_tspec_element *)
+			      (elems.wmm_tspec - 2), len);
+		return;
+#if 0
+	/* TODO: needed for client implementation */
+	case WMM_ACTION_CODE_ADDTS_RESP:
+		wmm_setup_request(hapd, mgmt, len);
+		return;
+	/* TODO: handle station teardown requests */
+	case WMM_ACTION_CODE_DELTS:
+		wmm_teardown(hapd, mgmt, len);
+		return;
+#endif
+	}
+
+	hostapd_logger(hapd, mgmt->sa, HOSTAPD_MODULE_IEEE80211,
+		       HOSTAPD_LEVEL_DEBUG,
+		       "hostapd_wmm_action - unknown action code %d",
+		       action_code);
+}
diff --git a/hostap/src/ap/wmm.h b/hostap/src/ap/wmm.h
new file mode 100644
index 0000000..96b04e8
--- /dev/null
+++ b/hostap/src/ap/wmm.h
@@ -0,0 +1,29 @@
+/*
+ * hostapd / WMM (Wi-Fi Multimedia)
+ * Copyright 2002-2003, Instant802 Networks, Inc.
+ * Copyright 2005-2006, Devicescape Software, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ *
+ * See README and COPYING for more details.
+ */
+
+#ifndef WME_H
+#define WME_H
+
+struct ieee80211_mgmt;
+struct wmm_tspec_element;
+
+u8 * hostapd_eid_wmm(struct hostapd_data *hapd, u8 *eid);
+int hostapd_eid_wmm_valid(struct hostapd_data *hapd, const u8 *eid,
+			  size_t len);
+void hostapd_wmm_action(struct hostapd_data *hapd,
+			const struct ieee80211_mgmt *mgmt, size_t len);
+int wmm_process_tspec(struct wmm_tspec_element *tspec);
+
+#endif /* WME_H */
diff --git a/hostap/src/ap/wnm_ap.c b/hostap/src/ap/wnm_ap.c
new file mode 100644
index 0000000..54a6b85
--- /dev/null
+++ b/hostap/src/ap/wnm_ap.c
@@ -0,0 +1,271 @@
+/*
+ * hostapd - WNM
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "ap/hostapd.h"
+#include "ap/sta_info.h"
+#include "ap/ap_config.h"
+#include "ap/ap_drv_ops.h"
+#include "ap/wpa_auth.h"
+#include "wnm_ap.h"
+
+#define MAX_TFS_IE_LEN  1024
+
+
+/* get the TFS IE from driver */
+static int ieee80211_11_get_tfs_ie(struct hostapd_data *hapd, const u8 *addr,
+				   u8 *buf, u16 *buf_len, enum wnm_oper oper)
+{
+	wpa_printf(MSG_DEBUG, "%s: TFS get operation %d", __func__, oper);
+
+	return hostapd_drv_wnm_oper(hapd, oper, addr, buf, buf_len);
+}
+
+
+/* set the TFS IE to driver */
+static int ieee80211_11_set_tfs_ie(struct hostapd_data *hapd, const u8 *addr,
+				   u8 *buf, u16 *buf_len, enum wnm_oper oper)
+{
+	wpa_printf(MSG_DEBUG, "%s: TFS set operation %d", __func__, oper);
+
+	return hostapd_drv_wnm_oper(hapd, oper, addr, buf, buf_len);
+}
+
+
+/* MLME-SLEEPMODE.response */
+static int ieee802_11_send_wnmsleep_resp(struct hostapd_data *hapd,
+					 const u8 *addr, u8 dialog_token,
+					 u8 action_type, u16 intval)
+{
+	struct ieee80211_mgmt *mgmt;
+	int res;
+	size_t len;
+	size_t gtk_elem_len = 0;
+	size_t igtk_elem_len = 0;
+	struct wnm_sleep_element wnmsleep_ie;
+	u8 *wnmtfs_ie;
+	u8 wnmsleep_ie_len;
+	u16 wnmtfs_ie_len;
+	u8 *pos;
+	struct sta_info *sta;
+	enum wnm_oper tfs_oper = action_type == WNM_SLEEP_MODE_ENTER ?
+		WNM_SLEEP_TFS_RESP_IE_ADD : WNM_SLEEP_TFS_RESP_IE_NONE;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL) {
+		wpa_printf(MSG_DEBUG, "%s: station not found", __func__);
+		return -EINVAL;
+	}
+
+	/* WNM-Sleep Mode IE */
+	os_memset(&wnmsleep_ie, 0, sizeof(struct wnm_sleep_element));
+	wnmsleep_ie_len = sizeof(struct wnm_sleep_element);
+	wnmsleep_ie.eid = WLAN_EID_WNMSLEEP;
+	wnmsleep_ie.len = wnmsleep_ie_len - 2;
+	wnmsleep_ie.action_type = action_type;
+	wnmsleep_ie.status = WNM_STATUS_SLEEP_ACCEPT;
+	wnmsleep_ie.intval = intval;
+
+	/* TFS IE(s) */
+	wnmtfs_ie = os_zalloc(MAX_TFS_IE_LEN);
+	if (wnmtfs_ie == NULL)
+		return -1;
+	if (ieee80211_11_get_tfs_ie(hapd, addr, wnmtfs_ie, &wnmtfs_ie_len,
+				    tfs_oper)) {
+		wnmtfs_ie_len = 0;
+		os_free(wnmtfs_ie);
+		wnmtfs_ie = NULL;
+	}
+
+#define MAX_GTK_SUBELEM_LEN 45
+#define MAX_IGTK_SUBELEM_LEN 26
+	mgmt = os_zalloc(sizeof(*mgmt) + wnmsleep_ie_len +
+			 MAX_GTK_SUBELEM_LEN + MAX_IGTK_SUBELEM_LEN);
+	if (mgmt == NULL) {
+		wpa_printf(MSG_DEBUG, "MLME: Failed to allocate buffer for "
+			   "WNM-Sleep Response action frame");
+		return -1;
+	}
+	os_memcpy(mgmt->da, addr, ETH_ALEN);
+	os_memcpy(mgmt->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(mgmt->bssid, hapd->own_addr, ETH_ALEN);
+	mgmt->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					   WLAN_FC_STYPE_ACTION);
+	mgmt->u.action.category = WLAN_ACTION_WNM;
+	mgmt->u.action.u.wnm_sleep_resp.action = WNM_SLEEP_MODE_RESP;
+	mgmt->u.action.u.wnm_sleep_resp.dialogtoken = dialog_token;
+	pos = (u8 *)mgmt->u.action.u.wnm_sleep_resp.variable;
+	/* add key data if MFP is enabled */
+	if (!wpa_auth_uses_mfp(sta->wpa_sm) ||
+	    action_type != WNM_SLEEP_MODE_EXIT) {
+		mgmt->u.action.u.wnm_sleep_resp.keydata_len = 0;
+	} else {
+		gtk_elem_len = wpa_wnmsleep_gtk_subelem(sta->wpa_sm, pos);
+		pos += gtk_elem_len;
+		wpa_printf(MSG_DEBUG, "Pass 4, gtk_len = %d",
+			   (int) gtk_elem_len);
+#ifdef CONFIG_IEEE80211W
+		res = wpa_wnmsleep_igtk_subelem(sta->wpa_sm, pos);
+		if (res < 0) {
+			os_free(wnmtfs_ie);
+			os_free(mgmt);
+			return -1;
+		}
+		igtk_elem_len = res;
+		pos += igtk_elem_len;
+		wpa_printf(MSG_DEBUG, "Pass 4 igtk_len = %d",
+			   (int) igtk_elem_len);
+#endif /* CONFIG_IEEE80211W */
+
+		WPA_PUT_LE16((u8 *)
+			     &mgmt->u.action.u.wnm_sleep_resp.keydata_len,
+			     gtk_elem_len + igtk_elem_len);
+	}
+	os_memcpy(pos, &wnmsleep_ie, wnmsleep_ie_len);
+	/* copy TFS IE here */
+	pos += wnmsleep_ie_len;
+	if (wnmtfs_ie)
+		os_memcpy(pos, wnmtfs_ie, wnmtfs_ie_len);
+
+	len = 1 + sizeof(mgmt->u.action.u.wnm_sleep_resp) + gtk_elem_len +
+		igtk_elem_len + wnmsleep_ie_len + wnmtfs_ie_len;
+
+	/* In driver, response frame should be forced to sent when STA is in
+	 * PS mode */
+	res = hostapd_drv_send_action(hapd, hapd->iface->freq, 0,
+				      mgmt->da, &mgmt->u.action.category, len);
+
+	if (!res) {
+		wpa_printf(MSG_DEBUG, "Successfully send WNM-Sleep Response "
+			   "frame");
+
+		/* when entering wnmsleep
+		 * 1. pause the node in driver
+		 * 2. mark the node so that AP won't update GTK/IGTK during
+		 * WNM Sleep
+		 */
+		if (wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT &&
+		    wnmsleep_ie.action_type == WNM_SLEEP_MODE_ENTER) {
+			hostapd_drv_wnm_oper(hapd, WNM_SLEEP_ENTER_CONFIRM,
+					     addr, NULL, NULL);
+			wpa_set_wnmsleep(sta->wpa_sm, 1);
+		}
+		/* when exiting wnmsleep
+		 * 1. unmark the node
+		 * 2. start GTK/IGTK update if MFP is not used
+		 * 3. unpause the node in driver
+		 */
+		if ((wnmsleep_ie.status == WNM_STATUS_SLEEP_ACCEPT ||
+		     wnmsleep_ie.status ==
+		     WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE) &&
+		    wnmsleep_ie.action_type == WNM_SLEEP_MODE_EXIT) {
+			wpa_set_wnmsleep(sta->wpa_sm, 0);
+			hostapd_drv_wnm_oper(hapd, WNM_SLEEP_EXIT_CONFIRM,
+					     addr, NULL, NULL);
+			if (!wpa_auth_uses_mfp(sta->wpa_sm))
+				wpa_wnmsleep_rekey_gtk(sta->wpa_sm);
+		}
+	} else
+		wpa_printf(MSG_DEBUG, "Fail to send WNM-Sleep Response frame");
+
+#undef MAX_GTK_SUBELEM_LEN
+#undef MAX_IGTK_SUBELEM_LEN
+	os_free(wnmtfs_ie);
+	os_free(mgmt);
+	return res;
+}
+
+
+static void ieee802_11_rx_wnmsleep_req(struct hostapd_data *hapd,
+				       const u8 *addr, const u8 *frm, int len)
+{
+	/* Dialog Token [1] | WNM-Sleep Mode IE | TFS Response IE */
+	const u8 *pos = frm;
+	u8 dialog_token;
+	struct wnm_sleep_element *wnmsleep_ie = NULL;
+	/* multiple TFS Req IE (assuming consecutive) */
+	u8 *tfsreq_ie_start = NULL;
+	u8 *tfsreq_ie_end = NULL;
+	u16 tfsreq_ie_len = 0;
+
+	dialog_token = *pos++;
+	while (pos + 1 < frm + len) {
+		u8 ie_len = pos[1];
+		if (pos + 2 + ie_len > frm + len)
+			break;
+		if (*pos == WLAN_EID_WNMSLEEP)
+			wnmsleep_ie = (struct wnm_sleep_element *) pos;
+		else if (*pos == WLAN_EID_TFS_REQ) {
+			if (!tfsreq_ie_start)
+				tfsreq_ie_start = (u8 *) pos;
+			tfsreq_ie_end = (u8 *) pos;
+		} else
+			wpa_printf(MSG_DEBUG, "WNM: EID %d not recognized",
+				   *pos);
+		pos += ie_len + 2;
+	}
+
+	if (!wnmsleep_ie) {
+		wpa_printf(MSG_DEBUG, "No WNM-Sleep IE found");
+		return;
+	}
+
+	if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_ENTER &&
+	    tfsreq_ie_start && tfsreq_ie_end &&
+	    tfsreq_ie_end - tfsreq_ie_start >= 0) {
+		tfsreq_ie_len = (tfsreq_ie_end + tfsreq_ie_end[1] + 2) -
+			tfsreq_ie_start;
+		wpa_printf(MSG_DEBUG, "TFS Req IE(s) found");
+		/* pass the TFS Req IE(s) to driver for processing */
+		if (ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start,
+					    &tfsreq_ie_len,
+					    WNM_SLEEP_TFS_REQ_IE_SET))
+			wpa_printf(MSG_DEBUG, "Fail to set TFS Req IE");
+	}
+
+	ieee802_11_send_wnmsleep_resp(hapd, addr, dialog_token,
+				      wnmsleep_ie->action_type,
+				      wnmsleep_ie->intval);
+
+	if (wnmsleep_ie->action_type == WNM_SLEEP_MODE_EXIT) {
+		/* clear the tfs after sending the resp frame */
+		ieee80211_11_set_tfs_ie(hapd, addr, tfsreq_ie_start,
+					&tfsreq_ie_len, WNM_SLEEP_TFS_IE_DEL);
+	}
+}
+
+
+int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
+				struct rx_action *action)
+{
+	if (action->len < 1 || action->data == NULL)
+		return -1;
+
+	switch (action->data[0]) {
+	case WNM_BSS_TRANS_MGMT_QUERY:
+		wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management Query");
+		/* TODO */
+		return -1;
+	case WNM_BSS_TRANS_MGMT_RESP:
+		wpa_printf(MSG_DEBUG, "WNM: BSS Transition Management "
+			   "Response");
+		/* TODO */
+		return -1;
+	case WNM_SLEEP_MODE_REQ:
+		ieee802_11_rx_wnmsleep_req(hapd, action->sa, action->data + 1,
+					   action->len - 1);
+		return 0;
+	}
+
+	wpa_printf(MSG_DEBUG, "WNM: Unsupported WNM Action %u from " MACSTR,
+		   action->data[0], MAC2STR(action->sa));
+	return -1;
+}
diff --git a/hostap/src/ap/wnm_ap.h b/hostap/src/ap/wnm_ap.h
new file mode 100644
index 0000000..f05726e
--- /dev/null
+++ b/hostap/src/ap/wnm_ap.h
@@ -0,0 +1,17 @@
+/*
+ * IEEE 802.11v WNM related functions and structures
+ * Copyright (c) 2011-2012, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WNM_AP_H
+#define WNM_AP_H
+
+struct rx_action;
+
+int ieee802_11_rx_wnm_action_ap(struct hostapd_data *hapd,
+				struct rx_action *action);
+
+#endif /* WNM_AP_H */
diff --git a/hostap/src/ap/wpa_auth.c b/hostap/src/ap/wpa_auth.c
new file mode 100644
index 0000000..2c70149
--- /dev/null
+++ b/hostap/src/ap/wpa_auth.c
@@ -0,0 +1,3022 @@
+/*
+ * IEEE 802.11 RSN / WPA Authenticator
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/state_machine.h"
+#include "common/ieee802_11_defs.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/random.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "ap_config.h"
+#include "ieee802_11.h"
+#include "wpa_auth.h"
+#include "pmksa_cache_auth.h"
+#include "wpa_auth_i.h"
+#include "wpa_auth_ie.h"
+
+#define STATE_MACHINE_DATA struct wpa_state_machine
+#define STATE_MACHINE_DEBUG_PREFIX "WPA"
+#define STATE_MACHINE_ADDR sm->addr
+
+
+static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx);
+static int wpa_sm_step(struct wpa_state_machine *sm);
+static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len);
+static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx);
+static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
+			      struct wpa_group *group);
+static void wpa_request_new_ptk(struct wpa_state_machine *sm);
+static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
+			  struct wpa_group *group);
+static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
+				       struct wpa_group *group);
+
+static const u32 dot11RSNAConfigGroupUpdateCount = 4;
+static const u32 dot11RSNAConfigPairwiseUpdateCount = 4;
+static const u32 eapol_key_timeout_first = 100; /* ms */
+static const u32 eapol_key_timeout_subseq = 1000; /* ms */
+static const u32 eapol_key_timeout_first_group = 500; /* ms */
+
+/* TODO: make these configurable */
+static const int dot11RSNAConfigPMKLifetime = 43200;
+static const int dot11RSNAConfigPMKReauthThreshold = 70;
+static const int dot11RSNAConfigSATimeout = 60;
+
+
+static inline int wpa_auth_mic_failure_report(
+	struct wpa_authenticator *wpa_auth, const u8 *addr)
+{
+	if (wpa_auth->cb.mic_failure_report)
+		return wpa_auth->cb.mic_failure_report(wpa_auth->cb.ctx, addr);
+	return 0;
+}
+
+
+static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
+				      const u8 *addr, wpa_eapol_variable var,
+				      int value)
+{
+	if (wpa_auth->cb.set_eapol)
+		wpa_auth->cb.set_eapol(wpa_auth->cb.ctx, addr, var, value);
+}
+
+
+static inline int wpa_auth_get_eapol(struct wpa_authenticator *wpa_auth,
+				     const u8 *addr, wpa_eapol_variable var)
+{
+	if (wpa_auth->cb.get_eapol == NULL)
+		return -1;
+	return wpa_auth->cb.get_eapol(wpa_auth->cb.ctx, addr, var);
+}
+
+
+static inline const u8 * wpa_auth_get_psk(struct wpa_authenticator *wpa_auth,
+					  const u8 *addr, const u8 *prev_psk)
+{
+	if (wpa_auth->cb.get_psk == NULL)
+		return NULL;
+	return wpa_auth->cb.get_psk(wpa_auth->cb.ctx, addr, prev_psk);
+}
+
+
+static inline int wpa_auth_get_msk(struct wpa_authenticator *wpa_auth,
+				   const u8 *addr, u8 *msk, size_t *len)
+{
+	if (wpa_auth->cb.get_msk == NULL)
+		return -1;
+	return wpa_auth->cb.get_msk(wpa_auth->cb.ctx, addr, msk, len);
+}
+
+
+static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
+				   int vlan_id,
+				   enum wpa_alg alg, const u8 *addr, int idx,
+				   u8 *key, size_t key_len)
+{
+	if (wpa_auth->cb.set_key == NULL)
+		return -1;
+	return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
+				    key, key_len);
+}
+
+
+static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
+				      const u8 *addr, int idx, u8 *seq)
+{
+	if (wpa_auth->cb.get_seqnum == NULL)
+		return -1;
+	return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
+}
+
+
+static inline int
+wpa_auth_send_eapol(struct wpa_authenticator *wpa_auth, const u8 *addr,
+		    const u8 *data, size_t data_len, int encrypt)
+{
+	if (wpa_auth->cb.send_eapol == NULL)
+		return -1;
+	return wpa_auth->cb.send_eapol(wpa_auth->cb.ctx, addr, data, data_len,
+				       encrypt);
+}
+
+
+int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
+			  int (*cb)(struct wpa_state_machine *sm, void *ctx),
+			  void *cb_ctx)
+{
+	if (wpa_auth->cb.for_each_sta == NULL)
+		return 0;
+	return wpa_auth->cb.for_each_sta(wpa_auth->cb.ctx, cb, cb_ctx);
+}
+
+
+int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
+			   int (*cb)(struct wpa_authenticator *a, void *ctx),
+			   void *cb_ctx)
+{
+	if (wpa_auth->cb.for_each_auth == NULL)
+		return 0;
+	return wpa_auth->cb.for_each_auth(wpa_auth->cb.ctx, cb, cb_ctx);
+}
+
+
+void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
+		     logger_level level, const char *txt)
+{
+	if (wpa_auth->cb.logger == NULL)
+		return;
+	wpa_auth->cb.logger(wpa_auth->cb.ctx, addr, level, txt);
+}
+
+
+void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
+		      logger_level level, const char *fmt, ...)
+{
+	char *format;
+	int maxlen;
+	va_list ap;
+
+	if (wpa_auth->cb.logger == NULL)
+		return;
+
+	maxlen = os_strlen(fmt) + 100;
+	format = os_malloc(maxlen);
+	if (!format)
+		return;
+
+	va_start(ap, fmt);
+	vsnprintf(format, maxlen, fmt, ap);
+	va_end(ap);
+
+	wpa_auth_logger(wpa_auth, addr, level, format);
+
+	os_free(format);
+}
+
+
+static void wpa_sta_disconnect(struct wpa_authenticator *wpa_auth,
+			       const u8 *addr)
+{
+	if (wpa_auth->cb.disconnect == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "wpa_sta_disconnect STA " MACSTR, MAC2STR(addr));
+	wpa_auth->cb.disconnect(wpa_auth->cb.ctx, addr,
+				WLAN_REASON_PREV_AUTH_NOT_VALID);
+}
+
+
+static int wpa_use_aes_cmac(struct wpa_state_machine *sm)
+{
+	int ret = 0;
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
+		ret = 1;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (wpa_key_mgmt_sha256(sm->wpa_key_mgmt))
+		ret = 1;
+#endif /* CONFIG_IEEE80211W */
+	return ret;
+}
+
+
+static void wpa_rekey_gmk(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_authenticator *wpa_auth = eloop_ctx;
+
+	if (random_get_bytes(wpa_auth->group->GMK, WPA_GMK_LEN)) {
+		wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
+			   "initialization.");
+	} else {
+		wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "GMK rekeyd");
+		wpa_hexdump_key(MSG_DEBUG, "GMK",
+				wpa_auth->group->GMK, WPA_GMK_LEN);
+	}
+
+	if (wpa_auth->conf.wpa_gmk_rekey) {
+		eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0,
+				       wpa_rekey_gmk, wpa_auth, NULL);
+	}
+}
+
+
+static void wpa_rekey_gtk(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_authenticator *wpa_auth = eloop_ctx;
+	struct wpa_group *group;
+
+	wpa_auth_logger(wpa_auth, NULL, LOGGER_DEBUG, "rekeying GTK");
+	for (group = wpa_auth->group; group; group = group->next) {
+		group->GTKReKey = TRUE;
+		do {
+			group->changed = FALSE;
+			wpa_group_sm_step(wpa_auth, group);
+		} while (group->changed);
+	}
+
+	if (wpa_auth->conf.wpa_group_rekey) {
+		eloop_register_timeout(wpa_auth->conf.wpa_group_rekey,
+				       0, wpa_rekey_gtk, wpa_auth, NULL);
+	}
+}
+
+
+static void wpa_rekey_ptk(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_authenticator *wpa_auth = eloop_ctx;
+	struct wpa_state_machine *sm = timeout_ctx;
+
+	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "rekeying PTK");
+	wpa_request_new_ptk(sm);
+	wpa_sm_step(sm);
+}
+
+
+static int wpa_auth_pmksa_clear_cb(struct wpa_state_machine *sm, void *ctx)
+{
+	if (sm->pmksa == ctx)
+		sm->pmksa = NULL;
+	return 0;
+}
+
+
+static void wpa_auth_pmksa_free_cb(struct rsn_pmksa_cache_entry *entry,
+				   void *ctx)
+{
+	struct wpa_authenticator *wpa_auth = ctx;
+	wpa_auth_for_each_sta(wpa_auth, wpa_auth_pmksa_clear_cb, entry);
+}
+
+
+static int wpa_group_init_gmk_and_counter(struct wpa_authenticator *wpa_auth,
+					  struct wpa_group *group)
+{
+	u8 buf[ETH_ALEN + 8 + sizeof(group)];
+	u8 rkey[32];
+
+	if (random_get_bytes(group->GMK, WPA_GMK_LEN) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "GMK", group->GMK, WPA_GMK_LEN);
+
+	/*
+	 * Counter = PRF-256(Random number, "Init Counter",
+	 *                   Local MAC Address || Time)
+	 */
+	os_memcpy(buf, wpa_auth->addr, ETH_ALEN);
+	wpa_get_ntp_timestamp(buf + ETH_ALEN);
+	os_memcpy(buf + ETH_ALEN + 8, &group, sizeof(group));
+	if (random_get_bytes(rkey, sizeof(rkey)) < 0)
+		return -1;
+
+	if (sha1_prf(rkey, sizeof(rkey), "Init Counter", buf, sizeof(buf),
+		     group->Counter, WPA_NONCE_LEN) < 0)
+		return -1;
+	wpa_hexdump_key(MSG_DEBUG, "Key Counter",
+			group->Counter, WPA_NONCE_LEN);
+
+	return 0;
+}
+
+
+static struct wpa_group * wpa_group_init(struct wpa_authenticator *wpa_auth,
+					 int vlan_id, int delay_init)
+{
+	struct wpa_group *group;
+
+	group = os_zalloc(sizeof(struct wpa_group));
+	if (group == NULL)
+		return NULL;
+
+	group->GTKAuthenticator = TRUE;
+	group->vlan_id = vlan_id;
+	group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
+
+	if (random_pool_ready() != 1) {
+		wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
+			   "for secure operations - update keys later when "
+			   "the first station connects");
+	}
+
+	/*
+	 * Set initial GMK/Counter value here. The actual values that will be
+	 * used in negotiations will be set once the first station tries to
+	 * connect. This allows more time for collecting additional randomness
+	 * on embedded devices.
+	 */
+	if (wpa_group_init_gmk_and_counter(wpa_auth, group) < 0) {
+		wpa_printf(MSG_ERROR, "Failed to get random data for WPA "
+			   "initialization.");
+		os_free(group);
+		return NULL;
+	}
+
+	group->GInit = TRUE;
+	if (delay_init) {
+		wpa_printf(MSG_DEBUG, "WPA: Delay group state machine start "
+			   "until Beacon frames have been configured");
+		/* Initialization is completed in wpa_init_keys(). */
+	} else {
+		wpa_group_sm_step(wpa_auth, group);
+		group->GInit = FALSE;
+		wpa_group_sm_step(wpa_auth, group);
+	}
+
+	return group;
+}
+
+
+/**
+ * wpa_init - Initialize WPA authenticator
+ * @addr: Authenticator address
+ * @conf: Configuration for WPA authenticator
+ * @cb: Callback functions for WPA authenticator
+ * Returns: Pointer to WPA authenticator data or %NULL on failure
+ */
+struct wpa_authenticator * wpa_init(const u8 *addr,
+				    struct wpa_auth_config *conf,
+				    struct wpa_auth_callbacks *cb)
+{
+	struct wpa_authenticator *wpa_auth;
+
+	wpa_auth = os_zalloc(sizeof(struct wpa_authenticator));
+	if (wpa_auth == NULL)
+		return NULL;
+	os_memcpy(wpa_auth->addr, addr, ETH_ALEN);
+	os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
+	os_memcpy(&wpa_auth->cb, cb, sizeof(*cb));
+
+	if (wpa_auth_gen_wpa_ie(wpa_auth)) {
+		wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
+		os_free(wpa_auth);
+		return NULL;
+	}
+
+	wpa_auth->group = wpa_group_init(wpa_auth, 0, 1);
+	if (wpa_auth->group == NULL) {
+		os_free(wpa_auth->wpa_ie);
+		os_free(wpa_auth);
+		return NULL;
+	}
+
+	wpa_auth->pmksa = pmksa_cache_auth_init(wpa_auth_pmksa_free_cb,
+						wpa_auth);
+	if (wpa_auth->pmksa == NULL) {
+		wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
+		os_free(wpa_auth->wpa_ie);
+		os_free(wpa_auth);
+		return NULL;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	wpa_auth->ft_pmk_cache = wpa_ft_pmk_cache_init();
+	if (wpa_auth->ft_pmk_cache == NULL) {
+		wpa_printf(MSG_ERROR, "FT PMK cache initialization failed.");
+		os_free(wpa_auth->wpa_ie);
+		pmksa_cache_auth_deinit(wpa_auth->pmksa);
+		os_free(wpa_auth);
+		return NULL;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	if (wpa_auth->conf.wpa_gmk_rekey) {
+		eloop_register_timeout(wpa_auth->conf.wpa_gmk_rekey, 0,
+				       wpa_rekey_gmk, wpa_auth, NULL);
+	}
+
+	if (wpa_auth->conf.wpa_group_rekey) {
+		eloop_register_timeout(wpa_auth->conf.wpa_group_rekey, 0,
+				       wpa_rekey_gtk, wpa_auth, NULL);
+	}
+
+	return wpa_auth;
+}
+
+
+int wpa_init_keys(struct wpa_authenticator *wpa_auth)
+{
+	struct wpa_group *group = wpa_auth->group;
+
+	wpa_printf(MSG_DEBUG, "WPA: Start group state machine to set initial "
+		   "keys");
+	wpa_group_sm_step(wpa_auth, group);
+	group->GInit = FALSE;
+	wpa_group_sm_step(wpa_auth, group);
+	return 0;
+}
+
+
+/**
+ * wpa_deinit - Deinitialize WPA authenticator
+ * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
+ */
+void wpa_deinit(struct wpa_authenticator *wpa_auth)
+{
+	struct wpa_group *group, *prev;
+
+	eloop_cancel_timeout(wpa_rekey_gmk, wpa_auth, NULL);
+	eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
+
+#ifdef CONFIG_PEERKEY
+	while (wpa_auth->stsl_negotiations)
+		wpa_stsl_remove(wpa_auth, wpa_auth->stsl_negotiations);
+#endif /* CONFIG_PEERKEY */
+
+	pmksa_cache_auth_deinit(wpa_auth->pmksa);
+
+#ifdef CONFIG_IEEE80211R
+	wpa_ft_pmk_cache_deinit(wpa_auth->ft_pmk_cache);
+	wpa_auth->ft_pmk_cache = NULL;
+#endif /* CONFIG_IEEE80211R */
+
+	os_free(wpa_auth->wpa_ie);
+
+	group = wpa_auth->group;
+	while (group) {
+		prev = group;
+		group = group->next;
+		os_free(prev);
+	}
+
+	os_free(wpa_auth);
+}
+
+
+/**
+ * wpa_reconfig - Update WPA authenticator configuration
+ * @wpa_auth: Pointer to WPA authenticator data from wpa_init()
+ * @conf: Configuration for WPA authenticator
+ */
+int wpa_reconfig(struct wpa_authenticator *wpa_auth,
+		 struct wpa_auth_config *conf)
+{
+	struct wpa_group *group;
+	if (wpa_auth == NULL)
+		return 0;
+
+	os_memcpy(&wpa_auth->conf, conf, sizeof(*conf));
+	if (wpa_auth_gen_wpa_ie(wpa_auth)) {
+		wpa_printf(MSG_ERROR, "Could not generate WPA IE.");
+		return -1;
+	}
+
+	/*
+	 * Reinitialize GTK to make sure it is suitable for the new
+	 * configuration.
+	 */
+	group = wpa_auth->group;
+	group->GTK_len = wpa_cipher_key_len(wpa_auth->conf.wpa_group);
+	group->GInit = TRUE;
+	wpa_group_sm_step(wpa_auth, group);
+	group->GInit = FALSE;
+	wpa_group_sm_step(wpa_auth, group);
+
+	return 0;
+}
+
+
+struct wpa_state_machine *
+wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr)
+{
+	struct wpa_state_machine *sm;
+
+	sm = os_zalloc(sizeof(struct wpa_state_machine));
+	if (sm == NULL)
+		return NULL;
+	os_memcpy(sm->addr, addr, ETH_ALEN);
+
+	sm->wpa_auth = wpa_auth;
+	sm->group = wpa_auth->group;
+
+	return sm;
+}
+
+
+int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
+			    struct wpa_state_machine *sm)
+{
+	if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
+		return -1;
+
+#ifdef CONFIG_IEEE80211R
+	if (sm->ft_completed) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+				"FT authentication already completed - do not "
+				"start 4-way handshake");
+		return 0;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	if (sm->started) {
+		os_memset(&sm->key_replay, 0, sizeof(sm->key_replay));
+		sm->ReAuthenticationRequest = TRUE;
+		return wpa_sm_step(sm);
+	}
+
+	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+			"start authentication");
+	sm->started = 1;
+
+	sm->Init = TRUE;
+	if (wpa_sm_step(sm) == 1)
+		return 1; /* should not really happen */
+	sm->Init = FALSE;
+	sm->AuthenticationRequest = TRUE;
+	return wpa_sm_step(sm);
+}
+
+
+void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm)
+{
+	/* WPA/RSN was not used - clear WPA state. This is needed if the STA
+	 * reassociates back to the same AP while the previous entry for the
+	 * STA has not yet been removed. */
+	if (sm == NULL)
+		return;
+
+	sm->wpa_key_mgmt = 0;
+}
+
+
+static void wpa_free_sta_sm(struct wpa_state_machine *sm)
+{
+	if (sm->GUpdateStationKeys) {
+		sm->group->GKeyDoneStations--;
+		sm->GUpdateStationKeys = FALSE;
+	}
+#ifdef CONFIG_IEEE80211R
+	os_free(sm->assoc_resp_ftie);
+#endif /* CONFIG_IEEE80211R */
+	os_free(sm->last_rx_eapol_key);
+	os_free(sm->wpa_ie);
+	os_free(sm);
+}
+
+
+void wpa_auth_sta_deinit(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return;
+
+	if (sm->wpa_auth->conf.wpa_strict_rekey && sm->has_GTK) {
+		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+				"strict rekeying - force GTK rekey since STA "
+				"is leaving");
+		eloop_cancel_timeout(wpa_rekey_gtk, sm->wpa_auth, NULL);
+		eloop_register_timeout(0, 500000, wpa_rekey_gtk, sm->wpa_auth,
+				       NULL);
+	}
+
+	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
+	sm->pending_1_of_4_timeout = 0;
+	eloop_cancel_timeout(wpa_sm_call_step, sm, NULL);
+	eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+	if (sm->in_step_loop) {
+		/* Must not free state machine while wpa_sm_step() is running.
+		 * Freeing will be completed in the end of wpa_sm_step(). */
+		wpa_printf(MSG_DEBUG, "WPA: Registering pending STA state "
+			   "machine deinit for " MACSTR, MAC2STR(sm->addr));
+		sm->pending_deinit = 1;
+	} else
+		wpa_free_sta_sm(sm);
+}
+
+
+static void wpa_request_new_ptk(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return;
+
+	sm->PTKRequest = TRUE;
+	sm->PTK_valid = 0;
+}
+
+
+static int wpa_replay_counter_valid(struct wpa_key_replay_counter *ctr,
+				    const u8 *replay_counter)
+{
+	int i;
+	for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
+		if (!ctr[i].valid)
+			break;
+		if (os_memcmp(replay_counter, ctr[i].counter,
+			      WPA_REPLAY_COUNTER_LEN) == 0)
+			return 1;
+	}
+	return 0;
+}
+
+
+static void wpa_replay_counter_mark_invalid(struct wpa_key_replay_counter *ctr,
+					    const u8 *replay_counter)
+{
+	int i;
+	for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
+		if (ctr[i].valid &&
+		    (replay_counter == NULL ||
+		     os_memcmp(replay_counter, ctr[i].counter,
+			       WPA_REPLAY_COUNTER_LEN) == 0))
+			ctr[i].valid = FALSE;
+	}
+}
+
+
+#ifdef CONFIG_IEEE80211R
+static int ft_check_msg_2_of_4(struct wpa_authenticator *wpa_auth,
+			       struct wpa_state_machine *sm,
+			       struct wpa_eapol_ie_parse *kde)
+{
+	struct wpa_ie_data ie;
+	struct rsn_mdie *mdie;
+
+	if (wpa_parse_wpa_ie_rsn(kde->rsn_ie, kde->rsn_ie_len, &ie) < 0 ||
+	    ie.num_pmkid != 1 || ie.pmkid == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No PMKR1Name in "
+			   "FT 4-way handshake message 2/4");
+		return -1;
+	}
+
+	os_memcpy(sm->sup_pmk_r1_name, ie.pmkid, PMKID_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from Supplicant",
+		    sm->sup_pmk_r1_name, PMKID_LEN);
+
+	if (!kde->mdie || !kde->ftie) {
+		wpa_printf(MSG_DEBUG, "FT: No %s in FT 4-way handshake "
+			   "message 2/4", kde->mdie ? "FTIE" : "MDIE");
+		return -1;
+	}
+
+	mdie = (struct rsn_mdie *) (kde->mdie + 2);
+	if (kde->mdie[1] < sizeof(struct rsn_mdie) ||
+	    os_memcmp(wpa_auth->conf.mobility_domain, mdie->mobility_domain,
+		      MOBILITY_DOMAIN_ID_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: MDIE mismatch");
+		return -1;
+	}
+
+	if (sm->assoc_resp_ftie &&
+	    (kde->ftie[1] != sm->assoc_resp_ftie[1] ||
+	     os_memcmp(kde->ftie, sm->assoc_resp_ftie,
+		       2 + sm->assoc_resp_ftie[1]) != 0)) {
+		wpa_printf(MSG_DEBUG, "FT: FTIE mismatch");
+		wpa_hexdump(MSG_DEBUG, "FT: FTIE in EAPOL-Key msg 2/4",
+			    kde->ftie, kde->ftie_len);
+		wpa_hexdump(MSG_DEBUG, "FT: FTIE in (Re)AssocResp",
+			    sm->assoc_resp_ftie, 2 + sm->assoc_resp_ftie[1]);
+		return -1;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+static int wpa_receive_error_report(struct wpa_authenticator *wpa_auth,
+				    struct wpa_state_machine *sm, int group)
+{
+	/* Supplicant reported a Michael MIC error */
+	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+			 "received EAPOL-Key Error Request "
+			 "(STA detected Michael MIC failure (group=%d))",
+			 group);
+
+	if (group && wpa_auth->conf.wpa_group != WPA_CIPHER_TKIP) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+				"ignore Michael MIC failure report since "
+				"group cipher is not TKIP");
+	} else if (!group && sm->pairwise != WPA_CIPHER_TKIP) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+				"ignore Michael MIC failure report since "
+				"pairwise cipher is not TKIP");
+	} else {
+		if (wpa_auth_mic_failure_report(wpa_auth, sm->addr) > 0)
+			return 1; /* STA entry was removed */
+		sm->dot11RSNAStatsTKIPRemoteMICFailures++;
+		wpa_auth->dot11RSNAStatsTKIPRemoteMICFailures++;
+	}
+
+	/*
+	 * Error report is not a request for a new key handshake, but since
+	 * Authenticator may do it, let's change the keys now anyway.
+	 */
+	wpa_request_new_ptk(sm);
+	return 0;
+}
+
+
+void wpa_receive(struct wpa_authenticator *wpa_auth,
+		 struct wpa_state_machine *sm,
+		 u8 *data, size_t data_len)
+{
+	struct ieee802_1x_hdr *hdr;
+	struct wpa_eapol_key *key;
+	u16 key_info, key_data_length;
+	enum { PAIRWISE_2, PAIRWISE_4, GROUP_2, REQUEST,
+	       SMK_M1, SMK_M3, SMK_ERROR } msg;
+	char *msgtxt;
+	struct wpa_eapol_ie_parse kde;
+	int ft;
+	const u8 *eapol_key_ie;
+	size_t eapol_key_ie_len;
+
+	if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
+		return;
+
+	if (data_len < sizeof(*hdr) + sizeof(*key))
+		return;
+
+	hdr = (struct ieee802_1x_hdr *) data;
+	key = (struct wpa_eapol_key *) (hdr + 1);
+	key_info = WPA_GET_BE16(key->key_info);
+	key_data_length = WPA_GET_BE16(key->key_data_length);
+	wpa_printf(MSG_DEBUG, "WPA: Received EAPOL-Key from " MACSTR
+		   " key_info=0x%x type=%u key_data_length=%u",
+		   MAC2STR(sm->addr), key_info, key->type, key_data_length);
+	if (key_data_length > data_len - sizeof(*hdr) - sizeof(*key)) {
+		wpa_printf(MSG_INFO, "WPA: Invalid EAPOL-Key frame - "
+			   "key_data overflow (%d > %lu)",
+			   key_data_length,
+			   (unsigned long) (data_len - sizeof(*hdr) -
+					    sizeof(*key)));
+		return;
+	}
+
+	if (sm->wpa == WPA_VERSION_WPA2) {
+		if (key->type == EAPOL_KEY_TYPE_WPA) {
+			/*
+			 * Some deployed station implementations seem to send
+			 * msg 4/4 with incorrect type value in WPA2 mode.
+			 */
+			wpa_printf(MSG_DEBUG, "Workaround: Allow EAPOL-Key "
+				   "with unexpected WPA type in RSN mode");
+		} else if (key->type != EAPOL_KEY_TYPE_RSN) {
+			wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
+				   "unexpected type %d in RSN mode",
+				   key->type);
+			return;
+		}
+	} else {
+		if (key->type != EAPOL_KEY_TYPE_WPA) {
+			wpa_printf(MSG_DEBUG, "Ignore EAPOL-Key with "
+				   "unexpected type %d in WPA mode",
+				   key->type);
+			return;
+		}
+	}
+
+	wpa_hexdump(MSG_DEBUG, "WPA: Received Key Nonce", key->key_nonce,
+		    WPA_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPA: Received Replay Counter",
+		    key->replay_counter, WPA_REPLAY_COUNTER_LEN);
+
+	/* FIX: verify that the EAPOL-Key frame was encrypted if pairwise keys
+	 * are set */
+
+	if ((key_info & (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) ==
+	    (WPA_KEY_INFO_SMK_MESSAGE | WPA_KEY_INFO_REQUEST)) {
+		if (key_info & WPA_KEY_INFO_ERROR) {
+			msg = SMK_ERROR;
+			msgtxt = "SMK Error";
+		} else {
+			msg = SMK_M1;
+			msgtxt = "SMK M1";
+		}
+	} else if (key_info & WPA_KEY_INFO_SMK_MESSAGE) {
+		msg = SMK_M3;
+		msgtxt = "SMK M3";
+	} else if (key_info & WPA_KEY_INFO_REQUEST) {
+		msg = REQUEST;
+		msgtxt = "Request";
+	} else if (!(key_info & WPA_KEY_INFO_KEY_TYPE)) {
+		msg = GROUP_2;
+		msgtxt = "2/2 Group";
+	} else if (key_data_length == 0) {
+		msg = PAIRWISE_4;
+		msgtxt = "4/4 Pairwise";
+	} else {
+		msg = PAIRWISE_2;
+		msgtxt = "2/4 Pairwise";
+	}
+
+	/* TODO: key_info type validation for PeerKey */
+	if (msg == REQUEST || msg == PAIRWISE_2 || msg == PAIRWISE_4 ||
+	    msg == GROUP_2) {
+		u16 ver = key_info & WPA_KEY_INFO_TYPE_MASK;
+		if (sm->pairwise == WPA_CIPHER_CCMP ||
+		    sm->pairwise == WPA_CIPHER_GCMP) {
+			if (wpa_use_aes_cmac(sm) &&
+			    ver != WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+				wpa_auth_logger(wpa_auth, sm->addr,
+						LOGGER_WARNING,
+						"advertised support for "
+						"AES-128-CMAC, but did not "
+						"use it");
+				return;
+			}
+
+			if (!wpa_use_aes_cmac(sm) &&
+			    ver != WPA_KEY_INFO_TYPE_HMAC_SHA1_AES) {
+				wpa_auth_logger(wpa_auth, sm->addr,
+						LOGGER_WARNING,
+						"did not use HMAC-SHA1-AES "
+						"with CCMP/GCMP");
+				return;
+			}
+		}
+	}
+
+	if (key_info & WPA_KEY_INFO_REQUEST) {
+		if (sm->req_replay_counter_used &&
+		    os_memcmp(key->replay_counter, sm->req_replay_counter,
+			      WPA_REPLAY_COUNTER_LEN) <= 0) {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_WARNING,
+					"received EAPOL-Key request with "
+					"replayed counter");
+			return;
+		}
+	}
+
+	if (!(key_info & WPA_KEY_INFO_REQUEST) &&
+	    !wpa_replay_counter_valid(sm->key_replay, key->replay_counter)) {
+		int i;
+
+		if (msg == PAIRWISE_2 &&
+		    wpa_replay_counter_valid(sm->prev_key_replay,
+					     key->replay_counter) &&
+		    sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING &&
+		    os_memcmp(sm->SNonce, key->key_nonce, WPA_NONCE_LEN) != 0)
+		{
+			/*
+			 * Some supplicant implementations (e.g., Windows XP
+			 * WZC) update SNonce for each EAPOL-Key 2/4. This
+			 * breaks the workaround on accepting any of the
+			 * pending requests, so allow the SNonce to be updated
+			 * even if we have already sent out EAPOL-Key 3/4.
+			 */
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+					 "Process SNonce update from STA "
+					 "based on retransmitted EAPOL-Key "
+					 "1/4");
+			sm->update_snonce = 1;
+			wpa_replay_counter_mark_invalid(sm->prev_key_replay,
+							key->replay_counter);
+			goto continue_processing;
+		}
+
+		if (msg == PAIRWISE_2 &&
+		    wpa_replay_counter_valid(sm->prev_key_replay,
+					     key->replay_counter) &&
+		    sm->wpa_ptk_state == WPA_PTK_PTKINITNEGOTIATING) {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+					 "ignore retransmitted EAPOL-Key %s - "
+					 "SNonce did not change", msgtxt);
+		} else {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+					 "received EAPOL-Key %s with "
+					 "unexpected replay counter", msgtxt);
+		}
+		for (i = 0; i < RSNA_MAX_EAPOL_RETRIES; i++) {
+			if (!sm->key_replay[i].valid)
+				break;
+			wpa_hexdump(MSG_DEBUG, "pending replay counter",
+				    sm->key_replay[i].counter,
+				    WPA_REPLAY_COUNTER_LEN);
+		}
+		wpa_hexdump(MSG_DEBUG, "received replay counter",
+			    key->replay_counter, WPA_REPLAY_COUNTER_LEN);
+		return;
+	}
+
+continue_processing:
+	switch (msg) {
+	case PAIRWISE_2:
+		if (sm->wpa_ptk_state != WPA_PTK_PTKSTART &&
+		    sm->wpa_ptk_state != WPA_PTK_PTKCALCNEGOTIATING &&
+		    (!sm->update_snonce ||
+		     sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING)) {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+					 "received EAPOL-Key msg 2/4 in "
+					 "invalid state (%d) - dropped",
+					 sm->wpa_ptk_state);
+			return;
+		}
+		random_add_randomness(key->key_nonce, WPA_NONCE_LEN);
+		if (sm->group->reject_4way_hs_for_entropy) {
+			/*
+			 * The system did not have enough entropy to generate
+			 * strong random numbers. Reject the first 4-way
+			 * handshake(s) and collect some entropy based on the
+			 * information from it. Once enough entropy is
+			 * available, the next atempt will trigger GMK/Key
+			 * Counter update and the station will be allowed to
+			 * continue.
+			 */
+			wpa_printf(MSG_DEBUG, "WPA: Reject 4-way handshake to "
+				   "collect more entropy for random number "
+				   "generation");
+			random_mark_pool_ready();
+			wpa_sta_disconnect(wpa_auth, sm->addr);
+			return;
+		}
+		if (wpa_parse_kde_ies((u8 *) (key + 1), key_data_length,
+				      &kde) < 0) {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+					 "received EAPOL-Key msg 2/4 with "
+					 "invalid Key Data contents");
+			return;
+		}
+		if (kde.rsn_ie) {
+			eapol_key_ie = kde.rsn_ie;
+			eapol_key_ie_len = kde.rsn_ie_len;
+		} else {
+			eapol_key_ie = kde.wpa_ie;
+			eapol_key_ie_len = kde.wpa_ie_len;
+		}
+		ft = sm->wpa == WPA_VERSION_WPA2 &&
+			wpa_key_mgmt_ft(sm->wpa_key_mgmt);
+		if (sm->wpa_ie == NULL ||
+		    wpa_compare_rsn_ie(ft,
+				       sm->wpa_ie, sm->wpa_ie_len,
+				       eapol_key_ie, eapol_key_ie_len)) {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"WPA IE from (Re)AssocReq did not "
+					"match with msg 2/4");
+			if (sm->wpa_ie) {
+				wpa_hexdump(MSG_DEBUG, "WPA IE in AssocReq",
+					    sm->wpa_ie, sm->wpa_ie_len);
+			}
+			wpa_hexdump(MSG_DEBUG, "WPA IE in msg 2/4",
+				    eapol_key_ie, eapol_key_ie_len);
+			/* MLME-DEAUTHENTICATE.request */
+			wpa_sta_disconnect(wpa_auth, sm->addr);
+			return;
+		}
+#ifdef CONFIG_IEEE80211R
+		if (ft && ft_check_msg_2_of_4(wpa_auth, sm, &kde) < 0) {
+			wpa_sta_disconnect(wpa_auth, sm->addr);
+			return;
+		}
+#endif /* CONFIG_IEEE80211R */
+		break;
+	case PAIRWISE_4:
+		if (sm->wpa_ptk_state != WPA_PTK_PTKINITNEGOTIATING ||
+		    !sm->PTK_valid) {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+					 "received EAPOL-Key msg 4/4 in "
+					 "invalid state (%d) - dropped",
+					 sm->wpa_ptk_state);
+			return;
+		}
+		break;
+	case GROUP_2:
+		if (sm->wpa_ptk_group_state != WPA_PTK_GROUP_REKEYNEGOTIATING
+		    || !sm->PTK_valid) {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_INFO,
+					 "received EAPOL-Key msg 2/2 in "
+					 "invalid state (%d) - dropped",
+					 sm->wpa_ptk_group_state);
+			return;
+		}
+		break;
+#ifdef CONFIG_PEERKEY
+	case SMK_M1:
+	case SMK_M3:
+	case SMK_ERROR:
+		if (!wpa_auth->conf.peerkey) {
+			wpa_printf(MSG_DEBUG, "RSN: SMK M1/M3/Error, but "
+				   "PeerKey use disabled - ignoring message");
+			return;
+		}
+		if (!sm->PTK_valid) {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"received EAPOL-Key msg SMK in "
+					"invalid state - dropped");
+			return;
+		}
+		break;
+#else /* CONFIG_PEERKEY */
+	case SMK_M1:
+	case SMK_M3:
+	case SMK_ERROR:
+		return; /* STSL disabled - ignore SMK messages */
+#endif /* CONFIG_PEERKEY */
+	case REQUEST:
+		break;
+	}
+
+	wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+			 "received EAPOL-Key frame (%s)", msgtxt);
+
+	if (key_info & WPA_KEY_INFO_ACK) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+				"received invalid EAPOL-Key: Key Ack set");
+		return;
+	}
+
+	if (!(key_info & WPA_KEY_INFO_MIC)) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+				"received invalid EAPOL-Key: Key MIC not set");
+		return;
+	}
+
+	sm->MICVerified = FALSE;
+	if (sm->PTK_valid && !sm->update_snonce) {
+		if (wpa_verify_key_mic(&sm->PTK, data, data_len)) {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"received EAPOL-Key with invalid MIC");
+			return;
+		}
+		sm->MICVerified = TRUE;
+		eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
+		sm->pending_1_of_4_timeout = 0;
+	}
+
+	if (key_info & WPA_KEY_INFO_REQUEST) {
+		if (sm->MICVerified) {
+			sm->req_replay_counter_used = 1;
+			os_memcpy(sm->req_replay_counter, key->replay_counter,
+				  WPA_REPLAY_COUNTER_LEN);
+		} else {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"received EAPOL-Key request with "
+					"invalid MIC");
+			return;
+		}
+
+		/*
+		 * TODO: should decrypt key data field if encryption was used;
+		 * even though MAC address KDE is not normally encrypted,
+		 * supplicant is allowed to encrypt it.
+		 */
+		if (msg == SMK_ERROR) {
+#ifdef CONFIG_PEERKEY
+			wpa_smk_error(wpa_auth, sm, key);
+#endif /* CONFIG_PEERKEY */
+			return;
+		} else if (key_info & WPA_KEY_INFO_ERROR) {
+			if (wpa_receive_error_report(
+				    wpa_auth, sm,
+				    !(key_info & WPA_KEY_INFO_KEY_TYPE)) > 0)
+				return; /* STA entry was removed */
+		} else if (key_info & WPA_KEY_INFO_KEY_TYPE) {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"received EAPOL-Key Request for new "
+					"4-Way Handshake");
+			wpa_request_new_ptk(sm);
+#ifdef CONFIG_PEERKEY
+		} else if (msg == SMK_M1) {
+			wpa_smk_m1(wpa_auth, sm, key);
+#endif /* CONFIG_PEERKEY */
+		} else if (key_data_length > 0 &&
+			   wpa_parse_kde_ies((const u8 *) (key + 1),
+					     key_data_length, &kde) == 0 &&
+			   kde.mac_addr) {
+		} else {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
+					"received EAPOL-Key Request for GTK "
+					"rekeying");
+			eloop_cancel_timeout(wpa_rekey_gtk, wpa_auth, NULL);
+			wpa_rekey_gtk(wpa_auth, NULL);
+		}
+	} else {
+		/* Do not allow the same key replay counter to be reused. */
+		wpa_replay_counter_mark_invalid(sm->key_replay,
+						key->replay_counter);
+
+		if (msg == PAIRWISE_2) {
+			/*
+			 * Maintain a copy of the pending EAPOL-Key frames in
+			 * case the EAPOL-Key frame was retransmitted. This is
+			 * needed to allow EAPOL-Key msg 2/4 reply to another
+			 * pending msg 1/4 to update the SNonce to work around
+			 * unexpected supplicant behavior.
+			 */
+			os_memcpy(sm->prev_key_replay, sm->key_replay,
+				  sizeof(sm->key_replay));
+		} else {
+			os_memset(sm->prev_key_replay, 0,
+				  sizeof(sm->prev_key_replay));
+		}
+
+		/*
+		 * Make sure old valid counters are not accepted anymore and
+		 * do not get copied again.
+		 */
+		wpa_replay_counter_mark_invalid(sm->key_replay, NULL);
+	}
+
+#ifdef CONFIG_PEERKEY
+	if (msg == SMK_M3) {
+		wpa_smk_m3(wpa_auth, sm, key);
+		return;
+	}
+#endif /* CONFIG_PEERKEY */
+
+	os_free(sm->last_rx_eapol_key);
+	sm->last_rx_eapol_key = os_malloc(data_len);
+	if (sm->last_rx_eapol_key == NULL)
+		return;
+	os_memcpy(sm->last_rx_eapol_key, data, data_len);
+	sm->last_rx_eapol_key_len = data_len;
+
+	sm->rx_eapol_key_secure = !!(key_info & WPA_KEY_INFO_SECURE);
+	sm->EAPOLKeyReceived = TRUE;
+	sm->EAPOLKeyPairwise = !!(key_info & WPA_KEY_INFO_KEY_TYPE);
+	sm->EAPOLKeyRequest = !!(key_info & WPA_KEY_INFO_REQUEST);
+	os_memcpy(sm->SNonce, key->key_nonce, WPA_NONCE_LEN);
+	wpa_sm_step(sm);
+}
+
+
+static int wpa_gmk_to_gtk(const u8 *gmk, const char *label, const u8 *addr,
+			  const u8 *gnonce, u8 *gtk, size_t gtk_len)
+{
+	u8 data[ETH_ALEN + WPA_NONCE_LEN + 8 + 16];
+	u8 *pos;
+	int ret = 0;
+
+	/* GTK = PRF-X(GMK, "Group key expansion",
+	 *	AA || GNonce || Time || random data)
+	 * The example described in the IEEE 802.11 standard uses only AA and
+	 * GNonce as inputs here. Add some more entropy since this derivation
+	 * is done only at the Authenticator and as such, does not need to be
+	 * exactly same.
+	 */
+	os_memcpy(data, addr, ETH_ALEN);
+	os_memcpy(data + ETH_ALEN, gnonce, WPA_NONCE_LEN);
+	pos = data + ETH_ALEN + WPA_NONCE_LEN;
+	wpa_get_ntp_timestamp(pos);
+	pos += 8;
+	if (random_get_bytes(pos, 16) < 0)
+		ret = -1;
+
+#ifdef CONFIG_IEEE80211W
+	sha256_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len);
+#else /* CONFIG_IEEE80211W */
+	if (sha1_prf(gmk, WPA_GMK_LEN, label, data, sizeof(data), gtk, gtk_len)
+	    < 0)
+		ret = -1;
+#endif /* CONFIG_IEEE80211W */
+
+	return ret;
+}
+
+
+static void wpa_send_eapol_timeout(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_authenticator *wpa_auth = eloop_ctx;
+	struct wpa_state_machine *sm = timeout_ctx;
+
+	sm->pending_1_of_4_timeout = 0;
+	wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG, "EAPOL-Key timeout");
+	sm->TimeoutEvt = TRUE;
+	wpa_sm_step(sm);
+}
+
+
+void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
+		      struct wpa_state_machine *sm, int key_info,
+		      const u8 *key_rsc, const u8 *nonce,
+		      const u8 *kde, size_t kde_len,
+		      int keyidx, int encr, int force_version)
+{
+	struct ieee802_1x_hdr *hdr;
+	struct wpa_eapol_key *key;
+	size_t len;
+	int alg;
+	int key_data_len, pad_len = 0;
+	u8 *buf, *pos;
+	int version, pairwise;
+	int i;
+
+	len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key);
+
+	if (force_version)
+		version = force_version;
+	else if (wpa_use_aes_cmac(sm))
+		version = WPA_KEY_INFO_TYPE_AES_128_CMAC;
+	else if (sm->pairwise != WPA_CIPHER_TKIP)
+		version = WPA_KEY_INFO_TYPE_HMAC_SHA1_AES;
+	else
+		version = WPA_KEY_INFO_TYPE_HMAC_MD5_RC4;
+
+	pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
+
+	wpa_printf(MSG_DEBUG, "WPA: Send EAPOL(version=%d secure=%d mic=%d "
+		   "ack=%d install=%d pairwise=%d kde_len=%lu keyidx=%d "
+		   "encr=%d)",
+		   version,
+		   (key_info & WPA_KEY_INFO_SECURE) ? 1 : 0,
+		   (key_info & WPA_KEY_INFO_MIC) ? 1 : 0,
+		   (key_info & WPA_KEY_INFO_ACK) ? 1 : 0,
+		   (key_info & WPA_KEY_INFO_INSTALL) ? 1 : 0,
+		   pairwise, (unsigned long) kde_len, keyidx, encr);
+
+	key_data_len = kde_len;
+
+	if ((version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
+	     version == WPA_KEY_INFO_TYPE_AES_128_CMAC) && encr) {
+		pad_len = key_data_len % 8;
+		if (pad_len)
+			pad_len = 8 - pad_len;
+		key_data_len += pad_len + 8;
+	}
+
+	len += key_data_len;
+
+	hdr = os_zalloc(len);
+	if (hdr == NULL)
+		return;
+	hdr->version = wpa_auth->conf.eapol_version;
+	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
+	hdr->length = host_to_be16(len  - sizeof(*hdr));
+	key = (struct wpa_eapol_key *) (hdr + 1);
+
+	key->type = sm->wpa == WPA_VERSION_WPA2 ?
+		EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
+	key_info |= version;
+	if (encr && sm->wpa == WPA_VERSION_WPA2)
+		key_info |= WPA_KEY_INFO_ENCR_KEY_DATA;
+	if (sm->wpa != WPA_VERSION_WPA2)
+		key_info |= keyidx << WPA_KEY_INFO_KEY_INDEX_SHIFT;
+	WPA_PUT_BE16(key->key_info, key_info);
+
+	alg = pairwise ? sm->pairwise : wpa_auth->conf.wpa_group;
+	WPA_PUT_BE16(key->key_length, wpa_cipher_key_len(alg));
+	if (key_info & WPA_KEY_INFO_SMK_MESSAGE)
+		WPA_PUT_BE16(key->key_length, 0);
+
+	/* FIX: STSL: what to use as key_replay_counter? */
+	for (i = RSNA_MAX_EAPOL_RETRIES - 1; i > 0; i--) {
+		sm->key_replay[i].valid = sm->key_replay[i - 1].valid;
+		os_memcpy(sm->key_replay[i].counter,
+			  sm->key_replay[i - 1].counter,
+			  WPA_REPLAY_COUNTER_LEN);
+	}
+	inc_byte_array(sm->key_replay[0].counter, WPA_REPLAY_COUNTER_LEN);
+	os_memcpy(key->replay_counter, sm->key_replay[0].counter,
+		  WPA_REPLAY_COUNTER_LEN);
+	sm->key_replay[0].valid = TRUE;
+
+	if (nonce)
+		os_memcpy(key->key_nonce, nonce, WPA_NONCE_LEN);
+
+	if (key_rsc)
+		os_memcpy(key->key_rsc, key_rsc, WPA_KEY_RSC_LEN);
+
+	if (kde && !encr) {
+		os_memcpy(key + 1, kde, kde_len);
+		WPA_PUT_BE16(key->key_data_length, kde_len);
+	} else if (encr && kde) {
+		buf = os_zalloc(key_data_len);
+		if (buf == NULL) {
+			os_free(hdr);
+			return;
+		}
+		pos = buf;
+		os_memcpy(pos, kde, kde_len);
+		pos += kde_len;
+
+		if (pad_len)
+			*pos++ = 0xdd;
+
+		wpa_hexdump_key(MSG_DEBUG, "Plaintext EAPOL-Key Key Data",
+				buf, key_data_len);
+		if (version == WPA_KEY_INFO_TYPE_HMAC_SHA1_AES ||
+		    version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
+			if (aes_wrap(sm->PTK.kek, (key_data_len - 8) / 8, buf,
+				     (u8 *) (key + 1))) {
+				os_free(hdr);
+				os_free(buf);
+				return;
+			}
+			WPA_PUT_BE16(key->key_data_length, key_data_len);
+		} else {
+			u8 ek[32];
+			os_memcpy(key->key_iv,
+				  sm->group->Counter + WPA_NONCE_LEN - 16, 16);
+			inc_byte_array(sm->group->Counter, WPA_NONCE_LEN);
+			os_memcpy(ek, key->key_iv, 16);
+			os_memcpy(ek + 16, sm->PTK.kek, 16);
+			os_memcpy(key + 1, buf, key_data_len);
+			rc4_skip(ek, 32, 256, (u8 *) (key + 1), key_data_len);
+			WPA_PUT_BE16(key->key_data_length, key_data_len);
+		}
+		os_free(buf);
+	}
+
+	if (key_info & WPA_KEY_INFO_MIC) {
+		if (!sm->PTK_valid) {
+			wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+					"PTK not valid when sending EAPOL-Key "
+					"frame");
+			os_free(hdr);
+			return;
+		}
+		wpa_eapol_key_mic(sm->PTK.kck, version, (u8 *) hdr, len,
+				  key->key_mic);
+	}
+
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_inc_EapolFramesTx,
+			   1);
+	wpa_auth_send_eapol(wpa_auth, sm->addr, (u8 *) hdr, len,
+			    sm->pairwise_set);
+	os_free(hdr);
+}
+
+
+static void wpa_send_eapol(struct wpa_authenticator *wpa_auth,
+			   struct wpa_state_machine *sm, int key_info,
+			   const u8 *key_rsc, const u8 *nonce,
+			   const u8 *kde, size_t kde_len,
+			   int keyidx, int encr)
+{
+	int timeout_ms;
+	int pairwise = key_info & WPA_KEY_INFO_KEY_TYPE;
+	int ctr;
+
+	if (sm == NULL)
+		return;
+
+	__wpa_send_eapol(wpa_auth, sm, key_info, key_rsc, nonce, kde, kde_len,
+			 keyidx, encr, 0);
+
+	ctr = pairwise ? sm->TimeoutCtr : sm->GTimeoutCtr;
+	if (ctr == 1 && wpa_auth->conf.tx_status)
+		timeout_ms = pairwise ? eapol_key_timeout_first :
+			eapol_key_timeout_first_group;
+	else
+		timeout_ms = eapol_key_timeout_subseq;
+	if (pairwise && ctr == 1 && !(key_info & WPA_KEY_INFO_MIC))
+		sm->pending_1_of_4_timeout = 1;
+	wpa_printf(MSG_DEBUG, "WPA: Use EAPOL-Key timeout of %u ms (retry "
+		   "counter %d)", timeout_ms, ctr);
+	eloop_register_timeout(timeout_ms / 1000, (timeout_ms % 1000) * 1000,
+			       wpa_send_eapol_timeout, wpa_auth, sm);
+}
+
+
+static int wpa_verify_key_mic(struct wpa_ptk *PTK, u8 *data, size_t data_len)
+{
+	struct ieee802_1x_hdr *hdr;
+	struct wpa_eapol_key *key;
+	u16 key_info;
+	int ret = 0;
+	u8 mic[16];
+
+	if (data_len < sizeof(*hdr) + sizeof(*key))
+		return -1;
+
+	hdr = (struct ieee802_1x_hdr *) data;
+	key = (struct wpa_eapol_key *) (hdr + 1);
+	key_info = WPA_GET_BE16(key->key_info);
+	os_memcpy(mic, key->key_mic, 16);
+	os_memset(key->key_mic, 0, 16);
+	if (wpa_eapol_key_mic(PTK->kck, key_info & WPA_KEY_INFO_TYPE_MASK,
+			      data, data_len, key->key_mic) ||
+	    os_memcmp(mic, key->key_mic, 16) != 0)
+		ret = -1;
+	os_memcpy(key->key_mic, mic, 16);
+	return ret;
+}
+
+
+void wpa_remove_ptk(struct wpa_state_machine *sm)
+{
+	sm->PTK_valid = FALSE;
+	os_memset(&sm->PTK, 0, sizeof(sm->PTK));
+	wpa_auth_set_key(sm->wpa_auth, 0, WPA_ALG_NONE, sm->addr, 0, NULL, 0);
+	sm->pairwise_set = FALSE;
+	eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+}
+
+
+int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event)
+{
+	int remove_ptk = 1;
+
+	if (sm == NULL)
+		return -1;
+
+	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			 "event %d notification", event);
+
+	switch (event) {
+	case WPA_AUTH:
+	case WPA_ASSOC:
+		break;
+	case WPA_DEAUTH:
+	case WPA_DISASSOC:
+		sm->DeauthenticationRequest = TRUE;
+		break;
+	case WPA_REAUTH:
+	case WPA_REAUTH_EAPOL:
+		if (!sm->started) {
+			/*
+			 * When using WPS, we may end up here if the STA
+			 * manages to re-associate without the previous STA
+			 * entry getting removed. Consequently, we need to make
+			 * sure that the WPA state machines gets initialized
+			 * properly at this point.
+			 */
+			wpa_printf(MSG_DEBUG, "WPA state machine had not been "
+				   "started - initialize now");
+			sm->started = 1;
+			sm->Init = TRUE;
+			if (wpa_sm_step(sm) == 1)
+				return 1; /* should not really happen */
+			sm->Init = FALSE;
+			sm->AuthenticationRequest = TRUE;
+			break;
+		}
+		if (sm->GUpdateStationKeys) {
+			/*
+			 * Reauthentication cancels the pending group key
+			 * update for this STA.
+			 */
+			sm->group->GKeyDoneStations--;
+			sm->GUpdateStationKeys = FALSE;
+			sm->PtkGroupInit = TRUE;
+		}
+		sm->ReAuthenticationRequest = TRUE;
+		break;
+	case WPA_ASSOC_FT:
+#ifdef CONFIG_IEEE80211R
+		wpa_printf(MSG_DEBUG, "FT: Retry PTK configuration "
+			   "after association");
+		wpa_ft_install_ptk(sm);
+
+		/* Using FT protocol, not WPA auth state machine */
+		sm->ft_completed = 1;
+		return 0;
+#else /* CONFIG_IEEE80211R */
+		break;
+#endif /* CONFIG_IEEE80211R */
+	}
+
+#ifdef CONFIG_IEEE80211R
+	sm->ft_completed = 0;
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef CONFIG_IEEE80211W
+	if (sm->mgmt_frame_prot && event == WPA_AUTH)
+		remove_ptk = 0;
+#endif /* CONFIG_IEEE80211W */
+
+	if (remove_ptk) {
+		sm->PTK_valid = FALSE;
+		os_memset(&sm->PTK, 0, sizeof(sm->PTK));
+
+		if (event != WPA_REAUTH_EAPOL)
+			wpa_remove_ptk(sm);
+	}
+
+	return wpa_sm_step(sm);
+}
+
+
+SM_STATE(WPA_PTK, INITIALIZE)
+{
+	SM_ENTRY_MA(WPA_PTK, INITIALIZE, wpa_ptk);
+	if (sm->Init) {
+		/* Init flag is not cleared here, so avoid busy
+		 * loop by claiming nothing changed. */
+		sm->changed = FALSE;
+	}
+
+	sm->keycount = 0;
+	if (sm->GUpdateStationKeys)
+		sm->group->GKeyDoneStations--;
+	sm->GUpdateStationKeys = FALSE;
+	if (sm->wpa == WPA_VERSION_WPA)
+		sm->PInitAKeys = FALSE;
+	if (1 /* Unicast cipher supported AND (ESS OR ((IBSS or WDS) and
+	       * Local AA > Remote AA)) */) {
+		sm->Pair = TRUE;
+	}
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 0);
+	wpa_remove_ptk(sm);
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid, 0);
+	sm->TimeoutCtr = 0;
+	if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+		wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
+				   WPA_EAPOL_authorized, 0);
+	}
+}
+
+
+SM_STATE(WPA_PTK, DISCONNECT)
+{
+	SM_ENTRY_MA(WPA_PTK, DISCONNECT, wpa_ptk);
+	sm->Disconnect = FALSE;
+	wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+}
+
+
+SM_STATE(WPA_PTK, DISCONNECTED)
+{
+	SM_ENTRY_MA(WPA_PTK, DISCONNECTED, wpa_ptk);
+	sm->DeauthenticationRequest = FALSE;
+}
+
+
+SM_STATE(WPA_PTK, AUTHENTICATION)
+{
+	SM_ENTRY_MA(WPA_PTK, AUTHENTICATION, wpa_ptk);
+	os_memset(&sm->PTK, 0, sizeof(sm->PTK));
+	sm->PTK_valid = FALSE;
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portControl_Auto,
+			   1);
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portEnabled, 1);
+	sm->AuthenticationRequest = FALSE;
+}
+
+
+static void wpa_group_ensure_init(struct wpa_authenticator *wpa_auth,
+				  struct wpa_group *group)
+{
+	if (group->first_sta_seen)
+		return;
+	/*
+	 * System has run bit further than at the time hostapd was started
+	 * potentially very early during boot up. This provides better chances
+	 * of collecting more randomness on embedded systems. Re-initialize the
+	 * GMK and Counter here to improve their strength if there was not
+	 * enough entropy available immediately after system startup.
+	 */
+	wpa_printf(MSG_DEBUG, "WPA: Re-initialize GMK/Counter on first "
+		   "station");
+	if (random_pool_ready() != 1) {
+		wpa_printf(MSG_INFO, "WPA: Not enough entropy in random pool "
+			   "to proceed - reject first 4-way handshake");
+		group->reject_4way_hs_for_entropy = TRUE;
+	} else {
+		group->first_sta_seen = TRUE;
+		group->reject_4way_hs_for_entropy = FALSE;
+	}
+
+	wpa_group_init_gmk_and_counter(wpa_auth, group);
+	wpa_gtk_update(wpa_auth, group);
+	wpa_group_config_group_keys(wpa_auth, group);
+}
+
+
+SM_STATE(WPA_PTK, AUTHENTICATION2)
+{
+	SM_ENTRY_MA(WPA_PTK, AUTHENTICATION2, wpa_ptk);
+
+	wpa_group_ensure_init(sm->wpa_auth, sm->group);
+
+	/*
+	 * Definition of ANonce selection in IEEE Std 802.11i-2004 is somewhat
+	 * ambiguous. The Authenticator state machine uses a counter that is
+	 * incremented by one for each 4-way handshake. However, the security
+	 * analysis of 4-way handshake points out that unpredictable nonces
+	 * help in preventing precomputation attacks. Instead of the state
+	 * machine definition, use an unpredictable nonce value here to provide
+	 * stronger protection against potential precomputation attacks.
+	 */
+	if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
+		wpa_printf(MSG_ERROR, "WPA: Failed to get random data for "
+			   "ANonce.");
+		wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+		return;
+	}
+	wpa_hexdump(MSG_DEBUG, "WPA: Assign ANonce", sm->ANonce,
+		    WPA_NONCE_LEN);
+	sm->ReAuthenticationRequest = FALSE;
+	/* IEEE 802.11i does not clear TimeoutCtr here, but this is more
+	 * logical place than INITIALIZE since AUTHENTICATION2 can be
+	 * re-entered on ReAuthenticationRequest without going through
+	 * INITIALIZE. */
+	sm->TimeoutCtr = 0;
+}
+
+
+SM_STATE(WPA_PTK, INITPMK)
+{
+	u8 msk[2 * PMK_LEN];
+	size_t len = 2 * PMK_LEN;
+
+	SM_ENTRY_MA(WPA_PTK, INITPMK, wpa_ptk);
+#ifdef CONFIG_IEEE80211R
+	sm->xxkey_len = 0;
+#endif /* CONFIG_IEEE80211R */
+	if (sm->pmksa) {
+		wpa_printf(MSG_DEBUG, "WPA: PMK from PMKSA cache");
+		os_memcpy(sm->PMK, sm->pmksa->pmk, PMK_LEN);
+	} else if (wpa_auth_get_msk(sm->wpa_auth, sm->addr, msk, &len) == 0) {
+		wpa_printf(MSG_DEBUG, "WPA: PMK from EAPOL state machine "
+			   "(len=%lu)", (unsigned long) len);
+		os_memcpy(sm->PMK, msk, PMK_LEN);
+#ifdef CONFIG_IEEE80211R
+		if (len >= 2 * PMK_LEN) {
+			os_memcpy(sm->xxkey, msk + PMK_LEN, PMK_LEN);
+			sm->xxkey_len = PMK_LEN;
+		}
+#endif /* CONFIG_IEEE80211R */
+	} else {
+		wpa_printf(MSG_DEBUG, "WPA: Could not get PMK");
+	}
+
+	sm->req_replay_counter_used = 0;
+	/* IEEE 802.11i does not set keyRun to FALSE, but not doing this
+	 * will break reauthentication since EAPOL state machines may not be
+	 * get into AUTHENTICATING state that clears keyRun before WPA state
+	 * machine enters AUTHENTICATION2 state and goes immediately to INITPMK
+	 * state and takes PMK from the previously used AAA Key. This will
+	 * eventually fail in 4-Way Handshake because Supplicant uses PMK
+	 * derived from the new AAA Key. Setting keyRun = FALSE here seems to
+	 * be good workaround for this issue. */
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyRun, 0);
+}
+
+
+SM_STATE(WPA_PTK, INITPSK)
+{
+	const u8 *psk;
+	SM_ENTRY_MA(WPA_PTK, INITPSK, wpa_ptk);
+	psk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL);
+	if (psk) {
+		os_memcpy(sm->PMK, psk, PMK_LEN);
+#ifdef CONFIG_IEEE80211R
+		os_memcpy(sm->xxkey, psk, PMK_LEN);
+		sm->xxkey_len = PMK_LEN;
+#endif /* CONFIG_IEEE80211R */
+	}
+	sm->req_replay_counter_used = 0;
+}
+
+
+SM_STATE(WPA_PTK, PTKSTART)
+{
+	u8 buf[2 + RSN_SELECTOR_LEN + PMKID_LEN], *pmkid = NULL;
+	size_t pmkid_len = 0;
+
+	SM_ENTRY_MA(WPA_PTK, PTKSTART, wpa_ptk);
+	sm->PTKRequest = FALSE;
+	sm->TimeoutEvt = FALSE;
+
+	sm->TimeoutCtr++;
+	if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
+		/* No point in sending the EAPOL-Key - we will disconnect
+		 * immediately following this. */
+		return;
+	}
+
+	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			"sending 1/4 msg of 4-Way Handshake");
+	/*
+	 * TODO: Could add PMKID even with WPA2-PSK, but only if there is only
+	 * one possible PSK for this STA.
+	 */
+	if (sm->wpa == WPA_VERSION_WPA2 &&
+	    wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt)) {
+		pmkid = buf;
+		pmkid_len = 2 + RSN_SELECTOR_LEN + PMKID_LEN;
+		pmkid[0] = WLAN_EID_VENDOR_SPECIFIC;
+		pmkid[1] = RSN_SELECTOR_LEN + PMKID_LEN;
+		RSN_SELECTOR_PUT(&pmkid[2], RSN_KEY_DATA_PMKID);
+		if (sm->pmksa)
+			os_memcpy(&pmkid[2 + RSN_SELECTOR_LEN],
+				  sm->pmksa->pmkid, PMKID_LEN);
+		else {
+			/*
+			 * Calculate PMKID since no PMKSA cache entry was
+			 * available with pre-calculated PMKID.
+			 */
+			rsn_pmkid(sm->PMK, PMK_LEN, sm->wpa_auth->addr,
+				  sm->addr, &pmkid[2 + RSN_SELECTOR_LEN],
+				  wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
+		}
+	}
+	wpa_send_eapol(sm->wpa_auth, sm,
+		       WPA_KEY_INFO_ACK | WPA_KEY_INFO_KEY_TYPE, NULL,
+		       sm->ANonce, pmkid, pmkid_len, 0, 0);
+}
+
+
+static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *pmk,
+			  struct wpa_ptk *ptk)
+{
+	size_t ptk_len = sm->pairwise != WPA_CIPHER_TKIP ? 48 : 64;
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
+		return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
+#endif /* CONFIG_IEEE80211R */
+
+	wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
+		       sm->wpa_auth->addr, sm->addr, sm->ANonce, sm->SNonce,
+		       (u8 *) ptk, ptk_len,
+		       wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
+
+	return 0;
+}
+
+
+SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
+{
+	struct wpa_ptk PTK;
+	int ok = 0;
+	const u8 *pmk = NULL;
+
+	SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
+	sm->EAPOLKeyReceived = FALSE;
+	sm->update_snonce = FALSE;
+
+	/* WPA with IEEE 802.1X: use the derived PMK from EAP
+	 * WPA-PSK: iterate through possible PSKs and select the one matching
+	 * the packet */
+	for (;;) {
+		if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+			pmk = wpa_auth_get_psk(sm->wpa_auth, sm->addr, pmk);
+			if (pmk == NULL)
+				break;
+		} else
+			pmk = sm->PMK;
+
+		wpa_derive_ptk(sm, pmk, &PTK);
+
+		if (wpa_verify_key_mic(&PTK, sm->last_rx_eapol_key,
+				       sm->last_rx_eapol_key_len) == 0) {
+			ok = 1;
+			break;
+		}
+
+		if (!wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt))
+			break;
+	}
+
+	if (!ok) {
+		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+				"invalid MIC in msg 2/4 of 4-Way Handshake");
+		return;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (sm->wpa == WPA_VERSION_WPA2 && wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+		/*
+		 * Verify that PMKR1Name from EAPOL-Key message 2/4 matches
+		 * with the value we derived.
+		 */
+		if (os_memcmp(sm->sup_pmk_r1_name, sm->pmk_r1_name,
+			      WPA_PMK_NAME_LEN) != 0) {
+			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+					"PMKR1Name mismatch in FT 4-way "
+					"handshake");
+			wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name from "
+				    "Supplicant",
+				    sm->sup_pmk_r1_name, WPA_PMK_NAME_LEN);
+			wpa_hexdump(MSG_DEBUG, "FT: Derived PMKR1Name",
+				    sm->pmk_r1_name, WPA_PMK_NAME_LEN);
+			return;
+		}
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	sm->pending_1_of_4_timeout = 0;
+	eloop_cancel_timeout(wpa_send_eapol_timeout, sm->wpa_auth, sm);
+
+	if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+		/* PSK may have changed from the previous choice, so update
+		 * state machine data based on whatever PSK was selected here.
+		 */
+		os_memcpy(sm->PMK, pmk, PMK_LEN);
+	}
+
+	sm->MICVerified = TRUE;
+
+	os_memcpy(&sm->PTK, &PTK, sizeof(PTK));
+	sm->PTK_valid = TRUE;
+}
+
+
+SM_STATE(WPA_PTK, PTKCALCNEGOTIATING2)
+{
+	SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING2, wpa_ptk);
+	sm->TimeoutCtr = 0;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+
+static int ieee80211w_kde_len(struct wpa_state_machine *sm)
+{
+	if (sm->mgmt_frame_prot) {
+		return 2 + RSN_SELECTOR_LEN + sizeof(struct wpa_igtk_kde);
+	}
+
+	return 0;
+}
+
+
+static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
+{
+	struct wpa_igtk_kde igtk;
+	struct wpa_group *gsm = sm->group;
+
+	if (!sm->mgmt_frame_prot)
+		return pos;
+
+	igtk.keyid[0] = gsm->GN_igtk;
+	igtk.keyid[1] = 0;
+	if (gsm->wpa_group_state != WPA_GROUP_SETKEYSDONE ||
+	    wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, igtk.pn) < 0)
+		os_memset(igtk.pn, 0, sizeof(igtk.pn));
+	os_memcpy(igtk.igtk, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+	if (sm->wpa_auth->conf.disable_gtk) {
+		/*
+		 * Provide unique random IGTK to each STA to prevent use of
+		 * IGTK in the BSS.
+		 */
+		if (random_get_bytes(igtk.igtk, WPA_IGTK_LEN) < 0)
+			return pos;
+	}
+	pos = wpa_add_kde(pos, RSN_KEY_DATA_IGTK,
+			  (const u8 *) &igtk, sizeof(igtk), NULL, 0);
+
+	return pos;
+}
+
+#else /* CONFIG_IEEE80211W */
+
+static int ieee80211w_kde_len(struct wpa_state_machine *sm)
+{
+	return 0;
+}
+
+
+static u8 * ieee80211w_kde_add(struct wpa_state_machine *sm, u8 *pos)
+{
+	return pos;
+}
+
+#endif /* CONFIG_IEEE80211W */
+
+
+SM_STATE(WPA_PTK, PTKINITNEGOTIATING)
+{
+	u8 rsc[WPA_KEY_RSC_LEN], *_rsc, *gtk, *kde, *pos, dummy_gtk[32];
+	size_t gtk_len, kde_len;
+	struct wpa_group *gsm = sm->group;
+	u8 *wpa_ie;
+	int wpa_ie_len, secure, keyidx, encr = 0;
+
+	SM_ENTRY_MA(WPA_PTK, PTKINITNEGOTIATING, wpa_ptk);
+	sm->TimeoutEvt = FALSE;
+
+	sm->TimeoutCtr++;
+	if (sm->TimeoutCtr > (int) dot11RSNAConfigPairwiseUpdateCount) {
+		/* No point in sending the EAPOL-Key - we will disconnect
+		 * immediately following this. */
+		return;
+	}
+
+	/* Send EAPOL(1, 1, 1, Pair, P, RSC, ANonce, MIC(PTK), RSNIE, [MDIE],
+	   GTK[GN], IGTK, [FTIE], [TIE * 2])
+	 */
+	os_memset(rsc, 0, WPA_KEY_RSC_LEN);
+	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
+	/* If FT is used, wpa_auth->wpa_ie includes both RSNIE and MDIE */
+	wpa_ie = sm->wpa_auth->wpa_ie;
+	wpa_ie_len = sm->wpa_auth->wpa_ie_len;
+	if (sm->wpa == WPA_VERSION_WPA &&
+	    (sm->wpa_auth->conf.wpa & WPA_PROTO_RSN) &&
+	    wpa_ie_len > wpa_ie[1] + 2 && wpa_ie[0] == WLAN_EID_RSN) {
+		/* WPA-only STA, remove RSN IE */
+		wpa_ie = wpa_ie + wpa_ie[1] + 2;
+		wpa_ie_len = wpa_ie[1] + 2;
+	}
+	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			"sending 3/4 msg of 4-Way Handshake");
+	if (sm->wpa == WPA_VERSION_WPA2) {
+		/* WPA2 send GTK in the 4-way handshake */
+		secure = 1;
+		gtk = gsm->GTK[gsm->GN - 1];
+		gtk_len = gsm->GTK_len;
+		if (sm->wpa_auth->conf.disable_gtk) {
+			/*
+			 * Provide unique random GTK to each STA to prevent use
+			 * of GTK in the BSS.
+			 */
+			if (random_get_bytes(dummy_gtk, gtk_len) < 0)
+				return;
+			gtk = dummy_gtk;
+		}
+		keyidx = gsm->GN;
+		_rsc = rsc;
+		encr = 1;
+	} else {
+		/* WPA does not include GTK in msg 3/4 */
+		secure = 0;
+		gtk = NULL;
+		gtk_len = 0;
+		keyidx = 0;
+		_rsc = NULL;
+		if (sm->rx_eapol_key_secure) {
+			/*
+			 * It looks like Windows 7 supplicant tries to use
+			 * Secure bit in msg 2/4 after having reported Michael
+			 * MIC failure and it then rejects the 4-way handshake
+			 * if msg 3/4 does not set Secure bit. Work around this
+			 * by setting the Secure bit here even in the case of
+			 * WPA if the supplicant used it first.
+			 */
+			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+					"STA used Secure bit in WPA msg 2/4 - "
+					"set Secure for 3/4 as workaround");
+			secure = 1;
+		}
+	}
+
+	kde_len = wpa_ie_len + ieee80211w_kde_len(sm);
+	if (gtk)
+		kde_len += 2 + RSN_SELECTOR_LEN + 2 + gtk_len;
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+		kde_len += 2 + PMKID_LEN; /* PMKR1Name into RSN IE */
+		kde_len += 300; /* FTIE + 2 * TIE */
+	}
+#endif /* CONFIG_IEEE80211R */
+	kde = os_malloc(kde_len);
+	if (kde == NULL)
+		return;
+
+	pos = kde;
+	os_memcpy(pos, wpa_ie, wpa_ie_len);
+	pos += wpa_ie_len;
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+		int res = wpa_insert_pmkid(kde, pos - kde, sm->pmk_r1_name);
+		if (res < 0) {
+			wpa_printf(MSG_ERROR, "FT: Failed to insert "
+				   "PMKR1Name into RSN IE in EAPOL-Key data");
+			os_free(kde);
+			return;
+		}
+		pos += res;
+	}
+#endif /* CONFIG_IEEE80211R */
+	if (gtk) {
+		u8 hdr[2];
+		hdr[0] = keyidx & 0x03;
+		hdr[1] = 0;
+		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
+				  gtk, gtk_len);
+	}
+	pos = ieee80211w_kde_add(sm, pos);
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+		int res;
+		struct wpa_auth_config *conf;
+
+		conf = &sm->wpa_auth->conf;
+		res = wpa_write_ftie(conf, conf->r0_key_holder,
+				     conf->r0_key_holder_len,
+				     NULL, NULL, pos, kde + kde_len - pos,
+				     NULL, 0);
+		if (res < 0) {
+			wpa_printf(MSG_ERROR, "FT: Failed to insert FTIE "
+				   "into EAPOL-Key Key Data");
+			os_free(kde);
+			return;
+		}
+		pos += res;
+
+		/* TIE[ReassociationDeadline] (TU) */
+		*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+		*pos++ = 5;
+		*pos++ = WLAN_TIMEOUT_REASSOC_DEADLINE;
+		WPA_PUT_LE32(pos, conf->reassociation_deadline);
+		pos += 4;
+
+		/* TIE[KeyLifetime] (seconds) */
+		*pos++ = WLAN_EID_TIMEOUT_INTERVAL;
+		*pos++ = 5;
+		*pos++ = WLAN_TIMEOUT_KEY_LIFETIME;
+		WPA_PUT_LE32(pos, conf->r0_key_lifetime * 60);
+		pos += 4;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	wpa_send_eapol(sm->wpa_auth, sm,
+		       (secure ? WPA_KEY_INFO_SECURE : 0) | WPA_KEY_INFO_MIC |
+		       WPA_KEY_INFO_ACK | WPA_KEY_INFO_INSTALL |
+		       WPA_KEY_INFO_KEY_TYPE,
+		       _rsc, sm->ANonce, kde, pos - kde, keyidx, encr);
+	os_free(kde);
+}
+
+
+SM_STATE(WPA_PTK, PTKINITDONE)
+{
+	SM_ENTRY_MA(WPA_PTK, PTKINITDONE, wpa_ptk);
+	sm->EAPOLKeyReceived = FALSE;
+	if (sm->Pair) {
+		enum wpa_alg alg = wpa_cipher_to_alg(sm->pairwise);
+		int klen = wpa_cipher_key_len(sm->pairwise);
+		if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
+				     sm->PTK.tk1, klen)) {
+			wpa_sta_disconnect(sm->wpa_auth, sm->addr);
+			return;
+		}
+		/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
+		sm->pairwise_set = TRUE;
+
+		if (sm->wpa_auth->conf.wpa_ptk_rekey) {
+			eloop_cancel_timeout(wpa_rekey_ptk, sm->wpa_auth, sm);
+			eloop_register_timeout(sm->wpa_auth->conf.
+					       wpa_ptk_rekey, 0, wpa_rekey_ptk,
+					       sm->wpa_auth, sm);
+		}
+
+		if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)) {
+			wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
+					   WPA_EAPOL_authorized, 1);
+		}
+	}
+
+	if (0 /* IBSS == TRUE */) {
+		sm->keycount++;
+		if (sm->keycount == 2) {
+			wpa_auth_set_eapol(sm->wpa_auth, sm->addr,
+					   WPA_EAPOL_portValid, 1);
+		}
+	} else {
+		wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_portValid,
+				   1);
+	}
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyAvailable, 0);
+	wpa_auth_set_eapol(sm->wpa_auth, sm->addr, WPA_EAPOL_keyDone, 1);
+	if (sm->wpa == WPA_VERSION_WPA)
+		sm->PInitAKeys = TRUE;
+	else
+		sm->has_GTK = TRUE;
+	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+			 "pairwise key handshake completed (%s)",
+			 sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
+
+#ifdef CONFIG_IEEE80211R
+	wpa_ft_push_pmk_r1(sm->wpa_auth, sm->addr);
+#endif /* CONFIG_IEEE80211R */
+}
+
+
+SM_STEP(WPA_PTK)
+{
+	struct wpa_authenticator *wpa_auth = sm->wpa_auth;
+
+	if (sm->Init)
+		SM_ENTER(WPA_PTK, INITIALIZE);
+	else if (sm->Disconnect
+		 /* || FIX: dot11RSNAConfigSALifetime timeout */) {
+		wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
+				"WPA_PTK: sm->Disconnect");
+		SM_ENTER(WPA_PTK, DISCONNECT);
+	}
+	else if (sm->DeauthenticationRequest)
+		SM_ENTER(WPA_PTK, DISCONNECTED);
+	else if (sm->AuthenticationRequest)
+		SM_ENTER(WPA_PTK, AUTHENTICATION);
+	else if (sm->ReAuthenticationRequest)
+		SM_ENTER(WPA_PTK, AUTHENTICATION2);
+	else if (sm->PTKRequest)
+		SM_ENTER(WPA_PTK, PTKSTART);
+	else switch (sm->wpa_ptk_state) {
+	case WPA_PTK_INITIALIZE:
+		break;
+	case WPA_PTK_DISCONNECT:
+		SM_ENTER(WPA_PTK, DISCONNECTED);
+		break;
+	case WPA_PTK_DISCONNECTED:
+		SM_ENTER(WPA_PTK, INITIALIZE);
+		break;
+	case WPA_PTK_AUTHENTICATION:
+		SM_ENTER(WPA_PTK, AUTHENTICATION2);
+		break;
+	case WPA_PTK_AUTHENTICATION2:
+		if (wpa_key_mgmt_wpa_ieee8021x(sm->wpa_key_mgmt) &&
+		    wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
+				       WPA_EAPOL_keyRun) > 0)
+			SM_ENTER(WPA_PTK, INITPMK);
+		else if (wpa_key_mgmt_wpa_psk(sm->wpa_key_mgmt)
+			 /* FIX: && 802.1X::keyRun */)
+			SM_ENTER(WPA_PTK, INITPSK);
+		break;
+	case WPA_PTK_INITPMK:
+		if (wpa_auth_get_eapol(sm->wpa_auth, sm->addr,
+				       WPA_EAPOL_keyAvailable) > 0)
+			SM_ENTER(WPA_PTK, PTKSTART);
+		else {
+			wpa_auth->dot11RSNA4WayHandshakeFailures++;
+			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+					"INITPMK - keyAvailable = false");
+			SM_ENTER(WPA_PTK, DISCONNECT);
+		}
+		break;
+	case WPA_PTK_INITPSK:
+		if (wpa_auth_get_psk(sm->wpa_auth, sm->addr, NULL))
+			SM_ENTER(WPA_PTK, PTKSTART);
+		else {
+			wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+					"no PSK configured for the STA");
+			wpa_auth->dot11RSNA4WayHandshakeFailures++;
+			SM_ENTER(WPA_PTK, DISCONNECT);
+		}
+		break;
+	case WPA_PTK_PTKSTART:
+		if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
+		    sm->EAPOLKeyPairwise)
+			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
+		else if (sm->TimeoutCtr >
+			 (int) dot11RSNAConfigPairwiseUpdateCount) {
+			wpa_auth->dot11RSNA4WayHandshakeFailures++;
+			wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+					 "PTKSTART: Retry limit %d reached",
+					 dot11RSNAConfigPairwiseUpdateCount);
+			SM_ENTER(WPA_PTK, DISCONNECT);
+		} else if (sm->TimeoutEvt)
+			SM_ENTER(WPA_PTK, PTKSTART);
+		break;
+	case WPA_PTK_PTKCALCNEGOTIATING:
+		if (sm->MICVerified)
+			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING2);
+		else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
+			 sm->EAPOLKeyPairwise)
+			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
+		else if (sm->TimeoutEvt)
+			SM_ENTER(WPA_PTK, PTKSTART);
+		break;
+	case WPA_PTK_PTKCALCNEGOTIATING2:
+		SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
+		break;
+	case WPA_PTK_PTKINITNEGOTIATING:
+		if (sm->update_snonce)
+			SM_ENTER(WPA_PTK, PTKCALCNEGOTIATING);
+		else if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
+			 sm->EAPOLKeyPairwise && sm->MICVerified)
+			SM_ENTER(WPA_PTK, PTKINITDONE);
+		else if (sm->TimeoutCtr >
+			 (int) dot11RSNAConfigPairwiseUpdateCount) {
+			wpa_auth->dot11RSNA4WayHandshakeFailures++;
+			wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+					 "PTKINITNEGOTIATING: Retry limit %d "
+					 "reached",
+					 dot11RSNAConfigPairwiseUpdateCount);
+			SM_ENTER(WPA_PTK, DISCONNECT);
+		} else if (sm->TimeoutEvt)
+			SM_ENTER(WPA_PTK, PTKINITNEGOTIATING);
+		break;
+	case WPA_PTK_PTKINITDONE:
+		break;
+	}
+}
+
+
+SM_STATE(WPA_PTK_GROUP, IDLE)
+{
+	SM_ENTRY_MA(WPA_PTK_GROUP, IDLE, wpa_ptk_group);
+	if (sm->Init) {
+		/* Init flag is not cleared here, so avoid busy
+		 * loop by claiming nothing changed. */
+		sm->changed = FALSE;
+	}
+	sm->GTimeoutCtr = 0;
+}
+
+
+SM_STATE(WPA_PTK_GROUP, REKEYNEGOTIATING)
+{
+	u8 rsc[WPA_KEY_RSC_LEN];
+	struct wpa_group *gsm = sm->group;
+	u8 *kde, *pos, hdr[2];
+	size_t kde_len;
+	u8 *gtk, dummy_gtk[32];
+
+	SM_ENTRY_MA(WPA_PTK_GROUP, REKEYNEGOTIATING, wpa_ptk_group);
+
+	sm->GTimeoutCtr++;
+	if (sm->GTimeoutCtr > (int) dot11RSNAConfigGroupUpdateCount) {
+		/* No point in sending the EAPOL-Key - we will disconnect
+		 * immediately following this. */
+		return;
+	}
+
+	if (sm->wpa == WPA_VERSION_WPA)
+		sm->PInitAKeys = FALSE;
+	sm->TimeoutEvt = FALSE;
+	/* Send EAPOL(1, 1, 1, !Pair, G, RSC, GNonce, MIC(PTK), GTK[GN]) */
+	os_memset(rsc, 0, WPA_KEY_RSC_LEN);
+	if (gsm->wpa_group_state == WPA_GROUP_SETKEYSDONE)
+		wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, rsc);
+	wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+			"sending 1/2 msg of Group Key Handshake");
+
+	gtk = gsm->GTK[gsm->GN - 1];
+	if (sm->wpa_auth->conf.disable_gtk) {
+		/*
+		 * Provide unique random GTK to each STA to prevent use
+		 * of GTK in the BSS.
+		 */
+		if (random_get_bytes(dummy_gtk, gsm->GTK_len) < 0)
+			return;
+		gtk = dummy_gtk;
+	}
+	if (sm->wpa == WPA_VERSION_WPA2) {
+		kde_len = 2 + RSN_SELECTOR_LEN + 2 + gsm->GTK_len +
+			ieee80211w_kde_len(sm);
+		kde = os_malloc(kde_len);
+		if (kde == NULL)
+			return;
+
+		pos = kde;
+		hdr[0] = gsm->GN & 0x03;
+		hdr[1] = 0;
+		pos = wpa_add_kde(pos, RSN_KEY_DATA_GROUPKEY, hdr, 2,
+				  gtk, gsm->GTK_len);
+		pos = ieee80211w_kde_add(sm, pos);
+	} else {
+		kde = gtk;
+		pos = kde + gsm->GTK_len;
+	}
+
+	wpa_send_eapol(sm->wpa_auth, sm,
+		       WPA_KEY_INFO_SECURE | WPA_KEY_INFO_MIC |
+		       WPA_KEY_INFO_ACK |
+		       (!sm->Pair ? WPA_KEY_INFO_INSTALL : 0),
+		       rsc, gsm->GNonce, kde, pos - kde, gsm->GN, 1);
+	if (sm->wpa == WPA_VERSION_WPA2)
+		os_free(kde);
+}
+
+
+SM_STATE(WPA_PTK_GROUP, REKEYESTABLISHED)
+{
+	SM_ENTRY_MA(WPA_PTK_GROUP, REKEYESTABLISHED, wpa_ptk_group);
+	sm->EAPOLKeyReceived = FALSE;
+	if (sm->GUpdateStationKeys)
+		sm->group->GKeyDoneStations--;
+	sm->GUpdateStationKeys = FALSE;
+	sm->GTimeoutCtr = 0;
+	/* FIX: MLME.SetProtection.Request(TA, Tx_Rx) */
+	wpa_auth_vlogger(sm->wpa_auth, sm->addr, LOGGER_INFO,
+			 "group key handshake completed (%s)",
+			 sm->wpa == WPA_VERSION_WPA ? "WPA" : "RSN");
+	sm->has_GTK = TRUE;
+}
+
+
+SM_STATE(WPA_PTK_GROUP, KEYERROR)
+{
+	SM_ENTRY_MA(WPA_PTK_GROUP, KEYERROR, wpa_ptk_group);
+	if (sm->GUpdateStationKeys)
+		sm->group->GKeyDoneStations--;
+	sm->GUpdateStationKeys = FALSE;
+	sm->Disconnect = TRUE;
+}
+
+
+SM_STEP(WPA_PTK_GROUP)
+{
+	if (sm->Init || sm->PtkGroupInit) {
+		SM_ENTER(WPA_PTK_GROUP, IDLE);
+		sm->PtkGroupInit = FALSE;
+	} else switch (sm->wpa_ptk_group_state) {
+	case WPA_PTK_GROUP_IDLE:
+		if (sm->GUpdateStationKeys ||
+		    (sm->wpa == WPA_VERSION_WPA && sm->PInitAKeys))
+			SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
+		break;
+	case WPA_PTK_GROUP_REKEYNEGOTIATING:
+		if (sm->EAPOLKeyReceived && !sm->EAPOLKeyRequest &&
+		    !sm->EAPOLKeyPairwise && sm->MICVerified)
+			SM_ENTER(WPA_PTK_GROUP, REKEYESTABLISHED);
+		else if (sm->GTimeoutCtr >
+			 (int) dot11RSNAConfigGroupUpdateCount)
+			SM_ENTER(WPA_PTK_GROUP, KEYERROR);
+		else if (sm->TimeoutEvt)
+			SM_ENTER(WPA_PTK_GROUP, REKEYNEGOTIATING);
+		break;
+	case WPA_PTK_GROUP_KEYERROR:
+		SM_ENTER(WPA_PTK_GROUP, IDLE);
+		break;
+	case WPA_PTK_GROUP_REKEYESTABLISHED:
+		SM_ENTER(WPA_PTK_GROUP, IDLE);
+		break;
+	}
+}
+
+
+static int wpa_gtk_update(struct wpa_authenticator *wpa_auth,
+			  struct wpa_group *group)
+{
+	int ret = 0;
+
+	os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
+	inc_byte_array(group->Counter, WPA_NONCE_LEN);
+	if (wpa_gmk_to_gtk(group->GMK, "Group key expansion",
+			   wpa_auth->addr, group->GNonce,
+			   group->GTK[group->GN - 1], group->GTK_len) < 0)
+		ret = -1;
+	wpa_hexdump_key(MSG_DEBUG, "GTK",
+			group->GTK[group->GN - 1], group->GTK_len);
+
+#ifdef CONFIG_IEEE80211W
+	if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+		os_memcpy(group->GNonce, group->Counter, WPA_NONCE_LEN);
+		inc_byte_array(group->Counter, WPA_NONCE_LEN);
+		if (wpa_gmk_to_gtk(group->GMK, "IGTK key expansion",
+				   wpa_auth->addr, group->GNonce,
+				   group->IGTK[group->GN_igtk - 4],
+				   WPA_IGTK_LEN) < 0)
+			ret = -1;
+		wpa_hexdump_key(MSG_DEBUG, "IGTK",
+				group->IGTK[group->GN_igtk - 4], WPA_IGTK_LEN);
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	return ret;
+}
+
+
+static void wpa_group_gtk_init(struct wpa_authenticator *wpa_auth,
+			       struct wpa_group *group)
+{
+	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
+		   "GTK_INIT (VLAN-ID %d)", group->vlan_id);
+	group->changed = FALSE; /* GInit is not cleared here; avoid loop */
+	group->wpa_group_state = WPA_GROUP_GTK_INIT;
+
+	/* GTK[0..N] = 0 */
+	os_memset(group->GTK, 0, sizeof(group->GTK));
+	group->GN = 1;
+	group->GM = 2;
+#ifdef CONFIG_IEEE80211W
+	group->GN_igtk = 4;
+	group->GM_igtk = 5;
+#endif /* CONFIG_IEEE80211W */
+	/* GTK[GN] = CalcGTK() */
+	wpa_gtk_update(wpa_auth, group);
+}
+
+
+static int wpa_group_update_sta(struct wpa_state_machine *sm, void *ctx)
+{
+	if (ctx != NULL && ctx != sm->group)
+		return 0;
+
+	if (sm->wpa_ptk_state != WPA_PTK_PTKINITDONE) {
+		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+				"Not in PTKINITDONE; skip Group Key update");
+		sm->GUpdateStationKeys = FALSE;
+		return 0;
+	}
+	if (sm->GUpdateStationKeys) {
+		/*
+		 * This should not really happen, so add a debug log entry.
+		 * Since we clear the GKeyDoneStations before the loop, the
+		 * station needs to be counted here anyway.
+		 */
+		wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
+				"GUpdateStationKeys was already set when "
+				"marking station for GTK rekeying");
+	}
+
+	/* Do not rekey GTK/IGTK when STA is in WNM-Sleep Mode */
+	if (sm->is_wnmsleep)
+		return 0;
+
+	sm->group->GKeyDoneStations++;
+	sm->GUpdateStationKeys = TRUE;
+
+	wpa_sm_step(sm);
+	return 0;
+}
+
+
+#ifdef CONFIG_WNM
+/* update GTK when exiting WNM-Sleep Mode */
+void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm)
+{
+	if (sm->is_wnmsleep)
+		return;
+
+	wpa_group_update_sta(sm, NULL);
+}
+
+
+void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag)
+{
+	sm->is_wnmsleep = !!flag;
+}
+
+
+int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+	struct wpa_group *gsm = sm->group;
+	u8 *start = pos;
+
+	/*
+	 * GTK subelement:
+	 * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
+	 * Key[5..32]
+	 */
+	*pos++ = WNM_SLEEP_SUBELEM_GTK;
+	*pos++ = 11 + gsm->GTK_len;
+	/* Key ID in B0-B1 of Key Info */
+	WPA_PUT_LE16(pos, gsm->GN & 0x03);
+	pos += 2;
+	*pos++ = gsm->GTK_len;
+	if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, pos) != 0)
+		return 0;
+	pos += 8;
+	os_memcpy(pos, gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+	pos += gsm->GTK_len;
+
+	wpa_printf(MSG_DEBUG, "WNM: GTK Key ID %u in WNM-Sleep Mode exit",
+		   gsm->GN);
+	wpa_hexdump_key(MSG_DEBUG, "WNM: GTK in WNM-Sleep Mode exit",
+			gsm->GTK[gsm->GN - 1], gsm->GTK_len);
+
+	return pos - start;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos)
+{
+	struct wpa_group *gsm = sm->group;
+	u8 *start = pos;
+
+	/*
+	 * IGTK subelement:
+	 * Sub-elem ID[1] | Length[1] | KeyID[2] | PN[6] | Key[16]
+	 */
+	*pos++ = WNM_SLEEP_SUBELEM_IGTK;
+	*pos++ = 2 + 6 + WPA_IGTK_LEN;
+	WPA_PUT_LE16(pos, gsm->GN_igtk);
+	pos += 2;
+	if (wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos) != 0)
+		return 0;
+	pos += 6;
+
+	os_memcpy(pos, gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+	pos += WPA_IGTK_LEN;
+
+	wpa_printf(MSG_DEBUG, "WNM: IGTK Key ID %u in WNM-Sleep Mode exit",
+		   gsm->GN_igtk);
+	wpa_hexdump_key(MSG_DEBUG, "WNM: IGTK in WNM-Sleep Mode exit",
+			gsm->IGTK[gsm->GN_igtk - 4], WPA_IGTK_LEN);
+
+	return pos - start;
+}
+#endif /* CONFIG_IEEE80211W */
+#endif /* CONFIG_WNM */
+
+
+static void wpa_group_setkeys(struct wpa_authenticator *wpa_auth,
+			      struct wpa_group *group)
+{
+	int tmp;
+
+	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
+		   "SETKEYS (VLAN-ID %d)", group->vlan_id);
+	group->changed = TRUE;
+	group->wpa_group_state = WPA_GROUP_SETKEYS;
+	group->GTKReKey = FALSE;
+	tmp = group->GM;
+	group->GM = group->GN;
+	group->GN = tmp;
+#ifdef CONFIG_IEEE80211W
+	tmp = group->GM_igtk;
+	group->GM_igtk = group->GN_igtk;
+	group->GN_igtk = tmp;
+#endif /* CONFIG_IEEE80211W */
+	/* "GKeyDoneStations = GNoStations" is done in more robust way by
+	 * counting the STAs that are marked with GUpdateStationKeys instead of
+	 * including all STAs that could be in not-yet-completed state. */
+	wpa_gtk_update(wpa_auth, group);
+
+	if (group->GKeyDoneStations) {
+		wpa_printf(MSG_DEBUG, "wpa_group_setkeys: Unexpected "
+			   "GKeyDoneStations=%d when starting new GTK rekey",
+			   group->GKeyDoneStations);
+		group->GKeyDoneStations = 0;
+	}
+	wpa_auth_for_each_sta(wpa_auth, wpa_group_update_sta, group);
+	wpa_printf(MSG_DEBUG, "wpa_group_setkeys: GKeyDoneStations=%d",
+		   group->GKeyDoneStations);
+}
+
+
+static int wpa_group_config_group_keys(struct wpa_authenticator *wpa_auth,
+				       struct wpa_group *group)
+{
+	int ret = 0;
+
+	if (wpa_auth_set_key(wpa_auth, group->vlan_id,
+			     wpa_cipher_to_alg(wpa_auth->conf.wpa_group),
+			     broadcast_ether_addr, group->GN,
+			     group->GTK[group->GN - 1], group->GTK_len) < 0)
+		ret = -1;
+
+#ifdef CONFIG_IEEE80211W
+	if (wpa_auth->conf.ieee80211w != NO_MGMT_FRAME_PROTECTION &&
+	    wpa_auth_set_key(wpa_auth, group->vlan_id, WPA_ALG_IGTK,
+			     broadcast_ether_addr, group->GN_igtk,
+			     group->IGTK[group->GN_igtk - 4],
+			     WPA_IGTK_LEN) < 0)
+		ret = -1;
+#endif /* CONFIG_IEEE80211W */
+
+	return ret;
+}
+
+
+static int wpa_group_setkeysdone(struct wpa_authenticator *wpa_auth,
+				 struct wpa_group *group)
+{
+	wpa_printf(MSG_DEBUG, "WPA: group state machine entering state "
+		   "SETKEYSDONE (VLAN-ID %d)", group->vlan_id);
+	group->changed = TRUE;
+	group->wpa_group_state = WPA_GROUP_SETKEYSDONE;
+
+	if (wpa_group_config_group_keys(wpa_auth, group) < 0)
+		return -1;
+
+	return 0;
+}
+
+
+static void wpa_group_sm_step(struct wpa_authenticator *wpa_auth,
+			      struct wpa_group *group)
+{
+	if (group->GInit) {
+		wpa_group_gtk_init(wpa_auth, group);
+	} else if (group->wpa_group_state == WPA_GROUP_GTK_INIT &&
+		   group->GTKAuthenticator) {
+		wpa_group_setkeysdone(wpa_auth, group);
+	} else if (group->wpa_group_state == WPA_GROUP_SETKEYSDONE &&
+		   group->GTKReKey) {
+		wpa_group_setkeys(wpa_auth, group);
+	} else if (group->wpa_group_state == WPA_GROUP_SETKEYS) {
+		if (group->GKeyDoneStations == 0)
+			wpa_group_setkeysdone(wpa_auth, group);
+		else if (group->GTKReKey)
+			wpa_group_setkeys(wpa_auth, group);
+	}
+}
+
+
+static int wpa_sm_step(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return 0;
+
+	if (sm->in_step_loop) {
+		/* This should not happen, but if it does, make sure we do not
+		 * end up freeing the state machine too early by exiting the
+		 * recursive call. */
+		wpa_printf(MSG_ERROR, "WPA: wpa_sm_step() called recursively");
+		return 0;
+	}
+
+	sm->in_step_loop = 1;
+	do {
+		if (sm->pending_deinit)
+			break;
+
+		sm->changed = FALSE;
+		sm->wpa_auth->group->changed = FALSE;
+
+		SM_STEP_RUN(WPA_PTK);
+		if (sm->pending_deinit)
+			break;
+		SM_STEP_RUN(WPA_PTK_GROUP);
+		if (sm->pending_deinit)
+			break;
+		wpa_group_sm_step(sm->wpa_auth, sm->group);
+	} while (sm->changed || sm->wpa_auth->group->changed);
+	sm->in_step_loop = 0;
+
+	if (sm->pending_deinit) {
+		wpa_printf(MSG_DEBUG, "WPA: Completing pending STA state "
+			   "machine deinit for " MACSTR, MAC2STR(sm->addr));
+		wpa_free_sta_sm(sm);
+		return 1;
+	}
+	return 0;
+}
+
+
+static void wpa_sm_call_step(void *eloop_ctx, void *timeout_ctx)
+{
+	struct wpa_state_machine *sm = eloop_ctx;
+	wpa_sm_step(sm);
+}
+
+
+void wpa_auth_sm_notify(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return;
+	eloop_register_timeout(0, 0, wpa_sm_call_step, sm, NULL);
+}
+
+
+void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth)
+{
+	int tmp, i;
+	struct wpa_group *group;
+
+	if (wpa_auth == NULL)
+		return;
+
+	group = wpa_auth->group;
+
+	for (i = 0; i < 2; i++) {
+		tmp = group->GM;
+		group->GM = group->GN;
+		group->GN = tmp;
+#ifdef CONFIG_IEEE80211W
+		tmp = group->GM_igtk;
+		group->GM_igtk = group->GN_igtk;
+		group->GN_igtk = tmp;
+#endif /* CONFIG_IEEE80211W */
+		wpa_gtk_update(wpa_auth, group);
+		wpa_group_config_group_keys(wpa_auth, group);
+	}
+}
+
+
+static const char * wpa_bool_txt(int bool)
+{
+	return bool ? "TRUE" : "FALSE";
+}
+
+
+#define RSN_SUITE "%02x-%02x-%02x-%d"
+#define RSN_SUITE_ARG(s) \
+((s) >> 24) & 0xff, ((s) >> 16) & 0xff, ((s) >> 8) & 0xff, (s) & 0xff
+
+int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen)
+{
+	int len = 0, ret;
+	char pmkid_txt[PMKID_LEN * 2 + 1];
+#ifdef CONFIG_RSN_PREAUTH
+	const int preauth = 1;
+#else /* CONFIG_RSN_PREAUTH */
+	const int preauth = 0;
+#endif /* CONFIG_RSN_PREAUTH */
+
+	if (wpa_auth == NULL)
+		return len;
+
+	ret = os_snprintf(buf + len, buflen - len,
+			  "dot11RSNAOptionImplemented=TRUE\n"
+			  "dot11RSNAPreauthenticationImplemented=%s\n"
+			  "dot11RSNAEnabled=%s\n"
+			  "dot11RSNAPreauthenticationEnabled=%s\n",
+			  wpa_bool_txt(preauth),
+			  wpa_bool_txt(wpa_auth->conf.wpa & WPA_PROTO_RSN),
+			  wpa_bool_txt(wpa_auth->conf.rsn_preauth));
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	wpa_snprintf_hex(pmkid_txt, sizeof(pmkid_txt),
+			 wpa_auth->dot11RSNAPMKIDUsed, PMKID_LEN);
+
+	ret = os_snprintf(
+		buf + len, buflen - len,
+		"dot11RSNAConfigVersion=%u\n"
+		"dot11RSNAConfigPairwiseKeysSupported=9999\n"
+		/* FIX: dot11RSNAConfigGroupCipher */
+		/* FIX: dot11RSNAConfigGroupRekeyMethod */
+		/* FIX: dot11RSNAConfigGroupRekeyTime */
+		/* FIX: dot11RSNAConfigGroupRekeyPackets */
+		"dot11RSNAConfigGroupRekeyStrict=%u\n"
+		"dot11RSNAConfigGroupUpdateCount=%u\n"
+		"dot11RSNAConfigPairwiseUpdateCount=%u\n"
+		"dot11RSNAConfigGroupCipherSize=%u\n"
+		"dot11RSNAConfigPMKLifetime=%u\n"
+		"dot11RSNAConfigPMKReauthThreshold=%u\n"
+		"dot11RSNAConfigNumberOfPTKSAReplayCounters=0\n"
+		"dot11RSNAConfigSATimeout=%u\n"
+		"dot11RSNAAuthenticationSuiteSelected=" RSN_SUITE "\n"
+		"dot11RSNAPairwiseCipherSelected=" RSN_SUITE "\n"
+		"dot11RSNAGroupCipherSelected=" RSN_SUITE "\n"
+		"dot11RSNAPMKIDUsed=%s\n"
+		"dot11RSNAAuthenticationSuiteRequested=" RSN_SUITE "\n"
+		"dot11RSNAPairwiseCipherRequested=" RSN_SUITE "\n"
+		"dot11RSNAGroupCipherRequested=" RSN_SUITE "\n"
+		"dot11RSNATKIPCounterMeasuresInvoked=%u\n"
+		"dot11RSNA4WayHandshakeFailures=%u\n"
+		"dot11RSNAConfigNumberOfGTKSAReplayCounters=0\n",
+		RSN_VERSION,
+		!!wpa_auth->conf.wpa_strict_rekey,
+		dot11RSNAConfigGroupUpdateCount,
+		dot11RSNAConfigPairwiseUpdateCount,
+		wpa_cipher_key_len(wpa_auth->conf.wpa_group) * 8,
+		dot11RSNAConfigPMKLifetime,
+		dot11RSNAConfigPMKReauthThreshold,
+		dot11RSNAConfigSATimeout,
+		RSN_SUITE_ARG(wpa_auth->dot11RSNAAuthenticationSuiteSelected),
+		RSN_SUITE_ARG(wpa_auth->dot11RSNAPairwiseCipherSelected),
+		RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherSelected),
+		pmkid_txt,
+		RSN_SUITE_ARG(wpa_auth->dot11RSNAAuthenticationSuiteRequested),
+		RSN_SUITE_ARG(wpa_auth->dot11RSNAPairwiseCipherRequested),
+		RSN_SUITE_ARG(wpa_auth->dot11RSNAGroupCipherRequested),
+		wpa_auth->dot11RSNATKIPCounterMeasuresInvoked,
+		wpa_auth->dot11RSNA4WayHandshakeFailures);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	/* TODO: dot11RSNAConfigPairwiseCiphersTable */
+	/* TODO: dot11RSNAConfigAuthenticationSuitesTable */
+
+	/* Private MIB */
+	ret = os_snprintf(buf + len, buflen - len, "hostapdWPAGroupState=%d\n",
+			  wpa_auth->group->wpa_group_state);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	return len;
+}
+
+
+int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen)
+{
+	int len = 0, ret;
+	u32 pairwise = 0;
+
+	if (sm == NULL)
+		return 0;
+
+	/* TODO: FF-FF-FF-FF-FF-FF entry for broadcast/multicast stats */
+
+	/* dot11RSNAStatsEntry */
+
+	pairwise = wpa_cipher_to_suite(sm->wpa == WPA_VERSION_WPA2 ?
+				       WPA_PROTO_RSN : WPA_PROTO_WPA,
+				       sm->pairwise);
+	if (pairwise == 0)
+		return 0;
+
+	ret = os_snprintf(
+		buf + len, buflen - len,
+		/* TODO: dot11RSNAStatsIndex */
+		"dot11RSNAStatsSTAAddress=" MACSTR "\n"
+		"dot11RSNAStatsVersion=1\n"
+		"dot11RSNAStatsSelectedPairwiseCipher=" RSN_SUITE "\n"
+		/* TODO: dot11RSNAStatsTKIPICVErrors */
+		"dot11RSNAStatsTKIPLocalMICFailures=%u\n"
+		"dot11RSNAStatsTKIPRemoteMICFailures=%u\n"
+		/* TODO: dot11RSNAStatsCCMPReplays */
+		/* TODO: dot11RSNAStatsCCMPDecryptErrors */
+		/* TODO: dot11RSNAStatsTKIPReplays */,
+		MAC2STR(sm->addr),
+		RSN_SUITE_ARG(pairwise),
+		sm->dot11RSNAStatsTKIPLocalMICFailures,
+		sm->dot11RSNAStatsTKIPRemoteMICFailures);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	/* Private MIB */
+	ret = os_snprintf(buf + len, buflen - len,
+			  "hostapdWPAPTKState=%d\n"
+			  "hostapdWPAPTKGroupState=%d\n",
+			  sm->wpa_ptk_state,
+			  sm->wpa_ptk_group_state);
+	if (ret < 0 || (size_t) ret >= buflen - len)
+		return len;
+	len += ret;
+
+	return len;
+}
+
+
+void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth)
+{
+	if (wpa_auth)
+		wpa_auth->dot11RSNATKIPCounterMeasuresInvoked++;
+}
+
+
+int wpa_auth_pairwise_set(struct wpa_state_machine *sm)
+{
+	return sm && sm->pairwise_set;
+}
+
+
+int wpa_auth_get_pairwise(struct wpa_state_machine *sm)
+{
+	return sm->pairwise;
+}
+
+
+int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return -1;
+	return sm->wpa_key_mgmt;
+}
+
+
+int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return 0;
+	return sm->wpa;
+}
+
+
+int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
+			     struct rsn_pmksa_cache_entry *entry)
+{
+	if (sm == NULL || sm->pmksa != entry)
+		return -1;
+	sm->pmksa = NULL;
+	return 0;
+}
+
+
+struct rsn_pmksa_cache_entry *
+wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm)
+{
+	return sm ? sm->pmksa : NULL;
+}
+
+
+void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm)
+{
+	if (sm)
+		sm->dot11RSNAStatsTKIPLocalMICFailures++;
+}
+
+
+const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth, size_t *len)
+{
+	if (wpa_auth == NULL)
+		return NULL;
+	*len = wpa_auth->wpa_ie_len;
+	return wpa_auth->wpa_ie;
+}
+
+
+int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
+		       int session_timeout, struct eapol_state_machine *eapol)
+{
+	if (sm == NULL || sm->wpa != WPA_VERSION_WPA2 ||
+	    sm->wpa_auth->conf.disable_pmksa_caching)
+		return -1;
+
+	if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
+				 sm->wpa_auth->addr, sm->addr, session_timeout,
+				 eapol, sm->wpa_key_mgmt))
+		return 0;
+
+	return -1;
+}
+
+
+int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
+			       const u8 *pmk, size_t len, const u8 *sta_addr,
+			       int session_timeout,
+			       struct eapol_state_machine *eapol)
+{
+	if (wpa_auth == NULL)
+		return -1;
+
+	if (pmksa_cache_auth_add(wpa_auth->pmksa, pmk, len, wpa_auth->addr,
+				 sta_addr, session_timeout, eapol,
+				 WPA_KEY_MGMT_IEEE8021X))
+		return 0;
+
+	return -1;
+}
+
+
+static struct wpa_group *
+wpa_auth_add_group(struct wpa_authenticator *wpa_auth, int vlan_id)
+{
+	struct wpa_group *group;
+
+	if (wpa_auth == NULL || wpa_auth->group == NULL)
+		return NULL;
+
+	wpa_printf(MSG_DEBUG, "WPA: Add group state machine for VLAN-ID %d",
+		   vlan_id);
+	group = wpa_group_init(wpa_auth, vlan_id, 0);
+	if (group == NULL)
+		return NULL;
+
+	group->next = wpa_auth->group->next;
+	wpa_auth->group->next = group;
+
+	return group;
+}
+
+
+int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id)
+{
+	struct wpa_group *group;
+
+	if (sm == NULL || sm->wpa_auth == NULL)
+		return 0;
+
+	group = sm->wpa_auth->group;
+	while (group) {
+		if (group->vlan_id == vlan_id)
+			break;
+		group = group->next;
+	}
+
+	if (group == NULL) {
+		group = wpa_auth_add_group(sm->wpa_auth, vlan_id);
+		if (group == NULL)
+			return -1;
+	}
+
+	if (sm->group == group)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "WPA: Moving STA " MACSTR " to use group state "
+		   "machine for VLAN ID %d", MAC2STR(sm->addr), vlan_id);
+
+	sm->group = group;
+	return 0;
+}
+
+
+void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
+				  struct wpa_state_machine *sm, int ack)
+{
+	if (wpa_auth == NULL || sm == NULL)
+		return;
+	wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key TX status for STA " MACSTR
+		   " ack=%d", MAC2STR(sm->addr), ack);
+	if (sm->pending_1_of_4_timeout && ack) {
+		/*
+		 * Some deployed supplicant implementations update their SNonce
+		 * for each EAPOL-Key 2/4 message even within the same 4-way
+		 * handshake and then fail to use the first SNonce when
+		 * deriving the PTK. This results in unsuccessful 4-way
+		 * handshake whenever the relatively short initial timeout is
+		 * reached and EAPOL-Key 1/4 is retransmitted. Try to work
+		 * around this by increasing the timeout now that we know that
+		 * the station has received the frame.
+		 */
+		int timeout_ms = eapol_key_timeout_subseq;
+		wpa_printf(MSG_DEBUG, "WPA: Increase initial EAPOL-Key 1/4 "
+			   "timeout by %u ms because of acknowledged frame",
+			   timeout_ms);
+		eloop_cancel_timeout(wpa_send_eapol_timeout, wpa_auth, sm);
+		eloop_register_timeout(timeout_ms / 1000,
+				       (timeout_ms % 1000) * 1000,
+				       wpa_send_eapol_timeout, wpa_auth, sm);
+	}
+}
+
+
+int wpa_auth_uses_sae(struct wpa_state_machine *sm)
+{
+	if (sm == NULL)
+		return 0;
+	return wpa_key_mgmt_sae(sm->wpa_key_mgmt);
+}
diff --git a/hostap/src/ap/wpa_auth.h b/hostap/src/ap/wpa_auth.h
new file mode 100644
index 0000000..465eec6
--- /dev/null
+++ b/hostap/src/ap/wpa_auth.h
@@ -0,0 +1,292 @@
+/*
+ * hostapd - IEEE 802.11i-2004 / WPA Authenticator
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_AUTH_H
+#define WPA_AUTH_H
+
+#include "common/defs.h"
+#include "common/eapol_common.h"
+#include "common/wpa_common.h"
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+/* IEEE Std 802.11r-2008, 11A.10.3 - Remote request/response frame definition
+ */
+struct ft_rrb_frame {
+	u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
+	u8 packet_type; /* FT_PACKET_REQUEST/FT_PACKET_RESPONSE */
+	le16 action_length; /* little endian length of action_frame */
+	u8 ap_address[ETH_ALEN];
+	/*
+	 * Followed by action_length bytes of FT Action frame (from Category
+	 * field to the end of Action Frame body.
+	 */
+} STRUCT_PACKED;
+
+#define RSN_REMOTE_FRAME_TYPE_FT_RRB 1
+
+#define FT_PACKET_REQUEST 0
+#define FT_PACKET_RESPONSE 1
+/* Vendor-specific types for R0KH-R1KH protocol; not defined in 802.11r */
+#define FT_PACKET_R0KH_R1KH_PULL 200
+#define FT_PACKET_R0KH_R1KH_RESP 201
+#define FT_PACKET_R0KH_R1KH_PUSH 202
+
+#define FT_R0KH_R1KH_PULL_DATA_LEN 44
+#define FT_R0KH_R1KH_RESP_DATA_LEN 76
+#define FT_R0KH_R1KH_PUSH_DATA_LEN 88
+
+struct ft_r0kh_r1kh_pull_frame {
+	u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
+	u8 packet_type; /* FT_PACKET_R0KH_R1KH_PULL */
+	le16 data_length; /* little endian length of data (44) */
+	u8 ap_address[ETH_ALEN];
+
+	u8 nonce[16];
+	u8 pmk_r0_name[WPA_PMK_NAME_LEN];
+	u8 r1kh_id[FT_R1KH_ID_LEN];
+	u8 s1kh_id[ETH_ALEN];
+	u8 pad[4]; /* 8-octet boundary for AES key wrap */
+	u8 key_wrap_extra[8];
+} STRUCT_PACKED;
+
+struct ft_r0kh_r1kh_resp_frame {
+	u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
+	u8 packet_type; /* FT_PACKET_R0KH_R1KH_RESP */
+	le16 data_length; /* little endian length of data (76) */
+	u8 ap_address[ETH_ALEN];
+
+	u8 nonce[16]; /* copied from pull */
+	u8 r1kh_id[FT_R1KH_ID_LEN]; /* copied from pull */
+	u8 s1kh_id[ETH_ALEN]; /* copied from pull */
+	u8 pmk_r1[PMK_LEN];
+	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+	le16 pairwise;
+	u8 pad[2]; /* 8-octet boundary for AES key wrap */
+	u8 key_wrap_extra[8];
+} STRUCT_PACKED;
+
+struct ft_r0kh_r1kh_push_frame {
+	u8 frame_type; /* RSN_REMOTE_FRAME_TYPE_FT_RRB */
+	u8 packet_type; /* FT_PACKET_R0KH_R1KH_PUSH */
+	le16 data_length; /* little endian length of data (88) */
+	u8 ap_address[ETH_ALEN];
+
+	/* Encrypted with AES key-wrap */
+	u8 timestamp[4]; /* current time in seconds since unix epoch, little
+			  * endian */
+	u8 r1kh_id[FT_R1KH_ID_LEN];
+	u8 s1kh_id[ETH_ALEN];
+	u8 pmk_r0_name[WPA_PMK_NAME_LEN];
+	u8 pmk_r1[PMK_LEN];
+	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+	le16 pairwise;
+	u8 pad[6]; /* 8-octet boundary for AES key wrap */
+	u8 key_wrap_extra[8];
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+/* per STA state machine data */
+
+struct wpa_authenticator;
+struct wpa_state_machine;
+struct rsn_pmksa_cache_entry;
+struct eapol_state_machine;
+
+
+struct ft_remote_r0kh {
+	struct ft_remote_r0kh *next;
+	u8 addr[ETH_ALEN];
+	u8 id[FT_R0KH_ID_MAX_LEN];
+	size_t id_len;
+	u8 key[16];
+};
+
+
+struct ft_remote_r1kh {
+	struct ft_remote_r1kh *next;
+	u8 addr[ETH_ALEN];
+	u8 id[FT_R1KH_ID_LEN];
+	u8 key[16];
+};
+
+
+struct wpa_auth_config {
+	int wpa;
+	int wpa_key_mgmt;
+	int wpa_pairwise;
+	int wpa_group;
+	int wpa_group_rekey;
+	int wpa_strict_rekey;
+	int wpa_gmk_rekey;
+	int wpa_ptk_rekey;
+	int rsn_pairwise;
+	int rsn_preauth;
+	int eapol_version;
+	int peerkey;
+	int wmm_enabled;
+	int wmm_uapsd;
+	int disable_pmksa_caching;
+	int okc;
+	int tx_status;
+#ifdef CONFIG_IEEE80211W
+	enum mfp_options ieee80211w;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211R
+#define SSID_LEN 32
+	u8 ssid[SSID_LEN];
+	size_t ssid_len;
+	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
+	u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
+	size_t r0_key_holder_len;
+	u8 r1_key_holder[FT_R1KH_ID_LEN];
+	u32 r0_key_lifetime;
+	u32 reassociation_deadline;
+	struct ft_remote_r0kh *r0kh_list;
+	struct ft_remote_r1kh *r1kh_list;
+	int pmk_r1_push;
+	int ft_over_ds;
+#endif /* CONFIG_IEEE80211R */
+	int disable_gtk;
+	int ap_mlme;
+};
+
+typedef enum {
+	LOGGER_DEBUG, LOGGER_INFO, LOGGER_WARNING
+} logger_level;
+
+typedef enum {
+	WPA_EAPOL_portEnabled, WPA_EAPOL_portValid, WPA_EAPOL_authorized,
+	WPA_EAPOL_portControl_Auto, WPA_EAPOL_keyRun, WPA_EAPOL_keyAvailable,
+	WPA_EAPOL_keyDone, WPA_EAPOL_inc_EapolFramesTx
+} wpa_eapol_variable;
+
+struct wpa_auth_callbacks {
+	void *ctx;
+	void (*logger)(void *ctx, const u8 *addr, logger_level level,
+		       const char *txt);
+	void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
+	int (*mic_failure_report)(void *ctx, const u8 *addr);
+	void (*set_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var,
+			  int value);
+	int (*get_eapol)(void *ctx, const u8 *addr, wpa_eapol_variable var);
+	const u8 * (*get_psk)(void *ctx, const u8 *addr, const u8 *prev_psk);
+	int (*get_msk)(void *ctx, const u8 *addr, u8 *msk, size_t *len);
+	int (*set_key)(void *ctx, int vlan_id, enum wpa_alg alg,
+		       const u8 *addr, int idx, u8 *key, size_t key_len);
+	int (*get_seqnum)(void *ctx, const u8 *addr, int idx, u8 *seq);
+	int (*send_eapol)(void *ctx, const u8 *addr, const u8 *data,
+			  size_t data_len, int encrypt);
+	int (*for_each_sta)(void *ctx, int (*cb)(struct wpa_state_machine *sm,
+						 void *ctx), void *cb_ctx);
+	int (*for_each_auth)(void *ctx, int (*cb)(struct wpa_authenticator *a,
+						  void *ctx), void *cb_ctx);
+	int (*send_ether)(void *ctx, const u8 *dst, u16 proto, const u8 *data,
+			  size_t data_len);
+#ifdef CONFIG_IEEE80211R
+	struct wpa_state_machine * (*add_sta)(void *ctx, const u8 *sta_addr);
+	int (*send_ft_action)(void *ctx, const u8 *dst,
+			      const u8 *data, size_t data_len);
+	int (*add_tspec)(void *ctx, const u8 *sta_addr, u8 *tspec_ie,
+                         size_t tspec_ielen);
+#endif /* CONFIG_IEEE80211R */
+};
+
+struct wpa_authenticator * wpa_init(const u8 *addr,
+				    struct wpa_auth_config *conf,
+				    struct wpa_auth_callbacks *cb);
+int wpa_init_keys(struct wpa_authenticator *wpa_auth);
+void wpa_deinit(struct wpa_authenticator *wpa_auth);
+int wpa_reconfig(struct wpa_authenticator *wpa_auth,
+		 struct wpa_auth_config *conf);
+
+enum {
+	WPA_IE_OK, WPA_INVALID_IE, WPA_INVALID_GROUP, WPA_INVALID_PAIRWISE,
+	WPA_INVALID_AKMP, WPA_NOT_ENABLED, WPA_ALLOC_FAIL,
+	WPA_MGMT_FRAME_PROTECTION_VIOLATION, WPA_INVALID_MGMT_GROUP_CIPHER,
+	WPA_INVALID_MDIE, WPA_INVALID_PROTO
+};
+	
+int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
+			struct wpa_state_machine *sm,
+			const u8 *wpa_ie, size_t wpa_ie_len,
+			const u8 *mdie, size_t mdie_len);
+int wpa_auth_uses_mfp(struct wpa_state_machine *sm);
+struct wpa_state_machine *
+wpa_auth_sta_init(struct wpa_authenticator *wpa_auth, const u8 *addr);
+int wpa_auth_sta_associated(struct wpa_authenticator *wpa_auth,
+			    struct wpa_state_machine *sm);
+void wpa_auth_sta_no_wpa(struct wpa_state_machine *sm);
+void wpa_auth_sta_deinit(struct wpa_state_machine *sm);
+void wpa_receive(struct wpa_authenticator *wpa_auth,
+		 struct wpa_state_machine *sm,
+		 u8 *data, size_t data_len);
+typedef enum {
+	WPA_AUTH, WPA_ASSOC, WPA_DISASSOC, WPA_DEAUTH, WPA_REAUTH,
+	WPA_REAUTH_EAPOL, WPA_ASSOC_FT
+} wpa_event;
+void wpa_remove_ptk(struct wpa_state_machine *sm);
+int wpa_auth_sm_event(struct wpa_state_machine *sm, wpa_event event);
+void wpa_auth_sm_notify(struct wpa_state_machine *sm);
+void wpa_gtk_rekey(struct wpa_authenticator *wpa_auth);
+int wpa_get_mib(struct wpa_authenticator *wpa_auth, char *buf, size_t buflen);
+int wpa_get_mib_sta(struct wpa_state_machine *sm, char *buf, size_t buflen);
+void wpa_auth_countermeasures_start(struct wpa_authenticator *wpa_auth);
+int wpa_auth_pairwise_set(struct wpa_state_machine *sm);
+int wpa_auth_get_pairwise(struct wpa_state_machine *sm);
+int wpa_auth_sta_key_mgmt(struct wpa_state_machine *sm);
+int wpa_auth_sta_wpa_version(struct wpa_state_machine *sm);
+int wpa_auth_sta_clear_pmksa(struct wpa_state_machine *sm,
+			     struct rsn_pmksa_cache_entry *entry);
+struct rsn_pmksa_cache_entry *
+wpa_auth_sta_get_pmksa(struct wpa_state_machine *sm);
+void wpa_auth_sta_local_mic_failure_report(struct wpa_state_machine *sm);
+const u8 * wpa_auth_get_wpa_ie(struct wpa_authenticator *wpa_auth,
+			       size_t *len);
+int wpa_auth_pmksa_add(struct wpa_state_machine *sm, const u8 *pmk,
+		       int session_timeout, struct eapol_state_machine *eapol);
+int wpa_auth_pmksa_add_preauth(struct wpa_authenticator *wpa_auth,
+			       const u8 *pmk, size_t len, const u8 *sta_addr,
+			       int session_timeout,
+			       struct eapol_state_machine *eapol);
+int wpa_auth_sta_set_vlan(struct wpa_state_machine *sm, int vlan_id);
+void wpa_auth_eapol_key_tx_status(struct wpa_authenticator *wpa_auth,
+				  struct wpa_state_machine *sm, int ack);
+
+#ifdef CONFIG_IEEE80211R
+u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
+				 size_t max_len, int auth_alg,
+				 const u8 *req_ies, size_t req_ies_len);
+void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
+			 u16 auth_transaction, const u8 *ies, size_t ies_len,
+			 void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
+				    u16 auth_transaction, u16 resp,
+				    const u8 *ies, size_t ies_len),
+			 void *ctx);
+u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
+			    size_t ies_len);
+int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len);
+int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
+		  const u8 *data, size_t data_len);
+void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr);
+#endif /* CONFIG_IEEE80211R */
+
+void wpa_wnmsleep_rekey_gtk(struct wpa_state_machine *sm);
+void wpa_set_wnmsleep(struct wpa_state_machine *sm, int flag);
+int wpa_wnmsleep_gtk_subelem(struct wpa_state_machine *sm, u8 *pos);
+int wpa_wnmsleep_igtk_subelem(struct wpa_state_machine *sm, u8 *pos);
+
+int wpa_auth_uses_sae(struct wpa_state_machine *sm);
+
+#endif /* WPA_AUTH_H */
diff --git a/hostap/src/ap/wpa_auth_ft.c b/hostap/src/ap/wpa_auth_ft.c
new file mode 100644
index 0000000..48bf79b
--- /dev/null
+++ b/hostap/src/ap/wpa_auth_ft.c
@@ -0,0 +1,1654 @@
+/*
+ * hostapd - IEEE 802.11r - Fast BSS Transition
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/random.h"
+#include "ap_config.h"
+#include "ieee802_11.h"
+#include "wmm.h"
+#include "wpa_auth.h"
+#include "wpa_auth_i.h"
+
+
+#ifdef CONFIG_IEEE80211R
+
+static int wpa_ft_rrb_send(struct wpa_authenticator *wpa_auth, const u8 *dst,
+			   const u8 *data, size_t data_len)
+{
+	if (wpa_auth->cb.send_ether == NULL)
+		return -1;
+	wpa_printf(MSG_DEBUG, "FT: RRB send to " MACSTR, MAC2STR(dst));
+	return wpa_auth->cb.send_ether(wpa_auth->cb.ctx, dst, ETH_P_RRB,
+				       data, data_len);
+}
+
+
+static int wpa_ft_action_send(struct wpa_authenticator *wpa_auth,
+			      const u8 *dst, const u8 *data, size_t data_len)
+{
+	if (wpa_auth->cb.send_ft_action == NULL)
+		return -1;
+	return wpa_auth->cb.send_ft_action(wpa_auth->cb.ctx, dst,
+					   data, data_len);
+}
+
+
+static struct wpa_state_machine *
+wpa_ft_add_sta(struct wpa_authenticator *wpa_auth, const u8 *sta_addr)
+{
+	if (wpa_auth->cb.add_sta == NULL)
+		return NULL;
+	return wpa_auth->cb.add_sta(wpa_auth->cb.ctx, sta_addr);
+}
+
+
+static int wpa_ft_add_tspec(struct wpa_authenticator *wpa_auth,
+			    const u8 *sta_addr,
+			    u8 *tspec_ie, size_t tspec_ielen)
+{
+	if (wpa_auth->cb.add_tspec == NULL) {
+	        wpa_printf(MSG_DEBUG, "FT: add_tspec is not initialized");
+		return -1;
+	}
+	return wpa_auth->cb.add_tspec(wpa_auth->cb.ctx, sta_addr, tspec_ie,
+				      tspec_ielen);
+}
+
+
+int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len)
+{
+	u8 *pos = buf;
+	u8 capab;
+	if (len < 2 + sizeof(struct rsn_mdie))
+		return -1;
+
+	*pos++ = WLAN_EID_MOBILITY_DOMAIN;
+	*pos++ = MOBILITY_DOMAIN_ID_LEN + 1;
+	os_memcpy(pos, conf->mobility_domain, MOBILITY_DOMAIN_ID_LEN);
+	pos += MOBILITY_DOMAIN_ID_LEN;
+	capab = 0;
+	if (conf->ft_over_ds)
+		capab |= RSN_FT_CAPAB_FT_OVER_DS;
+	*pos++ = capab;
+
+	return pos - buf;
+}
+
+
+int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
+		   size_t r0kh_id_len,
+		   const u8 *anonce, const u8 *snonce,
+		   u8 *buf, size_t len, const u8 *subelem,
+		   size_t subelem_len)
+{
+	u8 *pos = buf, *ielen;
+	struct rsn_ftie *hdr;
+
+	if (len < 2 + sizeof(*hdr) + 2 + FT_R1KH_ID_LEN + 2 + r0kh_id_len +
+	    subelem_len)
+		return -1;
+
+	*pos++ = WLAN_EID_FAST_BSS_TRANSITION;
+	ielen = pos++;
+
+	hdr = (struct rsn_ftie *) pos;
+	os_memset(hdr, 0, sizeof(*hdr));
+	pos += sizeof(*hdr);
+	WPA_PUT_LE16(hdr->mic_control, 0);
+	if (anonce)
+		os_memcpy(hdr->anonce, anonce, WPA_NONCE_LEN);
+	if (snonce)
+		os_memcpy(hdr->snonce, snonce, WPA_NONCE_LEN);
+
+	/* Optional Parameters */
+	*pos++ = FTIE_SUBELEM_R1KH_ID;
+	*pos++ = FT_R1KH_ID_LEN;
+	os_memcpy(pos, conf->r1_key_holder, FT_R1KH_ID_LEN);
+	pos += FT_R1KH_ID_LEN;
+
+	if (r0kh_id) {
+		*pos++ = FTIE_SUBELEM_R0KH_ID;
+		*pos++ = r0kh_id_len;
+		os_memcpy(pos, r0kh_id, r0kh_id_len);
+		pos += r0kh_id_len;
+	}
+
+	if (subelem) {
+		os_memcpy(pos, subelem, subelem_len);
+		pos += subelem_len;
+	}
+
+	*ielen = pos - buf - 2;
+
+	return pos - buf;
+}
+
+
+struct wpa_ft_pmk_r0_sa {
+	struct wpa_ft_pmk_r0_sa *next;
+	u8 pmk_r0[PMK_LEN];
+	u8 pmk_r0_name[WPA_PMK_NAME_LEN];
+	u8 spa[ETH_ALEN];
+	int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
+	/* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
+	int pmk_r1_pushed;
+};
+
+struct wpa_ft_pmk_r1_sa {
+	struct wpa_ft_pmk_r1_sa *next;
+	u8 pmk_r1[PMK_LEN];
+	u8 pmk_r1_name[WPA_PMK_NAME_LEN];
+	u8 spa[ETH_ALEN];
+	int pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
+	/* TODO: expiration, identity, radius_class, EAP type, VLAN ID */
+};
+
+struct wpa_ft_pmk_cache {
+	struct wpa_ft_pmk_r0_sa *pmk_r0;
+	struct wpa_ft_pmk_r1_sa *pmk_r1;
+};
+
+struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void)
+{
+	struct wpa_ft_pmk_cache *cache;
+
+	cache = os_zalloc(sizeof(*cache));
+
+	return cache;
+}
+
+
+void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache)
+{
+	struct wpa_ft_pmk_r0_sa *r0, *r0prev;
+	struct wpa_ft_pmk_r1_sa *r1, *r1prev;
+
+	r0 = cache->pmk_r0;
+	while (r0) {
+		r0prev = r0;
+		r0 = r0->next;
+		os_memset(r0prev->pmk_r0, 0, PMK_LEN);
+		os_free(r0prev);
+	}
+
+	r1 = cache->pmk_r1;
+	while (r1) {
+		r1prev = r1;
+		r1 = r1->next;
+		os_memset(r1prev->pmk_r1, 0, PMK_LEN);
+		os_free(r1prev);
+	}
+
+	os_free(cache);
+}
+
+
+static int wpa_ft_store_pmk_r0(struct wpa_authenticator *wpa_auth,
+			       const u8 *spa, const u8 *pmk_r0,
+			       const u8 *pmk_r0_name, int pairwise)
+{
+	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+	struct wpa_ft_pmk_r0_sa *r0;
+
+	/* TODO: add expiration and limit on number of entries in cache */
+
+	r0 = os_zalloc(sizeof(*r0));
+	if (r0 == NULL)
+		return -1;
+
+	os_memcpy(r0->pmk_r0, pmk_r0, PMK_LEN);
+	os_memcpy(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
+	os_memcpy(r0->spa, spa, ETH_ALEN);
+	r0->pairwise = pairwise;
+
+	r0->next = cache->pmk_r0;
+	cache->pmk_r0 = r0;
+
+	return 0;
+}
+
+
+static int wpa_ft_fetch_pmk_r0(struct wpa_authenticator *wpa_auth,
+			       const u8 *spa, const u8 *pmk_r0_name,
+			       u8 *pmk_r0, int *pairwise)
+{
+	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+	struct wpa_ft_pmk_r0_sa *r0;
+
+	r0 = cache->pmk_r0;
+	while (r0) {
+		if (os_memcmp(r0->spa, spa, ETH_ALEN) == 0 &&
+		    os_memcmp(r0->pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN)
+		    == 0) {
+			os_memcpy(pmk_r0, r0->pmk_r0, PMK_LEN);
+			if (pairwise)
+				*pairwise = r0->pairwise;
+			return 0;
+		}
+
+		r0 = r0->next;
+	}
+
+	return -1;
+}
+
+
+static int wpa_ft_store_pmk_r1(struct wpa_authenticator *wpa_auth,
+			       const u8 *spa, const u8 *pmk_r1,
+			       const u8 *pmk_r1_name, int pairwise)
+{
+	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+	struct wpa_ft_pmk_r1_sa *r1;
+
+	/* TODO: add expiration and limit on number of entries in cache */
+
+	r1 = os_zalloc(sizeof(*r1));
+	if (r1 == NULL)
+		return -1;
+
+	os_memcpy(r1->pmk_r1, pmk_r1, PMK_LEN);
+	os_memcpy(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
+	os_memcpy(r1->spa, spa, ETH_ALEN);
+	r1->pairwise = pairwise;
+
+	r1->next = cache->pmk_r1;
+	cache->pmk_r1 = r1;
+
+	return 0;
+}
+
+
+static int wpa_ft_fetch_pmk_r1(struct wpa_authenticator *wpa_auth,
+			       const u8 *spa, const u8 *pmk_r1_name,
+			       u8 *pmk_r1, int *pairwise)
+{
+	struct wpa_ft_pmk_cache *cache = wpa_auth->ft_pmk_cache;
+	struct wpa_ft_pmk_r1_sa *r1;
+
+	r1 = cache->pmk_r1;
+	while (r1) {
+		if (os_memcmp(r1->spa, spa, ETH_ALEN) == 0 &&
+		    os_memcmp(r1->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN)
+		    == 0) {
+			os_memcpy(pmk_r1, r1->pmk_r1, PMK_LEN);
+			if (pairwise)
+				*pairwise = r1->pairwise;
+			return 0;
+		}
+
+		r1 = r1->next;
+	}
+
+	return -1;
+}
+
+
+static int wpa_ft_pull_pmk_r1(struct wpa_authenticator *wpa_auth,
+			      const u8 *s1kh_id, const u8 *r0kh_id,
+			      size_t r0kh_id_len, const u8 *pmk_r0_name)
+{
+	struct ft_remote_r0kh *r0kh;
+	struct ft_r0kh_r1kh_pull_frame frame, f;
+
+	r0kh = wpa_auth->conf.r0kh_list;
+	while (r0kh) {
+		if (r0kh->id_len == r0kh_id_len &&
+		    os_memcmp(r0kh->id, r0kh_id, r0kh_id_len) == 0)
+			break;
+		r0kh = r0kh->next;
+	}
+	if (r0kh == NULL)
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "FT: Send PMK-R1 pull request to remote R0KH "
+		   "address " MACSTR, MAC2STR(r0kh->addr));
+
+	os_memset(&frame, 0, sizeof(frame));
+	frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
+	frame.packet_type = FT_PACKET_R0KH_R1KH_PULL;
+	frame.data_length = host_to_le16(FT_R0KH_R1KH_PULL_DATA_LEN);
+	os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN);
+
+	/* aes_wrap() does not support inplace encryption, so use a temporary
+	 * buffer for the data. */
+	if (random_get_bytes(f.nonce, sizeof(f.nonce))) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
+			   "nonce");
+		return -1;
+	}
+	os_memcpy(f.pmk_r0_name, pmk_r0_name, WPA_PMK_NAME_LEN);
+	os_memcpy(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
+	os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
+
+	if (aes_wrap(r0kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
+		     f.nonce, frame.nonce) < 0)
+		return -1;
+
+	wpa_ft_rrb_send(wpa_auth, r0kh->addr, (u8 *) &frame, sizeof(frame));
+
+	return 0;
+}
+
+
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
+			   struct wpa_ptk *ptk, size_t ptk_len)
+{
+	u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
+	u8 pmk_r1[PMK_LEN];
+	u8 ptk_name[WPA_PMK_NAME_LEN];
+	const u8 *mdid = sm->wpa_auth->conf.mobility_domain;
+	const u8 *r0kh = sm->wpa_auth->conf.r0_key_holder;
+	size_t r0kh_len = sm->wpa_auth->conf.r0_key_holder_len;
+	const u8 *r1kh = sm->wpa_auth->conf.r1_key_holder;
+	const u8 *ssid = sm->wpa_auth->conf.ssid;
+	size_t ssid_len = sm->wpa_auth->conf.ssid_len;
+
+
+	if (sm->xxkey_len == 0) {
+		wpa_printf(MSG_DEBUG, "FT: XXKey not available for key "
+			   "derivation");
+		return -1;
+	}
+
+	wpa_derive_pmk_r0(sm->xxkey, sm->xxkey_len, ssid, ssid_len, mdid,
+			  r0kh, r0kh_len, sm->addr, pmk_r0, pmk_r0_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R0", pmk_r0, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR0Name", pmk_r0_name, WPA_PMK_NAME_LEN);
+	wpa_ft_store_pmk_r0(sm->wpa_auth, sm->addr, pmk_r0, pmk_r0_name,
+			    sm->pairwise);
+
+	wpa_derive_pmk_r1(pmk_r0, pmk_r0_name, r1kh, sm->addr,
+			  pmk_r1, sm->pmk_r1_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", pmk_r1, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", sm->pmk_r1_name,
+		    WPA_PMK_NAME_LEN);
+	wpa_ft_store_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1, sm->pmk_r1_name,
+			    sm->pairwise);
+
+	wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
+			  sm->wpa_auth->addr, sm->pmk_r1_name,
+			  (u8 *) ptk, ptk_len, ptk_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PTK", (u8 *) ptk, ptk_len);
+	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+
+	return 0;
+}
+
+
+static inline int wpa_auth_get_seqnum(struct wpa_authenticator *wpa_auth,
+				      const u8 *addr, int idx, u8 *seq)
+{
+	if (wpa_auth->cb.get_seqnum == NULL)
+		return -1;
+	return wpa_auth->cb.get_seqnum(wpa_auth->cb.ctx, addr, idx, seq);
+}
+
+
+static u8 * wpa_ft_gtk_subelem(struct wpa_state_machine *sm, size_t *len)
+{
+	u8 *subelem;
+	struct wpa_group *gsm = sm->group;
+	size_t subelem_len, pad_len;
+	const u8 *key;
+	size_t key_len;
+	u8 keybuf[32];
+
+	key_len = gsm->GTK_len;
+	if (key_len > sizeof(keybuf))
+		return NULL;
+
+	/*
+	 * Pad key for AES Key Wrap if it is not multiple of 8 bytes or is less
+	 * than 16 bytes.
+	 */
+	pad_len = key_len % 8;
+	if (pad_len)
+		pad_len = 8 - pad_len;
+	if (key_len + pad_len < 16)
+		pad_len += 8;
+	if (pad_len) {
+		os_memcpy(keybuf, gsm->GTK[gsm->GN - 1], key_len);
+		os_memset(keybuf + key_len, 0, pad_len);
+		keybuf[key_len] = 0xdd;
+		key_len += pad_len;
+		key = keybuf;
+	} else
+		key = gsm->GTK[gsm->GN - 1];
+
+	/*
+	 * Sub-elem ID[1] | Length[1] | Key Info[2] | Key Length[1] | RSC[8] |
+	 * Key[5..32].
+	 */
+	subelem_len = 13 + key_len + 8;
+	subelem = os_zalloc(subelem_len);
+	if (subelem == NULL)
+		return NULL;
+
+	subelem[0] = FTIE_SUBELEM_GTK;
+	subelem[1] = 11 + key_len + 8;
+	/* Key ID in B0-B1 of Key Info */
+	WPA_PUT_LE16(&subelem[2], gsm->GN & 0x03);
+	subelem[4] = gsm->GTK_len;
+	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN, subelem + 5);
+	if (aes_wrap(sm->PTK.kek, key_len / 8, key, subelem + 13)) {
+		os_free(subelem);
+		return NULL;
+	}
+
+	*len = subelem_len;
+	return subelem;
+}
+
+
+#ifdef CONFIG_IEEE80211W
+static u8 * wpa_ft_igtk_subelem(struct wpa_state_machine *sm, size_t *len)
+{
+	u8 *subelem, *pos;
+	struct wpa_group *gsm = sm->group;
+	size_t subelem_len;
+
+	/* Sub-elem ID[1] | Length[1] | KeyID[2] | IPN[6] | Key Length[1] |
+	 * Key[16+8] */
+	subelem_len = 1 + 1 + 2 + 6 + 1 + WPA_IGTK_LEN + 8;
+	subelem = os_zalloc(subelem_len);
+	if (subelem == NULL)
+		return NULL;
+
+	pos = subelem;
+	*pos++ = FTIE_SUBELEM_IGTK;
+	*pos++ = subelem_len - 2;
+	WPA_PUT_LE16(pos, gsm->GN_igtk);
+	pos += 2;
+	wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
+	pos += 6;
+	*pos++ = WPA_IGTK_LEN;
+	if (aes_wrap(sm->PTK.kek, WPA_IGTK_LEN / 8,
+		     gsm->IGTK[gsm->GN_igtk - 4], pos)) {
+		os_free(subelem);
+		return NULL;
+	}
+
+	*len = subelem_len;
+	return subelem;
+}
+#endif /* CONFIG_IEEE80211W */
+
+
+static u8 * wpa_ft_process_rdie(struct wpa_state_machine *sm,
+				u8 *pos, u8 *end, u8 id, u8 descr_count,
+				const u8 *ies, size_t ies_len)
+{
+	struct ieee802_11_elems parse;
+	struct rsn_rdie *rdie;
+
+	wpa_printf(MSG_DEBUG, "FT: Resource Request: id=%d descr_count=%d",
+		   id, descr_count);
+	wpa_hexdump(MSG_MSGDUMP, "FT: Resource descriptor IE(s)",
+		    ies, ies_len);
+
+	if (end - pos < (int) sizeof(*rdie)) {
+		wpa_printf(MSG_ERROR, "FT: Not enough room for response RDIE");
+		return pos;
+	}
+
+	*pos++ = WLAN_EID_RIC_DATA;
+	*pos++ = sizeof(*rdie);
+	rdie = (struct rsn_rdie *) pos;
+	rdie->id = id;
+	rdie->descr_count = 0;
+	rdie->status_code = host_to_le16(WLAN_STATUS_SUCCESS);
+	pos += sizeof(*rdie);
+
+	if (ieee802_11_parse_elems((u8 *) ies, ies_len, &parse, 1) ==
+	    ParseFailed) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to parse request IEs");
+		rdie->status_code =
+			host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
+		return pos;
+	}
+
+#ifdef NEED_AP_MLME
+	if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
+		struct wmm_tspec_element *tspec;
+		int res;
+
+		if (parse.wmm_tspec_len + 2 < (int) sizeof(*tspec)) {
+			wpa_printf(MSG_DEBUG, "FT: Too short WMM TSPEC IE "
+				   "(%d)", (int) parse.wmm_tspec_len);
+			rdie->status_code =
+				host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
+			return pos;
+		}
+		if (end - pos < (int) sizeof(*tspec)) {
+			wpa_printf(MSG_ERROR, "FT: Not enough room for "
+				   "response TSPEC");
+			rdie->status_code =
+				host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
+			return pos;
+		}
+		tspec = (struct wmm_tspec_element *) pos;
+		os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
+		res = wmm_process_tspec(tspec);
+		wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res);
+		if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS)
+			rdie->status_code =
+				host_to_le16(WLAN_STATUS_INVALID_PARAMETERS);
+		else if (res == WMM_ADDTS_STATUS_REFUSED)
+			rdie->status_code =
+				host_to_le16(WLAN_STATUS_REQUEST_DECLINED);
+		else {
+			/* TSPEC accepted; include updated TSPEC in response */
+			rdie->descr_count = 1;
+			pos += sizeof(*tspec);
+		}
+		return pos;
+	}
+#endif /* NEED_AP_MLME */
+
+	if (parse.wmm_tspec && !sm->wpa_auth->conf.ap_mlme) {
+		struct wmm_tspec_element *tspec;
+		int res;
+
+		tspec = (struct wmm_tspec_element *) pos;
+		os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
+		res = wpa_ft_add_tspec(sm->wpa_auth, sm->addr, pos,
+				       sizeof(*tspec));
+		if (res >= 0) {
+			if (res)
+				rdie->status_code = host_to_le16(res);
+			else {
+				/* TSPEC accepted; include updated TSPEC in
+				 * response */
+		                rdie->descr_count = 1;
+	                        pos += sizeof(*tspec);
+			}
+			return pos;
+		}
+	}
+
+	wpa_printf(MSG_DEBUG, "FT: No supported resource requested");
+	rdie->status_code = host_to_le16(WLAN_STATUS_UNSPECIFIED_FAILURE);
+	return pos;
+}
+
+
+static u8 * wpa_ft_process_ric(struct wpa_state_machine *sm, u8 *pos, u8 *end,
+			       const u8 *ric, size_t ric_len)
+{
+	const u8 *rpos, *start;
+	const struct rsn_rdie *rdie;
+
+	wpa_hexdump(MSG_MSGDUMP, "FT: RIC Request", ric, ric_len);
+
+	rpos = ric;
+	while (rpos + sizeof(*rdie) < ric + ric_len) {
+		if (rpos[0] != WLAN_EID_RIC_DATA || rpos[1] < sizeof(*rdie) ||
+		    rpos + 2 + rpos[1] > ric + ric_len)
+			break;
+		rdie = (const struct rsn_rdie *) (rpos + 2);
+		rpos += 2 + rpos[1];
+		start = rpos;
+
+		while (rpos + 2 <= ric + ric_len &&
+		       rpos + 2 + rpos[1] <= ric + ric_len) {
+			if (rpos[0] == WLAN_EID_RIC_DATA)
+				break;
+			rpos += 2 + rpos[1];
+		}
+		pos = wpa_ft_process_rdie(sm, pos, end, rdie->id,
+					  rdie->descr_count,
+					  start, rpos - start);
+	}
+
+	return pos;
+}
+
+
+u8 * wpa_sm_write_assoc_resp_ies(struct wpa_state_machine *sm, u8 *pos,
+				 size_t max_len, int auth_alg,
+				 const u8 *req_ies, size_t req_ies_len)
+{
+	u8 *end, *mdie, *ftie, *rsnie = NULL, *r0kh_id, *subelem = NULL;
+	size_t mdie_len, ftie_len, rsnie_len = 0, r0kh_id_len, subelem_len = 0;
+	int res;
+	struct wpa_auth_config *conf;
+	struct rsn_ftie *_ftie;
+	struct wpa_ft_ies parse;
+	u8 *ric_start;
+	u8 *anonce, *snonce;
+
+	if (sm == NULL)
+		return pos;
+
+	conf = &sm->wpa_auth->conf;
+
+	if (sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_IEEE8021X &&
+	    sm->wpa_key_mgmt != WPA_KEY_MGMT_FT_PSK)
+		return pos;
+
+	end = pos + max_len;
+
+	if (auth_alg == WLAN_AUTH_FT) {
+		/*
+		 * RSN (only present if this is a Reassociation Response and
+		 * part of a fast BSS transition)
+		 */
+		res = wpa_write_rsn_ie(conf, pos, end - pos, sm->pmk_r1_name);
+		if (res < 0)
+			return pos;
+		rsnie = pos;
+		rsnie_len = res;
+		pos += res;
+	}
+
+	/* Mobility Domain Information */
+	res = wpa_write_mdie(conf, pos, end - pos);
+	if (res < 0)
+		return pos;
+	mdie = pos;
+	mdie_len = res;
+	pos += res;
+
+	/* Fast BSS Transition Information */
+	if (auth_alg == WLAN_AUTH_FT) {
+		subelem = wpa_ft_gtk_subelem(sm, &subelem_len);
+		r0kh_id = sm->r0kh_id;
+		r0kh_id_len = sm->r0kh_id_len;
+		anonce = sm->ANonce;
+		snonce = sm->SNonce;
+#ifdef CONFIG_IEEE80211W
+		if (sm->mgmt_frame_prot) {
+			u8 *igtk;
+			size_t igtk_len;
+			u8 *nbuf;
+			igtk = wpa_ft_igtk_subelem(sm, &igtk_len);
+			if (igtk == NULL) {
+				os_free(subelem);
+				return pos;
+			}
+			nbuf = os_realloc(subelem, subelem_len + igtk_len);
+			if (nbuf == NULL) {
+				os_free(subelem);
+				os_free(igtk);
+				return pos;
+			}
+			subelem = nbuf;
+			os_memcpy(subelem + subelem_len, igtk, igtk_len);
+			subelem_len += igtk_len;
+			os_free(igtk);
+		}
+#endif /* CONFIG_IEEE80211W */
+	} else {
+		r0kh_id = conf->r0_key_holder;
+		r0kh_id_len = conf->r0_key_holder_len;
+		anonce = NULL;
+		snonce = NULL;
+	}
+	res = wpa_write_ftie(conf, r0kh_id, r0kh_id_len, anonce, snonce, pos,
+			     end - pos, subelem, subelem_len);
+	os_free(subelem);
+	if (res < 0)
+		return pos;
+	ftie = pos;
+	ftie_len = res;
+	pos += res;
+
+	os_free(sm->assoc_resp_ftie);
+	sm->assoc_resp_ftie = os_malloc(ftie_len);
+	if (sm->assoc_resp_ftie)
+		os_memcpy(sm->assoc_resp_ftie, ftie, ftie_len);
+
+	_ftie = (struct rsn_ftie *) (ftie + 2);
+	if (auth_alg == WLAN_AUTH_FT)
+		_ftie->mic_control[1] = 3; /* Information element count */
+
+	ric_start = pos;
+	if (wpa_ft_parse_ies(req_ies, req_ies_len, &parse) == 0 && parse.ric) {
+		pos = wpa_ft_process_ric(sm, pos, end, parse.ric,
+					 parse.ric_len);
+		if (auth_alg == WLAN_AUTH_FT)
+			_ftie->mic_control[1] +=
+				ieee802_11_ie_count(ric_start,
+						    pos - ric_start);
+	}
+	if (ric_start == pos)
+		ric_start = NULL;
+
+	if (auth_alg == WLAN_AUTH_FT &&
+	    wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 6,
+		       mdie, mdie_len, ftie, ftie_len,
+		       rsnie, rsnie_len,
+		       ric_start, ric_start ? pos - ric_start : 0,
+		       _ftie->mic) < 0)
+		wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
+
+	return pos;
+}
+
+
+static inline int wpa_auth_set_key(struct wpa_authenticator *wpa_auth,
+				   int vlan_id,
+				   enum wpa_alg alg, const u8 *addr, int idx,
+				   u8 *key, size_t key_len)
+{
+	if (wpa_auth->cb.set_key == NULL)
+		return -1;
+	return wpa_auth->cb.set_key(wpa_auth->cb.ctx, vlan_id, alg, addr, idx,
+				    key, key_len);
+}
+
+
+void wpa_ft_install_ptk(struct wpa_state_machine *sm)
+{
+	enum wpa_alg alg;
+	int klen;
+
+	/* MLME-SETKEYS.request(PTK) */
+	alg = wpa_cipher_to_alg(sm->pairwise);
+	klen = wpa_cipher_key_len(sm->pairwise);
+	if (!wpa_cipher_valid_pairwise(sm->pairwise)) {
+		wpa_printf(MSG_DEBUG, "FT: Unknown pairwise alg 0x%x - skip "
+			   "PTK configuration", sm->pairwise);
+		return;
+	}
+
+	/* FIX: add STA entry to kernel/driver here? The set_key will fail
+	 * most likely without this.. At the moment, STA entry is added only
+	 * after association has been completed. This function will be called
+	 * again after association to get the PTK configured, but that could be
+	 * optimized by adding the STA entry earlier.
+	 */
+	if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
+			     sm->PTK.tk1, klen))
+		return;
+
+	/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
+	sm->pairwise_set = TRUE;
+}
+
+
+static u16 wpa_ft_process_auth_req(struct wpa_state_machine *sm,
+				   const u8 *ies, size_t ies_len,
+				   u8 **resp_ies, size_t *resp_ies_len)
+{
+	struct rsn_mdie *mdie;
+	struct rsn_ftie *ftie;
+	u8 pmk_r1[PMK_LEN], pmk_r1_name[WPA_PMK_NAME_LEN];
+	u8 ptk_name[WPA_PMK_NAME_LEN];
+	struct wpa_auth_config *conf;
+	struct wpa_ft_ies parse;
+	size_t buflen, ptk_len;
+	int ret;
+	u8 *pos, *end;
+	int pairwise;
+
+	*resp_ies = NULL;
+	*resp_ies_len = 0;
+
+	sm->pmk_r1_name_valid = 0;
+	conf = &sm->wpa_auth->conf;
+
+	wpa_hexdump(MSG_DEBUG, "FT: Received authentication frame IEs",
+		    ies, ies_len);
+
+	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	mdie = (struct rsn_mdie *) parse.mdie;
+	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
+	    os_memcmp(mdie->mobility_domain,
+		      sm->wpa_auth->conf.mobility_domain,
+		      MOBILITY_DOMAIN_ID_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
+		return WLAN_STATUS_INVALID_MDIE;
+	}
+
+	ftie = (struct rsn_ftie *) parse.ftie;
+	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+		return WLAN_STATUS_INVALID_FTIE;
+	}
+
+	os_memcpy(sm->SNonce, ftie->snonce, WPA_NONCE_LEN);
+
+	if (parse.r0kh_id == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE - no R0KH-ID");
+		return WLAN_STATUS_INVALID_FTIE;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "FT: STA R0KH-ID",
+		    parse.r0kh_id, parse.r0kh_id_len);
+	os_memcpy(sm->r0kh_id, parse.r0kh_id, parse.r0kh_id_len);
+	sm->r0kh_id_len = parse.r0kh_id_len;
+
+	if (parse.rsn_pmkid == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE");
+		return WLAN_STATUS_INVALID_PMKID;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "FT: Requested PMKR0Name",
+		    parse.rsn_pmkid, WPA_PMK_NAME_LEN);
+	wpa_derive_pmk_r1_name(parse.rsn_pmkid,
+			       sm->wpa_auth->conf.r1_key_holder, sm->addr,
+			       pmk_r1_name);
+	wpa_hexdump(MSG_DEBUG, "FT: Derived requested PMKR1Name",
+		    pmk_r1_name, WPA_PMK_NAME_LEN);
+
+	if (wpa_ft_fetch_pmk_r1(sm->wpa_auth, sm->addr, pmk_r1_name, pmk_r1,
+		    &pairwise) < 0) {
+		if (wpa_ft_pull_pmk_r1(sm->wpa_auth, sm->addr, sm->r0kh_id,
+				       sm->r0kh_id_len, parse.rsn_pmkid) < 0) {
+			wpa_printf(MSG_DEBUG, "FT: Did not have matching "
+				   "PMK-R1 and unknown R0KH-ID");
+			return WLAN_STATUS_INVALID_PMKID;
+		}
+
+		/*
+		 * TODO: Should return "status pending" (and the caller should
+		 * not send out response now). The real response will be sent
+		 * once the response from R0KH is received.
+		 */
+		return WLAN_STATUS_INVALID_PMKID;
+	}
+
+	wpa_hexdump_key(MSG_DEBUG, "FT: Selected PMK-R1", pmk_r1, PMK_LEN);
+	sm->pmk_r1_name_valid = 1;
+	os_memcpy(sm->pmk_r1_name, pmk_r1_name, WPA_PMK_NAME_LEN);
+
+	if (random_get_bytes(sm->ANonce, WPA_NONCE_LEN)) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to get random data for "
+			   "ANonce");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
+		    sm->SNonce, WPA_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: Generated ANonce",
+		    sm->ANonce, WPA_NONCE_LEN);
+
+	ptk_len = pairwise == WPA_CIPHER_TKIP ? 64 : 48;
+	wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
+			  sm->wpa_auth->addr, pmk_r1_name,
+			  (u8 *) &sm->PTK, ptk_len, ptk_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PTK",
+			(u8 *) &sm->PTK, ptk_len);
+	wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+
+	sm->pairwise = pairwise;
+	wpa_ft_install_ptk(sm);
+
+	buflen = 2 + sizeof(struct rsn_mdie) + 2 + sizeof(struct rsn_ftie) +
+		2 + FT_R1KH_ID_LEN + 200;
+	*resp_ies = os_zalloc(buflen);
+	if (*resp_ies == NULL) {
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	pos = *resp_ies;
+	end = *resp_ies + buflen;
+
+	ret = wpa_write_rsn_ie(conf, pos, end - pos, parse.rsn_pmkid);
+	if (ret < 0) {
+		os_free(*resp_ies);
+		*resp_ies = NULL;
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+	pos += ret;
+
+	ret = wpa_write_mdie(conf, pos, end - pos);
+	if (ret < 0) {
+		os_free(*resp_ies);
+		*resp_ies = NULL;
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+	pos += ret;
+
+	ret = wpa_write_ftie(conf, parse.r0kh_id, parse.r0kh_id_len,
+			     sm->ANonce, sm->SNonce, pos, end - pos, NULL, 0);
+	if (ret < 0) {
+		os_free(*resp_ies);
+		*resp_ies = NULL;
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+	pos += ret;
+
+	*resp_ies_len = pos - *resp_ies;
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+void wpa_ft_process_auth(struct wpa_state_machine *sm, const u8 *bssid,
+			 u16 auth_transaction, const u8 *ies, size_t ies_len,
+			 void (*cb)(void *ctx, const u8 *dst, const u8 *bssid,
+				    u16 auth_transaction, u16 status,
+				    const u8 *ies, size_t ies_len),
+			 void *ctx)
+{
+	u16 status;
+	u8 *resp_ies;
+	size_t resp_ies_len;
+
+	if (sm == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: Received authentication frame, but "
+			   "WPA SM not available");
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "FT: Received authentication frame: STA=" MACSTR
+		   " BSSID=" MACSTR " transaction=%d",
+		   MAC2STR(sm->addr), MAC2STR(bssid), auth_transaction);
+	status = wpa_ft_process_auth_req(sm, ies, ies_len, &resp_ies,
+					 &resp_ies_len);
+
+	wpa_printf(MSG_DEBUG, "FT: FT authentication response: dst=" MACSTR
+		   " auth_transaction=%d status=%d",
+		   MAC2STR(sm->addr), auth_transaction + 1, status);
+	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
+	cb(ctx, sm->addr, bssid, auth_transaction + 1, status,
+	   resp_ies, resp_ies_len);
+	os_free(resp_ies);
+}
+
+
+u16 wpa_ft_validate_reassoc(struct wpa_state_machine *sm, const u8 *ies,
+			    size_t ies_len)
+{
+	struct wpa_ft_ies parse;
+	struct rsn_mdie *mdie;
+	struct rsn_ftie *ftie;
+	u8 mic[16];
+	unsigned int count;
+
+	if (sm == NULL)
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+
+	wpa_hexdump(MSG_DEBUG, "FT: Reassoc Req IEs", ies, ies_len);
+
+	if (wpa_ft_parse_ies(ies, ies_len, &parse) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to parse FT IEs");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	if (parse.rsn == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No RSNIE in Reassoc Req");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	if (parse.rsn_pmkid == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No PMKID in RSNIE");
+		return WLAN_STATUS_INVALID_PMKID;
+	}
+
+	if (os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN) != 0)
+	{
+		wpa_printf(MSG_DEBUG, "FT: PMKID in Reassoc Req did not match "
+			   "with the PMKR1Name derived from auth request");
+		return WLAN_STATUS_INVALID_PMKID;
+	}
+
+	mdie = (struct rsn_mdie *) parse.mdie;
+	if (mdie == NULL || parse.mdie_len < sizeof(*mdie) ||
+	    os_memcmp(mdie->mobility_domain,
+		      sm->wpa_auth->conf.mobility_domain,
+		      MOBILITY_DOMAIN_ID_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid MDIE");
+		return WLAN_STATUS_INVALID_MDIE;
+	}
+
+	ftie = (struct rsn_ftie *) parse.ftie;
+	if (ftie == NULL || parse.ftie_len < sizeof(*ftie)) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid FTIE");
+		return WLAN_STATUS_INVALID_FTIE;
+	}
+
+	if (os_memcmp(ftie->snonce, sm->SNonce, WPA_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: SNonce mismatch in FTIE");
+		wpa_hexdump(MSG_DEBUG, "FT: Received SNonce",
+			    ftie->snonce, WPA_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "FT: Expected SNonce",
+			    sm->SNonce, WPA_NONCE_LEN);
+		return -1;
+	}
+
+	if (os_memcmp(ftie->anonce, sm->ANonce, WPA_NONCE_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: ANonce mismatch in FTIE");
+		wpa_hexdump(MSG_DEBUG, "FT: Received ANonce",
+			    ftie->anonce, WPA_NONCE_LEN);
+		wpa_hexdump(MSG_DEBUG, "FT: Expected ANonce",
+			    sm->ANonce, WPA_NONCE_LEN);
+		return -1;
+	}
+
+
+	if (parse.r0kh_id == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No R0KH-ID subelem in FTIE");
+		return -1;
+	}
+
+	if (parse.r0kh_id_len != sm->r0kh_id_len ||
+	    os_memcmp(parse.r0kh_id, sm->r0kh_id, parse.r0kh_id_len) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: R0KH-ID in FTIE did not match with "
+			   "the current R0KH-ID");
+		wpa_hexdump(MSG_DEBUG, "FT: R0KH-ID in FTIE",
+			    parse.r0kh_id, parse.r0kh_id_len);
+		wpa_hexdump(MSG_DEBUG, "FT: The current R0KH-ID",
+			    sm->r0kh_id, sm->r0kh_id_len);
+		return -1;
+	}
+
+	if (parse.r1kh_id == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No R1KH-ID subelem in FTIE");
+		return -1;
+	}
+
+	if (os_memcmp(parse.r1kh_id, sm->wpa_auth->conf.r1_key_holder,
+		      FT_R1KH_ID_LEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Unknown R1KH-ID used in "
+			   "ReassocReq");
+		wpa_hexdump(MSG_DEBUG, "FT: R1KH-ID in FTIE",
+			    parse.r1kh_id, FT_R1KH_ID_LEN);
+		wpa_hexdump(MSG_DEBUG, "FT: Expected R1KH-ID",
+			    sm->wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN);
+		return -1;
+	}
+
+	if (parse.rsn_pmkid == NULL ||
+	    os_memcmp(parse.rsn_pmkid, sm->pmk_r1_name, WPA_PMK_NAME_LEN)) {
+		wpa_printf(MSG_DEBUG, "FT: No matching PMKR1Name (PMKID) in "
+			   "RSNIE (pmkid=%d)", !!parse.rsn_pmkid);
+		return -1;
+	}
+
+	count = 3;
+	if (parse.ric)
+		count += ieee802_11_ie_count(parse.ric, parse.ric_len);
+	if (ftie->mic_control[1] != count) {
+		wpa_printf(MSG_DEBUG, "FT: Unexpected IE count in MIC "
+			   "Control: received %u expected %u",
+			   ftie->mic_control[1], count);
+		return -1;
+	}
+
+	if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5,
+		       parse.mdie - 2, parse.mdie_len + 2,
+		       parse.ftie - 2, parse.ftie_len + 2,
+		       parse.rsn - 2, parse.rsn_len + 2,
+		       parse.ric, parse.ric_len,
+		       mic) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to calculate MIC");
+		return WLAN_STATUS_UNSPECIFIED_FAILURE;
+	}
+
+	if (os_memcmp(mic, ftie->mic, 16) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid MIC in FTIE");
+		wpa_printf(MSG_DEBUG, "FT: addr=" MACSTR " auth_addr=" MACSTR,
+			   MAC2STR(sm->addr), MAC2STR(sm->wpa_auth->addr));
+		wpa_hexdump(MSG_MSGDUMP, "FT: Received MIC", ftie->mic, 16);
+		wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, 16);
+		wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
+			    parse.mdie - 2, parse.mdie_len + 2);
+		wpa_hexdump(MSG_MSGDUMP, "FT: FTIE",
+			    parse.ftie - 2, parse.ftie_len + 2);
+		wpa_hexdump(MSG_MSGDUMP, "FT: RSN",
+			    parse.rsn - 2, parse.rsn_len + 2);
+		return WLAN_STATUS_INVALID_FTIE;
+	}
+
+	return WLAN_STATUS_SUCCESS;
+}
+
+
+int wpa_ft_action_rx(struct wpa_state_machine *sm, const u8 *data, size_t len)
+{
+	const u8 *sta_addr, *target_ap;
+	const u8 *ies;
+	size_t ies_len;
+	u8 action;
+	struct ft_rrb_frame *frame;
+
+	if (sm == NULL)
+		return -1;
+
+	/*
+	 * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
+	 * FT Request action frame body[variable]
+	 */
+
+	if (len < 14) {
+		wpa_printf(MSG_DEBUG, "FT: Too short FT Action frame "
+			   "(len=%lu)", (unsigned long) len);
+		return -1;
+	}
+
+	action = data[1];
+	sta_addr = data + 2;
+	target_ap = data + 8;
+	ies = data + 14;
+	ies_len = len - 14;
+
+	wpa_printf(MSG_DEBUG, "FT: Received FT Action frame (STA=" MACSTR
+		   " Target AP=" MACSTR " Action=%d)",
+		   MAC2STR(sta_addr), MAC2STR(target_ap), action);
+
+	if (os_memcmp(sta_addr, sm->addr, ETH_ALEN) != 0) {
+		wpa_printf(MSG_DEBUG, "FT: Mismatch in FT Action STA address: "
+			   "STA=" MACSTR " STA-Address=" MACSTR,
+			   MAC2STR(sm->addr), MAC2STR(sta_addr));
+		return -1;
+	}
+
+	/*
+	 * Do some sanity checking on the target AP address (not own and not
+	 * broadcast. This could be extended to filter based on a list of known
+	 * APs in the MD (if such a list were configured).
+	 */
+	if ((target_ap[0] & 0x01) ||
+	    os_memcmp(target_ap, sm->wpa_auth->addr, ETH_ALEN) == 0) {
+		wpa_printf(MSG_DEBUG, "FT: Invalid Target AP in FT Action "
+			   "frame");
+		return -1;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "FT: Action frame body", ies, ies_len);
+
+	/* RRB - Forward action frame to the target AP */
+	frame = os_malloc(sizeof(*frame) + len);
+	frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
+	frame->packet_type = FT_PACKET_REQUEST;
+	frame->action_length = host_to_le16(len);
+	os_memcpy(frame->ap_address, sm->wpa_auth->addr, ETH_ALEN);
+	os_memcpy(frame + 1, data, len);
+
+	wpa_ft_rrb_send(sm->wpa_auth, target_ap, (u8 *) frame,
+			sizeof(*frame) + len);
+	os_free(frame);
+
+	return 0;
+}
+
+
+static int wpa_ft_rrb_rx_request(struct wpa_authenticator *wpa_auth,
+				 const u8 *current_ap, const u8 *sta_addr,
+				 const u8 *body, size_t len)
+{
+	struct wpa_state_machine *sm;
+	u16 status;
+	u8 *resp_ies, *pos;
+	size_t resp_ies_len, rlen;
+	struct ft_rrb_frame *frame;
+
+	sm = wpa_ft_add_sta(wpa_auth, sta_addr);
+	if (sm == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to add new STA based on "
+			   "RRB Request");
+		return -1;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "FT: RRB Request Frame body", body, len);
+
+	status = wpa_ft_process_auth_req(sm, body, len, &resp_ies,
+					 &resp_ies_len);
+
+	wpa_printf(MSG_DEBUG, "FT: RRB authentication response: STA=" MACSTR
+		   " CurrentAP=" MACSTR " status=%d",
+		   MAC2STR(sm->addr), MAC2STR(current_ap), status);
+	wpa_hexdump(MSG_DEBUG, "FT: Response IEs", resp_ies, resp_ies_len);
+
+	/* RRB - Forward action frame response to the Current AP */
+
+	/*
+	 * data: Category[1] Action[1] STA_Address[6] Target_AP_Address[6]
+	 * Status_Code[2] FT Request action frame body[variable]
+	 */
+	rlen = 2 + 2 * ETH_ALEN + 2 + resp_ies_len;
+
+	frame = os_malloc(sizeof(*frame) + rlen);
+	frame->frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
+	frame->packet_type = FT_PACKET_RESPONSE;
+	frame->action_length = host_to_le16(rlen);
+	os_memcpy(frame->ap_address, wpa_auth->addr, ETH_ALEN);
+	pos = (u8 *) (frame + 1);
+	*pos++ = WLAN_ACTION_FT;
+	*pos++ = 2; /* Action: Response */
+	os_memcpy(pos, sta_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+	os_memcpy(pos, wpa_auth->addr, ETH_ALEN);
+	pos += ETH_ALEN;
+	WPA_PUT_LE16(pos, status);
+	pos += 2;
+	if (resp_ies) {
+		os_memcpy(pos, resp_ies, resp_ies_len);
+		os_free(resp_ies);
+	}
+
+	wpa_ft_rrb_send(wpa_auth, current_ap, (u8 *) frame,
+			sizeof(*frame) + rlen);
+	os_free(frame);
+
+	return 0;
+}
+
+
+static int wpa_ft_rrb_rx_pull(struct wpa_authenticator *wpa_auth,
+			      const u8 *src_addr,
+			      const u8 *data, size_t data_len)
+{
+	struct ft_r0kh_r1kh_pull_frame *frame, f;
+	struct ft_remote_r1kh *r1kh;
+	struct ft_r0kh_r1kh_resp_frame resp, r;
+	u8 pmk_r0[PMK_LEN];
+	int pairwise;
+
+	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull");
+
+	if (data_len < sizeof(*frame))
+		return -1;
+
+	r1kh = wpa_auth->conf.r1kh_list;
+	while (r1kh) {
+		if (os_memcmp(r1kh->addr, src_addr, ETH_ALEN) == 0)
+			break;
+		r1kh = r1kh->next;
+	}
+	if (r1kh == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No matching R1KH address found for "
+			   "PMK-R1 pull source address " MACSTR,
+			   MAC2STR(src_addr));
+		return -1;
+	}
+
+	frame = (struct ft_r0kh_r1kh_pull_frame *) data;
+	/* aes_unwrap() does not support inplace decryption, so use a temporary
+	 * buffer for the data. */
+	if (aes_unwrap(r1kh->key, (FT_R0KH_R1KH_PULL_DATA_LEN + 7) / 8,
+		       frame->nonce, f.nonce) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
+			   "request from " MACSTR, MAC2STR(src_addr));
+		return -1;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
+		    f.nonce, sizeof(f.nonce));
+	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR0Name",
+		    f.pmk_r0_name, WPA_PMK_NAME_LEN);
+	wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID="
+		   MACSTR, MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id));
+
+	os_memset(&resp, 0, sizeof(resp));
+	resp.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
+	resp.packet_type = FT_PACKET_R0KH_R1KH_RESP;
+	resp.data_length = host_to_le16(FT_R0KH_R1KH_RESP_DATA_LEN);
+	os_memcpy(resp.ap_address, wpa_auth->addr, ETH_ALEN);
+
+	/* aes_wrap() does not support inplace encryption, so use a temporary
+	 * buffer for the data. */
+	os_memcpy(r.nonce, f.nonce, sizeof(f.nonce));
+	os_memcpy(r.r1kh_id, f.r1kh_id, FT_R1KH_ID_LEN);
+	os_memcpy(r.s1kh_id, f.s1kh_id, ETH_ALEN);
+	if (wpa_ft_fetch_pmk_r0(wpa_auth, f.s1kh_id, f.pmk_r0_name, pmk_r0,
+				&pairwise) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: No matching PMKR0Name found for "
+			   "PMK-R1 pull");
+		return -1;
+	}
+
+	wpa_derive_pmk_r1(pmk_r0, f.pmk_r0_name, f.r1kh_id, f.s1kh_id,
+			  r.pmk_r1, r.pmk_r1_name);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", r.pmk_r1, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", r.pmk_r1_name,
+		    WPA_PMK_NAME_LEN);
+	r.pairwise = host_to_le16(pairwise);
+
+	if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
+		     r.nonce, resp.nonce) < 0) {
+		os_memset(pmk_r0, 0, PMK_LEN);
+		return -1;
+	}
+
+	os_memset(pmk_r0, 0, PMK_LEN);
+
+	wpa_ft_rrb_send(wpa_auth, src_addr, (u8 *) &resp, sizeof(resp));
+
+	return 0;
+}
+
+
+static int wpa_ft_rrb_rx_resp(struct wpa_authenticator *wpa_auth,
+			      const u8 *src_addr,
+			      const u8 *data, size_t data_len)
+{
+	struct ft_r0kh_r1kh_resp_frame *frame, f;
+	struct ft_remote_r0kh *r0kh;
+	int pairwise;
+
+	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 pull response");
+
+	if (data_len < sizeof(*frame))
+		return -1;
+
+	r0kh = wpa_auth->conf.r0kh_list;
+	while (r0kh) {
+		if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
+			break;
+		r0kh = r0kh->next;
+	}
+	if (r0kh == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
+			   "PMK-R0 pull response source address " MACSTR,
+			   MAC2STR(src_addr));
+		return -1;
+	}
+
+	frame = (struct ft_r0kh_r1kh_resp_frame *) data;
+	/* aes_unwrap() does not support inplace decryption, so use a temporary
+	 * buffer for the data. */
+	if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_RESP_DATA_LEN + 7) / 8,
+		       frame->nonce, f.nonce) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 pull "
+			   "response from " MACSTR, MAC2STR(src_addr));
+		return -1;
+	}
+
+	if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
+	    != 0) {
+		wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull response did not use a "
+			   "matching R1KH-ID");
+		return -1;
+	}
+
+	/* TODO: verify that <nonce,s1kh_id> matches with a pending request
+	 * and call this requests callback function to finish request
+	 * processing */
+
+	pairwise = le_to_host16(f.pairwise);
+	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - nonce",
+		    f.nonce, sizeof(f.nonce));
+	wpa_printf(MSG_DEBUG, "FT: PMK-R1 pull - R1KH-ID=" MACSTR "S1KH-ID="
+		   MACSTR " pairwise=0x%x",
+		   MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 pull - PMK-R1",
+			f.pmk_r1, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 pull - PMKR1Name",
+			f.pmk_r1_name, WPA_PMK_NAME_LEN);
+
+	wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
+			    pairwise);
+	os_memset(f.pmk_r1, 0, PMK_LEN);
+
+	return 0;
+}
+
+
+static int wpa_ft_rrb_rx_push(struct wpa_authenticator *wpa_auth,
+			      const u8 *src_addr,
+			      const u8 *data, size_t data_len)
+{
+	struct ft_r0kh_r1kh_push_frame *frame, f;
+	struct ft_remote_r0kh *r0kh;
+	struct os_time now;
+	os_time_t tsend;
+	int pairwise;
+
+	wpa_printf(MSG_DEBUG, "FT: Received PMK-R1 push");
+
+	if (data_len < sizeof(*frame))
+		return -1;
+
+	r0kh = wpa_auth->conf.r0kh_list;
+	while (r0kh) {
+		if (os_memcmp(r0kh->addr, src_addr, ETH_ALEN) == 0)
+			break;
+		r0kh = r0kh->next;
+	}
+	if (r0kh == NULL) {
+		wpa_printf(MSG_DEBUG, "FT: No matching R0KH address found for "
+			   "PMK-R0 push source address " MACSTR,
+			   MAC2STR(src_addr));
+		return -1;
+	}
+
+	frame = (struct ft_r0kh_r1kh_push_frame *) data;
+	/* aes_unwrap() does not support inplace decryption, so use a temporary
+	 * buffer for the data. */
+	if (aes_unwrap(r0kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
+		       frame->timestamp, f.timestamp) < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Failed to decrypt PMK-R1 push from "
+			   MACSTR, MAC2STR(src_addr));
+		return -1;
+	}
+
+	os_get_time(&now);
+	tsend = WPA_GET_LE32(f.timestamp);
+	if ((now.sec > tsend && now.sec - tsend > 60) ||
+	    (now.sec < tsend && tsend - now.sec > 60)) {
+		wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not have a valid "
+			   "timestamp: sender time %d own time %d\n",
+			   (int) tsend, (int) now.sec);
+		return -1;
+	}
+
+	if (os_memcmp(f.r1kh_id, wpa_auth->conf.r1_key_holder, FT_R1KH_ID_LEN)
+	    != 0) {
+		wpa_printf(MSG_DEBUG, "FT: PMK-R1 push did not use a matching "
+			   "R1KH-ID (received " MACSTR " own " MACSTR ")",
+			   MAC2STR(f.r1kh_id),
+			   MAC2STR(wpa_auth->conf.r1_key_holder));
+		return -1;
+	}
+
+	pairwise = le_to_host16(f.pairwise);
+	wpa_printf(MSG_DEBUG, "FT: PMK-R1 push - R1KH-ID=" MACSTR " S1KH-ID="
+		   MACSTR " pairwise=0x%x",
+		   MAC2STR(f.r1kh_id), MAC2STR(f.s1kh_id), pairwise);
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1 push - PMK-R1",
+			f.pmk_r1, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMK-R1 push - PMKR1Name",
+			f.pmk_r1_name, WPA_PMK_NAME_LEN);
+
+	wpa_ft_store_pmk_r1(wpa_auth, f.s1kh_id, f.pmk_r1, f.pmk_r1_name,
+			    pairwise);
+	os_memset(f.pmk_r1, 0, PMK_LEN);
+
+	return 0;
+}
+
+
+int wpa_ft_rrb_rx(struct wpa_authenticator *wpa_auth, const u8 *src_addr,
+		  const u8 *data, size_t data_len)
+{
+	struct ft_rrb_frame *frame;
+	u16 alen;
+	const u8 *pos, *end, *start;
+	u8 action;
+	const u8 *sta_addr, *target_ap_addr;
+
+	wpa_printf(MSG_DEBUG, "FT: RRB received frame from remote AP " MACSTR,
+		   MAC2STR(src_addr));
+
+	if (data_len < sizeof(*frame)) {
+		wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (data_len=%lu)",
+			   (unsigned long) data_len);
+		return -1;
+	}
+
+	pos = data;
+	frame = (struct ft_rrb_frame *) pos;
+	pos += sizeof(*frame);
+
+	alen = le_to_host16(frame->action_length);
+	wpa_printf(MSG_DEBUG, "FT: RRB frame - frame_type=%d packet_type=%d "
+		   "action_length=%d ap_address=" MACSTR,
+		   frame->frame_type, frame->packet_type, alen,
+		   MAC2STR(frame->ap_address));
+
+	if (frame->frame_type != RSN_REMOTE_FRAME_TYPE_FT_RRB) {
+		/* Discard frame per IEEE Std 802.11r-2008, 11A.10.3 */
+		wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with "
+			   "unrecognized type %d", frame->frame_type);
+		return -1;
+	}
+
+	if (alen > data_len - sizeof(*frame)) {
+		wpa_printf(MSG_DEBUG, "FT: RRB frame too short for action "
+			   "frame");
+		return -1;
+	}
+
+	if (frame->packet_type == FT_PACKET_R0KH_R1KH_PULL)
+		return wpa_ft_rrb_rx_pull(wpa_auth, src_addr, data, data_len);
+	if (frame->packet_type == FT_PACKET_R0KH_R1KH_RESP)
+		return wpa_ft_rrb_rx_resp(wpa_auth, src_addr, data, data_len);
+	if (frame->packet_type == FT_PACKET_R0KH_R1KH_PUSH)
+		return wpa_ft_rrb_rx_push(wpa_auth, src_addr, data, data_len);
+
+	wpa_hexdump(MSG_MSGDUMP, "FT: RRB - FT Action frame", pos, alen);
+
+	if (alen < 1 + 1 + 2 * ETH_ALEN) {
+		wpa_printf(MSG_DEBUG, "FT: Too short RRB frame (not enough "
+			   "room for Action Frame body); alen=%lu",
+			   (unsigned long) alen);
+		return -1;
+	}
+	start = pos;
+	end = pos + alen;
+
+	if (*pos != WLAN_ACTION_FT) {
+		wpa_printf(MSG_DEBUG, "FT: Unexpected Action frame category "
+			   "%d", *pos);
+		return -1;
+	}
+
+	pos++;
+	action = *pos++;
+	sta_addr = pos;
+	pos += ETH_ALEN;
+	target_ap_addr = pos;
+	pos += ETH_ALEN;
+	wpa_printf(MSG_DEBUG, "FT: RRB Action Frame: action=%d sta_addr="
+		   MACSTR " target_ap_addr=" MACSTR,
+		   action, MAC2STR(sta_addr), MAC2STR(target_ap_addr));
+
+	if (frame->packet_type == FT_PACKET_REQUEST) {
+		wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Request");
+
+		if (action != 1) {
+			wpa_printf(MSG_DEBUG, "FT: Unexpected Action %d in "
+				   "RRB Request", action);
+			return -1;
+		}
+
+		if (os_memcmp(target_ap_addr, wpa_auth->addr, ETH_ALEN) != 0) {
+			wpa_printf(MSG_DEBUG, "FT: Target AP address in the "
+				   "RRB Request does not match with own "
+				   "address");
+			return -1;
+		}
+
+		if (wpa_ft_rrb_rx_request(wpa_auth, frame->ap_address,
+					  sta_addr, pos, end - pos) < 0)
+			return -1;
+	} else if (frame->packet_type == FT_PACKET_RESPONSE) {
+		u16 status_code;
+
+		if (end - pos < 2) {
+			wpa_printf(MSG_DEBUG, "FT: Not enough room for status "
+				   "code in RRB Response");
+			return -1;
+		}
+		status_code = WPA_GET_LE16(pos);
+		pos += 2;
+
+		wpa_printf(MSG_DEBUG, "FT: FT Packet Type - Response "
+			   "(status_code=%d)", status_code);
+
+		if (wpa_ft_action_send(wpa_auth, sta_addr, start, alen) < 0)
+			return -1;
+	} else {
+		wpa_printf(MSG_DEBUG, "FT: RRB discarded frame with unknown "
+			   "packet_type %d", frame->packet_type);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static void wpa_ft_generate_pmk_r1(struct wpa_authenticator *wpa_auth,
+				   struct wpa_ft_pmk_r0_sa *pmk_r0,
+				   struct ft_remote_r1kh *r1kh,
+				   const u8 *s1kh_id, int pairwise)
+{
+	struct ft_r0kh_r1kh_push_frame frame, f;
+	struct os_time now;
+
+	os_memset(&frame, 0, sizeof(frame));
+	frame.frame_type = RSN_REMOTE_FRAME_TYPE_FT_RRB;
+	frame.packet_type = FT_PACKET_R0KH_R1KH_PUSH;
+	frame.data_length = host_to_le16(FT_R0KH_R1KH_PUSH_DATA_LEN);
+	os_memcpy(frame.ap_address, wpa_auth->addr, ETH_ALEN);
+
+	/* aes_wrap() does not support inplace encryption, so use a temporary
+	 * buffer for the data. */
+	os_memcpy(f.r1kh_id, r1kh->id, FT_R1KH_ID_LEN);
+	os_memcpy(f.s1kh_id, s1kh_id, ETH_ALEN);
+	os_memcpy(f.pmk_r0_name, pmk_r0->pmk_r0_name, WPA_PMK_NAME_LEN);
+	wpa_derive_pmk_r1(pmk_r0->pmk_r0, pmk_r0->pmk_r0_name, r1kh->id,
+			  s1kh_id, f.pmk_r1, f.pmk_r1_name);
+	wpa_printf(MSG_DEBUG, "FT: R1KH-ID " MACSTR, MAC2STR(r1kh->id));
+	wpa_hexdump_key(MSG_DEBUG, "FT: PMK-R1", f.pmk_r1, PMK_LEN);
+	wpa_hexdump(MSG_DEBUG, "FT: PMKR1Name", f.pmk_r1_name,
+		    WPA_PMK_NAME_LEN);
+	os_get_time(&now);
+	WPA_PUT_LE32(f.timestamp, now.sec);
+	f.pairwise = host_to_le16(pairwise);
+	if (aes_wrap(r1kh->key, (FT_R0KH_R1KH_PUSH_DATA_LEN + 7) / 8,
+		     f.timestamp, frame.timestamp) < 0)
+		return;
+
+	wpa_ft_rrb_send(wpa_auth, r1kh->addr, (u8 *) &frame, sizeof(frame));
+}
+
+
+void wpa_ft_push_pmk_r1(struct wpa_authenticator *wpa_auth, const u8 *addr)
+{
+	struct wpa_ft_pmk_r0_sa *r0;
+	struct ft_remote_r1kh *r1kh;
+
+	if (!wpa_auth->conf.pmk_r1_push)
+		return;
+
+	r0 = wpa_auth->ft_pmk_cache->pmk_r0;
+	while (r0) {
+		if (os_memcmp(r0->spa, addr, ETH_ALEN) == 0)
+			break;
+		r0 = r0->next;
+	}
+
+	if (r0 == NULL || r0->pmk_r1_pushed)
+		return;
+	r0->pmk_r1_pushed = 1;
+
+	wpa_printf(MSG_DEBUG, "FT: Deriving and pushing PMK-R1 keys to R1KHs "
+		   "for STA " MACSTR, MAC2STR(addr));
+
+	r1kh = wpa_auth->conf.r1kh_list;
+	while (r1kh) {
+		wpa_ft_generate_pmk_r1(wpa_auth, r0, r1kh, addr, r0->pairwise);
+		r1kh = r1kh->next;
+	}
+}
+
+#endif /* CONFIG_IEEE80211R */
diff --git a/hostap/src/ap/wpa_auth_glue.c b/hostap/src/ap/wpa_auth_glue.c
new file mode 100644
index 0000000..76c61ea
--- /dev/null
+++ b/hostap/src/ap/wpa_auth_glue.c
@@ -0,0 +1,605 @@
+/*
+ * hostapd / WPA authenticator glue code
+ * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
+#include "eap_server/eap.h"
+#include "l2_packet/l2_packet.h"
+#include "drivers/driver.h"
+#include "hostapd.h"
+#include "ieee802_1x.h"
+#include "preauth_auth.h"
+#include "sta_info.h"
+#include "tkip_countermeasures.h"
+#include "ap_drv_ops.h"
+#include "ap_config.h"
+#include "wpa_auth.h"
+#include "wpa_auth_glue.h"
+
+
+static void hostapd_wpa_auth_conf(struct hostapd_bss_config *conf,
+				  struct wpa_auth_config *wconf)
+{
+	os_memset(wconf, 0, sizeof(*wconf));
+	wconf->wpa = conf->wpa;
+	wconf->wpa_key_mgmt = conf->wpa_key_mgmt;
+	wconf->wpa_pairwise = conf->wpa_pairwise;
+	wconf->wpa_group = conf->wpa_group;
+	wconf->wpa_group_rekey = conf->wpa_group_rekey;
+	wconf->wpa_strict_rekey = conf->wpa_strict_rekey;
+	wconf->wpa_gmk_rekey = conf->wpa_gmk_rekey;
+	wconf->wpa_ptk_rekey = conf->wpa_ptk_rekey;
+	wconf->rsn_pairwise = conf->rsn_pairwise;
+	wconf->rsn_preauth = conf->rsn_preauth;
+	wconf->eapol_version = conf->eapol_version;
+	wconf->peerkey = conf->peerkey;
+	wconf->wmm_enabled = conf->wmm_enabled;
+	wconf->wmm_uapsd = conf->wmm_uapsd;
+	wconf->disable_pmksa_caching = conf->disable_pmksa_caching;
+	wconf->okc = conf->okc;
+#ifdef CONFIG_IEEE80211W
+	wconf->ieee80211w = conf->ieee80211w;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211R
+	wconf->ssid_len = conf->ssid.ssid_len;
+	if (wconf->ssid_len > SSID_LEN)
+		wconf->ssid_len = SSID_LEN;
+	os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len);
+	os_memcpy(wconf->mobility_domain, conf->mobility_domain,
+		  MOBILITY_DOMAIN_ID_LEN);
+	if (conf->nas_identifier &&
+	    os_strlen(conf->nas_identifier) <= FT_R0KH_ID_MAX_LEN) {
+		wconf->r0_key_holder_len = os_strlen(conf->nas_identifier);
+		os_memcpy(wconf->r0_key_holder, conf->nas_identifier,
+			  wconf->r0_key_holder_len);
+	}
+	os_memcpy(wconf->r1_key_holder, conf->r1_key_holder, FT_R1KH_ID_LEN);
+	wconf->r0_key_lifetime = conf->r0_key_lifetime;
+	wconf->reassociation_deadline = conf->reassociation_deadline;
+	wconf->r0kh_list = conf->r0kh_list;
+	wconf->r1kh_list = conf->r1kh_list;
+	wconf->pmk_r1_push = conf->pmk_r1_push;
+	wconf->ft_over_ds = conf->ft_over_ds;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_HS20
+	wconf->disable_gtk = conf->disable_dgaf;
+#endif /* CONFIG_HS20 */
+}
+
+
+static void hostapd_wpa_auth_logger(void *ctx, const u8 *addr,
+				    logger_level level, const char *txt)
+{
+#ifndef CONFIG_NO_HOSTAPD_LOGGER
+	struct hostapd_data *hapd = ctx;
+	int hlevel;
+
+	switch (level) {
+	case LOGGER_WARNING:
+		hlevel = HOSTAPD_LEVEL_WARNING;
+		break;
+	case LOGGER_INFO:
+		hlevel = HOSTAPD_LEVEL_INFO;
+		break;
+	case LOGGER_DEBUG:
+	default:
+		hlevel = HOSTAPD_LEVEL_DEBUG;
+		break;
+	}
+
+	hostapd_logger(hapd, addr, HOSTAPD_MODULE_WPA, hlevel, "%s", txt);
+#endif /* CONFIG_NO_HOSTAPD_LOGGER */
+}
+
+
+static void hostapd_wpa_auth_disconnect(void *ctx, const u8 *addr,
+					u16 reason)
+{
+	struct hostapd_data *hapd = ctx;
+	wpa_printf(MSG_DEBUG, "%s: WPA authenticator requests disconnect: "
+		   "STA " MACSTR " reason %d",
+		   __func__, MAC2STR(addr), reason);
+	ap_sta_disconnect(hapd, NULL, addr, reason);
+}
+
+
+static int hostapd_wpa_auth_mic_failure_report(void *ctx, const u8 *addr)
+{
+	struct hostapd_data *hapd = ctx;
+	return michael_mic_failure(hapd, addr, 0);
+}
+
+
+static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr,
+				       wpa_eapol_variable var, int value)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+	if (sta == NULL)
+		return;
+	switch (var) {
+	case WPA_EAPOL_portEnabled:
+		ieee802_1x_notify_port_enabled(sta->eapol_sm, value);
+		break;
+	case WPA_EAPOL_portValid:
+		ieee802_1x_notify_port_valid(sta->eapol_sm, value);
+		break;
+	case WPA_EAPOL_authorized:
+		ieee802_1x_set_sta_authorized(hapd, sta, value);
+		break;
+	case WPA_EAPOL_portControl_Auto:
+		if (sta->eapol_sm)
+			sta->eapol_sm->portControl = Auto;
+		break;
+	case WPA_EAPOL_keyRun:
+		if (sta->eapol_sm)
+			sta->eapol_sm->keyRun = value ? TRUE : FALSE;
+		break;
+	case WPA_EAPOL_keyAvailable:
+		if (sta->eapol_sm)
+			sta->eapol_sm->eap_if->eapKeyAvailable =
+				value ? TRUE : FALSE;
+		break;
+	case WPA_EAPOL_keyDone:
+		if (sta->eapol_sm)
+			sta->eapol_sm->keyDone = value ? TRUE : FALSE;
+		break;
+	case WPA_EAPOL_inc_EapolFramesTx:
+		if (sta->eapol_sm)
+			sta->eapol_sm->dot1xAuthEapolFramesTx++;
+		break;
+	}
+}
+
+
+static int hostapd_wpa_auth_get_eapol(void *ctx, const u8 *addr,
+				      wpa_eapol_variable var)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+	if (sta == NULL || sta->eapol_sm == NULL)
+		return -1;
+	switch (var) {
+	case WPA_EAPOL_keyRun:
+		return sta->eapol_sm->keyRun;
+	case WPA_EAPOL_keyAvailable:
+		return sta->eapol_sm->eap_if->eapKeyAvailable;
+	default:
+		return -1;
+	}
+}
+
+
+static const u8 * hostapd_wpa_auth_get_psk(void *ctx, const u8 *addr,
+					   const u8 *prev_psk)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta = ap_get_sta(hapd, addr);
+	const u8 *psk = hostapd_get_psk(hapd->conf, addr, prev_psk);
+	/*
+	 * This is about to iterate over all psks, prev_psk gives the last
+	 * returned psk which should not be returned again.
+	 * logic list (all hostapd_get_psk; all sta->psk)
+	 */
+	if (sta && sta->psk && !psk) {
+		struct hostapd_sta_wpa_psk_short *pos;
+		psk = sta->psk->psk;
+		for (pos = sta->psk; pos; pos = pos->next) {
+			if (pos->psk == prev_psk) {
+				psk = pos->next ? pos->next->psk : NULL;
+				break;
+			}
+		}
+	}
+	return psk;
+}
+
+
+static int hostapd_wpa_auth_get_msk(void *ctx, const u8 *addr, u8 *msk,
+				    size_t *len)
+{
+	struct hostapd_data *hapd = ctx;
+	const u8 *key;
+	size_t keylen;
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta == NULL)
+		return -1;
+
+	key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
+	if (key == NULL)
+		return -1;
+
+	if (keylen > *len)
+		keylen = *len;
+	os_memcpy(msk, key, keylen);
+	*len = keylen;
+
+	return 0;
+}
+
+
+static int hostapd_wpa_auth_set_key(void *ctx, int vlan_id, enum wpa_alg alg,
+				    const u8 *addr, int idx, u8 *key,
+				    size_t key_len)
+{
+	struct hostapd_data *hapd = ctx;
+	const char *ifname = hapd->conf->iface;
+
+	if (vlan_id > 0) {
+		ifname = hostapd_get_vlan_id_ifname(hapd->conf->vlan, vlan_id);
+		if (ifname == NULL)
+			return -1;
+	}
+
+	return hostapd_drv_set_key(ifname, hapd, alg, addr, idx, 1, NULL, 0,
+				   key, key_len);
+}
+
+
+static int hostapd_wpa_auth_get_seqnum(void *ctx, const u8 *addr, int idx,
+				       u8 *seq)
+{
+	struct hostapd_data *hapd = ctx;
+	return hostapd_get_seqnum(hapd->conf->iface, hapd, addr, idx, seq);
+}
+
+
+static int hostapd_wpa_auth_send_eapol(void *ctx, const u8 *addr,
+				       const u8 *data, size_t data_len,
+				       int encrypt)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+	u32 flags = 0;
+
+	sta = ap_get_sta(hapd, addr);
+	if (sta)
+		flags = hostapd_sta_flags_to_drv(sta->flags);
+
+	return hostapd_drv_hapd_send_eapol(hapd, addr, data, data_len,
+					   encrypt, flags);
+}
+
+
+static int hostapd_wpa_auth_for_each_sta(
+	void *ctx, int (*cb)(struct wpa_state_machine *sm, void *ctx),
+	void *cb_ctx)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	for (sta = hapd->sta_list; sta; sta = sta->next) {
+		if (sta->wpa_sm && cb(sta->wpa_sm, cb_ctx))
+			return 1;
+	}
+	return 0;
+}
+
+
+struct wpa_auth_iface_iter_data {
+	int (*cb)(struct wpa_authenticator *sm, void *ctx);
+	void *cb_ctx;
+};
+
+static int wpa_auth_iface_iter(struct hostapd_iface *iface, void *ctx)
+{
+	struct wpa_auth_iface_iter_data *data = ctx;
+	size_t i;
+	for (i = 0; i < iface->num_bss; i++) {
+		if (iface->bss[i]->wpa_auth &&
+		    data->cb(iface->bss[i]->wpa_auth, data->cb_ctx))
+			return 1;
+	}
+	return 0;
+}
+
+
+static int hostapd_wpa_auth_for_each_auth(
+	void *ctx, int (*cb)(struct wpa_authenticator *sm, void *ctx),
+	void *cb_ctx)
+{
+	struct hostapd_data *hapd = ctx;
+	struct wpa_auth_iface_iter_data data;
+	if (hapd->iface->interfaces == NULL ||
+	    hapd->iface->interfaces->for_each_interface == NULL)
+		return -1;
+	data.cb = cb;
+	data.cb_ctx = cb_ctx;
+	return hapd->iface->interfaces->for_each_interface(
+		hapd->iface->interfaces, wpa_auth_iface_iter, &data);
+}
+
+
+#ifdef CONFIG_IEEE80211R
+
+struct wpa_auth_ft_iface_iter_data {
+	struct hostapd_data *src_hapd;
+	const u8 *dst;
+	const u8 *data;
+	size_t data_len;
+};
+
+
+static int hostapd_wpa_auth_ft_iter(struct hostapd_iface *iface, void *ctx)
+{
+	struct wpa_auth_ft_iface_iter_data *idata = ctx;
+	struct hostapd_data *hapd;
+	size_t j;
+
+	for (j = 0; j < iface->num_bss; j++) {
+		hapd = iface->bss[j];
+		if (hapd == idata->src_hapd)
+			continue;
+		if (os_memcmp(hapd->own_addr, idata->dst, ETH_ALEN) == 0) {
+			wpa_printf(MSG_DEBUG, "FT: Send RRB data directly to "
+				   "locally managed BSS " MACSTR "@%s -> "
+				   MACSTR "@%s",
+				   MAC2STR(idata->src_hapd->own_addr),
+				   idata->src_hapd->conf->iface,
+				   MAC2STR(hapd->own_addr), hapd->conf->iface);
+			wpa_ft_rrb_rx(hapd->wpa_auth,
+				      idata->src_hapd->own_addr,
+				      idata->data, idata->data_len);
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+#endif /* CONFIG_IEEE80211R */
+
+
+static int hostapd_wpa_auth_send_ether(void *ctx, const u8 *dst, u16 proto,
+				       const u8 *data, size_t data_len)
+{
+	struct hostapd_data *hapd = ctx;
+	struct l2_ethhdr *buf;
+	int ret;
+
+#ifdef CONFIG_IEEE80211R
+	if (proto == ETH_P_RRB && hapd->iface->interfaces &&
+	    hapd->iface->interfaces->for_each_interface) {
+		int res;
+		struct wpa_auth_ft_iface_iter_data idata;
+		idata.src_hapd = hapd;
+		idata.dst = dst;
+		idata.data = data;
+		idata.data_len = data_len;
+		res = hapd->iface->interfaces->for_each_interface(
+			hapd->iface->interfaces, hostapd_wpa_auth_ft_iter,
+			&idata);
+		if (res == 1)
+			return data_len;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	if (hapd->driver && hapd->driver->send_ether)
+		return hapd->driver->send_ether(hapd->drv_priv, dst,
+						hapd->own_addr, proto,
+						data, data_len);
+	if (hapd->l2 == NULL)
+		return -1;
+
+	buf = os_malloc(sizeof(*buf) + data_len);
+	if (buf == NULL)
+		return -1;
+	os_memcpy(buf->h_dest, dst, ETH_ALEN);
+	os_memcpy(buf->h_source, hapd->own_addr, ETH_ALEN);
+	buf->h_proto = host_to_be16(proto);
+	os_memcpy(buf + 1, data, data_len);
+	ret = l2_packet_send(hapd->l2, dst, proto, (u8 *) buf,
+			     sizeof(*buf) + data_len);
+	os_free(buf);
+	return ret;
+}
+
+
+#ifdef CONFIG_IEEE80211R
+
+static int hostapd_wpa_auth_send_ft_action(void *ctx, const u8 *dst,
+					   const u8 *data, size_t data_len)
+{
+	struct hostapd_data *hapd = ctx;
+	int res;
+	struct ieee80211_mgmt *m;
+	size_t mlen;
+	struct sta_info *sta;
+
+	sta = ap_get_sta(hapd, dst);
+	if (sta == NULL || sta->wpa_sm == NULL)
+		return -1;
+
+	m = os_zalloc(sizeof(*m) + data_len);
+	if (m == NULL)
+		return -1;
+	mlen = ((u8 *) &m->u - (u8 *) m) + data_len;
+	m->frame_control = IEEE80211_FC(WLAN_FC_TYPE_MGMT,
+					WLAN_FC_STYPE_ACTION);
+	os_memcpy(m->da, dst, ETH_ALEN);
+	os_memcpy(m->sa, hapd->own_addr, ETH_ALEN);
+	os_memcpy(m->bssid, hapd->own_addr, ETH_ALEN);
+	os_memcpy(&m->u, data, data_len);
+
+	res = hostapd_drv_send_mlme(hapd, (u8 *) m, mlen, 0);
+	os_free(m);
+	return res;
+}
+
+
+static struct wpa_state_machine *
+hostapd_wpa_auth_add_sta(void *ctx, const u8 *sta_addr)
+{
+	struct hostapd_data *hapd = ctx;
+	struct sta_info *sta;
+
+	if (hostapd_add_sta_node(hapd, sta_addr, WLAN_AUTH_FT) < 0)
+		return NULL;
+
+	sta = ap_sta_add(hapd, sta_addr);
+	if (sta == NULL)
+		return NULL;
+	if (sta->wpa_sm) {
+		sta->auth_alg = WLAN_AUTH_FT;
+		return sta->wpa_sm;
+	}
+
+	sta->wpa_sm = wpa_auth_sta_init(hapd->wpa_auth, sta->addr);
+	if (sta->wpa_sm == NULL) {
+		ap_free_sta(hapd, sta);
+		return NULL;
+	}
+	sta->auth_alg = WLAN_AUTH_FT;
+
+	return sta->wpa_sm;
+}
+
+
+static void hostapd_rrb_receive(void *ctx, const u8 *src_addr, const u8 *buf,
+				size_t len)
+{
+	struct hostapd_data *hapd = ctx;
+	struct l2_ethhdr *ethhdr;
+	if (len < sizeof(*ethhdr))
+		return;
+	ethhdr = (struct l2_ethhdr *) buf;
+	wpa_printf(MSG_DEBUG, "FT: RRB received packet " MACSTR " -> "
+		   MACSTR, MAC2STR(ethhdr->h_source), MAC2STR(ethhdr->h_dest));
+	wpa_ft_rrb_rx(hapd->wpa_auth, ethhdr->h_source, buf + sizeof(*ethhdr),
+		      len - sizeof(*ethhdr));
+}
+
+
+static int hostapd_wpa_auth_add_tspec(void *ctx, const u8 *sta_addr,
+				      u8 *tspec_ie, size_t tspec_ielen)
+{
+	struct hostapd_data *hapd = ctx;
+	return hostapd_add_tspec(hapd, sta_addr, tspec_ie, tspec_ielen);
+}
+
+#endif /* CONFIG_IEEE80211R */
+
+
+int hostapd_setup_wpa(struct hostapd_data *hapd)
+{
+	struct wpa_auth_config _conf;
+	struct wpa_auth_callbacks cb;
+	const u8 *wpa_ie;
+	size_t wpa_ie_len;
+
+	hostapd_wpa_auth_conf(hapd->conf, &_conf);
+	if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_EAPOL_TX_STATUS)
+		_conf.tx_status = 1;
+	if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_AP_MLME)
+		_conf.ap_mlme = 1;
+	os_memset(&cb, 0, sizeof(cb));
+	cb.ctx = hapd;
+	cb.logger = hostapd_wpa_auth_logger;
+	cb.disconnect = hostapd_wpa_auth_disconnect;
+	cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report;
+	cb.set_eapol = hostapd_wpa_auth_set_eapol;
+	cb.get_eapol = hostapd_wpa_auth_get_eapol;
+	cb.get_psk = hostapd_wpa_auth_get_psk;
+	cb.get_msk = hostapd_wpa_auth_get_msk;
+	cb.set_key = hostapd_wpa_auth_set_key;
+	cb.get_seqnum = hostapd_wpa_auth_get_seqnum;
+	cb.send_eapol = hostapd_wpa_auth_send_eapol;
+	cb.for_each_sta = hostapd_wpa_auth_for_each_sta;
+	cb.for_each_auth = hostapd_wpa_auth_for_each_auth;
+	cb.send_ether = hostapd_wpa_auth_send_ether;
+#ifdef CONFIG_IEEE80211R
+	cb.send_ft_action = hostapd_wpa_auth_send_ft_action;
+	cb.add_sta = hostapd_wpa_auth_add_sta;
+	cb.add_tspec = hostapd_wpa_auth_add_tspec;
+#endif /* CONFIG_IEEE80211R */
+	hapd->wpa_auth = wpa_init(hapd->own_addr, &_conf, &cb);
+	if (hapd->wpa_auth == NULL) {
+		wpa_printf(MSG_ERROR, "WPA initialization failed.");
+		return -1;
+	}
+
+	if (hostapd_set_privacy(hapd, 1)) {
+		wpa_printf(MSG_ERROR, "Could not set PrivacyInvoked "
+			   "for interface %s", hapd->conf->iface);
+		return -1;
+	}
+
+	wpa_ie = wpa_auth_get_wpa_ie(hapd->wpa_auth, &wpa_ie_len);
+	if (hostapd_set_generic_elem(hapd, wpa_ie, wpa_ie_len)) {
+		wpa_printf(MSG_ERROR, "Failed to configure WPA IE for "
+			   "the kernel driver.");
+		return -1;
+	}
+
+	if (rsn_preauth_iface_init(hapd)) {
+		wpa_printf(MSG_ERROR, "Initialization of RSN "
+			   "pre-authentication failed.");
+		return -1;
+	}
+
+#ifdef CONFIG_IEEE80211R
+	if (!hostapd_drv_none(hapd)) {
+		hapd->l2 = l2_packet_init(hapd->conf->bridge[0] ?
+					  hapd->conf->bridge :
+					  hapd->conf->iface, NULL, ETH_P_RRB,
+					  hostapd_rrb_receive, hapd, 1);
+		if (hapd->l2 == NULL &&
+		    (hapd->driver == NULL ||
+		     hapd->driver->send_ether == NULL)) {
+			wpa_printf(MSG_ERROR, "Failed to open l2_packet "
+				   "interface");
+			return -1;
+		}
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	return 0;
+
+}
+
+
+void hostapd_reconfig_wpa(struct hostapd_data *hapd)
+{
+	struct wpa_auth_config wpa_auth_conf;
+	hostapd_wpa_auth_conf(hapd->conf, &wpa_auth_conf);
+	wpa_reconfig(hapd->wpa_auth, &wpa_auth_conf);
+}
+
+
+void hostapd_deinit_wpa(struct hostapd_data *hapd)
+{
+	ieee80211_tkip_countermeasures_deinit(hapd);
+	rsn_preauth_iface_deinit(hapd);
+	if (hapd->wpa_auth) {
+		wpa_deinit(hapd->wpa_auth);
+		hapd->wpa_auth = NULL;
+
+		if (hostapd_set_privacy(hapd, 0)) {
+			wpa_printf(MSG_DEBUG, "Could not disable "
+				   "PrivacyInvoked for interface %s",
+				   hapd->conf->iface);
+		}
+
+		if (hostapd_set_generic_elem(hapd, (u8 *) "", 0)) {
+			wpa_printf(MSG_DEBUG, "Could not remove generic "
+				   "information element from interface %s",
+				   hapd->conf->iface);
+		}
+	}
+	ieee802_1x_deinit(hapd);
+
+#ifdef CONFIG_IEEE80211R
+	l2_packet_deinit(hapd->l2);
+#endif /* CONFIG_IEEE80211R */
+}
diff --git a/hostap/src/ap/wpa_auth_glue.h b/hostap/src/ap/wpa_auth_glue.h
new file mode 100644
index 0000000..1b13ae7
--- /dev/null
+++ b/hostap/src/ap/wpa_auth_glue.h
@@ -0,0 +1,16 @@
+/*
+ * hostapd / WPA authenticator glue code
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_AUTH_GLUE_H
+#define WPA_AUTH_GLUE_H
+
+int hostapd_setup_wpa(struct hostapd_data *hapd);
+void hostapd_reconfig_wpa(struct hostapd_data *hapd);
+void hostapd_deinit_wpa(struct hostapd_data *hapd);
+
+#endif /* WPA_AUTH_GLUE_H */
diff --git a/hostap/src/ap/wpa_auth_i.h b/hostap/src/ap/wpa_auth_i.h
new file mode 100644
index 0000000..97489d3
--- /dev/null
+++ b/hostap/src/ap/wpa_auth_i.h
@@ -0,0 +1,232 @@
+/*
+ * hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_AUTH_I_H
+#define WPA_AUTH_I_H
+
+/* max(dot11RSNAConfigGroupUpdateCount,dot11RSNAConfigPairwiseUpdateCount) */
+#define RSNA_MAX_EAPOL_RETRIES 4
+
+struct wpa_group;
+
+struct wpa_stsl_negotiation {
+	struct wpa_stsl_negotiation *next;
+	u8 initiator[ETH_ALEN];
+	u8 peer[ETH_ALEN];
+};
+
+
+struct wpa_state_machine {
+	struct wpa_authenticator *wpa_auth;
+	struct wpa_group *group;
+
+	u8 addr[ETH_ALEN];
+
+	enum {
+		WPA_PTK_INITIALIZE, WPA_PTK_DISCONNECT, WPA_PTK_DISCONNECTED,
+		WPA_PTK_AUTHENTICATION, WPA_PTK_AUTHENTICATION2,
+		WPA_PTK_INITPMK, WPA_PTK_INITPSK, WPA_PTK_PTKSTART,
+		WPA_PTK_PTKCALCNEGOTIATING, WPA_PTK_PTKCALCNEGOTIATING2,
+		WPA_PTK_PTKINITNEGOTIATING, WPA_PTK_PTKINITDONE
+	} wpa_ptk_state;
+
+	enum {
+		WPA_PTK_GROUP_IDLE = 0,
+		WPA_PTK_GROUP_REKEYNEGOTIATING,
+		WPA_PTK_GROUP_REKEYESTABLISHED,
+		WPA_PTK_GROUP_KEYERROR
+	} wpa_ptk_group_state;
+
+	Boolean Init;
+	Boolean DeauthenticationRequest;
+	Boolean AuthenticationRequest;
+	Boolean ReAuthenticationRequest;
+	Boolean Disconnect;
+	int TimeoutCtr;
+	int GTimeoutCtr;
+	Boolean TimeoutEvt;
+	Boolean EAPOLKeyReceived;
+	Boolean EAPOLKeyPairwise;
+	Boolean EAPOLKeyRequest;
+	Boolean MICVerified;
+	Boolean GUpdateStationKeys;
+	u8 ANonce[WPA_NONCE_LEN];
+	u8 SNonce[WPA_NONCE_LEN];
+	u8 PMK[PMK_LEN];
+	struct wpa_ptk PTK;
+	Boolean PTK_valid;
+	Boolean pairwise_set;
+	int keycount;
+	Boolean Pair;
+	struct wpa_key_replay_counter {
+		u8 counter[WPA_REPLAY_COUNTER_LEN];
+		Boolean valid;
+	} key_replay[RSNA_MAX_EAPOL_RETRIES],
+		prev_key_replay[RSNA_MAX_EAPOL_RETRIES];
+	Boolean PInitAKeys; /* WPA only, not in IEEE 802.11i */
+	Boolean PTKRequest; /* not in IEEE 802.11i state machine */
+	Boolean has_GTK;
+	Boolean PtkGroupInit; /* init request for PTK Group state machine */
+
+	u8 *last_rx_eapol_key; /* starting from IEEE 802.1X header */
+	size_t last_rx_eapol_key_len;
+
+	unsigned int changed:1;
+	unsigned int in_step_loop:1;
+	unsigned int pending_deinit:1;
+	unsigned int started:1;
+	unsigned int mgmt_frame_prot:1;
+	unsigned int rx_eapol_key_secure:1;
+	unsigned int update_snonce:1;
+#ifdef CONFIG_IEEE80211R
+	unsigned int ft_completed:1;
+	unsigned int pmk_r1_name_valid:1;
+#endif /* CONFIG_IEEE80211R */
+	unsigned int is_wnmsleep:1;
+
+	u8 req_replay_counter[WPA_REPLAY_COUNTER_LEN];
+	int req_replay_counter_used;
+
+	u8 *wpa_ie;
+	size_t wpa_ie_len;
+
+	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 pairwise; /* Pairwise cipher suite, WPA_CIPHER_* */
+	int wpa_key_mgmt; /* the selected WPA_KEY_MGMT_* */
+	struct rsn_pmksa_cache_entry *pmksa;
+
+	u32 dot11RSNAStatsTKIPLocalMICFailures;
+	u32 dot11RSNAStatsTKIPRemoteMICFailures;
+
+#ifdef CONFIG_IEEE80211R
+	u8 xxkey[PMK_LEN]; /* PSK or the second 256 bits of MSK */
+	size_t xxkey_len;
+	u8 pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name derived from FT Auth
+					   * Request */
+	u8 r0kh_id[FT_R0KH_ID_MAX_LEN]; /* R0KH-ID from FT Auth Request */
+	size_t r0kh_id_len;
+	u8 sup_pmk_r1_name[WPA_PMK_NAME_LEN]; /* PMKR1Name from EAPOL-Key
+					       * message 2/4 */
+	u8 *assoc_resp_ftie;
+#endif /* CONFIG_IEEE80211R */
+
+	int pending_1_of_4_timeout;
+};
+
+
+/* per group key state machine data */
+struct wpa_group {
+	struct wpa_group *next;
+	int vlan_id;
+
+	Boolean GInit;
+	int GKeyDoneStations;
+	Boolean GTKReKey;
+	int GTK_len;
+	int GN, GM;
+	Boolean GTKAuthenticator;
+	u8 Counter[WPA_NONCE_LEN];
+
+	enum {
+		WPA_GROUP_GTK_INIT = 0,
+		WPA_GROUP_SETKEYS, WPA_GROUP_SETKEYSDONE
+	} wpa_group_state;
+
+	u8 GMK[WPA_GMK_LEN];
+	u8 GTK[2][WPA_GTK_MAX_LEN];
+	u8 GNonce[WPA_NONCE_LEN];
+	Boolean changed;
+	Boolean first_sta_seen;
+	Boolean reject_4way_hs_for_entropy;
+#ifdef CONFIG_IEEE80211W
+	u8 IGTK[2][WPA_IGTK_LEN];
+	int GN_igtk, GM_igtk;
+#endif /* CONFIG_IEEE80211W */
+};
+
+
+struct wpa_ft_pmk_cache;
+
+/* per authenticator data */
+struct wpa_authenticator {
+	struct wpa_group *group;
+
+	unsigned int dot11RSNAStatsTKIPRemoteMICFailures;
+	u32 dot11RSNAAuthenticationSuiteSelected;
+	u32 dot11RSNAPairwiseCipherSelected;
+	u32 dot11RSNAGroupCipherSelected;
+	u8 dot11RSNAPMKIDUsed[PMKID_LEN];
+	u32 dot11RSNAAuthenticationSuiteRequested; /* FIX: update */
+	u32 dot11RSNAPairwiseCipherRequested; /* FIX: update */
+	u32 dot11RSNAGroupCipherRequested; /* FIX: update */
+	unsigned int dot11RSNATKIPCounterMeasuresInvoked;
+	unsigned int dot11RSNA4WayHandshakeFailures;
+
+	struct wpa_stsl_negotiation *stsl_negotiations;
+
+	struct wpa_auth_config conf;
+	struct wpa_auth_callbacks cb;
+
+	u8 *wpa_ie;
+	size_t wpa_ie_len;
+
+	u8 addr[ETH_ALEN];
+
+	struct rsn_pmksa_cache *pmksa;
+	struct wpa_ft_pmk_cache *ft_pmk_cache;
+};
+
+
+int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
+		     const u8 *pmkid);
+void wpa_auth_logger(struct wpa_authenticator *wpa_auth, const u8 *addr,
+		     logger_level level, const char *txt);
+void wpa_auth_vlogger(struct wpa_authenticator *wpa_auth, const u8 *addr,
+		      logger_level level, const char *fmt, ...);
+void __wpa_send_eapol(struct wpa_authenticator *wpa_auth,
+		      struct wpa_state_machine *sm, int key_info,
+		      const u8 *key_rsc, const u8 *nonce,
+		      const u8 *kde, size_t kde_len,
+		      int keyidx, int encr, int force_version);
+int wpa_auth_for_each_sta(struct wpa_authenticator *wpa_auth,
+			  int (*cb)(struct wpa_state_machine *sm, void *ctx),
+			  void *cb_ctx);
+int wpa_auth_for_each_auth(struct wpa_authenticator *wpa_auth,
+			   int (*cb)(struct wpa_authenticator *a, void *ctx),
+			   void *cb_ctx);
+
+#ifdef CONFIG_PEERKEY
+int wpa_stsl_remove(struct wpa_authenticator *wpa_auth,
+		    struct wpa_stsl_negotiation *neg);
+void wpa_smk_error(struct wpa_authenticator *wpa_auth,
+		   struct wpa_state_machine *sm, struct wpa_eapol_key *key);
+void wpa_smk_m1(struct wpa_authenticator *wpa_auth,
+		struct wpa_state_machine *sm, struct wpa_eapol_key *key);
+void wpa_smk_m3(struct wpa_authenticator *wpa_auth,
+		struct wpa_state_machine *sm, struct wpa_eapol_key *key);
+#endif /* CONFIG_PEERKEY */
+
+#ifdef CONFIG_IEEE80211R
+int wpa_write_mdie(struct wpa_auth_config *conf, u8 *buf, size_t len);
+int wpa_write_ftie(struct wpa_auth_config *conf, const u8 *r0kh_id,
+		   size_t r0kh_id_len,
+		   const u8 *anonce, const u8 *snonce,
+		   u8 *buf, size_t len, const u8 *subelem,
+		   size_t subelem_len);
+int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
+			   struct wpa_ptk *ptk, size_t ptk_len);
+struct wpa_ft_pmk_cache * wpa_ft_pmk_cache_init(void);
+void wpa_ft_pmk_cache_deinit(struct wpa_ft_pmk_cache *cache);
+void wpa_ft_install_ptk(struct wpa_state_machine *sm);
+#endif /* CONFIG_IEEE80211R */
+
+#endif /* WPA_AUTH_I_H */
diff --git a/hostap/src/ap/wpa_auth_ie.c b/hostap/src/ap/wpa_auth_ie.c
new file mode 100644
index 0000000..4fd0135
--- /dev/null
+++ b/hostap/src/ap/wpa_auth_ie.c
@@ -0,0 +1,778 @@
+/*
+ * hostapd - WPA/RSN IE and KDE definitions
+ * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "common/ieee802_11_defs.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "ap_config.h"
+#include "ieee802_11.h"
+#include "wpa_auth.h"
+#include "pmksa_cache_auth.h"
+#include "wpa_auth_ie.h"
+#include "wpa_auth_i.h"
+
+
+#ifdef CONFIG_RSN_TESTING
+int rsn_testing = 0;
+#endif /* CONFIG_RSN_TESTING */
+
+
+static int wpa_write_wpa_ie(struct wpa_auth_config *conf, u8 *buf, size_t len)
+{
+	struct wpa_ie_hdr *hdr;
+	int num_suites;
+	u8 *pos, *count;
+	u32 suite;
+
+	hdr = (struct wpa_ie_hdr *) buf;
+	hdr->elem_id = WLAN_EID_VENDOR_SPECIFIC;
+	RSN_SELECTOR_PUT(hdr->oui, WPA_OUI_TYPE);
+	WPA_PUT_LE16(hdr->version, WPA_VERSION);
+	pos = (u8 *) (hdr + 1);
+
+	suite = wpa_cipher_to_suite(WPA_PROTO_WPA, conf->wpa_group);
+	if (suite == 0) {
+		wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
+			   conf->wpa_group);
+		return -1;
+	}
+	RSN_SELECTOR_PUT(pos, suite);
+	pos += WPA_SELECTOR_LEN;
+
+	count = pos;
+	pos += 2;
+
+	num_suites = wpa_cipher_put_suites(pos, conf->wpa_pairwise);
+	if (num_suites == 0) {
+		wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
+			   conf->wpa_pairwise);
+		return -1;
+	}
+	pos += num_suites * WPA_SELECTOR_LEN;
+	WPA_PUT_LE16(count, num_suites);
+
+	num_suites = 0;
+	count = pos;
+	pos += 2;
+
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_UNSPEC_802_1X);
+		pos += WPA_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
+		RSN_SELECTOR_PUT(pos, WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X);
+		pos += WPA_SELECTOR_LEN;
+		num_suites++;
+	}
+
+	if (num_suites == 0) {
+		wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
+			   conf->wpa_key_mgmt);
+		return -1;
+	}
+	WPA_PUT_LE16(count, num_suites);
+
+	/* WPA Capabilities; use defaults, so no need to include it */
+
+	hdr->len = (pos - buf) - 2;
+
+	return pos - buf;
+}
+
+
+int wpa_write_rsn_ie(struct wpa_auth_config *conf, u8 *buf, size_t len,
+		     const u8 *pmkid)
+{
+	struct rsn_ie_hdr *hdr;
+	int num_suites, res;
+	u8 *pos, *count;
+	u16 capab;
+	u32 suite;
+
+	hdr = (struct rsn_ie_hdr *) buf;
+	hdr->elem_id = WLAN_EID_RSN;
+	WPA_PUT_LE16(hdr->version, RSN_VERSION);
+	pos = (u8 *) (hdr + 1);
+
+	suite = wpa_cipher_to_suite(WPA_PROTO_RSN, conf->wpa_group);
+	if (suite == 0) {
+		wpa_printf(MSG_DEBUG, "Invalid group cipher (%d).",
+			   conf->wpa_group);
+		return -1;
+	}
+	RSN_SELECTOR_PUT(pos, suite);
+	pos += RSN_SELECTOR_LEN;
+
+	num_suites = 0;
+	count = pos;
+	pos += 2;
+
+#ifdef CONFIG_RSN_TESTING
+	if (rsn_testing) {
+		RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_RSN_TESTING */
+
+	res = rsn_cipher_put_suites(pos, conf->rsn_pairwise);
+	num_suites += res;
+	pos += res * RSN_SELECTOR_LEN;
+
+#ifdef CONFIG_RSN_TESTING
+	if (rsn_testing) {
+		RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_RSN_TESTING */
+
+	if (num_suites == 0) {
+		wpa_printf(MSG_DEBUG, "Invalid pairwise cipher (%d).",
+			   conf->rsn_pairwise);
+		return -1;
+	}
+	WPA_PUT_LE16(count, num_suites);
+
+	num_suites = 0;
+	count = pos;
+	pos += 2;
+
+#ifdef CONFIG_RSN_TESTING
+	if (rsn_testing) {
+		RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 1));
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_RSN_TESTING */
+
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_UNSPEC_802_1X);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#ifdef CONFIG_IEEE80211R
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_802_1X);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_PSK) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_PSK);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SHA256);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK_SHA256) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_PSK_SHA256);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_SAE) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_SAE);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (conf->wpa_key_mgmt & WPA_KEY_MGMT_FT_SAE) {
+		RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_FT_SAE);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_SAE */
+
+#ifdef CONFIG_RSN_TESTING
+	if (rsn_testing) {
+		RSN_SELECTOR_PUT(pos, RSN_SELECTOR(0x12, 0x34, 0x56, 2));
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+#endif /* CONFIG_RSN_TESTING */
+
+	if (num_suites == 0) {
+		wpa_printf(MSG_DEBUG, "Invalid key management type (%d).",
+			   conf->wpa_key_mgmt);
+		return -1;
+	}
+	WPA_PUT_LE16(count, num_suites);
+
+	/* RSN Capabilities */
+	capab = 0;
+	if (conf->rsn_preauth)
+		capab |= WPA_CAPABILITY_PREAUTH;
+	if (conf->peerkey)
+		capab |= WPA_CAPABILITY_PEERKEY_ENABLED;
+	if (conf->wmm_enabled) {
+		/* 4 PTKSA replay counters when using WMM */
+		capab |= (RSN_NUM_REPLAY_COUNTERS_16 << 2);
+	}
+#ifdef CONFIG_IEEE80211W
+	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+		capab |= WPA_CAPABILITY_MFPC;
+		if (conf->ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED)
+			capab |= WPA_CAPABILITY_MFPR;
+	}
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_RSN_TESTING
+	if (rsn_testing)
+		capab |= BIT(8) | BIT(14) | BIT(15);
+#endif /* CONFIG_RSN_TESTING */
+	WPA_PUT_LE16(pos, capab);
+	pos += 2;
+
+	if (pmkid) {
+		if (pos + 2 + PMKID_LEN > buf + len)
+			return -1;
+		/* PMKID Count */
+		WPA_PUT_LE16(pos, 1);
+		pos += 2;
+		os_memcpy(pos, pmkid, PMKID_LEN);
+		pos += PMKID_LEN;
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION) {
+		if (pos + 2 + 4 > buf + len)
+			return -1;
+		if (pmkid == NULL) {
+			/* PMKID Count */
+			WPA_PUT_LE16(pos, 0);
+			pos += 2;
+		}
+
+		/* Management Group Cipher Suite */
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+		pos += RSN_SELECTOR_LEN;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_RSN_TESTING
+	if (rsn_testing) {
+		/*
+		 * Fill in any defined fields and add extra data to the end of
+		 * the element.
+		 */
+		int pmkid_count_set = pmkid != NULL;
+		if (conf->ieee80211w != NO_MGMT_FRAME_PROTECTION)
+			pmkid_count_set = 1;
+		/* PMKID Count */
+		WPA_PUT_LE16(pos, 0);
+		pos += 2;
+		if (conf->ieee80211w == NO_MGMT_FRAME_PROTECTION) {
+			/* Management Group Cipher Suite */
+			RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_AES_128_CMAC);
+			pos += RSN_SELECTOR_LEN;
+		}
+
+		os_memset(pos, 0x12, 17);
+		pos += 17;
+	}
+#endif /* CONFIG_RSN_TESTING */
+
+	hdr->len = (pos - buf) - 2;
+
+	return pos - buf;
+}
+
+
+int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth)
+{
+	u8 *pos, buf[128];
+	int res;
+
+	pos = buf;
+
+	if (wpa_auth->conf.wpa & WPA_PROTO_RSN) {
+		res = wpa_write_rsn_ie(&wpa_auth->conf,
+				       pos, buf + sizeof(buf) - pos, NULL);
+		if (res < 0)
+			return res;
+		pos += res;
+	}
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(wpa_auth->conf.wpa_key_mgmt)) {
+		res = wpa_write_mdie(&wpa_auth->conf, pos,
+				     buf + sizeof(buf) - pos);
+		if (res < 0)
+			return res;
+		pos += res;
+	}
+#endif /* CONFIG_IEEE80211R */
+	if (wpa_auth->conf.wpa & WPA_PROTO_WPA) {
+		res = wpa_write_wpa_ie(&wpa_auth->conf,
+				       pos, buf + sizeof(buf) - pos);
+		if (res < 0)
+			return res;
+		pos += res;
+	}
+
+	os_free(wpa_auth->wpa_ie);
+	wpa_auth->wpa_ie = os_malloc(pos - buf);
+	if (wpa_auth->wpa_ie == NULL)
+		return -1;
+	os_memcpy(wpa_auth->wpa_ie, buf, pos - buf);
+	wpa_auth->wpa_ie_len = pos - buf;
+
+	return 0;
+}
+
+
+u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
+		 const u8 *data2, size_t data2_len)
+{
+	*pos++ = WLAN_EID_VENDOR_SPECIFIC;
+	*pos++ = RSN_SELECTOR_LEN + data_len + data2_len;
+	RSN_SELECTOR_PUT(pos, kde);
+	pos += RSN_SELECTOR_LEN;
+	os_memcpy(pos, data, data_len);
+	pos += data_len;
+	if (data2) {
+		os_memcpy(pos, data2, data2_len);
+		pos += data2_len;
+	}
+	return pos;
+}
+
+
+struct wpa_auth_okc_iter_data {
+	struct rsn_pmksa_cache_entry *pmksa;
+	const u8 *aa;
+	const u8 *spa;
+	const u8 *pmkid;
+};
+
+
+static int wpa_auth_okc_iter(struct wpa_authenticator *a, void *ctx)
+{
+	struct wpa_auth_okc_iter_data *data = ctx;
+	data->pmksa = pmksa_cache_get_okc(a->pmksa, data->aa, data->spa,
+					  data->pmkid);
+	if (data->pmksa)
+		return 1;
+	return 0;
+}
+
+
+int wpa_validate_wpa_ie(struct wpa_authenticator *wpa_auth,
+			struct wpa_state_machine *sm,
+			const u8 *wpa_ie, size_t wpa_ie_len,
+			const u8 *mdie, size_t mdie_len)
+{
+	struct wpa_ie_data data;
+	int ciphers, key_mgmt, res, version;
+	u32 selector;
+	size_t i;
+	const u8 *pmkid = NULL;
+
+	if (wpa_auth == NULL || sm == NULL)
+		return WPA_NOT_ENABLED;
+
+	if (wpa_ie == NULL || wpa_ie_len < 1)
+		return WPA_INVALID_IE;
+
+	if (wpa_ie[0] == WLAN_EID_RSN)
+		version = WPA_PROTO_RSN;
+	else
+		version = WPA_PROTO_WPA;
+
+	if (!(wpa_auth->conf.wpa & version)) {
+		wpa_printf(MSG_DEBUG, "Invalid WPA proto (%d) from " MACSTR,
+			   version, MAC2STR(sm->addr));
+		return WPA_INVALID_PROTO;
+	}
+
+	if (version == WPA_PROTO_RSN) {
+		res = wpa_parse_wpa_ie_rsn(wpa_ie, wpa_ie_len, &data);
+
+		selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
+		if (0) {
+		}
+#ifdef CONFIG_IEEE80211R
+		else if (data.key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
+			selector = RSN_AUTH_KEY_MGMT_FT_802_1X;
+		else if (data.key_mgmt & WPA_KEY_MGMT_FT_PSK)
+			selector = RSN_AUTH_KEY_MGMT_FT_PSK;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
+			selector = RSN_AUTH_KEY_MGMT_802_1X_SHA256;
+		else if (data.key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+			selector = RSN_AUTH_KEY_MGMT_PSK_SHA256;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+		else if (data.key_mgmt & WPA_KEY_MGMT_SAE)
+			selector = RSN_AUTH_KEY_MGMT_SAE;
+		else if (data.key_mgmt & WPA_KEY_MGMT_FT_SAE)
+			selector = RSN_AUTH_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
+		else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+			selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
+		else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
+			selector = RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X;
+		wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
+
+		selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
+					       data.pairwise_cipher);
+		if (!selector)
+			selector = RSN_CIPHER_SUITE_CCMP;
+		wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
+
+		selector = wpa_cipher_to_suite(WPA_PROTO_RSN,
+					       data.group_cipher);
+		if (!selector)
+			selector = RSN_CIPHER_SUITE_CCMP;
+		wpa_auth->dot11RSNAGroupCipherSelected = selector;
+	} else {
+		res = wpa_parse_wpa_ie_wpa(wpa_ie, wpa_ie_len, &data);
+
+		selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
+		if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+			selector = WPA_AUTH_KEY_MGMT_UNSPEC_802_1X;
+		else if (data.key_mgmt & WPA_KEY_MGMT_PSK)
+			selector = WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X;
+		wpa_auth->dot11RSNAAuthenticationSuiteSelected = selector;
+
+		selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
+					       data.pairwise_cipher);
+		if (!selector)
+			selector = RSN_CIPHER_SUITE_TKIP;
+		wpa_auth->dot11RSNAPairwiseCipherSelected = selector;
+
+		selector = wpa_cipher_to_suite(WPA_PROTO_WPA,
+					       data.group_cipher);
+		if (!selector)
+			selector = WPA_CIPHER_SUITE_TKIP;
+		wpa_auth->dot11RSNAGroupCipherSelected = selector;
+	}
+	if (res) {
+		wpa_printf(MSG_DEBUG, "Failed to parse WPA/RSN IE from "
+			   MACSTR " (res=%d)", MAC2STR(sm->addr), res);
+		wpa_hexdump(MSG_DEBUG, "WPA/RSN IE", wpa_ie, wpa_ie_len);
+		return WPA_INVALID_IE;
+	}
+
+	if (data.group_cipher != wpa_auth->conf.wpa_group) {
+		wpa_printf(MSG_DEBUG, "Invalid WPA group cipher (0x%x) from "
+			   MACSTR, data.group_cipher, MAC2STR(sm->addr));
+		return WPA_INVALID_GROUP;
+	}
+
+	key_mgmt = data.key_mgmt & wpa_auth->conf.wpa_key_mgmt;
+	if (!key_mgmt) {
+		wpa_printf(MSG_DEBUG, "Invalid WPA key mgmt (0x%x) from "
+			   MACSTR, data.key_mgmt, MAC2STR(sm->addr));
+		return WPA_INVALID_AKMP;
+	}
+	if (0) {
+	}
+#ifdef CONFIG_IEEE80211R
+	else if (key_mgmt & WPA_KEY_MGMT_FT_IEEE8021X)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_IEEE8021X;
+	else if (key_mgmt & WPA_KEY_MGMT_FT_PSK)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_PSK;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SHA256)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SHA256;
+	else if (key_mgmt & WPA_KEY_MGMT_PSK_SHA256)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK_SHA256;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+	else if (key_mgmt & WPA_KEY_MGMT_SAE)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_SAE;
+	else if (key_mgmt & WPA_KEY_MGMT_FT_SAE)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
+	else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+	else
+		sm->wpa_key_mgmt = WPA_KEY_MGMT_PSK;
+
+	if (version == WPA_PROTO_RSN)
+		ciphers = data.pairwise_cipher & wpa_auth->conf.rsn_pairwise;
+	else
+		ciphers = data.pairwise_cipher & wpa_auth->conf.wpa_pairwise;
+	if (!ciphers) {
+		wpa_printf(MSG_DEBUG, "Invalid %s pairwise cipher (0x%x) "
+			   "from " MACSTR,
+			   version == WPA_PROTO_RSN ? "RSN" : "WPA",
+			   data.pairwise_cipher, MAC2STR(sm->addr));
+		return WPA_INVALID_PAIRWISE;
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (wpa_auth->conf.ieee80211w == MGMT_FRAME_PROTECTION_REQUIRED) {
+		if (!(data.capabilities & WPA_CAPABILITY_MFPC)) {
+			wpa_printf(MSG_DEBUG, "Management frame protection "
+				   "required, but client did not enable it");
+			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+		}
+
+		if (ciphers & WPA_CIPHER_TKIP) {
+			wpa_printf(MSG_DEBUG, "Management frame protection "
+				   "cannot use TKIP");
+			return WPA_MGMT_FRAME_PROTECTION_VIOLATION;
+		}
+
+		if (data.mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
+			wpa_printf(MSG_DEBUG, "Unsupported management group "
+				   "cipher %d", data.mgmt_group_cipher);
+			return WPA_INVALID_MGMT_GROUP_CIPHER;
+		}
+	}
+
+	if (wpa_auth->conf.ieee80211w == NO_MGMT_FRAME_PROTECTION ||
+	    !(data.capabilities & WPA_CAPABILITY_MFPC))
+		sm->mgmt_frame_prot = 0;
+	else
+		sm->mgmt_frame_prot = 1;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_IEEE80211R
+	if (wpa_key_mgmt_ft(sm->wpa_key_mgmt)) {
+		if (mdie == NULL || mdie_len < MOBILITY_DOMAIN_ID_LEN + 1) {
+			wpa_printf(MSG_DEBUG, "RSN: Trying to use FT, but "
+				   "MDIE not included");
+			return WPA_INVALID_MDIE;
+		}
+		if (os_memcmp(mdie, wpa_auth->conf.mobility_domain,
+			      MOBILITY_DOMAIN_ID_LEN) != 0) {
+			wpa_hexdump(MSG_DEBUG, "RSN: Attempted to use unknown "
+				    "MDIE", mdie, MOBILITY_DOMAIN_ID_LEN);
+			return WPA_INVALID_MDIE;
+		}
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	if (ciphers & WPA_CIPHER_CCMP)
+		sm->pairwise = WPA_CIPHER_CCMP;
+	else if (ciphers & WPA_CIPHER_GCMP)
+		sm->pairwise = WPA_CIPHER_GCMP;
+	else
+		sm->pairwise = WPA_CIPHER_TKIP;
+
+	/* TODO: clear WPA/WPA2 state if STA changes from one to another */
+	if (wpa_ie[0] == WLAN_EID_RSN)
+		sm->wpa = WPA_VERSION_WPA2;
+	else
+		sm->wpa = WPA_VERSION_WPA;
+
+	sm->pmksa = NULL;
+	for (i = 0; i < data.num_pmkid; i++) {
+		wpa_hexdump(MSG_DEBUG, "RSN IE: STA PMKID",
+			    &data.pmkid[i * PMKID_LEN], PMKID_LEN);
+		sm->pmksa = pmksa_cache_auth_get(wpa_auth->pmksa, sm->addr,
+						 &data.pmkid[i * PMKID_LEN]);
+		if (sm->pmksa) {
+			pmkid = sm->pmksa->pmkid;
+			break;
+		}
+	}
+	for (i = 0; sm->pmksa == NULL && wpa_auth->conf.okc &&
+		     i < data.num_pmkid; i++) {
+		struct wpa_auth_okc_iter_data idata;
+		idata.pmksa = NULL;
+		idata.aa = wpa_auth->addr;
+		idata.spa = sm->addr;
+		idata.pmkid = &data.pmkid[i * PMKID_LEN];
+		wpa_auth_for_each_auth(wpa_auth, wpa_auth_okc_iter, &idata);
+		if (idata.pmksa) {
+			wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+					 "OKC match for PMKID");
+			sm->pmksa = pmksa_cache_add_okc(wpa_auth->pmksa,
+							idata.pmksa,
+							wpa_auth->addr,
+							idata.pmkid);
+			pmkid = idata.pmkid;
+			break;
+		}
+	}
+	if (sm->pmksa) {
+		wpa_auth_vlogger(wpa_auth, sm->addr, LOGGER_DEBUG,
+				 "PMKID found from PMKSA cache "
+				 "eap_type=%d vlan_id=%d",
+				 sm->pmksa->eap_type_authsrv,
+				 sm->pmksa->vlan_id);
+		os_memcpy(wpa_auth->dot11RSNAPMKIDUsed, pmkid, PMKID_LEN);
+	}
+
+	if (sm->wpa_ie == NULL || sm->wpa_ie_len < wpa_ie_len) {
+		os_free(sm->wpa_ie);
+		sm->wpa_ie = os_malloc(wpa_ie_len);
+		if (sm->wpa_ie == NULL)
+			return WPA_ALLOC_FAIL;
+	}
+	os_memcpy(sm->wpa_ie, wpa_ie, wpa_ie_len);
+	sm->wpa_ie_len = wpa_ie_len;
+
+	return WPA_IE_OK;
+}
+
+
+/**
+ * wpa_parse_generic - Parse EAPOL-Key Key Data Generic IEs
+ * @pos: Pointer to the IE header
+ * @end: Pointer to the end of the Key Data buffer
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, 1 if end mark is found, -1 on failure
+ */
+static int wpa_parse_generic(const u8 *pos, const u8 *end,
+			     struct wpa_eapol_ie_parse *ie)
+{
+	if (pos[1] == 0)
+		return 1;
+
+	if (pos[1] >= 6 &&
+	    RSN_SELECTOR_GET(pos + 2) == WPA_OUI_TYPE &&
+	    pos[2 + WPA_SELECTOR_LEN] == 1 &&
+	    pos[2 + WPA_SELECTOR_LEN + 1] == 0) {
+		ie->wpa_ie = pos;
+		ie->wpa_ie_len = pos[1] + 2;
+		return 0;
+	}
+
+	if (pos + 1 + RSN_SELECTOR_LEN < end &&
+	    pos[1] >= RSN_SELECTOR_LEN + PMKID_LEN &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_PMKID) {
+		ie->pmkid = pos + 2 + RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_GROUPKEY) {
+		ie->gtk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->gtk_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_MAC_ADDR) {
+		ie->mac_addr = pos + 2 + RSN_SELECTOR_LEN;
+		ie->mac_addr_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+#ifdef CONFIG_PEERKEY
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_SMK) {
+		ie->smk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->smk_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_NONCE) {
+		ie->nonce = pos + 2 + RSN_SELECTOR_LEN;
+		ie->nonce_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_LIFETIME) {
+		ie->lifetime = pos + 2 + RSN_SELECTOR_LEN;
+		ie->lifetime_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_ERROR) {
+		ie->error = pos + 2 + RSN_SELECTOR_LEN;
+		ie->error_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+#endif /* CONFIG_PEERKEY */
+
+#ifdef CONFIG_IEEE80211W
+	if (pos[1] > RSN_SELECTOR_LEN + 2 &&
+	    RSN_SELECTOR_GET(pos + 2) == RSN_KEY_DATA_IGTK) {
+		ie->igtk = pos + 2 + RSN_SELECTOR_LEN;
+		ie->igtk_len = pos[1] - RSN_SELECTOR_LEN;
+		return 0;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	return 0;
+}
+
+
+/**
+ * wpa_parse_kde_ies - Parse EAPOL-Key Key Data IEs
+ * @buf: Pointer to the Key Data buffer
+ * @len: Key Data Length
+ * @ie: Pointer to parsed IE data
+ * Returns: 0 on success, -1 on failure
+ */
+int wpa_parse_kde_ies(const u8 *buf, size_t len, struct wpa_eapol_ie_parse *ie)
+{
+	const u8 *pos, *end;
+	int ret = 0;
+
+	os_memset(ie, 0, sizeof(*ie));
+	for (pos = buf, end = pos + len; pos + 1 < end; pos += 2 + pos[1]) {
+		if (pos[0] == 0xdd &&
+		    ((pos == buf + len - 1) || pos[1] == 0)) {
+			/* Ignore padding */
+			break;
+		}
+		if (pos + 2 + pos[1] > end) {
+			wpa_printf(MSG_DEBUG, "WPA: EAPOL-Key Key Data "
+				   "underflow (ie=%d len=%d pos=%d)",
+				   pos[0], pos[1], (int) (pos - buf));
+			wpa_hexdump_key(MSG_DEBUG, "WPA: Key Data",
+					buf, len);
+			ret = -1;
+			break;
+		}
+		if (*pos == WLAN_EID_RSN) {
+			ie->rsn_ie = pos;
+			ie->rsn_ie_len = pos[1] + 2;
+#ifdef CONFIG_IEEE80211R
+		} else if (*pos == WLAN_EID_MOBILITY_DOMAIN) {
+			ie->mdie = pos;
+			ie->mdie_len = pos[1] + 2;
+		} else if (*pos == WLAN_EID_FAST_BSS_TRANSITION) {
+			ie->ftie = pos;
+			ie->ftie_len = pos[1] + 2;
+#endif /* CONFIG_IEEE80211R */
+		} else if (*pos == WLAN_EID_VENDOR_SPECIFIC) {
+			ret = wpa_parse_generic(pos, end, ie);
+			if (ret < 0)
+				break;
+			if (ret > 0) {
+				ret = 0;
+				break;
+			}
+		} else {
+			wpa_hexdump(MSG_DEBUG, "WPA: Unrecognized EAPOL-Key "
+				    "Key Data IE", pos, 2 + pos[1]);
+		}
+	}
+
+	return ret;
+}
+
+
+int wpa_auth_uses_mfp(struct wpa_state_machine *sm)
+{
+	return sm ? sm->mgmt_frame_prot : 0;
+}
diff --git a/hostap/src/ap/wpa_auth_ie.h b/hostap/src/ap/wpa_auth_ie.h
new file mode 100644
index 0000000..4999139
--- /dev/null
+++ b/hostap/src/ap/wpa_auth_ie.h
@@ -0,0 +1,50 @@
+/*
+ * hostapd - WPA/RSN IE and KDE definitions
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_AUTH_IE_H
+#define WPA_AUTH_IE_H
+
+struct wpa_eapol_ie_parse {
+	const u8 *wpa_ie;
+	size_t wpa_ie_len;
+	const u8 *rsn_ie;
+	size_t rsn_ie_len;
+	const u8 *pmkid;
+	const u8 *gtk;
+	size_t gtk_len;
+	const u8 *mac_addr;
+	size_t mac_addr_len;
+#ifdef CONFIG_PEERKEY
+	const u8 *smk;
+	size_t smk_len;
+	const u8 *nonce;
+	size_t nonce_len;
+	const u8 *lifetime;
+	size_t lifetime_len;
+	const u8 *error;
+	size_t error_len;
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211W
+	const u8 *igtk;
+	size_t igtk_len;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_IEEE80211R
+	const u8 *mdie;
+	size_t mdie_len;
+	const u8 *ftie;
+	size_t ftie_len;
+#endif /* CONFIG_IEEE80211R */
+};
+
+int wpa_parse_kde_ies(const u8 *buf, size_t len,
+		      struct wpa_eapol_ie_parse *ie);
+u8 * wpa_add_kde(u8 *pos, u32 kde, const u8 *data, size_t data_len,
+		 const u8 *data2, size_t data2_len);
+int wpa_auth_gen_wpa_ie(struct wpa_authenticator *wpa_auth);
+
+#endif /* WPA_AUTH_IE_H */
diff --git a/hostap/src/ap/wps_hostapd.c b/hostap/src/ap/wps_hostapd.c
new file mode 100644
index 0000000..5ce4f1b
--- /dev/null
+++ b/hostap/src/ap/wps_hostapd.c
@@ -0,0 +1,1629 @@
+/*
+ * hostapd / WPS integration
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "utils/includes.h"
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "utils/uuid.h"
+#include "common/wpa_ctrl.h"
+#include "common/ieee802_11_defs.h"
+#include "common/ieee802_11_common.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
+#include "wps/wps.h"
+#include "wps/wps_defs.h"
+#include "wps/wps_dev_attr.h"
+#include "wps/wps_attr_parse.h"
+#include "hostapd.h"
+#include "ap_config.h"
+#include "ap_drv_ops.h"
+#include "beacon.h"
+#include "sta_info.h"
+#include "wps_hostapd.h"
+
+
+#ifdef CONFIG_WPS_UPNP
+#include "wps/wps_upnp.h"
+static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
+				 struct wps_context *wps);
+static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd);
+#endif /* CONFIG_WPS_UPNP */
+
+static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
+				    const u8 *bssid,
+				    const u8 *ie, size_t ie_len,
+				    int ssi_signal);
+static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx);
+
+
+struct wps_for_each_data {
+	int (*func)(struct hostapd_data *h, void *ctx);
+	void *ctx;
+};
+
+
+static int wps_for_each(struct hostapd_iface *iface, void *ctx)
+{
+	struct wps_for_each_data *data = ctx;
+	size_t j;
+
+	if (iface == NULL)
+		return 0;
+	for (j = 0; j < iface->num_bss; j++) {
+		struct hostapd_data *hapd = iface->bss[j];
+		int ret = data->func(hapd, data->ctx);
+		if (ret)
+			return ret;
+	}
+
+	return 0;
+}
+
+
+static int hostapd_wps_for_each(struct hostapd_data *hapd,
+				int (*func)(struct hostapd_data *h, void *ctx),
+				void *ctx)
+{
+	struct hostapd_iface *iface = hapd->iface;
+	struct wps_for_each_data data;
+	data.func = func;
+	data.ctx = ctx;
+	if (iface->interfaces == NULL ||
+	    iface->interfaces->for_each_interface == NULL)
+		return wps_for_each(iface, &data);
+	return iface->interfaces->for_each_interface(iface->interfaces,
+						     wps_for_each, &data);
+}
+
+
+static int hostapd_wps_new_psk_cb(void *ctx, const u8 *mac_addr, const u8 *psk,
+				  size_t psk_len)
+{
+	struct hostapd_data *hapd = ctx;
+	struct hostapd_wpa_psk *p;
+	struct hostapd_ssid *ssid = &hapd->conf->ssid;
+
+	wpa_printf(MSG_DEBUG, "Received new WPA/WPA2-PSK from WPS for STA "
+		   MACSTR, MAC2STR(mac_addr));
+	wpa_hexdump_key(MSG_DEBUG, "Per-device PSK", psk, psk_len);
+
+	if (psk_len != PMK_LEN) {
+		wpa_printf(MSG_DEBUG, "Unexpected PSK length %lu",
+			   (unsigned long) psk_len);
+		return -1;
+	}
+
+	/* Add the new PSK to runtime PSK list */
+	p = os_zalloc(sizeof(*p));
+	if (p == NULL)
+		return -1;
+	os_memcpy(p->addr, mac_addr, ETH_ALEN);
+	os_memcpy(p->psk, psk, PMK_LEN);
+
+	p->next = ssid->wpa_psk;
+	ssid->wpa_psk = p;
+
+	if (ssid->wpa_psk_file) {
+		FILE *f;
+		char hex[PMK_LEN * 2 + 1];
+		/* Add the new PSK to PSK list file */
+		f = fopen(ssid->wpa_psk_file, "a");
+		if (f == NULL) {
+			wpa_printf(MSG_DEBUG, "Failed to add the PSK to "
+				   "'%s'", ssid->wpa_psk_file);
+			return -1;
+		}
+
+		wpa_snprintf_hex(hex, sizeof(hex), psk, psk_len);
+		fprintf(f, MACSTR " %s\n", MAC2STR(mac_addr), hex);
+		fclose(f);
+	}
+
+	return 0;
+}
+
+
+static int hostapd_wps_set_ie_cb(void *ctx, struct wpabuf *beacon_ie,
+				 struct wpabuf *probe_resp_ie)
+{
+	struct hostapd_data *hapd = ctx;
+	wpabuf_free(hapd->wps_beacon_ie);
+	hapd->wps_beacon_ie = beacon_ie;
+	wpabuf_free(hapd->wps_probe_resp_ie);
+	hapd->wps_probe_resp_ie = probe_resp_ie;
+	if (hapd->beacon_set_done)
+		ieee802_11_set_beacon(hapd);
+	return hostapd_set_ap_wps_ie(hapd);
+}
+
+
+static void hostapd_wps_pin_needed_cb(void *ctx, const u8 *uuid_e,
+				      const struct wps_device_data *dev)
+{
+	struct hostapd_data *hapd = ctx;
+	char uuid[40], txt[400];
+	int len;
+	char devtype[WPS_DEV_TYPE_BUFSIZE];
+	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
+		return;
+	wpa_printf(MSG_DEBUG, "WPS: PIN needed for E-UUID %s", uuid);
+	len = os_snprintf(txt, sizeof(txt), WPS_EVENT_PIN_NEEDED
+			  "%s " MACSTR " [%s|%s|%s|%s|%s|%s]",
+			  uuid, MAC2STR(dev->mac_addr), dev->device_name,
+			  dev->manufacturer, dev->model_name,
+			  dev->model_number, dev->serial_number,
+			  wps_dev_type_bin2str(dev->pri_dev_type, devtype,
+					       sizeof(devtype)));
+	if (len > 0 && len < (int) sizeof(txt))
+		wpa_msg(hapd->msg_ctx, MSG_INFO, "%s", txt);
+
+	if (hapd->conf->wps_pin_requests) {
+		FILE *f;
+		struct os_time t;
+		f = fopen(hapd->conf->wps_pin_requests, "a");
+		if (f == NULL)
+			return;
+		os_get_time(&t);
+		fprintf(f, "%ld\t%s\t" MACSTR "\t%s\t%s\t%s\t%s\t%s"
+			"\t%s\n",
+			t.sec, uuid, MAC2STR(dev->mac_addr), dev->device_name,
+			dev->manufacturer, dev->model_name, dev->model_number,
+			dev->serial_number,
+			wps_dev_type_bin2str(dev->pri_dev_type, devtype,
+					     sizeof(devtype)));
+		fclose(f);
+	}
+}
+
+
+struct wps_stop_reg_data {
+	struct hostapd_data *current_hapd;
+	const u8 *uuid_e;
+	const u8 *dev_pw;
+	size_t dev_pw_len;
+};
+
+static int wps_stop_registrar(struct hostapd_data *hapd, void *ctx)
+{
+	struct wps_stop_reg_data *data = ctx;
+	if (hapd != data->current_hapd && hapd->wps != NULL)
+		wps_registrar_complete(hapd->wps->registrar, data->uuid_e,
+				       data->dev_pw, data->dev_pw_len);
+	return 0;
+}
+
+
+static void hostapd_wps_reg_success_cb(void *ctx, const u8 *mac_addr,
+				       const u8 *uuid_e, const u8 *dev_pw,
+				       size_t dev_pw_len)
+{
+	struct hostapd_data *hapd = ctx;
+	char uuid[40];
+	struct wps_stop_reg_data data;
+	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
+		return;
+	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_REG_SUCCESS MACSTR " %s",
+		MAC2STR(mac_addr), uuid);
+	if (hapd->wps_reg_success_cb)
+		hapd->wps_reg_success_cb(hapd->wps_reg_success_cb_ctx,
+					 mac_addr, uuid_e);
+	data.current_hapd = hapd;
+	data.uuid_e = uuid_e;
+	data.dev_pw = dev_pw;
+	data.dev_pw_len = dev_pw_len;
+	hostapd_wps_for_each(hapd, wps_stop_registrar, &data);
+}
+
+
+static void hostapd_wps_enrollee_seen_cb(void *ctx, const u8 *addr,
+					 const u8 *uuid_e,
+					 const u8 *pri_dev_type,
+					 u16 config_methods,
+					 u16 dev_password_id, u8 request_type,
+					 const char *dev_name)
+{
+	struct hostapd_data *hapd = ctx;
+	char uuid[40];
+	char devtype[WPS_DEV_TYPE_BUFSIZE];
+	if (uuid_bin2str(uuid_e, uuid, sizeof(uuid)))
+		return;
+	if (dev_name == NULL)
+		dev_name = "";
+	wpa_msg_ctrl(hapd->msg_ctx, MSG_INFO, WPS_EVENT_ENROLLEE_SEEN MACSTR
+		     " %s %s 0x%x %u %u [%s]",
+		     MAC2STR(addr), uuid,
+		     wps_dev_type_bin2str(pri_dev_type, devtype,
+					  sizeof(devtype)),
+		     config_methods, dev_password_id, request_type, dev_name);
+}
+
+
+static int str_starts(const char *str, const char *start)
+{
+	return os_strncmp(str, start, os_strlen(start)) == 0;
+}
+
+
+static void wps_reload_config(void *eloop_data, void *user_ctx)
+{
+	struct hostapd_iface *iface = eloop_data;
+
+	wpa_printf(MSG_DEBUG, "WPS: Reload configuration data");
+	if (iface->interfaces == NULL ||
+	    iface->interfaces->reload_config(iface) < 0) {
+		wpa_printf(MSG_WARNING, "WPS: Failed to reload the updated "
+			   "configuration");
+	}
+}
+
+
+static void hapd_new_ap_event(struct hostapd_data *hapd, const u8 *attr,
+			      size_t attr_len)
+{
+	size_t blen = attr_len * 2 + 1;
+	char *buf = os_malloc(blen);
+	if (buf) {
+		wpa_snprintf_hex(buf, blen, attr, attr_len);
+		wpa_msg(hapd->msg_ctx, MSG_INFO,
+			WPS_EVENT_NEW_AP_SETTINGS "%s", buf);
+		os_free(buf);
+	}
+}
+
+
+static int hapd_wps_cred_cb(struct hostapd_data *hapd, void *ctx)
+{
+	const struct wps_credential *cred = ctx;
+	FILE *oconf, *nconf;
+	size_t len, i;
+	char *tmp_fname;
+	char buf[1024];
+	int multi_bss;
+	int wpa;
+
+	if (hapd->wps == NULL)
+		return 0;
+
+	wpa_hexdump_key(MSG_DEBUG, "WPS: Received Credential attribute",
+			cred->cred_attr, cred->cred_attr_len);
+
+	wpa_printf(MSG_DEBUG, "WPS: Received new AP Settings");
+	wpa_hexdump_ascii(MSG_DEBUG, "WPS: SSID", cred->ssid, cred->ssid_len);
+	wpa_printf(MSG_DEBUG, "WPS: Authentication Type 0x%x",
+		   cred->auth_type);
+	wpa_printf(MSG_DEBUG, "WPS: Encryption Type 0x%x", cred->encr_type);
+	wpa_printf(MSG_DEBUG, "WPS: Network Key Index %d", cred->key_idx);
+	wpa_hexdump_key(MSG_DEBUG, "WPS: Network Key",
+			cred->key, cred->key_len);
+	wpa_printf(MSG_DEBUG, "WPS: MAC Address " MACSTR,
+		   MAC2STR(cred->mac_addr));
+
+	if ((hapd->conf->wps_cred_processing == 1 ||
+	     hapd->conf->wps_cred_processing == 2) && cred->cred_attr) {
+		hapd_new_ap_event(hapd, cred->cred_attr, cred->cred_attr_len);
+	} else if (hapd->conf->wps_cred_processing == 1 ||
+		   hapd->conf->wps_cred_processing == 2) {
+		struct wpabuf *attr;
+		attr = wpabuf_alloc(200);
+		if (attr && wps_build_credential_wrap(attr, cred) == 0)
+			hapd_new_ap_event(hapd, wpabuf_head_u8(attr),
+					  wpabuf_len(attr));
+		wpabuf_free(attr);
+	} else
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_NEW_AP_SETTINGS);
+
+	if (hapd->conf->wps_cred_processing == 1)
+		return 0;
+
+	os_memcpy(hapd->wps->ssid, cred->ssid, cred->ssid_len);
+	hapd->wps->ssid_len = cred->ssid_len;
+	hapd->wps->encr_types = cred->encr_type;
+	hapd->wps->auth_types = cred->auth_type;
+	if (cred->key_len == 0) {
+		os_free(hapd->wps->network_key);
+		hapd->wps->network_key = NULL;
+		hapd->wps->network_key_len = 0;
+	} else {
+		if (hapd->wps->network_key == NULL ||
+		    hapd->wps->network_key_len < cred->key_len) {
+			hapd->wps->network_key_len = 0;
+			os_free(hapd->wps->network_key);
+			hapd->wps->network_key = os_malloc(cred->key_len);
+			if (hapd->wps->network_key == NULL)
+				return -1;
+		}
+		hapd->wps->network_key_len = cred->key_len;
+		os_memcpy(hapd->wps->network_key, cred->key, cred->key_len);
+	}
+	hapd->wps->wps_state = WPS_STATE_CONFIGURED;
+
+	if (hapd->iface->config_fname == NULL)
+		return 0;
+	len = os_strlen(hapd->iface->config_fname) + 5;
+	tmp_fname = os_malloc(len);
+	if (tmp_fname == NULL)
+		return -1;
+	os_snprintf(tmp_fname, len, "%s-new", hapd->iface->config_fname);
+
+	oconf = fopen(hapd->iface->config_fname, "r");
+	if (oconf == NULL) {
+		wpa_printf(MSG_WARNING, "WPS: Could not open current "
+			   "configuration file");
+		os_free(tmp_fname);
+		return -1;
+	}
+
+	nconf = fopen(tmp_fname, "w");
+	if (nconf == NULL) {
+		wpa_printf(MSG_WARNING, "WPS: Could not write updated "
+			   "configuration file");
+		os_free(tmp_fname);
+		fclose(oconf);
+		return -1;
+	}
+
+	fprintf(nconf, "# WPS configuration - START\n");
+
+	fprintf(nconf, "wps_state=2\n");
+
+	if (is_hex(cred->ssid, cred->ssid_len)) {
+		fprintf(nconf, "ssid2=");
+		for (i = 0; i < cred->ssid_len; i++)
+			fprintf(nconf, "%02x", cred->ssid[i]);
+		fprintf(nconf, "\n");
+	} else {
+		fprintf(nconf, "ssid=");
+		for (i = 0; i < cred->ssid_len; i++)
+			fputc(cred->ssid[i], nconf);
+		fprintf(nconf, "\n");
+	}
+
+	if ((cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK)) &&
+	    (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK)))
+		wpa = 3;
+	else if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA2PSK))
+		wpa = 2;
+	else if (cred->auth_type & (WPS_AUTH_WPA | WPS_AUTH_WPAPSK))
+		wpa = 1;
+	else
+		wpa = 0;
+
+	if (wpa) {
+		char *prefix;
+		fprintf(nconf, "wpa=%d\n", wpa);
+
+		fprintf(nconf, "wpa_key_mgmt=");
+		prefix = "";
+		if (cred->auth_type & (WPS_AUTH_WPA2 | WPS_AUTH_WPA)) {
+			fprintf(nconf, "WPA-EAP");
+			prefix = " ";
+		}
+		if (cred->auth_type & (WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK))
+			fprintf(nconf, "%sWPA-PSK", prefix);
+		fprintf(nconf, "\n");
+
+		fprintf(nconf, "wpa_pairwise=");
+		prefix = "";
+		if (cred->encr_type & WPS_ENCR_AES) {
+			fprintf(nconf, "CCMP");
+			prefix = " ";
+		}
+		if (cred->encr_type & WPS_ENCR_TKIP) {
+			fprintf(nconf, "%sTKIP", prefix);
+		}
+		fprintf(nconf, "\n");
+
+		if (cred->key_len >= 8 && cred->key_len < 64) {
+			fprintf(nconf, "wpa_passphrase=");
+			for (i = 0; i < cred->key_len; i++)
+				fputc(cred->key[i], nconf);
+			fprintf(nconf, "\n");
+		} else if (cred->key_len == 64) {
+			fprintf(nconf, "wpa_psk=");
+			for (i = 0; i < cred->key_len; i++)
+				fputc(cred->key[i], nconf);
+			fprintf(nconf, "\n");
+		} else {
+			wpa_printf(MSG_WARNING, "WPS: Invalid key length %lu "
+				   "for WPA/WPA2",
+				   (unsigned long) cred->key_len);
+		}
+
+		fprintf(nconf, "auth_algs=1\n");
+	} else {
+		if ((cred->auth_type & WPS_AUTH_OPEN) &&
+		    (cred->auth_type & WPS_AUTH_SHARED))
+			fprintf(nconf, "auth_algs=3\n");
+		else if (cred->auth_type & WPS_AUTH_SHARED)
+			fprintf(nconf, "auth_algs=2\n");
+		else
+			fprintf(nconf, "auth_algs=1\n");
+
+		if (cred->encr_type & WPS_ENCR_WEP && cred->key_idx <= 4) {
+			int key_idx = cred->key_idx;
+			if (key_idx)
+				key_idx--;
+			fprintf(nconf, "wep_default_key=%d\n", key_idx);
+			fprintf(nconf, "wep_key%d=", key_idx);
+			if (cred->key_len == 10 || cred->key_len == 26) {
+				/* WEP key as a hex string */
+				for (i = 0; i < cred->key_len; i++)
+					fputc(cred->key[i], nconf);
+			} else {
+				/* Raw WEP key; convert to hex */
+				for (i = 0; i < cred->key_len; i++)
+					fprintf(nconf, "%02x", cred->key[i]);
+			}
+			fprintf(nconf, "\n");
+		}
+	}
+
+	fprintf(nconf, "# WPS configuration - END\n");
+
+	multi_bss = 0;
+	while (fgets(buf, sizeof(buf), oconf)) {
+		if (os_strncmp(buf, "bss=", 4) == 0)
+			multi_bss = 1;
+		if (!multi_bss &&
+		    (str_starts(buf, "ssid=") ||
+		     str_starts(buf, "ssid2=") ||
+		     str_starts(buf, "auth_algs=") ||
+		     str_starts(buf, "wep_default_key=") ||
+		     str_starts(buf, "wep_key") ||
+		     str_starts(buf, "wps_state=") ||
+		     str_starts(buf, "wpa=") ||
+		     str_starts(buf, "wpa_psk=") ||
+		     str_starts(buf, "wpa_pairwise=") ||
+		     str_starts(buf, "rsn_pairwise=") ||
+		     str_starts(buf, "wpa_key_mgmt=") ||
+		     str_starts(buf, "wpa_passphrase="))) {
+			fprintf(nconf, "#WPS# %s", buf);
+		} else
+			fprintf(nconf, "%s", buf);
+	}
+
+	fclose(nconf);
+	fclose(oconf);
+
+	if (rename(tmp_fname, hapd->iface->config_fname) < 0) {
+		wpa_printf(MSG_WARNING, "WPS: Failed to rename the updated "
+			   "configuration file: %s", strerror(errno));
+		os_free(tmp_fname);
+		return -1;
+	}
+
+	os_free(tmp_fname);
+
+	/* Schedule configuration reload after short period of time to allow
+	 * EAP-WSC to be finished.
+	 */
+	eloop_register_timeout(0, 100000, wps_reload_config, hapd->iface,
+			       NULL);
+
+	wpa_printf(MSG_DEBUG, "WPS: AP configuration updated");
+
+	return 0;
+}
+
+
+static int hostapd_wps_cred_cb(void *ctx, const struct wps_credential *cred)
+{
+	struct hostapd_data *hapd = ctx;
+	return hostapd_wps_for_each(hapd, hapd_wps_cred_cb, (void *) cred);
+}
+
+
+static void hostapd_wps_reenable_ap_pin(void *eloop_data, void *user_ctx)
+{
+	struct hostapd_data *hapd = eloop_data;
+
+	if (hapd->conf->ap_setup_locked)
+		return;
+	if (hapd->ap_pin_failures_consecutive >= 10)
+		return;
+
+	wpa_printf(MSG_DEBUG, "WPS: Re-enable AP PIN");
+	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
+	hapd->wps->ap_setup_locked = 0;
+	wps_registrar_update_ie(hapd->wps->registrar);
+}
+
+
+static int wps_pwd_auth_fail(struct hostapd_data *hapd, void *ctx)
+{
+	struct wps_event_pwd_auth_fail *data = ctx;
+
+	if (!data->enrollee || hapd->conf->ap_pin == NULL || hapd->wps == NULL)
+		return 0;
+
+	/*
+	 * Registrar failed to prove its knowledge of the AP PIN. Lock AP setup
+	 * for some time if this happens multiple times to slow down brute
+	 * force attacks.
+	 */
+	hapd->ap_pin_failures++;
+	hapd->ap_pin_failures_consecutive++;
+	wpa_printf(MSG_DEBUG, "WPS: AP PIN authentication failure number %u "
+		   "(%u consecutive)",
+		   hapd->ap_pin_failures, hapd->ap_pin_failures_consecutive);
+	if (hapd->ap_pin_failures < 3)
+		return 0;
+
+	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_LOCKED);
+	hapd->wps->ap_setup_locked = 1;
+
+	wps_registrar_update_ie(hapd->wps->registrar);
+
+	if (!hapd->conf->ap_setup_locked &&
+	    hapd->ap_pin_failures_consecutive >= 10) {
+		/*
+		 * In indefinite lockdown - disable automatic AP PIN
+		 * reenablement.
+		 */
+		eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
+		wpa_printf(MSG_DEBUG, "WPS: AP PIN disabled indefinitely");
+	} else if (!hapd->conf->ap_setup_locked) {
+		if (hapd->ap_pin_lockout_time == 0)
+			hapd->ap_pin_lockout_time = 60;
+		else if (hapd->ap_pin_lockout_time < 365 * 24 * 60 * 60 &&
+			 (hapd->ap_pin_failures % 3) == 0)
+			hapd->ap_pin_lockout_time *= 2;
+
+		wpa_printf(MSG_DEBUG, "WPS: Disable AP PIN for %u seconds",
+			   hapd->ap_pin_lockout_time);
+		eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
+		eloop_register_timeout(hapd->ap_pin_lockout_time, 0,
+				       hostapd_wps_reenable_ap_pin, hapd,
+				       NULL);
+	}
+
+	return 0;
+}
+
+
+static void hostapd_pwd_auth_fail(struct hostapd_data *hapd,
+				  struct wps_event_pwd_auth_fail *data)
+{
+	hostapd_wps_for_each(hapd, wps_pwd_auth_fail, data);
+}
+
+
+static int wps_ap_pin_success(struct hostapd_data *hapd, void *ctx)
+{
+	if (hapd->conf->ap_pin == NULL || hapd->wps == NULL)
+		return 0;
+
+	if (hapd->ap_pin_failures_consecutive == 0)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "WPS: Clear consecutive AP PIN failure counter "
+		   "- total validation failures %u (%u consecutive)",
+		   hapd->ap_pin_failures, hapd->ap_pin_failures_consecutive);
+	hapd->ap_pin_failures_consecutive = 0;
+
+	return 0;
+}
+
+
+static void hostapd_wps_ap_pin_success(struct hostapd_data *hapd)
+{
+	hostapd_wps_for_each(hapd, wps_ap_pin_success, NULL);
+}
+
+
+static const char * wps_event_fail_reason[NUM_WPS_EI_VALUES] = {
+	"No Error", /* WPS_EI_NO_ERROR */
+	"TKIP Only Prohibited", /* WPS_EI_SECURITY_TKIP_ONLY_PROHIBITED */
+	"WEP Prohibited" /* WPS_EI_SECURITY_WEP_PROHIBITED */
+};
+
+static void hostapd_wps_event_fail(struct hostapd_data *hapd,
+				   struct wps_event_fail *fail)
+{
+	if (fail->error_indication > 0 &&
+	    fail->error_indication < NUM_WPS_EI_VALUES) {
+		wpa_msg(hapd->msg_ctx, MSG_INFO,
+			WPS_EVENT_FAIL "msg=%d config_error=%d reason=%d (%s)",
+			fail->msg, fail->config_error, fail->error_indication,
+			wps_event_fail_reason[fail->error_indication]);
+	} else {
+		wpa_msg(hapd->msg_ctx, MSG_INFO,
+			WPS_EVENT_FAIL "msg=%d config_error=%d",
+			fail->msg, fail->config_error);
+	}
+}
+
+
+static void hostapd_wps_event_cb(void *ctx, enum wps_event event,
+				 union wps_event_data *data)
+{
+	struct hostapd_data *hapd = ctx;
+
+	switch (event) {
+	case WPS_EV_M2D:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_M2D);
+		break;
+	case WPS_EV_FAIL:
+		hostapd_wps_event_fail(hapd, &data->fail);
+		break;
+	case WPS_EV_SUCCESS:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_SUCCESS);
+		break;
+	case WPS_EV_PWD_AUTH_FAIL:
+		hostapd_pwd_auth_fail(hapd, &data->pwd_auth_fail);
+		break;
+	case WPS_EV_PBC_OVERLAP:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_OVERLAP);
+		break;
+	case WPS_EV_PBC_TIMEOUT:
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_TIMEOUT);
+		break;
+	case WPS_EV_ER_AP_ADD:
+		break;
+	case WPS_EV_ER_AP_REMOVE:
+		break;
+	case WPS_EV_ER_ENROLLEE_ADD:
+		break;
+	case WPS_EV_ER_ENROLLEE_REMOVE:
+		break;
+	case WPS_EV_ER_AP_SETTINGS:
+		break;
+	case WPS_EV_ER_SET_SELECTED_REGISTRAR:
+		break;
+	case WPS_EV_AP_PIN_SUCCESS:
+		hostapd_wps_ap_pin_success(hapd);
+		break;
+	}
+	if (hapd->wps_event_cb)
+		hapd->wps_event_cb(hapd->wps_event_cb_ctx, event, data);
+}
+
+
+static void hostapd_wps_clear_ies(struct hostapd_data *hapd)
+{
+	wpabuf_free(hapd->wps_beacon_ie);
+	hapd->wps_beacon_ie = NULL;
+
+	wpabuf_free(hapd->wps_probe_resp_ie);
+	hapd->wps_probe_resp_ie = NULL;
+
+	hostapd_set_ap_wps_ie(hapd);
+}
+
+
+static int get_uuid_cb(struct hostapd_iface *iface, void *ctx)
+{
+	const u8 **uuid = ctx;
+	size_t j;
+
+	if (iface == NULL)
+		return 0;
+	for (j = 0; j < iface->num_bss; j++) {
+		struct hostapd_data *hapd = iface->bss[j];
+		if (hapd->wps && !is_nil_uuid(hapd->wps->uuid)) {
+			*uuid = hapd->wps->uuid;
+			return 1;
+		}
+	}
+
+	return 0;
+}
+
+
+static const u8 * get_own_uuid(struct hostapd_iface *iface)
+{
+	const u8 *uuid;
+	if (iface->interfaces == NULL ||
+	    iface->interfaces->for_each_interface == NULL)
+		return NULL;
+	uuid = NULL;
+	iface->interfaces->for_each_interface(iface->interfaces, get_uuid_cb,
+					      &uuid);
+	return uuid;
+}
+
+
+static int count_interface_cb(struct hostapd_iface *iface, void *ctx)
+{
+	int *count= ctx;
+	(*count)++;
+	return 0;
+}
+
+
+static int interface_count(struct hostapd_iface *iface)
+{
+	int count = 0;
+	if (iface->interfaces == NULL ||
+	    iface->interfaces->for_each_interface == NULL)
+		return 0;
+	iface->interfaces->for_each_interface(iface->interfaces,
+					      count_interface_cb, &count);
+	return count;
+}
+
+
+static int hostapd_wps_set_vendor_ext(struct hostapd_data *hapd,
+				      struct wps_context *wps)
+{
+	int i;
+
+	for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++) {
+		wpabuf_free(wps->dev.vendor_ext[i]);
+		wps->dev.vendor_ext[i] = NULL;
+
+		if (hapd->conf->wps_vendor_ext[i] == NULL)
+			continue;
+
+		wps->dev.vendor_ext[i] =
+			wpabuf_dup(hapd->conf->wps_vendor_ext[i]);
+		if (wps->dev.vendor_ext[i] == NULL) {
+			while (--i >= 0)
+				wpabuf_free(wps->dev.vendor_ext[i]);
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+int hostapd_init_wps(struct hostapd_data *hapd,
+		     struct hostapd_bss_config *conf)
+{
+	struct wps_context *wps;
+	struct wps_registrar_config cfg;
+
+	if (conf->wps_state == 0) {
+		hostapd_wps_clear_ies(hapd);
+		return 0;
+	}
+
+	wps = os_zalloc(sizeof(*wps));
+	if (wps == NULL)
+		return -1;
+
+	wps->cred_cb = hostapd_wps_cred_cb;
+	wps->event_cb = hostapd_wps_event_cb;
+	wps->cb_ctx = hapd;
+
+	os_memset(&cfg, 0, sizeof(cfg));
+	wps->wps_state = hapd->conf->wps_state;
+	wps->ap_setup_locked = hapd->conf->ap_setup_locked;
+	if (is_nil_uuid(hapd->conf->uuid)) {
+		const u8 *uuid;
+		uuid = get_own_uuid(hapd->iface);
+		if (uuid) {
+			os_memcpy(wps->uuid, uuid, UUID_LEN);
+			wpa_hexdump(MSG_DEBUG, "WPS: Clone UUID from another "
+				    "interface", wps->uuid, UUID_LEN);
+		} else {
+			uuid_gen_mac_addr(hapd->own_addr, wps->uuid);
+			wpa_hexdump(MSG_DEBUG, "WPS: UUID based on MAC "
+				    "address", wps->uuid, UUID_LEN);
+		}
+	} else {
+		os_memcpy(wps->uuid, hapd->conf->uuid, UUID_LEN);
+		wpa_hexdump(MSG_DEBUG, "WPS: Use configured UUID",
+			    wps->uuid, UUID_LEN);
+	}
+	wps->ssid_len = hapd->conf->ssid.ssid_len;
+	os_memcpy(wps->ssid, hapd->conf->ssid.ssid, wps->ssid_len);
+	wps->ap = 1;
+	os_memcpy(wps->dev.mac_addr, hapd->own_addr, ETH_ALEN);
+	wps->dev.device_name = hapd->conf->device_name ?
+		os_strdup(hapd->conf->device_name) : NULL;
+	wps->dev.manufacturer = hapd->conf->manufacturer ?
+		os_strdup(hapd->conf->manufacturer) : NULL;
+	wps->dev.model_name = hapd->conf->model_name ?
+		os_strdup(hapd->conf->model_name) : NULL;
+	wps->dev.model_number = hapd->conf->model_number ?
+		os_strdup(hapd->conf->model_number) : NULL;
+	wps->dev.serial_number = hapd->conf->serial_number ?
+		os_strdup(hapd->conf->serial_number) : NULL;
+	wps->config_methods =
+		wps_config_methods_str2bin(hapd->conf->config_methods);
+#ifdef CONFIG_WPS2
+	if ((wps->config_methods &
+	     (WPS_CONFIG_DISPLAY | WPS_CONFIG_VIRT_DISPLAY |
+	      WPS_CONFIG_PHY_DISPLAY)) == WPS_CONFIG_DISPLAY) {
+		wpa_printf(MSG_INFO, "WPS: Converting display to "
+			   "virtual_display for WPS 2.0 compliance");
+		wps->config_methods |= WPS_CONFIG_VIRT_DISPLAY;
+	}
+	if ((wps->config_methods &
+	     (WPS_CONFIG_PUSHBUTTON | WPS_CONFIG_VIRT_PUSHBUTTON |
+	      WPS_CONFIG_PHY_PUSHBUTTON)) == WPS_CONFIG_PUSHBUTTON) {
+		wpa_printf(MSG_INFO, "WPS: Converting push_button to "
+			   "virtual_push_button for WPS 2.0 compliance");
+		wps->config_methods |= WPS_CONFIG_VIRT_PUSHBUTTON;
+	}
+#endif /* CONFIG_WPS2 */
+	os_memcpy(wps->dev.pri_dev_type, hapd->conf->device_type,
+		  WPS_DEV_TYPE_LEN);
+
+	if (hostapd_wps_set_vendor_ext(hapd, wps) < 0) {
+		os_free(wps);
+		return -1;
+	}
+
+	wps->dev.os_version = WPA_GET_BE32(hapd->conf->os_version);
+
+	if (conf->wps_rf_bands) {
+		wps->dev.rf_bands = conf->wps_rf_bands;
+	} else {
+		wps->dev.rf_bands =
+			hapd->iconf->hw_mode == HOSTAPD_MODE_IEEE80211A ?
+			WPS_RF_50GHZ : WPS_RF_24GHZ; /* FIX: dualband AP */
+	}
+
+	if (conf->wpa & WPA_PROTO_RSN) {
+		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
+			wps->auth_types |= WPS_AUTH_WPA2PSK;
+		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+			wps->auth_types |= WPS_AUTH_WPA2;
+
+		if (conf->rsn_pairwise & WPA_CIPHER_CCMP)
+			wps->encr_types |= WPS_ENCR_AES;
+		if (conf->rsn_pairwise & WPA_CIPHER_TKIP)
+			wps->encr_types |= WPS_ENCR_TKIP;
+	}
+
+	if (conf->wpa & WPA_PROTO_WPA) {
+		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_PSK)
+			wps->auth_types |= WPS_AUTH_WPAPSK;
+		if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X)
+			wps->auth_types |= WPS_AUTH_WPA;
+
+		if (conf->wpa_pairwise & WPA_CIPHER_CCMP)
+			wps->encr_types |= WPS_ENCR_AES;
+		if (conf->wpa_pairwise & WPA_CIPHER_TKIP)
+			wps->encr_types |= WPS_ENCR_TKIP;
+	}
+
+	if (conf->ssid.security_policy == SECURITY_PLAINTEXT) {
+		wps->encr_types |= WPS_ENCR_NONE;
+		wps->auth_types |= WPS_AUTH_OPEN;
+	} else if (conf->ssid.security_policy == SECURITY_STATIC_WEP) {
+		wps->encr_types |= WPS_ENCR_WEP;
+		if (conf->auth_algs & WPA_AUTH_ALG_OPEN)
+			wps->auth_types |= WPS_AUTH_OPEN;
+		if (conf->auth_algs & WPA_AUTH_ALG_SHARED)
+			wps->auth_types |= WPS_AUTH_SHARED;
+	} else if (conf->ssid.security_policy == SECURITY_IEEE_802_1X) {
+		wps->auth_types |= WPS_AUTH_OPEN;
+		if (conf->default_wep_key_len)
+			wps->encr_types |= WPS_ENCR_WEP;
+		else
+			wps->encr_types |= WPS_ENCR_NONE;
+	}
+
+	if (conf->ssid.wpa_psk_file) {
+		/* Use per-device PSKs */
+	} else if (conf->ssid.wpa_passphrase) {
+		wps->network_key = (u8 *) os_strdup(conf->ssid.wpa_passphrase);
+		wps->network_key_len = os_strlen(conf->ssid.wpa_passphrase);
+	} else if (conf->ssid.wpa_psk) {
+		wps->network_key = os_malloc(2 * PMK_LEN + 1);
+		if (wps->network_key == NULL) {
+			os_free(wps);
+			return -1;
+		}
+		wpa_snprintf_hex((char *) wps->network_key, 2 * PMK_LEN + 1,
+				 conf->ssid.wpa_psk->psk, PMK_LEN);
+		wps->network_key_len = 2 * PMK_LEN;
+	} else if (conf->ssid.wep.keys_set && conf->ssid.wep.key[0]) {
+		wps->network_key = os_malloc(conf->ssid.wep.len[0]);
+		if (wps->network_key == NULL) {
+			os_free(wps);
+			return -1;
+		}
+		os_memcpy(wps->network_key, conf->ssid.wep.key[0],
+			  conf->ssid.wep.len[0]);
+		wps->network_key_len = conf->ssid.wep.len[0];
+	}
+
+	if (conf->ssid.wpa_psk) {
+		os_memcpy(wps->psk, conf->ssid.wpa_psk->psk, PMK_LEN);
+		wps->psk_set = 1;
+	}
+
+	if (conf->wps_state == WPS_STATE_NOT_CONFIGURED) {
+		/* Override parameters to enable security by default */
+		wps->auth_types = WPS_AUTH_WPA2PSK | WPS_AUTH_WPAPSK;
+		wps->encr_types = WPS_ENCR_AES | WPS_ENCR_TKIP;
+	}
+
+	wps->ap_settings = conf->ap_settings;
+	wps->ap_settings_len = conf->ap_settings_len;
+
+	cfg.new_psk_cb = hostapd_wps_new_psk_cb;
+	cfg.set_ie_cb = hostapd_wps_set_ie_cb;
+	cfg.pin_needed_cb = hostapd_wps_pin_needed_cb;
+	cfg.reg_success_cb = hostapd_wps_reg_success_cb;
+	cfg.enrollee_seen_cb = hostapd_wps_enrollee_seen_cb;
+	cfg.cb_ctx = hapd;
+	cfg.skip_cred_build = conf->skip_cred_build;
+	cfg.extra_cred = conf->extra_cred;
+	cfg.extra_cred_len = conf->extra_cred_len;
+	cfg.disable_auto_conf = (hapd->conf->wps_cred_processing == 1) &&
+		conf->skip_cred_build;
+	if (conf->ssid.security_policy == SECURITY_STATIC_WEP)
+		cfg.static_wep_only = 1;
+	cfg.dualband = interface_count(hapd->iface) > 1;
+	if ((wps->dev.rf_bands & (WPS_RF_50GHZ | WPS_RF_24GHZ)) ==
+	    (WPS_RF_50GHZ | WPS_RF_24GHZ))
+		cfg.dualband = 1;
+	if (cfg.dualband)
+		wpa_printf(MSG_DEBUG, "WPS: Dualband AP");
+
+	wps->registrar = wps_registrar_init(wps, &cfg);
+	if (wps->registrar == NULL) {
+		wpa_printf(MSG_ERROR, "Failed to initialize WPS Registrar");
+		os_free(wps->network_key);
+		os_free(wps);
+		return -1;
+	}
+
+#ifdef CONFIG_WPS_UPNP
+	wps->friendly_name = hapd->conf->friendly_name;
+	wps->manufacturer_url = hapd->conf->manufacturer_url;
+	wps->model_description = hapd->conf->model_description;
+	wps->model_url = hapd->conf->model_url;
+	wps->upc = hapd->conf->upc;
+#endif /* CONFIG_WPS_UPNP */
+
+	hostapd_register_probereq_cb(hapd, hostapd_wps_probe_req_rx, hapd);
+
+	hapd->wps = wps;
+
+	return 0;
+}
+
+
+int hostapd_init_wps_complete(struct hostapd_data *hapd)
+{
+	struct wps_context *wps = hapd->wps;
+
+	if (wps == NULL)
+		return 0;
+
+#ifdef CONFIG_WPS_UPNP
+	if (hostapd_wps_upnp_init(hapd, wps) < 0) {
+		wpa_printf(MSG_ERROR, "Failed to initialize WPS UPnP");
+		wps_registrar_deinit(wps->registrar);
+		os_free(wps->network_key);
+		os_free(wps);
+		hapd->wps = NULL;
+		return -1;
+	}
+#endif /* CONFIG_WPS_UPNP */
+
+	return 0;
+}
+
+
+static void hostapd_wps_nfc_clear(struct wps_context *wps)
+{
+#ifdef CONFIG_WPS_NFC
+	wps->ap_nfc_dev_pw_id = 0;
+	wpabuf_free(wps->ap_nfc_dh_pubkey);
+	wps->ap_nfc_dh_pubkey = NULL;
+	wpabuf_free(wps->ap_nfc_dh_privkey);
+	wps->ap_nfc_dh_privkey = NULL;
+	wpabuf_free(wps->ap_nfc_dev_pw);
+	wps->ap_nfc_dev_pw = NULL;
+#endif /* CONFIG_WPS_NFC */
+}
+
+
+void hostapd_deinit_wps(struct hostapd_data *hapd)
+{
+	eloop_cancel_timeout(hostapd_wps_reenable_ap_pin, hapd, NULL);
+	eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
+	if (hapd->wps == NULL)
+		return;
+#ifdef CONFIG_WPS_UPNP
+	hostapd_wps_upnp_deinit(hapd);
+#endif /* CONFIG_WPS_UPNP */
+	wps_registrar_deinit(hapd->wps->registrar);
+	os_free(hapd->wps->network_key);
+	wps_device_data_free(&hapd->wps->dev);
+	wpabuf_free(hapd->wps->dh_pubkey);
+	wpabuf_free(hapd->wps->dh_privkey);
+	wps_free_pending_msgs(hapd->wps->upnp_msgs);
+	hostapd_wps_nfc_clear(hapd->wps);
+	os_free(hapd->wps);
+	hapd->wps = NULL;
+	hostapd_wps_clear_ies(hapd);
+}
+
+
+void hostapd_update_wps(struct hostapd_data *hapd)
+{
+	if (hapd->wps == NULL)
+		return;
+
+#ifdef CONFIG_WPS_UPNP
+	hapd->wps->friendly_name = hapd->conf->friendly_name;
+	hapd->wps->manufacturer_url = hapd->conf->manufacturer_url;
+	hapd->wps->model_description = hapd->conf->model_description;
+	hapd->wps->model_url = hapd->conf->model_url;
+	hapd->wps->upc = hapd->conf->upc;
+#endif /* CONFIG_WPS_UPNP */
+
+	hostapd_wps_set_vendor_ext(hapd, hapd->wps);
+
+	if (hapd->conf->wps_state)
+		wps_registrar_update_ie(hapd->wps->registrar);
+	else
+		hostapd_deinit_wps(hapd);
+}
+
+
+struct wps_add_pin_data {
+	const u8 *addr;
+	const u8 *uuid;
+	const u8 *pin;
+	size_t pin_len;
+	int timeout;
+	int added;
+};
+
+
+static int wps_add_pin(struct hostapd_data *hapd, void *ctx)
+{
+	struct wps_add_pin_data *data = ctx;
+	int ret;
+
+	if (hapd->wps == NULL)
+		return 0;
+	ret = wps_registrar_add_pin(hapd->wps->registrar, data->addr,
+				    data->uuid, data->pin, data->pin_len,
+				    data->timeout);
+	if (ret == 0)
+		data->added++;
+	return ret;
+}
+
+
+int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
+			const char *uuid, const char *pin, int timeout)
+{
+	u8 u[UUID_LEN];
+	struct wps_add_pin_data data;
+
+	data.addr = addr;
+	data.uuid = u;
+	data.pin = (const u8 *) pin;
+	data.pin_len = os_strlen(pin);
+	data.timeout = timeout;
+	data.added = 0;
+
+	if (os_strcmp(uuid, "any") == 0)
+		data.uuid = NULL;
+	else {
+		if (uuid_str2bin(uuid, u))
+			return -1;
+		data.uuid = u;
+	}
+	if (hostapd_wps_for_each(hapd, wps_add_pin, &data) < 0)
+		return -1;
+	return data.added ? 0 : -1;
+}
+
+
+static int wps_button_pushed(struct hostapd_data *hapd, void *ctx)
+{
+	const u8 *p2p_dev_addr = ctx;
+	if (hapd->wps == NULL)
+		return 0;
+	return wps_registrar_button_pushed(hapd->wps->registrar, p2p_dev_addr);
+}
+
+
+int hostapd_wps_button_pushed(struct hostapd_data *hapd,
+			      const u8 *p2p_dev_addr)
+{
+	return hostapd_wps_for_each(hapd, wps_button_pushed,
+				    (void *) p2p_dev_addr);
+}
+
+
+static int wps_cancel(struct hostapd_data *hapd, void *ctx)
+{
+	if (hapd->wps == NULL)
+		return 0;
+
+	wps_registrar_wps_cancel(hapd->wps->registrar);
+	ap_for_each_sta(hapd, ap_sta_wps_cancel, NULL);
+
+	return 0;
+}
+
+
+int hostapd_wps_cancel(struct hostapd_data *hapd)
+{
+	return hostapd_wps_for_each(hapd, wps_cancel, NULL);
+}
+
+
+static int hostapd_wps_probe_req_rx(void *ctx, const u8 *addr, const u8 *da,
+				    const u8 *bssid,
+				    const u8 *ie, size_t ie_len,
+				    int ssi_signal)
+{
+	struct hostapd_data *hapd = ctx;
+	struct wpabuf *wps_ie;
+	struct ieee802_11_elems elems;
+
+	if (hapd->wps == NULL)
+		return 0;
+
+	if (ieee802_11_parse_elems(ie, ie_len, &elems, 0) == ParseFailed) {
+		wpa_printf(MSG_DEBUG, "WPS: Could not parse ProbeReq from "
+			   MACSTR, MAC2STR(addr));
+		return 0;
+	}
+
+	if (elems.ssid && elems.ssid_len > 0 &&
+	    (elems.ssid_len != hapd->conf->ssid.ssid_len ||
+	     os_memcmp(elems.ssid, hapd->conf->ssid.ssid, elems.ssid_len) !=
+	     0))
+		return 0; /* Not for us */
+
+	wps_ie = ieee802_11_vendor_ie_concat(ie, ie_len, WPS_DEV_OUI_WFA);
+	if (wps_ie == NULL)
+		return 0;
+	if (wps_validate_probe_req(wps_ie, addr) < 0) {
+		wpabuf_free(wps_ie);
+		return 0;
+	}
+
+	if (wpabuf_len(wps_ie) > 0) {
+		int p2p_wildcard = 0;
+#ifdef CONFIG_P2P
+		if (elems.ssid && elems.ssid_len == P2P_WILDCARD_SSID_LEN &&
+		    os_memcmp(elems.ssid, P2P_WILDCARD_SSID,
+			      P2P_WILDCARD_SSID_LEN) == 0)
+			p2p_wildcard = 1;
+#endif /* CONFIG_P2P */
+		wps_registrar_probe_req_rx(hapd->wps->registrar, addr, wps_ie,
+					   p2p_wildcard);
+#ifdef CONFIG_WPS_UPNP
+		/* FIX: what exactly should be included in the WLANEvent?
+		 * WPS attributes? Full ProbeReq frame? */
+		if (!p2p_wildcard)
+			upnp_wps_device_send_wlan_event(
+				hapd->wps_upnp, addr,
+				UPNP_WPS_WLANEVENT_TYPE_PROBE, wps_ie);
+#endif /* CONFIG_WPS_UPNP */
+	}
+
+	wpabuf_free(wps_ie);
+
+	return 0;
+}
+
+
+#ifdef CONFIG_WPS_UPNP
+
+static int hostapd_rx_req_put_wlan_response(
+	void *priv, enum upnp_wps_wlanevent_type ev_type,
+	const u8 *mac_addr, const struct wpabuf *msg,
+	enum wps_msg_type msg_type)
+{
+	struct hostapd_data *hapd = priv;
+	struct sta_info *sta;
+	struct upnp_pending_message *p;
+
+	wpa_printf(MSG_DEBUG, "WPS UPnP: PutWLANResponse ev_type=%d mac_addr="
+		   MACSTR, ev_type, MAC2STR(mac_addr));
+	wpa_hexdump(MSG_MSGDUMP, "WPS UPnP: PutWLANResponse NewMessage",
+		    wpabuf_head(msg), wpabuf_len(msg));
+	if (ev_type != UPNP_WPS_WLANEVENT_TYPE_EAP) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: Ignored unexpected "
+			   "PutWLANResponse WLANEventType %d", ev_type);
+		return -1;
+	}
+
+	/*
+	 * EAP response to ongoing to WPS Registration. Send it to EAP-WSC
+	 * server implementation for delivery to the peer.
+	 */
+
+	sta = ap_get_sta(hapd, mac_addr);
+#ifndef CONFIG_WPS_STRICT
+	if (!sta) {
+		/*
+		 * Workaround - Intel wsccmd uses bogus NewWLANEventMAC:
+		 * Pick STA that is in an ongoing WPS registration without
+		 * checking the MAC address.
+		 */
+		wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found based "
+			   "on NewWLANEventMAC; try wildcard match");
+		for (sta = hapd->sta_list; sta; sta = sta->next) {
+			if (sta->eapol_sm && (sta->flags & WLAN_STA_WPS))
+				break;
+		}
+	}
+#endif /* CONFIG_WPS_STRICT */
+
+	if (!sta || !(sta->flags & WLAN_STA_WPS)) {
+		wpa_printf(MSG_DEBUG, "WPS UPnP: No matching STA found");
+		return 0;
+	}
+
+	p = os_zalloc(sizeof(*p));
+	if (p == NULL)
+		return -1;
+	os_memcpy(p->addr, sta->addr, ETH_ALEN);
+	p->msg = wpabuf_dup(msg);
+	p->type = msg_type;
+	p->next = hapd->wps->upnp_msgs;
+	hapd->wps->upnp_msgs = p;
+
+	return eapol_auth_eap_pending_cb(sta->eapol_sm, sta->eapol_sm->eap);
+}
+
+
+static int hostapd_wps_upnp_init(struct hostapd_data *hapd,
+				 struct wps_context *wps)
+{
+	struct upnp_wps_device_ctx *ctx;
+
+	if (!hapd->conf->upnp_iface)
+		return 0;
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return -1;
+
+	ctx->rx_req_put_wlan_response = hostapd_rx_req_put_wlan_response;
+	if (hapd->conf->ap_pin)
+		ctx->ap_pin = os_strdup(hapd->conf->ap_pin);
+
+	hapd->wps_upnp = upnp_wps_device_init(ctx, wps, hapd,
+					      hapd->conf->upnp_iface);
+	if (hapd->wps_upnp == NULL)
+		return -1;
+	wps->wps_upnp = hapd->wps_upnp;
+
+	return 0;
+}
+
+
+static void hostapd_wps_upnp_deinit(struct hostapd_data *hapd)
+{
+	upnp_wps_device_deinit(hapd->wps_upnp, hapd);
+}
+
+#endif /* CONFIG_WPS_UPNP */
+
+
+int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
+			    char *buf, size_t buflen)
+{
+	if (hapd->wps == NULL)
+		return 0;
+	return wps_registrar_get_info(hapd->wps->registrar, addr, buf, buflen);
+}
+
+
+static void hostapd_wps_ap_pin_timeout(void *eloop_data, void *user_ctx)
+{
+	struct hostapd_data *hapd = eloop_data;
+	wpa_printf(MSG_DEBUG, "WPS: AP PIN timed out");
+	hostapd_wps_ap_pin_disable(hapd);
+	wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_PIN_DISABLED);
+}
+
+
+static void hostapd_wps_ap_pin_enable(struct hostapd_data *hapd, int timeout)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Enabling AP PIN (timeout=%d)", timeout);
+	hapd->ap_pin_failures = 0;
+	hapd->ap_pin_failures_consecutive = 0;
+	hapd->conf->ap_setup_locked = 0;
+	if (hapd->wps->ap_setup_locked) {
+		wpa_msg(hapd->msg_ctx, MSG_INFO, WPS_EVENT_AP_SETUP_UNLOCKED);
+		hapd->wps->ap_setup_locked = 0;
+		wps_registrar_update_ie(hapd->wps->registrar);
+	}
+	eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
+	if (timeout > 0)
+		eloop_register_timeout(timeout, 0,
+				       hostapd_wps_ap_pin_timeout, hapd, NULL);
+}
+
+
+static int wps_ap_pin_disable(struct hostapd_data *hapd, void *ctx)
+{
+	os_free(hapd->conf->ap_pin);
+	hapd->conf->ap_pin = NULL;
+#ifdef CONFIG_WPS_UPNP
+	upnp_wps_set_ap_pin(hapd->wps_upnp, NULL);
+#endif /* CONFIG_WPS_UPNP */
+	eloop_cancel_timeout(hostapd_wps_ap_pin_timeout, hapd, NULL);
+	return 0;
+}
+
+
+void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd)
+{
+	wpa_printf(MSG_DEBUG, "WPS: Disabling AP PIN");
+	hostapd_wps_for_each(hapd, wps_ap_pin_disable, NULL);
+}
+
+
+struct wps_ap_pin_data {
+	char pin_txt[9];
+	int timeout;
+};
+
+
+static int wps_ap_pin_set(struct hostapd_data *hapd, void *ctx)
+{
+	struct wps_ap_pin_data *data = ctx;
+	os_free(hapd->conf->ap_pin);
+	hapd->conf->ap_pin = os_strdup(data->pin_txt);
+#ifdef CONFIG_WPS_UPNP
+	upnp_wps_set_ap_pin(hapd->wps_upnp, data->pin_txt);
+#endif /* CONFIG_WPS_UPNP */
+	hostapd_wps_ap_pin_enable(hapd, data->timeout);
+	return 0;
+}
+
+
+const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout)
+{
+	unsigned int pin;
+	struct wps_ap_pin_data data;
+
+	pin = wps_generate_pin();
+	os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%08u", pin);
+	data.timeout = timeout;
+	hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
+	return hapd->conf->ap_pin;
+}
+
+
+const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd)
+{
+	return hapd->conf->ap_pin;
+}
+
+
+int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
+			   int timeout)
+{
+	struct wps_ap_pin_data data;
+	int ret;
+
+	ret = os_snprintf(data.pin_txt, sizeof(data.pin_txt), "%s", pin);
+	if (ret < 0 || ret >= (int) sizeof(data.pin_txt))
+		return -1;
+	data.timeout = timeout;
+	return hostapd_wps_for_each(hapd, wps_ap_pin_set, &data);
+}
+
+
+static int wps_update_ie(struct hostapd_data *hapd, void *ctx)
+{
+	if (hapd->wps)
+		wps_registrar_update_ie(hapd->wps->registrar);
+	return 0;
+}
+
+
+void hostapd_wps_update_ie(struct hostapd_data *hapd)
+{
+	hostapd_wps_for_each(hapd, wps_update_ie, NULL);
+}
+
+
+int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
+			  const char *auth, const char *encr, const char *key)
+{
+	struct wps_credential cred;
+	size_t len;
+
+	os_memset(&cred, 0, sizeof(cred));
+
+	len = os_strlen(ssid);
+	if ((len & 1) || len > 2 * sizeof(cred.ssid) ||
+	    hexstr2bin(ssid, cred.ssid, len / 2))
+		return -1;
+	cred.ssid_len = len / 2;
+
+	if (os_strncmp(auth, "OPEN", 4) == 0)
+		cred.auth_type = WPS_AUTH_OPEN;
+	else if (os_strncmp(auth, "WPAPSK", 6) == 0)
+		cred.auth_type = WPS_AUTH_WPAPSK;
+	else if (os_strncmp(auth, "WPA2PSK", 7) == 0)
+		cred.auth_type = WPS_AUTH_WPA2PSK;
+	else
+		return -1;
+
+	if (encr) {
+		if (os_strncmp(encr, "NONE", 4) == 0)
+			cred.encr_type = WPS_ENCR_NONE;
+		else if (os_strncmp(encr, "WEP", 3) == 0)
+			cred.encr_type = WPS_ENCR_WEP;
+		else if (os_strncmp(encr, "TKIP", 4) == 0)
+			cred.encr_type = WPS_ENCR_TKIP;
+		else if (os_strncmp(encr, "CCMP", 4) == 0)
+			cred.encr_type = WPS_ENCR_AES;
+		else
+			return -1;
+	} else
+		cred.encr_type = WPS_ENCR_NONE;
+
+	if (key) {
+		len = os_strlen(key);
+		if ((len & 1) || len > 2 * sizeof(cred.key) ||
+		    hexstr2bin(key, cred.key, len / 2))
+			return -1;
+		cred.key_len = len / 2;
+	}
+
+	return wps_registrar_config_ap(hapd->wps->registrar, &cred);
+}
+
+
+#ifdef CONFIG_WPS_NFC
+
+struct wps_nfc_password_token_data {
+	const u8 *oob_dev_pw;
+	size_t oob_dev_pw_len;
+	int added;
+};
+
+
+static int wps_add_nfc_password_token(struct hostapd_data *hapd, void *ctx)
+{
+	struct wps_nfc_password_token_data *data = ctx;
+	int ret;
+
+	if (hapd->wps == NULL)
+		return 0;
+	ret = wps_registrar_add_nfc_password_token(hapd->wps->registrar,
+						   data->oob_dev_pw,
+						   data->oob_dev_pw_len);
+	if (ret == 0)
+		data->added++;
+	return ret;
+}
+
+
+static int hostapd_wps_add_nfc_password_token(struct hostapd_data *hapd,
+					      struct wps_parse_attr *attr)
+{
+	struct wps_nfc_password_token_data data;
+
+	data.oob_dev_pw = attr->oob_dev_password;
+	data.oob_dev_pw_len = attr->oob_dev_password_len;
+	data.added = 0;
+	if (hostapd_wps_for_each(hapd, wps_add_nfc_password_token, &data) < 0)
+		return -1;
+	return data.added ? 0 : -1;
+}
+
+
+static int hostapd_wps_nfc_tag_process(struct hostapd_data *hapd,
+				       const struct wpabuf *wps)
+{
+	struct wps_parse_attr attr;
+
+	wpa_hexdump_buf(MSG_DEBUG, "WPS: Received NFC tag payload", wps);
+
+	if (wps_parse_msg(wps, &attr)) {
+		wpa_printf(MSG_DEBUG, "WPS: Ignore invalid data from NFC tag");
+		return -1;
+	}
+
+	if (attr.oob_dev_password)
+		return hostapd_wps_add_nfc_password_token(hapd, &attr);
+
+	wpa_printf(MSG_DEBUG, "WPS: Ignore unrecognized NFC tag");
+	return -1;
+}
+
+
+int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
+			     const struct wpabuf *data)
+{
+	const struct wpabuf *wps = data;
+	struct wpabuf *tmp = NULL;
+	int ret;
+
+	if (wpabuf_len(data) < 4)
+		return -1;
+
+	if (*wpabuf_head_u8(data) != 0x10) {
+		/* Assume this contains full NDEF record */
+		tmp = ndef_parse_wifi(data);
+		if (tmp == NULL) {
+			wpa_printf(MSG_DEBUG, "WPS: Could not parse NDEF");
+			return -1;
+		}
+		wps = tmp;
+	}
+
+	ret = hostapd_wps_nfc_tag_process(hapd, wps);
+	wpabuf_free(tmp);
+	return ret;
+}
+
+
+struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
+					     int ndef)
+{
+	struct wpabuf *ret;
+
+	if (hapd->wps == NULL)
+		return NULL;
+
+	ret = wps_get_oob_cred(hapd->wps);
+	if (ndef && ret) {
+		struct wpabuf *tmp;
+		tmp = ndef_build_wifi(ret);
+		wpabuf_free(ret);
+		if (tmp == NULL)
+			return NULL;
+		ret = tmp;
+	}
+
+	return ret;
+}
+
+
+struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef)
+{
+	return wps_nfc_token_gen(ndef, &hapd->conf->wps_nfc_dev_pw_id,
+				 &hapd->conf->wps_nfc_dh_pubkey,
+				 &hapd->conf->wps_nfc_dh_privkey,
+				 &hapd->conf->wps_nfc_dev_pw);
+}
+
+
+int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd)
+{
+	struct wps_context *wps = hapd->wps;
+
+	if (wps == NULL)
+		return -1;
+
+	if (!hapd->conf->wps_nfc_dh_pubkey ||
+	    !hapd->conf->wps_nfc_dh_privkey ||
+	    !hapd->conf->wps_nfc_dev_pw ||
+	    !hapd->conf->wps_nfc_dev_pw_id)
+		return -1;
+
+	hostapd_wps_nfc_clear(wps);
+	wps->ap_nfc_dev_pw_id = hapd->conf->wps_nfc_dev_pw_id;
+	wps->ap_nfc_dh_pubkey = wpabuf_dup(hapd->conf->wps_nfc_dh_pubkey);
+	wps->ap_nfc_dh_privkey = wpabuf_dup(hapd->conf->wps_nfc_dh_privkey);
+	wps->ap_nfc_dev_pw = wpabuf_dup(hapd->conf->wps_nfc_dev_pw);
+
+	if (!wps->ap_nfc_dh_pubkey || !wps->ap_nfc_dh_privkey ||
+	    !wps->ap_nfc_dev_pw) {
+		hostapd_wps_nfc_clear(wps);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd)
+{
+	hostapd_wps_nfc_clear(hapd->wps);
+}
+
+#endif /* CONFIG_WPS_NFC */
diff --git a/hostap/src/ap/wps_hostapd.h b/hostap/src/ap/wps_hostapd.h
new file mode 100644
index 0000000..4e5026b
--- /dev/null
+++ b/hostap/src/ap/wps_hostapd.h
@@ -0,0 +1,83 @@
+/*
+ * hostapd / WPS integration
+ * Copyright (c) 2008-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPS_HOSTAPD_H
+#define WPS_HOSTAPD_H
+
+#ifdef CONFIG_WPS
+
+int hostapd_init_wps(struct hostapd_data *hapd,
+		     struct hostapd_bss_config *conf);
+int hostapd_init_wps_complete(struct hostapd_data *hapd);
+void hostapd_deinit_wps(struct hostapd_data *hapd);
+void hostapd_update_wps(struct hostapd_data *hapd);
+int hostapd_wps_add_pin(struct hostapd_data *hapd, const u8 *addr,
+			const char *uuid, const char *pin, int timeout);
+int hostapd_wps_button_pushed(struct hostapd_data *hapd,
+			      const u8 *p2p_dev_addr);
+int hostapd_wps_cancel(struct hostapd_data *hapd);
+int hostapd_wps_get_mib_sta(struct hostapd_data *hapd, const u8 *addr,
+			    char *buf, size_t buflen);
+void hostapd_wps_ap_pin_disable(struct hostapd_data *hapd);
+const char * hostapd_wps_ap_pin_random(struct hostapd_data *hapd, int timeout);
+const char * hostapd_wps_ap_pin_get(struct hostapd_data *hapd);
+int hostapd_wps_ap_pin_set(struct hostapd_data *hapd, const char *pin,
+			   int timeout);
+void hostapd_wps_update_ie(struct hostapd_data *hapd);
+int hostapd_wps_config_ap(struct hostapd_data *hapd, const char *ssid,
+			  const char *auth, const char *encr, const char *key);
+int hostapd_wps_nfc_tag_read(struct hostapd_data *hapd,
+			     const struct wpabuf *data);
+struct wpabuf * hostapd_wps_nfc_config_token(struct hostapd_data *hapd,
+					     int ndef);
+struct wpabuf * hostapd_wps_nfc_token_gen(struct hostapd_data *hapd, int ndef);
+int hostapd_wps_nfc_token_enable(struct hostapd_data *hapd);
+void hostapd_wps_nfc_token_disable(struct hostapd_data *hapd);
+
+#else /* CONFIG_WPS */
+
+static inline int hostapd_init_wps(struct hostapd_data *hapd,
+				   struct hostapd_bss_config *conf)
+{
+	return 0;
+}
+
+static inline void hostapd_deinit_wps(struct hostapd_data *hapd)
+{
+}
+
+static inline int hostapd_init_wps_complete(struct hostapd_data *hapd)
+{
+    return 0;
+}
+
+static inline void hostapd_update_wps(struct hostapd_data *hapd)
+{
+}
+
+static inline int hostapd_wps_get_mib_sta(struct hostapd_data *hapd,
+					  const u8 *addr,
+					  char *buf, size_t buflen)
+{
+	return 0;
+}
+
+static inline int hostapd_wps_button_pushed(struct hostapd_data *hapd,
+					    const u8 *p2p_dev_addr)
+{
+	return 0;
+}
+
+static inline int hostapd_wps_cancel(struct hostapd_data *hapd)
+{
+	return 0;
+}
+
+#endif /* CONFIG_WPS */
+
+#endif /* WPS_HOSTAPD_H */
diff --git a/hostap/src/common/Makefile b/hostap/src/common/Makefile
new file mode 100644
index 0000000..9c41962
--- /dev/null
+++ b/hostap/src/common/Makefile
@@ -0,0 +1,8 @@
+all:
+	@echo Nothing to be made.
+
+clean:
+	rm -f *~ *.o *.d
+
+install:
+	@echo Nothing to be made.
diff --git a/hostap/src/common/defs.h b/hostap/src/common/defs.h
new file mode 100644
index 0000000..281dd8a
--- /dev/null
+++ b/hostap/src/common/defs.h
@@ -0,0 +1,321 @@
+/*
+ * WPA Supplicant - Common definitions
+ * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DEFS_H
+#define DEFS_H
+
+#ifdef FALSE
+#undef FALSE
+#endif
+#ifdef TRUE
+#undef TRUE
+#endif
+typedef enum { FALSE = 0, TRUE = 1 } Boolean;
+
+
+#define WPA_CIPHER_NONE BIT(0)
+#define WPA_CIPHER_WEP40 BIT(1)
+#define WPA_CIPHER_WEP104 BIT(2)
+#define WPA_CIPHER_TKIP BIT(3)
+#define WPA_CIPHER_CCMP BIT(4)
+#ifdef CONFIG_IEEE80211W
+#define WPA_CIPHER_AES_128_CMAC BIT(5)
+#endif /* CONFIG_IEEE80211W */
+#define WPA_CIPHER_GCMP BIT(6)
+#define WPA_CIPHER_SMS4 BIT(7)
+
+#define WPA_KEY_MGMT_IEEE8021X BIT(0)
+#define WPA_KEY_MGMT_PSK BIT(1)
+#define WPA_KEY_MGMT_NONE BIT(2)
+#define WPA_KEY_MGMT_IEEE8021X_NO_WPA BIT(3)
+#define WPA_KEY_MGMT_WPA_NONE BIT(4)
+#define WPA_KEY_MGMT_FT_IEEE8021X BIT(5)
+#define WPA_KEY_MGMT_FT_PSK BIT(6)
+#define WPA_KEY_MGMT_IEEE8021X_SHA256 BIT(7)
+#define WPA_KEY_MGMT_PSK_SHA256 BIT(8)
+#define WPA_KEY_MGMT_WPS BIT(9)
+#define WPA_KEY_MGMT_SAE BIT(10)
+#define WPA_KEY_MGMT_FT_SAE BIT(11)
+#define WPA_KEY_MGMT_WAPI_PSK BIT(12)
+#define WPA_KEY_MGMT_WAPI_CERT BIT(13)
+#define WPA_KEY_MGMT_CCKM BIT(14)
+
+static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_IEEE8021X |
+			 WPA_KEY_MGMT_FT_IEEE8021X |
+			 WPA_KEY_MGMT_CCKM |
+			 WPA_KEY_MGMT_IEEE8021X_SHA256));
+}
+
+static inline int wpa_key_mgmt_wpa_psk(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_PSK |
+			 WPA_KEY_MGMT_FT_PSK |
+			 WPA_KEY_MGMT_PSK_SHA256 |
+			 WPA_KEY_MGMT_SAE));
+}
+
+static inline int wpa_key_mgmt_ft(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_FT_PSK |
+			 WPA_KEY_MGMT_FT_IEEE8021X |
+			 WPA_KEY_MGMT_FT_SAE));
+}
+
+static inline int wpa_key_mgmt_sae(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_SAE |
+			 WPA_KEY_MGMT_FT_SAE));
+}
+
+static inline int wpa_key_mgmt_sha256(int akm)
+{
+	return !!(akm & (WPA_KEY_MGMT_PSK_SHA256 |
+			 WPA_KEY_MGMT_IEEE8021X_SHA256));
+}
+
+static inline int wpa_key_mgmt_wpa(int akm)
+{
+	return wpa_key_mgmt_wpa_ieee8021x(akm) ||
+		wpa_key_mgmt_wpa_psk(akm);
+}
+
+static inline int wpa_key_mgmt_wpa_any(int akm)
+{
+	return wpa_key_mgmt_wpa(akm) || (akm & WPA_KEY_MGMT_WPA_NONE);
+}
+
+static inline int wpa_key_mgmt_cckm(int akm)
+{
+	return akm == WPA_KEY_MGMT_CCKM;
+}
+
+
+#define WPA_PROTO_WPA BIT(0)
+#define WPA_PROTO_RSN BIT(1)
+#define WPA_PROTO_WAPI BIT(2)
+
+#define WPA_AUTH_ALG_OPEN BIT(0)
+#define WPA_AUTH_ALG_SHARED BIT(1)
+#define WPA_AUTH_ALG_LEAP BIT(2)
+#define WPA_AUTH_ALG_FT BIT(3)
+#define WPA_AUTH_ALG_SAE BIT(4)
+
+
+enum wpa_alg {
+	WPA_ALG_NONE,
+	WPA_ALG_WEP,
+	WPA_ALG_TKIP,
+	WPA_ALG_CCMP,
+	WPA_ALG_IGTK,
+	WPA_ALG_PMK,
+	WPA_ALG_GCMP,
+	WPA_ALG_SMS4,
+	WPA_ALG_KRK
+};
+
+/**
+ * enum wpa_cipher - Cipher suites
+ */
+enum wpa_cipher {
+	CIPHER_NONE,
+	CIPHER_WEP40,
+	CIPHER_TKIP,
+	CIPHER_CCMP,
+	CIPHER_WEP104,
+	CIPHER_GCMP,
+	CIPHER_SMS4
+};
+
+/**
+ * enum wpa_key_mgmt - Key management suites
+ */
+enum wpa_key_mgmt {
+	KEY_MGMT_802_1X,
+	KEY_MGMT_PSK,
+	KEY_MGMT_NONE,
+	KEY_MGMT_802_1X_NO_WPA,
+	KEY_MGMT_WPA_NONE,
+	KEY_MGMT_FT_802_1X,
+	KEY_MGMT_FT_PSK,
+	KEY_MGMT_802_1X_SHA256,
+	KEY_MGMT_PSK_SHA256,
+	KEY_MGMT_WPS,
+	KEY_MGMT_SAE,
+	KEY_MGMT_FT_SAE,
+	KEY_MGMT_WAPI_PSK,
+	KEY_MGMT_WAPI_CERT,
+	KEY_MGMT_CCKM
+};
+
+/**
+ * enum wpa_states - wpa_supplicant state
+ *
+ * These enumeration values are used to indicate the current wpa_supplicant
+ * state (wpa_s->wpa_state). The current state can be retrieved with
+ * wpa_supplicant_get_state() function and the state can be changed by calling
+ * wpa_supplicant_set_state(). In WPA state machine (wpa.c and preauth.c), the
+ * wrapper functions wpa_sm_get_state() and wpa_sm_set_state() should be used
+ * to access the state variable.
+ */
+enum wpa_states {
+	/**
+	 * WPA_DISCONNECTED - Disconnected state
+	 *
+	 * This state indicates that client is not associated, but is likely to
+	 * start looking for an access point. This state is entered when a
+	 * connection is lost.
+	 */
+	WPA_DISCONNECTED,
+
+	/**
+	 * WPA_INTERFACE_DISABLED - Interface disabled
+	 *
+	 * This stat eis entered if the network interface is disabled, e.g.,
+	 * due to rfkill. wpa_supplicant refuses any new operations that would
+	 * use the radio until the interface has been enabled.
+	 */
+	WPA_INTERFACE_DISABLED,
+
+	/**
+	 * WPA_INACTIVE - Inactive state (wpa_supplicant disabled)
+	 *
+	 * This state is entered if there are no enabled networks in the
+	 * configuration. wpa_supplicant is not trying to associate with a new
+	 * network and external interaction (e.g., ctrl_iface call to add or
+	 * enable a network) is needed to start association.
+	 */
+	WPA_INACTIVE,
+
+	/**
+	 * WPA_SCANNING - Scanning for a network
+	 *
+	 * This state is entered when wpa_supplicant starts scanning for a
+	 * network.
+	 */
+	WPA_SCANNING,
+
+	/**
+	 * WPA_AUTHENTICATING - Trying to authenticate with a BSS/SSID
+	 *
+	 * This state is entered when wpa_supplicant has found a suitable BSS
+	 * to authenticate with and the driver is configured to try to
+	 * authenticate with this BSS. This state is used only with drivers
+	 * that use wpa_supplicant as the SME.
+	 */
+	WPA_AUTHENTICATING,
+
+	/**
+	 * WPA_ASSOCIATING - Trying to associate with a BSS/SSID
+	 *
+	 * This state is entered when wpa_supplicant has found a suitable BSS
+	 * to associate with and the driver is configured to try to associate
+	 * with this BSS in ap_scan=1 mode. When using ap_scan=2 mode, this
+	 * state is entered when the driver is configured to try to associate
+	 * with a network using the configured SSID and security policy.
+	 */
+	WPA_ASSOCIATING,
+
+	/**
+	 * WPA_ASSOCIATED - Association completed
+	 *
+	 * This state is entered when the driver reports that association has
+	 * been successfully completed with an AP. If IEEE 802.1X is used
+	 * (with or without WPA/WPA2), wpa_supplicant remains in this state
+	 * until the IEEE 802.1X/EAPOL authentication has been completed.
+	 */
+	WPA_ASSOCIATED,
+
+	/**
+	 * WPA_4WAY_HANDSHAKE - WPA 4-Way Key Handshake in progress
+	 *
+	 * This state is entered when WPA/WPA2 4-Way Handshake is started. In
+	 * case of WPA-PSK, this happens when receiving the first EAPOL-Key
+	 * frame after association. In case of WPA-EAP, this state is entered
+	 * when the IEEE 802.1X/EAPOL authentication has been completed.
+	 */
+	WPA_4WAY_HANDSHAKE,
+
+	/**
+	 * WPA_GROUP_HANDSHAKE - WPA Group Key Handshake in progress
+	 *
+	 * This state is entered when 4-Way Key Handshake has been completed
+	 * (i.e., when the supplicant sends out message 4/4) and when Group
+	 * Key rekeying is started by the AP (i.e., when supplicant receives
+	 * message 1/2).
+	 */
+	WPA_GROUP_HANDSHAKE,
+
+	/**
+	 * WPA_COMPLETED - All authentication completed
+	 *
+	 * This state is entered when the full authentication process is
+	 * completed. In case of WPA2, this happens when the 4-Way Handshake is
+	 * successfully completed. With WPA, this state is entered after the
+	 * Group Key Handshake; with IEEE 802.1X (non-WPA) connection is
+	 * completed after dynamic keys are received (or if not used, after
+	 * the EAP authentication has been completed). With static WEP keys and
+	 * plaintext connections, this state is entered when an association
+	 * has been completed.
+	 *
+	 * This state indicates that the supplicant has completed its
+	 * processing for the association phase and that data connection is
+	 * fully configured.
+	 */
+	WPA_COMPLETED
+};
+
+#define MLME_SETPROTECTION_PROTECT_TYPE_NONE 0
+#define MLME_SETPROTECTION_PROTECT_TYPE_RX 1
+#define MLME_SETPROTECTION_PROTECT_TYPE_TX 2
+#define MLME_SETPROTECTION_PROTECT_TYPE_RX_TX 3
+
+#define MLME_SETPROTECTION_KEY_TYPE_GROUP 0
+#define MLME_SETPROTECTION_KEY_TYPE_PAIRWISE 1
+
+
+/**
+ * enum mfp_options - Management frame protection (IEEE 802.11w) options
+ */
+enum mfp_options {
+	NO_MGMT_FRAME_PROTECTION = 0,
+	MGMT_FRAME_PROTECTION_OPTIONAL = 1,
+	MGMT_FRAME_PROTECTION_REQUIRED = 2,
+};
+#define MGMT_FRAME_PROTECTION_DEFAULT 3
+
+/**
+ * enum hostapd_hw_mode - Hardware mode
+ */
+enum hostapd_hw_mode {
+	HOSTAPD_MODE_IEEE80211B,
+	HOSTAPD_MODE_IEEE80211G,
+	HOSTAPD_MODE_IEEE80211A,
+	HOSTAPD_MODE_IEEE80211AD,
+	NUM_HOSTAPD_MODES
+};
+
+/**
+ * enum wpa_ctrl_req_type - Control interface request types
+ */
+enum wpa_ctrl_req_type {
+	WPA_CTRL_REQ_UNKNOWN,
+	WPA_CTRL_REQ_EAP_IDENTITY,
+	WPA_CTRL_REQ_EAP_PASSWORD,
+	WPA_CTRL_REQ_EAP_NEW_PASSWORD,
+	WPA_CTRL_REQ_EAP_PIN,
+	WPA_CTRL_REQ_EAP_OTP,
+	WPA_CTRL_REQ_EAP_PASSPHRASE,
+	NUM_WPA_CTRL_REQS
+};
+
+/* Maximum number of EAP methods to store for EAP server user information */
+#define EAP_MAX_METHODS 8
+
+#endif /* DEFS_H */
diff --git a/hostap/src/common/eapol_common.h b/hostap/src/common/eapol_common.h
new file mode 100644
index 0000000..4811f38
--- /dev/null
+++ b/hostap/src/common/eapol_common.h
@@ -0,0 +1,81 @@
+/*
+ * EAPOL definitions shared between hostapd and wpa_supplicant
+ * Copyright (c) 2002-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef EAPOL_COMMON_H
+#define EAPOL_COMMON_H
+
+/* IEEE Std 802.1X-2004 */
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct ieee802_1x_hdr {
+	u8 version;
+	u8 type;
+	be16 length;
+	/* followed by length octets of data */
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#define EAPOL_VERSION 2
+
+enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
+       IEEE802_1X_TYPE_EAPOL_START = 1,
+       IEEE802_1X_TYPE_EAPOL_LOGOFF = 2,
+       IEEE802_1X_TYPE_EAPOL_KEY = 3,
+       IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4
+};
+
+enum { EAPOL_KEY_TYPE_RC4 = 1, EAPOL_KEY_TYPE_RSN = 2,
+       EAPOL_KEY_TYPE_WPA = 254 };
+
+
+#define IEEE8021X_REPLAY_COUNTER_LEN 8
+#define IEEE8021X_KEY_SIGN_LEN 16
+#define IEEE8021X_KEY_IV_LEN 16
+
+#define IEEE8021X_KEY_INDEX_FLAG 0x80
+#define IEEE8021X_KEY_INDEX_MASK 0x03
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct ieee802_1x_eapol_key {
+	u8 type;
+	/* Note: key_length is unaligned */
+	u8 key_length[2];
+	/* does not repeat within the life of the keying material used to
+	 * encrypt the Key field; 64-bit NTP timestamp MAY be used here */
+	u8 replay_counter[IEEE8021X_REPLAY_COUNTER_LEN];
+	u8 key_iv[IEEE8021X_KEY_IV_LEN]; /* cryptographically random number */
+	u8 key_index; /* key flag in the most significant bit:
+		       * 0 = broadcast (default key),
+		       * 1 = unicast (key mapping key); key index is in the
+		       * 7 least significant bits */
+	/* HMAC-MD5 message integrity check computed with MS-MPPE-Send-Key as
+	 * the key */
+	u8 key_signature[IEEE8021X_KEY_SIGN_LEN];
+
+	/* followed by key: if packet body length = 44 + key length, then the
+	 * key field (of key_length bytes) contains the key in encrypted form;
+	 * if packet body length = 44, key field is absent and key_length
+	 * represents the number of least significant octets from
+	 * MS-MPPE-Send-Key attribute to be used as the keying material;
+	 * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#endif /* EAPOL_COMMON_H */
diff --git a/hostap/src/common/gas.c b/hostap/src/common/gas.c
new file mode 100644
index 0000000..cff9254
--- /dev/null
+++ b/hostap/src/common/gas.c
@@ -0,0 +1,273 @@
+/*
+ * Generic advertisement service (GAS) (IEEE 802.11u)
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011-2012, Qualcomm Atheros
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "ieee802_11_defs.h"
+#include "gas.h"
+
+
+static struct wpabuf *
+gas_build_req(u8 action, u8 dialog_token, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(100 + size);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+	wpabuf_put_u8(buf, action);
+	wpabuf_put_u8(buf, dialog_token);
+
+	return buf;
+}
+
+
+struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size)
+{
+	return gas_build_req(WLAN_PA_GAS_INITIAL_REQ, dialog_token,
+			     size);
+}
+
+
+struct wpabuf * gas_build_comeback_req(u8 dialog_token)
+{
+	return gas_build_req(WLAN_PA_GAS_COMEBACK_REQ, dialog_token, 0);
+}
+
+
+static struct wpabuf *
+gas_build_resp(u8 action, u8 dialog_token, u16 status_code, u8 frag_id,
+	       u8 more, u16 comeback_delay, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = wpabuf_alloc(100 + size);
+	if (buf == NULL)
+		return NULL;
+
+	wpabuf_put_u8(buf, WLAN_ACTION_PUBLIC);
+	wpabuf_put_u8(buf, action);
+	wpabuf_put_u8(buf, dialog_token);
+	wpabuf_put_le16(buf, status_code);
+	if (action == WLAN_PA_GAS_COMEBACK_RESP)
+		wpabuf_put_u8(buf, frag_id | (more ? 0x80 : 0));
+	wpabuf_put_le16(buf, comeback_delay);
+
+	return buf;
+}
+
+
+struct wpabuf *
+gas_build_initial_resp(u8 dialog_token, u16 status_code, u16 comeback_delay,
+		       size_t size)
+{
+	return gas_build_resp(WLAN_PA_GAS_INITIAL_RESP, dialog_token,
+			      status_code, 0, 0, comeback_delay, size);
+}
+
+
+static struct wpabuf *
+gas_build_comeback_resp(u8 dialog_token, u16 status_code, u8 frag_id, u8 more,
+			u16 comeback_delay, size_t size)
+{
+	return gas_build_resp(WLAN_PA_GAS_COMEBACK_RESP, dialog_token,
+			      status_code, frag_id, more, comeback_delay,
+			      size);
+}
+
+
+/**
+ * gas_add_adv_proto_anqp - Add an Advertisement Protocol element
+ * @buf: Buffer to which the element is added
+ * @query_resp_len_limit: Query Response Length Limit in units of 256 octets
+ * @pame_bi: Pre-Association Message Exchange BSSID Independent (0/1)
+ *
+ *
+ * @query_resp_len_limit is 0 for request and 1-0x7f for response. 0x7f means
+ * that the maximum limit is determined by the maximum allowable number of
+ * fragments in the GAS Query Response Fragment ID.
+ */
+static void gas_add_adv_proto_anqp(struct wpabuf *buf, u8 query_resp_len_limit,
+				   u8 pame_bi)
+{
+	/* Advertisement Protocol IE */
+	wpabuf_put_u8(buf, WLAN_EID_ADV_PROTO);
+	wpabuf_put_u8(buf, 2); /* Length */
+	wpabuf_put_u8(buf, (query_resp_len_limit & 0x7f) |
+		      (pame_bi ? 0x80 : 0));
+	/* Advertisement Protocol */
+	wpabuf_put_u8(buf, ACCESS_NETWORK_QUERY_PROTOCOL);
+}
+
+
+struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = gas_build_initial_req(dialog_token, 4 + size);
+	if (buf == NULL)
+		return NULL;
+
+	gas_add_adv_proto_anqp(buf, 0, 0);
+
+	wpabuf_put(buf, 2); /* Query Request Length to be filled */
+
+	return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
+					    u16 comeback_delay, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = gas_build_initial_resp(dialog_token, status_code, comeback_delay,
+				     4 + size);
+	if (buf == NULL)
+		return NULL;
+
+	gas_add_adv_proto_anqp(buf, 0x7f, 0);
+
+	wpabuf_put(buf, 2); /* Query Response Length to be filled */
+
+	return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
+						u16 status_code,
+						u16 comeback_delay,
+						struct wpabuf *payload)
+{
+	struct wpabuf *buf;
+
+	buf = gas_anqp_build_initial_resp(dialog_token, status_code,
+					  comeback_delay,
+					  payload ? wpabuf_len(payload) : 0);
+	if (buf == NULL)
+		return NULL;
+
+	if (payload)
+		wpabuf_put_buf(buf, payload);
+
+	gas_anqp_set_len(buf);
+
+	return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
+					     u8 frag_id, u8 more,
+					     u16 comeback_delay, size_t size)
+{
+	struct wpabuf *buf;
+
+	buf = gas_build_comeback_resp(dialog_token, status_code,
+				      frag_id, more, comeback_delay, 4 + size);
+	if (buf == NULL)
+		return NULL;
+
+	gas_add_adv_proto_anqp(buf, 0x7f, 0);
+
+	wpabuf_put(buf, 2); /* Query Response Length to be filled */
+
+	return buf;
+}
+
+
+struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
+						 u16 status_code,
+						 u8 frag_id, u8 more,
+						 u16 comeback_delay,
+						 struct wpabuf *payload)
+{
+	struct wpabuf *buf;
+
+	buf = gas_anqp_build_comeback_resp(dialog_token, status_code, frag_id,
+					   more, comeback_delay,
+					   payload ? wpabuf_len(payload) : 0);
+	if (buf == NULL)
+		return NULL;
+
+	if (payload)
+		wpabuf_put_buf(buf, payload);
+
+	gas_anqp_set_len(buf);
+
+	return buf;
+}
+
+
+/**
+ * gas_anqp_set_len - Set Query Request/Response Length
+ * @buf: GAS message
+ *
+ * This function is used to update the Query Request/Response Length field once
+ * the payload has been filled.
+ */
+void gas_anqp_set_len(struct wpabuf *buf)
+{
+	u8 action;
+	size_t offset;
+	u8 *len;
+
+	if (buf == NULL || wpabuf_len(buf) < 2)
+		return;
+
+	action = *(wpabuf_head_u8(buf) + 1);
+	switch (action) {
+	case WLAN_PA_GAS_INITIAL_REQ:
+		offset = 3 + 4;
+		break;
+	case WLAN_PA_GAS_INITIAL_RESP:
+		offset = 7 + 4;
+		break;
+	case WLAN_PA_GAS_COMEBACK_RESP:
+		offset = 8 + 4;
+		break;
+	default:
+		return;
+	}
+
+	if (wpabuf_len(buf) < offset + 2)
+		return;
+
+	len = wpabuf_mhead_u8(buf) + offset;
+	WPA_PUT_LE16(len, (u8 *) wpabuf_put(buf, 0) - len - 2);
+}
+
+
+/**
+ * gas_anqp_add_element - Add ANQP element header
+ * @buf: GAS message
+ * @info_id: ANQP Info ID
+ * Returns: Pointer to the Length field for gas_anqp_set_element_len()
+ */
+u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id)
+{
+	wpabuf_put_le16(buf, info_id);
+	return wpabuf_put(buf, 2); /* Length to be filled */
+}
+
+
+/**
+ * gas_anqp_set_element_len - Update ANQP element Length field
+ * @buf: GAS message
+ * @len_pos: Length field position from gas_anqp_add_element()
+ *
+ * This function is called after the ANQP element payload has been added to the
+ * buffer.
+ */
+void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos)
+{
+	WPA_PUT_LE16(len_pos, (u8 *) wpabuf_put(buf, 0) - len_pos - 2);
+}
diff --git a/hostap/src/common/gas.h b/hostap/src/common/gas.h
new file mode 100644
index 0000000..306adc5
--- /dev/null
+++ b/hostap/src/common/gas.h
@@ -0,0 +1,37 @@
+/*
+ * Generic advertisement service (GAS) (IEEE 802.11u)
+ * Copyright (c) 2009, Atheros Communications
+ * Copyright (c) 2011-2012, Qualcomm Atheros
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef GAS_H
+#define GAS_H
+
+struct wpabuf * gas_build_initial_req(u8 dialog_token, size_t size);
+struct wpabuf * gas_build_comeback_req(u8 dialog_token);
+struct wpabuf * gas_build_initial_resp(u8 dialog_token, u16 status_code,
+				       u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_initial_req(u8 dialog_token, size_t size);
+struct wpabuf * gas_anqp_build_initial_resp(u8 dialog_token, u16 status_code,
+					    u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_initial_resp_buf(u8 dialog_token,
+						u16 status_code,
+						u16 comeback_delay,
+						struct wpabuf *payload);
+struct wpabuf * gas_anqp_build_comeback_resp(u8 dialog_token, u16 status_code,
+					     u8 frag_id, u8 more,
+					     u16 comeback_delay, size_t size);
+struct wpabuf * gas_anqp_build_comeback_resp_buf(u8 dialog_token,
+						 u16 status_code,
+						 u8 frag_id, u8 more,
+						 u16 comeback_delay,
+						 struct wpabuf *payload);
+void gas_anqp_set_len(struct wpabuf *buf);
+
+u8 * gas_anqp_add_element(struct wpabuf *buf, u16 info_id);
+void gas_anqp_set_element_len(struct wpabuf *buf, u8 *len_pos);
+
+#endif /* GAS_H */
diff --git a/hostap/src/common/ieee802_11_common.c b/hostap/src/common/ieee802_11_common.c
new file mode 100644
index 0000000..98fadda
--- /dev/null
+++ b/hostap/src/common/ieee802_11_common.c
@@ -0,0 +1,488 @@
+/*
+ * IEEE 802.11 Common routines
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "ieee802_11_defs.h"
+#include "ieee802_11_common.h"
+
+
+static int ieee802_11_parse_vendor_specific(const u8 *pos, size_t elen,
+					    struct ieee802_11_elems *elems,
+					    int show_errors)
+{
+	unsigned int oui;
+
+	/* first 3 bytes in vendor specific information element are the IEEE
+	 * OUI of the vendor. The following byte is used a vendor specific
+	 * sub-type. */
+	if (elen < 4) {
+		if (show_errors) {
+			wpa_printf(MSG_MSGDUMP, "short vendor specific "
+				   "information element ignored (len=%lu)",
+				   (unsigned long) elen);
+		}
+		return -1;
+	}
+
+	oui = WPA_GET_BE24(pos);
+	switch (oui) {
+	case OUI_MICROSOFT:
+		/* Microsoft/Wi-Fi information elements are further typed and
+		 * subtyped */
+		switch (pos[3]) {
+		case 1:
+			/* Microsoft OUI (00:50:F2) with OUI Type 1:
+			 * real WPA information element */
+			elems->wpa_ie = pos;
+			elems->wpa_ie_len = elen;
+			break;
+		case WMM_OUI_TYPE:
+			/* WMM information element */
+			if (elen < 5) {
+				wpa_printf(MSG_MSGDUMP, "short WMM "
+					   "information element ignored "
+					   "(len=%lu)",
+					   (unsigned long) elen);
+				return -1;
+			}
+			switch (pos[4]) {
+			case WMM_OUI_SUBTYPE_INFORMATION_ELEMENT:
+			case WMM_OUI_SUBTYPE_PARAMETER_ELEMENT:
+				/*
+				 * Share same pointer since only one of these
+				 * is used and they start with same data.
+				 * Length field can be used to distinguish the
+				 * IEs.
+				 */
+				elems->wmm = pos;
+				elems->wmm_len = elen;
+				break;
+			case WMM_OUI_SUBTYPE_TSPEC_ELEMENT:
+				elems->wmm_tspec = pos;
+				elems->wmm_tspec_len = elen;
+				break;
+			default:
+				wpa_printf(MSG_EXCESSIVE, "unknown WMM "
+					   "information element ignored "
+					   "(subtype=%d len=%lu)",
+					   pos[4], (unsigned long) elen);
+				return -1;
+			}
+			break;
+		case 4:
+			/* Wi-Fi Protected Setup (WPS) IE */
+			elems->wps_ie = pos;
+			elems->wps_ie_len = elen;
+			break;
+		default:
+			wpa_printf(MSG_EXCESSIVE, "Unknown Microsoft "
+				   "information element ignored "
+				   "(type=%d len=%lu)",
+				   pos[3], (unsigned long) elen);
+			return -1;
+		}
+		break;
+
+	case OUI_WFA:
+		switch (pos[3]) {
+		case P2P_OUI_TYPE:
+			/* Wi-Fi Alliance - P2P IE */
+			elems->p2p = pos;
+			elems->p2p_len = elen;
+			break;
+		case WFD_OUI_TYPE:
+			/* Wi-Fi Alliance - WFD IE */
+			elems->wfd = pos;
+			elems->wfd_len = elen;
+			break;
+		case HS20_INDICATION_OUI_TYPE:
+			/* Hotspot 2.0 */
+			elems->hs20 = pos;
+			elems->hs20_len = elen;
+			break;
+		default:
+			wpa_printf(MSG_MSGDUMP, "Unknown WFA "
+				   "information element ignored "
+				   "(type=%d len=%lu)\n",
+				   pos[3], (unsigned long) elen);
+			return -1;
+		}
+		break;
+
+	case OUI_BROADCOM:
+		switch (pos[3]) {
+		case VENDOR_HT_CAPAB_OUI_TYPE:
+			elems->vendor_ht_cap = pos;
+			elems->vendor_ht_cap_len = elen;
+			break;
+		default:
+			wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
+				   "information element ignored "
+				   "(type=%d len=%lu)",
+				   pos[3], (unsigned long) elen);
+			return -1;
+		}
+		break;
+
+	default:
+		wpa_printf(MSG_EXCESSIVE, "unknown vendor specific "
+			   "information element ignored (vendor OUI "
+			   "%02x:%02x:%02x len=%lu)",
+			   pos[0], pos[1], pos[2], (unsigned long) elen);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * ieee802_11_parse_elems - Parse information elements in management frames
+ * @start: Pointer to the start of IEs
+ * @len: Length of IE buffer in octets
+ * @elems: Data structure for parsed elements
+ * @show_errors: Whether to show parsing errors in debug log
+ * Returns: Parsing result
+ */
+ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
+				struct ieee802_11_elems *elems,
+				int show_errors)
+{
+	size_t left = len;
+	const u8 *pos = start;
+	int unknown = 0;
+
+	os_memset(elems, 0, sizeof(*elems));
+
+	while (left >= 2) {
+		u8 id, elen;
+
+		id = *pos++;
+		elen = *pos++;
+		left -= 2;
+
+		if (elen > left) {
+			if (show_errors) {
+				wpa_printf(MSG_DEBUG, "IEEE 802.11 element "
+					   "parse failed (id=%d elen=%d "
+					   "left=%lu)",
+					   id, elen, (unsigned long) left);
+				wpa_hexdump(MSG_MSGDUMP, "IEs", start, len);
+			}
+			return ParseFailed;
+		}
+
+		switch (id) {
+		case WLAN_EID_SSID:
+			elems->ssid = pos;
+			elems->ssid_len = elen;
+			break;
+		case WLAN_EID_SUPP_RATES:
+			elems->supp_rates = pos;
+			elems->supp_rates_len = elen;
+			break;
+		case WLAN_EID_FH_PARAMS:
+			elems->fh_params = pos;
+			elems->fh_params_len = elen;
+			break;
+		case WLAN_EID_DS_PARAMS:
+			elems->ds_params = pos;
+			elems->ds_params_len = elen;
+			break;
+		case WLAN_EID_CF_PARAMS:
+			elems->cf_params = pos;
+			elems->cf_params_len = elen;
+			break;
+		case WLAN_EID_TIM:
+			elems->tim = pos;
+			elems->tim_len = elen;
+			break;
+		case WLAN_EID_IBSS_PARAMS:
+			elems->ibss_params = pos;
+			elems->ibss_params_len = elen;
+			break;
+		case WLAN_EID_CHALLENGE:
+			elems->challenge = pos;
+			elems->challenge_len = elen;
+			break;
+		case WLAN_EID_ERP_INFO:
+			elems->erp_info = pos;
+			elems->erp_info_len = elen;
+			break;
+		case WLAN_EID_EXT_SUPP_RATES:
+			elems->ext_supp_rates = pos;
+			elems->ext_supp_rates_len = elen;
+			break;
+		case WLAN_EID_VENDOR_SPECIFIC:
+			if (ieee802_11_parse_vendor_specific(pos, elen,
+							     elems,
+							     show_errors))
+				unknown++;
+			break;
+		case WLAN_EID_RSN:
+			elems->rsn_ie = pos;
+			elems->rsn_ie_len = elen;
+			break;
+		case WLAN_EID_PWR_CAPABILITY:
+			elems->power_cap = pos;
+			elems->power_cap_len = elen;
+			break;
+		case WLAN_EID_SUPPORTED_CHANNELS:
+			elems->supp_channels = pos;
+			elems->supp_channels_len = elen;
+			break;
+		case WLAN_EID_MOBILITY_DOMAIN:
+			elems->mdie = pos;
+			elems->mdie_len = elen;
+			break;
+		case WLAN_EID_FAST_BSS_TRANSITION:
+			elems->ftie = pos;
+			elems->ftie_len = elen;
+			break;
+		case WLAN_EID_TIMEOUT_INTERVAL:
+			elems->timeout_int = pos;
+			elems->timeout_int_len = elen;
+			break;
+		case WLAN_EID_HT_CAP:
+			elems->ht_capabilities = pos;
+			elems->ht_capabilities_len = elen;
+			break;
+		case WLAN_EID_HT_OPERATION:
+			elems->ht_operation = pos;
+			elems->ht_operation_len = elen;
+			break;
+		case WLAN_EID_VHT_CAP:
+			elems->vht_capabilities = pos;
+			elems->vht_capabilities_len = elen;
+			break;
+		case WLAN_EID_VHT_OPERATION:
+			elems->vht_operation = pos;
+			elems->vht_operation_len = elen;
+			break;
+		case WLAN_EID_LINK_ID:
+			if (elen < 18)
+				break;
+			elems->link_id = pos;
+			break;
+		case WLAN_EID_INTERWORKING:
+			elems->interworking = pos;
+			elems->interworking_len = elen;
+			break;
+		case WLAN_EID_EXT_CAPAB:
+			elems->ext_capab = pos;
+			elems->ext_capab_len = elen;
+			break;
+		case WLAN_EID_BSS_MAX_IDLE_PERIOD:
+			if (elen < 3)
+				break;
+			elems->bss_max_idle_period = pos;
+			break;
+		case WLAN_EID_SSID_LIST:
+			elems->ssid_list = pos;
+			elems->ssid_list_len = elen;
+			break;
+		default:
+			unknown++;
+			if (!show_errors)
+				break;
+			wpa_printf(MSG_MSGDUMP, "IEEE 802.11 element parse "
+				   "ignored unknown element (id=%d elen=%d)",
+				   id, elen);
+			break;
+		}
+
+		left -= elen;
+		pos += elen;
+	}
+
+	if (left)
+		return ParseFailed;
+
+	return unknown ? ParseUnknown : ParseOK;
+}
+
+
+int ieee802_11_ie_count(const u8 *ies, size_t ies_len)
+{
+	int count = 0;
+	const u8 *pos, *end;
+
+	if (ies == NULL)
+		return 0;
+
+	pos = ies;
+	end = ies + ies_len;
+
+	while (pos + 2 <= end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		count++;
+		pos += 2 + pos[1];
+	}
+
+	return count;
+}
+
+
+struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
+					    u32 oui_type)
+{
+	struct wpabuf *buf;
+	const u8 *end, *pos, *ie;
+
+	pos = ies;
+	end = ies + ies_len;
+	ie = NULL;
+
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			return NULL;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    WPA_GET_BE32(&pos[2]) == oui_type) {
+			ie = pos;
+			break;
+		}
+		pos += 2 + pos[1];
+	}
+
+	if (ie == NULL)
+		return NULL; /* No specified vendor IE found */
+
+	buf = wpabuf_alloc(ies_len);
+	if (buf == NULL)
+		return NULL;
+
+	/*
+	 * There may be multiple vendor IEs in the message, so need to
+	 * concatenate their data fields.
+	 */
+	while (pos + 1 < end) {
+		if (pos + 2 + pos[1] > end)
+			break;
+		if (pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
+		    WPA_GET_BE32(&pos[2]) == oui_type)
+			wpabuf_put_data(buf, pos + 6, pos[1] - 4);
+		pos += 2 + pos[1];
+	}
+
+	return buf;
+}
+
+
+const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len)
+{
+	u16 fc, type, stype;
+
+	/*
+	 * PS-Poll frames are 16 bytes. All other frames are
+	 * 24 bytes or longer.
+	 */
+	if (len < 16)
+		return NULL;
+
+	fc = le_to_host16(hdr->frame_control);
+	type = WLAN_FC_GET_TYPE(fc);
+	stype = WLAN_FC_GET_STYPE(fc);
+
+	switch (type) {
+	case WLAN_FC_TYPE_DATA:
+		if (len < 24)
+			return NULL;
+		switch (fc & (WLAN_FC_FROMDS | WLAN_FC_TODS)) {
+		case WLAN_FC_FROMDS | WLAN_FC_TODS:
+		case WLAN_FC_TODS:
+			return hdr->addr1;
+		case WLAN_FC_FROMDS:
+			return hdr->addr2;
+		default:
+			return NULL;
+		}
+	case WLAN_FC_TYPE_CTRL:
+		if (stype != WLAN_FC_STYPE_PSPOLL)
+			return NULL;
+		return hdr->addr1;
+	case WLAN_FC_TYPE_MGMT:
+		return hdr->addr3;
+	default:
+		return NULL;
+	}
+}
+
+
+int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
+			  const char *name, const char *val)
+{
+	int num, v;
+	const char *pos;
+	struct hostapd_wmm_ac_params *ac;
+
+	/* skip 'wme_ac_' or 'wmm_ac_' prefix */
+	pos = name + 7;
+	if (os_strncmp(pos, "be_", 3) == 0) {
+		num = 0;
+		pos += 3;
+	} else if (os_strncmp(pos, "bk_", 3) == 0) {
+		num = 1;
+		pos += 3;
+	} else if (os_strncmp(pos, "vi_", 3) == 0) {
+		num = 2;
+		pos += 3;
+	} else if (os_strncmp(pos, "vo_", 3) == 0) {
+		num = 3;
+		pos += 3;
+	} else {
+		wpa_printf(MSG_ERROR, "Unknown WMM name '%s'", pos);
+		return -1;
+	}
+
+	ac = &wmm_ac_params[num];
+
+	if (os_strcmp(pos, "aifs") == 0) {
+		v = atoi(val);
+		if (v < 1 || v > 255) {
+			wpa_printf(MSG_ERROR, "Invalid AIFS value %d", v);
+			return -1;
+		}
+		ac->aifs = v;
+	} else if (os_strcmp(pos, "cwmin") == 0) {
+		v = atoi(val);
+		if (v < 0 || v > 12) {
+			wpa_printf(MSG_ERROR, "Invalid cwMin value %d", v);
+			return -1;
+		}
+		ac->cwmin = v;
+	} else if (os_strcmp(pos, "cwmax") == 0) {
+		v = atoi(val);
+		if (v < 0 || v > 12) {
+			wpa_printf(MSG_ERROR, "Invalid cwMax value %d", v);
+			return -1;
+		}
+		ac->cwmax = v;
+	} else if (os_strcmp(pos, "txop_limit") == 0) {
+		v = atoi(val);
+		if (v < 0 || v > 0xffff) {
+			wpa_printf(MSG_ERROR, "Invalid txop value %d", v);
+			return -1;
+		}
+		ac->txop_limit = v;
+	} else if (os_strcmp(pos, "acm") == 0) {
+		v = atoi(val);
+		if (v < 0 || v > 1) {
+			wpa_printf(MSG_ERROR, "Invalid acm value %d", v);
+			return -1;
+		}
+		ac->admission_control_mandatory = v;
+	} else {
+		wpa_printf(MSG_ERROR, "Unknown wmm_ac_ field '%s'", pos);
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/hostap/src/common/ieee802_11_common.h b/hostap/src/common/ieee802_11_common.h
new file mode 100644
index 0000000..55fa49d
--- /dev/null
+++ b/hostap/src/common/ieee802_11_common.h
@@ -0,0 +1,103 @@
+/*
+ * IEEE 802.11 Common routines
+ * Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_11_COMMON_H
+#define IEEE802_11_COMMON_H
+
+/* Parsed Information Elements */
+struct ieee802_11_elems {
+	const u8 *ssid;
+	const u8 *supp_rates;
+	const u8 *fh_params;
+	const u8 *ds_params;
+	const u8 *cf_params;
+	const u8 *tim;
+	const u8 *ibss_params;
+	const u8 *challenge;
+	const u8 *erp_info;
+	const u8 *ext_supp_rates;
+	const u8 *wpa_ie;
+	const u8 *rsn_ie;
+	const u8 *wmm; /* WMM Information or Parameter Element */
+	const u8 *wmm_tspec;
+	const u8 *wps_ie;
+	const u8 *power_cap;
+	const u8 *supp_channels;
+	const u8 *mdie;
+	const u8 *ftie;
+	const u8 *timeout_int;
+	const u8 *ht_capabilities;
+	const u8 *ht_operation;
+	const u8 *vht_capabilities;
+	const u8 *vht_operation;
+	const u8 *vendor_ht_cap;
+	const u8 *p2p;
+	const u8 *wfd;
+	const u8 *link_id;
+	const u8 *interworking;
+	const u8 *hs20;
+	const u8 *ext_capab;
+	const u8 *bss_max_idle_period;
+	const u8 *ssid_list;
+
+	u8 ssid_len;
+	u8 supp_rates_len;
+	u8 fh_params_len;
+	u8 ds_params_len;
+	u8 cf_params_len;
+	u8 tim_len;
+	u8 ibss_params_len;
+	u8 challenge_len;
+	u8 erp_info_len;
+	u8 ext_supp_rates_len;
+	u8 wpa_ie_len;
+	u8 rsn_ie_len;
+	u8 wmm_len; /* 7 = WMM Information; 24 = WMM Parameter */
+	u8 wmm_tspec_len;
+	u8 wps_ie_len;
+	u8 power_cap_len;
+	u8 supp_channels_len;
+	u8 mdie_len;
+	u8 ftie_len;
+	u8 timeout_int_len;
+	u8 ht_capabilities_len;
+	u8 ht_operation_len;
+	u8 vht_capabilities_len;
+	u8 vht_operation_len;
+	u8 vendor_ht_cap_len;
+	u8 p2p_len;
+	u8 wfd_len;
+	u8 interworking_len;
+	u8 hs20_len;
+	u8 ext_capab_len;
+	u8 ssid_list_len;
+};
+
+typedef enum { ParseOK = 0, ParseUnknown = 1, ParseFailed = -1 } ParseRes;
+
+ParseRes ieee802_11_parse_elems(const u8 *start, size_t len,
+				struct ieee802_11_elems *elems,
+				int show_errors);
+int ieee802_11_ie_count(const u8 *ies, size_t ies_len);
+struct wpabuf * ieee802_11_vendor_ie_concat(const u8 *ies, size_t ies_len,
+					    u32 oui_type);
+struct ieee80211_hdr;
+const u8 * get_hdr_bssid(const struct ieee80211_hdr *hdr, size_t len);
+
+struct hostapd_wmm_ac_params {
+	int cwmin;
+	int cwmax;
+	int aifs;
+	int txop_limit; /* in units of 32us */
+	int admission_control_mandatory;
+};
+
+int hostapd_config_wmm_ac(struct hostapd_wmm_ac_params wmm_ac_params[],
+			  const char *name, const char *val);
+
+#endif /* IEEE802_11_COMMON_H */
diff --git a/hostap/src/common/ieee802_11_defs.h b/hostap/src/common/ieee802_11_defs.h
new file mode 100644
index 0000000..e873545
--- /dev/null
+++ b/hostap/src/common/ieee802_11_defs.h
@@ -0,0 +1,1085 @@
+/*
+ * IEEE 802.11 Frame type definitions
+ * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2007-2008 Intel Corporation
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef IEEE802_11_DEFS_H
+#define IEEE802_11_DEFS_H
+
+/* IEEE 802.11 defines */
+
+#define WLAN_FC_PVER		0x0003
+#define WLAN_FC_TODS		0x0100
+#define WLAN_FC_FROMDS		0x0200
+#define WLAN_FC_MOREFRAG	0x0400
+#define WLAN_FC_RETRY		0x0800
+#define WLAN_FC_PWRMGT		0x1000
+#define WLAN_FC_MOREDATA	0x2000
+#define WLAN_FC_ISWEP		0x4000
+#define WLAN_FC_ORDER		0x8000
+
+#define WLAN_FC_GET_TYPE(fc)	(((fc) & 0x000c) >> 2)
+#define WLAN_FC_GET_STYPE(fc)	(((fc) & 0x00f0) >> 4)
+
+#define WLAN_GET_SEQ_FRAG(seq) ((seq) & (BIT(3) | BIT(2) | BIT(1) | BIT(0)))
+#define WLAN_GET_SEQ_SEQ(seq) \
+	(((seq) & (~(BIT(3) | BIT(2) | BIT(1) | BIT(0)))) >> 4)
+
+#define WLAN_FC_TYPE_MGMT		0
+#define WLAN_FC_TYPE_CTRL		1
+#define WLAN_FC_TYPE_DATA		2
+
+/* management */
+#define WLAN_FC_STYPE_ASSOC_REQ		0
+#define WLAN_FC_STYPE_ASSOC_RESP	1
+#define WLAN_FC_STYPE_REASSOC_REQ	2
+#define WLAN_FC_STYPE_REASSOC_RESP	3
+#define WLAN_FC_STYPE_PROBE_REQ		4
+#define WLAN_FC_STYPE_PROBE_RESP	5
+#define WLAN_FC_STYPE_BEACON		8
+#define WLAN_FC_STYPE_ATIM		9
+#define WLAN_FC_STYPE_DISASSOC		10
+#define WLAN_FC_STYPE_AUTH		11
+#define WLAN_FC_STYPE_DEAUTH		12
+#define WLAN_FC_STYPE_ACTION		13
+
+/* control */
+#define WLAN_FC_STYPE_PSPOLL		10
+#define WLAN_FC_STYPE_RTS		11
+#define WLAN_FC_STYPE_CTS		12
+#define WLAN_FC_STYPE_ACK		13
+#define WLAN_FC_STYPE_CFEND		14
+#define WLAN_FC_STYPE_CFENDACK		15
+
+/* data */
+#define WLAN_FC_STYPE_DATA		0
+#define WLAN_FC_STYPE_DATA_CFACK	1
+#define WLAN_FC_STYPE_DATA_CFPOLL	2
+#define WLAN_FC_STYPE_DATA_CFACKPOLL	3
+#define WLAN_FC_STYPE_NULLFUNC		4
+#define WLAN_FC_STYPE_CFACK		5
+#define WLAN_FC_STYPE_CFPOLL		6
+#define WLAN_FC_STYPE_CFACKPOLL		7
+#define WLAN_FC_STYPE_QOS_DATA		8
+#define WLAN_FC_STYPE_QOS_DATA_CFACK	9
+#define WLAN_FC_STYPE_QOS_DATA_CFPOLL	10
+#define WLAN_FC_STYPE_QOS_DATA_CFACKPOLL	11
+#define WLAN_FC_STYPE_QOS_NULL		12
+#define WLAN_FC_STYPE_QOS_CFPOLL	14
+#define WLAN_FC_STYPE_QOS_CFACKPOLL	15
+
+/* Authentication algorithms */
+#define WLAN_AUTH_OPEN			0
+#define WLAN_AUTH_SHARED_KEY		1
+#define WLAN_AUTH_FT			2
+#define WLAN_AUTH_SAE			3
+#define WLAN_AUTH_LEAP			128
+
+#define WLAN_AUTH_CHALLENGE_LEN 128
+
+#define WLAN_CAPABILITY_ESS BIT(0)
+#define WLAN_CAPABILITY_IBSS BIT(1)
+#define WLAN_CAPABILITY_CF_POLLABLE BIT(2)
+#define WLAN_CAPABILITY_CF_POLL_REQUEST BIT(3)
+#define WLAN_CAPABILITY_PRIVACY BIT(4)
+#define WLAN_CAPABILITY_SHORT_PREAMBLE BIT(5)
+#define WLAN_CAPABILITY_PBCC BIT(6)
+#define WLAN_CAPABILITY_CHANNEL_AGILITY BIT(7)
+#define WLAN_CAPABILITY_SPECTRUM_MGMT BIT(8)
+#define WLAN_CAPABILITY_SHORT_SLOT_TIME BIT(10)
+#define WLAN_CAPABILITY_DSSS_OFDM BIT(13)
+
+/* Status codes (IEEE 802.11-2007, 7.3.1.9, Table 7-23) */
+#define WLAN_STATUS_SUCCESS 0
+#define WLAN_STATUS_UNSPECIFIED_FAILURE 1
+#define WLAN_STATUS_TDLS_WAKEUP_ALTERNATE 2
+#define WLAN_STATUS_TDLS_WAKEUP_REJECT 3
+#define WLAN_STATUS_SECURITY_DISABLED 5
+#define WLAN_STATUS_UNACCEPTABLE_LIFETIME 6
+#define WLAN_STATUS_NOT_IN_SAME_BSS 7
+#define WLAN_STATUS_CAPS_UNSUPPORTED 10
+#define WLAN_STATUS_REASSOC_NO_ASSOC 11
+#define WLAN_STATUS_ASSOC_DENIED_UNSPEC 12
+#define WLAN_STATUS_NOT_SUPPORTED_AUTH_ALG 13
+#define WLAN_STATUS_UNKNOWN_AUTH_TRANSACTION 14
+#define WLAN_STATUS_CHALLENGE_FAIL 15
+#define WLAN_STATUS_AUTH_TIMEOUT 16
+#define WLAN_STATUS_AP_UNABLE_TO_HANDLE_NEW_STA 17
+#define WLAN_STATUS_ASSOC_DENIED_RATES 18
+/* IEEE 802.11b */
+#define WLAN_STATUS_ASSOC_DENIED_NOSHORT 19
+#define WLAN_STATUS_ASSOC_DENIED_NOPBCC 20
+#define WLAN_STATUS_ASSOC_DENIED_NOAGILITY 21
+/* IEEE 802.11h */
+#define WLAN_STATUS_SPEC_MGMT_REQUIRED 22
+#define WLAN_STATUS_PWR_CAPABILITY_NOT_VALID 23
+#define WLAN_STATUS_SUPPORTED_CHANNEL_NOT_VALID 24
+/* IEEE 802.11g */
+#define WLAN_STATUS_ASSOC_DENIED_NO_SHORT_SLOT_TIME 25
+#define WLAN_STATUS_ASSOC_DENIED_NO_DSSS_OFDM 26
+#define WLAN_STATUS_ASSOC_DENIED_NO_HT 27
+#define WLAN_STATUS_R0KH_UNREACHABLE 28
+#define WLAN_STATUS_ASSOC_DENIED_NO_PCO 29
+/* IEEE 802.11w */
+#define WLAN_STATUS_ASSOC_REJECTED_TEMPORARILY 30
+#define WLAN_STATUS_ROBUST_MGMT_FRAME_POLICY_VIOLATION 31
+#define WLAN_STATUS_UNSPECIFIED_QOS_FAILURE 32
+#define WLAN_STATUS_REQUEST_DECLINED 37
+#define WLAN_STATUS_INVALID_PARAMETERS 38
+/* IEEE 802.11i */
+#define WLAN_STATUS_INVALID_IE 40
+#define WLAN_STATUS_GROUP_CIPHER_NOT_VALID 41
+#define WLAN_STATUS_PAIRWISE_CIPHER_NOT_VALID 42
+#define WLAN_STATUS_AKMP_NOT_VALID 43
+#define WLAN_STATUS_UNSUPPORTED_RSN_IE_VERSION 44
+#define WLAN_STATUS_INVALID_RSN_IE_CAPAB 45
+#define WLAN_STATUS_CIPHER_REJECTED_PER_POLICY 46
+#define WLAN_STATUS_TS_NOT_CREATED 47
+#define WLAN_STATUS_DIRECT_LINK_NOT_ALLOWED 48
+#define WLAN_STATUS_DEST_STA_NOT_PRESENT 49
+#define WLAN_STATUS_DEST_STA_NOT_QOS_STA 50
+#define WLAN_STATUS_ASSOC_DENIED_LISTEN_INT_TOO_LARGE 51
+/* IEEE 802.11r */
+#define WLAN_STATUS_INVALID_FT_ACTION_FRAME_COUNT 52
+#define WLAN_STATUS_INVALID_PMKID 53
+#define WLAN_STATUS_INVALID_MDIE 54
+#define WLAN_STATUS_INVALID_FTIE 55
+#define WLAN_STATUS_GAS_ADV_PROTO_NOT_SUPPORTED 59
+#define WLAN_STATUS_NO_OUTSTANDING_GAS_REQ 60
+#define WLAN_STATUS_GAS_RESP_NOT_RECEIVED 61
+#define WLAN_STATUS_STA_TIMED_OUT_WAITING_FOR_GAS_RESP 62
+#define WLAN_STATUS_GAS_RESP_LARGER_THAN_LIMIT 63
+#define WLAN_STATUS_REQ_REFUSED_HOME 64
+#define WLAN_STATUS_ADV_SRV_UNREACHABLE 65
+#define WLAN_STATUS_REQ_REFUSED_SSPN 67
+#define WLAN_STATUS_REQ_REFUSED_UNAUTH_ACCESS 68
+#define WLAN_STATUS_INVALID_RSNIE 72
+#define WLAN_STATUS_ANTI_CLOGGING_TOKEN_REQ 76
+#define WLAN_STATUS_FINITE_CYCLIC_GROUP_NOT_SUPPORTED 77
+#define WLAN_STATUS_TRANSMISSION_FAILURE 79
+
+/* Reason codes (IEEE 802.11-2007, 7.3.1.7, Table 7-22) */
+#define WLAN_REASON_UNSPECIFIED 1
+#define WLAN_REASON_PREV_AUTH_NOT_VALID 2
+#define WLAN_REASON_DEAUTH_LEAVING 3
+#define WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY 4
+#define WLAN_REASON_DISASSOC_AP_BUSY 5
+#define WLAN_REASON_CLASS2_FRAME_FROM_NONAUTH_STA 6
+#define WLAN_REASON_CLASS3_FRAME_FROM_NONASSOC_STA 7
+#define WLAN_REASON_DISASSOC_STA_HAS_LEFT 8
+#define WLAN_REASON_STA_REQ_ASSOC_WITHOUT_AUTH 9
+/* IEEE 802.11h */
+#define WLAN_REASON_PWR_CAPABILITY_NOT_VALID 10
+#define WLAN_REASON_SUPPORTED_CHANNEL_NOT_VALID 11
+/* IEEE 802.11i */
+#define WLAN_REASON_INVALID_IE 13
+#define WLAN_REASON_MICHAEL_MIC_FAILURE 14
+#define WLAN_REASON_4WAY_HANDSHAKE_TIMEOUT 15
+#define WLAN_REASON_GROUP_KEY_UPDATE_TIMEOUT 16
+#define WLAN_REASON_IE_IN_4WAY_DIFFERS 17
+#define WLAN_REASON_GROUP_CIPHER_NOT_VALID 18
+#define WLAN_REASON_PAIRWISE_CIPHER_NOT_VALID 19
+#define WLAN_REASON_AKMP_NOT_VALID 20
+#define WLAN_REASON_UNSUPPORTED_RSN_IE_VERSION 21
+#define WLAN_REASON_INVALID_RSN_IE_CAPAB 22
+#define WLAN_REASON_IEEE_802_1X_AUTH_FAILED 23
+#define WLAN_REASON_CIPHER_SUITE_REJECTED 24
+#define WLAN_REASON_TDLS_TEARDOWN_UNREACHABLE 25
+#define WLAN_REASON_TDLS_TEARDOWN_UNSPECIFIED 26
+/* IEEE 802.11e */
+#define WLAN_REASON_DISASSOC_LOW_ACK 34
+
+
+/* Information Element IDs */
+#define WLAN_EID_SSID 0
+#define WLAN_EID_SUPP_RATES 1
+#define WLAN_EID_FH_PARAMS 2
+#define WLAN_EID_DS_PARAMS 3
+#define WLAN_EID_CF_PARAMS 4
+#define WLAN_EID_TIM 5
+#define WLAN_EID_IBSS_PARAMS 6
+#define WLAN_EID_COUNTRY 7
+#define WLAN_EID_CHALLENGE 16
+/* EIDs defined by IEEE 802.11h - START */
+#define WLAN_EID_PWR_CONSTRAINT 32
+#define WLAN_EID_PWR_CAPABILITY 33
+#define WLAN_EID_TPC_REQUEST 34
+#define WLAN_EID_TPC_REPORT 35
+#define WLAN_EID_SUPPORTED_CHANNELS 36
+#define WLAN_EID_CHANNEL_SWITCH 37
+#define WLAN_EID_MEASURE_REQUEST 38
+#define WLAN_EID_MEASURE_REPORT 39
+#define WLAN_EID_QUITE 40
+#define WLAN_EID_IBSS_DFS 41
+/* EIDs defined by IEEE 802.11h - END */
+#define WLAN_EID_ERP_INFO 42
+#define WLAN_EID_HT_CAP 45
+#define WLAN_EID_RSN 48
+#define WLAN_EID_EXT_SUPP_RATES 50
+#define WLAN_EID_MOBILITY_DOMAIN 54
+#define WLAN_EID_FAST_BSS_TRANSITION 55
+#define WLAN_EID_TIMEOUT_INTERVAL 56
+#define WLAN_EID_RIC_DATA 57
+#define WLAN_EID_HT_OPERATION 61
+#define WLAN_EID_SECONDARY_CHANNEL_OFFSET 62
+#define WLAN_EID_WAPI 68
+#define WLAN_EID_TIME_ADVERTISEMENT 69
+#define WLAN_EID_20_40_BSS_COEXISTENCE 72
+#define WLAN_EID_20_40_BSS_INTOLERANT 73
+#define WLAN_EID_OVERLAPPING_BSS_SCAN_PARAMS 74
+#define WLAN_EID_MMIE 76
+#define WLAN_EID_SSID_LIST 84
+#define WLAN_EID_BSS_MAX_IDLE_PERIOD 90
+#define WLAN_EID_TFS_REQ 91
+#define WLAN_EID_TFS_RESP 92
+#define WLAN_EID_WNMSLEEP 93
+#define WLAN_EID_TIME_ZONE 98
+#define WLAN_EID_LINK_ID 101
+#define WLAN_EID_INTERWORKING 107
+#define WLAN_EID_ADV_PROTO 108
+#define WLAN_EID_ROAMING_CONSORTIUM 111
+#define WLAN_EID_EXT_CAPAB 127
+#define WLAN_EID_CCKM 156
+#define WLAN_EID_VHT_CAP 191
+#define WLAN_EID_VHT_OPERATION 192
+#define WLAN_EID_VHT_EXTENDED_BSS_LOAD 193
+#define WLAN_EID_VHT_WIDE_BW_CHSWITCH  194
+#define WLAN_EID_VHT_TRANSMIT_POWER_ENVELOPE 195
+#define WLAN_EID_VHT_CHANNEL_SWITCH_WRAPPER 196
+#define WLAN_EID_VHT_AID 197
+#define WLAN_EID_VHT_QUIET_CHANNEL 198
+#define WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION 199
+#define WLAN_EID_VENDOR_SPECIFIC 221
+
+
+/* Action frame categories (IEEE 802.11-2007, 7.3.1.11, Table 7-24) */
+#define WLAN_ACTION_SPECTRUM_MGMT 0
+#define WLAN_ACTION_QOS 1
+#define WLAN_ACTION_DLS 2
+#define WLAN_ACTION_BLOCK_ACK 3
+#define WLAN_ACTION_PUBLIC 4
+#define WLAN_ACTION_RADIO_MEASUREMENT 5
+#define WLAN_ACTION_FT 6
+#define WLAN_ACTION_HT 7
+#define WLAN_ACTION_SA_QUERY 8
+#define WLAN_ACTION_WNM 10
+#define WLAN_ACTION_UNPROTECTED_WNM 11
+#define WLAN_ACTION_TDLS 12
+#define WLAN_ACTION_WMM 17 /* WMM Specification 1.1 */
+#define WLAN_ACTION_VENDOR_SPECIFIC 127
+
+/* Public action codes */
+#define WLAN_PA_20_40_BSS_COEX 0
+#define WLAN_PA_VENDOR_SPECIFIC 9
+#define WLAN_PA_GAS_INITIAL_REQ 10
+#define WLAN_PA_GAS_INITIAL_RESP 11
+#define WLAN_PA_GAS_COMEBACK_REQ 12
+#define WLAN_PA_GAS_COMEBACK_RESP 13
+#define WLAN_TDLS_DISCOVERY_RESPONSE 14
+
+/* SA Query Action frame (IEEE 802.11w/D8.0, 7.4.9) */
+#define WLAN_SA_QUERY_REQUEST 0
+#define WLAN_SA_QUERY_RESPONSE 1
+
+#define WLAN_SA_QUERY_TR_ID_LEN 2
+
+/* TDLS action codes */
+#define WLAN_TDLS_SETUP_REQUEST 0
+#define WLAN_TDLS_SETUP_RESPONSE 1
+#define WLAN_TDLS_SETUP_CONFIRM 2
+#define WLAN_TDLS_TEARDOWN 3
+#define WLAN_TDLS_PEER_TRAFFIC_INDICATION 4
+#define WLAN_TDLS_CHANNEL_SWITCH_REQUEST 5
+#define WLAN_TDLS_CHANNEL_SWITCH_RESPONSE 6
+#define WLAN_TDLS_PEER_PSM_REQUEST 7
+#define WLAN_TDLS_PEER_PSM_RESPONSE 8
+#define WLAN_TDLS_PEER_TRAFFIC_RESPONSE 9
+#define WLAN_TDLS_DISCOVERY_REQUEST 10
+
+/* Timeout Interval Type */
+#define WLAN_TIMEOUT_REASSOC_DEADLINE 1
+#define WLAN_TIMEOUT_KEY_LIFETIME 2
+#define WLAN_TIMEOUT_ASSOC_COMEBACK 3
+
+/* Interworking element (IEEE 802.11u) - Access Network Options */
+#define INTERWORKING_ANO_ACCESS_NETWORK_MASK 0x0f
+#define INTERWORKING_ANO_INTERNET 0x10
+#define INTERWORKING_ANO_ASRA 0x20
+#define INTERWORKING_ANO_ESR 0x40
+#define INTERWORKING_ANO_UESA 0x80
+
+#define INTERWORKING_ANT_PRIVATE 0
+#define INTERWORKING_ANT_PRIVATE_WITH_GUEST 1
+#define INTERWORKING_ANT_CHARGEABLE_PUBLIC 2
+#define INTERWORKING_ANT_FREE_PUBLIC 3
+#define INTERWORKING_ANT_PERSONAL_DEVICE 4
+#define INTERWORKING_ANT_EMERGENCY_SERVICES 5
+#define INTERWORKING_ANT_TEST 6
+#define INTERWORKING_ANT_WILDCARD 15
+
+/* Advertisement Protocol ID definitions (IEEE Std 802.11u-2011) */
+enum adv_proto_id {
+	ACCESS_NETWORK_QUERY_PROTOCOL = 0,
+	MIH_INFO_SERVICE = 1,
+	MIH_CMD_AND_EVENT_DISCOVERY = 2,
+	EMERGENCY_ALERT_SYSTEM = 3,
+	ADV_PROTO_VENDOR_SPECIFIC = 221
+};
+
+/* Access Network Query Protocol info ID definitions (IEEE Std 802.11u-2011) */
+enum anqp_info_id {
+	ANQP_QUERY_LIST = 256,
+	ANQP_CAPABILITY_LIST = 257,
+	ANQP_VENUE_NAME = 258,
+	ANQP_EMERGENCY_CALL_NUMBER = 259,
+	ANQP_NETWORK_AUTH_TYPE = 260,
+	ANQP_ROAMING_CONSORTIUM = 261,
+	ANQP_IP_ADDR_TYPE_AVAILABILITY = 262,
+	ANQP_NAI_REALM = 263,
+	ANQP_3GPP_CELLULAR_NETWORK = 264,
+	ANQP_AP_GEOSPATIAL_LOCATION = 265,
+	ANQP_AP_CIVIC_LOCATION = 266,
+	ANQP_AP_LOCATION_PUBLIC_URI = 267,
+	ANQP_DOMAIN_NAME = 268,
+	ANQP_EMERGENCY_ALERT_URI = 269,
+	ANQP_EMERGENCY_NAI = 271,
+	ANQP_VENDOR_SPECIFIC = 56797
+};
+
+/* NAI Realm list - EAP Method subfield - Authentication Parameter ID */
+enum nai_realm_eap_auth_param {
+	NAI_REALM_EAP_AUTH_EXPANDED_EAP_METHOD = 1,
+	NAI_REALM_EAP_AUTH_NON_EAP_INNER_AUTH = 2,
+	NAI_REALM_EAP_AUTH_INNER_AUTH_EAP_METHOD = 3,
+	NAI_REALM_EAP_AUTH_EXPANDED_INNER_EAP_METHOD = 4,
+	NAI_REALM_EAP_AUTH_CRED_TYPE = 5,
+	NAI_REALM_EAP_AUTH_TUNNELED_CRED_TYPE = 6,
+	NAI_REALM_EAP_AUTH_VENDOR_SPECIFIC = 221
+};
+
+enum nai_realm_eap_auth_inner_non_eap {
+	NAI_REALM_INNER_NON_EAP_PAP = 1,
+	NAI_REALM_INNER_NON_EAP_CHAP = 2,
+	NAI_REALM_INNER_NON_EAP_MSCHAP = 3,
+	NAI_REALM_INNER_NON_EAP_MSCHAPV2 = 4
+};
+
+enum nai_realm_eap_cred_type {
+	NAI_REALM_CRED_TYPE_SIM = 1,
+	NAI_REALM_CRED_TYPE_USIM = 2,
+	NAI_REALM_CRED_TYPE_NFC_SECURE_ELEMENT = 3,
+	NAI_REALM_CRED_TYPE_HARDWARE_TOKEN = 4,
+	NAI_REALM_CRED_TYPE_SOFTOKEN = 5,
+	NAI_REALM_CRED_TYPE_CERTIFICATE = 6,
+	NAI_REALM_CRED_TYPE_USERNAME_PASSWORD = 7,
+	NAI_REALM_CRED_TYPE_NONE = 8,
+	NAI_REALM_CRED_TYPE_ANONYMOUS = 9,
+	NAI_REALM_CRED_TYPE_VENDOR_SPECIFIC = 10
+};
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+struct ieee80211_hdr {
+	le16 frame_control;
+	le16 duration_id;
+	u8 addr1[6];
+	u8 addr2[6];
+	u8 addr3[6];
+	le16 seq_ctrl;
+	/* followed by 'u8 addr4[6];' if ToDS and FromDS is set in data frame
+	 */
+} STRUCT_PACKED;
+
+#define IEEE80211_DA_FROMDS addr1
+#define IEEE80211_BSSID_FROMDS addr2
+#define IEEE80211_SA_FROMDS addr3
+
+#define IEEE80211_HDRLEN (sizeof(struct ieee80211_hdr))
+
+#define IEEE80211_FC(type, stype) host_to_le16((type << 2) | (stype << 4))
+
+struct ieee80211_mgmt {
+	le16 frame_control;
+	le16 duration;
+	u8 da[6];
+	u8 sa[6];
+	u8 bssid[6];
+	le16 seq_ctrl;
+	union {
+		struct {
+			le16 auth_alg;
+			le16 auth_transaction;
+			le16 status_code;
+			/* possibly followed by Challenge text */
+			u8 variable[0];
+		} STRUCT_PACKED auth;
+		struct {
+			le16 reason_code;
+			u8 variable[0];
+		} STRUCT_PACKED deauth;
+		struct {
+			le16 capab_info;
+			le16 listen_interval;
+			/* followed by SSID and Supported rates */
+			u8 variable[0];
+		} STRUCT_PACKED assoc_req;
+		struct {
+			le16 capab_info;
+			le16 status_code;
+			le16 aid;
+			/* followed by Supported rates */
+			u8 variable[0];
+		} STRUCT_PACKED assoc_resp, reassoc_resp;
+		struct {
+			le16 capab_info;
+			le16 listen_interval;
+			u8 current_ap[6];
+			/* followed by SSID and Supported rates */
+			u8 variable[0];
+		} STRUCT_PACKED reassoc_req;
+		struct {
+			le16 reason_code;
+			u8 variable[0];
+		} STRUCT_PACKED disassoc;
+		struct {
+			u8 timestamp[8];
+			le16 beacon_int;
+			le16 capab_info;
+			/* followed by some of SSID, Supported rates,
+			 * FH Params, DS Params, CF Params, IBSS Params, TIM */
+			u8 variable[0];
+		} STRUCT_PACKED beacon;
+		struct {
+			/* only variable items: SSID, Supported rates */
+			u8 variable[0];
+		} STRUCT_PACKED probe_req;
+		struct {
+			u8 timestamp[8];
+			le16 beacon_int;
+			le16 capab_info;
+			/* followed by some of SSID, Supported rates,
+			 * FH Params, DS Params, CF Params, IBSS Params */
+			u8 variable[0];
+		} STRUCT_PACKED probe_resp;
+		struct {
+			u8 category;
+			union {
+				struct {
+					u8 action_code;
+					u8 dialog_token;
+					u8 status_code;
+					u8 variable[0];
+				} STRUCT_PACKED wmm_action;
+				struct{
+					u8 action_code;
+					u8 element_id;
+					u8 length;
+					u8 switch_mode;
+					u8 new_chan;
+					u8 switch_count;
+				} STRUCT_PACKED chan_switch;
+				struct {
+					u8 action;
+					u8 sta_addr[ETH_ALEN];
+					u8 target_ap_addr[ETH_ALEN];
+					u8 variable[0]; /* FT Request */
+				} STRUCT_PACKED ft_action_req;
+				struct {
+					u8 action;
+					u8 sta_addr[ETH_ALEN];
+					u8 target_ap_addr[ETH_ALEN];
+					le16 status_code;
+					u8 variable[0]; /* FT Request */
+				} STRUCT_PACKED ft_action_resp;
+				struct {
+					u8 action;
+					u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+				} STRUCT_PACKED sa_query_req;
+				struct {
+					u8 action; /* */
+					u8 trans_id[WLAN_SA_QUERY_TR_ID_LEN];
+				} STRUCT_PACKED sa_query_resp;
+				struct {
+					u8 action;
+					u8 dialogtoken;
+					u8 variable[0];
+				} STRUCT_PACKED wnm_sleep_req;
+				struct {
+					u8 action;
+					u8 dialogtoken;
+					le16 keydata_len;
+					u8 variable[0];
+				} STRUCT_PACKED wnm_sleep_resp;
+				struct {
+					u8 action;
+					u8 variable[0];
+				} STRUCT_PACKED public_action;
+				struct {
+					u8 action; /* 9 */
+					u8 oui[3];
+					/* Vendor-specific content */
+					u8 variable[0];
+				} STRUCT_PACKED vs_public_action;
+				struct {
+					u8 action; /* 7 */
+					u8 dialog_token;
+					u8 req_mode;
+					le16 disassoc_timer;
+					u8 validity_interval;
+					/* BSS Termination Duration (optional),
+					 * Session Information URL (optional),
+					 * BSS Transition Candidate List
+					 * Entries */
+					u8 variable[0];
+				} STRUCT_PACKED bss_tm_req;
+				struct {
+					u8 action; /* 8 */
+					u8 dialog_token;
+					u8 status_code;
+					u8 bss_termination_delay;
+					/* Target BSSID (optional),
+					 * BSS Transition Candidate List
+					 * Entries (optional) */
+					u8 variable[0];
+				} STRUCT_PACKED bss_tm_resp;
+			} u;
+		} STRUCT_PACKED action;
+	} u;
+} STRUCT_PACKED;
+
+
+/* Rx MCS bitmask is in the first 77 bits of supported_mcs_set */
+#define IEEE80211_HT_MCS_MASK_LEN 10
+
+struct ieee80211_ht_capabilities {
+	le16 ht_capabilities_info;
+	u8 a_mpdu_params;
+	u8 supported_mcs_set[16];
+	le16 ht_extended_capabilities;
+	le32 tx_bf_capability_info;
+	u8 asel_capabilities;
+} STRUCT_PACKED;
+
+
+struct ieee80211_ht_operation {
+	u8 control_chan;
+	u8 ht_param;
+	le16 operation_mode;
+	le16 stbc_param;
+	u8 basic_set[16];
+} STRUCT_PACKED;
+
+
+struct ieee80211_vht_capabilities {
+	le32 vht_capabilities_info;
+	u8 vht_supported_mcs_set[8];
+} STRUCT_PACKED;
+
+struct ieee80211_vht_operation {
+	u8 vht_op_info_chwidth;
+	u8 vht_op_info_chan_center_freq_seg0_idx;
+	u8 vht_op_info_chan_center_freq_seg1_idx;
+	le16 vht_basic_mcs_set;
+} STRUCT_PACKED;
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+#define ERP_INFO_NON_ERP_PRESENT BIT(0)
+#define ERP_INFO_USE_PROTECTION BIT(1)
+#define ERP_INFO_BARKER_PREAMBLE_MODE BIT(2)
+
+
+#define HT_CAP_INFO_LDPC_CODING_CAP		((u16) BIT(0))
+#define HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET	((u16) BIT(1))
+#define HT_CAP_INFO_SMPS_MASK			((u16) (BIT(2) | BIT(3)))
+#define HT_CAP_INFO_SMPS_STATIC			((u16) 0)
+#define HT_CAP_INFO_SMPS_DYNAMIC		((u16) BIT(2))
+#define HT_CAP_INFO_SMPS_DISABLED		((u16) (BIT(2) | BIT(3)))
+#define HT_CAP_INFO_GREEN_FIELD			((u16) BIT(4))
+#define HT_CAP_INFO_SHORT_GI20MHZ		((u16) BIT(5))
+#define HT_CAP_INFO_SHORT_GI40MHZ		((u16) BIT(6))
+#define HT_CAP_INFO_TX_STBC			((u16) BIT(7))
+#define HT_CAP_INFO_RX_STBC_MASK		((u16) (BIT(8) | BIT(9)))
+#define HT_CAP_INFO_RX_STBC_1			((u16) BIT(8))
+#define HT_CAP_INFO_RX_STBC_12			((u16) BIT(9))
+#define HT_CAP_INFO_RX_STBC_123			((u16) (BIT(8) | BIT(9)))
+#define HT_CAP_INFO_DELAYED_BA			((u16) BIT(10))
+#define HT_CAP_INFO_MAX_AMSDU_SIZE		((u16) BIT(11))
+#define HT_CAP_INFO_DSSS_CCK40MHZ		((u16) BIT(12))
+#define HT_CAP_INFO_PSMP_SUPP			((u16) BIT(13))
+#define HT_CAP_INFO_40MHZ_INTOLERANT		((u16) BIT(14))
+#define HT_CAP_INFO_LSIG_TXOP_PROTECT_SUPPORT	((u16) BIT(15))
+
+
+#define EXT_HT_CAP_INFO_PCO			((u16) BIT(0))
+#define EXT_HT_CAP_INFO_TRANS_TIME_OFFSET	1
+#define EXT_HT_CAP_INFO_MCS_FEEDBACK_OFFSET	8
+#define EXT_HT_CAP_INFO_HTC_SUPPORTED		((u16) BIT(10))
+#define EXT_HT_CAP_INFO_RD_RESPONDER		((u16) BIT(11))
+
+
+#define TX_BEAMFORM_CAP_TXBF_CAP ((u32) BIT(0))
+#define TX_BEAMFORM_CAP_RX_STAGGERED_SOUNDING_CAP ((u32) BIT(1))
+#define TX_BEAMFORM_CAP_TX_STAGGERED_SOUNDING_CAP ((u32) BIT(2))
+#define TX_BEAMFORM_CAP_RX_ZLF_CAP ((u32) BIT(3))
+#define TX_BEAMFORM_CAP_TX_ZLF_CAP ((u32) BIT(4))
+#define TX_BEAMFORM_CAP_IMPLICIT_ZLF_CAP ((u32) BIT(5))
+#define TX_BEAMFORM_CAP_CALIB_OFFSET 6
+#define TX_BEAMFORM_CAP_EXPLICIT_CSI_TXBF_CAP ((u32) BIT(8))
+#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_CAP ((u32) BIT(9))
+#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_CAP ((u32) BIT(10))
+#define TX_BEAMFORM_CAP_EXPLICIT_BF_CSI_FEEDBACK_OFFSET 11
+#define TX_BEAMFORM_CAP_EXPLICIT_UNCOMPR_STEERING_MATRIX_FEEDBACK_OFFSET 13
+#define TX_BEAMFORM_CAP_EXPLICIT_COMPRESSED_STEERING_MATRIX_FEEDBACK_OFFSET 15
+#define TX_BEAMFORM_CAP_MINIMAL_GROUPING_OFFSET 17
+#define TX_BEAMFORM_CAP_CSI_NUM_BEAMFORMER_ANT_OFFSET 19
+#define TX_BEAMFORM_CAP_UNCOMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 21
+#define TX_BEAMFORM_CAP_COMPRESSED_STEERING_MATRIX_BEAMFORMER_ANT_OFFSET 23
+#define TX_BEAMFORM_CAP_SCI_MAX_OF_ROWS_BEANFORMER_SUPPORTED_OFFSET 25
+
+
+#define ASEL_CAPABILITY_ASEL_CAPABLE ((u8) BIT(0))
+#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(1))
+#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_BASED_TX_AS_CAP ((u8) BIT(2))
+#define ASEL_CAPABILITY_EXPLICIT_CSI_FEEDBACK_CAP ((u8) BIT(3))
+#define ASEL_CAPABILITY_ANT_INDICES_FEEDBACK_CAP ((u8) BIT(4))
+#define ASEL_CAPABILITY_RX_AS_CAP ((u8) BIT(5))
+#define ASEL_CAPABILITY_TX_SOUND_PPDUS_CAP ((u8) BIT(6))
+
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK	((u8) BIT(0) | BIT(1))
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_ABOVE		((u8) BIT(0))
+#define HT_INFO_HT_PARAM_SECONDARY_CHNL_BELOW		((u8) BIT(0) | BIT(1))
+#define HT_INFO_HT_PARAM_REC_TRANS_CHNL_WIDTH		((u8) BIT(2))
+#define HT_INFO_HT_PARAM_RIFS_MODE			((u8) BIT(3))
+#define HT_INFO_HT_PARAM_CTRL_ACCESS_ONLY		((u8) BIT(4))
+#define HT_INFO_HT_PARAM_SRV_INTERVAL_GRANULARITY	((u8) BIT(5))
+
+
+#define OP_MODE_PURE                    0
+#define OP_MODE_MAY_BE_LEGACY_STAS      1
+#define OP_MODE_20MHZ_HT_STA_ASSOCED    2
+#define OP_MODE_MIXED                   3
+
+#define HT_INFO_OPERATION_MODE_OP_MODE_MASK	\
+		(0x0001 | 0x0002)
+#define HT_INFO_OPERATION_MODE_OP_MODE_OFFSET		0
+#define HT_INFO_OPERATION_MODE_NON_GF_DEVS_PRESENT	((u8) BIT(2))
+#define HT_INFO_OPERATION_MODE_TRANSMIT_BURST_LIMIT	((u8) BIT(3))
+#define HT_INFO_OPERATION_MODE_NON_HT_STA_PRESENT	((u8) BIT(4))
+
+#define HT_INFO_STBC_PARAM_DUAL_BEACON			((u16) BIT(6))
+#define HT_INFO_STBC_PARAM_DUAL_STBC_PROTECT		((u16) BIT(7))
+#define HT_INFO_STBC_PARAM_SECONDARY_BCN		((u16) BIT(8))
+#define HT_INFO_STBC_PARAM_LSIG_TXOP_PROTECT_ALLOWED	((u16) BIT(9))
+#define HT_INFO_STBC_PARAM_PCO_ACTIVE			((u16) BIT(10))
+#define HT_INFO_STBC_PARAM_PCO_PHASE			((u16) BIT(11))
+
+#define BSS_MEMBERSHIP_SELECTOR_VHT_PHY 126
+#define BSS_MEMBERSHIP_SELECTOR_HT_PHY 127
+
+/* VHT Defines */
+#define VHT_CAP_MAX_MPDU_LENGTH_7991                ((u32) BIT(0))
+#define VHT_CAP_MAX_MPDU_LENGTH_11454               ((u32) BIT(1))
+#define VHT_CAP_SUPP_CHAN_WIDTH_160MHZ              ((u32) BIT(2))
+#define VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ     ((u32) BIT(3))
+#define VHT_CAP_RXLDPC                              ((u32) BIT(4))
+#define VHT_CAP_SHORT_GI_80                         ((u32) BIT(5))
+#define VHT_CAP_SHORT_GI_160                        ((u32) BIT(6))
+#define VHT_CAP_TXSTBC                              ((u32) BIT(7))
+#define VHT_CAP_RXSTBC_1                            ((u32) BIT(8))
+#define VHT_CAP_RXSTBC_2                            ((u32) BIT(9))
+#define VHT_CAP_RXSTBC_3                            ((u32) BIT(8) | BIT(9))
+#define VHT_CAP_RXSTBC_4                            ((u32) BIT(10))
+#define VHT_CAP_SU_BEAMFORMER_CAPABLE               ((u32) BIT(11))
+#define VHT_CAP_SU_BEAMFORMEE_CAPABLE               ((u32) BIT(12))
+#define VHT_CAP_BEAMFORMER_ANTENNAS_MAX             ((u32) BIT(13) | BIT(14))
+#define VHT_CAP_SOUNDING_DIMENTION_MAX              ((u32) BIT(16) | BIT(17))
+#define VHT_CAP_MU_BEAMFORMER_CAPABLE               ((u32) BIT(19))
+#define VHT_CAP_MU_BEAMFORMEE_CAPABLE               ((u32) BIT(20))
+#define VHT_CAP_VHT_TXOP_PS                         ((u32) BIT(21))
+#define VHT_CAP_HTC_VHT                             ((u32) BIT(22))
+#define VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT          ((u32) BIT(23))
+#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_UNSOL_MFB   ((u32) BIT(27))
+#define VHT_CAP_VHT_LINK_ADAPTATION_VHT_MRQ_MFB     ((u32) BIT(26) | BIT(27))
+#define VHT_CAP_RX_ANTENNA_PATTERN                  ((u32) BIT(28))
+#define VHT_CAP_TX_ANTENNA_PATTERN                  ((u32) BIT(29))
+
+#define OUI_MICROSOFT 0x0050f2 /* Microsoft (also used in Wi-Fi specs)
+				* 00:50:F2 */
+#define WPA_IE_VENDOR_TYPE 0x0050f201
+#define WPS_IE_VENDOR_TYPE 0x0050f204
+#define OUI_WFA 0x506f9a
+#define P2P_IE_VENDOR_TYPE 0x506f9a09
+#define WFD_IE_VENDOR_TYPE 0x506f9a0a
+#define WFD_OUI_TYPE 10
+#define HS20_IE_VENDOR_TYPE 0x506f9a10
+
+#define WMM_OUI_TYPE 2
+#define WMM_OUI_SUBTYPE_INFORMATION_ELEMENT 0
+#define WMM_OUI_SUBTYPE_PARAMETER_ELEMENT 1
+#define WMM_OUI_SUBTYPE_TSPEC_ELEMENT 2
+#define WMM_VERSION 1
+
+#define WMM_ACTION_CODE_ADDTS_REQ 0
+#define WMM_ACTION_CODE_ADDTS_RESP 1
+#define WMM_ACTION_CODE_DELTS 2
+
+#define WMM_ADDTS_STATUS_ADMISSION_ACCEPTED 0
+#define WMM_ADDTS_STATUS_INVALID_PARAMETERS 1
+/* 2 - Reserved */
+#define WMM_ADDTS_STATUS_REFUSED 3
+/* 4-255 - Reserved */
+
+/* WMM TSPEC Direction Field Values */
+#define WMM_TSPEC_DIRECTION_UPLINK 0
+#define WMM_TSPEC_DIRECTION_DOWNLINK 1
+/* 2 - Reserved */
+#define WMM_TSPEC_DIRECTION_BI_DIRECTIONAL 3
+
+/*
+ * WMM Information Element (used in (Re)Association Request frames; may also be
+ * used in Beacon frames)
+ */
+struct wmm_information_element {
+	/* Element ID: 221 (0xdd); Length: 7 */
+	/* required fields for WMM version 1 */
+	u8 oui[3]; /* 00:50:f2 */
+	u8 oui_type; /* 2 */
+	u8 oui_subtype; /* 0 */
+	u8 version; /* 1 for WMM version 1.0 */
+	u8 qos_info; /* AP/STA specific QoS info */
+
+} STRUCT_PACKED;
+
+#define WMM_QOSINFO_STA_AC_MASK 0x0f
+#define WMM_QOSINFO_STA_SP_MASK 0x03
+#define WMM_QOSINFO_STA_SP_SHIFT 5
+
+#define WMM_AC_AIFSN_MASK 0x0f
+#define WMM_AC_AIFNS_SHIFT 0
+#define WMM_AC_ACM 0x10
+#define WMM_AC_ACI_MASK 0x60
+#define WMM_AC_ACI_SHIFT 5
+
+#define WMM_AC_ECWMIN_MASK 0x0f
+#define WMM_AC_ECWMIN_SHIFT 0
+#define WMM_AC_ECWMAX_MASK 0xf0
+#define WMM_AC_ECWMAX_SHIFT 4
+
+struct wmm_ac_parameter {
+	u8 aci_aifsn; /* AIFSN, ACM, ACI */
+	u8 cw; /* ECWmin, ECWmax (CW = 2^ECW - 1) */
+	le16 txop_limit;
+}  STRUCT_PACKED;
+
+/*
+ * WMM Parameter Element (used in Beacon, Probe Response, and (Re)Association
+ * Response frmaes)
+ */
+struct wmm_parameter_element {
+	/* Element ID: 221 (0xdd); Length: 24 */
+	/* required fields for WMM version 1 */
+	u8 oui[3]; /* 00:50:f2 */
+	u8 oui_type; /* 2 */
+	u8 oui_subtype; /* 1 */
+	u8 version; /* 1 for WMM version 1.0 */
+	u8 qos_info; /* AP/STA specific QoS info */
+	u8 reserved; /* 0 */
+	struct wmm_ac_parameter ac[4]; /* AC_BE, AC_BK, AC_VI, AC_VO */
+
+} STRUCT_PACKED;
+
+/* WMM TSPEC Element */
+struct wmm_tspec_element {
+	u8 eid; /* 221 = 0xdd */
+	u8 length; /* 6 + 55 = 61 */
+	u8 oui[3]; /* 00:50:f2 */
+	u8 oui_type; /* 2 */
+	u8 oui_subtype; /* 2 */
+	u8 version; /* 1 */
+	/* WMM TSPEC body (55 octets): */
+	u8 ts_info[3];
+	le16 nominal_msdu_size;
+	le16 maximum_msdu_size;
+	le32 minimum_service_interval;
+	le32 maximum_service_interval;
+	le32 inactivity_interval;
+	le32 suspension_interval;
+	le32 service_start_time;
+	le32 minimum_data_rate;
+	le32 mean_data_rate;
+	le32 peak_data_rate;
+	le32 maximum_burst_size;
+	le32 delay_bound;
+	le32 minimum_phy_rate;
+	le16 surplus_bandwidth_allowance;
+	le16 medium_time;
+} STRUCT_PACKED;
+
+
+/* Access Categories / ACI to AC coding */
+enum {
+	WMM_AC_BE = 0 /* Best Effort */,
+	WMM_AC_BK = 1 /* Background */,
+	WMM_AC_VI = 2 /* Video */,
+	WMM_AC_VO = 3 /* Voice */
+};
+
+
+#define HS20_INDICATION_OUI_TYPE 16
+#define HS20_ANQP_OUI_TYPE 17
+#define HS20_STYPE_QUERY_LIST 1
+#define HS20_STYPE_CAPABILITY_LIST 2
+#define HS20_STYPE_OPERATOR_FRIENDLY_NAME 3
+#define HS20_STYPE_WAN_METRICS 4
+#define HS20_STYPE_CONNECTION_CAPABILITY 5
+#define HS20_STYPE_NAI_HOME_REALM_QUERY 6
+#define HS20_STYPE_OPERATING_CLASS 7
+
+/* Wi-Fi Direct (P2P) */
+
+#define P2P_OUI_TYPE 9
+
+enum p2p_attr_id {
+	P2P_ATTR_STATUS = 0,
+	P2P_ATTR_MINOR_REASON_CODE = 1,
+	P2P_ATTR_CAPABILITY = 2,
+	P2P_ATTR_DEVICE_ID = 3,
+	P2P_ATTR_GROUP_OWNER_INTENT = 4,
+	P2P_ATTR_CONFIGURATION_TIMEOUT = 5,
+	P2P_ATTR_LISTEN_CHANNEL = 6,
+	P2P_ATTR_GROUP_BSSID = 7,
+	P2P_ATTR_EXT_LISTEN_TIMING = 8,
+	P2P_ATTR_INTENDED_INTERFACE_ADDR = 9,
+	P2P_ATTR_MANAGEABILITY = 10,
+	P2P_ATTR_CHANNEL_LIST = 11,
+	P2P_ATTR_NOTICE_OF_ABSENCE = 12,
+	P2P_ATTR_DEVICE_INFO = 13,
+	P2P_ATTR_GROUP_INFO = 14,
+	P2P_ATTR_GROUP_ID = 15,
+	P2P_ATTR_INTERFACE = 16,
+	P2P_ATTR_OPERATING_CHANNEL = 17,
+	P2P_ATTR_INVITATION_FLAGS = 18,
+	P2P_ATTR_VENDOR_SPECIFIC = 221
+};
+
+#define P2P_MAX_GO_INTENT 15
+
+/* P2P Capability - Device Capability bitmap */
+#define P2P_DEV_CAPAB_SERVICE_DISCOVERY BIT(0)
+#define P2P_DEV_CAPAB_CLIENT_DISCOVERABILITY BIT(1)
+#define P2P_DEV_CAPAB_CONCURRENT_OPER BIT(2)
+#define P2P_DEV_CAPAB_INFRA_MANAGED BIT(3)
+#define P2P_DEV_CAPAB_DEVICE_LIMIT BIT(4)
+#define P2P_DEV_CAPAB_INVITATION_PROCEDURE BIT(5)
+
+/* P2P Capability - Group Capability bitmap */
+#define P2P_GROUP_CAPAB_GROUP_OWNER BIT(0)
+#define P2P_GROUP_CAPAB_PERSISTENT_GROUP BIT(1)
+#define P2P_GROUP_CAPAB_GROUP_LIMIT BIT(2)
+#define P2P_GROUP_CAPAB_INTRA_BSS_DIST BIT(3)
+#define P2P_GROUP_CAPAB_CROSS_CONN BIT(4)
+#define P2P_GROUP_CAPAB_PERSISTENT_RECONN BIT(5)
+#define P2P_GROUP_CAPAB_GROUP_FORMATION BIT(6)
+
+/* Invitation Flags */
+#define P2P_INVITATION_FLAGS_TYPE BIT(0)
+
+/* P2P Manageability */
+#define P2P_MAN_DEVICE_MANAGEMENT BIT(0)
+#define P2P_MAN_CROSS_CONNECTION_PERMITTED BIT(1)
+#define P2P_MAN_COEXISTENCE_OPTIONAL BIT(2)
+
+enum p2p_status_code {
+	P2P_SC_SUCCESS = 0,
+	P2P_SC_FAIL_INFO_CURRENTLY_UNAVAILABLE = 1,
+	P2P_SC_FAIL_INCOMPATIBLE_PARAMS = 2,
+	P2P_SC_FAIL_LIMIT_REACHED = 3,
+	P2P_SC_FAIL_INVALID_PARAMS = 4,
+	P2P_SC_FAIL_UNABLE_TO_ACCOMMODATE = 5,
+	P2P_SC_FAIL_PREV_PROTOCOL_ERROR = 6,
+	P2P_SC_FAIL_NO_COMMON_CHANNELS = 7,
+	P2P_SC_FAIL_UNKNOWN_GROUP = 8,
+	P2P_SC_FAIL_BOTH_GO_INTENT_15 = 9,
+	P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10,
+	P2P_SC_FAIL_REJECTED_BY_USER = 11,
+};
+
+#define P2P_WILDCARD_SSID "DIRECT-"
+#define P2P_WILDCARD_SSID_LEN 7
+
+/* P2P action frames */
+enum p2p_act_frame_type {
+	P2P_NOA = 0,
+	P2P_PRESENCE_REQ = 1,
+	P2P_PRESENCE_RESP = 2,
+	P2P_GO_DISC_REQ = 3
+};
+
+/* P2P public action frames */
+enum p2p_action_frame_type {
+	P2P_GO_NEG_REQ = 0,
+	P2P_GO_NEG_RESP = 1,
+	P2P_GO_NEG_CONF = 2,
+	P2P_INVITATION_REQ = 3,
+	P2P_INVITATION_RESP = 4,
+	P2P_DEV_DISC_REQ = 5,
+	P2P_DEV_DISC_RESP = 6,
+	P2P_PROV_DISC_REQ = 7,
+	P2P_PROV_DISC_RESP = 8
+};
+
+enum p2p_service_protocol_type {
+	P2P_SERV_ALL_SERVICES = 0,
+	P2P_SERV_BONJOUR = 1,
+	P2P_SERV_UPNP = 2,
+	P2P_SERV_WS_DISCOVERY = 3,
+	P2P_SERV_WIFI_DISPLAY = 4,
+	P2P_SERV_VENDOR_SPECIFIC = 255
+};
+
+enum p2p_sd_status {
+	P2P_SD_SUCCESS = 0,
+	P2P_SD_PROTO_NOT_AVAILABLE = 1,
+	P2P_SD_REQUESTED_INFO_NOT_AVAILABLE = 2,
+	P2P_SD_BAD_REQUEST = 3
+};
+
+
+enum wifi_display_subelem {
+	WFD_SUBELEM_DEVICE_INFO = 0,
+	WFD_SUBELEM_ASSOCIATED_BSSID = 1,
+	WFD_SUBELEM_AUDIO_FORMATS = 2,
+	WFD_SUBELEM_VIDEO_FORMATS = 3,
+	WFD_SUBELEM_3D_VIDEO_FORMATS = 4,
+	WFD_SUBELEM_CONTENT_PROTECTION = 5,
+	WFD_SUBELEM_COUPLED_SINK = 6,
+	WFD_SUBELEM_EXT_CAPAB = 7,
+	WFD_SUBELEM_LOCAL_IP_ADDRESS = 8,
+	WFD_SUBELEM_SESSION_INFO = 9
+};
+
+
+#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
+
+#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
+
+/* cipher suite selectors */
+#define WLAN_CIPHER_SUITE_USE_GROUP	0x000FAC00
+#define WLAN_CIPHER_SUITE_WEP40		0x000FAC01
+#define WLAN_CIPHER_SUITE_TKIP		0x000FAC02
+/* reserved: 				0x000FAC03 */
+#define WLAN_CIPHER_SUITE_CCMP		0x000FAC04
+#define WLAN_CIPHER_SUITE_WEP104	0x000FAC05
+#define WLAN_CIPHER_SUITE_AES_CMAC	0x000FAC06
+#define WLAN_CIPHER_SUITE_NO_GROUP_ADDR	0x000FAC07
+#define WLAN_CIPHER_SUITE_GCMP		0x000FAC08
+
+#define WLAN_CIPHER_SUITE_SMS4		0x00147201
+
+#define WLAN_CIPHER_SUITE_CKIP		0x00409600
+#define WLAN_CIPHER_SUITE_CKIP_CMIC	0x00409601
+#define WLAN_CIPHER_SUITE_CMIC		0x00409602
+#define WLAN_CIPHER_SUITE_KRK		0x004096FF /* for nl80211 use only */
+
+/* AKM suite selectors */
+#define WLAN_AKM_SUITE_8021X		0x000FAC01
+#define WLAN_AKM_SUITE_PSK		0x000FAC02
+#define WLAN_AKM_SUITE_CCKM		0x00409600
+
+
+/* IEEE 802.11v - WNM Action field values */
+enum wnm_action {
+	WNM_EVENT_REQ = 0,
+	WNM_EVENT_REPORT = 1,
+	WNM_DIAGNOSTIC_REQ = 2,
+	WNM_DIAGNOSTIC_REPORT = 3,
+	WNM_LOCATION_CFG_REQ = 4,
+	WNM_LOCATION_CFG_RESP = 5,
+	WNM_BSS_TRANS_MGMT_QUERY = 6,
+	WNM_BSS_TRANS_MGMT_REQ = 7,
+	WNM_BSS_TRANS_MGMT_RESP = 8,
+	WNM_FMS_REQ = 9,
+	WNM_FMS_RESP = 10,
+	WNM_COLLOCATED_INTERFERENCE_REQ = 11,
+	WNM_COLLOCATED_INTERFERENCE_REPORT = 12,
+	WNM_TFS_REQ = 13,
+	WNM_TFS_RESP = 14,
+	WNM_TFS_NOTIFY = 15,
+	WNM_SLEEP_MODE_REQ = 16,
+	WNM_SLEEP_MODE_RESP = 17,
+	WNM_TIM_BROADCAST_REQ = 18,
+	WNM_TIM_BROADCAST_RESP = 19,
+	WNM_QOS_TRAFFIC_CAPAB_UPDATE = 20,
+	WNM_CHANNEL_USAGE_REQ = 21,
+	WNM_CHANNEL_USAGE_RESP = 22,
+	WNM_DMS_REQ = 23,
+	WNM_DMS_RESP = 24,
+	WNM_TIMING_MEASUREMENT_REQ = 25,
+	WNM_NOTIFICATION_REQ = 26,
+	WNM_NOTIFICATION_RESP = 27
+};
+
+/* IEEE 802.11v - BSS Transition Management Request - Request Mode */
+#define WNM_BSS_TM_REQ_PREF_CAND_LIST_INCLUDED BIT(0)
+#define WNM_BSS_TM_REQ_ABRIDGED BIT(1)
+#define WNM_BSS_TM_REQ_DISASSOC_IMMINENT BIT(2)
+#define WNM_BSS_TM_REQ_BSS_TERMINATION_INCLUDED BIT(3)
+#define WNM_BSS_TM_REQ_ESS_DISASSOC_IMMINENT BIT(4)
+
+/* IEEE Std 802.11-2012, 8.4.2.62 20/40 BSS Coexistence element */
+#define WLAN_20_40_BSS_COEX_INFO_REQ            BIT(0)
+#define WLAN_20_40_BSS_COEX_40MHZ_INTOL         BIT(1)
+#define WLAN_20_40_BSS_COEX_20MHZ_WIDTH_REQ     BIT(2)
+#define WLAN_20_40_BSS_COEX_OBSS_EXEMPT_REQ     BIT(3)
+#define WLAN_20_40_BSS_COEX_OBSS_EXEMPT_GRNT    BIT(4)
+
+struct ieee80211_2040_bss_coex_ie {
+	u8 element_id;
+	u8 length;
+	u8 coex_param;
+} STRUCT_PACKED;
+
+struct ieee80211_2040_intol_chan_report {
+	u8 element_id;
+	u8 length;
+	u8 op_class;
+	u8 variable[0];	/* Channel List */
+} STRUCT_PACKED;
+
+/* IEEE 802.11v - WNM-Sleep Mode element */
+struct wnm_sleep_element {
+	u8 eid;     /* WLAN_EID_WNMSLEEP */
+	u8 len;
+	u8 action_type; /* WNM_SLEEP_ENTER/WNM_SLEEP_MODE_EXIT */
+	u8 status;
+	le16 intval;
+} STRUCT_PACKED;
+
+#define WNM_SLEEP_MODE_ENTER 0
+#define WNM_SLEEP_MODE_EXIT 1
+
+enum wnm_sleep_mode_response_status {
+	WNM_STATUS_SLEEP_ACCEPT = 0,
+	WNM_STATUS_SLEEP_EXIT_ACCEPT_GTK_UPDATE = 1,
+	WNM_STATUS_DENIED_ACTION = 2,
+	WNM_STATUS_DENIED_TMP = 3,
+	WNM_STATUS_DENIED_KEY = 4,
+	WNM_STATUS_DENIED_OTHER_WNM_SERVICE = 5
+};
+
+/* WNM-Sleep Mode subelement IDs */
+enum wnm_sleep_mode_subelement_id {
+	WNM_SLEEP_SUBELEM_GTK = 0,
+	WNM_SLEEP_SUBELEM_IGTK = 1
+};
+
+#endif /* IEEE802_11_DEFS_H */
diff --git a/hostap/src/common/privsep_commands.h b/hostap/src/common/privsep_commands.h
new file mode 100644
index 0000000..858b51d
--- /dev/null
+++ b/hostap/src/common/privsep_commands.h
@@ -0,0 +1,69 @@
+/*
+ * WPA Supplicant - privilege separation commands
+ * Copyright (c) 2007-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef PRIVSEP_COMMANDS_H
+#define PRIVSEP_COMMANDS_H
+
+enum privsep_cmd {
+	PRIVSEP_CMD_REGISTER,
+	PRIVSEP_CMD_UNREGISTER,
+	PRIVSEP_CMD_SCAN,
+	PRIVSEP_CMD_GET_SCAN_RESULTS,
+	PRIVSEP_CMD_ASSOCIATE,
+	PRIVSEP_CMD_GET_BSSID,
+	PRIVSEP_CMD_GET_SSID,
+	PRIVSEP_CMD_SET_KEY,
+	PRIVSEP_CMD_GET_CAPA,
+	PRIVSEP_CMD_L2_REGISTER,
+	PRIVSEP_CMD_L2_UNREGISTER,
+	PRIVSEP_CMD_L2_NOTIFY_AUTH_START,
+	PRIVSEP_CMD_L2_SEND,
+	PRIVSEP_CMD_SET_COUNTRY,
+};
+
+struct privsep_cmd_associate
+{
+	u8 bssid[ETH_ALEN];
+	u8 ssid[32];
+	size_t ssid_len;
+	int freq;
+	int pairwise_suite;
+	int group_suite;
+	int key_mgmt_suite;
+	int auth_alg;
+	int mode;
+	size_t wpa_ie_len;
+	/* followed by wpa_ie_len bytes of wpa_ie */
+};
+
+struct privsep_cmd_set_key
+{
+	int alg;
+	u8 addr[ETH_ALEN];
+	int key_idx;
+	int set_tx;
+	u8 seq[8];
+	size_t seq_len;
+	u8 key[32];
+	size_t key_len;
+};
+
+enum privsep_event {
+	PRIVSEP_EVENT_SCAN_RESULTS,
+	PRIVSEP_EVENT_ASSOC,
+	PRIVSEP_EVENT_DISASSOC,
+	PRIVSEP_EVENT_ASSOCINFO,
+	PRIVSEP_EVENT_MICHAEL_MIC_FAILURE,
+	PRIVSEP_EVENT_INTERFACE_STATUS,
+	PRIVSEP_EVENT_PMKID_CANDIDATE,
+	PRIVSEP_EVENT_STKSTART,
+	PRIVSEP_EVENT_FT_RESPONSE,
+	PRIVSEP_EVENT_RX_EAPOL,
+};
+
+#endif /* PRIVSEP_COMMANDS_H */
diff --git a/hostap/src/common/version.h b/hostap/src/common/version.h
new file mode 100644
index 0000000..04ed0ac
--- /dev/null
+++ b/hostap/src/common/version.h
@@ -0,0 +1,10 @@
+#ifndef VERSION_H
+#define VERSION_H
+
+#ifndef VERSION_STR_POSTFIX
+#define VERSION_STR_POSTFIX ""
+#endif /* VERSION_STR_POSTFIX */
+
+#define VERSION_STR "2.0" VERSION_STR_POSTFIX
+
+#endif /* VERSION_H */
diff --git a/hostap/src/common/wpa_common.c b/hostap/src/common/wpa_common.c
new file mode 100644
index 0000000..8d7a11c
--- /dev/null
+++ b/hostap/src/common/wpa_common.c
@@ -0,0 +1,1216 @@
+/*
+ * WPA/RSN - Shared functions for supplicant and authenticator
+ * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/md5.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/crypto.h"
+#include "ieee802_11_defs.h"
+#include "defs.h"
+#include "wpa_common.h"
+
+
+/**
+ * wpa_eapol_key_mic - Calculate EAPOL-Key MIC
+ * @key: EAPOL-Key Key Confirmation Key (KCK)
+ * @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
+ * @buf: Pointer to the beginning of the EAPOL header (version field)
+ * @len: Length of the EAPOL frame (from EAPOL header to the end of the frame)
+ * @mic: Pointer to the buffer to which the EAPOL-Key MIC is written
+ * Returns: 0 on success, -1 on failure
+ *
+ * Calculate EAPOL-Key MIC for an EAPOL-Key packet. The EAPOL-Key MIC field has
+ * to be cleared (all zeroes) when calling this function.
+ *
+ * Note: 'IEEE Std 802.11i-2004 - 8.5.2 EAPOL-Key frames' has an error in the
+ * description of the Key MIC calculation. It includes packet data from the
+ * beginning of the EAPOL-Key header, not EAPOL header. This incorrect change
+ * happened during final editing of the standard and the correct behavior is
+ * defined in the last draft (IEEE 802.11i/D10).
+ */
+int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
+		      u8 *mic)
+{
+	u8 hash[SHA1_MAC_LEN];
+
+	switch (ver) {
+#ifndef CONFIG_FIPS
+	case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
+		return hmac_md5(key, 16, buf, len, mic);
+#endif /* CONFIG_FIPS */
+	case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
+		if (hmac_sha1(key, 16, buf, len, hash))
+			return -1;
+		os_memcpy(mic, hash, MD5_MAC_LEN);
+		break;
+#if defined(CONFIG_IEEE80211R) || defined(CONFIG_IEEE80211W)
+	case WPA_KEY_INFO_TYPE_AES_128_CMAC:
+		return omac1_aes_128(key, buf, len, mic);
+#endif /* CONFIG_IEEE80211R || CONFIG_IEEE80211W */
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+
+/**
+ * wpa_pmk_to_ptk - Calculate PTK from PMK, addresses, and nonces
+ * @pmk: Pairwise master key
+ * @pmk_len: Length of PMK
+ * @label: Label to use in derivation
+ * @addr1: AA or SA
+ * @addr2: SA or AA
+ * @nonce1: ANonce or SNonce
+ * @nonce2: SNonce or ANonce
+ * @ptk: Buffer for pairwise transient key
+ * @ptk_len: Length of PTK
+ * @use_sha256: Whether to use SHA256-based KDF
+ *
+ * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
+ * PTK = PRF-X(PMK, "Pairwise key expansion",
+ *             Min(AA, SA) || Max(AA, SA) ||
+ *             Min(ANonce, SNonce) || Max(ANonce, SNonce))
+ *
+ * STK = PRF-X(SMK, "Peer key expansion",
+ *             Min(MAC_I, MAC_P) || Max(MAC_I, MAC_P) ||
+ *             Min(INonce, PNonce) || Max(INonce, PNonce))
+ */
+void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
+		    const u8 *addr1, const u8 *addr2,
+		    const u8 *nonce1, const u8 *nonce2,
+		    u8 *ptk, size_t ptk_len, int use_sha256)
+{
+	u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
+
+	if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
+		os_memcpy(data, addr1, ETH_ALEN);
+		os_memcpy(data + ETH_ALEN, addr2, ETH_ALEN);
+	} else {
+		os_memcpy(data, addr2, ETH_ALEN);
+		os_memcpy(data + ETH_ALEN, addr1, ETH_ALEN);
+	}
+
+	if (os_memcmp(nonce1, nonce2, WPA_NONCE_LEN) < 0) {
+		os_memcpy(data + 2 * ETH_ALEN, nonce1, WPA_NONCE_LEN);
+		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce2,
+			  WPA_NONCE_LEN);
+	} else {
+		os_memcpy(data + 2 * ETH_ALEN, nonce2, WPA_NONCE_LEN);
+		os_memcpy(data + 2 * ETH_ALEN + WPA_NONCE_LEN, nonce1,
+			  WPA_NONCE_LEN);
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (use_sha256)
+		sha256_prf(pmk, pmk_len, label, data, sizeof(data),
+			   ptk, ptk_len);
+	else
+#endif /* CONFIG_IEEE80211W */
+		sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
+			 ptk_len);
+
+	wpa_printf(MSG_DEBUG, "WPA: PTK derivation - A1=" MACSTR " A2=" MACSTR,
+		   MAC2STR(addr1), MAC2STR(addr2));
+	wpa_hexdump(MSG_DEBUG, "WPA: Nonce1", nonce1, WPA_NONCE_LEN);
+	wpa_hexdump(MSG_DEBUG, "WPA: Nonce2", nonce2, WPA_NONCE_LEN);
+	wpa_hexdump_key(MSG_DEBUG, "WPA: PMK", pmk, pmk_len);
+	wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", ptk, ptk_len);
+}
+
+
+#ifdef CONFIG_IEEE80211R
+int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
+	       u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
+	       const u8 *ftie, size_t ftie_len,
+	       const u8 *rsnie, size_t rsnie_len,
+	       const u8 *ric, size_t ric_len, u8 *mic)
+{
+	u8 *buf, *pos;
+	size_t buf_len;
+
+	buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
+	buf = os_malloc(buf_len);
+	if (buf == NULL)
+		return -1;
+
+	pos = buf;
+	os_memcpy(pos, sta_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+	os_memcpy(pos, ap_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+	*pos++ = transaction_seqnum;
+	if (rsnie) {
+		os_memcpy(pos, rsnie, rsnie_len);
+		pos += rsnie_len;
+	}
+	if (mdie) {
+		os_memcpy(pos, mdie, mdie_len);
+		pos += mdie_len;
+	}
+	if (ftie) {
+		struct rsn_ftie *_ftie;
+		os_memcpy(pos, ftie, ftie_len);
+		if (ftie_len < 2 + sizeof(*_ftie)) {
+			os_free(buf);
+			return -1;
+		}
+		_ftie = (struct rsn_ftie *) (pos + 2);
+		os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
+		pos += ftie_len;
+	}
+	if (ric) {
+		os_memcpy(pos, ric, ric_len);
+		pos += ric_len;
+	}
+
+	wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
+	if (omac1_aes_128(kck, buf, pos - buf, mic)) {
+		os_free(buf);
+		return -1;
+	}
+
+	os_free(buf);
+
+	return 0;
+}
+
+
+static int wpa_ft_parse_ftie(const u8 *ie, size_t ie_len,
+			     struct wpa_ft_ies *parse)
+{
+	const u8 *end, *pos;
+
+	parse->ftie = ie;
+	parse->ftie_len = ie_len;
+
+	pos = ie + sizeof(struct rsn_ftie);
+	end = ie + ie_len;
+
+	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+		switch (pos[0]) {
+		case FTIE_SUBELEM_R1KH_ID:
+			if (pos[1] != FT_R1KH_ID_LEN) {
+				wpa_printf(MSG_DEBUG, "FT: Invalid R1KH-ID "
+					   "length in FTIE: %d", pos[1]);
+				return -1;
+			}
+			parse->r1kh_id = pos + 2;
+			break;
+		case FTIE_SUBELEM_GTK:
+			parse->gtk = pos + 2;
+			parse->gtk_len = pos[1];
+			break;
+		case FTIE_SUBELEM_R0KH_ID:
+			if (pos[1] < 1 || pos[1] > FT_R0KH_ID_MAX_LEN) {
+				wpa_printf(MSG_DEBUG, "FT: Invalid R0KH-ID "
+					   "length in FTIE: %d", pos[1]);
+				return -1;
+			}
+			parse->r0kh_id = pos + 2;
+			parse->r0kh_id_len = pos[1];
+			break;
+#ifdef CONFIG_IEEE80211W
+		case FTIE_SUBELEM_IGTK:
+			parse->igtk = pos + 2;
+			parse->igtk_len = pos[1];
+			break;
+#endif /* CONFIG_IEEE80211W */
+		}
+
+		pos += 2 + pos[1];
+	}
+
+	return 0;
+}
+
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len,
+		     struct wpa_ft_ies *parse)
+{
+	const u8 *end, *pos;
+	struct wpa_ie_data data;
+	int ret;
+	const struct rsn_ftie *ftie;
+	int prot_ie_count = 0;
+
+	os_memset(parse, 0, sizeof(*parse));
+	if (ies == NULL)
+		return 0;
+
+	pos = ies;
+	end = ies + ies_len;
+	while (pos + 2 <= end && pos + 2 + pos[1] <= end) {
+		switch (pos[0]) {
+		case WLAN_EID_RSN:
+			parse->rsn = pos + 2;
+			parse->rsn_len = pos[1];
+			ret = wpa_parse_wpa_ie_rsn(parse->rsn - 2,
+						   parse->rsn_len + 2,
+						   &data);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "FT: Failed to parse "
+					   "RSN IE: %d", ret);
+				return -1;
+			}
+			if (data.num_pmkid == 1 && data.pmkid)
+				parse->rsn_pmkid = data.pmkid;
+			break;
+		case WLAN_EID_MOBILITY_DOMAIN:
+			parse->mdie = pos + 2;
+			parse->mdie_len = pos[1];
+			break;
+		case WLAN_EID_FAST_BSS_TRANSITION:
+			if (pos[1] < sizeof(*ftie))
+				return -1;
+			ftie = (const struct rsn_ftie *) (pos + 2);
+			prot_ie_count = ftie->mic_control[1];
+			if (wpa_ft_parse_ftie(pos + 2, pos[1], parse) < 0)
+				return -1;
+			break;
+		case WLAN_EID_TIMEOUT_INTERVAL:
+			parse->tie = pos + 2;
+			parse->tie_len = pos[1];
+			break;
+		case WLAN_EID_RIC_DATA:
+			if (parse->ric == NULL)
+				parse->ric = pos;
+			break;
+		}
+
+		pos += 2 + pos[1];
+	}
+
+	if (prot_ie_count == 0)
+		return 0; /* no MIC */
+
+	/*
+	 * Check that the protected IE count matches with IEs included in the
+	 * frame.
+	 */
+	if (parse->rsn)
+		prot_ie_count--;
+	if (parse->mdie)
+		prot_ie_count--;
+	if (parse->ftie)
+		prot_ie_count--;
+	if (prot_ie_count < 0) {
+		wpa_printf(MSG_DEBUG, "FT: Some required IEs not included in "
+			   "the protected IE count");
+		return -1;
+	}
+
+	if (prot_ie_count == 0 && parse->ric) {
+		wpa_printf(MSG_DEBUG, "FT: RIC IE(s) in the frame, but not "
+			   "included in protected IE count");
+		return -1;
+	}
+
+	/* Determine the end of the RIC IE(s) */
+	pos = parse->ric;
+	while (pos && pos + 2 <= end && pos + 2 + pos[1] <= end &&
+	       prot_ie_count) {
+		prot_ie_count--;
+		pos += 2 + pos[1];
+	}
+	parse->ric_len = pos - parse->ric;
+	if (prot_ie_count) {
+		wpa_printf(MSG_DEBUG, "FT: %d protected IEs missing from "
+			   "frame", (int) prot_ie_count);
+		return -1;
+	}
+
+	return 0;
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+#ifndef CONFIG_NO_WPA2
+static int rsn_selector_to_bitfield(const u8 *s)
+{
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_NONE)
+		return WPA_CIPHER_NONE;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP40)
+		return WPA_CIPHER_WEP40;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_TKIP)
+		return WPA_CIPHER_TKIP;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_CCMP)
+		return WPA_CIPHER_CCMP;
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_WEP104)
+		return WPA_CIPHER_WEP104;
+#ifdef CONFIG_IEEE80211W
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_AES_128_CMAC)
+		return WPA_CIPHER_AES_128_CMAC;
+#endif /* CONFIG_IEEE80211W */
+	if (RSN_SELECTOR_GET(s) == RSN_CIPHER_SUITE_GCMP)
+		return WPA_CIPHER_GCMP;
+	return 0;
+}
+
+
+static int rsn_key_mgmt_to_bitfield(const u8 *s)
+{
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_UNSPEC_802_1X)
+		return WPA_KEY_MGMT_IEEE8021X;
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X)
+		return WPA_KEY_MGMT_PSK;
+#ifdef CONFIG_IEEE80211R
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_802_1X)
+		return WPA_KEY_MGMT_FT_IEEE8021X;
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_PSK)
+		return WPA_KEY_MGMT_FT_PSK;
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SHA256)
+		return WPA_KEY_MGMT_IEEE8021X_SHA256;
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_PSK_SHA256)
+		return WPA_KEY_MGMT_PSK_SHA256;
+#endif /* CONFIG_IEEE80211W */
+#ifdef CONFIG_SAE
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_SAE)
+		return WPA_KEY_MGMT_SAE;
+	if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_FT_SAE)
+		return WPA_KEY_MGMT_FT_SAE;
+#endif /* CONFIG_SAE */
+	return 0;
+}
+#endif /* CONFIG_NO_WPA2 */
+
+
+/**
+ * wpa_parse_wpa_ie_rsn - Parse RSN IE
+ * @rsn_ie: Buffer containing RSN IE
+ * @rsn_ie_len: RSN IE buffer length (including IE number and length octets)
+ * @data: Pointer to structure that will be filled in with parsed data
+ * Returns: 0 on success, <0 on failure
+ */
+int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
+			 struct wpa_ie_data *data)
+{
+#ifndef CONFIG_NO_WPA2
+	const struct rsn_ie_hdr *hdr;
+	const u8 *pos;
+	int left;
+	int i, count;
+
+	os_memset(data, 0, sizeof(*data));
+	data->proto = WPA_PROTO_RSN;
+	data->pairwise_cipher = WPA_CIPHER_CCMP;
+	data->group_cipher = WPA_CIPHER_CCMP;
+	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+	data->capabilities = 0;
+	data->pmkid = NULL;
+	data->num_pmkid = 0;
+#ifdef CONFIG_IEEE80211W
+	data->mgmt_group_cipher = WPA_CIPHER_AES_128_CMAC;
+#else /* CONFIG_IEEE80211W */
+	data->mgmt_group_cipher = 0;
+#endif /* CONFIG_IEEE80211W */
+
+	if (rsn_ie_len == 0) {
+		/* No RSN IE - fail silently */
+		return -1;
+	}
+
+	if (rsn_ie_len < sizeof(struct rsn_ie_hdr)) {
+		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
+			   __func__, (unsigned long) rsn_ie_len);
+		return -1;
+	}
+
+	hdr = (const struct rsn_ie_hdr *) rsn_ie;
+
+	if (hdr->elem_id != WLAN_EID_RSN ||
+	    hdr->len != rsn_ie_len - 2 ||
+	    WPA_GET_LE16(hdr->version) != RSN_VERSION) {
+		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
+			   __func__);
+		return -2;
+	}
+
+	pos = (const u8 *) (hdr + 1);
+	left = rsn_ie_len - sizeof(*hdr);
+
+	if (left >= RSN_SELECTOR_LEN) {
+		data->group_cipher = rsn_selector_to_bitfield(pos);
+#ifdef CONFIG_IEEE80211W
+		if (data->group_cipher == WPA_CIPHER_AES_128_CMAC) {
+			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as group "
+				   "cipher", __func__);
+			return -1;
+		}
+#endif /* CONFIG_IEEE80211W */
+		pos += RSN_SELECTOR_LEN;
+		left -= RSN_SELECTOR_LEN;
+	} else if (left > 0) {
+		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
+			   __func__, left);
+		return -3;
+	}
+
+	if (left >= 2) {
+		data->pairwise_cipher = 0;
+		count = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
+				   "count %u left %u", __func__, count, left);
+			return -4;
+		}
+		for (i = 0; i < count; i++) {
+			data->pairwise_cipher |= rsn_selector_to_bitfield(pos);
+			pos += RSN_SELECTOR_LEN;
+			left -= RSN_SELECTOR_LEN;
+		}
+#ifdef CONFIG_IEEE80211W
+		if (data->pairwise_cipher & WPA_CIPHER_AES_128_CMAC) {
+			wpa_printf(MSG_DEBUG, "%s: AES-128-CMAC used as "
+				   "pairwise cipher", __func__);
+			return -1;
+		}
+#endif /* CONFIG_IEEE80211W */
+	} else if (left == 1) {
+		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
+			   __func__);
+		return -5;
+	}
+
+	if (left >= 2) {
+		data->key_mgmt = 0;
+		count = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (count == 0 || left < count * RSN_SELECTOR_LEN) {
+			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
+				   "count %u left %u", __func__, count, left);
+			return -6;
+		}
+		for (i = 0; i < count; i++) {
+			data->key_mgmt |= rsn_key_mgmt_to_bitfield(pos);
+			pos += RSN_SELECTOR_LEN;
+			left -= RSN_SELECTOR_LEN;
+		}
+	} else if (left == 1) {
+		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
+			   __func__);
+		return -7;
+	}
+
+	if (left >= 2) {
+		data->capabilities = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+	}
+
+	if (left >= 2) {
+		data->num_pmkid = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (left < (int) data->num_pmkid * PMKID_LEN) {
+			wpa_printf(MSG_DEBUG, "%s: PMKID underflow "
+				   "(num_pmkid=%lu left=%d)",
+				   __func__, (unsigned long) data->num_pmkid,
+				   left);
+			data->num_pmkid = 0;
+			return -9;
+		} else {
+			data->pmkid = pos;
+			pos += data->num_pmkid * PMKID_LEN;
+			left -= data->num_pmkid * PMKID_LEN;
+		}
+	}
+
+#ifdef CONFIG_IEEE80211W
+	if (left >= 4) {
+		data->mgmt_group_cipher = rsn_selector_to_bitfield(pos);
+		if (data->mgmt_group_cipher != WPA_CIPHER_AES_128_CMAC) {
+			wpa_printf(MSG_DEBUG, "%s: Unsupported management "
+				   "group cipher 0x%x", __func__,
+				   data->mgmt_group_cipher);
+			return -10;
+		}
+		pos += RSN_SELECTOR_LEN;
+		left -= RSN_SELECTOR_LEN;
+	}
+#endif /* CONFIG_IEEE80211W */
+
+	if (left > 0) {
+		wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
+			   __func__, left);
+	}
+
+	return 0;
+#else /* CONFIG_NO_WPA2 */
+	return -1;
+#endif /* CONFIG_NO_WPA2 */
+}
+
+
+static int wpa_selector_to_bitfield(const u8 *s)
+{
+	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_NONE)
+		return WPA_CIPHER_NONE;
+	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP40)
+		return WPA_CIPHER_WEP40;
+	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_TKIP)
+		return WPA_CIPHER_TKIP;
+	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_CCMP)
+		return WPA_CIPHER_CCMP;
+	if (RSN_SELECTOR_GET(s) == WPA_CIPHER_SUITE_WEP104)
+		return WPA_CIPHER_WEP104;
+	return 0;
+}
+
+
+static int wpa_key_mgmt_to_bitfield(const u8 *s)
+{
+	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_UNSPEC_802_1X)
+		return WPA_KEY_MGMT_IEEE8021X;
+	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X)
+		return WPA_KEY_MGMT_PSK;
+	if (RSN_SELECTOR_GET(s) == WPA_AUTH_KEY_MGMT_NONE)
+		return WPA_KEY_MGMT_WPA_NONE;
+	return 0;
+}
+
+
+int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
+			 struct wpa_ie_data *data)
+{
+	const struct wpa_ie_hdr *hdr;
+	const u8 *pos;
+	int left;
+	int i, count;
+
+	os_memset(data, 0, sizeof(*data));
+	data->proto = WPA_PROTO_WPA;
+	data->pairwise_cipher = WPA_CIPHER_TKIP;
+	data->group_cipher = WPA_CIPHER_TKIP;
+	data->key_mgmt = WPA_KEY_MGMT_IEEE8021X;
+	data->capabilities = 0;
+	data->pmkid = NULL;
+	data->num_pmkid = 0;
+	data->mgmt_group_cipher = 0;
+
+	if (wpa_ie_len == 0) {
+		/* No WPA IE - fail silently */
+		return -1;
+	}
+
+	if (wpa_ie_len < sizeof(struct wpa_ie_hdr)) {
+		wpa_printf(MSG_DEBUG, "%s: ie len too short %lu",
+			   __func__, (unsigned long) wpa_ie_len);
+		return -1;
+	}
+
+	hdr = (const struct wpa_ie_hdr *) wpa_ie;
+
+	if (hdr->elem_id != WLAN_EID_VENDOR_SPECIFIC ||
+	    hdr->len != wpa_ie_len - 2 ||
+	    RSN_SELECTOR_GET(hdr->oui) != WPA_OUI_TYPE ||
+	    WPA_GET_LE16(hdr->version) != WPA_VERSION) {
+		wpa_printf(MSG_DEBUG, "%s: malformed ie or unknown version",
+			   __func__);
+		return -2;
+	}
+
+	pos = (const u8 *) (hdr + 1);
+	left = wpa_ie_len - sizeof(*hdr);
+
+	if (left >= WPA_SELECTOR_LEN) {
+		data->group_cipher = wpa_selector_to_bitfield(pos);
+		pos += WPA_SELECTOR_LEN;
+		left -= WPA_SELECTOR_LEN;
+	} else if (left > 0) {
+		wpa_printf(MSG_DEBUG, "%s: ie length mismatch, %u too much",
+			   __func__, left);
+		return -3;
+	}
+
+	if (left >= 2) {
+		data->pairwise_cipher = 0;
+		count = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+			wpa_printf(MSG_DEBUG, "%s: ie count botch (pairwise), "
+				   "count %u left %u", __func__, count, left);
+			return -4;
+		}
+		for (i = 0; i < count; i++) {
+			data->pairwise_cipher |= wpa_selector_to_bitfield(pos);
+			pos += WPA_SELECTOR_LEN;
+			left -= WPA_SELECTOR_LEN;
+		}
+	} else if (left == 1) {
+		wpa_printf(MSG_DEBUG, "%s: ie too short (for key mgmt)",
+			   __func__);
+		return -5;
+	}
+
+	if (left >= 2) {
+		data->key_mgmt = 0;
+		count = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+		if (count == 0 || left < count * WPA_SELECTOR_LEN) {
+			wpa_printf(MSG_DEBUG, "%s: ie count botch (key mgmt), "
+				   "count %u left %u", __func__, count, left);
+			return -6;
+		}
+		for (i = 0; i < count; i++) {
+			data->key_mgmt |= wpa_key_mgmt_to_bitfield(pos);
+			pos += WPA_SELECTOR_LEN;
+			left -= WPA_SELECTOR_LEN;
+		}
+	} else if (left == 1) {
+		wpa_printf(MSG_DEBUG, "%s: ie too short (for capabilities)",
+			   __func__);
+		return -7;
+	}
+
+	if (left >= 2) {
+		data->capabilities = WPA_GET_LE16(pos);
+		pos += 2;
+		left -= 2;
+	}
+
+	if (left > 0) {
+		wpa_printf(MSG_DEBUG, "%s: ie has %u trailing bytes - ignored",
+			   __func__, left);
+	}
+
+	return 0;
+}
+
+
+#ifdef CONFIG_IEEE80211R
+
+/**
+ * wpa_derive_pmk_r0 - Derive PMK-R0 and PMKR0Name
+ *
+ * IEEE Std 802.11r-2008 - 8.5.1.5.3
+ */
+void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
+		       const u8 *ssid, size_t ssid_len,
+		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
+		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name)
+{
+	u8 buf[1 + WPA_MAX_SSID_LEN + MOBILITY_DOMAIN_ID_LEN + 1 +
+	       FT_R0KH_ID_MAX_LEN + ETH_ALEN];
+	u8 *pos, r0_key_data[48], hash[32];
+	const u8 *addr[2];
+	size_t len[2];
+
+	/*
+	 * R0-Key-Data = KDF-384(XXKey, "FT-R0",
+	 *                       SSIDlength || SSID || MDID || R0KHlength ||
+	 *                       R0KH-ID || S0KH-ID)
+	 * XXKey is either the second 256 bits of MSK or PSK.
+	 * PMK-R0 = L(R0-Key-Data, 0, 256)
+	 * PMK-R0Name-Salt = L(R0-Key-Data, 256, 128)
+	 */
+	if (ssid_len > WPA_MAX_SSID_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
+		return;
+	pos = buf;
+	*pos++ = ssid_len;
+	os_memcpy(pos, ssid, ssid_len);
+	pos += ssid_len;
+	os_memcpy(pos, mdid, MOBILITY_DOMAIN_ID_LEN);
+	pos += MOBILITY_DOMAIN_ID_LEN;
+	*pos++ = r0kh_id_len;
+	os_memcpy(pos, r0kh_id, r0kh_id_len);
+	pos += r0kh_id_len;
+	os_memcpy(pos, s0kh_id, ETH_ALEN);
+	pos += ETH_ALEN;
+
+	sha256_prf(xxkey, xxkey_len, "FT-R0", buf, pos - buf,
+		   r0_key_data, sizeof(r0_key_data));
+	os_memcpy(pmk_r0, r0_key_data, PMK_LEN);
+
+	/*
+	 * PMKR0Name = Truncate-128(SHA-256("FT-R0N" || PMK-R0Name-Salt)
+	 */
+	addr[0] = (const u8 *) "FT-R0N";
+	len[0] = 6;
+	addr[1] = r0_key_data + PMK_LEN;
+	len[1] = 16;
+
+	sha256_vector(2, addr, len, hash);
+	os_memcpy(pmk_r0_name, hash, WPA_PMK_NAME_LEN);
+}
+
+
+/**
+ * wpa_derive_pmk_r1_name - Derive PMKR1Name
+ *
+ * IEEE Std 802.11r-2008 - 8.5.1.5.4
+ */
+void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
+			    const u8 *s1kh_id, u8 *pmk_r1_name)
+{
+	u8 hash[32];
+	const u8 *addr[4];
+	size_t len[4];
+
+	/*
+	 * PMKR1Name = Truncate-128(SHA-256("FT-R1N" || PMKR0Name ||
+	 *                                  R1KH-ID || S1KH-ID))
+	 */
+	addr[0] = (const u8 *) "FT-R1N";
+	len[0] = 6;
+	addr[1] = pmk_r0_name;
+	len[1] = WPA_PMK_NAME_LEN;
+	addr[2] = r1kh_id;
+	len[2] = FT_R1KH_ID_LEN;
+	addr[3] = s1kh_id;
+	len[3] = ETH_ALEN;
+
+	sha256_vector(4, addr, len, hash);
+	os_memcpy(pmk_r1_name, hash, WPA_PMK_NAME_LEN);
+}
+
+
+/**
+ * wpa_derive_pmk_r1 - Derive PMK-R1 and PMKR1Name from PMK-R0
+ *
+ * IEEE Std 802.11r-2008 - 8.5.1.5.4
+ */
+void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+		       const u8 *r1kh_id, const u8 *s1kh_id,
+		       u8 *pmk_r1, u8 *pmk_r1_name)
+{
+	u8 buf[FT_R1KH_ID_LEN + ETH_ALEN];
+	u8 *pos;
+
+	/* PMK-R1 = KDF-256(PMK-R0, "FT-R1", R1KH-ID || S1KH-ID) */
+	pos = buf;
+	os_memcpy(pos, r1kh_id, FT_R1KH_ID_LEN);
+	pos += FT_R1KH_ID_LEN;
+	os_memcpy(pos, s1kh_id, ETH_ALEN);
+	pos += ETH_ALEN;
+
+	sha256_prf(pmk_r0, PMK_LEN, "FT-R1", buf, pos - buf, pmk_r1, PMK_LEN);
+
+	wpa_derive_pmk_r1_name(pmk_r0_name, r1kh_id, s1kh_id, pmk_r1_name);
+}
+
+
+/**
+ * wpa_pmk_r1_to_ptk - Derive PTK and PTKName from PMK-R1
+ *
+ * IEEE Std 802.11r-2008 - 8.5.1.5.5
+ */
+void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+		       const u8 *sta_addr, const u8 *bssid,
+		       const u8 *pmk_r1_name,
+		       u8 *ptk, size_t ptk_len, u8 *ptk_name)
+{
+	u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
+	u8 *pos, hash[32];
+	const u8 *addr[6];
+	size_t len[6];
+
+	/*
+	 * PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
+	 *                  BSSID || STA-ADDR)
+	 */
+	pos = buf;
+	os_memcpy(pos, snonce, WPA_NONCE_LEN);
+	pos += WPA_NONCE_LEN;
+	os_memcpy(pos, anonce, WPA_NONCE_LEN);
+	pos += WPA_NONCE_LEN;
+	os_memcpy(pos, bssid, ETH_ALEN);
+	pos += ETH_ALEN;
+	os_memcpy(pos, sta_addr, ETH_ALEN);
+	pos += ETH_ALEN;
+
+	sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
+
+	/*
+	 * PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
+	 *                                ANonce || BSSID || STA-ADDR))
+	 */
+	addr[0] = pmk_r1_name;
+	len[0] = WPA_PMK_NAME_LEN;
+	addr[1] = (const u8 *) "FT-PTKN";
+	len[1] = 7;
+	addr[2] = snonce;
+	len[2] = WPA_NONCE_LEN;
+	addr[3] = anonce;
+	len[3] = WPA_NONCE_LEN;
+	addr[4] = bssid;
+	len[4] = ETH_ALEN;
+	addr[5] = sta_addr;
+	len[5] = ETH_ALEN;
+
+	sha256_vector(6, addr, len, hash);
+	os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
+}
+
+#endif /* CONFIG_IEEE80211R */
+
+
+/**
+ * rsn_pmkid - Calculate PMK identifier
+ * @pmk: Pairwise master key
+ * @pmk_len: Length of pmk in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @pmkid: Buffer for PMKID
+ * @use_sha256: Whether to use SHA256-based KDF
+ *
+ * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
+ * PMKID = HMAC-SHA1-128(PMK, "PMK Name" || AA || SPA)
+ */
+void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
+	       u8 *pmkid, int use_sha256)
+{
+	char *title = "PMK Name";
+	const u8 *addr[3];
+	const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
+	unsigned char hash[SHA256_MAC_LEN];
+
+	addr[0] = (u8 *) title;
+	addr[1] = aa;
+	addr[2] = spa;
+
+#ifdef CONFIG_IEEE80211W
+	if (use_sha256)
+		hmac_sha256_vector(pmk, pmk_len, 3, addr, len, hash);
+	else
+#endif /* CONFIG_IEEE80211W */
+		hmac_sha1_vector(pmk, pmk_len, 3, addr, len, hash);
+	os_memcpy(pmkid, hash, PMKID_LEN);
+}
+
+
+/**
+ * wpa_cipher_txt - Convert cipher suite to a text string
+ * @cipher: Cipher suite (WPA_CIPHER_* enum)
+ * Returns: Pointer to a text string of the cipher suite name
+ */
+const char * wpa_cipher_txt(int cipher)
+{
+	switch (cipher) {
+	case WPA_CIPHER_NONE:
+		return "NONE";
+	case WPA_CIPHER_WEP40:
+		return "WEP-40";
+	case WPA_CIPHER_WEP104:
+		return "WEP-104";
+	case WPA_CIPHER_TKIP:
+		return "TKIP";
+	case WPA_CIPHER_CCMP:
+		return "CCMP";
+	case WPA_CIPHER_CCMP | WPA_CIPHER_TKIP:
+		return "CCMP+TKIP";
+	case WPA_CIPHER_GCMP:
+		return "GCMP";
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+/**
+ * wpa_key_mgmt_txt - Convert key management suite to a text string
+ * @key_mgmt: Key management suite (WPA_KEY_MGMT_* enum)
+ * @proto: WPA/WPA2 version (WPA_PROTO_*)
+ * Returns: Pointer to a text string of the key management suite name
+ */
+const char * wpa_key_mgmt_txt(int key_mgmt, int proto)
+{
+	switch (key_mgmt) {
+	case WPA_KEY_MGMT_IEEE8021X:
+		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
+			return "WPA2+WPA/IEEE 802.1X/EAP";
+		return proto == WPA_PROTO_RSN ?
+			"WPA2/IEEE 802.1X/EAP" : "WPA/IEEE 802.1X/EAP";
+	case WPA_KEY_MGMT_PSK:
+		if (proto == (WPA_PROTO_RSN | WPA_PROTO_WPA))
+			return "WPA2-PSK+WPA-PSK";
+		return proto == WPA_PROTO_RSN ?
+			"WPA2-PSK" : "WPA-PSK";
+	case WPA_KEY_MGMT_NONE:
+		return "NONE";
+	case WPA_KEY_MGMT_IEEE8021X_NO_WPA:
+		return "IEEE 802.1X (no WPA)";
+#ifdef CONFIG_IEEE80211R
+	case WPA_KEY_MGMT_FT_IEEE8021X:
+		return "FT-EAP";
+	case WPA_KEY_MGMT_FT_PSK:
+		return "FT-PSK";
+#endif /* CONFIG_IEEE80211R */
+#ifdef CONFIG_IEEE80211W
+	case WPA_KEY_MGMT_IEEE8021X_SHA256:
+		return "WPA2-EAP-SHA256";
+	case WPA_KEY_MGMT_PSK_SHA256:
+		return "WPA2-PSK-SHA256";
+#endif /* CONFIG_IEEE80211W */
+	default:
+		return "UNKNOWN";
+	}
+}
+
+
+int wpa_compare_rsn_ie(int ft_initial_assoc,
+		       const u8 *ie1, size_t ie1len,
+		       const u8 *ie2, size_t ie2len)
+{
+	if (ie1 == NULL || ie2 == NULL)
+		return -1;
+
+	if (ie1len == ie2len && os_memcmp(ie1, ie2, ie1len) == 0)
+		return 0; /* identical IEs */
+
+#ifdef CONFIG_IEEE80211R
+	if (ft_initial_assoc) {
+		struct wpa_ie_data ie1d, ie2d;
+		/*
+		 * The PMKID-List in RSN IE is different between Beacon/Probe
+		 * Response/(Re)Association Request frames and EAPOL-Key
+		 * messages in FT initial mobility domain association. Allow
+		 * for this, but verify that other parts of the RSN IEs are
+		 * identical.
+		 */
+		if (wpa_parse_wpa_ie_rsn(ie1, ie1len, &ie1d) < 0 ||
+		    wpa_parse_wpa_ie_rsn(ie2, ie2len, &ie2d) < 0)
+			return -1;
+		if (ie1d.proto == ie2d.proto &&
+		    ie1d.pairwise_cipher == ie2d.pairwise_cipher &&
+		    ie1d.group_cipher == ie2d.group_cipher &&
+		    ie1d.key_mgmt == ie2d.key_mgmt &&
+		    ie1d.capabilities == ie2d.capabilities &&
+		    ie1d.mgmt_group_cipher == ie2d.mgmt_group_cipher)
+			return 0;
+	}
+#endif /* CONFIG_IEEE80211R */
+
+	return -1;
+}
+
+
+#ifdef CONFIG_IEEE80211R
+int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid)
+{
+	u8 *start, *end, *rpos, *rend;
+	int added = 0;
+
+	start = ies;
+	end = ies + ies_len;
+
+	while (start < end) {
+		if (*start == WLAN_EID_RSN)
+			break;
+		start += 2 + start[1];
+	}
+	if (start >= end) {
+		wpa_printf(MSG_ERROR, "FT: Could not find RSN IE in "
+			   "IEs data");
+		return -1;
+	}
+	wpa_hexdump(MSG_DEBUG, "FT: RSN IE before modification",
+		    start, 2 + start[1]);
+
+	/* Find start of PMKID-Count */
+	rpos = start + 2;
+	rend = rpos + start[1];
+
+	/* Skip Version and Group Data Cipher Suite */
+	rpos += 2 + 4;
+	/* Skip Pairwise Cipher Suite Count and List */
+	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
+	/* Skip AKM Suite Count and List */
+	rpos += 2 + WPA_GET_LE16(rpos) * RSN_SELECTOR_LEN;
+
+	if (rpos == rend) {
+		/* Add RSN Capabilities */
+		os_memmove(rpos + 2, rpos, end - rpos);
+		*rpos++ = 0;
+		*rpos++ = 0;
+	} else {
+		/* Skip RSN Capabilities */
+		rpos += 2;
+		if (rpos > rend) {
+			wpa_printf(MSG_ERROR, "FT: Could not parse RSN IE in "
+				   "IEs data");
+			return -1;
+		}
+	}
+
+	if (rpos == rend) {
+		/* No PMKID-Count field included; add it */
+		os_memmove(rpos + 2 + PMKID_LEN, rpos, end - rpos);
+		WPA_PUT_LE16(rpos, 1);
+		rpos += 2;
+		os_memcpy(rpos, pmkid, PMKID_LEN);
+		added += 2 + PMKID_LEN;
+		start[1] += 2 + PMKID_LEN;
+	} else {
+		/* PMKID-Count was included; use it */
+		if (WPA_GET_LE16(rpos) != 0) {
+			wpa_printf(MSG_ERROR, "FT: Unexpected PMKID "
+				   "in RSN IE in EAPOL-Key data");
+			return -1;
+		}
+		WPA_PUT_LE16(rpos, 1);
+		rpos += 2;
+		os_memmove(rpos + PMKID_LEN, rpos, end - rpos);
+		os_memcpy(rpos, pmkid, PMKID_LEN);
+		added += PMKID_LEN;
+		start[1] += PMKID_LEN;
+	}
+
+	wpa_hexdump(MSG_DEBUG, "FT: RSN IE after modification "
+		    "(PMKID inserted)", start, 2 + start[1]);
+
+	return added;
+}
+#endif /* CONFIG_IEEE80211R */
+
+
+int wpa_cipher_key_len(int cipher)
+{
+	switch (cipher) {
+	case WPA_CIPHER_CCMP:
+	case WPA_CIPHER_GCMP:
+		return 16;
+	case WPA_CIPHER_TKIP:
+		return 32;
+	case WPA_CIPHER_WEP104:
+		return 13;
+	case WPA_CIPHER_WEP40:
+		return 5;
+	}
+
+	return 0;
+}
+
+
+int wpa_cipher_rsc_len(int cipher)
+{
+	switch (cipher) {
+	case WPA_CIPHER_CCMP:
+	case WPA_CIPHER_GCMP:
+	case WPA_CIPHER_TKIP:
+		return 6;
+	case WPA_CIPHER_WEP104:
+	case WPA_CIPHER_WEP40:
+		return 0;
+	}
+
+	return 0;
+}
+
+
+int wpa_cipher_to_alg(int cipher)
+{
+	switch (cipher) {
+	case WPA_CIPHER_CCMP:
+		return WPA_ALG_CCMP;
+	case WPA_CIPHER_GCMP:
+		return WPA_ALG_GCMP;
+	case WPA_CIPHER_TKIP:
+		return WPA_ALG_TKIP;
+	case WPA_CIPHER_WEP104:
+	case WPA_CIPHER_WEP40:
+		return WPA_ALG_WEP;
+	}
+	return WPA_ALG_NONE;
+}
+
+
+int wpa_cipher_valid_pairwise(int cipher)
+{
+	return cipher == WPA_CIPHER_CCMP ||
+		cipher == WPA_CIPHER_GCMP ||
+		cipher == WPA_CIPHER_TKIP;
+}
+
+
+u32 wpa_cipher_to_suite(int proto, int cipher)
+{
+	if (cipher & WPA_CIPHER_CCMP)
+		return (proto == WPA_PROTO_RSN ?
+			RSN_CIPHER_SUITE_CCMP : WPA_CIPHER_SUITE_CCMP);
+	if (cipher & WPA_CIPHER_GCMP)
+		return RSN_CIPHER_SUITE_GCMP;
+	if (cipher & WPA_CIPHER_TKIP)
+		return (proto == WPA_PROTO_RSN ?
+			RSN_CIPHER_SUITE_TKIP : WPA_CIPHER_SUITE_TKIP);
+	if (cipher & WPA_CIPHER_WEP104)
+		return (proto == WPA_PROTO_RSN ?
+			RSN_CIPHER_SUITE_WEP104 : WPA_CIPHER_SUITE_WEP104);
+	if (cipher & WPA_CIPHER_WEP40)
+		return (proto == WPA_PROTO_RSN ?
+			RSN_CIPHER_SUITE_WEP40 : WPA_CIPHER_SUITE_WEP40);
+	if (cipher & WPA_CIPHER_NONE)
+		return (proto == WPA_PROTO_RSN ?
+			RSN_CIPHER_SUITE_NONE : WPA_CIPHER_SUITE_NONE);
+	return 0;
+}
+
+
+int rsn_cipher_put_suites(u8 *pos, int ciphers)
+{
+	int num_suites = 0;
+
+	if (ciphers & WPA_CIPHER_CCMP) {
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_CCMP);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (ciphers & WPA_CIPHER_GCMP) {
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_GCMP);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (ciphers & WPA_CIPHER_TKIP) {
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_TKIP);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (ciphers & WPA_CIPHER_NONE) {
+		RSN_SELECTOR_PUT(pos, RSN_CIPHER_SUITE_NONE);
+		pos += RSN_SELECTOR_LEN;
+		num_suites++;
+	}
+
+	return num_suites;
+}
+
+
+int wpa_cipher_put_suites(u8 *pos, int ciphers)
+{
+	int num_suites = 0;
+
+	if (ciphers & WPA_CIPHER_CCMP) {
+		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_CCMP);
+		pos += WPA_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (ciphers & WPA_CIPHER_TKIP) {
+		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_TKIP);
+		pos += WPA_SELECTOR_LEN;
+		num_suites++;
+	}
+	if (ciphers & WPA_CIPHER_NONE) {
+		RSN_SELECTOR_PUT(pos, WPA_CIPHER_SUITE_NONE);
+		pos += WPA_SELECTOR_LEN;
+		num_suites++;
+	}
+
+	return num_suites;
+}
diff --git a/hostap/src/common/wpa_common.h b/hostap/src/common/wpa_common.h
new file mode 100644
index 0000000..20c79d8
--- /dev/null
+++ b/hostap/src/common/wpa_common.h
@@ -0,0 +1,394 @@
+/*
+ * WPA definitions shared between hostapd and wpa_supplicant
+ * Copyright (c) 2002-2008, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_COMMON_H
+#define WPA_COMMON_H
+
+#define WPA_MAX_SSID_LEN 32
+
+/* IEEE 802.11i */
+#define PMKID_LEN 16
+#define PMK_LEN 32
+#define WPA_REPLAY_COUNTER_LEN 8
+#define WPA_NONCE_LEN 32
+#define WPA_KEY_RSC_LEN 8
+#define WPA_GMK_LEN 32
+#define WPA_GTK_MAX_LEN 32
+
+#define WPA_SELECTOR_LEN 4
+#define WPA_VERSION 1
+#define RSN_SELECTOR_LEN 4
+#define RSN_VERSION 1
+
+#define RSN_SELECTOR(a, b, c, d) \
+	((((u32) (a)) << 24) | (((u32) (b)) << 16) | (((u32) (c)) << 8) | \
+	 (u32) (d))
+
+#define WPA_AUTH_KEY_MGMT_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
+#define WPA_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
+#define WPA_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
+#define WPA_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0)
+#define WPA_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x50, 0xf2, 0)
+#define WPA_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
+#define WPA_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x50, 0xf2, 2)
+#if 0
+#define WPA_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x50, 0xf2, 3)
+#endif
+#define WPA_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x50, 0xf2, 4)
+#define WPA_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x50, 0xf2, 5)
+
+
+#define RSN_AUTH_KEY_MGMT_UNSPEC_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
+#define RSN_AUTH_KEY_MGMT_PSK_OVER_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
+#ifdef CONFIG_IEEE80211R
+#define RSN_AUTH_KEY_MGMT_FT_802_1X RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
+#define RSN_AUTH_KEY_MGMT_FT_PSK RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
+#endif /* CONFIG_IEEE80211R */
+#define RSN_AUTH_KEY_MGMT_802_1X_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
+#define RSN_AUTH_KEY_MGMT_PSK_SHA256 RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
+#define RSN_AUTH_KEY_MGMT_TPK_HANDSHAKE RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
+#define RSN_AUTH_KEY_MGMT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
+#define RSN_AUTH_KEY_MGMT_FT_SAE RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
+#define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
+
+#define RSN_CIPHER_SUITE_NONE RSN_SELECTOR(0x00, 0x0f, 0xac, 0)
+#define RSN_CIPHER_SUITE_WEP40 RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
+#define RSN_CIPHER_SUITE_TKIP RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
+#if 0
+#define RSN_CIPHER_SUITE_WRAP RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
+#endif
+#define RSN_CIPHER_SUITE_CCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
+#define RSN_CIPHER_SUITE_WEP104 RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
+#ifdef CONFIG_IEEE80211W
+#define RSN_CIPHER_SUITE_AES_128_CMAC RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
+#endif /* CONFIG_IEEE80211W */
+#define RSN_CIPHER_SUITE_NO_GROUP_ADDRESSED RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
+#define RSN_CIPHER_SUITE_GCMP RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
+
+/* EAPOL-Key Key Data Encapsulation
+ * GroupKey and PeerKey require encryption, otherwise, encryption is optional.
+ */
+#define RSN_KEY_DATA_GROUPKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 1)
+#if 0
+#define RSN_KEY_DATA_STAKEY RSN_SELECTOR(0x00, 0x0f, 0xac, 2)
+#endif
+#define RSN_KEY_DATA_MAC_ADDR RSN_SELECTOR(0x00, 0x0f, 0xac, 3)
+#define RSN_KEY_DATA_PMKID RSN_SELECTOR(0x00, 0x0f, 0xac, 4)
+#ifdef CONFIG_PEERKEY
+#define RSN_KEY_DATA_SMK RSN_SELECTOR(0x00, 0x0f, 0xac, 5)
+#define RSN_KEY_DATA_NONCE RSN_SELECTOR(0x00, 0x0f, 0xac, 6)
+#define RSN_KEY_DATA_LIFETIME RSN_SELECTOR(0x00, 0x0f, 0xac, 7)
+#define RSN_KEY_DATA_ERROR RSN_SELECTOR(0x00, 0x0f, 0xac, 8)
+#endif /* CONFIG_PEERKEY */
+#ifdef CONFIG_IEEE80211W
+#define RSN_KEY_DATA_IGTK RSN_SELECTOR(0x00, 0x0f, 0xac, 9)
+#endif /* CONFIG_IEEE80211W */
+#define RSN_KEY_DATA_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 10)
+#define RSN_KEY_DATA_MULTIBAND_GTK RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
+#define RSN_KEY_DATA_MULTIBAND_KEYID RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
+
+#define WPA_OUI_TYPE RSN_SELECTOR(0x00, 0x50, 0xf2, 1)
+
+#define RSN_SELECTOR_PUT(a, val) WPA_PUT_BE32((u8 *) (a), (val))
+#define RSN_SELECTOR_GET(a) WPA_GET_BE32((const u8 *) (a))
+
+#define RSN_NUM_REPLAY_COUNTERS_1 0
+#define RSN_NUM_REPLAY_COUNTERS_2 1
+#define RSN_NUM_REPLAY_COUNTERS_4 2
+#define RSN_NUM_REPLAY_COUNTERS_16 3
+
+
+#ifdef _MSC_VER
+#pragma pack(push, 1)
+#endif /* _MSC_VER */
+
+#ifdef CONFIG_IEEE80211W
+#define WPA_IGTK_LEN 16
+#endif /* CONFIG_IEEE80211W */
+
+
+/* IEEE 802.11, 7.3.2.25.3 RSN Capabilities */
+#define WPA_CAPABILITY_PREAUTH BIT(0)
+#define WPA_CAPABILITY_NO_PAIRWISE BIT(1)
+/* B2-B3: PTKSA Replay Counter */
+/* B4-B5: GTKSA Replay Counter */
+#define WPA_CAPABILITY_MFPR BIT(6)
+#define WPA_CAPABILITY_MFPC BIT(7)
+/* B8: Reserved */
+#define WPA_CAPABILITY_PEERKEY_ENABLED BIT(9)
+#define WPA_CAPABILITY_SPP_A_MSDU_CAPABLE BIT(10)
+#define WPA_CAPABILITY_SPP_A_MSDU_REQUIRED BIT(11)
+#define WPA_CAPABILITY_PBAC BIT(12)
+#define WPA_CAPABILITY_EXT_KEY_ID_FOR_UNICAST BIT(13)
+/* B14-B15: Reserved */
+
+
+/* IEEE 802.11r */
+#define MOBILITY_DOMAIN_ID_LEN 2
+#define FT_R0KH_ID_MAX_LEN 48
+#define FT_R1KH_ID_LEN 6
+#define WPA_PMK_NAME_LEN 16
+
+
+/* IEEE 802.11, 8.5.2 EAPOL-Key frames */
+#define WPA_KEY_INFO_TYPE_MASK ((u16) (BIT(0) | BIT(1) | BIT(2)))
+#define WPA_KEY_INFO_TYPE_HMAC_MD5_RC4 BIT(0)
+#define WPA_KEY_INFO_TYPE_HMAC_SHA1_AES BIT(1)
+#define WPA_KEY_INFO_TYPE_AES_128_CMAC 3
+#define WPA_KEY_INFO_KEY_TYPE BIT(3) /* 1 = Pairwise, 0 = Group key */
+/* bit4..5 is used in WPA, but is reserved in IEEE 802.11i/RSN */
+#define WPA_KEY_INFO_KEY_INDEX_MASK (BIT(4) | BIT(5))
+#define WPA_KEY_INFO_KEY_INDEX_SHIFT 4
+#define WPA_KEY_INFO_INSTALL BIT(6) /* pairwise */
+#define WPA_KEY_INFO_TXRX BIT(6) /* group */
+#define WPA_KEY_INFO_ACK BIT(7)
+#define WPA_KEY_INFO_MIC BIT(8)
+#define WPA_KEY_INFO_SECURE BIT(9)
+#define WPA_KEY_INFO_ERROR BIT(10)
+#define WPA_KEY_INFO_REQUEST BIT(11)
+#define WPA_KEY_INFO_ENCR_KEY_DATA BIT(12) /* IEEE 802.11i/RSN only */
+#define WPA_KEY_INFO_SMK_MESSAGE BIT(13)
+
+
+struct wpa_eapol_key {
+	u8 type;
+	/* Note: key_info, key_length, and key_data_length are unaligned */
+	u8 key_info[2]; /* big endian */
+	u8 key_length[2]; /* big endian */
+	u8 replay_counter[WPA_REPLAY_COUNTER_LEN];
+	u8 key_nonce[WPA_NONCE_LEN];
+	u8 key_iv[16];
+	u8 key_rsc[WPA_KEY_RSC_LEN];
+	u8 key_id[8]; /* Reserved in IEEE 802.11i/RSN */
+	u8 key_mic[16];
+	u8 key_data_length[2]; /* big endian */
+	/* followed by key_data_length bytes of key_data */
+} STRUCT_PACKED;
+
+/**
+ * struct wpa_ptk - WPA Pairwise Transient Key
+ * IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
+ */
+struct wpa_ptk {
+	u8 kck[16]; /* EAPOL-Key Key Confirmation Key (KCK) */
+	u8 kek[16]; /* EAPOL-Key Key Encryption Key (KEK) */
+	u8 tk1[16]; /* Temporal Key 1 (TK1) */
+	union {
+		u8 tk2[16]; /* Temporal Key 2 (TK2) */
+		struct {
+			u8 tx_mic_key[8];
+			u8 rx_mic_key[8];
+		} auth;
+	} u;
+} STRUCT_PACKED;
+
+
+/* WPA IE version 1
+ * 00-50-f2:1 (OUI:OUI type)
+ * 0x01 0x00 (version; little endian)
+ * (all following fields are optional:)
+ * Group Suite Selector (4 octets) (default: TKIP)
+ * Pairwise Suite Count (2 octets, little endian) (default: 1)
+ * Pairwise Suite List (4 * n octets) (default: TKIP)
+ * Authenticated Key Management Suite Count (2 octets, little endian)
+ *    (default: 1)
+ * Authenticated Key Management Suite List (4 * n octets)
+ *    (default: unspec 802.1X)
+ * WPA Capabilities (2 octets, little endian) (default: 0)
+ */
+
+struct wpa_ie_hdr {
+	u8 elem_id;
+	u8 len;
+	u8 oui[4]; /* 24-bit OUI followed by 8-bit OUI type */
+	u8 version[2]; /* little endian */
+} STRUCT_PACKED;
+
+
+/* 1/4: PMKID
+ * 2/4: RSN IE
+ * 3/4: one or two RSN IEs + GTK IE (encrypted)
+ * 4/4: empty
+ * 1/2: GTK IE (encrypted)
+ * 2/2: empty
+ */
+
+/* RSN IE version 1
+ * 0x01 0x00 (version; little endian)
+ * (all following fields are optional:)
+ * Group Suite Selector (4 octets) (default: CCMP)
+ * Pairwise Suite Count (2 octets, little endian) (default: 1)
+ * Pairwise Suite List (4 * n octets) (default: CCMP)
+ * Authenticated Key Management Suite Count (2 octets, little endian)
+ *    (default: 1)
+ * Authenticated Key Management Suite List (4 * n octets)
+ *    (default: unspec 802.1X)
+ * RSN Capabilities (2 octets, little endian) (default: 0)
+ * PMKID Count (2 octets) (default: 0)
+ * PMKID List (16 * n octets)
+ * Management Group Cipher Suite (4 octets) (default: AES-128-CMAC)
+ */
+
+struct rsn_ie_hdr {
+	u8 elem_id; /* WLAN_EID_RSN */
+	u8 len;
+	u8 version[2]; /* little endian */
+} STRUCT_PACKED;
+
+
+#ifdef CONFIG_PEERKEY
+enum {
+	STK_MUI_4WAY_STA_AP = 1,
+	STK_MUI_4WAY_STAT_STA = 2,
+	STK_MUI_GTK = 3,
+	STK_MUI_SMK = 4
+};
+
+enum {
+	STK_ERR_STA_NR = 1,
+	STK_ERR_STA_NRSN = 2,
+	STK_ERR_CPHR_NS = 3,
+	STK_ERR_NO_STSL = 4
+};
+#endif /* CONFIG_PEERKEY */
+
+struct rsn_error_kde {
+	be16 mui;
+	be16 error_type;
+} STRUCT_PACKED;
+
+#ifdef CONFIG_IEEE80211W
+struct wpa_igtk_kde {
+	u8 keyid[2];
+	u8 pn[6];
+	u8 igtk[WPA_IGTK_LEN];
+} STRUCT_PACKED;
+#endif /* CONFIG_IEEE80211W */
+
+#ifdef CONFIG_IEEE80211R
+struct rsn_mdie {
+	u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
+	u8 ft_capab;
+} STRUCT_PACKED;
+
+#define RSN_FT_CAPAB_FT_OVER_DS BIT(0)
+#define RSN_FT_CAPAB_FT_RESOURCE_REQ_SUPP BIT(1)
+
+struct rsn_ftie {
+	u8 mic_control[2];
+	u8 mic[16];
+	u8 anonce[WPA_NONCE_LEN];
+	u8 snonce[WPA_NONCE_LEN];
+	/* followed by optional parameters */
+} STRUCT_PACKED;
+
+#define FTIE_SUBELEM_R1KH_ID 1
+#define FTIE_SUBELEM_GTK 2
+#define FTIE_SUBELEM_R0KH_ID 3
+#define FTIE_SUBELEM_IGTK 4
+
+struct rsn_rdie {
+	u8 id;
+	u8 descr_count;
+	le16 status_code;
+} STRUCT_PACKED;
+
+#endif /* CONFIG_IEEE80211R */
+
+#ifdef _MSC_VER
+#pragma pack(pop)
+#endif /* _MSC_VER */
+
+
+int wpa_eapol_key_mic(const u8 *key, int ver, const u8 *buf, size_t len,
+		      u8 *mic);
+void wpa_pmk_to_ptk(const u8 *pmk, size_t pmk_len, const char *label,
+		    const u8 *addr1, const u8 *addr2,
+		    const u8 *nonce1, const u8 *nonce2,
+		    u8 *ptk, size_t ptk_len, int use_sha256);
+
+#ifdef CONFIG_IEEE80211R
+int wpa_ft_mic(const u8 *kck, const u8 *sta_addr, const u8 *ap_addr,
+	       u8 transaction_seqnum, const u8 *mdie, size_t mdie_len,
+	       const u8 *ftie, size_t ftie_len,
+	       const u8 *rsnie, size_t rsnie_len,
+	       const u8 *ric, size_t ric_len, u8 *mic);
+void wpa_derive_pmk_r0(const u8 *xxkey, size_t xxkey_len,
+		       const u8 *ssid, size_t ssid_len,
+		       const u8 *mdid, const u8 *r0kh_id, size_t r0kh_id_len,
+		       const u8 *s0kh_id, u8 *pmk_r0, u8 *pmk_r0_name);
+void wpa_derive_pmk_r1_name(const u8 *pmk_r0_name, const u8 *r1kh_id,
+			    const u8 *s1kh_id, u8 *pmk_r1_name);
+void wpa_derive_pmk_r1(const u8 *pmk_r0, const u8 *pmk_r0_name,
+		       const u8 *r1kh_id, const u8 *s1kh_id,
+		       u8 *pmk_r1, u8 *pmk_r1_name);
+void wpa_pmk_r1_to_ptk(const u8 *pmk_r1, const u8 *snonce, const u8 *anonce,
+		       const u8 *sta_addr, const u8 *bssid,
+		       const u8 *pmk_r1_name,
+		       u8 *ptk, size_t ptk_len, u8 *ptk_name);
+#endif /* CONFIG_IEEE80211R */
+
+struct wpa_ie_data {
+	int proto;
+	int pairwise_cipher;
+	int group_cipher;
+	int key_mgmt;
+	int capabilities;
+	size_t num_pmkid;
+	const u8 *pmkid;
+	int mgmt_group_cipher;
+};
+
+
+int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
+			 struct wpa_ie_data *data);
+int wpa_parse_wpa_ie_wpa(const u8 *wpa_ie, size_t wpa_ie_len,
+			 struct wpa_ie_data *data);
+
+void rsn_pmkid(const u8 *pmk, size_t pmk_len, const u8 *aa, const u8 *spa,
+	       u8 *pmkid, int use_sha256);
+
+const char * wpa_cipher_txt(int cipher);
+const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
+int wpa_compare_rsn_ie(int ft_initial_assoc,
+		       const u8 *ie1, size_t ie1len,
+		       const u8 *ie2, size_t ie2len);
+int wpa_insert_pmkid(u8 *ies, size_t ies_len, const u8 *pmkid);
+
+struct wpa_ft_ies {
+	const u8 *mdie;
+	size_t mdie_len;
+	const u8 *ftie;
+	size_t ftie_len;
+	const u8 *r1kh_id;
+	const u8 *gtk;
+	size_t gtk_len;
+	const u8 *r0kh_id;
+	size_t r0kh_id_len;
+	const u8 *rsn;
+	size_t rsn_len;
+	const u8 *rsn_pmkid;
+	const u8 *tie;
+	size_t tie_len;
+	const u8 *igtk;
+	size_t igtk_len;
+	const u8 *ric;
+	size_t ric_len;
+};
+
+int wpa_ft_parse_ies(const u8 *ies, size_t ies_len, struct wpa_ft_ies *parse);
+
+int wpa_cipher_key_len(int cipher);
+int wpa_cipher_rsc_len(int cipher);
+int wpa_cipher_to_alg(int cipher);
+int wpa_cipher_valid_pairwise(int cipher);
+u32 wpa_cipher_to_suite(int proto, int cipher);
+int rsn_cipher_put_suites(u8 *pos, int ciphers);
+int wpa_cipher_put_suites(u8 *pos, int ciphers);
+
+#endif /* WPA_COMMON_H */
diff --git a/hostap/src/common/wpa_ctrl.c b/hostap/src/common/wpa_ctrl.c
new file mode 100644
index 0000000..58cbe6a
--- /dev/null
+++ b/hostap/src/common/wpa_ctrl.c
@@ -0,0 +1,652 @@
+/*
+ * wpa_supplicant/hostapd control interface library
+ * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#ifdef CONFIG_CTRL_IFACE
+
+#ifdef CONFIG_CTRL_IFACE_UNIX
+#include <sys/un.h>
+#include <unistd.h>
+#include <fcntl.h>
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+#include <netdb.h>
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+#ifdef ANDROID
+#include <dirent.h>
+#include <cutils/sockets.h>
+#include "private/android_filesystem_config.h"
+#endif /* ANDROID */
+
+#include "wpa_ctrl.h"
+#include "common.h"
+
+
+#if defined(CONFIG_CTRL_IFACE_UNIX) || defined(CONFIG_CTRL_IFACE_UDP)
+#define CTRL_IFACE_SOCKET
+#endif /* CONFIG_CTRL_IFACE_UNIX || CONFIG_CTRL_IFACE_UDP */
+
+
+/**
+ * struct wpa_ctrl - Internal structure for control interface library
+ *
+ * This structure is used by the wpa_supplicant/hostapd control interface
+ * library to store internal data. Programs using the library should not touch
+ * this data directly. They can only use the pointer to the data structure as
+ * an identifier for the control interface connection and use this as one of
+ * the arguments for most of the control interface library functions.
+ */
+struct wpa_ctrl {
+#ifdef CONFIG_CTRL_IFACE_UDP
+	int s;
+	struct sockaddr_in local;
+	struct sockaddr_in dest;
+	char *cookie;
+	char *remote_ifname;
+	char *remote_ip;
+#endif /* CONFIG_CTRL_IFACE_UDP */
+#ifdef CONFIG_CTRL_IFACE_UNIX
+	int s;
+	struct sockaddr_un local;
+	struct sockaddr_un dest;
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+	HANDLE pipe;
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+};
+
+
+#ifdef CONFIG_CTRL_IFACE_UNIX
+
+#ifndef CONFIG_CTRL_IFACE_CLIENT_DIR
+#define CONFIG_CTRL_IFACE_CLIENT_DIR "/tmp"
+#endif /* CONFIG_CTRL_IFACE_CLIENT_DIR */
+#ifndef CONFIG_CTRL_IFACE_CLIENT_PREFIX
+#define CONFIG_CTRL_IFACE_CLIENT_PREFIX "wpa_ctrl_"
+#endif /* CONFIG_CTRL_IFACE_CLIENT_PREFIX */
+
+
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
+{
+	struct wpa_ctrl *ctrl;
+	static int counter = 0;
+	int ret;
+	size_t res;
+	int tries = 0;
+	int flags;
+
+	ctrl = os_malloc(sizeof(*ctrl));
+	if (ctrl == NULL)
+		return NULL;
+	os_memset(ctrl, 0, sizeof(*ctrl));
+
+	ctrl->s = socket(PF_UNIX, SOCK_DGRAM, 0);
+	if (ctrl->s < 0) {
+		os_free(ctrl);
+		return NULL;
+	}
+
+	ctrl->local.sun_family = AF_UNIX;
+	counter++;
+try_again:
+	ret = os_snprintf(ctrl->local.sun_path, sizeof(ctrl->local.sun_path),
+			  CONFIG_CTRL_IFACE_CLIENT_DIR "/"
+			  CONFIG_CTRL_IFACE_CLIENT_PREFIX "%d-%d",
+			  (int) getpid(), counter);
+	if (ret < 0 || (size_t) ret >= sizeof(ctrl->local.sun_path)) {
+		close(ctrl->s);
+		os_free(ctrl);
+		return NULL;
+	}
+	tries++;
+	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
+		    sizeof(ctrl->local)) < 0) {
+		if (errno == EADDRINUSE && tries < 2) {
+			/*
+			 * getpid() returns unique identifier for this instance
+			 * of wpa_ctrl, so the existing socket file must have
+			 * been left by unclean termination of an earlier run.
+			 * Remove the file and try again.
+			 */
+			unlink(ctrl->local.sun_path);
+			goto try_again;
+		}
+		close(ctrl->s);
+		os_free(ctrl);
+		return NULL;
+	}
+
+#ifdef ANDROID
+	chmod(ctrl->local.sun_path, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
+	chown(ctrl->local.sun_path, AID_SYSTEM, AID_WIFI);
+	/*
+	 * If the ctrl_path isn't an absolute pathname, assume that
+	 * it's the name of a socket in the Android reserved namespace.
+	 * Otherwise, it's a normal UNIX domain socket appearing in the
+	 * filesystem.
+	 */
+	if (ctrl_path != NULL && *ctrl_path != '/') {
+		char buf[21];
+		os_snprintf(buf, sizeof(buf), "wpa_%s", ctrl_path);
+		if (socket_local_client_connect(
+			    ctrl->s, buf,
+			    ANDROID_SOCKET_NAMESPACE_RESERVED,
+			    SOCK_DGRAM) < 0) {
+			close(ctrl->s);
+			unlink(ctrl->local.sun_path);
+			os_free(ctrl);
+			return NULL;
+		}
+		return ctrl;
+	}
+#endif /* ANDROID */
+
+	ctrl->dest.sun_family = AF_UNIX;
+	res = os_strlcpy(ctrl->dest.sun_path, ctrl_path,
+			 sizeof(ctrl->dest.sun_path));
+	if (res >= sizeof(ctrl->dest.sun_path)) {
+		close(ctrl->s);
+		os_free(ctrl);
+		return NULL;
+	}
+	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
+		    sizeof(ctrl->dest)) < 0) {
+		close(ctrl->s);
+		unlink(ctrl->local.sun_path);
+		os_free(ctrl);
+		return NULL;
+	}
+
+	/*
+	 * Make socket non-blocking so that we don't hang forever if
+	 * target dies unexpectedly.
+	 */
+	flags = fcntl(ctrl->s, F_GETFL);
+	if (flags >= 0) {
+		flags |= O_NONBLOCK;
+		if (fcntl(ctrl->s, F_SETFL, flags) < 0) {
+			perror("fcntl(ctrl->s, O_NONBLOCK)");
+			/* Not fatal, continue on.*/
+		}
+	}
+
+	return ctrl;
+}
+
+
+void wpa_ctrl_close(struct wpa_ctrl *ctrl)
+{
+	if (ctrl == NULL)
+		return;
+	unlink(ctrl->local.sun_path);
+	if (ctrl->s >= 0)
+		close(ctrl->s);
+	os_free(ctrl);
+}
+
+
+#ifdef ANDROID
+/**
+ * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
+ * may be left over from clients that were previously connected to
+ * wpa_supplicant. This keeps these files from being orphaned in the
+ * event of crashes that prevented them from being removed as part
+ * of the normal orderly shutdown.
+ */
+void wpa_ctrl_cleanup(void)
+{
+	DIR *dir;
+	struct dirent entry;
+	struct dirent *result;
+	size_t dirnamelen;
+	int prefixlen = os_strlen(CONFIG_CTRL_IFACE_CLIENT_PREFIX);
+	size_t maxcopy;
+	char pathname[PATH_MAX];
+	char *namep;
+
+	if ((dir = opendir(CONFIG_CTRL_IFACE_CLIENT_DIR)) == NULL)
+		return;
+
+	dirnamelen = (size_t) os_snprintf(pathname, sizeof(pathname), "%s/",
+					  CONFIG_CTRL_IFACE_CLIENT_DIR);
+	if (dirnamelen >= sizeof(pathname)) {
+		closedir(dir);
+		return;
+	}
+	namep = pathname + dirnamelen;
+	maxcopy = PATH_MAX - dirnamelen;
+	while (readdir_r(dir, &entry, &result) == 0 && result != NULL) {
+		if (os_strncmp(entry.d_name, CONFIG_CTRL_IFACE_CLIENT_PREFIX,
+			       prefixlen) == 0) {
+			if (os_strlcpy(namep, entry.d_name, maxcopy) < maxcopy)
+				unlink(pathname);
+		}
+	}
+	closedir(dir);
+}
+#endif /* ANDROID */
+
+#else /* CONFIG_CTRL_IFACE_UNIX */
+
+#ifdef ANDROID
+void wpa_ctrl_cleanup(void)
+{
+}
+#endif /* ANDROID */
+
+#endif /* CONFIG_CTRL_IFACE_UNIX */
+
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
+{
+	struct wpa_ctrl *ctrl;
+	char buf[128];
+	size_t len;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+	struct hostent *h;
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+	ctrl = os_malloc(sizeof(*ctrl));
+	if (ctrl == NULL)
+		return NULL;
+	os_memset(ctrl, 0, sizeof(*ctrl));
+
+	ctrl->s = socket(PF_INET, SOCK_DGRAM, 0);
+	if (ctrl->s < 0) {
+		perror("socket");
+		os_free(ctrl);
+		return NULL;
+	}
+
+	ctrl->local.sin_family = AF_INET;
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+	ctrl->local.sin_addr.s_addr = INADDR_ANY;
+#else /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+	ctrl->local.sin_addr.s_addr = htonl((127 << 24) | 1);
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+	if (bind(ctrl->s, (struct sockaddr *) &ctrl->local,
+		 sizeof(ctrl->local)) < 0) {
+		close(ctrl->s);
+		os_free(ctrl);
+		return NULL;
+	}
+
+	ctrl->dest.sin_family = AF_INET;
+	ctrl->dest.sin_addr.s_addr = htonl((127 << 24) | 1);
+	ctrl->dest.sin_port = htons(WPA_CTRL_IFACE_PORT);
+
+#ifdef CONFIG_CTRL_IFACE_UDP_REMOTE
+	if (ctrl_path) {
+		char *port, *name;
+		int port_id;
+
+		name = os_strdup(ctrl_path);
+		if (name == NULL) {
+			close(ctrl->s);
+			os_free(ctrl);
+			return NULL;
+		}
+		port = os_strchr(name, ':');
+
+		if (port) {
+			port_id = atoi(&port[1]);
+			port[0] = '\0';
+		} else
+			port_id = WPA_CTRL_IFACE_PORT;
+
+		h = gethostbyname(name);
+		ctrl->remote_ip = os_strdup(name);
+		os_free(name);
+		if (h == NULL) {
+			perror("gethostbyname");
+			close(ctrl->s);
+			os_free(ctrl->remote_ip);
+			os_free(ctrl);
+			return NULL;
+		}
+		ctrl->dest.sin_port = htons(port_id);
+		os_memcpy(h->h_addr, (char *) &ctrl->dest.sin_addr.s_addr,
+			  h->h_length);
+	} else
+		ctrl->remote_ip = os_strdup("localhost");
+#endif /* CONFIG_CTRL_IFACE_UDP_REMOTE */
+
+	if (connect(ctrl->s, (struct sockaddr *) &ctrl->dest,
+		    sizeof(ctrl->dest)) < 0) {
+		perror("connect");
+		close(ctrl->s);
+		os_free(ctrl->remote_ip);
+		os_free(ctrl);
+		return NULL;
+	}
+
+	len = sizeof(buf) - 1;
+	if (wpa_ctrl_request(ctrl, "GET_COOKIE", 10, buf, &len, NULL) == 0) {
+		buf[len] = '\0';
+		ctrl->cookie = os_strdup(buf);
+	}
+
+	if (wpa_ctrl_request(ctrl, "IFNAME", 6, buf, &len, NULL) == 0) {
+		buf[len] = '\0';
+		ctrl->remote_ifname = os_strdup(buf);
+	}
+
+	return ctrl;
+}
+
+
+char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl)
+{
+#define WPA_CTRL_MAX_PS_NAME 100
+	static char ps[WPA_CTRL_MAX_PS_NAME] = {};
+	os_snprintf(ps, WPA_CTRL_MAX_PS_NAME, "%s/%s",
+		    ctrl->remote_ip, ctrl->remote_ifname);
+	return ps;
+}
+
+
+void wpa_ctrl_close(struct wpa_ctrl *ctrl)
+{
+	close(ctrl->s);
+	os_free(ctrl->cookie);
+	os_free(ctrl->remote_ifname);
+	os_free(ctrl->remote_ip);
+	os_free(ctrl);
+}
+
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+
+#ifdef CTRL_IFACE_SOCKET
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+		     char *reply, size_t *reply_len,
+		     void (*msg_cb)(char *msg, size_t len))
+{
+	struct timeval tv;
+	struct os_time started_at;
+	int res;
+	fd_set rfds;
+	const char *_cmd;
+	char *cmd_buf = NULL;
+	size_t _cmd_len;
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+	if (ctrl->cookie) {
+		char *pos;
+		_cmd_len = os_strlen(ctrl->cookie) + 1 + cmd_len;
+		cmd_buf = os_malloc(_cmd_len);
+		if (cmd_buf == NULL)
+			return -1;
+		_cmd = cmd_buf;
+		pos = cmd_buf;
+		os_strlcpy(pos, ctrl->cookie, _cmd_len);
+		pos += os_strlen(ctrl->cookie);
+		*pos++ = ' ';
+		os_memcpy(pos, cmd, cmd_len);
+	} else
+#endif /* CONFIG_CTRL_IFACE_UDP */
+	{
+		_cmd = cmd;
+		_cmd_len = cmd_len;
+	}
+
+	errno = 0;
+	started_at.sec = 0;
+	started_at.usec = 0;
+retry_send:
+	if (send(ctrl->s, _cmd, _cmd_len, 0) < 0) {
+		if (errno == EAGAIN || errno == EBUSY || errno == EWOULDBLOCK)
+		{
+			/*
+			 * Must be a non-blocking socket... Try for a bit
+			 * longer before giving up.
+			 */
+			if (started_at.sec == 0)
+				os_get_time(&started_at);
+			else {
+				struct os_time n;
+				os_get_time(&n);
+				/* Try for a few seconds. */
+				if (n.sec > started_at.sec + 5)
+					goto send_err;
+			}
+			os_sleep(1, 0);
+			goto retry_send;
+		}
+	send_err:
+		os_free(cmd_buf);
+		return -1;
+	}
+	os_free(cmd_buf);
+
+	for (;;) {
+		tv.tv_sec = 10;
+		tv.tv_usec = 0;
+		FD_ZERO(&rfds);
+		FD_SET(ctrl->s, &rfds);
+		res = select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+		if (res < 0)
+			return res;
+		if (FD_ISSET(ctrl->s, &rfds)) {
+			res = recv(ctrl->s, reply, *reply_len, 0);
+			if (res < 0)
+				return res;
+			if (res > 0 && reply[0] == '<') {
+				/* This is an unsolicited message from
+				 * wpa_supplicant, not the reply to the
+				 * request. Use msg_cb to report this to the
+				 * caller. */
+				if (msg_cb) {
+					/* Make sure the message is nul
+					 * terminated. */
+					if ((size_t) res == *reply_len)
+						res = (*reply_len) - 1;
+					reply[res] = '\0';
+					msg_cb(reply, res);
+				}
+				continue;
+			}
+			*reply_len = res;
+			break;
+		} else {
+			return -2;
+		}
+	}
+	return 0;
+}
+#endif /* CTRL_IFACE_SOCKET */
+
+
+static int wpa_ctrl_attach_helper(struct wpa_ctrl *ctrl, int attach)
+{
+	char buf[10];
+	int ret;
+	size_t len = 10;
+
+	ret = wpa_ctrl_request(ctrl, attach ? "ATTACH" : "DETACH", 6,
+			       buf, &len, NULL);
+	if (ret < 0)
+		return ret;
+	if (len == 3 && os_memcmp(buf, "OK\n", 3) == 0)
+		return 0;
+	return -1;
+}
+
+
+int wpa_ctrl_attach(struct wpa_ctrl *ctrl)
+{
+	return wpa_ctrl_attach_helper(ctrl, 1);
+}
+
+
+int wpa_ctrl_detach(struct wpa_ctrl *ctrl)
+{
+	return wpa_ctrl_attach_helper(ctrl, 0);
+}
+
+
+#ifdef CTRL_IFACE_SOCKET
+
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
+{
+	int res;
+
+	res = recv(ctrl->s, reply, *reply_len, 0);
+	if (res < 0)
+		return res;
+	*reply_len = res;
+	return 0;
+}
+
+
+int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
+{
+	struct timeval tv;
+	fd_set rfds;
+	tv.tv_sec = 0;
+	tv.tv_usec = 0;
+	FD_ZERO(&rfds);
+	FD_SET(ctrl->s, &rfds);
+	select(ctrl->s + 1, &rfds, NULL, NULL, &tv);
+	return FD_ISSET(ctrl->s, &rfds);
+}
+
+
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
+{
+	return ctrl->s;
+}
+
+#endif /* CTRL_IFACE_SOCKET */
+
+
+#ifdef CONFIG_CTRL_IFACE_NAMED_PIPE
+
+#ifndef WPA_SUPPLICANT_NAMED_PIPE
+#define WPA_SUPPLICANT_NAMED_PIPE "WpaSupplicant"
+#endif
+#define NAMED_PIPE_PREFIX TEXT("\\\\.\\pipe\\") TEXT(WPA_SUPPLICANT_NAMED_PIPE)
+
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path)
+{
+	struct wpa_ctrl *ctrl;
+	DWORD mode;
+	TCHAR name[256];
+	int i, ret;
+
+	ctrl = os_malloc(sizeof(*ctrl));
+	if (ctrl == NULL)
+		return NULL;
+	os_memset(ctrl, 0, sizeof(*ctrl));
+
+#ifdef UNICODE
+	if (ctrl_path == NULL)
+		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX);
+	else
+		ret = _snwprintf(name, 256, NAMED_PIPE_PREFIX TEXT("-%S"),
+				 ctrl_path);
+#else /* UNICODE */
+	if (ctrl_path == NULL)
+		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX);
+	else
+		ret = os_snprintf(name, 256, NAMED_PIPE_PREFIX "-%s",
+				  ctrl_path);
+#endif /* UNICODE */
+	if (ret < 0 || ret >= 256) {
+		os_free(ctrl);
+		return NULL;
+	}
+
+	for (i = 0; i < 10; i++) {
+		ctrl->pipe = CreateFile(name, GENERIC_READ | GENERIC_WRITE, 0,
+					NULL, OPEN_EXISTING, 0, NULL);
+		/*
+		 * Current named pipe server side in wpa_supplicant is
+		 * re-opening the pipe for new clients only after the previous
+		 * one is taken into use. This leaves a small window for race
+		 * conditions when two connections are being opened at almost
+		 * the same time. Retry if that was the case.
+		 */
+		if (ctrl->pipe != INVALID_HANDLE_VALUE ||
+		    GetLastError() != ERROR_PIPE_BUSY)
+			break;
+		WaitNamedPipe(name, 1000);
+	}
+	if (ctrl->pipe == INVALID_HANDLE_VALUE) {
+		os_free(ctrl);
+		return NULL;
+	}
+
+	mode = PIPE_READMODE_MESSAGE;
+	if (!SetNamedPipeHandleState(ctrl->pipe, &mode, NULL, NULL)) {
+		CloseHandle(ctrl->pipe);
+		os_free(ctrl);
+		return NULL;
+	}
+
+	return ctrl;
+}
+
+
+void wpa_ctrl_close(struct wpa_ctrl *ctrl)
+{
+	CloseHandle(ctrl->pipe);
+	os_free(ctrl);
+}
+
+
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+		     char *reply, size_t *reply_len,
+		     void (*msg_cb)(char *msg, size_t len))
+{
+	DWORD written;
+	DWORD readlen = *reply_len;
+
+	if (!WriteFile(ctrl->pipe, cmd, cmd_len, &written, NULL))
+		return -1;
+
+	if (!ReadFile(ctrl->pipe, reply, *reply_len, &readlen, NULL))
+		return -1;
+	*reply_len = readlen;
+
+	return 0;
+}
+
+
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len)
+{
+	DWORD len = *reply_len;
+	if (!ReadFile(ctrl->pipe, reply, *reply_len, &len, NULL))
+		return -1;
+	*reply_len = len;
+	return 0;
+}
+
+
+int wpa_ctrl_pending(struct wpa_ctrl *ctrl)
+{
+	DWORD left;
+
+	if (!PeekNamedPipe(ctrl->pipe, NULL, 0, NULL, &left, NULL))
+		return -1;
+	return left ? 1 : 0;
+}
+
+
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl)
+{
+	return -1;
+}
+
+#endif /* CONFIG_CTRL_IFACE_NAMED_PIPE */
+
+#endif /* CONFIG_CTRL_IFACE */
diff --git a/hostap/src/common/wpa_ctrl.h b/hostap/src/common/wpa_ctrl.h
new file mode 100644
index 0000000..bb9b558
--- /dev/null
+++ b/hostap/src/common/wpa_ctrl.h
@@ -0,0 +1,322 @@
+/*
+ * wpa_supplicant/hostapd control interface library
+ * Copyright (c) 2004-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef WPA_CTRL_H
+#define WPA_CTRL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/* wpa_supplicant control interface - fixed message prefixes */
+
+/** Interactive request for identity/password/pin */
+#define WPA_CTRL_REQ "CTRL-REQ-"
+
+/** Response to identity/password/pin request */
+#define WPA_CTRL_RSP "CTRL-RSP-"
+
+/* Event messages with fixed prefix */
+/** Authentication completed successfully and data connection enabled */
+#define WPA_EVENT_CONNECTED "CTRL-EVENT-CONNECTED "
+/** Disconnected, data connection is not available */
+#define WPA_EVENT_DISCONNECTED "CTRL-EVENT-DISCONNECTED "
+/** Association rejected during connection attempt */
+#define WPA_EVENT_ASSOC_REJECT "CTRL-EVENT-ASSOC-REJECT "
+/** wpa_supplicant is exiting */
+#define WPA_EVENT_TERMINATING "CTRL-EVENT-TERMINATING "
+/** Password change was completed successfully */
+#define WPA_EVENT_PASSWORD_CHANGED "CTRL-EVENT-PASSWORD-CHANGED "
+/** EAP-Request/Notification received */
+#define WPA_EVENT_EAP_NOTIFICATION "CTRL-EVENT-EAP-NOTIFICATION "
+/** EAP authentication started (EAP-Request/Identity received) */
+#define WPA_EVENT_EAP_STARTED "CTRL-EVENT-EAP-STARTED "
+/** EAP method proposed by the server */
+#define WPA_EVENT_EAP_PROPOSED_METHOD "CTRL-EVENT-EAP-PROPOSED-METHOD "
+/** EAP method selected */
+#define WPA_EVENT_EAP_METHOD "CTRL-EVENT-EAP-METHOD "
+/** EAP peer certificate from TLS */
+#define WPA_EVENT_EAP_PEER_CERT "CTRL-EVENT-EAP-PEER-CERT "
+/** EAP TLS certificate chain validation error */
+#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
+/** EAP authentication completed successfully */
+#define WPA_EVENT_EAP_SUCCESS "CTRL-EVENT-EAP-SUCCESS "
+/** EAP authentication failed (EAP-Failure received) */
+#define WPA_EVENT_EAP_FAILURE "CTRL-EVENT-EAP-FAILURE "
+/** Network block temporarily disabled (e.g., due to authentication failure) */
+#define WPA_EVENT_TEMP_DISABLED "CTRL-EVENT-SSID-TEMP-DISABLED "
+/** Temporarily disabled network block re-enabled */
+#define WPA_EVENT_REENABLED "CTRL-EVENT-SSID-REENABLED "
+/** New scan results available */
+#define WPA_EVENT_SCAN_RESULTS "CTRL-EVENT-SCAN-RESULTS "
+/** wpa_supplicant state change */
+#define WPA_EVENT_STATE_CHANGE "CTRL-EVENT-STATE-CHANGE "
+/** A new BSS entry was added (followed by BSS entry id and BSSID) */
+#define WPA_EVENT_BSS_ADDED "CTRL-EVENT-BSS-ADDED "
+/** A BSS entry was removed (followed by BSS entry id and BSSID) */
+#define WPA_EVENT_BSS_REMOVED "CTRL-EVENT-BSS-REMOVED "
+
+/** WPS overlap detected in PBC mode */
+#define WPS_EVENT_OVERLAP "WPS-OVERLAP-DETECTED "
+/** Available WPS AP with active PBC found in scan results */
+#define WPS_EVENT_AP_AVAILABLE_PBC "WPS-AP-AVAILABLE-PBC "
+/** Available WPS AP with our address as authorized in scan results */
+#define WPS_EVENT_AP_AVAILABLE_AUTH "WPS-AP-AVAILABLE-AUTH "
+/** Available WPS AP with recently selected PIN registrar found in scan results
+ */
+#define WPS_EVENT_AP_AVAILABLE_PIN "WPS-AP-AVAILABLE-PIN "
+/** Available WPS AP found in scan results */
+#define WPS_EVENT_AP_AVAILABLE "WPS-AP-AVAILABLE "
+/** A new credential received */
+#define WPS_EVENT_CRED_RECEIVED "WPS-CRED-RECEIVED "
+/** M2D received */
+#define WPS_EVENT_M2D "WPS-M2D "
+/** WPS registration failed after M2/M2D */
+#define WPS_EVENT_FAIL "WPS-FAIL "
+/** WPS registration completed successfully */
+#define WPS_EVENT_SUCCESS "WPS-SUCCESS "
+/** WPS enrollment attempt timed out and was terminated */
+#define WPS_EVENT_TIMEOUT "WPS-TIMEOUT "
+
+#define WPS_EVENT_ENROLLEE_SEEN "WPS-ENROLLEE-SEEN "
+
+#define WPS_EVENT_OPEN_NETWORK "WPS-OPEN-NETWORK "
+
+/* WPS ER events */
+#define WPS_EVENT_ER_AP_ADD "WPS-ER-AP-ADD "
+#define WPS_EVENT_ER_AP_REMOVE "WPS-ER-AP-REMOVE "
+#define WPS_EVENT_ER_ENROLLEE_ADD "WPS-ER-ENROLLEE-ADD "
+#define WPS_EVENT_ER_ENROLLEE_REMOVE "WPS-ER-ENROLLEE-REMOVE "
+#define WPS_EVENT_ER_AP_SETTINGS "WPS-ER-AP-SETTINGS "
+#define WPS_EVENT_ER_SET_SEL_REG "WPS-ER-AP-SET-SEL-REG "
+
+/** P2P device found */
+#define P2P_EVENT_DEVICE_FOUND "P2P-DEVICE-FOUND "
+
+/** P2P device lost */
+#define P2P_EVENT_DEVICE_LOST "P2P-DEVICE-LOST "
+
+/** A P2P device requested GO negotiation, but we were not ready to start the
+ * negotiation */
+#define P2P_EVENT_GO_NEG_REQUEST "P2P-GO-NEG-REQUEST "
+#define P2P_EVENT_GO_NEG_SUCCESS "P2P-GO-NEG-SUCCESS "
+#define P2P_EVENT_GO_NEG_FAILURE "P2P-GO-NEG-FAILURE "
+#define P2P_EVENT_GROUP_FORMATION_SUCCESS "P2P-GROUP-FORMATION-SUCCESS "
+#define P2P_EVENT_GROUP_FORMATION_FAILURE "P2P-GROUP-FORMATION-FAILURE "
+#define P2P_EVENT_GROUP_STARTED "P2P-GROUP-STARTED "
+#define P2P_EVENT_GROUP_REMOVED "P2P-GROUP-REMOVED "
+#define P2P_EVENT_CROSS_CONNECT_ENABLE "P2P-CROSS-CONNECT-ENABLE "
+#define P2P_EVENT_CROSS_CONNECT_DISABLE "P2P-CROSS-CONNECT-DISABLE "
+/* parameters: <peer address> <PIN> */
+#define P2P_EVENT_PROV_DISC_SHOW_PIN "P2P-PROV-DISC-SHOW-PIN "
+/* parameters: <peer address> */
+#define P2P_EVENT_PROV_DISC_ENTER_PIN "P2P-PROV-DISC-ENTER-PIN "
+/* parameters: <peer address> */
+#define P2P_EVENT_PROV_DISC_PBC_REQ "P2P-PROV-DISC-PBC-REQ "
+/* parameters: <peer address> */
+#define P2P_EVENT_PROV_DISC_PBC_RESP "P2P-PROV-DISC-PBC-RESP "
+/* parameters: <peer address> <status> */
+#define P2P_EVENT_PROV_DISC_FAILURE "P2P-PROV-DISC-FAILURE"
+/* parameters: <freq> <src addr> <dialog token> <update indicator> <TLVs> */
+#define P2P_EVENT_SERV_DISC_REQ "P2P-SERV-DISC-REQ "
+/* parameters: <src addr> <update indicator> <TLVs> */
+#define P2P_EVENT_SERV_DISC_RESP "P2P-SERV-DISC-RESP "
+#define P2P_EVENT_INVITATION_RECEIVED "P2P-INVITATION-RECEIVED "
+#define P2P_EVENT_INVITATION_RESULT "P2P-INVITATION-RESULT "
+#define P2P_EVENT_FIND_STOPPED "P2P-FIND-STOPPED "
+
+#define INTERWORKING_AP "INTERWORKING-AP "
+#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
+
+#define GAS_RESPONSE_INFO "GAS-RESPONSE-INFO "
+
+/* hostapd control interface - fixed message prefixes */
+#define WPS_EVENT_PIN_NEEDED "WPS-PIN-NEEDED "
+#define WPS_EVENT_NEW_AP_SETTINGS "WPS-NEW-AP-SETTINGS "
+#define WPS_EVENT_REG_SUCCESS "WPS-REG-SUCCESS "
+#define WPS_EVENT_AP_SETUP_LOCKED "WPS-AP-SETUP-LOCKED "
+#define WPS_EVENT_AP_SETUP_UNLOCKED "WPS-AP-SETUP-UNLOCKED "
+#define WPS_EVENT_AP_PIN_ENABLED "WPS-AP-PIN-ENABLED "
+#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
+#define AP_STA_CONNECTED "AP-STA-CONNECTED "
+#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
+
+
+/* BSS command information masks */
+
+#define WPA_BSS_MASK_ALL		0xFFFFFFFF
+#define WPA_BSS_MASK_ID			BIT(0)
+#define WPA_BSS_MASK_BSSID		BIT(1)
+#define WPA_BSS_MASK_FREQ		BIT(2)
+#define WPA_BSS_MASK_BEACON_INT		BIT(3)
+#define WPA_BSS_MASK_CAPABILITIES	BIT(4)
+#define WPA_BSS_MASK_QUAL		BIT(5)
+#define WPA_BSS_MASK_NOISE		BIT(6)
+#define WPA_BSS_MASK_LEVEL		BIT(7)
+#define WPA_BSS_MASK_TSF		BIT(8)
+#define WPA_BSS_MASK_AGE		BIT(9)
+#define WPA_BSS_MASK_IE			BIT(10)
+#define WPA_BSS_MASK_FLAGS		BIT(11)
+#define WPA_BSS_MASK_SSID		BIT(12)
+#define WPA_BSS_MASK_WPS_SCAN		BIT(13)
+#define WPA_BSS_MASK_P2P_SCAN		BIT(14)
+#define WPA_BSS_MASK_INTERNETW		BIT(15)
+#define WPA_BSS_MASK_WIFI_DISPLAY	BIT(16)
+
+
+/* wpa_supplicant/hostapd control interface access */
+
+/**
+ * wpa_ctrl_open - Open a control interface to wpa_supplicant/hostapd
+ * @ctrl_path: Path for UNIX domain sockets; ignored if UDP sockets are used.
+ * Returns: Pointer to abstract control interface data or %NULL on failure
+ *
+ * This function is used to open a control interface to wpa_supplicant/hostapd.
+ * ctrl_path is usually /var/run/wpa_supplicant or /var/run/hostapd. This path
+ * is configured in wpa_supplicant/hostapd and other programs using the control
+ * interface need to use matching path configuration.
+ */
+struct wpa_ctrl * wpa_ctrl_open(const char *ctrl_path);
+
+
+/**
+ * wpa_ctrl_close - Close a control interface to wpa_supplicant/hostapd
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ *
+ * This function is used to close a control interface.
+ */
+void wpa_ctrl_close(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_request - Send a command to wpa_supplicant/hostapd
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * @cmd: Command; usually, ASCII text, e.g., "PING"
+ * @cmd_len: Length of the cmd in bytes
+ * @reply: Buffer for the response
+ * @reply_len: Reply buffer length
+ * @msg_cb: Callback function for unsolicited messages or %NULL if not used
+ * Returns: 0 on success, -1 on error (send or receive failed), -2 on timeout
+ *
+ * This function is used to send commands to wpa_supplicant/hostapd. Received
+ * response will be written to reply and reply_len is set to the actual length
+ * of the reply. This function will block for up to two seconds while waiting
+ * for the reply. If unsolicited messages are received, the blocking time may
+ * be longer.
+ *
+ * msg_cb can be used to register a callback function that will be called for
+ * unsolicited messages received while waiting for the command response. These
+ * messages may be received if wpa_ctrl_request() is called at the same time as
+ * wpa_supplicant/hostapd is sending such a message. This can happen only if
+ * the program has used wpa_ctrl_attach() to register itself as a monitor for
+ * event messages. Alternatively to msg_cb, programs can register two control
+ * interface connections and use one of them for commands and the other one for
+ * receiving event messages, in other words, call wpa_ctrl_attach() only for
+ * the control interface connection that will be used for event messages.
+ */
+int wpa_ctrl_request(struct wpa_ctrl *ctrl, const char *cmd, size_t cmd_len,
+		     char *reply, size_t *reply_len,
+		     void (*msg_cb)(char *msg, size_t len));
+
+
+/**
+ * wpa_ctrl_attach - Register as an event monitor for the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: 0 on success, -1 on failure, -2 on timeout
+ *
+ * This function registers the control interface connection as a monitor for
+ * wpa_supplicant/hostapd events. After a success wpa_ctrl_attach() call, the
+ * control interface connection starts receiving event messages that can be
+ * read with wpa_ctrl_recv().
+ */
+int wpa_ctrl_attach(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_detach - Unregister event monitor from the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: 0 on success, -1 on failure, -2 on timeout
+ *
+ * This function unregisters the control interface connection as a monitor for
+ * wpa_supplicant/hostapd events, i.e., cancels the registration done with
+ * wpa_ctrl_attach().
+ */
+int wpa_ctrl_detach(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_recv - Receive a pending control interface message
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * @reply: Buffer for the message data
+ * @reply_len: Length of the reply buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function will receive a pending control interface message. This
+ * function will block if no messages are available. The received response will
+ * be written to reply and reply_len is set to the actual length of the reply.
+ * wpa_ctrl_recv() is only used for event messages, i.e., wpa_ctrl_attach()
+ * must have been used to register the control interface as an event monitor.
+ */
+int wpa_ctrl_recv(struct wpa_ctrl *ctrl, char *reply, size_t *reply_len);
+
+
+/**
+ * wpa_ctrl_pending - Check whether there are pending event messages
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: 1 if there are pending messages, 0 if no, or -1 on error
+ *
+ * This function will check whether there are any pending control interface
+ * message available to be received with wpa_ctrl_recv(). wpa_ctrl_pending() is
+ * only used for event messages, i.e., wpa_ctrl_attach() must have been used to
+ * register the control interface as an event monitor.
+ */
+int wpa_ctrl_pending(struct wpa_ctrl *ctrl);
+
+
+/**
+ * wpa_ctrl_get_fd - Get file descriptor used by the control interface
+ * @ctrl: Control interface data from wpa_ctrl_open()
+ * Returns: File descriptor used for the connection
+ *
+ * This function can be used to get the file descriptor that is used for the
+ * control interface connection. The returned value can be used, e.g., with
+ * select() while waiting for multiple events.
+ *
+ * The returned file descriptor must not be used directly for sending or
+ * receiving packets; instead, the library functions wpa_ctrl_request() and
+ * wpa_ctrl_recv() must be used for this.
+ */
+int wpa_ctrl_get_fd(struct wpa_ctrl *ctrl);
+
+char * wpa_ctrl_get_remote_ifname(struct wpa_ctrl *ctrl);
+
+#ifdef ANDROID
+/**
+ * wpa_ctrl_cleanup() - Delete any local UNIX domain socket files that
+ * may be left over from clients that were previously connected to
+ * wpa_supplicant. This keeps these files from being orphaned in the
+ * event of crashes that prevented them from being removed as part
+ * of the normal orderly shutdown.
+ */
+void wpa_ctrl_cleanup(void);
+#endif /* ANDROID */
+
+#ifdef CONFIG_CTRL_IFACE_UDP
+/* Port range for multiple wpa_supplicant instances and multiple VIFs */
+#define WPA_CTRL_IFACE_PORT 9877
+#define WPA_CTRL_IFACE_PORT_LIMIT 50 /* decremented from start */
+#define WPA_GLOBAL_CTRL_IFACE_PORT 9878
+#define WPA_GLOBAL_CTRL_IFACE_PORT_LIMIT 20 /* incremented from start */
+#endif /* CONFIG_CTRL_IFACE_UDP */
+
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* WPA_CTRL_H */
diff --git a/hostap/src/crypto/Makefile b/hostap/src/crypto/Makefile
new file mode 100644
index 0000000..a605a65
--- /dev/null
+++ b/hostap/src/crypto/Makefile
@@ -0,0 +1,62 @@
+all: libcrypto.a
+
+clean:
+	rm -f *~ *.o *.d libcrypto.a
+
+install:
+	@echo Nothing to be made.
+
+
+include ../lib.rules
+
+CFLAGS += -DCONFIG_TLS_INTERNAL_CLIENT
+CFLAGS += -DCONFIG_TLS_INTERNAL_SERVER
+#CFLAGS += -DALL_DH_GROUPS
+CFLAGS += -DCONFIG_SHA256
+
+LIB_OBJS= \
+	aes-cbc.o \
+	aes-ccm.o \
+	aes-ctr.o \
+	aes-eax.o \
+	aes-encblock.o \
+	aes-gcm.o \
+	aes-internal.o \
+	aes-internal-dec.o \
+	aes-internal-enc.o \
+	aes-omac1.o \
+	aes-unwrap.o \
+	aes-wrap.o \
+	des-internal.o \
+	dh_group5.o \
+	dh_groups.o \
+	md4-internal.o \
+	md5.o \
+	md5-internal.o \
+	milenage.o \
+	ms_funcs.o \
+	rc4.o \
+	sha1.o \
+	sha1-internal.o \
+	sha1-pbkdf2.o \
+	sha1-prf.o \
+	sha1-tlsprf.o \
+	sha1-tprf.o \
+	sha256.o \
+	sha256-prf.o \
+	sha256-tlsprf.o \
+	sha256-internal.o
+
+LIB_OBJS += crypto_internal.o
+LIB_OBJS += crypto_internal-cipher.o
+LIB_OBJS += crypto_internal-modexp.o
+LIB_OBJS += crypto_internal-rsa.o
+LIB_OBJS += tls_internal.o
+LIB_OBJS += fips_prf_internal.o
+LIB_OBJS += random.o
+
+
+libcrypto.a: $(LIB_OBJS)
+	$(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/hostap/src/crypto/aes-cbc.c b/hostap/src/crypto/aes-cbc.c
new file mode 100644
index 0000000..2833cfc
--- /dev/null
+++ b/hostap/src/crypto/aes-cbc.c
@@ -0,0 +1,80 @@
+/*
+ * AES-128 CBC
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "aes.h"
+#include "aes_wrap.h"
+
+/**
+ * aes_128_cbc_encrypt - AES-128 CBC encryption
+ * @key: Encryption key
+ * @iv: Encryption IV for CBC mode (16 bytes)
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes (must be divisible by 16)
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+	void *ctx;
+	u8 cbc[AES_BLOCK_SIZE];
+	u8 *pos = data;
+	int i, j, blocks;
+
+	ctx = aes_encrypt_init(key, 16);
+	if (ctx == NULL)
+		return -1;
+	os_memcpy(cbc, iv, AES_BLOCK_SIZE);
+
+	blocks = data_len / AES_BLOCK_SIZE;
+	for (i = 0; i < blocks; i++) {
+		for (j = 0; j < AES_BLOCK_SIZE; j++)
+			cbc[j] ^= pos[j];
+		aes_encrypt(ctx, cbc, cbc);
+		os_memcpy(pos, cbc, AES_BLOCK_SIZE);
+		pos += AES_BLOCK_SIZE;
+	}
+	aes_encrypt_deinit(ctx);
+	return 0;
+}
+
+
+/**
+ * aes_128_cbc_decrypt - AES-128 CBC decryption
+ * @key: Decryption key
+ * @iv: Decryption IV for CBC mode (16 bytes)
+ * @data: Data to decrypt in-place
+ * @data_len: Length of data in bytes (must be divisible by 16)
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+	void *ctx;
+	u8 cbc[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE];
+	u8 *pos = data;
+	int i, j, blocks;
+
+	ctx = aes_decrypt_init(key, 16);
+	if (ctx == NULL)
+		return -1;
+	os_memcpy(cbc, iv, AES_BLOCK_SIZE);
+
+	blocks = data_len / AES_BLOCK_SIZE;
+	for (i = 0; i < blocks; i++) {
+		os_memcpy(tmp, pos, AES_BLOCK_SIZE);
+		aes_decrypt(ctx, pos, pos);
+		for (j = 0; j < AES_BLOCK_SIZE; j++)
+			pos[j] ^= cbc[j];
+		os_memcpy(cbc, tmp, AES_BLOCK_SIZE);
+		pos += AES_BLOCK_SIZE;
+	}
+	aes_decrypt_deinit(ctx);
+	return 0;
+}
diff --git a/hostap/src/crypto/aes-ccm.c b/hostap/src/crypto/aes-ccm.c
new file mode 100644
index 0000000..d14670d
--- /dev/null
+++ b/hostap/src/crypto/aes-ccm.c
@@ -0,0 +1,212 @@
+/*
+ * Counter with CBC-MAC (CCM) with AES
+ *
+ * Copyright (c) 2010-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "aes.h"
+#include "aes_wrap.h"
+
+
+static void xor_aes_block(u8 *dst, const u8 *src)
+{
+	u32 *d = (u32 *) dst;
+	u32 *s = (u32 *) src;
+	*d++ ^= *s++;
+	*d++ ^= *s++;
+	*d++ ^= *s++;
+	*d++ ^= *s++;
+}
+
+
+static void aes_ccm_auth_start(void *aes, size_t M, size_t L, const u8 *nonce,
+			       const u8 *aad, size_t aad_len, size_t plain_len,
+			       u8 *x)
+{
+	u8 aad_buf[2 * AES_BLOCK_SIZE];
+	u8 b[AES_BLOCK_SIZE];
+
+	/* Authentication */
+	/* B_0: Flags | Nonce N | l(m) */
+	b[0] = aad_len ? 0x40 : 0 /* Adata */;
+	b[0] |= (((M - 2) / 2) /* M' */ << 3);
+	b[0] |= (L - 1) /* L' */;
+	os_memcpy(&b[1], nonce, 15 - L);
+	WPA_PUT_BE16(&b[AES_BLOCK_SIZE - L], plain_len);
+
+	wpa_hexdump_key(MSG_EXCESSIVE, "CCM B_0", b, AES_BLOCK_SIZE);
+	aes_encrypt(aes, b, x); /* X_1 = E(K, B_0) */
+
+	if (!aad_len)
+		return;
+
+	WPA_PUT_BE16(aad_buf, aad_len);
+	os_memcpy(aad_buf + 2, aad, aad_len);
+	os_memset(aad_buf + 2 + aad_len, 0, sizeof(aad_buf) - 2 - aad_len);
+
+	xor_aes_block(aad_buf, x);
+	aes_encrypt(aes, aad_buf, x); /* X_2 = E(K, X_1 XOR B_1) */
+
+	if (aad_len > AES_BLOCK_SIZE - 2) {
+		xor_aes_block(&aad_buf[AES_BLOCK_SIZE], x);
+		/* X_3 = E(K, X_2 XOR B_2) */
+		aes_encrypt(aes, &aad_buf[AES_BLOCK_SIZE], x);
+	}
+}
+
+
+static void aes_ccm_auth(void *aes, const u8 *data, size_t len, u8 *x)
+{
+	size_t last = len % AES_BLOCK_SIZE;
+	size_t i;
+
+	for (i = 0; i < len / AES_BLOCK_SIZE; i++) {
+		/* X_i+1 = E(K, X_i XOR B_i) */
+		xor_aes_block(x, data);
+		data += AES_BLOCK_SIZE;
+		aes_encrypt(aes, x, x);
+	}
+	if (last) {
+		/* XOR zero-padded last block */
+		for (i = 0; i < last; i++)
+			x[i] ^= *data++;
+		aes_encrypt(aes, x, x);
+	}
+}
+
+
+static void aes_ccm_encr_start(size_t L, const u8 *nonce, u8 *a)
+{
+	/* A_i = Flags | Nonce N | Counter i */
+	a[0] = L - 1; /* Flags = L' */
+	os_memcpy(&a[1], nonce, 15 - L);
+}
+
+
+static void aes_ccm_encr(void *aes, size_t L, const u8 *in, size_t len, u8 *out,
+			 u8 *a)
+{
+	size_t last = len % AES_BLOCK_SIZE;
+	size_t i;
+
+	/* crypt = msg XOR (S_1 | S_2 | ... | S_n) */
+	for (i = 1; i <= len / AES_BLOCK_SIZE; i++) {
+		WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], i);
+		/* S_i = E(K, A_i) */
+		aes_encrypt(aes, a, out);
+		xor_aes_block(out, in);
+		out += AES_BLOCK_SIZE;
+		in += AES_BLOCK_SIZE;
+	}
+	if (last) {
+		WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], i);
+		aes_encrypt(aes, a, out);
+		/* XOR zero-padded last block */
+		for (i = 0; i < last; i++)
+			*out++ ^= *in++;
+	}
+}
+
+
+static void aes_ccm_encr_auth(void *aes, size_t M, u8 *x, u8 *a, u8 *auth)
+{
+	size_t i;
+	u8 tmp[AES_BLOCK_SIZE];
+
+	wpa_hexdump_key(MSG_EXCESSIVE, "CCM T", x, M);
+	/* U = T XOR S_0; S_0 = E(K, A_0) */
+	WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], 0);
+	aes_encrypt(aes, a, tmp);
+	for (i = 0; i < M; i++)
+		auth[i] = x[i] ^ tmp[i];
+	wpa_hexdump_key(MSG_EXCESSIVE, "CCM U", auth, M);
+}
+
+
+static void aes_ccm_decr_auth(void *aes, size_t M, u8 *a, const u8 *auth, u8 *t)
+{
+	size_t i;
+	u8 tmp[AES_BLOCK_SIZE];
+
+	wpa_hexdump_key(MSG_EXCESSIVE, "CCM U", auth, M);
+	/* U = T XOR S_0; S_0 = E(K, A_0) */
+	WPA_PUT_BE16(&a[AES_BLOCK_SIZE - 2], 0);
+	aes_encrypt(aes, a, tmp);
+	for (i = 0; i < M; i++)
+		t[i] = auth[i] ^ tmp[i];
+	wpa_hexdump_key(MSG_EXCESSIVE, "CCM T", t, M);
+}
+
+
+/* AES-CCM with fixed L=2 and aad_len <= 30 assumption */
+int aes_ccm_ae(const u8 *key, size_t key_len, const u8 *nonce,
+	       size_t M, const u8 *plain, size_t plain_len,
+	       const u8 *aad, size_t aad_len, u8 *crypt, u8 *auth)
+{
+	const size_t L = 2;
+	void *aes;
+	u8 x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE];
+
+	if (aad_len > 30 || M > AES_BLOCK_SIZE)
+		return -1;
+
+	aes = aes_encrypt_init(key, key_len);
+	if (aes == NULL)
+		return -1;
+
+	aes_ccm_auth_start(aes, M, L, nonce, aad, aad_len, plain_len, x);
+	aes_ccm_auth(aes, plain, plain_len, x);
+
+	/* Encryption */
+	aes_ccm_encr_start(L, nonce, a);
+	aes_ccm_encr(aes, L, plain, plain_len, crypt, a);
+	aes_ccm_encr_auth(aes, M, x, a, auth);
+
+	aes_encrypt_deinit(aes);
+
+	return 0;
+}
+
+
+/* AES-CCM with fixed L=2 and aad_len <= 30 assumption */
+int aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce,
+	       size_t M, const u8 *crypt, size_t crypt_len,
+	       const u8 *aad, size_t aad_len, const u8 *auth, u8 *plain)
+{
+	const size_t L = 2;
+	void *aes;
+	u8 x[AES_BLOCK_SIZE], a[AES_BLOCK_SIZE];
+	u8 t[AES_BLOCK_SIZE];
+
+	if (aad_len > 30 || M > AES_BLOCK_SIZE)
+		return -1;
+
+	aes = aes_encrypt_init(key, key_len);
+	if (aes == NULL)
+		return -1;
+
+	/* Decryption */
+	aes_ccm_encr_start(L, nonce, a);
+	aes_ccm_decr_auth(aes, M, a, auth, t);
+
+	/* plaintext = msg XOR (S_1 | S_2 | ... | S_n) */
+	aes_ccm_encr(aes, L, crypt, crypt_len, plain, a);
+
+	aes_ccm_auth_start(aes, M, L, nonce, aad, aad_len, crypt_len, x);
+	aes_ccm_auth(aes, plain, crypt_len, x);
+
+	aes_encrypt_deinit(aes);
+
+	if (os_memcmp(x, t, M) != 0) {
+		wpa_printf(MSG_EXCESSIVE, "CCM: Auth mismatch");
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/hostap/src/crypto/aes-ctr.c b/hostap/src/crypto/aes-ctr.c
new file mode 100644
index 0000000..d4d874d
--- /dev/null
+++ b/hostap/src/crypto/aes-ctr.c
@@ -0,0 +1,55 @@
+/*
+ * AES-128 CTR
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "aes.h"
+#include "aes_wrap.h"
+
+/**
+ * aes_128_ctr_encrypt - AES-128 CTR mode encryption
+ * @key: Key for encryption (16 bytes)
+ * @nonce: Nonce for counter mode (16 bytes)
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
+			u8 *data, size_t data_len)
+{
+	void *ctx;
+	size_t j, len, left = data_len;
+	int i;
+	u8 *pos = data;
+	u8 counter[AES_BLOCK_SIZE], buf[AES_BLOCK_SIZE];
+
+	ctx = aes_encrypt_init(key, 16);
+	if (ctx == NULL)
+		return -1;
+	os_memcpy(counter, nonce, AES_BLOCK_SIZE);
+
+	while (left > 0) {
+		aes_encrypt(ctx, counter, buf);
+
+		len = (left < AES_BLOCK_SIZE) ? left : AES_BLOCK_SIZE;
+		for (j = 0; j < len; j++)
+			pos[j] ^= buf[j];
+		pos += len;
+		left -= len;
+
+		for (i = AES_BLOCK_SIZE - 1; i >= 0; i--) {
+			counter[i]++;
+			if (counter[i])
+				break;
+		}
+	}
+	aes_encrypt_deinit(ctx);
+	return 0;
+}
diff --git a/hostap/src/crypto/aes-eax.c b/hostap/src/crypto/aes-eax.c
new file mode 100644
index 0000000..21941c6
--- /dev/null
+++ b/hostap/src/crypto/aes-eax.c
@@ -0,0 +1,145 @@
+/*
+ * AES-128 EAX
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "aes.h"
+#include "aes_wrap.h"
+
+/**
+ * aes_128_eax_encrypt - AES-128 EAX mode encryption
+ * @key: Key for encryption (16 bytes)
+ * @nonce: Nonce for counter mode
+ * @nonce_len: Nonce length in bytes
+ * @hdr: Header data to be authenticity protected
+ * @hdr_len: Length of the header data bytes
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes
+ * @tag: 16-byte tag value
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_eax_encrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
+			const u8 *hdr, size_t hdr_len,
+			u8 *data, size_t data_len, u8 *tag)
+{
+	u8 *buf;
+	size_t buf_len;
+	u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE],
+		data_mac[AES_BLOCK_SIZE];
+	int i, ret = -1;
+
+	if (nonce_len > data_len)
+		buf_len = nonce_len;
+	else
+		buf_len = data_len;
+	if (hdr_len > buf_len)
+		buf_len = hdr_len;
+	buf_len += 16;
+
+	buf = os_malloc(buf_len);
+	if (buf == NULL)
+		return -1;
+
+	os_memset(buf, 0, 15);
+
+	buf[15] = 0;
+	os_memcpy(buf + 16, nonce, nonce_len);
+	if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac))
+		goto fail;
+
+	buf[15] = 1;
+	os_memcpy(buf + 16, hdr, hdr_len);
+	if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac))
+		goto fail;
+
+	if (aes_128_ctr_encrypt(key, nonce_mac, data, data_len))
+		goto fail;
+	buf[15] = 2;
+	os_memcpy(buf + 16, data, data_len);
+	if (omac1_aes_128(key, buf, 16 + data_len, data_mac))
+		goto fail;
+
+	for (i = 0; i < AES_BLOCK_SIZE; i++)
+		tag[i] = nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i];
+
+	ret = 0;
+fail:
+	os_free(buf);
+
+	return ret;
+}
+
+
+/**
+ * aes_128_eax_decrypt - AES-128 EAX mode decryption
+ * @key: Key for decryption (16 bytes)
+ * @nonce: Nonce for counter mode
+ * @nonce_len: Nonce length in bytes
+ * @hdr: Header data to be authenticity protected
+ * @hdr_len: Length of the header data bytes
+ * @data: Data to encrypt in-place
+ * @data_len: Length of data in bytes
+ * @tag: 16-byte tag value
+ * Returns: 0 on success, -1 on failure, -2 if tag does not match
+ */
+int aes_128_eax_decrypt(const u8 *key, const u8 *nonce, size_t nonce_len,
+			const u8 *hdr, size_t hdr_len,
+			u8 *data, size_t data_len, const u8 *tag)
+{
+	u8 *buf;
+	size_t buf_len;
+	u8 nonce_mac[AES_BLOCK_SIZE], hdr_mac[AES_BLOCK_SIZE],
+		data_mac[AES_BLOCK_SIZE];
+	int i;
+
+	if (nonce_len > data_len)
+		buf_len = nonce_len;
+	else
+		buf_len = data_len;
+	if (hdr_len > buf_len)
+		buf_len = hdr_len;
+	buf_len += 16;
+
+	buf = os_malloc(buf_len);
+	if (buf == NULL)
+		return -1;
+
+	os_memset(buf, 0, 15);
+
+	buf[15] = 0;
+	os_memcpy(buf + 16, nonce, nonce_len);
+	if (omac1_aes_128(key, buf, 16 + nonce_len, nonce_mac)) {
+		os_free(buf);
+		return -1;
+	}
+
+	buf[15] = 1;
+	os_memcpy(buf + 16, hdr, hdr_len);
+	if (omac1_aes_128(key, buf, 16 + hdr_len, hdr_mac)) {
+		os_free(buf);
+		return -1;
+	}
+
+	buf[15] = 2;
+	os_memcpy(buf + 16, data, data_len);
+	if (omac1_aes_128(key, buf, 16 + data_len, data_mac)) {
+		os_free(buf);
+		return -1;
+	}
+
+	os_free(buf);
+
+	for (i = 0; i < AES_BLOCK_SIZE; i++) {
+		if (tag[i] != (nonce_mac[i] ^ data_mac[i] ^ hdr_mac[i]))
+			return -2;
+	}
+
+	return aes_128_ctr_encrypt(key, nonce_mac, data, data_len);
+}
diff --git a/hostap/src/crypto/aes-encblock.c b/hostap/src/crypto/aes-encblock.c
new file mode 100644
index 0000000..a521621
--- /dev/null
+++ b/hostap/src/crypto/aes-encblock.c
@@ -0,0 +1,32 @@
+/*
+ * AES encrypt_block
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "aes.h"
+#include "aes_wrap.h"
+
+/**
+ * aes_128_encrypt_block - Perform one AES 128-bit block operation
+ * @key: Key for AES
+ * @in: Input data (16 bytes)
+ * @out: Output of the AES block operation (16 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out)
+{
+	void *ctx;
+	ctx = aes_encrypt_init(key, 16);
+	if (ctx == NULL)
+		return -1;
+	aes_encrypt(ctx, in, out);
+	aes_encrypt_deinit(ctx);
+	return 0;
+}
diff --git a/hostap/src/crypto/aes-gcm.c b/hostap/src/crypto/aes-gcm.c
new file mode 100644
index 0000000..3d91c71
--- /dev/null
+++ b/hostap/src/crypto/aes-gcm.c
@@ -0,0 +1,327 @@
+/*
+ * Galois/Counter Mode (GCM) and GMAC with AES
+ *
+ * Copyright (c) 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "aes.h"
+#include "aes_wrap.h"
+
+static void inc32(u8 *block)
+{
+	u32 val;
+	val = WPA_GET_BE32(block + AES_BLOCK_SIZE - 4);
+	val++;
+	WPA_PUT_BE32(block + AES_BLOCK_SIZE - 4, val);
+}
+
+
+static void xor_block(u8 *dst, const u8 *src)
+{
+	u32 *d = (u32 *) dst;
+	u32 *s = (u32 *) src;
+	*d++ ^= *s++;
+	*d++ ^= *s++;
+	*d++ ^= *s++;
+	*d++ ^= *s++;
+}
+
+
+static void shift_right_block(u8 *v)
+{
+	u32 val;
+
+	val = WPA_GET_BE32(v + 12);
+	val >>= 1;
+	if (v[11] & 0x01)
+		val |= 0x80000000;
+	WPA_PUT_BE32(v + 12, val);
+
+	val = WPA_GET_BE32(v + 8);
+	val >>= 1;
+	if (v[7] & 0x01)
+		val |= 0x80000000;
+	WPA_PUT_BE32(v + 8, val);
+
+	val = WPA_GET_BE32(v + 4);
+	val >>= 1;
+	if (v[3] & 0x01)
+		val |= 0x80000000;
+	WPA_PUT_BE32(v + 4, val);
+
+	val = WPA_GET_BE32(v);
+	val >>= 1;
+	WPA_PUT_BE32(v, val);
+}
+
+
+/* Multiplication in GF(2^128) */
+static void gf_mult(const u8 *x, const u8 *y, u8 *z)
+{
+	u8 v[16];
+	int i, j;
+
+	os_memset(z, 0, 16); /* Z_0 = 0^128 */
+	os_memcpy(v, y, 16); /* V_0 = Y */
+
+	for (i = 0; i < 16; i++) {
+		for (j = 0; j < 8; j++) {
+			if (x[i] & BIT(7 - j)) {
+				/* Z_(i + 1) = Z_i XOR V_i */
+				xor_block(z, v);
+			} else {
+				/* Z_(i + 1) = Z_i */
+			}
+
+			if (v[15] & 0x01) {
+				/* V_(i + 1) = (V_i >> 1) XOR R */
+				shift_right_block(v);
+				/* R = 11100001 || 0^120 */
+				v[0] ^= 0xe1;
+			} else {
+				/* V_(i + 1) = V_i >> 1 */
+				shift_right_block(v);
+			}
+		}
+	}
+}
+
+
+static void ghash_start(u8 *y)
+{
+	/* Y_0 = 0^128 */
+	os_memset(y, 0, 16);
+}
+
+
+static void ghash(const u8 *h, const u8 *x, size_t xlen, u8 *y)
+{
+	size_t m, i;
+	const u8 *xpos = x;
+	u8 tmp[16];
+
+	m = xlen / 16;
+
+	for (i = 0; i < m; i++) {
+		/* Y_i = (Y^(i-1) XOR X_i) dot H */
+		xor_block(y, xpos);
+		xpos += 16;
+
+		/* dot operation:
+		 * multiplication operation for binary Galois (finite) field of
+		 * 2^128 elements */
+		gf_mult(y, h, tmp);
+		os_memcpy(y, tmp, 16);
+	}
+
+	if (x + xlen > xpos) {
+		/* Add zero padded last block */
+		size_t last = x + xlen - xpos;
+		os_memcpy(tmp, xpos, last);
+		os_memset(tmp + last, 0, sizeof(tmp) - last);
+
+		/* Y_i = (Y^(i-1) XOR X_i) dot H */
+		xor_block(y, tmp);
+
+		/* dot operation:
+		 * multiplication operation for binary Galois (finite) field of
+		 * 2^128 elements */
+		gf_mult(y, h, tmp);
+		os_memcpy(y, tmp, 16);
+	}
+
+	/* Return Y_m */
+}
+
+
+static void aes_gctr(void *aes, const u8 *icb, const u8 *x, size_t xlen, u8 *y)
+{
+	size_t i, n, last;
+	u8 cb[AES_BLOCK_SIZE], tmp[AES_BLOCK_SIZE];
+	const u8 *xpos = x;
+	u8 *ypos = y;
+
+	if (xlen == 0)
+		return;
+
+	n = xlen / 16;
+
+	os_memcpy(cb, icb, AES_BLOCK_SIZE);
+	/* Full blocks */
+	for (i = 0; i < n; i++) {
+		aes_encrypt(aes, cb, ypos);
+		xor_block(ypos, xpos);
+		xpos += AES_BLOCK_SIZE;
+		ypos += AES_BLOCK_SIZE;
+		inc32(cb);
+	}
+
+	last = x + xlen - xpos;
+	if (last) {
+		/* Last, partial block */
+		aes_encrypt(aes, cb, tmp);
+		for (i = 0; i < last; i++)
+			*ypos++ = *xpos++ ^ tmp[i];
+	}
+}
+
+
+static void * aes_gcm_init_hash_subkey(const u8 *key, size_t key_len, u8 *H)
+{
+	void *aes;
+
+	aes = aes_encrypt_init(key, key_len);
+	if (aes == NULL)
+		return NULL;
+
+	/* Generate hash subkey H = AES_K(0^128) */
+	os_memset(H, 0, AES_BLOCK_SIZE);
+	aes_encrypt(aes, H, H);
+	wpa_hexdump_key(MSG_EXCESSIVE, "Hash subkey H for GHASH",
+			H, AES_BLOCK_SIZE);
+	return aes;
+}
+
+
+static void aes_gcm_prepare_j0(const u8 *iv, size_t iv_len, const u8 *H, u8 *J0)
+{
+	u8 len_buf[16];
+
+	if (iv_len == 12) {
+		/* Prepare block J_0 = IV || 0^31 || 1 [len(IV) = 96] */
+		os_memcpy(J0, iv, iv_len);
+		os_memset(J0 + iv_len, 0, AES_BLOCK_SIZE - iv_len);
+		J0[AES_BLOCK_SIZE - 1] = 0x01;
+	} else {
+		/*
+		 * s = 128 * ceil(len(IV)/128) - len(IV)
+		 * J_0 = GHASH_H(IV || 0^(s+64) || [len(IV)]_64)
+		 */
+		ghash_start(J0);
+		ghash(H, iv, iv_len, J0);
+		WPA_PUT_BE64(len_buf, 0);
+		WPA_PUT_BE64(len_buf + 8, iv_len * 8);
+		ghash(H, len_buf, sizeof(len_buf), J0);
+	}
+}
+
+
+static void aes_gcm_gctr(void *aes, const u8 *J0, const u8 *in, size_t len,
+			 u8 *out)
+{
+	u8 J0inc[AES_BLOCK_SIZE];
+
+	if (len == 0)
+		return;
+
+	os_memcpy(J0inc, J0, AES_BLOCK_SIZE);
+	inc32(J0inc);
+	aes_gctr(aes, J0inc, in, len, out);
+}
+
+
+static void aes_gcm_ghash(const u8 *H, const u8 *aad, size_t aad_len,
+			  const u8 *crypt, size_t crypt_len, u8 *S)
+{
+	u8 len_buf[16];
+
+	/*
+	 * u = 128 * ceil[len(C)/128] - len(C)
+	 * v = 128 * ceil[len(A)/128] - len(A)
+	 * S = GHASH_H(A || 0^v || C || 0^u || [len(A)]64 || [len(C)]64)
+	 * (i.e., zero padded to block size A || C and lengths of each in bits)
+	 */
+	ghash_start(S);
+	ghash(H, aad, aad_len, S);
+	ghash(H, crypt, crypt_len, S);
+	WPA_PUT_BE64(len_buf, aad_len * 8);
+	WPA_PUT_BE64(len_buf + 8, crypt_len * 8);
+	ghash(H, len_buf, sizeof(len_buf), S);
+
+	wpa_hexdump_key(MSG_EXCESSIVE, "S = GHASH_H(...)", S, 16);
+}
+
+
+/**
+ * aes_gcm_ae - GCM-AE_K(IV, P, A)
+ */
+int aes_gcm_ae(const u8 *key, size_t key_len, const u8 *iv, size_t iv_len,
+	       const u8 *plain, size_t plain_len,
+	       const u8 *aad, size_t aad_len, u8 *crypt, u8 *tag)
+{
+	u8 H[AES_BLOCK_SIZE];
+	u8 J0[AES_BLOCK_SIZE];
+	u8 S[16];
+	void *aes;
+
+	aes = aes_gcm_init_hash_subkey(key, key_len, H);
+	if (aes == NULL)
+		return -1;
+
+	aes_gcm_prepare_j0(iv, iv_len, H, J0);
+
+	/* C = GCTR_K(inc_32(J_0), P) */
+	aes_gcm_gctr(aes, J0, plain, plain_len, crypt);
+
+	aes_gcm_ghash(H, aad, aad_len, crypt, plain_len, S);
+
+	/* T = MSB_t(GCTR_K(J_0, S)) */
+	aes_gctr(aes, J0, S, sizeof(S), tag);
+
+	/* Return (C, T) */
+
+	aes_encrypt_deinit(aes);
+
+	return 0;
+}
+
+
+/**
+ * aes_gcm_ad - GCM-AD_K(IV, C, A, T)
+ */
+int aes_gcm_ad(const u8 *key, size_t key_len, const u8 *iv, size_t iv_len,
+	       const u8 *crypt, size_t crypt_len,
+	       const u8 *aad, size_t aad_len, const u8 *tag, u8 *plain)
+{
+	u8 H[AES_BLOCK_SIZE];
+	u8 J0[AES_BLOCK_SIZE];
+	u8 S[16], T[16];
+	void *aes;
+
+	aes = aes_gcm_init_hash_subkey(key, key_len, H);
+	if (aes == NULL)
+		return -1;
+
+	aes_gcm_prepare_j0(iv, iv_len, H, J0);
+
+	/* P = GCTR_K(inc_32(J_0), C) */
+	aes_gcm_gctr(aes, J0, crypt, crypt_len, plain);
+
+	aes_gcm_ghash(H, aad, aad_len, crypt, crypt_len, S);
+
+	/* T' = MSB_t(GCTR_K(J_0, S)) */
+	aes_gctr(aes, J0, S, sizeof(S), T);
+
+	aes_encrypt_deinit(aes);
+
+	if (os_memcmp(tag, T, 16) != 0) {
+		wpa_printf(MSG_EXCESSIVE, "GCM: Tag mismatch");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int aes_gmac(const u8 *key, size_t key_len, const u8 *iv, size_t iv_len,
+	     const u8 *aad, size_t aad_len, u8 *tag)
+{
+	return aes_gcm_ae(key, key_len, iv, iv_len, NULL, 0, aad, aad_len, NULL,
+			  tag);
+}
diff --git a/hostap/src/crypto/aes-internal-dec.c b/hostap/src/crypto/aes-internal-dec.c
new file mode 100644
index 0000000..720c703
--- /dev/null
+++ b/hostap/src/crypto/aes-internal-dec.c
@@ -0,0 +1,161 @@
+/*
+ * AES (Rijndael) cipher - decrypt
+ *
+ * Modifications to public domain implementation:
+ * - cleanup
+ * - use C pre-processor to make it easier to change S table access
+ * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
+ *   cost of reduced throughput (quite small difference on Pentium 4,
+ *   10-25% when using -O1 or -O2 optimization)
+ *
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+#include "aes_i.h"
+
+/**
+ * Expand the cipher key into the decryption key schedule.
+ *
+ * @return	the number of rounds for the given cipher key size.
+ */
+static int rijndaelKeySetupDec(u32 rk[], const u8 cipherKey[], int keyBits)
+{
+	int Nr, i, j;
+	u32 temp;
+
+	/* expand the cipher key: */
+	Nr = rijndaelKeySetupEnc(rk, cipherKey, keyBits);
+	if (Nr < 0)
+		return Nr;
+	/* invert the order of the round keys: */
+	for (i = 0, j = 4*Nr; i < j; i += 4, j -= 4) {
+		temp = rk[i    ]; rk[i    ] = rk[j    ]; rk[j    ] = temp;
+		temp = rk[i + 1]; rk[i + 1] = rk[j + 1]; rk[j + 1] = temp;
+		temp = rk[i + 2]; rk[i + 2] = rk[j + 2]; rk[j + 2] = temp;
+		temp = rk[i + 3]; rk[i + 3] = rk[j + 3]; rk[j + 3] = temp;
+	}
+	/* apply the inverse MixColumn transform to all round keys but the
+	 * first and the last: */
+	for (i = 1; i < Nr; i++) {
+		rk += 4;
+		for (j = 0; j < 4; j++) {
+			rk[j] = TD0_(TE4((rk[j] >> 24)       )) ^
+				TD1_(TE4((rk[j] >> 16) & 0xff)) ^
+				TD2_(TE4((rk[j] >>  8) & 0xff)) ^
+				TD3_(TE4((rk[j]      ) & 0xff));
+		}
+	}
+
+	return Nr;
+}
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+	u32 *rk;
+	int res;
+	rk = os_malloc(AES_PRIV_SIZE);
+	if (rk == NULL)
+		return NULL;
+	res = rijndaelKeySetupDec(rk, key, len * 8);
+	if (res < 0) {
+		os_free(rk);
+		return NULL;
+	}
+	rk[AES_PRIV_NR_POS] = res;
+	return rk;
+}
+
+static void rijndaelDecrypt(const u32 rk[/*44*/], int Nr, const u8 ct[16],
+			    u8 pt[16])
+{
+	u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+	int r;
+#endif /* ?FULL_UNROLL */
+
+	/*
+	 * map byte array block to cipher state
+	 * and add initial round key:
+	 */
+	s0 = GETU32(ct     ) ^ rk[0];
+	s1 = GETU32(ct +  4) ^ rk[1];
+	s2 = GETU32(ct +  8) ^ rk[2];
+	s3 = GETU32(ct + 12) ^ rk[3];
+
+#define ROUND(i,d,s) \
+d##0 = TD0(s##0) ^ TD1(s##3) ^ TD2(s##2) ^ TD3(s##1) ^ rk[4 * i]; \
+d##1 = TD0(s##1) ^ TD1(s##0) ^ TD2(s##3) ^ TD3(s##2) ^ rk[4 * i + 1]; \
+d##2 = TD0(s##2) ^ TD1(s##1) ^ TD2(s##0) ^ TD3(s##3) ^ rk[4 * i + 2]; \
+d##3 = TD0(s##3) ^ TD1(s##2) ^ TD2(s##1) ^ TD3(s##0) ^ rk[4 * i + 3]
+
+#ifdef FULL_UNROLL
+
+	ROUND(1,t,s);
+	ROUND(2,s,t);
+	ROUND(3,t,s);
+	ROUND(4,s,t);
+	ROUND(5,t,s);
+	ROUND(6,s,t);
+	ROUND(7,t,s);
+	ROUND(8,s,t);
+	ROUND(9,t,s);
+	if (Nr > 10) {
+		ROUND(10,s,t);
+		ROUND(11,t,s);
+		if (Nr > 12) {
+			ROUND(12,s,t);
+			ROUND(13,t,s);
+		}
+	}
+
+	rk += Nr << 2;
+
+#else  /* !FULL_UNROLL */
+
+	/* Nr - 1 full rounds: */
+	r = Nr >> 1;
+	for (;;) {
+		ROUND(1,t,s);
+		rk += 8;
+		if (--r == 0)
+			break;
+		ROUND(0,s,t);
+	}
+
+#endif /* ?FULL_UNROLL */
+
+#undef ROUND
+
+	/*
+	 * apply last round and
+	 * map cipher state to byte array block:
+	 */
+	s0 = TD41(t0) ^ TD42(t3) ^ TD43(t2) ^ TD44(t1) ^ rk[0];
+	PUTU32(pt     , s0);
+	s1 = TD41(t1) ^ TD42(t0) ^ TD43(t3) ^ TD44(t2) ^ rk[1];
+	PUTU32(pt +  4, s1);
+	s2 = TD41(t2) ^ TD42(t1) ^ TD43(t0) ^ TD44(t3) ^ rk[2];
+	PUTU32(pt +  8, s2);
+	s3 = TD41(t3) ^ TD42(t2) ^ TD43(t1) ^ TD44(t0) ^ rk[3];
+	PUTU32(pt + 12, s3);
+}
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+	u32 *rk = ctx;
+	rijndaelDecrypt(ctx, rk[AES_PRIV_NR_POS], crypt, plain);
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+	os_memset(ctx, 0, AES_PRIV_SIZE);
+	os_free(ctx);
+}
diff --git a/hostap/src/crypto/aes-internal-enc.c b/hostap/src/crypto/aes-internal-enc.c
new file mode 100644
index 0000000..f3c61b8
--- /dev/null
+++ b/hostap/src/crypto/aes-internal-enc.c
@@ -0,0 +1,126 @@
+/*
+ * AES (Rijndael) cipher - encrypt
+ *
+ * Modifications to public domain implementation:
+ * - cleanup
+ * - use C pre-processor to make it easier to change S table access
+ * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
+ *   cost of reduced throughput (quite small difference on Pentium 4,
+ *   10-25% when using -O1 or -O2 optimization)
+ *
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+#include "aes_i.h"
+
+static void rijndaelEncrypt(const u32 rk[], int Nr, const u8 pt[16], u8 ct[16])
+{
+	u32 s0, s1, s2, s3, t0, t1, t2, t3;
+#ifndef FULL_UNROLL
+	int r;
+#endif /* ?FULL_UNROLL */
+
+	/*
+	 * map byte array block to cipher state
+	 * and add initial round key:
+	 */
+	s0 = GETU32(pt     ) ^ rk[0];
+	s1 = GETU32(pt +  4) ^ rk[1];
+	s2 = GETU32(pt +  8) ^ rk[2];
+	s3 = GETU32(pt + 12) ^ rk[3];
+
+#define ROUND(i,d,s) \
+d##0 = TE0(s##0) ^ TE1(s##1) ^ TE2(s##2) ^ TE3(s##3) ^ rk[4 * i]; \
+d##1 = TE0(s##1) ^ TE1(s##2) ^ TE2(s##3) ^ TE3(s##0) ^ rk[4 * i + 1]; \
+d##2 = TE0(s##2) ^ TE1(s##3) ^ TE2(s##0) ^ TE3(s##1) ^ rk[4 * i + 2]; \
+d##3 = TE0(s##3) ^ TE1(s##0) ^ TE2(s##1) ^ TE3(s##2) ^ rk[4 * i + 3]
+
+#ifdef FULL_UNROLL
+
+	ROUND(1,t,s);
+	ROUND(2,s,t);
+	ROUND(3,t,s);
+	ROUND(4,s,t);
+	ROUND(5,t,s);
+	ROUND(6,s,t);
+	ROUND(7,t,s);
+	ROUND(8,s,t);
+	ROUND(9,t,s);
+	if (Nr > 10) {
+		ROUND(10,s,t);
+		ROUND(11,t,s);
+		if (Nr > 12) {
+			ROUND(12,s,t);
+			ROUND(13,t,s);
+		}
+	}
+
+	rk += Nr << 2;
+
+#else  /* !FULL_UNROLL */
+
+	/* Nr - 1 full rounds: */
+	r = Nr >> 1;
+	for (;;) {
+		ROUND(1,t,s);
+		rk += 8;
+		if (--r == 0)
+			break;
+		ROUND(0,s,t);
+	}
+
+#endif /* ?FULL_UNROLL */
+
+#undef ROUND
+
+	/*
+	 * apply last round and
+	 * map cipher state to byte array block:
+	 */
+	s0 = TE41(t0) ^ TE42(t1) ^ TE43(t2) ^ TE44(t3) ^ rk[0];
+	PUTU32(ct     , s0);
+	s1 = TE41(t1) ^ TE42(t2) ^ TE43(t3) ^ TE44(t0) ^ rk[1];
+	PUTU32(ct +  4, s1);
+	s2 = TE41(t2) ^ TE42(t3) ^ TE43(t0) ^ TE44(t1) ^ rk[2];
+	PUTU32(ct +  8, s2);
+	s3 = TE41(t3) ^ TE42(t0) ^ TE43(t1) ^ TE44(t2) ^ rk[3];
+	PUTU32(ct + 12, s3);
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+	u32 *rk;
+	int res;
+	rk = os_malloc(AES_PRIV_SIZE);
+	if (rk == NULL)
+		return NULL;
+	res = rijndaelKeySetupEnc(rk, key, len * 8);
+	if (res < 0) {
+		os_free(rk);
+		return NULL;
+	}
+	rk[AES_PRIV_NR_POS] = res;
+	return rk;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+	u32 *rk = ctx;
+	rijndaelEncrypt(ctx, rk[AES_PRIV_NR_POS], plain, crypt);
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+	os_memset(ctx, 0, AES_PRIV_SIZE);
+	os_free(ctx);
+}
diff --git a/hostap/src/crypto/aes-internal.c b/hostap/src/crypto/aes-internal.c
new file mode 100644
index 0000000..bd4535d
--- /dev/null
+++ b/hostap/src/crypto/aes-internal.c
@@ -0,0 +1,845 @@
+/*
+ * AES (Rijndael) cipher
+ *
+ * Modifications to public domain implementation:
+ * - cleanup
+ * - use C pre-processor to make it easier to change S table access
+ * - added option (AES_SMALL_TABLES) for reducing code size by about 8 kB at
+ *   cost of reduced throughput (quite small difference on Pentium 4,
+ *   10-25% when using -O1 or -O2 optimization)
+ *
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+#include "aes_i.h"
+
+/*
+ * rijndael-alg-fst.c
+ *
+ * @version 3.0 (December 2000)
+ *
+ * Optimised ANSI C code for the Rijndael cipher (now AES)
+ *
+ * @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+ * @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+ * @author Paulo Barreto <paulo.barreto@terra.com.br>
+ *
+ * This code is hereby placed in the public domain.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+/*
+Te0[x] = S [x].[02, 01, 01, 03];
+Te1[x] = S [x].[03, 02, 01, 01];
+Te2[x] = S [x].[01, 03, 02, 01];
+Te3[x] = S [x].[01, 01, 03, 02];
+Te4[x] = S [x].[01, 01, 01, 01];
+
+Td0[x] = Si[x].[0e, 09, 0d, 0b];
+Td1[x] = Si[x].[0b, 0e, 09, 0d];
+Td2[x] = Si[x].[0d, 0b, 0e, 09];
+Td3[x] = Si[x].[09, 0d, 0b, 0e];
+Td4[x] = Si[x].[01, 01, 01, 01];
+*/
+
+const u32 Te0[256] = {
+    0xc66363a5U, 0xf87c7c84U, 0xee777799U, 0xf67b7b8dU,
+    0xfff2f20dU, 0xd66b6bbdU, 0xde6f6fb1U, 0x91c5c554U,
+    0x60303050U, 0x02010103U, 0xce6767a9U, 0x562b2b7dU,
+    0xe7fefe19U, 0xb5d7d762U, 0x4dababe6U, 0xec76769aU,
+    0x8fcaca45U, 0x1f82829dU, 0x89c9c940U, 0xfa7d7d87U,
+    0xeffafa15U, 0xb25959ebU, 0x8e4747c9U, 0xfbf0f00bU,
+    0x41adadecU, 0xb3d4d467U, 0x5fa2a2fdU, 0x45afafeaU,
+    0x239c9cbfU, 0x53a4a4f7U, 0xe4727296U, 0x9bc0c05bU,
+    0x75b7b7c2U, 0xe1fdfd1cU, 0x3d9393aeU, 0x4c26266aU,
+    0x6c36365aU, 0x7e3f3f41U, 0xf5f7f702U, 0x83cccc4fU,
+    0x6834345cU, 0x51a5a5f4U, 0xd1e5e534U, 0xf9f1f108U,
+    0xe2717193U, 0xabd8d873U, 0x62313153U, 0x2a15153fU,
+    0x0804040cU, 0x95c7c752U, 0x46232365U, 0x9dc3c35eU,
+    0x30181828U, 0x379696a1U, 0x0a05050fU, 0x2f9a9ab5U,
+    0x0e070709U, 0x24121236U, 0x1b80809bU, 0xdfe2e23dU,
+    0xcdebeb26U, 0x4e272769U, 0x7fb2b2cdU, 0xea75759fU,
+    0x1209091bU, 0x1d83839eU, 0x582c2c74U, 0x341a1a2eU,
+    0x361b1b2dU, 0xdc6e6eb2U, 0xb45a5aeeU, 0x5ba0a0fbU,
+    0xa45252f6U, 0x763b3b4dU, 0xb7d6d661U, 0x7db3b3ceU,
+    0x5229297bU, 0xdde3e33eU, 0x5e2f2f71U, 0x13848497U,
+    0xa65353f5U, 0xb9d1d168U, 0x00000000U, 0xc1eded2cU,
+    0x40202060U, 0xe3fcfc1fU, 0x79b1b1c8U, 0xb65b5bedU,
+    0xd46a6abeU, 0x8dcbcb46U, 0x67bebed9U, 0x7239394bU,
+    0x944a4adeU, 0x984c4cd4U, 0xb05858e8U, 0x85cfcf4aU,
+    0xbbd0d06bU, 0xc5efef2aU, 0x4faaaae5U, 0xedfbfb16U,
+    0x864343c5U, 0x9a4d4dd7U, 0x66333355U, 0x11858594U,
+    0x8a4545cfU, 0xe9f9f910U, 0x04020206U, 0xfe7f7f81U,
+    0xa05050f0U, 0x783c3c44U, 0x259f9fbaU, 0x4ba8a8e3U,
+    0xa25151f3U, 0x5da3a3feU, 0x804040c0U, 0x058f8f8aU,
+    0x3f9292adU, 0x219d9dbcU, 0x70383848U, 0xf1f5f504U,
+    0x63bcbcdfU, 0x77b6b6c1U, 0xafdada75U, 0x42212163U,
+    0x20101030U, 0xe5ffff1aU, 0xfdf3f30eU, 0xbfd2d26dU,
+    0x81cdcd4cU, 0x180c0c14U, 0x26131335U, 0xc3ecec2fU,
+    0xbe5f5fe1U, 0x359797a2U, 0x884444ccU, 0x2e171739U,
+    0x93c4c457U, 0x55a7a7f2U, 0xfc7e7e82U, 0x7a3d3d47U,
+    0xc86464acU, 0xba5d5de7U, 0x3219192bU, 0xe6737395U,
+    0xc06060a0U, 0x19818198U, 0x9e4f4fd1U, 0xa3dcdc7fU,
+    0x44222266U, 0x542a2a7eU, 0x3b9090abU, 0x0b888883U,
+    0x8c4646caU, 0xc7eeee29U, 0x6bb8b8d3U, 0x2814143cU,
+    0xa7dede79U, 0xbc5e5ee2U, 0x160b0b1dU, 0xaddbdb76U,
+    0xdbe0e03bU, 0x64323256U, 0x743a3a4eU, 0x140a0a1eU,
+    0x924949dbU, 0x0c06060aU, 0x4824246cU, 0xb85c5ce4U,
+    0x9fc2c25dU, 0xbdd3d36eU, 0x43acacefU, 0xc46262a6U,
+    0x399191a8U, 0x319595a4U, 0xd3e4e437U, 0xf279798bU,
+    0xd5e7e732U, 0x8bc8c843U, 0x6e373759U, 0xda6d6db7U,
+    0x018d8d8cU, 0xb1d5d564U, 0x9c4e4ed2U, 0x49a9a9e0U,
+    0xd86c6cb4U, 0xac5656faU, 0xf3f4f407U, 0xcfeaea25U,
+    0xca6565afU, 0xf47a7a8eU, 0x47aeaee9U, 0x10080818U,
+    0x6fbabad5U, 0xf0787888U, 0x4a25256fU, 0x5c2e2e72U,
+    0x381c1c24U, 0x57a6a6f1U, 0x73b4b4c7U, 0x97c6c651U,
+    0xcbe8e823U, 0xa1dddd7cU, 0xe874749cU, 0x3e1f1f21U,
+    0x964b4bddU, 0x61bdbddcU, 0x0d8b8b86U, 0x0f8a8a85U,
+    0xe0707090U, 0x7c3e3e42U, 0x71b5b5c4U, 0xcc6666aaU,
+    0x904848d8U, 0x06030305U, 0xf7f6f601U, 0x1c0e0e12U,
+    0xc26161a3U, 0x6a35355fU, 0xae5757f9U, 0x69b9b9d0U,
+    0x17868691U, 0x99c1c158U, 0x3a1d1d27U, 0x279e9eb9U,
+    0xd9e1e138U, 0xebf8f813U, 0x2b9898b3U, 0x22111133U,
+    0xd26969bbU, 0xa9d9d970U, 0x078e8e89U, 0x339494a7U,
+    0x2d9b9bb6U, 0x3c1e1e22U, 0x15878792U, 0xc9e9e920U,
+    0x87cece49U, 0xaa5555ffU, 0x50282878U, 0xa5dfdf7aU,
+    0x038c8c8fU, 0x59a1a1f8U, 0x09898980U, 0x1a0d0d17U,
+    0x65bfbfdaU, 0xd7e6e631U, 0x844242c6U, 0xd06868b8U,
+    0x824141c3U, 0x299999b0U, 0x5a2d2d77U, 0x1e0f0f11U,
+    0x7bb0b0cbU, 0xa85454fcU, 0x6dbbbbd6U, 0x2c16163aU,
+};
+#ifndef AES_SMALL_TABLES
+const u32 Te1[256] = {
+    0xa5c66363U, 0x84f87c7cU, 0x99ee7777U, 0x8df67b7bU,
+    0x0dfff2f2U, 0xbdd66b6bU, 0xb1de6f6fU, 0x5491c5c5U,
+    0x50603030U, 0x03020101U, 0xa9ce6767U, 0x7d562b2bU,
+    0x19e7fefeU, 0x62b5d7d7U, 0xe64dababU, 0x9aec7676U,
+    0x458fcacaU, 0x9d1f8282U, 0x4089c9c9U, 0x87fa7d7dU,
+    0x15effafaU, 0xebb25959U, 0xc98e4747U, 0x0bfbf0f0U,
+    0xec41adadU, 0x67b3d4d4U, 0xfd5fa2a2U, 0xea45afafU,
+    0xbf239c9cU, 0xf753a4a4U, 0x96e47272U, 0x5b9bc0c0U,
+    0xc275b7b7U, 0x1ce1fdfdU, 0xae3d9393U, 0x6a4c2626U,
+    0x5a6c3636U, 0x417e3f3fU, 0x02f5f7f7U, 0x4f83ccccU,
+    0x5c683434U, 0xf451a5a5U, 0x34d1e5e5U, 0x08f9f1f1U,
+    0x93e27171U, 0x73abd8d8U, 0x53623131U, 0x3f2a1515U,
+    0x0c080404U, 0x5295c7c7U, 0x65462323U, 0x5e9dc3c3U,
+    0x28301818U, 0xa1379696U, 0x0f0a0505U, 0xb52f9a9aU,
+    0x090e0707U, 0x36241212U, 0x9b1b8080U, 0x3ddfe2e2U,
+    0x26cdebebU, 0x694e2727U, 0xcd7fb2b2U, 0x9fea7575U,
+    0x1b120909U, 0x9e1d8383U, 0x74582c2cU, 0x2e341a1aU,
+    0x2d361b1bU, 0xb2dc6e6eU, 0xeeb45a5aU, 0xfb5ba0a0U,
+    0xf6a45252U, 0x4d763b3bU, 0x61b7d6d6U, 0xce7db3b3U,
+    0x7b522929U, 0x3edde3e3U, 0x715e2f2fU, 0x97138484U,
+    0xf5a65353U, 0x68b9d1d1U, 0x00000000U, 0x2cc1ededU,
+    0x60402020U, 0x1fe3fcfcU, 0xc879b1b1U, 0xedb65b5bU,
+    0xbed46a6aU, 0x468dcbcbU, 0xd967bebeU, 0x4b723939U,
+    0xde944a4aU, 0xd4984c4cU, 0xe8b05858U, 0x4a85cfcfU,
+    0x6bbbd0d0U, 0x2ac5efefU, 0xe54faaaaU, 0x16edfbfbU,
+    0xc5864343U, 0xd79a4d4dU, 0x55663333U, 0x94118585U,
+    0xcf8a4545U, 0x10e9f9f9U, 0x06040202U, 0x81fe7f7fU,
+    0xf0a05050U, 0x44783c3cU, 0xba259f9fU, 0xe34ba8a8U,
+    0xf3a25151U, 0xfe5da3a3U, 0xc0804040U, 0x8a058f8fU,
+    0xad3f9292U, 0xbc219d9dU, 0x48703838U, 0x04f1f5f5U,
+    0xdf63bcbcU, 0xc177b6b6U, 0x75afdadaU, 0x63422121U,
+    0x30201010U, 0x1ae5ffffU, 0x0efdf3f3U, 0x6dbfd2d2U,
+    0x4c81cdcdU, 0x14180c0cU, 0x35261313U, 0x2fc3ececU,
+    0xe1be5f5fU, 0xa2359797U, 0xcc884444U, 0x392e1717U,
+    0x5793c4c4U, 0xf255a7a7U, 0x82fc7e7eU, 0x477a3d3dU,
+    0xacc86464U, 0xe7ba5d5dU, 0x2b321919U, 0x95e67373U,
+    0xa0c06060U, 0x98198181U, 0xd19e4f4fU, 0x7fa3dcdcU,
+    0x66442222U, 0x7e542a2aU, 0xab3b9090U, 0x830b8888U,
+    0xca8c4646U, 0x29c7eeeeU, 0xd36bb8b8U, 0x3c281414U,
+    0x79a7dedeU, 0xe2bc5e5eU, 0x1d160b0bU, 0x76addbdbU,
+    0x3bdbe0e0U, 0x56643232U, 0x4e743a3aU, 0x1e140a0aU,
+    0xdb924949U, 0x0a0c0606U, 0x6c482424U, 0xe4b85c5cU,
+    0x5d9fc2c2U, 0x6ebdd3d3U, 0xef43acacU, 0xa6c46262U,
+    0xa8399191U, 0xa4319595U, 0x37d3e4e4U, 0x8bf27979U,
+    0x32d5e7e7U, 0x438bc8c8U, 0x596e3737U, 0xb7da6d6dU,
+    0x8c018d8dU, 0x64b1d5d5U, 0xd29c4e4eU, 0xe049a9a9U,
+    0xb4d86c6cU, 0xfaac5656U, 0x07f3f4f4U, 0x25cfeaeaU,
+    0xafca6565U, 0x8ef47a7aU, 0xe947aeaeU, 0x18100808U,
+    0xd56fbabaU, 0x88f07878U, 0x6f4a2525U, 0x725c2e2eU,
+    0x24381c1cU, 0xf157a6a6U, 0xc773b4b4U, 0x5197c6c6U,
+    0x23cbe8e8U, 0x7ca1ddddU, 0x9ce87474U, 0x213e1f1fU,
+    0xdd964b4bU, 0xdc61bdbdU, 0x860d8b8bU, 0x850f8a8aU,
+    0x90e07070U, 0x427c3e3eU, 0xc471b5b5U, 0xaacc6666U,
+    0xd8904848U, 0x05060303U, 0x01f7f6f6U, 0x121c0e0eU,
+    0xa3c26161U, 0x5f6a3535U, 0xf9ae5757U, 0xd069b9b9U,
+    0x91178686U, 0x5899c1c1U, 0x273a1d1dU, 0xb9279e9eU,
+    0x38d9e1e1U, 0x13ebf8f8U, 0xb32b9898U, 0x33221111U,
+    0xbbd26969U, 0x70a9d9d9U, 0x89078e8eU, 0xa7339494U,
+    0xb62d9b9bU, 0x223c1e1eU, 0x92158787U, 0x20c9e9e9U,
+    0x4987ceceU, 0xffaa5555U, 0x78502828U, 0x7aa5dfdfU,
+    0x8f038c8cU, 0xf859a1a1U, 0x80098989U, 0x171a0d0dU,
+    0xda65bfbfU, 0x31d7e6e6U, 0xc6844242U, 0xb8d06868U,
+    0xc3824141U, 0xb0299999U, 0x775a2d2dU, 0x111e0f0fU,
+    0xcb7bb0b0U, 0xfca85454U, 0xd66dbbbbU, 0x3a2c1616U,
+};
+const u32 Te2[256] = {
+    0x63a5c663U, 0x7c84f87cU, 0x7799ee77U, 0x7b8df67bU,
+    0xf20dfff2U, 0x6bbdd66bU, 0x6fb1de6fU, 0xc55491c5U,
+    0x30506030U, 0x01030201U, 0x67a9ce67U, 0x2b7d562bU,
+    0xfe19e7feU, 0xd762b5d7U, 0xabe64dabU, 0x769aec76U,
+    0xca458fcaU, 0x829d1f82U, 0xc94089c9U, 0x7d87fa7dU,
+    0xfa15effaU, 0x59ebb259U, 0x47c98e47U, 0xf00bfbf0U,
+    0xadec41adU, 0xd467b3d4U, 0xa2fd5fa2U, 0xafea45afU,
+    0x9cbf239cU, 0xa4f753a4U, 0x7296e472U, 0xc05b9bc0U,
+    0xb7c275b7U, 0xfd1ce1fdU, 0x93ae3d93U, 0x266a4c26U,
+    0x365a6c36U, 0x3f417e3fU, 0xf702f5f7U, 0xcc4f83ccU,
+    0x345c6834U, 0xa5f451a5U, 0xe534d1e5U, 0xf108f9f1U,
+    0x7193e271U, 0xd873abd8U, 0x31536231U, 0x153f2a15U,
+    0x040c0804U, 0xc75295c7U, 0x23654623U, 0xc35e9dc3U,
+    0x18283018U, 0x96a13796U, 0x050f0a05U, 0x9ab52f9aU,
+    0x07090e07U, 0x12362412U, 0x809b1b80U, 0xe23ddfe2U,
+    0xeb26cdebU, 0x27694e27U, 0xb2cd7fb2U, 0x759fea75U,
+    0x091b1209U, 0x839e1d83U, 0x2c74582cU, 0x1a2e341aU,
+    0x1b2d361bU, 0x6eb2dc6eU, 0x5aeeb45aU, 0xa0fb5ba0U,
+    0x52f6a452U, 0x3b4d763bU, 0xd661b7d6U, 0xb3ce7db3U,
+    0x297b5229U, 0xe33edde3U, 0x2f715e2fU, 0x84971384U,
+    0x53f5a653U, 0xd168b9d1U, 0x00000000U, 0xed2cc1edU,
+    0x20604020U, 0xfc1fe3fcU, 0xb1c879b1U, 0x5bedb65bU,
+    0x6abed46aU, 0xcb468dcbU, 0xbed967beU, 0x394b7239U,
+    0x4ade944aU, 0x4cd4984cU, 0x58e8b058U, 0xcf4a85cfU,
+    0xd06bbbd0U, 0xef2ac5efU, 0xaae54faaU, 0xfb16edfbU,
+    0x43c58643U, 0x4dd79a4dU, 0x33556633U, 0x85941185U,
+    0x45cf8a45U, 0xf910e9f9U, 0x02060402U, 0x7f81fe7fU,
+    0x50f0a050U, 0x3c44783cU, 0x9fba259fU, 0xa8e34ba8U,
+    0x51f3a251U, 0xa3fe5da3U, 0x40c08040U, 0x8f8a058fU,
+    0x92ad3f92U, 0x9dbc219dU, 0x38487038U, 0xf504f1f5U,
+    0xbcdf63bcU, 0xb6c177b6U, 0xda75afdaU, 0x21634221U,
+    0x10302010U, 0xff1ae5ffU, 0xf30efdf3U, 0xd26dbfd2U,
+    0xcd4c81cdU, 0x0c14180cU, 0x13352613U, 0xec2fc3ecU,
+    0x5fe1be5fU, 0x97a23597U, 0x44cc8844U, 0x17392e17U,
+    0xc45793c4U, 0xa7f255a7U, 0x7e82fc7eU, 0x3d477a3dU,
+    0x64acc864U, 0x5de7ba5dU, 0x192b3219U, 0x7395e673U,
+    0x60a0c060U, 0x81981981U, 0x4fd19e4fU, 0xdc7fa3dcU,
+    0x22664422U, 0x2a7e542aU, 0x90ab3b90U, 0x88830b88U,
+    0x46ca8c46U, 0xee29c7eeU, 0xb8d36bb8U, 0x143c2814U,
+    0xde79a7deU, 0x5ee2bc5eU, 0x0b1d160bU, 0xdb76addbU,
+    0xe03bdbe0U, 0x32566432U, 0x3a4e743aU, 0x0a1e140aU,
+    0x49db9249U, 0x060a0c06U, 0x246c4824U, 0x5ce4b85cU,
+    0xc25d9fc2U, 0xd36ebdd3U, 0xacef43acU, 0x62a6c462U,
+    0x91a83991U, 0x95a43195U, 0xe437d3e4U, 0x798bf279U,
+    0xe732d5e7U, 0xc8438bc8U, 0x37596e37U, 0x6db7da6dU,
+    0x8d8c018dU, 0xd564b1d5U, 0x4ed29c4eU, 0xa9e049a9U,
+    0x6cb4d86cU, 0x56faac56U, 0xf407f3f4U, 0xea25cfeaU,
+    0x65afca65U, 0x7a8ef47aU, 0xaee947aeU, 0x08181008U,
+    0xbad56fbaU, 0x7888f078U, 0x256f4a25U, 0x2e725c2eU,
+    0x1c24381cU, 0xa6f157a6U, 0xb4c773b4U, 0xc65197c6U,
+    0xe823cbe8U, 0xdd7ca1ddU, 0x749ce874U, 0x1f213e1fU,
+    0x4bdd964bU, 0xbddc61bdU, 0x8b860d8bU, 0x8a850f8aU,
+    0x7090e070U, 0x3e427c3eU, 0xb5c471b5U, 0x66aacc66U,
+    0x48d89048U, 0x03050603U, 0xf601f7f6U, 0x0e121c0eU,
+    0x61a3c261U, 0x355f6a35U, 0x57f9ae57U, 0xb9d069b9U,
+    0x86911786U, 0xc15899c1U, 0x1d273a1dU, 0x9eb9279eU,
+    0xe138d9e1U, 0xf813ebf8U, 0x98b32b98U, 0x11332211U,
+    0x69bbd269U, 0xd970a9d9U, 0x8e89078eU, 0x94a73394U,
+    0x9bb62d9bU, 0x1e223c1eU, 0x87921587U, 0xe920c9e9U,
+    0xce4987ceU, 0x55ffaa55U, 0x28785028U, 0xdf7aa5dfU,
+    0x8c8f038cU, 0xa1f859a1U, 0x89800989U, 0x0d171a0dU,
+    0xbfda65bfU, 0xe631d7e6U, 0x42c68442U, 0x68b8d068U,
+    0x41c38241U, 0x99b02999U, 0x2d775a2dU, 0x0f111e0fU,
+    0xb0cb7bb0U, 0x54fca854U, 0xbbd66dbbU, 0x163a2c16U,
+};
+const u32 Te3[256] = {
+
+    0x6363a5c6U, 0x7c7c84f8U, 0x777799eeU, 0x7b7b8df6U,
+    0xf2f20dffU, 0x6b6bbdd6U, 0x6f6fb1deU, 0xc5c55491U,
+    0x30305060U, 0x01010302U, 0x6767a9ceU, 0x2b2b7d56U,
+    0xfefe19e7U, 0xd7d762b5U, 0xababe64dU, 0x76769aecU,
+    0xcaca458fU, 0x82829d1fU, 0xc9c94089U, 0x7d7d87faU,
+    0xfafa15efU, 0x5959ebb2U, 0x4747c98eU, 0xf0f00bfbU,
+    0xadadec41U, 0xd4d467b3U, 0xa2a2fd5fU, 0xafafea45U,
+    0x9c9cbf23U, 0xa4a4f753U, 0x727296e4U, 0xc0c05b9bU,
+    0xb7b7c275U, 0xfdfd1ce1U, 0x9393ae3dU, 0x26266a4cU,
+    0x36365a6cU, 0x3f3f417eU, 0xf7f702f5U, 0xcccc4f83U,
+    0x34345c68U, 0xa5a5f451U, 0xe5e534d1U, 0xf1f108f9U,
+    0x717193e2U, 0xd8d873abU, 0x31315362U, 0x15153f2aU,
+    0x04040c08U, 0xc7c75295U, 0x23236546U, 0xc3c35e9dU,
+    0x18182830U, 0x9696a137U, 0x05050f0aU, 0x9a9ab52fU,
+    0x0707090eU, 0x12123624U, 0x80809b1bU, 0xe2e23ddfU,
+    0xebeb26cdU, 0x2727694eU, 0xb2b2cd7fU, 0x75759feaU,
+    0x09091b12U, 0x83839e1dU, 0x2c2c7458U, 0x1a1a2e34U,
+    0x1b1b2d36U, 0x6e6eb2dcU, 0x5a5aeeb4U, 0xa0a0fb5bU,
+    0x5252f6a4U, 0x3b3b4d76U, 0xd6d661b7U, 0xb3b3ce7dU,
+    0x29297b52U, 0xe3e33eddU, 0x2f2f715eU, 0x84849713U,
+    0x5353f5a6U, 0xd1d168b9U, 0x00000000U, 0xeded2cc1U,
+    0x20206040U, 0xfcfc1fe3U, 0xb1b1c879U, 0x5b5bedb6U,
+    0x6a6abed4U, 0xcbcb468dU, 0xbebed967U, 0x39394b72U,
+    0x4a4ade94U, 0x4c4cd498U, 0x5858e8b0U, 0xcfcf4a85U,
+    0xd0d06bbbU, 0xefef2ac5U, 0xaaaae54fU, 0xfbfb16edU,
+    0x4343c586U, 0x4d4dd79aU, 0x33335566U, 0x85859411U,
+    0x4545cf8aU, 0xf9f910e9U, 0x02020604U, 0x7f7f81feU,
+    0x5050f0a0U, 0x3c3c4478U, 0x9f9fba25U, 0xa8a8e34bU,
+    0x5151f3a2U, 0xa3a3fe5dU, 0x4040c080U, 0x8f8f8a05U,
+    0x9292ad3fU, 0x9d9dbc21U, 0x38384870U, 0xf5f504f1U,
+    0xbcbcdf63U, 0xb6b6c177U, 0xdada75afU, 0x21216342U,
+    0x10103020U, 0xffff1ae5U, 0xf3f30efdU, 0xd2d26dbfU,
+    0xcdcd4c81U, 0x0c0c1418U, 0x13133526U, 0xecec2fc3U,
+    0x5f5fe1beU, 0x9797a235U, 0x4444cc88U, 0x1717392eU,
+    0xc4c45793U, 0xa7a7f255U, 0x7e7e82fcU, 0x3d3d477aU,
+    0x6464acc8U, 0x5d5de7baU, 0x19192b32U, 0x737395e6U,
+    0x6060a0c0U, 0x81819819U, 0x4f4fd19eU, 0xdcdc7fa3U,
+    0x22226644U, 0x2a2a7e54U, 0x9090ab3bU, 0x8888830bU,
+    0x4646ca8cU, 0xeeee29c7U, 0xb8b8d36bU, 0x14143c28U,
+    0xdede79a7U, 0x5e5ee2bcU, 0x0b0b1d16U, 0xdbdb76adU,
+    0xe0e03bdbU, 0x32325664U, 0x3a3a4e74U, 0x0a0a1e14U,
+    0x4949db92U, 0x06060a0cU, 0x24246c48U, 0x5c5ce4b8U,
+    0xc2c25d9fU, 0xd3d36ebdU, 0xacacef43U, 0x6262a6c4U,
+    0x9191a839U, 0x9595a431U, 0xe4e437d3U, 0x79798bf2U,
+    0xe7e732d5U, 0xc8c8438bU, 0x3737596eU, 0x6d6db7daU,
+    0x8d8d8c01U, 0xd5d564b1U, 0x4e4ed29cU, 0xa9a9e049U,
+    0x6c6cb4d8U, 0x5656faacU, 0xf4f407f3U, 0xeaea25cfU,
+    0x6565afcaU, 0x7a7a8ef4U, 0xaeaee947U, 0x08081810U,
+    0xbabad56fU, 0x787888f0U, 0x25256f4aU, 0x2e2e725cU,
+    0x1c1c2438U, 0xa6a6f157U, 0xb4b4c773U, 0xc6c65197U,
+    0xe8e823cbU, 0xdddd7ca1U, 0x74749ce8U, 0x1f1f213eU,
+    0x4b4bdd96U, 0xbdbddc61U, 0x8b8b860dU, 0x8a8a850fU,
+    0x707090e0U, 0x3e3e427cU, 0xb5b5c471U, 0x6666aaccU,
+    0x4848d890U, 0x03030506U, 0xf6f601f7U, 0x0e0e121cU,
+    0x6161a3c2U, 0x35355f6aU, 0x5757f9aeU, 0xb9b9d069U,
+    0x86869117U, 0xc1c15899U, 0x1d1d273aU, 0x9e9eb927U,
+    0xe1e138d9U, 0xf8f813ebU, 0x9898b32bU, 0x11113322U,
+    0x6969bbd2U, 0xd9d970a9U, 0x8e8e8907U, 0x9494a733U,
+    0x9b9bb62dU, 0x1e1e223cU, 0x87879215U, 0xe9e920c9U,
+    0xcece4987U, 0x5555ffaaU, 0x28287850U, 0xdfdf7aa5U,
+    0x8c8c8f03U, 0xa1a1f859U, 0x89898009U, 0x0d0d171aU,
+    0xbfbfda65U, 0xe6e631d7U, 0x4242c684U, 0x6868b8d0U,
+    0x4141c382U, 0x9999b029U, 0x2d2d775aU, 0x0f0f111eU,
+    0xb0b0cb7bU, 0x5454fca8U, 0xbbbbd66dU, 0x16163a2cU,
+};
+const u32 Te4[256] = {
+    0x63636363U, 0x7c7c7c7cU, 0x77777777U, 0x7b7b7b7bU,
+    0xf2f2f2f2U, 0x6b6b6b6bU, 0x6f6f6f6fU, 0xc5c5c5c5U,
+    0x30303030U, 0x01010101U, 0x67676767U, 0x2b2b2b2bU,
+    0xfefefefeU, 0xd7d7d7d7U, 0xababababU, 0x76767676U,
+    0xcacacacaU, 0x82828282U, 0xc9c9c9c9U, 0x7d7d7d7dU,
+    0xfafafafaU, 0x59595959U, 0x47474747U, 0xf0f0f0f0U,
+    0xadadadadU, 0xd4d4d4d4U, 0xa2a2a2a2U, 0xafafafafU,
+    0x9c9c9c9cU, 0xa4a4a4a4U, 0x72727272U, 0xc0c0c0c0U,
+    0xb7b7b7b7U, 0xfdfdfdfdU, 0x93939393U, 0x26262626U,
+    0x36363636U, 0x3f3f3f3fU, 0xf7f7f7f7U, 0xccccccccU,
+    0x34343434U, 0xa5a5a5a5U, 0xe5e5e5e5U, 0xf1f1f1f1U,
+    0x71717171U, 0xd8d8d8d8U, 0x31313131U, 0x15151515U,
+    0x04040404U, 0xc7c7c7c7U, 0x23232323U, 0xc3c3c3c3U,
+    0x18181818U, 0x96969696U, 0x05050505U, 0x9a9a9a9aU,
+    0x07070707U, 0x12121212U, 0x80808080U, 0xe2e2e2e2U,
+    0xebebebebU, 0x27272727U, 0xb2b2b2b2U, 0x75757575U,
+    0x09090909U, 0x83838383U, 0x2c2c2c2cU, 0x1a1a1a1aU,
+    0x1b1b1b1bU, 0x6e6e6e6eU, 0x5a5a5a5aU, 0xa0a0a0a0U,
+    0x52525252U, 0x3b3b3b3bU, 0xd6d6d6d6U, 0xb3b3b3b3U,
+    0x29292929U, 0xe3e3e3e3U, 0x2f2f2f2fU, 0x84848484U,
+    0x53535353U, 0xd1d1d1d1U, 0x00000000U, 0xededededU,
+    0x20202020U, 0xfcfcfcfcU, 0xb1b1b1b1U, 0x5b5b5b5bU,
+    0x6a6a6a6aU, 0xcbcbcbcbU, 0xbebebebeU, 0x39393939U,
+    0x4a4a4a4aU, 0x4c4c4c4cU, 0x58585858U, 0xcfcfcfcfU,
+    0xd0d0d0d0U, 0xefefefefU, 0xaaaaaaaaU, 0xfbfbfbfbU,
+    0x43434343U, 0x4d4d4d4dU, 0x33333333U, 0x85858585U,
+    0x45454545U, 0xf9f9f9f9U, 0x02020202U, 0x7f7f7f7fU,
+    0x50505050U, 0x3c3c3c3cU, 0x9f9f9f9fU, 0xa8a8a8a8U,
+    0x51515151U, 0xa3a3a3a3U, 0x40404040U, 0x8f8f8f8fU,
+    0x92929292U, 0x9d9d9d9dU, 0x38383838U, 0xf5f5f5f5U,
+    0xbcbcbcbcU, 0xb6b6b6b6U, 0xdadadadaU, 0x21212121U,
+    0x10101010U, 0xffffffffU, 0xf3f3f3f3U, 0xd2d2d2d2U,
+    0xcdcdcdcdU, 0x0c0c0c0cU, 0x13131313U, 0xececececU,
+    0x5f5f5f5fU, 0x97979797U, 0x44444444U, 0x17171717U,
+    0xc4c4c4c4U, 0xa7a7a7a7U, 0x7e7e7e7eU, 0x3d3d3d3dU,
+    0x64646464U, 0x5d5d5d5dU, 0x19191919U, 0x73737373U,
+    0x60606060U, 0x81818181U, 0x4f4f4f4fU, 0xdcdcdcdcU,
+    0x22222222U, 0x2a2a2a2aU, 0x90909090U, 0x88888888U,
+    0x46464646U, 0xeeeeeeeeU, 0xb8b8b8b8U, 0x14141414U,
+    0xdedededeU, 0x5e5e5e5eU, 0x0b0b0b0bU, 0xdbdbdbdbU,
+    0xe0e0e0e0U, 0x32323232U, 0x3a3a3a3aU, 0x0a0a0a0aU,
+    0x49494949U, 0x06060606U, 0x24242424U, 0x5c5c5c5cU,
+    0xc2c2c2c2U, 0xd3d3d3d3U, 0xacacacacU, 0x62626262U,
+    0x91919191U, 0x95959595U, 0xe4e4e4e4U, 0x79797979U,
+    0xe7e7e7e7U, 0xc8c8c8c8U, 0x37373737U, 0x6d6d6d6dU,
+    0x8d8d8d8dU, 0xd5d5d5d5U, 0x4e4e4e4eU, 0xa9a9a9a9U,
+    0x6c6c6c6cU, 0x56565656U, 0xf4f4f4f4U, 0xeaeaeaeaU,
+    0x65656565U, 0x7a7a7a7aU, 0xaeaeaeaeU, 0x08080808U,
+    0xbabababaU, 0x78787878U, 0x25252525U, 0x2e2e2e2eU,
+    0x1c1c1c1cU, 0xa6a6a6a6U, 0xb4b4b4b4U, 0xc6c6c6c6U,
+    0xe8e8e8e8U, 0xddddddddU, 0x74747474U, 0x1f1f1f1fU,
+    0x4b4b4b4bU, 0xbdbdbdbdU, 0x8b8b8b8bU, 0x8a8a8a8aU,
+    0x70707070U, 0x3e3e3e3eU, 0xb5b5b5b5U, 0x66666666U,
+    0x48484848U, 0x03030303U, 0xf6f6f6f6U, 0x0e0e0e0eU,
+    0x61616161U, 0x35353535U, 0x57575757U, 0xb9b9b9b9U,
+    0x86868686U, 0xc1c1c1c1U, 0x1d1d1d1dU, 0x9e9e9e9eU,
+    0xe1e1e1e1U, 0xf8f8f8f8U, 0x98989898U, 0x11111111U,
+    0x69696969U, 0xd9d9d9d9U, 0x8e8e8e8eU, 0x94949494U,
+    0x9b9b9b9bU, 0x1e1e1e1eU, 0x87878787U, 0xe9e9e9e9U,
+    0xcecececeU, 0x55555555U, 0x28282828U, 0xdfdfdfdfU,
+    0x8c8c8c8cU, 0xa1a1a1a1U, 0x89898989U, 0x0d0d0d0dU,
+    0xbfbfbfbfU, 0xe6e6e6e6U, 0x42424242U, 0x68686868U,
+    0x41414141U, 0x99999999U, 0x2d2d2d2dU, 0x0f0f0f0fU,
+    0xb0b0b0b0U, 0x54545454U, 0xbbbbbbbbU, 0x16161616U,
+};
+#endif /* AES_SMALL_TABLES */
+const u32 Td0[256] = {
+    0x51f4a750U, 0x7e416553U, 0x1a17a4c3U, 0x3a275e96U,
+    0x3bab6bcbU, 0x1f9d45f1U, 0xacfa58abU, 0x4be30393U,
+    0x2030fa55U, 0xad766df6U, 0x88cc7691U, 0xf5024c25U,
+    0x4fe5d7fcU, 0xc52acbd7U, 0x26354480U, 0xb562a38fU,
+    0xdeb15a49U, 0x25ba1b67U, 0x45ea0e98U, 0x5dfec0e1U,
+    0xc32f7502U, 0x814cf012U, 0x8d4697a3U, 0x6bd3f9c6U,
+    0x038f5fe7U, 0x15929c95U, 0xbf6d7aebU, 0x955259daU,
+    0xd4be832dU, 0x587421d3U, 0x49e06929U, 0x8ec9c844U,
+    0x75c2896aU, 0xf48e7978U, 0x99583e6bU, 0x27b971ddU,
+    0xbee14fb6U, 0xf088ad17U, 0xc920ac66U, 0x7dce3ab4U,
+    0x63df4a18U, 0xe51a3182U, 0x97513360U, 0x62537f45U,
+    0xb16477e0U, 0xbb6bae84U, 0xfe81a01cU, 0xf9082b94U,
+    0x70486858U, 0x8f45fd19U, 0x94de6c87U, 0x527bf8b7U,
+    0xab73d323U, 0x724b02e2U, 0xe31f8f57U, 0x6655ab2aU,
+    0xb2eb2807U, 0x2fb5c203U, 0x86c57b9aU, 0xd33708a5U,
+    0x302887f2U, 0x23bfa5b2U, 0x02036abaU, 0xed16825cU,
+    0x8acf1c2bU, 0xa779b492U, 0xf307f2f0U, 0x4e69e2a1U,
+    0x65daf4cdU, 0x0605bed5U, 0xd134621fU, 0xc4a6fe8aU,
+    0x342e539dU, 0xa2f355a0U, 0x058ae132U, 0xa4f6eb75U,
+    0x0b83ec39U, 0x4060efaaU, 0x5e719f06U, 0xbd6e1051U,
+    0x3e218af9U, 0x96dd063dU, 0xdd3e05aeU, 0x4de6bd46U,
+    0x91548db5U, 0x71c45d05U, 0x0406d46fU, 0x605015ffU,
+    0x1998fb24U, 0xd6bde997U, 0x894043ccU, 0x67d99e77U,
+    0xb0e842bdU, 0x07898b88U, 0xe7195b38U, 0x79c8eedbU,
+    0xa17c0a47U, 0x7c420fe9U, 0xf8841ec9U, 0x00000000U,
+    0x09808683U, 0x322bed48U, 0x1e1170acU, 0x6c5a724eU,
+    0xfd0efffbU, 0x0f853856U, 0x3daed51eU, 0x362d3927U,
+    0x0a0fd964U, 0x685ca621U, 0x9b5b54d1U, 0x24362e3aU,
+    0x0c0a67b1U, 0x9357e70fU, 0xb4ee96d2U, 0x1b9b919eU,
+    0x80c0c54fU, 0x61dc20a2U, 0x5a774b69U, 0x1c121a16U,
+    0xe293ba0aU, 0xc0a02ae5U, 0x3c22e043U, 0x121b171dU,
+    0x0e090d0bU, 0xf28bc7adU, 0x2db6a8b9U, 0x141ea9c8U,
+    0x57f11985U, 0xaf75074cU, 0xee99ddbbU, 0xa37f60fdU,
+    0xf701269fU, 0x5c72f5bcU, 0x44663bc5U, 0x5bfb7e34U,
+    0x8b432976U, 0xcb23c6dcU, 0xb6edfc68U, 0xb8e4f163U,
+    0xd731dccaU, 0x42638510U, 0x13972240U, 0x84c61120U,
+    0x854a247dU, 0xd2bb3df8U, 0xaef93211U, 0xc729a16dU,
+    0x1d9e2f4bU, 0xdcb230f3U, 0x0d8652ecU, 0x77c1e3d0U,
+    0x2bb3166cU, 0xa970b999U, 0x119448faU, 0x47e96422U,
+    0xa8fc8cc4U, 0xa0f03f1aU, 0x567d2cd8U, 0x223390efU,
+    0x87494ec7U, 0xd938d1c1U, 0x8ccaa2feU, 0x98d40b36U,
+    0xa6f581cfU, 0xa57ade28U, 0xdab78e26U, 0x3fadbfa4U,
+    0x2c3a9de4U, 0x5078920dU, 0x6a5fcc9bU, 0x547e4662U,
+    0xf68d13c2U, 0x90d8b8e8U, 0x2e39f75eU, 0x82c3aff5U,
+    0x9f5d80beU, 0x69d0937cU, 0x6fd52da9U, 0xcf2512b3U,
+    0xc8ac993bU, 0x10187da7U, 0xe89c636eU, 0xdb3bbb7bU,
+    0xcd267809U, 0x6e5918f4U, 0xec9ab701U, 0x834f9aa8U,
+    0xe6956e65U, 0xaaffe67eU, 0x21bccf08U, 0xef15e8e6U,
+    0xbae79bd9U, 0x4a6f36ceU, 0xea9f09d4U, 0x29b07cd6U,
+    0x31a4b2afU, 0x2a3f2331U, 0xc6a59430U, 0x35a266c0U,
+    0x744ebc37U, 0xfc82caa6U, 0xe090d0b0U, 0x33a7d815U,
+    0xf104984aU, 0x41ecdaf7U, 0x7fcd500eU, 0x1791f62fU,
+    0x764dd68dU, 0x43efb04dU, 0xccaa4d54U, 0xe49604dfU,
+    0x9ed1b5e3U, 0x4c6a881bU, 0xc12c1fb8U, 0x4665517fU,
+    0x9d5eea04U, 0x018c355dU, 0xfa877473U, 0xfb0b412eU,
+    0xb3671d5aU, 0x92dbd252U, 0xe9105633U, 0x6dd64713U,
+    0x9ad7618cU, 0x37a10c7aU, 0x59f8148eU, 0xeb133c89U,
+    0xcea927eeU, 0xb761c935U, 0xe11ce5edU, 0x7a47b13cU,
+    0x9cd2df59U, 0x55f2733fU, 0x1814ce79U, 0x73c737bfU,
+    0x53f7cdeaU, 0x5ffdaa5bU, 0xdf3d6f14U, 0x7844db86U,
+    0xcaaff381U, 0xb968c43eU, 0x3824342cU, 0xc2a3405fU,
+    0x161dc372U, 0xbce2250cU, 0x283c498bU, 0xff0d9541U,
+    0x39a80171U, 0x080cb3deU, 0xd8b4e49cU, 0x6456c190U,
+    0x7bcb8461U, 0xd532b670U, 0x486c5c74U, 0xd0b85742U,
+};
+#ifndef AES_SMALL_TABLES
+const u32 Td1[256] = {
+    0x5051f4a7U, 0x537e4165U, 0xc31a17a4U, 0x963a275eU,
+    0xcb3bab6bU, 0xf11f9d45U, 0xabacfa58U, 0x934be303U,
+    0x552030faU, 0xf6ad766dU, 0x9188cc76U, 0x25f5024cU,
+    0xfc4fe5d7U, 0xd7c52acbU, 0x80263544U, 0x8fb562a3U,
+    0x49deb15aU, 0x6725ba1bU, 0x9845ea0eU, 0xe15dfec0U,
+    0x02c32f75U, 0x12814cf0U, 0xa38d4697U, 0xc66bd3f9U,
+    0xe7038f5fU, 0x9515929cU, 0xebbf6d7aU, 0xda955259U,
+    0x2dd4be83U, 0xd3587421U, 0x2949e069U, 0x448ec9c8U,
+    0x6a75c289U, 0x78f48e79U, 0x6b99583eU, 0xdd27b971U,
+    0xb6bee14fU, 0x17f088adU, 0x66c920acU, 0xb47dce3aU,
+    0x1863df4aU, 0x82e51a31U, 0x60975133U, 0x4562537fU,
+    0xe0b16477U, 0x84bb6baeU, 0x1cfe81a0U, 0x94f9082bU,
+    0x58704868U, 0x198f45fdU, 0x8794de6cU, 0xb7527bf8U,
+    0x23ab73d3U, 0xe2724b02U, 0x57e31f8fU, 0x2a6655abU,
+    0x07b2eb28U, 0x032fb5c2U, 0x9a86c57bU, 0xa5d33708U,
+    0xf2302887U, 0xb223bfa5U, 0xba02036aU, 0x5ced1682U,
+    0x2b8acf1cU, 0x92a779b4U, 0xf0f307f2U, 0xa14e69e2U,
+    0xcd65daf4U, 0xd50605beU, 0x1fd13462U, 0x8ac4a6feU,
+    0x9d342e53U, 0xa0a2f355U, 0x32058ae1U, 0x75a4f6ebU,
+    0x390b83ecU, 0xaa4060efU, 0x065e719fU, 0x51bd6e10U,
+    0xf93e218aU, 0x3d96dd06U, 0xaedd3e05U, 0x464de6bdU,
+    0xb591548dU, 0x0571c45dU, 0x6f0406d4U, 0xff605015U,
+    0x241998fbU, 0x97d6bde9U, 0xcc894043U, 0x7767d99eU,
+    0xbdb0e842U, 0x8807898bU, 0x38e7195bU, 0xdb79c8eeU,
+    0x47a17c0aU, 0xe97c420fU, 0xc9f8841eU, 0x00000000U,
+    0x83098086U, 0x48322bedU, 0xac1e1170U, 0x4e6c5a72U,
+    0xfbfd0effU, 0x560f8538U, 0x1e3daed5U, 0x27362d39U,
+    0x640a0fd9U, 0x21685ca6U, 0xd19b5b54U, 0x3a24362eU,
+    0xb10c0a67U, 0x0f9357e7U, 0xd2b4ee96U, 0x9e1b9b91U,
+    0x4f80c0c5U, 0xa261dc20U, 0x695a774bU, 0x161c121aU,
+    0x0ae293baU, 0xe5c0a02aU, 0x433c22e0U, 0x1d121b17U,
+    0x0b0e090dU, 0xadf28bc7U, 0xb92db6a8U, 0xc8141ea9U,
+    0x8557f119U, 0x4caf7507U, 0xbbee99ddU, 0xfda37f60U,
+    0x9ff70126U, 0xbc5c72f5U, 0xc544663bU, 0x345bfb7eU,
+    0x768b4329U, 0xdccb23c6U, 0x68b6edfcU, 0x63b8e4f1U,
+    0xcad731dcU, 0x10426385U, 0x40139722U, 0x2084c611U,
+    0x7d854a24U, 0xf8d2bb3dU, 0x11aef932U, 0x6dc729a1U,
+    0x4b1d9e2fU, 0xf3dcb230U, 0xec0d8652U, 0xd077c1e3U,
+    0x6c2bb316U, 0x99a970b9U, 0xfa119448U, 0x2247e964U,
+    0xc4a8fc8cU, 0x1aa0f03fU, 0xd8567d2cU, 0xef223390U,
+    0xc787494eU, 0xc1d938d1U, 0xfe8ccaa2U, 0x3698d40bU,
+    0xcfa6f581U, 0x28a57adeU, 0x26dab78eU, 0xa43fadbfU,
+    0xe42c3a9dU, 0x0d507892U, 0x9b6a5fccU, 0x62547e46U,
+    0xc2f68d13U, 0xe890d8b8U, 0x5e2e39f7U, 0xf582c3afU,
+    0xbe9f5d80U, 0x7c69d093U, 0xa96fd52dU, 0xb3cf2512U,
+    0x3bc8ac99U, 0xa710187dU, 0x6ee89c63U, 0x7bdb3bbbU,
+    0x09cd2678U, 0xf46e5918U, 0x01ec9ab7U, 0xa8834f9aU,
+    0x65e6956eU, 0x7eaaffe6U, 0x0821bccfU, 0xe6ef15e8U,
+    0xd9bae79bU, 0xce4a6f36U, 0xd4ea9f09U, 0xd629b07cU,
+    0xaf31a4b2U, 0x312a3f23U, 0x30c6a594U, 0xc035a266U,
+    0x37744ebcU, 0xa6fc82caU, 0xb0e090d0U, 0x1533a7d8U,
+    0x4af10498U, 0xf741ecdaU, 0x0e7fcd50U, 0x2f1791f6U,
+    0x8d764dd6U, 0x4d43efb0U, 0x54ccaa4dU, 0xdfe49604U,
+    0xe39ed1b5U, 0x1b4c6a88U, 0xb8c12c1fU, 0x7f466551U,
+    0x049d5eeaU, 0x5d018c35U, 0x73fa8774U, 0x2efb0b41U,
+    0x5ab3671dU, 0x5292dbd2U, 0x33e91056U, 0x136dd647U,
+    0x8c9ad761U, 0x7a37a10cU, 0x8e59f814U, 0x89eb133cU,
+    0xeecea927U, 0x35b761c9U, 0xede11ce5U, 0x3c7a47b1U,
+    0x599cd2dfU, 0x3f55f273U, 0x791814ceU, 0xbf73c737U,
+    0xea53f7cdU, 0x5b5ffdaaU, 0x14df3d6fU, 0x867844dbU,
+    0x81caaff3U, 0x3eb968c4U, 0x2c382434U, 0x5fc2a340U,
+    0x72161dc3U, 0x0cbce225U, 0x8b283c49U, 0x41ff0d95U,
+    0x7139a801U, 0xde080cb3U, 0x9cd8b4e4U, 0x906456c1U,
+    0x617bcb84U, 0x70d532b6U, 0x74486c5cU, 0x42d0b857U,
+};
+const u32 Td2[256] = {
+    0xa75051f4U, 0x65537e41U, 0xa4c31a17U, 0x5e963a27U,
+    0x6bcb3babU, 0x45f11f9dU, 0x58abacfaU, 0x03934be3U,
+    0xfa552030U, 0x6df6ad76U, 0x769188ccU, 0x4c25f502U,
+    0xd7fc4fe5U, 0xcbd7c52aU, 0x44802635U, 0xa38fb562U,
+    0x5a49deb1U, 0x1b6725baU, 0x0e9845eaU, 0xc0e15dfeU,
+    0x7502c32fU, 0xf012814cU, 0x97a38d46U, 0xf9c66bd3U,
+    0x5fe7038fU, 0x9c951592U, 0x7aebbf6dU, 0x59da9552U,
+    0x832dd4beU, 0x21d35874U, 0x692949e0U, 0xc8448ec9U,
+    0x896a75c2U, 0x7978f48eU, 0x3e6b9958U, 0x71dd27b9U,
+    0x4fb6bee1U, 0xad17f088U, 0xac66c920U, 0x3ab47dceU,
+    0x4a1863dfU, 0x3182e51aU, 0x33609751U, 0x7f456253U,
+    0x77e0b164U, 0xae84bb6bU, 0xa01cfe81U, 0x2b94f908U,
+    0x68587048U, 0xfd198f45U, 0x6c8794deU, 0xf8b7527bU,
+    0xd323ab73U, 0x02e2724bU, 0x8f57e31fU, 0xab2a6655U,
+    0x2807b2ebU, 0xc2032fb5U, 0x7b9a86c5U, 0x08a5d337U,
+    0x87f23028U, 0xa5b223bfU, 0x6aba0203U, 0x825ced16U,
+    0x1c2b8acfU, 0xb492a779U, 0xf2f0f307U, 0xe2a14e69U,
+    0xf4cd65daU, 0xbed50605U, 0x621fd134U, 0xfe8ac4a6U,
+    0x539d342eU, 0x55a0a2f3U, 0xe132058aU, 0xeb75a4f6U,
+    0xec390b83U, 0xefaa4060U, 0x9f065e71U, 0x1051bd6eU,
+
+    0x8af93e21U, 0x063d96ddU, 0x05aedd3eU, 0xbd464de6U,
+    0x8db59154U, 0x5d0571c4U, 0xd46f0406U, 0x15ff6050U,
+    0xfb241998U, 0xe997d6bdU, 0x43cc8940U, 0x9e7767d9U,
+    0x42bdb0e8U, 0x8b880789U, 0x5b38e719U, 0xeedb79c8U,
+    0x0a47a17cU, 0x0fe97c42U, 0x1ec9f884U, 0x00000000U,
+    0x86830980U, 0xed48322bU, 0x70ac1e11U, 0x724e6c5aU,
+    0xfffbfd0eU, 0x38560f85U, 0xd51e3daeU, 0x3927362dU,
+    0xd9640a0fU, 0xa621685cU, 0x54d19b5bU, 0x2e3a2436U,
+    0x67b10c0aU, 0xe70f9357U, 0x96d2b4eeU, 0x919e1b9bU,
+    0xc54f80c0U, 0x20a261dcU, 0x4b695a77U, 0x1a161c12U,
+    0xba0ae293U, 0x2ae5c0a0U, 0xe0433c22U, 0x171d121bU,
+    0x0d0b0e09U, 0xc7adf28bU, 0xa8b92db6U, 0xa9c8141eU,
+    0x198557f1U, 0x074caf75U, 0xddbbee99U, 0x60fda37fU,
+    0x269ff701U, 0xf5bc5c72U, 0x3bc54466U, 0x7e345bfbU,
+    0x29768b43U, 0xc6dccb23U, 0xfc68b6edU, 0xf163b8e4U,
+    0xdccad731U, 0x85104263U, 0x22401397U, 0x112084c6U,
+    0x247d854aU, 0x3df8d2bbU, 0x3211aef9U, 0xa16dc729U,
+    0x2f4b1d9eU, 0x30f3dcb2U, 0x52ec0d86U, 0xe3d077c1U,
+    0x166c2bb3U, 0xb999a970U, 0x48fa1194U, 0x642247e9U,
+    0x8cc4a8fcU, 0x3f1aa0f0U, 0x2cd8567dU, 0x90ef2233U,
+    0x4ec78749U, 0xd1c1d938U, 0xa2fe8ccaU, 0x0b3698d4U,
+    0x81cfa6f5U, 0xde28a57aU, 0x8e26dab7U, 0xbfa43fadU,
+    0x9de42c3aU, 0x920d5078U, 0xcc9b6a5fU, 0x4662547eU,
+    0x13c2f68dU, 0xb8e890d8U, 0xf75e2e39U, 0xaff582c3U,
+    0x80be9f5dU, 0x937c69d0U, 0x2da96fd5U, 0x12b3cf25U,
+    0x993bc8acU, 0x7da71018U, 0x636ee89cU, 0xbb7bdb3bU,
+    0x7809cd26U, 0x18f46e59U, 0xb701ec9aU, 0x9aa8834fU,
+    0x6e65e695U, 0xe67eaaffU, 0xcf0821bcU, 0xe8e6ef15U,
+    0x9bd9bae7U, 0x36ce4a6fU, 0x09d4ea9fU, 0x7cd629b0U,
+    0xb2af31a4U, 0x23312a3fU, 0x9430c6a5U, 0x66c035a2U,
+    0xbc37744eU, 0xcaa6fc82U, 0xd0b0e090U, 0xd81533a7U,
+    0x984af104U, 0xdaf741ecU, 0x500e7fcdU, 0xf62f1791U,
+    0xd68d764dU, 0xb04d43efU, 0x4d54ccaaU, 0x04dfe496U,
+    0xb5e39ed1U, 0x881b4c6aU, 0x1fb8c12cU, 0x517f4665U,
+    0xea049d5eU, 0x355d018cU, 0x7473fa87U, 0x412efb0bU,
+    0x1d5ab367U, 0xd25292dbU, 0x5633e910U, 0x47136dd6U,
+    0x618c9ad7U, 0x0c7a37a1U, 0x148e59f8U, 0x3c89eb13U,
+    0x27eecea9U, 0xc935b761U, 0xe5ede11cU, 0xb13c7a47U,
+    0xdf599cd2U, 0x733f55f2U, 0xce791814U, 0x37bf73c7U,
+    0xcdea53f7U, 0xaa5b5ffdU, 0x6f14df3dU, 0xdb867844U,
+    0xf381caafU, 0xc43eb968U, 0x342c3824U, 0x405fc2a3U,
+    0xc372161dU, 0x250cbce2U, 0x498b283cU, 0x9541ff0dU,
+    0x017139a8U, 0xb3de080cU, 0xe49cd8b4U, 0xc1906456U,
+    0x84617bcbU, 0xb670d532U, 0x5c74486cU, 0x5742d0b8U,
+};
+const u32 Td3[256] = {
+    0xf4a75051U, 0x4165537eU, 0x17a4c31aU, 0x275e963aU,
+    0xab6bcb3bU, 0x9d45f11fU, 0xfa58abacU, 0xe303934bU,
+    0x30fa5520U, 0x766df6adU, 0xcc769188U, 0x024c25f5U,
+    0xe5d7fc4fU, 0x2acbd7c5U, 0x35448026U, 0x62a38fb5U,
+    0xb15a49deU, 0xba1b6725U, 0xea0e9845U, 0xfec0e15dU,
+    0x2f7502c3U, 0x4cf01281U, 0x4697a38dU, 0xd3f9c66bU,
+    0x8f5fe703U, 0x929c9515U, 0x6d7aebbfU, 0x5259da95U,
+    0xbe832dd4U, 0x7421d358U, 0xe0692949U, 0xc9c8448eU,
+    0xc2896a75U, 0x8e7978f4U, 0x583e6b99U, 0xb971dd27U,
+    0xe14fb6beU, 0x88ad17f0U, 0x20ac66c9U, 0xce3ab47dU,
+    0xdf4a1863U, 0x1a3182e5U, 0x51336097U, 0x537f4562U,
+    0x6477e0b1U, 0x6bae84bbU, 0x81a01cfeU, 0x082b94f9U,
+    0x48685870U, 0x45fd198fU, 0xde6c8794U, 0x7bf8b752U,
+    0x73d323abU, 0x4b02e272U, 0x1f8f57e3U, 0x55ab2a66U,
+    0xeb2807b2U, 0xb5c2032fU, 0xc57b9a86U, 0x3708a5d3U,
+    0x2887f230U, 0xbfa5b223U, 0x036aba02U, 0x16825cedU,
+    0xcf1c2b8aU, 0x79b492a7U, 0x07f2f0f3U, 0x69e2a14eU,
+    0xdaf4cd65U, 0x05bed506U, 0x34621fd1U, 0xa6fe8ac4U,
+    0x2e539d34U, 0xf355a0a2U, 0x8ae13205U, 0xf6eb75a4U,
+    0x83ec390bU, 0x60efaa40U, 0x719f065eU, 0x6e1051bdU,
+    0x218af93eU, 0xdd063d96U, 0x3e05aeddU, 0xe6bd464dU,
+    0x548db591U, 0xc45d0571U, 0x06d46f04U, 0x5015ff60U,
+    0x98fb2419U, 0xbde997d6U, 0x4043cc89U, 0xd99e7767U,
+    0xe842bdb0U, 0x898b8807U, 0x195b38e7U, 0xc8eedb79U,
+    0x7c0a47a1U, 0x420fe97cU, 0x841ec9f8U, 0x00000000U,
+    0x80868309U, 0x2bed4832U, 0x1170ac1eU, 0x5a724e6cU,
+    0x0efffbfdU, 0x8538560fU, 0xaed51e3dU, 0x2d392736U,
+    0x0fd9640aU, 0x5ca62168U, 0x5b54d19bU, 0x362e3a24U,
+    0x0a67b10cU, 0x57e70f93U, 0xee96d2b4U, 0x9b919e1bU,
+    0xc0c54f80U, 0xdc20a261U, 0x774b695aU, 0x121a161cU,
+    0x93ba0ae2U, 0xa02ae5c0U, 0x22e0433cU, 0x1b171d12U,
+    0x090d0b0eU, 0x8bc7adf2U, 0xb6a8b92dU, 0x1ea9c814U,
+    0xf1198557U, 0x75074cafU, 0x99ddbbeeU, 0x7f60fda3U,
+    0x01269ff7U, 0x72f5bc5cU, 0x663bc544U, 0xfb7e345bU,
+    0x4329768bU, 0x23c6dccbU, 0xedfc68b6U, 0xe4f163b8U,
+    0x31dccad7U, 0x63851042U, 0x97224013U, 0xc6112084U,
+    0x4a247d85U, 0xbb3df8d2U, 0xf93211aeU, 0x29a16dc7U,
+    0x9e2f4b1dU, 0xb230f3dcU, 0x8652ec0dU, 0xc1e3d077U,
+    0xb3166c2bU, 0x70b999a9U, 0x9448fa11U, 0xe9642247U,
+    0xfc8cc4a8U, 0xf03f1aa0U, 0x7d2cd856U, 0x3390ef22U,
+    0x494ec787U, 0x38d1c1d9U, 0xcaa2fe8cU, 0xd40b3698U,
+    0xf581cfa6U, 0x7ade28a5U, 0xb78e26daU, 0xadbfa43fU,
+    0x3a9de42cU, 0x78920d50U, 0x5fcc9b6aU, 0x7e466254U,
+    0x8d13c2f6U, 0xd8b8e890U, 0x39f75e2eU, 0xc3aff582U,
+    0x5d80be9fU, 0xd0937c69U, 0xd52da96fU, 0x2512b3cfU,
+    0xac993bc8U, 0x187da710U, 0x9c636ee8U, 0x3bbb7bdbU,
+    0x267809cdU, 0x5918f46eU, 0x9ab701ecU, 0x4f9aa883U,
+    0x956e65e6U, 0xffe67eaaU, 0xbccf0821U, 0x15e8e6efU,
+    0xe79bd9baU, 0x6f36ce4aU, 0x9f09d4eaU, 0xb07cd629U,
+    0xa4b2af31U, 0x3f23312aU, 0xa59430c6U, 0xa266c035U,
+    0x4ebc3774U, 0x82caa6fcU, 0x90d0b0e0U, 0xa7d81533U,
+    0x04984af1U, 0xecdaf741U, 0xcd500e7fU, 0x91f62f17U,
+    0x4dd68d76U, 0xefb04d43U, 0xaa4d54ccU, 0x9604dfe4U,
+    0xd1b5e39eU, 0x6a881b4cU, 0x2c1fb8c1U, 0x65517f46U,
+    0x5eea049dU, 0x8c355d01U, 0x877473faU, 0x0b412efbU,
+    0x671d5ab3U, 0xdbd25292U, 0x105633e9U, 0xd647136dU,
+    0xd7618c9aU, 0xa10c7a37U, 0xf8148e59U, 0x133c89ebU,
+    0xa927eeceU, 0x61c935b7U, 0x1ce5ede1U, 0x47b13c7aU,
+    0xd2df599cU, 0xf2733f55U, 0x14ce7918U, 0xc737bf73U,
+    0xf7cdea53U, 0xfdaa5b5fU, 0x3d6f14dfU, 0x44db8678U,
+    0xaff381caU, 0x68c43eb9U, 0x24342c38U, 0xa3405fc2U,
+    0x1dc37216U, 0xe2250cbcU, 0x3c498b28U, 0x0d9541ffU,
+    0xa8017139U, 0x0cb3de08U, 0xb4e49cd8U, 0x56c19064U,
+    0xcb84617bU, 0x32b670d5U, 0x6c5c7448U, 0xb85742d0U,
+};
+const u32 Td4[256] = {
+    0x52525252U, 0x09090909U, 0x6a6a6a6aU, 0xd5d5d5d5U,
+    0x30303030U, 0x36363636U, 0xa5a5a5a5U, 0x38383838U,
+    0xbfbfbfbfU, 0x40404040U, 0xa3a3a3a3U, 0x9e9e9e9eU,
+    0x81818181U, 0xf3f3f3f3U, 0xd7d7d7d7U, 0xfbfbfbfbU,
+    0x7c7c7c7cU, 0xe3e3e3e3U, 0x39393939U, 0x82828282U,
+    0x9b9b9b9bU, 0x2f2f2f2fU, 0xffffffffU, 0x87878787U,
+    0x34343434U, 0x8e8e8e8eU, 0x43434343U, 0x44444444U,
+    0xc4c4c4c4U, 0xdedededeU, 0xe9e9e9e9U, 0xcbcbcbcbU,
+    0x54545454U, 0x7b7b7b7bU, 0x94949494U, 0x32323232U,
+    0xa6a6a6a6U, 0xc2c2c2c2U, 0x23232323U, 0x3d3d3d3dU,
+    0xeeeeeeeeU, 0x4c4c4c4cU, 0x95959595U, 0x0b0b0b0bU,
+    0x42424242U, 0xfafafafaU, 0xc3c3c3c3U, 0x4e4e4e4eU,
+    0x08080808U, 0x2e2e2e2eU, 0xa1a1a1a1U, 0x66666666U,
+    0x28282828U, 0xd9d9d9d9U, 0x24242424U, 0xb2b2b2b2U,
+    0x76767676U, 0x5b5b5b5bU, 0xa2a2a2a2U, 0x49494949U,
+    0x6d6d6d6dU, 0x8b8b8b8bU, 0xd1d1d1d1U, 0x25252525U,
+    0x72727272U, 0xf8f8f8f8U, 0xf6f6f6f6U, 0x64646464U,
+    0x86868686U, 0x68686868U, 0x98989898U, 0x16161616U,
+    0xd4d4d4d4U, 0xa4a4a4a4U, 0x5c5c5c5cU, 0xccccccccU,
+    0x5d5d5d5dU, 0x65656565U, 0xb6b6b6b6U, 0x92929292U,
+    0x6c6c6c6cU, 0x70707070U, 0x48484848U, 0x50505050U,
+    0xfdfdfdfdU, 0xededededU, 0xb9b9b9b9U, 0xdadadadaU,
+    0x5e5e5e5eU, 0x15151515U, 0x46464646U, 0x57575757U,
+    0xa7a7a7a7U, 0x8d8d8d8dU, 0x9d9d9d9dU, 0x84848484U,
+    0x90909090U, 0xd8d8d8d8U, 0xababababU, 0x00000000U,
+    0x8c8c8c8cU, 0xbcbcbcbcU, 0xd3d3d3d3U, 0x0a0a0a0aU,
+    0xf7f7f7f7U, 0xe4e4e4e4U, 0x58585858U, 0x05050505U,
+    0xb8b8b8b8U, 0xb3b3b3b3U, 0x45454545U, 0x06060606U,
+    0xd0d0d0d0U, 0x2c2c2c2cU, 0x1e1e1e1eU, 0x8f8f8f8fU,
+    0xcacacacaU, 0x3f3f3f3fU, 0x0f0f0f0fU, 0x02020202U,
+    0xc1c1c1c1U, 0xafafafafU, 0xbdbdbdbdU, 0x03030303U,
+    0x01010101U, 0x13131313U, 0x8a8a8a8aU, 0x6b6b6b6bU,
+    0x3a3a3a3aU, 0x91919191U, 0x11111111U, 0x41414141U,
+    0x4f4f4f4fU, 0x67676767U, 0xdcdcdcdcU, 0xeaeaeaeaU,
+    0x97979797U, 0xf2f2f2f2U, 0xcfcfcfcfU, 0xcecececeU,
+    0xf0f0f0f0U, 0xb4b4b4b4U, 0xe6e6e6e6U, 0x73737373U,
+    0x96969696U, 0xacacacacU, 0x74747474U, 0x22222222U,
+    0xe7e7e7e7U, 0xadadadadU, 0x35353535U, 0x85858585U,
+    0xe2e2e2e2U, 0xf9f9f9f9U, 0x37373737U, 0xe8e8e8e8U,
+    0x1c1c1c1cU, 0x75757575U, 0xdfdfdfdfU, 0x6e6e6e6eU,
+    0x47474747U, 0xf1f1f1f1U, 0x1a1a1a1aU, 0x71717171U,
+    0x1d1d1d1dU, 0x29292929U, 0xc5c5c5c5U, 0x89898989U,
+    0x6f6f6f6fU, 0xb7b7b7b7U, 0x62626262U, 0x0e0e0e0eU,
+    0xaaaaaaaaU, 0x18181818U, 0xbebebebeU, 0x1b1b1b1bU,
+    0xfcfcfcfcU, 0x56565656U, 0x3e3e3e3eU, 0x4b4b4b4bU,
+    0xc6c6c6c6U, 0xd2d2d2d2U, 0x79797979U, 0x20202020U,
+    0x9a9a9a9aU, 0xdbdbdbdbU, 0xc0c0c0c0U, 0xfefefefeU,
+    0x78787878U, 0xcdcdcdcdU, 0x5a5a5a5aU, 0xf4f4f4f4U,
+    0x1f1f1f1fU, 0xddddddddU, 0xa8a8a8a8U, 0x33333333U,
+    0x88888888U, 0x07070707U, 0xc7c7c7c7U, 0x31313131U,
+    0xb1b1b1b1U, 0x12121212U, 0x10101010U, 0x59595959U,
+    0x27272727U, 0x80808080U, 0xececececU, 0x5f5f5f5fU,
+    0x60606060U, 0x51515151U, 0x7f7f7f7fU, 0xa9a9a9a9U,
+    0x19191919U, 0xb5b5b5b5U, 0x4a4a4a4aU, 0x0d0d0d0dU,
+    0x2d2d2d2dU, 0xe5e5e5e5U, 0x7a7a7a7aU, 0x9f9f9f9fU,
+    0x93939393U, 0xc9c9c9c9U, 0x9c9c9c9cU, 0xefefefefU,
+    0xa0a0a0a0U, 0xe0e0e0e0U, 0x3b3b3b3bU, 0x4d4d4d4dU,
+    0xaeaeaeaeU, 0x2a2a2a2aU, 0xf5f5f5f5U, 0xb0b0b0b0U,
+    0xc8c8c8c8U, 0xebebebebU, 0xbbbbbbbbU, 0x3c3c3c3cU,
+    0x83838383U, 0x53535353U, 0x99999999U, 0x61616161U,
+    0x17171717U, 0x2b2b2b2bU, 0x04040404U, 0x7e7e7e7eU,
+    0xbabababaU, 0x77777777U, 0xd6d6d6d6U, 0x26262626U,
+    0xe1e1e1e1U, 0x69696969U, 0x14141414U, 0x63636363U,
+    0x55555555U, 0x21212121U, 0x0c0c0c0cU, 0x7d7d7d7dU,
+};
+const u32 rcon[] = {
+	0x01000000, 0x02000000, 0x04000000, 0x08000000,
+	0x10000000, 0x20000000, 0x40000000, 0x80000000,
+	0x1B000000, 0x36000000, /* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+#else /* AES_SMALL_TABLES */
+const u8 Td4s[256] = {
+    0x52U, 0x09U, 0x6aU, 0xd5U, 0x30U, 0x36U, 0xa5U, 0x38U,
+    0xbfU, 0x40U, 0xa3U, 0x9eU, 0x81U, 0xf3U, 0xd7U, 0xfbU,
+    0x7cU, 0xe3U, 0x39U, 0x82U, 0x9bU, 0x2fU, 0xffU, 0x87U,
+    0x34U, 0x8eU, 0x43U, 0x44U, 0xc4U, 0xdeU, 0xe9U, 0xcbU,
+    0x54U, 0x7bU, 0x94U, 0x32U, 0xa6U, 0xc2U, 0x23U, 0x3dU,
+    0xeeU, 0x4cU, 0x95U, 0x0bU, 0x42U, 0xfaU, 0xc3U, 0x4eU,
+    0x08U, 0x2eU, 0xa1U, 0x66U, 0x28U, 0xd9U, 0x24U, 0xb2U,
+    0x76U, 0x5bU, 0xa2U, 0x49U, 0x6dU, 0x8bU, 0xd1U, 0x25U,
+    0x72U, 0xf8U, 0xf6U, 0x64U, 0x86U, 0x68U, 0x98U, 0x16U,
+    0xd4U, 0xa4U, 0x5cU, 0xccU, 0x5dU, 0x65U, 0xb6U, 0x92U,
+    0x6cU, 0x70U, 0x48U, 0x50U, 0xfdU, 0xedU, 0xb9U, 0xdaU,
+    0x5eU, 0x15U, 0x46U, 0x57U, 0xa7U, 0x8dU, 0x9dU, 0x84U,
+    0x90U, 0xd8U, 0xabU, 0x00U, 0x8cU, 0xbcU, 0xd3U, 0x0aU,
+    0xf7U, 0xe4U, 0x58U, 0x05U, 0xb8U, 0xb3U, 0x45U, 0x06U,
+    0xd0U, 0x2cU, 0x1eU, 0x8fU, 0xcaU, 0x3fU, 0x0fU, 0x02U,
+    0xc1U, 0xafU, 0xbdU, 0x03U, 0x01U, 0x13U, 0x8aU, 0x6bU,
+    0x3aU, 0x91U, 0x11U, 0x41U, 0x4fU, 0x67U, 0xdcU, 0xeaU,
+    0x97U, 0xf2U, 0xcfU, 0xceU, 0xf0U, 0xb4U, 0xe6U, 0x73U,
+    0x96U, 0xacU, 0x74U, 0x22U, 0xe7U, 0xadU, 0x35U, 0x85U,
+    0xe2U, 0xf9U, 0x37U, 0xe8U, 0x1cU, 0x75U, 0xdfU, 0x6eU,
+    0x47U, 0xf1U, 0x1aU, 0x71U, 0x1dU, 0x29U, 0xc5U, 0x89U,
+    0x6fU, 0xb7U, 0x62U, 0x0eU, 0xaaU, 0x18U, 0xbeU, 0x1bU,
+    0xfcU, 0x56U, 0x3eU, 0x4bU, 0xc6U, 0xd2U, 0x79U, 0x20U,
+    0x9aU, 0xdbU, 0xc0U, 0xfeU, 0x78U, 0xcdU, 0x5aU, 0xf4U,
+    0x1fU, 0xddU, 0xa8U, 0x33U, 0x88U, 0x07U, 0xc7U, 0x31U,
+    0xb1U, 0x12U, 0x10U, 0x59U, 0x27U, 0x80U, 0xecU, 0x5fU,
+    0x60U, 0x51U, 0x7fU, 0xa9U, 0x19U, 0xb5U, 0x4aU, 0x0dU,
+    0x2dU, 0xe5U, 0x7aU, 0x9fU, 0x93U, 0xc9U, 0x9cU, 0xefU,
+    0xa0U, 0xe0U, 0x3bU, 0x4dU, 0xaeU, 0x2aU, 0xf5U, 0xb0U,
+    0xc8U, 0xebU, 0xbbU, 0x3cU, 0x83U, 0x53U, 0x99U, 0x61U,
+    0x17U, 0x2bU, 0x04U, 0x7eU, 0xbaU, 0x77U, 0xd6U, 0x26U,
+    0xe1U, 0x69U, 0x14U, 0x63U, 0x55U, 0x21U, 0x0cU, 0x7dU,
+};
+const u8 rcons[] = {
+	0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
+	/* for 128-bit blocks, Rijndael never uses more than 10 rcon values */
+};
+#endif /* AES_SMALL_TABLES */
+/**
+ * Expand the cipher key into the encryption key schedule.
+ *
+ * @return	the number of rounds for the given cipher key size.
+ */
+int rijndaelKeySetupEnc(u32 rk[], const u8 cipherKey[], int keyBits)
+{
+	int i;
+	u32 temp;
+
+	rk[0] = GETU32(cipherKey     );
+	rk[1] = GETU32(cipherKey +  4);
+	rk[2] = GETU32(cipherKey +  8);
+	rk[3] = GETU32(cipherKey + 12);
+
+	if (keyBits == 128) {
+		for (i = 0; i < 10; i++) {
+			temp  = rk[3];
+			rk[4] = rk[0] ^ TE421(temp) ^ TE432(temp) ^
+				TE443(temp) ^ TE414(temp) ^ RCON(i);
+			rk[5] = rk[1] ^ rk[4];
+			rk[6] = rk[2] ^ rk[5];
+			rk[7] = rk[3] ^ rk[6];
+			rk += 4;
+		}
+		return 10;
+	}
+
+	rk[4] = GETU32(cipherKey + 16);
+	rk[5] = GETU32(cipherKey + 20);
+
+	if (keyBits == 192) {
+		for (i = 0; i < 8; i++) {
+			temp  = rk[5];
+			rk[6] = rk[0] ^ TE421(temp) ^ TE432(temp) ^
+				TE443(temp) ^ TE414(temp) ^ RCON(i);
+			rk[7] = rk[1] ^ rk[6];
+			rk[8] = rk[2] ^ rk[7];
+			rk[9] = rk[3] ^ rk[8];
+			if (i == 7)
+				return 12;
+			rk[10] = rk[4] ^ rk[9];
+			rk[11] = rk[5] ^ rk[10];
+			rk += 6;
+		}
+	}
+
+	rk[6] = GETU32(cipherKey + 24);
+	rk[7] = GETU32(cipherKey + 28);
+
+	if (keyBits == 256) {
+		for (i = 0; i < 7; i++) {
+			temp  = rk[7];
+			rk[8] = rk[0] ^ TE421(temp) ^ TE432(temp) ^
+				TE443(temp) ^ TE414(temp) ^ RCON(i);
+			rk[9] = rk[1] ^ rk[8];
+			rk[10] = rk[2] ^ rk[9];
+			rk[11] = rk[3] ^ rk[10];
+			if (i == 6)
+				return 14;
+			temp  = rk[11];
+			rk[12] = rk[4] ^ TE411(temp) ^ TE422(temp) ^
+				TE433(temp) ^ TE444(temp);
+			rk[13] = rk[5] ^ rk[12];
+			rk[14] = rk[6] ^ rk[13];
+			rk[15] = rk[7] ^ rk[14];
+			rk += 8;
+		}
+	}
+
+	return -1;
+}
diff --git a/hostap/src/crypto/aes-omac1.c b/hostap/src/crypto/aes-omac1.c
new file mode 100644
index 0000000..27895eb
--- /dev/null
+++ b/hostap/src/crypto/aes-omac1.c
@@ -0,0 +1,118 @@
+/*
+ * One-key CBC MAC (OMAC1) hash with AES-128
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "aes.h"
+#include "aes_wrap.h"
+
+static void gf_mulx(u8 *pad)
+{
+	int i, carry;
+
+	carry = pad[0] & 0x80;
+	for (i = 0; i < AES_BLOCK_SIZE - 1; i++)
+		pad[i] = (pad[i] << 1) | (pad[i + 1] >> 7);
+	pad[AES_BLOCK_SIZE - 1] <<= 1;
+	if (carry)
+		pad[AES_BLOCK_SIZE - 1] ^= 0x87;
+}
+
+
+/**
+ * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
+ * @key: 128-bit key for the hash operation
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+			 const u8 *addr[], const size_t *len, u8 *mac)
+{
+	void *ctx;
+	u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE];
+	const u8 *pos, *end;
+	size_t i, e, left, total_len;
+
+	ctx = aes_encrypt_init(key, 16);
+	if (ctx == NULL)
+		return -1;
+	os_memset(cbc, 0, AES_BLOCK_SIZE);
+
+	total_len = 0;
+	for (e = 0; e < num_elem; e++)
+		total_len += len[e];
+	left = total_len;
+
+	e = 0;
+	pos = addr[0];
+	end = pos + len[0];
+
+	while (left >= AES_BLOCK_SIZE) {
+		for (i = 0; i < AES_BLOCK_SIZE; i++) {
+			cbc[i] ^= *pos++;
+			if (pos >= end) {
+				e++;
+				pos = addr[e];
+				end = pos + len[e];
+			}
+		}
+		if (left > AES_BLOCK_SIZE)
+			aes_encrypt(ctx, cbc, cbc);
+		left -= AES_BLOCK_SIZE;
+	}
+
+	os_memset(pad, 0, AES_BLOCK_SIZE);
+	aes_encrypt(ctx, pad, pad);
+	gf_mulx(pad);
+
+	if (left || total_len == 0) {
+		for (i = 0; i < left; i++) {
+			cbc[i] ^= *pos++;
+			if (pos >= end) {
+				e++;
+				pos = addr[e];
+				end = pos + len[e];
+			}
+		}
+		cbc[left] ^= 0x80;
+		gf_mulx(pad);
+	}
+
+	for (i = 0; i < AES_BLOCK_SIZE; i++)
+		pad[i] ^= cbc[i];
+	aes_encrypt(ctx, pad, mac);
+	aes_encrypt_deinit(ctx);
+	return 0;
+}
+
+
+/**
+ * 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_len: Length of data buffer in bytes
+ * @mac: Buffer for MAC (128 bits, i.e., 16 bytes)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This is a mode for using block cipher (AES in this case) for authentication.
+ * OMAC1 was standardized with the name CMAC by NIST in a Special Publication
+ * (SP) 800-38B.
+ */
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+	return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
+}
diff --git a/hostap/src/crypto/aes-unwrap.c b/hostap/src/crypto/aes-unwrap.c
new file mode 100644
index 0000000..9dd5160
--- /dev/null
+++ b/hostap/src/crypto/aes-unwrap.c
@@ -0,0 +1,73 @@
+/*
+ * AES key unwrap (128-bit KEK, RFC3394)
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "aes.h"
+#include "aes_wrap.h"
+
+/**
+ * aes_unwrap - Unwrap key with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * @kek: Key encryption key (KEK)
+ * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
+ * bytes
+ * @cipher: Wrapped key to be unwrapped, (n + 1) * 64 bits
+ * @plain: Plaintext key, n * 64 bits
+ * Returns: 0 on success, -1 on failure (e.g., integrity verification failed)
+ */
+int aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain)
+{
+	u8 a[8], *r, b[16];
+	int i, j;
+	void *ctx;
+
+	/* 1) Initialize variables. */
+	os_memcpy(a, cipher, 8);
+	r = plain;
+	os_memcpy(r, cipher + 8, 8 * n);
+
+	ctx = aes_decrypt_init(kek, 16);
+	if (ctx == NULL)
+		return -1;
+
+	/* 2) Compute intermediate values.
+	 * For j = 5 to 0
+	 *     For i = n to 1
+	 *         B = AES-1(K, (A ^ t) | R[i]) where t = n*j+i
+	 *         A = MSB(64, B)
+	 *         R[i] = LSB(64, B)
+	 */
+	for (j = 5; j >= 0; j--) {
+		r = plain + (n - 1) * 8;
+		for (i = n; i >= 1; i--) {
+			os_memcpy(b, a, 8);
+			b[7] ^= n * j + i;
+
+			os_memcpy(b + 8, r, 8);
+			aes_decrypt(ctx, b, b);
+			os_memcpy(a, b, 8);
+			os_memcpy(r, b + 8, 8);
+			r -= 8;
+		}
+	}
+	aes_decrypt_deinit(ctx);
+
+	/* 3) Output results.
+	 *
+	 * These are already in @plain due to the location of temporary
+	 * variables. Just verify that the IV matches with the expected value.
+	 */
+	for (i = 0; i < 8; i++) {
+		if (a[i] != 0xa6)
+			return -1;
+	}
+
+	return 0;
+}
diff --git a/hostap/src/crypto/aes-wrap.c b/hostap/src/crypto/aes-wrap.c
new file mode 100644
index 0000000..89d6f94
--- /dev/null
+++ b/hostap/src/crypto/aes-wrap.c
@@ -0,0 +1,70 @@
+/*
+ * AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ *
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "aes.h"
+#include "aes_wrap.h"
+
+/**
+ * aes_wrap - Wrap keys with AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * @kek: 16-octet Key encryption key (KEK)
+ * @n: Length of the plaintext key in 64-bit units; e.g., 2 = 128-bit = 16
+ * bytes
+ * @plain: Plaintext key to be wrapped, n * 64 bits
+ * @cipher: Wrapped key, (n + 1) * 64 bits
+ * Returns: 0 on success, -1 on failure
+ */
+int aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher)
+{
+	u8 *a, *r, b[16];
+	int i, j;
+	void *ctx;
+
+	a = cipher;
+	r = cipher + 8;
+
+	/* 1) Initialize variables. */
+	os_memset(a, 0xa6, 8);
+	os_memcpy(r, plain, 8 * n);
+
+	ctx = aes_encrypt_init(kek, 16);
+	if (ctx == NULL)
+		return -1;
+
+	/* 2) Calculate intermediate values.
+	 * For j = 0 to 5
+	 *     For i=1 to n
+	 *         B = AES(K, A | R[i])
+	 *         A = MSB(64, B) ^ t where t = (n*j)+i
+	 *         R[i] = LSB(64, B)
+	 */
+	for (j = 0; j <= 5; j++) {
+		r = cipher + 8;
+		for (i = 1; i <= n; i++) {
+			os_memcpy(b, a, 8);
+			os_memcpy(b + 8, r, 8);
+			aes_encrypt(ctx, b, b);
+			os_memcpy(a, b, 8);
+			a[7] ^= n * j + i;
+			os_memcpy(r, b + 8, 8);
+			r += 8;
+		}
+	}
+	aes_encrypt_deinit(ctx);
+
+	/* 3) Output the results.
+	 *
+	 * These are already in @cipher due to the location of temporary
+	 * variables.
+	 */
+
+	return 0;
+}
diff --git a/hostap/src/crypto/aes.h b/hostap/src/crypto/aes.h
new file mode 100644
index 0000000..2de59e0
--- /dev/null
+++ b/hostap/src/crypto/aes.h
@@ -0,0 +1,21 @@
+/*
+ * AES functions
+ * Copyright (c) 2003-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AES_H
+#define AES_H
+
+#define AES_BLOCK_SIZE 16
+
+void * aes_encrypt_init(const u8 *key, size_t len);
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
+void aes_encrypt_deinit(void *ctx);
+void * aes_decrypt_init(const u8 *key, size_t len);
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
+void aes_decrypt_deinit(void *ctx);
+
+#endif /* AES_H */
diff --git a/hostap/src/crypto/aes_i.h b/hostap/src/crypto/aes_i.h
new file mode 100644
index 0000000..54375cf
--- /dev/null
+++ b/hostap/src/crypto/aes_i.h
@@ -0,0 +1,125 @@
+/*
+ * AES (Rijndael) cipher
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AES_I_H
+#define AES_I_H
+
+#include "aes.h"
+
+/* #define FULL_UNROLL */
+#define AES_SMALL_TABLES
+
+extern const u32 Te0[256];
+extern const u32 Te1[256];
+extern const u32 Te2[256];
+extern const u32 Te3[256];
+extern const u32 Te4[256];
+extern const u32 Td0[256];
+extern const u32 Td1[256];
+extern const u32 Td2[256];
+extern const u32 Td3[256];
+extern const u32 Td4[256];
+extern const u32 rcon[10];
+extern const u8 Td4s[256];
+extern const u8 rcons[10];
+
+#ifndef AES_SMALL_TABLES
+
+#define RCON(i) rcon[(i)]
+
+#define TE0(i) Te0[((i) >> 24) & 0xff]
+#define TE1(i) Te1[((i) >> 16) & 0xff]
+#define TE2(i) Te2[((i) >> 8) & 0xff]
+#define TE3(i) Te3[(i) & 0xff]
+#define TE41(i) (Te4[((i) >> 24) & 0xff] & 0xff000000)
+#define TE42(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TE43(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TE44(i) (Te4[(i) & 0xff] & 0x000000ff)
+#define TE421(i) (Te4[((i) >> 16) & 0xff] & 0xff000000)
+#define TE432(i) (Te4[((i) >> 8) & 0xff] & 0x00ff0000)
+#define TE443(i) (Te4[(i) & 0xff] & 0x0000ff00)
+#define TE414(i) (Te4[((i) >> 24) & 0xff] & 0x000000ff)
+#define TE411(i) (Te4[((i) >> 24) & 0xff] & 0xff000000)
+#define TE422(i) (Te4[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TE433(i) (Te4[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TE444(i) (Te4[(i) & 0xff] & 0x000000ff)
+#define TE4(i) (Te4[(i)] & 0x000000ff)
+
+#define TD0(i) Td0[((i) >> 24) & 0xff]
+#define TD1(i) Td1[((i) >> 16) & 0xff]
+#define TD2(i) Td2[((i) >> 8) & 0xff]
+#define TD3(i) Td3[(i) & 0xff]
+#define TD41(i) (Td4[((i) >> 24) & 0xff] & 0xff000000)
+#define TD42(i) (Td4[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TD43(i) (Td4[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TD44(i) (Td4[(i) & 0xff] & 0x000000ff)
+#define TD0_(i) Td0[(i) & 0xff]
+#define TD1_(i) Td1[(i) & 0xff]
+#define TD2_(i) Td2[(i) & 0xff]
+#define TD3_(i) Td3[(i) & 0xff]
+
+#else /* AES_SMALL_TABLES */
+
+#define RCON(i) (rcons[(i)] << 24)
+
+static inline u32 rotr(u32 val, int bits)
+{
+	return (val >> bits) | (val << (32 - bits));
+}
+
+#define TE0(i) Te0[((i) >> 24) & 0xff]
+#define TE1(i) rotr(Te0[((i) >> 16) & 0xff], 8)
+#define TE2(i) rotr(Te0[((i) >> 8) & 0xff], 16)
+#define TE3(i) rotr(Te0[(i) & 0xff], 24)
+#define TE41(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000)
+#define TE42(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TE43(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TE44(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff)
+#define TE421(i) ((Te0[((i) >> 16) & 0xff] << 8) & 0xff000000)
+#define TE432(i) (Te0[((i) >> 8) & 0xff] & 0x00ff0000)
+#define TE443(i) (Te0[(i) & 0xff] & 0x0000ff00)
+#define TE414(i) ((Te0[((i) >> 24) & 0xff] >> 8) & 0x000000ff)
+#define TE411(i) ((Te0[((i) >> 24) & 0xff] << 8) & 0xff000000)
+#define TE422(i) (Te0[((i) >> 16) & 0xff] & 0x00ff0000)
+#define TE433(i) (Te0[((i) >> 8) & 0xff] & 0x0000ff00)
+#define TE444(i) ((Te0[(i) & 0xff] >> 8) & 0x000000ff)
+#define TE4(i) ((Te0[(i)] >> 8) & 0x000000ff)
+
+#define TD0(i) Td0[((i) >> 24) & 0xff]
+#define TD1(i) rotr(Td0[((i) >> 16) & 0xff], 8)
+#define TD2(i) rotr(Td0[((i) >> 8) & 0xff], 16)
+#define TD3(i) rotr(Td0[(i) & 0xff], 24)
+#define TD41(i) (Td4s[((i) >> 24) & 0xff] << 24)
+#define TD42(i) (Td4s[((i) >> 16) & 0xff] << 16)
+#define TD43(i) (Td4s[((i) >> 8) & 0xff] << 8)
+#define TD44(i) (Td4s[(i) & 0xff])
+#define TD0_(i) Td0[(i) & 0xff]
+#define TD1_(i) rotr(Td0[(i) & 0xff], 8)
+#define TD2_(i) rotr(Td0[(i) & 0xff], 16)
+#define TD3_(i) rotr(Td0[(i) & 0xff], 24)
+
+#endif /* AES_SMALL_TABLES */
+
+#ifdef _MSC_VER
+#define SWAP(x) (_lrotl(x, 8) & 0x00ff00ff | _lrotr(x, 8) & 0xff00ff00)
+#define GETU32(p) SWAP(*((u32 *)(p)))
+#define PUTU32(ct, st) { *((u32 *)(ct)) = SWAP((st)); }
+#else
+#define GETU32(pt) (((u32)(pt)[0] << 24) ^ ((u32)(pt)[1] << 16) ^ \
+((u32)(pt)[2] <<  8) ^ ((u32)(pt)[3]))
+#define PUTU32(ct, st) { \
+(ct)[0] = (u8)((st) >> 24); (ct)[1] = (u8)((st) >> 16); \
+(ct)[2] = (u8)((st) >>  8); (ct)[3] = (u8)(st); }
+#endif
+
+#define AES_PRIV_SIZE (4 * 4 * 15 + 4)
+#define AES_PRIV_NR_POS (4 * 15)
+
+int rijndaelKeySetupEnc(u32 rk[], const u8 cipherKey[], int keyBits);
+
+#endif /* AES_I_H */
diff --git a/hostap/src/crypto/aes_wrap.h b/hostap/src/crypto/aes_wrap.h
new file mode 100644
index 0000000..0433c04
--- /dev/null
+++ b/hostap/src/crypto/aes_wrap.h
@@ -0,0 +1,64 @@
+/*
+ * AES-based functions
+ *
+ * - AES Key Wrap Algorithm (128-bit KEK) (RFC3394)
+ * - One-Key CBC MAC (OMAC1) hash with AES-128
+ * - AES-128 CTR mode encryption
+ * - AES-128 EAX mode encryption/decryption
+ * - AES-128 CBC
+ * - AES-GCM
+ * - AES-CCM
+ *
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef AES_WRAP_H
+#define AES_WRAP_H
+
+int __must_check aes_wrap(const u8 *kek, int n, const u8 *plain, u8 *cipher);
+int __must_check aes_unwrap(const u8 *kek, int n, const u8 *cipher, u8 *plain);
+int __must_check omac1_aes_128_vector(const u8 *key, size_t num_elem,
+				      const u8 *addr[], const size_t *len,
+				      u8 *mac);
+int __must_check omac1_aes_128(const u8 *key, const u8 *data, size_t data_len,
+			       u8 *mac);
+int __must_check aes_128_encrypt_block(const u8 *key, const u8 *in, u8 *out);
+int __must_check aes_128_ctr_encrypt(const u8 *key, const u8 *nonce,
+				     u8 *data, size_t data_len);
+int __must_check aes_128_eax_encrypt(const u8 *key,
+				     const u8 *nonce, size_t nonce_len,
+				     const u8 *hdr, size_t hdr_len,
+				     u8 *data, size_t data_len, u8 *tag);
+int __must_check aes_128_eax_decrypt(const u8 *key,
+				     const u8 *nonce, size_t nonce_len,
+				     const u8 *hdr, size_t hdr_len,
+				     u8 *data, size_t data_len, const u8 *tag);
+int __must_check aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data,
+				     size_t data_len);
+int __must_check aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data,
+				     size_t data_len);
+int __must_check aes_gcm_ae(const u8 *key, size_t key_len,
+			    const u8 *iv, size_t iv_len,
+			    const u8 *plain, size_t plain_len,
+			    const u8 *aad, size_t aad_len,
+			    u8 *crypt, u8 *tag);
+int __must_check aes_gcm_ad(const u8 *key, size_t key_len,
+			    const u8 *iv, size_t iv_len,
+			    const u8 *crypt, size_t crypt_len,
+			    const u8 *aad, size_t aad_len, const u8 *tag,
+			    u8 *plain);
+int __must_check aes_gmac(const u8 *key, size_t key_len,
+			  const u8 *iv, size_t iv_len,
+			  const u8 *aad, size_t aad_len, u8 *tag);
+int __must_check aes_ccm_ae(const u8 *key, size_t key_len, const u8 *nonce,
+			    size_t M, const u8 *plain, size_t plain_len,
+			    const u8 *aad, size_t aad_len, u8 *crypt, u8 *auth);
+int __must_check aes_ccm_ad(const u8 *key, size_t key_len, const u8 *nonce,
+			    size_t M, const u8 *crypt, size_t crypt_len,
+			    const u8 *aad, size_t aad_len, const u8 *auth,
+			    u8 *plain);
+
+#endif /* AES_WRAP_H */
diff --git a/hostap/src/crypto/crypto.h b/hostap/src/crypto/crypto.h
new file mode 100644
index 0000000..26b9acf
--- /dev/null
+++ b/hostap/src/crypto/crypto.h
@@ -0,0 +1,460 @@
+/*
+ * WPA Supplicant / wrapper functions for crypto libraries
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file defines the cryptographic functions that need to be implemented
+ * for wpa_supplicant and hostapd. When TLS is not used, internal
+ * implementation of MD5, SHA1, and AES is used and no external libraries are
+ * required. When TLS is enabled (e.g., by enabling EAP-TLS or EAP-PEAP), the
+ * crypto library used by the TLS implementation is expected to be used for
+ * non-TLS needs, too, in order to save space by not implementing these
+ * functions twice.
+ *
+ * Wrapper code for using each crypto library is in its own file (crypto*.c)
+ * and one of these files is build and linked in to provide the functions
+ * defined here.
+ */
+
+#ifndef CRYPTO_H
+#define CRYPTO_H
+
+/**
+ * md4_vector - MD4 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
+
+/**
+ * md5_vector - MD5 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac);
+
+
+/**
+ * sha1_vector - SHA-1 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		u8 *mac);
+
+/**
+ * fips186_2-prf - NIST FIPS Publication 186-2 change notice 1 PRF
+ * @seed: Seed/key for the PRF
+ * @seed_len: Seed length in bytes
+ * @x: Buffer for PRF output
+ * @xlen: Output length in bytes
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function implements random number generation specified in NIST FIPS
+ * Publication 186-2 for EAP-SIM. This PRF uses a function that is similar to
+ * SHA-1, but has different message padding.
+ */
+int __must_check fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x,
+			       size_t xlen);
+
+/**
+ * sha256_vector - SHA256 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 on failure
+ */
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		  u8 *mac);
+
+/**
+ * des_encrypt - Encrypt one block with DES
+ * @clear: 8 octets (in)
+ * @key: 7 octets (in) (no parity bits included)
+ * @cypher: 8 octets (out)
+ */
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher);
+
+/**
+ * aes_encrypt_init - Initialize AES for encryption
+ * @key: Encryption key
+ * @len: Key length in bytes (usually 16, i.e., 128 bits)
+ * Returns: Pointer to context data or %NULL on failure
+ */
+void * aes_encrypt_init(const u8 *key, size_t len);
+
+/**
+ * aes_encrypt - Encrypt one AES block
+ * @ctx: Context pointer from aes_encrypt_init()
+ * @plain: Plaintext data to be encrypted (16 bytes)
+ * @crypt: Buffer for the encrypted data (16 bytes)
+ */
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt);
+
+/**
+ * aes_encrypt_deinit - Deinitialize AES encryption
+ * @ctx: Context pointer from aes_encrypt_init()
+ */
+void aes_encrypt_deinit(void *ctx);
+
+/**
+ * aes_decrypt_init - Initialize AES for decryption
+ * @key: Decryption key
+ * @len: Key length in bytes (usually 16, i.e., 128 bits)
+ * Returns: Pointer to context data or %NULL on failure
+ */
+void * aes_decrypt_init(const u8 *key, size_t len);
+
+/**
+ * aes_decrypt - Decrypt one AES block
+ * @ctx: Context pointer from aes_encrypt_init()
+ * @crypt: Encrypted data (16 bytes)
+ * @plain: Buffer for the decrypted data (16 bytes)
+ */
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain);
+
+/**
+ * aes_decrypt_deinit - Deinitialize AES decryption
+ * @ctx: Context pointer from aes_encrypt_init()
+ */
+void aes_decrypt_deinit(void *ctx);
+
+
+enum crypto_hash_alg {
+	CRYPTO_HASH_ALG_MD5, CRYPTO_HASH_ALG_SHA1,
+	CRYPTO_HASH_ALG_HMAC_MD5, CRYPTO_HASH_ALG_HMAC_SHA1,
+	CRYPTO_HASH_ALG_SHA256, CRYPTO_HASH_ALG_HMAC_SHA256
+};
+
+struct crypto_hash;
+
+/**
+ * crypto_hash_init - Initialize hash/HMAC function
+ * @alg: Hash algorithm
+ * @key: Key for keyed hash (e.g., HMAC) or %NULL if not needed
+ * @key_len: Length of the key in bytes
+ * Returns: Pointer to hash context to use with other hash functions or %NULL
+ * on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+				      size_t key_len);
+
+/**
+ * crypto_hash_update - Add data to hash calculation
+ * @ctx: Context pointer from crypto_hash_init()
+ * @data: Data buffer to add
+ * @len: Length of the buffer
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len);
+
+/**
+ * crypto_hash_finish - Complete hash calculation
+ * @ctx: Context pointer from crypto_hash_init()
+ * @hash: Buffer for hash value or %NULL if caller is just freeing the hash
+ * context
+ * @len: Pointer to length of the buffer or %NULL if caller is just freeing the
+ * hash context; on return, this is set to the actual length of the hash value
+ * Returns: 0 on success, -1 if buffer is too small (len set to needed length),
+ * or -2 on other failures (including failed crypto_hash_update() operations)
+ *
+ * This function calculates the hash value and frees the context buffer that
+ * was used for hash calculation.
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *hash, size_t *len);
+
+
+enum crypto_cipher_alg {
+	CRYPTO_CIPHER_NULL = 0, CRYPTO_CIPHER_ALG_AES, CRYPTO_CIPHER_ALG_3DES,
+	CRYPTO_CIPHER_ALG_DES, CRYPTO_CIPHER_ALG_RC2, CRYPTO_CIPHER_ALG_RC4
+};
+
+struct crypto_cipher;
+
+/**
+ * crypto_cipher_init - Initialize block/stream cipher function
+ * @alg: Cipher algorithm
+ * @iv: Initialization vector for block ciphers or %NULL for stream ciphers
+ * @key: Cipher key
+ * @key_len: Length of key in bytes
+ * Returns: Pointer to cipher context to use with other cipher functions or
+ * %NULL on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len);
+
+/**
+ * crypto_cipher_encrypt - Cipher encrypt
+ * @ctx: Context pointer from crypto_cipher_init()
+ * @plain: Plaintext to cipher
+ * @crypt: Resulting ciphertext
+ * @len: Length of the plaintext
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int __must_check crypto_cipher_encrypt(struct crypto_cipher *ctx,
+				       const u8 *plain, u8 *crypt, size_t len);
+
+/**
+ * crypto_cipher_decrypt - Cipher decrypt
+ * @ctx: Context pointer from crypto_cipher_init()
+ * @crypt: Ciphertext to decrypt
+ * @plain: Resulting plaintext
+ * @len: Length of the cipher text
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int __must_check crypto_cipher_decrypt(struct crypto_cipher *ctx,
+				       const u8 *crypt, u8 *plain, size_t len);
+
+/**
+ * crypto_cipher_decrypt - Free cipher context
+ * @ctx: Context pointer from crypto_cipher_init()
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_cipher_deinit(struct crypto_cipher *ctx);
+
+
+struct crypto_public_key;
+struct crypto_private_key;
+
+/**
+ * crypto_public_key_import - Import an RSA public key
+ * @key: Key buffer (DER encoded RSA public key)
+ * @len: Key buffer length in bytes
+ * Returns: Pointer to the public key or %NULL on failure
+ *
+ * This function can just return %NULL if the crypto library supports X.509
+ * parsing. In that case, crypto_public_key_from_cert() is used to import the
+ * public key from a certificate.
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len);
+
+/**
+ * crypto_private_key_import - Import an RSA private key
+ * @key: Key buffer (DER encoded RSA private key)
+ * @len: Key buffer length in bytes
+ * @passwd: Key encryption password or %NULL if key is not encrypted
+ * Returns: Pointer to the private key or %NULL on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_private_key * crypto_private_key_import(const u8 *key,
+						      size_t len,
+						      const char *passwd);
+
+/**
+ * crypto_public_key_from_cert - Import an RSA public key from a certificate
+ * @buf: DER encoded X.509 certificate
+ * @len: Certificate buffer length in bytes
+ * Returns: Pointer to public key or %NULL on failure
+ *
+ * This function can just return %NULL if the crypto library does not support
+ * X.509 parsing. In that case, internal code will be used to parse the
+ * certificate and public key is imported using crypto_public_key_import().
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
+						       size_t len);
+
+/**
+ * crypto_public_key_encrypt_pkcs1_v15 - Public key encryption (PKCS #1 v1.5)
+ * @key: Public key
+ * @in: Plaintext buffer
+ * @inlen: Length of plaintext buffer in bytes
+ * @out: Output buffer for encrypted data
+ * @outlen: Length of output buffer in bytes; set to used length on success
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int __must_check crypto_public_key_encrypt_pkcs1_v15(
+	struct crypto_public_key *key, const u8 *in, size_t inlen,
+	u8 *out, size_t *outlen);
+
+/**
+ * crypto_private_key_decrypt_pkcs1_v15 - Private key decryption (PKCS #1 v1.5)
+ * @key: Private key
+ * @in: Encrypted buffer
+ * @inlen: Length of encrypted buffer in bytes
+ * @out: Output buffer for encrypted data
+ * @outlen: Length of output buffer in bytes; set to used length on success
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int __must_check crypto_private_key_decrypt_pkcs1_v15(
+	struct crypto_private_key *key, const u8 *in, size_t inlen,
+	u8 *out, size_t *outlen);
+
+/**
+ * crypto_private_key_sign_pkcs1 - Sign with private key (PKCS #1)
+ * @key: Private key from crypto_private_key_import()
+ * @in: Plaintext buffer
+ * @inlen: Length of plaintext buffer in bytes
+ * @out: Output buffer for encrypted (signed) data
+ * @outlen: Length of output buffer in bytes; set to used length on success
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int __must_check crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
+					       const u8 *in, size_t inlen,
+					       u8 *out, size_t *outlen);
+
+/**
+ * crypto_public_key_free - Free public key
+ * @key: Public key
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_public_key_free(struct crypto_public_key *key);
+
+/**
+ * crypto_private_key_free - Free private key
+ * @key: Private key from crypto_private_key_import()
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_private_key_free(struct crypto_private_key *key);
+
+/**
+ * crypto_public_key_decrypt_pkcs1 - Decrypt PKCS #1 signature
+ * @key: Public key
+ * @crypt: Encrypted signature data (using the private key)
+ * @crypt_len: Encrypted signature data length
+ * @plain: Buffer for plaintext (at least crypt_len bytes)
+ * @plain_len: Plaintext length (max buffer size on input, real len on output);
+ * Returns: 0 on success, -1 on failure
+ */
+int __must_check crypto_public_key_decrypt_pkcs1(
+	struct crypto_public_key *key, const u8 *crypt, size_t crypt_len,
+	u8 *plain, size_t *plain_len);
+
+/**
+ * crypto_global_init - Initialize crypto wrapper
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int __must_check crypto_global_init(void);
+
+/**
+ * crypto_global_deinit - Deinitialize crypto wrapper
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+void crypto_global_deinit(void);
+
+/**
+ * crypto_mod_exp - Modular exponentiation of large integers
+ * @base: Base integer (big endian byte array)
+ * @base_len: Length of base integer in bytes
+ * @power: Power integer (big endian byte array)
+ * @power_len: Length of power integer in bytes
+ * @modulus: Modulus integer (big endian byte array)
+ * @modulus_len: Length of modulus integer in bytes
+ * @result: Buffer for the result
+ * @result_len: Result length (max buffer size on input, real len on output)
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function calculates result = base ^ power mod modulus. modules_len is
+ * used as the maximum size of modulus buffer. It is set to the used size on
+ * success.
+ *
+ * This function is only used with internal TLSv1 implementation
+ * (CONFIG_TLS=internal). If that is not used, the crypto wrapper does not need
+ * to implement this.
+ */
+int __must_check crypto_mod_exp(const u8 *base, size_t base_len,
+				const u8 *power, size_t power_len,
+				const u8 *modulus, size_t modulus_len,
+				u8 *result, size_t *result_len);
+
+/**
+ * rc4_skip - XOR RC4 stream to given data with skip-stream-start
+ * @key: RC4 key
+ * @keylen: RC4 key length
+ * @skip: number of bytes to skip from the beginning of the RC4 stream
+ * @data: data to be XOR'ed with RC4 stream
+ * @data_len: buf length
+ * Returns: 0 on success, -1 on failure
+ *
+ * Generate RC4 pseudo random stream for the given key, skip beginning of the
+ * stream, and XOR the end result with the data buffer to perform RC4
+ * encryption/decryption.
+ */
+int rc4_skip(const u8 *key, size_t keylen, size_t skip,
+	     u8 *data, size_t data_len);
+
+/**
+ * crypto_get_random - Generate cryptographically strong pseudy-random bytes
+ * @buf: Buffer for data
+ * @len: Number of bytes to generate
+ * Returns: 0 on success, -1 on failure
+ *
+ * If the PRNG does not have enough entropy to ensure unpredictable byte
+ * sequence, this functions must return -1.
+ */
+int crypto_get_random(void *buf, size_t len);
+
+#endif /* CRYPTO_H */
diff --git a/hostap/src/crypto/crypto_cryptoapi.c b/hostap/src/crypto/crypto_cryptoapi.c
new file mode 100644
index 0000000..55a069b
--- /dev/null
+++ b/hostap/src/crypto/crypto_cryptoapi.c
@@ -0,0 +1,783 @@
+/*
+ * Crypto wrapper for Microsoft CryptoAPI
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <windows.h>
+#include <wincrypt.h>
+
+#include "common.h"
+#include "crypto.h"
+
+#ifndef MS_ENH_RSA_AES_PROV
+#ifdef UNICODE
+#define MS_ENH_RSA_AES_PROV \
+L"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
+#else
+#define MS_ENH_RSA_AES_PROV \
+"Microsoft Enhanced RSA and AES Cryptographic Provider (Prototype)"
+#endif
+#endif /* MS_ENH_RSA_AES_PROV */
+
+#ifndef CALG_HMAC
+#define CALG_HMAC (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_HMAC)
+#endif
+
+#ifdef __MINGW32_VERSION
+/*
+ * MinGW does not yet include all the needed definitions for CryptoAPI, so
+ * define here whatever extra is needed.
+ */
+
+static BOOL WINAPI
+(*CryptImportPublicKeyInfo)(HCRYPTPROV hCryptProv, DWORD dwCertEncodingType,
+			    PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
+= NULL; /* to be loaded from crypt32.dll */
+
+
+static int mingw_load_crypto_func(void)
+{
+	HINSTANCE dll;
+
+	/* MinGW does not yet have full CryptoAPI support, so load the needed
+	 * function here. */
+
+	if (CryptImportPublicKeyInfo)
+		return 0;
+
+	dll = LoadLibrary("crypt32");
+	if (dll == NULL) {
+		wpa_printf(MSG_DEBUG, "CryptoAPI: Could not load crypt32 "
+			   "library");
+		return -1;
+	}
+
+	CryptImportPublicKeyInfo = GetProcAddress(
+		dll, "CryptImportPublicKeyInfo");
+	if (CryptImportPublicKeyInfo == NULL) {
+		wpa_printf(MSG_DEBUG, "CryptoAPI: Could not get "
+			   "CryptImportPublicKeyInfo() address from "
+			   "crypt32 library");
+		return -1;
+	}
+
+	return 0;
+}
+
+#else /* __MINGW32_VERSION */
+
+static int mingw_load_crypto_func(void)
+{
+	return 0;
+}
+
+#endif /* __MINGW32_VERSION */
+
+
+static void cryptoapi_report_error(const char *msg)
+{
+	char *s, *pos;
+	DWORD err = GetLastError();
+
+	if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+			  FORMAT_MESSAGE_FROM_SYSTEM,
+			  NULL, err, 0, (LPTSTR) &s, 0, NULL) == 0) {
+ 		wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d", msg, (int) err);
+	}
+
+	pos = s;
+	while (*pos) {
+		if (*pos == '\n' || *pos == '\r') {
+			*pos = '\0';
+			break;
+		}
+		pos++;
+	}
+
+	wpa_printf(MSG_DEBUG, "CryptoAPI: %s: %d: (%s)", msg, (int) err, s);
+	LocalFree(s);
+}
+
+
+int cryptoapi_hash_vector(ALG_ID alg, size_t hash_len, size_t num_elem,
+			  const u8 *addr[], const size_t *len, u8 *mac)
+{
+	HCRYPTPROV prov;
+	HCRYPTHASH hash;
+	size_t i;
+	DWORD hlen;
+	int ret = 0;
+
+	if (!CryptAcquireContext(&prov, NULL, NULL, PROV_RSA_FULL, 0)) {
+		cryptoapi_report_error("CryptAcquireContext");
+		return -1;
+	}
+
+	if (!CryptCreateHash(prov, alg, 0, 0, &hash)) {
+		cryptoapi_report_error("CryptCreateHash");
+		CryptReleaseContext(prov, 0);
+		return -1;
+	}
+
+	for (i = 0; i < num_elem; i++) {
+		if (!CryptHashData(hash, (BYTE *) addr[i], len[i], 0)) {
+			cryptoapi_report_error("CryptHashData");
+			CryptDestroyHash(hash);
+			CryptReleaseContext(prov, 0);
+		}
+	}
+
+	hlen = hash_len;
+	if (!CryptGetHashParam(hash, HP_HASHVAL, mac, &hlen, 0)) {
+		cryptoapi_report_error("CryptGetHashParam");
+		ret = -1;
+	}
+
+	CryptDestroyHash(hash);
+	CryptReleaseContext(prov, 0);
+
+	return ret;
+}
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return cryptoapi_hash_vector(CALG_MD4, 16, num_elem, addr, len, mac);
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+	u8 next, tmp;
+	int i;
+	HCRYPTPROV prov;
+	HCRYPTKEY ckey;
+	DWORD dlen;
+	struct {
+		BLOBHEADER hdr;
+		DWORD len;
+		BYTE key[8];
+	} key_blob;
+	DWORD mode = CRYPT_MODE_ECB;
+
+	key_blob.hdr.bType = PLAINTEXTKEYBLOB;
+	key_blob.hdr.bVersion = CUR_BLOB_VERSION;
+	key_blob.hdr.reserved = 0;
+	key_blob.hdr.aiKeyAlg = CALG_DES;
+	key_blob.len = 8;
+
+	/* Add parity bits to the key */
+	next = 0;
+	for (i = 0; i < 7; i++) {
+		tmp = key[i];
+		key_blob.key[i] = (tmp >> i) | next | 1;
+		next = tmp << (7 - i);
+	}
+	key_blob.key[i] = next | 1;
+
+	if (!CryptAcquireContext(&prov, NULL, MS_ENHANCED_PROV, PROV_RSA_FULL,
+				 CRYPT_VERIFYCONTEXT)) {
+ 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
+			   "%d", (int) GetLastError());
+		return;
+	}
+
+	if (!CryptImportKey(prov, (BYTE *) &key_blob, sizeof(key_blob), 0, 0,
+			    &ckey)) {
+ 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
+			   (int) GetLastError());
+		CryptReleaseContext(prov, 0);
+		return;
+	}
+
+	if (!CryptSetKeyParam(ckey, KP_MODE, (BYTE *) &mode, 0)) {
+ 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
+			   "failed: %d", (int) GetLastError());
+		CryptDestroyKey(ckey);
+		CryptReleaseContext(prov, 0);
+		return;
+	}
+
+	os_memcpy(cypher, clear, 8);
+	dlen = 8;
+	if (!CryptEncrypt(ckey, 0, FALSE, 0, cypher, &dlen, 8)) {
+		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
+			   (int) GetLastError());
+		os_memset(cypher, 0, 8);
+	}
+
+	CryptDestroyKey(ckey);
+	CryptReleaseContext(prov, 0);
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return cryptoapi_hash_vector(CALG_MD5, 16, num_elem, addr, len, mac);
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return cryptoapi_hash_vector(CALG_SHA, 20, num_elem, addr, len, mac);
+}
+
+
+struct aes_context {
+	HCRYPTPROV prov;
+	HCRYPTKEY ckey;
+};
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+	struct aes_context *akey;
+	struct {
+		BLOBHEADER hdr;
+		DWORD len;
+		BYTE key[16];
+	} key_blob;
+	DWORD mode = CRYPT_MODE_ECB;
+
+	if (len != 16)
+		return NULL;
+
+	key_blob.hdr.bType = PLAINTEXTKEYBLOB;
+	key_blob.hdr.bVersion = CUR_BLOB_VERSION;
+	key_blob.hdr.reserved = 0;
+	key_blob.hdr.aiKeyAlg = CALG_AES_128;
+	key_blob.len = len;
+	os_memcpy(key_blob.key, key, len);
+
+	akey = os_zalloc(sizeof(*akey));
+	if (akey == NULL)
+		return NULL;
+
+	if (!CryptAcquireContext(&akey->prov, NULL,
+				 MS_ENH_RSA_AES_PROV, PROV_RSA_AES,
+				 CRYPT_VERIFYCONTEXT)) {
+ 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptAcquireContext failed: "
+			   "%d", (int) GetLastError());
+		os_free(akey);
+		return NULL;
+	}
+
+	if (!CryptImportKey(akey->prov, (BYTE *) &key_blob, sizeof(key_blob),
+			    0, 0, &akey->ckey)) {
+ 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptImportKey failed: %d",
+			   (int) GetLastError());
+		CryptReleaseContext(akey->prov, 0);
+		os_free(akey);
+		return NULL;
+	}
+
+	if (!CryptSetKeyParam(akey->ckey, KP_MODE, (BYTE *) &mode, 0)) {
+ 		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptSetKeyParam(KP_MODE) "
+			   "failed: %d", (int) GetLastError());
+		CryptDestroyKey(akey->ckey);
+		CryptReleaseContext(akey->prov, 0);
+		os_free(akey);
+		return NULL;
+	}
+
+	return akey;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+	struct aes_context *akey = ctx;
+	DWORD dlen;
+
+	os_memcpy(crypt, plain, 16);
+	dlen = 16;
+	if (!CryptEncrypt(akey->ckey, 0, FALSE, 0, crypt, &dlen, 16)) {
+		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptEncrypt failed: %d",
+			   (int) GetLastError());
+		os_memset(crypt, 0, 16);
+	}
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+	struct aes_context *akey = ctx;
+	if (akey) {
+		CryptDestroyKey(akey->ckey);
+		CryptReleaseContext(akey->prov, 0);
+		os_free(akey);
+	}
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+	return aes_encrypt_init(key, len);
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+	struct aes_context *akey = ctx;
+	DWORD dlen;
+
+	os_memcpy(plain, crypt, 16);
+	dlen = 16;
+
+	if (!CryptDecrypt(akey->ckey, 0, FALSE, 0, plain, &dlen)) {
+		wpa_printf(MSG_DEBUG, "CryptoAPI: CryptDecrypt failed: %d",
+			   (int) GetLastError());
+	}
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+	aes_encrypt_deinit(ctx);
+}
+
+
+struct crypto_hash {
+	enum crypto_hash_alg alg;
+	int error;
+	HCRYPTPROV prov;
+	HCRYPTHASH hash;
+	HCRYPTKEY key;
+};
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+				      size_t key_len)
+{
+	struct crypto_hash *ctx;
+	ALG_ID calg;
+	struct {
+		BLOBHEADER hdr;
+		DWORD len;
+		BYTE key[32];
+	} key_blob;
+
+	os_memset(&key_blob, 0, sizeof(key_blob));
+	switch (alg) {
+	case CRYPTO_HASH_ALG_MD5:
+		calg = CALG_MD5;
+		break;
+	case CRYPTO_HASH_ALG_SHA1:
+		calg = CALG_SHA;
+		break;
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		calg = CALG_HMAC;
+		key_blob.hdr.bType = PLAINTEXTKEYBLOB;
+		key_blob.hdr.bVersion = CUR_BLOB_VERSION;
+		key_blob.hdr.reserved = 0;
+		/*
+		 * Note: RC2 is not really used, but that can be used to
+		 * import HMAC keys of up to 16 byte long.
+		 * CRYPT_IPSEC_HMAC_KEY flag for CryptImportKey() is needed to
+		 * be able to import longer keys (HMAC-SHA1 uses 20-byte key).
+		 */
+		key_blob.hdr.aiKeyAlg = CALG_RC2;
+		key_blob.len = key_len;
+		if (key_len > sizeof(key_blob.key))
+			return NULL;
+		os_memcpy(key_blob.key, key, key_len);
+		break;
+	default:
+		return NULL;
+	}
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	ctx->alg = alg;
+
+	if (!CryptAcquireContext(&ctx->prov, NULL, NULL, PROV_RSA_FULL, 0)) {
+		cryptoapi_report_error("CryptAcquireContext");
+		os_free(ctx);
+		return NULL;
+	}
+
+	if (calg == CALG_HMAC) {
+#ifndef CRYPT_IPSEC_HMAC_KEY
+#define CRYPT_IPSEC_HMAC_KEY 0x00000100
+#endif
+		if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
+				    sizeof(key_blob), 0, CRYPT_IPSEC_HMAC_KEY,
+				    &ctx->key)) {
+			cryptoapi_report_error("CryptImportKey");
+			CryptReleaseContext(ctx->prov, 0);
+			os_free(ctx);
+			return NULL;
+		}
+	}
+
+	if (!CryptCreateHash(ctx->prov, calg, ctx->key, 0, &ctx->hash)) {
+		cryptoapi_report_error("CryptCreateHash");
+		CryptReleaseContext(ctx->prov, 0);
+		os_free(ctx);
+		return NULL;
+	}
+
+	if (calg == CALG_HMAC) {
+		HMAC_INFO info;
+		os_memset(&info, 0, sizeof(info));
+		switch (alg) {
+		case CRYPTO_HASH_ALG_HMAC_MD5:
+			info.HashAlgid = CALG_MD5;
+			break;
+		case CRYPTO_HASH_ALG_HMAC_SHA1:
+			info.HashAlgid = CALG_SHA;
+			break;
+		default:
+			/* unreachable */
+			break;
+		}
+
+		if (!CryptSetHashParam(ctx->hash, HP_HMAC_INFO, (BYTE *) &info,
+				       0)) {
+			cryptoapi_report_error("CryptSetHashParam");
+			CryptDestroyHash(ctx->hash);
+			CryptReleaseContext(ctx->prov, 0);
+			os_free(ctx);
+			return NULL;
+		}
+	}
+
+	return ctx;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+	if (ctx == NULL || ctx->error)
+		return;
+
+	if (!CryptHashData(ctx->hash, (BYTE *) data, len, 0)) {
+		cryptoapi_report_error("CryptHashData");
+		ctx->error = 1;
+	}
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+	int ret = 0;
+	DWORD hlen;
+
+	if (ctx == NULL)
+		return -2;
+
+	if (mac == NULL || len == NULL)
+		goto done;
+
+	if (ctx->error) {
+		ret = -2;
+		goto done;
+	}
+
+	hlen = *len;
+	if (!CryptGetHashParam(ctx->hash, HP_HASHVAL, mac, &hlen, 0)) {
+		cryptoapi_report_error("CryptGetHashParam");
+		ret = -2;
+	}
+	*len = hlen;
+
+done:
+	if (ctx->alg == CRYPTO_HASH_ALG_HMAC_SHA1 ||
+	    ctx->alg == CRYPTO_HASH_ALG_HMAC_MD5)
+		CryptDestroyKey(ctx->key);
+
+	os_free(ctx);
+
+	return ret;
+}
+
+
+struct crypto_cipher {
+	HCRYPTPROV prov;
+	HCRYPTKEY key;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len)
+{	
+	struct crypto_cipher *ctx;
+	struct {
+		BLOBHEADER hdr;
+		DWORD len;
+		BYTE key[32];
+	} key_blob;
+	DWORD mode = CRYPT_MODE_CBC;
+
+	key_blob.hdr.bType = PLAINTEXTKEYBLOB;
+	key_blob.hdr.bVersion = CUR_BLOB_VERSION;
+	key_blob.hdr.reserved = 0;
+	key_blob.len = key_len;
+	if (key_len > sizeof(key_blob.key))
+		return NULL;
+	os_memcpy(key_blob.key, key, key_len);
+
+	switch (alg) {
+	case CRYPTO_CIPHER_ALG_AES:
+		if (key_len == 32)
+			key_blob.hdr.aiKeyAlg = CALG_AES_256;
+		else if (key_len == 24)
+			key_blob.hdr.aiKeyAlg = CALG_AES_192;
+		else
+			key_blob.hdr.aiKeyAlg = CALG_AES_128;
+		break;
+	case CRYPTO_CIPHER_ALG_3DES:
+		key_blob.hdr.aiKeyAlg = CALG_3DES;
+		break;
+	case CRYPTO_CIPHER_ALG_DES:
+		key_blob.hdr.aiKeyAlg = CALG_DES;
+		break;
+	case CRYPTO_CIPHER_ALG_RC2:
+		key_blob.hdr.aiKeyAlg = CALG_RC2;
+		break;
+	case CRYPTO_CIPHER_ALG_RC4:
+		key_blob.hdr.aiKeyAlg = CALG_RC4;
+		break;
+	default:
+		return NULL;
+	}
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	if (!CryptAcquireContext(&ctx->prov, NULL, MS_ENH_RSA_AES_PROV,
+				 PROV_RSA_AES, CRYPT_VERIFYCONTEXT)) {
+		cryptoapi_report_error("CryptAcquireContext");
+		goto fail1;
+	}
+
+	if (!CryptImportKey(ctx->prov, (BYTE *) &key_blob,
+			    sizeof(key_blob), 0, 0, &ctx->key)) {
+ 		cryptoapi_report_error("CryptImportKey");
+		goto fail2;
+	}
+
+	if (!CryptSetKeyParam(ctx->key, KP_MODE, (BYTE *) &mode, 0)) {
+ 		cryptoapi_report_error("CryptSetKeyParam(KP_MODE)");
+		goto fail3;
+	}
+
+	if (iv && !CryptSetKeyParam(ctx->key, KP_IV, (BYTE *) iv, 0)) {
+ 		cryptoapi_report_error("CryptSetKeyParam(KP_IV)");
+		goto fail3;
+	}
+
+	return ctx;
+
+fail3:
+	CryptDestroyKey(ctx->key);
+fail2:
+	CryptReleaseContext(ctx->prov, 0);
+fail1:
+	os_free(ctx);
+	return NULL;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+			  u8 *crypt, size_t len)
+{
+	DWORD dlen;
+
+	os_memcpy(crypt, plain, len);
+	dlen = len;
+	if (!CryptEncrypt(ctx->key, 0, FALSE, 0, crypt, &dlen, len)) {
+ 		cryptoapi_report_error("CryptEncrypt");
+		os_memset(crypt, 0, len);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+			  u8 *plain, size_t len)
+{
+	DWORD dlen;
+
+	os_memcpy(plain, crypt, len);
+	dlen = len;
+	if (!CryptDecrypt(ctx->key, 0, FALSE, 0, plain, &dlen)) {
+ 		cryptoapi_report_error("CryptDecrypt");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+	CryptDestroyKey(ctx->key);
+	CryptReleaseContext(ctx->prov, 0);
+	os_free(ctx);
+}
+
+
+struct crypto_public_key {
+	HCRYPTPROV prov;
+	HCRYPTKEY rsa;
+};
+
+struct crypto_private_key {
+	HCRYPTPROV prov;
+	HCRYPTKEY rsa;
+};
+
+
+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
+{
+	/* Use crypto_public_key_from_cert() instead. */
+	return NULL;
+}
+
+
+struct crypto_private_key * crypto_private_key_import(const u8 *key,
+						      size_t len,
+						      const char *passwd)
+{
+	/* TODO */
+	return NULL;
+}
+
+
+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
+						       size_t len)
+{
+	struct crypto_public_key *pk;
+	PCCERT_CONTEXT cc;
+
+	pk = os_zalloc(sizeof(*pk));
+	if (pk == NULL)
+		return NULL;
+
+	cc = CertCreateCertificateContext(X509_ASN_ENCODING |
+					  PKCS_7_ASN_ENCODING, buf, len);
+	if (!cc) {
+ 		cryptoapi_report_error("CryptCreateCertificateContext");
+		os_free(pk);
+		return NULL;
+	}
+
+	if (!CryptAcquireContext(&pk->prov, NULL, MS_DEF_PROV, PROV_RSA_FULL,
+				 0)) {
+ 		cryptoapi_report_error("CryptAcquireContext");
+		os_free(pk);
+		CertFreeCertificateContext(cc);
+		return NULL;
+	}
+
+	if (!CryptImportPublicKeyInfo(pk->prov, X509_ASN_ENCODING |
+				      PKCS_7_ASN_ENCODING,
+				      &cc->pCertInfo->SubjectPublicKeyInfo,
+				      &pk->rsa)) {
+ 		cryptoapi_report_error("CryptImportPublicKeyInfo");
+		CryptReleaseContext(pk->prov, 0);
+		os_free(pk);
+		CertFreeCertificateContext(cc);
+		return NULL;
+	}
+
+	CertFreeCertificateContext(cc);
+
+	return pk;
+}
+
+
+int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
+					const u8 *in, size_t inlen,
+					u8 *out, size_t *outlen)
+{
+	DWORD clen;
+	u8 *tmp;
+	size_t i;
+
+	if (*outlen < inlen)
+		return -1;
+	tmp = malloc(*outlen);
+	if (tmp == NULL)
+		return -1;
+
+	os_memcpy(tmp, in, inlen);
+	clen = inlen;
+	if (!CryptEncrypt(key->rsa, 0, TRUE, 0, tmp, &clen, *outlen)) {
+		wpa_printf(MSG_DEBUG, "CryptoAPI: Failed to encrypt using "
+			   "public key: %d", (int) GetLastError());
+		os_free(tmp);
+		return -1;
+	}
+
+	*outlen = clen;
+
+	/* Reverse the output */
+	for (i = 0; i < *outlen; i++)
+		out[i] = tmp[*outlen - 1 - i];
+
+	os_free(tmp);
+
+	return 0;
+}
+
+
+int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
+				  const u8 *in, size_t inlen,
+				  u8 *out, size_t *outlen)
+{
+	/* TODO */
+	return -1;
+}
+
+
+void crypto_public_key_free(struct crypto_public_key *key)
+{
+	if (key) {
+		CryptDestroyKey(key->rsa);
+		CryptReleaseContext(key->prov, 0);
+		os_free(key);
+	}
+}
+
+
+void crypto_private_key_free(struct crypto_private_key *key)
+{
+	if (key) {
+		CryptDestroyKey(key->rsa);
+		CryptReleaseContext(key->prov, 0);
+		os_free(key);
+	}
+}
+
+
+int crypto_global_init(void)
+{
+	return mingw_load_crypto_func();
+}
+
+
+void crypto_global_deinit(void)
+{
+}
+
+
+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)
+{
+	/* TODO */
+	return -1;
+}
diff --git a/hostap/src/crypto/crypto_gnutls.c b/hostap/src/crypto/crypto_gnutls.c
new file mode 100644
index 0000000..0dfd54d
--- /dev/null
+++ b/hostap/src/crypto/crypto_gnutls.c
@@ -0,0 +1,299 @@
+/*
+ * WPA Supplicant / wrapper functions for libgcrypt
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <gcrypt.h>
+
+#include "common.h"
+#include "crypto.h"
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	gcry_md_hd_t hd;
+	unsigned char *p;
+	size_t i;
+
+	if (gcry_md_open(&hd, GCRY_MD_MD4, 0) != GPG_ERR_NO_ERROR)
+		return -1;
+	for (i = 0; i < num_elem; i++)
+		gcry_md_write(hd, addr[i], len[i]);
+	p = gcry_md_read(hd, GCRY_MD_MD4);
+	if (p)
+		memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD4));
+	gcry_md_close(hd);
+	return 0;
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+	gcry_cipher_hd_t hd;
+	u8 pkey[8], next, tmp;
+	int i;
+
+	/* 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;
+
+	gcry_cipher_open(&hd, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+	gcry_err_code(gcry_cipher_setkey(hd, pkey, 8));
+	gcry_cipher_encrypt(hd, cypher, 8, clear, 8);
+	gcry_cipher_close(hd);
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	gcry_md_hd_t hd;
+	unsigned char *p;
+	size_t i;
+
+	if (gcry_md_open(&hd, GCRY_MD_MD5, 0) != GPG_ERR_NO_ERROR)
+		return -1;
+	for (i = 0; i < num_elem; i++)
+		gcry_md_write(hd, addr[i], len[i]);
+	p = gcry_md_read(hd, GCRY_MD_MD5);
+	if (p)
+		memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_MD5));
+	gcry_md_close(hd);
+	return 0;
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	gcry_md_hd_t hd;
+	unsigned char *p;
+	size_t i;
+
+	if (gcry_md_open(&hd, GCRY_MD_SHA1, 0) != GPG_ERR_NO_ERROR)
+		return -1;
+	for (i = 0; i < num_elem; i++)
+		gcry_md_write(hd, addr[i], len[i]);
+	p = gcry_md_read(hd, GCRY_MD_SHA1);
+	if (p)
+		memcpy(mac, p, gcry_md_get_algo_dlen(GCRY_MD_SHA1));
+	gcry_md_close(hd);
+	return 0;
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+	gcry_cipher_hd_t hd;
+
+	if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
+	    GPG_ERR_NO_ERROR) {
+		printf("cipher open failed\n");
+		return NULL;
+	}
+	if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) {
+		printf("setkey failed\n");
+		gcry_cipher_close(hd);
+		return NULL;
+	}
+
+	return hd;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+	gcry_cipher_hd_t hd = ctx;
+	gcry_cipher_encrypt(hd, crypt, 16, plain, 16);
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+	gcry_cipher_hd_t hd = ctx;
+	gcry_cipher_close(hd);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+	gcry_cipher_hd_t hd;
+
+	if (gcry_cipher_open(&hd, GCRY_CIPHER_AES, GCRY_CIPHER_MODE_ECB, 0) !=
+	    GPG_ERR_NO_ERROR)
+		return NULL;
+	if (gcry_cipher_setkey(hd, key, len) != GPG_ERR_NO_ERROR) {
+		gcry_cipher_close(hd);
+		return NULL;
+	}
+
+	return hd;
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+	gcry_cipher_hd_t hd = ctx;
+	gcry_cipher_decrypt(hd, plain, 16, crypt, 16);
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+	gcry_cipher_hd_t hd = ctx;
+	gcry_cipher_close(hd);
+}
+
+
+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)
+{
+	gcry_mpi_t bn_base = NULL, bn_exp = NULL, bn_modulus = NULL,
+		bn_result = NULL;
+	int ret = -1;
+
+	if (gcry_mpi_scan(&bn_base, GCRYMPI_FMT_USG, base, base_len, NULL) !=
+	    GPG_ERR_NO_ERROR ||
+	    gcry_mpi_scan(&bn_exp, GCRYMPI_FMT_USG, power, power_len, NULL) !=
+	    GPG_ERR_NO_ERROR ||
+	    gcry_mpi_scan(&bn_modulus, GCRYMPI_FMT_USG, modulus, modulus_len,
+			  NULL) != GPG_ERR_NO_ERROR)
+		goto error;
+	bn_result = gcry_mpi_new(modulus_len * 8);
+
+	gcry_mpi_powm(bn_result, bn_base, bn_exp, bn_modulus);
+
+	if (gcry_mpi_print(GCRYMPI_FMT_USG, result, *result_len, result_len,
+			   bn_result) != GPG_ERR_NO_ERROR)
+		goto error;
+
+	ret = 0;
+
+error:
+	gcry_mpi_release(bn_base);
+	gcry_mpi_release(bn_exp);
+	gcry_mpi_release(bn_modulus);
+	gcry_mpi_release(bn_result);
+	return ret;
+}
+
+
+struct crypto_cipher {
+	gcry_cipher_hd_t enc;
+	gcry_cipher_hd_t dec;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len)
+{
+	struct crypto_cipher *ctx;
+	gcry_error_t res;
+	enum gcry_cipher_algos a;
+	int ivlen;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	switch (alg) {
+	case CRYPTO_CIPHER_ALG_RC4:
+		a = GCRY_CIPHER_ARCFOUR;
+		res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_STREAM,
+				       0);
+		gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_STREAM, 0);
+		break;
+	case CRYPTO_CIPHER_ALG_AES:
+		if (key_len == 24)
+			a = GCRY_CIPHER_AES192;
+		else if (key_len == 32)
+			a = GCRY_CIPHER_AES256;
+		else
+			a = GCRY_CIPHER_AES;
+		res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
+		gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
+		break;
+	case CRYPTO_CIPHER_ALG_3DES:
+		a = GCRY_CIPHER_3DES;
+		res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
+		gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
+		break;
+	case CRYPTO_CIPHER_ALG_DES:
+		a = GCRY_CIPHER_DES;
+		res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
+		gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
+		break;
+	case CRYPTO_CIPHER_ALG_RC2:
+		if (key_len == 5)
+			a = GCRY_CIPHER_RFC2268_40;
+		else
+			a = GCRY_CIPHER_RFC2268_128;
+		res = gcry_cipher_open(&ctx->enc, a, GCRY_CIPHER_MODE_CBC, 0);
+		gcry_cipher_open(&ctx->dec, a, GCRY_CIPHER_MODE_CBC, 0);
+		break;
+	default:
+		os_free(ctx);
+		return NULL;
+	}
+
+	if (res != GPG_ERR_NO_ERROR) {
+		os_free(ctx);
+		return NULL;
+	}
+
+	if (gcry_cipher_setkey(ctx->enc, key, key_len) != GPG_ERR_NO_ERROR ||
+	    gcry_cipher_setkey(ctx->dec, key, key_len) != GPG_ERR_NO_ERROR) {
+		gcry_cipher_close(ctx->enc);
+		gcry_cipher_close(ctx->dec);
+		os_free(ctx);
+		return NULL;
+	}
+
+	ivlen = gcry_cipher_get_algo_blklen(a);
+	if (gcry_cipher_setiv(ctx->enc, iv, ivlen) != GPG_ERR_NO_ERROR ||
+	    gcry_cipher_setiv(ctx->dec, iv, ivlen) != GPG_ERR_NO_ERROR) {
+		gcry_cipher_close(ctx->enc);
+		gcry_cipher_close(ctx->dec);
+		os_free(ctx);
+		return NULL;
+	}
+
+	return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+			  u8 *crypt, size_t len)
+{
+	if (gcry_cipher_encrypt(ctx->enc, crypt, len, plain, len) !=
+	    GPG_ERR_NO_ERROR)
+		return -1;
+	return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+			  u8 *plain, size_t len)
+{
+	if (gcry_cipher_decrypt(ctx->dec, plain, len, crypt, len) !=
+	    GPG_ERR_NO_ERROR)
+		return -1;
+	return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+	gcry_cipher_close(ctx->enc);
+	gcry_cipher_close(ctx->dec);
+	os_free(ctx);
+}
diff --git a/hostap/src/crypto/crypto_internal-cipher.c b/hostap/src/crypto/crypto_internal-cipher.c
new file mode 100644
index 0000000..ad0930a
--- /dev/null
+++ b/hostap/src/crypto/crypto_internal-cipher.c
@@ -0,0 +1,243 @@
+/*
+ * Crypto wrapper for internal crypto implementation - Cipher wrappers
+ * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+#include "aes.h"
+#include "des_i.h"
+
+
+struct crypto_cipher {
+	enum crypto_cipher_alg alg;
+	union {
+		struct {
+			size_t used_bytes;
+			u8 key[16];
+			size_t keylen;
+		} rc4;
+		struct {
+			u8 cbc[32];
+			void *ctx_enc;
+			void *ctx_dec;
+		} aes;
+		struct {
+			struct des3_key_s key;
+			u8 cbc[8];
+		} des3;
+		struct {
+			u32 ek[32];
+			u32 dk[32];
+			u8 cbc[8];
+		} des;
+	} u;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len)
+{
+	struct crypto_cipher *ctx;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	ctx->alg = alg;
+
+	switch (alg) {
+	case CRYPTO_CIPHER_ALG_RC4:
+		if (key_len > sizeof(ctx->u.rc4.key)) {
+			os_free(ctx);
+			return NULL;
+		}
+		ctx->u.rc4.keylen = key_len;
+		os_memcpy(ctx->u.rc4.key, key, key_len);
+		break;
+	case CRYPTO_CIPHER_ALG_AES:
+		ctx->u.aes.ctx_enc = aes_encrypt_init(key, key_len);
+		if (ctx->u.aes.ctx_enc == NULL) {
+			os_free(ctx);
+			return NULL;
+		}
+		ctx->u.aes.ctx_dec = aes_decrypt_init(key, key_len);
+		if (ctx->u.aes.ctx_dec == NULL) {
+			aes_encrypt_deinit(ctx->u.aes.ctx_enc);
+			os_free(ctx);
+			return NULL;
+		}
+		os_memcpy(ctx->u.aes.cbc, iv, AES_BLOCK_SIZE);
+		break;
+	case CRYPTO_CIPHER_ALG_3DES:
+		if (key_len != 24) {
+			os_free(ctx);
+			return NULL;
+		}
+		des3_key_setup(key, &ctx->u.des3.key);
+		os_memcpy(ctx->u.des3.cbc, iv, 8);
+		break;
+	case CRYPTO_CIPHER_ALG_DES:
+		if (key_len != 8) {
+			os_free(ctx);
+			return NULL;
+		}
+		des_key_setup(key, ctx->u.des.ek, ctx->u.des.dk);
+		os_memcpy(ctx->u.des.cbc, iv, 8);
+		break;
+	default:
+		os_free(ctx);
+		return NULL;
+	}
+
+	return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+			  u8 *crypt, size_t len)
+{
+	size_t i, j, blocks;
+
+	switch (ctx->alg) {
+	case CRYPTO_CIPHER_ALG_RC4:
+		if (plain != crypt)
+			os_memcpy(crypt, plain, len);
+		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
+			 ctx->u.rc4.used_bytes, crypt, len);
+		ctx->u.rc4.used_bytes += len;
+		break;
+	case CRYPTO_CIPHER_ALG_AES:
+		if (len % AES_BLOCK_SIZE)
+			return -1;
+		blocks = len / AES_BLOCK_SIZE;
+		for (i = 0; i < blocks; i++) {
+			for (j = 0; j < AES_BLOCK_SIZE; j++)
+				ctx->u.aes.cbc[j] ^= plain[j];
+			aes_encrypt(ctx->u.aes.ctx_enc, ctx->u.aes.cbc,
+				    ctx->u.aes.cbc);
+			os_memcpy(crypt, ctx->u.aes.cbc, AES_BLOCK_SIZE);
+			plain += AES_BLOCK_SIZE;
+			crypt += AES_BLOCK_SIZE;
+		}
+		break;
+	case CRYPTO_CIPHER_ALG_3DES:
+		if (len % 8)
+			return -1;
+		blocks = len / 8;
+		for (i = 0; i < blocks; i++) {
+			for (j = 0; j < 8; j++)
+				ctx->u.des3.cbc[j] ^= plain[j];
+			des3_encrypt(ctx->u.des3.cbc, &ctx->u.des3.key,
+				     ctx->u.des3.cbc);
+			os_memcpy(crypt, ctx->u.des3.cbc, 8);
+			plain += 8;
+			crypt += 8;
+		}
+		break;
+	case CRYPTO_CIPHER_ALG_DES:
+		if (len % 8)
+			return -1;
+		blocks = len / 8;
+		for (i = 0; i < blocks; i++) {
+			for (j = 0; j < 8; j++)
+				ctx->u.des3.cbc[j] ^= plain[j];
+			des_block_encrypt(ctx->u.des.cbc, ctx->u.des.ek,
+					  ctx->u.des.cbc);
+			os_memcpy(crypt, ctx->u.des.cbc, 8);
+			plain += 8;
+			crypt += 8;
+		}
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+			  u8 *plain, size_t len)
+{
+	size_t i, j, blocks;
+	u8 tmp[32];
+
+	switch (ctx->alg) {
+	case CRYPTO_CIPHER_ALG_RC4:
+		if (plain != crypt)
+			os_memcpy(plain, crypt, len);
+		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
+			 ctx->u.rc4.used_bytes, plain, len);
+		ctx->u.rc4.used_bytes += len;
+		break;
+	case CRYPTO_CIPHER_ALG_AES:
+		if (len % AES_BLOCK_SIZE)
+			return -1;
+		blocks = len / AES_BLOCK_SIZE;
+		for (i = 0; i < blocks; i++) {
+			os_memcpy(tmp, crypt, AES_BLOCK_SIZE);
+			aes_decrypt(ctx->u.aes.ctx_dec, crypt, plain);
+			for (j = 0; j < AES_BLOCK_SIZE; j++)
+				plain[j] ^= ctx->u.aes.cbc[j];
+			os_memcpy(ctx->u.aes.cbc, tmp, AES_BLOCK_SIZE);
+			plain += AES_BLOCK_SIZE;
+			crypt += AES_BLOCK_SIZE;
+		}
+		break;
+	case CRYPTO_CIPHER_ALG_3DES:
+		if (len % 8)
+			return -1;
+		blocks = len / 8;
+		for (i = 0; i < blocks; i++) {
+			os_memcpy(tmp, crypt, 8);
+			des3_decrypt(crypt, &ctx->u.des3.key, plain);
+			for (j = 0; j < 8; j++)
+				plain[j] ^= ctx->u.des3.cbc[j];
+			os_memcpy(ctx->u.des3.cbc, tmp, 8);
+			plain += 8;
+			crypt += 8;
+		}
+		break;
+	case CRYPTO_CIPHER_ALG_DES:
+		if (len % 8)
+			return -1;
+		blocks = len / 8;
+		for (i = 0; i < blocks; i++) {
+			os_memcpy(tmp, crypt, 8);
+			des_block_decrypt(crypt, ctx->u.des.dk, plain);
+			for (j = 0; j < 8; j++)
+				plain[j] ^= ctx->u.des.cbc[j];
+			os_memcpy(ctx->u.des.cbc, tmp, 8);
+			plain += 8;
+			crypt += 8;
+		}
+		break;
+	default:
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+	switch (ctx->alg) {
+	case CRYPTO_CIPHER_ALG_AES:
+		aes_encrypt_deinit(ctx->u.aes.ctx_enc);
+		aes_decrypt_deinit(ctx->u.aes.ctx_dec);
+		break;
+	case CRYPTO_CIPHER_ALG_3DES:
+		break;
+	default:
+		break;
+	}
+	os_free(ctx);
+}
diff --git a/hostap/src/crypto/crypto_internal-modexp.c b/hostap/src/crypto/crypto_internal-modexp.c
new file mode 100644
index 0000000..9dcabb9
--- /dev/null
+++ b/hostap/src/crypto/crypto_internal-modexp.c
@@ -0,0 +1,49 @@
+/*
+ * Crypto wrapper for internal crypto implementation - modexp
+ * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "tls/bignum.h"
+#include "crypto.h"
+
+
+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)
+{
+	struct bignum *bn_base, *bn_exp, *bn_modulus, *bn_result;
+	int ret = -1;
+
+	bn_base = bignum_init();
+	bn_exp = bignum_init();
+	bn_modulus = bignum_init();
+	bn_result = bignum_init();
+
+	if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL ||
+	    bn_result == NULL)
+		goto error;
+
+	if (bignum_set_unsigned_bin(bn_base, base, base_len) < 0 ||
+	    bignum_set_unsigned_bin(bn_exp, power, power_len) < 0 ||
+	    bignum_set_unsigned_bin(bn_modulus, modulus, modulus_len) < 0)
+		goto error;
+
+	if (bignum_exptmod(bn_base, bn_exp, bn_modulus, bn_result) < 0)
+		goto error;
+
+	ret = bignum_get_unsigned_bin(bn_result, result, result_len);
+
+error:
+	bignum_deinit(bn_base);
+	bignum_deinit(bn_exp);
+	bignum_deinit(bn_modulus);
+	bignum_deinit(bn_result);
+	return ret;
+}
diff --git a/hostap/src/crypto/crypto_internal-rsa.c b/hostap/src/crypto/crypto_internal-rsa.c
new file mode 100644
index 0000000..54209fa
--- /dev/null
+++ b/hostap/src/crypto/crypto_internal-rsa.c
@@ -0,0 +1,108 @@
+/*
+ * Crypto wrapper for internal crypto implementation - RSA parts
+ * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+#include "tls/rsa.h"
+#include "tls/pkcs1.h"
+#include "tls/pkcs8.h"
+
+/* Dummy structures; these are just typecast to struct crypto_rsa_key */
+struct crypto_public_key;
+struct crypto_private_key;
+
+
+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
+{
+	return (struct crypto_public_key *)
+		crypto_rsa_import_public_key(key, len);
+}
+
+
+struct crypto_private_key * crypto_private_key_import(const u8 *key,
+						      size_t len,
+						      const char *passwd)
+{
+	struct crypto_private_key *res;
+
+	/* First, check for possible PKCS #8 encoding */
+	res = pkcs8_key_import(key, len);
+	if (res)
+		return res;
+
+	if (passwd) {
+		/* Try to parse as encrypted PKCS #8 */
+		res = pkcs8_enc_key_import(key, len, passwd);
+		if (res)
+			return res;
+	}
+
+	/* Not PKCS#8, so try to import PKCS #1 encoded RSA private key */
+	wpa_printf(MSG_DEBUG, "Trying to parse PKCS #1 encoded RSA private "
+		   "key");
+	return (struct crypto_private_key *)
+		crypto_rsa_import_private_key(key, len);
+}
+
+
+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
+						       size_t len)
+{
+	/* No X.509 support in crypto_internal.c */
+	return NULL;
+}
+
+
+int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
+					const u8 *in, size_t inlen,
+					u8 *out, size_t *outlen)
+{
+	return pkcs1_encrypt(2, (struct crypto_rsa_key *) key,
+			     0, in, inlen, out, outlen);
+}
+
+
+int crypto_private_key_decrypt_pkcs1_v15(struct crypto_private_key *key,
+					 const u8 *in, size_t inlen,
+					 u8 *out, size_t *outlen)
+{
+	return pkcs1_v15_private_key_decrypt((struct crypto_rsa_key *) key,
+					     in, inlen, out, outlen);
+}
+
+
+int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
+				  const u8 *in, size_t inlen,
+				  u8 *out, size_t *outlen)
+{
+	return pkcs1_encrypt(1, (struct crypto_rsa_key *) key,
+			     1, in, inlen, out, outlen);
+}
+
+
+void crypto_public_key_free(struct crypto_public_key *key)
+{
+	crypto_rsa_free((struct crypto_rsa_key *) key);
+}
+
+
+void crypto_private_key_free(struct crypto_private_key *key)
+{
+	crypto_rsa_free((struct crypto_rsa_key *) key);
+}
+
+
+int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
+				    const u8 *crypt, size_t crypt_len,
+				    u8 *plain, size_t *plain_len)
+{
+	return pkcs1_decrypt_public_key((struct crypto_rsa_key *) key,
+					crypt, crypt_len, plain, plain_len);
+}
diff --git a/hostap/src/crypto/crypto_internal.c b/hostap/src/crypto/crypto_internal.c
new file mode 100644
index 0000000..f3602da
--- /dev/null
+++ b/hostap/src/crypto/crypto_internal.c
@@ -0,0 +1,275 @@
+/*
+ * Crypto wrapper for internal crypto implementation
+ * Copyright (c) 2006-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+#include "sha256_i.h"
+#include "sha1_i.h"
+#include "md5_i.h"
+
+struct crypto_hash {
+	enum crypto_hash_alg alg;
+	union {
+		struct MD5Context md5;
+		struct SHA1Context sha1;
+#ifdef CONFIG_SHA256
+		struct sha256_state sha256;
+#endif /* CONFIG_SHA256 */
+	} u;
+	u8 key[64];
+	size_t key_len;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+				      size_t key_len)
+{
+	struct crypto_hash *ctx;
+	u8 k_pad[64];
+	u8 tk[32];
+	size_t i;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	ctx->alg = alg;
+
+	switch (alg) {
+	case CRYPTO_HASH_ALG_MD5:
+		MD5Init(&ctx->u.md5);
+		break;
+	case CRYPTO_HASH_ALG_SHA1:
+		SHA1Init(&ctx->u.sha1);
+		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_SHA256:
+		sha256_init(&ctx->u.sha256);
+		break;
+#endif /* CONFIG_SHA256 */
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		if (key_len > sizeof(k_pad)) {
+			MD5Init(&ctx->u.md5);
+			MD5Update(&ctx->u.md5, key, key_len);
+			MD5Final(tk, &ctx->u.md5);
+			key = tk;
+			key_len = 16;
+		}
+		os_memcpy(ctx->key, key, key_len);
+		ctx->key_len = key_len;
+
+		os_memcpy(k_pad, key, key_len);
+		if (key_len < sizeof(k_pad))
+			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+		for (i = 0; i < sizeof(k_pad); i++)
+			k_pad[i] ^= 0x36;
+		MD5Init(&ctx->u.md5);
+		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
+		break;
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		if (key_len > sizeof(k_pad)) {
+			SHA1Init(&ctx->u.sha1);
+			SHA1Update(&ctx->u.sha1, key, key_len);
+			SHA1Final(tk, &ctx->u.sha1);
+			key = tk;
+			key_len = 20;
+		}
+		os_memcpy(ctx->key, key, key_len);
+		ctx->key_len = key_len;
+
+		os_memcpy(k_pad, key, key_len);
+		if (key_len < sizeof(k_pad))
+			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+		for (i = 0; i < sizeof(k_pad); i++)
+			k_pad[i] ^= 0x36;
+		SHA1Init(&ctx->u.sha1);
+		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
+		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		if (key_len > sizeof(k_pad)) {
+			sha256_init(&ctx->u.sha256);
+			sha256_process(&ctx->u.sha256, key, key_len);
+			sha256_done(&ctx->u.sha256, tk);
+			key = tk;
+			key_len = 32;
+		}
+		os_memcpy(ctx->key, key, key_len);
+		ctx->key_len = key_len;
+
+		os_memcpy(k_pad, key, key_len);
+		if (key_len < sizeof(k_pad))
+			os_memset(k_pad + key_len, 0, sizeof(k_pad) - key_len);
+		for (i = 0; i < sizeof(k_pad); i++)
+			k_pad[i] ^= 0x36;
+		sha256_init(&ctx->u.sha256);
+		sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
+		break;
+#endif /* CONFIG_SHA256 */
+	default:
+		os_free(ctx);
+		return NULL;
+	}
+
+	return ctx;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+	if (ctx == NULL)
+		return;
+
+	switch (ctx->alg) {
+	case CRYPTO_HASH_ALG_MD5:
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		MD5Update(&ctx->u.md5, data, len);
+		break;
+	case CRYPTO_HASH_ALG_SHA1:
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		SHA1Update(&ctx->u.sha1, data, len);
+		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_SHA256:
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		sha256_process(&ctx->u.sha256, data, len);
+		break;
+#endif /* CONFIG_SHA256 */
+	default:
+		break;
+	}
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+	u8 k_pad[64];
+	size_t i;
+
+	if (ctx == NULL)
+		return -2;
+
+	if (mac == NULL || len == NULL) {
+		os_free(ctx);
+		return 0;
+	}
+
+	switch (ctx->alg) {
+	case CRYPTO_HASH_ALG_MD5:
+		if (*len < 16) {
+			*len = 16;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 16;
+		MD5Final(mac, &ctx->u.md5);
+		break;
+	case CRYPTO_HASH_ALG_SHA1:
+		if (*len < 20) {
+			*len = 20;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 20;
+		SHA1Final(mac, &ctx->u.sha1);
+		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_SHA256:
+		if (*len < 32) {
+			*len = 32;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 32;
+		sha256_done(&ctx->u.sha256, mac);
+		break;
+#endif /* CONFIG_SHA256 */
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		if (*len < 16) {
+			*len = 16;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 16;
+
+		MD5Final(mac, &ctx->u.md5);
+
+		os_memcpy(k_pad, ctx->key, ctx->key_len);
+		os_memset(k_pad + ctx->key_len, 0,
+			  sizeof(k_pad) - ctx->key_len);
+		for (i = 0; i < sizeof(k_pad); i++)
+			k_pad[i] ^= 0x5c;
+		MD5Init(&ctx->u.md5);
+		MD5Update(&ctx->u.md5, k_pad, sizeof(k_pad));
+		MD5Update(&ctx->u.md5, mac, 16);
+		MD5Final(mac, &ctx->u.md5);
+		break;
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		if (*len < 20) {
+			*len = 20;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 20;
+
+		SHA1Final(mac, &ctx->u.sha1);
+
+		os_memcpy(k_pad, ctx->key, ctx->key_len);
+		os_memset(k_pad + ctx->key_len, 0,
+			  sizeof(k_pad) - ctx->key_len);
+		for (i = 0; i < sizeof(k_pad); i++)
+			k_pad[i] ^= 0x5c;
+		SHA1Init(&ctx->u.sha1);
+		SHA1Update(&ctx->u.sha1, k_pad, sizeof(k_pad));
+		SHA1Update(&ctx->u.sha1, mac, 20);
+		SHA1Final(mac, &ctx->u.sha1);
+		break;
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		if (*len < 32) {
+			*len = 32;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 32;
+
+		sha256_done(&ctx->u.sha256, mac);
+
+		os_memcpy(k_pad, ctx->key, ctx->key_len);
+		os_memset(k_pad + ctx->key_len, 0,
+			  sizeof(k_pad) - ctx->key_len);
+		for (i = 0; i < sizeof(k_pad); i++)
+			k_pad[i] ^= 0x5c;
+		sha256_init(&ctx->u.sha256);
+		sha256_process(&ctx->u.sha256, k_pad, sizeof(k_pad));
+		sha256_process(&ctx->u.sha256, mac, 32);
+		sha256_done(&ctx->u.sha256, mac);
+		break;
+#endif /* CONFIG_SHA256 */
+	default:
+		os_free(ctx);
+		return -1;
+	}
+
+	os_free(ctx);
+
+	return 0;
+}
+
+
+int crypto_global_init(void)
+{
+	return 0;
+}
+
+
+void crypto_global_deinit(void)
+{
+}
diff --git a/hostap/src/crypto/crypto_libtomcrypt.c b/hostap/src/crypto/crypto_libtomcrypt.c
new file mode 100644
index 0000000..a55edd1
--- /dev/null
+++ b/hostap/src/crypto/crypto_libtomcrypt.c
@@ -0,0 +1,726 @@
+/*
+ * WPA Supplicant / Crypto wrapper for LibTomCrypt (for internal TLSv1)
+ * Copyright (c) 2005-2006, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <tomcrypt.h>
+
+#include "common.h"
+#include "crypto.h"
+
+#ifndef mp_init_multi
+#define mp_init_multi                ltc_init_multi
+#define mp_clear_multi               ltc_deinit_multi
+#define mp_unsigned_bin_size(a)      ltc_mp.unsigned_size(a)
+#define mp_to_unsigned_bin(a, b)     ltc_mp.unsigned_write(a, b)
+#define mp_read_unsigned_bin(a, b, c) ltc_mp.unsigned_read(a, b, c)
+#define mp_exptmod(a,b,c,d)          ltc_mp.exptmod(a,b,c,d)
+#endif
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	hash_state md;
+	size_t i;
+
+	md4_init(&md);
+	for (i = 0; i < num_elem; i++)
+		md4_process(&md, addr[i], len[i]);
+	md4_done(&md, mac);
+	return 0;
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+	u8 pkey[8], next, tmp;
+	int i;
+	symmetric_key skey;
+
+	/* Add parity bits to the key */
+	next = 0;
+	for (i = 0; i < 7; i++) {
+		tmp = key[i];
+		pkey[i] = (tmp >> i) | next | 1;
+		next = tmp << (7 - i);
+	}
+	pkey[i] = next | 1;
+
+	des_setup(pkey, 8, 0, &skey);
+	des_ecb_encrypt(clear, cypher, &skey);
+	des_done(&skey);
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	hash_state md;
+	size_t i;
+
+	md5_init(&md);
+	for (i = 0; i < num_elem; i++)
+		md5_process(&md, addr[i], len[i]);
+	md5_done(&md, mac);
+	return 0;
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	hash_state md;
+	size_t i;
+
+	sha1_init(&md);
+	for (i = 0; i < num_elem; i++)
+		sha1_process(&md, addr[i], len[i]);
+	sha1_done(&md, mac);
+	return 0;
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+	symmetric_key *skey;
+	skey = os_malloc(sizeof(*skey));
+	if (skey == NULL)
+		return NULL;
+	if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
+		os_free(skey);
+		return NULL;
+	}
+	return skey;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+	symmetric_key *skey = ctx;
+	aes_ecb_encrypt(plain, crypt, skey);
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+	symmetric_key *skey = ctx;
+	aes_done(skey);
+	os_free(skey);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+	symmetric_key *skey;
+	skey = os_malloc(sizeof(*skey));
+	if (skey == NULL)
+		return NULL;
+	if (aes_setup(key, len, 0, skey) != CRYPT_OK) {
+		os_free(skey);
+		return NULL;
+	}
+	return skey;
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+	symmetric_key *skey = ctx;
+	aes_ecb_encrypt(plain, (u8 *) crypt, skey);
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+	symmetric_key *skey = ctx;
+	aes_done(skey);
+	os_free(skey);
+}
+
+
+struct crypto_hash {
+	enum crypto_hash_alg alg;
+	int error;
+	union {
+		hash_state md;
+		hmac_state hmac;
+	} u;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+				      size_t key_len)
+{
+	struct crypto_hash *ctx;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	ctx->alg = alg;
+
+	switch (alg) {
+	case CRYPTO_HASH_ALG_MD5:
+		if (md5_init(&ctx->u.md) != CRYPT_OK)
+			goto fail;
+		break;
+	case CRYPTO_HASH_ALG_SHA1:
+		if (sha1_init(&ctx->u.md) != CRYPT_OK)
+			goto fail;
+		break;
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		if (hmac_init(&ctx->u.hmac, find_hash("md5"), key, key_len) !=
+		    CRYPT_OK)
+			goto fail;
+		break;
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		if (hmac_init(&ctx->u.hmac, find_hash("sha1"), key, key_len) !=
+		    CRYPT_OK)
+			goto fail;
+		break;
+	default:
+		goto fail;
+	}
+
+	return ctx;
+
+fail:
+	os_free(ctx);
+	return NULL;
+}
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+	if (ctx == NULL || ctx->error)
+		return;
+
+	switch (ctx->alg) {
+	case CRYPTO_HASH_ALG_MD5:
+		ctx->error = md5_process(&ctx->u.md, data, len) != CRYPT_OK;
+		break;
+	case CRYPTO_HASH_ALG_SHA1:
+		ctx->error = sha1_process(&ctx->u.md, data, len) != CRYPT_OK;
+		break;
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		ctx->error = hmac_process(&ctx->u.hmac, data, len) != CRYPT_OK;
+		break;
+	}
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+	int ret = 0;
+	unsigned long clen;
+
+	if (ctx == NULL)
+		return -2;
+
+	if (mac == NULL || len == NULL) {
+		os_free(ctx);
+		return 0;
+	}
+
+	if (ctx->error) {
+		os_free(ctx);
+		return -2;
+	}
+
+	switch (ctx->alg) {
+	case CRYPTO_HASH_ALG_MD5:
+		if (*len < 16) {
+			*len = 16;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 16;
+		if (md5_done(&ctx->u.md, mac) != CRYPT_OK)
+			ret = -2;
+		break;
+	case CRYPTO_HASH_ALG_SHA1:
+		if (*len < 20) {
+			*len = 20;
+			os_free(ctx);
+			return -1;
+		}
+		*len = 20;
+		if (sha1_done(&ctx->u.md, mac) != CRYPT_OK)
+			ret = -2;
+		break;
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		if (*len < 20) {
+			*len = 20;
+			os_free(ctx);
+			return -1;
+		}
+		/* continue */
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		if (*len < 16) {
+			*len = 16;
+			os_free(ctx);
+			return -1;
+		}
+		clen = *len;
+		if (hmac_done(&ctx->u.hmac, mac, &clen) != CRYPT_OK) {
+			os_free(ctx);
+			return -1;
+		}
+		*len = clen;
+		break;
+	default:
+		ret = -2;
+		break;
+	}
+
+	os_free(ctx);
+
+	return ret;
+}
+
+
+struct crypto_cipher {
+	int rc4;
+	union {
+		symmetric_CBC cbc;
+		struct {
+			size_t used_bytes;
+			u8 key[16];
+			size_t keylen;
+		} rc4;
+	} u;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len)
+{	
+	struct crypto_cipher *ctx;
+	int idx, res, rc4 = 0;
+
+	switch (alg) {
+	case CRYPTO_CIPHER_ALG_AES:
+		idx = find_cipher("aes");
+		break;
+	case CRYPTO_CIPHER_ALG_3DES:
+		idx = find_cipher("3des");
+		break;
+	case CRYPTO_CIPHER_ALG_DES:
+		idx = find_cipher("des");
+		break;
+	case CRYPTO_CIPHER_ALG_RC2:
+		idx = find_cipher("rc2");
+		break;
+	case CRYPTO_CIPHER_ALG_RC4:
+		idx = -1;
+		rc4 = 1;
+		break;
+	default:
+		return NULL;
+	}
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	if (rc4) {
+		ctx->rc4 = 1;
+		if (key_len > sizeof(ctx->u.rc4.key)) {
+			os_free(ctx);
+			return NULL;
+		}
+		ctx->u.rc4.keylen = key_len;
+		os_memcpy(ctx->u.rc4.key, key, key_len);
+	} else {
+		res = cbc_start(idx, iv, key, key_len, 0, &ctx->u.cbc);
+		if (res != CRYPT_OK) {
+			wpa_printf(MSG_DEBUG, "LibTomCrypt: Cipher start "
+				   "failed: %s", error_to_string(res));
+			os_free(ctx);
+			return NULL;
+		}
+	}
+
+	return ctx;
+}
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+			  u8 *crypt, size_t len)
+{
+	int res;
+
+	if (ctx->rc4) {
+		if (plain != crypt)
+			os_memcpy(crypt, plain, len);
+		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
+			 ctx->u.rc4.used_bytes, crypt, len);
+		ctx->u.rc4.used_bytes += len;
+		return 0;
+	}
+
+	res = cbc_encrypt(plain, crypt, len, &ctx->u.cbc);
+	if (res != CRYPT_OK) {
+		wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC encryption "
+			   "failed: %s", error_to_string(res));
+		return -1;
+	}
+	return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+			  u8 *plain, size_t len)
+{
+	int res;
+
+	if (ctx->rc4) {
+		if (plain != crypt)
+			os_memcpy(plain, crypt, len);
+		rc4_skip(ctx->u.rc4.key, ctx->u.rc4.keylen,
+			 ctx->u.rc4.used_bytes, plain, len);
+		ctx->u.rc4.used_bytes += len;
+		return 0;
+	}
+
+	res = cbc_decrypt(crypt, plain, len, &ctx->u.cbc);
+	if (res != CRYPT_OK) {
+		wpa_printf(MSG_DEBUG, "LibTomCrypt: CBC decryption "
+			   "failed: %s", error_to_string(res));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+	if (!ctx->rc4)
+		cbc_done(&ctx->u.cbc);
+	os_free(ctx);
+}
+
+
+struct crypto_public_key {
+	rsa_key rsa;
+};
+
+struct crypto_private_key {
+	rsa_key rsa;
+};
+
+
+struct crypto_public_key * crypto_public_key_import(const u8 *key, size_t len)
+{
+	int res;
+	struct crypto_public_key *pk;
+
+	pk = os_zalloc(sizeof(*pk));
+	if (pk == NULL)
+		return NULL;
+
+	res = rsa_import(key, len, &pk->rsa);
+	if (res != CRYPT_OK) {
+		wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
+			   "public key (res=%d '%s')",
+			   res, error_to_string(res));
+		os_free(pk);
+		return NULL;
+	}
+
+	if (pk->rsa.type != PK_PUBLIC) {
+		wpa_printf(MSG_ERROR, "LibTomCrypt: Public key was not of "
+			   "correct type");
+		rsa_free(&pk->rsa);
+		os_free(pk);
+		return NULL;
+	}
+
+	return pk;
+}
+
+
+struct crypto_private_key * crypto_private_key_import(const u8 *key,
+						      size_t len,
+						      const char *passwd)
+{
+	int res;
+	struct crypto_private_key *pk;
+
+	pk = os_zalloc(sizeof(*pk));
+	if (pk == NULL)
+		return NULL;
+
+	res = rsa_import(key, len, &pk->rsa);
+	if (res != CRYPT_OK) {
+		wpa_printf(MSG_ERROR, "LibTomCrypt: Failed to import "
+			   "private key (res=%d '%s')",
+			   res, error_to_string(res));
+		os_free(pk);
+		return NULL;
+	}
+
+	if (pk->rsa.type != PK_PRIVATE) {
+		wpa_printf(MSG_ERROR, "LibTomCrypt: Private key was not of "
+			   "correct type");
+		rsa_free(&pk->rsa);
+		os_free(pk);
+		return NULL;
+	}
+
+	return pk;
+}
+
+
+struct crypto_public_key * crypto_public_key_from_cert(const u8 *buf,
+						       size_t len)
+{
+	/* No X.509 support in LibTomCrypt */
+	return NULL;
+}
+
+
+static int pkcs1_generate_encryption_block(u8 block_type, size_t modlen,
+					   const u8 *in, size_t inlen,
+					   u8 *out, size_t *outlen)
+{
+	size_t ps_len;
+	u8 *pos;
+
+	/*
+	 * PKCS #1 v1.5, 8.1:
+	 *
+	 * EB = 00 || BT || PS || 00 || D
+	 * BT = 00 or 01 for private-key operation; 02 for public-key operation
+	 * PS = k-3-||D||; at least eight octets
+	 * (BT=0: PS=0x00, BT=1: PS=0xff, BT=2: PS=pseudorandom non-zero)
+	 * k = length of modulus in octets (modlen)
+	 */
+
+	if (modlen < 12 || modlen > *outlen || inlen > modlen - 11) {
+		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Invalid buffer "
+			   "lengths (modlen=%lu outlen=%lu inlen=%lu)",
+			   __func__, (unsigned long) modlen,
+			   (unsigned long) *outlen,
+			   (unsigned long) inlen);
+		return -1;
+	}
+
+	pos = out;
+	*pos++ = 0x00;
+	*pos++ = block_type; /* BT */
+	ps_len = modlen - inlen - 3;
+	switch (block_type) {
+	case 0:
+		os_memset(pos, 0x00, ps_len);
+		pos += ps_len;
+		break;
+	case 1:
+		os_memset(pos, 0xff, ps_len);
+		pos += ps_len;
+		break;
+	case 2:
+		if (os_get_random(pos, ps_len) < 0) {
+			wpa_printf(MSG_DEBUG, "PKCS #1: %s - Failed to get "
+				   "random data for PS", __func__);
+			return -1;
+		}
+		while (ps_len--) {
+			if (*pos == 0x00)
+				*pos = 0x01;
+			pos++;
+		}
+		break;
+	default:
+		wpa_printf(MSG_DEBUG, "PKCS #1: %s - Unsupported block type "
+			   "%d", __func__, block_type);
+		return -1;
+	}
+	*pos++ = 0x00;
+	os_memcpy(pos, in, inlen); /* D */
+
+	return 0;
+}
+
+
+static int crypto_rsa_encrypt_pkcs1(int block_type, rsa_key *key, int key_type,
+				    const u8 *in, size_t inlen,
+				    u8 *out, size_t *outlen)
+{
+	unsigned long len, modlen;
+	int res;
+
+	modlen = mp_unsigned_bin_size(key->N);
+
+	if (pkcs1_generate_encryption_block(block_type, modlen, in, inlen,
+					    out, outlen) < 0)
+		return -1;
+
+	len = *outlen;
+	res = rsa_exptmod(out, modlen, out, &len, key_type, key);
+	if (res != CRYPT_OK) {
+		wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
+			   error_to_string(res));
+		return -1;
+	}
+	*outlen = len;
+
+	return 0;
+}
+
+
+int crypto_public_key_encrypt_pkcs1_v15(struct crypto_public_key *key,
+					const u8 *in, size_t inlen,
+					u8 *out, size_t *outlen)
+{
+	return crypto_rsa_encrypt_pkcs1(2, &key->rsa, PK_PUBLIC, in, inlen,
+					out, outlen);
+}
+
+
+int crypto_private_key_sign_pkcs1(struct crypto_private_key *key,
+				  const u8 *in, size_t inlen,
+				  u8 *out, size_t *outlen)
+{
+	return crypto_rsa_encrypt_pkcs1(1, &key->rsa, PK_PRIVATE, in, inlen,
+					out, outlen);
+}
+
+
+void crypto_public_key_free(struct crypto_public_key *key)
+{
+	if (key) {
+		rsa_free(&key->rsa);
+		os_free(key);
+	}
+}
+
+
+void crypto_private_key_free(struct crypto_private_key *key)
+{
+	if (key) {
+		rsa_free(&key->rsa);
+		os_free(key);
+	}
+}
+
+
+int crypto_public_key_decrypt_pkcs1(struct crypto_public_key *key,
+				    const u8 *crypt, size_t crypt_len,
+				    u8 *plain, size_t *plain_len)
+{
+	int res;
+	unsigned long len;
+	u8 *pos;
+
+	len = *plain_len;
+	res = rsa_exptmod(crypt, crypt_len, plain, &len, PK_PUBLIC,
+			  &key->rsa);
+	if (res != CRYPT_OK) {
+		wpa_printf(MSG_DEBUG, "LibTomCrypt: rsa_exptmod failed: %s",
+			   error_to_string(res));
+		return -1;
+	}
+
+	/*
+	 * PKCS #1 v1.5, 8.1:
+	 *
+	 * EB = 00 || BT || PS || 00 || D
+	 * BT = 01
+	 * PS = k-3-||D|| times FF
+	 * k = length of modulus in octets
+	 */
+
+	if (len < 3 + 8 + 16 /* min hash len */ ||
+	    plain[0] != 0x00 || plain[1] != 0x01 || plain[2] != 0xff) {
+		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
+			   "structure");
+		return -1;
+	}
+
+	pos = plain + 3;
+	while (pos < plain + len && *pos == 0xff)
+		pos++;
+	if (pos - plain - 2 < 8) {
+		/* PKCS #1 v1.5, 8.1: At least eight octets long PS */
+		wpa_printf(MSG_INFO, "LibTomCrypt: Too short signature "
+			   "padding");
+		return -1;
+	}
+
+	if (pos + 16 /* min hash len */ >= plain + len || *pos != 0x00) {
+		wpa_printf(MSG_INFO, "LibTomCrypt: Invalid signature EB "
+			   "structure (2)");
+		return -1;
+	}
+	pos++;
+	len -= pos - plain;
+
+	/* Strip PKCS #1 header */
+	os_memmove(plain, pos, len);
+	*plain_len = len;
+
+	return 0;
+}
+
+
+int crypto_global_init(void)
+{
+	ltc_mp = tfm_desc;
+	/* TODO: only register algorithms that are really needed */
+	if (register_hash(&md4_desc) < 0 ||
+	    register_hash(&md5_desc) < 0 ||
+	    register_hash(&sha1_desc) < 0 ||
+	    register_cipher(&aes_desc) < 0 ||
+	    register_cipher(&des_desc) < 0 ||
+	    register_cipher(&des3_desc) < 0) {
+		wpa_printf(MSG_ERROR, "TLSv1: Failed to register "
+			   "hash/cipher functions");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void crypto_global_deinit(void)
+{
+}
+
+
+#ifdef CONFIG_MODEXP
+
+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)
+{
+	void *b, *p, *m, *r;
+
+	if (mp_init_multi(&b, &p, &m, &r, NULL) != CRYPT_OK)
+		return -1;
+
+	if (mp_read_unsigned_bin(b, (u8 *) base, base_len) != CRYPT_OK ||
+	    mp_read_unsigned_bin(p, (u8 *) power, power_len) != CRYPT_OK ||
+	    mp_read_unsigned_bin(m, (u8 *) modulus, modulus_len) != CRYPT_OK)
+		goto fail;
+
+	if (mp_exptmod(b, p, m, r) != CRYPT_OK)
+		goto fail;
+
+	*result_len = mp_unsigned_bin_size(r);
+	if (mp_to_unsigned_bin(r, result) != CRYPT_OK)
+		goto fail;
+
+	mp_clear_multi(b, p, m, r, NULL);
+	return 0;
+
+fail:
+	mp_clear_multi(b, p, m, r, NULL);
+	return -1;
+}
+
+#endif /* CONFIG_MODEXP */
diff --git a/hostap/src/crypto/crypto_none.c b/hostap/src/crypto/crypto_none.c
new file mode 100644
index 0000000..011f3f3
--- /dev/null
+++ b/hostap/src/crypto/crypto_none.c
@@ -0,0 +1,23 @@
+/*
+ * WPA Supplicant / Empty template functions for crypto wrapper
+ * Copyright (c) 2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return 0;
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+}
diff --git a/hostap/src/crypto/crypto_nss.c b/hostap/src/crypto/crypto_nss.c
new file mode 100644
index 0000000..acd0a55
--- /dev/null
+++ b/hostap/src/crypto/crypto_nss.c
@@ -0,0 +1,207 @@
+/*
+ * Crypto wrapper functions for NSS
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <nspr/prtypes.h>
+#include <nspr/plarenas.h>
+#include <nspr/plhash.h>
+#include <nspr/prtime.h>
+#include <nspr/prinrval.h>
+#include <nspr/prclist.h>
+#include <nspr/prlock.h>
+#include <nss/sechash.h>
+#include <nss/pk11pub.h>
+
+#include "common.h"
+#include "crypto.h"
+
+
+static int nss_hash(HASH_HashType type, unsigned int max_res_len,
+		    size_t num_elem, const u8 *addr[], const size_t *len,
+		    u8 *mac)
+{
+	HASHContext *ctx;
+	size_t i;
+	unsigned int reslen;
+
+	ctx = HASH_Create(type);
+	if (ctx == NULL)
+		return -1;
+
+	HASH_Begin(ctx);
+	for (i = 0; i < num_elem; i++)
+		HASH_Update(ctx, addr[i], len[i]);
+	HASH_End(ctx, mac, &reslen, max_res_len);
+	HASH_Destroy(ctx);
+
+	return 0;
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+	PK11Context *ctx = NULL;
+	PK11SlotInfo *slot;
+	SECItem *param = NULL;
+	PK11SymKey *symkey = NULL;
+	SECItem item;
+	int olen;
+	u8 pkey[8], next, tmp;
+	int i;
+
+	/* 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;
+
+	slot = PK11_GetBestSlot(CKM_DES_ECB, NULL);
+	if (slot == NULL) {
+		wpa_printf(MSG_ERROR, "NSS: PK11_GetBestSlot failed");
+		goto out;
+	}
+
+	item.type = siBuffer;
+	item.data = pkey;
+	item.len = 8;
+	symkey = PK11_ImportSymKey(slot, CKM_DES_ECB, PK11_OriginDerive,
+				   CKA_ENCRYPT, &item, NULL);
+	if (symkey == NULL) {
+		wpa_printf(MSG_ERROR, "NSS: PK11_ImportSymKey failed");
+		goto out;
+	}
+
+	param = PK11_GenerateNewParam(CKM_DES_ECB, symkey);
+	if (param == NULL) {
+		wpa_printf(MSG_ERROR, "NSS: PK11_GenerateNewParam failed");
+		goto out;
+	}
+
+	ctx = PK11_CreateContextBySymKey(CKM_DES_ECB, CKA_ENCRYPT,
+					 symkey, param);
+	if (ctx == NULL) {
+		wpa_printf(MSG_ERROR, "NSS: PK11_CreateContextBySymKey("
+			   "CKM_DES_ECB) failed");
+		goto out;
+	}
+
+	if (PK11_CipherOp(ctx, cypher, &olen, 8, (void *) clear, 8) !=
+	    SECSuccess) {
+		wpa_printf(MSG_ERROR, "NSS: PK11_CipherOp failed");
+		goto out;
+	}
+
+out:
+	if (ctx)
+		PK11_DestroyContext(ctx, PR_TRUE);
+	if (symkey)
+		PK11_FreeSymKey(symkey);
+	if (param)
+		SECITEM_FreeItem(param, PR_TRUE);
+}
+
+
+int rc4_skip(const u8 *key, size_t keylen, size_t skip,
+	     u8 *data, size_t data_len)
+{
+	return -1;
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return nss_hash(HASH_AlgMD5, 16, num_elem, addr, len, mac);
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return nss_hash(HASH_AlgSHA1, 20, num_elem, addr, len, mac);
+}
+
+
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		  u8 *mac)
+{
+	return nss_hash(HASH_AlgSHA256, 32, num_elem, addr, len, mac);
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+	return NULL;
+}
+
+
+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)
+{
+	return NULL;
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+}
+
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+		   const u8 *power, size_t power_len,
+		   const u8 *modulus, size_t modulus_len,
+		   u8 *result, size_t *result_len)
+{
+	return -1;
+}
+
+
+struct crypto_cipher {
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len)
+{
+	return NULL;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+			  u8 *crypt, size_t len)
+{
+	return -1;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+			  u8 *plain, size_t len)
+{
+	return -1;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+}
diff --git a/hostap/src/crypto/crypto_openssl.c b/hostap/src/crypto/crypto_openssl.c
new file mode 100644
index 0000000..711e312
--- /dev/null
+++ b/hostap/src/crypto/crypto_openssl.c
@@ -0,0 +1,820 @@
+/*
+ * WPA Supplicant / wrapper functions for libcrypto
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <openssl/opensslv.h>
+#include <openssl/err.h>
+#include <openssl/des.h>
+#include <openssl/aes.h>
+#include <openssl/bn.h>
+#include <openssl/evp.h>
+#include <openssl/dh.h>
+#include <openssl/hmac.h>
+#include <openssl/rand.h>
+#ifdef CONFIG_OPENSSL_CMAC
+#include <openssl/cmac.h>
+#endif /* CONFIG_OPENSSL_CMAC */
+
+#include "common.h"
+#include "wpabuf.h"
+#include "dh_group5.h"
+#include "crypto.h"
+
+#if OPENSSL_VERSION_NUMBER < 0x00907000
+#define DES_key_schedule des_key_schedule
+#define DES_cblock des_cblock
+#define DES_set_key(key, schedule) des_set_key((key), *(schedule))
+#define DES_ecb_encrypt(input, output, ks, enc) \
+	des_ecb_encrypt((input), (output), *(ks), (enc))
+#endif /* openssl < 0.9.7 */
+
+static BIGNUM * get_group5_prime(void)
+{
+#if OPENSSL_VERSION_NUMBER < 0x00908000
+	static const unsigned char RFC3526_PRIME_1536[] = {
+		0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xC9,0x0F,0xDA,0xA2,
+		0x21,0x68,0xC2,0x34,0xC4,0xC6,0x62,0x8B,0x80,0xDC,0x1C,0xD1,
+		0x29,0x02,0x4E,0x08,0x8A,0x67,0xCC,0x74,0x02,0x0B,0xBE,0xA6,
+		0x3B,0x13,0x9B,0x22,0x51,0x4A,0x08,0x79,0x8E,0x34,0x04,0xDD,
+		0xEF,0x95,0x19,0xB3,0xCD,0x3A,0x43,0x1B,0x30,0x2B,0x0A,0x6D,
+		0xF2,0x5F,0x14,0x37,0x4F,0xE1,0x35,0x6D,0x6D,0x51,0xC2,0x45,
+		0xE4,0x85,0xB5,0x76,0x62,0x5E,0x7E,0xC6,0xF4,0x4C,0x42,0xE9,
+		0xA6,0x37,0xED,0x6B,0x0B,0xFF,0x5C,0xB6,0xF4,0x06,0xB7,0xED,
+		0xEE,0x38,0x6B,0xFB,0x5A,0x89,0x9F,0xA5,0xAE,0x9F,0x24,0x11,
+		0x7C,0x4B,0x1F,0xE6,0x49,0x28,0x66,0x51,0xEC,0xE4,0x5B,0x3D,
+		0xC2,0x00,0x7C,0xB8,0xA1,0x63,0xBF,0x05,0x98,0xDA,0x48,0x36,
+		0x1C,0x55,0xD3,0x9A,0x69,0x16,0x3F,0xA8,0xFD,0x24,0xCF,0x5F,
+		0x83,0x65,0x5D,0x23,0xDC,0xA3,0xAD,0x96,0x1C,0x62,0xF3,0x56,
+		0x20,0x85,0x52,0xBB,0x9E,0xD5,0x29,0x07,0x70,0x96,0x96,0x6D,
+		0x67,0x0C,0x35,0x4E,0x4A,0xBC,0x98,0x04,0xF1,0x74,0x6C,0x08,
+		0xCA,0x23,0x73,0x27,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+	};
+        return BN_bin2bn(RFC3526_PRIME_1536, sizeof(RFC3526_PRIME_1536), NULL);
+#else /* openssl < 0.9.8 */
+	return get_rfc3526_prime_1536(NULL);
+#endif /* openssl < 0.9.8 */
+}
+
+#if OPENSSL_VERSION_NUMBER < 0x00908000
+#ifndef OPENSSL_NO_SHA256
+#ifndef OPENSSL_FIPS
+#define NO_SHA256_WRAPPER
+#endif
+#endif
+
+#endif /* openssl < 0.9.8 */
+
+#ifdef OPENSSL_NO_SHA256
+#define NO_SHA256_WRAPPER
+#endif
+
+static int openssl_digest_vector(const EVP_MD *type, size_t num_elem,
+				 const u8 *addr[], const size_t *len, u8 *mac)
+{
+	EVP_MD_CTX ctx;
+	size_t i;
+	unsigned int mac_len;
+
+	EVP_MD_CTX_init(&ctx);
+	if (!EVP_DigestInit_ex(&ctx, type, NULL)) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestInit_ex failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+	for (i = 0; i < num_elem; i++) {
+		if (!EVP_DigestUpdate(&ctx, addr[i], len[i])) {
+			wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestUpdate "
+				   "failed: %s",
+				   ERR_error_string(ERR_get_error(), NULL));
+			return -1;
+		}
+	}
+	if (!EVP_DigestFinal(&ctx, mac, &mac_len)) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DigestFinal failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return openssl_digest_vector(EVP_md4(), num_elem, addr, len, mac);
+}
+
+
+void des_encrypt(const u8 *clear, const u8 *key, u8 *cypher)
+{
+	u8 pkey[8], next, tmp;
+	int i;
+	DES_key_schedule ks;
+
+	/* Add parity bits to the key */
+	next = 0;
+	for (i = 0; i < 7; i++) {
+		tmp = key[i];
+		pkey[i] = (tmp >> i) | next | 1;
+		next = tmp << (7 - i);
+	}
+	pkey[i] = next | 1;
+
+	DES_set_key(&pkey, &ks);
+	DES_ecb_encrypt((DES_cblock *) clear, (DES_cblock *) cypher, &ks,
+			DES_ENCRYPT);
+}
+
+
+int rc4_skip(const u8 *key, size_t keylen, size_t skip,
+	     u8 *data, size_t data_len)
+{
+#ifdef OPENSSL_NO_RC4
+	return -1;
+#else /* OPENSSL_NO_RC4 */
+	EVP_CIPHER_CTX ctx;
+	int outl;
+	int res = -1;
+	unsigned char skip_buf[16];
+
+	EVP_CIPHER_CTX_init(&ctx);
+	if (!EVP_CIPHER_CTX_set_padding(&ctx, 0) ||
+	    !EVP_CipherInit_ex(&ctx, EVP_rc4(), NULL, NULL, NULL, 1) ||
+	    !EVP_CIPHER_CTX_set_key_length(&ctx, keylen) ||
+	    !EVP_CipherInit_ex(&ctx, NULL, NULL, key, NULL, 1))
+		goto out;
+
+	while (skip >= sizeof(skip_buf)) {
+		size_t len = skip;
+		if (len > sizeof(skip_buf))
+			len = sizeof(skip_buf);
+		if (!EVP_CipherUpdate(&ctx, skip_buf, &outl, skip_buf, len))
+			goto out;
+		skip -= len;
+	}
+
+	if (EVP_CipherUpdate(&ctx, data, &outl, data, data_len))
+		res = 0;
+
+out:
+	EVP_CIPHER_CTX_cleanup(&ctx);
+	return res;
+#endif /* OPENSSL_NO_RC4 */
+}
+
+
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return openssl_digest_vector(EVP_md5(), num_elem, addr, len, mac);
+}
+
+
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	return openssl_digest_vector(EVP_sha1(), num_elem, addr, len, mac);
+}
+
+
+#ifndef NO_SHA256_WRAPPER
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		  u8 *mac)
+{
+	return openssl_digest_vector(EVP_sha256(), num_elem, addr, len, mac);
+}
+#endif /* NO_SHA256_WRAPPER */
+
+
+static const EVP_CIPHER * aes_get_evp_cipher(size_t keylen)
+{
+	switch (keylen) {
+	case 16:
+		return EVP_aes_128_ecb();
+	case 24:
+		return EVP_aes_192_ecb();
+	case 32:
+		return EVP_aes_256_ecb();
+	}
+
+	return NULL;
+}
+
+
+void * aes_encrypt_init(const u8 *key, size_t len)
+{
+	EVP_CIPHER_CTX *ctx;
+	const EVP_CIPHER *type;
+
+	type = aes_get_evp_cipher(len);
+	if (type == NULL)
+		return NULL;
+
+	ctx = os_malloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+	EVP_CIPHER_CTX_init(ctx);
+	if (EVP_EncryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
+		os_free(ctx);
+		return NULL;
+	}
+	EVP_CIPHER_CTX_set_padding(ctx, 0);
+	return ctx;
+}
+
+
+void aes_encrypt(void *ctx, const u8 *plain, u8 *crypt)
+{
+	EVP_CIPHER_CTX *c = ctx;
+	int clen = 16;
+	if (EVP_EncryptUpdate(c, crypt, &clen, plain, 16) != 1) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_EncryptUpdate failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+	}
+}
+
+
+void aes_encrypt_deinit(void *ctx)
+{
+	EVP_CIPHER_CTX *c = ctx;
+	u8 buf[16];
+	int len = sizeof(buf);
+	if (EVP_EncryptFinal_ex(c, buf, &len) != 1) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_EncryptFinal_ex failed: "
+			   "%s", ERR_error_string(ERR_get_error(), NULL));
+	}
+	if (len != 0) {
+		wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
+			   "in AES encrypt", len);
+	}
+	EVP_CIPHER_CTX_cleanup(c);
+	os_free(c);
+}
+
+
+void * aes_decrypt_init(const u8 *key, size_t len)
+{
+	EVP_CIPHER_CTX *ctx;
+	const EVP_CIPHER *type;
+
+	type = aes_get_evp_cipher(len);
+	if (type == NULL)
+		return NULL;
+
+	ctx = os_malloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+	EVP_CIPHER_CTX_init(ctx);
+	if (EVP_DecryptInit_ex(ctx, type, NULL, key, NULL) != 1) {
+		os_free(ctx);
+		return NULL;
+	}
+	EVP_CIPHER_CTX_set_padding(ctx, 0);
+	return ctx;
+}
+
+
+void aes_decrypt(void *ctx, const u8 *crypt, u8 *plain)
+{
+	EVP_CIPHER_CTX *c = ctx;
+	int plen = 16;
+	if (EVP_DecryptUpdate(c, plain, &plen, crypt, 16) != 1) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DecryptUpdate failed: %s",
+			   ERR_error_string(ERR_get_error(), NULL));
+	}
+}
+
+
+void aes_decrypt_deinit(void *ctx)
+{
+	EVP_CIPHER_CTX *c = ctx;
+	u8 buf[16];
+	int len = sizeof(buf);
+	if (EVP_DecryptFinal_ex(c, buf, &len) != 1) {
+		wpa_printf(MSG_ERROR, "OpenSSL: EVP_DecryptFinal_ex failed: "
+			   "%s", ERR_error_string(ERR_get_error(), NULL));
+	}
+	if (len != 0) {
+		wpa_printf(MSG_ERROR, "OpenSSL: Unexpected padding length %d "
+			   "in AES decrypt", len);
+	}
+	EVP_CIPHER_CTX_cleanup(c);
+	os_free(ctx);
+}
+
+
+int crypto_mod_exp(const u8 *base, size_t base_len,
+		   const u8 *power, size_t power_len,
+		   const u8 *modulus, size_t modulus_len,
+		   u8 *result, size_t *result_len)
+{
+	BIGNUM *bn_base, *bn_exp, *bn_modulus, *bn_result;
+	int ret = -1;
+	BN_CTX *ctx;
+
+	ctx = BN_CTX_new();
+	if (ctx == NULL)
+		return -1;
+
+	bn_base = BN_bin2bn(base, base_len, NULL);
+	bn_exp = BN_bin2bn(power, power_len, NULL);
+	bn_modulus = BN_bin2bn(modulus, modulus_len, NULL);
+	bn_result = BN_new();
+
+	if (bn_base == NULL || bn_exp == NULL || bn_modulus == NULL ||
+	    bn_result == NULL)
+		goto error;
+
+	if (BN_mod_exp(bn_result, bn_base, bn_exp, bn_modulus, ctx) != 1)
+		goto error;
+
+	*result_len = BN_bn2bin(bn_result, result);
+	ret = 0;
+
+error:
+	BN_free(bn_base);
+	BN_free(bn_exp);
+	BN_free(bn_modulus);
+	BN_free(bn_result);
+	BN_CTX_free(ctx);
+	return ret;
+}
+
+
+struct crypto_cipher {
+	EVP_CIPHER_CTX enc;
+	EVP_CIPHER_CTX dec;
+};
+
+
+struct crypto_cipher * crypto_cipher_init(enum crypto_cipher_alg alg,
+					  const u8 *iv, const u8 *key,
+					  size_t key_len)
+{
+	struct crypto_cipher *ctx;
+	const EVP_CIPHER *cipher;
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+
+	switch (alg) {
+#ifndef OPENSSL_NO_RC4
+	case CRYPTO_CIPHER_ALG_RC4:
+		cipher = EVP_rc4();
+		break;
+#endif /* OPENSSL_NO_RC4 */
+#ifndef OPENSSL_NO_AES
+	case CRYPTO_CIPHER_ALG_AES:
+		switch (key_len) {
+		case 16:
+			cipher = EVP_aes_128_cbc();
+			break;
+		case 24:
+			cipher = EVP_aes_192_cbc();
+			break;
+		case 32:
+			cipher = EVP_aes_256_cbc();
+			break;
+		default:
+			os_free(ctx);
+			return NULL;
+		}
+		break;
+#endif /* OPENSSL_NO_AES */
+#ifndef OPENSSL_NO_DES
+	case CRYPTO_CIPHER_ALG_3DES:
+		cipher = EVP_des_ede3_cbc();
+		break;
+	case CRYPTO_CIPHER_ALG_DES:
+		cipher = EVP_des_cbc();
+		break;
+#endif /* OPENSSL_NO_DES */
+#ifndef OPENSSL_NO_RC2
+	case CRYPTO_CIPHER_ALG_RC2:
+		cipher = EVP_rc2_ecb();
+		break;
+#endif /* OPENSSL_NO_RC2 */
+	default:
+		os_free(ctx);
+		return NULL;
+	}
+
+	EVP_CIPHER_CTX_init(&ctx->enc);
+	EVP_CIPHER_CTX_set_padding(&ctx->enc, 0);
+	if (!EVP_EncryptInit_ex(&ctx->enc, cipher, NULL, NULL, NULL) ||
+	    !EVP_CIPHER_CTX_set_key_length(&ctx->enc, key_len) ||
+	    !EVP_EncryptInit_ex(&ctx->enc, NULL, NULL, key, iv)) {
+		EVP_CIPHER_CTX_cleanup(&ctx->enc);
+		os_free(ctx);
+		return NULL;
+	}
+
+	EVP_CIPHER_CTX_init(&ctx->dec);
+	EVP_CIPHER_CTX_set_padding(&ctx->dec, 0);
+	if (!EVP_DecryptInit_ex(&ctx->dec, cipher, NULL, NULL, NULL) ||
+	    !EVP_CIPHER_CTX_set_key_length(&ctx->dec, key_len) ||
+	    !EVP_DecryptInit_ex(&ctx->dec, NULL, NULL, key, iv)) {
+		EVP_CIPHER_CTX_cleanup(&ctx->enc);
+		EVP_CIPHER_CTX_cleanup(&ctx->dec);
+		os_free(ctx);
+		return NULL;
+	}
+
+	return ctx;
+}
+
+
+int crypto_cipher_encrypt(struct crypto_cipher *ctx, const u8 *plain,
+			  u8 *crypt, size_t len)
+{
+	int outl;
+	if (!EVP_EncryptUpdate(&ctx->enc, crypt, &outl, plain, len))
+		return -1;
+	return 0;
+}
+
+
+int crypto_cipher_decrypt(struct crypto_cipher *ctx, const u8 *crypt,
+			  u8 *plain, size_t len)
+{
+	int outl;
+	outl = len;
+	if (!EVP_DecryptUpdate(&ctx->dec, plain, &outl, crypt, len))
+		return -1;
+	return 0;
+}
+
+
+void crypto_cipher_deinit(struct crypto_cipher *ctx)
+{
+	EVP_CIPHER_CTX_cleanup(&ctx->enc);
+	EVP_CIPHER_CTX_cleanup(&ctx->dec);
+	os_free(ctx);
+}
+
+
+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
+{
+	DH *dh;
+	struct wpabuf *pubkey = NULL, *privkey = NULL;
+	size_t publen, privlen;
+
+	*priv = NULL;
+	*publ = NULL;
+
+	dh = DH_new();
+	if (dh == NULL)
+		return NULL;
+
+	dh->g = BN_new();
+	if (dh->g == NULL || BN_set_word(dh->g, 2) != 1)
+		goto err;
+
+	dh->p = get_group5_prime();
+	if (dh->p == NULL)
+		goto err;
+
+	if (DH_generate_key(dh) != 1)
+		goto err;
+
+	publen = BN_num_bytes(dh->pub_key);
+	pubkey = wpabuf_alloc(publen);
+	if (pubkey == NULL)
+		goto err;
+	privlen = BN_num_bytes(dh->priv_key);
+	privkey = wpabuf_alloc(privlen);
+	if (privkey == NULL)
+		goto err;
+
+	BN_bn2bin(dh->pub_key, wpabuf_put(pubkey, publen));
+	BN_bn2bin(dh->priv_key, wpabuf_put(privkey, privlen));
+
+	*priv = privkey;
+	*publ = pubkey;
+	return dh;
+
+err:
+	wpabuf_free(pubkey);
+	wpabuf_free(privkey);
+	DH_free(dh);
+	return NULL;
+}
+
+
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
+{
+	DH *dh;
+
+	dh = DH_new();
+	if (dh == NULL)
+		return NULL;
+
+	dh->g = BN_new();
+	if (dh->g == NULL || BN_set_word(dh->g, 2) != 1)
+		goto err;
+
+	dh->p = get_group5_prime();
+	if (dh->p == NULL)
+		goto err;
+
+	dh->priv_key = BN_bin2bn(wpabuf_head(priv), wpabuf_len(priv), NULL);
+	if (dh->priv_key == NULL)
+		goto err;
+
+	dh->pub_key = BN_bin2bn(wpabuf_head(publ), wpabuf_len(publ), NULL);
+	if (dh->pub_key == NULL)
+		goto err;
+
+	if (DH_generate_key(dh) != 1)
+		goto err;
+
+	return dh;
+
+err:
+	DH_free(dh);
+	return NULL;
+}
+
+
+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
+				  const struct wpabuf *own_private)
+{
+	BIGNUM *pub_key;
+	struct wpabuf *res = NULL;
+	size_t rlen;
+	DH *dh = ctx;
+	int keylen;
+
+	if (ctx == NULL)
+		return NULL;
+
+	pub_key = BN_bin2bn(wpabuf_head(peer_public), wpabuf_len(peer_public),
+			    NULL);
+	if (pub_key == NULL)
+		return NULL;
+
+	rlen = DH_size(dh);
+	res = wpabuf_alloc(rlen);
+	if (res == NULL)
+		goto err;
+
+	keylen = DH_compute_key(wpabuf_mhead(res), pub_key, dh);
+	if (keylen < 0)
+		goto err;
+	wpabuf_put(res, keylen);
+	BN_free(pub_key);
+
+	return res;
+
+err:
+	BN_free(pub_key);
+	wpabuf_free(res);
+	return NULL;
+}
+
+
+void dh5_free(void *ctx)
+{
+	DH *dh;
+	if (ctx == NULL)
+		return;
+	dh = ctx;
+	DH_free(dh);
+}
+
+
+struct crypto_hash {
+	HMAC_CTX ctx;
+};
+
+
+struct crypto_hash * crypto_hash_init(enum crypto_hash_alg alg, const u8 *key,
+				      size_t key_len)
+{
+	struct crypto_hash *ctx;
+	const EVP_MD *md;
+
+	switch (alg) {
+#ifndef OPENSSL_NO_MD5
+	case CRYPTO_HASH_ALG_HMAC_MD5:
+		md = EVP_md5();
+		break;
+#endif /* OPENSSL_NO_MD5 */
+#ifndef OPENSSL_NO_SHA
+	case CRYPTO_HASH_ALG_HMAC_SHA1:
+		md = EVP_sha1();
+		break;
+#endif /* OPENSSL_NO_SHA */
+#ifndef OPENSSL_NO_SHA256
+#ifdef CONFIG_SHA256
+	case CRYPTO_HASH_ALG_HMAC_SHA256:
+		md = EVP_sha256();
+		break;
+#endif /* CONFIG_SHA256 */
+#endif /* OPENSSL_NO_SHA256 */
+	default:
+		return NULL;
+	}
+
+	ctx = os_zalloc(sizeof(*ctx));
+	if (ctx == NULL)
+		return NULL;
+	HMAC_CTX_init(&ctx->ctx);
+
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+	HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL);
+#else /* openssl < 0.9.9 */
+	if (HMAC_Init_ex(&ctx->ctx, key, key_len, md, NULL) != 1) {
+		os_free(ctx);
+		return NULL;
+	}
+#endif /* openssl < 0.9.9 */
+
+	return ctx;
+}
+
+
+void crypto_hash_update(struct crypto_hash *ctx, const u8 *data, size_t len)
+{
+	if (ctx == NULL)
+		return;
+	HMAC_Update(&ctx->ctx, data, len);
+}
+
+
+int crypto_hash_finish(struct crypto_hash *ctx, u8 *mac, size_t *len)
+{
+	unsigned int mdlen;
+	int res;
+
+	if (ctx == NULL)
+		return -2;
+
+	if (mac == NULL || len == NULL) {
+		os_free(ctx);
+		return 0;
+	}
+
+	mdlen = *len;
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+	HMAC_Final(&ctx->ctx, mac, &mdlen);
+	res = 1;
+#else /* openssl < 0.9.9 */
+	res = HMAC_Final(&ctx->ctx, mac, &mdlen);
+#endif /* openssl < 0.9.9 */
+	HMAC_CTX_cleanup(&ctx->ctx);
+	os_free(ctx);
+
+	if (res == 1) {
+		*len = mdlen;
+		return 0;
+	}
+
+	return -1;
+}
+
+
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+		int iterations, u8 *buf, size_t buflen)
+{
+#if OPENSSL_VERSION_NUMBER < 0x00908000
+	if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase),
+				   (unsigned char *) ssid,
+				   ssid_len, 4096, buflen, buf) != 1)
+		return -1;
+#else /* openssl < 0.9.8 */
+	if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
+				   ssid_len, 4096, buflen, buf) != 1)
+		return -1;
+#endif /* openssl < 0.9.8 */
+	return 0;
+}
+
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac)
+{
+	HMAC_CTX ctx;
+	size_t i;
+	unsigned int mdlen;
+	int res;
+
+	HMAC_CTX_init(&ctx);
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+	HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL);
+#else /* openssl < 0.9.9 */
+	if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL) != 1)
+		return -1;
+#endif /* openssl < 0.9.9 */
+
+	for (i = 0; i < num_elem; i++)
+		HMAC_Update(&ctx, addr[i], len[i]);
+
+	mdlen = 20;
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+	HMAC_Final(&ctx, mac, &mdlen);
+	res = 1;
+#else /* openssl < 0.9.9 */
+	res = HMAC_Final(&ctx, mac, &mdlen);
+#endif /* openssl < 0.9.9 */
+	HMAC_CTX_cleanup(&ctx);
+
+	return res == 1 ? 0 : -1;
+}
+
+
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	       u8 *mac)
+{
+	return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+
+#ifdef CONFIG_SHA256
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	HMAC_CTX ctx;
+	size_t i;
+	unsigned int mdlen;
+	int res;
+
+	HMAC_CTX_init(&ctx);
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+	HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL);
+#else /* openssl < 0.9.9 */
+	if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha256(), NULL) != 1)
+		return -1;
+#endif /* openssl < 0.9.9 */
+
+	for (i = 0; i < num_elem; i++)
+		HMAC_Update(&ctx, addr[i], len[i]);
+
+	mdlen = 32;
+#if OPENSSL_VERSION_NUMBER < 0x00909000
+	HMAC_Final(&ctx, mac, &mdlen);
+	res = 1;
+#else /* openssl < 0.9.9 */
+	res = HMAC_Final(&ctx, mac, &mdlen);
+#endif /* openssl < 0.9.9 */
+	HMAC_CTX_cleanup(&ctx);
+
+	return res == 1 ? 0 : -1;
+}
+
+
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA256 */
+
+
+int crypto_get_random(void *buf, size_t len)
+{
+	if (RAND_bytes(buf, len) != 1)
+		return -1;
+	return 0;
+}
+
+
+#ifdef CONFIG_OPENSSL_CMAC
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+			 const u8 *addr[], const size_t *len, u8 *mac)
+{
+	CMAC_CTX *ctx;
+	int ret = -1;
+	size_t outlen, i;
+
+	ctx = CMAC_CTX_new();
+	if (ctx == NULL)
+		return -1;
+
+	if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
+		goto fail;
+	for (i = 0; i < num_elem; i++) {
+		if (!CMAC_Update(ctx, addr[i], len[i]))
+			goto fail;
+	}
+	if (!CMAC_Final(ctx, mac, &outlen) || outlen != 16)
+		goto fail;
+
+	ret = 0;
+fail:
+	CMAC_CTX_free(ctx);
+	return ret;
+}
+
+
+int omac1_aes_128(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+	return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
+}
+#endif /* CONFIG_OPENSSL_CMAC */
diff --git a/hostap/src/crypto/des-internal.c b/hostap/src/crypto/des-internal.c
new file mode 100644
index 0000000..dec39ef
--- /dev/null
+++ b/hostap/src/crypto/des-internal.c
@@ -0,0 +1,493 @@
+/*
+ * DES and 3DES-EDE ciphers
+ *
+ * Modifications to LibTomCrypt implementation:
+ * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+#include "des_i.h"
+
+/*
+ * 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]);
+
+	os_memset(pkey, 0, sizeof(pkey));
+	os_memset(ek, 0, sizeof(ek));
+}
+
+
+void des_key_setup(const u8 *key, u32 *ek, u32 *dk)
+{
+	deskey(key, 0, ek);
+	deskey(key, 1, dk);
+}
+
+
+void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt)
+{
+	u32 work[2];
+	work[0] = WPA_GET_BE32(plain);
+	work[1] = WPA_GET_BE32(plain + 4);
+	desfunc(work, ek);
+	WPA_PUT_BE32(crypt, work[0]);
+	WPA_PUT_BE32(crypt + 4, work[1]);
+}
+
+
+void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain)
+{
+	u32 work[2];
+	work[0] = WPA_GET_BE32(crypt);
+	work[1] = WPA_GET_BE32(crypt + 4);
+	desfunc(work, dk);
+	WPA_PUT_BE32(plain, work[0]);
+	WPA_PUT_BE32(plain + 4, work[1]);
+}
+
+
+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]);
+}
diff --git a/hostap/src/crypto/des_i.h b/hostap/src/crypto/des_i.h
new file mode 100644
index 0000000..c9563d2
--- /dev/null
+++ b/hostap/src/crypto/des_i.h
@@ -0,0 +1,25 @@
+/*
+ * DES and 3DES-EDE ciphers
+ * Copyright (c) 2006-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DES_I_H
+#define DES_I_H
+
+struct des3_key_s {
+	u32 ek[3][32];
+	u32 dk[3][32];
+};
+
+void des_key_setup(const u8 *key, u32 *ek, u32 *dk);
+void des_block_encrypt(const u8 *plain, const u32 *ek, u8 *crypt);
+void des_block_decrypt(const u8 *crypt, const u32 *dk, u8 *plain);
+
+void des3_key_setup(const u8 *key, struct des3_key_s *dkey);
+void des3_encrypt(const u8 *plain, const struct des3_key_s *key, u8 *crypt);
+void des3_decrypt(const u8 *crypt, const struct des3_key_s *key, u8 *plain);
+
+#endif /* DES_I_H */
diff --git a/hostap/src/crypto/dh_group5.c b/hostap/src/crypto/dh_group5.c
new file mode 100644
index 0000000..ccdbfc8
--- /dev/null
+++ b/hostap/src/crypto/dh_group5.c
@@ -0,0 +1,40 @@
+/*
+ * Diffie-Hellman group 5 operations
+ * Copyright (c) 2009, 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "dh_groups.h"
+#include "dh_group5.h"
+
+
+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ)
+{
+	*publ = dh_init(dh_groups_get(5), priv);
+	if (*publ == NULL)
+		return NULL;
+	return (void *) 1;
+}
+
+
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ)
+{
+	return (void *) 1;
+}
+
+
+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
+				  const struct wpabuf *own_private)
+{
+	return dh_derive_shared(peer_public, own_private, dh_groups_get(5));
+}
+
+
+void dh5_free(void *ctx)
+{
+}
diff --git a/hostap/src/crypto/dh_group5.h b/hostap/src/crypto/dh_group5.h
new file mode 100644
index 0000000..abee8ea
--- /dev/null
+++ b/hostap/src/crypto/dh_group5.h
@@ -0,0 +1,18 @@
+/*
+ * Diffie-Hellman group 5 operations
+ * Copyright (c) 2009, 2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DH_GROUP5_H
+#define DH_GROUP5_H
+
+void * dh5_init(struct wpabuf **priv, struct wpabuf **publ);
+void * dh5_init_fixed(const struct wpabuf *priv, const struct wpabuf *publ);
+struct wpabuf * dh5_derive_shared(void *ctx, const struct wpabuf *peer_public,
+				  const struct wpabuf *own_private);
+void dh5_free(void *ctx);
+
+#endif /* DH_GROUP5_H */
diff --git a/hostap/src/crypto/dh_groups.c b/hostap/src/crypto/dh_groups.c
new file mode 100644
index 0000000..f757b6b
--- /dev/null
+++ b/hostap/src/crypto/dh_groups.c
@@ -0,0 +1,627 @@
+/*
+ * Diffie-Hellman groups
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+#include "random.h"
+#include "dh_groups.h"
+
+
+#ifdef ALL_DH_GROUPS
+
+/* RFC 4306, B.1. Group 1 - 768 Bit MODP
+ * Generator: 2
+ * Prime: 2^768 - 2 ^704 - 1 + 2^64 * { [2^638 pi] + 149686 }
+ */
+static const u8 dh_group1_generator[1] = { 0x02 };
+static const u8 dh_group1_prime[96] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x3A, 0x36, 0x20,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/* RFC 4306, B.2. Group 2 - 1024 Bit MODP
+ * Generator: 2
+ * Prime: 2^1024 - 2^960 - 1 + 2^64 * { [2^894 pi] + 129093 }
+ */
+static const u8 dh_group2_generator[1] = { 0x02 };
+static const u8 dh_group2_prime[128] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE6, 0x53, 0x81,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+#endif /* ALL_DH_GROUPS */
+
+/* RFC 3526, 2. Group 5 - 1536 Bit MODP
+ * Generator: 2
+ * Prime: 2^1536 - 2^1472 - 1 + 2^64 * { [2^1406 pi] + 741804 }
+ */
+static const u8 dh_group5_generator[1] = { 0x02 };
+static const u8 dh_group5_prime[192] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
+	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
+	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
+	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
+	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
+	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x23, 0x73, 0x27,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+#ifdef ALL_DH_GROUPS
+
+/* RFC 3526, 3. Group 14 - 2048 Bit MODP
+ * Generator: 2
+ * Prime: 2^2048 - 2^1984 - 1 + 2^64 * { [2^1918 pi] + 124476 }
+ */
+static const u8 dh_group14_generator[1] = { 0x02 };
+static const u8 dh_group14_prime[256] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
+	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
+	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
+	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
+	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
+	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
+	0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
+	0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
+	0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
+	0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
+	0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
+	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
+	0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
+	0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAC, 0xAA, 0x68,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/* RFC 3526, 4. Group 15 - 3072 Bit MODP
+ * Generator: 2
+ * Prime: 2^3072 - 2^3008 - 1 + 2^64 * { [2^2942 pi] + 1690314 }
+ */
+static const u8 dh_group15_generator[1] = { 0x02 };
+static const u8 dh_group15_prime[384] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
+	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
+	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
+	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
+	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
+	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
+	0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
+	0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
+	0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
+	0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
+	0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
+	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
+	0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
+	0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
+	0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
+	0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
+	0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
+	0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
+	0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
+	0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
+	0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
+	0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
+	0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
+	0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
+	0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
+	0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
+	0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
+	0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
+	0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
+	0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x3A, 0xD2, 0xCA,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/* RFC 3526, 5. Group 16 - 4096 Bit MODP
+ * Generator: 2
+ * Prime: 2^4096 - 2^4032 - 1 + 2^64 * { [2^3966 pi] + 240904 }
+ */
+static const u8 dh_group16_generator[1] = { 0x02 };
+static const u8 dh_group16_prime[512] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
+	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
+	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
+	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
+	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
+	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
+	0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
+	0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
+	0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
+	0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
+	0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
+	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
+	0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
+	0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
+	0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
+	0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
+	0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
+	0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
+	0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
+	0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
+	0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
+	0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
+	0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
+	0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
+	0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
+	0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
+	0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
+	0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
+	0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
+	0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
+	0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
+	0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
+	0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
+	0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
+	0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
+	0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
+	0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
+	0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
+	0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
+	0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
+	0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
+	0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
+	0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
+	0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
+	0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
+	0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x06, 0x31, 0x99,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/* RFC 3526, 6. Group 17 - 6144 Bit MODP
+ * Generator: 2
+ * Prime: 2^6144 - 2^6080 - 1 + 2^64 * { [2^6014 pi] + 929484 }
+ */
+static const u8 dh_group17_generator[1] = { 0x02 };
+static const u8 dh_group17_prime[768] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
+	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
+	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
+	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
+	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
+	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
+	0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
+	0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
+	0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
+	0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
+	0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
+	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
+	0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
+	0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
+	0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
+	0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
+	0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
+	0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
+	0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
+	0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
+	0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
+	0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
+	0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
+	0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
+	0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
+	0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
+	0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
+	0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
+	0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
+	0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
+	0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
+	0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
+	0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
+	0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
+	0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
+	0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
+	0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
+	0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
+	0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
+	0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
+	0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
+	0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
+	0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
+	0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
+	0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
+	0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92,
+	0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26,
+	0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE,
+	0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD,
+	0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E,
+	0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE,
+	0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31,
+	0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18,
+	0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED,
+	0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B,
+	0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B,
+	0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42,
+	0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF,
+	0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC,
+	0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03,
+	0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6,
+	0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82,
+	0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E,
+	0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3,
+	0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE,
+	0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5,
+	0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA,
+	0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8,
+	0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0,
+	0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28,
+	0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76,
+	0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0,
+	0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C,
+	0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32,
+	0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68,
+	0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE,
+	0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6,
+	0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xCC, 0x40, 0x24,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+/* RFC 3526, 7. Group 18 - 8192 Bit MODP
+ * Generator: 2
+ * Prime: 2^8192 - 2^8128 - 1 + 2^64 * { [2^8062 pi] + 4743158 }
+ */
+static const u8 dh_group18_generator[1] = { 0x02 };
+static const u8 dh_group18_prime[1024] = {
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+	0xC9, 0x0F, 0xDA, 0xA2, 0x21, 0x68, 0xC2, 0x34,
+	0xC4, 0xC6, 0x62, 0x8B, 0x80, 0xDC, 0x1C, 0xD1,
+	0x29, 0x02, 0x4E, 0x08, 0x8A, 0x67, 0xCC, 0x74,
+	0x02, 0x0B, 0xBE, 0xA6, 0x3B, 0x13, 0x9B, 0x22,
+	0x51, 0x4A, 0x08, 0x79, 0x8E, 0x34, 0x04, 0xDD,
+	0xEF, 0x95, 0x19, 0xB3, 0xCD, 0x3A, 0x43, 0x1B,
+	0x30, 0x2B, 0x0A, 0x6D, 0xF2, 0x5F, 0x14, 0x37,
+	0x4F, 0xE1, 0x35, 0x6D, 0x6D, 0x51, 0xC2, 0x45,
+	0xE4, 0x85, 0xB5, 0x76, 0x62, 0x5E, 0x7E, 0xC6,
+	0xF4, 0x4C, 0x42, 0xE9, 0xA6, 0x37, 0xED, 0x6B,
+	0x0B, 0xFF, 0x5C, 0xB6, 0xF4, 0x06, 0xB7, 0xED,
+	0xEE, 0x38, 0x6B, 0xFB, 0x5A, 0x89, 0x9F, 0xA5,
+	0xAE, 0x9F, 0x24, 0x11, 0x7C, 0x4B, 0x1F, 0xE6,
+	0x49, 0x28, 0x66, 0x51, 0xEC, 0xE4, 0x5B, 0x3D,
+	0xC2, 0x00, 0x7C, 0xB8, 0xA1, 0x63, 0xBF, 0x05,
+	0x98, 0xDA, 0x48, 0x36, 0x1C, 0x55, 0xD3, 0x9A,
+	0x69, 0x16, 0x3F, 0xA8, 0xFD, 0x24, 0xCF, 0x5F,
+	0x83, 0x65, 0x5D, 0x23, 0xDC, 0xA3, 0xAD, 0x96,
+	0x1C, 0x62, 0xF3, 0x56, 0x20, 0x85, 0x52, 0xBB,
+	0x9E, 0xD5, 0x29, 0x07, 0x70, 0x96, 0x96, 0x6D,
+	0x67, 0x0C, 0x35, 0x4E, 0x4A, 0xBC, 0x98, 0x04,
+	0xF1, 0x74, 0x6C, 0x08, 0xCA, 0x18, 0x21, 0x7C,
+	0x32, 0x90, 0x5E, 0x46, 0x2E, 0x36, 0xCE, 0x3B,
+	0xE3, 0x9E, 0x77, 0x2C, 0x18, 0x0E, 0x86, 0x03,
+	0x9B, 0x27, 0x83, 0xA2, 0xEC, 0x07, 0xA2, 0x8F,
+	0xB5, 0xC5, 0x5D, 0xF0, 0x6F, 0x4C, 0x52, 0xC9,
+	0xDE, 0x2B, 0xCB, 0xF6, 0x95, 0x58, 0x17, 0x18,
+	0x39, 0x95, 0x49, 0x7C, 0xEA, 0x95, 0x6A, 0xE5,
+	0x15, 0xD2, 0x26, 0x18, 0x98, 0xFA, 0x05, 0x10,
+	0x15, 0x72, 0x8E, 0x5A, 0x8A, 0xAA, 0xC4, 0x2D,
+	0xAD, 0x33, 0x17, 0x0D, 0x04, 0x50, 0x7A, 0x33,
+	0xA8, 0x55, 0x21, 0xAB, 0xDF, 0x1C, 0xBA, 0x64,
+	0xEC, 0xFB, 0x85, 0x04, 0x58, 0xDB, 0xEF, 0x0A,
+	0x8A, 0xEA, 0x71, 0x57, 0x5D, 0x06, 0x0C, 0x7D,
+	0xB3, 0x97, 0x0F, 0x85, 0xA6, 0xE1, 0xE4, 0xC7,
+	0xAB, 0xF5, 0xAE, 0x8C, 0xDB, 0x09, 0x33, 0xD7,
+	0x1E, 0x8C, 0x94, 0xE0, 0x4A, 0x25, 0x61, 0x9D,
+	0xCE, 0xE3, 0xD2, 0x26, 0x1A, 0xD2, 0xEE, 0x6B,
+	0xF1, 0x2F, 0xFA, 0x06, 0xD9, 0x8A, 0x08, 0x64,
+	0xD8, 0x76, 0x02, 0x73, 0x3E, 0xC8, 0x6A, 0x64,
+	0x52, 0x1F, 0x2B, 0x18, 0x17, 0x7B, 0x20, 0x0C,
+	0xBB, 0xE1, 0x17, 0x57, 0x7A, 0x61, 0x5D, 0x6C,
+	0x77, 0x09, 0x88, 0xC0, 0xBA, 0xD9, 0x46, 0xE2,
+	0x08, 0xE2, 0x4F, 0xA0, 0x74, 0xE5, 0xAB, 0x31,
+	0x43, 0xDB, 0x5B, 0xFC, 0xE0, 0xFD, 0x10, 0x8E,
+	0x4B, 0x82, 0xD1, 0x20, 0xA9, 0x21, 0x08, 0x01,
+	0x1A, 0x72, 0x3C, 0x12, 0xA7, 0x87, 0xE6, 0xD7,
+	0x88, 0x71, 0x9A, 0x10, 0xBD, 0xBA, 0x5B, 0x26,
+	0x99, 0xC3, 0x27, 0x18, 0x6A, 0xF4, 0xE2, 0x3C,
+	0x1A, 0x94, 0x68, 0x34, 0xB6, 0x15, 0x0B, 0xDA,
+	0x25, 0x83, 0xE9, 0xCA, 0x2A, 0xD4, 0x4C, 0xE8,
+	0xDB, 0xBB, 0xC2, 0xDB, 0x04, 0xDE, 0x8E, 0xF9,
+	0x2E, 0x8E, 0xFC, 0x14, 0x1F, 0xBE, 0xCA, 0xA6,
+	0x28, 0x7C, 0x59, 0x47, 0x4E, 0x6B, 0xC0, 0x5D,
+	0x99, 0xB2, 0x96, 0x4F, 0xA0, 0x90, 0xC3, 0xA2,
+	0x23, 0x3B, 0xA1, 0x86, 0x51, 0x5B, 0xE7, 0xED,
+	0x1F, 0x61, 0x29, 0x70, 0xCE, 0xE2, 0xD7, 0xAF,
+	0xB8, 0x1B, 0xDD, 0x76, 0x21, 0x70, 0x48, 0x1C,
+	0xD0, 0x06, 0x91, 0x27, 0xD5, 0xB0, 0x5A, 0xA9,
+	0x93, 0xB4, 0xEA, 0x98, 0x8D, 0x8F, 0xDD, 0xC1,
+	0x86, 0xFF, 0xB7, 0xDC, 0x90, 0xA6, 0xC0, 0x8F,
+	0x4D, 0xF4, 0x35, 0xC9, 0x34, 0x02, 0x84, 0x92,
+	0x36, 0xC3, 0xFA, 0xB4, 0xD2, 0x7C, 0x70, 0x26,
+	0xC1, 0xD4, 0xDC, 0xB2, 0x60, 0x26, 0x46, 0xDE,
+	0xC9, 0x75, 0x1E, 0x76, 0x3D, 0xBA, 0x37, 0xBD,
+	0xF8, 0xFF, 0x94, 0x06, 0xAD, 0x9E, 0x53, 0x0E,
+	0xE5, 0xDB, 0x38, 0x2F, 0x41, 0x30, 0x01, 0xAE,
+	0xB0, 0x6A, 0x53, 0xED, 0x90, 0x27, 0xD8, 0x31,
+	0x17, 0x97, 0x27, 0xB0, 0x86, 0x5A, 0x89, 0x18,
+	0xDA, 0x3E, 0xDB, 0xEB, 0xCF, 0x9B, 0x14, 0xED,
+	0x44, 0xCE, 0x6C, 0xBA, 0xCE, 0xD4, 0xBB, 0x1B,
+	0xDB, 0x7F, 0x14, 0x47, 0xE6, 0xCC, 0x25, 0x4B,
+	0x33, 0x20, 0x51, 0x51, 0x2B, 0xD7, 0xAF, 0x42,
+	0x6F, 0xB8, 0xF4, 0x01, 0x37, 0x8C, 0xD2, 0xBF,
+	0x59, 0x83, 0xCA, 0x01, 0xC6, 0x4B, 0x92, 0xEC,
+	0xF0, 0x32, 0xEA, 0x15, 0xD1, 0x72, 0x1D, 0x03,
+	0xF4, 0x82, 0xD7, 0xCE, 0x6E, 0x74, 0xFE, 0xF6,
+	0xD5, 0x5E, 0x70, 0x2F, 0x46, 0x98, 0x0C, 0x82,
+	0xB5, 0xA8, 0x40, 0x31, 0x90, 0x0B, 0x1C, 0x9E,
+	0x59, 0xE7, 0xC9, 0x7F, 0xBE, 0xC7, 0xE8, 0xF3,
+	0x23, 0xA9, 0x7A, 0x7E, 0x36, 0xCC, 0x88, 0xBE,
+	0x0F, 0x1D, 0x45, 0xB7, 0xFF, 0x58, 0x5A, 0xC5,
+	0x4B, 0xD4, 0x07, 0xB2, 0x2B, 0x41, 0x54, 0xAA,
+	0xCC, 0x8F, 0x6D, 0x7E, 0xBF, 0x48, 0xE1, 0xD8,
+	0x14, 0xCC, 0x5E, 0xD2, 0x0F, 0x80, 0x37, 0xE0,
+	0xA7, 0x97, 0x15, 0xEE, 0xF2, 0x9B, 0xE3, 0x28,
+	0x06, 0xA1, 0xD5, 0x8B, 0xB7, 0xC5, 0xDA, 0x76,
+	0xF5, 0x50, 0xAA, 0x3D, 0x8A, 0x1F, 0xBF, 0xF0,
+	0xEB, 0x19, 0xCC, 0xB1, 0xA3, 0x13, 0xD5, 0x5C,
+	0xDA, 0x56, 0xC9, 0xEC, 0x2E, 0xF2, 0x96, 0x32,
+	0x38, 0x7F, 0xE8, 0xD7, 0x6E, 0x3C, 0x04, 0x68,
+	0x04, 0x3E, 0x8F, 0x66, 0x3F, 0x48, 0x60, 0xEE,
+	0x12, 0xBF, 0x2D, 0x5B, 0x0B, 0x74, 0x74, 0xD6,
+	0xE6, 0x94, 0xF9, 0x1E, 0x6D, 0xBE, 0x11, 0x59,
+	0x74, 0xA3, 0x92, 0x6F, 0x12, 0xFE, 0xE5, 0xE4,
+	0x38, 0x77, 0x7C, 0xB6, 0xA9, 0x32, 0xDF, 0x8C,
+	0xD8, 0xBE, 0xC4, 0xD0, 0x73, 0xB9, 0x31, 0xBA,
+	0x3B, 0xC8, 0x32, 0xB6, 0x8D, 0x9D, 0xD3, 0x00,
+	0x74, 0x1F, 0xA7, 0xBF, 0x8A, 0xFC, 0x47, 0xED,
+	0x25, 0x76, 0xF6, 0x93, 0x6B, 0xA4, 0x24, 0x66,
+	0x3A, 0xAB, 0x63, 0x9C, 0x5A, 0xE4, 0xF5, 0x68,
+	0x34, 0x23, 0xB4, 0x74, 0x2B, 0xF1, 0xC9, 0x78,
+	0x23, 0x8F, 0x16, 0xCB, 0xE3, 0x9D, 0x65, 0x2D,
+	0xE3, 0xFD, 0xB8, 0xBE, 0xFC, 0x84, 0x8A, 0xD9,
+	0x22, 0x22, 0x2E, 0x04, 0xA4, 0x03, 0x7C, 0x07,
+	0x13, 0xEB, 0x57, 0xA8, 0x1A, 0x23, 0xF0, 0xC7,
+	0x34, 0x73, 0xFC, 0x64, 0x6C, 0xEA, 0x30, 0x6B,
+	0x4B, 0xCB, 0xC8, 0x86, 0x2F, 0x83, 0x85, 0xDD,
+	0xFA, 0x9D, 0x4B, 0x7F, 0xA2, 0xC0, 0x87, 0xE8,
+	0x79, 0x68, 0x33, 0x03, 0xED, 0x5B, 0xDD, 0x3A,
+	0x06, 0x2B, 0x3C, 0xF5, 0xB3, 0xA2, 0x78, 0xA6,
+	0x6D, 0x2A, 0x13, 0xF8, 0x3F, 0x44, 0xF8, 0x2D,
+	0xDF, 0x31, 0x0E, 0xE0, 0x74, 0xAB, 0x6A, 0x36,
+	0x45, 0x97, 0xE8, 0x99, 0xA0, 0x25, 0x5D, 0xC1,
+	0x64, 0xF3, 0x1C, 0xC5, 0x08, 0x46, 0x85, 0x1D,
+	0xF9, 0xAB, 0x48, 0x19, 0x5D, 0xED, 0x7E, 0xA1,
+	0xB1, 0xD5, 0x10, 0xBD, 0x7E, 0xE7, 0x4D, 0x73,
+	0xFA, 0xF3, 0x6B, 0xC3, 0x1E, 0xCF, 0xA2, 0x68,
+	0x35, 0x90, 0x46, 0xF4, 0xEB, 0x87, 0x9F, 0x92,
+	0x40, 0x09, 0x43, 0x8B, 0x48, 0x1C, 0x6C, 0xD7,
+	0x88, 0x9A, 0x00, 0x2E, 0xD5, 0xEE, 0x38, 0x2B,
+	0xC9, 0x19, 0x0D, 0xA6, 0xFC, 0x02, 0x6E, 0x47,
+	0x95, 0x58, 0xE4, 0x47, 0x56, 0x77, 0xE9, 0xAA,
+	0x9E, 0x30, 0x50, 0xE2, 0x76, 0x56, 0x94, 0xDF,
+	0xC8, 0x1F, 0x56, 0xE8, 0x80, 0xB9, 0x6E, 0x71,
+	0x60, 0xC9, 0x80, 0xDD, 0x98, 0xED, 0xD3, 0xDF,
+	0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+};
+
+#endif /* ALL_DH_GROUPS */
+
+
+#define DH_GROUP(id) \
+{ id, dh_group ## id ## _generator, sizeof(dh_group ## id ## _generator), \
+dh_group ## id ## _prime, sizeof(dh_group ## id ## _prime) }
+		
+
+static struct dh_group dh_groups[] = {
+	DH_GROUP(5),
+#ifdef ALL_DH_GROUPS
+	DH_GROUP(1),
+	DH_GROUP(2),
+	DH_GROUP(14),
+	DH_GROUP(15),
+	DH_GROUP(16),
+	DH_GROUP(17),
+	DH_GROUP(18)
+#endif /* ALL_DH_GROUPS */
+};
+
+#define NUM_DH_GROUPS (sizeof(dh_groups) / sizeof(dh_groups[0]))
+
+
+const struct dh_group * dh_groups_get(int id)
+{
+	size_t i;
+
+	for (i = 0; i < NUM_DH_GROUPS; i++) {
+		if (dh_groups[i].id == id)
+			return &dh_groups[i];
+	}
+	return NULL;
+}
+
+
+/**
+ * dh_init - Initialize Diffie-Hellman handshake
+ * @dh: Selected Diffie-Hellman group
+ * @priv: Pointer for returning Diffie-Hellman private key
+ * Returns: Diffie-Hellman public value
+ */
+struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv)
+{
+	struct wpabuf *pv;
+	size_t pv_len;
+
+	if (dh == NULL)
+		return NULL;
+
+	wpabuf_free(*priv);
+	*priv = wpabuf_alloc(dh->prime_len);
+	if (*priv == NULL)
+		return NULL;
+
+	if (random_get_bytes(wpabuf_put(*priv, dh->prime_len), dh->prime_len))
+	{
+		wpabuf_free(*priv);
+		*priv = NULL;
+		return NULL;
+	}
+
+	if (os_memcmp(wpabuf_head(*priv), dh->prime, dh->prime_len) > 0) {
+		/* Make sure private value is smaller than prime */
+		*(wpabuf_mhead_u8(*priv)) = 0;
+	}
+	wpa_hexdump_buf_key(MSG_DEBUG, "DH: private value", *priv);
+
+	pv_len = dh->prime_len;
+	pv = wpabuf_alloc(pv_len);
+	if (pv == NULL)
+		return NULL;
+	if (crypto_mod_exp(dh->generator, dh->generator_len,
+			   wpabuf_head(*priv), wpabuf_len(*priv),
+			   dh->prime, dh->prime_len, wpabuf_mhead(pv),
+			   &pv_len) < 0) {
+		wpabuf_free(pv);
+		wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
+		return NULL;
+	}
+	wpabuf_put(pv, pv_len);
+	wpa_hexdump_buf(MSG_DEBUG, "DH: public value", pv);
+
+	return pv;
+}
+
+
+/**
+ * dh_derive_shared - Derive shared Diffie-Hellman key
+ * @peer_public: Diffie-Hellman public value from peer
+ * @own_private: Diffie-Hellman private key from dh_init()
+ * @dh: Selected Diffie-Hellman group
+ * Returns: Diffie-Hellman shared key
+ */
+struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
+				 const struct wpabuf *own_private,
+				 const struct dh_group *dh)
+{
+	struct wpabuf *shared;
+	size_t shared_len;
+
+	if (dh == NULL || peer_public == NULL || own_private == NULL)
+		return NULL;
+
+	shared_len = dh->prime_len;
+	shared = wpabuf_alloc(shared_len);
+	if (shared == NULL)
+		return NULL;
+	if (crypto_mod_exp(wpabuf_head(peer_public), wpabuf_len(peer_public),
+			   wpabuf_head(own_private), wpabuf_len(own_private),
+			   dh->prime, dh->prime_len,
+			   wpabuf_mhead(shared), &shared_len) < 0) {
+		wpabuf_free(shared);
+		wpa_printf(MSG_INFO, "DH: crypto_mod_exp failed");
+		return NULL;
+	}
+	wpabuf_put(shared, shared_len);
+	wpa_hexdump_buf_key(MSG_DEBUG, "DH: shared key", shared);
+
+	return shared;
+}
diff --git a/hostap/src/crypto/dh_groups.h b/hostap/src/crypto/dh_groups.h
new file mode 100644
index 0000000..225f006
--- /dev/null
+++ b/hostap/src/crypto/dh_groups.h
@@ -0,0 +1,26 @@
+/*
+ * Diffie-Hellman groups
+ * Copyright (c) 2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef DH_GROUPS_H
+#define DH_GROUPS_H
+
+struct dh_group {
+	int id;
+	const u8 *generator;
+	size_t generator_len;
+	const u8 *prime;
+	size_t prime_len;
+};
+
+const struct dh_group * dh_groups_get(int id);
+struct wpabuf * dh_init(const struct dh_group *dh, struct wpabuf **priv);
+struct wpabuf * dh_derive_shared(const struct wpabuf *peer_public,
+				 const struct wpabuf *own_private,
+				 const struct dh_group *dh);
+
+#endif /* DH_GROUPS_H */
diff --git a/hostap/src/crypto/fips_prf_cryptoapi.c b/hostap/src/crypto/fips_prf_cryptoapi.c
new file mode 100644
index 0000000..dca93a3
--- /dev/null
+++ b/hostap/src/crypto/fips_prf_cryptoapi.c
@@ -0,0 +1,19 @@
+/*
+ * FIPS 186-2 PRF for Microsoft CryptoAPI
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+	/* FIX: how to do this with CryptoAPI? */
+	return -1;
+}
diff --git a/hostap/src/crypto/fips_prf_gnutls.c b/hostap/src/crypto/fips_prf_gnutls.c
new file mode 100644
index 0000000..947e6f6
--- /dev/null
+++ b/hostap/src/crypto/fips_prf_gnutls.c
@@ -0,0 +1,20 @@
+/*
+ * FIPS 186-2 PRF for libgcrypt
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <gcrypt.h>
+
+#include "common.h"
+#include "crypto.h"
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+	/* FIX: how to do this with libgcrypt? */
+	return -1;
+}
diff --git a/hostap/src/crypto/fips_prf_internal.c b/hostap/src/crypto/fips_prf_internal.c
new file mode 100644
index 0000000..a4bf50a
--- /dev/null
+++ b/hostap/src/crypto/fips_prf_internal.c
@@ -0,0 +1,69 @@
+/*
+ * FIPS 186-2 PRF for internal crypto implementation
+ * Copyright (c) 2006-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+#include "sha1_i.h"
+#include "crypto.h"
+
+
+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))
+		os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
+	else
+		seed_len = sizeof(xkey);
+
+	/* FIPS 186-2 + change notice 1 */
+
+	os_memcpy(xkey, seed, seed_len);
+	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);
+			SHA1Transform(_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 += SHA1_MAC_LEN;
+		}
+		/* x_j = w_0|w_1 */
+	}
+
+	return 0;
+}
diff --git a/hostap/src/crypto/fips_prf_nss.c b/hostap/src/crypto/fips_prf_nss.c
new file mode 100644
index 0000000..2c962f4
--- /dev/null
+++ b/hostap/src/crypto/fips_prf_nss.c
@@ -0,0 +1,19 @@
+/*
+ * FIPS 186-2 PRF for NSS
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <openssl/sha.h>
+
+#include "common.h"
+#include "crypto.h"
+
+
+int fips186_2_prf(const u8 *seed, size_t seed_len, u8 *x, size_t xlen)
+{
+	return -1;
+}
diff --git a/hostap/src/crypto/fips_prf_openssl.c b/hostap/src/crypto/fips_prf_openssl.c
new file mode 100644
index 0000000..d69ecea
--- /dev/null
+++ b/hostap/src/crypto/fips_prf_openssl.c
@@ -0,0 +1,78 @@
+/*
+ * FIPS 186-2 PRF for libcrypto
+ * Copyright (c) 2004-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <openssl/sha.h>
+
+#include "common.h"
+#include "crypto.h"
+
+
+static void sha1_transform(u8 *state, const u8 data[64])
+{
+	SHA_CTX context;
+	os_memset(&context, 0, sizeof(context));
+	os_memcpy(&context.h0, state, 5 * 4);
+	SHA1_Transform(&context, data);
+	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))
+		os_memset(xkey + seed_len, 0, sizeof(xkey) - seed_len);
+	else
+		seed_len = sizeof(xkey);
+
+	/* FIPS 186-2 + change notice 1 */
+
+	os_memcpy(xkey, seed, seed_len);
+	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;
+}
diff --git a/hostap/src/crypto/md4-internal.c b/hostap/src/crypto/md4-internal.c
new file mode 100644
index 0000000..cd5e6ca
--- /dev/null
+++ b/hostap/src/crypto/md4-internal.c
@@ -0,0 +1,272 @@
+/*
+ * MD4 hash implementation
+ * Copyright (c) 2006, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+
+#define	MD4_BLOCK_LENGTH		64
+#define	MD4_DIGEST_LENGTH		16
+
+typedef struct MD4Context {
+	u32 state[4];			/* state */
+	u64 count;			/* number of bits, mod 2^64 */
+	u8 buffer[MD4_BLOCK_LENGTH];	/* input buffer */
+} MD4_CTX;
+
+
+static void MD4Init(MD4_CTX *ctx);
+static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len);
+static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx);
+
+
+int md4_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	MD4_CTX ctx;
+	size_t i;
+
+	MD4Init(&ctx);
+	for (i = 0; i < num_elem; i++)
+		MD4Update(&ctx, addr[i], len[i]);
+	MD4Final(mac, &ctx);
+	return 0;
+}
+
+
+/* ===== start - public domain MD4 implementation ===== */
+/*	$OpenBSD: md4.c,v 1.7 2005/08/08 08:05:35 espie Exp $	*/
+
+/*
+ * This code implements the MD4 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.	This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ * Todd C. Miller modified the MD5 code to do MD4 based on RFC 1186.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD4Context structure, pass it to MD4Init, call MD4Update as
+ * needed on buffers full of bytes, and then call MD4Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#define	MD4_DIGEST_STRING_LENGTH	(MD4_DIGEST_LENGTH * 2 + 1)
+
+
+static void
+MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH]);
+
+#define PUT_64BIT_LE(cp, value) do {					\
+	(cp)[7] = (value) >> 56;					\
+	(cp)[6] = (value) >> 48;					\
+	(cp)[5] = (value) >> 40;					\
+	(cp)[4] = (value) >> 32;					\
+	(cp)[3] = (value) >> 24;					\
+	(cp)[2] = (value) >> 16;					\
+	(cp)[1] = (value) >> 8;						\
+	(cp)[0] = (value); } while (0)
+
+#define PUT_32BIT_LE(cp, value) do {					\
+	(cp)[3] = (value) >> 24;					\
+	(cp)[2] = (value) >> 16;					\
+	(cp)[1] = (value) >> 8;						\
+	(cp)[0] = (value); } while (0)
+
+static u8 PADDING[MD4_BLOCK_LENGTH] = {
+	0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/*
+ * Start MD4 accumulation.
+ * Set bit count to 0 and buffer to mysterious initialization constants.
+ */
+static void MD4Init(MD4_CTX *ctx)
+{
+	ctx->count = 0;
+	ctx->state[0] = 0x67452301;
+	ctx->state[1] = 0xefcdab89;
+	ctx->state[2] = 0x98badcfe;
+	ctx->state[3] = 0x10325476;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+static void MD4Update(MD4_CTX *ctx, const unsigned char *input, size_t len)
+{
+	size_t have, need;
+
+	/* Check how many bytes we already have and how many more we need. */
+	have = (size_t)((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1));
+	need = MD4_BLOCK_LENGTH - have;
+
+	/* Update bitcount */
+	ctx->count += (u64)len << 3;
+
+	if (len >= need) {
+		if (have != 0) {
+			os_memcpy(ctx->buffer + have, input, need);
+			MD4Transform(ctx->state, ctx->buffer);
+			input += need;
+			len -= need;
+			have = 0;
+		}
+
+		/* Process data in MD4_BLOCK_LENGTH-byte chunks. */
+		while (len >= MD4_BLOCK_LENGTH) {
+			MD4Transform(ctx->state, input);
+			input += MD4_BLOCK_LENGTH;
+			len -= MD4_BLOCK_LENGTH;
+		}
+	}
+
+	/* Handle any remaining bytes of data. */
+	if (len != 0)
+		os_memcpy(ctx->buffer + have, input, len);
+}
+
+/*
+ * Pad pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+static void MD4Pad(MD4_CTX *ctx)
+{
+	u8 count[8];
+	size_t padlen;
+
+	/* Convert count to 8 bytes in little endian order. */
+	PUT_64BIT_LE(count, ctx->count);
+
+	/* Pad out to 56 mod 64. */
+	padlen = MD4_BLOCK_LENGTH -
+	    ((ctx->count >> 3) & (MD4_BLOCK_LENGTH - 1));
+	if (padlen < 1 + 8)
+		padlen += MD4_BLOCK_LENGTH;
+	MD4Update(ctx, PADDING, padlen - 8);		/* padlen - 8 <= 64 */
+	MD4Update(ctx, count, 8);
+}
+
+/*
+ * Final wrapup--call MD4Pad, fill in digest and zero out ctx.
+ */
+static void MD4Final(unsigned char digest[MD4_DIGEST_LENGTH], MD4_CTX *ctx)
+{
+	int i;
+
+	MD4Pad(ctx);
+	if (digest != NULL) {
+		for (i = 0; i < 4; i++)
+			PUT_32BIT_LE(digest + i * 4, ctx->state[i]);
+		os_memset(ctx, 0, sizeof(*ctx));
+	}
+}
+
+
+/* The three core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) ((x & y) | (x & z) | (y & z))
+#define F3(x, y, z) (x ^ y ^ z)
+
+/* This is the central step in the MD4 algorithm. */
+#define MD4STEP(f, w, x, y, z, data, s) \
+	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s) )
+
+/*
+ * The core of the MD4 algorithm, this alters an existing MD4 hash to
+ * reflect the addition of 16 longwords of new data.  MD4Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void
+MD4Transform(u32 state[4], const u8 block[MD4_BLOCK_LENGTH])
+{
+	u32 a, b, c, d, in[MD4_BLOCK_LENGTH / 4];
+
+#if BYTE_ORDER == LITTLE_ENDIAN
+	os_memcpy(in, block, sizeof(in));
+#else
+	for (a = 0; a < MD4_BLOCK_LENGTH / 4; a++) {
+		in[a] = (u32)(
+		    (u32)(block[a * 4 + 0]) |
+		    (u32)(block[a * 4 + 1]) <<  8 |
+		    (u32)(block[a * 4 + 2]) << 16 |
+		    (u32)(block[a * 4 + 3]) << 24);
+	}
+#endif
+
+	a = state[0];
+	b = state[1];
+	c = state[2];
+	d = state[3];
+
+	MD4STEP(F1, a, b, c, d, in[ 0],  3);
+	MD4STEP(F1, d, a, b, c, in[ 1],  7);
+	MD4STEP(F1, c, d, a, b, in[ 2], 11);
+	MD4STEP(F1, b, c, d, a, in[ 3], 19);
+	MD4STEP(F1, a, b, c, d, in[ 4],  3);
+	MD4STEP(F1, d, a, b, c, in[ 5],  7);
+	MD4STEP(F1, c, d, a, b, in[ 6], 11);
+	MD4STEP(F1, b, c, d, a, in[ 7], 19);
+	MD4STEP(F1, a, b, c, d, in[ 8],  3);
+	MD4STEP(F1, d, a, b, c, in[ 9],  7);
+	MD4STEP(F1, c, d, a, b, in[10], 11);
+	MD4STEP(F1, b, c, d, a, in[11], 19);
+	MD4STEP(F1, a, b, c, d, in[12],  3);
+	MD4STEP(F1, d, a, b, c, in[13],  7);
+	MD4STEP(F1, c, d, a, b, in[14], 11);
+	MD4STEP(F1, b, c, d, a, in[15], 19);
+
+	MD4STEP(F2, a, b, c, d, in[ 0] + 0x5a827999,  3);
+	MD4STEP(F2, d, a, b, c, in[ 4] + 0x5a827999,  5);
+	MD4STEP(F2, c, d, a, b, in[ 8] + 0x5a827999,  9);
+	MD4STEP(F2, b, c, d, a, in[12] + 0x5a827999, 13);
+	MD4STEP(F2, a, b, c, d, in[ 1] + 0x5a827999,  3);
+	MD4STEP(F2, d, a, b, c, in[ 5] + 0x5a827999,  5);
+	MD4STEP(F2, c, d, a, b, in[ 9] + 0x5a827999,  9);
+	MD4STEP(F2, b, c, d, a, in[13] + 0x5a827999, 13);
+	MD4STEP(F2, a, b, c, d, in[ 2] + 0x5a827999,  3);
+	MD4STEP(F2, d, a, b, c, in[ 6] + 0x5a827999,  5);
+	MD4STEP(F2, c, d, a, b, in[10] + 0x5a827999,  9);
+	MD4STEP(F2, b, c, d, a, in[14] + 0x5a827999, 13);
+	MD4STEP(F2, a, b, c, d, in[ 3] + 0x5a827999,  3);
+	MD4STEP(F2, d, a, b, c, in[ 7] + 0x5a827999,  5);
+	MD4STEP(F2, c, d, a, b, in[11] + 0x5a827999,  9);
+	MD4STEP(F2, b, c, d, a, in[15] + 0x5a827999, 13);
+
+	MD4STEP(F3, a, b, c, d, in[ 0] + 0x6ed9eba1,  3);
+	MD4STEP(F3, d, a, b, c, in[ 8] + 0x6ed9eba1,  9);
+	MD4STEP(F3, c, d, a, b, in[ 4] + 0x6ed9eba1, 11);
+	MD4STEP(F3, b, c, d, a, in[12] + 0x6ed9eba1, 15);
+	MD4STEP(F3, a, b, c, d, in[ 2] + 0x6ed9eba1,  3);
+	MD4STEP(F3, d, a, b, c, in[10] + 0x6ed9eba1,  9);
+	MD4STEP(F3, c, d, a, b, in[ 6] + 0x6ed9eba1, 11);
+	MD4STEP(F3, b, c, d, a, in[14] + 0x6ed9eba1, 15);
+	MD4STEP(F3, a, b, c, d, in[ 1] + 0x6ed9eba1,  3);
+	MD4STEP(F3, d, a, b, c, in[ 9] + 0x6ed9eba1,  9);
+	MD4STEP(F3, c, d, a, b, in[ 5] + 0x6ed9eba1, 11);
+	MD4STEP(F3, b, c, d, a, in[13] + 0x6ed9eba1, 15);
+	MD4STEP(F3, a, b, c, d, in[ 3] + 0x6ed9eba1,  3);
+	MD4STEP(F3, d, a, b, c, in[11] + 0x6ed9eba1,  9);
+	MD4STEP(F3, c, d, a, b, in[ 7] + 0x6ed9eba1, 11);
+	MD4STEP(F3, b, c, d, a, in[15] + 0x6ed9eba1, 15);
+
+	state[0] += a;
+	state[1] += b;
+	state[2] += c;
+	state[3] += d;
+}
+/* ===== end - public domain MD4 implementation ===== */
diff --git a/hostap/src/crypto/md5-internal.c b/hostap/src/crypto/md5-internal.c
new file mode 100644
index 0000000..f0a2a5d
--- /dev/null
+++ b/hostap/src/crypto/md5-internal.c
@@ -0,0 +1,287 @@
+/*
+ * MD5 hash implementation and interface functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "md5.h"
+#include "md5_i.h"
+#include "crypto.h"
+
+
+static void MD5Transform(u32 buf[4], u32 const in[16]);
+
+
+typedef struct MD5Context MD5_CTX;
+
+
+/**
+ * md5_vector - MD5 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 of failure
+ */
+int md5_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	MD5_CTX ctx;
+	size_t i;
+
+	MD5Init(&ctx);
+	for (i = 0; i < num_elem; i++)
+		MD5Update(&ctx, addr[i], len[i]);
+	MD5Final(mac, &ctx);
+	return 0;
+}
+
+
+/* ===== start - public domain MD5 implementation ===== */
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest.  This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+
+#ifndef WORDS_BIGENDIAN
+#define byteReverse(buf, len)	/* Nothing */
+#else
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+    u32 t;
+    do {
+	t = (u32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+	    ((unsigned) buf[1] << 8 | buf[0]);
+	*(u32 *) buf = t;
+	buf += 4;
+    } while (--longs);
+}
+#endif
+
+/*
+ * Start MD5 accumulation.  Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD5Init(struct MD5Context *ctx)
+{
+    ctx->buf[0] = 0x67452301;
+    ctx->buf[1] = 0xefcdab89;
+    ctx->buf[2] = 0x98badcfe;
+    ctx->buf[3] = 0x10325476;
+
+    ctx->bits[0] = 0;
+    ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+    u32 t;
+
+    /* Update bitcount */
+
+    t = ctx->bits[0];
+    if ((ctx->bits[0] = t + ((u32) len << 3)) < t)
+	ctx->bits[1]++;		/* Carry from low to high */
+    ctx->bits[1] += len >> 29;
+
+    t = (t >> 3) & 0x3f;	/* Bytes already in shsInfo->data */
+
+    /* Handle any leading odd-sized chunks */
+
+    if (t) {
+	unsigned char *p = (unsigned char *) ctx->in + t;
+
+	t = 64 - t;
+	if (len < t) {
+	    os_memcpy(p, buf, len);
+	    return;
+	}
+	os_memcpy(p, buf, t);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (u32 *) ctx->in);
+	buf += t;
+	len -= t;
+    }
+    /* Process data in 64-byte chunks */
+
+    while (len >= 64) {
+	os_memcpy(ctx->in, buf, 64);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (u32 *) ctx->in);
+	buf += 64;
+	len -= 64;
+    }
+
+    /* Handle any remaining bytes of data. */
+
+    os_memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+    unsigned count;
+    unsigned char *p;
+
+    /* Compute number of bytes mod 64 */
+    count = (ctx->bits[0] >> 3) & 0x3F;
+
+    /* Set the first char of padding to 0x80.  This is safe since there is
+       always at least one byte free */
+    p = ctx->in + count;
+    *p++ = 0x80;
+
+    /* Bytes of padding needed to make 64 bytes */
+    count = 64 - 1 - count;
+
+    /* Pad out to 56 mod 64 */
+    if (count < 8) {
+	/* Two lots of padding:  Pad the first block to 64 bytes */
+	os_memset(p, 0, count);
+	byteReverse(ctx->in, 16);
+	MD5Transform(ctx->buf, (u32 *) ctx->in);
+
+	/* Now fill the next block with 56 bytes */
+	os_memset(ctx->in, 0, 56);
+    } else {
+	/* Pad block to 56 bytes */
+	os_memset(p, 0, count - 8);
+    }
+    byteReverse(ctx->in, 14);
+
+    /* Append length in bits and transform */
+    ((u32 *) aliasing_hide_typecast(ctx->in, u32))[14] = ctx->bits[0];
+    ((u32 *) aliasing_hide_typecast(ctx->in, u32))[15] = ctx->bits[1];
+
+    MD5Transform(ctx->buf, (u32 *) ctx->in);
+    byteReverse((unsigned char *) ctx->buf, 4);
+    os_memcpy(digest, ctx->buf, 16);
+    os_memset(ctx, 0, sizeof(*ctx));	/* In case it's sensitive */
+}
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+	( w += f(x, y, z) + data,  w = w<<s | w>>(32-s),  w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data.  MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+static void MD5Transform(u32 buf[4], u32 const in[16])
+{
+    register u32 a, b, c, d;
+
+    a = buf[0];
+    b = buf[1];
+    c = buf[2];
+    d = buf[3];
+
+    MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+    MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+    MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+    MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+    MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+    MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+    MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+    MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+    MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+    MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+    MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+    MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+    MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+    MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+    MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+    MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+    MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+    MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+    MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+    MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+    MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+    MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+    MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+    MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+    MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+    MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+    MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+    MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+    MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+    MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+    MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+    MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+    MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+    MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+    MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+    MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+    MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+    MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+    MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+    MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+    MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+    MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+    MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+    MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+    MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+    MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+    MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+    MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+    MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+    MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+    MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+    MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+    MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+    MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+    MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+    MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+    MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+    MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+    MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+    MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+    MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+    MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+    MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+    MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+    buf[0] += a;
+    buf[1] += b;
+    buf[2] += c;
+    buf[3] += d;
+}
+/* ===== end - public domain MD5 implementation ===== */
diff --git a/hostap/src/crypto/md5-non-fips.c b/hostap/src/crypto/md5-non-fips.c
new file mode 100644
index 0000000..418f782
--- /dev/null
+++ b/hostap/src/crypto/md5-non-fips.c
@@ -0,0 +1,107 @@
+/*
+ * MD5 hash implementation and interface functions (non-FIPS allowed cases)
+ * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "md5.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_md5_vector_non_fips_allow - HMAC-MD5 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash (16 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_md5_vector_non_fips_allow(const u8 *key, size_t key_len,
+				   size_t num_elem, const u8 *addr[],
+				   const size_t *len, u8 *mac)
+{
+	u8 k_pad[64]; /* padding - key XORd with ipad/opad */
+	u8 tk[16];
+	const u8 *_addr[6];
+	size_t i, _len[6];
+
+	if (num_elem > 5) {
+		/*
+		 * Fixed limit on the number of fragments to avoid having to
+		 * allocate memory (which could fail).
+		 */
+		return -1;
+	}
+
+        /* if key is longer than 64 bytes reset it to key = MD5(key) */
+        if (key_len > 64) {
+		if (md5_vector_non_fips_allow(1, &key, &key_len, tk))
+			return -1;
+		key = tk;
+		key_len = 16;
+        }
+
+	/* the HMAC_MD5 transform looks like:
+	 *
+	 * MD5(K XOR opad, MD5(K XOR ipad, text))
+	 *
+	 * where K is an n byte key
+	 * ipad is the byte 0x36 repeated 64 times
+	 * opad is the byte 0x5c repeated 64 times
+	 * and text is the data being protected */
+
+	/* start out by storing key in ipad */
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+
+	/* XOR key with ipad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x36;
+
+	/* perform inner MD5 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	for (i = 0; i < num_elem; i++) {
+		_addr[i + 1] = addr[i];
+		_len[i + 1] = len[i];
+	}
+	if (md5_vector_non_fips_allow(1 + num_elem, _addr, _len, mac))
+		return -1;
+
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+	/* XOR key with opad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x5c;
+
+	/* perform outer MD5 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	_addr[1] = mac;
+	_len[1] = MD5_MAC_LEN;
+	return md5_vector_non_fips_allow(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_md5_non_fips_allow - HMAC-MD5 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (16 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_md5_non_fips_allow(const u8 *key, size_t key_len, const u8 *data,
+			    size_t data_len, u8 *mac)
+{
+	return hmac_md5_vector_non_fips_allow(key, key_len, 1, &data,
+					      &data_len, mac);
+}
diff --git a/hostap/src/crypto/md5.c b/hostap/src/crypto/md5.c
new file mode 100644
index 0000000..db2b8cc
--- /dev/null
+++ b/hostap/src/crypto/md5.c
@@ -0,0 +1,105 @@
+/*
+ * MD5 hash implementation and interface functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "md5.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_md5_vector - HMAC-MD5 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash (16 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+		    const u8 *addr[], const size_t *len, u8 *mac)
+{
+	u8 k_pad[64]; /* padding - key XORd with ipad/opad */
+	u8 tk[16];
+	const u8 *_addr[6];
+	size_t i, _len[6];
+
+	if (num_elem > 5) {
+		/*
+		 * Fixed limit on the number of fragments to avoid having to
+		 * allocate memory (which could fail).
+		 */
+		return -1;
+	}
+
+        /* if key is longer than 64 bytes reset it to key = MD5(key) */
+        if (key_len > 64) {
+		if (md5_vector(1, &key, &key_len, tk))
+			return -1;
+		key = tk;
+		key_len = 16;
+        }
+
+	/* the HMAC_MD5 transform looks like:
+	 *
+	 * MD5(K XOR opad, MD5(K XOR ipad, text))
+	 *
+	 * where K is an n byte key
+	 * ipad is the byte 0x36 repeated 64 times
+	 * opad is the byte 0x5c repeated 64 times
+	 * and text is the data being protected */
+
+	/* start out by storing key in ipad */
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+
+	/* XOR key with ipad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x36;
+
+	/* perform inner MD5 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	for (i = 0; i < num_elem; i++) {
+		_addr[i + 1] = addr[i];
+		_len[i + 1] = len[i];
+	}
+	if (md5_vector(1 + num_elem, _addr, _len, mac))
+		return -1;
+
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+	/* XOR key with opad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x5c;
+
+	/* perform outer MD5 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	_addr[1] = mac;
+	_len[1] = MD5_MAC_LEN;
+	return md5_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_md5 - HMAC-MD5 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (16 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	      u8 *mac)
+{
+	return hmac_md5_vector(key, key_len, 1, &data, &data_len, mac);
+}
diff --git a/hostap/src/crypto/md5.h b/hostap/src/crypto/md5.h
new file mode 100644
index 0000000..33f8426
--- /dev/null
+++ b/hostap/src/crypto/md5.h
@@ -0,0 +1,19 @@
+/*
+ * MD5 hash implementation and interface functions
+ * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MD5_H
+#define MD5_H
+
+#define MD5_MAC_LEN 16
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+		    const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_md5(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	     u8 *mac);
+
+#endif /* MD5_H */
diff --git a/hostap/src/crypto/md5_i.h b/hostap/src/crypto/md5_i.h
new file mode 100644
index 0000000..7dfc100
--- /dev/null
+++ b/hostap/src/crypto/md5_i.h
@@ -0,0 +1,23 @@
+/*
+ * MD5 internal definitions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MD5_I_H
+#define MD5_I_H
+
+struct MD5Context {
+	u32 buf[4];
+	u32 bits[2];
+	u8 in[64];
+};
+
+void MD5Init(struct MD5Context *context);
+void MD5Update(struct MD5Context *context, unsigned char const *buf,
+	       unsigned len);
+void MD5Final(unsigned char digest[16], struct MD5Context *context);
+
+#endif /* MD5_I_H */
diff --git a/hostap/src/crypto/milenage.c b/hostap/src/crypto/milenage.c
new file mode 100644
index 0000000..a7f9c6a
--- /dev/null
+++ b/hostap/src/crypto/milenage.c
@@ -0,0 +1,323 @@
+/*
+ * 3GPP AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
+ * Copyright (c) 2006-2007 <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file implements an example authentication algorithm defined for 3GPP
+ * AKA. This can be used to implement a simple HLR/AuC into hlr_auc_gw to allow
+ * EAP-AKA to be tested properly with real USIM cards.
+ *
+ * This implementations assumes that the r1..r5 and c1..c5 constants defined in
+ * TS 35.206 are used, i.e., r1=64, r2=0, r3=32, r4=64, r5=96, c1=00..00,
+ * c2=00..01, c3=00..02, c4=00..04, c5=00..08. The block cipher is assumed to
+ * be AES (Rijndael).
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto/aes_wrap.h"
+#include "milenage.h"
+
+
+/**
+ * milenage_f1 - Milenage f1 and f1* algorithms
+ * @opc: OPc = 128-bit value derived from OP and K
+ * @k: K = 128-bit subscriber key
+ * @_rand: RAND = 128-bit random challenge
+ * @sqn: SQN = 48-bit sequence number
+ * @amf: AMF = 16-bit authentication management field
+ * @mac_a: Buffer for MAC-A = 64-bit network authentication code, or %NULL
+ * @mac_s: Buffer for MAC-S = 64-bit resync authentication code, or %NULL
+ * Returns: 0 on success, -1 on failure
+ */
+int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand,
+		const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s)
+{
+	u8 tmp1[16], tmp2[16], tmp3[16];
+	int i;
+
+	/* tmp1 = TEMP = E_K(RAND XOR OP_C) */
+	for (i = 0; i < 16; i++)
+		tmp1[i] = _rand[i] ^ opc[i];
+	if (aes_128_encrypt_block(k, tmp1, tmp1))
+		return -1;
+
+	/* tmp2 = IN1 = SQN || AMF || SQN || AMF */
+	os_memcpy(tmp2, sqn, 6);
+	os_memcpy(tmp2 + 6, amf, 2);
+	os_memcpy(tmp2 + 8, tmp2, 8);
+
+	/* OUT1 = E_K(TEMP XOR rot(IN1 XOR OP_C, r1) XOR c1) XOR OP_C */
+
+	/* rotate (tmp2 XOR OP_C) by r1 (= 0x40 = 8 bytes) */
+	for (i = 0; i < 16; i++)
+		tmp3[(i + 8) % 16] = tmp2[i] ^ opc[i];
+	/* XOR with TEMP = E_K(RAND XOR OP_C) */
+	for (i = 0; i < 16; i++)
+		tmp3[i] ^= tmp1[i];
+	/* XOR with c1 (= ..00, i.e., NOP) */
+
+	/* f1 || f1* = E_K(tmp3) XOR OP_c */
+	if (aes_128_encrypt_block(k, tmp3, tmp1))
+		return -1;
+	for (i = 0; i < 16; i++)
+		tmp1[i] ^= opc[i];
+	if (mac_a)
+		os_memcpy(mac_a, tmp1, 8); /* f1 */
+	if (mac_s)
+		os_memcpy(mac_s, tmp1 + 8, 8); /* f1* */
+	return 0;
+}
+
+
+/**
+ * milenage_f2345 - Milenage f2, f3, f4, f5, f5* algorithms
+ * @opc: OPc = 128-bit value derived from OP and K
+ * @k: K = 128-bit subscriber key
+ * @_rand: RAND = 128-bit random challenge
+ * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
+ * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
+ * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
+ * @ak: Buffer for AK = 48-bit anonymity key (f5), or %NULL
+ * @akstar: Buffer for AK = 48-bit anonymity key (f5*), or %NULL
+ * Returns: 0 on success, -1 on failure
+ */
+int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand,
+		   u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar)
+{
+	u8 tmp1[16], tmp2[16], tmp3[16];
+	int i;
+
+	/* tmp2 = TEMP = E_K(RAND XOR OP_C) */
+	for (i = 0; i < 16; i++)
+		tmp1[i] = _rand[i] ^ opc[i];
+	if (aes_128_encrypt_block(k, tmp1, tmp2))
+		return -1;
+
+	/* OUT2 = E_K(rot(TEMP XOR OP_C, r2) XOR c2) XOR OP_C */
+	/* OUT3 = E_K(rot(TEMP XOR OP_C, r3) XOR c3) XOR OP_C */
+	/* OUT4 = E_K(rot(TEMP XOR OP_C, r4) XOR c4) XOR OP_C */
+	/* OUT5 = E_K(rot(TEMP XOR OP_C, r5) XOR c5) XOR OP_C */
+
+	/* f2 and f5 */
+	/* rotate by r2 (= 0, i.e., NOP) */
+	for (i = 0; i < 16; i++)
+		tmp1[i] = tmp2[i] ^ opc[i];
+	tmp1[15] ^= 1; /* XOR c2 (= ..01) */
+	/* f5 || f2 = E_K(tmp1) XOR OP_c */
+	if (aes_128_encrypt_block(k, tmp1, tmp3))
+		return -1;
+	for (i = 0; i < 16; i++)
+		tmp3[i] ^= opc[i];
+	if (res)
+		os_memcpy(res, tmp3 + 8, 8); /* f2 */
+	if (ak)
+		os_memcpy(ak, tmp3, 6); /* f5 */
+
+	/* f3 */
+	if (ck) {
+		/* rotate by r3 = 0x20 = 4 bytes */
+		for (i = 0; i < 16; i++)
+			tmp1[(i + 12) % 16] = tmp2[i] ^ opc[i];
+		tmp1[15] ^= 2; /* XOR c3 (= ..02) */
+		if (aes_128_encrypt_block(k, tmp1, ck))
+			return -1;
+		for (i = 0; i < 16; i++)
+			ck[i] ^= opc[i];
+	}
+
+	/* f4 */
+	if (ik) {
+		/* rotate by r4 = 0x40 = 8 bytes */
+		for (i = 0; i < 16; i++)
+			tmp1[(i + 8) % 16] = tmp2[i] ^ opc[i];
+		tmp1[15] ^= 4; /* XOR c4 (= ..04) */
+		if (aes_128_encrypt_block(k, tmp1, ik))
+			return -1;
+		for (i = 0; i < 16; i++)
+			ik[i] ^= opc[i];
+	}
+
+	/* f5* */
+	if (akstar) {
+		/* rotate by r5 = 0x60 = 12 bytes */
+		for (i = 0; i < 16; i++)
+			tmp1[(i + 4) % 16] = tmp2[i] ^ opc[i];
+		tmp1[15] ^= 8; /* XOR c5 (= ..08) */
+		if (aes_128_encrypt_block(k, tmp1, tmp1))
+			return -1;
+		for (i = 0; i < 6; i++)
+			akstar[i] = tmp1[i] ^ opc[i];
+	}
+
+	return 0;
+}
+
+
+/**
+ * milenage_generate - Generate AKA AUTN,IK,CK,RES
+ * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
+ * @amf: AMF = 16-bit authentication management field
+ * @k: K = 128-bit subscriber key
+ * @sqn: SQN = 48-bit sequence number
+ * @_rand: RAND = 128-bit random challenge
+ * @autn: Buffer for AUTN = 128-bit authentication token
+ * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
+ * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
+ * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
+ * @res_len: Max length for res; set to used length or 0 on failure
+ */
+void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k,
+		       const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik,
+		       u8 *ck, u8 *res, size_t *res_len)
+{
+	int i;
+	u8 mac_a[8], ak[6];
+
+	if (*res_len < 8) {
+		*res_len = 0;
+		return;
+	}
+	if (milenage_f1(opc, k, _rand, sqn, amf, mac_a, NULL) ||
+	    milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL)) {
+		*res_len = 0;
+		return;
+	}
+	*res_len = 8;
+
+	/* AUTN = (SQN ^ AK) || AMF || MAC */
+	for (i = 0; i < 6; i++)
+		autn[i] = sqn[i] ^ ak[i];
+	os_memcpy(autn + 6, amf, 2);
+	os_memcpy(autn + 8, mac_a, 8);
+}
+
+
+/**
+ * milenage_auts - Milenage AUTS validation
+ * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
+ * @k: K = 128-bit subscriber key
+ * @_rand: RAND = 128-bit random challenge
+ * @auts: AUTS = 112-bit authentication token from client
+ * @sqn: Buffer for SQN = 48-bit sequence number
+ * Returns: 0 = success (sqn filled), -1 on failure
+ */
+int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
+		  u8 *sqn)
+{
+	u8 amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
+	u8 ak[6], mac_s[8];
+	int i;
+
+	if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
+		return -1;
+	for (i = 0; i < 6; i++)
+		sqn[i] = auts[i] ^ ak[i];
+	if (milenage_f1(opc, k, _rand, sqn, amf, NULL, mac_s) ||
+	    memcmp(mac_s, auts + 6, 8) != 0)
+		return -1;
+	return 0;
+}
+
+
+/**
+ * gsm_milenage - Generate GSM-Milenage (3GPP TS 55.205) authentication triplet
+ * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
+ * @k: K = 128-bit subscriber key
+ * @_rand: RAND = 128-bit random challenge
+ * @sres: Buffer for SRES = 32-bit SRES
+ * @kc: Buffer for Kc = 64-bit Kc
+ * Returns: 0 on success, -1 on failure
+ */
+int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres, u8 *kc)
+{
+	u8 res[8], ck[16], ik[16];
+	int i;
+
+	if (milenage_f2345(opc, k, _rand, res, ck, ik, NULL, NULL))
+		return -1;
+
+	for (i = 0; i < 8; i++)
+		kc[i] = ck[i] ^ ck[i + 8] ^ ik[i] ^ ik[i + 8];
+
+#ifdef GSM_MILENAGE_ALT_SRES
+	os_memcpy(sres, res, 4);
+#else /* GSM_MILENAGE_ALT_SRES */
+	for (i = 0; i < 4; i++)
+		sres[i] = res[i] ^ res[i + 4];
+#endif /* GSM_MILENAGE_ALT_SRES */
+	return 0;
+}
+
+
+/**
+ * milenage_generate - Generate AKA AUTN,IK,CK,RES
+ * @opc: OPc = 128-bit operator variant algorithm configuration field (encr.)
+ * @k: K = 128-bit subscriber key
+ * @sqn: SQN = 48-bit sequence number
+ * @_rand: RAND = 128-bit random challenge
+ * @autn: AUTN = 128-bit authentication token
+ * @ik: Buffer for IK = 128-bit integrity key (f4), or %NULL
+ * @ck: Buffer for CK = 128-bit confidentiality key (f3), or %NULL
+ * @res: Buffer for RES = 64-bit signed response (f2), or %NULL
+ * @res_len: Variable that will be set to RES length
+ * @auts: 112-bit buffer for AUTS
+ * Returns: 0 on success, -1 on failure, or -2 on synchronization failure
+ */
+int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand,
+		   const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len,
+		   u8 *auts)
+{
+	int i;
+	u8 mac_a[8], ak[6], rx_sqn[6];
+	const u8 *amf;
+
+	wpa_hexdump(MSG_DEBUG, "Milenage: AUTN", autn, 16);
+	wpa_hexdump(MSG_DEBUG, "Milenage: RAND", _rand, 16);
+
+	if (milenage_f2345(opc, k, _rand, res, ck, ik, ak, NULL))
+		return -1;
+
+	*res_len = 8;
+	wpa_hexdump_key(MSG_DEBUG, "Milenage: RES", res, *res_len);
+	wpa_hexdump_key(MSG_DEBUG, "Milenage: CK", ck, 16);
+	wpa_hexdump_key(MSG_DEBUG, "Milenage: IK", ik, 16);
+	wpa_hexdump_key(MSG_DEBUG, "Milenage: AK", ak, 6);
+
+	/* AUTN = (SQN ^ AK) || AMF || MAC */
+	for (i = 0; i < 6; i++)
+		rx_sqn[i] = autn[i] ^ ak[i];
+	wpa_hexdump(MSG_DEBUG, "Milenage: SQN", rx_sqn, 6);
+
+	if (os_memcmp(rx_sqn, sqn, 6) <= 0) {
+		u8 auts_amf[2] = { 0x00, 0x00 }; /* TS 33.102 v7.0.0, 6.3.3 */
+		if (milenage_f2345(opc, k, _rand, NULL, NULL, NULL, NULL, ak))
+			return -1;
+		wpa_hexdump_key(MSG_DEBUG, "Milenage: AK*", ak, 6);
+		for (i = 0; i < 6; i++)
+			auts[i] = sqn[i] ^ ak[i];
+		if (milenage_f1(opc, k, _rand, sqn, auts_amf, NULL, auts + 6))
+			return -1;
+		wpa_hexdump(MSG_DEBUG, "Milenage: AUTS", auts, 14);
+		return -2;
+	}
+
+	amf = autn + 6;
+	wpa_hexdump(MSG_DEBUG, "Milenage: AMF", amf, 2);
+	if (milenage_f1(opc, k, _rand, rx_sqn, amf, mac_a, NULL))
+		return -1;
+
+	wpa_hexdump(MSG_DEBUG, "Milenage: MAC_A", mac_a, 8);
+
+	if (os_memcmp(mac_a, autn + 8, 8) != 0) {
+		wpa_printf(MSG_DEBUG, "Milenage: MAC mismatch");
+		wpa_hexdump(MSG_DEBUG, "Milenage: Received MAC_A",
+			    autn + 8, 8);
+		return -1;
+	}
+
+	return 0;
+}
diff --git a/hostap/src/crypto/milenage.h b/hostap/src/crypto/milenage.h
new file mode 100644
index 0000000..62137d9
--- /dev/null
+++ b/hostap/src/crypto/milenage.h
@@ -0,0 +1,27 @@
+/*
+ * UMTS AKA - Milenage algorithm (3GPP TS 35.205, .206, .207, .208)
+ * Copyright (c) 2006-2007 <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MILENAGE_H
+#define MILENAGE_H
+
+void milenage_generate(const u8 *opc, const u8 *amf, const u8 *k,
+		       const u8 *sqn, const u8 *_rand, u8 *autn, u8 *ik,
+		       u8 *ck, u8 *res, size_t *res_len);
+int milenage_auts(const u8 *opc, const u8 *k, const u8 *_rand, const u8 *auts,
+		  u8 *sqn);
+int gsm_milenage(const u8 *opc, const u8 *k, const u8 *_rand, u8 *sres,
+		 u8 *kc);
+int milenage_check(const u8 *opc, const u8 *k, const u8 *sqn, const u8 *_rand,
+		   const u8 *autn, u8 *ik, u8 *ck, u8 *res, size_t *res_len,
+		   u8 *auts);
+int milenage_f1(const u8 *opc, const u8 *k, const u8 *_rand,
+		const u8 *sqn, const u8 *amf, u8 *mac_a, u8 *mac_s);
+int milenage_f2345(const u8 *opc, const u8 *k, const u8 *_rand,
+		   u8 *res, u8 *ck, u8 *ik, u8 *ak, u8 *akstar);
+
+#endif /* MILENAGE_H */
diff --git a/hostap/src/crypto/ms_funcs.c b/hostap/src/crypto/ms_funcs.c
new file mode 100644
index 0000000..b2bbab2
--- /dev/null
+++ b/hostap/src/crypto/ms_funcs.c
@@ -0,0 +1,526 @@
+/*
+ * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
+ * Copyright (c) 2004-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+#include "ms_funcs.h"
+#include "crypto.h"
+
+/**
+ * utf8_to_ucs2 - Convert UTF-8 string to UCS-2 encoding
+ * @utf8_string: UTF-8 string (IN)
+ * @utf8_string_len: Length of utf8_string (IN)
+ * @ucs2_buffer: UCS-2 buffer (OUT)
+ * @ucs2_buffer_size: Length of UCS-2 buffer (IN)
+ * @ucs2_string_size: Number of 2-byte words in the resulting UCS-2 string
+ * Returns: 0 on success, -1 on failure
+ */
+static int utf8_to_ucs2(const u8 *utf8_string, size_t utf8_string_len,
+                        u8 *ucs2_buffer, size_t ucs2_buffer_size,
+                        size_t *ucs2_string_size)
+{
+	size_t i, j;
+
+	for (i = 0, j = 0; i < utf8_string_len; i++) {
+		u8 c = utf8_string[i];
+		if (j >= ucs2_buffer_size) {
+			/* input too long */
+			return -1;
+		}
+		if (c <= 0x7F) {
+			WPA_PUT_LE16(ucs2_buffer + j, c);
+			j += 2;
+		} else if (i == utf8_string_len - 1 ||
+			   j >= ucs2_buffer_size - 1) {
+			/* incomplete surrogate */
+			return -1;
+		} else {
+			u8 c2 = utf8_string[++i];
+			if ((c & 0xE0) == 0xC0) {
+				/* two-byte encoding */
+				WPA_PUT_LE16(ucs2_buffer + j,
+					     ((c & 0x1F) << 6) | (c2 & 0x3F));
+				j += 2;
+			} else if (i == utf8_string_len ||
+				   j >= ucs2_buffer_size - 1) {
+				/* incomplete surrogate */
+				return -1;
+			} else {
+				/* three-byte encoding */
+				u8 c3 = utf8_string[++i];
+				WPA_PUT_LE16(ucs2_buffer + j,
+					     ((c & 0xF) << 12) |
+					     ((c2 & 0x3F) << 6) | (c3 & 0x3F));
+			}
+		}
+	}
+
+	if (ucs2_string_size)
+		*ucs2_string_size = j / 2;
+	return 0;
+}
+
+
+/**
+ * challenge_hash - ChallengeHash() - RFC 2759, Sect. 8.2
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @challenge: 8-octet Challenge (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+static int challenge_hash(const u8 *peer_challenge, const u8 *auth_challenge,
+			  const u8 *username, size_t username_len,
+			  u8 *challenge)
+{
+	u8 hash[SHA1_MAC_LEN];
+	const unsigned char *addr[3];
+	size_t len[3];
+
+	addr[0] = peer_challenge;
+	len[0] = 16;
+	addr[1] = auth_challenge;
+	len[1] = 16;
+	addr[2] = username;
+	len[2] = username_len;
+
+	if (sha1_vector(3, addr, len, hash))
+		return -1;
+	os_memcpy(challenge, hash, 8);
+	return 0;
+}
+
+
+/**
+ * nt_password_hash - NtPasswordHash() - RFC 2759, Sect. 8.3
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
+ * @password_len: Length of password
+ * @password_hash: 16-octet PasswordHash (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int nt_password_hash(const u8 *password, size_t password_len,
+		      u8 *password_hash)
+{
+	u8 buf[512], *pos;
+	size_t len, max_len;
+
+	max_len = sizeof(buf);
+	if (utf8_to_ucs2(password, password_len, buf, max_len, &len) < 0)
+		return -1;
+
+	len *= 2;
+	pos = buf;
+	return md4_vector(1, (const u8 **) &pos, &len, password_hash);
+}
+
+
+/**
+ * hash_nt_password_hash - HashNtPasswordHash() - RFC 2759, Sect. 8.4
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @password_hash_hash: 16-octet PasswordHashHash (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash)
+{
+	size_t len = 16;
+	return md4_vector(1, &password_hash, &len, password_hash_hash);
+}
+
+
+/**
+ * challenge_response - ChallengeResponse() - RFC 2759, Sect. 8.5
+ * @challenge: 8-octet Challenge (IN)
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @response: 24-octet Response (OUT)
+ */
+void challenge_response(const u8 *challenge, const u8 *password_hash,
+			u8 *response)
+{
+	u8 zpwd[7];
+	des_encrypt(challenge, password_hash, response);
+	des_encrypt(challenge, password_hash + 7, response + 8);
+	zpwd[0] = password_hash[14];
+	zpwd[1] = password_hash[15];
+	os_memset(zpwd + 2, 0, 5);
+	des_encrypt(challenge, zpwd, response + 16);
+}
+
+
+/**
+ * generate_nt_response - GenerateNTResponse() - RFC 2759, Sect. 8.1
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
+ * @password_len: Length of password
+ * @response: 24-octet Response (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
+			 const u8 *username, size_t username_len,
+			 const u8 *password, size_t password_len,
+			 u8 *response)
+{
+	u8 challenge[8];
+	u8 password_hash[16];
+
+	if (challenge_hash(peer_challenge, auth_challenge, username,
+			   username_len, challenge))
+		return -1;
+	if (nt_password_hash(password, password_len, password_hash))
+		return -1;
+	challenge_response(challenge, password_hash, response);
+	return 0;
+}
+
+
+/**
+ * generate_nt_response_pwhash - GenerateNTResponse() - RFC 2759, Sect. 8.1
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @response: 24-octet Response (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int generate_nt_response_pwhash(const u8 *auth_challenge,
+				const u8 *peer_challenge,
+				const u8 *username, size_t username_len,
+				const u8 *password_hash,
+				u8 *response)
+{
+	u8 challenge[8];
+
+	if (challenge_hash(peer_challenge, auth_challenge,
+			   username, username_len,
+			   challenge))
+		return -1;
+	challenge_response(challenge, password_hash, response);
+	return 0;
+}
+
+
+/**
+ * generate_authenticator_response_pwhash - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @nt_response: 24-octet NT-Response (IN)
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
+ * encoded as a 42-octet ASCII string (S=hexdump_of_response)
+ * Returns: 0 on success, -1 on failure
+ */
+int generate_authenticator_response_pwhash(
+	const u8 *password_hash,
+	const u8 *peer_challenge, const u8 *auth_challenge,
+	const u8 *username, size_t username_len,
+	const u8 *nt_response, u8 *response)
+{
+	static const u8 magic1[39] = {
+		0x4D, 0x61, 0x67, 0x69, 0x63, 0x20, 0x73, 0x65, 0x72, 0x76,
+		0x65, 0x72, 0x20, 0x74, 0x6F, 0x20, 0x63, 0x6C, 0x69, 0x65,
+		0x6E, 0x74, 0x20, 0x73, 0x69, 0x67, 0x6E, 0x69, 0x6E, 0x67,
+		0x20, 0x63, 0x6F, 0x6E, 0x73, 0x74, 0x61, 0x6E, 0x74
+	};
+	static const u8 magic2[41] = {
+		0x50, 0x61, 0x64, 0x20, 0x74, 0x6F, 0x20, 0x6D, 0x61, 0x6B,
+		0x65, 0x20, 0x69, 0x74, 0x20, 0x64, 0x6F, 0x20, 0x6D, 0x6F,
+		0x72, 0x65, 0x20, 0x74, 0x68, 0x61, 0x6E, 0x20, 0x6F, 0x6E,
+		0x65, 0x20, 0x69, 0x74, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6F,
+		0x6E
+	};
+
+	u8 password_hash_hash[16], challenge[8];
+	const unsigned char *addr1[3];
+	const size_t len1[3] = { 16, 24, sizeof(magic1) };
+	const unsigned char *addr2[3];
+	const size_t len2[3] = { SHA1_MAC_LEN, 8, sizeof(magic2) };
+
+	addr1[0] = password_hash_hash;
+	addr1[1] = nt_response;
+	addr1[2] = magic1;
+
+	addr2[0] = response;
+	addr2[1] = challenge;
+	addr2[2] = magic2;
+
+	if (hash_nt_password_hash(password_hash, password_hash_hash))
+		return -1;
+	if (sha1_vector(3, addr1, len1, response))
+		return -1;
+
+	if (challenge_hash(peer_challenge, auth_challenge, username,
+			   username_len, challenge))
+		return -1;
+	return sha1_vector(3, addr2, len2, response);
+}
+
+
+/**
+ * generate_authenticator_response - GenerateAuthenticatorResponse() - RFC 2759, Sect. 8.7
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
+ * @password_len: Length of password
+ * @nt_response: 24-octet NT-Response (IN)
+ * @peer_challenge: 16-octet PeerChallenge (IN)
+ * @auth_challenge: 16-octet AuthenticatorChallenge (IN)
+ * @username: 0-to-256-char UserName (IN)
+ * @username_len: Length of username
+ * @response: 20-octet AuthenticatorResponse (OUT) (note: this value is usually
+ * encoded as a 42-octet ASCII string (S=hexdump_of_response)
+ * Returns: 0 on success, -1 on failure
+ */
+int generate_authenticator_response(const u8 *password, size_t password_len,
+				    const u8 *peer_challenge,
+				    const u8 *auth_challenge,
+				    const u8 *username, size_t username_len,
+				    const u8 *nt_response, u8 *response)
+{
+	u8 password_hash[16];
+	if (nt_password_hash(password, password_len, password_hash))
+		return -1;
+	return generate_authenticator_response_pwhash(
+		password_hash, peer_challenge, auth_challenge,
+		username, username_len, nt_response, response);
+}
+
+
+/**
+ * nt_challenge_response - NtChallengeResponse() - RFC 2433, Sect. A.5
+ * @challenge: 8-octet Challenge (IN)
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
+ * @password_len: Length of password
+ * @response: 24-octet Response (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int nt_challenge_response(const u8 *challenge, const u8 *password,
+			  size_t password_len, u8 *response)
+{
+	u8 password_hash[16];
+	if (nt_password_hash(password, password_len, password_hash))
+		return -1;
+	challenge_response(challenge, password_hash, response);
+	return 0;
+}
+
+
+/**
+ * get_master_key - GetMasterKey() - RFC 3079, Sect. 3.4
+ * @password_hash_hash: 16-octet PasswordHashHash (IN)
+ * @nt_response: 24-octet NTResponse (IN)
+ * @master_key: 16-octet MasterKey (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
+		   u8 *master_key)
+{
+	static const u8 magic1[27] = {
+		0x54, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74,
+		0x68, 0x65, 0x20, 0x4d, 0x50, 0x50, 0x45, 0x20, 0x4d,
+		0x61, 0x73, 0x74, 0x65, 0x72, 0x20, 0x4b, 0x65, 0x79
+	};
+	const unsigned char *addr[3];
+	const size_t len[3] = { 16, 24, sizeof(magic1) };
+	u8 hash[SHA1_MAC_LEN];
+
+	addr[0] = password_hash_hash;
+	addr[1] = nt_response;
+	addr[2] = magic1;
+
+	if (sha1_vector(3, addr, len, hash))
+		return -1;
+	os_memcpy(master_key, hash, 16);
+	return 0;
+}
+
+
+/**
+ * get_asymetric_start_key - GetAsymetricStartKey() - RFC 3079, Sect. 3.4
+ * @master_key: 16-octet MasterKey (IN)
+ * @session_key: 8-to-16 octet SessionKey (OUT)
+ * @session_key_len: SessionKeyLength (Length of session_key) (IN)
+ * @is_send: IsSend (IN, BOOLEAN)
+ * @is_server: IsServer (IN, BOOLEAN)
+ * Returns: 0 on success, -1 on failure
+ */
+int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
+			    size_t session_key_len, int is_send,
+			    int is_server)
+{
+	static const u8 magic2[84] = {
+		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
+		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
+		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+		0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20, 0x6b, 0x65, 0x79,
+		0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73,
+		0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73, 0x69, 0x64, 0x65,
+		0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+		0x6b, 0x65, 0x79, 0x2e
+	};
+	static const u8 magic3[84] = {
+		0x4f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6c, 0x69,
+		0x65, 0x6e, 0x74, 0x20, 0x73, 0x69, 0x64, 0x65, 0x2c, 0x20,
+		0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68,
+		0x65, 0x20, 0x72, 0x65, 0x63, 0x65, 0x69, 0x76, 0x65, 0x20,
+		0x6b, 0x65, 0x79, 0x3b, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68,
+		0x65, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x73,
+		0x69, 0x64, 0x65, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73,
+		0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x65, 0x6e, 0x64, 0x20,
+		0x6b, 0x65, 0x79, 0x2e
+	};
+	static const u8 shs_pad1[40] = {
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+		0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+	};
+
+	static const u8 shs_pad2[40] = {
+		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2,
+		0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2
+	};
+	u8 digest[SHA1_MAC_LEN];
+	const unsigned char *addr[4];
+	const size_t len[4] = { 16, 40, 84, 40 };
+
+	addr[0] = master_key;
+	addr[1] = shs_pad1;
+	if (is_send) {
+		addr[2] = is_server ? magic3 : magic2;
+	} else {
+		addr[2] = is_server ? magic2 : magic3;
+	}
+	addr[3] = shs_pad2;
+
+	if (sha1_vector(4, addr, len, digest))
+		return -1;
+
+	if (session_key_len > SHA1_MAC_LEN)
+		session_key_len = SHA1_MAC_LEN;
+	os_memcpy(session_key, digest, session_key_len);
+	return 0;
+}
+
+
+#define PWBLOCK_LEN 516
+
+/**
+ * encrypt_pw_block_with_password_hash - EncryptPwBlockWithPasswordHash() - RFC 2759, Sect. 8.10
+ * @password: 0-to-256-unicode-char Password (IN; UTF-8)
+ * @password_len: Length of password
+ * @password_hash: 16-octet PasswordHash (IN)
+ * @pw_block: 516-byte PwBlock (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int encrypt_pw_block_with_password_hash(
+	const u8 *password, size_t password_len,
+	const u8 *password_hash, u8 *pw_block)
+{
+	size_t ucs2_len, offset;
+	u8 *pos;
+
+	os_memset(pw_block, 0, PWBLOCK_LEN);
+
+	if (utf8_to_ucs2(password, password_len, pw_block, 512, &ucs2_len) < 0)
+		return -1;
+
+	if (ucs2_len > 256)
+		return -1;
+
+	offset = (256 - ucs2_len) * 2;
+	if (offset != 0) {
+		os_memmove(pw_block + offset, pw_block, ucs2_len * 2);
+		if (os_get_random(pw_block, offset) < 0)
+			return -1;
+	}
+	/*
+	 * PasswordLength is 4 octets, but since the maximum password length is
+	 * 256, only first two (in little endian byte order) can be non-zero.
+	 */
+	pos = &pw_block[2 * 256];
+	WPA_PUT_LE16(pos, password_len * 2);
+	rc4_skip(password_hash, 16, 0, pw_block, PWBLOCK_LEN);
+	return 0;
+}
+
+
+/**
+ * new_password_encrypted_with_old_nt_password_hash - NewPasswordEncryptedWithOldNtPasswordHash() - RFC 2759, Sect. 8.9
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
+ * @new_password_len: Length of new_password
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
+ * @old_password_len: Length of old_password
+ * @encrypted_pw_block: 516-octet EncryptedPwBlock (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int new_password_encrypted_with_old_nt_password_hash(
+	const u8 *new_password, size_t new_password_len,
+	const u8 *old_password, size_t old_password_len,
+	u8 *encrypted_pw_block)
+{
+	u8 password_hash[16];
+
+	if (nt_password_hash(old_password, old_password_len, password_hash))
+		return -1;
+	if (encrypt_pw_block_with_password_hash(new_password, new_password_len,
+						password_hash,
+						encrypted_pw_block))
+		return -1;
+	return 0;
+}
+
+
+/**
+ * nt_password_hash_encrypted_with_block - NtPasswordHashEncryptedWithBlock() - RFC 2759, Sect 8.13
+ * @password_hash: 16-octer PasswordHash (IN)
+ * @block: 16-octet Block (IN)
+ * @cypher: 16-octer Cypher (OUT)
+ */
+void nt_password_hash_encrypted_with_block(const u8 *password_hash,
+					   const u8 *block, u8 *cypher)
+{
+	des_encrypt(password_hash, block, cypher);
+	des_encrypt(password_hash + 8, block + 7, cypher + 8);
+}
+
+
+/**
+ * old_nt_password_hash_encrypted_with_new_nt_password_hash - OldNtPasswordHashEncryptedWithNewNtPasswordHash() - RFC 2759, Sect. 8.12
+ * @new_password: 0-to-256-unicode-char NewPassword (IN; UTF-8)
+ * @new_password_len: Length of new_password
+ * @old_password: 0-to-256-unicode-char OldPassword (IN; UTF-8)
+ * @old_password_len: Length of old_password
+ * @encrypted_password_hash: 16-octet EncryptedPasswordHash (OUT)
+ * Returns: 0 on success, -1 on failure
+ */
+int old_nt_password_hash_encrypted_with_new_nt_password_hash(
+	const u8 *new_password, size_t new_password_len,
+	const u8 *old_password, size_t old_password_len,
+	u8 *encrypted_password_hash)
+{
+	u8 old_password_hash[16], new_password_hash[16];
+
+	if (nt_password_hash(old_password, old_password_len,
+			     old_password_hash) ||
+	    nt_password_hash(new_password, new_password_len,
+			     new_password_hash))
+		return -1;
+	nt_password_hash_encrypted_with_block(old_password_hash,
+					      new_password_hash,
+					      encrypted_password_hash);
+	return 0;
+}
diff --git a/hostap/src/crypto/ms_funcs.h b/hostap/src/crypto/ms_funcs.h
new file mode 100644
index 0000000..bd9bfee
--- /dev/null
+++ b/hostap/src/crypto/ms_funcs.h
@@ -0,0 +1,58 @@
+/*
+ * WPA Supplicant / shared MSCHAPV2 helper functions / RFC 2433 / RFC 2759
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef MS_FUNCS_H
+#define MS_FUNCS_H
+
+int generate_nt_response(const u8 *auth_challenge, const u8 *peer_challenge,
+			 const u8 *username, size_t username_len,
+			 const u8 *password, size_t password_len,
+			 u8 *response);
+int generate_nt_response_pwhash(const u8 *auth_challenge,
+				const u8 *peer_challenge,
+				const u8 *username, size_t username_len,
+				const u8 *password_hash,
+				u8 *response);
+int generate_authenticator_response(const u8 *password, size_t password_len,
+				    const u8 *peer_challenge,
+				    const u8 *auth_challenge,
+				    const u8 *username, size_t username_len,
+				    const u8 *nt_response, u8 *response);
+int generate_authenticator_response_pwhash(
+	const u8 *password_hash,
+	const u8 *peer_challenge, const u8 *auth_challenge,
+	const u8 *username, size_t username_len,
+	const u8 *nt_response, u8 *response);
+int nt_challenge_response(const u8 *challenge, const u8 *password,
+			  size_t password_len, u8 *response);
+
+void challenge_response(const u8 *challenge, const u8 *password_hash,
+			u8 *response);
+int nt_password_hash(const u8 *password, size_t password_len,
+		     u8 *password_hash);
+int hash_nt_password_hash(const u8 *password_hash, u8 *password_hash_hash);
+int get_master_key(const u8 *password_hash_hash, const u8 *nt_response,
+		   u8 *master_key);
+int get_asymetric_start_key(const u8 *master_key, u8 *session_key,
+			    size_t session_key_len, int is_send,
+			    int is_server);
+int __must_check encrypt_pw_block_with_password_hash(
+	const u8 *password, size_t password_len,
+	const u8 *password_hash, u8 *pw_block);
+int __must_check new_password_encrypted_with_old_nt_password_hash(
+	const u8 *new_password, size_t new_password_len,
+	const u8 *old_password, size_t old_password_len,
+	u8 *encrypted_pw_block);
+void nt_password_hash_encrypted_with_block(const u8 *password_hash,
+					   const u8 *block, u8 *cypher);
+int old_nt_password_hash_encrypted_with_new_nt_password_hash(
+	const u8 *new_password, size_t new_password_len,
+	const u8 *old_password, size_t old_password_len,
+	u8 *encrypted_password_hash);
+
+#endif /* MS_FUNCS_H */
diff --git a/hostap/src/crypto/random.c b/hostap/src/crypto/random.c
new file mode 100644
index 0000000..053740e
--- /dev/null
+++ b/hostap/src/crypto/random.c
@@ -0,0 +1,446 @@
+/*
+ * Random number generator
+ * Copyright (c) 2010-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This random number generator is used to provide additional entropy to the
+ * one provided by the operating system (os_get_random()) for session key
+ * generation. The os_get_random() output is expected to be secure and the
+ * implementation here is expected to provide only limited protection against
+ * cases where os_get_random() cannot provide strong randomness. This
+ * implementation shall not be assumed to be secure as the sole source of
+ * randomness. The random_get_bytes() function mixes in randomness from
+ * os_get_random() and as such, calls to os_get_random() can be replaced with
+ * calls to random_get_bytes() without reducing security.
+ *
+ * The design here follows partially the design used in the Linux
+ * drivers/char/random.c, but the implementation here is simpler and not as
+ * strong. This is a compromise to reduce duplicated CPU effort and to avoid
+ * extra code/memory size. As pointed out above, os_get_random() needs to be
+ * guaranteed to be secure for any of the security assumptions to hold.
+ */
+
+#include "utils/includes.h"
+#ifdef __linux__
+#include <fcntl.h>
+#endif /* __linux__ */
+
+#include "utils/common.h"
+#include "utils/eloop.h"
+#include "crypto/crypto.h"
+#include "sha1.h"
+#include "random.h"
+
+#define POOL_WORDS 32
+#define POOL_WORDS_MASK (POOL_WORDS - 1)
+#define POOL_TAP1 26
+#define POOL_TAP2 20
+#define POOL_TAP3 14
+#define POOL_TAP4 7
+#define POOL_TAP5 1
+#define EXTRACT_LEN 16
+#define MIN_READY_MARK 2
+
+static u32 pool[POOL_WORDS];
+static unsigned int input_rotate = 0;
+static unsigned int pool_pos = 0;
+static u8 dummy_key[20];
+#ifdef __linux__
+static size_t dummy_key_avail = 0;
+static int random_fd = -1;
+#endif /* __linux__ */
+static unsigned int own_pool_ready = 0;
+#define RANDOM_ENTROPY_SIZE 20
+static char *random_entropy_file = NULL;
+static int random_entropy_file_read = 0;
+
+#define MIN_COLLECT_ENTROPY 1000
+static unsigned int entropy = 0;
+static unsigned int total_collected = 0;
+
+
+static void random_write_entropy(void);
+
+
+static u32 __ROL32(u32 x, u32 y)
+{
+	return (x << (y & 31)) | (x >> (32 - (y & 31)));
+}
+
+
+static void random_mix_pool(const void *buf, size_t len)
+{
+	static const u32 twist[8] = {
+		0x00000000, 0x3b6e20c8, 0x76dc4190, 0x4db26158,
+		0xedb88320, 0xd6d6a3e8, 0x9b64c2b0, 0xa00ae278
+	};
+	const u8 *pos = buf;
+	u32 w;
+
+	wpa_hexdump_key(MSG_EXCESSIVE, "random_mix_pool", buf, len);
+
+	while (len--) {
+		w = __ROL32(*pos++, input_rotate & 31);
+		input_rotate += pool_pos ? 7 : 14;
+		pool_pos = (pool_pos - 1) & POOL_WORDS_MASK;
+		w ^= pool[pool_pos];
+		w ^= pool[(pool_pos + POOL_TAP1) & POOL_WORDS_MASK];
+		w ^= pool[(pool_pos + POOL_TAP2) & POOL_WORDS_MASK];
+		w ^= pool[(pool_pos + POOL_TAP3) & POOL_WORDS_MASK];
+		w ^= pool[(pool_pos + POOL_TAP4) & POOL_WORDS_MASK];
+		w ^= pool[(pool_pos + POOL_TAP5) & POOL_WORDS_MASK];
+		pool[pool_pos] = (w >> 3) ^ twist[w & 7];
+	}
+}
+
+
+static void random_extract(u8 *out)
+{
+	unsigned int i;
+	u8 hash[SHA1_MAC_LEN];
+	u32 *hash_ptr;
+	u32 buf[POOL_WORDS / 2];
+
+	/* First, add hash back to pool to make backtracking more difficult. */
+	hmac_sha1(dummy_key, sizeof(dummy_key), (const u8 *) pool,
+		  sizeof(pool), hash);
+	random_mix_pool(hash, sizeof(hash));
+	/* Hash half the pool to extra data */
+	for (i = 0; i < POOL_WORDS / 2; i++)
+		buf[i] = pool[(pool_pos - i) & POOL_WORDS_MASK];
+	hmac_sha1(dummy_key, sizeof(dummy_key), (const u8 *) buf,
+		  sizeof(buf), hash);
+	/*
+	 * Fold the hash to further reduce any potential output pattern.
+	 * Though, compromise this to reduce CPU use for the most common output
+	 * length (32) and return 16 bytes from instead of only half.
+	 */
+	hash_ptr = (u32 *) hash;
+	hash_ptr[0] ^= hash_ptr[4];
+	os_memcpy(out, hash, EXTRACT_LEN);
+}
+
+
+void random_add_randomness(const void *buf, size_t len)
+{
+	struct os_time t;
+	static unsigned int count = 0;
+
+	count++;
+	if (entropy > MIN_COLLECT_ENTROPY && (count & 0x3ff) != 0) {
+		/*
+		 * No need to add more entropy at this point, so save CPU and
+		 * skip the update.
+		 */
+		return;
+	}
+	wpa_printf(MSG_EXCESSIVE, "Add randomness: count=%u entropy=%u",
+		   count, entropy);
+
+	os_get_time(&t);
+	wpa_hexdump_key(MSG_EXCESSIVE, "random pool",
+			(const u8 *) pool, sizeof(pool));
+	random_mix_pool(&t, sizeof(t));
+	random_mix_pool(buf, len);
+	wpa_hexdump_key(MSG_EXCESSIVE, "random pool",
+			(const u8 *) pool, sizeof(pool));
+	entropy++;
+	total_collected++;
+}
+
+
+int random_get_bytes(void *buf, size_t len)
+{
+	int ret;
+	u8 *bytes = buf;
+	size_t left;
+
+	wpa_printf(MSG_MSGDUMP, "Get randomness: len=%u entropy=%u",
+		   (unsigned int) len, entropy);
+
+	/* Start with assumed strong randomness from OS */
+	ret = os_get_random(buf, len);
+	wpa_hexdump_key(MSG_EXCESSIVE, "random from os_get_random",
+			buf, len);
+
+	/* Mix in additional entropy extracted from the internal pool */
+	left = len;
+	while (left) {
+		size_t siz, i;
+		u8 tmp[EXTRACT_LEN];
+		random_extract(tmp);
+		wpa_hexdump_key(MSG_EXCESSIVE, "random from internal pool",
+				tmp, sizeof(tmp));
+		siz = left > EXTRACT_LEN ? EXTRACT_LEN : left;
+		for (i = 0; i < siz; i++)
+			*bytes++ ^= tmp[i];
+		left -= siz;
+	}
+
+#ifdef CONFIG_FIPS
+	/* Mix in additional entropy from the crypto module */
+	left = len;
+	while (left) {
+		size_t siz, i;
+		u8 tmp[EXTRACT_LEN];
+		if (crypto_get_random(tmp, sizeof(tmp)) < 0) {
+			wpa_printf(MSG_ERROR, "random: No entropy available "
+				   "for generating strong random bytes");
+			return -1;
+		}
+		wpa_hexdump_key(MSG_EXCESSIVE, "random from crypto module",
+				tmp, sizeof(tmp));
+		siz = left > EXTRACT_LEN ? EXTRACT_LEN : left;
+		for (i = 0; i < siz; i++)
+			*bytes++ ^= tmp[i];
+		left -= siz;
+	}
+#endif /* CONFIG_FIPS */
+
+	wpa_hexdump_key(MSG_EXCESSIVE, "mixed random", buf, len);
+
+	if (entropy < len)
+		entropy = 0;
+	else
+		entropy -= len;
+
+	return ret;
+}
+
+
+int random_pool_ready(void)
+{
+#ifdef __linux__
+	int fd;
+	ssize_t res;
+
+	/*
+	 * Make sure that there is reasonable entropy available before allowing
+	 * some key derivation operations to proceed.
+	 */
+
+	if (dummy_key_avail == sizeof(dummy_key))
+		return 1; /* Already initialized - good to continue */
+
+	/*
+	 * Try to fetch some more data from the kernel high quality
+	 * /dev/random. There may not be enough data available at this point,
+	 * so use non-blocking read to avoid blocking the application
+	 * completely.
+	 */
+	fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+	if (fd < 0) {
+#ifndef CONFIG_NO_STDOUT_DEBUG
+		int error = errno;
+		perror("open(/dev/random)");
+		wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
+			   strerror(error));
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+		return -1;
+	}
+
+	res = read(fd, dummy_key + dummy_key_avail,
+		   sizeof(dummy_key) - dummy_key_avail);
+	if (res < 0) {
+		wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
+			   "%s", strerror(errno));
+		res = 0;
+	}
+	wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from "
+		   "/dev/random", (unsigned) res,
+		   (unsigned) (sizeof(dummy_key) - dummy_key_avail));
+	dummy_key_avail += res;
+	close(fd);
+
+	if (dummy_key_avail == sizeof(dummy_key)) {
+		if (own_pool_ready < MIN_READY_MARK)
+			own_pool_ready = MIN_READY_MARK;
+		random_write_entropy();
+		return 1;
+	}
+
+	wpa_printf(MSG_INFO, "random: Only %u/%u bytes of strong "
+		   "random data available from /dev/random",
+		   (unsigned) dummy_key_avail, (unsigned) sizeof(dummy_key));
+
+	if (own_pool_ready >= MIN_READY_MARK ||
+	    total_collected + 10 * own_pool_ready > MIN_COLLECT_ENTROPY) {
+		wpa_printf(MSG_INFO, "random: Allow operation to proceed "
+			   "based on internal entropy");
+		return 1;
+	}
+
+	wpa_printf(MSG_INFO, "random: Not enough entropy pool available for "
+		   "secure operations");
+	return 0;
+#else /* __linux__ */
+	/* TODO: could do similar checks on non-Linux platforms */
+	return 1;
+#endif /* __linux__ */
+}
+
+
+void random_mark_pool_ready(void)
+{
+	own_pool_ready++;
+	wpa_printf(MSG_DEBUG, "random: Mark internal entropy pool to be "
+		   "ready (count=%u/%u)", own_pool_ready, MIN_READY_MARK);
+	random_write_entropy();
+}
+
+
+#ifdef __linux__
+
+static void random_close_fd(void)
+{
+	if (random_fd >= 0) {
+		eloop_unregister_read_sock(random_fd);
+		close(random_fd);
+		random_fd = -1;
+	}
+}
+
+
+static void random_read_fd(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	ssize_t res;
+
+	if (dummy_key_avail == sizeof(dummy_key)) {
+		random_close_fd();
+		return;
+	}
+
+	res = read(sock, dummy_key + dummy_key_avail,
+		   sizeof(dummy_key) - dummy_key_avail);
+	if (res < 0) {
+		wpa_printf(MSG_ERROR, "random: Cannot read from /dev/random: "
+			   "%s", strerror(errno));
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "random: Got %u/%u bytes from /dev/random",
+		   (unsigned) res,
+		   (unsigned) (sizeof(dummy_key) - dummy_key_avail));
+	dummy_key_avail += res;
+
+	if (dummy_key_avail == sizeof(dummy_key)) {
+		random_close_fd();
+		if (own_pool_ready < MIN_READY_MARK)
+			own_pool_ready = MIN_READY_MARK;
+		random_write_entropy();
+	}
+}
+
+#endif /* __linux__ */
+
+
+static void random_read_entropy(void)
+{
+	char *buf;
+	size_t len;
+
+	if (!random_entropy_file)
+		return;
+
+	buf = os_readfile(random_entropy_file, &len);
+	if (buf == NULL)
+		return; /* entropy file not yet available */
+
+	if (len != 1 + RANDOM_ENTROPY_SIZE) {
+		wpa_printf(MSG_DEBUG, "random: Invalid entropy file %s",
+			   random_entropy_file);
+		os_free(buf);
+		return;
+	}
+
+	own_pool_ready = (u8) buf[0];
+	random_add_randomness(buf + 1, RANDOM_ENTROPY_SIZE);
+	random_entropy_file_read = 1;
+	os_free(buf);
+	wpa_printf(MSG_DEBUG, "random: Added entropy from %s "
+		   "(own_pool_ready=%u)",
+		   random_entropy_file, own_pool_ready);
+}
+
+
+static void random_write_entropy(void)
+{
+	char buf[RANDOM_ENTROPY_SIZE];
+	FILE *f;
+	u8 opr;
+	int fail = 0;
+
+	if (!random_entropy_file)
+		return;
+
+	if (random_get_bytes(buf, RANDOM_ENTROPY_SIZE) < 0)
+		return;
+
+	f = fopen(random_entropy_file, "wb");
+	if (f == NULL) {
+		wpa_printf(MSG_ERROR, "random: Could not open entropy file %s "
+			   "for writing", random_entropy_file);
+		return;
+	}
+
+	opr = own_pool_ready > 0xff ? 0xff : own_pool_ready;
+	if (fwrite(&opr, 1, 1, f) != 1 ||
+	    fwrite(buf, RANDOM_ENTROPY_SIZE, 1, f) != 1)
+		fail = 1;
+	fclose(f);
+	if (fail) {
+		wpa_printf(MSG_ERROR, "random: Could not write entropy data "
+			   "to %s", random_entropy_file);
+		return;
+	}
+
+	wpa_printf(MSG_DEBUG, "random: Updated entropy file %s "
+		   "(own_pool_ready=%u)",
+		   random_entropy_file, own_pool_ready);
+}
+
+
+void random_init(const char *entropy_file)
+{
+	os_free(random_entropy_file);
+	if (entropy_file)
+		random_entropy_file = os_strdup(entropy_file);
+	else
+		random_entropy_file = NULL;
+	random_read_entropy();
+
+#ifdef __linux__
+	if (random_fd >= 0)
+		return;
+
+	random_fd = open("/dev/random", O_RDONLY | O_NONBLOCK);
+	if (random_fd < 0) {
+#ifndef CONFIG_NO_STDOUT_DEBUG
+		int error = errno;
+		perror("open(/dev/random)");
+		wpa_printf(MSG_ERROR, "random: Cannot open /dev/random: %s",
+			   strerror(error));
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+		return;
+	}
+	wpa_printf(MSG_DEBUG, "random: Trying to read entropy from "
+		   "/dev/random");
+
+	eloop_register_read_sock(random_fd, random_read_fd, NULL, NULL);
+#endif /* __linux__ */
+
+	random_write_entropy();
+}
+
+
+void random_deinit(void)
+{
+#ifdef __linux__
+	random_close_fd();
+#endif /* __linux__ */
+	random_write_entropy();
+	os_free(random_entropy_file);
+	random_entropy_file = NULL;
+}
diff --git a/hostap/src/crypto/random.h b/hostap/src/crypto/random.h
new file mode 100644
index 0000000..d13e1c4
--- /dev/null
+++ b/hostap/src/crypto/random.h
@@ -0,0 +1,28 @@
+/*
+ * Random number generator
+ * Copyright (c) 2010-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef RANDOM_H
+#define RANDOM_H
+
+#ifdef CONFIG_NO_RANDOM_POOL
+#define random_init(e) do { } while (0)
+#define random_deinit() do { } while (0)
+#define random_add_randomness(b, l) do { } while (0)
+#define random_get_bytes(b, l) os_get_random((b), (l))
+#define random_pool_ready() 1
+#define random_mark_pool_ready() do { } while (0)
+#else /* CONFIG_NO_RANDOM_POOL */
+void random_init(const char *entropy_file);
+void random_deinit(void);
+void random_add_randomness(const void *buf, size_t len);
+int random_get_bytes(void *buf, size_t len);
+int random_pool_ready(void);
+void random_mark_pool_ready(void);
+#endif /* CONFIG_NO_RANDOM_POOL */
+
+#endif /* RANDOM_H */
diff --git a/hostap/src/crypto/rc4.c b/hostap/src/crypto/rc4.c
new file mode 100644
index 0000000..98ae269
--- /dev/null
+++ b/hostap/src/crypto/rc4.c
@@ -0,0 +1,54 @@
+/*
+ * RC4 stream cipher
+ * Copyright (c) 2002-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "crypto.h"
+
+#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
+
+int rc4_skip(const u8 *key, size_t keylen, size_t skip,
+	     u8 *data, size_t data_len)
+{
+	u32 i, j, k;
+	u8 S[256], *pos;
+	size_t kpos;
+
+	/* Setup RC4 state */
+	for (i = 0; i < 256; i++)
+		S[i] = i;
+	j = 0;
+	kpos = 0;
+	for (i = 0; i < 256; i++) {
+		j = (j + S[i] + key[kpos]) & 0xff;
+		kpos++;
+		if (kpos >= keylen)
+			kpos = 0;
+		S_SWAP(i, j);
+	}
+
+	/* Skip the start of the stream */
+	i = j = 0;
+	for (k = 0; k < skip; k++) {
+		i = (i + 1) & 0xff;
+		j = (j + S[i]) & 0xff;
+		S_SWAP(i, j);
+	}
+
+	/* Apply RC4 to data */
+	pos = data;
+	for (k = 0; k < data_len; k++) {
+		i = (i + 1) & 0xff;
+		j = (j + S[i]) & 0xff;
+		S_SWAP(i, j);
+		*pos++ ^= S[(S[i] + S[j]) & 0xff];
+	}
+
+	return 0;
+}
diff --git a/hostap/src/crypto/sha1-internal.c b/hostap/src/crypto/sha1-internal.c
new file mode 100644
index 0000000..10bf153
--- /dev/null
+++ b/hostap/src/crypto/sha1-internal.c
@@ -0,0 +1,302 @@
+/*
+ * SHA1 hash implementation and interface functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+#include "sha1_i.h"
+#include "md5.h"
+#include "crypto.h"
+
+typedef struct SHA1Context SHA1_CTX;
+
+void SHA1Transform(u32 state[5], const unsigned char buffer[64]);
+
+
+/**
+ * sha1_vector - SHA-1 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 of failure
+ */
+int sha1_vector(size_t num_elem, const u8 *addr[], const size_t *len, u8 *mac)
+{
+	SHA1_CTX ctx;
+	size_t i;
+
+	SHA1Init(&ctx);
+	for (i = 0; i < num_elem; i++)
+		SHA1Update(&ctx, addr[i], len[i]);
+	SHA1Final(mac, &ctx);
+	return 0;
+}
+
+
+/* ===== start - public domain SHA1 implementation ===== */
+
+/*
+SHA-1 in C
+By Steve Reid <sreid@sea-to-sky.net>
+100% Public Domain
+
+-----------------
+Modified 7/98 
+By James H. Brown <jbrown@burgoyne.com>
+Still 100% Public Domain
+
+Corrected a problem which generated improper hash values on 16 bit machines
+Routine SHA1Update changed from
+	void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned int
+len)
+to
+	void SHA1Update(SHA1_CTX* context, unsigned char* data, unsigned
+long len)
+
+The 'len' parameter was declared an int which works fine on 32 bit machines.
+However, on 16 bit machines an int is too small for the shifts being done
+against
+it.  This caused the hash function to generate incorrect values if len was
+greater than 8191 (8K - 1) due to the 'len << 3' on line 3 of SHA1Update().
+
+Since the file IO in main() reads 16K at a time, any file 8K or larger would
+be guaranteed to generate the wrong hash (e.g. Test Vector #3, a million
+"a"s).
+
+I also changed the declaration of variables i & j in SHA1Update to 
+unsigned long from unsigned int for the same reason.
+
+These changes should make no difference to any 32 bit implementations since
+an
+int and a long are the same size in those environments.
+
+--
+I also corrected a few compiler warnings generated by Borland C.
+1. Added #include <process.h> for exit() prototype
+2. Removed unused variable 'j' in SHA1Final
+3. Changed exit(0) to return(0) at end of main.
+
+ALL changes I made can be located by searching for comments containing 'JHB'
+-----------------
+Modified 8/98
+By Steve Reid <sreid@sea-to-sky.net>
+Still 100% public domain
+
+1- Removed #include <process.h> and used return() instead of exit()
+2- Fixed overwriting of finalcount in SHA1Final() (discovered by Chris Hall)
+3- Changed email address from steve@edmweb.com to sreid@sea-to-sky.net
+
+-----------------
+Modified 4/01
+By Saul Kravitz <Saul.Kravitz@celera.com>
+Still 100% PD
+Modified to run on Compaq Alpha hardware.  
+
+-----------------
+Modified 4/01
+By Jouni Malinen <j@w1.fi>
+Minor changes to match the coding style used in Dynamics.
+
+Modified September 24, 2004
+By Jouni Malinen <j@w1.fi>
+Fixed alignment issue in SHA1Transform when SHA1HANDSOFF is defined.
+
+*/
+
+/*
+Test Vectors (from FIPS PUB 180-1)
+"abc"
+  A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D
+"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+  84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1
+A million repetitions of "a"
+  34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F
+*/
+
+#define SHA1HANDSOFF
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+/* blk0() and blk() perform the initial expand. */
+/* I got the idea of expanding during the round function from SSLeay */
+#ifndef WORDS_BIGENDIAN
+#define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) | \
+	(rol(block->l[i], 8) & 0x00FF00FF))
+#else
+#define blk0(i) block->l[i]
+#endif
+#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \
+	block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1))
+
+/* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */
+#define R0(v,w,x,y,z,i) \
+	z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \
+	w = rol(w, 30);
+#define R1(v,w,x,y,z,i) \
+	z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \
+	w = rol(w, 30);
+#define R2(v,w,x,y,z,i) \
+	z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); w = rol(w, 30);
+#define R3(v,w,x,y,z,i) \
+	z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \
+	w = rol(w, 30);
+#define R4(v,w,x,y,z,i) \
+	z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \
+	w=rol(w, 30);
+
+
+#ifdef VERBOSE  /* SAK */
+void SHAPrintContext(SHA1_CTX *context, char *msg)
+{
+	printf("%s (%d,%d) %x %x %x %x %x\n",
+	       msg,
+	       context->count[0], context->count[1], 
+	       context->state[0],
+	       context->state[1],
+	       context->state[2],
+	       context->state[3],
+	       context->state[4]);
+}
+#endif
+
+/* Hash a single 512-bit block. This is the core of the algorithm. */
+
+void SHA1Transform(u32 state[5], const unsigned char buffer[64])
+{
+	u32 a, b, c, d, e;
+	typedef union {
+		unsigned char c[64];
+		u32 l[16];
+	} CHAR64LONG16;
+	CHAR64LONG16* block;
+#ifdef SHA1HANDSOFF
+	CHAR64LONG16 workspace;
+	block = &workspace;
+	os_memcpy(block, buffer, 64);
+#else
+	block = (CHAR64LONG16 *) buffer;
+#endif
+	/* Copy context->state[] to working vars */
+	a = state[0];
+	b = state[1];
+	c = state[2];
+	d = state[3];
+	e = state[4];
+	/* 4 rounds of 20 operations each. Loop unrolled. */
+	R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+	R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+	R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+	R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+	R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+	R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+	R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+	R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+	R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+	R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+	R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+	R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+	R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+	R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+	R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+	R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+	R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+	R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+	R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+	R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+	/* Add the working vars back into context.state[] */
+	state[0] += a;
+	state[1] += b;
+	state[2] += c;
+	state[3] += d;
+	state[4] += e;
+	/* Wipe variables */
+	a = b = c = d = e = 0;
+#ifdef SHA1HANDSOFF
+	os_memset(block, 0, 64);
+#endif
+}
+
+
+/* SHA1Init - Initialize new context */
+
+void SHA1Init(SHA1_CTX* context)
+{
+	/* SHA1 initialization constants */
+	context->state[0] = 0x67452301;
+	context->state[1] = 0xEFCDAB89;
+	context->state[2] = 0x98BADCFE;
+	context->state[3] = 0x10325476;
+	context->state[4] = 0xC3D2E1F0;
+	context->count[0] = context->count[1] = 0;
+}
+
+
+/* Run your data through this. */
+
+void SHA1Update(SHA1_CTX* context, const void *_data, u32 len)
+{
+	u32 i, j;
+	const unsigned char *data = _data;
+
+#ifdef VERBOSE
+	SHAPrintContext(context, "before");
+#endif
+	j = (context->count[0] >> 3) & 63;
+	if ((context->count[0] += len << 3) < (len << 3))
+		context->count[1]++;
+	context->count[1] += (len >> 29);
+	if ((j + len) > 63) {
+		os_memcpy(&context->buffer[j], data, (i = 64-j));
+		SHA1Transform(context->state, context->buffer);
+		for ( ; i + 63 < len; i += 64) {
+			SHA1Transform(context->state, &data[i]);
+		}
+		j = 0;
+	}
+	else i = 0;
+	os_memcpy(&context->buffer[j], &data[i], len - i);
+#ifdef VERBOSE
+	SHAPrintContext(context, "after ");
+#endif
+}
+
+
+/* Add padding and return the message digest. */
+
+void SHA1Final(unsigned char digest[20], SHA1_CTX* context)
+{
+	u32 i;
+	unsigned char finalcount[8];
+
+	for (i = 0; i < 8; i++) {
+		finalcount[i] = (unsigned char)
+			((context->count[(i >= 4 ? 0 : 1)] >>
+			  ((3-(i & 3)) * 8) ) & 255);  /* Endian independent */
+	}
+	SHA1Update(context, (unsigned char *) "\200", 1);
+	while ((context->count[0] & 504) != 448) {
+		SHA1Update(context, (unsigned char *) "\0", 1);
+	}
+	SHA1Update(context, finalcount, 8);  /* Should cause a SHA1Transform()
+					      */
+	for (i = 0; i < 20; i++) {
+		digest[i] = (unsigned char)
+			((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) &
+			 255);
+	}
+	/* Wipe variables */
+	i = 0;
+	os_memset(context->buffer, 0, 64);
+	os_memset(context->state, 0, 20);
+	os_memset(context->count, 0, 8);
+	os_memset(finalcount, 0, 8);
+}
+
+/* ===== end - public domain SHA1 implementation ===== */
diff --git a/hostap/src/crypto/sha1-pbkdf2.c b/hostap/src/crypto/sha1-pbkdf2.c
new file mode 100644
index 0000000..8effe2f
--- /dev/null
+++ b/hostap/src/crypto/sha1-pbkdf2.c
@@ -0,0 +1,92 @@
+/*
+ * SHA1-based key derivation function (PBKDF2) for IEEE 802.11i
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+
+static int pbkdf2_sha1_f(const char *passphrase, const u8 *ssid,
+			 size_t ssid_len, int iterations, unsigned int count,
+			 u8 *digest)
+{
+	unsigned char tmp[SHA1_MAC_LEN], tmp2[SHA1_MAC_LEN];
+	int i, j;
+	unsigned char count_buf[4];
+	const u8 *addr[2];
+	size_t len[2];
+	size_t passphrase_len = os_strlen(passphrase);
+
+	addr[0] = ssid;
+	len[0] = ssid_len;
+	addr[1] = count_buf;
+	len[1] = 4;
+
+	/* F(P, S, c, i) = U1 xor U2 xor ... Uc
+	 * U1 = PRF(P, S || i)
+	 * U2 = PRF(P, U1)
+	 * Uc = PRF(P, Uc-1)
+	 */
+
+	count_buf[0] = (count >> 24) & 0xff;
+	count_buf[1] = (count >> 16) & 0xff;
+	count_buf[2] = (count >> 8) & 0xff;
+	count_buf[3] = count & 0xff;
+	if (hmac_sha1_vector((u8 *) passphrase, passphrase_len, 2, addr, len,
+			     tmp))
+		return -1;
+	os_memcpy(digest, tmp, SHA1_MAC_LEN);
+
+	for (i = 1; i < iterations; i++) {
+		if (hmac_sha1((u8 *) passphrase, passphrase_len, tmp,
+			      SHA1_MAC_LEN, tmp2))
+			return -1;
+		os_memcpy(tmp, tmp2, SHA1_MAC_LEN);
+		for (j = 0; j < SHA1_MAC_LEN; j++)
+			digest[j] ^= tmp2[j];
+	}
+
+	return 0;
+}
+
+
+/**
+ * pbkdf2_sha1 - SHA1-based key derivation function (PBKDF2) for IEEE 802.11i
+ * @passphrase: ASCII passphrase
+ * @ssid: SSID
+ * @ssid_len: SSID length in bytes
+ * @iterations: Number of iterations to run
+ * @buf: Buffer for the generated key
+ * @buflen: Length of the buffer in bytes
+ * Returns: 0 on success, -1 of failure
+ *
+ * This function is used to derive PSK for WPA-PSK. For this protocol,
+ * iterations is set to 4096 and buflen to 32. This function is described in
+ * IEEE Std 802.11-2004, Clause H.4. The main construction is from PKCS#5 v2.0.
+ */
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+		int iterations, u8 *buf, size_t buflen)
+{
+	unsigned int count = 0;
+	unsigned char *pos = buf;
+	size_t left = buflen, plen;
+	unsigned char digest[SHA1_MAC_LEN];
+
+	while (left > 0) {
+		count++;
+		if (pbkdf2_sha1_f(passphrase, ssid, ssid_len, iterations,
+				  count, digest))
+			return -1;
+		plen = left > SHA1_MAC_LEN ? SHA1_MAC_LEN : left;
+		os_memcpy(pos, digest, plen);
+		pos += plen;
+		left -= plen;
+	}
+
+	return 0;
+}
diff --git a/hostap/src/crypto/sha1-prf.c b/hostap/src/crypto/sha1-prf.c
new file mode 100644
index 0000000..90b9e74
--- /dev/null
+++ b/hostap/src/crypto/sha1-prf.c
@@ -0,0 +1,66 @@
+/*
+ * SHA1-based PRF
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+#include "crypto.h"
+
+
+/**
+ * sha1_prf - SHA1-based Pseudo-Random Function (PRF) (IEEE 802.11i, 8.5.1.1)
+ * @key: Key for PRF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ * Returns: 0 on success, -1 of failure
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key (e.g., PMK in IEEE 802.11i).
+ */
+int sha1_prf(const u8 *key, size_t key_len, const char *label,
+	     const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+{
+	u8 counter = 0;
+	size_t pos, plen;
+	u8 hash[SHA1_MAC_LEN];
+	size_t label_len = os_strlen(label) + 1;
+	const unsigned char *addr[3];
+	size_t len[3];
+
+	addr[0] = (u8 *) label;
+	len[0] = label_len;
+	addr[1] = data;
+	len[1] = data_len;
+	addr[2] = &counter;
+	len[2] = 1;
+
+	pos = 0;
+	while (pos < buf_len) {
+		plen = buf_len - pos;
+		if (plen >= SHA1_MAC_LEN) {
+			if (hmac_sha1_vector(key, key_len, 3, addr, len,
+					     &buf[pos]))
+				return -1;
+			pos += SHA1_MAC_LEN;
+		} else {
+			if (hmac_sha1_vector(key, key_len, 3, addr, len,
+					     hash))
+				return -1;
+			os_memcpy(&buf[pos], hash, plen);
+			break;
+		}
+		counter++;
+	}
+
+	return 0;
+}
diff --git a/hostap/src/crypto/sha1-tlsprf.c b/hostap/src/crypto/sha1-tlsprf.c
new file mode 100644
index 0000000..0effd9b
--- /dev/null
+++ b/hostap/src/crypto/sha1-tlsprf.c
@@ -0,0 +1,99 @@
+/*
+ * TLS PRF (SHA1 + MD5)
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+#include "md5.h"
+
+
+/**
+ * tls_prf_sha1_md5 - Pseudo-Random Function for TLS (TLS-PRF, RFC 2246)
+ * @secret: Key for PRF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
+ */
+int tls_prf_sha1_md5(const u8 *secret, size_t secret_len, const char *label,
+		     const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+	size_t L_S1, L_S2, i;
+	const u8 *S1, *S2;
+	u8 A_MD5[MD5_MAC_LEN], A_SHA1[SHA1_MAC_LEN];
+	u8 P_MD5[MD5_MAC_LEN], P_SHA1[SHA1_MAC_LEN];
+	int MD5_pos, SHA1_pos;
+	const u8 *MD5_addr[3];
+	size_t MD5_len[3];
+	const unsigned char *SHA1_addr[3];
+	size_t SHA1_len[3];
+
+	if (secret_len & 1)
+		return -1;
+
+	MD5_addr[0] = A_MD5;
+	MD5_len[0] = MD5_MAC_LEN;
+	MD5_addr[1] = (unsigned char *) label;
+	MD5_len[1] = os_strlen(label);
+	MD5_addr[2] = seed;
+	MD5_len[2] = seed_len;
+
+	SHA1_addr[0] = A_SHA1;
+	SHA1_len[0] = SHA1_MAC_LEN;
+	SHA1_addr[1] = (unsigned char *) label;
+	SHA1_len[1] = os_strlen(label);
+	SHA1_addr[2] = seed;
+	SHA1_len[2] = seed_len;
+
+	/* RFC 2246, Chapter 5
+	 * A(0) = seed, A(i) = HMAC(secret, A(i-1))
+	 * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
+	 * PRF = P_MD5(S1, label + seed) XOR P_SHA-1(S2, label + seed)
+	 */
+
+	L_S1 = L_S2 = (secret_len + 1) / 2;
+	S1 = secret;
+	S2 = secret + L_S1;
+	if (secret_len & 1) {
+		/* The last byte of S1 will be shared with S2 */
+		S2--;
+	}
+
+	hmac_md5_vector(S1, L_S1, 2, &MD5_addr[1], &MD5_len[1], A_MD5);
+	hmac_sha1_vector(S2, L_S2, 2, &SHA1_addr[1], &SHA1_len[1], A_SHA1);
+
+	MD5_pos = MD5_MAC_LEN;
+	SHA1_pos = SHA1_MAC_LEN;
+	for (i = 0; i < outlen; i++) {
+		if (MD5_pos == MD5_MAC_LEN) {
+			hmac_md5_vector(S1, L_S1, 3, MD5_addr, MD5_len, P_MD5);
+			MD5_pos = 0;
+			hmac_md5(S1, L_S1, A_MD5, MD5_MAC_LEN, A_MD5);
+		}
+		if (SHA1_pos == SHA1_MAC_LEN) {
+			hmac_sha1_vector(S2, L_S2, 3, SHA1_addr, SHA1_len,
+					 P_SHA1);
+			SHA1_pos = 0;
+			hmac_sha1(S2, L_S2, A_SHA1, SHA1_MAC_LEN, A_SHA1);
+		}
+
+		out[i] = P_MD5[MD5_pos] ^ P_SHA1[SHA1_pos];
+
+		MD5_pos++;
+		SHA1_pos++;
+	}
+
+	return 0;
+}
diff --git a/hostap/src/crypto/sha1-tprf.c b/hostap/src/crypto/sha1-tprf.c
new file mode 100644
index 0000000..a529494
--- /dev/null
+++ b/hostap/src/crypto/sha1-tprf.c
@@ -0,0 +1,70 @@
+/*
+ * SHA1 T-PRF for EAP-FAST
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+#include "crypto.h"
+
+/**
+ * sha1_t_prf - EAP-FAST Pseudo-Random Function (T-PRF)
+ * @key: Key for PRF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ * Returns: 0 on success, -1 of failure
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key for EAP-FAST. T-PRF is defined in RFC 4851, Section 5.5.
+ */
+int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
+	       const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len)
+{
+	unsigned char counter = 0;
+	size_t pos, plen;
+	u8 hash[SHA1_MAC_LEN];
+	size_t label_len = os_strlen(label);
+	u8 output_len[2];
+	const unsigned char *addr[5];
+	size_t len[5];
+
+	addr[0] = hash;
+	len[0] = 0;
+	addr[1] = (unsigned char *) label;
+	len[1] = label_len + 1;
+	addr[2] = seed;
+	len[2] = seed_len;
+	addr[3] = output_len;
+	len[3] = 2;
+	addr[4] = &counter;
+	len[4] = 1;
+
+	output_len[0] = (buf_len >> 8) & 0xff;
+	output_len[1] = buf_len & 0xff;
+	pos = 0;
+	while (pos < buf_len) {
+		counter++;
+		plen = buf_len - pos;
+		if (hmac_sha1_vector(key, key_len, 5, addr, len, hash))
+			return -1;
+		if (plen >= SHA1_MAC_LEN) {
+			os_memcpy(&buf[pos], hash, SHA1_MAC_LEN);
+			pos += SHA1_MAC_LEN;
+		} else {
+			os_memcpy(&buf[pos], hash, plen);
+			break;
+		}
+		len[0] = SHA1_MAC_LEN;
+	}
+
+	return 0;
+}
diff --git a/hostap/src/crypto/sha1.c b/hostap/src/crypto/sha1.c
new file mode 100644
index 0000000..d48c77d
--- /dev/null
+++ b/hostap/src/crypto/sha1.c
@@ -0,0 +1,104 @@
+/*
+ * SHA1 hash implementation and interface functions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha1.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_sha1_vector - HMAC-SHA1 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash (20 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac)
+{
+	unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
+	unsigned char tk[20];
+	const u8 *_addr[6];
+	size_t _len[6], i;
+
+	if (num_elem > 5) {
+		/*
+		 * Fixed limit on the number of fragments to avoid having to
+		 * allocate memory (which could fail).
+		 */
+		return -1;
+	}
+
+        /* if key is longer than 64 bytes reset it to key = SHA1(key) */
+        if (key_len > 64) {
+		if (sha1_vector(1, &key, &key_len, tk))
+			return -1;
+		key = tk;
+		key_len = 20;
+        }
+
+	/* the HMAC_SHA1 transform looks like:
+	 *
+	 * SHA1(K XOR opad, SHA1(K XOR ipad, text))
+	 *
+	 * where K is an n byte key
+	 * ipad is the byte 0x36 repeated 64 times
+	 * opad is the byte 0x5c repeated 64 times
+	 * and text is the data being protected */
+
+	/* start out by storing key in ipad */
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+	/* XOR key with ipad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x36;
+
+	/* perform inner SHA1 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	for (i = 0; i < num_elem; i++) {
+		_addr[i + 1] = addr[i];
+		_len[i + 1] = len[i];
+	}
+	if (sha1_vector(1 + num_elem, _addr, _len, mac))
+		return -1;
+
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+	/* XOR key with opad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x5c;
+
+	/* perform outer SHA1 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	_addr[1] = mac;
+	_len[1] = SHA1_MAC_LEN;
+	return sha1_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_sha1 - HMAC-SHA1 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (20 bytes)
+ * Returns: 0 on success, -1 of failure
+ */
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	       u8 *mac)
+{
+	return hmac_sha1_vector(key, key_len, 1, &data, &data_len, mac);
+}
diff --git a/hostap/src/crypto/sha1.h b/hostap/src/crypto/sha1.h
new file mode 100644
index 0000000..933cd81
--- /dev/null
+++ b/hostap/src/crypto/sha1.h
@@ -0,0 +1,27 @@
+/*
+ * SHA1 hash implementation and interface functions
+ * Copyright (c) 2003-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA1_H
+#define SHA1_H
+
+#define SHA1_MAC_LEN 20
+
+int hmac_sha1_vector(const u8 *key, size_t key_len, size_t num_elem,
+		     const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
+	       u8 *mac);
+int sha1_prf(const u8 *key, size_t key_len, const char *label,
+	     const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+int sha1_t_prf(const u8 *key, size_t key_len, const char *label,
+	       const u8 *seed, size_t seed_len, u8 *buf, size_t buf_len);
+int __must_check tls_prf_sha1_md5(const u8 *secret, size_t secret_len,
+				  const char *label, const u8 *seed,
+				  size_t seed_len, u8 *out, size_t outlen);
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+		int iterations, u8 *buf, size_t buflen);
+#endif /* SHA1_H */
diff --git a/hostap/src/crypto/sha1_i.h b/hostap/src/crypto/sha1_i.h
new file mode 100644
index 0000000..344387e
--- /dev/null
+++ b/hostap/src/crypto/sha1_i.h
@@ -0,0 +1,23 @@
+/*
+ * SHA1 internal definitions
+ * Copyright (c) 2003-2005, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA1_I_H
+#define SHA1_I_H
+
+struct SHA1Context {
+	u32 state[5];
+	u32 count[2];
+	unsigned char buffer[64];
+};
+
+void SHA1Init(struct SHA1Context *context);
+void SHA1Update(struct SHA1Context *context, const void *data, u32 len);
+void SHA1Final(unsigned char digest[20], struct SHA1Context *context);
+void SHA1Transform(u32 state[5], const unsigned char buffer[64]);
+
+#endif /* SHA1_I_H */
diff --git a/hostap/src/crypto/sha256-internal.c b/hostap/src/crypto/sha256-internal.c
new file mode 100644
index 0000000..35299b0
--- /dev/null
+++ b/hostap/src/crypto/sha256-internal.c
@@ -0,0 +1,226 @@
+/*
+ * SHA-256 hash implementation and interface functions
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha256.h"
+#include "sha256_i.h"
+#include "crypto.h"
+
+
+/**
+ * sha256_vector - SHA256 hash for data vector
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash
+ * Returns: 0 on success, -1 of failure
+ */
+int sha256_vector(size_t num_elem, const u8 *addr[], const size_t *len,
+		  u8 *mac)
+{
+	struct sha256_state ctx;
+	size_t i;
+
+	sha256_init(&ctx);
+	for (i = 0; i < num_elem; i++)
+		if (sha256_process(&ctx, addr[i], len[i]))
+			return -1;
+	if (sha256_done(&ctx, mac))
+		return -1;
+	return 0;
+}
+
+
+/* ===== start - public domain SHA256 implementation ===== */
+
+/* This is based on SHA256 implementation in LibTomCrypt that was released into
+ * public domain by Tom St Denis. */
+
+/* the K array */
+static const unsigned long K[64] = {
+	0x428a2f98UL, 0x71374491UL, 0xb5c0fbcfUL, 0xe9b5dba5UL, 0x3956c25bUL,
+	0x59f111f1UL, 0x923f82a4UL, 0xab1c5ed5UL, 0xd807aa98UL, 0x12835b01UL,
+	0x243185beUL, 0x550c7dc3UL, 0x72be5d74UL, 0x80deb1feUL, 0x9bdc06a7UL,
+	0xc19bf174UL, 0xe49b69c1UL, 0xefbe4786UL, 0x0fc19dc6UL, 0x240ca1ccUL,
+	0x2de92c6fUL, 0x4a7484aaUL, 0x5cb0a9dcUL, 0x76f988daUL, 0x983e5152UL,
+	0xa831c66dUL, 0xb00327c8UL, 0xbf597fc7UL, 0xc6e00bf3UL, 0xd5a79147UL,
+	0x06ca6351UL, 0x14292967UL, 0x27b70a85UL, 0x2e1b2138UL, 0x4d2c6dfcUL,
+	0x53380d13UL, 0x650a7354UL, 0x766a0abbUL, 0x81c2c92eUL, 0x92722c85UL,
+	0xa2bfe8a1UL, 0xa81a664bUL, 0xc24b8b70UL, 0xc76c51a3UL, 0xd192e819UL,
+	0xd6990624UL, 0xf40e3585UL, 0x106aa070UL, 0x19a4c116UL, 0x1e376c08UL,
+	0x2748774cUL, 0x34b0bcb5UL, 0x391c0cb3UL, 0x4ed8aa4aUL, 0x5b9cca4fUL,
+	0x682e6ff3UL, 0x748f82eeUL, 0x78a5636fUL, 0x84c87814UL, 0x8cc70208UL,
+	0x90befffaUL, 0xa4506cebUL, 0xbef9a3f7UL, 0xc67178f2UL
+};
+
+
+/* Various logical functions */
+#define RORc(x, y) \
+( ((((unsigned long) (x) & 0xFFFFFFFFUL) >> (unsigned long) ((y) & 31)) | \
+   ((unsigned long) (x) << (unsigned long) (32 - ((y) & 31)))) & 0xFFFFFFFFUL)
+#define Ch(x,y,z)       (z ^ (x & (y ^ z)))
+#define Maj(x,y,z)      (((x | y) & z) | (x & y)) 
+#define S(x, n)         RORc((x), (n))
+#define R(x, n)         (((x)&0xFFFFFFFFUL)>>(n))
+#define Sigma0(x)       (S(x, 2) ^ S(x, 13) ^ S(x, 22))
+#define Sigma1(x)       (S(x, 6) ^ S(x, 11) ^ S(x, 25))
+#define Gamma0(x)       (S(x, 7) ^ S(x, 18) ^ R(x, 3))
+#define Gamma1(x)       (S(x, 17) ^ S(x, 19) ^ R(x, 10))
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+/* compress 512-bits */
+static int sha256_compress(struct sha256_state *md, unsigned char *buf)
+{
+	u32 S[8], W[64], t0, t1;
+	u32 t;
+	int i;
+
+	/* copy state into S */
+	for (i = 0; i < 8; i++) {
+		S[i] = md->state[i];
+	}
+
+	/* copy the state into 512-bits into W[0..15] */
+	for (i = 0; i < 16; i++)
+		W[i] = WPA_GET_BE32(buf + (4 * i));
+
+	/* fill W[16..63] */
+	for (i = 16; i < 64; i++) {
+		W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) +
+			W[i - 16];
+	}        
+
+	/* Compress */
+#define RND(a,b,c,d,e,f,g,h,i)                          \
+	t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i];	\
+	t1 = Sigma0(a) + Maj(a, b, c);			\
+	d += t0;					\
+	h  = t0 + t1;
+
+	for (i = 0; i < 64; ++i) {
+		RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i);
+		t = S[7]; S[7] = S[6]; S[6] = S[5]; S[5] = S[4]; 
+		S[4] = S[3]; S[3] = S[2]; S[2] = S[1]; S[1] = S[0]; S[0] = t;
+	}
+
+	/* feedback */
+	for (i = 0; i < 8; i++) {
+		md->state[i] = md->state[i] + S[i];
+	}
+	return 0;
+}
+
+
+/* Initialize the hash state */
+void sha256_init(struct sha256_state *md)
+{
+	md->curlen = 0;
+	md->length = 0;
+	md->state[0] = 0x6A09E667UL;
+	md->state[1] = 0xBB67AE85UL;
+	md->state[2] = 0x3C6EF372UL;
+	md->state[3] = 0xA54FF53AUL;
+	md->state[4] = 0x510E527FUL;
+	md->state[5] = 0x9B05688CUL;
+	md->state[6] = 0x1F83D9ABUL;
+	md->state[7] = 0x5BE0CD19UL;
+}
+
+/**
+   Process a block of memory though the hash
+   @param md     The hash state
+   @param in     The data to hash
+   @param inlen  The length of the data (octets)
+   @return CRYPT_OK if successful
+*/
+int sha256_process(struct sha256_state *md, const unsigned char *in,
+		   unsigned long inlen)
+{
+	unsigned long n;
+
+	if (md->curlen >= sizeof(md->buf))
+		return -1;
+
+	while (inlen > 0) {
+		if (md->curlen == 0 && inlen >= SHA256_BLOCK_SIZE) {
+			if (sha256_compress(md, (unsigned char *) in) < 0)
+				return -1;
+			md->length += SHA256_BLOCK_SIZE * 8;
+			in += SHA256_BLOCK_SIZE;
+			inlen -= SHA256_BLOCK_SIZE;
+		} else {
+			n = MIN(inlen, (SHA256_BLOCK_SIZE - md->curlen));
+			os_memcpy(md->buf + md->curlen, in, n);
+			md->curlen += n;
+			in += n;
+			inlen -= n;
+			if (md->curlen == SHA256_BLOCK_SIZE) {
+				if (sha256_compress(md, md->buf) < 0)
+					return -1;
+				md->length += 8 * SHA256_BLOCK_SIZE;
+				md->curlen = 0;
+			}
+		}
+	}
+
+	return 0;
+}
+
+
+/**
+   Terminate the hash to get the digest
+   @param md  The hash state
+   @param out [out] The destination of the hash (32 bytes)
+   @return CRYPT_OK if successful
+*/
+int sha256_done(struct sha256_state *md, unsigned char *out)
+{
+	int i;
+
+	if (md->curlen >= sizeof(md->buf))
+		return -1;
+
+	/* increase the length of the message */
+	md->length += md->curlen * 8;
+
+	/* append the '1' bit */
+	md->buf[md->curlen++] = (unsigned char) 0x80;
+
+	/* if the length is currently above 56 bytes we append zeros
+	 * then compress.  Then we can fall back to padding zeros and length
+	 * encoding like normal.
+	 */
+	if (md->curlen > 56) {
+		while (md->curlen < SHA256_BLOCK_SIZE) {
+			md->buf[md->curlen++] = (unsigned char) 0;
+		}
+		sha256_compress(md, md->buf);
+		md->curlen = 0;
+	}
+
+	/* pad up to 56 bytes of zeroes */
+	while (md->curlen < 56) {
+		md->buf[md->curlen++] = (unsigned char) 0;
+	}
+
+	/* store length */
+	WPA_PUT_BE64(md->buf + 56, md->length);
+	sha256_compress(md, md->buf);
+
+	/* copy output */
+	for (i = 0; i < 8; i++)
+		WPA_PUT_BE32(out + (4 * i), md->state[i]);
+
+	return 0;
+}
+
+/* ===== end - public domain SHA256 implementation ===== */
diff --git a/hostap/src/crypto/sha256-prf.c b/hostap/src/crypto/sha256-prf.c
new file mode 100644
index 0000000..0da6d13
--- /dev/null
+++ b/hostap/src/crypto/sha256-prf.c
@@ -0,0 +1,64 @@
+/*
+ * SHA256-based PRF (IEEE 802.11r)
+ * Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha256.h"
+#include "crypto.h"
+
+
+/**
+ * sha256_prf - SHA256-based Pseudo-Random Function (IEEE 802.11r, 8.5.1.5.2)
+ * @key: Key for PRF
+ * @key_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @data: Extra data to bind into the key
+ * @data_len: Length of the data
+ * @buf: Buffer for the generated pseudo-random key
+ * @buf_len: Number of bytes of key to generate
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key.
+ */
+void sha256_prf(const u8 *key, size_t key_len, const char *label,
+		const u8 *data, size_t data_len, u8 *buf, size_t buf_len)
+{
+	u16 counter = 1;
+	size_t pos, plen;
+	u8 hash[SHA256_MAC_LEN];
+	const u8 *addr[4];
+	size_t len[4];
+	u8 counter_le[2], length_le[2];
+
+	addr[0] = counter_le;
+	len[0] = 2;
+	addr[1] = (u8 *) label;
+	len[1] = os_strlen(label);
+	addr[2] = data;
+	len[2] = data_len;
+	addr[3] = length_le;
+	len[3] = sizeof(length_le);
+
+	WPA_PUT_LE16(length_le, buf_len * 8);
+	pos = 0;
+	while (pos < buf_len) {
+		plen = buf_len - pos;
+		WPA_PUT_LE16(counter_le, counter);
+		if (plen >= SHA256_MAC_LEN) {
+			hmac_sha256_vector(key, key_len, 4, addr, len,
+					   &buf[pos]);
+			pos += SHA256_MAC_LEN;
+		} else {
+			hmac_sha256_vector(key, key_len, 4, addr, len, hash);
+			os_memcpy(&buf[pos], hash, plen);
+			break;
+		}
+		counter++;
+	}
+}
diff --git a/hostap/src/crypto/sha256-tlsprf.c b/hostap/src/crypto/sha256-tlsprf.c
new file mode 100644
index 0000000..0528dad
--- /dev/null
+++ b/hostap/src/crypto/sha256-tlsprf.c
@@ -0,0 +1,66 @@
+/*
+ * TLS PRF P_SHA256
+ * Copyright (c) 2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha256.h"
+
+
+/**
+ * tls_prf_sha256 - Pseudo-Random Function for TLS v1.2 (P_SHA256, RFC 5246)
+ * @secret: Key for PRF
+ * @secret_len: Length of the key in bytes
+ * @label: A unique label for each purpose of the PRF
+ * @seed: Seed value to bind into the key
+ * @seed_len: Length of the seed
+ * @out: Buffer for the generated pseudo-random key
+ * @outlen: Number of bytes of key to generate
+ * Returns: 0 on success, -1 on failure.
+ *
+ * This function is used to derive new, cryptographically separate keys from a
+ * given key in TLS. This PRF is defined in RFC 2246, Chapter 5.
+ */
+void tls_prf_sha256(const u8 *secret, size_t secret_len, const char *label,
+		    const u8 *seed, size_t seed_len, u8 *out, size_t outlen)
+{
+	size_t clen;
+	u8 A[SHA256_MAC_LEN];
+	u8 P[SHA256_MAC_LEN];
+	size_t pos;
+	const unsigned char *addr[3];
+	size_t len[3];
+
+	addr[0] = A;
+	len[0] = SHA256_MAC_LEN;
+	addr[1] = (unsigned char *) label;
+	len[1] = os_strlen(label);
+	addr[2] = seed;
+	len[2] = seed_len;
+
+	/*
+	 * RFC 5246, Chapter 5
+	 * A(0) = seed, A(i) = HMAC(secret, A(i-1))
+	 * P_hash = HMAC(secret, A(1) + seed) + HMAC(secret, A(2) + seed) + ..
+	 * PRF(secret, label, seed) = P_SHA256(secret, label + seed)
+	 */
+
+	hmac_sha256_vector(secret, secret_len, 2, &addr[1], &len[1], A);
+
+	pos = 0;
+	while (pos < outlen) {
+		hmac_sha256_vector(secret, secret_len, 3, addr, len, P);
+		hmac_sha256(secret, secret_len, A, SHA256_MAC_LEN, A);
+
+		clen = outlen - pos;
+		if (clen > SHA256_MAC_LEN)
+			clen = SHA256_MAC_LEN;
+		os_memcpy(out + pos, P, clen);
+		pos += clen;
+	}
+}
diff --git a/hostap/src/crypto/sha256.c b/hostap/src/crypto/sha256.c
new file mode 100644
index 0000000..b55e976
--- /dev/null
+++ b/hostap/src/crypto/sha256.c
@@ -0,0 +1,104 @@
+/*
+ * SHA-256 hash implementation and interface functions
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "sha256.h"
+#include "crypto.h"
+
+
+/**
+ * hmac_sha256_vector - HMAC-SHA256 over data vector (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @num_elem: Number of elements in the data vector
+ * @addr: Pointers to the data areas
+ * @len: Lengths of the data blocks
+ * @mac: Buffer for the hash (32 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac)
+{
+	unsigned char k_pad[64]; /* padding - key XORd with ipad/opad */
+	unsigned char tk[32];
+	const u8 *_addr[6];
+	size_t _len[6], i;
+
+	if (num_elem > 5) {
+		/*
+		 * Fixed limit on the number of fragments to avoid having to
+		 * allocate memory (which could fail).
+		 */
+		return -1;
+	}
+
+        /* if key is longer than 64 bytes reset it to key = SHA256(key) */
+        if (key_len > 64) {
+		if (sha256_vector(1, &key, &key_len, tk) < 0)
+			return -1;
+		key = tk;
+		key_len = 32;
+        }
+
+	/* the HMAC_SHA256 transform looks like:
+	 *
+	 * SHA256(K XOR opad, SHA256(K XOR ipad, text))
+	 *
+	 * where K is an n byte key
+	 * ipad is the byte 0x36 repeated 64 times
+	 * opad is the byte 0x5c repeated 64 times
+	 * and text is the data being protected */
+
+	/* start out by storing key in ipad */
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+	/* XOR key with ipad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x36;
+
+	/* perform inner SHA256 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	for (i = 0; i < num_elem; i++) {
+		_addr[i + 1] = addr[i];
+		_len[i + 1] = len[i];
+	}
+	if (sha256_vector(1 + num_elem, _addr, _len, mac) < 0)
+		return -1;
+
+	os_memset(k_pad, 0, sizeof(k_pad));
+	os_memcpy(k_pad, key, key_len);
+	/* XOR key with opad values */
+	for (i = 0; i < 64; i++)
+		k_pad[i] ^= 0x5c;
+
+	/* perform outer SHA256 */
+	_addr[0] = k_pad;
+	_len[0] = 64;
+	_addr[1] = mac;
+	_len[1] = SHA256_MAC_LEN;
+	return sha256_vector(2, _addr, _len, mac);
+}
+
+
+/**
+ * hmac_sha256 - HMAC-SHA256 over data buffer (RFC 2104)
+ * @key: Key for HMAC operations
+ * @key_len: Length of the key in bytes
+ * @data: Pointers to the data area
+ * @data_len: Length of the data area
+ * @mac: Buffer for the hash (32 bytes)
+ * Returns: 0 on success, -1 on failure
+ */
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac)
+{
+	return hmac_sha256_vector(key, key_len, 1, &data, &data_len, mac);
+}
diff --git a/hostap/src/crypto/sha256.h b/hostap/src/crypto/sha256.h
new file mode 100644
index 0000000..fcac800
--- /dev/null
+++ b/hostap/src/crypto/sha256.h
@@ -0,0 +1,24 @@
+/*
+ * SHA256 hash implementation and interface functions
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA256_H
+#define SHA256_H
+
+#define SHA256_MAC_LEN 32
+
+int hmac_sha256_vector(const u8 *key, size_t key_len, size_t num_elem,
+		       const u8 *addr[], const size_t *len, u8 *mac);
+int hmac_sha256(const u8 *key, size_t key_len, const u8 *data,
+		size_t data_len, u8 *mac);
+void sha256_prf(const u8 *key, size_t key_len, const char *label,
+	      const u8 *data, size_t data_len, u8 *buf, size_t buf_len);
+void tls_prf_sha256(const u8 *secret, size_t secret_len,
+		    const char *label, const u8 *seed, size_t seed_len,
+		    u8 *out, size_t outlen);
+
+#endif /* SHA256_H */
diff --git a/hostap/src/crypto/sha256_i.h b/hostap/src/crypto/sha256_i.h
new file mode 100644
index 0000000..a502d2b
--- /dev/null
+++ b/hostap/src/crypto/sha256_i.h
@@ -0,0 +1,25 @@
+/*
+ * SHA-256 internal definitions
+ * Copyright (c) 2003-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef SHA256_I_H
+#define SHA256_I_H
+
+#define SHA256_BLOCK_SIZE 64
+
+struct sha256_state {
+	u64 length;
+	u32 state[8], curlen;
+	u8 buf[SHA256_BLOCK_SIZE];
+};
+
+void sha256_init(struct sha256_state *md);
+int sha256_process(struct sha256_state *md, const unsigned char *in,
+		   unsigned long inlen);
+int sha256_done(struct sha256_state *md, unsigned char *out);
+
+#endif /* SHA256_I_H */
diff --git a/hostap/src/crypto/tls.h b/hostap/src/crypto/tls.h
new file mode 100644
index 0000000..b61e439
--- /dev/null
+++ b/hostap/src/crypto/tls.h
@@ -0,0 +1,529 @@
+/*
+ * SSL/TLS interface definition
+ * Copyright (c) 2004-2010, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef TLS_H
+#define TLS_H
+
+struct tls_connection;
+
+struct tls_keys {
+	const u8 *master_key; /* TLS master secret */
+	size_t master_key_len;
+	const u8 *client_random;
+	size_t client_random_len;
+	const u8 *server_random;
+	size_t server_random_len;
+};
+
+enum tls_event {
+	TLS_CERT_CHAIN_SUCCESS,
+	TLS_CERT_CHAIN_FAILURE,
+	TLS_PEER_CERTIFICATE,
+	TLS_ALERT
+};
+
+/*
+ * Note: These are used as identifier with external programs and as such, the
+ * values must not be changed.
+ */
+enum tls_fail_reason {
+	TLS_FAIL_UNSPECIFIED = 0,
+	TLS_FAIL_UNTRUSTED = 1,
+	TLS_FAIL_REVOKED = 2,
+	TLS_FAIL_NOT_YET_VALID = 3,
+	TLS_FAIL_EXPIRED = 4,
+	TLS_FAIL_SUBJECT_MISMATCH = 5,
+	TLS_FAIL_ALTSUBJECT_MISMATCH = 6,
+	TLS_FAIL_BAD_CERTIFICATE = 7,
+	TLS_FAIL_SERVER_CHAIN_PROBE = 8
+};
+
+union tls_event_data {
+	struct {
+		int depth;
+		const char *subject;
+		enum tls_fail_reason reason;
+		const char *reason_txt;
+		const struct wpabuf *cert;
+	} cert_fail;
+
+	struct {
+		int depth;
+		const char *subject;
+		const struct wpabuf *cert;
+		const u8 *hash;
+		size_t hash_len;
+	} peer_cert;
+
+	struct {
+		int is_local;
+		const char *type;
+		const char *description;
+	} alert;
+};
+
+struct tls_config {
+	const char *opensc_engine_path;
+	const char *pkcs11_engine_path;
+	const char *pkcs11_module_path;
+	int fips_mode;
+	int cert_in_cb;
+
+	void (*event_cb)(void *ctx, enum tls_event ev,
+			 union tls_event_data *data);
+	void *cb_ctx;
+};
+
+#define TLS_CONN_ALLOW_SIGN_RSA_MD5 BIT(0)
+#define TLS_CONN_DISABLE_TIME_CHECKS BIT(1)
+#define TLS_CONN_DISABLE_SESSION_TICKET BIT(2)
+
+/**
+ * struct tls_connection_params - Parameters for TLS connection
+ * @ca_cert: File or reference name for CA X.509 certificate in PEM or DER
+ * format
+ * @ca_cert_blob: ca_cert as inlined data or %NULL if not used
+ * @ca_cert_blob_len: ca_cert_blob length
+ * @ca_path: Path to CA certificates (OpenSSL specific)
+ * @subject_match: String to match in the subject of the peer certificate or
+ * %NULL to allow all subjects
+ * @altsubject_match: String to match in the alternative subject of the peer
+ * certificate or %NULL to allow all alternative subjects
+ * @client_cert: File or reference name for client X.509 certificate in PEM or
+ * DER format
+ * @client_cert_blob: client_cert as inlined data or %NULL if not used
+ * @client_cert_blob_len: client_cert_blob length
+ * @private_key: File or reference name for client private key in PEM or DER
+ * format (traditional format (RSA PRIVATE KEY) or PKCS#8 (PRIVATE KEY)
+ * @private_key_blob: private_key as inlined data or %NULL if not used
+ * @private_key_blob_len: private_key_blob length
+ * @private_key_passwd: Passphrase for decrypted private key, %NULL if no
+ * passphrase is used.
+ * @dh_file: File name for DH/DSA data in PEM format, or %NULL if not used
+ * @dh_blob: dh_file as inlined data or %NULL if not used
+ * @dh_blob_len: dh_blob length
+ * @engine: 1 = use engine (e.g., a smartcard) for private key operations
+ * (this is OpenSSL specific for now)
+ * @engine_id: engine id string (this is OpenSSL specific for now)
+ * @ppin: pointer to the pin variable in the configuration
+ * (this is OpenSSL specific for now)
+ * @key_id: the private key's id when using engine (this is OpenSSL
+ * specific for now)
+ * @cert_id: the certificate's id when using engine
+ * @ca_cert_id: the CA certificate's id when using engine
+ * @flags: Parameter options (TLS_CONN_*)
+ *
+ * TLS connection parameters to be configured with tls_connection_set_params()
+ * and tls_global_set_params().
+ *
+ * Certificates and private key can be configured either as a reference name
+ * (file path or reference to certificate store) or by providing the same data
+ * as a pointer to the data in memory. Only one option will be used for each
+ * field.
+ */
+struct tls_connection_params {
+	const char *ca_cert;
+	const u8 *ca_cert_blob;
+	size_t ca_cert_blob_len;
+	const char *ca_path;
+	const char *subject_match;
+	const char *altsubject_match;
+	const char *client_cert;
+	const u8 *client_cert_blob;
+	size_t client_cert_blob_len;
+	const char *private_key;
+	const u8 *private_key_blob;
+	size_t private_key_blob_len;
+	const char *private_key_passwd;
+	const char *dh_file;
+	const u8 *dh_blob;
+	size_t dh_blob_len;
+
+	/* OpenSSL specific variables */
+	int engine;
+	const char *engine_id;
+	const char *pin;
+	const char *key_id;
+	const char *cert_id;
+	const char *ca_cert_id;
+
+	unsigned int flags;
+};
+
+
+/**
+ * tls_init - Initialize TLS library
+ * @conf: Configuration data for TLS library
+ * Returns: Context data to be used as tls_ctx in calls to other functions,
+ * or %NULL on failure.
+ *
+ * Called once during program startup and once for each RSN pre-authentication
+ * session. In other words, there can be two concurrent TLS contexts. If global
+ * library initialization is needed (i.e., one that is shared between both
+ * authentication types), the TLS library wrapper should maintain a reference
+ * counter and do global initialization only when moving from 0 to 1 reference.
+ */
+void * tls_init(const struct tls_config *conf);
+
+/**
+ * tls_deinit - Deinitialize TLS library
+ * @tls_ctx: TLS context data from tls_init()
+ *
+ * Called once during program shutdown and once for each RSN pre-authentication
+ * session. If global library deinitialization is needed (i.e., one that is
+ * shared between both authentication types), the TLS library wrapper should
+ * maintain a reference counter and do global deinitialization only when moving
+ * from 1 to 0 references.
+ */
+void tls_deinit(void *tls_ctx);
+
+/**
+ * tls_get_errors - Process pending errors
+ * @tls_ctx: TLS context data from tls_init()
+ * Returns: Number of found error, 0 if no errors detected.
+ *
+ * Process all pending TLS errors.
+ */
+int tls_get_errors(void *tls_ctx);
+
+/**
+ * tls_connection_init - Initialize a new TLS connection
+ * @tls_ctx: TLS context data from tls_init()
+ * Returns: Connection context data, conn for other function calls
+ */
+struct tls_connection * tls_connection_init(void *tls_ctx);
+
+/**
+ * tls_connection_deinit - Free TLS connection data
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ *
+ * Release all resources allocated for TLS connection.
+ */
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn);
+
+/**
+ * tls_connection_established - Has the TLS connection been completed?
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: 1 if TLS connection has been completed, 0 if not.
+ */
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn);
+
+/**
+ * tls_connection_shutdown - Shutdown TLS connection
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: 0 on success, -1 on failure
+ *
+ * Shutdown current TLS connection without releasing all resources. New
+ * connection can be started by using the same conn without having to call
+ * tls_connection_init() or setting certificates etc. again. The new
+ * connection should try to use session resumption.
+ */
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn);
+
+enum {
+	TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED = -3,
+	TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED = -2
+};
+
+/**
+ * tls_connection_set_params - Set TLS connection parameters
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @params: Connection parameters
+ * Returns: 0 on success, -1 on failure,
+ * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
+ * PKCS#11 engine failure, or
+ * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
+ * PKCS#11 engine private key.
+ */
+int __must_check
+tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			  const struct tls_connection_params *params);
+
+/**
+ * tls_global_set_params - Set TLS parameters for all TLS connection
+ * @tls_ctx: TLS context data from tls_init()
+ * @params: Global TLS parameters
+ * Returns: 0 on success, -1 on failure,
+ * TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED (-2) on possible PIN error causing
+ * PKCS#11 engine failure, or
+ * TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED (-3) on failure to verify the
+ * PKCS#11 engine private key.
+ */
+int __must_check tls_global_set_params(
+	void *tls_ctx, const struct tls_connection_params *params);
+
+/**
+ * tls_global_set_verify - Set global certificate verification options
+ * @tls_ctx: TLS context data from tls_init()
+ * @check_crl: 0 = do not verify CRLs, 1 = verify CRL for the user certificate,
+ * 2 = verify CRL for all certificates
+ * Returns: 0 on success, -1 on failure
+ */
+int __must_check tls_global_set_verify(void *tls_ctx, int check_crl);
+
+/**
+ * tls_connection_set_verify - Set certificate verification options
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @verify_peer: 1 = verify peer certificate
+ * Returns: 0 on success, -1 on failure
+ */
+int __must_check tls_connection_set_verify(void *tls_ctx,
+					   struct tls_connection *conn,
+					   int verify_peer);
+
+/**
+ * tls_connection_get_keys - Get master key and random data from TLS connection
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @keys: Structure of key/random data (filled on success)
+ * Returns: 0 on success, -1 on failure
+ */
+int __must_check tls_connection_get_keys(void *tls_ctx,
+					 struct tls_connection *conn,
+					 struct tls_keys *keys);
+
+/**
+ * tls_connection_prf - Use TLS-PRF to derive keying material
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @label: Label (e.g., description of the key) for PRF
+ * @server_random_first: seed is 0 = client_random|server_random,
+ * 1 = server_random|client_random
+ * @out: Buffer for output data from TLS-PRF
+ * @out_len: Length of the output buffer
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is optional to implement if tls_connection_get_keys() provides
+ * access to master secret and server/client random values. If these values are
+ * not exported from the TLS library, tls_connection_prf() is required so that
+ * further keying material can be derived from the master secret. If not
+ * implemented, the function will still need to be defined, but it can just
+ * return -1. Example implementation of this function is in tls_prf_sha1_md5()
+ * when it is called with seed set to client_random|server_random (or
+ * server_random|client_random).
+ */
+int __must_check  tls_connection_prf(void *tls_ctx,
+				     struct tls_connection *conn,
+				     const char *label,
+				     int server_random_first,
+				     u8 *out, size_t out_len);
+
+/**
+ * tls_connection_handshake - Process TLS handshake (client side)
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @in_data: Input data from TLS server
+ * @appl_data: Pointer to application data pointer, or %NULL if dropped
+ * Returns: Output data, %NULL on failure
+ *
+ * The caller is responsible for freeing the returned output data. If the final
+ * handshake message includes application data, this is decrypted and
+ * appl_data (if not %NULL) is set to point this data. The caller is
+ * responsible for freeing appl_data.
+ *
+ * This function is used during TLS handshake. The first call is done with
+ * in_data == %NULL and the library is expected to return ClientHello packet.
+ * This packet is then send to the server and a response from server is given
+ * to TLS library by calling this function again with in_data pointing to the
+ * TLS message from the server.
+ *
+ * If the TLS handshake fails, this function may return %NULL. However, if the
+ * TLS library has a TLS alert to send out, that should be returned as the
+ * output data. In this case, tls_connection_get_failed() must return failure
+ * (> 0).
+ *
+ * tls_connection_established() should return 1 once the TLS handshake has been
+ * completed successfully.
+ */
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+					 struct tls_connection *conn,
+					 const struct wpabuf *in_data,
+					 struct wpabuf **appl_data);
+
+struct wpabuf * tls_connection_handshake2(void *tls_ctx,
+					  struct tls_connection *conn,
+					  const struct wpabuf *in_data,
+					  struct wpabuf **appl_data,
+					  int *more_data_needed);
+
+/**
+ * tls_connection_server_handshake - Process TLS handshake (server side)
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @in_data: Input data from TLS peer
+ * @appl_data: Pointer to application data pointer, or %NULL if dropped
+ * Returns: Output data, %NULL on failure
+ *
+ * The caller is responsible for freeing the returned output data.
+ */
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+						struct tls_connection *conn,
+						const struct wpabuf *in_data,
+						struct wpabuf **appl_data);
+
+/**
+ * tls_connection_encrypt - Encrypt data into TLS tunnel
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @in_data: Plaintext data to be encrypted
+ * Returns: Encrypted TLS data or %NULL on failure
+ *
+ * This function is used after TLS handshake has been completed successfully to
+ * send data in the encrypted tunnel. The caller is responsible for freeing the
+ * returned output data.
+ */
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data);
+
+/**
+ * tls_connection_decrypt - Decrypt data from TLS tunnel
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @in_data: Encrypted TLS data
+ * Returns: Decrypted TLS data or %NULL on failure
+ *
+ * This function is used after TLS handshake has been completed successfully to
+ * receive data from the encrypted tunnel. The caller is responsible for
+ * freeing the returned output data.
+ */
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data);
+
+struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
+					struct tls_connection *conn,
+					const struct wpabuf *in_data,
+					int *more_data_needed);
+
+/**
+ * tls_connection_resumed - Was session resumption used
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: 1 if current session used session resumption, 0 if not
+ */
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn);
+
+enum {
+	TLS_CIPHER_NONE,
+	TLS_CIPHER_RC4_SHA /* 0x0005 */,
+	TLS_CIPHER_AES128_SHA /* 0x002f */,
+	TLS_CIPHER_RSA_DHE_AES128_SHA /* 0x0031 */,
+	TLS_CIPHER_ANON_DH_AES128_SHA /* 0x0034 */
+};
+
+/**
+ * tls_connection_set_cipher_list - Configure acceptable cipher suites
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @ciphers: Zero (TLS_CIPHER_NONE) terminated list of allowed ciphers
+ * (TLS_CIPHER_*).
+ * Returns: 0 on success, -1 on failure
+ */
+int __must_check tls_connection_set_cipher_list(void *tls_ctx,
+						struct tls_connection *conn,
+						u8 *ciphers);
+
+/**
+ * tls_get_cipher - Get current cipher name
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @buf: Buffer for the cipher name
+ * @buflen: buf size
+ * Returns: 0 on success, -1 on failure
+ *
+ * Get the name of the currently used cipher.
+ */
+int __must_check tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+				char *buf, size_t buflen);
+
+/**
+ * tls_connection_enable_workaround - Enable TLS workaround options
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: 0 on success, -1 on failure
+ *
+ * This function is used to enable connection-specific workaround options for
+ * buffer SSL/TLS implementations.
+ */
+int __must_check tls_connection_enable_workaround(void *tls_ctx,
+						  struct tls_connection *conn);
+
+/**
+ * tls_connection_client_hello_ext - Set TLS extension for ClientHello
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * @ext_type: Extension type
+ * @data: Extension payload (%NULL to remove extension)
+ * @data_len: Extension payload length
+ * Returns: 0 on success, -1 on failure
+ */
+int __must_check tls_connection_client_hello_ext(void *tls_ctx,
+						 struct tls_connection *conn,
+						 int ext_type, const u8 *data,
+						 size_t data_len);
+
+/**
+ * tls_connection_get_failed - Get connection failure status
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ *
+ * Returns >0 if connection has failed, 0 if not.
+ */
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn);
+
+/**
+ * tls_connection_get_read_alerts - Get connection read alert status
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: Number of times a fatal read (remote end reported error) has
+ * happened during this connection.
+ */
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn);
+
+/**
+ * tls_connection_get_write_alerts - Get connection write alert status
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: Number of times a fatal write (locally detected error) has happened
+ * during this connection.
+ */
+int tls_connection_get_write_alerts(void *tls_ctx,
+				    struct tls_connection *conn);
+
+/**
+ * tls_connection_get_keyblock_size - Get TLS key_block size
+ * @tls_ctx: TLS context data from tls_init()
+ * @conn: Connection context data from tls_connection_init()
+ * Returns: Size of the key_block for the negotiated cipher suite or -1 on
+ * failure
+ */
+int tls_connection_get_keyblock_size(void *tls_ctx,
+				     struct tls_connection *conn);
+
+/**
+ * tls_capabilities - Get supported TLS capabilities
+ * @tls_ctx: TLS context data from tls_init()
+ * Returns: Bit field of supported TLS capabilities (TLS_CAPABILITY_*)
+ */
+unsigned int tls_capabilities(void *tls_ctx);
+
+typedef int (*tls_session_ticket_cb)
+(void *ctx, const u8 *ticket, size_t len, const u8 *client_random,
+ const u8 *server_random, u8 *master_secret);
+
+int __must_check  tls_connection_set_session_ticket_cb(
+	void *tls_ctx, struct tls_connection *conn,
+	tls_session_ticket_cb cb, void *ctx);
+
+#endif /* TLS_H */
diff --git a/hostap/src/crypto/tls_gnutls.c b/hostap/src/crypto/tls_gnutls.c
new file mode 100644
index 0000000..a5d72f4
--- /dev/null
+++ b/hostap/src/crypto/tls_gnutls.c
@@ -0,0 +1,1192 @@
+/*
+ * SSL/TLS interface functions for GnuTLS
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#ifdef PKCS12_FUNCS
+#include <gnutls/pkcs12.h>
+#endif /* PKCS12_FUNCS */
+
+#include "common.h"
+#include "tls.h"
+
+
+#define WPA_TLS_RANDOM_SIZE 32
+#define WPA_TLS_MASTER_SIZE 48
+
+
+#if LIBGNUTLS_VERSION_NUMBER < 0x010302
+/* GnuTLS 1.3.2 added functions for using master secret. Older versions require
+ * use of internal structures to get the master_secret and
+ * {server,client}_random.
+ */
+#define GNUTLS_INTERNAL_STRUCTURE_HACK
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
+
+
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
+/*
+ * It looks like gnutls does not provide access to client/server_random and
+ * master_key. This is somewhat unfortunate since these are needed for key
+ * derivation in EAP-{TLS,TTLS,PEAP,FAST}. Workaround for now is a horrible
+ * hack that copies the gnutls_session_int definition from gnutls_int.h so that
+ * we can get the needed information.
+ */
+
+typedef u8 uint8;
+typedef unsigned char opaque;
+typedef struct {
+    uint8 suite[2];
+} cipher_suite_st;
+
+typedef struct {
+	gnutls_connection_end_t entity;
+	gnutls_kx_algorithm_t kx_algorithm;
+	gnutls_cipher_algorithm_t read_bulk_cipher_algorithm;
+	gnutls_mac_algorithm_t read_mac_algorithm;
+	gnutls_compression_method_t read_compression_algorithm;
+	gnutls_cipher_algorithm_t write_bulk_cipher_algorithm;
+	gnutls_mac_algorithm_t write_mac_algorithm;
+	gnutls_compression_method_t write_compression_algorithm;
+	cipher_suite_st current_cipher_suite;
+	opaque master_secret[WPA_TLS_MASTER_SIZE];
+	opaque client_random[WPA_TLS_RANDOM_SIZE];
+	opaque server_random[WPA_TLS_RANDOM_SIZE];
+	/* followed by stuff we are not interested in */
+} security_parameters_st;
+
+struct gnutls_session_int {
+	security_parameters_st security_parameters;
+	/* followed by things we are not interested in */
+};
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x010302 */
+
+static int tls_gnutls_ref_count = 0;
+
+struct tls_global {
+	/* Data for session resumption */
+	void *session_data;
+	size_t session_data_size;
+
+	int server;
+
+	int params_set;
+	gnutls_certificate_credentials_t xcred;
+};
+
+struct tls_connection {
+	gnutls_session session;
+	char *subject_match, *altsubject_match;
+	int read_alerts, write_alerts, failed;
+
+	u8 *pre_shared_secret;
+	size_t pre_shared_secret_len;
+	int established;
+	int verify_peer;
+
+	struct wpabuf *push_buf;
+	struct wpabuf *pull_buf;
+	const u8 *pull_buf_offset;
+
+	int params_set;
+	gnutls_certificate_credentials_t xcred;
+};
+
+
+static void tls_log_func(int level, const char *msg)
+{
+	char *s, *pos;
+	if (level == 6 || level == 7) {
+		/* These levels seem to be mostly I/O debug and msg dumps */
+		return;
+	}
+
+	s = os_strdup(msg);
+	if (s == NULL)
+		return;
+
+	pos = s;
+	while (*pos != '\0') {
+		if (*pos == '\n') {
+			*pos = '\0';
+			break;
+		}
+		pos++;
+	}
+	wpa_printf(level > 3 ? MSG_MSGDUMP : MSG_DEBUG,
+		   "gnutls<%d> %s", level, s);
+	os_free(s);
+}
+
+
+extern int wpa_debug_show_keys;
+
+void * tls_init(const struct tls_config *conf)
+{
+	struct tls_global *global;
+
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
+	/* Because of the horrible hack to get master_secret and client/server
+	 * random, we need to make sure that the gnutls version is something
+	 * that is expected to have same structure definition for the session
+	 * data.. */
+	const char *ver;
+	const char *ok_ver[] = { "1.2.3", "1.2.4", "1.2.5", "1.2.6", "1.2.9",
+				 "1.3.2",
+				 NULL };
+	int i;
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+
+	global = os_zalloc(sizeof(*global));
+	if (global == NULL)
+		return NULL;
+
+	if (tls_gnutls_ref_count == 0 && gnutls_global_init() < 0) {
+		os_free(global);
+		return NULL;
+	}
+	tls_gnutls_ref_count++;
+
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
+	ver = gnutls_check_version(NULL);
+	if (ver == NULL) {
+		tls_deinit(global);
+		return NULL;
+	}
+	wpa_printf(MSG_DEBUG, "%s - gnutls version %s", __func__, ver);
+	for (i = 0; ok_ver[i]; i++) {
+		if (strcmp(ok_ver[i], ver) == 0)
+			break;
+	}
+	if (ok_ver[i] == NULL) {
+		wpa_printf(MSG_INFO, "Untested gnutls version %s - this needs "
+			   "to be tested and enabled in tls_gnutls.c", ver);
+		tls_deinit(global);
+		return NULL;
+	}
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+
+	gnutls_global_set_log_function(tls_log_func);
+	if (wpa_debug_show_keys)
+		gnutls_global_set_log_level(11);
+	return global;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+	struct tls_global *global = ssl_ctx;
+	if (global) {
+		if (global->params_set)
+			gnutls_certificate_free_credentials(global->xcred);
+		os_free(global->session_data);
+		os_free(global);
+	}
+
+	tls_gnutls_ref_count--;
+	if (tls_gnutls_ref_count == 0)
+		gnutls_global_deinit();
+}
+
+
+int tls_get_errors(void *ssl_ctx)
+{
+	return 0;
+}
+
+
+static ssize_t tls_pull_func(gnutls_transport_ptr ptr, void *buf,
+			     size_t len)
+{
+	struct tls_connection *conn = (struct tls_connection *) ptr;
+	const u8 *end;
+	if (conn->pull_buf == NULL) {
+		errno = EWOULDBLOCK;
+		return -1;
+	}
+
+	end = wpabuf_head_u8(conn->pull_buf) + wpabuf_len(conn->pull_buf);
+	if ((size_t) (end - conn->pull_buf_offset) < len)
+		len = end - conn->pull_buf_offset;
+	os_memcpy(buf, conn->pull_buf_offset, len);
+	conn->pull_buf_offset += len;
+	if (conn->pull_buf_offset == end) {
+		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
+		wpabuf_free(conn->pull_buf);
+		conn->pull_buf = NULL;
+		conn->pull_buf_offset = NULL;
+	} else {
+		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
+			   __func__,
+			   (unsigned long) (end - conn->pull_buf_offset));
+	}
+	return len;
+}
+
+
+static ssize_t tls_push_func(gnutls_transport_ptr ptr, const void *buf,
+			     size_t len)
+{
+	struct tls_connection *conn = (struct tls_connection *) ptr;
+
+	if (wpabuf_resize(&conn->push_buf, len) < 0) {
+		errno = ENOMEM;
+		return -1;
+	}
+	wpabuf_put_data(conn->push_buf, buf, len);
+
+	return len;
+}
+
+
+static int tls_gnutls_init_session(struct tls_global *global,
+				   struct tls_connection *conn)
+{
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
+	const char *err;
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
+	const int cert_types[2] = { GNUTLS_CRT_X509, 0 };
+	const int protos[2] = { GNUTLS_TLS1, 0 };
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
+	int ret;
+
+	ret = gnutls_init(&conn->session,
+			  global->server ? GNUTLS_SERVER : GNUTLS_CLIENT);
+	if (ret < 0) {
+		wpa_printf(MSG_INFO, "TLS: Failed to initialize new TLS "
+			   "connection: %s", gnutls_strerror(ret));
+		return -1;
+	}
+
+	ret = gnutls_set_default_priority(conn->session);
+	if (ret < 0)
+		goto fail;
+
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020200
+	ret = gnutls_priority_set_direct(conn->session, "NORMAL:-VERS-SSL3.0",
+					 &err);
+	if (ret < 0) {
+		wpa_printf(MSG_ERROR, "GnuTLS: Priority string failure at "
+			   "'%s'", err);
+		goto fail;
+	}
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x020200 */
+	ret = gnutls_certificate_type_set_priority(conn->session, cert_types);
+	if (ret < 0)
+		goto fail;
+
+	ret = gnutls_protocol_set_priority(conn->session, protos);
+	if (ret < 0)
+		goto fail;
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020200 */
+
+	gnutls_transport_set_pull_function(conn->session, tls_pull_func);
+	gnutls_transport_set_push_function(conn->session, tls_push_func);
+	gnutls_transport_set_ptr(conn->session, (gnutls_transport_ptr) conn);
+
+	return 0;
+
+fail:
+	wpa_printf(MSG_INFO, "TLS: Failed to setup new TLS connection: %s",
+		   gnutls_strerror(ret));
+	gnutls_deinit(conn->session);
+	return -1;
+}
+
+
+struct tls_connection * tls_connection_init(void *ssl_ctx)
+{
+	struct tls_global *global = ssl_ctx;
+	struct tls_connection *conn;
+	int ret;
+
+	conn = os_zalloc(sizeof(*conn));
+	if (conn == NULL)
+		return NULL;
+
+	if (tls_gnutls_init_session(global, conn)) {
+		os_free(conn);
+		return NULL;
+	}
+
+	if (global->params_set) {
+		ret = gnutls_credentials_set(conn->session,
+					     GNUTLS_CRD_CERTIFICATE,
+					     global->xcred);
+		if (ret < 0) {
+			wpa_printf(MSG_INFO, "Failed to configure "
+				   "credentials: %s", gnutls_strerror(ret));
+			os_free(conn);
+			return NULL;
+		}
+	}
+
+	if (gnutls_certificate_allocate_credentials(&conn->xcred)) {
+		os_free(conn);
+		return NULL;
+	}
+
+	return conn;
+}
+
+
+void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return;
+
+	gnutls_certificate_free_credentials(conn->xcred);
+	gnutls_deinit(conn->session);
+	os_free(conn->pre_shared_secret);
+	os_free(conn->subject_match);
+	os_free(conn->altsubject_match);
+	wpabuf_free(conn->push_buf);
+	wpabuf_free(conn->pull_buf);
+	os_free(conn);
+}
+
+
+int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
+{
+	return conn ? conn->established : 0;
+}
+
+
+int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
+{
+	struct tls_global *global = ssl_ctx;
+	int ret;
+
+	if (conn == NULL)
+		return -1;
+
+	/* Shutdown previous TLS connection without notifying the peer
+	 * because the connection was already terminated in practice
+	 * and "close notify" shutdown alert would confuse AS. */
+	gnutls_bye(conn->session, GNUTLS_SHUT_RDWR);
+	wpabuf_free(conn->push_buf);
+	conn->push_buf = NULL;
+	conn->established = 0;
+
+	gnutls_deinit(conn->session);
+	if (tls_gnutls_init_session(global, conn)) {
+		wpa_printf(MSG_INFO, "GnuTLS: Failed to preparare new session "
+			   "for session resumption use");
+		return -1;
+	}
+
+	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
+				     conn->params_set ? conn->xcred :
+				     global->xcred);
+	if (ret < 0) {
+		wpa_printf(MSG_INFO, "GnuTLS: Failed to configure credentials "
+			   "for session resumption: %s", gnutls_strerror(ret));
+		return -1;
+	}
+
+	if (global->session_data) {
+		ret = gnutls_session_set_data(conn->session,
+					      global->session_data,
+					      global->session_data_size);
+		if (ret < 0) {
+			wpa_printf(MSG_INFO, "GnuTLS: Failed to set session "
+				   "data: %s", gnutls_strerror(ret));
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+
+#if 0
+static int tls_match_altsubject(X509 *cert, const char *match)
+{
+	GENERAL_NAME *gen;
+	char *field, *tmp;
+	void *ext;
+	int i, found = 0;
+	size_t len;
+
+	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+
+	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
+		gen = sk_GENERAL_NAME_value(ext, i);
+		switch (gen->type) {
+		case GEN_EMAIL:
+			field = "EMAIL";
+			break;
+		case GEN_DNS:
+			field = "DNS";
+			break;
+		case GEN_URI:
+			field = "URI";
+			break;
+		default:
+			field = NULL;
+			wpa_printf(MSG_DEBUG, "TLS: altSubjectName: "
+				   "unsupported type=%d", gen->type);
+			break;
+		}
+
+		if (!field)
+			continue;
+
+		wpa_printf(MSG_DEBUG, "TLS: altSubjectName: %s:%s",
+			   field, gen->d.ia5->data);
+		len = os_strlen(field) + 1 +
+			strlen((char *) gen->d.ia5->data) + 1;
+		tmp = os_malloc(len);
+		if (tmp == NULL)
+			continue;
+		snprintf(tmp, len, "%s:%s", field, gen->d.ia5->data);
+		if (strstr(tmp, match))
+			found++;
+		os_free(tmp);
+	}
+
+	return found;
+}
+#endif
+
+
+#if 0
+static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+	char buf[256];
+	X509 *err_cert;
+	int err, depth;
+	SSL *ssl;
+	struct tls_connection *conn;
+	char *match, *altmatch;
+
+	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
+	err = X509_STORE_CTX_get_error(x509_ctx);
+	depth = X509_STORE_CTX_get_error_depth(x509_ctx);
+	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
+					 SSL_get_ex_data_X509_STORE_CTX_idx());
+	X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
+
+	conn = SSL_get_app_data(ssl);
+	match = conn ? conn->subject_match : NULL;
+	altmatch = conn ? conn->altsubject_match : NULL;
+
+	if (!preverify_ok) {
+		wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
+			   " error %d (%s) depth %d for '%s'", err,
+			   X509_verify_cert_error_string(err), depth, buf);
+	} else {
+		wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - "
+			   "preverify_ok=%d err=%d (%s) depth=%d buf='%s'",
+			   preverify_ok, err,
+			   X509_verify_cert_error_string(err), depth, buf);
+		if (depth == 0 && match && strstr(buf, match) == NULL) {
+			wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
+				   "match with '%s'", buf, match);
+			preverify_ok = 0;
+		} else if (depth == 0 && altmatch &&
+			   !tls_match_altsubject(err_cert, altmatch)) {
+			wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
+				   "'%s' not found", altmatch);
+			preverify_ok = 0;
+		}
+	}
+
+	return preverify_ok;
+}
+#endif
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+	int ret;
+
+	if (conn == NULL || params == NULL)
+		return -1;
+
+	os_free(conn->subject_match);
+	conn->subject_match = NULL;
+	if (params->subject_match) {
+		conn->subject_match = os_strdup(params->subject_match);
+		if (conn->subject_match == NULL)
+			return -1;
+	}
+
+	os_free(conn->altsubject_match);
+	conn->altsubject_match = NULL;
+	if (params->altsubject_match) {
+		conn->altsubject_match = os_strdup(params->altsubject_match);
+		if (conn->altsubject_match == NULL)
+			return -1;
+	}
+
+	/* TODO: gnutls_certificate_set_verify_flags(xcred, flags); 
+	 * to force peer validation(?) */
+
+	if (params->ca_cert) {
+		conn->verify_peer = 1;
+		ret = gnutls_certificate_set_x509_trust_file(
+			conn->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
+				   "in PEM format: %s", params->ca_cert,
+				   gnutls_strerror(ret));
+			ret = gnutls_certificate_set_x509_trust_file(
+				conn->xcred, params->ca_cert,
+				GNUTLS_X509_FMT_DER);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
+					   "'%s' in DER format: %s",
+					   params->ca_cert,
+					   gnutls_strerror(ret));
+				return -1;
+			}
+		}
+
+		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
+			gnutls_certificate_set_verify_flags(
+				conn->xcred, GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
+		}
+
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
+		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
+			gnutls_certificate_set_verify_flags(
+				conn->xcred,
+				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
+		}
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
+	}
+
+	if (params->client_cert && params->private_key) {
+		/* TODO: private_key_passwd? */
+		ret = gnutls_certificate_set_x509_key_file(
+			conn->xcred, params->client_cert, params->private_key,
+			GNUTLS_X509_FMT_PEM);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
+				   "in PEM format: %s", gnutls_strerror(ret));
+			ret = gnutls_certificate_set_x509_key_file(
+				conn->xcred, params->client_cert,
+				params->private_key, GNUTLS_X509_FMT_DER);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "Failed to read client "
+					   "cert/key in DER format: %s",
+					   gnutls_strerror(ret));
+				return ret;
+			}
+		}
+	} else if (params->private_key) {
+		int pkcs12_ok = 0;
+#ifdef PKCS12_FUNCS
+		/* Try to load in PKCS#12 format */
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
+		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
+			conn->xcred, params->private_key, GNUTLS_X509_FMT_DER,
+			params->private_key_passwd);
+		if (ret != 0) {
+			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
+				   "PKCS#12 format: %s", gnutls_strerror(ret));
+			return -1;
+		} else
+			pkcs12_ok = 1;
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+#endif /* PKCS12_FUNCS */
+
+		if (!pkcs12_ok) {
+			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
+				   "included");
+			return -1;
+		}
+	}
+
+	conn->params_set = 1;
+
+	ret = gnutls_credentials_set(conn->session, GNUTLS_CRD_CERTIFICATE,
+				     conn->xcred);
+	if (ret < 0) {
+		wpa_printf(MSG_INFO, "Failed to configure credentials: %s",
+			   gnutls_strerror(ret));
+	}
+
+	return ret;
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+	struct tls_global *global = tls_ctx;
+	int ret;
+
+	/* Currently, global parameters are only set when running in server
+	 * mode. */
+	global->server = 1;
+
+	if (global->params_set) {
+		gnutls_certificate_free_credentials(global->xcred);
+		global->params_set = 0;
+	}
+
+	ret = gnutls_certificate_allocate_credentials(&global->xcred);
+	if (ret) {
+		wpa_printf(MSG_DEBUG, "Failed to allocate global credentials "
+			   "%s", gnutls_strerror(ret));
+		return -1;
+	}
+
+	if (params->ca_cert) {
+		ret = gnutls_certificate_set_x509_trust_file(
+			global->xcred, params->ca_cert, GNUTLS_X509_FMT_PEM);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "Failed to read CA cert '%s' "
+				   "in PEM format: %s", params->ca_cert,
+				   gnutls_strerror(ret));
+			ret = gnutls_certificate_set_x509_trust_file(
+				global->xcred, params->ca_cert,
+				GNUTLS_X509_FMT_DER);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "Failed to read CA cert "
+					   "'%s' in DER format: %s",
+					   params->ca_cert,
+					   gnutls_strerror(ret));
+				goto fail;
+			}
+		}
+
+		if (params->flags & TLS_CONN_ALLOW_SIGN_RSA_MD5) {
+			gnutls_certificate_set_verify_flags(
+				global->xcred,
+				GNUTLS_VERIFY_ALLOW_SIGN_RSA_MD5);
+		}
+
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
+		if (params->flags & TLS_CONN_DISABLE_TIME_CHECKS) {
+			gnutls_certificate_set_verify_flags(
+				global->xcred,
+				GNUTLS_VERIFY_DISABLE_TIME_CHECKS);
+		}
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
+	}
+
+	if (params->client_cert && params->private_key) {
+		/* TODO: private_key_passwd? */
+		ret = gnutls_certificate_set_x509_key_file(
+			global->xcred, params->client_cert,
+			params->private_key, GNUTLS_X509_FMT_PEM);
+		if (ret < 0) {
+			wpa_printf(MSG_DEBUG, "Failed to read client cert/key "
+				   "in PEM format: %s", gnutls_strerror(ret));
+			ret = gnutls_certificate_set_x509_key_file(
+				global->xcred, params->client_cert,
+				params->private_key, GNUTLS_X509_FMT_DER);
+			if (ret < 0) {
+				wpa_printf(MSG_DEBUG, "Failed to read client "
+					   "cert/key in DER format: %s",
+					   gnutls_strerror(ret));
+				goto fail;
+			}
+		}
+	} else if (params->private_key) {
+		int pkcs12_ok = 0;
+#ifdef PKCS12_FUNCS
+		/* Try to load in PKCS#12 format */
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
+		ret = gnutls_certificate_set_x509_simple_pkcs12_file(
+			global->xcred, params->private_key,
+			GNUTLS_X509_FMT_DER, params->private_key_passwd);
+		if (ret != 0) {
+			wpa_printf(MSG_DEBUG, "Failed to load private_key in "
+				   "PKCS#12 format: %s", gnutls_strerror(ret));
+			goto fail;
+		} else
+			pkcs12_ok = 1;
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+#endif /* PKCS12_FUNCS */
+
+		if (!pkcs12_ok) {
+			wpa_printf(MSG_DEBUG, "GnuTLS: PKCS#12 support not "
+				   "included");
+			goto fail;
+		}
+	}
+
+	global->params_set = 1;
+
+	return 0;
+
+fail:
+	gnutls_certificate_free_credentials(global->xcred);
+	return -1;
+}
+
+
+int tls_global_set_verify(void *ssl_ctx, int check_crl)
+{
+	/* TODO */
+	return 0;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+			      int verify_peer)
+{
+	if (conn == NULL || conn->session == NULL)
+		return -1;
+
+	conn->verify_peer = verify_peer;
+	gnutls_certificate_server_set_request(conn->session,
+					      verify_peer ? GNUTLS_CERT_REQUIRE
+					      : GNUTLS_CERT_REQUEST);
+
+	return 0;
+}
+
+
+int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
+			    struct tls_keys *keys)
+{
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
+	security_parameters_st *sec;
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+
+	if (conn == NULL || conn->session == NULL || keys == NULL)
+		return -1;
+
+	os_memset(keys, 0, sizeof(*keys));
+
+#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
+#ifdef GNUTLS_INTERNAL_STRUCTURE_HACK
+	sec = &conn->session->security_parameters;
+	keys->master_key = sec->master_secret;
+	keys->master_key_len = WPA_TLS_MASTER_SIZE;
+	keys->client_random = sec->client_random;
+	keys->server_random = sec->server_random;
+#else /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+	keys->client_random =
+		(u8 *) gnutls_session_get_client_random(conn->session);
+	keys->server_random =
+		(u8 *) gnutls_session_get_server_random(conn->session);
+	/* No access to master_secret */
+#endif /* GNUTLS_INTERNAL_STRUCTURE_HACK */
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
+
+#if LIBGNUTLS_VERSION_NUMBER < 0x020c00
+	keys->client_random_len = WPA_TLS_RANDOM_SIZE;
+	keys->server_random_len = WPA_TLS_RANDOM_SIZE;
+#endif /* LIBGNUTLS_VERSION_NUMBER < 0x020c00 */
+
+	return 0;
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len)
+{
+#if LIBGNUTLS_VERSION_NUMBER >= 0x010302
+	if (conn == NULL || conn->session == NULL)
+		return -1;
+
+	return gnutls_prf(conn->session, os_strlen(label), label,
+			  server_random_first, 0, NULL, out_len, (char *) out);
+#else /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+	return -1;
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x010302 */
+}
+
+
+static int tls_connection_verify_peer(struct tls_connection *conn,
+				      gnutls_alert_description_t *err)
+{
+	unsigned int status, num_certs, i;
+	struct os_time now;
+	const gnutls_datum_t *certs;
+	gnutls_x509_crt_t cert;
+
+	if (gnutls_certificate_verify_peers2(conn->session, &status) < 0) {
+		wpa_printf(MSG_INFO, "TLS: Failed to verify peer "
+			   "certificate chain");
+		*err = GNUTLS_A_INTERNAL_ERROR;
+		return -1;
+	}
+
+	if (conn->verify_peer && (status & GNUTLS_CERT_INVALID)) {
+		wpa_printf(MSG_INFO, "TLS: Peer certificate not trusted");
+		*err = GNUTLS_A_INTERNAL_ERROR;
+		if (status & GNUTLS_CERT_INSECURE_ALGORITHM) {
+			wpa_printf(MSG_INFO, "TLS: Certificate uses insecure "
+				   "algorithm");
+			*err = GNUTLS_A_INSUFFICIENT_SECURITY;
+		}
+#if LIBGNUTLS_VERSION_NUMBER >= 0x020800
+		if (status & GNUTLS_CERT_NOT_ACTIVATED) {
+			wpa_printf(MSG_INFO, "TLS: Certificate not yet "
+				   "activated");
+			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
+		}
+		if (status & GNUTLS_CERT_EXPIRED) {
+			wpa_printf(MSG_INFO, "TLS: Certificate expired");
+			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
+		}
+#endif /* LIBGNUTLS_VERSION_NUMBER >= 0x020800 */
+		return -1;
+	}
+
+	if (status & GNUTLS_CERT_SIGNER_NOT_FOUND) {
+		wpa_printf(MSG_INFO, "TLS: Peer certificate does not have a "
+			   "known issuer");
+		*err = GNUTLS_A_UNKNOWN_CA;
+		return -1;
+	}
+
+	if (status & GNUTLS_CERT_REVOKED) {
+		wpa_printf(MSG_INFO, "TLS: Peer certificate has been revoked");
+		*err = GNUTLS_A_CERTIFICATE_REVOKED;
+		return -1;
+	}
+
+	os_get_time(&now);
+
+	certs = gnutls_certificate_get_peers(conn->session, &num_certs);
+	if (certs == NULL) {
+		wpa_printf(MSG_INFO, "TLS: No peer certificate chain "
+			   "received");
+		*err = GNUTLS_A_UNKNOWN_CA;
+		return -1;
+	}
+
+	for (i = 0; i < num_certs; i++) {
+		char *buf;
+		size_t len;
+		if (gnutls_x509_crt_init(&cert) < 0) {
+			wpa_printf(MSG_INFO, "TLS: Certificate initialization "
+				   "failed");
+			*err = GNUTLS_A_BAD_CERTIFICATE;
+			return -1;
+		}
+
+		if (gnutls_x509_crt_import(cert, &certs[i],
+					   GNUTLS_X509_FMT_DER) < 0) {
+			wpa_printf(MSG_INFO, "TLS: Could not parse peer "
+				   "certificate %d/%d", i + 1, num_certs);
+			gnutls_x509_crt_deinit(cert);
+			*err = GNUTLS_A_BAD_CERTIFICATE;
+			return -1;
+		}
+
+		gnutls_x509_crt_get_dn(cert, NULL, &len);
+		len++;
+		buf = os_malloc(len + 1);
+		if (buf) {
+			buf[0] = buf[len] = '\0';
+			gnutls_x509_crt_get_dn(cert, buf, &len);
+		}
+		wpa_printf(MSG_DEBUG, "TLS: Peer cert chain %d/%d: %s",
+			   i + 1, num_certs, buf);
+
+		if (i == 0) {
+			/* TODO: validate subject_match and altsubject_match */
+		}
+
+		os_free(buf);
+
+		if (gnutls_x509_crt_get_expiration_time(cert) < now.sec ||
+		    gnutls_x509_crt_get_activation_time(cert) > now.sec) {
+			wpa_printf(MSG_INFO, "TLS: Peer certificate %d/%d is "
+				   "not valid at this time",
+				   i + 1, num_certs);
+			gnutls_x509_crt_deinit(cert);
+			*err = GNUTLS_A_CERTIFICATE_EXPIRED;
+			return -1;
+		}
+
+		gnutls_x509_crt_deinit(cert);
+	}
+
+	return 0;
+}
+
+
+static struct wpabuf * gnutls_get_appl_data(struct tls_connection *conn)
+{
+	int res;
+	struct wpabuf *ad;
+	wpa_printf(MSG_DEBUG, "GnuTLS: Check for possible Application Data");
+	ad = wpabuf_alloc((wpabuf_len(conn->pull_buf) + 500) * 3);
+	if (ad == NULL)
+		return NULL;
+
+	res = gnutls_record_recv(conn->session, wpabuf_mhead(ad),
+				 wpabuf_size(ad));
+	wpa_printf(MSG_DEBUG, "GnuTLS: gnutls_record_recv: %d", res);
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
+			   "(%s)", __func__, (int) res,
+			   gnutls_strerror(res));
+		wpabuf_free(ad);
+		return NULL;
+	}
+
+	wpabuf_put(ad, res);
+	wpa_printf(MSG_DEBUG, "GnuTLS: Received %d bytes of Application Data",
+		   res);
+	return ad;
+}
+
+
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+					 struct tls_connection *conn,
+					 const struct wpabuf *in_data,
+					 struct wpabuf **appl_data)
+{
+	struct tls_global *global = tls_ctx;
+	struct wpabuf *out_data;
+	int ret;
+
+	if (appl_data)
+		*appl_data = NULL;
+
+	if (in_data && wpabuf_len(in_data) > 0) {
+		if (conn->pull_buf) {
+			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
+				   "pull_buf", __func__,
+				   (unsigned long) wpabuf_len(conn->pull_buf));
+			wpabuf_free(conn->pull_buf);
+		}
+		conn->pull_buf = wpabuf_dup(in_data);
+		if (conn->pull_buf == NULL)
+			return NULL;
+		conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
+	}
+
+	ret = gnutls_handshake(conn->session);
+	if (ret < 0) {
+		switch (ret) {
+		case GNUTLS_E_AGAIN:
+			if (global->server && conn->established &&
+			    conn->push_buf == NULL) {
+				/* Need to return something to trigger
+				 * completion of EAP-TLS. */
+				conn->push_buf = wpabuf_alloc(0);
+			}
+			break;
+		case GNUTLS_E_FATAL_ALERT_RECEIVED:
+			wpa_printf(MSG_DEBUG, "%s - received fatal '%s' alert",
+				   __func__, gnutls_alert_get_name(
+					   gnutls_alert_get(conn->session)));
+			conn->read_alerts++;
+			/* continue */
+		default:
+			wpa_printf(MSG_DEBUG, "%s - gnutls_handshake failed "
+				   "-> %s", __func__, gnutls_strerror(ret));
+			conn->failed++;
+		}
+	} else {
+		size_t size;
+		gnutls_alert_description_t err;
+
+		if (conn->verify_peer &&
+		    tls_connection_verify_peer(conn, &err)) {
+			wpa_printf(MSG_INFO, "TLS: Peer certificate chain "
+				   "failed validation");
+			conn->failed++;
+			gnutls_alert_send(conn->session, GNUTLS_AL_FATAL, err);
+			goto out;
+		}
+
+		wpa_printf(MSG_DEBUG, "TLS: Handshake completed successfully");
+		conn->established = 1;
+		if (conn->push_buf == NULL) {
+			/* Need to return something to get final TLS ACK. */
+			conn->push_buf = wpabuf_alloc(0);
+		}
+
+		gnutls_session_get_data(conn->session, NULL, &size);
+		if (global->session_data == NULL ||
+		    global->session_data_size < size) {
+			os_free(global->session_data);
+			global->session_data = os_malloc(size);
+		}
+		if (global->session_data) {
+			global->session_data_size = size;
+			gnutls_session_get_data(conn->session,
+						global->session_data,
+						&global->session_data_size);
+		}
+
+		if (conn->pull_buf && appl_data)
+			*appl_data = gnutls_get_appl_data(conn);
+	}
+
+out:
+	out_data = conn->push_buf;
+	conn->push_buf = NULL;
+	return out_data;
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+						struct tls_connection *conn,
+						const struct wpabuf *in_data,
+						struct wpabuf **appl_data)
+{
+	return tls_connection_handshake(tls_ctx, conn, in_data, appl_data);
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	ssize_t res;
+	struct wpabuf *buf;
+
+	res = gnutls_record_send(conn->session, wpabuf_head(in_data),
+				 wpabuf_len(in_data));
+	if (res < 0) {
+		wpa_printf(MSG_INFO, "%s: Encryption failed: %s",
+			   __func__, gnutls_strerror(res));
+		return NULL;
+	}
+
+	buf = conn->push_buf;
+	conn->push_buf = NULL;
+	return buf;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	ssize_t res;
+	struct wpabuf *out;
+
+	if (conn->pull_buf) {
+		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
+			   "pull_buf", __func__,
+			   (unsigned long) wpabuf_len(conn->pull_buf));
+		wpabuf_free(conn->pull_buf);
+	}
+	conn->pull_buf = wpabuf_dup(in_data);
+	if (conn->pull_buf == NULL)
+		return NULL;
+	conn->pull_buf_offset = wpabuf_head(conn->pull_buf);
+
+	/*
+	 * Even though we try to disable TLS compression, it is possible that
+	 * this cannot be done with all TLS libraries. Add extra buffer space
+	 * to handle the possibility of the decrypted data being longer than
+	 * input data.
+	 */
+	out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
+	if (out == NULL)
+		return NULL;
+
+	res = gnutls_record_recv(conn->session, wpabuf_mhead(out),
+				 wpabuf_size(out));
+	if (res < 0) {
+		wpa_printf(MSG_DEBUG, "%s - gnutls_record_recv failed: %d "
+			   "(%s)", __func__, (int) res, gnutls_strerror(res));
+		wpabuf_free(out);
+		return NULL;
+	}
+	wpabuf_put(out, res);
+
+	return out;
+}
+
+
+int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return 0;
+	return gnutls_session_is_resumed(conn->session);
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
+{
+	/* TODO */
+	return -1;
+}
+
+
+int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
+		   char *buf, size_t buflen)
+{
+	/* TODO */
+	buf[0] = '\0';
+	return 0;
+}
+
+
+int tls_connection_enable_workaround(void *ssl_ctx,
+				     struct tls_connection *conn)
+{
+	gnutls_record_disable_padding(conn->session);
+	return 0;
+}
+
+
+int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
+				    int ext_type, const u8 *data,
+				    size_t data_len)
+{
+	/* TODO */
+	return -1;
+}
+
+
+int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->failed;
+}
+
+
+int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->read_alerts;
+}
+
+
+int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->write_alerts;
+}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	/* TODO */
+	return -1;
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+	return 0;
+}
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+					 struct tls_connection *conn,
+					 tls_session_ticket_cb cb, void *ctx)
+{
+	return -1;
+}
diff --git a/hostap/src/crypto/tls_internal.c b/hostap/src/crypto/tls_internal.c
new file mode 100644
index 0000000..91f0690
--- /dev/null
+++ b/hostap/src/crypto/tls_internal.c
@@ -0,0 +1,630 @@
+/*
+ * TLS interface functions and an internal TLS implementation
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file interface functions for hostapd/wpa_supplicant to use the
+ * integrated TLSv1 implementation.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "tls.h"
+#include "tls/tlsv1_client.h"
+#include "tls/tlsv1_server.h"
+
+
+static int tls_ref_count = 0;
+
+struct tls_global {
+	int server;
+	struct tlsv1_credentials *server_cred;
+	int check_crl;
+};
+
+struct tls_connection {
+	struct tlsv1_client *client;
+	struct tlsv1_server *server;
+};
+
+
+void * tls_init(const struct tls_config *conf)
+{
+	struct tls_global *global;
+
+	if (tls_ref_count == 0) {
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+		if (tlsv1_client_global_init())
+			return NULL;
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+		if (tlsv1_server_global_init())
+			return NULL;
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	}
+	tls_ref_count++;
+
+	global = os_zalloc(sizeof(*global));
+	if (global == NULL)
+		return NULL;
+
+	return global;
+}
+
+void tls_deinit(void *ssl_ctx)
+{
+	struct tls_global *global = ssl_ctx;
+	tls_ref_count--;
+	if (tls_ref_count == 0) {
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+		tlsv1_client_global_deinit();
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+		tlsv1_cred_free(global->server_cred);
+		tlsv1_server_global_deinit();
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	}
+	os_free(global);
+}
+
+
+int tls_get_errors(void *tls_ctx)
+{
+	return 0;
+}
+
+
+struct tls_connection * tls_connection_init(void *tls_ctx)
+{
+	struct tls_connection *conn;
+	struct tls_global *global = tls_ctx;
+
+	conn = os_zalloc(sizeof(*conn));
+	if (conn == NULL)
+		return NULL;
+
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (!global->server) {
+		conn->client = tlsv1_client_init();
+		if (conn->client == NULL) {
+			os_free(conn);
+			return NULL;
+		}
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (global->server) {
+		conn->server = tlsv1_server_init(global->server_cred);
+		if (conn->server == NULL) {
+			os_free(conn);
+			return NULL;
+		}
+	}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+
+	return conn;
+}
+
+
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return;
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		tlsv1_client_deinit(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		tlsv1_server_deinit(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	os_free(conn);
+}
+
+
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_established(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_established(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return 0;
+}
+
+
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_shutdown(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_shutdown(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	struct tlsv1_credentials *cred;
+
+	if (conn->client == NULL)
+		return -1;
+
+	cred = tlsv1_cred_alloc();
+	if (cred == NULL)
+		return -1;
+
+	if (tlsv1_set_ca_cert(cred, params->ca_cert,
+			      params->ca_cert_blob, params->ca_cert_blob_len,
+			      params->ca_path)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
+			   "certificates");
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	if (tlsv1_set_cert(cred, params->client_cert,
+			   params->client_cert_blob,
+			   params->client_cert_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to configure client "
+			   "certificate");
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	if (tlsv1_set_private_key(cred, params->private_key,
+				  params->private_key_passwd,
+				  params->private_key_blob,
+				  params->private_key_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load private key");
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
+			       params->dh_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	if (tlsv1_client_set_cred(conn->client, cred) < 0) {
+		tlsv1_cred_free(cred);
+		return -1;
+	}
+
+	tlsv1_client_set_time_checks(
+		conn->client, !(params->flags & TLS_CONN_DISABLE_TIME_CHECKS));
+
+	return 0;
+#else /* CONFIG_TLS_INTERNAL_CLIENT */
+	return -1;
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	struct tls_global *global = tls_ctx;
+	struct tlsv1_credentials *cred;
+
+	/* Currently, global parameters are only set when running in server
+	 * mode. */
+	global->server = 1;
+	tlsv1_cred_free(global->server_cred);
+	global->server_cred = cred = tlsv1_cred_alloc();
+	if (cred == NULL)
+		return -1;
+
+	if (tlsv1_set_ca_cert(cred, params->ca_cert, params->ca_cert_blob,
+			      params->ca_cert_blob_len, params->ca_path)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to configure trusted CA "
+			   "certificates");
+		return -1;
+	}
+
+	if (tlsv1_set_cert(cred, params->client_cert, params->client_cert_blob,
+			   params->client_cert_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to configure server "
+			   "certificate");
+		return -1;
+	}
+
+	if (tlsv1_set_private_key(cred, params->private_key,
+				  params->private_key_passwd,
+				  params->private_key_blob,
+				  params->private_key_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load private key");
+		return -1;
+	}
+
+	if (tlsv1_set_dhparams(cred, params->dh_file, params->dh_blob,
+			       params->dh_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load DH parameters");
+		return -1;
+	}
+
+	return 0;
+#else /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+}
+
+
+int tls_global_set_verify(void *tls_ctx, int check_crl)
+{
+	struct tls_global *global = tls_ctx;
+	global->check_crl = check_crl;
+	return 0;
+}
+
+
+int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
+			      int verify_peer)
+{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_set_verify(conn->server, verify_peer);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
+			    struct tls_keys *keys)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_get_keys(conn->client, keys);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_get_keys(conn->server, keys);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client) {
+		return tlsv1_client_prf(conn->client, label,
+					server_random_first,
+					out, out_len);
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server) {
+		return tlsv1_server_prf(conn->server, label,
+					server_random_first,
+					out, out_len);
+	}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+					 struct tls_connection *conn,
+					 const struct wpabuf *in_data,
+					 struct wpabuf **appl_data)
+{
+	return tls_connection_handshake2(tls_ctx, conn, in_data, appl_data,
+					 NULL);
+}
+
+
+struct wpabuf * tls_connection_handshake2(void *tls_ctx,
+					  struct tls_connection *conn,
+					  const struct wpabuf *in_data,
+					  struct wpabuf **appl_data,
+					  int *need_more_data)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	u8 *res, *ad;
+	size_t res_len, ad_len;
+	struct wpabuf *out;
+
+	if (conn->client == NULL)
+		return NULL;
+
+	ad = NULL;
+	res = tlsv1_client_handshake(conn->client,
+				     in_data ? wpabuf_head(in_data) : NULL,
+				     in_data ? wpabuf_len(in_data) : 0,
+				     &res_len, &ad, &ad_len, need_more_data);
+	if (res == NULL)
+		return NULL;
+	out = wpabuf_alloc_ext_data(res, res_len);
+	if (out == NULL) {
+		os_free(res);
+		os_free(ad);
+		return NULL;
+	}
+	if (appl_data) {
+		if (ad) {
+			*appl_data = wpabuf_alloc_ext_data(ad, ad_len);
+			if (*appl_data == NULL)
+				os_free(ad);
+		} else
+			*appl_data = NULL;
+	} else
+		os_free(ad);
+
+	return out;
+#else /* CONFIG_TLS_INTERNAL_CLIENT */
+	return NULL;
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+						struct tls_connection *conn,
+						const struct wpabuf *in_data,
+						struct wpabuf **appl_data)
+{
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	u8 *res;
+	size_t res_len;
+	struct wpabuf *out;
+
+	if (conn->server == NULL)
+		return NULL;
+
+	if (appl_data)
+		*appl_data = NULL;
+
+	res = tlsv1_server_handshake(conn->server, wpabuf_head(in_data),
+				     wpabuf_len(in_data), &res_len);
+	if (res == NULL && tlsv1_server_established(conn->server))
+		return wpabuf_alloc(0);
+	if (res == NULL)
+		return NULL;
+	out = wpabuf_alloc_ext_data(res, res_len);
+	if (out == NULL) {
+		os_free(res);
+		return NULL;
+	}
+
+	return out;
+#else /* CONFIG_TLS_INTERNAL_SERVER */
+	return NULL;
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client) {
+		struct wpabuf *buf;
+		int res;
+		buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
+		if (buf == NULL)
+			return NULL;
+		res = tlsv1_client_encrypt(conn->client, wpabuf_head(in_data),
+					   wpabuf_len(in_data),
+					   wpabuf_mhead(buf),
+					   wpabuf_size(buf));
+		if (res < 0) {
+			wpabuf_free(buf);
+			return NULL;
+		}
+		wpabuf_put(buf, res);
+		return buf;
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server) {
+		struct wpabuf *buf;
+		int res;
+		buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
+		if (buf == NULL)
+			return NULL;
+		res = tlsv1_server_encrypt(conn->server, wpabuf_head(in_data),
+					   wpabuf_len(in_data),
+					   wpabuf_mhead(buf),
+					   wpabuf_size(buf));
+		if (res < 0) {
+			wpabuf_free(buf);
+			return NULL;
+		}
+		wpabuf_put(buf, res);
+		return buf;
+	}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return NULL;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	return tls_connection_decrypt2(tls_ctx, conn, in_data, NULL);
+}
+
+
+struct wpabuf * tls_connection_decrypt2(void *tls_ctx,
+					struct tls_connection *conn,
+					const struct wpabuf *in_data,
+					int *need_more_data)
+{
+	if (need_more_data)
+		*need_more_data = 0;
+
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client) {
+		return tlsv1_client_decrypt(conn->client, wpabuf_head(in_data),
+					    wpabuf_len(in_data),
+					    need_more_data);
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server) {
+		struct wpabuf *buf;
+		int res;
+		buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
+		if (buf == NULL)
+			return NULL;
+		res = tlsv1_server_decrypt(conn->server, wpabuf_head(in_data),
+					   wpabuf_len(in_data),
+					   wpabuf_mhead(buf),
+					   wpabuf_size(buf));
+		if (res < 0) {
+			wpabuf_free(buf);
+			return NULL;
+		}
+		wpabuf_put(buf, res);
+		return buf;
+	}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return NULL;
+}
+
+
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_resumed(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_resumed(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_set_cipher_list(conn->client, ciphers);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_set_cipher_list(conn->server, ciphers);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+		   char *buf, size_t buflen)
+{
+	if (conn == NULL)
+		return -1;
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_get_cipher(conn->client, buf, buflen);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_get_cipher(conn->server, buf, buflen);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+int tls_connection_enable_workaround(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
+				    int ext_type, const u8 *data,
+				    size_t data_len)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client) {
+		return tlsv1_client_hello_ext(conn->client, ext_type,
+					      data, data_len);
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+	return -1;
+}
+
+
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_write_alerts(void *tls_ctx,
+				    struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client)
+		return tlsv1_client_get_keyblock_size(conn->client);
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server)
+		return tlsv1_server_get_keyblock_size(conn->server);
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+	return 0;
+}
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+					 struct tls_connection *conn,
+					 tls_session_ticket_cb cb,
+					 void *ctx)
+{
+#ifdef CONFIG_TLS_INTERNAL_CLIENT
+	if (conn->client) {
+		tlsv1_client_set_session_ticket_cb(conn->client, cb, ctx);
+		return 0;
+	}
+#endif /* CONFIG_TLS_INTERNAL_CLIENT */
+#ifdef CONFIG_TLS_INTERNAL_SERVER
+	if (conn->server) {
+		tlsv1_server_set_session_ticket_cb(conn->server, cb, ctx);
+		return 0;
+	}
+#endif /* CONFIG_TLS_INTERNAL_SERVER */
+	return -1;
+}
diff --git a/hostap/src/crypto/tls_none.c b/hostap/src/crypto/tls_none.c
new file mode 100644
index 0000000..1a1092a
--- /dev/null
+++ b/hostap/src/crypto/tls_none.c
@@ -0,0 +1,194 @@
+/*
+ * SSL/TLS interface functions for no TLS case
+ * Copyright (c) 2004-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#include "common.h"
+#include "tls.h"
+
+void * tls_init(const struct tls_config *conf)
+{
+	return (void *) 1;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+}
+
+
+int tls_get_errors(void *tls_ctx)
+{
+	return 0;
+}
+
+
+struct tls_connection * tls_connection_init(void *tls_ctx)
+{
+	return NULL;
+}
+
+
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
+{
+}
+
+
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+	return -1;
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+	return -1;
+}
+
+
+int tls_global_set_verify(void *tls_ctx, int check_crl)
+{
+	return -1;
+}
+
+
+int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
+			      int verify_peer)
+{
+	return -1;
+}
+
+
+int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
+			    struct tls_keys *keys)
+{
+	return -1;
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len)
+{
+	return -1;
+}
+
+
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+					 struct tls_connection *conn,
+					 const struct wpabuf *in_data,
+					 struct wpabuf **appl_data)
+{
+	return NULL;
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+						struct tls_connection *conn,
+						const struct wpabuf *in_data,
+						struct wpabuf **appl_data)
+{
+	return NULL;
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	return NULL;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	return NULL;
+}
+
+
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
+{
+	return -1;
+}
+
+
+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+		   char *buf, size_t buflen)
+{
+	return -1;
+}
+
+
+int tls_connection_enable_workaround(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
+				    int ext_type, const u8 *data,
+				    size_t data_len)
+{
+	return -1;
+}
+
+
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_write_alerts(void *tls_ctx,
+				    struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+	return 0;
+}
diff --git a/hostap/src/crypto/tls_nss.c b/hostap/src/crypto/tls_nss.c
new file mode 100644
index 0000000..c53c192
--- /dev/null
+++ b/hostap/src/crypto/tls_nss.c
@@ -0,0 +1,645 @@
+/*
+ * SSL/TLS interface functions for NSS
+ * Copyright (c) 2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+#include <nspr/prtypes.h>
+#include <nspr/plarenas.h>
+#include <nspr/plhash.h>
+#include <nspr/prio.h>
+#include <nspr/prclist.h>
+#include <nspr/prlock.h>
+#include <nspr/prinit.h>
+#include <nspr/prerror.h>
+#include <nspr/prmem.h>
+#include <nss/nss.h>
+#include <nss/nssilckt.h>
+#include <nss/ssl.h>
+#include <nss/pk11func.h>
+#include <nss/secerr.h>
+
+#include "common.h"
+#include "tls.h"
+
+static int tls_nss_ref_count = 0;
+
+static PRDescIdentity nss_layer_id;
+
+
+struct tls_connection {
+	PRFileDesc *fd;
+
+	int established;
+	int verify_peer;
+	u8 *push_buf, *pull_buf, *pull_buf_offset;
+	size_t push_buf_len, pull_buf_len;
+};
+
+
+static PRStatus nss_io_close(PRFileDesc *fd)
+{
+	wpa_printf(MSG_DEBUG, "NSS: I/O close");
+	return PR_SUCCESS;
+}
+
+
+static PRInt32 nss_io_read(PRFileDesc *fd, void *buf, PRInt32 amount)
+{
+	wpa_printf(MSG_DEBUG, "NSS: I/O read(%d)", amount);
+	return PR_FAILURE;
+}
+
+
+static PRInt32 nss_io_write(PRFileDesc *fd, const void *buf, PRInt32 amount)
+{
+	wpa_printf(MSG_DEBUG, "NSS: I/O write(%d)", amount);
+	return PR_FAILURE;
+}
+
+
+static PRInt32 nss_io_writev(PRFileDesc *fd, const PRIOVec *iov,
+			     PRInt32 iov_size, PRIntervalTime timeout)
+{
+	wpa_printf(MSG_DEBUG, "NSS: I/O writev(%d)", iov_size);
+	return PR_FAILURE;
+}
+
+
+static PRInt32 nss_io_recv(PRFileDesc *fd, void *buf, PRInt32 amount,
+			   PRIntn flags, PRIntervalTime timeout)
+{
+	struct tls_connection *conn = (struct tls_connection *) fd->secret;
+	u8 *end;
+
+	wpa_printf(MSG_DEBUG, "NSS: I/O recv(%d)", amount);
+
+	if (conn->pull_buf == NULL) {
+		wpa_printf(MSG_DEBUG, "NSS: No data available to be read yet");
+		return PR_FAILURE;
+	}
+
+	end = conn->pull_buf + conn->pull_buf_len;
+	if (end - conn->pull_buf_offset < amount)
+		amount = end - conn->pull_buf_offset;
+	os_memcpy(buf, conn->pull_buf_offset, amount);
+	conn->pull_buf_offset += amount;
+	if (conn->pull_buf_offset == end) {
+		wpa_printf(MSG_DEBUG, "%s - pull_buf consumed", __func__);
+		os_free(conn->pull_buf);
+		conn->pull_buf = conn->pull_buf_offset = NULL;
+		conn->pull_buf_len = 0;
+	} else {
+		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in pull_buf",
+			   __func__,
+			   (unsigned long) (end - conn->pull_buf_offset));
+	}
+	return amount;
+}
+
+
+static PRInt32 nss_io_send(PRFileDesc *fd, const void *buf, PRInt32 amount,
+			   PRIntn flags, PRIntervalTime timeout)
+{
+	struct tls_connection *conn = (struct tls_connection *) fd->secret;
+	u8 *nbuf;
+
+	wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
+	wpa_hexdump(MSG_MSGDUMP, "NSS: I/O send data", buf, amount);
+
+	nbuf = os_realloc(conn->push_buf, conn->push_buf_len + amount);
+	if (nbuf == NULL) {
+		wpa_printf(MSG_ERROR, "NSS: Failed to allocate memory for the "
+			   "data to be sent");
+		return PR_FAILURE;
+	}
+	os_memcpy(nbuf + conn->push_buf_len, buf, amount);
+	conn->push_buf = nbuf;
+	conn->push_buf_len += amount;
+
+	return amount;
+}
+
+
+static PRInt32 nss_io_recvfrom(PRFileDesc *fd, void *buf, PRInt32 amount,
+			       PRIntn flags, PRNetAddr *addr,
+			       PRIntervalTime timeout)
+{
+	wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
+	return PR_FAILURE;
+}
+
+
+static PRInt32 nss_io_sendto(PRFileDesc *fd, const void *buf, PRInt32 amount,
+			     PRIntn flags, const PRNetAddr *addr,
+			     PRIntervalTime timeout)
+{
+	wpa_printf(MSG_DEBUG, "NSS: I/O %s", __func__);
+	return PR_FAILURE;
+}
+
+
+static PRStatus nss_io_getpeername(PRFileDesc *fd, PRNetAddr *addr)
+{
+	wpa_printf(MSG_DEBUG, "NSS: I/O getpeername");
+
+	/*
+	 * It Looks like NSS only supports IPv4 and IPv6 TCP sockets. Provide a
+	 * fake IPv4 address to work around this even though we are not really
+	 * using TCP.
+	 */
+	os_memset(addr, 0, sizeof(*addr));
+	addr->inet.family = PR_AF_INET;
+
+	return PR_SUCCESS;
+}
+
+
+static PRStatus nss_io_getsocketoption(PRFileDesc *fd,
+				       PRSocketOptionData *data)
+{
+	switch (data->option) {
+	case PR_SockOpt_Nonblocking:
+		wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(Nonblocking)");
+		data->value.non_blocking = PR_TRUE;
+		return PR_SUCCESS;
+	default:
+		wpa_printf(MSG_DEBUG, "NSS: I/O getsocketoption(%d)",
+			   data->option);
+		return PR_FAILURE;
+	}
+}
+
+
+static const PRIOMethods nss_io = {
+	PR_DESC_LAYERED,
+	nss_io_close,
+	nss_io_read,
+	nss_io_write,
+	NULL /* available */,
+	NULL /* available64 */,
+	NULL /* fsync */,
+	NULL /* fseek */,
+	NULL /* fseek64 */,
+	NULL /* fileinfo */,
+	NULL /* fileinfo64 */,
+	nss_io_writev,
+	NULL /* connect */,
+	NULL /* accept */,
+	NULL /* bind */,
+	NULL /* listen */,
+	NULL /* shutdown */,
+	nss_io_recv,
+	nss_io_send,
+	nss_io_recvfrom,
+	nss_io_sendto,
+	NULL /* poll */,
+	NULL /* acceptread */,
+	NULL /* transmitfile */,
+	NULL /* getsockname */,
+	nss_io_getpeername,
+	NULL /* reserved_fn_6 */,
+	NULL /* reserved_fn_5 */,
+	nss_io_getsocketoption,
+	NULL /* setsocketoption */,
+	NULL /* sendfile */,
+	NULL /* connectcontinue */,
+	NULL /* reserved_fn_3 */,
+	NULL /* reserved_fn_2 */,
+	NULL /* reserved_fn_1 */,
+	NULL /* reserved_fn_0 */
+};
+
+
+static char * nss_password_cb(PK11SlotInfo *slot, PRBool retry, void *arg)
+{
+	wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
+	return NULL;
+}
+
+
+void * tls_init(const struct tls_config *conf)
+{
+	char *dir;
+
+	tls_nss_ref_count++;
+	if (tls_nss_ref_count > 1)
+		return (void *) 1;
+
+	PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1);
+
+	nss_layer_id = PR_GetUniqueIdentity("wpa_supplicant");
+
+	PK11_SetPasswordFunc(nss_password_cb);
+
+	dir = getenv("SSL_DIR");
+	if (dir) {
+		if (NSS_Init(dir) != SECSuccess) {
+			wpa_printf(MSG_ERROR, "NSS: NSS_Init(cert_dir=%s) "
+				   "failed", dir);
+			return NULL;
+		}
+	} else {
+		if (NSS_NoDB_Init(NULL) != SECSuccess) {
+			wpa_printf(MSG_ERROR, "NSS: NSS_NoDB_Init(NULL) "
+				   "failed");
+			return NULL;
+		}
+	}
+
+	if (SSL_OptionSetDefault(SSL_V2_COMPATIBLE_HELLO, PR_FALSE) !=
+	    SECSuccess ||
+	    SSL_OptionSetDefault(SSL_ENABLE_SSL3, PR_FALSE) != SECSuccess ||
+	    SSL_OptionSetDefault(SSL_ENABLE_SSL2, PR_FALSE) != SECSuccess ||
+	    SSL_OptionSetDefault(SSL_ENABLE_TLS, PR_TRUE) != SECSuccess) {
+		wpa_printf(MSG_ERROR, "NSS: SSL_OptionSetDefault failed");
+		return NULL;
+	}
+
+	if (NSS_SetDomesticPolicy() != SECSuccess) {
+		wpa_printf(MSG_ERROR, "NSS: NSS_SetDomesticPolicy() failed");
+		return NULL;
+	}
+
+	return (void *) 1;
+}
+
+void tls_deinit(void *ssl_ctx)
+{
+	tls_nss_ref_count--;
+	if (tls_nss_ref_count == 0) {
+		if (NSS_Shutdown() != SECSuccess)
+			wpa_printf(MSG_ERROR, "NSS: NSS_Shutdown() failed");
+	}
+}
+
+
+int tls_get_errors(void *tls_ctx)
+{
+	return 0;
+}
+
+
+static SECStatus nss_bad_cert_cb(void *arg, PRFileDesc *fd)
+{
+	struct tls_connection *conn = arg;
+	SECStatus res = SECSuccess;
+	PRErrorCode err;
+	CERTCertificate *cert;
+	char *subject, *issuer;
+
+	err = PR_GetError();
+	if (IS_SEC_ERROR(err))
+		wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (sec err "
+			   "%d)", err - SEC_ERROR_BASE);
+	else
+		wpa_printf(MSG_DEBUG, "NSS: Bad Server Certificate (err %d)",
+			   err);
+	cert = SSL_PeerCertificate(fd);
+	subject = CERT_NameToAscii(&cert->subject);
+	issuer = CERT_NameToAscii(&cert->issuer);
+	wpa_printf(MSG_DEBUG, "NSS: Peer certificate subject='%s' issuer='%s'",
+		   subject, issuer);
+	CERT_DestroyCertificate(cert);
+	PR_Free(subject);
+	PR_Free(issuer);
+	if (conn->verify_peer)
+		res = SECFailure;
+
+	return res;
+}
+
+
+static void nss_handshake_cb(PRFileDesc *fd, void *client_data)
+{
+	struct tls_connection *conn = client_data;
+	wpa_printf(MSG_DEBUG, "NSS: Handshake completed");
+	conn->established = 1;
+}
+
+
+struct tls_connection * tls_connection_init(void *tls_ctx)
+{
+	struct tls_connection *conn;
+
+	conn = os_zalloc(sizeof(*conn));
+	if (conn == NULL)
+		return NULL;
+
+	conn->fd = PR_CreateIOLayerStub(nss_layer_id, &nss_io);
+	if (conn->fd == NULL) {
+		os_free(conn);
+		return NULL;
+	}
+	conn->fd->secret = (void *) conn;
+
+	conn->fd = SSL_ImportFD(NULL, conn->fd);
+	if (conn->fd == NULL) {
+		os_free(conn);
+		return NULL;
+	}
+
+	if (SSL_OptionSet(conn->fd, SSL_SECURITY, PR_TRUE) != SECSuccess ||
+	    SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) !=
+	    SECSuccess ||
+	    SSL_OptionSet(conn->fd, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) !=
+	    SECSuccess ||
+	    SSL_OptionSet(conn->fd, SSL_ENABLE_TLS, PR_TRUE) != SECSuccess ||
+	    SSL_BadCertHook(conn->fd, nss_bad_cert_cb, conn) != SECSuccess ||
+	    SSL_HandshakeCallback(conn->fd, nss_handshake_cb, conn) !=
+	    SECSuccess) {
+		wpa_printf(MSG_ERROR, "NSS: Failed to set options");
+		PR_Close(conn->fd);
+		os_free(conn);
+		return NULL;
+	}
+
+	SSL_ResetHandshake(conn->fd, PR_FALSE);
+
+	return conn;
+}
+
+
+void tls_connection_deinit(void *tls_ctx, struct tls_connection *conn)
+{
+	PR_Close(conn->fd);
+	os_free(conn->push_buf);
+	os_free(conn->pull_buf);
+	os_free(conn);
+}
+
+
+int tls_connection_established(void *tls_ctx, struct tls_connection *conn)
+{
+	return conn->established;
+}
+
+
+int tls_connection_shutdown(void *tls_ctx, struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+	wpa_printf(MSG_ERROR, "NSS: TODO - %s", __func__);
+	return 0;
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+	return -1;
+}
+
+
+int tls_global_set_verify(void *tls_ctx, int check_crl)
+{
+	return -1;
+}
+
+
+int tls_connection_set_verify(void *tls_ctx, struct tls_connection *conn,
+			      int verify_peer)
+{
+	conn->verify_peer = verify_peer;
+	return 0;
+}
+
+
+int tls_connection_get_keys(void *tls_ctx, struct tls_connection *conn,
+			    struct tls_keys *keys)
+{
+	/* NSS does not export master secret or client/server random. */
+	return -1;
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len)
+{
+	if (conn == NULL || server_random_first) {
+		wpa_printf(MSG_INFO, "NSS: Unsupported PRF request "
+			   "(server_random_first=%d)",
+			   server_random_first);
+		return -1;
+	}
+
+	if (SSL_ExportKeyingMaterial(conn->fd, label, NULL, 0, out, out_len) !=
+	    SECSuccess) {
+		wpa_printf(MSG_INFO, "NSS: Failed to use TLS extractor "
+			   "(label='%s' out_len=%d", label, (int) out_len);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+					 struct tls_connection *conn,
+					 const struct wpabuf *in_data,
+					 struct wpabuf **appl_data)
+{
+	struct wpabuf *out_data;
+
+	wpa_printf(MSG_DEBUG, "NSS: handshake: in_len=%u",
+		   in_data ? (unsigned int) wpabuf_len(in_data) : 0);
+
+	if (appl_data)
+		*appl_data = NULL;
+
+	if (in_data && wpabuf_len(in_data) > 0) {
+		if (conn->pull_buf) {
+			wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
+				   "pull_buf", __func__,
+				   (unsigned long) conn->pull_buf_len);
+			os_free(conn->pull_buf);
+		}
+		conn->pull_buf = os_malloc(wpabuf_len(in_data));
+		if (conn->pull_buf == NULL)
+			return NULL;
+		os_memcpy(conn->pull_buf, wpabuf_head(in_data),
+			  wpabuf_len(in_data));
+		conn->pull_buf_offset = conn->pull_buf;
+		conn->pull_buf_len = wpabuf_len(in_data);
+	}
+
+	SSL_ForceHandshake(conn->fd);
+
+	if (conn->established && conn->push_buf == NULL) {
+		/* Need to return something to get final TLS ACK. */
+		conn->push_buf = os_malloc(1);
+	}
+
+	if (conn->push_buf == NULL)
+		return NULL;
+	out_data = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
+	if (out_data == NULL)
+		os_free(conn->push_buf);
+	conn->push_buf = NULL;
+	conn->push_buf_len = 0;
+	return out_data;
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+						struct tls_connection *conn,
+						const struct wpabuf *in_data,
+						struct wpabuf **appl_data)
+{
+	return NULL;
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	PRInt32 res;
+	struct wpabuf *buf;
+
+	wpa_printf(MSG_DEBUG, "NSS: encrypt %d bytes",
+		   (int) wpabuf_len(in_data));
+	res = PR_Send(conn->fd, wpabuf_head(in_data), wpabuf_len(in_data), 0,
+		      0);
+	if (res < 0) {
+		wpa_printf(MSG_ERROR, "NSS: Encryption failed");
+		return NULL;
+	}
+	if (conn->push_buf == NULL)
+		return NULL;
+	buf = wpabuf_alloc_ext_data(conn->push_buf, conn->push_buf_len);
+	if (buf == NULL)
+		os_free(conn->push_buf);
+	conn->push_buf = NULL;
+	conn->push_buf_len = 0;
+	return buf;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	PRInt32 res;
+	struct wpabuf *out;
+
+	wpa_printf(MSG_DEBUG, "NSS: decrypt %d bytes",
+		   (int) wpabuf_len(in_data));
+	if (conn->pull_buf) {
+		wpa_printf(MSG_DEBUG, "%s - %lu bytes remaining in "
+			   "pull_buf", __func__,
+			   (unsigned long) conn->pull_buf_len);
+		os_free(conn->pull_buf);
+	}
+	conn->pull_buf = os_malloc(wpabuf_len(in_data));
+	if (conn->pull_buf == NULL)
+		return NULL;
+	os_memcpy(conn->pull_buf, wpabuf_head(in_data), wpabuf_len(in_data));
+	conn->pull_buf_offset = conn->pull_buf;
+	conn->pull_buf_len = wpabuf_len(in_data);
+
+	/*
+	 * Even though we try to disable TLS compression, it is possible that
+	 * this cannot be done with all TLS libraries. Add extra buffer space
+	 * to handle the possibility of the decrypted data being longer than
+	 * input data.
+	 */
+	out = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
+	if (out == NULL)
+		return NULL;
+
+	res = PR_Recv(conn->fd, wpabuf_mhead(out), wpabuf_size(out), 0, 0);
+	wpa_printf(MSG_DEBUG, "NSS: PR_Recv: %d", res);
+	if (res < 0) {
+		wpabuf_free(out);
+		return NULL;
+	}
+	wpabuf_put(out, res);
+
+	return out;
+}
+
+
+int tls_connection_resumed(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
+{
+	return -1;
+}
+
+
+int tls_get_cipher(void *tls_ctx, struct tls_connection *conn,
+		   char *buf, size_t buflen)
+{
+	return -1;
+}
+
+
+int tls_connection_enable_workaround(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+int tls_connection_client_hello_ext(void *tls_ctx, struct tls_connection *conn,
+				    int ext_type, const u8 *data,
+				    size_t data_len)
+{
+	return -1;
+}
+
+
+int tls_connection_get_failed(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_read_alerts(void *tls_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_write_alerts(void *tls_ctx,
+				    struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	return -1;
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+	return 0;
+}
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+					 struct tls_connection *conn,
+					 tls_session_ticket_cb cb,
+					 void *ctx)
+{
+	return -1;
+}
diff --git a/hostap/src/crypto/tls_openssl.c b/hostap/src/crypto/tls_openssl.c
new file mode 100644
index 0000000..2c3db47
--- /dev/null
+++ b/hostap/src/crypto/tls_openssl.c
@@ -0,0 +1,3035 @@
+/*
+ * SSL/TLS interface functions for OpenSSL
+ * Copyright (c) 2004-2011, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#include "includes.h"
+
+#ifndef CONFIG_SMARTCARD
+#ifndef OPENSSL_NO_ENGINE
+#define OPENSSL_NO_ENGINE
+#endif
+#endif
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/pkcs12.h>
+#include <openssl/x509v3.h>
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif /* OPENSSL_NO_ENGINE */
+
+#ifdef ANDROID
+#include <openssl/pem.h>
+#include "keystore_get.h"
+#endif /* ANDROID */
+
+#include "common.h"
+#include "crypto.h"
+#include "tls.h"
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090800fL
+#define OPENSSL_d2i_TYPE const unsigned char **
+#else
+#define OPENSSL_d2i_TYPE unsigned char **
+#endif
+
+#ifdef SSL_F_SSL_SET_SESSION_TICKET_EXT
+#ifdef SSL_OP_NO_TICKET
+/*
+ * Session ticket override patch was merged into OpenSSL 0.9.9 tree on
+ * 2008-11-15. This version uses a bit different API compared to the old patch.
+ */
+#define CONFIG_OPENSSL_TICKET_OVERRIDE
+#endif
+#endif
+
+static int tls_openssl_ref_count = 0;
+
+struct tls_global {
+	void (*event_cb)(void *ctx, enum tls_event ev,
+			 union tls_event_data *data);
+	void *cb_ctx;
+	int cert_in_cb;
+};
+
+static struct tls_global *tls_global = NULL;
+
+
+struct tls_connection {
+	SSL *ssl;
+	BIO *ssl_in, *ssl_out;
+#ifndef OPENSSL_NO_ENGINE
+	ENGINE *engine;        /* functional reference to the engine */
+	EVP_PKEY *private_key; /* the private key if using engine */
+#endif /* OPENSSL_NO_ENGINE */
+	char *subject_match, *altsubject_match;
+	int read_alerts, write_alerts, failed;
+
+	tls_session_ticket_cb session_ticket_cb;
+	void *session_ticket_cb_ctx;
+
+	/* SessionTicket received from OpenSSL hello_extension_cb (server) */
+	u8 *session_ticket;
+	size_t session_ticket_len;
+
+	unsigned int ca_cert_verify:1;
+	unsigned int cert_probe:1;
+	unsigned int server_cert_only:1;
+
+	u8 srv_cert_hash[32];
+
+	unsigned int flags;
+};
+
+
+#ifdef CONFIG_NO_STDOUT_DEBUG
+
+static void _tls_show_errors(void)
+{
+	unsigned long err;
+
+	while ((err = ERR_get_error())) {
+		/* Just ignore the errors, since stdout is disabled */
+	}
+}
+#define tls_show_errors(l, f, t) _tls_show_errors()
+
+#else /* CONFIG_NO_STDOUT_DEBUG */
+
+static void tls_show_errors(int level, const char *func, const char *txt)
+{
+	unsigned long err;
+
+	wpa_printf(level, "OpenSSL: %s - %s %s",
+		   func, txt, ERR_error_string(ERR_get_error(), NULL));
+
+	while ((err = ERR_get_error())) {
+		wpa_printf(MSG_INFO, "OpenSSL: pending error: %s",
+			   ERR_error_string(err, NULL));
+	}
+}
+
+#endif /* CONFIG_NO_STDOUT_DEBUG */
+
+
+#ifdef CONFIG_NATIVE_WINDOWS
+
+/* Windows CryptoAPI and access to certificate stores */
+#include <wincrypt.h>
+
+#ifdef __MINGW32_VERSION
+/*
+ * MinGW does not yet include all the needed definitions for CryptoAPI, so
+ * define here whatever extra is needed.
+ */
+#define CERT_SYSTEM_STORE_CURRENT_USER (1 << 16)
+#define CERT_STORE_READONLY_FLAG 0x00008000
+#define CERT_STORE_OPEN_EXISTING_FLAG 0x00004000
+
+#endif /* __MINGW32_VERSION */
+
+
+struct cryptoapi_rsa_data {
+	const CERT_CONTEXT *cert;
+	HCRYPTPROV crypt_prov;
+	DWORD key_spec;
+	BOOL free_crypt_prov;
+};
+
+
+static void cryptoapi_error(const char *msg)
+{
+	wpa_printf(MSG_INFO, "CryptoAPI: %s; err=%u",
+		   msg, (unsigned int) GetLastError());
+}
+
+
+static int cryptoapi_rsa_pub_enc(int flen, const unsigned char *from,
+				 unsigned char *to, RSA *rsa, int padding)
+{
+	wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
+	return 0;
+}
+
+
+static int cryptoapi_rsa_pub_dec(int flen, const unsigned char *from,
+				 unsigned char *to, RSA *rsa, int padding)
+{
+	wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
+	return 0;
+}
+
+
+static int cryptoapi_rsa_priv_enc(int flen, const unsigned char *from,
+				  unsigned char *to, RSA *rsa, int padding)
+{
+	struct cryptoapi_rsa_data *priv =
+		(struct cryptoapi_rsa_data *) rsa->meth->app_data;
+	HCRYPTHASH hash;
+	DWORD hash_size, len, i;
+	unsigned char *buf = NULL;
+	int ret = 0;
+
+	if (priv == NULL) {
+		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
+		       ERR_R_PASSED_NULL_PARAMETER);
+		return 0;
+	}
+
+	if (padding != RSA_PKCS1_PADDING) {
+		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
+		       RSA_R_UNKNOWN_PADDING_TYPE);
+		return 0;
+	}
+
+	if (flen != 16 /* MD5 */ + 20 /* SHA-1 */) {
+		wpa_printf(MSG_INFO, "%s - only MD5-SHA1 hash supported",
+			   __func__);
+		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
+		       RSA_R_INVALID_MESSAGE_LENGTH);
+		return 0;
+	}
+
+	if (!CryptCreateHash(priv->crypt_prov, CALG_SSL3_SHAMD5, 0, 0, &hash))
+	{
+		cryptoapi_error("CryptCreateHash failed");
+		return 0;
+	}
+
+	len = sizeof(hash_size);
+	if (!CryptGetHashParam(hash, HP_HASHSIZE, (BYTE *) &hash_size, &len,
+			       0)) {
+		cryptoapi_error("CryptGetHashParam failed");
+		goto err;
+	}
+
+	if ((int) hash_size != flen) {
+		wpa_printf(MSG_INFO, "CryptoAPI: Invalid hash size (%u != %d)",
+			   (unsigned) hash_size, flen);
+		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT,
+		       RSA_R_INVALID_MESSAGE_LENGTH);
+		goto err;
+	}
+	if (!CryptSetHashParam(hash, HP_HASHVAL, (BYTE * ) from, 0)) {
+		cryptoapi_error("CryptSetHashParam failed");
+		goto err;
+	}
+
+	len = RSA_size(rsa);
+	buf = os_malloc(len);
+	if (buf == NULL) {
+		RSAerr(RSA_F_RSA_EAY_PRIVATE_ENCRYPT, ERR_R_MALLOC_FAILURE);
+		goto err;
+	}
+
+	if (!CryptSignHash(hash, priv->key_spec, NULL, 0, buf, &len)) {
+		cryptoapi_error("CryptSignHash failed");
+		goto err;
+	}
+
+	for (i = 0; i < len; i++)
+		to[i] = buf[len - i - 1];
+	ret = len;
+
+err:
+	os_free(buf);
+	CryptDestroyHash(hash);
+
+	return ret;
+}
+
+
+static int cryptoapi_rsa_priv_dec(int flen, const unsigned char *from,
+				  unsigned char *to, RSA *rsa, int padding)
+{
+	wpa_printf(MSG_DEBUG, "%s - not implemented", __func__);
+	return 0;
+}
+
+
+static void cryptoapi_free_data(struct cryptoapi_rsa_data *priv)
+{
+	if (priv == NULL)
+		return;
+	if (priv->crypt_prov && priv->free_crypt_prov)
+		CryptReleaseContext(priv->crypt_prov, 0);
+	if (priv->cert)
+		CertFreeCertificateContext(priv->cert);
+	os_free(priv);
+}
+
+
+static int cryptoapi_finish(RSA *rsa)
+{
+	cryptoapi_free_data((struct cryptoapi_rsa_data *) rsa->meth->app_data);
+	os_free((void *) rsa->meth);
+	rsa->meth = NULL;
+	return 1;
+}
+
+
+static const CERT_CONTEXT * cryptoapi_find_cert(const char *name, DWORD store)
+{
+	HCERTSTORE cs;
+	const CERT_CONTEXT *ret = NULL;
+
+	cs = CertOpenStore((LPCSTR) CERT_STORE_PROV_SYSTEM, 0, 0,
+			   store | CERT_STORE_OPEN_EXISTING_FLAG |
+			   CERT_STORE_READONLY_FLAG, L"MY");
+	if (cs == NULL) {
+		cryptoapi_error("Failed to open 'My system store'");
+		return NULL;
+	}
+
+	if (strncmp(name, "cert://", 7) == 0) {
+		unsigned short wbuf[255];
+		MultiByteToWideChar(CP_ACP, 0, name + 7, -1, wbuf, 255);
+		ret = CertFindCertificateInStore(cs, X509_ASN_ENCODING |
+						 PKCS_7_ASN_ENCODING,
+						 0, CERT_FIND_SUBJECT_STR,
+						 wbuf, NULL);
+	} else if (strncmp(name, "hash://", 7) == 0) {
+		CRYPT_HASH_BLOB blob;
+		int len;
+		const char *hash = name + 7;
+		unsigned char *buf;
+
+		len = os_strlen(hash) / 2;
+		buf = os_malloc(len);
+		if (buf && hexstr2bin(hash, buf, len) == 0) {
+			blob.cbData = len;
+			blob.pbData = buf;
+			ret = CertFindCertificateInStore(cs,
+							 X509_ASN_ENCODING |
+							 PKCS_7_ASN_ENCODING,
+							 0, CERT_FIND_HASH,
+							 &blob, NULL);
+		}
+		os_free(buf);
+	}
+
+	CertCloseStore(cs, 0);
+
+	return ret;
+}
+
+
+static int tls_cryptoapi_cert(SSL *ssl, const char *name)
+{
+	X509 *cert = NULL;
+	RSA *rsa = NULL, *pub_rsa;
+	struct cryptoapi_rsa_data *priv;
+	RSA_METHOD *rsa_meth;
+
+	if (name == NULL ||
+	    (strncmp(name, "cert://", 7) != 0 &&
+	     strncmp(name, "hash://", 7) != 0))
+		return -1;
+
+	priv = os_zalloc(sizeof(*priv));
+	rsa_meth = os_zalloc(sizeof(*rsa_meth));
+	if (priv == NULL || rsa_meth == NULL) {
+		wpa_printf(MSG_WARNING, "CryptoAPI: Failed to allocate memory "
+			   "for CryptoAPI RSA method");
+		os_free(priv);
+		os_free(rsa_meth);
+		return -1;
+	}
+
+	priv->cert = cryptoapi_find_cert(name, CERT_SYSTEM_STORE_CURRENT_USER);
+	if (priv->cert == NULL) {
+		priv->cert = cryptoapi_find_cert(
+			name, CERT_SYSTEM_STORE_LOCAL_MACHINE);
+	}
+	if (priv->cert == NULL) {
+		wpa_printf(MSG_INFO, "CryptoAPI: Could not find certificate "
+			   "'%s'", name);
+		goto err;
+	}
+
+	cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &priv->cert->pbCertEncoded,
+			priv->cert->cbCertEncoded);
+	if (cert == NULL) {
+		wpa_printf(MSG_INFO, "CryptoAPI: Could not process X509 DER "
+			   "encoding");
+		goto err;
+	}
+
+	if (!CryptAcquireCertificatePrivateKey(priv->cert,
+					       CRYPT_ACQUIRE_COMPARE_KEY_FLAG,
+					       NULL, &priv->crypt_prov,
+					       &priv->key_spec,
+					       &priv->free_crypt_prov)) {
+		cryptoapi_error("Failed to acquire a private key for the "
+				"certificate");
+		goto err;
+	}
+
+	rsa_meth->name = "Microsoft CryptoAPI RSA Method";
+	rsa_meth->rsa_pub_enc = cryptoapi_rsa_pub_enc;
+	rsa_meth->rsa_pub_dec = cryptoapi_rsa_pub_dec;
+	rsa_meth->rsa_priv_enc = cryptoapi_rsa_priv_enc;
+	rsa_meth->rsa_priv_dec = cryptoapi_rsa_priv_dec;
+	rsa_meth->finish = cryptoapi_finish;
+	rsa_meth->flags = RSA_METHOD_FLAG_NO_CHECK;
+	rsa_meth->app_data = (char *) priv;
+
+	rsa = RSA_new();
+	if (rsa == NULL) {
+		SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE,
+		       ERR_R_MALLOC_FAILURE);
+		goto err;
+	}
+
+	if (!SSL_use_certificate(ssl, cert)) {
+		RSA_free(rsa);
+		rsa = NULL;
+		goto err;
+	}
+	pub_rsa = cert->cert_info->key->pkey->pkey.rsa;
+	X509_free(cert);
+	cert = NULL;
+
+	rsa->n = BN_dup(pub_rsa->n);
+	rsa->e = BN_dup(pub_rsa->e);
+	if (!RSA_set_method(rsa, rsa_meth))
+		goto err;
+
+	if (!SSL_use_RSAPrivateKey(ssl, rsa))
+		goto err;
+	RSA_free(rsa);
+
+	return 0;
+
+err:
+	if (cert)
+		X509_free(cert);
+	if (rsa)
+		RSA_free(rsa);
+	else {
+		os_free(rsa_meth);
+		cryptoapi_free_data(priv);
+	}
+	return -1;
+}
+
+
+static int tls_cryptoapi_ca_cert(SSL_CTX *ssl_ctx, SSL *ssl, const char *name)
+{
+	HCERTSTORE cs;
+	PCCERT_CONTEXT ctx = NULL;
+	X509 *cert;
+	char buf[128];
+	const char *store;
+#ifdef UNICODE
+	WCHAR *wstore;
+#endif /* UNICODE */
+
+	if (name == NULL || strncmp(name, "cert_store://", 13) != 0)
+		return -1;
+
+	store = name + 13;
+#ifdef UNICODE
+	wstore = os_malloc((os_strlen(store) + 1) * sizeof(WCHAR));
+	if (wstore == NULL)
+		return -1;
+	wsprintf(wstore, L"%S", store);
+	cs = CertOpenSystemStore(0, wstore);
+	os_free(wstore);
+#else /* UNICODE */
+	cs = CertOpenSystemStore(0, store);
+#endif /* UNICODE */
+	if (cs == NULL) {
+		wpa_printf(MSG_DEBUG, "%s: failed to open system cert store "
+			   "'%s': error=%d", __func__, store,
+			   (int) GetLastError());
+		return -1;
+	}
+
+	while ((ctx = CertEnumCertificatesInStore(cs, ctx))) {
+		cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ctx->pbCertEncoded,
+				ctx->cbCertEncoded);
+		if (cert == NULL) {
+			wpa_printf(MSG_INFO, "CryptoAPI: Could not process "
+				   "X509 DER encoding for CA cert");
+			continue;
+		}
+
+		X509_NAME_oneline(X509_get_subject_name(cert), buf,
+				  sizeof(buf));
+		wpa_printf(MSG_DEBUG, "OpenSSL: Loaded CA certificate for "
+			   "system certificate store: subject='%s'", buf);
+
+		if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+			tls_show_errors(MSG_WARNING, __func__,
+					"Failed to add ca_cert to OpenSSL "
+					"certificate store");
+		}
+
+		X509_free(cert);
+	}
+
+	if (!CertCloseStore(cs, 0)) {
+		wpa_printf(MSG_DEBUG, "%s: failed to close system cert store "
+			   "'%s': error=%d", __func__, name + 13,
+			   (int) GetLastError());
+	}
+
+	return 0;
+}
+
+
+#else /* CONFIG_NATIVE_WINDOWS */
+
+static int tls_cryptoapi_cert(SSL *ssl, const char *name)
+{
+	return -1;
+}
+
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+
+static void ssl_info_cb(const SSL *ssl, int where, int ret)
+{
+	const char *str;
+	int w;
+
+	wpa_printf(MSG_DEBUG, "SSL: (where=0x%x ret=0x%x)", where, ret);
+	w = where & ~SSL_ST_MASK;
+	if (w & SSL_ST_CONNECT)
+		str = "SSL_connect";
+	else if (w & SSL_ST_ACCEPT)
+		str = "SSL_accept";
+	else
+		str = "undefined";
+
+	if (where & SSL_CB_LOOP) {
+		wpa_printf(MSG_DEBUG, "SSL: %s:%s",
+			   str, SSL_state_string_long(ssl));
+	} else if (where & SSL_CB_ALERT) {
+		wpa_printf(MSG_INFO, "SSL: SSL3 alert: %s:%s:%s",
+			   where & SSL_CB_READ ?
+			   "read (remote end reported an error)" :
+			   "write (local SSL3 detected an error)",
+			   SSL_alert_type_string_long(ret),
+			   SSL_alert_desc_string_long(ret));
+		if ((ret >> 8) == SSL3_AL_FATAL) {
+			struct tls_connection *conn =
+				SSL_get_app_data((SSL *) ssl);
+			if (where & SSL_CB_READ)
+				conn->read_alerts++;
+			else
+				conn->write_alerts++;
+		}
+		if (tls_global->event_cb != NULL) {
+			union tls_event_data ev;
+			os_memset(&ev, 0, sizeof(ev));
+			ev.alert.is_local = !(where & SSL_CB_READ);
+			ev.alert.type = SSL_alert_type_string_long(ret);
+			ev.alert.description = SSL_alert_desc_string_long(ret);
+			tls_global->event_cb(tls_global->cb_ctx, TLS_ALERT,
+					     &ev);
+		}
+	} else if (where & SSL_CB_EXIT && ret <= 0) {
+		wpa_printf(MSG_DEBUG, "SSL: %s:%s in %s",
+			   str, ret == 0 ? "failed" : "error",
+			   SSL_state_string_long(ssl));
+	}
+}
+
+
+#ifndef OPENSSL_NO_ENGINE
+/**
+ * tls_engine_load_dynamic_generic - load any openssl engine
+ * @pre: an array of commands and values that load an engine initialized
+ *       in the engine specific function
+ * @post: an array of commands and values that initialize an already loaded
+ *        engine (or %NULL if not required)
+ * @id: the engine id of the engine to load (only required if post is not %NULL
+ *
+ * This function is a generic function that loads any openssl engine.
+ *
+ * Returns: 0 on success, -1 on failure
+ */
+static int tls_engine_load_dynamic_generic(const char *pre[],
+					   const char *post[], const char *id)
+{
+	ENGINE *engine;
+	const char *dynamic_id = "dynamic";
+
+	engine = ENGINE_by_id(id);
+	if (engine) {
+		ENGINE_free(engine);
+		wpa_printf(MSG_DEBUG, "ENGINE: engine '%s' is already "
+			   "available", id);
+		return 0;
+	}
+	ERR_clear_error();
+
+	engine = ENGINE_by_id(dynamic_id);
+	if (engine == NULL) {
+		wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
+			   dynamic_id,
+			   ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+
+	/* Perform the pre commands. This will load the engine. */
+	while (pre && pre[0]) {
+		wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", pre[0], pre[1]);
+		if (ENGINE_ctrl_cmd_string(engine, pre[0], pre[1], 0) == 0) {
+			wpa_printf(MSG_INFO, "ENGINE: ctrl cmd_string failed: "
+				   "%s %s [%s]", pre[0], pre[1],
+				   ERR_error_string(ERR_get_error(), NULL));
+			ENGINE_free(engine);
+			return -1;
+		}
+		pre += 2;
+	}
+
+	/*
+	 * Free the reference to the "dynamic" engine. The loaded engine can
+	 * now be looked up using ENGINE_by_id().
+	 */
+	ENGINE_free(engine);
+
+	engine = ENGINE_by_id(id);
+	if (engine == NULL) {
+		wpa_printf(MSG_INFO, "ENGINE: Can't find engine %s [%s]",
+			   id, ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+
+	while (post && post[0]) {
+		wpa_printf(MSG_DEBUG, "ENGINE: '%s' '%s'", post[0], post[1]);
+		if (ENGINE_ctrl_cmd_string(engine, post[0], post[1], 0) == 0) {
+			wpa_printf(MSG_DEBUG, "ENGINE: ctrl cmd_string failed:"
+				" %s %s [%s]", post[0], post[1],
+				   ERR_error_string(ERR_get_error(), NULL));
+			ENGINE_remove(engine);
+			ENGINE_free(engine);
+			return -1;
+		}
+		post += 2;
+	}
+	ENGINE_free(engine);
+
+	return 0;
+}
+
+
+/**
+ * tls_engine_load_dynamic_pkcs11 - load the pkcs11 engine provided by opensc
+ * @pkcs11_so_path: pksc11_so_path from the configuration
+ * @pcks11_module_path: pkcs11_module_path from the configuration
+ */
+static int tls_engine_load_dynamic_pkcs11(const char *pkcs11_so_path,
+					  const char *pkcs11_module_path)
+{
+	char *engine_id = "pkcs11";
+	const char *pre_cmd[] = {
+		"SO_PATH", NULL /* pkcs11_so_path */,
+		"ID", NULL /* engine_id */,
+		"LIST_ADD", "1",
+		/* "NO_VCHECK", "1", */
+		"LOAD", NULL,
+		NULL, NULL
+	};
+	const char *post_cmd[] = {
+		"MODULE_PATH", NULL /* pkcs11_module_path */,
+		NULL, NULL
+	};
+
+	if (!pkcs11_so_path || !pkcs11_module_path)
+		return 0;
+
+	pre_cmd[1] = pkcs11_so_path;
+	pre_cmd[3] = engine_id;
+	post_cmd[1] = pkcs11_module_path;
+
+	wpa_printf(MSG_DEBUG, "ENGINE: Loading pkcs11 Engine from %s",
+		   pkcs11_so_path);
+
+	return tls_engine_load_dynamic_generic(pre_cmd, post_cmd, engine_id);
+}
+
+
+/**
+ * tls_engine_load_dynamic_opensc - load the opensc engine provided by opensc
+ * @opensc_so_path: opensc_so_path from the configuration
+ */
+static int tls_engine_load_dynamic_opensc(const char *opensc_so_path)
+{
+	char *engine_id = "opensc";
+	const char *pre_cmd[] = {
+		"SO_PATH", NULL /* opensc_so_path */,
+		"ID", NULL /* engine_id */,
+		"LIST_ADD", "1",
+		"LOAD", NULL,
+		NULL, NULL
+	};
+
+	if (!opensc_so_path)
+		return 0;
+
+	pre_cmd[1] = opensc_so_path;
+	pre_cmd[3] = engine_id;
+
+	wpa_printf(MSG_DEBUG, "ENGINE: Loading OpenSC Engine from %s",
+		   opensc_so_path);
+
+	return tls_engine_load_dynamic_generic(pre_cmd, NULL, engine_id);
+}
+#endif /* OPENSSL_NO_ENGINE */
+
+
+void * tls_init(const struct tls_config *conf)
+{
+	SSL_CTX *ssl;
+
+	if (tls_openssl_ref_count == 0) {
+		tls_global = os_zalloc(sizeof(*tls_global));
+		if (tls_global == NULL)
+			return NULL;
+		if (conf) {
+			tls_global->event_cb = conf->event_cb;
+			tls_global->cb_ctx = conf->cb_ctx;
+			tls_global->cert_in_cb = conf->cert_in_cb;
+		}
+
+#ifdef CONFIG_FIPS
+#ifdef OPENSSL_FIPS
+		if (conf && conf->fips_mode) {
+			if (!FIPS_mode_set(1)) {
+				wpa_printf(MSG_ERROR, "Failed to enable FIPS "
+					   "mode");
+				ERR_load_crypto_strings();
+				ERR_print_errors_fp(stderr);
+				os_free(tls_global);
+				tls_global = NULL;
+				return NULL;
+			} else
+				wpa_printf(MSG_INFO, "Running in FIPS mode");
+		}
+#else /* OPENSSL_FIPS */
+		if (conf && conf->fips_mode) {
+			wpa_printf(MSG_ERROR, "FIPS mode requested, but not "
+				   "supported");
+			os_free(tls_global);
+			tls_global = NULL;
+			return NULL;
+		}
+#endif /* OPENSSL_FIPS */
+#endif /* CONFIG_FIPS */
+		SSL_load_error_strings();
+		SSL_library_init();
+#if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256)
+		EVP_add_digest(EVP_sha256());
+#endif /* OPENSSL_NO_SHA256 */
+		/* TODO: if /dev/urandom is available, PRNG is seeded
+		 * automatically. If this is not the case, random data should
+		 * be added here. */
+
+#ifdef PKCS12_FUNCS
+#ifndef OPENSSL_NO_RC2
+		/*
+		 * 40-bit RC2 is commonly used in PKCS#12 files, so enable it.
+		 * This is enabled by PKCS12_PBE_add() in OpenSSL 0.9.8
+		 * versions, but it looks like OpenSSL 1.0.0 does not do that
+		 * anymore.
+		 */
+		EVP_add_cipher(EVP_rc2_40_cbc());
+#endif /* OPENSSL_NO_RC2 */
+		PKCS12_PBE_add();
+#endif  /* PKCS12_FUNCS */
+	}
+	tls_openssl_ref_count++;
+
+	ssl = SSL_CTX_new(TLSv1_method());
+	if (ssl == NULL)
+		return NULL;
+
+	SSL_CTX_set_info_callback(ssl, ssl_info_cb);
+
+#ifndef OPENSSL_NO_ENGINE
+	if (conf &&
+	    (conf->opensc_engine_path || conf->pkcs11_engine_path ||
+	     conf->pkcs11_module_path)) {
+		wpa_printf(MSG_DEBUG, "ENGINE: Loading dynamic engine");
+		ERR_load_ENGINE_strings();
+		ENGINE_load_dynamic();
+
+		if (tls_engine_load_dynamic_opensc(conf->opensc_engine_path) ||
+		    tls_engine_load_dynamic_pkcs11(conf->pkcs11_engine_path,
+						   conf->pkcs11_module_path)) {
+			tls_deinit(ssl);
+			return NULL;
+		}
+	}
+#endif /* OPENSSL_NO_ENGINE */
+
+	return ssl;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+	SSL_CTX *ssl = ssl_ctx;
+	SSL_CTX_free(ssl);
+
+	tls_openssl_ref_count--;
+	if (tls_openssl_ref_count == 0) {
+#ifndef OPENSSL_NO_ENGINE
+		ENGINE_cleanup();
+#endif /* OPENSSL_NO_ENGINE */
+		CRYPTO_cleanup_all_ex_data();
+		ERR_remove_state(0);
+		ERR_free_strings();
+		EVP_cleanup();
+		os_free(tls_global);
+		tls_global = NULL;
+	}
+}
+
+
+static int tls_engine_init(struct tls_connection *conn, const char *engine_id,
+			   const char *pin, const char *key_id,
+			   const char *cert_id, const char *ca_cert_id)
+{
+#ifndef OPENSSL_NO_ENGINE
+	int ret = -1;
+	if (engine_id == NULL) {
+		wpa_printf(MSG_ERROR, "ENGINE: Engine ID not set");
+		return -1;
+	}
+	if (pin == NULL) {
+		wpa_printf(MSG_ERROR, "ENGINE: Smartcard PIN not set");
+		return -1;
+	}
+	if (key_id == NULL) {
+		wpa_printf(MSG_ERROR, "ENGINE: Key Id not set");
+		return -1;
+	}
+
+	ERR_clear_error();
+	conn->engine = ENGINE_by_id(engine_id);
+	if (!conn->engine) {
+		wpa_printf(MSG_ERROR, "ENGINE: engine %s not available [%s]",
+			   engine_id, ERR_error_string(ERR_get_error(), NULL));
+		goto err;
+	}
+	if (ENGINE_init(conn->engine) != 1) {
+		wpa_printf(MSG_ERROR, "ENGINE: engine init failed "
+			   "(engine: %s) [%s]", engine_id,
+			   ERR_error_string(ERR_get_error(), NULL));
+		goto err;
+	}
+	wpa_printf(MSG_DEBUG, "ENGINE: engine initialized");
+
+	if (ENGINE_ctrl_cmd_string(conn->engine, "PIN", pin, 0) == 0) {
+		wpa_printf(MSG_ERROR, "ENGINE: cannot set pin [%s]",
+			   ERR_error_string(ERR_get_error(), NULL));
+		goto err;
+	}
+	/* load private key first in-case PIN is required for cert */
+	conn->private_key = ENGINE_load_private_key(conn->engine,
+						    key_id, NULL, NULL);
+	if (!conn->private_key) {
+		wpa_printf(MSG_ERROR, "ENGINE: cannot load private key with id"
+				" '%s' [%s]", key_id,
+			   ERR_error_string(ERR_get_error(), NULL));
+		ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+		goto err;
+	}
+
+	/* handle a certificate and/or CA certificate */
+	if (cert_id || ca_cert_id) {
+		const char *cmd_name = "LOAD_CERT_CTRL";
+
+		/* test if the engine supports a LOAD_CERT_CTRL */
+		if (!ENGINE_ctrl(conn->engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
+				 0, (void *)cmd_name, NULL)) {
+			wpa_printf(MSG_ERROR, "ENGINE: engine does not support"
+				   " loading certificates");
+			ret = TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+			goto err;
+		}
+	}
+
+	return 0;
+
+err:
+	if (conn->engine) {
+		ENGINE_free(conn->engine);
+		conn->engine = NULL;
+	}
+
+	if (conn->private_key) {
+		EVP_PKEY_free(conn->private_key);
+		conn->private_key = NULL;
+	}
+
+	return ret;
+#else /* OPENSSL_NO_ENGINE */
+	return 0;
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+static void tls_engine_deinit(struct tls_connection *conn)
+{
+#ifndef OPENSSL_NO_ENGINE
+	wpa_printf(MSG_DEBUG, "ENGINE: engine deinit");
+	if (conn->private_key) {
+		EVP_PKEY_free(conn->private_key);
+		conn->private_key = NULL;
+	}
+	if (conn->engine) {
+		ENGINE_finish(conn->engine);
+		conn->engine = NULL;
+	}
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+int tls_get_errors(void *ssl_ctx)
+{
+	int count = 0;
+	unsigned long err;
+
+	while ((err = ERR_get_error())) {
+		wpa_printf(MSG_INFO, "TLS - SSL error: %s",
+			   ERR_error_string(err, NULL));
+		count++;
+	}
+
+	return count;
+}
+
+struct tls_connection * tls_connection_init(void *ssl_ctx)
+{
+	SSL_CTX *ssl = ssl_ctx;
+	struct tls_connection *conn;
+	long options;
+
+	conn = os_zalloc(sizeof(*conn));
+	if (conn == NULL)
+		return NULL;
+	conn->ssl = SSL_new(ssl);
+	if (conn->ssl == NULL) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to initialize new SSL connection");
+		os_free(conn);
+		return NULL;
+	}
+
+	SSL_set_app_data(conn->ssl, conn);
+	options = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
+		SSL_OP_SINGLE_DH_USE;
+#ifdef SSL_OP_NO_COMPRESSION
+	options |= SSL_OP_NO_COMPRESSION;
+#endif /* SSL_OP_NO_COMPRESSION */
+	SSL_set_options(conn->ssl, options);
+
+	conn->ssl_in = BIO_new(BIO_s_mem());
+	if (!conn->ssl_in) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to create a new BIO for ssl_in");
+		SSL_free(conn->ssl);
+		os_free(conn);
+		return NULL;
+	}
+
+	conn->ssl_out = BIO_new(BIO_s_mem());
+	if (!conn->ssl_out) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to create a new BIO for ssl_out");
+		SSL_free(conn->ssl);
+		BIO_free(conn->ssl_in);
+		os_free(conn);
+		return NULL;
+	}
+
+	SSL_set_bio(conn->ssl, conn->ssl_in, conn->ssl_out);
+
+	return conn;
+}
+
+
+void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return;
+	SSL_free(conn->ssl);
+	tls_engine_deinit(conn);
+	os_free(conn->subject_match);
+	os_free(conn->altsubject_match);
+	os_free(conn->session_ticket);
+	os_free(conn);
+}
+
+
+int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
+{
+	return conn ? SSL_is_init_finished(conn->ssl) : 0;
+}
+
+
+int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+
+	/* Shutdown previous TLS connection without notifying the peer
+	 * because the connection was already terminated in practice
+	 * and "close notify" shutdown alert would confuse AS. */
+	SSL_set_quiet_shutdown(conn->ssl, 1);
+	SSL_shutdown(conn->ssl);
+	return 0;
+}
+
+
+static int tls_match_altsubject_component(X509 *cert, int type,
+					  const char *value, size_t len)
+{
+	GENERAL_NAME *gen;
+	void *ext;
+	int i, found = 0;
+
+	ext = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL);
+
+	for (i = 0; ext && i < sk_GENERAL_NAME_num(ext); i++) {
+		gen = sk_GENERAL_NAME_value(ext, i);
+		if (gen->type != type)
+			continue;
+		if (os_strlen((char *) gen->d.ia5->data) == len &&
+		    os_memcmp(value, gen->d.ia5->data, len) == 0)
+			found++;
+	}
+
+	return found;
+}
+
+
+static int tls_match_altsubject(X509 *cert, const char *match)
+{
+	int type;
+	const char *pos, *end;
+	size_t len;
+
+	pos = match;
+	do {
+		if (os_strncmp(pos, "EMAIL:", 6) == 0) {
+			type = GEN_EMAIL;
+			pos += 6;
+		} else if (os_strncmp(pos, "DNS:", 4) == 0) {
+			type = GEN_DNS;
+			pos += 4;
+		} else if (os_strncmp(pos, "URI:", 4) == 0) {
+			type = GEN_URI;
+			pos += 4;
+		} else {
+			wpa_printf(MSG_INFO, "TLS: Invalid altSubjectName "
+				   "match '%s'", pos);
+			return 0;
+		}
+		end = os_strchr(pos, ';');
+		while (end) {
+			if (os_strncmp(end + 1, "EMAIL:", 6) == 0 ||
+			    os_strncmp(end + 1, "DNS:", 4) == 0 ||
+			    os_strncmp(end + 1, "URI:", 4) == 0)
+				break;
+			end = os_strchr(end + 1, ';');
+		}
+		if (end)
+			len = end - pos;
+		else
+			len = os_strlen(pos);
+		if (tls_match_altsubject_component(cert, type, pos, len) > 0)
+			return 1;
+		pos = end + 1;
+	} while (end);
+
+	return 0;
+}
+
+
+static enum tls_fail_reason openssl_tls_fail_reason(int err)
+{
+	switch (err) {
+	case X509_V_ERR_CERT_REVOKED:
+		return TLS_FAIL_REVOKED;
+	case X509_V_ERR_CERT_NOT_YET_VALID:
+	case X509_V_ERR_CRL_NOT_YET_VALID:
+		return TLS_FAIL_NOT_YET_VALID;
+	case X509_V_ERR_CERT_HAS_EXPIRED:
+	case X509_V_ERR_CRL_HAS_EXPIRED:
+		return TLS_FAIL_EXPIRED;
+	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
+	case X509_V_ERR_UNABLE_TO_GET_CRL:
+	case X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER:
+	case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
+	case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY:
+	case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
+	case X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE:
+	case X509_V_ERR_CERT_CHAIN_TOO_LONG:
+	case X509_V_ERR_PATH_LENGTH_EXCEEDED:
+	case X509_V_ERR_INVALID_CA:
+		return TLS_FAIL_UNTRUSTED;
+	case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
+	case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
+	case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
+	case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD:
+	case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD:
+	case X509_V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD:
+	case X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD:
+	case X509_V_ERR_CERT_UNTRUSTED:
+	case X509_V_ERR_CERT_REJECTED:
+		return TLS_FAIL_BAD_CERTIFICATE;
+	default:
+		return TLS_FAIL_UNSPECIFIED;
+	}
+}
+
+
+static struct wpabuf * get_x509_cert(X509 *cert)
+{
+	struct wpabuf *buf;
+	u8 *tmp;
+
+	int cert_len = i2d_X509(cert, NULL);
+	if (cert_len <= 0)
+		return NULL;
+
+	buf = wpabuf_alloc(cert_len);
+	if (buf == NULL)
+		return NULL;
+
+	tmp = wpabuf_put(buf, cert_len);
+	i2d_X509(cert, &tmp);
+	return buf;
+}
+
+
+static void openssl_tls_fail_event(struct tls_connection *conn,
+				   X509 *err_cert, int err, int depth,
+				   const char *subject, const char *err_str,
+				   enum tls_fail_reason reason)
+{
+	union tls_event_data ev;
+	struct wpabuf *cert = NULL;
+
+	if (tls_global->event_cb == NULL)
+		return;
+
+	cert = get_x509_cert(err_cert);
+	os_memset(&ev, 0, sizeof(ev));
+	ev.cert_fail.reason = reason != TLS_FAIL_UNSPECIFIED ?
+		reason : openssl_tls_fail_reason(err);
+	ev.cert_fail.depth = depth;
+	ev.cert_fail.subject = subject;
+	ev.cert_fail.reason_txt = err_str;
+	ev.cert_fail.cert = cert;
+	tls_global->event_cb(tls_global->cb_ctx, TLS_CERT_CHAIN_FAILURE, &ev);
+	wpabuf_free(cert);
+}
+
+
+static void openssl_tls_cert_event(struct tls_connection *conn,
+				   X509 *err_cert, int depth,
+				   const char *subject)
+{
+	struct wpabuf *cert = NULL;
+	union tls_event_data ev;
+#ifdef CONFIG_SHA256
+	u8 hash[32];
+#endif /* CONFIG_SHA256 */
+
+	if (tls_global->event_cb == NULL)
+		return;
+
+	os_memset(&ev, 0, sizeof(ev));
+	if (conn->cert_probe || tls_global->cert_in_cb) {
+		cert = get_x509_cert(err_cert);
+		ev.peer_cert.cert = cert;
+	}
+#ifdef CONFIG_SHA256
+	if (cert) {
+		const u8 *addr[1];
+		size_t len[1];
+		addr[0] = wpabuf_head(cert);
+		len[0] = wpabuf_len(cert);
+		if (sha256_vector(1, addr, len, hash) == 0) {
+			ev.peer_cert.hash = hash;
+			ev.peer_cert.hash_len = sizeof(hash);
+		}
+	}
+#endif /* CONFIG_SHA256 */
+	ev.peer_cert.depth = depth;
+	ev.peer_cert.subject = subject;
+	tls_global->event_cb(tls_global->cb_ctx, TLS_PEER_CERTIFICATE, &ev);
+	wpabuf_free(cert);
+}
+
+
+static int tls_verify_cb(int preverify_ok, X509_STORE_CTX *x509_ctx)
+{
+	char buf[256];
+	X509 *err_cert;
+	int err, depth;
+	SSL *ssl;
+	struct tls_connection *conn;
+	char *match, *altmatch;
+	const char *err_str;
+
+	err_cert = X509_STORE_CTX_get_current_cert(x509_ctx);
+	err = X509_STORE_CTX_get_error(x509_ctx);
+	depth = X509_STORE_CTX_get_error_depth(x509_ctx);
+	ssl = X509_STORE_CTX_get_ex_data(x509_ctx,
+					 SSL_get_ex_data_X509_STORE_CTX_idx());
+	X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
+
+	conn = SSL_get_app_data(ssl);
+	if (conn == NULL)
+		return 0;
+	match = conn->subject_match;
+	altmatch = conn->altsubject_match;
+
+	if (!preverify_ok && !conn->ca_cert_verify)
+		preverify_ok = 1;
+	if (!preverify_ok && depth > 0 && conn->server_cert_only)
+		preverify_ok = 1;
+	if (!preverify_ok && (conn->flags & TLS_CONN_DISABLE_TIME_CHECKS) &&
+	    (err == X509_V_ERR_CERT_HAS_EXPIRED ||
+	     err == X509_V_ERR_CERT_NOT_YET_VALID)) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Ignore certificate validity "
+			   "time mismatch");
+		preverify_ok = 1;
+	}
+
+	err_str = X509_verify_cert_error_string(err);
+
+#ifdef CONFIG_SHA256
+	if (preverify_ok && depth == 0 && conn->server_cert_only) {
+		struct wpabuf *cert;
+		cert = get_x509_cert(err_cert);
+		if (!cert) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: Could not fetch "
+				   "server certificate data");
+			preverify_ok = 0;
+		} else {
+			u8 hash[32];
+			const u8 *addr[1];
+			size_t len[1];
+			addr[0] = wpabuf_head(cert);
+			len[0] = wpabuf_len(cert);
+			if (sha256_vector(1, addr, len, hash) < 0 ||
+			    os_memcmp(conn->srv_cert_hash, hash, 32) != 0) {
+				err_str = "Server certificate mismatch";
+				err = X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
+				preverify_ok = 0;
+			}
+			wpabuf_free(cert);
+		}
+	}
+#endif /* CONFIG_SHA256 */
+
+	if (!preverify_ok) {
+		wpa_printf(MSG_WARNING, "TLS: Certificate verification failed,"
+			   " error %d (%s) depth %d for '%s'", err, err_str,
+			   depth, buf);
+		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+				       err_str, TLS_FAIL_UNSPECIFIED);
+		return preverify_ok;
+	}
+
+	wpa_printf(MSG_DEBUG, "TLS: tls_verify_cb - preverify_ok=%d "
+		   "err=%d (%s) ca_cert_verify=%d depth=%d buf='%s'",
+		   preverify_ok, err, err_str,
+		   conn->ca_cert_verify, depth, buf);
+	if (depth == 0 && match && os_strstr(buf, match) == NULL) {
+		wpa_printf(MSG_WARNING, "TLS: Subject '%s' did not "
+			   "match with '%s'", buf, match);
+		preverify_ok = 0;
+		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+				       "Subject mismatch",
+				       TLS_FAIL_SUBJECT_MISMATCH);
+	} else if (depth == 0 && altmatch &&
+		   !tls_match_altsubject(err_cert, altmatch)) {
+		wpa_printf(MSG_WARNING, "TLS: altSubjectName match "
+			   "'%s' not found", altmatch);
+		preverify_ok = 0;
+		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+				       "AltSubject mismatch",
+				       TLS_FAIL_ALTSUBJECT_MISMATCH);
+	} else
+		openssl_tls_cert_event(conn, err_cert, depth, buf);
+
+	if (conn->cert_probe && preverify_ok && depth == 0) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Reject server certificate "
+			   "on probe-only run");
+		preverify_ok = 0;
+		openssl_tls_fail_event(conn, err_cert, err, depth, buf,
+				       "Server certificate chain probe",
+				       TLS_FAIL_SERVER_CHAIN_PROBE);
+	}
+
+	if (preverify_ok && tls_global->event_cb != NULL)
+		tls_global->event_cb(tls_global->cb_ctx,
+				     TLS_CERT_CHAIN_SUCCESS, NULL);
+
+	return preverify_ok;
+}
+
+
+#ifndef OPENSSL_NO_STDIO
+static int tls_load_ca_der(void *_ssl_ctx, const char *ca_cert)
+{
+	SSL_CTX *ssl_ctx = _ssl_ctx;
+	X509_LOOKUP *lookup;
+	int ret = 0;
+
+	lookup = X509_STORE_add_lookup(ssl_ctx->cert_store,
+				       X509_LOOKUP_file());
+	if (lookup == NULL) {
+		tls_show_errors(MSG_WARNING, __func__,
+				"Failed add lookup for X509 store");
+		return -1;
+	}
+
+	if (!X509_LOOKUP_load_file(lookup, ca_cert, X509_FILETYPE_ASN1)) {
+		unsigned long err = ERR_peek_error();
+		tls_show_errors(MSG_WARNING, __func__,
+				"Failed load CA in DER format");
+		if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
+		    ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
+				   "cert already in hash table error",
+				   __func__);
+		} else
+			ret = -1;
+	}
+
+	return ret;
+}
+#endif /* OPENSSL_NO_STDIO */
+
+
+#ifdef ANDROID
+static BIO * BIO_from_keystore(const char *key)
+{
+	BIO *bio = NULL;
+	char value[KEYSTORE_MESSAGE_SIZE];
+	int length = keystore_get(key, strlen(key), value);
+	if (length != -1 && (bio = BIO_new(BIO_s_mem())) != NULL)
+		BIO_write(bio, value, length);
+	return bio;
+}
+#endif /* ANDROID */
+
+
+static int tls_connection_ca_cert(void *_ssl_ctx, struct tls_connection *conn,
+				  const char *ca_cert, const u8 *ca_cert_blob,
+				  size_t ca_cert_blob_len, const char *ca_path)
+{
+	SSL_CTX *ssl_ctx = _ssl_ctx;
+
+	/*
+	 * Remove previously configured trusted CA certificates before adding
+	 * new ones.
+	 */
+	X509_STORE_free(ssl_ctx->cert_store);
+	ssl_ctx->cert_store = X509_STORE_new();
+	if (ssl_ctx->cert_store == NULL) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
+			   "certificate store", __func__);
+		return -1;
+	}
+
+	SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+	conn->ca_cert_verify = 1;
+
+	if (ca_cert && os_strncmp(ca_cert, "probe://", 8) == 0) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Probe for server certificate "
+			   "chain");
+		conn->cert_probe = 1;
+		conn->ca_cert_verify = 0;
+		return 0;
+	}
+
+	if (ca_cert && os_strncmp(ca_cert, "hash://", 7) == 0) {
+#ifdef CONFIG_SHA256
+		const char *pos = ca_cert + 7;
+		if (os_strncmp(pos, "server/sha256/", 14) != 0) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: Unsupported ca_cert "
+				   "hash value '%s'", ca_cert);
+			return -1;
+		}
+		pos += 14;
+		if (os_strlen(pos) != 32 * 2) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: Unexpected SHA256 "
+				   "hash length in ca_cert '%s'", ca_cert);
+			return -1;
+		}
+		if (hexstr2bin(pos, conn->srv_cert_hash, 32) < 0) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: Invalid SHA256 hash "
+				   "value in ca_cert '%s'", ca_cert);
+			return -1;
+		}
+		conn->server_cert_only = 1;
+		wpa_printf(MSG_DEBUG, "OpenSSL: Checking only server "
+			   "certificate match");
+		return 0;
+#else /* CONFIG_SHA256 */
+		wpa_printf(MSG_INFO, "No SHA256 included in the build - "
+			   "cannot validate server certificate hash");
+		return -1;
+#endif /* CONFIG_SHA256 */
+	}
+
+	if (ca_cert_blob) {
+		X509 *cert = d2i_X509(NULL, (OPENSSL_d2i_TYPE) &ca_cert_blob,
+				      ca_cert_blob_len);
+		if (cert == NULL) {
+			tls_show_errors(MSG_WARNING, __func__,
+					"Failed to parse ca_cert_blob");
+			return -1;
+		}
+
+		if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+			unsigned long err = ERR_peek_error();
+			tls_show_errors(MSG_WARNING, __func__,
+					"Failed to add ca_cert_blob to "
+					"certificate store");
+			if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
+			    ERR_GET_REASON(err) ==
+			    X509_R_CERT_ALREADY_IN_HASH_TABLE) {
+				wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring "
+					   "cert already in hash table error",
+					   __func__);
+			} else {
+				X509_free(cert);
+				return -1;
+			}
+		}
+		X509_free(cert);
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s - added ca_cert_blob "
+			   "to certificate store", __func__);
+		return 0;
+	}
+
+#ifdef ANDROID
+	if (ca_cert && os_strncmp("keystore://", ca_cert, 11) == 0) {
+		BIO *bio = BIO_from_keystore(&ca_cert[11]);
+		STACK_OF(X509_INFO) *stack = NULL;
+		int i;
+
+		if (bio) {
+			stack = PEM_X509_INFO_read_bio(bio, NULL, NULL, NULL);
+			BIO_free(bio);
+		}
+		if (!stack)
+			return -1;
+
+		for (i = 0; i < sk_X509_INFO_num(stack); ++i) {
+			X509_INFO *info = sk_X509_INFO_value(stack, i);
+			if (info->x509) {
+				X509_STORE_add_cert(ssl_ctx->cert_store,
+						    info->x509);
+			}
+			if (info->crl) {
+				X509_STORE_add_crl(ssl_ctx->cert_store,
+						   info->crl);
+			}
+		}
+		sk_X509_INFO_pop_free(stack, X509_INFO_free);
+		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+		return 0;
+	}
+#endif /* ANDROID */
+
+#ifdef CONFIG_NATIVE_WINDOWS
+	if (ca_cert && tls_cryptoapi_ca_cert(ssl_ctx, conn->ssl, ca_cert) ==
+	    0) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Added CA certificates from "
+			   "system certificate store");
+		return 0;
+	}
+#endif /* CONFIG_NATIVE_WINDOWS */
+
+	if (ca_cert || ca_path) {
+#ifndef OPENSSL_NO_STDIO
+		if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, ca_path) !=
+		    1) {
+			tls_show_errors(MSG_WARNING, __func__,
+					"Failed to load root certificates");
+			if (ca_cert &&
+			    tls_load_ca_der(ssl_ctx, ca_cert) == 0) {
+				wpa_printf(MSG_DEBUG, "OpenSSL: %s - loaded "
+					   "DER format CA certificate",
+					   __func__);
+			} else
+				return -1;
+		} else {
+			wpa_printf(MSG_DEBUG, "TLS: Trusted root "
+				   "certificate(s) loaded");
+			tls_get_errors(ssl_ctx);
+		}
+#else /* OPENSSL_NO_STDIO */
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
+			   __func__);
+		return -1;
+#endif /* OPENSSL_NO_STDIO */
+	} else {
+		/* No ca_cert configured - do not try to verify server
+		 * certificate */
+		conn->ca_cert_verify = 0;
+	}
+
+	return 0;
+}
+
+
+static int tls_global_ca_cert(SSL_CTX *ssl_ctx, const char *ca_cert)
+{
+	if (ca_cert) {
+		if (SSL_CTX_load_verify_locations(ssl_ctx, ca_cert, NULL) != 1)
+		{
+			tls_show_errors(MSG_WARNING, __func__,
+					"Failed to load root certificates");
+			return -1;
+		}
+
+		wpa_printf(MSG_DEBUG, "TLS: Trusted root "
+			   "certificate(s) loaded");
+
+#ifndef OPENSSL_NO_STDIO
+		/* Add the same CAs to the client certificate requests */
+		SSL_CTX_set_client_CA_list(ssl_ctx,
+					   SSL_load_client_CA_file(ca_cert));
+#endif /* OPENSSL_NO_STDIO */
+	}
+
+	return 0;
+}
+
+
+int tls_global_set_verify(void *ssl_ctx, int check_crl)
+{
+	int flags;
+
+	if (check_crl) {
+		X509_STORE *cs = SSL_CTX_get_cert_store(ssl_ctx);
+		if (cs == NULL) {
+			tls_show_errors(MSG_INFO, __func__, "Failed to get "
+					"certificate store when enabling "
+					"check_crl");
+			return -1;
+		}
+		flags = X509_V_FLAG_CRL_CHECK;
+		if (check_crl == 2)
+			flags |= X509_V_FLAG_CRL_CHECK_ALL;
+		X509_STORE_set_flags(cs, flags);
+	}
+	return 0;
+}
+
+
+static int tls_connection_set_subject_match(struct tls_connection *conn,
+					    const char *subject_match,
+					    const char *altsubject_match)
+{
+	os_free(conn->subject_match);
+	conn->subject_match = NULL;
+	if (subject_match) {
+		conn->subject_match = os_strdup(subject_match);
+		if (conn->subject_match == NULL)
+			return -1;
+	}
+
+	os_free(conn->altsubject_match);
+	conn->altsubject_match = NULL;
+	if (altsubject_match) {
+		conn->altsubject_match = os_strdup(altsubject_match);
+		if (conn->altsubject_match == NULL)
+			return -1;
+	}
+
+	return 0;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+			      int verify_peer)
+{
+	static int counter = 0;
+
+	if (conn == NULL)
+		return -1;
+
+	if (verify_peer) {
+		conn->ca_cert_verify = 1;
+		SSL_set_verify(conn->ssl, SSL_VERIFY_PEER |
+			       SSL_VERIFY_FAIL_IF_NO_PEER_CERT |
+			       SSL_VERIFY_CLIENT_ONCE, tls_verify_cb);
+	} else {
+		conn->ca_cert_verify = 0;
+		SSL_set_verify(conn->ssl, SSL_VERIFY_NONE, NULL);
+	}
+
+	SSL_set_accept_state(conn->ssl);
+
+	/*
+	 * Set session id context in order to avoid fatal errors when client
+	 * tries to resume a session. However, set the context to a unique
+	 * value in order to effectively disable session resumption for now
+	 * since not all areas of the server code are ready for it (e.g.,
+	 * EAP-TTLS needs special handling for Phase 2 after abbreviated TLS
+	 * handshake).
+	 */
+	counter++;
+	SSL_set_session_id_context(conn->ssl,
+				   (const unsigned char *) &counter,
+				   sizeof(counter));
+
+	return 0;
+}
+
+
+static int tls_connection_client_cert(struct tls_connection *conn,
+				      const char *client_cert,
+				      const u8 *client_cert_blob,
+				      size_t client_cert_blob_len)
+{
+	if (client_cert == NULL && client_cert_blob == NULL)
+		return 0;
+
+	if (client_cert_blob &&
+	    SSL_use_certificate_ASN1(conn->ssl, (u8 *) client_cert_blob,
+				     client_cert_blob_len) == 1) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_ASN1 --> "
+			   "OK");
+		return 0;
+	} else if (client_cert_blob) {
+		tls_show_errors(MSG_DEBUG, __func__,
+				"SSL_use_certificate_ASN1 failed");
+	}
+
+	if (client_cert == NULL)
+		return -1;
+
+#ifdef ANDROID
+	if (os_strncmp("keystore://", client_cert, 11) == 0) {
+		BIO *bio = BIO_from_keystore(&client_cert[11]);
+		X509 *x509 = NULL;
+		int ret = -1;
+		if (bio) {
+			x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL);
+			BIO_free(bio);
+		}
+		if (x509) {
+			if (SSL_use_certificate(conn->ssl, x509) == 1)
+				ret = 0;
+			X509_free(x509);
+		}
+		return ret;
+	}
+#endif /* ANDROID */
+
+#ifndef OPENSSL_NO_STDIO
+	if (SSL_use_certificate_file(conn->ssl, client_cert,
+				     SSL_FILETYPE_ASN1) == 1) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (DER)"
+			   " --> OK");
+		return 0;
+	}
+
+	if (SSL_use_certificate_file(conn->ssl, client_cert,
+				     SSL_FILETYPE_PEM) == 1) {
+		ERR_clear_error();
+		wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_certificate_file (PEM)"
+			   " --> OK");
+		return 0;
+	}
+
+	tls_show_errors(MSG_DEBUG, __func__,
+			"SSL_use_certificate_file failed");
+#else /* OPENSSL_NO_STDIO */
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
+#endif /* OPENSSL_NO_STDIO */
+
+	return -1;
+}
+
+
+static int tls_global_client_cert(SSL_CTX *ssl_ctx, const char *client_cert)
+{
+#ifndef OPENSSL_NO_STDIO
+	if (client_cert == NULL)
+		return 0;
+
+	if (SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
+					 SSL_FILETYPE_ASN1) != 1 &&
+	    SSL_CTX_use_certificate_chain_file(ssl_ctx, client_cert) != 1 &&
+	    SSL_CTX_use_certificate_file(ssl_ctx, client_cert,
+					 SSL_FILETYPE_PEM) != 1) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to load client certificate");
+		return -1;
+	}
+	return 0;
+#else /* OPENSSL_NO_STDIO */
+	if (client_cert == NULL)
+		return 0;
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO", __func__);
+	return -1;
+#endif /* OPENSSL_NO_STDIO */
+}
+
+
+static int tls_passwd_cb(char *buf, int size, int rwflag, void *password)
+{
+	if (password == NULL) {
+		return 0;
+	}
+	os_strlcpy(buf, (char *) password, size);
+	return os_strlen(buf);
+}
+
+
+#ifdef PKCS12_FUNCS
+static int tls_parse_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, PKCS12 *p12,
+			    const char *passwd)
+{
+	EVP_PKEY *pkey;
+	X509 *cert;
+	STACK_OF(X509) *certs;
+	int res = 0;
+	char buf[256];
+
+	pkey = NULL;
+	cert = NULL;
+	certs = NULL;
+	if (!PKCS12_parse(p12, passwd, &pkey, &cert, &certs)) {
+		tls_show_errors(MSG_DEBUG, __func__,
+				"Failed to parse PKCS12 file");
+		PKCS12_free(p12);
+		return -1;
+	}
+	wpa_printf(MSG_DEBUG, "TLS: Successfully parsed PKCS12 data");
+
+	if (cert) {
+		X509_NAME_oneline(X509_get_subject_name(cert), buf,
+				  sizeof(buf));
+		wpa_printf(MSG_DEBUG, "TLS: Got certificate from PKCS12: "
+			   "subject='%s'", buf);
+		if (ssl) {
+			if (SSL_use_certificate(ssl, cert) != 1)
+				res = -1;
+		} else {
+			if (SSL_CTX_use_certificate(ssl_ctx, cert) != 1)
+				res = -1;
+		}
+		X509_free(cert);
+	}
+
+	if (pkey) {
+		wpa_printf(MSG_DEBUG, "TLS: Got private key from PKCS12");
+		if (ssl) {
+			if (SSL_use_PrivateKey(ssl, pkey) != 1)
+				res = -1;
+		} else {
+			if (SSL_CTX_use_PrivateKey(ssl_ctx, pkey) != 1)
+				res = -1;
+		}
+		EVP_PKEY_free(pkey);
+	}
+
+	if (certs) {
+		while ((cert = sk_X509_pop(certs)) != NULL) {
+			X509_NAME_oneline(X509_get_subject_name(cert), buf,
+					  sizeof(buf));
+			wpa_printf(MSG_DEBUG, "TLS: additional certificate"
+				   " from PKCS12: subject='%s'", buf);
+			/*
+			 * There is no SSL equivalent for the chain cert - so
+			 * always add it to the context...
+			 */
+			if (SSL_CTX_add_extra_chain_cert(ssl_ctx, cert) != 1) {
+				res = -1;
+				break;
+			}
+		}
+		sk_X509_free(certs);
+	}
+
+	PKCS12_free(p12);
+
+	if (res < 0)
+		tls_get_errors(ssl_ctx);
+
+	return res;
+}
+#endif  /* PKCS12_FUNCS */
+
+
+static int tls_read_pkcs12(SSL_CTX *ssl_ctx, SSL *ssl, const char *private_key,
+			   const char *passwd)
+{
+#ifdef PKCS12_FUNCS
+	FILE *f;
+	PKCS12 *p12;
+
+	f = fopen(private_key, "rb");
+	if (f == NULL)
+		return -1;
+
+	p12 = d2i_PKCS12_fp(f, NULL);
+	fclose(f);
+
+	if (p12 == NULL) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to use PKCS#12 file");
+		return -1;
+	}
+
+	return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
+
+#else /* PKCS12_FUNCS */
+	wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot read "
+		   "p12/pfx files");
+	return -1;
+#endif  /* PKCS12_FUNCS */
+}
+
+
+static int tls_read_pkcs12_blob(SSL_CTX *ssl_ctx, SSL *ssl,
+				const u8 *blob, size_t len, const char *passwd)
+{
+#ifdef PKCS12_FUNCS
+	PKCS12 *p12;
+
+	p12 = d2i_PKCS12(NULL, (OPENSSL_d2i_TYPE) &blob, len);
+	if (p12 == NULL) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to use PKCS#12 blob");
+		return -1;
+	}
+
+	return tls_parse_pkcs12(ssl_ctx, ssl, p12, passwd);
+
+#else /* PKCS12_FUNCS */
+	wpa_printf(MSG_INFO, "TLS: PKCS12 support disabled - cannot parse "
+		   "p12/pfx blobs");
+	return -1;
+#endif  /* PKCS12_FUNCS */
+}
+
+
+#ifndef OPENSSL_NO_ENGINE
+static int tls_engine_get_cert(struct tls_connection *conn,
+			       const char *cert_id,
+			       X509 **cert)
+{
+	/* this runs after the private key is loaded so no PIN is required */
+	struct {
+		const char *cert_id;
+		X509 *cert;
+	} params;
+	params.cert_id = cert_id;
+	params.cert = NULL;
+
+	if (!ENGINE_ctrl_cmd(conn->engine, "LOAD_CERT_CTRL",
+			     0, &params, NULL, 1)) {
+		wpa_printf(MSG_ERROR, "ENGINE: cannot load client cert with id"
+			   " '%s' [%s]", cert_id,
+			   ERR_error_string(ERR_get_error(), NULL));
+		return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+	}
+	if (!params.cert) {
+		wpa_printf(MSG_ERROR, "ENGINE: did not properly cert with id"
+			   " '%s'", cert_id);
+		return TLS_SET_PARAMS_ENGINE_PRV_INIT_FAILED;
+	}
+	*cert = params.cert;
+	return 0;
+}
+#endif /* OPENSSL_NO_ENGINE */
+
+
+static int tls_connection_engine_client_cert(struct tls_connection *conn,
+					     const char *cert_id)
+{
+#ifndef OPENSSL_NO_ENGINE
+	X509 *cert;
+
+	if (tls_engine_get_cert(conn, cert_id, &cert))
+		return -1;
+
+	if (!SSL_use_certificate(conn->ssl, cert)) {
+		tls_show_errors(MSG_ERROR, __func__,
+				"SSL_use_certificate failed");
+                X509_free(cert);
+		return -1;
+	}
+	X509_free(cert);
+	wpa_printf(MSG_DEBUG, "ENGINE: SSL_use_certificate --> "
+		   "OK");
+	return 0;
+
+#else /* OPENSSL_NO_ENGINE */
+	return -1;
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+static int tls_connection_engine_ca_cert(void *_ssl_ctx,
+					 struct tls_connection *conn,
+					 const char *ca_cert_id)
+{
+#ifndef OPENSSL_NO_ENGINE
+	X509 *cert;
+	SSL_CTX *ssl_ctx = _ssl_ctx;
+
+	if (tls_engine_get_cert(conn, ca_cert_id, &cert))
+		return -1;
+
+	/* start off the same as tls_connection_ca_cert */
+	X509_STORE_free(ssl_ctx->cert_store);
+	ssl_ctx->cert_store = X509_STORE_new();
+	if (ssl_ctx->cert_store == NULL) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s - failed to allocate new "
+			   "certificate store", __func__);
+		X509_free(cert);
+		return -1;
+	}
+	if (!X509_STORE_add_cert(ssl_ctx->cert_store, cert)) {
+		unsigned long err = ERR_peek_error();
+		tls_show_errors(MSG_WARNING, __func__,
+				"Failed to add CA certificate from engine "
+				"to certificate store");
+		if (ERR_GET_LIB(err) == ERR_LIB_X509 &&
+		    ERR_GET_REASON(err) == X509_R_CERT_ALREADY_IN_HASH_TABLE) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: %s - ignoring cert"
+				   " already in hash table error",
+				   __func__);
+		} else {
+			X509_free(cert);
+			return -1;
+		}
+	}
+	X509_free(cert);
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s - added CA certificate from engine "
+		   "to certificate store", __func__);
+	SSL_set_verify(conn->ssl, SSL_VERIFY_PEER, tls_verify_cb);
+	conn->ca_cert_verify = 1;
+
+	return 0;
+
+#else /* OPENSSL_NO_ENGINE */
+	return -1;
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+static int tls_connection_engine_private_key(struct tls_connection *conn)
+{
+#ifndef OPENSSL_NO_ENGINE
+	if (SSL_use_PrivateKey(conn->ssl, conn->private_key) != 1) {
+		tls_show_errors(MSG_ERROR, __func__,
+				"ENGINE: cannot use private key for TLS");
+		return -1;
+	}
+	if (!SSL_check_private_key(conn->ssl)) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Private key failed verification");
+		return -1;
+	}
+	return 0;
+#else /* OPENSSL_NO_ENGINE */
+	wpa_printf(MSG_ERROR, "SSL: Configuration uses engine, but "
+		   "engine support was not compiled in");
+	return -1;
+#endif /* OPENSSL_NO_ENGINE */
+}
+
+
+static int tls_connection_private_key(void *_ssl_ctx,
+				      struct tls_connection *conn,
+				      const char *private_key,
+				      const char *private_key_passwd,
+				      const u8 *private_key_blob,
+				      size_t private_key_blob_len)
+{
+	SSL_CTX *ssl_ctx = _ssl_ctx;
+	char *passwd;
+	int ok;
+
+	if (private_key == NULL && private_key_blob == NULL)
+		return 0;
+
+	if (private_key_passwd) {
+		passwd = os_strdup(private_key_passwd);
+		if (passwd == NULL)
+			return -1;
+	} else
+		passwd = NULL;
+
+	SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
+	SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
+
+	ok = 0;
+	while (private_key_blob) {
+		if (SSL_use_PrivateKey_ASN1(EVP_PKEY_RSA, conn->ssl,
+					    (u8 *) private_key_blob,
+					    private_key_blob_len) == 1) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
+				   "ASN1(EVP_PKEY_RSA) --> OK");
+			ok = 1;
+			break;
+		}
+
+		if (SSL_use_PrivateKey_ASN1(EVP_PKEY_DSA, conn->ssl,
+					    (u8 *) private_key_blob,
+					    private_key_blob_len) == 1) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: SSL_use_PrivateKey_"
+				   "ASN1(EVP_PKEY_DSA) --> OK");
+			ok = 1;
+			break;
+		}
+
+		if (SSL_use_RSAPrivateKey_ASN1(conn->ssl,
+					       (u8 *) private_key_blob,
+					       private_key_blob_len) == 1) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: "
+				   "SSL_use_RSAPrivateKey_ASN1 --> OK");
+			ok = 1;
+			break;
+		}
+
+		if (tls_read_pkcs12_blob(ssl_ctx, conn->ssl, private_key_blob,
+					 private_key_blob_len, passwd) == 0) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: PKCS#12 as blob --> "
+				   "OK");
+			ok = 1;
+			break;
+		}
+
+		break;
+	}
+
+#ifdef ANDROID
+	if (!ok && private_key &&
+	    os_strncmp("keystore://", private_key, 11) == 0) {
+		BIO *bio = BIO_from_keystore(&private_key[11]);
+		EVP_PKEY *pkey = NULL;
+		if (bio) {
+			pkey = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
+			BIO_free(bio);
+		}
+		if (pkey) {
+			if (SSL_use_PrivateKey(conn->ssl, pkey) == 1) {
+				wpa_printf(MSG_DEBUG, "OpenSSL: Private key "
+					   "from keystore");
+				ok = 1;
+			}
+			EVP_PKEY_free(pkey);
+		}
+	}
+#endif /* ANDROID */
+
+	while (!ok && private_key) {
+#ifndef OPENSSL_NO_STDIO
+		if (SSL_use_PrivateKey_file(conn->ssl, private_key,
+					    SSL_FILETYPE_ASN1) == 1) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: "
+				   "SSL_use_PrivateKey_File (DER) --> OK");
+			ok = 1;
+			break;
+		}
+
+		if (SSL_use_PrivateKey_file(conn->ssl, private_key,
+					    SSL_FILETYPE_PEM) == 1) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: "
+				   "SSL_use_PrivateKey_File (PEM) --> OK");
+			ok = 1;
+			break;
+		}
+#else /* OPENSSL_NO_STDIO */
+		wpa_printf(MSG_DEBUG, "OpenSSL: %s - OPENSSL_NO_STDIO",
+			   __func__);
+#endif /* OPENSSL_NO_STDIO */
+
+		if (tls_read_pkcs12(ssl_ctx, conn->ssl, private_key, passwd)
+		    == 0) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: Reading PKCS#12 file "
+				   "--> OK");
+			ok = 1;
+			break;
+		}
+
+		if (tls_cryptoapi_cert(conn->ssl, private_key) == 0) {
+			wpa_printf(MSG_DEBUG, "OpenSSL: Using CryptoAPI to "
+				   "access certificate store --> OK");
+			ok = 1;
+			break;
+		}
+
+		break;
+	}
+
+	if (!ok) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to load private key");
+		os_free(passwd);
+		return -1;
+	}
+	ERR_clear_error();
+	SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
+	os_free(passwd);
+
+	if (!SSL_check_private_key(conn->ssl)) {
+		tls_show_errors(MSG_INFO, __func__, "Private key failed "
+				"verification");
+		return -1;
+	}
+
+	wpa_printf(MSG_DEBUG, "SSL: Private key loaded successfully");
+	return 0;
+}
+
+
+static int tls_global_private_key(SSL_CTX *ssl_ctx, const char *private_key,
+				  const char *private_key_passwd)
+{
+	char *passwd;
+
+	if (private_key == NULL)
+		return 0;
+
+	if (private_key_passwd) {
+		passwd = os_strdup(private_key_passwd);
+		if (passwd == NULL)
+			return -1;
+	} else
+		passwd = NULL;
+
+	SSL_CTX_set_default_passwd_cb(ssl_ctx, tls_passwd_cb);
+	SSL_CTX_set_default_passwd_cb_userdata(ssl_ctx, passwd);
+	if (
+#ifndef OPENSSL_NO_STDIO
+	    SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
+					SSL_FILETYPE_ASN1) != 1 &&
+	    SSL_CTX_use_PrivateKey_file(ssl_ctx, private_key,
+					SSL_FILETYPE_PEM) != 1 &&
+#endif /* OPENSSL_NO_STDIO */
+	    tls_read_pkcs12(ssl_ctx, NULL, private_key, passwd)) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Failed to load private key");
+		os_free(passwd);
+		ERR_clear_error();
+		return -1;
+	}
+	os_free(passwd);
+	ERR_clear_error();
+	SSL_CTX_set_default_passwd_cb(ssl_ctx, NULL);
+
+	if (!SSL_CTX_check_private_key(ssl_ctx)) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Private key failed verification");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+static int tls_connection_dh(struct tls_connection *conn, const char *dh_file)
+{
+#ifdef OPENSSL_NO_DH
+	if (dh_file == NULL)
+		return 0;
+	wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
+		   "dh_file specified");
+	return -1;
+#else /* OPENSSL_NO_DH */
+	DH *dh;
+	BIO *bio;
+
+	/* TODO: add support for dh_blob */
+	if (dh_file == NULL)
+		return 0;
+	if (conn == NULL)
+		return -1;
+
+	bio = BIO_new_file(dh_file, "r");
+	if (bio == NULL) {
+		wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
+			   dh_file, ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+	dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+	BIO_free(bio);
+#ifndef OPENSSL_NO_DSA
+	while (dh == NULL) {
+		DSA *dsa;
+		wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
+			   " trying to parse as DSA params", dh_file,
+			   ERR_error_string(ERR_get_error(), NULL));
+		bio = BIO_new_file(dh_file, "r");
+		if (bio == NULL)
+			break;
+		dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
+		BIO_free(bio);
+		if (!dsa) {
+			wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
+				   "'%s': %s", dh_file,
+				   ERR_error_string(ERR_get_error(), NULL));
+			break;
+		}
+
+		wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
+		dh = DSA_dup_DH(dsa);
+		DSA_free(dsa);
+		if (dh == NULL) {
+			wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
+				   "params into DH params");
+			break;
+		}
+		break;
+	}
+#endif /* !OPENSSL_NO_DSA */
+	if (dh == NULL) {
+		wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
+			   "'%s'", dh_file);
+		return -1;
+	}
+
+	if (SSL_set_tmp_dh(conn->ssl, dh) != 1) {
+		wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
+			   "%s", dh_file,
+			   ERR_error_string(ERR_get_error(), NULL));
+		DH_free(dh);
+		return -1;
+	}
+	DH_free(dh);
+	return 0;
+#endif /* OPENSSL_NO_DH */
+}
+
+
+static int tls_global_dh(SSL_CTX *ssl_ctx, const char *dh_file)
+{
+#ifdef OPENSSL_NO_DH
+	if (dh_file == NULL)
+		return 0;
+	wpa_printf(MSG_ERROR, "TLS: openssl does not include DH support, but "
+		   "dh_file specified");
+	return -1;
+#else /* OPENSSL_NO_DH */
+	DH *dh;
+	BIO *bio;
+
+	/* TODO: add support for dh_blob */
+	if (dh_file == NULL)
+		return 0;
+	if (ssl_ctx == NULL)
+		return -1;
+
+	bio = BIO_new_file(dh_file, "r");
+	if (bio == NULL) {
+		wpa_printf(MSG_INFO, "TLS: Failed to open DH file '%s': %s",
+			   dh_file, ERR_error_string(ERR_get_error(), NULL));
+		return -1;
+	}
+	dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+	BIO_free(bio);
+#ifndef OPENSSL_NO_DSA
+	while (dh == NULL) {
+		DSA *dsa;
+		wpa_printf(MSG_DEBUG, "TLS: Failed to parse DH file '%s': %s -"
+			   " trying to parse as DSA params", dh_file,
+			   ERR_error_string(ERR_get_error(), NULL));
+		bio = BIO_new_file(dh_file, "r");
+		if (bio == NULL)
+			break;
+		dsa = PEM_read_bio_DSAparams(bio, NULL, NULL, NULL);
+		BIO_free(bio);
+		if (!dsa) {
+			wpa_printf(MSG_DEBUG, "TLS: Failed to parse DSA file "
+				   "'%s': %s", dh_file,
+				   ERR_error_string(ERR_get_error(), NULL));
+			break;
+		}
+
+		wpa_printf(MSG_DEBUG, "TLS: DH file in DSA param format");
+		dh = DSA_dup_DH(dsa);
+		DSA_free(dsa);
+		if (dh == NULL) {
+			wpa_printf(MSG_INFO, "TLS: Failed to convert DSA "
+				   "params into DH params");
+			break;
+		}
+		break;
+	}
+#endif /* !OPENSSL_NO_DSA */
+	if (dh == NULL) {
+		wpa_printf(MSG_INFO, "TLS: Failed to read/parse DH/DSA file "
+			   "'%s'", dh_file);
+		return -1;
+	}
+
+	if (SSL_CTX_set_tmp_dh(ssl_ctx, dh) != 1) {
+		wpa_printf(MSG_INFO, "TLS: Failed to set DH params from '%s': "
+			   "%s", dh_file,
+			   ERR_error_string(ERR_get_error(), NULL));
+		DH_free(dh);
+		return -1;
+	}
+	DH_free(dh);
+	return 0;
+#endif /* OPENSSL_NO_DH */
+}
+
+
+int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
+			    struct tls_keys *keys)
+{
+#ifdef CONFIG_FIPS
+	wpa_printf(MSG_ERROR, "OpenSSL: TLS keys cannot be exported in FIPS "
+		   "mode");
+	return -1;
+#else /* CONFIG_FIPS */
+	SSL *ssl;
+
+	if (conn == NULL || keys == NULL)
+		return -1;
+	ssl = conn->ssl;
+	if (ssl == NULL || ssl->s3 == NULL || ssl->session == NULL)
+		return -1;
+
+	os_memset(keys, 0, sizeof(*keys));
+	keys->master_key = ssl->session->master_key;
+	keys->master_key_len = ssl->session->master_key_length;
+	keys->client_random = ssl->s3->client_random;
+	keys->client_random_len = SSL3_RANDOM_SIZE;
+	keys->server_random = ssl->s3->server_random;
+	keys->server_random_len = SSL3_RANDOM_SIZE;
+
+	return 0;
+#endif /* CONFIG_FIPS */
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len)
+{
+#if OPENSSL_VERSION_NUMBER >= 0x10001000L
+	SSL *ssl;
+	if (conn == NULL)
+		return -1;
+	if (server_random_first)
+		return -1;
+	ssl = conn->ssl;
+	if (SSL_export_keying_material(ssl, out, out_len, label,
+				       os_strlen(label), NULL, 0, 0) == 1) {
+		wpa_printf(MSG_DEBUG, "OpenSSL: Using internal PRF");
+		return 0;
+	}
+#endif
+	return -1;
+}
+
+
+static struct wpabuf *
+openssl_handshake(struct tls_connection *conn, const struct wpabuf *in_data,
+		  int server)
+{
+	int res;
+	struct wpabuf *out_data;
+
+	/*
+	 * Give TLS handshake data from the server (if available) to OpenSSL
+	 * for processing.
+	 */
+	if (in_data &&
+	    BIO_write(conn->ssl_in, wpabuf_head(in_data), wpabuf_len(in_data))
+	    < 0) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Handshake failed - BIO_write");
+		return NULL;
+	}
+
+	/* Initiate TLS handshake or continue the existing handshake */
+	if (server)
+		res = SSL_accept(conn->ssl);
+	else
+		res = SSL_connect(conn->ssl);
+	if (res != 1) {
+		int err = SSL_get_error(conn->ssl, res);
+		if (err == SSL_ERROR_WANT_READ)
+			wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want "
+				   "more data");
+		else if (err == SSL_ERROR_WANT_WRITE)
+			wpa_printf(MSG_DEBUG, "SSL: SSL_connect - want to "
+				   "write");
+		else {
+			tls_show_errors(MSG_INFO, __func__, "SSL_connect");
+			conn->failed++;
+		}
+	}
+
+	/* Get the TLS handshake data to be sent to the server */
+	res = BIO_ctrl_pending(conn->ssl_out);
+	wpa_printf(MSG_DEBUG, "SSL: %d bytes pending from ssl_out", res);
+	out_data = wpabuf_alloc(res);
+	if (out_data == NULL) {
+		wpa_printf(MSG_DEBUG, "SSL: Failed to allocate memory for "
+			   "handshake output (%d bytes)", res);
+		if (BIO_reset(conn->ssl_out) < 0) {
+			tls_show_errors(MSG_INFO, __func__,
+					"BIO_reset failed");
+		}
+		return NULL;
+	}
+	res = res == 0 ? 0 : BIO_read(conn->ssl_out, wpabuf_mhead(out_data),
+				      res);
+	if (res < 0) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Handshake failed - BIO_read");
+		if (BIO_reset(conn->ssl_out) < 0) {
+			tls_show_errors(MSG_INFO, __func__,
+					"BIO_reset failed");
+		}
+		wpabuf_free(out_data);
+		return NULL;
+	}
+	wpabuf_put(out_data, res);
+
+	return out_data;
+}
+
+
+static struct wpabuf *
+openssl_get_appl_data(struct tls_connection *conn, size_t max_len)
+{
+	struct wpabuf *appl_data;
+	int res;
+
+	appl_data = wpabuf_alloc(max_len + 100);
+	if (appl_data == NULL)
+		return NULL;
+
+	res = SSL_read(conn->ssl, wpabuf_mhead(appl_data),
+		       wpabuf_size(appl_data));
+	if (res < 0) {
+		int err = SSL_get_error(conn->ssl, res);
+		if (err == SSL_ERROR_WANT_READ ||
+		    err == SSL_ERROR_WANT_WRITE) {
+			wpa_printf(MSG_DEBUG, "SSL: No Application Data "
+				   "included");
+		} else {
+			tls_show_errors(MSG_INFO, __func__,
+					"Failed to read possible "
+					"Application Data");
+		}
+		wpabuf_free(appl_data);
+		return NULL;
+	}
+
+	wpabuf_put(appl_data, res);
+	wpa_hexdump_buf_key(MSG_MSGDUMP, "SSL: Application Data in Finished "
+			    "message", appl_data);
+
+	return appl_data;
+}
+
+
+static struct wpabuf *
+openssl_connection_handshake(struct tls_connection *conn,
+			     const struct wpabuf *in_data,
+			     struct wpabuf **appl_data, int server)
+{
+	struct wpabuf *out_data;
+
+	if (appl_data)
+		*appl_data = NULL;
+
+	out_data = openssl_handshake(conn, in_data, server);
+	if (out_data == NULL)
+		return NULL;
+
+	if (SSL_is_init_finished(conn->ssl) && appl_data && in_data)
+		*appl_data = openssl_get_appl_data(conn, wpabuf_len(in_data));
+
+	return out_data;
+}
+
+
+struct wpabuf *
+tls_connection_handshake(void *ssl_ctx, struct tls_connection *conn,
+			 const struct wpabuf *in_data,
+			 struct wpabuf **appl_data)
+{
+	return openssl_connection_handshake(conn, in_data, appl_data, 0);
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+						struct tls_connection *conn,
+						const struct wpabuf *in_data,
+						struct wpabuf **appl_data)
+{
+	return openssl_connection_handshake(conn, in_data, appl_data, 1);
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	int res;
+	struct wpabuf *buf;
+
+	if (conn == NULL)
+		return NULL;
+
+	/* Give plaintext data for OpenSSL to encrypt into the TLS tunnel. */
+	if ((res = BIO_reset(conn->ssl_in)) < 0 ||
+	    (res = BIO_reset(conn->ssl_out)) < 0) {
+		tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
+		return NULL;
+	}
+	res = SSL_write(conn->ssl, wpabuf_head(in_data), wpabuf_len(in_data));
+	if (res < 0) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Encryption failed - SSL_write");
+		return NULL;
+	}
+
+	/* Read encrypted data to be sent to the server */
+	buf = wpabuf_alloc(wpabuf_len(in_data) + 300);
+	if (buf == NULL)
+		return NULL;
+	res = BIO_read(conn->ssl_out, wpabuf_mhead(buf), wpabuf_size(buf));
+	if (res < 0) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Encryption failed - BIO_read");
+		wpabuf_free(buf);
+		return NULL;
+	}
+	wpabuf_put(buf, res);
+
+	return buf;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	int res;
+	struct wpabuf *buf;
+
+	/* Give encrypted data from TLS tunnel for OpenSSL to decrypt. */
+	res = BIO_write(conn->ssl_in, wpabuf_head(in_data),
+			wpabuf_len(in_data));
+	if (res < 0) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Decryption failed - BIO_write");
+		return NULL;
+	}
+	if (BIO_reset(conn->ssl_out) < 0) {
+		tls_show_errors(MSG_INFO, __func__, "BIO_reset failed");
+		return NULL;
+	}
+
+	/* Read decrypted data for further processing */
+	/*
+	 * Even though we try to disable TLS compression, it is possible that
+	 * this cannot be done with all TLS libraries. Add extra buffer space
+	 * to handle the possibility of the decrypted data being longer than
+	 * input data.
+	 */
+	buf = wpabuf_alloc((wpabuf_len(in_data) + 500) * 3);
+	if (buf == NULL)
+		return NULL;
+	res = SSL_read(conn->ssl, wpabuf_mhead(buf), wpabuf_size(buf));
+	if (res < 0) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Decryption failed - SSL_read");
+		wpabuf_free(buf);
+		return NULL;
+	}
+	wpabuf_put(buf, res);
+
+	return buf;
+}
+
+
+int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
+{
+	return conn ? conn->ssl->hit : 0;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
+{
+	char buf[100], *pos, *end;
+	u8 *c;
+	int ret;
+
+	if (conn == NULL || conn->ssl == NULL || ciphers == NULL)
+		return -1;
+
+	buf[0] = '\0';
+	pos = buf;
+	end = pos + sizeof(buf);
+
+	c = ciphers;
+	while (*c != TLS_CIPHER_NONE) {
+		const char *suite;
+
+		switch (*c) {
+		case TLS_CIPHER_RC4_SHA:
+			suite = "RC4-SHA";
+			break;
+		case TLS_CIPHER_AES128_SHA:
+			suite = "AES128-SHA";
+			break;
+		case TLS_CIPHER_RSA_DHE_AES128_SHA:
+			suite = "DHE-RSA-AES128-SHA";
+			break;
+		case TLS_CIPHER_ANON_DH_AES128_SHA:
+			suite = "ADH-AES128-SHA";
+			break;
+		default:
+			wpa_printf(MSG_DEBUG, "TLS: Unsupported "
+				   "cipher selection: %d", *c);
+			return -1;
+		}
+		ret = os_snprintf(pos, end - pos, ":%s", suite);
+		if (ret < 0 || ret >= end - pos)
+			break;
+		pos += ret;
+
+		c++;
+	}
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: cipher suites: %s", buf + 1);
+
+	if (SSL_set_cipher_list(conn->ssl, buf + 1) != 1) {
+		tls_show_errors(MSG_INFO, __func__,
+				"Cipher suite configuration failed");
+		return -1;
+	}
+
+	return 0;
+}
+
+
+int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
+		   char *buf, size_t buflen)
+{
+	const char *name;
+	if (conn == NULL || conn->ssl == NULL)
+		return -1;
+
+	name = SSL_get_cipher(conn->ssl);
+	if (name == NULL)
+		return -1;
+
+	os_strlcpy(buf, name, buflen);
+	return 0;
+}
+
+
+int tls_connection_enable_workaround(void *ssl_ctx,
+				     struct tls_connection *conn)
+{
+	SSL_set_options(conn->ssl, SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS);
+
+	return 0;
+}
+
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+/* ClientHello TLS extensions require a patch to openssl, so this function is
+ * commented out unless explicitly needed for EAP-FAST in order to be able to
+ * build this file with unmodified openssl. */
+int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
+				    int ext_type, const u8 *data,
+				    size_t data_len)
+{
+	if (conn == NULL || conn->ssl == NULL || ext_type != 35)
+		return -1;
+
+#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
+	if (SSL_set_session_ticket_ext(conn->ssl, (void *) data,
+				       data_len) != 1)
+		return -1;
+#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+	if (SSL_set_hello_extension(conn->ssl, ext_type, (void *) data,
+				    data_len) != 1)
+		return -1;
+#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+
+	return 0;
+}
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+
+
+int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->failed;
+}
+
+
+int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->read_alerts;
+}
+
+
+int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->write_alerts;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+	int ret;
+	unsigned long err;
+
+	if (conn == NULL)
+		return -1;
+
+	while ((err = ERR_get_error())) {
+		wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
+			   __func__, ERR_error_string(err, NULL));
+	}
+
+	if (params->engine) {
+		wpa_printf(MSG_DEBUG, "SSL: Initializing TLS engine");
+		ret = tls_engine_init(conn, params->engine_id, params->pin,
+				      params->key_id, params->cert_id,
+				      params->ca_cert_id);
+		if (ret)
+			return ret;
+	}
+	if (tls_connection_set_subject_match(conn,
+					     params->subject_match,
+					     params->altsubject_match))
+		return -1;
+
+	if (params->engine && params->ca_cert_id) {
+		if (tls_connection_engine_ca_cert(tls_ctx, conn,
+						  params->ca_cert_id))
+			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
+	} else if (tls_connection_ca_cert(tls_ctx, conn, params->ca_cert,
+					  params->ca_cert_blob,
+					  params->ca_cert_blob_len,
+					  params->ca_path))
+		return -1;
+
+	if (params->engine && params->cert_id) {
+		if (tls_connection_engine_client_cert(conn, params->cert_id))
+			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
+	} else if (tls_connection_client_cert(conn, params->client_cert,
+					      params->client_cert_blob,
+					      params->client_cert_blob_len))
+		return -1;
+
+	if (params->engine && params->key_id) {
+		wpa_printf(MSG_DEBUG, "TLS: Using private key from engine");
+		if (tls_connection_engine_private_key(conn))
+			return TLS_SET_PARAMS_ENGINE_PRV_VERIFY_FAILED;
+	} else if (tls_connection_private_key(tls_ctx, conn,
+					      params->private_key,
+					      params->private_key_passwd,
+					      params->private_key_blob,
+					      params->private_key_blob_len)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load private key '%s'",
+			   params->private_key);
+		return -1;
+	}
+
+	if (tls_connection_dh(conn, params->dh_file)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
+			   params->dh_file);
+		return -1;
+	}
+
+#ifdef SSL_OP_NO_TICKET
+	if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
+		SSL_set_options(conn->ssl, SSL_OP_NO_TICKET);
+	else
+		SSL_clear_options(conn->ssl, SSL_OP_NO_TICKET);
+#endif /*  SSL_OP_NO_TICKET */
+
+	conn->flags = params->flags;
+
+	tls_get_errors(tls_ctx);
+
+	return 0;
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+	SSL_CTX *ssl_ctx = tls_ctx;
+	unsigned long err;
+
+	while ((err = ERR_get_error())) {
+		wpa_printf(MSG_INFO, "%s: Clearing pending SSL error: %s",
+			   __func__, ERR_error_string(err, NULL));
+	}
+
+	if (tls_global_ca_cert(ssl_ctx, params->ca_cert))
+		return -1;
+
+	if (tls_global_client_cert(ssl_ctx, params->client_cert))
+		return -1;
+
+	if (tls_global_private_key(ssl_ctx, params->private_key,
+				   params->private_key_passwd))
+		return -1;
+
+	if (tls_global_dh(ssl_ctx, params->dh_file)) {
+		wpa_printf(MSG_INFO, "TLS: Failed to load DH file '%s'",
+			   params->dh_file);
+		return -1;
+	}
+
+#ifdef SSL_OP_NO_TICKET
+	if (params->flags & TLS_CONN_DISABLE_SESSION_TICKET)
+		SSL_CTX_set_options(ssl_ctx, SSL_OP_NO_TICKET);
+	else
+		SSL_CTX_clear_options(ssl_ctx, SSL_OP_NO_TICKET);
+#endif /*  SSL_OP_NO_TICKET */
+
+	return 0;
+}
+
+
+int tls_connection_get_keyblock_size(void *tls_ctx,
+				     struct tls_connection *conn)
+{
+	const EVP_CIPHER *c;
+	const EVP_MD *h;
+	int md_size;
+
+	if (conn == NULL || conn->ssl == NULL ||
+	    conn->ssl->enc_read_ctx == NULL ||
+	    conn->ssl->enc_read_ctx->cipher == NULL ||
+	    conn->ssl->read_hash == NULL)
+		return -1;
+
+	c = conn->ssl->enc_read_ctx->cipher;
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+	h = EVP_MD_CTX_md(conn->ssl->read_hash);
+#else
+	h = conn->ssl->read_hash;
+#endif
+	if (h)
+		md_size = EVP_MD_size(h);
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+	else if (conn->ssl->s3)
+		md_size = conn->ssl->s3->tmp.new_mac_secret_size;
+#endif
+	else
+		return -1;
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: keyblock size: key_len=%d MD_size=%d "
+		   "IV_len=%d", EVP_CIPHER_key_length(c), md_size,
+		   EVP_CIPHER_iv_length(c));
+	return 2 * (EVP_CIPHER_key_length(c) +
+		    md_size +
+		    EVP_CIPHER_iv_length(c));
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+	return 0;
+}
+
+
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+/* Pre-shared secred requires a patch to openssl, so this function is
+ * commented out unless explicitly needed for EAP-FAST in order to be able to
+ * build this file with unmodified openssl. */
+
+static int tls_sess_sec_cb(SSL *s, void *secret, int *secret_len,
+			   STACK_OF(SSL_CIPHER) *peer_ciphers,
+			   SSL_CIPHER **cipher, void *arg)
+{
+	struct tls_connection *conn = arg;
+	int ret;
+
+	if (conn == NULL || conn->session_ticket_cb == NULL)
+		return 0;
+
+	ret = conn->session_ticket_cb(conn->session_ticket_cb_ctx,
+				      conn->session_ticket,
+				      conn->session_ticket_len,
+				      s->s3->client_random,
+				      s->s3->server_random, secret);
+	os_free(conn->session_ticket);
+	conn->session_ticket = NULL;
+
+	if (ret <= 0)
+		return 0;
+
+	*secret_len = SSL_MAX_MASTER_KEY_LENGTH;
+	return 1;
+}
+
+
+#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
+static int tls_session_ticket_ext_cb(SSL *s, const unsigned char *data,
+				     int len, void *arg)
+{
+	struct tls_connection *conn = arg;
+
+	if (conn == NULL || conn->session_ticket_cb == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s: length=%d", __func__, len);
+
+	os_free(conn->session_ticket);
+	conn->session_ticket = NULL;
+
+	wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
+		    "extension", data, len);
+
+	conn->session_ticket = os_malloc(len);
+	if (conn->session_ticket == NULL)
+		return 0;
+
+	os_memcpy(conn->session_ticket, data, len);
+	conn->session_ticket_len = len;
+
+	return 1;
+}
+#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+#ifdef SSL_OP_NO_TICKET
+static void tls_hello_ext_cb(SSL *s, int client_server, int type,
+			     unsigned char *data, int len, void *arg)
+{
+	struct tls_connection *conn = arg;
+
+	if (conn == NULL || conn->session_ticket_cb == NULL)
+		return;
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
+		   type, len);
+
+	if (type == TLSEXT_TYPE_session_ticket && !client_server) {
+		os_free(conn->session_ticket);
+		conn->session_ticket = NULL;
+
+		wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
+			    "extension", data, len);
+		conn->session_ticket = os_malloc(len);
+		if (conn->session_ticket == NULL)
+			return;
+
+		os_memcpy(conn->session_ticket, data, len);
+		conn->session_ticket_len = len;
+	}
+}
+#else /* SSL_OP_NO_TICKET */
+static int tls_hello_ext_cb(SSL *s, TLS_EXTENSION *ext, void *arg)
+{
+	struct tls_connection *conn = arg;
+
+	if (conn == NULL || conn->session_ticket_cb == NULL)
+		return 0;
+
+	wpa_printf(MSG_DEBUG, "OpenSSL: %s: type=%d length=%d", __func__,
+		   ext->type, ext->length);
+
+	os_free(conn->session_ticket);
+	conn->session_ticket = NULL;
+
+	if (ext->type == 35) {
+		wpa_hexdump(MSG_DEBUG, "OpenSSL: ClientHello SessionTicket "
+			    "extension", ext->data, ext->length);
+		conn->session_ticket = os_malloc(ext->length);
+		if (conn->session_ticket == NULL)
+			return SSL_AD_INTERNAL_ERROR;
+
+		os_memcpy(conn->session_ticket, ext->data, ext->length);
+		conn->session_ticket_len = ext->length;
+	}
+
+	return 0;
+}
+#endif /* SSL_OP_NO_TICKET */
+#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+
+
+int tls_connection_set_session_ticket_cb(void *tls_ctx,
+					 struct tls_connection *conn,
+					 tls_session_ticket_cb cb,
+					 void *ctx)
+{
+#if defined(EAP_FAST) || defined(EAP_FAST_DYNAMIC) || defined(EAP_SERVER_FAST)
+	conn->session_ticket_cb = cb;
+	conn->session_ticket_cb_ctx = ctx;
+
+	if (cb) {
+		if (SSL_set_session_secret_cb(conn->ssl, tls_sess_sec_cb,
+					      conn) != 1)
+			return -1;
+#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
+		SSL_set_session_ticket_ext_cb(conn->ssl,
+					      tls_session_ticket_ext_cb, conn);
+#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+#ifdef SSL_OP_NO_TICKET
+		SSL_set_tlsext_debug_callback(conn->ssl, tls_hello_ext_cb);
+		SSL_set_tlsext_debug_arg(conn->ssl, conn);
+#else /* SSL_OP_NO_TICKET */
+		if (SSL_set_hello_extension_cb(conn->ssl, tls_hello_ext_cb,
+					       conn) != 1)
+			return -1;
+#endif /* SSL_OP_NO_TICKET */
+#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+	} else {
+		if (SSL_set_session_secret_cb(conn->ssl, NULL, NULL) != 1)
+			return -1;
+#ifdef CONFIG_OPENSSL_TICKET_OVERRIDE
+		SSL_set_session_ticket_ext_cb(conn->ssl, NULL, NULL);
+#else /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+#ifdef SSL_OP_NO_TICKET
+		SSL_set_tlsext_debug_callback(conn->ssl, NULL);
+		SSL_set_tlsext_debug_arg(conn->ssl, conn);
+#else /* SSL_OP_NO_TICKET */
+		if (SSL_set_hello_extension_cb(conn->ssl, NULL, NULL) != 1)
+			return -1;
+#endif /* SSL_OP_NO_TICKET */
+#endif /* CONFIG_OPENSSL_TICKET_OVERRIDE */
+	}
+
+	return 0;
+#else /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+	return -1;
+#endif /* EAP_FAST || EAP_FAST_DYNAMIC || EAP_SERVER_FAST */
+}
diff --git a/hostap/src/crypto/tls_schannel.c b/hostap/src/crypto/tls_schannel.c
new file mode 100644
index 0000000..2c2daa8
--- /dev/null
+++ b/hostap/src/crypto/tls_schannel.c
@@ -0,0 +1,732 @@
+/*
+ * SSL/TLS interface functions for Microsoft Schannel
+ * Copyright (c) 2005-2009, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+/*
+ * FIX: Go through all SSPI functions and verify what needs to be freed
+ * FIX: session resumption
+ * TODO: add support for server cert chain validation
+ * TODO: add support for CA cert validation
+ * TODO: add support for EAP-TLS (client cert/key conf)
+ */
+
+#include "includes.h"
+#include <windows.h>
+#include <wincrypt.h>
+#include <schannel.h>
+#define SECURITY_WIN32
+#include <security.h>
+#include <sspi.h>
+
+#include "common.h"
+#include "tls.h"
+
+
+struct tls_global {
+	HMODULE hsecurity;
+	PSecurityFunctionTable sspi;
+	HCERTSTORE my_cert_store;
+};
+
+struct tls_connection {
+	int established, start;
+	int failed, read_alerts, write_alerts;
+
+	SCHANNEL_CRED schannel_cred;
+	CredHandle creds;
+	CtxtHandle context;
+
+	u8 eap_tls_prf[128];
+	int eap_tls_prf_set;
+};
+
+
+static int schannel_load_lib(struct tls_global *global)
+{
+	INIT_SECURITY_INTERFACE pInitSecurityInterface;
+
+	global->hsecurity = LoadLibrary(TEXT("Secur32.dll"));
+	if (global->hsecurity == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Could not load Secur32.dll - 0x%x",
+			   __func__, (unsigned int) GetLastError());
+		return -1;
+	}
+
+	pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(
+		global->hsecurity, "InitSecurityInterfaceA");
+	if (pInitSecurityInterface == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Could not find "
+			   "InitSecurityInterfaceA from Secur32.dll",
+			   __func__);
+		FreeLibrary(global->hsecurity);
+		global->hsecurity = NULL;
+		return -1;
+	}
+
+	global->sspi = pInitSecurityInterface();
+	if (global->sspi == NULL) {
+		wpa_printf(MSG_ERROR, "%s: Could not read security "
+			   "interface - 0x%x",
+			   __func__, (unsigned int) GetLastError());
+		FreeLibrary(global->hsecurity);
+		global->hsecurity = NULL;
+		return -1;
+	}
+
+	return 0;
+}
+
+
+void * tls_init(const struct tls_config *conf)
+{
+	struct tls_global *global;
+
+	global = os_zalloc(sizeof(*global));
+	if (global == NULL)
+		return NULL;
+	if (schannel_load_lib(global)) {
+		os_free(global);
+		return NULL;
+	}
+	return global;
+}
+
+
+void tls_deinit(void *ssl_ctx)
+{
+	struct tls_global *global = ssl_ctx;
+
+	if (global->my_cert_store)
+		CertCloseStore(global->my_cert_store, 0);
+	FreeLibrary(global->hsecurity);
+	os_free(global);
+}
+
+
+int tls_get_errors(void *ssl_ctx)
+{
+	return 0;
+}
+
+
+struct tls_connection * tls_connection_init(void *ssl_ctx)
+{
+	struct tls_connection *conn;
+
+	conn = os_zalloc(sizeof(*conn));
+	if (conn == NULL)
+		return NULL;
+	conn->start = 1;
+
+	return conn;
+}
+
+
+void tls_connection_deinit(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return;
+
+	os_free(conn);
+}
+
+
+int tls_connection_established(void *ssl_ctx, struct tls_connection *conn)
+{
+	return conn ? conn->established : 0;
+}
+
+
+int tls_connection_shutdown(void *ssl_ctx, struct tls_connection *conn)
+{
+	struct tls_global *global = ssl_ctx;
+	if (conn == NULL)
+		return -1;
+
+	conn->eap_tls_prf_set = 0;
+	conn->established = conn->failed = 0;
+	conn->read_alerts = conn->write_alerts = 0;
+	global->sspi->DeleteSecurityContext(&conn->context);
+	/* FIX: what else needs to be reseted? */
+
+	return 0;
+}
+
+
+int tls_global_set_params(void *tls_ctx,
+			  const struct tls_connection_params *params)
+{
+	return -1;
+}
+
+
+int tls_global_set_verify(void *ssl_ctx, int check_crl)
+{
+	return -1;
+}
+
+
+int tls_connection_set_verify(void *ssl_ctx, struct tls_connection *conn,
+			      int verify_peer)
+{
+	return -1;
+}
+
+
+int tls_connection_get_keys(void *ssl_ctx, struct tls_connection *conn,
+			    struct tls_keys *keys)
+{
+	/* Schannel does not export master secret or client/server random. */
+	return -1;
+}
+
+
+int tls_connection_prf(void *tls_ctx, struct tls_connection *conn,
+		       const char *label, int server_random_first,
+		       u8 *out, size_t out_len)
+{
+	/*
+	 * Cannot get master_key from Schannel, but EapKeyBlock can be used to
+	 * generate session keys for EAP-TLS and EAP-PEAPv0. EAP-PEAPv2 and
+	 * EAP-TTLS cannot use this, though, since they are using different
+	 * labels. The only option could be to implement TLSv1 completely here
+	 * and just use Schannel or CryptoAPI for low-level crypto
+	 * functionality..
+	 */
+
+	if (conn == NULL || !conn->eap_tls_prf_set || server_random_first ||
+	    os_strcmp(label, "client EAP encryption") != 0 ||
+	    out_len > sizeof(conn->eap_tls_prf))
+		return -1;
+
+	os_memcpy(out, conn->eap_tls_prf, out_len);
+
+	return 0;
+}
+
+
+static struct wpabuf * tls_conn_hs_clienthello(struct tls_global *global,
+					       struct tls_connection *conn)
+{
+	DWORD sspi_flags, sspi_flags_out;
+	SecBufferDesc outbuf;
+	SecBuffer outbufs[1];
+	SECURITY_STATUS status;
+	TimeStamp ts_expiry;
+
+	sspi_flags = ISC_REQ_REPLAY_DETECT |
+		ISC_REQ_CONFIDENTIALITY |
+		ISC_RET_EXTENDED_ERROR |
+		ISC_REQ_ALLOCATE_MEMORY |
+		ISC_REQ_MANUAL_CRED_VALIDATION;
+
+	wpa_printf(MSG_DEBUG, "%s: Generating ClientHello", __func__);
+
+	outbufs[0].pvBuffer = NULL;
+	outbufs[0].BufferType = SECBUFFER_TOKEN;
+	outbufs[0].cbBuffer = 0;
+
+	outbuf.cBuffers = 1;
+	outbuf.pBuffers = outbufs;
+	outbuf.ulVersion = SECBUFFER_VERSION;
+
+#ifdef UNICODE
+	status = global->sspi->InitializeSecurityContextW(
+		&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
+		SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
+		&outbuf, &sspi_flags_out, &ts_expiry);
+#else /* UNICODE */
+	status = global->sspi->InitializeSecurityContextA(
+		&conn->creds, NULL, NULL /* server name */, sspi_flags, 0,
+		SECURITY_NATIVE_DREP, NULL, 0, &conn->context,
+		&outbuf, &sspi_flags_out, &ts_expiry);
+#endif /* UNICODE */
+	if (status != SEC_I_CONTINUE_NEEDED) {
+		wpa_printf(MSG_ERROR, "%s: InitializeSecurityContextA "
+			   "failed - 0x%x",
+			   __func__, (unsigned int) status);
+		return NULL;
+	}
+
+	if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
+		struct wpabuf *buf;
+		wpa_hexdump(MSG_MSGDUMP, "SChannel - ClientHello",
+			    outbufs[0].pvBuffer, outbufs[0].cbBuffer);
+		conn->start = 0;
+		buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
+					outbufs[0].cbBuffer);
+		if (buf == NULL)
+			return NULL;
+		global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
+		return buf;
+	}
+
+	wpa_printf(MSG_ERROR, "SChannel: Failed to generate ClientHello");
+
+	return NULL;
+}
+
+
+#ifndef SECPKG_ATTR_EAP_KEY_BLOCK
+#define SECPKG_ATTR_EAP_KEY_BLOCK 0x5b
+
+typedef struct _SecPkgContext_EapKeyBlock {
+	BYTE rgbKeys[128];
+	BYTE rgbIVs[64];
+} SecPkgContext_EapKeyBlock, *PSecPkgContext_EapKeyBlock;
+#endif /* !SECPKG_ATTR_EAP_KEY_BLOCK */
+
+static int tls_get_eap(struct tls_global *global, struct tls_connection *conn)
+{
+	SECURITY_STATUS status;
+	SecPkgContext_EapKeyBlock kb;
+
+	/* Note: Windows NT and Windows Me/98/95 do not support getting
+	 * EapKeyBlock */
+
+	status = global->sspi->QueryContextAttributes(
+		&conn->context, SECPKG_ATTR_EAP_KEY_BLOCK, &kb);
+	if (status != SEC_E_OK) {
+		wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes("
+			   "SECPKG_ATTR_EAP_KEY_BLOCK) failed (%d)",
+			   __func__, (int) status);
+		return -1;
+	}
+
+	wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbKeys",
+			kb.rgbKeys, sizeof(kb.rgbKeys));
+	wpa_hexdump_key(MSG_MSGDUMP, "Schannel - EapKeyBlock - rgbIVs",
+			kb.rgbIVs, sizeof(kb.rgbIVs));
+
+	os_memcpy(conn->eap_tls_prf, kb.rgbKeys, sizeof(kb.rgbKeys));
+	conn->eap_tls_prf_set = 1;
+	return 0;
+}
+
+
+struct wpabuf * tls_connection_handshake(void *tls_ctx,
+					 struct tls_connection *conn,
+					 const struct wpabuf *in_data,
+					 struct wpabuf **appl_data)
+{
+	struct tls_global *global = tls_ctx;
+	DWORD sspi_flags, sspi_flags_out;
+	SecBufferDesc inbuf, outbuf;
+	SecBuffer inbufs[2], outbufs[1];
+	SECURITY_STATUS status;
+	TimeStamp ts_expiry;
+	struct wpabuf *out_buf = NULL;
+
+	if (appl_data)
+		*appl_data = NULL;
+
+	if (conn->start)
+		return tls_conn_hs_clienthello(global, conn);
+
+	wpa_printf(MSG_DEBUG, "SChannel: %d bytes handshake data to process",
+		   (int) wpabuf_len(in_data));
+
+	sspi_flags = ISC_REQ_REPLAY_DETECT |
+		ISC_REQ_CONFIDENTIALITY |
+		ISC_RET_EXTENDED_ERROR |
+		ISC_REQ_ALLOCATE_MEMORY |
+		ISC_REQ_MANUAL_CRED_VALIDATION;
+
+	/* Input buffer for Schannel */
+	inbufs[0].pvBuffer = (u8 *) wpabuf_head(in_data);
+	inbufs[0].cbBuffer = wpabuf_len(in_data);
+	inbufs[0].BufferType = SECBUFFER_TOKEN;
+
+	/* Place for leftover data from Schannel */
+	inbufs[1].pvBuffer = NULL;
+	inbufs[1].cbBuffer = 0;
+	inbufs[1].BufferType = SECBUFFER_EMPTY;
+
+	inbuf.cBuffers = 2;
+	inbuf.pBuffers = inbufs;
+	inbuf.ulVersion = SECBUFFER_VERSION;
+
+	/* Output buffer for Schannel */
+	outbufs[0].pvBuffer = NULL;
+	outbufs[0].cbBuffer = 0;
+	outbufs[0].BufferType = SECBUFFER_TOKEN;
+
+	outbuf.cBuffers = 1;
+	outbuf.pBuffers = outbufs;
+	outbuf.ulVersion = SECBUFFER_VERSION;
+
+#ifdef UNICODE
+	status = global->sspi->InitializeSecurityContextW(
+		&conn->creds, &conn->context, NULL, sspi_flags, 0,
+		SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
+		&outbuf, &sspi_flags_out, &ts_expiry);
+#else /* UNICODE */
+	status = global->sspi->InitializeSecurityContextA(
+		&conn->creds, &conn->context, NULL, sspi_flags, 0,
+		SECURITY_NATIVE_DREP, &inbuf, 0, NULL,
+		&outbuf, &sspi_flags_out, &ts_expiry);
+#endif /* UNICODE */
+
+	wpa_printf(MSG_MSGDUMP, "Schannel: InitializeSecurityContext -> "
+		   "status=%d inlen[0]=%d intype[0]=%d inlen[1]=%d "
+		   "intype[1]=%d outlen[0]=%d",
+		   (int) status, (int) inbufs[0].cbBuffer,
+		   (int) inbufs[0].BufferType, (int) inbufs[1].cbBuffer,
+		   (int) inbufs[1].BufferType,
+		   (int) outbufs[0].cbBuffer);
+	if (status == SEC_E_OK || status == SEC_I_CONTINUE_NEEDED ||
+	    (FAILED(status) && (sspi_flags_out & ISC_RET_EXTENDED_ERROR))) {
+		if (outbufs[0].cbBuffer != 0 && outbufs[0].pvBuffer) {
+			wpa_hexdump(MSG_MSGDUMP, "SChannel - output",
+				    outbufs[0].pvBuffer, outbufs[0].cbBuffer);
+			out_buf = wpabuf_alloc_copy(outbufs[0].pvBuffer,
+						    outbufs[0].cbBuffer);
+			global->sspi->FreeContextBuffer(outbufs[0].pvBuffer);
+			outbufs[0].pvBuffer = NULL;
+			if (out_buf == NULL)
+				return NULL;
+		}
+	}
+
+	switch (status) {
+	case SEC_E_INCOMPLETE_MESSAGE:
+		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INCOMPLETE_MESSAGE");
+		break;
+	case SEC_I_CONTINUE_NEEDED:
+		wpa_printf(MSG_DEBUG, "Schannel: SEC_I_CONTINUE_NEEDED");
+		break;
+	case SEC_E_OK:
+		/* TODO: verify server certificate chain */
+		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_OK - Handshake "
+			   "completed successfully");
+		conn->established = 1;
+		tls_get_eap(global, conn);
+
+		/* Need to return something to get final TLS ACK. */
+		if (out_buf == NULL)
+			out_buf = wpabuf_alloc(0);
+
+		if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
+			wpa_hexdump(MSG_MSGDUMP, "SChannel - Encrypted "
+				    "application data",
+				    inbufs[1].pvBuffer, inbufs[1].cbBuffer);
+			if (appl_data) {
+				*appl_data = wpabuf_alloc_copy(
+					outbufs[1].pvBuffer,
+					outbufs[1].cbBuffer);
+			}
+			global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
+			inbufs[1].pvBuffer = NULL;
+		}
+		break;
+	case SEC_I_INCOMPLETE_CREDENTIALS:
+		wpa_printf(MSG_DEBUG,
+			   "Schannel: SEC_I_INCOMPLETE_CREDENTIALS");
+		break;
+	case SEC_E_WRONG_PRINCIPAL:
+		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_WRONG_PRINCIPAL");
+		break;
+	case SEC_E_INTERNAL_ERROR:
+		wpa_printf(MSG_DEBUG, "Schannel: SEC_E_INTERNAL_ERROR");
+		break;
+	}
+
+	if (FAILED(status)) {
+		wpa_printf(MSG_DEBUG, "Schannel: Handshake failed "
+			   "(out_buf=%p)", out_buf);
+		conn->failed++;
+		global->sspi->DeleteSecurityContext(&conn->context);
+		return out_buf;
+	}
+
+	if (inbufs[1].BufferType == SECBUFFER_EXTRA) {
+		/* TODO: Can this happen? What to do with this data? */
+		wpa_hexdump(MSG_MSGDUMP, "SChannel - Leftover data",
+			    inbufs[1].pvBuffer, inbufs[1].cbBuffer);
+		global->sspi->FreeContextBuffer(inbufs[1].pvBuffer);
+		inbufs[1].pvBuffer = NULL;
+	}
+
+	return out_buf;
+}
+
+
+struct wpabuf * tls_connection_server_handshake(void *tls_ctx,
+						struct tls_connection *conn,
+						const struct wpabuf *in_data,
+						struct wpabuf **appl_data)
+{
+	return NULL;
+}
+
+
+struct wpabuf * tls_connection_encrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	struct tls_global *global = tls_ctx;
+	SECURITY_STATUS status;
+	SecBufferDesc buf;
+	SecBuffer bufs[4];
+	SecPkgContext_StreamSizes sizes;
+	int i;
+	struct wpabuf *out;
+
+	status = global->sspi->QueryContextAttributes(&conn->context,
+						      SECPKG_ATTR_STREAM_SIZES,
+						      &sizes);
+	if (status != SEC_E_OK) {
+		wpa_printf(MSG_DEBUG, "%s: QueryContextAttributes failed",
+			   __func__);
+		return NULL;
+	}
+	wpa_printf(MSG_DEBUG, "%s: Stream sizes: header=%u trailer=%u",
+		   __func__,
+		   (unsigned int) sizes.cbHeader,
+		   (unsigned int) sizes.cbTrailer);
+
+	out = wpabuf_alloc(sizes.cbHeader + wpabuf_len(in_data) +
+			   sizes.cbTrailer);
+
+	os_memset(&bufs, 0, sizeof(bufs));
+	bufs[0].pvBuffer = wpabuf_put(out, sizes.cbHeader);
+	bufs[0].cbBuffer = sizes.cbHeader;
+	bufs[0].BufferType = SECBUFFER_STREAM_HEADER;
+
+	bufs[1].pvBuffer = wpabuf_put(out, 0);
+	wpabuf_put_buf(out, in_data);
+	bufs[1].cbBuffer = wpabuf_len(in_data);
+	bufs[1].BufferType = SECBUFFER_DATA;
+
+	bufs[2].pvBuffer = wpabuf_put(out, sizes.cbTrailer);
+	bufs[2].cbBuffer = sizes.cbTrailer;
+	bufs[2].BufferType = SECBUFFER_STREAM_TRAILER;
+
+	buf.ulVersion = SECBUFFER_VERSION;
+	buf.cBuffers = 3;
+	buf.pBuffers = bufs;
+
+	status = global->sspi->EncryptMessage(&conn->context, 0, &buf, 0);
+
+	wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage -> "
+		   "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
+		   "len[2]=%d type[2]=%d",
+		   (int) status,
+		   (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
+		   (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
+		   (int) bufs[2].cbBuffer, (int) bufs[2].BufferType);
+	wpa_printf(MSG_MSGDUMP, "Schannel: EncryptMessage pointers: "
+		   "out_data=%p bufs %p %p %p",
+		   wpabuf_head(out), bufs[0].pvBuffer, bufs[1].pvBuffer,
+		   bufs[2].pvBuffer);
+
+	for (i = 0; i < 3; i++) {
+		if (bufs[i].pvBuffer && bufs[i].BufferType != SECBUFFER_EMPTY)
+		{
+			wpa_hexdump(MSG_MSGDUMP, "SChannel: bufs",
+				    bufs[i].pvBuffer, bufs[i].cbBuffer);
+		}
+	}
+
+	if (status == SEC_E_OK) {
+		wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
+		wpa_hexdump_buf_key(MSG_MSGDUMP, "Schannel: Encrypted data "
+				    "from EncryptMessage", out);
+		return out;
+	}
+
+	wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
+		   __func__, (int) status);
+	wpabuf_free(out);
+	return NULL;
+}
+
+
+struct wpabuf * tls_connection_decrypt(void *tls_ctx,
+				       struct tls_connection *conn,
+				       const struct wpabuf *in_data)
+{
+	struct tls_global *global = tls_ctx;
+	SECURITY_STATUS status;
+	SecBufferDesc buf;
+	SecBuffer bufs[4];
+	int i;
+	struct wpabuf *out, *tmp;
+
+	wpa_hexdump_buf(MSG_MSGDUMP,
+			"Schannel: Encrypted data to DecryptMessage", in_data);
+	os_memset(&bufs, 0, sizeof(bufs));
+	tmp = wpabuf_dup(in_data);
+	if (tmp == NULL)
+		return NULL;
+	bufs[0].pvBuffer = wpabuf_mhead(tmp);
+	bufs[0].cbBuffer = wpabuf_len(in_data);
+	bufs[0].BufferType = SECBUFFER_DATA;
+
+	bufs[1].BufferType = SECBUFFER_EMPTY;
+	bufs[2].BufferType = SECBUFFER_EMPTY;
+	bufs[3].BufferType = SECBUFFER_EMPTY;
+
+	buf.ulVersion = SECBUFFER_VERSION;
+	buf.cBuffers = 4;
+	buf.pBuffers = bufs;
+
+	status = global->sspi->DecryptMessage(&conn->context, &buf, 0,
+						    NULL);
+	wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage -> "
+		   "status=%d len[0]=%d type[0]=%d len[1]=%d type[1]=%d "
+		   "len[2]=%d type[2]=%d len[3]=%d type[3]=%d",
+		   (int) status,
+		   (int) bufs[0].cbBuffer, (int) bufs[0].BufferType,
+		   (int) bufs[1].cbBuffer, (int) bufs[1].BufferType,
+		   (int) bufs[2].cbBuffer, (int) bufs[2].BufferType,
+		   (int) bufs[3].cbBuffer, (int) bufs[3].BufferType);
+	wpa_printf(MSG_MSGDUMP, "Schannel: DecryptMessage pointers: "
+		   "out_data=%p bufs %p %p %p %p",
+		   wpabuf_head(tmp), bufs[0].pvBuffer, bufs[1].pvBuffer,
+		   bufs[2].pvBuffer, bufs[3].pvBuffer);
+
+	switch (status) {
+	case SEC_E_INCOMPLETE_MESSAGE:
+		wpa_printf(MSG_DEBUG, "%s: SEC_E_INCOMPLETE_MESSAGE",
+			   __func__);
+		break;
+	case SEC_E_OK:
+		wpa_printf(MSG_DEBUG, "%s: SEC_E_OK", __func__);
+		for (i = 0; i < 4; i++) {
+			if (bufs[i].BufferType == SECBUFFER_DATA)
+				break;
+		}
+		if (i == 4) {
+			wpa_printf(MSG_DEBUG, "%s: No output data from "
+				   "DecryptMessage", __func__);
+			wpabuf_free(tmp);
+			return NULL;
+		}
+		wpa_hexdump_key(MSG_MSGDUMP, "Schannel: Decrypted data from "
+				"DecryptMessage",
+				bufs[i].pvBuffer, bufs[i].cbBuffer);
+		out = wpabuf_alloc_copy(bufs[i].pvBuffer, bufs[i].cbBuffer);
+		wpabuf_free(tmp);
+		return out;
+	}
+
+	wpa_printf(MSG_DEBUG, "%s: Failed - status=%d",
+		   __func__, (int) status);
+	wpabuf_free(tmp);
+	return NULL;
+}
+
+
+int tls_connection_resumed(void *ssl_ctx, struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_set_cipher_list(void *tls_ctx, struct tls_connection *conn,
+				   u8 *ciphers)
+{
+	return -1;
+}
+
+
+int tls_get_cipher(void *ssl_ctx, struct tls_connection *conn,
+		   char *buf, size_t buflen)
+{
+	return -1;
+}
+
+
+int tls_connection_enable_workaround(void *ssl_ctx,
+				     struct tls_connection *conn)
+{
+	return 0;
+}
+
+
+int tls_connection_client_hello_ext(void *ssl_ctx, struct tls_connection *conn,
+				    int ext_type, const u8 *data,
+				    size_t data_len)
+{
+	return -1;
+}
+
+
+int tls_connection_get_failed(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->failed;
+}
+
+
+int tls_connection_get_read_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->read_alerts;
+}
+
+
+int tls_connection_get_write_alerts(void *ssl_ctx, struct tls_connection *conn)
+{
+	if (conn == NULL)
+		return -1;
+	return conn->write_alerts;
+}
+
+
+int tls_connection_set_params(void *tls_ctx, struct tls_connection *conn,
+			      const struct tls_connection_params *params)
+{
+	struct tls_global *global = tls_ctx;
+	ALG_ID algs[1];
+	SECURITY_STATUS status;
+	TimeStamp ts_expiry;
+
+	if (conn == NULL)
+		return -1;
+
+	if (global->my_cert_store == NULL &&
+	    (global->my_cert_store = CertOpenSystemStore(0, TEXT("MY"))) ==
+	    NULL) {
+		wpa_printf(MSG_ERROR, "%s: CertOpenSystemStore failed - 0x%x",
+			   __func__, (unsigned int) GetLastError());
+		return -1;
+	}
+
+	os_memset(&conn->schannel_cred, 0, sizeof(conn->schannel_cred));
+	conn->schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
+	conn->schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1;
+	algs[0] = CALG_RSA_KEYX;
+	conn->schannel_cred.cSupportedAlgs = 1;
+	conn->schannel_cred.palgSupportedAlgs = algs;
+	conn->schannel_cred.dwFlags |= SCH_CRED_NO_DEFAULT_CREDS;
+#ifdef UNICODE
+	status = global->sspi->AcquireCredentialsHandleW(
+		NULL, UNISP_NAME_W, SECPKG_CRED_OUTBOUND, NULL,
+		&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
+#else /* UNICODE */
+	status = global->sspi->AcquireCredentialsHandleA(
+		NULL, UNISP_NAME_A, SECPKG_CRED_OUTBOUND, NULL,
+		&conn->schannel_cred, NULL, NULL, &conn->creds, &ts_expiry);
+#endif /* UNICODE */
+	if (status != SEC_E_OK) {
+		wpa_printf(MSG_DEBUG, "%s: AcquireCredentialsHandleA failed - "
+			   "0x%x", __func__, (unsigned int) status);
+		return -1;
+	}
+
+	return 0;
+}
+
+
+unsigned int tls_capabilities(void *tls_ctx)
+{
+	return 0;
+}
diff --git a/hostap/src/drivers/Makefile b/hostap/src/drivers/Makefile
new file mode 100644
index 0000000..07600e5
--- /dev/null
+++ b/hostap/src/drivers/Makefile
@@ -0,0 +1,9 @@
+all:
+	@echo Nothing to be made.
+
+clean:
+	rm -f *~ *.o *.d
+	rm -f build.wpa_supplicant build.hostapd
+
+install:
+	@echo Nothing to be made.
diff --git a/hostap/src/drivers/android_drv.h b/hostap/src/drivers/android_drv.h
new file mode 100644
index 0000000..5906527
--- /dev/null
+++ b/hostap/src/drivers/android_drv.h
@@ -0,0 +1,60 @@
+/*
+ * Android driver interface
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * Alternatively, this software may be distributed under the terms of BSD
+ * license.
+ */
+
+#ifndef ANDROID_DRV_H
+#define ANDROID_DRV_H
+
+#define WPA_EVENT_DRIVER_STATE "CTRL-EVENT-DRIVER-STATE "
+
+#define MAX_SSID_LEN 32
+
+#define MAX_DRV_CMD_SIZE		248
+#define DRV_NUMBER_SEQUENTIAL_ERRORS	4
+
+#define WEXT_PNOSETUP_HEADER		"PNOSETUP "
+#define WEXT_PNOSETUP_HEADER_SIZE	9
+#define WEXT_PNO_TLV_PREFIX		'S'
+#define WEXT_PNO_TLV_VERSION		'1'
+#define WEXT_PNO_TLV_SUBVERSION		'2'
+#define WEXT_PNO_TLV_RESERVED		'0'
+#define WEXT_PNO_VERSION_SIZE		4
+#define WEXT_PNO_AMOUNT			16
+#define WEXT_PNO_SSID_SECTION		'S'
+/* SSID header size is SSID section type above + SSID length */
+#define WEXT_PNO_SSID_HEADER_SIZE	2
+#define WEXT_PNO_SCAN_INTERVAL_SECTION	'T'
+#define WEXT_PNO_SCAN_INTERVAL_LENGTH	2
+#define WEXT_PNO_SCAN_INTERVAL		30
+/* Scan interval size is scan interval section type + scan interval length
+ * above */
+#define WEXT_PNO_SCAN_INTERVAL_SIZE	(1 + WEXT_PNO_SCAN_INTERVAL_LENGTH)
+#define WEXT_PNO_REPEAT_SECTION		'R'
+#define WEXT_PNO_REPEAT_LENGTH		1
+#define WEXT_PNO_REPEAT			4
+/* Repeat section size is Repeat section type + Repeat value length above */
+#define WEXT_PNO_REPEAT_SIZE		(1 + WEXT_PNO_REPEAT_LENGTH)
+#define WEXT_PNO_MAX_REPEAT_SECTION	'M'
+#define WEXT_PNO_MAX_REPEAT_LENGTH	1
+#define WEXT_PNO_MAX_REPEAT		3
+/* Max Repeat section size is Max Repeat section type + Max Repeat value length
+ * above */
+#define WEXT_PNO_MAX_REPEAT_SIZE	(1 + WEXT_PNO_MAX_REPEAT_LENGTH)
+/* This corresponds to the size of all sections expect SSIDs */
+#define WEXT_PNO_NONSSID_SECTIONS_SIZE \
+(WEXT_PNO_SCAN_INTERVAL_SIZE + WEXT_PNO_REPEAT_SIZE + WEXT_PNO_MAX_REPEAT_SIZE)
+/* PNO Max command size is total of header, version, ssid and other sections +
+ * Null termination */
+#define WEXT_PNO_MAX_COMMAND_SIZE \
+	(WEXT_PNOSETUP_HEADER_SIZE + WEXT_PNO_VERSION_SIZE \
+	 + WEXT_PNO_AMOUNT * (WEXT_PNO_SSID_HEADER_SIZE + MAX_SSID_LEN) \
+	 + WEXT_PNO_NONSSID_SECTIONS_SIZE + 1)
+
+#endif /* ANDROID_DRV_H */
diff --git a/hostap/src/drivers/driver.h b/hostap/src/drivers/driver.h
new file mode 100644
index 0000000..4815c7e
--- /dev/null
+++ b/hostap/src/drivers/driver.h
@@ -0,0 +1,3774 @@
+/*
+ * Driver interface definition
+ * Copyright (c) 2003-2012, Jouni Malinen <j@w1.fi>
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ *
+ * This file defines a driver interface used by both %wpa_supplicant and
+ * hostapd. The first part of the file defines data structures used in various
+ * driver operations. This is followed by the struct wpa_driver_ops that each
+ * driver wrapper will beed to define with callback functions for requesting
+ * driver operations. After this, there are definitions for driver event
+ * reporting with wpa_supplicant_event() and some convenience helper functions
+ * that can be used to report events.
+ */
+
+#ifndef DRIVER_H
+#define DRIVER_H
+
+#define WPA_SUPPLICANT_DRIVER_VERSION 4
+
+#include "common/defs.h"
+
+#define HOSTAPD_CHAN_DISABLED 0x00000001
+#define HOSTAPD_CHAN_PASSIVE_SCAN 0x00000002
+#define HOSTAPD_CHAN_NO_IBSS 0x00000004
+#define HOSTAPD_CHAN_RADAR 0x00000008
+#define HOSTAPD_CHAN_HT40PLUS 0x00000010
+#define HOSTAPD_CHAN_HT40MINUS 0x00000020
+#define HOSTAPD_CHAN_HT40 0x00000040
+
+/**
+ * struct hostapd_channel_data - Channel information
+ */
+struct hostapd_channel_data {
+	/**
+	 * chan - Channel number (IEEE 802.11)
+	 */
+	short chan;
+
+	/**
+	 * freq - Frequency in MHz
+	 */
+	int freq;
+
+	/**
+	 * flag - Channel flags (HOSTAPD_CHAN_*)
+	 */
+	int flag;
+
+	/**
+	 * max_tx_power - maximum transmit power in dBm
+	 */
+	u8 max_tx_power;
+};
+
+#define HOSTAPD_MODE_FLAG_HT_INFO_KNOWN BIT(0)
+
+/**
+ * struct hostapd_hw_modes - Supported hardware mode information
+ */
+struct hostapd_hw_modes {
+	/**
+	 * mode - Hardware mode
+	 */
+	enum hostapd_hw_mode mode;
+
+	/**
+	 * num_channels - Number of entries in the channels array
+	 */
+	int num_channels;
+
+	/**
+	 * channels - Array of supported channels
+	 */
+	struct hostapd_channel_data *channels;
+
+	/**
+	 * num_rates - Number of entries in the rates array
+	 */
+	int num_rates;
+
+	/**
+	 * rates - Array of supported rates in 100 kbps units
+	 */
+	int *rates;
+
+	/**
+	 * ht_capab - HT (IEEE 802.11n) capabilities
+	 */
+	u16 ht_capab;
+
+	/**
+	 * mcs_set - MCS (IEEE 802.11n) rate parameters
+	 */
+	u8 mcs_set[16];
+
+	/**
+	 * a_mpdu_params - A-MPDU (IEEE 802.11n) parameters
+	 */
+	u8 a_mpdu_params;
+
+	/**
+	 * vht_capab - VHT (IEEE 802.11ac) capabilities
+	 */
+	u32 vht_capab;
+
+	/**
+	 * vht_mcs_set - VHT MCS (IEEE 802.11ac) rate parameters
+	 */
+	u8 vht_mcs_set[8];
+
+	unsigned int flags; /* HOSTAPD_MODE_FLAG_* */
+};
+
+
+#define IEEE80211_MODE_INFRA	0
+#define IEEE80211_MODE_IBSS	1
+#define IEEE80211_MODE_AP	2
+
+#define IEEE80211_CAP_ESS	0x0001
+#define IEEE80211_CAP_IBSS	0x0002
+#define IEEE80211_CAP_PRIVACY	0x0010
+
+#define WPA_SCAN_QUAL_INVALID		BIT(0)
+#define WPA_SCAN_NOISE_INVALID		BIT(1)
+#define WPA_SCAN_LEVEL_INVALID		BIT(2)
+#define WPA_SCAN_LEVEL_DBM		BIT(3)
+#define WPA_SCAN_AUTHENTICATED		BIT(4)
+#define WPA_SCAN_ASSOCIATED		BIT(5)
+
+/**
+ * struct wpa_scan_res - Scan result for an BSS/IBSS
+ * @flags: information flags about the BSS/IBSS (WPA_SCAN_*)
+ * @bssid: BSSID
+ * @freq: frequency of the channel in MHz (e.g., 2412 = channel 1)
+ * @beacon_int: beacon interval in TUs (host byte order)
+ * @caps: capability information field in host byte order
+ * @qual: signal quality
+ * @noise: noise level
+ * @level: signal level
+ * @tsf: Timestamp
+ * @age: Age of the information in milliseconds (i.e., how many milliseconds
+ * ago the last Beacon or Probe Response frame was received)
+ * @ie_len: length of the following IE field in octets
+ * @beacon_ie_len: length of the following Beacon IE field in octets
+ *
+ * This structure is used as a generic format for scan results from the
+ * driver. Each driver interface implementation is responsible for converting
+ * the driver or OS specific scan results into this format.
+ *
+ * If the driver does not support reporting all IEs, the IE data structure is
+ * constructed of the IEs that are available. This field will also need to
+ * include SSID in IE format. All drivers are encouraged to be extended to
+ * report all IEs to make it easier to support future additions.
+ */
+struct wpa_scan_res {
+	unsigned int flags;
+	u8 bssid[ETH_ALEN];
+	int freq;
+	u16 beacon_int;
+	u16 caps;
+	int qual;
+	int noise;
+	int level;
+	u64 tsf;
+	unsigned int age;
+	size_t ie_len;
+	size_t beacon_ie_len;
+	/*
+	 * Followed by ie_len octets of IEs from Probe Response frame (or if
+	 * the driver does not indicate source of IEs, these may also be from
+	 * Beacon frame). After the first set of IEs, another set of IEs may
+	 * follow (with beacon_ie_len octets of data) if the driver provides
+	 * both IE sets.
+	 */
+};
+
+/**
+ * struct wpa_scan_results - Scan results
+ * @res: Array of pointers to allocated variable length scan result entries
+ * @num: Number of entries in the scan result array
+ */
+struct wpa_scan_results {
+	struct wpa_scan_res **res;
+	size_t num;
+};
+
+/**
+ * struct wpa_interface_info - Network interface information
+ * @next: Pointer to the next interface or NULL if this is the last one
+ * @ifname: Interface name that can be used with init() or init2()
+ * @desc: Human readable adapter description (e.g., vendor/model) or NULL if
+ *	not available
+ * @drv_name: struct wpa_driver_ops::name (note: unlike other strings, this one
+ *	is not an allocated copy, i.e., get_interfaces() caller will not free
+ *	this)
+ */
+struct wpa_interface_info {
+	struct wpa_interface_info *next;
+	char *ifname;
+	char *desc;
+	const char *drv_name;
+};
+
+#define WPAS_MAX_SCAN_SSIDS 16
+
+/**
+ * struct wpa_driver_scan_params - Scan parameters
+ * Data for struct wpa_driver_ops::scan2().
+ */
+struct wpa_driver_scan_params {
+	/**
+	 * ssids - SSIDs to scan for
+	 */
+	struct wpa_driver_scan_ssid {
+		/**
+		 * ssid - specific SSID to scan for (ProbeReq)
+		 * %NULL or zero-length SSID is used to indicate active scan
+		 * with wildcard SSID.
+		 */
+		const u8 *ssid;
+		/**
+		 * ssid_len: Length of the SSID in octets
+		 */
+		size_t ssid_len;
+	} ssids[WPAS_MAX_SCAN_SSIDS];
+
+	/**
+	 * num_ssids - Number of entries in ssids array
+	 * Zero indicates a request for a passive scan.
+	 */
+	size_t num_ssids;
+
+	/**
+	 * extra_ies - Extra IE(s) to add into Probe Request or %NULL
+	 */
+	const u8 *extra_ies;
+
+	/**
+	 * extra_ies_len - Length of extra_ies in octets
+	 */
+	size_t extra_ies_len;
+
+	/**
+	 * freqs - Array of frequencies to scan or %NULL for all frequencies
+	 *
+	 * The frequency is set in MHz. The array is zero-terminated.
+	 */
+	int *freqs;
+
+	/**
+	 * filter_ssids - Filter for reporting SSIDs
+	 *
+	 * This optional parameter can be used to request the driver wrapper to
+	 * filter scan results to include only the specified SSIDs. %NULL
+	 * indicates that no filtering is to be done. This can be used to
+	 * reduce memory needs for scan results in environments that have large
+	 * number of APs with different SSIDs.
+	 *
+	 * The driver wrapper is allowed to take this allocated buffer into its
+	 * own use by setting the pointer to %NULL. In that case, the driver
+	 * wrapper is responsible for freeing the buffer with os_free() once it
+	 * is not needed anymore.
+	 */
+	struct wpa_driver_scan_filter {
+		u8 ssid[32];
+		size_t ssid_len;
+	} *filter_ssids;
+
+	/**
+	 * num_filter_ssids - Number of entries in filter_ssids array
+	 */
+	size_t num_filter_ssids;
+
+	/**
+	 * filter_rssi - Filter by RSSI
+	 *
+	 * The driver may filter scan results in firmware to reduce host
+	 * wakeups and thereby save power. Specify the RSSI threshold in s32
+	 * dBm.
+	 */
+	s32 filter_rssi;
+
+	/**
+	 * p2p_probe - Used to disable CCK (802.11b) rates for P2P probes
+	 *
+	 * When set, the driver is expected to remove rates 1, 2, 5.5, and 11
+	 * Mbps from the support rates element(s) in the Probe Request frames
+	 * and not to transmit the frames at any of those rates.
+	 */
+	u8 p2p_probe;
+};
+
+/**
+ * struct wpa_driver_auth_params - Authentication parameters
+ * Data for struct wpa_driver_ops::authenticate().
+ */
+struct wpa_driver_auth_params {
+	int freq;
+	const u8 *bssid;
+	const u8 *ssid;
+	size_t ssid_len;
+	int auth_alg;
+	const u8 *ie;
+	size_t ie_len;
+	const u8 *wep_key[4];
+	size_t wep_key_len[4];
+	int wep_tx_keyidx;
+	int local_state_change;
+
+	/**
+	 * p2p - Whether this connection is a P2P group
+	 */
+	int p2p;
+
+	const u8 *sae_data;
+	size_t sae_data_len;
+
+};
+
+enum wps_mode {
+	WPS_MODE_NONE /* no WPS provisioning being used */,
+	WPS_MODE_OPEN /* WPS provisioning with AP that is in open mode */,
+	WPS_MODE_PRIVACY /* WPS provisioning with AP that is using protection
+			  */
+};
+
+/**
+ * struct wpa_driver_associate_params - Association parameters
+ * Data for struct wpa_driver_ops::associate().
+ */
+struct wpa_driver_associate_params {
+	/**
+	 * bssid - BSSID of the selected AP
+	 * This can be %NULL, if ap_scan=2 mode is used and the driver is
+	 * responsible for selecting with which BSS to associate. */
+	const u8 *bssid;
+
+	/**
+	 * ssid - The selected SSID
+	 */
+	const u8 *ssid;
+
+	/**
+	 * ssid_len - Length of the SSID (1..32)
+	 */
+	size_t ssid_len;
+
+	/**
+	 * freq - Frequency of the channel the selected AP is using
+	 * Frequency that the selected AP is using (in MHz as
+	 * reported in the scan results)
+	 */
+	int freq;
+
+	/**
+	 * bg_scan_period - Background scan period in seconds, 0 to disable
+	 * background scan, or -1 to indicate no change to default driver
+	 * configuration
+	 */
+	int bg_scan_period;
+
+	/**
+	 * wpa_ie - WPA information element for (Re)Association Request
+	 * WPA information element to be included in (Re)Association
+	 * Request (including information element id and length). Use
+	 * of this WPA IE is optional. If the driver generates the WPA
+	 * IE, it can use pairwise_suite, group_suite, and
+	 * key_mgmt_suite to select proper algorithms. In this case,
+	 * the driver has to notify wpa_supplicant about the used WPA
+	 * IE by generating an event that the interface code will
+	 * convert into EVENT_ASSOCINFO data (see below).
+	 *
+	 * When using WPA2/IEEE 802.11i, wpa_ie is used for RSN IE
+	 * instead. The driver can determine which version is used by
+	 * looking at the first byte of the IE (0xdd for WPA, 0x30 for
+	 * WPA2/RSN).
+	 *
+	 * When using WPS, wpa_ie is used for WPS IE instead of WPA/RSN IE.
+	 */
+	const u8 *wpa_ie;
+
+	/**
+	 * wpa_ie_len - length of the wpa_ie
+	 */
+	size_t wpa_ie_len;
+
+	/**
+	 * wpa_proto - Bitfield of WPA_PROTO_* values to indicate WPA/WPA2
+	 */
+	unsigned int wpa_proto;
+
+	/**
+	 * pairwise_suite - Selected pairwise cipher suite
+	 *
+	 * This is usually ignored if @wpa_ie is used.
+	 */
+	enum wpa_cipher pairwise_suite;
+
+	/**
+	 * group_suite - Selected group cipher suite
+	 *
+	 * This is usually ignored if @wpa_ie is used.
+	 */
+	enum wpa_cipher group_suite;
+
+	/**
+	 * key_mgmt_suite - Selected key management suite
+	 *
+	 * This is usually ignored if @wpa_ie is used.
+	 */
+	enum wpa_key_mgmt key_mgmt_suite;
+
+	/**
+	 * auth_alg - Allowed authentication algorithms
+	 * Bit field of WPA_AUTH_ALG_*
+	 */
+	int auth_alg;
+
+	/**
+	 * mode - Operation mode (infra/ibss) IEEE80211_MODE_*
+	 */
+	int mode;
+
+	/**
+	 * wep_key - WEP keys for static WEP configuration
+	 */
+	const u8 *wep_key[4];
+
+	/**
+	 * wep_key_len - WEP key length for static WEP configuration
+	 */
+	size_t wep_key_len[4];
+
+	/**
+	 * wep_tx_keyidx - WEP TX key index for static WEP configuration
+	 */
+	int wep_tx_keyidx;
+
+	/**
+	 * mgmt_frame_protection - IEEE 802.11w management frame protection
+	 */
+	enum mfp_options mgmt_frame_protection;
+
+	/**
+	 * ft_ies - IEEE 802.11r / FT information elements
+	 * If the supplicant is using IEEE 802.11r (FT) and has the needed keys
+	 * for fast transition, this parameter is set to include the IEs that
+	 * are to be sent in the next FT Authentication Request message.
+	 * update_ft_ies() handler is called to update the IEs for further
+	 * FT messages in the sequence.
+	 *
+	 * The driver should use these IEs only if the target AP is advertising
+	 * the same mobility domain as the one included in the MDIE here.
+	 *
+	 * In ap_scan=2 mode, the driver can use these IEs when moving to a new
+	 * AP after the initial association. These IEs can only be used if the
+	 * target AP is advertising support for FT and is using the same MDIE
+	 * and SSID as the current AP.
+	 *
+	 * The driver is responsible for reporting the FT IEs received from the
+	 * AP's response using wpa_supplicant_event() with EVENT_FT_RESPONSE
+	 * type. update_ft_ies() handler will then be called with the FT IEs to
+	 * include in the next frame in the authentication sequence.
+	 */
+	const u8 *ft_ies;
+
+	/**
+	 * ft_ies_len - Length of ft_ies in bytes
+	 */
+	size_t ft_ies_len;
+
+	/**
+	 * ft_md - FT Mobility domain (6 octets) (also included inside ft_ies)
+	 *
+	 * This value is provided to allow the driver interface easier access
+	 * to the current mobility domain. This value is set to %NULL if no
+	 * mobility domain is currently active.
+	 */
+	const u8 *ft_md;
+
+	/**
+	 * passphrase - RSN passphrase for PSK
+	 *
+	 * This value is made available only for WPA/WPA2-Personal (PSK) and
+	 * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is
+	 * the 8..63 character ASCII passphrase, if available. Please note that
+	 * this can be %NULL if passphrase was not used to generate the PSK. In
+	 * that case, the psk field must be used to fetch the PSK.
+	 */
+	const char *passphrase;
+
+	/**
+	 * psk - RSN PSK (alternative for passphrase for PSK)
+	 *
+	 * This value is made available only for WPA/WPA2-Personal (PSK) and
+	 * only for drivers that set WPA_DRIVER_FLAGS_4WAY_HANDSHAKE. This is
+	 * the 32-octet (256-bit) PSK, if available. The driver wrapper should
+	 * be prepared to handle %NULL value as an error.
+	 */
+	const u8 *psk;
+
+	/**
+	 * drop_unencrypted - Enable/disable unencrypted frame filtering
+	 *
+	 * Configure the driver to drop all non-EAPOL frames (both receive and
+	 * transmit paths). Unencrypted EAPOL frames (ethertype 0x888e) must
+	 * still be allowed for key negotiation.
+	 */
+	int drop_unencrypted;
+
+	/**
+	 * prev_bssid - Previously used BSSID in this ESS
+	 *
+	 * When not %NULL, this is a request to use reassociation instead of
+	 * association.
+	 */
+	const u8 *prev_bssid;
+
+	/**
+	 * wps - WPS mode
+	 *
+	 * If the driver needs to do special configuration for WPS association,
+	 * this variable provides more information on what type of association
+	 * is being requested. Most drivers should not need ot use this.
+	 */
+	enum wps_mode wps;
+
+	/**
+	 * p2p - Whether this connection is a P2P group
+	 */
+	int p2p;
+
+	/**
+	 * uapsd - UAPSD parameters for the network
+	 * -1 = do not change defaults
+	 * AP mode: 1 = enabled, 0 = disabled
+	 * STA mode: bits 0..3 UAPSD enabled for VO,VI,BK,BE
+	 */
+	int uapsd;
+
+	/**
+	 * fixed_bssid - Whether to force this BSSID in IBSS mode
+	 * 1 = Fix this BSSID and prevent merges.
+	 * 0 = Do not fix BSSID.
+	 */
+	int fixed_bssid;
+
+	/**
+	 * disable_ht - Disable HT (IEEE 802.11n) for this connection
+	 */
+	int disable_ht;
+
+	/**
+	 * HT Capabilities over-rides. Only bits set in the mask will be used,
+	 * and not all values are used by the kernel anyway. Currently, MCS,
+	 * MPDU and MSDU fields are used.
+	 */
+	const u8 *htcaps;       /* struct ieee80211_ht_capabilities * */
+	const u8 *htcaps_mask;  /* struct ieee80211_ht_capabilities * */
+};
+
+enum hide_ssid {
+	NO_SSID_HIDING,
+	HIDDEN_SSID_ZERO_LEN,
+	HIDDEN_SSID_ZERO_CONTENTS
+};
+
+struct wpa_driver_ap_params {
+	/**
+	 * head - Beacon head from IEEE 802.11 header to IEs before TIM IE
+	 */
+	const u8 *head;
+
+	/**
+	 * head_len - Length of the head buffer in octets
+	 */
+	size_t head_len;
+
+	/**
+	 * tail - Beacon tail following TIM IE
+	 */
+	const u8 *tail;
+
+	/**
+	 * tail_len - Length of the tail buffer in octets
+	 */
+	size_t tail_len;
+
+	/**
+	 * dtim_period - DTIM period
+	 */
+	int dtim_period;
+
+	/**
+	 * beacon_int - Beacon interval
+	 */
+	int beacon_int;
+
+	/**
+	 * basic_rates: -1 terminated array of basic rates in 100 kbps
+	 *
+	 * This parameter can be used to set a specific basic rate set for the
+	 * BSS. If %NULL, default basic rate set is used.
+	 */
+	int *basic_rates;
+
+	/**
+	 * proberesp - Probe Response template
+	 *
+	 * This is used by drivers that reply to Probe Requests internally in
+	 * AP mode and require the full Probe Response template.
+	 */
+	const u8 *proberesp;
+
+	/**
+	 * proberesp_len - Length of the proberesp buffer in octets
+	 */
+	size_t proberesp_len;
+
+	/**
+	 * ssid - The SSID to use in Beacon/Probe Response frames
+	 */
+	const u8 *ssid;
+
+	/**
+	 * ssid_len - Length of the SSID (1..32)
+	 */
+	size_t ssid_len;
+
+	/**
+	 * hide_ssid - Whether to hide the SSID
+	 */
+	enum hide_ssid hide_ssid;
+
+	/**
+	 * pairwise_ciphers - WPA_CIPHER_* bitfield
+	 */
+	unsigned int pairwise_ciphers;
+
+	/**
+	 * group_cipher - WPA_CIPHER_*
+	 */
+	unsigned int group_cipher;
+
+	/**
+	 * key_mgmt_suites - WPA_KEY_MGMT_* bitfield
+	 */
+	unsigned int key_mgmt_suites;
+
+	/**
+	 * auth_algs - WPA_AUTH_ALG_* bitfield
+	 */
+	unsigned int auth_algs;
+
+	/**
+	 * wpa_version - WPA_PROTO_* bitfield
+	 */
+	unsigned int wpa_version;
+
+	/**
+	 * privacy - Whether privacy is used in the BSS
+	 */
+	int privacy;
+
+	/**
+	 * beacon_ies - WPS/P2P IE(s) for Beacon frames
+	 *
+	 * This is used to add IEs like WPS IE and P2P IE by drivers that do
+	 * not use the full Beacon template.
+	 */
+	const struct wpabuf *beacon_ies;
+
+	/**
+	 * proberesp_ies - P2P/WPS IE(s) for Probe Response frames
+	 *
+	 * This is used to add IEs like WPS IE and P2P IE by drivers that
+	 * reply to Probe Request frames internally.
+	 */
+	const struct wpabuf *proberesp_ies;
+
+	/**
+	 * assocresp_ies - WPS IE(s) for (Re)Association Response frames
+	 *
+	 * This is used to add IEs like WPS IE by drivers that reply to
+	 * (Re)Association Request frames internally.
+	 */
+	const struct wpabuf *assocresp_ies;
+
+	/**
+	 * isolate - Whether to isolate frames between associated stations
+	 *
+	 * If this is non-zero, the AP is requested to disable forwarding of
+	 * frames between associated stations.
+	 */
+	int isolate;
+
+	/**
+	 * cts_protect - Whether CTS protection is enabled
+	 */
+	int cts_protect;
+
+	/**
+	 * preamble - Whether short preamble is enabled
+	 */
+	int preamble;
+
+	/**
+	 * short_slot_time - Whether short slot time is enabled
+	 *
+	 * 0 = short slot time disable, 1 = short slot time enabled, -1 = do
+	 * not set (e.g., when 802.11g mode is not in use)
+	 */
+	int short_slot_time;
+
+	/**
+	 * ht_opmode - HT operation mode or -1 if HT not in use
+	 */
+	int ht_opmode;
+
+	/**
+	 * interworking - Whether Interworking is enabled
+	 */
+	int interworking;
+
+	/**
+	 * hessid - Homogeneous ESS identifier or %NULL if not set
+	 */
+	const u8 *hessid;
+
+	/**
+	 * access_network_type - Access Network Type (0..15)
+	 *
+	 * This is used for filtering Probe Request frames when Interworking is
+	 * enabled.
+	 */
+	u8 access_network_type;
+
+	/**
+	 * ap_max_inactivity - Timeout in seconds to detect STA's inactivity
+	 *
+	 * This is used by driver which advertises this capability.
+	 */
+	int ap_max_inactivity;
+
+	/**
+	 * disable_dgaf - Whether group-addressed frames are disabled
+	 */
+	int disable_dgaf;
+};
+
+/**
+ * struct wpa_driver_capa - Driver capability information
+ */
+struct wpa_driver_capa {
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA		0x00000001
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2		0x00000002
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA_PSK	0x00000004
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA2_PSK	0x00000008
+#define WPA_DRIVER_CAPA_KEY_MGMT_WPA_NONE	0x00000010
+#define WPA_DRIVER_CAPA_KEY_MGMT_FT		0x00000020
+#define WPA_DRIVER_CAPA_KEY_MGMT_FT_PSK		0x00000040
+#define WPA_DRIVER_CAPA_KEY_MGMT_WAPI_PSK	0x00000080
+	unsigned int key_mgmt;
+
+#define WPA_DRIVER_CAPA_ENC_WEP40	0x00000001
+#define WPA_DRIVER_CAPA_ENC_WEP104	0x00000002
+#define WPA_DRIVER_CAPA_ENC_TKIP	0x00000004
+#define WPA_DRIVER_CAPA_ENC_CCMP	0x00000008
+#define WPA_DRIVER_CAPA_ENC_WEP128	0x00000010
+#define WPA_DRIVER_CAPA_ENC_GCMP	0x00000020
+	unsigned int enc;
+
+#define WPA_DRIVER_AUTH_OPEN		0x00000001
+#define WPA_DRIVER_AUTH_SHARED		0x00000002
+#define WPA_DRIVER_AUTH_LEAP		0x00000004
+	unsigned int auth;
+
+/* Driver generated WPA/RSN IE */
+#define WPA_DRIVER_FLAGS_DRIVER_IE	0x00000001
+/* Driver needs static WEP key setup after association command */
+#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC 0x00000002
+/* unused: 0x00000004 */
+/* Driver takes care of RSN 4-way handshake internally; PMK is configured with
+ * struct wpa_driver_ops::set_key using alg = WPA_ALG_PMK */
+#define WPA_DRIVER_FLAGS_4WAY_HANDSHAKE 0x00000008
+#define WPA_DRIVER_FLAGS_WIRED		0x00000010
+/* Driver provides separate commands for authentication and association (SME in
+ * wpa_supplicant). */
+#define WPA_DRIVER_FLAGS_SME		0x00000020
+/* Driver supports AP mode */
+#define WPA_DRIVER_FLAGS_AP		0x00000040
+/* Driver needs static WEP key setup after association has been completed */
+#define WPA_DRIVER_FLAGS_SET_KEYS_AFTER_ASSOC_DONE	0x00000080
+/* Driver takes care of P2P management operations */
+#define WPA_DRIVER_FLAGS_P2P_MGMT	0x00000100
+/* Driver supports concurrent P2P operations */
+#define WPA_DRIVER_FLAGS_P2P_CONCURRENT	0x00000200
+/*
+ * Driver uses the initial interface as a dedicated management interface, i.e.,
+ * it cannot be used for P2P group operations or non-P2P purposes.
+ */
+#define WPA_DRIVER_FLAGS_P2P_DEDICATED_INTERFACE	0x00000400
+/* This interface is P2P capable (P2P Device, GO, or P2P Client */
+#define WPA_DRIVER_FLAGS_P2P_CAPABLE	0x00000800
+/* Driver supports concurrent operations on multiple channels */
+#define WPA_DRIVER_FLAGS_MULTI_CHANNEL_CONCURRENT	0x00001000
+/*
+ * Driver uses the initial interface for P2P management interface and non-P2P
+ * purposes (e.g., connect to infra AP), but this interface cannot be used for
+ * P2P group operations.
+ */
+#define WPA_DRIVER_FLAGS_P2P_MGMT_AND_NON_P2P		0x00002000
+/*
+ * Driver is known to use sane error codes, i.e., when it indicates that
+ * something (e.g., association) fails, there was indeed a failure and the
+ * operation does not end up getting completed successfully later.
+ */
+#define WPA_DRIVER_FLAGS_SANE_ERROR_CODES		0x00004000
+/* Driver supports off-channel TX */
+#define WPA_DRIVER_FLAGS_OFFCHANNEL_TX			0x00008000
+/* Driver indicates TX status events for EAPOL Data frames */
+#define WPA_DRIVER_FLAGS_EAPOL_TX_STATUS		0x00010000
+/* Driver indicates TX status events for Deauth/Disassoc frames */
+#define WPA_DRIVER_FLAGS_DEAUTH_TX_STATUS		0x00020000
+/* Driver supports roaming (BSS selection) in firmware */
+#define WPA_DRIVER_FLAGS_BSS_SELECTION			0x00040000
+/* Driver supports operating as a TDLS peer */
+#define WPA_DRIVER_FLAGS_TDLS_SUPPORT			0x00080000
+/* Driver requires external TDLS setup/teardown/discovery */
+#define WPA_DRIVER_FLAGS_TDLS_EXTERNAL_SETUP		0x00100000
+/* Driver indicates support for Probe Response offloading in AP mode */
+#define WPA_DRIVER_FLAGS_PROBE_RESP_OFFLOAD		0x00200000
+/* Driver supports U-APSD in AP mode */
+#define WPA_DRIVER_FLAGS_AP_UAPSD			0x00400000
+/* Driver supports inactivity timer in AP mode */
+#define WPA_DRIVER_FLAGS_INACTIVITY_TIMER		0x00800000
+/* Driver expects user space implementation of MLME in AP mode */
+#define WPA_DRIVER_FLAGS_AP_MLME			0x01000000
+/* Driver supports SAE with user space SME */
+#define WPA_DRIVER_FLAGS_SAE				0x02000000
+/* Driver makes use of OBSS scan mechanism in wpa_supplicant */
+#define WPA_DRIVER_FLAGS_OBSS_SCAN			0x04000000
+	unsigned int flags;
+
+	int max_scan_ssids;
+	int max_sched_scan_ssids;
+	int sched_scan_supported;
+	int max_match_sets;
+
+	/**
+	 * max_remain_on_chan - Maximum remain-on-channel duration in msec
+	 */
+	unsigned int max_remain_on_chan;
+
+	/**
+	 * max_stations - Maximum number of associated stations the driver
+	 * supports in AP mode
+	 */
+	unsigned int max_stations;
+
+	/**
+	 * probe_resp_offloads - Bitmap of supported protocols by the driver
+	 * for Probe Response offloading.
+	 */
+/* Driver Probe Response offloading support for WPS ver. 1 */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS		0x00000001
+/* Driver Probe Response offloading support for WPS ver. 2 */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_WPS2		0x00000002
+/* Driver Probe Response offloading support for P2P */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_P2P		0x00000004
+/* Driver Probe Response offloading support for IEEE 802.11u (Interworking) */
+#define WPA_DRIVER_PROBE_RESP_OFFLOAD_INTERWORKING	0x00000008
+	unsigned int probe_resp_offloads;
+};
+
+
+struct hostapd_data;
+
+struct hostap_sta_driver_data {
+	unsigned long rx_packets, tx_packets, rx_bytes, tx_bytes;
+	unsigned long current_tx_rate;
+	unsigned long inactive_msec;
+	unsigned long flags;
+	unsigned long num_ps_buf_frames;
+	unsigned long tx_retry_failed;
+	unsigned long tx_retry_count;
+	int last_rssi;
+	int last_ack_rssi;
+};
+
+struct hostapd_sta_add_params {
+	const u8 *addr;
+	u16 aid;
+	u16 capability;
+	const u8 *supp_rates;
+	size_t supp_rates_len;
+	u16 listen_interval;
+	const struct ieee80211_ht_capabilities *ht_capabilities;
+	u32 flags; /* bitmask of WPA_STA_* flags */
+	int set; /* Set STA parameters instead of add */
+	u8 qosinfo;
+};
+
+struct hostapd_freq_params {
+	int mode;
+	int freq;
+	int channel;
+	int ht_enabled;
+	int sec_channel_offset; /* 0 = HT40 disabled, -1 = HT40 enabled,
+				 * secondary channel below primary, 1 = HT40
+				 * enabled, secondary channel above primary */
+};
+
+struct hostapd_channel_switch {
+	int freq;
+	int tx_block;			/* immediately block the tx on the
+					 * operational channel
+					 * (prior channel switch) */
+	int post_switch_block_tx;	/* block tx on the target ch (after
+					 * channel switch) */
+	int ch_switch_count;
+};
+
+enum wpa_driver_if_type {
+	/**
+	 * WPA_IF_STATION - Station mode interface
+	 */
+	WPA_IF_STATION,
+
+	/**
+	 * WPA_IF_AP_VLAN - AP mode VLAN interface
+	 *
+	 * This interface shares its address and Beacon frame with the main
+	 * BSS.
+	 */
+	WPA_IF_AP_VLAN,
+
+	/**
+	 * WPA_IF_AP_BSS - AP mode BSS interface
+	 *
+	 * This interface has its own address and Beacon frame.
+	 */
+	WPA_IF_AP_BSS,
+
+	/**
+	 * WPA_IF_P2P_GO - P2P Group Owner
+	 */
+	WPA_IF_P2P_GO,
+
+	/**
+	 * WPA_IF_P2P_CLIENT - P2P Client
+	 */
+	WPA_IF_P2P_CLIENT,
+
+	/**
+	 * WPA_IF_P2P_GROUP - P2P Group interface (will become either
+	 * WPA_IF_P2P_GO or WPA_IF_P2P_CLIENT, but the role is not yet known)
+	 */
+	WPA_IF_P2P_GROUP
+};
+
+struct wpa_init_params {
+	void *global_priv;
+	const u8 *bssid;
+	const char *ifname;
+	const u8 *ssid;
+	size_t ssid_len;
+	const char *test_socket;
+	int use_pae_group_addr;
+	char **bridge;
+	size_t num_bridge;
+
+	u8 *own_addr; /* buffer for writing own MAC address */
+};
+
+
+struct wpa_bss_params {
+	/** Interface name (for multi-SSID/VLAN support) */
+	const char *ifname;
+	/** Whether IEEE 802.1X or WPA/WPA2 is enabled */
+	int enabled;
+
+	int wpa;
+	int ieee802_1x;
+	int wpa_group;
+	int wpa_pairwise;
+	int wpa_key_mgmt;
+	int rsn_preauth;
+	enum mfp_options ieee80211w;
+};
+
+#define WPA_STA_AUTHORIZED BIT(0)
+#define WPA_STA_WMM BIT(1)
+#define WPA_STA_SHORT_PREAMBLE BIT(2)
+#define WPA_STA_MFP BIT(3)
+#define WPA_STA_TDLS_PEER BIT(4)
+
+/**
+ * struct p2p_params - P2P parameters for driver-based P2P management
+ */
+struct p2p_params {
+	const char *dev_name;
+	u8 pri_dev_type[8];
+#define DRV_MAX_SEC_DEV_TYPES 5
+	u8 sec_dev_type[DRV_MAX_SEC_DEV_TYPES][8];
+	size_t num_sec_dev_types;
+};
+
+enum tdls_oper {
+	TDLS_DISCOVERY_REQ,
+	TDLS_SETUP,
+	TDLS_TEARDOWN,
+	TDLS_ENABLE_LINK,
+	TDLS_DISABLE_LINK,
+	TDLS_ENABLE,
+	TDLS_DISABLE
+};
+
+enum wnm_oper {
+	WNM_SLEEP_ENTER_CONFIRM,
+	WNM_SLEEP_ENTER_FAIL,
+	WNM_SLEEP_EXIT_CONFIRM,
+	WNM_SLEEP_EXIT_FAIL,
+	WNM_SLEEP_TFS_REQ_IE_ADD,   /* STA requests driver to add TFS req IE */
+	WNM_SLEEP_TFS_REQ_IE_NONE,  /* STA requests empty TFS req IE */
+	WNM_SLEEP_TFS_REQ_IE_SET,   /* AP requests driver to set TFS req IE for
+				     * a STA */
+	WNM_SLEEP_TFS_RESP_IE_ADD,  /* AP requests driver to add TFS resp IE
+				     * for a STA */
+	WNM_SLEEP_TFS_RESP_IE_NONE, /* AP requests empty TFS resp IE */
+	WNM_SLEEP_TFS_RESP_IE_SET,  /* AP requests driver to set TFS resp IE
+				     * for a STA */
+	WNM_SLEEP_TFS_IE_DEL        /* AP delete the TFS IE */
+};
+
+/**
+ * struct wpa_signal_info - Information about channel signal quality
+ */
+struct wpa_signal_info {
+	u32 frequency;
+	int above_threshold;
+	int current_signal;
+	int current_noise;
+	int current_txrate;
+};
+
+/**
+ * struct wpa_driver_ops - Driver interface API definition
+ *
+ * This structure defines the API that each driver interface needs to implement
+ * for core wpa_supplicant code. All driver specific functionality is captured
+ * in this wrapper.
+ */
+struct wpa_driver_ops {
+	/** Name of the driver interface */
+	const char *name;
+	/** One line description of the driver interface */
+	const char *desc;
+
+	/**
+	 * get_bssid - Get the current BSSID
+	 * @priv: private driver interface data
+	 * @bssid: buffer for BSSID (ETH_ALEN = 6 bytes)
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Query kernel driver for the current BSSID and copy it to bssid.
+	 * Setting bssid to 00:00:00:00:00:00 is recommended if the STA is not
+	 * associated.
+	 */
+	int (*get_bssid)(void *priv, u8 *bssid);
+
+	/**
+	 * get_ssid - Get the current SSID
+	 * @priv: private driver interface data
+	 * @ssid: buffer for SSID (at least 32 bytes)
+	 *
+	 * Returns: Length of the SSID on success, -1 on failure
+	 *
+	 * Query kernel driver for the current SSID and copy it to ssid.
+	 * Returning zero is recommended if the STA is not associated.
+	 *
+	 * Note: SSID is an array of octets, i.e., it is not nul terminated and
+	 * can, at least in theory, contain control characters (including nul)
+	 * and as such, should be processed as binary data, not a printable
+	 * string.
+	 */
+	int (*get_ssid)(void *priv, u8 *ssid);
+
+	/**
+	 * set_key - Configure encryption key
+	 * @ifname: Interface name (for multi-SSID/VLAN support)
+	 * @priv: private driver interface data
+	 * @alg: encryption algorithm (%WPA_ALG_NONE, %WPA_ALG_WEP,
+	 *	%WPA_ALG_TKIP, %WPA_ALG_CCMP, %WPA_ALG_IGTK, %WPA_ALG_PMK,
+	 *	%WPA_ALG_GCMP);
+	 *	%WPA_ALG_NONE clears the key.
+	 * @addr: Address of the peer STA (BSSID of the current AP when setting
+	 *	pairwise key in station mode), ff:ff:ff:ff:ff:ff for
+	 *	broadcast keys, %NULL for default keys that are used both for
+	 *	broadcast and unicast; when clearing keys, %NULL is used to
+	 *	indicate that both the broadcast-only and default key of the
+	 *	specified key index is to be cleared
+	 * @key_idx: key index (0..3), usually 0 for unicast keys; 0..4095 for
+	 *	IGTK
+	 * @set_tx: configure this key as the default Tx key (only used when
+	 *	driver does not support separate unicast/individual key
+	 * @seq: sequence number/packet number, seq_len octets, the next
+	 *	packet number to be used for in replay protection; configured
+	 *	for Rx keys (in most cases, this is only used with broadcast
+	 *	keys and set to zero for unicast keys); %NULL if not set
+	 * @seq_len: length of the seq, depends on the algorithm:
+	 *	TKIP: 6 octets, CCMP/GCMP: 6 octets, IGTK: 6 octets
+	 * @key: key buffer; TKIP: 16-byte temporal key, 8-byte Tx Mic key,
+	 *	8-byte Rx Mic Key
+	 * @key_len: length of the key buffer in octets (WEP: 5 or 13,
+	 *	TKIP: 32, CCMP/GCMP: 16, IGTK: 16)
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Configure the given key for the kernel driver. If the driver
+	 * supports separate individual keys (4 default keys + 1 individual),
+	 * addr can be used to determine whether the key is default or
+	 * individual. If only 4 keys are supported, the default key with key
+	 * index 0 is used as the individual key. STA must be configured to use
+	 * it as the default Tx key (set_tx is set) and accept Rx for all the
+	 * key indexes. In most cases, WPA uses only key indexes 1 and 2 for
+	 * broadcast keys, so key index 0 is available for this kind of
+	 * configuration.
+	 *
+	 * Please note that TKIP keys include separate TX and RX MIC keys and
+	 * some drivers may expect them in different order than wpa_supplicant
+	 * is using. If the TX/RX keys are swapped, all TKIP encrypted packets
+	 * will trigger Michael MIC errors. This can be fixed by changing the
+	 * order of MIC keys by swapping te bytes 16..23 and 24..31 of the key
+	 * in driver_*.c set_key() implementation, see driver_ndis.c for an
+	 * example on how this can be done.
+	 */
+	int (*set_key)(const char *ifname, void *priv, enum wpa_alg alg,
+		       const u8 *addr, int key_idx, int set_tx,
+		       const u8 *seq, size_t seq_len,
+		       const u8 *key, size_t key_len);
+
+	/**
+	 * init - Initialize driver interface
+	 * @ctx: context to be used when calling wpa_supplicant functions,
+	 * e.g., wpa_supplicant_event()
+	 * @ifname: interface name, e.g., wlan0
+	 *
+	 * Returns: Pointer to private data, %NULL on failure
+	 *
+	 * Initialize driver interface, including event processing for kernel
+	 * driver events (e.g., associated, scan results, Michael MIC failure).
+	 * This function can allocate a private configuration data area for
+	 * @ctx, file descriptor, interface name, etc. information that may be
+	 * needed in future driver operations. If this is not used, non-NULL
+	 * value will need to be returned because %NULL is used to indicate
+	 * failure. The returned value will be used as 'void *priv' data for
+	 * all other driver_ops functions.
+	 *
+	 * The main event loop (eloop.c) of wpa_supplicant can be used to
+	 * register callback for read sockets (eloop_register_read_sock()).
+	 *
+	 * See below for more information about events and
+	 * wpa_supplicant_event() function.
+	 */
+	void * (*init)(void *ctx, const char *ifname);
+
+	/**
+	 * deinit - Deinitialize driver interface
+	 * @priv: private driver interface data from init()
+	 *
+	 * Shut down driver interface and processing of driver events. Free
+	 * private data buffer if one was allocated in init() handler.
+	 */
+	void (*deinit)(void *priv);
+
+	/**
+	 * set_param - Set driver configuration parameters
+	 * @priv: private driver interface data from init()
+	 * @param: driver specific configuration parameters
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Optional handler for notifying driver interface about configuration
+	 * parameters (driver_param).
+	 */
+	int (*set_param)(void *priv, const char *param);
+
+	/**
+	 * set_countermeasures - Enable/disable TKIP countermeasures
+	 * @priv: private driver interface data
+	 * @enabled: 1 = countermeasures enabled, 0 = disabled
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Configure TKIP countermeasures. When these are enabled, the driver
+	 * should drop all received and queued frames that are using TKIP.
+	 */
+	int (*set_countermeasures)(void *priv, int enabled);
+
+	/**
+	 * deauthenticate - Request driver to deauthenticate
+	 * @priv: private driver interface data
+	 * @addr: peer address (BSSID of the AP)
+	 * @reason_code: 16-bit reason code to be sent in the deauthentication
+	 *	frame
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*deauthenticate)(void *priv, const u8 *addr, int reason_code);
+
+	/**
+	 * associate - Request driver to associate
+	 * @priv: private driver interface data
+	 * @params: association parameters
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*associate)(void *priv,
+			 struct wpa_driver_associate_params *params);
+
+	/**
+	 * add_pmkid - Add PMKSA cache entry to the driver
+	 * @priv: private driver interface data
+	 * @bssid: BSSID for the PMKSA cache entry
+	 * @pmkid: PMKID for the PMKSA cache entry
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is called when a new PMK is received, as a result of
+	 * either normal authentication or RSN pre-authentication.
+	 *
+	 * If the driver generates RSN IE, i.e., it does not use wpa_ie in
+	 * associate(), add_pmkid() can be used to add new PMKSA cache entries
+	 * in the driver. If the driver uses wpa_ie from wpa_supplicant, this
+	 * driver_ops function does not need to be implemented. Likewise, if
+	 * the driver does not support WPA, this function is not needed.
+	 */
+	int (*add_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid);
+
+	/**
+	 * remove_pmkid - Remove PMKSA cache entry to the driver
+	 * @priv: private driver interface data
+	 * @bssid: BSSID for the PMKSA cache entry
+	 * @pmkid: PMKID for the PMKSA cache entry
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is called when the supplicant drops a PMKSA cache
+	 * entry for any reason.
+	 *
+	 * If the driver generates RSN IE, i.e., it does not use wpa_ie in
+	 * associate(), remove_pmkid() can be used to synchronize PMKSA caches
+	 * between the driver and wpa_supplicant. If the driver uses wpa_ie
+	 * from wpa_supplicant, this driver_ops function does not need to be
+	 * implemented. Likewise, if the driver does not support WPA, this
+	 * function is not needed.
+	 */
+	int (*remove_pmkid)(void *priv, const u8 *bssid, const u8 *pmkid);
+
+	/**
+	 * flush_pmkid - Flush PMKSA cache
+	 * @priv: private driver interface data
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is called when the supplicant drops all PMKSA cache
+	 * entries for any reason.
+	 *
+	 * If the driver generates RSN IE, i.e., it does not use wpa_ie in
+	 * associate(), remove_pmkid() can be used to synchronize PMKSA caches
+	 * between the driver and wpa_supplicant. If the driver uses wpa_ie
+	 * from wpa_supplicant, this driver_ops function does not need to be
+	 * implemented. Likewise, if the driver does not support WPA, this
+	 * function is not needed.
+	 */
+	int (*flush_pmkid)(void *priv);
+
+	/**
+	 * get_capa - Get driver capabilities
+	 * @priv: private driver interface data
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Get driver/firmware/hardware capabilities.
+	 */
+	int (*get_capa)(void *priv, struct wpa_driver_capa *capa);
+
+	/**
+	 * poll - Poll driver for association information
+	 * @priv: private driver interface data
+	 *
+	 * This is an option callback that can be used when the driver does not
+	 * provide event mechanism for association events. This is called when
+	 * receiving WPA EAPOL-Key messages that require association
+	 * information. The driver interface is supposed to generate associnfo
+	 * event before returning from this callback function. In addition, the
+	 * driver interface should generate an association event after having
+	 * sent out associnfo.
+	 */
+	void (*poll)(void *priv);
+
+	/**
+	 * get_ifname - Get interface name
+	 * @priv: private driver interface data
+	 *
+	 * Returns: Pointer to the interface name. This can differ from the
+	 * interface name used in init() call. Init() is called first.
+	 *
+	 * This optional function can be used to allow the driver interface to
+	 * replace the interface name with something else, e.g., based on an
+	 * interface mapping from a more descriptive name.
+	 */
+	const char * (*get_ifname)(void *priv);
+
+	/**
+	 * get_mac_addr - Get own MAC address
+	 * @priv: private driver interface data
+	 *
+	 * Returns: Pointer to own MAC address or %NULL on failure
+	 *
+	 * This optional function can be used to get the own MAC address of the
+	 * device from the driver interface code. This is only needed if the
+	 * l2_packet implementation for the OS does not provide easy access to
+	 * a MAC address. */
+	const u8 * (*get_mac_addr)(void *priv);
+
+	/**
+	 * send_eapol - Optional function for sending EAPOL packets
+	 * @priv: private driver interface data
+	 * @dest: Destination MAC address
+	 * @proto: Ethertype
+	 * @data: EAPOL packet starting with IEEE 802.1X header
+	 * @data_len: Size of the EAPOL packet
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This optional function can be used to override l2_packet operations
+	 * with driver specific functionality. If this function pointer is set,
+	 * l2_packet module is not used at all and the driver interface code is
+	 * responsible for receiving and sending all EAPOL packets. The
+	 * received EAPOL packets are sent to core code with EVENT_EAPOL_RX
+	 * event. The driver interface is required to implement get_mac_addr()
+	 * handler if send_eapol() is used.
+	 */
+	int (*send_eapol)(void *priv, const u8 *dest, u16 proto,
+			  const u8 *data, size_t data_len);
+
+	/**
+	 * set_operstate - Sets device operating state to DORMANT or UP
+	 * @priv: private driver interface data
+	 * @state: 0 = dormant, 1 = up
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function that can be used on operating systems
+	 * that support a concept of controlling network device state from user
+	 * space applications. This function, if set, gets called with
+	 * state = 1 when authentication has been completed and with state = 0
+	 * when connection is lost.
+	 */
+	int (*set_operstate)(void *priv, int state);
+
+	/**
+	 * mlme_setprotection - MLME-SETPROTECTION.request primitive
+	 * @priv: Private driver interface data
+	 * @addr: Address of the station for which to set protection (may be
+	 * %NULL for group keys)
+	 * @protect_type: MLME_SETPROTECTION_PROTECT_TYPE_*
+	 * @key_type: MLME_SETPROTECTION_KEY_TYPE_*
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function that can be used to set the driver to
+	 * require protection for Tx and/or Rx frames. This uses the layer
+	 * interface defined in IEEE 802.11i-2004 clause 10.3.22.1
+	 * (MLME-SETPROTECTION.request). Many drivers do not use explicit
+	 * set protection operation; instead, they set protection implicitly
+	 * based on configured keys.
+	 */
+	int (*mlme_setprotection)(void *priv, const u8 *addr, int protect_type,
+				  int key_type);
+
+	/**
+	 * get_hw_feature_data - Get hardware support data (channels and rates)
+	 * @priv: Private driver interface data
+	 * @num_modes: Variable for returning the number of returned modes
+	 * flags: Variable for returning hardware feature flags
+	 * Returns: Pointer to allocated hardware data on success or %NULL on
+	 * failure. Caller is responsible for freeing this.
+	 */
+	struct hostapd_hw_modes * (*get_hw_feature_data)(void *priv,
+							 u16 *num_modes,
+							 u16 *flags);
+
+	/**
+	 * send_mlme - Send management frame from MLME
+	 * @priv: Private driver interface data
+	 * @data: IEEE 802.11 management frame with IEEE 802.11 header
+	 * @data_len: Size of the management frame
+	 * @noack: Do not wait for this frame to be acked (disable retries)
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*send_mlme)(void *priv, const u8 *data, size_t data_len,
+			 int noack);
+
+	/**
+	 * update_ft_ies - Update FT (IEEE 802.11r) IEs
+	 * @priv: Private driver interface data
+	 * @md: Mobility domain (2 octets) (also included inside ies)
+	 * @ies: FT IEs (MDIE, FTIE, ...) or %NULL to remove IEs
+	 * @ies_len: Length of FT IEs in bytes
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * The supplicant uses this callback to let the driver know that keying
+	 * material for FT is available and that the driver can use the
+	 * provided IEs in the next message in FT authentication sequence.
+	 *
+	 * This function is only needed for driver that support IEEE 802.11r
+	 * (Fast BSS Transition).
+	 */
+	int (*update_ft_ies)(void *priv, const u8 *md, const u8 *ies,
+			     size_t ies_len);
+
+	/**
+	 * send_ft_action - Send FT Action frame (IEEE 802.11r)
+	 * @priv: Private driver interface data
+	 * @action: Action field value
+	 * @target_ap: Target AP address
+	 * @ies: FT IEs (MDIE, FTIE, ...) (FT Request action frame body)
+	 * @ies_len: Length of FT IEs in bytes
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * The supplicant uses this callback to request the driver to transmit
+	 * an FT Action frame (action category 6) for over-the-DS fast BSS
+	 * transition.
+	 */
+	int (*send_ft_action)(void *priv, u8 action, const u8 *target_ap,
+			      const u8 *ies, size_t ies_len);
+
+	/**
+	 * get_scan_results2 - Fetch the latest scan results
+	 * @priv: private driver interface data
+	 *
+	 * Returns: Allocated buffer of scan results (caller is responsible for
+	 * freeing the data structure) on success, NULL on failure
+	 */
+	 struct wpa_scan_results * (*get_scan_results2)(void *priv);
+
+	/**
+	 * set_country - Set country
+	 * @priv: Private driver interface data
+	 * @alpha2: country to which to switch to
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This function is for drivers which support some form
+	 * of setting a regulatory domain.
+	 */
+	int (*set_country)(void *priv, const char *alpha2);
+
+	/**
+	 * global_init - Global driver initialization
+	 * Returns: Pointer to private data (global), %NULL on failure
+	 *
+	 * This optional function is called to initialize the driver wrapper
+	 * for global data, i.e., data that applies to all interfaces. If this
+	 * function is implemented, global_deinit() will also need to be
+	 * implemented to free the private data. The driver will also likely
+	 * use init2() function instead of init() to get the pointer to global
+	 * data available to per-interface initializer.
+	 */
+	void * (*global_init)(void);
+
+	/**
+	 * global_deinit - Global driver deinitialization
+	 * @priv: private driver global data from global_init()
+	 *
+	 * Terminate any global driver related functionality and free the
+	 * global data structure.
+	 */
+	void (*global_deinit)(void *priv);
+
+	/**
+	 * init2 - Initialize driver interface (with global data)
+	 * @ctx: context to be used when calling wpa_supplicant functions,
+	 * e.g., wpa_supplicant_event()
+	 * @ifname: interface name, e.g., wlan0
+	 * @global_priv: private driver global data from global_init()
+	 * Returns: Pointer to private data, %NULL on failure
+	 *
+	 * This function can be used instead of init() if the driver wrapper
+	 * uses global data.
+	 */
+	void * (*init2)(void *ctx, const char *ifname, void *global_priv);
+
+	/**
+	 * get_interfaces - Get information about available interfaces
+	 * @global_priv: private driver global data from global_init()
+	 * Returns: Allocated buffer of interface information (caller is
+	 * responsible for freeing the data structure) on success, NULL on
+	 * failure
+	 */
+	struct wpa_interface_info * (*get_interfaces)(void *global_priv);
+
+	/**
+	 * scan2 - Request the driver to initiate scan
+	 * @priv: private driver interface data
+	 * @params: Scan parameters
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * Once the scan results are ready, the driver should report scan
+	 * results event for wpa_supplicant which will eventually request the
+	 * results with wpa_driver_get_scan_results2().
+	 */
+	int (*scan2)(void *priv, struct wpa_driver_scan_params *params);
+
+	/**
+	 * authenticate - Request driver to authenticate
+	 * @priv: private driver interface data
+	 * @params: authentication parameters
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function that can be used with drivers that
+	 * support separate authentication and association steps, i.e., when
+	 * wpa_supplicant can act as the SME. If not implemented, associate()
+	 * function is expected to take care of IEEE 802.11 authentication,
+	 * too.
+	 */
+	int (*authenticate)(void *priv,
+			    struct wpa_driver_auth_params *params);
+
+	/**
+	 * set_ap - Set Beacon and Probe Response information for AP mode
+	 * @priv: Private driver interface data
+	 * @params: Parameters to use in AP mode
+	 *
+	 * This function is used to configure Beacon template and/or extra IEs
+	 * to add for Beacon and Probe Response frames for the driver in
+	 * AP mode. The driver is responsible for building the full Beacon
+	 * frame by concatenating the head part with TIM IE generated by the
+	 * driver/firmware and finishing with the tail part. Depending on the
+	 * driver architectue, this can be done either by using the full
+	 * template or the set of additional IEs (e.g., WPS and P2P IE).
+	 * Similarly, Probe Response processing depends on the driver design.
+	 * If the driver (or firmware) takes care of replying to Probe Request
+	 * frames, the extra IEs provided here needs to be added to the Probe
+	 * Response frames.
+	 *
+	 * Returns: 0 on success, -1 on failure
+	 */
+	int (*set_ap)(void *priv, struct wpa_driver_ap_params *params);
+
+	/**
+	 * hapd_init - Initialize driver interface (hostapd only)
+	 * @hapd: Pointer to hostapd context
+	 * @params: Configuration for the driver wrapper
+	 * Returns: Pointer to private data, %NULL on failure
+	 *
+	 * This function is used instead of init() or init2() when the driver
+	 * wrapper is used with hostapd.
+	 */
+	void * (*hapd_init)(struct hostapd_data *hapd,
+			    struct wpa_init_params *params);
+
+	/**
+	 * hapd_deinit - Deinitialize driver interface (hostapd only)
+	 * @priv: Private driver interface data from hapd_init()
+	 */
+	void (*hapd_deinit)(void *priv);
+
+	/**
+	 * set_ieee8021x - Enable/disable IEEE 802.1X support (AP only)
+	 * @priv: Private driver interface data
+	 * @params: BSS parameters
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function to configure the kernel driver to
+	 * enable/disable IEEE 802.1X support and set WPA/WPA2 parameters. This
+	 * can be left undefined (set to %NULL) if IEEE 802.1X support is
+	 * always enabled and the driver uses set_ap() to set WPA/RSN IE
+	 * for Beacon frames.
+	 *
+	 * DEPRECATED - use set_ap() instead
+	 */
+	int (*set_ieee8021x)(void *priv, struct wpa_bss_params *params);
+
+	/**
+	 * set_privacy - Enable/disable privacy (AP only)
+	 * @priv: Private driver interface data
+	 * @enabled: 1 = privacy enabled, 0 = disabled
+	 * Returns: 0 on success, -1 on failure
+	 *
+	 * This is an optional function to configure privacy field in the
+	 * kernel driver for Beacon frames. This can be left undefined (set to
+	 * %NULL) if the driver uses the Beacon template from set_ap().
+	 *
+	 * DEPRECATED - use set_ap() instead
+	 */
+	int (*set_privacy)(void *priv, int enabled);
+
+	/**
+	 * get_seqnum - Fetch the current TSC/packet number (AP only)
+	 * @ifname: The interface name (main or virtual)
+	 * @priv: Private driver interface data
+	 * @addr: MAC address of