Merge hostapd upstream into master.
Current as of:
http://w1.fi/cgit/hostap/commit/?id=ca68a8b561c48393c8ba25055ce294caaa3ac008
Note that this resolves the merge conflicts, but does not compile.
A second commit on top of this one is needed to get a working hostapd.
Change-Id: Ib1f533ef8f3399aaec7d4bc6708f7ea126a2c39c
diff --git a/CONTRIBUTIONS b/CONTRIBUTIONS
index d20a556..ca09bae 100644
--- a/CONTRIBUTIONS
+++ b/CONTRIBUTIONS
@@ -112,7 +112,7 @@
Modified BSD license (no advertisement clause):
-Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/COPYING b/COPYING
index 8a98582..5962e2f 100644
--- a/COPYING
+++ b/COPYING
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
-Copyright (c) 2002-2012, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
diff --git a/README b/README
index 8de14a6..07d1d25 100644
--- a/README
+++ b/README
@@ -1,7 +1,7 @@
wpa_supplicant and hostapd
--------------------------
-Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
These programs are licensed under the BSD license (the one with
diff --git a/doc/Makefile b/doc/Makefile
index 4e1c1bd..62af04a 100644
--- a/doc/Makefile
+++ b/doc/Makefile
@@ -16,20 +16,23 @@
_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
+_wpa_supplicant.eps: wpa_supplicant.eps
+ 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 _wpa_supplicant.png _wpa_supplicant.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
+html: docs-pics
(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 _wpa_supplicant.png _wpa_supplicant.eps
rm -f hostapd.eps hostapd.png
rm -f p2p_sm.eps p2p_sm.png
rm -f p2p_arch.eps p2p_arch.png
diff --git a/doc/code_structure.doxygen b/doc/code_structure.doxygen
index 26f5f6d..454f179 100644
--- a/doc/code_structure.doxygen
+++ b/doc/code_structure.doxygen
@@ -13,7 +13,7 @@
\ref win_port "Windows port" |
\ref test_programs "Test programs" ]
-%wpa_supplicant implementation is divided into number of independent
+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
@@ -21,82 +21,77 @@
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 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
+\ref driver_wrapper "Driver interface API" is defined in \ref driver.h and
all hardware/driver dependent functionality is implemented in
driver_*.c.
\section _wpa_supplicant_core wpa_supplicant core functionality
-wpa_supplicant.c
+\ref wpa_supplicant.c
Program initialization, main control loop
-main.c
+\ref wpa_supplicant/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
+\ref events.c
+ Driver event processing; \ref wpa_supplicant_event() and related functions
-wpa_supplicant_i.h
- Internal definitions for %wpa_supplicant core; should not be
+\ref 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
+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
+\ref eloop.c and \ref eloop.h
Event loop (select() loop with registerable timeouts, socket read
callbacks, and signal callbacks)
-common.c and common.h
+\ref common.c and \ref common.h
Common helper functions
-defs.h
+\ref defs.h
Definitions shared by multiple files
-l2_packet.h, l2_packet_linux.c, and l2_packet_pcap.c
+\ref l2_packet.h, \ref l2_packet_linux.c, and \ref 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
+ l2_packet implementation is included. \ref l2_packet_linux.c uses Linux
+ packet sockets and \ref l2_packet_pcap.c has a more portable version using
libpcap and libdnet.
-pcsc_funcs.c and pcsc_funcs.h
+\ref pcsc_funcs.c and \ref pcsc_funcs.h
Wrapper for PC/SC lite SIM and smart card readers
-priv_netlink.h
+\ref 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
+\ref 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
+\ref md5.c and \ref 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
+\ref rc4.c and \ref rc4.h
RC4 (broadcast/default key encryption)
-sha1.c and sha1.h
+\ref sha1.c and \ref 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)
@@ -104,10 +99,10 @@
T-PRF (for EAP-FAST)
TLS-PRF (RFC 2246)
-sha256.c and sha256.h
+\ref sha256.c and \ref sha256.h
SHA-256 (replaced with a crypto library if TLS support is included)
-aes_wrap.c, aes_wrap.h, aes.c
+\ref aes-wrap.c, \ref aes_wrap.h, \ref 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),
@@ -116,207 +111,205 @@
AES-128 EAX mode encryption/decryption,
AES-128 CBC
-crypto.h
+\ref crypto.h
Definition of crypto library wrapper
-crypto_openssl.c
+\ref crypto_openssl.c
Wrapper functions for libcrypto (OpenSSL)
-crypto_internal.c
+\ref crypto_internal.c
Wrapper functions for internal crypto implementation
-crypto_gnutls.c
+\ref crypto_gnutls.c
Wrapper functions for libgcrypt (used by GnuTLS)
-ms_funcs.c and ms_funcs.h
+\ref ms_funcs.c and \ref ms_funcs.h
Helper functions for MSCHAPV2 and LEAP
-tls.h
+\ref tls.h
Definition of TLS library wrapper
-tls_none.c
+\ref tls_none.c
Dummy implementation of TLS library wrapper for cases where TLS
functionality is not included.
-tls_openssl.c
+\ref tls_openssl.c
TLS library wrapper for openssl
-tls_internal.c
+\ref tls_internal.c
TLS library for internal TLS implementation
-tls_gnutls.c
+\ref tls_gnutls.c
TLS library wrapper for GnuTLS
\section tls_func TLS library
-asn1.c and asn1.h
+\ref asn1.c and \ref asn1.h
ASN.1 DER parsing
-bignum.c and bignum.h
+\ref bignum.c and \ref bignum.h
Big number math
-rsa.c and rsa.h
+\ref rsa.c and \ref rsa.h
RSA
-x509v3.c and x509v3.h
+\ref x509v3.c and \ref x509v3.h
X.509v3 certificate parsing and processing
-tlsv1_client.c, tlsv1_client.h
+\ref tlsv1_client.c, \ref tlsv1_client.h
TLSv1 client (RFC 2246)
-tlsv1_client_i.h
+\ref tlsv1_client_i.h
Internal structures for TLSv1 client
-tlsv1_client_read.c
+\ref tlsv1_client_read.c
TLSv1 client: read handshake messages
-tlsv1_client_write.c
+\ref tlsv1_client_write.c
TLSv1 client: write handshake messages
-tlsv1_common.c and tlsv1_common.h
+\ref tlsv1_common.c and \ref tlsv1_common.h
Common TLSv1 routines and definitions
-tlsv1_cred.c and tlsv1_cred.h
+\ref tlsv1_cred.c and \ref tlsv1_cred.h
TLSv1 credentials
-tlsv1_record.c and tlsv1_record.h
+\ref tlsv1_record.c and \ref tlsv1_record.h
TLSv1 record protocol
\section configuration Configuration
-config_ssid.h
+\ref config_ssid.h
Definition of per network configuration items
-config.h
- Definition of the %wpa_supplicant configuration
+\ref config.h
+ Definition of the wpa_supplicant configuration
-config.c
+\ref config.c
Configuration parser and common functions
-config_file.c
+\ref wpa_supplicant/config_file.c
Configuration backend for text files (e.g., wpa_supplicant.conf)
-config_winreg.c
+\ref config_winreg.c
Configuration backend for Windows registry
\section ctrl_iface Control interface
-%wpa_supplicant has a \ref ctrl_iface_page "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.
+are included in the wpa_supplicant distribution.
-ctrl_iface.c and ctrl_iface.h
- %wpa_supplicant-side of the control interface
+\ref wpa_supplicant/ctrl_iface.c and \ref wpa_supplicant/ctrl_iface.h
+ wpa_supplicant-side of the control interface
-ctrl_iface_unix.c
+\ref ctrl_iface_unix.c
UNIX domain sockets -based control interface backend
-ctrl_iface_udp.c
+\ref ctrl_iface_udp.c
UDP sockets -based control interface backend
-ctrl_iface_named_pipe.c
+\ref ctrl_iface_named_pipe.c
Windows named pipes -based control interface backend
-wpa_ctrl.c and wpa_ctrl.h
+\ref wpa_ctrl.c and \ref wpa_ctrl.h
Library functions for external programs to provide access to the
- %wpa_supplicant control interface
+ wpa_supplicant control interface
-wpa_cli.c
- Example program for using %wpa_supplicant control interface
+\ref wpa_cli.c
+ Example program for using wpa_supplicant control interface
\section wpa_code WPA supplicant
-wpa.c and wpa.h
+\ref wpa.c and \ref wpa.h
WPA state machine and 4-Way/Group Key Handshake processing
-preauth.c and preauth.h
+\ref preauth.c and \ref preauth.h
PMKSA caching and pre-authentication (RSN/WPA2)
-wpa_i.h
+\ref 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.
+can be used by other programs than just wpa_supplicant.
-eap.c and eap.h
+\ref eap.c and \ref eap.h
EAP state machine and method interface
-eap_defs.h
+\ref eap_defs.h
Common EAP definitions
-eap_i.h
+\ref 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
+\ref eap_sim_common.c and \ref eap_sim_common.h
Common code for EAP-SIM and EAP-AKA
-eap_tls_common.c and eap_tls_common.h
+\ref eap_tls_common.c and \ref 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
+\ref eap_ttls.c and \ref eap_ttls.h
EAP-TTLS
-eap_pax.c, eap_pax_common.h, eap_pax_common.c
+\ref eap_pax.c, \ref eap_pax_common.h, \ref eap_pax_common.c
EAP-PAX
-eap_psk.c, eap_psk_common.h, eap_psk_common.c
+\ref eap_psk.c, \ref eap_psk_common.h, \ref 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
+\ref eap_sake.c, \ref eap_sake_common.h, \ref eap_sake_common.c
EAP-SAKE
-eap_gpsk.c, eap_gpsk_common.h, eap_gpsk_common.c
+\ref eap_gpsk.c, \ref eap_gpsk_common.h, \ref 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
+\ref eap_aka.c, \ref eap_fast.c, \ref eap_gtc.c, \ref eap_leap.c,
+\ref eap_md5.c, \ref eap_mschapv2.c, \ref eap_otp.c, \ref eap_peap.c,
+\ref eap_sim.c, \ref eap_tls.c
Other EAP method implementations
\section eapol_supp EAPOL supplicant
-eapol_supp_sm.c and eapol_supp_sm.h
+\ref eapol_supp_sm.c and \ref eapol_supp_sm.h
EAPOL supplicant state machine and IEEE 802.1X processing
\section win_port Windows port
-ndis_events.c
+\ref ndis_events.c
Code for receiving NdisMIndicateStatus() events and delivering them to
- %wpa_supplicant driver_ndis.c in more easier to use form
+ wpa_supplicant \ref driver_ndis.c in more easier to use form
-win_if_list.c
+\ref win_if_list.c
External program for listing current network interface
\section test_programs Test programs
-radius_client.c and radius_client.h
+\ref radius_client.c and \ref radius_client.h
RADIUS authentication client implementation for eapol_test
-radius.c and radius.h
+\ref radius.c and \ref radius.h
RADIUS message processing for eapol_test
-eapol_test.c
+\ref eapol_test.c
Standalone EAP testing tool with integrated RADIUS authentication
client
-preauth_test.c
+\ref preauth_test.c
Standalone RSN pre-authentication tool
-wpa_passphrase.c
+\ref wpa_passphrase.c
WPA ASCII passphrase to PSK conversion
*/
diff --git a/doc/ctrl_iface.doxygen b/doc/ctrl_iface.doxygen
index 0d06625..be8916f 100644
--- a/doc/ctrl_iface.doxygen
+++ b/doc/ctrl_iface.doxygen
@@ -1,47 +1,47 @@
/**
-\page ctrl_iface_page %wpa_supplicant control interface
+\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
+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
+a small C library, in a form of a single C file, \ref 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
+the library functions documented in \ref wpa_ctrl.h to interact with
+wpa_supplicant. This library can also be used with C++. \ref 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
+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 functions defined in \ref 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
+communicate with wpa_supplicant should link in \ref 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().
+interface with \ref wpa_ctrl_open() and to send commands with
+\ref wpa_ctrl_request().
-%wpa_supplicant uses the control interface for two types of communication:
+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
+wpa_supplicant. These can be executed using \ref 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
+attach to the control interface with \ref 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,
+\ref 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
+control interface connections by calling \ref 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
@@ -49,20 +49,20 @@
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
+be closed by calling \ref wpa_ctrl_close(). If the connection was used for
unsolicited event messages, it should be first detached by calling
-wpa_ctrl_detach().
+\ref wpa_ctrl_detach().
\section ctrl_iface_cmds Control interface commands
-Following commands can be used with wpa_ctrl_request():
+Following commands can be used with \ref wpa_ctrl_request():
\subsection ctrl_iface_PING PING
-This command can be used to test whether %wpa_supplicant is replying
+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.
+connection is open and wpa_supplicant is processing commands.
\subsection ctrl_iface_MIB MIB
@@ -217,13 +217,13 @@
\subsection ctrl_iface_ATTACH ATTACH
Attach the connection as a monitor for unsolicited events. This can
-be done with wpa_ctrl_attach().
+be done with \ref 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().
+be done with \ref wpa_ctrl_detach().
\subsection ctrl_iface_LEVEL LEVEL <debug level>
@@ -233,12 +233,12 @@
\subsection ctrl_iface_RECONFIGURE RECONFIGURE
-Force %wpa_supplicant to re-read its configuration data.
+Force wpa_supplicant to re-read its configuration data.
\subsection ctrl_iface_TERMINATE TERMINATE
-Terminate %wpa_supplicant process.
+Terminate wpa_supplicant process.
\subsection ctrl_iface_BSSID BSSID <network id> <BSSID>
@@ -563,7 +563,7 @@
\section ctrl_iface_interactive Interactive requests
-If %wpa_supplicant needs additional information during authentication
+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
@@ -583,7 +583,7 @@
CTRL-RSP-<field name>-<network id>-<value>
\endverbatim
-For example, request from %wpa_supplicant:
+For example, request from wpa_supplicant:
\verbatim
CTRL-REQ-PASSWORD-1-Password needed for SSID test-network
\endverbatim
@@ -598,7 +598,7 @@
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.
+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
@@ -645,8 +645,8 @@
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
+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
@@ -662,14 +662,14 @@
\section ctrl_iface_events Control interface events
-%wpa_supplicant generates number messages based on events like
+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().
+interface with \ref 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
+a fixed prefix text as defined in \ref 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:
@@ -694,11 +694,11 @@
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
+text to the event strings from \ref wpa_ctrl.h that the program is
interested in processing.
Following subsections describe the most common event notifications
-generated by %wpa_supplicant.
+generated by wpa_supplicant.
\subsection ctrl_iface_event_CTRL_REQ CTRL-REQ-
@@ -717,7 +717,7 @@
\subsection ctrl_iface_event_TERMINATING CTRL-EVENT-TERMINATING
-WPA_EVENT_TERMINATING: %wpa_supplicant is exiting
+WPA_EVENT_TERMINATING: wpa_supplicant is exiting
\subsection ctrl_iface_event_PASSWORD_CHANGED CTRL-EVENT-PASSWORD-CHANGED
diff --git a/doc/dbus.doxygen b/doc/dbus.doxygen
index 02c7407..329e5d0 100644
--- a/doc/dbus.doxygen
+++ b/doc/dbus.doxygen
@@ -1,8 +1,8 @@
/**
-\page dbus %wpa_supplicant D-Bus API
+\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
+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.
@@ -10,13 +10,17 @@
- \ref dbus_main
- \ref dbus_interface
- \ref dbus_wps
+- \ref dbus_p2pdevice
- \ref dbus_bss
- \ref dbus_network
+- \ref dbus_peer
+- \ref dbus_group
+- \ref dbus_persistent_group
\section dbus_main fi.w1.wpa_supplicant1
-Interface implemented by the main %wpa_supplicant D-Bus object
+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
@@ -24,12 +28,12 @@
<ul>
<li>
<h3>CreateInterface ( a{sv} : args ) --> o : interface</h3>
- <p>Registers a wireless interface in %wpa_supplicant.</p>
+ <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:
+ 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>
@@ -47,7 +51,7 @@
<h4>Possible errors</h4>
<dl>
<dt>fi.w1.wpa_supplicant1.InterfaceExists</dt>
- <dd>%wpa_supplicant already controls this interface.</dd>
+ <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>
@@ -57,7 +61,7 @@
<li>
<h3>RemoveInterface ( o : interface ) --> nothing</h3>
- <p>Deregisters a wireless interface from %wpa_supplicant.</p>
+ <p>Deregisters a wireless interface from wpa_supplicant.</p>
<h4>Arguments</h4>
<dl>
<dt>o : interface</dt>
@@ -74,7 +78,7 @@
<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>
+ <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>
@@ -88,7 +92,7 @@
<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>
+ <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>
@@ -100,19 +104,19 @@
<ul>
<li>
<h3>DebugLevel - s - (read/write)</h3>
- <p>Global %wpa_supplicant debugging level. Possible values are
+ <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>
+ <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>
+ <p>Global wpa_supplicant debugging parameter. Determines if secrets are shown in debug logs.</p>
</li>
<li>
@@ -129,6 +133,11 @@
<h3>Capabilities - as - (read)</h3>
<p>An array with supported capabilities (e.g., "ap", "ibss-rsn", "p2p", "interworking").</p>
</li>
+
+ <li>
+ <h3>WFDIEs - ay - (read/write)</h3>
+ <p>Wi-Fi Display subelements.</p>
+ </li>
</ul>
\subsection dbus_main_signals Signals
@@ -136,7 +145,7 @@
<ul>
<li>
<h3>InterfaceAdded ( o : interface, a{sv} : properties )</h3>
- <p>A new interface was added to %wpa_supplicant.</p>
+ <p>A new interface was added to wpa_supplicant.</p>
<h4>Arguments</h4>
<dl>
<dt>o : interface</dt>
@@ -150,7 +159,7 @@
<li>
<h3>InterfaceRemoved ( o : interface )</h3>
- <p>An interface was removed from %wpa_supplicant.</p>
+ <p>An interface was removed from wpa_supplicant.</p>
<h4>Arguments</h4>
<dl>
<dt>o : interface</dt>
@@ -173,7 +182,7 @@
\section dbus_interface fi.w1.wpa_supplicant1.Interface
Interface implemented by objects related to network interface added to
-%wpa_supplicant, i.e., returned by
+wpa_supplicant, i.e., returned by
fi.w1.wpa_supplicant1.CreateInterface.
\subsection dbus_interface_methods Methods
@@ -220,7 +229,7 @@
<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>
+ <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>
@@ -511,6 +520,30 @@
<dd>Maximum age in seconds for BSS entries to keep in cache (0 = remove all entries).</dd>
</dl>
</li>
+
+ <li>
+ <h3>SubscribeProbeReq ( ) --> nothing</h3>
+ <p>Subscribe to receive Probe Request events. This is needed in addition to registering a signal handler for the ProbeRequest signal to avoid flooding D-Bus with all Probe Request indications when no application is interested in them.</p>
+ <h4>Possible errors</h4>
+ <dl>
+ <dt>fi.w1.wpa_supplicant1.SubscriptionInUse</dt>
+ <dd>Another application is already subscribed.</dd>
+ <dt>fi.w1.wpa_supplicant1.NoMemory</dt>
+ <dd>Needed memory was not possible to get allocated.</dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>UnsubscribeProbeReq ( ) --> nothing</h3>
+ <p>Unsubscribe from receiving Probe Request events.</p>
+ <h4>Possible errors</h4>
+ <dl>
+ <dt>fi.w1.wpa_supplicant1.NoSubscription</dt>
+ <dd>No subscription in place.</dd>
+ <dt>fi.w1.wpa_supplicant1.SubscriptionNotYou</dt>
+ <dd>Subscription in place, but for another process.</dd>
+ </dl>
+ </li>
</ul>
\subsection dbus_interface_properties Properties
@@ -543,22 +576,22 @@
<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>
+ <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>
+ <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>
+ <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>
+ <p>Identical to country entry in wpa_supplicant configuration file.</p>
</li>
<li>
@@ -578,12 +611,17 @@
<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>
+ <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>
+ <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>CurrentAuthMode - s - (read)</h3>
+ <p>Current authentication type.</p>
</li>
<li>
@@ -603,7 +641,7 @@
<li>
<h3>FastReauth - b - (read/write)</h3>
- <p>Identical to fast_reauth entry in %wpa_supplicant configuration file.</p>
+ <p>Identical to fast_reauth entry in wpa_supplicant configuration file.</p>
</li>
<li>
@@ -620,6 +658,11 @@
<h3>PKCS11ModulePath - s - (read)</h3>
<p>PKCS #11 module path.</p>
</li>
+
+ <li>
+ <h3>DisconnectReason - i - (read)</h3>
+ <p>The most recent IEEE 802.11 reason code for disconnect. Negative value indicates locally generated disconnection.</p>
+ </li>
</ul>
\subsection dbus_interface_signals Signals
@@ -749,7 +792,7 @@
<h4>Arguments</h4>
<dl>
<dt>a{sv} : parameters</dt>
- <dd>A dictionary with pairs of field names and their values. Possible dictionary keys are: "depth", "subject", "cert_hash", "cert".</dd>
+ <dd>A dictionary with pairs of field names and their values. Possible dictionary keys are: "depth", "subject", "altsubject", "cert_hash", "cert".</dd>
</dl>
</li>
@@ -778,20 +821,29 @@
<dd>Human readable information about the requested information.</dd>
</dl>
</li>
+
+ <li>
+ <h3>ProbeRequest ( a{sv} : args )</h3>
+ <p>Information about a received Probe Request frame. This signal is delivered only to a single application that has subscribed to received the events with SubscribeProbeReq().</p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : args</dt>
+ <dd>A dictionary with pairs of field names and their values. Possible dictionary keys are: "addr", "dst", "bssid", "ies", "signal".</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.
+Interface for performing WPS (Wi-Fi Simple Config) operations.
\subsection dbus_wps_methods Methods
<ul>
<li>
<h3>Start ( a{sv} : args ) --> a{sv} : output</h3>
- <p>Starts WPS configuration.</p>
+ <p>Starts WPS configuration. Note: When used with P2P groups, this needs to be issued on the GO group interface.</p>
<h4>Arguments</h4>
<dl>
<dt>a{sv} : args</dt>
@@ -802,7 +854,8 @@
<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>
+ <tr><td>Bssid</td><td>ay</td><td>Note: This is used to specify the peer MAC address when authorizing WPS connection in AP or P2P GO role.</td><td>No</td>
+ <tr><td>P2PDeviceAddress</td><td>ay</td><td>P2P Device Address of a peer to authorize for PBC connection. Used only in P2P GO role.</td><td>No</td>
</table>
</dd>
</dl>
@@ -833,6 +886,10 @@
<h3>ProcessCredentials - b - (read/write)</h3>
<p>Determines if the interface will process the credentials (credentials_processed configuration file parameter).</p>
</li>
+ <li>
+ <h3>ConfigMethods - s - (read/write)</h3>
+ <p>The currently advertised WPS 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.</p>
+ </li>
</ul>
\subsection dbus_wps_signals Signals
@@ -889,6 +946,553 @@
</ul>
+\section dbus_p2pdevice fi.w1.wpa_supplicant1.Interface.P2PDevice
+
+Interface for performing P2P (Wi-Fi Peer-to-Peer) P2P Device operations.
+
+\subsection dbus_p2pdevice_methods Methods
+
+<ul>
+ <li>
+ <h3>Find ( a{sv} : args ) --> nothing</h3>
+ <p>Start P2P find operation (i.e., alternating P2P Search and Listen states to discover peers and be discoverable).</p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : args</dt>
+ <dd>
+ A dictionary with parameters for the P2P find operation:
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+ <tr><td>Timeout</td><td>i</td><td>Timeout for operating in seconds</td><td>no</td></tr>
+ <tr><td>RequestedDevicesTypes</td><td>aay</td><td>WPS Device Types to search for</td><td>no</td></tr>
+ <tr><td>DiscoveryType</td><td>s</td><td>"start_with_full" (default, if not specified), "social", "progressive"</td><td>no</td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>StopFind ( nothing ) --> nothing</h3>
+ <p>Stop P2P find operation.</p>
+ </li>
+
+ <li>
+ <h3>Listen ( i : timeout ) --> nothing</h3>
+ <p>Start P2P listen operation (i.e., be discoverable).</p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>i : timeout</dt>
+ <dd>Timeout in seconds for stopping the listen operation.</dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>ExtendedListen ( a{sv} : args ) --> nothing</h3>
+ <p>Configure Extended Listen Timing. If the parameters are omitted, this feature is disabled. If the parameters are included, Listen State will be entered every interval msec for at least period msec. Both values have acceptable range of 1-65535 (with interval obviously having to be larger than or equal to duration). If the P2P module is not idle at the time the Extended Listen Timing timeout occurs, the Listen State operation will be skipped.</p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : args</dt>
+ <dd>
+ A dictionary with parameters for extended listen. Leave out all items to disable extended listen.
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+ <tr><td>period</td><td>i</td><td>Extended listen period in milliseconds; 1-65535.</td><td>no</td></tr>
+ <tr><td>interval</td><td>i</td><td>Extended listen interval in milliseconds; 1-65535.</td><td>no</td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>PresenceRequest ( a{sv} : args ) --> nothing</h3>
+ <p>Request a specific GO presence in a P2P group where the local device is a P2P Client. Send a P2P Presence Request to the GO (this is only available when acting as a P2P client). If no duration/interval pairs are given, the request indicates that this client has no special needs for GO presence. The first parameter pair gives the preferred duration and interval values in microseconds. If the second pair is included, that indicates which value would be acceptable.
+ \note This needs to be issued on a P2P group interface if separate group interfaces are used.
+ \bug It would be cleaner to not require .P2PDevice methods to be issued on a group interface. In other words, args['group_object'] could be used to specify the group or this method could be moved to be a .Group PresenceRequest() method.</p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : args</dt>
+ <dd>
+ A dictionary with parameters for the presence request.
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+ <tr><td>duration1</td><td>i</td><td>Duration in microseconds.</td><td>no</td></tr>
+ <tr><td>interval1</td><td>i</td><td>Interval in microseconds.</td><td>no</td></tr>
+ <tr><td>duration2</td><td>i</td><td>Duration in microseconds.</td><td>no</td></tr>
+ <tr><td>interval2</td><td>i</td><td>Interval in microseconds.</td><td>no</td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>ProvisionDiscoveryRequest ( o : peer, s : config_method ) --> nothing</h3>
+ </li>
+
+ <li>
+ <h3>Connect ( a{sv} : args ) --> s : generated_pin</h3>
+ <p>Request a P2P group to be started through GO Negotiation or by joining an already operating group.</p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : args</dt>
+ <dd>
+ A dictionary with parameters for the requested connection:
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+ <tr><td>peer</td><td>o</td><td></td><td>yes</td></tr>
+ <tr><td>persistent</td><td>b</td><td>Whether to form a persistent group.</td><td>no</td></tr>
+ <tr><td>join</td><td>b</td><td>Whether to join an already operating group instead of forming a new group.</td><td>no</td></tr>
+ <tr><td>authorize_only</td><td>b</td><td>Whether to authorize a peer to initiate GO Negotiation instead of initiating immediately.</td><td>no</td></tr>
+ <tr><td>frequency</td><td>i</td><td>Operating frequency in MHz</td><td>no</td></tr>
+ <tr><td>go_intent</td><td>i</td><td>GO intent 0-15</td><td>no</td></tr>
+ <tr><td>wps_method</td><td>s</td><td>"pbc", "display", "keypad", "pin" (alias for "display")</td><td>yes</td></tr>
+ <tr><td>pin</td><td>s</td><td></td><td>no</td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>GroupAdd ( a{sv} : args ) --> nothing</h3>
+ <p>Request a P2P group to be started without GO Negotiation.</p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : args</dt>
+ <dd>
+ A dictionary with parameters for the requested group:
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+ <tr><td>persistent</td><td>b</td><td>Whether to form a persistent group.</td><td>no</td></tr>
+ <tr><td>persistent_group_object</td><td>o</td><td></td><td>no</td></tr>
+ <tr><td>frequency</td><td>i</td><td>Operating frequency in MHz</td><td>no</td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>Invite ( a{sv} : args ) --> nothing</h3>
+ <p>Invite a peer to join an already operating group or to re-invoke a persistent group.</p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : args</dt>
+ <dd>
+ A dictionary with parameters for the invitation:
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+ <tr><td>peer</td><td>o</td><td></td><td>yes</td></tr>
+ <tr><td>persistent_group_object</td><td>o</td><td></td><td>no</td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>Disconnect ( nothing ) --> nothing</h3>
+ <p>Terminate a P2P group.
+ \note This needs to be issued on a P2P group interface if separate group interfaces are used.
+ \bug It would be cleaner to not require .P2PDevice methods to be issued on a group interface. In other words, this would either need to be Disconnect(group_object) or moved to be a .Group Disconnect() method.</p>
+ </li>
+
+ <li>
+ <h3>RejectPeer ( o : peer ) --> nothing</h3>
+ <p>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.</p>
+ </li>
+
+ <li>
+ <h3>Flush ( nothing ) --> nothing</h3>
+ <p>Flush P2P peer table and state.</p>
+ </li>
+
+ <li>
+ <h3>AddService ( a{sv} : args ) --> nothing</h3>
+ <p></p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : args</dt>
+ <dd>
+ A dictionary with parameters for the service:
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+ <tr><td>service_type</td><td>s</td><td>"upnp", "bonjour"</td><td>yes</td></tr>
+ <tr><td>version</td><td>u</td><td>Required for UPnP services.</td><td>no</td></tr>
+ <tr><td>service</td><td>s</td><td></td><td></td></tr>
+ <tr><td>query</td><td>ay</td><td></td><td></td></tr>
+ <tr><td>response</td><td>ay</td><td></td><td></td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>DeleteService ( a{sv} : args ) --> nothing</h3>
+ <p></p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : args</dt>
+ <dd>
+ A dictionary with parameters for the service:
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+ <tr><td>service_type</td><td>s</td><td>"upnp", "bonjour"</td><td>yes</td></tr>
+ <tr><td>version</td><td>u</td><td>Required for UPnP services.</td><td>no</td></tr>
+ <tr><td>service</td><td>s</td><td></td><td></td></tr>
+ <tr><td>query</td><td>ay</td><td></td><td></td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>FlushService ( nothing ) --> nothing</h3>
+ </li>
+
+ <li>
+ <h3>ServiceDiscoveryRequest ( a{sv} : args ) --> t : ref</h3>
+ <p></p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : args</dt>
+ <dd>
+ A dictionary with following parameters:
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+ <tr><td>peer_object</td><td>o</td><td></td><td>no</td></tr>
+ <tr><td>service_type</td><td>s</td><td>"upnp"</td><td>no</td></tr>
+ <tr><td>version</td><td>u</td><td>Required for UPnP services.</td><td>no</td></tr>
+ <tr><td>service</td><td>s</td><td></td><td></td></tr>
+ <tr><td>tlv</td><td>ay</td><td></td><td></td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>ServiceDiscoveryResponse ( a{sv} : args ) --> nothing : ref</h3>
+ <p></p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : args</dt>
+ <dd>
+ A dictionary with following parameters:
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+ <tr><td>peer_object</td><td>o</td><td></td><td>yes</td></tr>
+ <tr><td>frequency</td><td>i</td><td></td><td>yes</td></tr>
+ <tr><td>dialog_token</td><td>i</td><td></td><td>yes</td></tr>
+ <tr><td>tlvs</td><td>ay</td><td></td><td>yes</td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>ServiceDiscoveryCancelRequest ( t : args ) --> nothing : ref</h3>
+ </li>
+
+ <li>
+ <h3>ServiceUpdate ( nothing ) --> nothing</h3>
+ </li>
+
+ <li>
+ <h3>ServiceDiscoveryExternal ( i : arg ) --> nothing</h3>
+ </li>
+
+ <li>
+ <h3>AddPersistentGroup ( a{sv} : args ) --> o : path</h3>
+ <p></p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : args</dt>
+ <dd>
+ A dictionary with following parameters:
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th><th>Required</th></tr>
+ <tr><td>bssid</td><td>s</td><td>P2P Device Address of the GO in the persistent group.</td><td>yes</td></tr>
+ <tr><td>ssid</td><td>s</td><td>SSID of the group</td><td>yes</td></tr>
+ <tr><td>psk</td><td>s</td><td>Passphrase (on the GO and optionally on P2P Client) or PSK (on P2P Client if passphrase ise not known)</td><td>yes</td></tr>
+ <tr><td>mode</td><td>s</td><td>"3" on GO or "0" on P2P Client</td><td>yes</td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>RemovePersistentGroup ( o : path ) --> nothing</h3>
+ </li>
+
+ <li>
+ <h3>RemoveAllPersistentGroups ( nothing ) --> nothing</h3>
+ </li>
+</ul>
+
+\subsection dbus_p2pdevice_properties Properties
+
+<ul>
+ <li>
+ <h3>P2PDeviceConfig - a{sv} - (read/write)</h3>
+ <p>Dictionary with following entries. On write, only the included values are changed.</p>
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+ <tr><td>DeviceName</td><td>s</td><td></td></tr>
+ <tr><td>PrimaryDeviceType</td><td>ay</td><td></td></tr>
+ <tr><td>SecondaryDeviceTypes</td><td>aay</td><td></td></tr>
+ <tr><td>VendorExtension</td><td>aay</td><td></td></tr>
+ <tr><td>GOIntent</td><td>u</td><td></td></tr>
+ <tr><td>PersistentReconnect</td><td>b</td><td></td></tr>
+ <tr><td>ListenRegClass</td><td>u</td><td></td></tr>
+ <tr><td>OperRegClass</td><td>u</td><td></td></tr>
+ <tr><td>OperChannel</td><td>u</td><td></td></tr>
+ <tr><td>SsidPostfix</td><td>s</td><td></td></tr>
+ <tr><td>IntraBss</td><td>b</td><td></td></tr>
+ <tr><td>GroupIdle</td><td>u</td><td></td></tr>
+ <tr><td>disassoc_low_ack</td><td>u</td><td></td></tr>
+ <tr><td>NoGroupIface</td><td>b</td><td></td></tr>
+ <tr><td>p2p_search_delay</td><td>u</td><td></td></tr>
+ </table>
+ </li>
+
+ <li>
+ <h3>Peers - ao - (read)</h3>
+ </li>
+
+ <li>
+ <h3>Role - s - (read)</h3>
+ <p>\bug What is this trying to indicate? It does not make much sense to have a P2PDevice property role since there can be multiple concurrent groups and the P2P Device role is always active anyway.</p>
+ </li>
+
+ <li>
+ <h3>Group - o - (read)</h3>
+ <p>\bug What is this trying to indicate? It does not make much sense to have a P2PDevice property Group since there can be multiple concurrent groups.</p>
+ </li>
+
+ <li>
+ <h3>PeerGO - o - (read)</h3>
+ <p>\bug What is this trying to indicate? It does not make much sense to have a P2PDevice property PeerGO since there can be multiple concurrent groups.</p>
+ </li>
+
+ <li>
+ <h3>PersistentGroups - ao - (read)</h3>
+ </li>
+</ul>
+
+\subsection dbus_p2pdevice_signals Signals
+
+<ul>
+ <li>
+ <h3>DeviceFound ( o : path )</h3>
+ </li>
+
+ <li>
+ <h3>DeviceLost ( o : path )</h3>
+ </li>
+
+ <li>
+ <h3>ProvisionDiscoveryRequestDisplayPin ( o : peer_object, s : pin )</h3>
+ </li>
+
+ <li>
+ <h3>ProvisionDiscoveryResponseDisplayPin ( o : peer_object, s : pin )</h3>
+ </li>
+
+ <li>
+ <h3>ProvisionDiscoveryRequestEnterPin ( o : peer_object )</h3>
+ </li>
+
+ <li>
+ <h3>ProvisionDiscoveryResponseEnterPin ( o : peer_object )</h3>
+ </li>
+
+ <li>
+ <h3>ProvisionDiscoveryPBCRequest ( o : peer_object )</h3>
+ </li>
+
+ <li>
+ <h3>ProvisionDiscoveryPBCResponse ( o : peer_object )</h3>
+ </li>
+
+ <li>
+ <h3>ProvisionDiscoveryFailure ( o : peer_object, i : status )</h3>
+ </li>
+
+ <li>
+ <h3>GroupStarted ( a{sv} : properties )</h3>
+ <p>A new P2P group was started or joined.</p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : properties</dt>
+ <dd>A dictionary with following information on the added group:
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+ <tr><td>interface_object</td><td>o</td><td>D-Bus path of the interface on which this group is operating on. See \ref dbus_interface.</td></tr>
+ <tr><td>role</td><td>s</td><td>The role of the local device in the group: "GO" or "client".</td></tr>
+ <tr><td>group_object</td><td>o</td><td>D-Bus path of the group. See \ref dbus_group.</td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>GONegotiationSuccess ( a{sv} : properties )</h3>
+ <p></p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : properties</dt>
+ <dd>A dictionary with following information:
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+ <tr><td>peer_object</td><td>o</td><td>D-Bus path of the peer. See \ref dbus_peer.</td></tr>
+ <tr><td>status</td><td>i</td><td></td></tr>
+ <tr><td>passphrase</td><td>s</td><td>Passphrase for the group. Included only if this device becomes the GO of the group.</td></tr>
+ <tr><td>role_go</td><td>s</td><td>The role of the local device in the group: "GO" or "client".</td></tr>
+ <tr><td>ssid</td><td>ay</td><td></td></tr>
+ <tr><td>peer_device_addr</td><td>ay</td><td></td></tr>
+ <tr><td>peer_interface_addr</td><td>ay</td><td></td></tr>
+ <tr><td>wps_method</td><td>s</td><td></td></tr>
+ <tr><td>frequency_list</td><td>ai</td><td></td></tr>
+ <tr><td>persistent_group</td><td>i</td><td></td></tr>
+ <tr><td>peer_config_timeout</td><td>u</td><td></td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>GONegotiationFailure ( a{sv} : properties )</h3>
+ <p></p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : properties</dt>
+ <dd>A dictionary with following information:
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+ <tr><td>peer_object</td><td>o</td><td>D-Bus path of the peer. See \ref dbus_peer.</td></tr>
+ <tr><td>status</td><td>i</td><td></td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>GONegotiationRequest ( o : path, i : dev_passwd_id )</h3>
+ </li>
+
+ <li>
+ <h3>InvitationResult ( a{sv} : invite_result )</h3>
+ <p></p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : invite_result</dt>
+ <dd>A dictionary with following information:
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+ <tr><td>status</td><td>i</td><td></td></tr>
+ <tr><td>BSSID</td><td>ay</td><td>Optionally present</td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>GroupFinished ( a{sv} : properties )</h3>
+ <p>A P2P group was removed.</p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : properties</dt>
+ <dd>A dictionary with following information of the removed group:
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+ <tr><td>interface_object</td><td>o</td><td>D-Bus path of the interface on which this group is operating on. See \ref dbus_interface.</td></tr>
+ <tr><td>role</td><td>s</td><td>The role of the local device in the group: "GO" or "client".</td></tr>
+ <tr><td>group_object</td><td>o</td><td>D-Bus path of the group. See \ref dbus_group.</td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>ServiceDiscoveryRequest ( a{sv} : sd_request )</h3>
+ <p></p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : sd_request</dt>
+ <dd>A dictionary with following information:
+ <table>
+ <tr><td>peer_object</td><td>o</td><td></td></tr>
+ <tr><td>frequency</td><td>i</td><td></td></tr>
+ <tr><td>dialog_token</td><td>i</td><td></td></tr>
+ <tr><td>update_indicator</td><td>q</td><td></td></tr>
+ <tr><td>tlvs</td><td>ay</td><td></td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>ServiceDiscoveryResponse ( a{sv} : sd_response )</h3>
+ <p></p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : sd_response</dt>
+ <dd>A dictionary with following information:
+ <table>
+ <tr><td>peer_object</td><td>o</td><td></td></tr>
+ <tr><td>update_indicator</td><td>q</td><td></td></tr>
+ <tr><td>tlvs</td><td>ay</td><td></td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>PersistentGroupAdded ( o : path, a{sv} : properties )</h3>
+ <p></p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>o : path</dt>
+ <dd>D-Bus object path for the persistent group. See \ref dbus_persistent_group.</dd>
+ <dt>a{sv} : properties</dt>
+ <dd>A dictionary with following information:
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+ <tr><td>bssid</td><td>s</td><td>P2P Device Address of the GO in the persistent group.</td></tr>
+ <tr><td>ssid</td><td>s</td><td>SSID of the group</td></tr>
+ <tr><td>psk</td><td>s</td><td>Passphrase (on the GO and optionally on P2P Client) or PSK (on P2P Client if passphrase ise not known)</td></tr>
+ <tr><td>disabled</td><td>s</td><td>Set to "2" to indicate special network block use as a P2P persistent group information</td></tr>
+ <tr><td>mode</td><td>s</td><td>"3" on GO or "0" on P2P Client</td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>PersistentGroupRemoved ( o : path )</h3>
+ <p></p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>o : path</dt>
+ <dd>D-Bus object path for the persistent group. See \ref dbus_persistent_group.</dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>WpsFailed ( s : name, a{sv} : args )</h3>
+ <p></p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>s : name</dt>
+ <dd>"fail"</dd>
+ <dt>a{sv} : args</dt>
+ <dd>A dictionary with following information:
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+ <tr><td>msg</td><td>i</td><td></td></tr>
+ <tr><td>config_error</td><td>n</td><td></td></tr>
+ </table>
+ </dd>
+ </dl>
+ </li>
+</ul>
+
\section dbus_bss fi.w1.wpa_supplicant1.BSS
Interface implemented by objects representing a scanned BSSs, i.e.,
@@ -925,6 +1529,13 @@
</table>
</li>
<li>
+ <h3>WPS - a{sv} - (read)</h3>
+ <p>WPS information of the BSS. Empty dictionary indicates no WPS support. Dictionary entries are:</p>
+ <table>
+ <tr><td>Type</td><td>s</td><td>"pbc", "pin", ""</td>
+ </table>
+ </li>
+ <li>
<h3>IEs - ay - (read)</h3>
<p>All IEs of the BSS as a chain of TLVs</p>
</li>
@@ -948,6 +1559,10 @@
<h3>Signal - n - (read)</h3>
<p>Signal strength of the BSS.</p>
</li>
+ <li>
+ <h3>Age - u - (read)</h3>
+ <p>Number of seconds since the BSS was last seen.</p>
+ </li>
</ul>
\subsection dbus_bss_signals Signals
@@ -979,8 +1594,8 @@
</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.
+ <h3>Properties - a{sv} - (read/write)</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>
@@ -998,4 +1613,179 @@
</li>
</ul>
+\section dbus_peer fi.w1.wpa_supplicant1.Peer
+
+Interface implemented by objects representing P2P peer devices.
+
+\subsection dbus_peer_properties Properties
+
+<ul>
+ <li>
+ <h3>DeviceName - s - (read)</h3>
+ </li>
+
+ <li>
+ <h3>PrimaryDeviceType - ay - (read)</h3>
+ </li>
+
+ <li>
+ <h3>config_method - q - (read)</h3>
+ </li>
+
+ <li>
+ <h3>level - i - (read)</h3>
+ </li>
+
+ <li>
+ <h3>devicecapability - y - (read)</h3>
+ </li>
+
+ <li>
+ <h3>groupcapability - y - (read)</h3>
+ <p>Group Capability field from the last frame from which this peer information was updated.
+ \note This field is only for debugging purposes and must not be used to determine whether the peer happens to be operating a group as a GO at the moment.
+ </p>
+ </li>
+
+ <li>
+ <h3>SecondaryDeviceTypes - aay - (read)</h3>
+ </li>
+
+ <li>
+ <h3>VendorExtension - aay - (read)</h3>
+ </li>
+
+ <li>
+ <h3>IEs - ay - (read)</h3>
+ <p>This is a confusingly named property that includes Wi-Fi Display subelements from the peer.
+ \bug This should really be renamed since "IEs" means something completely different..
+ </p>
+ </li>
+
+ <li>
+ <h3>DeviceAddress - ay - (read)</h3>
+ <p>The P2P Device Address of the peer.</p>
+ </li>
+
+ <li>
+ <h3>Groups - ao - (read)</h3>
+ <p>The current groups in which this peer is connected.</p>
+ </li>
+</ul>
+
+\subsection dbus_peer_signals Signals
+
+<ul>
+ <li>
+ <h3>PropertiesChanged ( a{sv} : properties )</h3>
+ <p>Some properties have changed.
+ \deprecated Use org.freedesktop.DBus.Properties.PropertiesChanged instead.</p>
+ \todo Explain how ProertiesChanged signals are supposed to be of any real use with Peer objects (i.e., one signal for multiple peers).
+ <h4>Arguments</h4>
+ <dl>
+ <dt>a{sv} : properties</dt>
+ <dd>A dictionary with pairs of properties names which have changed and their new values.</dd>
+ </dl>
+ </li>
+ </ul>
+
+\section dbus_group fi.w1.wpa_supplicant1.Group
+
+Interface implemented by objects representing active P2P groups.
+
+\subsection dbus_group_properties Properties
+
+<ul>
+ <li>
+ <h3>Members - ao - (read)</h3>
+ <p>Array of D-Bus object paths for the peer devices that are currently connected to the group. This is valid only on the GO device. An empty array is returned in P2P Client role.
+ </li>
+
+ <li>
+ <h3>Group - o - (read)</h3>
+ <p>\todo Why is this here? This D-Bus object path is to this specific group and one needs to know it to fetching this information in the first place..
+ </p>
+ </li>
+
+ <li>
+ <h3>Role - s - (read)</h3>
+ <p>The role of this device in the group: "GO", "client".</p>
+ </li>
+
+ <li>
+ <h3>SSID - ay - (read)</h3>
+ <p>P2P Group SSID.</p>
+ </li>
+
+ <li>
+ <h3>BSSID - ay - (read)</h3>
+ <p>P2P Group BSSID (the P2P Interface Address of the GO).</p>
+ </li>
+
+ <li>
+ <h3>Frequency - q - (read)</h3>
+ <p>The frequency (in MHz) of the group operating channel.</p>
+ </li>
+
+ <li>
+ <h3>Passphrase - s - (read)</h3>
+ <p>Passphrase used in the group. This is always available on the GO. For P2P Client role, this may be available depending on whether the peer GO provided the passphrase during the WPS provisioning step. If not available, an empty string is returned.</p>
+ </li>
+
+ <li>
+ <h3>PSK - ay - (read)</h3>
+ <p>PSK used in the group.</p>
+ </li>
+
+ <li>
+ <h3>WPSVendorExtensions - aay - (read/write)</h3>
+ <p>WPS vendor extension attributes used on the GO. This is valid only the in the GO role. An empty array is returned in P2P Client role. At maximum, 10 separate vendor extension byte arrays can be configured. The GO device will include the configured attributes in WPS exchanges.</p>
+ </li>
+</ul>
+
+\subsection dbus_group_signals Signals
+
+<ul>
+ <li>
+ <h3>PeerJoined ( o : peer )</h3>
+ <p>A peer device has joined the group. This is indicated only on the GO device.</p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>o : peer</dt>
+ <dd>A D-Bus path to the object representing the peer. See \ref dbus_peer.</dd>
+ </dl>
+ </li>
+
+ <li>
+ <h3>PeerDisconnected ( o : peer )</h3>
+ <p>A peer device has left the group. This is indicated only on the GO device.</p>
+ <h4>Arguments</h4>
+ <dl>
+ <dt>o : peer</dt>
+ <dd>A D-Bus path to the object representing the peer. See \ref dbus_peer.</dd>
+ </dl>
+ </li>
+</ul>
+
+\section dbus_persistent_group fi.w1.wpa_supplicant1.PersistentGroup
+
+Interface implemented by objects representing persistent P2P groups.
+
+\subsection dbus_persistent_group_properties Properties
+
+<ul>
+ <li>
+ <h3>Properties - a{sv} - (read/write)</h3>
+ <p>Properties of the persistent group. These are same properties as in the \ref dbus_network. When writing this, only the entries to be modified are included, i.e., any item that is not included will be left at its existing value. The following entries are used for persistent groups:</p>
+ <table>
+ <tr><th>Key</th><th>Value type</th><th>Description</th></tr>
+ <tr><td>bssid</td><td>s</td><td>P2P Device Address of the GO in the persistent group.</td></tr>
+ <tr><td>ssid</td><td>s</td><td>SSID of the group</td></tr>
+ <tr><td>psk</td><td>s</td><td>Passphrase (on the GO and optionally on P2P Client) or PSK (on P2P Client if passphrase ise not known)</td></tr>
+ <tr><td>disabled</td><td>s</td><td>Set to "2" to indicate special network block use as a P2P persistent group information</td></tr>
+ <tr><td>mode</td><td>s</td><td>"3" on GO or "0" on P2P Client</td></tr>
+ </table>
+ </li>
+</ul>
+
*/
diff --git a/doc/directories.doxygen b/doc/directories.doxygen
index 7465afe..15e5bda 100644
--- a/doc/directories.doxygen
+++ b/doc/directories.doxygen
@@ -82,9 +82,9 @@
functionality needed to implement Wi-Fi Protected Setup.
-\dir wpa_supplicant %wpa_supplicant
+\dir wpa_supplicant wpa_supplicant
-%wpa_supplicant-specific code for configuration, control interface, and
+wpa_supplicant-specific code for configuration, control interface, and
client management.
*/
diff --git a/doc/doxygen.conf b/doc/doxygen.conf
index b8c40e3..06be6a5 100644
--- a/doc/doxygen.conf
+++ b/doc/doxygen.conf
@@ -31,7 +31,7 @@
# This could be handy for archiving the generated documentation or
# if some version control system is used.
-PROJECT_NUMBER = 2.0
+PROJECT_NUMBER = 2.4
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
@@ -572,6 +572,8 @@
doc \
hostapd \
wpa_supplicant \
+ wpa_supplicant/dbus \
+ eap_example \
src/ap \
src/common \
src/crypto \
@@ -583,6 +585,7 @@
src/eap_server \
src/l2_packet \
src/p2p \
+ src/pae \
src/radius \
src/rsn_supp \
src/tls \
@@ -1533,3 +1536,12 @@
# the various graphs.
DOT_CLEANUP = YES
+
+
+#---------------------------------------------------------------------------
+# Project additions
+#---------------------------------------------------------------------------
+
+# Disable autolink support due to wpa_supplicant getting unfortunately
+# auto-linked to struct wpa_supplicant due to having an underscore in the name.
+AUTOLINK_SUPPORT = FALSE
diff --git a/doc/driver_wrapper.doxygen b/doc/driver_wrapper.doxygen
index 28aea50..a3b470a 100644
--- a/doc/driver_wrapper.doxygen
+++ b/doc/driver_wrapper.doxygen
@@ -3,7 +3,7 @@
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
+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
@@ -13,45 +13,45 @@
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
+can be replaced with generic code in \ref 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
+defined in \ref driver.h. These functions are registered by filling struct
+\ref 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.
+callback function, \ref wpa_supplicant_event(), and its parameters are
+documented in \ref driver.h. In addition, a pointer to the 'struct
+\ref wpa_driver_ops' needs to be registered in \ref 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
+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
+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
+\ref 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.
+\ref driver_hostap.c. These files need to define struct \ref wpa_driver_ops
+entry that will be used in \ref wpa_supplicant.c when calling driver
+functions. struct \ref wpa_driver_ops entries are registered in \ref 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)
+one. \ref driver_hostap.c and \ref driver_wext.c include a complete
+implementation for Linux drivers that use wpa_supplicant-based control
+of WPA IE and roaming. \ref driver_ndis.c (with help from \ref 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.
@@ -61,7 +61,7 @@
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.
+wpa_supplicant.
\subsection driver_tkip_ccmp TKIP/CCMP
@@ -86,12 +86,12 @@
\subsection driver_roaming Roaming control and scanning support
-%wpa_supplicant can optionally control AP selection based on the
+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
+recommended. The current driver wrapper (\ref driver_wext.c) uses this for
scan results.
Scan results must also include the WPA information element. Support for
@@ -99,9 +99,9 @@
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
+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
+\ref driver_hostap.c wrapper uses following sequence for this
request. Similar/identical mechanism should be usable also with other
drivers.
@@ -113,28 +113,28 @@
\subsection driver_wpa_ie WPA IE generation
-%wpa_supplicant selects which cipher suites and key management suites
+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
+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
+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
+\ref 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
+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).
+details are defined in \ref driver.h (\ref wpa_supplicant_event() function
+and enum \ref wpa_event_type).
On Linux, association and disassociation can use existing Wireless
Extensions event that is reporting new AP with SIOCGIWAP
@@ -153,18 +153,18 @@
ap_scan=1:
-- %wpa_supplicant requests scan with SIOCSIWSCAN
+- wpa_supplicant requests scan with SIOCSIWSCAN
- driver reports scan complete with wireless event SIOCGIWSCAN
-- %wpa_supplicant reads scan results with SIOCGIWSCAN (multiple call if
+- 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
+- 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
+- wpa_supplicant configures driver to associate with an SSID
(SIOCSIWMODE, SIOCSIWGENIE, SIOCSIWAUTH, SIOCSIWESSID)
@@ -174,7 +174,7 @@
(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
+- wpa_supplicant takes care of EAPOL frame handling (validating
information from associnfo and if needed, from scan results if WPA/RSN
IE from the Beacon frame is not reported through associnfo)
*/
diff --git a/doc/eap.doxygen b/doc/eap.doxygen
index 6a24829..fc7ea26 100644
--- a/doc/eap.doxygen
+++ b/doc/eap.doxygen
@@ -2,44 +2,44 @@
\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
+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.
+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
+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
+file named eap_<name of the method>.c, e.g., \ref 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
+\ref eap_peer_register_methods() function of \ref 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 methods must implement the interface defined in \ref 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
+functions, \ref eap_msg_alloc() and \ref 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
@@ -48,23 +48,23 @@
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
+\ref 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
+\ref 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
+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
+\ref eap_example_peer.c shows the initialization and glue code needed to
+control the EAP peer implementation. \ref eap_example_server.c does the
+same for EAP server. \ref eap_example.c is an example that ties in both the
EAP server and client parts to allow an EAP authentication to be
shown.
@@ -77,9 +77,9 @@
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
+The EAP library links in number of helper functions from \ref src/utils and
+\ref src/crypto directories. Most of these are suitable as-is, but it may
+be desirable to replace the debug output code in \ref src/utils/wpa_debug.c
by dropping this file from the library and re-implementing the
functions there in a way that better fits in with the main
application.
diff --git a/doc/eap_server.doxygen b/doc/eap_server.doxygen
index 4aca53d..f60ac79 100644
--- a/doc/eap_server.doxygen
+++ b/doc/eap_server.doxygen
@@ -14,32 +14,32 @@
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
+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
+file named eap_server_<name of the method>.c, e.g., \ref eap_server_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
+\ref eap_server_register_methods() function of \ref eap_server_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
+EAP methods must implement the interface defined in \ref eap_i.h. struct
+\ref 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
+functions, \ref eap_msg_alloc() and \ref 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
@@ -48,9 +48,9 @@
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
+\ref 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
+\ref eap_server_vendor_test.c for an example of an EAP method implementation that
is implemented as an expanded type.
*/
diff --git a/doc/hostapd_ctrl_iface.doxygen b/doc/hostapd_ctrl_iface.doxygen
index ae778bc..4d2bac8 100644
--- a/doc/hostapd_ctrl_iface.doxygen
+++ b/doc/hostapd_ctrl_iface.doxygen
@@ -4,58 +4,58 @@
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
+a small C library, in a form of a single C file, \ref 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
+the library functions documented in \ref wpa_ctrl.h to interact with
+wpa_supplicant. This library can also be used with C++. \ref 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
+control interface. The use of the functions defined in \ref 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
+communicate with hostapd should link in \ref 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().
+interface with \ref wpa_ctrl_open() and to send commands with
+\ref 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().
+hostapd. These can be executed using \ref 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
+attach to the control interface with \ref 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,
+\ref 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
+control interface connections by calling \ref 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
+not be broken by unsolicited messages. \ref wpa_cli.c 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
+be closed by calling \ref wpa_ctrl_close(). If the connection was used for
unsolicited event messages, it should be first detached by calling
-wpa_ctrl_detach().
+\ref wpa_ctrl_detach().
\section ctrl_iface_cmds Control interface commands
-Following commands can be used with wpa_ctrl_request():
+Following commands can be used with \ref wpa_ctrl_request():
\subsection ctrl_iface_PING PING
diff --git a/doc/mainpage.doxygen b/doc/mainpage.doxygen
index 26dc929..329afea 100644
--- a/doc/mainpage.doxygen
+++ b/doc/mainpage.doxygen
@@ -3,17 +3,17 @@
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
+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
+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
+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
@@ -22,14 +22,14 @@
\section _wpa_supplicant wpa_supplicant
-%wpa_supplicant is a WPA Supplicant for Linux, BSD and Windows with
+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
+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
@@ -41,15 +41,15 @@
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
+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
+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
+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++.
diff --git a/doc/p2p.doxygen b/doc/p2p.doxygen
index 27656eb..c1a81db 100644
--- a/doc/p2p.doxygen
+++ b/doc/p2p.doxygen
@@ -3,7 +3,7 @@
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,
+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.
@@ -19,16 +19,16 @@
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
+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.
+\ref src/p2p/p2p.h.
Provisioning step of Group Formation is implemented using WPS
-(src/wps/wps.h).
+(\ref 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
+wpa_supplicant includes code in interact with both the P2P module
+(\ref wpa_supplicant/p2p_supplicant.c) and WPS
+(\ref 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.
@@ -48,7 +48,7 @@
\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,
+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.
@@ -82,7 +82,7 @@
\subsection p2p_module_api P2P module API
-P2P module API is defined in src/p2p/p2p.h. The API consists of
+P2P module API is defined in \ref 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
@@ -92,51 +92,51 @@
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()
+- \ref p2p_find()
+- \ref p2p_stop_find()
+- \ref p2p_listen()
+- \ref p2p_connect()
+- \ref p2p_reject()
+- \ref p2p_prov_disc_req()
+- \ref p2p_sd_request()
+- \ref p2p_sd_cancel_request()
+- \ref p2p_sd_response()
+- \ref p2p_sd_service_update()
+- \ref 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()
+- \ref p2p_config::dev_found()
+- \ref p2p_config::go_neg_req_rx()
+- \ref p2p_config::go_neg_completed()
+- \ref p2p_config::sd_request()
+- \ref p2p_config::sd_response()
+- \ref p2p_config::prov_disc_req()
+- \ref p2p_config::prov_disc_resp()
+- \ref p2p_config::invitation_process()
+- \ref p2p_config::invitation_received()
+- \ref 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()
+- \ref p2p_config::p2p_scan()
+- \ref p2p_config::send_probe_resp()
+- \ref p2p_config::send_action()
+- \ref p2p_config::send_action_done()
+- \ref p2p_config::start_listen()
+- \ref 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()
+- \ref p2p_probe_req_rx()
+- \ref p2p_rx_action()
+- \ref p2p_scan_res_handler()
+- \ref p2p_scan_res_handled()
+- \ref p2p_send_action_cb()
+- \ref 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
@@ -144,39 +144,36 @@
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()
+- \ref p2p_group_notif_assoc()
+- \ref p2p_group_notif_disassoc()
+- \ref p2p_group_notif_formation_done()
+- \ref 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()
+- \ref 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()
+within wpa_supplicant:
+- \ref wpa_driver_ops::if_add()
+- \ref wpa_driver_ops::if_remove()
+- \ref wpa_driver_ops::remain_on_channel()
+- \ref wpa_driver_ops::cancel_remain_on_channel()
+- \ref wpa_driver_ops::send_action()
+- \ref wpa_driver_ops::probe_req_report()
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
+wpa_supplicant:
+- \ref wpa_event_type::EVENT_RX_MGMT
+- \ref wpa_event_type::EVENT_REMAIN_ON_CHANNEL
+- \ref wpa_event_type::EVENT_CANCEL_REMAIN_ON_CHANNEL
+- \ref wpa_event_type::EVENT_RX_PROBE_REQ
\section p2p_go_neg P2P device discovery and group formation
@@ -188,40 +185,40 @@
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
+calling \ref p2p_find(). The P2P module start the discovery by requesting a
+full scan to be completed by calling \ref p2p_config::p2p_scan(). Results
+from the scan will be reported by calling \ref 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.
+call to \ref p2p_scan_res_handled(). The P2P peers that are found during
+the full scan are reported with the \ref 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().
+terminated, e.g., with a call to \ref 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
+\ref 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
+\ref 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
+\ref p2p_config::p2p_probe_req_rx() and P2P module request a response to
+these to be sent by using \ref 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.
+upper layer code with the \ref 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
+i.e., the P2P module will call \ref 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.
+\ref p2p_scan_res_handler() and \ref 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
+negotiation by calling \ref 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
@@ -231,25 +228,25 @@
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
+\ref p2p_prov_disc_req(). The response to this will be reported with the
+\ref 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
+\ref 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
+generate the PIN and to configure it with following \ref p2p_connect() call
to actually authorize the connection.
-The P2P module will use p2p_config::send_action() callback to request
+The P2P module will use \ref 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
+negotiation. \ref 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
+be reported with the \ref 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
@@ -258,15 +255,15 @@
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
+to \ref 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.
+calling \ref 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
+a call to \ref 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.
@@ -289,23 +286,23 @@
\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
+part of the device discovery phase. \ref 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
+discovered peers. \ref 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
+is started with a call to \ref 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.
+\ref 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().
+\ref p2p_config::sd_request() callback. The response to the query is sent
+by calling \ref p2p_sd_response().
\subsection p2p_sd_indicator Service update indicator
@@ -314,9 +311,9 @@
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
+\ref p2p_config::sd_request() and \ref 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
+\ref p2p_sd_service_update() whenever availibility of the local services
changes.
@@ -329,29 +326,29 @@
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
+data is initialized with \ref 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()
+per-group operation. The configured \ref 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
+case of manual group setup), \ref 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
+\ref p2p_group_notif_assoc() and \ref 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
+clients. The \ref 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
+can use \ref 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
@@ -359,13 +356,13 @@
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
+\ref 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
+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
@@ -414,11 +411,11 @@
\subsection p2p_wpa_cli wpa_cli example
-wpa_cli can be used to control %wpa_supplicant in interactive
+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.
+lines starting with "<2>" are event messages from wpa_supplicant.
P2P device "Wireless Client":
diff --git a/doc/porting.doxygen b/doc/porting.doxygen
index 7ea6a34..b4b78ef 100644
--- a/doc/porting.doxygen
+++ b/doc/porting.doxygen
@@ -1,14 +1,14 @@
/**
\page porting Porting to different target boards and operating systems
-%wpa_supplicant was designed to be easily portable to different
+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
+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,
+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.
@@ -16,48 +16,48 @@
\section ansi_c_extra Extra functions on top of ANSI C
-%wpa_supplicant is mostly using ANSI C functions that are available on
+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
+prototypes in \ref 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
+definitions in \ref 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
+available. In addition, \ref os.h defines couple of common platform
+specific functions that are implemented in \ref os_unix.c for UNIX like
+targets and in \ref 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
+platform needs different versions of the functions, \ref 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
+\ref 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
+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
+a suitable source depending on the target platform. \ref 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
+The included \ref config_file.c backend uses a text file for configuration
+and \ref 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
+\ref config_none.c can be used as an empty starting point for building a
new configuration backend.
@@ -69,19 +69,19 @@
(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.
+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
+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.
+and RSN pre-authentication 0x88c7. \ref 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
+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
@@ -89,26 +89,27 @@
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
+The main wpa_supplicant repository includes l2_packet implementations
+for Linux using packet sockets (\ref l2_packet_linux.c), more portable
+version using libpcap/libdnet libraries (\ref l2_packet_pcap.c; this
supports WinPcap, too), and FreeBSD specific version of libpcap
-interface (l2_packet_freebsd.c).
+interface (\ref 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
+libdnet (sending), \ref 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
+added. Alternatively, for hostapd,
+struct \ref wpa_driver_ops::hapd_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
+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
+signal). eloop.h defines the event loop interface. \ref 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
@@ -117,64 +118,64 @@
\section ctrl_iface_porting Control interface
-%wpa_supplicant uses a \ref ctrl_iface_page "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
+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.
+The wpa_supplicant side of the control interface is implemented in
+\ref wpa_supplicant/ctrl_iface.c. Matching client side is implemented as a control
+interface library in \ref wpa_ctrl.c.
\section entry_point Program entry point
-%wpa_supplicant defines a set of functions that can be used to
+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.
+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.
+\ref 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. \ref wpa_supplicant/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
+\ref 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
+wpa_supplicant context is initialized with a call to
+\ref wpa_supplicant_init(). After this, existing network interfaces can be
+added with \ref wpa_supplicant_add_iface(). \ref 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
+termination time, \ref wpa_supplicant_deinit() is used to release global
context data.
-wpa_supplicant_add_iface() and wpa_supplicant_remove_iface() can be
+\ref wpa_supplicant_add_iface() and \ref 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.,
+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
+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
+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:
+wpa_supplicant:
\verbatim
cc -o wpa_supplicant config.c eloop.c common.c md5.c rc4.c sha1.c \
@@ -192,7 +193,7 @@
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),
+registration in \ref 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.
diff --git a/doc/testing_tools.doxygen b/doc/testing_tools.doxygen
index 774bafb..d126524 100644
--- a/doc/testing_tools.doxygen
+++ b/doc/testing_tools.doxygen
@@ -6,7 +6,7 @@
\ref unit_tests "Unit tests" |
\ref wpa_trace "Tracing code" ]
-%wpa_supplicant source tree includes number of testing and development
+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.
@@ -14,7 +14,7 @@
\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
+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
@@ -34,7 +34,7 @@
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
+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:
@@ -77,7 +77,7 @@
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.
+network blocks as wpa_supplicant.
\section preauth_test preauth_test - WPA2 pre-authentication and EAP peer testing
@@ -85,8 +85,8 @@
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
+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:
@@ -112,7 +112,7 @@
\section unit_tests Unit tests
-Number of the components (.c files) used in %wpa_supplicant define
+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
@@ -131,7 +131,7 @@
\section wpa_trace Tracing code for developer debuggin
-%wpa_supplicant and hostapd can be built with tracing code that will
+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
diff --git a/eap_example/dh.conf b/eap_example/dh.conf
new file mode 100644
index 0000000..7bc8325
--- /dev/null
+++ b/eap_example/dh.conf
@@ -0,0 +1,5 @@
+-----BEGIN DH PARAMETERS-----
+MIGHAoGBAP3V8IHq3H2DUlYywsvjYNuS17eCdt0mJo6/os6PHqdhgkMrPxF9u4Gr
+qKXq9e6GqmZYdjta30N3FkXaV924BJ0xOqb2TntiKg4u50/l6hSUneWt6UFBaizd
+XrqjNFIme/5RXMZ7RglXliBpCepAaFLMcKhOS4ulUyYYHSy+oqRjAgEC
+-----END DH PARAMETERS-----
diff --git a/eap_example/eap_example_server.c b/eap_example/eap_example_server.c
index 7097bca..a081b87 100644
--- a/eap_example/eap_example_server.c
+++ b/eap_example/eap_example_server.c
@@ -81,6 +81,7 @@
/* tparams.private_key = "server.key"; */
tparams.private_key = "server-key.pem";
/* tparams.private_key_passwd = "whatever"; */
+ tparams.dh_file = "dh.conf";
if (tls_global_set_params(eap_ctx.tls_ctx, &tparams)) {
printf("Failed to set TLS parameters\n");
diff --git a/hostapd/Android.mk b/hostapd/Android.mk
index d6d04c5..78a1506 100644
--- a/hostapd/Android.mk
+++ b/hostapd/Android.mk
@@ -134,6 +134,7 @@
OBJS += src/common/ieee802_11_common.c
OBJS += src/common/wpa_common.c
+OBJS += src/common/hw_features_common.c
OBJS += src/eapol_auth/eapol_auth_sm.c
@@ -180,8 +181,6 @@
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
@@ -214,6 +213,11 @@
NEED_AES_OMAC1=y
endif
+ifdef CONFIG_SUITEB192
+L_CFLAGS += -DCONFIG_SUITEB192
+NEED_SHA384=y
+endif
+
ifdef CONFIG_IEEE80211W
L_CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y
@@ -554,33 +558,6 @@
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_internal.c
-OBJS += src/crypto/sha1-internal.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
@@ -687,7 +664,9 @@
AESOBJS += src/crypto/aes-internal.c src/crypto/aes-internal-enc.c
endif
+ifneq ($(CONFIG_TLS), openssl)
AESOBJS += src/crypto/aes-wrap.c
+endif
ifdef NEED_AES_EAX
AESOBJS += src/crypto/aes-eax.c
NEED_AES_CTR=y
@@ -702,13 +681,17 @@
AESOBJS += src/crypto/aes-omac1.c
endif
ifdef NEED_AES_UNWRAP
+ifneq ($(CONFIG_TLS), openssl)
NEED_AES_DEC=y
AESOBJS += src/crypto/aes-unwrap.c
endif
+endif
ifdef NEED_AES_CBC
NEED_AES_DEC=y
+ifneq ($(CONFIG_TLS), openssl)
AESOBJS += src/crypto/aes-cbc.c
endif
+endif
ifdef NEED_AES_DEC
ifdef CONFIG_INTERNAL_AES
AESOBJS += src/crypto/aes-internal-dec.c
@@ -745,6 +728,10 @@
OBJS += $(SHA1OBJS)
endif
+ifneq ($(CONFIG_TLS), openssl)
+OBJS += src/crypto/md5.c
+endif
+
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
OBJS += src/crypto/md5-internal.c
@@ -783,6 +770,9 @@
OBJS += src/crypto/sha256-tlsprf.c
endif
endif
+ifdef NEED_SHA384
+L_CFLAGS += -DCONFIG_SHA384
+endif
ifdef NEED_DH_GROUPS
OBJS += src/crypto/dh_groups.c
@@ -807,8 +797,10 @@
HOBJS += src/crypto/random.c
HOBJS += src/utils/eloop.c
HOBJS += $(SHA1OBJS)
+ifneq ($(CONFIG_TLS), openssl)
HOBJS += src/crypto/md5.c
endif
+endif
ifdef CONFIG_RADIUS_SERVER
L_CFLAGS += -DRADIUS_SERVER
diff --git a/hostapd/ChangeLog b/hostapd/ChangeLog
index f0e4604..e6f8c6a 100644
--- a/hostapd/ChangeLog
+++ b/hostapd/ChangeLog
@@ -1,5 +1,49 @@
ChangeLog for hostapd
+2015-03-15 - v2.4
+ * allow OpenSSL cipher configuration to be set for internal EAP server
+ (openssl_ciphers parameter)
+ * fixed number of small issues based on hwsim test case failures and
+ static analyzer reports
+ * fixed Accounting-Request to not include duplicated Acct-Session-Id
+ * add support for Acct-Multi-Session-Id in RADIUS Accounting messages
+ * add support for PMKSA caching with SAE
+ * add support for generating BSS Load element (bss_load_update_period)
+ * fixed channel switch from VHT to HT
+ * add INTERFACE-ENABLED and INTERFACE-DISABLED ctrl_iface events
+ * add support for learning STA IPv4/IPv6 addresses and configuring
+ ProxyARP support
+ * dropped support for the madwifi driver interface
+ * add support for Suite B (128-bit and 192-bit level) key management and
+ cipher suites
+ * fixed a regression with driver=wired
+ * extend EAPOL-Key msg 1/4 retry workaround for changing SNonce
+ * add BSS_TM_REQ ctrl_iface command to send BSS Transition Management
+ Request frames and BSS-TM-RESP event to indicate response to such
+ frame
+ * add support for EAP Re-Authentication Protocol (ERP)
+ * fixed AP IE in EAPOL-Key 3/4 when both WPA and FT was enabled
+ * fixed a regression in HT 20/40 coex Action frame parsing
+ * set stdout to be line-buffered
+ * add support for vendor specific VHT extension to enable 256 QAM rates
+ (VHT-MCS 8 and 9) on 2.4 GHz band
+ * RADIUS DAS:
+ - extend Disconnect-Request processing to allow matching of multiple
+ sessions
+ - support Acct-Multi-Session-Id as an identifier
+ - allow PMKSA cache entry to be removed without association
+ * expire hostapd STA entry if kernel does not have a matching entry
+ * allow chanlist to be used to specify a subset of channels for ACS
+ * improve ACS behavior on 2.4 GHz band and allow channel bias to be
+ configured with acs_chan_bias parameter
+ * do not reply to a Probe Request frame that includes DSS Parameter Set
+ element in which the channel does not match the current operating
+ channel
+ * add UPDATE_BEACON ctrl_iface command; this can be used to force Beacon
+ frame contents to be updated and to start beaconing on an interface
+ that used start_disabled=1
+ * fixed some RADIUS server failover cases
+
2014-10-09 - v2.3
* fixed number of minor issues identified in static analyzer warnings
* fixed DFS and channel switch operation for multi-BSS cases
diff --git a/hostapd/Makefile b/hostapd/Makefile
index f10556b..b95cbcd 100644
--- a/hostapd/Makefile
+++ b/hostapd/Makefile
@@ -6,6 +6,7 @@
CFLAGS = -MMD -O2 -Wall -g
endif
+CFLAGS += $(EXTRA_CFLAGS)
CFLAGS += -I$(abspath ../src)
CFLAGS += -I$(abspath ../src/utils)
@@ -115,6 +116,7 @@
OBJS += ../src/common/ieee802_11_common.o
OBJS += ../src/common/wpa_common.o
+OBJS += ../src/common/hw_features_common.o
OBJS += ../src/eapol_auth/eapol_auth_sm.o
@@ -169,8 +171,6 @@
OBJS += ../src/ap/ctrl_iface_ap.o
endif
-OBJS += ../src/crypto/md5.o
-
CFLAGS += -DCONFIG_CTRL_IFACE -DCONFIG_CTRL_IFACE_UNIX
ifdef CONFIG_IAPP
@@ -203,6 +203,11 @@
NEED_AES_OMAC1=y
endif
+ifdef CONFIG_SUITEB192
+CFLAGS += -DCONFIG_SUITEB192
+NEED_SHA384=y
+endif
+
ifdef CONFIG_IEEE80211W
CFLAGS += -DCONFIG_IEEE80211W
NEED_SHA256=y
@@ -222,6 +227,7 @@
OBJS += ../src/common/sae.o
NEED_ECC=y
NEED_DH_GROUPS=y
+NEED_AP_MLME=y
endif
ifdef CONFIG_WNM
@@ -548,33 +554,6 @@
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_internal.o
-SHA1OBJS += ../src/crypto/sha1-internal.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
@@ -681,7 +660,9 @@
AESOBJS += ../src/crypto/aes-internal.o ../src/crypto/aes-internal-enc.o
endif
+ifneq ($(CONFIG_TLS), openssl)
AESOBJS += ../src/crypto/aes-wrap.o
+endif
ifdef NEED_AES_EAX
AESOBJS += ../src/crypto/aes-eax.o
NEED_AES_CTR=y
@@ -696,13 +677,17 @@
AESOBJS += ../src/crypto/aes-omac1.o
endif
ifdef NEED_AES_UNWRAP
+ifneq ($(CONFIG_TLS), openssl)
NEED_AES_DEC=y
AESOBJS += ../src/crypto/aes-unwrap.o
endif
+endif
ifdef NEED_AES_CBC
NEED_AES_DEC=y
+ifneq ($(CONFIG_TLS), openssl)
AESOBJS += ../src/crypto/aes-cbc.o
endif
+endif
ifdef NEED_AES_DEC
ifdef CONFIG_INTERNAL_AES
AESOBJS += ../src/crypto/aes-internal-dec.o
@@ -738,6 +723,10 @@
OBJS += $(SHA1OBJS)
endif
+ifneq ($(CONFIG_TLS), openssl)
+OBJS += ../src/crypto/md5.o
+endif
+
ifdef NEED_MD5
ifdef CONFIG_INTERNAL_MD5
OBJS += ../src/crypto/md5-internal.o
@@ -779,6 +768,9 @@
OBJS += ../src/crypto/sha256-kdf.o
endif
endif
+ifdef NEED_SHA384
+CFLAGS += -DCONFIG_SHA384
+endif
ifdef NEED_DH_GROUPS
OBJS += ../src/crypto/dh_groups.o
@@ -803,8 +795,10 @@
HOBJS += ../src/crypto/random.o
HOBJS += ../src/utils/eloop.o
HOBJS += $(SHA1OBJS)
+ifneq ($(CONFIG_TLS), openssl)
HOBJS += ../src/crypto/md5.o
endif
+endif
ifdef CONFIG_RADIUS_SERVER
CFLAGS += -DRADIUS_SERVER
@@ -969,7 +963,8 @@
$(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
+NOBJS = nt_password_hash.o ../src/crypto/ms_funcs.o $(SHA1OBJS)
+NOBJS += ../src/utils/common.o
ifdef NEED_RC4
ifdef CONFIG_INTERNAL_RC4
NOBJS += ../src/crypto/rc4.o
diff --git a/hostapd/README b/hostapd/README
index ea016cc..366b199 100644
--- a/hostapd/README
+++ b/hostapd/README
@@ -2,7 +2,7 @@
Authenticator and RADIUS authentication server
================================================================
-Copyright (c) 2002-2014, Jouni Malinen <j@w1.fi> and contributors
+Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> and contributors
All Rights Reserved.
This program is licensed under the BSD license (the one with
diff --git a/hostapd/config_file.c b/hostapd/config_file.c
index a12f4a0..6846b99 100644
--- a/hostapd/config_file.c
+++ b/hostapd/config_file.c
@@ -1,6 +1,6 @@
/*
* hostapd / Configuration file parser
- * Copyright (c) 2003-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2003-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -216,15 +216,21 @@
FILE *f;
char buf[512], *pos, *start, *pos2;
int line = 0, ret = 0, num_methods;
- struct hostapd_eap_user *user = NULL, *tail = NULL;
+ struct hostapd_eap_user *user = NULL, *tail = NULL, *new_user = NULL;
if (!fname)
return 0;
if (os_strncmp(fname, "sqlite:", 7) == 0) {
+#ifdef CONFIG_SQLITE
os_free(conf->eap_user_sqlite);
conf->eap_user_sqlite = os_strdup(fname + 7);
return 0;
+#else /* CONFIG_SQLITE */
+ wpa_printf(MSG_ERROR,
+ "EAP user file in SQLite DB, but CONFIG_SQLITE was not enabled in the build.");
+ return -1;
+#endif /* CONFIG_SQLITE */
}
f = fopen(fname, "r");
@@ -494,7 +500,7 @@
done:
if (tail == NULL) {
- tail = conf->eap_user = user;
+ tail = new_user = user;
} else {
tail->next = user;
tail = user;
@@ -510,6 +516,18 @@
fclose(f);
+ if (ret == 0) {
+ user = conf->eap_user;
+ while (user) {
+ struct hostapd_eap_user *prev;
+
+ prev = user;
+ user = user->next;
+ hostapd_config_free_eap_user(prev);
+ }
+ conf->eap_user = new_user;
+ }
+
return ret;
}
#endif /* EAP_SERVER */
@@ -680,8 +698,14 @@
else if (os_strcmp(start, "FT-SAE") == 0)
val |= WPA_KEY_MGMT_FT_SAE;
#endif /* CONFIG_SAE */
+#ifdef CONFIG_SUITEB
else if (os_strcmp(start, "WPA-EAP-SUITE-B") == 0)
val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B;
+#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+ else if (os_strcmp(start, "WPA-EAP-SUITE-B-192") == 0)
+ val |= WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+#endif /* CONFIG_SUITEB192 */
else {
wpa_printf(MSG_ERROR, "Line %d: invalid key_mgmt '%s'",
line, start);
@@ -757,6 +781,24 @@
}
+static int hostapd_parse_chanlist(struct hostapd_config *conf, char *val)
+{
+ char *pos;
+
+ /* for backwards compatibility, translate ' ' in conf str to ',' */
+ pos = val;
+ while (pos) {
+ pos = os_strchr(pos, ' ');
+ if (pos)
+ *pos++ = ',';
+ }
+ if (freq_range_list_parse(&conf->acs_ch_list, val))
+ return -1;
+
+ return 0;
+}
+
+
static int hostapd_parse_intlist(int **int_list, char *val)
{
int *list;
@@ -1681,7 +1723,7 @@
char *str;
str = wpa_config_parse_string(pos, &slen);
- if (str == NULL || slen < 1 || slen > HOSTAPD_MAX_SSID_LEN) {
+ if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) {
wpa_printf(MSG_ERROR, "Line %d: Invalid SSID '%s'", line, pos);
os_free(str);
return -1;
@@ -1838,6 +1880,48 @@
#endif /* CONFIG_WPS_NFC */
+#ifdef CONFIG_ACS
+static int hostapd_config_parse_acs_chan_bias(struct hostapd_config *conf,
+ char *pos)
+{
+ struct acs_bias *bias = NULL, *tmp;
+ unsigned int num = 0;
+ char *end;
+
+ while (*pos) {
+ tmp = os_realloc_array(bias, num + 1, sizeof(*bias));
+ if (!tmp)
+ goto fail;
+ bias = tmp;
+
+ bias[num].channel = atoi(pos);
+ if (bias[num].channel <= 0)
+ goto fail;
+ pos = os_strchr(pos, ':');
+ if (!pos)
+ goto fail;
+ pos++;
+ bias[num].bias = strtod(pos, &end);
+ if (end == pos || bias[num].bias < 0.0)
+ goto fail;
+ pos = end;
+ if (*pos != ' ' && *pos != '\0')
+ goto fail;
+ num++;
+ }
+
+ os_free(conf->acs_chan_bias);
+ conf->acs_chan_bias = bias;
+ conf->num_acs_chan_bias = num;
+
+ return 0;
+fail:
+ os_free(bias);
+ return -1;
+}
+#endif /* CONFIG_ACS */
+
+
static int hostapd_config_fill(struct hostapd_config *conf,
struct hostapd_bss_config *bss,
char *buf, char *pos, int line)
@@ -1886,7 +1970,7 @@
line);
} else if (os_strcmp(buf, "ssid") == 0) {
bss->ssid.ssid_len = os_strlen(pos);
- if (bss->ssid.ssid_len > HOSTAPD_MAX_SSID_LEN ||
+ if (bss->ssid.ssid_len > SSID_MAX_LEN ||
bss->ssid.ssid_len < 1) {
wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
line, pos);
@@ -1897,7 +1981,7 @@
} 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) {
+ if (str == NULL || slen < 1 || slen > SSID_MAX_LEN) {
wpa_printf(MSG_ERROR, "Line %d: invalid SSID '%s'",
line, pos);
os_free(str);
@@ -2129,6 +2213,14 @@
os_free(bss->nas_identifier);
bss->nas_identifier = os_strdup(pos);
#ifndef CONFIG_NO_RADIUS
+ } else if (os_strcmp(buf, "radius_client_addr") == 0) {
+ if (hostapd_parse_ip_addr(pos, &bss->radius->client_addr)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid IP address '%s'",
+ line, pos);
+ return 1;
+ }
+ bss->radius->force_client_addr = 1;
} else if (os_strcmp(buf, "auth_server_addr") == 0) {
if (hostapd_config_read_radius_addr(
&bss->radius->auth_servers,
@@ -2140,6 +2232,15 @@
return 1;
}
} else if (bss->radius->auth_server &&
+ os_strcmp(buf, "auth_server_addr_replace") == 0) {
+ if (hostapd_parse_ip_addr(pos,
+ &bss->radius->auth_server->addr)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid IP address '%s'",
+ line, pos);
+ return 1;
+ }
+ } 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 &&
@@ -2165,6 +2266,15 @@
return 1;
}
} else if (bss->radius->acct_server &&
+ os_strcmp(buf, "acct_server_addr_replace") == 0) {
+ if (hostapd_parse_ip_addr(pos,
+ &bss->radius->acct_server->addr)) {
+ wpa_printf(MSG_ERROR,
+ "Line %d: invalid IP address '%s'",
+ line, pos);
+ return 1;
+ }
+ } 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 &&
@@ -2265,12 +2375,11 @@
os_free(bss->ssid.wpa_passphrase);
bss->ssid.wpa_passphrase = os_strdup(pos);
if (bss->ssid.wpa_passphrase) {
- os_free(bss->ssid.wpa_psk);
- bss->ssid.wpa_psk = NULL;
+ hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
bss->ssid.wpa_passphrase_set = 1;
}
} else if (os_strcmp(buf, "wpa_psk") == 0) {
- os_free(bss->ssid.wpa_psk);
+ hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
bss->ssid.wpa_psk = os_zalloc(sizeof(struct hostapd_wpa_psk));
if (bss->ssid.wpa_psk == NULL)
return 1;
@@ -2278,8 +2387,7 @@
pos[PMK_LEN * 2] != '\0') {
wpa_printf(MSG_ERROR, "Line %d: Invalid PSK '%s'.",
line, pos);
- os_free(bss->ssid.wpa_psk);
- bss->ssid.wpa_psk = NULL;
+ hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
return 1;
}
bss->ssid.wpa_psk->group = 1;
@@ -2458,12 +2566,15 @@
line);
return 1;
#else /* CONFIG_ACS */
+ conf->acs = 1;
conf->channel = 0;
#endif /* CONFIG_ACS */
- } else
+ } else {
conf->channel = atoi(pos);
+ conf->acs = conf->channel == 0;
+ }
} else if (os_strcmp(buf, "chanlist") == 0) {
- if (hostapd_parse_intlist(&conf->chanlist, pos)) {
+ if (hostapd_parse_chanlist(conf, pos)) {
wpa_printf(MSG_ERROR, "Line %d: invalid channel list",
line);
return 1;
@@ -2490,6 +2601,12 @@
return 1;
}
conf->acs_num_scans = val;
+ } else if (os_strcmp(buf, "acs_chan_bias") == 0) {
+ if (hostapd_config_parse_acs_chan_bias(conf, pos)) {
+ wpa_printf(MSG_ERROR, "Line %d: invalid acs_chan_bias",
+ line);
+ return -1;
+ }
#endif /* CONFIG_ACS */
} else if (os_strcmp(buf, "dtim_period") == 0) {
bss->dtim_period = atoi(pos);
@@ -2690,6 +2807,8 @@
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);
+ } else if (os_strcmp(buf, "vendor_vht") == 0) {
+ bss->vendor_vht = atoi(pos);
#endif /* CONFIG_IEEE80211AC */
} else if (os_strcmp(buf, "max_listen_interval") == 0) {
bss->max_listen_interval = atoi(pos);
@@ -2718,7 +2837,7 @@
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) {
+ if (os_strlen(pos) > WPS_DEV_NAME_MAX_LEN) {
wpa_printf(MSG_ERROR, "Line %d: Too long "
"device_name", line);
return 1;
diff --git a/hostapd/ctrl_iface.c b/hostapd/ctrl_iface.c
index 0e35aa6..86f1aa6 100644
--- a/hostapd/ctrl_iface.c
+++ b/hostapd/ctrl_iface.c
@@ -1,6 +1,6 @@
/*
* hostapd / UNIX domain socket -based control interface
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -23,6 +23,7 @@
#include "utils/eloop.h"
#include "common/version.h"
#include "common/ieee802_11_defs.h"
+#include "crypto/tls.h"
#include "drivers/driver.h"
#include "radius/radius_client.h"
#include "radius/radius_server.h"
@@ -39,6 +40,7 @@
#include "ap/hs20.h"
#include "ap/wnm_ap.h"
#include "ap/wpa_auth.h"
+#include "ap/beacon.h"
#include "wps/wps_defs.h"
#include "wps/wps.h"
#include "config_file.h"
@@ -1170,6 +1172,14 @@
return pos - buf;
pos += ret;
}
+ if (hapd->conf->wpa_key_mgmt &
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ ret = os_snprintf(pos, end - pos,
+ "WPA-EAP-SUITE-B-192 ");
+ if (os_snprintf_error(end - pos, ret))
+ return pos - buf;
+ pos += ret;
+ }
ret = os_snprintf(pos, end - pos, "\n");
if (os_snprintf_error(end - pos, ret))
@@ -1326,6 +1336,11 @@
if (os_snprintf_error(buflen, res))
return -1;
return res;
+ } else if (os_strcmp(cmd, "tls_library") == 0) {
+ res = tls_get_library_version(buf, buflen);
+ if (os_snprintf_error(buflen, res))
+ return -1;
+ return res;
}
return -1;
@@ -1692,6 +1707,45 @@
return res < 0 ? -1 : 0;
}
+
+static int hostapd_ctrl_test_alloc_fail(struct hostapd_data *hapd, char *cmd)
+{
+#ifdef WPA_TRACE_BFD
+ extern char wpa_trace_fail_func[256];
+ extern unsigned int wpa_trace_fail_after;
+ char *pos;
+
+ wpa_trace_fail_after = atoi(cmd);
+ pos = os_strchr(cmd, ':');
+ if (pos) {
+ pos++;
+ os_strlcpy(wpa_trace_fail_func, pos,
+ sizeof(wpa_trace_fail_func));
+ } else {
+ wpa_trace_fail_after = 0;
+ }
+
+ return 0;
+#else /* WPA_TRACE_BFD */
+ return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
+
+static int hostapd_ctrl_get_alloc_fail(struct hostapd_data *hapd,
+ char *buf, size_t buflen)
+{
+#ifdef WPA_TRACE_BFD
+ extern char wpa_trace_fail_func[256];
+ extern unsigned int wpa_trace_fail_after;
+
+ return os_snprintf(buf, buflen, "%u:%s", wpa_trace_fail_after,
+ wpa_trace_fail_func);
+#else /* WPA_TRACE_BFD */
+ return -1;
+#endif /* WPA_TRACE_BFD */
+}
+
#endif /* CONFIG_TESTING_OPTIONS */
@@ -1902,6 +1956,9 @@
} else if (os_strncmp(buf, "DISASSOCIATE ", 13) == 0) {
if (hostapd_ctrl_iface_disassociate(hapd, buf + 13))
reply_len = -1;
+ } else if (os_strcmp(buf, "STOP_AP") == 0) {
+ if (hostapd_ctrl_iface_stop_ap(hapd))
+ reply_len = -1;
#ifdef CONFIG_IEEE80211W
#ifdef NEED_AP_MLME
} else if (os_strncmp(buf, "SA_QUERY ", 9) == 0) {
@@ -1994,6 +2051,9 @@
} else if (os_strncmp(buf, "DISABLE", 7) == 0) {
if (hostapd_ctrl_iface_disable(hapd->iface))
reply_len = -1;
+ } else if (os_strcmp(buf, "UPDATE_BEACON") == 0) {
+ if (ieee802_11_set_beacon(hapd))
+ reply_len = -1;
#ifdef CONFIG_TESTING_OPTIONS
} else if (os_strncmp(buf, "RADAR ", 6) == 0) {
if (hostapd_ctrl_iface_radar(hapd, buf + 6))
@@ -2013,6 +2073,12 @@
} else if (os_strncmp(buf, "DATA_TEST_FRAME ", 16) == 0) {
if (hostapd_ctrl_iface_data_test_frame(hapd, buf + 16) < 0)
reply_len = -1;
+ } else if (os_strncmp(buf, "TEST_ALLOC_FAIL ", 16) == 0) {
+ if (hostapd_ctrl_test_alloc_fail(hapd, buf + 16) < 0)
+ reply_len = -1;
+ } else if (os_strcmp(buf, "GET_ALLOC_FAIL") == 0) {
+ reply_len = hostapd_ctrl_get_alloc_fail(hapd, reply,
+ reply_size);
#endif /* CONFIG_TESTING_OPTIONS */
} else if (os_strncmp(buf, "CHAN_SWITCH ", 12) == 0) {
if (hostapd_ctrl_iface_chan_switch(hapd->iface, buf + 12))
@@ -2206,8 +2272,11 @@
os_free(fname);
hapd->ctrl_sock = s;
- eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
- NULL);
+ if (eloop_register_read_sock(s, hostapd_ctrl_iface_receive, hapd,
+ NULL) < 0) {
+ hostapd_ctrl_iface_deinit(hapd);
+ return -1;
+ }
hapd->msg_ctx = hapd;
wpa_msg_register_cb(hostapd_ctrl_iface_msg_cb);
@@ -2254,6 +2323,7 @@
}
dst = hapd->ctrl_dst;
+ hapd->ctrl_dst = NULL;
while (dst) {
prev = dst;
dst = dst->next;
diff --git a/hostapd/hlr_auc_gw.c b/hostapd/hlr_auc_gw.c
index 42d59db..8afe457 100644
--- a/hostapd/hlr_auc_gw.c
+++ b/hostapd/hlr_auc_gw.c
@@ -87,6 +87,7 @@
u8 amf[2];
u8 sqn[6];
int set;
+ size_t res_len;
};
static struct milenage_parameters *milenage_db = NULL;
@@ -96,6 +97,7 @@
#define EAP_AKA_RAND_LEN 16
#define EAP_AKA_AUTN_LEN 16
#define EAP_AKA_AUTS_LEN 14
+#define EAP_AKA_RES_MIN_LEN 4
#define EAP_AKA_RES_MAX_LEN 16
#define EAP_AKA_IK_LEN 16
#define EAP_AKA_CK_LEN 16
@@ -124,7 +126,8 @@
" ki CHAR(32) NOT NULL,"
" opc CHAR(32) NOT NULL,"
" amf CHAR(4) NOT NULL,"
- " sqn CHAR(12) NOT NULL"
+ " sqn CHAR(12) NOT NULL,"
+ " res_len INTEGER"
");";
printf("Adding database table for milenage information\n");
@@ -190,6 +193,10 @@
printf("Invalid sqn value in database\n");
return -1;
}
+
+ if (os_strcmp(col[i], "res_len") == 0 && argv[i]) {
+ m->res_len = atoi(argv[i]);
+ }
}
return 0;
@@ -206,8 +213,7 @@
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);
+ "SELECT * FROM milenage WHERE imsi=%llu;", imsi);
if (sqlite3_exec(sqlite_db, cmd, get_milenage_cb, &db_tmp_milenage,
NULL) != SQLITE_OK)
return NULL;
@@ -424,7 +430,7 @@
while (fgets(buf, sizeof(buf), f)) {
line++;
- /* Parse IMSI Ki OPc AMF SQN */
+ /* Parse IMSI Ki OPc AMF SQN [RES_len] */
buf[sizeof(buf) - 1] = '\0';
if (buf[0] == '#')
continue;
@@ -515,7 +521,19 @@
ret = -1;
break;
}
- pos = pos2 + 1;
+
+ if (pos2) {
+ pos = pos2 + 1;
+ m->res_len = atoi(pos);
+ if (m->res_len &&
+ (m->res_len < EAP_AKA_RES_MIN_LEN ||
+ m->res_len > EAP_AKA_RES_MAX_LEN)) {
+ printf("%s:%d - Invalid RES_len (%s)\n",
+ fname, line, pos);
+ ret = -1;
+ break;
+ }
+ }
m->next = milenage_db;
milenage_db = m;
@@ -798,6 +816,10 @@
}
milenage_generate(m->opc, m->amf, m->ki, m->sqn, _rand,
autn, ik, ck, res, &res_len);
+ if (m->res_len >= EAP_AKA_RES_MIN_LEN &&
+ m->res_len <= EAP_AKA_RES_MAX_LEN &&
+ m->res_len < res_len)
+ res_len = m->res_len;
} else {
printf("Unknown IMSI: %s\n", imsi);
#ifdef AKA_USE_FIXED_TEST_VALUES
diff --git a/hostapd/hlr_auc_gw.milenage_db b/hostapd/hlr_auc_gw.milenage_db
index ecd06d7..c156a29 100644
--- a/hostapd/hlr_auc_gw.milenage_db
+++ b/hostapd/hlr_auc_gw.milenage_db
@@ -5,8 +5,10 @@
# 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
+# IMSI Ki OPc AMF SQN [RES_len]
232010000000000 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000
+# Example using truncated 32-bit RES instead of 64-bit default
+232010000000001 90dca4eda45b53cf0f12d7c9c3bc6a89 cb9cccc4b9258e6dca4760379fb82581 61df 000000000000 4
# 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.
diff --git a/hostapd/hostapd.conf b/hostapd/hostapd.conf
index 2f6126c..90d1523 100644
--- a/hostapd/hostapd.conf
+++ b/hostapd/hostapd.conf
@@ -154,16 +154,27 @@
# interference that may help choosing a better channel. This can also help fine
# tune the ACS scan time in case a driver has different scan dwell times.
#
+# acs_chan_bias is a space-separated list of <channel>:<bias> pairs. It can be
+# used to increase (or decrease) the likelihood of a specific channel to be
+# selected by the ACS algorithm. The total interference factor for each channel
+# gets multiplied by the specified bias value before finding the channel with
+# the lowest value. In other words, values between 0.0 and 1.0 can be used to
+# make a channel more likely to be picked while values larger than 1.0 make the
+# specified channel less likely to be picked. This can be used, e.g., to prefer
+# the commonly used 2.4 GHz band channels 1, 6, and 11 (which is the default
+# behavior on 2.4 GHz band if no acs_chan_bias parameter is specified).
+#
# Defaults:
#acs_num_scans=5
+#acs_chan_bias=1:0.8 6:0.8 11:0.8
# Channel list restriction. This option allows hostapd to select one of the
-# provided channels when a channel should be automatically selected. This
-# is currently only used for DFS when the current channels becomes unavailable
-# due to radar interference, and is currently only useful when ieee80211h=1 is
-# set.
-# Default: not set (allow any enabled channel to be selected)
+# provided channels when a channel should be automatically selected.
+# Channel list can be provided as range using hyphen ('-') or individual
+# channels can be specified by space (' ') seperated values
+# Default: all channels allowed in selected hw_mode
#chanlist=100 104 108 112 116
+#chanlist=1 6 11-13
# Beacon interval in kus (1.024 ms) (default: 100; range 15..65535)
beacon_int=100
@@ -497,9 +508,9 @@
# If set non-zero, require stations to perform scans of overlapping
# channels to test for stations which would be affected by 40 MHz traffic.
-# This parameter sets the interval in seconds between these scans. This
-# is useful only for testing that stations properly set the OBSS interval,
-# since the other parameters in the OBSS scan parameters IE are set to 0.
+# This parameter sets the interval in seconds between these scans. Setting this
+# to non-zero allows 2.4 GHz band AP to move dynamically to a 40 MHz channel if
+# no co-existence issues with neighboring devices are found.
#obss_interval=0
##### IEEE 802.11ac related configuration #####################################
@@ -877,6 +888,12 @@
# 48 octets long.
#nas_identifier=ap.example.com
+# RADIUS client forced local IP address for the access point
+# Normally the local IP address is determined automatically based on configured
+# IP addresses, but this field can be used to force a specific address to be
+# used, e.g., when the device has multiple IP addresses.
+#radius_client_addr=127.0.0.1
+
# RADIUS authentication server
#auth_server_addr=127.0.0.1
#auth_server_port=1812
diff --git a/hostapd/hostapd_cli.c b/hostapd/hostapd_cli.c
index 7009184..719d021 100644
--- a/hostapd/hostapd_cli.c
+++ b/hostapd/hostapd_cli.c
@@ -1,6 +1,6 @@
/*
* hostapd - command line interface for hostapd daemon
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,7 @@
#include <dirent.h>
#include "common/wpa_ctrl.h"
+#include "common/ieee802_11_defs.h"
#include "utils/common.h"
#include "utils/eloop.h"
#include "utils/edit.h"
@@ -18,7 +19,7 @@
static const char *hostapd_cli_version =
"hostapd_cli v" VERSION_STR "\n"
-"Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi> and contributors";
+"Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi> and contributors";
static const char *hostapd_cli_license =
@@ -541,7 +542,7 @@
char *argv[])
{
char buf[256];
- char ssid_hex[2 * 32 + 1];
+ char ssid_hex[2 * SSID_MAX_LEN + 1];
char key_hex[2 * 64 + 1];
int i;
@@ -552,7 +553,7 @@
}
ssid_hex[0] = '\0';
- for (i = 0; i < 32; i++) {
+ for (i = 0; i < SSID_MAX_LEN; i++) {
if (argv[0][i] == '\0')
break;
os_snprintf(&ssid_hex[i * 2], 3, "%02x", argv[0][i]);
diff --git a/hostapd/main.c b/hostapd/main.c
index 0fe7ac8..0c8686a 100644
--- a/hostapd/main.c
+++ b/hostapd/main.c
@@ -1,6 +1,6 @@
/*
* hostapd / main()
- * Copyright (c) 2002-2011, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -428,7 +428,7 @@
"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-2014, Jouni Malinen <j@w1.fi> "
+ "Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi> "
"and contributors\n");
}
diff --git a/hs20/client/Android.mk b/hs20/client/Android.mk
index 63cbc6f..b23ac17 100644
--- a/hs20/client/Android.mk
+++ b/hs20/client/Android.mk
@@ -8,23 +8,28 @@
INCLUDES += external/libxml2/include
INCLUDES += external/curl/include
INCLUDES += external/webkit/Source/WebKit/gtk
-ifneq ($(wildcard external/icu),)
-INCLUDES += external/icu/icu4c/source/common
-else
+
+# We try to keep this compiling against older platform versions.
+# The new icu location (external/icu) exports its own headers, but
+# the older versions in external/icu4c don't, and we need to add those
+# headers to the include path by hand.
+ifeq ($(wildcard external/icu),)
INCLUDES += external/icu4c/common
+else
+# The LOCAL_EXPORT_C_INCLUDE_DIRS from ICU did not seem to fully resolve the
+# build (e.g., "mm -B" failed to build, but following that with "mm" allowed
+# the build to complete). For now, add the include directory manually here for
+# Android 5.0.
+ver = $(filter 5.0%,$(PLATFORM_VERSION))
+ifneq (,$(strip $(ver)))
+INCLUDES += external/icu/icu4c/source/common
+endif
endif
-#GTKCFLAGS := $(shell pkg-config --cflags gtk+-2.0 webkit-1.0)
-#GTKLIBS := $(shell pkg-config --libs gtk+-2.0 webkit-1.0)
-#CFLAGS += $(GTKCFLAGS)
-#LIBS += $(GTKLIBS)
-
L_CFLAGS += -DCONFIG_CTRL_IFACE
L_CFLAGS += -DCONFIG_CTRL_IFACE_UNIX
L_CFLAGS += -DCONFIG_CTRL_IFACE_CLIENT_DIR=\"/data/misc/wifi/sockets\"
-L_CFLAGS += -DLIBXML_SCHEMAS_ENABLED
-L_CFLAGS += -DLIBXML_REGEXP_ENABLED
OBJS = spp_client.c
OBJS += oma_dm_client.c
@@ -53,8 +58,7 @@
L_CFLAGS += -DEAP_TLS_OPENSSL
-#CFLAGS += $(shell xml2-config --cflags)
-#LIBS += $(shell xml2-config --libs)
+L_CFLAGS += -Wno-unused-parameter
########################
diff --git a/hs20/client/Makefile b/hs20/client/Makefile
index ca67b54..94cd5f1 100644
--- a/hs20/client/Makefile
+++ b/hs20/client/Makefile
@@ -67,7 +67,13 @@
CFLAGS += $(shell xml2-config --cflags)
LIBS += $(shell xml2-config --libs)
+
+# Allow static/custom linking of libcurl.
+ifdef CUST_CURL_LINKAGE
+LIBS += ${CUST_CURL_LINKAGE}
+else
LIBS += -lcurl
+endif
CFLAGS += -DEAP_TLS_OPENSSL
LIBS += -lssl -lcrypto
diff --git a/hs20/client/oma_dm_client.c b/hs20/client/oma_dm_client.c
index 82e9106..5854b72 100644
--- a/hs20/client/oma_dm_client.c
+++ b/hs20/client/oma_dm_client.c
@@ -394,6 +394,10 @@
}
data = xml_node_get_text(ctx->xml, node);
+ if (data == NULL) {
+ wpa_printf(MSG_INFO, "Invalid data");
+ return DM_RESP_BAD_REQUEST;
+ }
wpa_printf(MSG_INFO, "Data: %s", data);
wpa_printf(MSG_INFO, "Launch browser to URI '%s'", data);
write_summary(ctx, "Launch browser to URI '%s'", data);
@@ -428,6 +432,10 @@
}
data = xml_node_get_text(ctx->xml, node);
+ if (data == NULL) {
+ wpa_printf(MSG_INFO, "Invalid data");
+ return DM_RESP_BAD_REQUEST;
+ }
wpa_printf(MSG_INFO, "Data: %s", data);
getcert = xml_node_from_buf(ctx->xml, data);
xml_node_get_text_free(ctx->xml, data);
@@ -576,6 +584,11 @@
if (node) {
char *type;
type = xml_node_get_text(ctx->xml, node);
+ if (type == NULL) {
+ wpa_printf(MSG_ERROR, "Could not find type text");
+ os_free(uri);
+ return DM_RESP_BAD_REQUEST;
+ }
use_tnds = node &&
os_strstr(type, "application/vnd.syncml.dmtnds+xml");
}
@@ -648,6 +661,10 @@
return DM_RESP_BAD_REQUEST;
}
locuri = xml_node_get_text(ctx->xml, node);
+ if (locuri == NULL) {
+ wpa_printf(MSG_ERROR, "No LocURI node text found");
+ return DM_RESP_BAD_REQUEST;
+ }
wpa_printf(MSG_INFO, "Target LocURI: %s", locuri);
if (os_strncasecmp(locuri, "./Wi-Fi/", 8) != 0) {
wpa_printf(MSG_INFO, "Unsupported Add Target LocURI");
@@ -755,6 +772,11 @@
if (node) {
char *type;
type = xml_node_get_text(ctx->xml, node);
+ if (type == NULL) {
+ wpa_printf(MSG_INFO, "Could not find type text");
+ os_free(locuri);
+ return DM_RESP_BAD_REQUEST;
+ }
use_tnds = node &&
os_strstr(type, "application/vnd.syncml.dmtnds+xml");
}
diff --git a/hs20/client/osu_client.c b/hs20/client/osu_client.c
index a439bde..5cd823e 100644
--- a/hs20/client/osu_client.c
+++ b/hs20/client/osu_client.c
@@ -9,6 +9,9 @@
#include "includes.h"
#include <time.h>
#include <sys/stat.h>
+#ifdef ANDROID
+#include "private/android_filesystem_config.h"
+#endif /* ANDROID */
#include "common.h"
#include "utils/browser.h"
@@ -22,6 +25,8 @@
#include "crypto/sha256.h"
#include "osu_client.h"
+const char *spp_xsd_fname = "spp.xsd";
+
void write_result(struct hs20_osu_client *ctx, const char *fmt, ...)
{
@@ -397,9 +402,9 @@
}
node = get_child_node(ctx->xml, pps,
- "PolicyUpdate/TrustRoot");
+ "Policy/PolicyUpdate/TrustRoot");
if (node == NULL) {
- wpa_printf(MSG_INFO, "No PolicyUpdate/TrustRoot/CertURL found from PPS");
+ wpa_printf(MSG_INFO, "No Policy/PolicyUpdate/TrustRoot/CertURL found from PPS");
xml_node_free(ctx->xml, pps);
return -1;
}
@@ -544,8 +549,9 @@
wpa_printf(MSG_INFO, "SP FQDN: %s", fqdn);
if (!server_dnsname_suffix_match(ctx, fqdn)) {
- wpa_printf(MSG_INFO, "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values",
- fqdn);
+ wpa_printf(MSG_INFO,
+ "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values, count: %d",
+ fqdn, (int) ctx->server_dnsname_count);
write_result(ctx, "FQDN '%s' for new PPS MO did not have suffix match with server's dNSName values",
fqdn);
free(fqdn);
@@ -571,6 +577,21 @@
}
}
+#ifdef ANDROID
+ /* Allow processes running with Group ID as AID_WIFI,
+ * to read files from SP/<fqdn> directory */
+ if (chown(fname, -1, AID_WIFI)) {
+ wpa_printf(MSG_INFO, "CTRL: Could not chown directory: %s",
+ strerror(errno));
+ /* Try to continue anyway */
+ }
+ if (chmod(fname, S_IRWXU | S_IRGRP | S_IXGRP) < 0) {
+ wpa_printf(MSG_INFO, "CTRL: Could not chmod directory: %s",
+ strerror(errno));
+ /* Try to continue anyway */
+ }
+#endif /* ANDROID */
+
snprintf(fname, fname_len, "SP/%s/pps.xml", fqdn);
if (os_file_exists(fname)) {
@@ -669,6 +690,10 @@
wpa_printf(MSG_INFO, "Updating PPS MO %s", pps_fname);
str = xml_node_to_str(ctx->xml, pps);
+ if (str == NULL) {
+ wpa_printf(MSG_ERROR, "No node found");
+ return -1;
+ }
wpa_printf(MSG_MSGDUMP, "[hs20] Updated PPS: '%s'", str);
snprintf(backup, sizeof(backup), "%s.bak", pps_fname);
@@ -2072,10 +2097,14 @@
}
ctx->no_reconnect = 1;
- if (methods & 0x02)
+ if (methods & 0x02) {
+ wpa_printf(MSG_DEBUG, "Calling cmd_prov from osu_connect");
res = cmd_prov(ctx, url);
- else if (methods & 0x01)
+ } else if (methods & 0x01) {
+ wpa_printf(MSG_DEBUG,
+ "Calling cmd_oma_dm_prov from osu_connect");
res = cmd_oma_dm_prov(ctx, url);
+ }
wpa_printf(MSG_INFO, "Remove OSU network connection");
write_summary(ctx, "Remove OSU network connection");
@@ -2117,7 +2146,7 @@
snprintf(fname, sizeof(fname), "%s/osu-providers.txt", dir);
osu = parse_osu_providers(fname, &osu_count);
if (osu == NULL) {
- wpa_printf(MSG_INFO, "Could not any OSU providers from %s",
+ wpa_printf(MSG_INFO, "Could not find any OSU providers from %s",
fname);
write_result(ctx, "No OSU providers available");
return -1;
@@ -2268,12 +2297,19 @@
}
if (connect == 2) {
- if (last->methods & 0x02)
+ if (last->methods & 0x02) {
+ wpa_printf(MSG_DEBUG,
+ "Calling cmd_prov from cmd_osu_select");
ret = cmd_prov(ctx, last->url);
- else if (last->methods & 0x01)
+ } else if (last->methods & 0x01) {
+ wpa_printf(MSG_DEBUG,
+ "Calling cmd_oma_dm_prov from cmd_osu_select");
ret = cmd_oma_dm_prov(ctx, last->url);
- else
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "No supported OSU provisioning method");
ret = -1;
+ }
} else if (connect)
ret = osu_connect(ctx, last->bssid, last->osu_ssid,
last->url, last->methods,
@@ -2343,8 +2379,8 @@
}
-static void cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
- const char *pps_fname, const char *ca_fname)
+static int cmd_sub_rem(struct hs20_osu_client *ctx, const char *address,
+ const char *pps_fname, const char *ca_fname)
{
xml_node_t *pps, *node;
char pps_fname_buf[300];
@@ -2371,12 +2407,12 @@
} else if (get_wpa_status(ctx->ifname, "provisioning_sp", buf,
sizeof(buf)) < 0) {
wpa_printf(MSG_INFO, "Could not get provisioning Home SP FQDN from wpa_supplicant");
- return;
+ return -1;
}
os_free(ctx->fqdn);
ctx->fqdn = os_strdup(buf);
if (ctx->fqdn == NULL)
- return;
+ return -1;
wpa_printf(MSG_INFO, "Home SP FQDN for current credential: %s",
buf);
os_snprintf(pps_fname_buf, sizeof(pps_fname_buf),
@@ -2391,14 +2427,14 @@
if (!os_file_exists(pps_fname)) {
wpa_printf(MSG_INFO, "PPS file '%s' does not exist or is not accessible",
pps_fname);
- return;
+ return -1;
}
wpa_printf(MSG_INFO, "Using PPS file: %s", pps_fname);
if (ca_fname && !os_file_exists(ca_fname)) {
wpa_printf(MSG_INFO, "CA file '%s' does not exist or is not accessible",
ca_fname);
- return;
+ return -1;
}
wpa_printf(MSG_INFO, "Using server trust root: %s", ca_fname);
ctx->ca_fname = ca_fname;
@@ -2406,7 +2442,7 @@
pps = node_from_file(ctx->xml, pps_fname);
if (pps == NULL) {
wpa_printf(MSG_INFO, "Could not read PPS MO");
- return;
+ return -1;
}
if (!ctx->fqdn) {
@@ -2414,18 +2450,18 @@
node = get_child_node(ctx->xml, pps, "HomeSP/FQDN");
if (node == NULL) {
wpa_printf(MSG_INFO, "No HomeSP/FQDN found from PPS");
- return;
+ return -1;
}
tmp = xml_node_get_text(ctx->xml, node);
if (tmp == NULL) {
wpa_printf(MSG_INFO, "No HomeSP/FQDN text found from PPS");
- return;
+ return -1;
}
ctx->fqdn = os_strdup(tmp);
xml_node_get_text_free(ctx->xml, tmp);
if (!ctx->fqdn) {
wpa_printf(MSG_INFO, "No FQDN known");
- return;
+ return -1;
}
}
@@ -2474,7 +2510,7 @@
}
if (!address) {
wpa_printf(MSG_INFO, "Server URL not known");
- return;
+ return -1;
}
write_summary(ctx, "Wait for IP address for subscriptiom remediation");
@@ -2497,6 +2533,7 @@
xml_node_get_text_free(ctx->xml, cred_username);
str_clear_free(cred_password);
xml_node_free(ctx->xml, pps);
+ return 0;
}
@@ -2787,17 +2824,21 @@
char *name = ctx->icon_filename[j];
size_t name_len = os_strlen(name);
- wpa_printf(MSG_INFO, "Looking for icon file name '%s' match",
- name);
+ wpa_printf(MSG_INFO,
+ "[%i] Looking for icon file name '%s' match",
+ j, name);
for (i = 0; i < cert->num_logo; i++) {
struct http_logo *logo = &cert->logo[i];
size_t uri_len = os_strlen(logo->uri);
char *pos;
- wpa_printf(MSG_INFO, "Comparing to '%s' uri_len=%d name_len=%d",
- logo->uri, (int) uri_len, (int) name_len);
- if (uri_len < 1 + name_len)
+ wpa_printf(MSG_INFO,
+ "[%i] Comparing to '%s' uri_len=%d name_len=%d",
+ i, logo->uri, (int) uri_len, (int) name_len);
+ if (uri_len < 1 + name_len) {
+ wpa_printf(MSG_INFO, "URI Length is too short");
continue;
+ }
pos = &logo->uri[uri_len - name_len - 1];
if (*pos != '/')
continue;
@@ -2824,17 +2865,30 @@
for (i = 0; i < cert->num_logo; i++) {
struct http_logo *logo = &cert->logo[i];
- if (logo->hash_len != 32)
+ if (logo->hash_len != 32) {
+ wpa_printf(MSG_INFO,
+ "[%i][%i] Icon hash length invalid (should be 32): %d",
+ j, i, (int) logo->hash_len);
continue;
+ }
if (os_memcmp(logo->hash, ctx->icon_hash[j], 32) == 0) {
found = 1;
break;
}
+
+ wpa_printf(MSG_DEBUG,
+ "[%u][%u] Icon hash did not match", j, i);
+ wpa_hexdump_ascii(MSG_DEBUG, "logo->hash",
+ logo->hash, 32);
+ wpa_hexdump_ascii(MSG_DEBUG, "ctx->icon_hash[j]",
+ ctx->icon_hash[j], 32);
}
if (!found) {
- wpa_printf(MSG_INFO, "No icon hash match found");
- write_result(ctx, "No icon hash match found");
+ wpa_printf(MSG_INFO,
+ "No icon hash match (by hash) found");
+ write_result(ctx,
+ "No icon hash match (by hash) found");
return -1;
}
}
@@ -2932,6 +2986,7 @@
" [-w<wpa_supplicant ctrl_iface dir>] "
"[-r<result file>] [-f<debug file>] \\\n"
" [-s<summary file>] \\\n"
+ " [-x<spp.xsd file name>] \\\n"
" <command> [arguments..]\n"
"commands:\n"
"- to_tnds <XML MO> <XML MO in TNDS format> [URN]\n"
@@ -2973,7 +3028,7 @@
return -1;
for (;;) {
- c = getopt(argc, argv, "df:hi:KNO:qr:s:S:tw:");
+ c = getopt(argc, argv, "df:hKNO:qr:s:S:tw:x:");
if (c < 0)
break;
switch (c) {
@@ -3011,6 +3066,9 @@
case 'w':
wpas_ctrl_path = optarg;
break;
+ case 'x':
+ spp_xsd_fname = optarg;
+ break;
case 'h':
default:
usage();
@@ -3066,10 +3124,11 @@
if (argc - optind < 2)
wpa_printf(MSG_ERROR, "Server URL missing from command line");
else
- cmd_sub_rem(&ctx, argv[optind + 1],
- argc > optind + 2 ? argv[optind + 2] : NULL,
- argc > optind + 3 ? argv[optind + 3] :
- NULL);
+ ret = cmd_sub_rem(&ctx, argv[optind + 1],
+ argc > optind + 2 ?
+ argv[optind + 2] : NULL,
+ argc > optind + 3 ?
+ argv[optind + 3] : NULL);
} else if (strcmp(argv[optind], "pol_upd") == 0) {
if (argc - optind < 2) {
usage();
@@ -3084,6 +3143,7 @@
exit(0);
}
ctx.ca_fname = argv[optind + 2];
+ wpa_printf(MSG_DEBUG, "Calling cmd_prov from main");
cmd_prov(&ctx, argv[optind + 1]);
} else if (strcmp(argv[optind], "sim_prov") == 0) {
if (argc - optind < 2) {
diff --git a/hs20/client/spp_client.c b/hs20/client/spp_client.c
index 302a050..cc1a0bf 100644
--- a/hs20/client/spp_client.c
+++ b/hs20/client/spp_client.c
@@ -21,6 +21,8 @@
#include "osu_client.h"
+extern const char *spp_xsd_fname;
+
static int hs20_spp_update_response(struct hs20_osu_client *ctx,
const char *session_id,
const char *spp_status,
@@ -59,7 +61,7 @@
return -1;
}
- ret = xml_validate(xctx, node, "spp.xsd", &err);
+ ret = xml_validate(xctx, node, spp_xsd_fname, &err);
if (ret < 0) {
wpa_printf(MSG_INFO, "XML schema validation error(s)\n%s", err);
write_summary(ctx, "SPP XML schema validation failed");
@@ -952,7 +954,9 @@
return -1;
}
- wpa_printf(MSG_INFO, "Credential provisioning requested");
+ wpa_printf(MSG_INFO,
+ "Credential provisioning requested - URL: %s ca_fname: %s",
+ url, ctx->ca_fname ? ctx->ca_fname : "N/A");
os_free(ctx->server_url);
ctx->server_url = os_strdup(url);
diff --git a/hs20/server/ca/clean.sh b/hs20/server/ca/clean.sh
index c69a1f5..c72dcbd 100755
--- a/hs20/server/ca/clean.sh
+++ b/hs20/server/ca/clean.sh
@@ -5,6 +5,9 @@
done
rm -f openssl.cnf.tmp
-rm -r demoCA
+if [ -d demoCA ]; then
+ rm -r demoCA
+fi
rm -f ca.pem logo.asn1 logo.der server.der ocsp-server-cache.der
+rm -f my-openssl.cnf my-openssl-root.cnf
#rm -r rootCA
diff --git a/hs20/server/ca/openssl-root.cnf b/hs20/server/ca/openssl-root.cnf
index 5b220fe..5bc50be 100644
--- a/hs20/server/ca/openssl-root.cnf
+++ b/hs20/server/ca/openssl-root.cnf
@@ -69,8 +69,8 @@
attributes = req_attributes
x509_extensions = v3_ca # The extentions to add to the self signed cert
-input_password = whatever
-output_password = whatever
+input_password = @PASSWORD@
+output_password = @PASSWORD@
string_mask = utf8only
diff --git a/hs20/server/ca/openssl.cnf b/hs20/server/ca/openssl.cnf
index a939f08..6141013 100644
--- a/hs20/server/ca/openssl.cnf
+++ b/hs20/server/ca/openssl.cnf
@@ -80,8 +80,8 @@
attributes = req_attributes
x509_extensions = v3_ca # The extentions to add to the self signed cert
-input_password = whatever
-output_password = whatever
+input_password = @PASSWORD@
+output_password = @PASSWORD@
string_mask = utf8only
@@ -95,7 +95,7 @@
localityName_default = Tuusula
0.organizationName = Organization Name (eg, company)
-0.organizationName_default = w1.fi
+0.organizationName_default = @DOMAIN@
##organizationalUnitName = Organizational Unit Name (eg, section)
#organizationalUnitName_default =
@@ -117,10 +117,10 @@
authorityKeyIdentifier=keyid:always,issuer
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, cRLSign, keyCertSign
-authorityInfoAccess = OCSP;URI:http://osu.w1.fi:8888/
+authorityInfoAccess = OCSP;URI:@OCSP_URI@
# For SP intermediate CA
#subjectAltName=critical,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:engExample OSU
-#nameConstraints=permitted;DNS:.w1.fi
+#nameConstraints=permitted;DNS:.@DOMAIN@
#1.3.6.1.5.5.7.1.12=ASN1:SEQUENCE:LogotypeExtn
[ v3_osu_server ]
@@ -150,16 +150,16 @@
#value2=SEQUENCE:HashAlgAndValueSHA1
[HashAlgAndValueSHA256]
hashAlg=SEQUENCE:sha256_alg
-hashValue=FORMAT:HEX,OCTETSTRING:4532f7ec36424381617c03c6ce87b55a51d6e7177ffafda243cebf280a68954d
+hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH256@
[HashAlgAndValueSHA1]
hashAlg=SEQUENCE:sha1_alg
-hashValue=FORMAT:HEX,OCTETSTRING:5e1d5085676eede6b02da14d31c523ec20ffba0b
+hashValue=FORMAT:HEX,OCTETSTRING:@LOGO_HASH1@
[sha256_alg]
algorithm=OID:sha256
[sha1_alg]
algorithm=OID:sha1
[URI]
-uri=IA5STRING:http://osu.w1.fi/w1fi_logo.png
+uri=IA5STRING:@LOGO_URI@
[LogotypeImageInfo]
# default value color(1), component optional
#type=IMP:0,INTEGER:1
@@ -184,7 +184,7 @@
basicConstraints=CA:FALSE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
-authorityInfoAccess = OCSP;URI:http://osu.w1.fi:8888/
+authorityInfoAccess = OCSP;URI:@OCSP_URI@
#@ALTNAME@
extendedKeyUsage = clientAuth
@@ -194,7 +194,7 @@
basicConstraints=critical, CA:FALSE
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid,issuer
-authorityInfoAccess = OCSP;URI:http://osu.w1.fi:8888/
+authorityInfoAccess = OCSP;URI:@OCSP_URI@
#@ALTNAME@
extendedKeyUsage = critical, serverAuth
keyUsage = critical, keyEncipherment
diff --git a/hs20/server/ca/setup.sh b/hs20/server/ca/setup.sh
index f61bf73..78abccc 100755
--- a/hs20/server/ca/setup.sh
+++ b/hs20/server/ca/setup.sh
@@ -5,6 +5,67 @@
fi
export OPENSSL_CONF=$PWD/openssl.cnf
PASS=whatever
+if [ -z "$DOMAIN" ]; then
+ DOMAIN=w1.fi
+fi
+COMPANY=w1.fi
+OPER_ENG="engw1.fi TESTING USE"
+OPER_FI="finw1.fi TESTIKÄYTTÖ"
+CNR="Hotspot 2.0 Trust Root CA - 99"
+CNO="ocsp.$DOMAIN"
+CNV="osu-revoked.$DOMAIN"
+CNOC="osu-client.$DOMAIN"
+OSU_SERVER_HOSTNAME="osu.$DOMAIN"
+DEBUG=0
+OCSP_URI="http://$CNO:8888/"
+LOGO_URI="http://osu.w1.fi/w1fi_logo.png"
+LOGO_HASH256="4532f7ec36424381617c03c6ce87b55a51d6e7177ffafda243cebf280a68954d"
+LOGO_HASH1="5e1d5085676eede6b02da14d31c523ec20ffba0b"
+
+# Command line overrides
+USAGE=$( cat <<EOF
+Usage:\n
+# -c: Company name, used to generate Subject name CN for Intermediate CA\n
+# -C: Subject name CN of the Root CA ($CNR)\n
+# -D: Enable debugging (set -x, etc)\n
+# -g: Logo sha1 hash ($LOGO_HASH1)\n
+# -G: Logo sha256 hash ($LOGO_HASH256)\n
+# -h: Show this help message\n
+# -l: Logo URI ($LOGO_URI)\n
+# -m: Domain ($DOMAIN)\n
+# -o: Subject name CN for OSU-Client Server ($CNOC)\n
+# -O: Subject name CN for OCSP Server ($CNO)\n
+# -p: passphrase for private keys ($PASS)\n
+# -r: Operator-english ($OPER_ENG)\n
+# -R: Operator-finish ($OPER_FI)\n
+# -S: OSU Server name ($OSU_SERVER_HOSTNAME)\n
+# -u: OCSP-URI ($OCSP_URI)\n
+# -V: Subject name CN for OSU-Revoked Server ($CNV)\n
+EOF
+)
+
+while getopts "c:C:Dg:G:l:m:o:O:p:r:R:S:u:V:h" flag
+ do
+ case $flag in
+ c) COMPANY=$OPTARG;;
+ C) CNR=$OPTARG;;
+ D) DEBUG=1;;
+ g) LOGO_HASH1=$OPTARG;;
+ G) LOGO_HASH256=$OPTARG;;
+ h) echo -e $USAGE; exit 0;;
+ l) LOGO_URI=$OPTARG;;
+ m) DOMAIN=$OPTARG;;
+ o) CNOC=$OPTARG;;
+ O) CNO=$OPTARG;;
+ p) PASS=$OPTARG;;
+ r) OPER_ENG=$OPTARG;;
+ R) OPER_FI=$OPTARG;;
+ S) OSU_SERVER_HOSTNAME=$OPTARG;;
+ u) OCSP_URI=$OPTARG;;
+ V) CNV=$OPTARG;;
+ *) echo "Unknown flag: $flag"; echo -e $USAGE; exit 1;;
+ esac
+done
fail()
{
@@ -16,7 +77,25 @@
echo "---[ Root CA ]----------------------------------------------------------"
echo
-cat openssl-root.cnf | sed "s/#@CN@/commonName_default = Hotspot 2.0 Trust Root CA - 99/" > openssl.cnf.tmp
+if [ $DEBUG = 1 ]
+then
+ set -x
+fi
+
+# Set the passphrase and some other common config accordingly.
+cat openssl-root.cnf | sed "s/@PASSWORD@/$PASS/" \
+ > my-openssl-root.cnf
+
+cat openssl.cnf | sed "s/@PASSWORD@/$PASS/" |
+sed "s,@OCSP_URI@,$OCSP_URI," |
+sed "s,@LOGO_URI@,$LOGO_URI," |
+sed "s,@LOGO_HASH1@,$LOGO_HASH1," |
+sed "s,@LOGO_HASH256@,$LOGO_HASH256," |
+sed "s/@DOMAIN@/$DOMAIN/" \
+ > my-openssl.cnf
+
+
+cat my-openssl-root.cnf | sed "s/#@CN@/commonName_default = $CNR/" > openssl.cnf.tmp
mkdir -p rootCA/certs rootCA/crl rootCA/newcerts rootCA/private
touch rootCA/index.txt
if [ -e rootCA/private/cakey.pem ]; then
@@ -26,6 +105,8 @@
$OPENSSL req -config openssl.cnf.tmp -batch -new -newkey rsa:4096 -keyout rootCA/private/cakey.pem -out rootCA/careq.pem || fail "Failed to generate Root CA private key"
echo " * Sign Root CA certificate"
$OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out rootCA/cacert.pem -days 10957 -batch -keyfile rootCA/private/cakey.pem -passin pass:$PASS -selfsign -extensions v3_ca -outdir rootCA/newcerts -infiles rootCA/careq.pem || fail "Failed to sign Root CA certificate"
+ $OPENSSL x509 -in rootCA/cacert.pem -out rootCA/cacert.der -outform DER || fail "Failed to create rootCA DER"
+ sha256sum rootCA/cacert.der > rootCA/cacert.fingerprint || fail "Failed to create rootCA fingerprint"
fi
if [ ! -e rootCA/crlnumber ]; then
echo 00 > rootCA/crlnumber
@@ -35,7 +116,7 @@
echo "---[ Intermediate CA ]--------------------------------------------------"
echo
-cat openssl.cnf | sed "s/#@CN@/commonName_default = w1.fi Hotspot 2.0 Intermediate CA/" > openssl.cnf.tmp
+cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $COMPANY Hotspot 2.0 Intermediate CA/" > openssl.cnf.tmp
mkdir -p demoCA/certs demoCA/crl demoCA/newcerts demoCA/private
touch demoCA/index.txt
if [ -e demoCA/private/cakey.pem ]; then
@@ -47,6 +128,8 @@
$OPENSSL ca -config openssl.cnf.tmp -md sha256 -create_serial -out demoCA/cacert.pem -days 3652 -batch -keyfile rootCA/private/cakey.pem -cert rootCA/cacert.pem -passin pass:$PASS -extensions v3_ca -infiles demoCA/careq.pem || fail "Failed to sign Intermediate CA certificate"
# horrible from security view point, but for testing purposes since OCSP responder does not seem to support -passin
openssl rsa -in demoCA/private/cakey.pem -out demoCA/private/cakey-plain.pem -passin pass:$PASS
+ $OPENSSL x509 -in demoCA/cacert.pem -out demoCA/cacert.der -outform DER || fail "Failed to create demoCA DER."
+ sha256sum demoCA/cacert.der > demoCA/cacert.fingerprint || fail "Failed to create demoCA fingerprint"
fi
if [ ! -e demoCA/crlnumber ]; then
echo 00 > demoCA/crlnumber
@@ -56,45 +139,46 @@
echo "OCSP responder"
echo
-cat openssl.cnf | sed "s/#@CN@/commonName_default = ocsp.w1.fi/" > openssl.cnf.tmp
+cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNO/" > openssl.cnf.tmp
$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out ocsp.csr -keyout ocsp.key -extensions v3_OCSP
-$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -keyfile demoCA/private/cakey.pem -passin pass:$PASS -in ocsp.csr -out ocsp.pem -days 730 -extensions v3_OCSP
+$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -keyfile demoCA/private/cakey.pem -passin pass:$PASS -in ocsp.csr -out ocsp.pem -days 730 -extensions v3_OCSP || fail "Could not generate ocsp.pem"
echo
echo "---[ Server - to be revoked ] ------------------------------------------"
echo
-cat openssl.cnf | sed "s/#@CN@/commonName_default = osu-revoked.w1.fi/" > openssl.cnf.tmp
+cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNV/" > openssl.cnf.tmp
$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-revoked.csr -keyout server-revoked.key
$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-revoked.csr -out server-revoked.pem -key $PASS -days 730 -extensions ext_server
$OPENSSL ca -revoke server-revoked.pem -key $PASS
echo
echo "---[ Server - with client ext key use ] ---------------------------------"
+echo "---[ Only used for negative-testing for OSU-client implementation ] -----"
echo
-cat openssl.cnf | sed "s/#@CN@/commonName_default = osu-client.w1.fi/" > openssl.cnf.tmp
-$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-client.csr -keyout server-client.key
-$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-client.csr -out server-client.pem -key $PASS -days 730 -extensions ext_client
+cat my-openssl.cnf | sed "s/#@CN@/commonName_default = $CNOC/" > openssl.cnf.tmp
+$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out server-client.csr -keyout server-client.key || fail "Could not create server-client.key"
+$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in server-client.csr -out server-client.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create server-client.pem"
echo
echo "---[ User ]-------------------------------------------------------------"
echo
-cat openssl.cnf | sed "s/#@CN@/commonName_default = User/" > openssl.cnf.tmp
-$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out user.csr -keyout user.key
-$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in user.csr -out user.pem -key $PASS -days 730 -extensions ext_client
+cat my-openssl.cnf | sed "s/#@CN@/commonName_default = User/" > openssl.cnf.tmp
+$OPENSSL req -config $PWD/openssl.cnf.tmp -batch -new -newkey rsa:2048 -nodes -out user.csr -keyout user.key || fail "Could not create user.key"
+$OPENSSL ca -config $PWD/openssl.cnf.tmp -batch -md sha256 -in user.csr -out user.pem -key $PASS -days 730 -extensions ext_client || fail "Could not create user.pem"
echo
echo "---[ Server ]-----------------------------------------------------------"
echo
-ALT="DNS:osu.w1.fi"
-ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:engw1.fi TESTING USE"
-ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:finw1.fi TESTIKÄYTTÖ"
+ALT="DNS:$OSU_SERVER_HOSTNAME"
+ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_ENG"
+ALT="$ALT,otherName:1.3.6.1.4.1.40808.1.1.1;UTF8String:$OPER_FI"
-cat openssl.cnf |
- sed "s/#@CN@/commonName_default = osu.w1.fi/" |
+cat my-openssl.cnf |
+ sed "s/#@CN@/commonName_default = $OSU_SERVER_HOSTNAME/" |
sed "s/^##organizationalUnitName/organizationalUnitName/" |
sed "s/#@OU@/organizationalUnitName_default = Hotspot 2.0 Online Sign Up Server/" |
sed "s/#@ALTNAME@/subjectAltName=critical,$ALT/" \
@@ -113,7 +197,7 @@
echo "---[ CRL ]---------------------------------------------------------------"
echo
-$OPENSSL ca -config $PWD/openssl.cnf -gencrl -md sha256 -out demoCA/crl/crl.pem -passin pass:$PASS
+$OPENSSL ca -config $PWD/my-openssl.cnf -gencrl -md sha256 -out demoCA/crl/crl.pem -passin pass:$PASS
echo
echo "---[ Verify ]------------------------------------------------------------"
diff --git a/hs20/server/hs20-osu-server.txt b/hs20/server/hs20-osu-server.txt
index 80985f7..001d6f2 100644
--- a/hs20/server/hs20-osu-server.txt
+++ b/hs20/server/hs20-osu-server.txt
@@ -100,6 +100,21 @@
# the examples as-is for initial testing).
cp -r www /home/user/hs20-server
+# Build local keys and certs
+cd ca
+# Display help options.
+./setup.sh -h
+
+# Remove old keys, fill in appropriate values, and generate your keys.
+# For instance:
+./clean.sh
+rm -fr rootCA"
+old_hostname=myserver.local
+./setup.sh -C "Hotspot 2.0 Trust Root CA - CT" -d $old_hostname \
+ -I "Hotspot 2.0 Intermediate CA - CT" -o $old_hostname-osu-client \
+ -O $old_hostname-oscp -p lanforge -S $old_hostname \
+ -V $old_hostname-osu-revoked \
+ -m local -u http://$old_hostname:8888/
# Configure subscription policies
mkdir -p /home/user/hs20-server/spp/policy
@@ -156,6 +171,50 @@
./hostapd -B as-sql.conf
+OSEN RADIUS server configuration notes
+
+The OSEN RADIUS server config file should have the 'ocsp_stapling_response'
+configuration in it. For example:
+
+# hostapd-radius config for the radius used by the OSEN AP
+interface=eth0#0
+driver=none
+logger_syslog=-1
+logger_syslog_level=2
+logger_stdout=-1
+logger_stdout_level=2
+ctrl_interface=/var/run/hostapd
+ctrl_interface_group=0
+eap_server=1
+eap_user_file=/home/user/hs20-server/AS/hostapd-osen.eap_user
+server_id=ben-ota-2-osen
+radius_server_auth_port=1811
+radius_server_clients=/home/user/hs20-server/AS/hostap.radius_clients
+
+ca_cert=/home/user/hs20-server/ca/ca.pem
+server_cert=/home/user/hs20-server/ca/server.pem
+private_key=/home/user/hs20-server/ca/server.key
+private_key_passwd=whatever
+
+ocsp_stapling_response=/home/user/hs20-server/ca/ocsp-server-cache.der
+
+The /home/user/hs20-server/AS/hostapd-osen.eap_user file should look
+similar to this, and should coorelate with the osu_nai entry in
+the non-OSEN VAP config file. For instance:
+
+# cat hostapd-osen.eap_user
+# For OSEN authentication (Hotspot 2.0 Release 2)
+"osen@w1.fi" WFA-UNAUTH-TLS
+
+
+# Run OCSP server:
+cd /home/user/hs20-server/ca
+./ocsp-responder.sh&
+
+# Update cache (This should be run periodically)
+./ocsp-update-cache.sh
+
+
Configure web server
--------------------
@@ -172,6 +231,8 @@
</Directory>
Update SSL configuration to use the OSU server certificate/key.
+They keys and certs are called 'server.key' and 'server.pem' from
+ca/setup.sh.
Enable default-ssl site and restart Apache2:
sudo a2ensite default-ssl
diff --git a/hs20/server/spp_server.c b/hs20/server/spp_server.c
index 4d77d0e..33e3fa1 100644
--- a/hs20/server/spp_server.c
+++ b/hs20/server/spp_server.c
@@ -103,6 +103,28 @@
}
+static void db_update_session_machine_managed(struct hs20_svc *ctx,
+ const char *user,
+ const char *realm,
+ const char *sessionid,
+ const int pw_mm)
+{
+ char *sql;
+
+ sql = sqlite3_mprintf("UPDATE sessions SET machine_managed=%Q WHERE id=%Q AND user=%Q AND realm=%Q",
+ pw_mm ? "1" : "0", sessionid, user, realm);
+ if (sql == NULL)
+ return;
+ debug_print(ctx, 1, "DB: %s", sql);
+ if (sqlite3_exec(ctx->db, sql, NULL, NULL, NULL) != SQLITE_OK) {
+ debug_print(ctx, 1,
+ "Failed to update session machine_managed: %s",
+ sqlite3_errmsg(ctx->db));
+ }
+ sqlite3_free(sql);
+}
+
+
static void db_add_session_pps(struct hs20_svc *ctx, const char *user,
const char *realm, const char *sessionid,
xml_node_t *node)
@@ -1378,6 +1400,11 @@
debug_print(ctx, 1, "Request DB subscription registration on success "
"notification");
+ if (machine_managed) {
+ db_update_session_password(ctx, user, realm, session_id, pw);
+ db_update_session_machine_managed(ctx, user, realm, session_id,
+ machine_managed);
+ }
db_add_session_pps(ctx, user, realm, session_id, pps);
hs20_eventlog_node(ctx, user, realm, session_id,
@@ -2169,7 +2196,9 @@
session_id = xml_node_get_attr_value_ns(ctx->xml, node,
SPP_NS_URI,
"sessionID");
- debug_print(ctx, 1, "SPP message failed validation");
+ debug_print(ctx, 1,
+ "SPP message failed validation, xsd file: %s xml-error: %s",
+ fname, xml_err);
hs20_eventlog_node(ctx, auth_user, auth_realm, session_id,
"SPP message failed validation", node);
hs20_eventlog(ctx, auth_user, auth_realm, session_id,
diff --git a/hs20/server/www/signup.php b/hs20/server/www/signup.php
index a626704..aeb2f68 100644
--- a/hs20/server/www/signup.php
+++ b/hs20/server/www/signup.php
@@ -17,7 +17,7 @@
$row = $db->query("SELECT realm FROM sessions WHERE id='$id'")->fetch();
if ($row == false) {
- die("Session not found");
+ die("Session not found for id: $id");
}
$realm = $row['realm'];
diff --git a/patches/openssl-0.9.8zf-tls-extensions.patch b/patches/openssl-0.9.8zf-tls-extensions.patch
new file mode 100644
index 0000000..3a8f90e
--- /dev/null
+++ b/patches/openssl-0.9.8zf-tls-extensions.patch
@@ -0,0 +1,398 @@
+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.8zf 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.8zf.orig/ssl/s3_clnt.c openssl-0.9.8zf/ssl/s3_clnt.c
+--- openssl-0.9.8zf.orig/ssl/s3_clnt.c 2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/s3_clnt.c 2015-03-24 16:19:14.043911769 +0200
+@@ -760,6 +760,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);
++ s->s3->flags |= SSL3_FLAGS_CCS_OK;
++ }
++ }
++#endif /* OPENSSL_NO_TLSEXT */
++
+ if (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
+@@ -2684,12 +2701,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,
+diff -upr openssl-0.9.8zf.orig/ssl/s3_srvr.c openssl-0.9.8zf/ssl/s3_srvr.c
+--- openssl-0.9.8zf.orig/ssl/s3_srvr.c 2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/s3_srvr.c 2015-03-24 16:23:34.567909681 +0200
+@@ -999,6 +999,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
+@@ -1143,15 +1196,21 @@ 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.8zf.orig/ssl/ssl_err.c openssl-0.9.8zf/ssl/ssl_err.c
+--- openssl-0.9.8zf.orig/ssl/ssl_err.c 2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/ssl_err.c 2015-03-24 16:35:58.627903717 +0200
+@@ -316,6 +316,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.8zf.orig/ssl/ssl.h openssl-0.9.8zf/ssl/ssl.h
+--- openssl-0.9.8zf.orig/ssl/ssl.h 2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/ssl.h 2015-03-24 16:25:44.339908641 +0200
+@@ -349,6 +349,7 @@ extern "C" {
+ * 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 {
+@@ -366,6 +367,12 @@ 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 {
+ int version;
+@@ -1116,6 +1123,18 @@ struct ssl_st {
+ int tlsext_ocsp_resplen;
+ /* 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
+@@ -1772,6 +1791,17 @@ 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
+@@ -1977,6 +2007,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.8zf.orig/ssl/ssl_sess.c openssl-0.9.8zf/ssl/ssl_sess.c
+--- openssl-0.9.8zf.orig/ssl/ssl_sess.c 2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/ssl_sess.c 2015-03-24 16:28:04.819907515 +0200
+@@ -716,6 +716,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;
+ long time;
+diff -upr openssl-0.9.8zf.orig/ssl/t1_lib.c openssl-0.9.8zf/ssl/t1_lib.c
+--- openssl-0.9.8zf.orig/ssl/t1_lib.c 2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/t1_lib.c 2015-03-24 16:32:46.923905254 +0200
+@@ -108,6 +108,11 @@ 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 +211,20 @@ unsigned char *ssl_add_clienthello_tlsex
+ int ticklen;
+ if (!s->new_session && s->session && s->session->tlsext_tick)
+ ticklen = s->session->tlsext_ticklen;
+- else
++ 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 +238,7 @@ unsigned char *ssl_add_clienthello_tlsex
+ ret += ticklen;
+ }
+ }
++skip_ext:
+
+ if (s->tlsext_status_type == TLSEXT_STATUSTYPE_ocsp &&
+ s->version != DTLS1_VERSION) {
+@@ -560,6 +578,14 @@ int ssl_parse_clienthello_tlsext(SSL *s,
+ if (!ssl_parse_clienthello_renegotiate_ext(s, data, size, al))
+ 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) {
+
+@@ -710,6 +736,13 @@ int ssl_parse_serverhello_tlsext(SSL *s,
+ }
+ tlsext_servername = 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;
++ }
+ if ((SSL_get_options(s) & SSL_OP_NO_TICKET)
+ || (size > 0)) {
+ *al = TLS1_AD_UNSUPPORTED_EXTENSION;
+@@ -993,6 +1026,14 @@ 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);
+ }
+ p += size;
+diff -upr openssl-0.9.8zf.orig/ssl/tls1.h openssl-0.9.8zf/ssl/tls1.h
+--- openssl-0.9.8zf.orig/ssl/tls1.h 2015-03-19 15:46:46.000000000 +0200
++++ openssl-0.9.8zf/ssl/tls1.h 2015-03-24 16:33:31.855904894 +0200
+@@ -460,6 +460,12 @@ 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"
+ # endif
+
++/* TLS extension struct */
++struct tls_session_ticket_ext_st {
++ unsigned short length;
++ void *data;
++};
++
+ #ifdef __cplusplus
+ }
+ #endif
+diff -upr openssl-0.9.8zf.orig/util/ssleay.num openssl-0.9.8zf/util/ssleay.num
+--- openssl-0.9.8zf.orig/util/ssleay.num 2015-03-19 15:47:15.000000000 +0200
++++ openssl-0.9.8zf/util/ssleay.num 2015-03-24 16:33:51.127904739 +0200
+@@ -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/src/ap/Makefile b/src/ap/Makefile
index adfd3df..98788fe 100644
--- a/src/ap/Makefile
+++ b/src/ap/Makefile
@@ -1,8 +1,67 @@
-all:
- @echo Nothing to be made.
+all: libap.a
clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+ rm -f *~ *.o *.d *.gcno *.gcda *.gcov libap.a
install:
@echo Nothing to be made.
+
+include ../lib.rules
+
+CFLAGS += -DHOSTAPD
+CFLAGS += -DNEED_AP_MLME
+CFLAGS += -DCONFIG_HS20
+CFLAGS += -DCONFIG_INTERWORKING
+CFLAGS += -DCONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211W
+CFLAGS += -DCONFIG_WPS
+CFLAGS += -DCONFIG_PROXYARP
+CFLAGS += -DCONFIG_IAPP
+
+LIB_OBJS= \
+ accounting.o \
+ ap_config.o \
+ ap_drv_ops.o \
+ ap_list.o \
+ ap_mlme.o \
+ authsrv.o \
+ beacon.o \
+ bss_load.o \
+ ctrl_iface_ap.o \
+ dfs.o \
+ dhcp_snoop.o \
+ drv_callbacks.o \
+ eap_user_db.o \
+ gas_serv.o \
+ hostapd.o \
+ hs20.o \
+ hw_features.o \
+ iapp.o \
+ ieee802_11_auth.o \
+ ieee802_11.o \
+ ieee802_11_ht.o \
+ ieee802_11_shared.o \
+ ieee802_11_vht.o \
+ ieee802_1x.o \
+ ndisc_snoop.o \
+ p2p_hostapd.o \
+ peerkey_auth.o \
+ pmksa_cache_auth.o \
+ preauth_auth.o \
+ sta_info.o \
+ tkip_countermeasures.o \
+ utils.o \
+ vlan_init.o \
+ wmm.o \
+ wnm_ap.o \
+ wpa_auth.o \
+ wpa_auth_ft.o \
+ wpa_auth_glue.o \
+ wpa_auth_ie.o \
+ wps_hostapd.o \
+ x_snoop.o
+
+libap.a: $(LIB_OBJS)
+ $(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/ap/acs.c b/src/ap/acs.c
index 97cf26f..652d020 100644
--- a/src/ap/acs.c
+++ b/src/ap/acs.c
@@ -242,6 +242,7 @@
static int acs_request_scan(struct hostapd_iface *iface);
+static int acs_survey_is_sufficient(struct freq_survey *survey);
static void acs_clean_chan_surveys(struct hostapd_channel_data *chan)
@@ -328,6 +329,7 @@
struct freq_survey *survey;
unsigned int i = 0;
long double int_factor = 0;
+ unsigned count = 0;
if (dl_list_empty(&chan->survey_list))
return;
@@ -339,18 +341,27 @@
dl_list_for_each(survey, &chan->survey_list, struct freq_survey, list)
{
+ i++;
+
+ if (!acs_survey_is_sufficient(survey)) {
+ wpa_printf(MSG_DEBUG, "ACS: %d: insufficient data", i);
+ continue;
+ }
+
+ count++;
int_factor = acs_survey_interference_factor(survey,
iface->lowest_nf);
chan->interference_factor += int_factor;
wpa_printf(MSG_DEBUG, "ACS: %d: min_nf=%d interference_factor=%Lg nf=%d time=%lu busy=%lu rx=%lu",
- ++i, chan->min_nf, int_factor,
+ i, chan->min_nf, int_factor,
survey->nf, (unsigned long) survey->channel_time,
(unsigned long) survey->channel_time_busy,
(unsigned long) survey->channel_time_rx);
}
- chan->interference_factor = chan->interference_factor /
- dl_list_len(&chan->survey_list);
+ if (!count)
+ return;
+ chan->interference_factor /= count;
}
@@ -384,18 +395,19 @@
static int acs_survey_is_sufficient(struct freq_survey *survey)
{
if (!(survey->filled & SURVEY_HAS_NF)) {
- wpa_printf(MSG_ERROR, "ACS: Survey is missing noise floor");
+ wpa_printf(MSG_INFO, "ACS: Survey is missing noise floor");
return 0;
}
if (!(survey->filled & SURVEY_HAS_CHAN_TIME)) {
- wpa_printf(MSG_ERROR, "ACS: Survey is missing channel time");
+ wpa_printf(MSG_INFO, "ACS: Survey is missing channel time");
return 0;
}
if (!(survey->filled & SURVEY_HAS_CHAN_TIME_BUSY) &&
!(survey->filled & SURVEY_HAS_CHAN_TIME_RX)) {
- wpa_printf(MSG_ERROR, "ACS: Survey is missing RX and busy time (at least one is required)");
+ wpa_printf(MSG_INFO,
+ "ACS: Survey is missing RX and busy time (at least one is required)");
return 0;
}
@@ -406,18 +418,27 @@
static int acs_survey_list_is_sufficient(struct hostapd_channel_data *chan)
{
struct freq_survey *survey;
+ int ret = -1;
dl_list_for_each(survey, &chan->survey_list, struct freq_survey, list)
{
- if (!acs_survey_is_sufficient(survey)) {
- wpa_printf(MSG_ERROR, "ACS: Channel %d has insufficient survey data",
- chan->chan);
- return 0;
+ if (acs_survey_is_sufficient(survey)) {
+ ret = 1;
+ break;
}
+ ret = 0;
}
- return 1;
+ if (ret == -1)
+ ret = 1; /* no survey list entries */
+ if (!ret) {
+ wpa_printf(MSG_INFO,
+ "ACS: Channel %d has insufficient survey data",
+ chan->chan);
+ }
+
+ return ret;
}
@@ -455,6 +476,16 @@
}
+static int is_in_chanlist(struct hostapd_iface *iface,
+ struct hostapd_channel_data *chan)
+{
+ if (!iface->conf->acs_ch_list.num)
+ return 1;
+
+ return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
+}
+
+
static void acs_survey_all_chans_intereference_factor(
struct hostapd_iface *iface)
{
@@ -467,6 +498,9 @@
if (!acs_usable_chan(chan))
continue;
+ if (!is_in_chanlist(iface, chan))
+ continue;
+
wpa_printf(MSG_DEBUG, "ACS: Survey analysis for channel %d (%d MHz)",
chan->chan, chan->freq);
@@ -498,6 +532,36 @@
}
+static int is_24ghz_mode(enum hostapd_hw_mode mode)
+{
+ return mode == HOSTAPD_MODE_IEEE80211B ||
+ mode == HOSTAPD_MODE_IEEE80211G;
+}
+
+
+static int is_common_24ghz_chan(int chan)
+{
+ return chan == 1 || chan == 6 || chan == 11;
+}
+
+
+#ifndef ACS_ADJ_WEIGHT
+#define ACS_ADJ_WEIGHT 0.85
+#endif /* ACS_ADJ_WEIGHT */
+
+#ifndef ACS_NEXT_ADJ_WEIGHT
+#define ACS_NEXT_ADJ_WEIGHT 0.55
+#endif /* ACS_NEXT_ADJ_WEIGHT */
+
+#ifndef ACS_24GHZ_PREFER_1_6_11
+/*
+ * Select commonly used channels 1, 6, 11 by default even if a neighboring
+ * channel has a smaller interference factor as long as it is not better by more
+ * than this multiplier.
+ */
+#define ACS_24GHZ_PREFER_1_6_11 0.8
+#endif /* ACS_24GHZ_PREFER_1_6_11 */
+
/*
* At this point it's assumed chan->interface_factor has been computed.
* This function should be reusable regardless of interference computation
@@ -512,6 +576,7 @@
long double factor, ideal_factor = 0;
int i, j;
int n_chans = 1;
+ unsigned int k;
/* TODO: HT40- support */
@@ -538,11 +603,16 @@
-1);
for (i = 0; i < iface->current_mode->num_channels; i++) {
+ double total_weight;
+ struct acs_bias *bias, tmp_bias;
+
chan = &iface->current_mode->channels[i];
if (chan->flag & HOSTAPD_CHAN_DISABLED)
continue;
+ if (!is_in_chanlist(iface, chan))
+ continue;
/* HT40 on 5 GHz has a limited set of primary channels as per
* 11n Annex J */
@@ -567,14 +637,17 @@
factor = 0;
if (acs_usable_chan(chan))
factor = chan->interference_factor;
+ total_weight = 1;
for (j = 1; j < n_chans; j++) {
adj_chan = acs_find_chan(iface, chan->freq + (j * 20));
if (!adj_chan)
break;
- if (acs_usable_chan(adj_chan))
+ if (acs_usable_chan(adj_chan)) {
factor += adj_chan->interference_factor;
+ total_weight += 1;
+ }
}
if (j != n_chans) {
@@ -585,36 +658,69 @@
/* 2.4 GHz has overlapping 20 MHz channels. Include adjacent
* channel interference factor. */
- if (iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B ||
- iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G) {
+ if (is_24ghz_mode(iface->current_mode->mode)) {
for (j = 0; j < n_chans; j++) {
- /* TODO: perhaps a multiplier should be used
- * here? */
-
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) - 5);
- if (adj_chan && acs_usable_chan(adj_chan))
- factor += adj_chan->interference_factor;
+ if (adj_chan && acs_usable_chan(adj_chan)) {
+ factor += ACS_ADJ_WEIGHT *
+ adj_chan->interference_factor;
+ total_weight += ACS_ADJ_WEIGHT;
+ }
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) - 10);
- if (adj_chan && acs_usable_chan(adj_chan))
- factor += adj_chan->interference_factor;
+ if (adj_chan && acs_usable_chan(adj_chan)) {
+ factor += ACS_NEXT_ADJ_WEIGHT *
+ adj_chan->interference_factor;
+ total_weight += ACS_NEXT_ADJ_WEIGHT;
+ }
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) + 5);
- if (adj_chan && acs_usable_chan(adj_chan))
- factor += adj_chan->interference_factor;
+ if (adj_chan && acs_usable_chan(adj_chan)) {
+ factor += ACS_ADJ_WEIGHT *
+ adj_chan->interference_factor;
+ total_weight += ACS_ADJ_WEIGHT;
+ }
adj_chan = acs_find_chan(iface, chan->freq +
(j * 20) + 10);
- if (adj_chan && acs_usable_chan(adj_chan))
- factor += adj_chan->interference_factor;
+ if (adj_chan && acs_usable_chan(adj_chan)) {
+ factor += ACS_NEXT_ADJ_WEIGHT *
+ adj_chan->interference_factor;
+ total_weight += ACS_NEXT_ADJ_WEIGHT;
+ }
}
}
- wpa_printf(MSG_DEBUG, "ACS: * channel %d: total interference = %Lg",
- chan->chan, factor);
+ factor /= total_weight;
+
+ bias = NULL;
+ if (iface->conf->acs_chan_bias) {
+ for (k = 0; k < iface->conf->num_acs_chan_bias; k++) {
+ bias = &iface->conf->acs_chan_bias[k];
+ if (bias->channel == chan->chan)
+ break;
+ bias = NULL;
+ }
+ } else if (is_24ghz_mode(iface->current_mode->mode) &&
+ is_common_24ghz_chan(chan->chan)) {
+ tmp_bias.channel = chan->chan;
+ tmp_bias.bias = ACS_24GHZ_PREFER_1_6_11;
+ bias = &tmp_bias;
+ }
+
+ if (bias) {
+ factor *= bias->bias;
+ wpa_printf(MSG_DEBUG,
+ "ACS: * channel %d: total interference = %Lg (%f bias)",
+ chan->chan, factor, bias->bias);
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "ACS: * channel %d: total interference = %Lg",
+ chan->chan, factor);
+ }
if (acs_usable_chan(chan) &&
(!ideal_chan || factor < ideal_factor)) {
diff --git a/src/ap/ap_config.c b/src/ap/ap_config.c
index 5bc468a..cccbfab 100644
--- a/src/ap/ap_config.c
+++ b/src/ap/ap_config.c
@@ -181,6 +181,8 @@
conf->corrupt_gtk_rekey_mic_probability = 0.0;
#endif /* CONFIG_TESTING_OPTIONS */
+ conf->acs = 0;
+ conf->acs_ch_list.num = 0;
#ifdef CONFIG_ACS
conf->acs_num_scans = 5;
#endif /* CONFIG_ACS */
@@ -394,20 +396,27 @@
}
+void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **l)
+{
+ struct hostapd_wpa_psk *psk, *tmp;
+
+ for (psk = *l; psk;) {
+ tmp = psk;
+ psk = psk->next;
+ bin_clear_free(tmp, sizeof(*tmp));
+ }
+ *l = NULL;
+}
+
+
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;
- bin_clear_free(prev, sizeof(*prev));
- }
+ hostapd_config_clear_wpa_psk(&conf->ssid.wpa_psk);
str_clear_free(conf->ssid.wpa_passphrase);
os_free(conf->ssid.wpa_psk_file);
@@ -496,6 +505,12 @@
os_free(conf->model_description);
os_free(conf->model_url);
os_free(conf->upc);
+ {
+ unsigned int i;
+
+ for (i = 0; i < MAX_WPS_VENDOR_EXTENSIONS; i++)
+ wpabuf_free(conf->wps_vendor_ext[i]);
+ }
wpabuf_free(conf->wps_nfc_dh_pubkey);
wpabuf_free(conf->wps_nfc_dh_privkey);
wpabuf_free(conf->wps_nfc_dev_pw);
@@ -566,8 +581,11 @@
os_free(conf->bss);
os_free(conf->supported_rates);
os_free(conf->basic_rates);
- os_free(conf->chanlist);
+ os_free(conf->acs_ch_list.range);
os_free(conf->driver_params);
+#ifdef CONFIG_ACS
+ os_free(conf->acs_chan_bias);
+#endif /* CONFIG_ACS */
os_free(conf);
}
diff --git a/src/ap/ap_config.h b/src/ap/ap_config.h
index ce8ac9b..00848ba 100644
--- a/src/ap/ap_config.h
+++ b/src/ap/ap_config.h
@@ -12,6 +12,7 @@
#include "common/defs.h"
#include "ip_addr.h"
#include "common/wpa_common.h"
+#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "wps/wps.h"
@@ -57,8 +58,6 @@
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;
@@ -78,7 +77,7 @@
} secpolicy;
struct hostapd_ssid {
- u8 ssid[HOSTAPD_MAX_SSID_LEN];
+ u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
unsigned int ssid_set:1;
unsigned int utf8_ssid:1;
@@ -114,6 +113,7 @@
struct hostapd_vlan *next;
int vlan_id; /* VLAN ID or -1 (VLAN_ID_WILDCARD) for wildcard entry */
char ifname[IFNAMSIZ + 1];
+ int configured;
int dynamic_vlan;
#ifdef CONFIG_FULL_DYNAMIC_VLAN
@@ -510,7 +510,7 @@
char file[256];
} *hs20_icons;
size_t hs20_icons_count;
- u8 osu_ssid[HOSTAPD_MAX_SSID_LEN];
+ u8 osu_ssid[SSID_MAX_LEN];
size_t osu_ssid_len;
struct hs20_osu_provider {
unsigned int friendly_name_count;
@@ -551,6 +551,9 @@
int mesh;
int radio_measurements;
+
+ int vendor_vht;
+
char *neighbor_ap_list_file;
};
@@ -567,7 +570,8 @@
int fragm_threshold;
u8 send_probe_response;
u8 channel;
- int *chanlist;
+ u8 acs;
+ struct wpa_freq_range_list acs_ch_list;
enum hostapd_hw_mode hw_mode; /* HOSTAPD_MODE_IEEE80211A, .. */
enum {
LONG_PREAMBLE = 0,
@@ -628,6 +632,10 @@
u8 vht_oper_centr_freq_seg0_idx;
u8 vht_oper_centr_freq_seg1_idx;
+#ifdef CONFIG_P2P
+ u8 p2p_go_ctwindow;
+#endif /* CONFIG_P2P */
+
#ifdef CONFIG_TESTING_OPTIONS
double ignore_probe_probability;
double ignore_auth_probability;
@@ -638,6 +646,11 @@
#ifdef CONFIG_ACS
unsigned int acs_num_scans;
+ struct acs_bias {
+ int channel;
+ double bias;
+ } *acs_chan_bias;
+ unsigned int num_acs_chan_bias;
#endif /* CONFIG_ACS */
};
@@ -647,6 +660,7 @@
struct hostapd_config * hostapd_config_defaults(void);
void hostapd_config_defaults_bss(struct hostapd_bss_config *bss);
void hostapd_config_free_eap_user(struct hostapd_eap_user *user);
+void hostapd_config_clear_wpa_psk(struct hostapd_wpa_psk **p);
void hostapd_config_free_bss(struct hostapd_bss_config *conf);
void hostapd_config_free(struct hostapd_config *conf);
int hostapd_maclist_found(struct mac_acl_entry *list, int num_entries,
diff --git a/src/ap/ap_drv_ops.c b/src/ap/ap_drv_ops.c
index 7486fda..9ee88b4 100644
--- a/src/ap/ap_drv_ops.c
+++ b/src/ap/ap_drv_ops.c
@@ -10,6 +10,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
#include "wps/wps.h"
#include "p2p/p2p.h"
#include "hostapd.h"
@@ -216,6 +217,15 @@
}
+int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL || hapd->driver->set_ap_wps_ie == NULL)
+ return 0;
+
+ return hapd->driver->set_ap_wps_ie(hapd->drv_priv, NULL, NULL, NULL);
+}
+
+
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd)
{
struct wpabuf *beacon, *proberesp, *assocresp;
@@ -477,93 +487,8 @@
}
-int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
- int freq, int channel, int ht_enabled,
- int vht_enabled, int sec_channel_offset,
- int vht_oper_chwidth, int center_segment0,
- int center_segment1, u32 vht_caps)
-{
- int tmp;
-
- os_memset(data, 0, sizeof(*data));
- data->mode = mode;
- data->freq = freq;
- data->channel = channel;
- data->ht_enabled = ht_enabled;
- data->vht_enabled = vht_enabled;
- data->sec_channel_offset = sec_channel_offset;
- data->center_freq1 = freq + sec_channel_offset * 10;
- data->center_freq2 = 0;
- data->bandwidth = sec_channel_offset ? 40 : 20;
-
- /*
- * This validation code is probably misplaced, maybe it should be
- * in src/ap/hw_features.c and check the hardware support as well.
- */
- if (data->vht_enabled) switch (vht_oper_chwidth) {
- case VHT_CHANWIDTH_USE_HT:
- if (center_segment1)
- return -1;
- if (center_segment0 != 0 &&
- 5000 + center_segment0 * 5 != data->center_freq1 &&
- 2407 + center_segment0 * 5 != data->center_freq1)
- return -1;
- break;
- case VHT_CHANWIDTH_80P80MHZ:
- if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
- wpa_printf(MSG_ERROR,
- "80+80 channel width is not supported!");
- return -1;
- }
- if (center_segment1 == center_segment0 + 4 ||
- center_segment1 == center_segment0 - 4)
- return -1;
- data->center_freq2 = 5000 + center_segment1 * 5;
- /* fall through */
- case VHT_CHANWIDTH_80MHZ:
- data->bandwidth = 80;
- if (vht_oper_chwidth == 1 && center_segment1)
- return -1;
- if (vht_oper_chwidth == 3 && !center_segment1)
- return -1;
- if (!sec_channel_offset)
- return -1;
- /* primary 40 part must match the HT configuration */
- tmp = (30 + freq - 5000 - center_segment0 * 5)/20;
- tmp /= 2;
- if (data->center_freq1 != 5000 +
- center_segment0 * 5 - 20 + 40 * tmp)
- return -1;
- data->center_freq1 = 5000 + center_segment0 * 5;
- break;
- case VHT_CHANWIDTH_160MHZ:
- data->bandwidth = 160;
- if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
- VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
- wpa_printf(MSG_ERROR,
- "160MHZ channel width is not supported!");
- return -1;
- }
- if (center_segment1)
- return -1;
- if (!sec_channel_offset)
- return -1;
- /* primary 40 part must match the HT configuration */
- tmp = (70 + freq - 5000 - center_segment0 * 5)/20;
- tmp /= 2;
- if (data->center_freq1 != 5000 +
- center_segment0 * 5 - 60 + 40 * tmp)
- return -1;
- data->center_freq1 = 5000 + center_segment0 * 5;
- break;
- }
-
- return 0;
-}
-
-
-int hostapd_set_freq(struct hostapd_data *hapd, int mode, int freq,
- int channel, int ht_enabled, int vht_enabled,
+int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
+ int freq, int channel, int ht_enabled, int vht_enabled,
int sec_channel_offset, int vht_oper_chwidth,
int center_segment0, int center_segment1)
{
@@ -748,7 +673,8 @@
}
-int hostapd_start_dfs_cac(struct hostapd_iface *iface, int mode, int freq,
+int hostapd_start_dfs_cac(struct hostapd_iface *iface,
+ enum hostapd_hw_mode mode, int freq,
int channel, int ht_enabled, int vht_enabled,
int sec_channel_offset, int vht_oper_chwidth,
int center_segment0, int center_segment1)
@@ -798,13 +724,66 @@
int hostapd_drv_do_acs(struct hostapd_data *hapd)
{
struct drv_acs_params params;
+ int ret, i, acs_ch_list_all = 0;
+ u8 *channels = NULL;
+ unsigned int num_channels = 0;
+ struct hostapd_hw_modes *mode;
if (hapd->driver == NULL || hapd->driver->do_acs == NULL)
return 0;
+
os_memset(¶ms, 0, sizeof(params));
params.hw_mode = hapd->iface->conf->hw_mode;
+
+ /*
+ * If no chanlist config parameter is provided, include all enabled
+ * channels of the selected hw_mode.
+ */
+ if (!hapd->iface->conf->acs_ch_list.num)
+ acs_ch_list_all = 1;
+
+ mode = hapd->iface->current_mode;
+ if (mode == NULL)
+ return -1;
+ channels = os_malloc(mode->num_channels);
+ if (channels == NULL)
+ return -1;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *chan = &mode->channels[i];
+ if (!acs_ch_list_all &&
+ !freq_range_list_includes(&hapd->iface->conf->acs_ch_list,
+ chan->chan))
+ continue;
+ if (!(chan->flag & HOSTAPD_CHAN_DISABLED))
+ channels[num_channels++] = chan->chan;
+ }
+
+ params.ch_list = channels;
+ params.ch_list_len = num_channels;
+
params.ht_enabled = !!(hapd->iface->conf->ieee80211n);
params.ht40_enabled = !!(hapd->iface->conf->ht_capab &
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET);
- return hapd->driver->do_acs(hapd->drv_priv, ¶ms);
+ params.vht_enabled = !!(hapd->iface->conf->ieee80211ac);
+ params.ch_width = 20;
+ if (hapd->iface->conf->ieee80211n && params.ht40_enabled)
+ params.ch_width = 40;
+
+ /* Note: VHT20 is defined by combination of ht_capab & vht_oper_chwidth
+ */
+ if (hapd->iface->conf->ieee80211ac && params.ht40_enabled) {
+ if (hapd->iface->conf->vht_oper_chwidth == VHT_CHANWIDTH_80MHZ)
+ params.ch_width = 80;
+ else if (hapd->iface->conf->vht_oper_chwidth ==
+ VHT_CHANWIDTH_160MHZ ||
+ hapd->iface->conf->vht_oper_chwidth ==
+ VHT_CHANWIDTH_80P80MHZ)
+ params.ch_width = 160;
+ }
+
+ ret = hapd->driver->do_acs(hapd->drv_priv, ¶ms);
+ os_free(channels);
+
+ return ret;
}
diff --git a/src/ap/ap_drv_ops.h b/src/ap/ap_drv_ops.h
index 7ad3ed7..82eaf3f 100644
--- a/src/ap/ap_drv_ops.h
+++ b/src/ap/ap_drv_ops.h
@@ -24,6 +24,7 @@
void hostapd_free_ap_extra_ies(struct hostapd_data *hapd, struct wpabuf *beacon,
struct wpabuf *proberesp,
struct wpabuf *assocresp);
+int hostapd_reset_ap_wps_ie(struct hostapd_data *hapd);
int hostapd_set_ap_wps_ie(struct hostapd_data *hapd);
int hostapd_set_authorized(struct hostapd_data *hapd,
struct sta_info *sta, int authorized);
@@ -57,8 +58,8 @@
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 vht_enabled,
+int hostapd_set_freq(struct hostapd_data *hapd, enum hostapd_hw_mode mode,
+ int freq, int channel, int ht_enabled, int vht_enabled,
int sec_channel_offset, int vht_oper_chwidth,
int center_segment0, int center_segment1);
int hostapd_set_rts(struct hostapd_data *hapd, int rts);
@@ -102,15 +103,11 @@
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_start_dfs_cac(struct hostapd_iface *iface, int mode, int freq,
+int hostapd_start_dfs_cac(struct hostapd_iface *iface,
+ enum hostapd_hw_mode mode, int freq,
int channel, int ht_enabled, int vht_enabled,
int sec_channel_offset, int vht_oper_chwidth,
int center_segment0, int center_segment1);
-int hostapd_set_freq_params(struct hostapd_freq_params *data, int mode,
- int freq, int channel, int ht_enabled,
- int vht_enabled, int sec_channel_offset,
- int vht_oper_chwidth, int center_segment0,
- int center_segment1, u32 vht_caps);
int hostapd_drv_do_acs(struct hostapd_data *hapd);
@@ -333,4 +330,11 @@
data_len, buf);
}
+static inline int hostapd_drv_stop_ap(struct hostapd_data *hapd)
+{
+ if (hapd->driver == NULL || hapd->driver->stop_ap == NULL)
+ return 0;
+ return hapd->driver->stop_ap(hapd->drv_priv);
+}
+
#endif /* AP_DRV_OPS */
diff --git a/src/ap/ap_list.c b/src/ap/ap_list.c
index d4fec5b..2f007c5 100644
--- a/src/ap/ap_list.c
+++ b/src/ap/ap_list.c
@@ -111,8 +111,8 @@
if (s->hnext != NULL)
s->hnext = s->hnext->hnext;
else
- printf("AP: could not remove AP " MACSTR " from hash table\n",
- MAC2STR(ap->addr));
+ wpa_printf(MSG_INFO, "AP: could not remove AP " MACSTR
+ " from hash table", MAC2STR(ap->addr));
}
@@ -182,7 +182,8 @@
if (!ap) {
ap = ap_ap_add(iface, mgmt->bssid);
if (!ap) {
- printf("Failed to allocate AP information entry\n");
+ wpa_printf(MSG_INFO,
+ "Failed to allocate AP information entry");
return;
}
new_ap = 1;
@@ -192,14 +193,14 @@
elems->supp_rates, elems->supp_rates_len,
elems->ext_supp_rates, elems->ext_supp_rates_len);
- if (elems->erp_info && elems->erp_info_len == 1)
+ if (elems->erp_info)
ap->erp = elems->erp_info[0];
else
ap->erp = -1;
- if (elems->ds_params && elems->ds_params_len == 1)
+ if (elems->ds_params)
ap->channel = elems->ds_params[0];
- else if (elems->ht_operation && elems->ht_operation_len >= 1)
+ else if (elems->ht_operation)
ap->channel = elems->ht_operation[0];
else if (fi)
ap->channel = fi->channel;
diff --git a/src/ap/authsrv.c b/src/ap/authsrv.c
index bd1778e..f10e1b7 100644
--- a/src/ap/authsrv.c
+++ b/src/ap/authsrv.c
@@ -55,10 +55,11 @@
{
const struct hostapd_eap_user *eap_user;
int i;
+ int rv = -1;
eap_user = hostapd_get_eap_user(ctx, identity, identity_len, phase2);
if (eap_user == NULL)
- return -1;
+ goto out;
if (user == NULL)
return 0;
@@ -72,7 +73,7 @@
if (eap_user->password) {
user->password = os_malloc(eap_user->password_len);
if (user->password == NULL)
- return -1;
+ goto out;
os_memcpy(user->password, eap_user->password,
eap_user->password_len);
user->password_len = eap_user->password_len;
@@ -83,8 +84,13 @@
user->ttls_auth = eap_user->ttls_auth;
user->remediation = eap_user->remediation;
user->accept_attr = eap_user->accept_attr;
+ rv = 0;
- return 0;
+out:
+ if (rv)
+ wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__);
+
+ return rv;
}
diff --git a/src/ap/beacon.c b/src/ap/beacon.c
index 82fd7c4..1a46d4d 100644
--- a/src/ap/beacon.c
+++ b/src/ap/beacon.c
@@ -15,6 +15,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
+#include "common/hw_features_common.h"
#include "wps/wps_defs.h"
#include "p2p/p2p.h"
#include "hostapd.h"
@@ -363,7 +364,6 @@
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)
{
@@ -383,6 +383,10 @@
#endif /* CONFIG_P2P */
if (hapd->conf->vendor_elements)
buflen += wpabuf_len(hapd->conf->vendor_elements);
+ if (hapd->conf->vendor_vht) {
+ buflen += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
+ 2 + sizeof(struct ieee80211_vht_operation);
+ }
resp = os_zalloc(buflen);
if (resp == NULL)
return NULL;
@@ -401,7 +405,7 @@
/* 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));
+ host_to_le16(hostapd_own_capab_info(hapd));
pos = resp->u.probe_resp.variable;
*pos++ = WLAN_EID_SSID;
@@ -450,8 +454,12 @@
pos = hostapd_add_csa_elems(hapd, pos, (u8 *)resp,
&hapd->cs_c_off_proberesp);
#ifdef CONFIG_IEEE80211AC
- pos = hostapd_eid_vht_capabilities(hapd, pos);
- pos = hostapd_eid_vht_operation(hapd, pos);
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_operation(hapd, pos);
+ }
+ if (hapd->conf->vendor_vht)
+ pos = hostapd_eid_vendor_vht(hapd, pos);
#endif /* CONFIG_IEEE80211AC */
/* Wi-Fi Alliance WMM */
@@ -543,7 +551,6 @@
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;
@@ -579,6 +586,27 @@
return;
}
+ /*
+ * No need to reply if the Probe Request frame was sent on an adjacent
+ * channel. IEEE Std 802.11-2012 describes this as a requirement for an
+ * AP with dot11RadioMeasurementActivated set to true, but strictly
+ * speaking does not allow such ignoring of Probe Request frames if
+ * dot11RadioMeasurementActivated is false. Anyway, this can help reduce
+ * number of unnecessary Probe Response frames for cases where the STA
+ * is less likely to see them (Probe Request frame sent on a
+ * neighboring, but partially overlapping, channel).
+ */
+ if (elems.ds_params &&
+ hapd->iface->current_mode &&
+ (hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211G ||
+ hapd->iface->current_mode->mode == HOSTAPD_MODE_IEEE80211B) &&
+ hapd->iconf->channel != elems.ds_params[0]) {
+ wpa_printf(MSG_DEBUG,
+ "Ignore Probe Request due to DS Params mismatch: chan=%u != ds.chan=%u",
+ hapd->iconf->channel, elems.ds_params[0]);
+ return;
+ }
+
#ifdef CONFIG_P2P
if (hapd->p2p && elems.wps_ie) {
struct wpabuf *wps;
@@ -613,8 +641,6 @@
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 &&
@@ -634,10 +660,7 @@
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 (res == NO_SSID_MATCH) {
if (!(mgmt->da[0] & 0x01)) {
wpa_printf(MSG_MSGDUMP, "Probe Request from " MACSTR
" for foreign SSID '%s' (DA " MACSTR ")%s",
@@ -704,7 +727,7 @@
}
#endif /* CONFIG_TESTING_OPTIONS */
- resp = hostapd_gen_probe_resp(hapd, sta, mgmt, elems.p2p != NULL,
+ resp = hostapd_gen_probe_resp(hapd, mgmt, elems.p2p != NULL,
&resp_len);
if (resp == NULL)
return;
@@ -759,7 +782,7 @@
"this");
/* Generate a Probe Response template for the non-P2P case */
- return hostapd_gen_probe_resp(hapd, NULL, NULL, 0, resp_len);
+ return hostapd_gen_probe_resp(hapd, NULL, 0, resp_len);
}
#endif /* NEED_AP_MLME */
@@ -791,6 +814,14 @@
#endif /* CONFIG_P2P */
if (hapd->conf->vendor_elements)
tail_len += wpabuf_len(hapd->conf->vendor_elements);
+
+#ifdef CONFIG_IEEE80211AC
+ if (hapd->conf->vendor_vht) {
+ tail_len += 5 + 2 + sizeof(struct ieee80211_vht_capabilities) +
+ 2 + sizeof(struct ieee80211_vht_operation);
+ }
+#endif /* CONFIG_IEEE80211AC */
+
tailpos = tail = os_malloc(tail_len);
if (head == NULL || tail == NULL) {
wpa_printf(MSG_ERROR, "Failed to set beacon data");
@@ -810,7 +841,7 @@
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);
+ capab_info = hostapd_own_capab_info(hapd);
head->u.beacon.capab_info = host_to_le16(capab_info);
pos = &head->u.beacon.variable[0];
@@ -880,8 +911,12 @@
tailpos = hostapd_add_csa_elems(hapd, tailpos, tail,
&hapd->cs_c_off_beacon);
#ifdef CONFIG_IEEE80211AC
- tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
- tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ tailpos = hostapd_eid_vht_capabilities(hapd, tailpos);
+ tailpos = hostapd_eid_vht_operation(hapd, tailpos);
+ }
+ if (hapd->conf->vendor_vht)
+ tailpos = hostapd_eid_vendor_vht(hapd, tailpos);
#endif /* CONFIG_IEEE80211AC */
/* Wi-Fi Alliance WMM */
@@ -981,6 +1016,9 @@
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_P2P
+ params->p2p_go_ctwindow = hapd->iconf->p2p_go_ctwindow;
+#endif /* CONFIG_P2P */
#ifdef CONFIG_HS20
params->disable_dgaf = hapd->conf->disable_dgaf;
if (hapd->conf->osen) {
@@ -1029,6 +1067,8 @@
params.beacon_ies = beacon;
params.proberesp_ies = proberesp;
params.assocresp_ies = assocresp;
+ params.reenable = hapd->reenable_beacon;
+ hapd->reenable_beacon = 0;
if (iface->current_mode &&
hostapd_set_freq_params(&freq, iconf->hw_mode, iface->freq,
diff --git a/src/ap/ctrl_iface_ap.c b/src/ap/ctrl_iface_ap.c
index 8c84e3e..41ab988 100644
--- a/src/ap/ctrl_iface_ap.c
+++ b/src/ap/ctrl_iface_ap.c
@@ -537,3 +537,9 @@
return 0;
}
+
+
+int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd)
+{
+ return hostapd_drv_stop_ap(hapd);
+}
diff --git a/src/ap/ctrl_iface_ap.h b/src/ap/ctrl_iface_ap.h
index ee58b4c..e5297d0 100644
--- a/src/ap/ctrl_iface_ap.h
+++ b/src/ap/ctrl_iface_ap.h
@@ -23,6 +23,6 @@
size_t buflen);
int hostapd_parse_csa_settings(const char *pos,
struct csa_settings *settings);
-
+int hostapd_ctrl_iface_stop_ap(struct hostapd_data *hapd);
#endif /* CTRL_IFACE_AP_H */
diff --git a/src/ap/dfs.c b/src/ap/dfs.c
index 0db5ef6..715f19b 100644
--- a/src/ap/dfs.c
+++ b/src/ap/dfs.c
@@ -1,7 +1,7 @@
/*
* DFS - Dynamic Frequency Selection
* Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
- * Copyright (c) 2013, Qualcomm Atheros, Inc.
+ * Copyright (c) 2013-2015, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
+#include "common/hw_features_common.h"
#include "common/wpa_ctrl.h"
#include "hostapd.h"
#include "ap_drv_ops.h"
@@ -121,6 +122,20 @@
}
+static struct hostapd_channel_data *
+dfs_get_chan_data(struct hostapd_hw_modes *mode, int freq, int first_chan_idx)
+{
+ int i;
+
+ for (i = first_chan_idx; i < mode->num_channels; i++) {
+ if (mode->channels[i].freq == freq)
+ return &mode->channels[i];
+ }
+
+ return NULL;
+}
+
+
static int dfs_chan_range_available(struct hostapd_hw_modes *mode,
int first_chan_idx, int num_chans,
int skip_radar)
@@ -128,15 +143,15 @@
struct hostapd_channel_data *first_chan, *chan;
int i;
- if (first_chan_idx + num_chans >= mode->num_channels)
+ if (first_chan_idx + num_chans > mode->num_channels)
return 0;
first_chan = &mode->channels[first_chan_idx];
for (i = 0; i < num_chans; i++) {
- chan = &mode->channels[first_chan_idx + i];
-
- if (first_chan->freq + i * 20 != chan->freq)
+ chan = dfs_get_chan_data(mode, first_chan->freq + i * 20,
+ first_chan_idx);
+ if (!chan)
return 0;
if (!dfs_channel_available(chan, skip_radar))
@@ -150,16 +165,10 @@
static int is_in_chanlist(struct hostapd_iface *iface,
struct hostapd_channel_data *chan)
{
- int *entry;
-
- if (!iface->conf->chanlist)
+ if (!iface->conf->acs_ch_list.num)
return 1;
- for (entry = iface->conf->chanlist; *entry != -1; entry++) {
- if (*entry == chan->chan)
- return 1;
- }
- return 0;
+ return freq_range_list_includes(&iface->conf->acs_ch_list, chan->chan);
}
@@ -747,11 +756,19 @@
if (success) {
/* Complete iface/ap configuration */
- set_dfs_state(iface, freq, ht_enabled, chan_offset,
- chan_width, cf1, cf2,
- HOSTAPD_CHAN_DFS_AVAILABLE);
- iface->cac_started = 0;
- hostapd_setup_interface_complete(iface, 0);
+ if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
+ /* Complete AP configuration for the first bring up. */
+ if (iface->state != HAPD_IFACE_ENABLED)
+ hostapd_setup_interface_complete(iface, 0);
+ else
+ iface->cac_started = 0;
+ } else {
+ set_dfs_state(iface, freq, ht_enabled, chan_offset,
+ chan_width, cf1, cf2,
+ HOSTAPD_CHAN_DFS_AVAILABLE);
+ iface->cac_started = 0;
+ hostapd_setup_interface_complete(iface, 0);
+ }
}
return 0;
@@ -933,13 +950,17 @@
{
int res;
- if (!iface->conf->ieee80211h)
- return 0;
-
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_RADAR_DETECTED
"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+ /* Proceed only if DFS is not offloaded to the driver */
+ if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
+ return 0;
+
+ if (!iface->conf->ieee80211h)
+ return 0;
+
/* mark radar frequency as invalid */
set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
cf1, cf2, HOSTAPD_CHAN_DFS_UNAVAILABLE);
@@ -963,6 +984,11 @@
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_NOP_FINISHED
"freq=%d ht_enabled=%d chan_offset=%d chan_width=%d cf1=%d cf2=%d",
freq, ht_enabled, chan_offset, chan_width, cf1, cf2);
+
+ /* Proceed only if DFS is not offloaded to the driver */
+ if (iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD)
+ return 0;
+
/* TODO add correct implementation here */
set_dfs_state(iface, freq, ht_enabled, chan_offset, chan_width,
cf1, cf2, HOSTAPD_CHAN_DFS_USABLE);
@@ -994,3 +1020,53 @@
res = dfs_check_chans_radar(iface, start_chan_idx1, n_chans1);
return res;
}
+
+
+int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
+ int ht_enabled, int chan_offset, int chan_width,
+ int cf1, int cf2)
+{
+ wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, DFS_EVENT_CAC_START
+ "freq=%d chan=%d chan_offset=%d width=%d seg0=%d "
+ "seg1=%d cac_time=%ds",
+ freq, (freq - 5000) / 5, chan_offset, chan_width, cf1, cf2, 60);
+ iface->cac_started = 1;
+ return 0;
+}
+
+
+/*
+ * Main DFS handler for offloaded case.
+ * 2 - continue channel/AP setup for non-DFS channel
+ * 1 - continue channel/AP setup for DFS channel
+ * 0 - channel/AP setup will be continued after CAC
+ * -1 - hit critical error
+ */
+int hostapd_handle_dfs_offload(struct hostapd_iface *iface)
+{
+ wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
+ __func__, iface->cac_started);
+
+ /*
+ * If DFS has already been started, then we are being called from a
+ * callback to continue AP/channel setup. Reset the CAC start flag and
+ * return.
+ */
+ if (iface->cac_started) {
+ wpa_printf(MSG_DEBUG, "%s: iface->cac_started: %d",
+ __func__, iface->cac_started);
+ iface->cac_started = 0;
+ return 1;
+ }
+
+ if (ieee80211_is_dfs(iface->freq)) {
+ wpa_printf(MSG_DEBUG, "%s: freq %d MHz requires DFS",
+ __func__, iface->freq);
+ return 0;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "%s: freq %d MHz does not require DFS. Continue channel/AP setup",
+ __func__, iface->freq);
+ return 2;
+}
diff --git a/src/ap/dfs.h b/src/ap/dfs.h
index a619c55..be8c0e6 100644
--- a/src/ap/dfs.h
+++ b/src/ap/dfs.h
@@ -22,5 +22,9 @@
int ht_enabled,
int chan_offset, int chan_width, int cf1, int cf2);
int hostapd_is_dfs_required(struct hostapd_iface *iface);
+int hostapd_dfs_start_cac(struct hostapd_iface *iface, int freq,
+ int ht_enabled, int chan_offset, int chan_width,
+ int cf1, int cf2);
+int hostapd_handle_dfs_offload(struct hostapd_iface *iface);
#endif /* DFS_H */
diff --git a/src/ap/dhcp_snoop.c b/src/ap/dhcp_snoop.c
index a706024..3a77225 100644
--- a/src/ap/dhcp_snoop.c
+++ b/src/ap/dhcp_snoop.c
@@ -42,6 +42,17 @@
static const u8 ic_bootp_cookie[] = { 99, 130, 83, 99 };
+static const char * ipaddr_str(u32 addr)
+{
+ static char buf[17];
+
+ os_snprintf(buf, sizeof(buf), "%u.%u.%u.%u",
+ (addr >> 24) & 0xff, (addr >> 16) & 0xff,
+ (addr >> 8) & 0xff, addr & 0xff);
+ return buf;
+}
+
+
static void handle_dhcp(void *ctx, const u8 *src_addr, const u8 *buf,
size_t len)
{
@@ -109,16 +120,17 @@
return;
wpa_printf(MSG_DEBUG, "dhcp_snoop: Found DHCPACK for " MACSTR
- " @ IPv4 address %X/%d",
- MAC2STR(sta->addr), ntohl(b->your_ip), prefixlen);
+ " @ IPv4 address %s/%d",
+ MAC2STR(sta->addr), ipaddr_str(ntohl(b->your_ip)),
+ prefixlen);
if (sta->ipaddr == b->your_ip)
return;
if (sta->ipaddr != 0) {
wpa_printf(MSG_DEBUG,
- "dhcp_snoop: Removing IPv4 address %X from the ip neigh table",
- sta->ipaddr);
+ "dhcp_snoop: Removing IPv4 address %s from the ip neigh table",
+ ipaddr_str(be_to_host32(sta->ipaddr)));
hostapd_drv_br_delete_ip_neigh(hapd, 4,
(u8 *) &sta->ipaddr);
}
diff --git a/src/ap/drv_callbacks.c b/src/ap/drv_callbacks.c
index 016f5ed..55f429a 100644
--- a/src/ap/drv_callbacks.c
+++ b/src/ap/drv_callbacks.c
@@ -128,8 +128,6 @@
#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
if (elems.ht_capabilities &&
- elems.ht_capabilities_len >=
- sizeof(struct ieee80211_ht_capabilities) &&
(hapd->iface->conf->ht_capab &
HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET)) {
struct ieee80211_ht_capabilities *ht_cap =
@@ -441,7 +439,7 @@
int offset, int width, int cf1, int cf2)
{
#ifdef NEED_AP_MLME
- int channel, chwidth, seg0_idx = 0, seg1_idx = 0;
+ int channel, chwidth, seg0_idx = 0, seg1_idx = 0, is_dfs;
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_INFO,
@@ -499,13 +497,18 @@
hapd->iconf->vht_oper_centr_freq_seg0_idx = seg0_idx;
hapd->iconf->vht_oper_centr_freq_seg1_idx = seg1_idx;
+ is_dfs = ieee80211_is_dfs(freq);
+
if (hapd->csa_in_progress &&
freq == hapd->cs_freq_params.freq) {
hostapd_cleanup_cs_params(hapd);
ieee802_11_set_beacon(hapd);
- wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED "freq=%d",
- freq);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
+ "freq=%d dfs=%d", freq, is_dfs);
+ } else if (hapd->iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) {
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_CSA_FINISHED
+ "freq=%d dfs=%d", freq, is_dfs);
}
#endif /* NEED_AP_MLME */
}
@@ -529,9 +532,8 @@
#ifdef CONFIG_ACS
static void hostapd_acs_channel_selected(struct hostapd_data *hapd,
- u8 pri_channel, u8 sec_channel)
+ struct acs_selected_channels *acs_res)
{
- int channel;
int ret;
if (hapd->iconf->channel) {
@@ -540,29 +542,55 @@
return;
}
- hapd->iface->freq = hostapd_hw_get_freq(hapd, pri_channel);
+ hapd->iface->freq = hostapd_hw_get_freq(hapd, acs_res->pri_channel);
- channel = pri_channel;
- if (!channel) {
+ if (!acs_res->pri_channel) {
hostapd_logger(hapd, NULL, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_WARNING,
"driver switched to bad channel");
return;
}
- hapd->iconf->channel = channel;
+ hapd->iconf->channel = acs_res->pri_channel;
+ hapd->iconf->acs = 1;
- if (sec_channel == 0)
+ if (acs_res->sec_channel == 0)
hapd->iconf->secondary_channel = 0;
- else if (sec_channel < pri_channel)
+ else if (acs_res->sec_channel < acs_res->pri_channel)
hapd->iconf->secondary_channel = -1;
- else if (sec_channel > pri_channel)
+ else if (acs_res->sec_channel > acs_res->pri_channel)
hapd->iconf->secondary_channel = 1;
else {
wpa_printf(MSG_ERROR, "Invalid secondary channel!");
return;
}
+ if (hapd->iface->conf->ieee80211ac) {
+ /* set defaults for backwards compatibility */
+ hapd->iconf->vht_oper_centr_freq_seg1_idx = 0;
+ hapd->iconf->vht_oper_centr_freq_seg0_idx = 0;
+ hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_USE_HT;
+ if (acs_res->ch_width == 80) {
+ hapd->iconf->vht_oper_centr_freq_seg0_idx =
+ acs_res->vht_seg0_center_ch;
+ hapd->iconf->vht_oper_chwidth = VHT_CHANWIDTH_80MHZ;
+ } else if (acs_res->ch_width == 160) {
+ if (acs_res->vht_seg1_center_ch == 0) {
+ hapd->iconf->vht_oper_centr_freq_seg0_idx =
+ acs_res->vht_seg0_center_ch;
+ hapd->iconf->vht_oper_chwidth =
+ VHT_CHANWIDTH_160MHZ;
+ } else {
+ hapd->iconf->vht_oper_centr_freq_seg0_idx =
+ acs_res->vht_seg0_center_ch;
+ hapd->iconf->vht_oper_centr_freq_seg1_idx =
+ acs_res->vht_seg1_center_ch;
+ hapd->iconf->vht_oper_chwidth =
+ VHT_CHANWIDTH_80P80MHZ;
+ }
+ }
+ }
+
ret = hostapd_acs_completed(hapd->iface, 0);
if (ret) {
wpa_printf(MSG_ERROR,
@@ -1034,6 +1062,16 @@
radar->cf1, radar->cf2);
}
+
+static void hostapd_event_dfs_cac_started(struct hostapd_data *hapd,
+ struct dfs_event *radar)
+{
+ wpa_printf(MSG_DEBUG, "DFS offload CAC started on %d MHz", radar->freq);
+ hostapd_dfs_start_cac(hapd->iface, radar->freq, radar->ht_enabled,
+ radar->chan_offset, radar->chan_width,
+ radar->cf1, radar->cf2);
+}
+
#endif /* NEED_AP_MLME */
@@ -1250,18 +1288,34 @@
eloop_terminate();
}
break;
+ case EVENT_DFS_CAC_STARTED:
+ if (!data)
+ break;
+ hostapd_event_dfs_cac_started(hapd, &data->dfs_event);
+ break;
#endif /* NEED_AP_MLME */
case EVENT_INTERFACE_ENABLED:
wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_ENABLED);
+ if (hapd->disabled && hapd->started) {
+ hapd->disabled = 0;
+ /*
+ * Try to re-enable interface if the driver stopped it
+ * when the interface got disabled.
+ */
+ wpa_auth_reconfig_group_keys(hapd->wpa_auth);
+ hapd->reenable_beacon = 1;
+ ieee802_11_set_beacon(hapd);
+ }
break;
case EVENT_INTERFACE_DISABLED:
+ hostapd_free_stas(hapd);
wpa_msg(hapd->msg_ctx, MSG_INFO, INTERFACE_DISABLED);
+ hapd->disabled = 1;
break;
#ifdef CONFIG_ACS
case EVENT_ACS_CHANNEL_SELECTED:
- hostapd_acs_channel_selected(
- hapd, data->acs_selected_channels.pri_channel,
- data->acs_selected_channels.sec_channel);
+ hostapd_acs_channel_selected(hapd,
+ &data->acs_selected_channels);
break;
#endif /* CONFIG_ACS */
default:
diff --git a/src/ap/eap_user_db.c b/src/ap/eap_user_db.c
index 559d77f..082d0f5 100644
--- a/src/ap/eap_user_db.c
+++ b/src/ap/eap_user_db.c
@@ -138,8 +138,12 @@
char id_str[256], cmd[300];
size_t i;
- if (identity_len >= sizeof(id_str))
+ if (identity_len >= sizeof(id_str)) {
+ wpa_printf(MSG_DEBUG, "%s: identity len too big: %d >= %d",
+ __func__, (int) identity_len,
+ (int) (sizeof(id_str)));
return NULL;
+ }
os_memcpy(id_str, identity, identity_len);
id_str[identity_len] = '\0';
for (i = 0; i < identity_len; i++) {
@@ -182,7 +186,9 @@
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");
+ wpa_printf(MSG_DEBUG,
+ "DB: Failed to complete SQL operation: %s db: %s",
+ sqlite3_errmsg(db), hapd->conf->eap_user_sqlite);
} else if (hapd->tmp_eap_user.next)
user = &hapd->tmp_eap_user;
@@ -192,8 +198,10 @@
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");
+ wpa_printf(MSG_DEBUG,
+ "DB: Failed to complete SQL operation: %s db: %s",
+ sqlite3_errmsg(db),
+ hapd->conf->eap_user_sqlite);
} else if (hapd->tmp_eap_user.next) {
user = &hapd->tmp_eap_user;
os_free(user->identity);
diff --git a/src/ap/hostapd.c b/src/ap/hostapd.c
index 2103747..5abe5ed 100644
--- a/src/ap/hostapd.c
+++ b/src/ap/hostapd.c
@@ -15,6 +15,8 @@
#include "radius/radius_client.h"
#include "radius/radius_das.h"
#include "eap_server/tncs.h"
+#include "eapol_auth/eapol_auth_sm.h"
+#include "eapol_auth/eapol_auth_sm_i.h"
#include "hostapd.h"
#include "authsrv.h"
#include "sta_info.h"
@@ -80,8 +82,7 @@
* Force PSK to be derived again since SSID or passphrase may
* have changed.
*/
- os_free(ssid->wpa_psk);
- ssid->wpa_psk = NULL;
+ hostapd_config_clear_wpa_psk(&hapd->conf->ssid.wpa_psk);
}
if (hostapd_setup_wpa_psk(hapd->conf)) {
wpa_printf(MSG_ERROR, "Failed to re-configure WPA PSK "
@@ -178,6 +179,7 @@
hapd = iface->bss[j];
hapd->iconf = newconf;
hapd->iconf->channel = oldconf->channel;
+ hapd->iconf->acs = oldconf->acs;
hapd->iconf->secondary_channel = oldconf->secondary_channel;
hapd->iconf->ieee80211n = oldconf->ieee80211n;
hapd->iconf->ieee80211ac = oldconf->ieee80211ac;
@@ -355,6 +357,11 @@
static void hostapd_cleanup_iface_partial(struct hostapd_iface *iface)
{
wpa_printf(MSG_DEBUG, "%s(%p)", __func__, iface);
+#ifdef CONFIG_IEEE80211N
+#ifdef NEED_AP_MLME
+ hostapd_stop_setup_timers(iface);
+#endif /* NEED_AP_MLME */
+#endif /* CONFIG_IEEE80211N */
hostapd_free_hw_features(iface->hw_features, iface->num_hw_features);
iface->hw_features = NULL;
os_free(iface->current_rates);
@@ -614,51 +621,190 @@
static struct sta_info * hostapd_das_find_sta(struct hostapd_data *hapd,
- struct radius_das_attrs *attr)
+ struct radius_das_attrs *attr,
+ int *multi)
{
- struct sta_info *sta = NULL;
+ struct sta_info *selected, *sta;
char buf[128];
+ int num_attr = 0;
+ int count;
- if (attr->sta_addr)
+ *multi = 0;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next)
+ sta->radius_das_match = 1;
+
+ if (attr->sta_addr) {
+ num_attr++;
sta = ap_get_sta(hapd, attr->sta_addr);
+ if (!sta) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No Calling-Station-Id match");
+ return NULL;
+ }
- if (sta == NULL && attr->acct_session_id &&
- attr->acct_session_id_len == 17) {
+ selected = sta;
for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (sta != selected)
+ sta->radius_das_match = 0;
+ }
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: Calling-Station-Id match");
+ }
+
+ if (attr->acct_session_id) {
+ num_attr++;
+ if (attr->acct_session_id_len != 17) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Acct-Session-Id cannot match");
+ return NULL;
+ }
+ count = 0;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!sta->radius_das_match)
+ continue;
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 (os_memcmp(attr->acct_session_id, buf, 17) != 0)
+ sta->radius_das_match = 0;
+ else
+ count++;
}
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No matches remaining after Acct-Session-Id check");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: Acct-Session-Id match");
}
- if (sta == NULL && attr->cui) {
+ if (attr->acct_multi_session_id) {
+ num_attr++;
+ if (attr->acct_multi_session_id_len != 17) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Acct-Multi-Session-Id cannot match");
+ return NULL;
+ }
+ count = 0;
+
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (!sta->radius_das_match)
+ continue;
+ if (!sta->eapol_sm ||
+ !sta->eapol_sm->acct_multi_session_id_hi) {
+ sta->radius_das_match = 0;
+ continue;
+ }
+ os_snprintf(buf, sizeof(buf), "%08X+%08X",
+ sta->eapol_sm->acct_multi_session_id_hi,
+ sta->eapol_sm->acct_multi_session_id_lo);
+ if (os_memcmp(attr->acct_multi_session_id, buf, 17) !=
+ 0)
+ sta->radius_das_match = 0;
+ else
+ count++;
+ }
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No matches remaining after Acct-Multi-Session-Id check");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Acct-Multi-Session-Id match");
+ }
+
+ if (attr->cui) {
+ num_attr++;
+ count = 0;
+
for (sta = hapd->sta_list; sta; sta = sta->next) {
struct wpabuf *cui;
+
+ if (!sta->radius_das_match)
+ continue;
cui = ieee802_1x_get_radius_cui(sta->eapol_sm);
- if (cui && wpabuf_len(cui) == attr->cui_len &&
+ if (!cui || wpabuf_len(cui) != attr->cui_len ||
os_memcmp(wpabuf_head(cui), attr->cui,
- attr->cui_len) == 0)
- break;
+ attr->cui_len) != 0)
+ sta->radius_das_match = 0;
+ else
+ count++;
}
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No matches remaining after Chargeable-User-Identity check");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Chargeable-User-Identity match");
}
- if (sta == NULL && attr->user_name) {
+ if (attr->user_name) {
+ num_attr++;
+ count = 0;
+
for (sta = hapd->sta_list; sta; sta = sta->next) {
u8 *identity;
size_t identity_len;
+
+ if (!sta->radius_das_match)
+ continue;
identity = ieee802_1x_get_identity(sta->eapol_sm,
&identity_len);
- if (identity &&
- identity_len == attr->user_name_len &&
+ if (!identity ||
+ identity_len != attr->user_name_len ||
os_memcmp(identity, attr->user_name, identity_len)
- == 0)
- break;
+ != 0)
+ sta->radius_das_match = 0;
+ else
+ count++;
+ }
+
+ if (count == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No matches remaining after User-Name check");
+ return NULL;
+ }
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: User-Name match");
+ }
+
+ if (num_attr == 0) {
+ /*
+ * In theory, we could match all current associations, but it
+ * seems safer to just reject requests that do not include any
+ * session identification attributes.
+ */
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: No session identification attributes included");
+ return NULL;
+ }
+
+ selected = NULL;
+ for (sta = hapd->sta_list; sta; sta = sta->next) {
+ if (sta->radius_das_match) {
+ if (selected) {
+ *multi = 1;
+ return NULL;
+ }
+ selected = sta;
}
}
- return sta;
+ return selected;
+}
+
+
+static int hostapd_das_disconnect_pmksa(struct hostapd_data *hapd,
+ struct radius_das_attrs *attr)
+{
+ if (!hapd->wpa_auth)
+ return -1;
+ return wpa_auth_radius_das_disconnect_pmksa(hapd->wpa_auth, attr);
}
@@ -667,14 +813,29 @@
{
struct hostapd_data *hapd = ctx;
struct sta_info *sta;
+ int multi;
if (hostapd_das_nas_mismatch(hapd, attr))
return RADIUS_DAS_NAS_MISMATCH;
- sta = hostapd_das_find_sta(hapd, attr);
- if (sta == NULL)
+ sta = hostapd_das_find_sta(hapd, attr, &multi);
+ if (sta == NULL) {
+ if (multi) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: Multiple sessions match - not supported");
+ return RADIUS_DAS_MULTI_SESSION_MATCH;
+ }
+ if (hostapd_das_disconnect_pmksa(hapd, attr) == 0) {
+ wpa_printf(MSG_DEBUG,
+ "RADIUS DAS: PMKSA cache entry matched");
+ return RADIUS_DAS_SUCCESS;
+ }
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: No matching session found");
return RADIUS_DAS_SESSION_NOT_FOUND;
+ }
+ wpa_printf(MSG_DEBUG, "RADIUS DAS: Found a matching session " MACSTR
+ " - disconnecting", MAC2STR(sta->addr));
wpa_auth_pmksa_remove(hapd->wpa_auth, sta->addr);
hostapd_drv_sta_deauth(hapd, sta->addr,
@@ -701,7 +862,7 @@
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];
+ u8 ssid[SSID_MAX_LEN + 1];
int ssid_len, set_ssid;
char force_ifname[IFNAMSIZ];
u8 if_addr[ETH_ALEN];
@@ -1217,6 +1378,7 @@
size_t j;
u8 *prev_addr;
int delay_apply_cfg = 0;
+ int res_dfs_offload = 0;
if (err)
goto fail;
@@ -1243,6 +1405,23 @@
goto fail;
return res;
}
+ } else {
+ /* If DFS is offloaded to the driver */
+ res_dfs_offload = hostapd_handle_dfs_offload(iface);
+ if (res_dfs_offload <= 0) {
+ if (res_dfs_offload < 0)
+ goto fail;
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "Proceed with AP/channel setup");
+ /*
+ * If this is a DFS channel, move to completing
+ * AP setup.
+ */
+ if (res_dfs_offload == 1)
+ goto dfs_offload;
+ /* Otherwise fall through. */
+ }
}
#endif /* NEED_AP_MLME */
@@ -1337,6 +1516,19 @@
goto fail;
}
+ if ((iface->drv_flags & WPA_DRIVER_FLAGS_DFS_OFFLOAD) &&
+ !res_dfs_offload) {
+ /*
+ * If freq is DFS, and DFS is offloaded to the driver, then wait
+ * for CAC to complete.
+ */
+ wpa_printf(MSG_DEBUG, "%s: Wait for CAC to complete", __func__);
+ return res_dfs_offload;
+ }
+
+#ifdef NEED_AP_MLME
+dfs_offload:
+#endif /* NEED_AP_MLME */
hostapd_set_state(iface, HAPD_IFACE_ENABLED);
wpa_msg(iface->bss[0]->msg_ctx, MSG_INFO, AP_EVENT_ENABLED);
if (hapd->setup_complete_cb)
@@ -1428,6 +1620,7 @@
wpa_printf(MSG_DEBUG, "%s: deinit bss %s", __func__,
hapd->conf->iface);
hostapd_bss_deinit_no_free(hapd);
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_EVENT_DISABLED);
hostapd_cleanup(hapd);
}
@@ -1440,6 +1633,8 @@
if (iface == NULL)
return;
+ hostapd_set_state(iface, HAPD_IFACE_DISABLED);
+
#ifdef CONFIG_IEEE80211N
#ifdef NEED_AP_MLME
hostapd_stop_setup_timers(iface);
@@ -1872,33 +2067,37 @@
}
-static struct hostapd_iface * hostapd_data_alloc(
- struct hapd_interfaces *interfaces, struct hostapd_config *conf)
+static int hostapd_data_alloc(struct hostapd_iface *hapd_iface,
+ 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_calloc(conf->num_bss,
sizeof(struct hostapd_data *));
if (hapd_iface->bss == NULL)
- return NULL;
+ return -1;
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;
+ if (hapd == NULL) {
+ while (i > 0) {
+ i--;
+ os_free(hapd_iface->bss[i]);
+ hapd_iface->bss[i] = NULL;
+ }
+ os_free(hapd_iface->bss);
+ hapd_iface->bss = NULL;
+ return -1;
+ }
hapd->msg_ctx = hapd;
}
- hapd_iface->interfaces = interfaces;
+ hapd_iface->conf = conf;
+ hapd_iface->num_bss = conf->num_bss;
- return hapd_iface;
+ return 0;
}
@@ -1945,13 +2144,10 @@
}
if (new_iface) {
- if (interfaces->driver_init(hapd_iface)) {
- interfaces->count--;
+ if (interfaces->driver_init(hapd_iface))
goto fail;
- }
if (hostapd_setup_interface(hapd_iface)) {
- interfaces->count--;
hostapd_deinit_driver(
hapd_iface->bss[0]->driver,
hapd_iface->bss[0]->drv_priv,
@@ -1975,6 +2171,8 @@
hapd_iface->num_bss--;
wpa_printf(MSG_DEBUG, "%s: free hapd %p %s",
__func__, hapd, hapd->conf->iface);
+ hostapd_config_free_bss(hapd->conf);
+ hapd->conf = NULL;
os_free(hapd);
return -1;
}
@@ -2005,6 +2203,7 @@
"for interface", __func__);
goto fail;
}
+ new_iface = hapd_iface;
if (conf_file && interfaces->config_read_cb) {
conf = interfaces->config_read_cb(conf_file);
@@ -2019,17 +2218,18 @@
goto fail;
}
- hapd_iface = hostapd_data_alloc(interfaces, conf);
- if (hapd_iface == NULL) {
+ if (hostapd_data_alloc(hapd_iface, conf) < 0) {
wpa_printf(MSG_ERROR, "%s: Failed to allocate memory "
"for hostapd", __func__);
goto fail;
}
+ conf = NULL;
if (start_ctrl_iface(hapd_iface) < 0)
goto fail;
- wpa_printf(MSG_INFO, "Add interface '%s'", conf->bss[0]->iface);
+ wpa_printf(MSG_INFO, "Add interface '%s'",
+ hapd_iface->conf->bss[0]->iface);
return 0;
@@ -2056,6 +2256,10 @@
os_free(hapd_iface->bss);
hapd_iface->bss = NULL;
}
+ if (new_iface) {
+ interfaces->count--;
+ interfaces->iface[interfaces->count] = NULL;
+ }
hostapd_cleanup_iface(hapd_iface);
}
return -1;
@@ -2076,6 +2280,7 @@
wpa_printf(MSG_DEBUG, "%s: free hapd %p (%s)",
__func__, hapd, hapd->conf->iface);
hostapd_config_free_bss(hapd->conf);
+ hapd->conf = NULL;
os_free(hapd);
iface->num_bss--;
diff --git a/src/ap/hostapd.h b/src/ap/hostapd.h
index e291d08..788b118 100644
--- a/src/ap/hostapd.h
+++ b/src/ap/hostapd.h
@@ -108,6 +108,8 @@
struct hostapd_bss_config *conf;
int interface_added; /* virtual interface added for this BSS */
unsigned int started:1;
+ unsigned int disabled:1;
+ unsigned int reenable_beacon:1;
u8 own_addr[ETH_ALEN];
diff --git a/src/ap/hw_features.c b/src/ap/hw_features.c
index 7d672c8..6d84ee4 100644
--- a/src/ap/hw_features.c
+++ b/src/ap/hw_features.c
@@ -15,6 +15,7 @@
#include "common/ieee802_11_defs.h"
#include "common/ieee802_11_common.h"
#include "common/wpa_ctrl.h"
+#include "common/hw_features_common.h"
#include "hostapd.h"
#include "ap_config.h"
#include "ap_drv_ops.h"
@@ -74,7 +75,7 @@
int hostapd_get_hw_features(struct hostapd_iface *iface)
{
struct hostapd_data *hapd = iface->bss[0];
- int ret = 0, i, j;
+ int i, j;
u16 num_modes, flags;
struct hostapd_hw_modes *modes;
@@ -137,7 +138,7 @@
}
}
- return ret;
+ return 0;
}
@@ -232,66 +233,16 @@
#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;
+ int pri_chan, sec_chan;
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);
+ pri_chan = iface->conf->channel;
+ sec_chan = pri_chan + iface->conf->secondary_channel * 4;
- /* 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 < ARRAY_SIZE(allowed); 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;
+ return allowed_ht40_channel_pair(iface->current_mode, pri_chan,
+ sec_chan);
}
@@ -307,224 +258,34 @@
}
-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->primary_chan;
- if (oper->ht_param & HT_INFO_HT_PARAM_STA_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;
+ int pri_chan, sec_chan;
+ int res;
pri_chan = iface->conf->channel;
sec_chan = pri_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) {
- if (!experiment("NoSwapWifiPrimaryChannel")) {
- 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);
- return 1;
- } else {
- wpa_printf(MSG_INFO, "NoSwapPrimaryWifiChannel: "
- "would have swapped channels (1).");
- }
- }
+ res = check_40mhz_5g(iface->current_mode, scan_res, pri_chan, sec_chan);
- /*
- * 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) {
- if (!experiment("NoSwapWifiPrimaryChannel")) {
- wpa_printf(MSG_INFO, "Switch own primary and "
- "secondary channel due to BSS "
- "overlap with " MACSTR,
- MAC2STR(bss->bssid));
- ieee80211n_switch_pri_sec(iface);
- } else {
- wpa_printf(MSG_INFO, "NoSwapPrimaryWifiChannel: "
- "would have swapped channels (2).");
- }
- break;
- }
- }
- }
+ if (res == 2)
+ ieee80211n_switch_pri_sec(iface);
- return 1;
-}
-
-
-static int ieee80211n_check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq,
- int start, int end)
-{
- struct ieee802_11_elems elems;
- struct ieee80211_ht_operation *oper;
-
- if (bss->freq < start || bss->freq > end || bss->freq == pri_freq)
- return 0;
-
- ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
- if (!elems.ht_capabilities) {
- wpa_printf(MSG_DEBUG, "Found overlapping legacy BSS: "
- MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
- return 1;
- }
-
- if (elems.ht_operation &&
- elems.ht_operation_len >= sizeof(*oper)) {
- oper = (struct ieee80211_ht_operation *) elems.ht_operation;
- if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)
- return 0;
-
- wpa_printf(MSG_DEBUG, "Found overlapping 20 MHz HT BSS: "
- MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
- return 1;
- }
- return 0;
+ return !!res;
}
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;
+ int pri_chan, sec_chan;
- 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;
- struct ieee802_11_elems elems;
+ pri_chan = iface->conf->channel;
+ sec_chan = pri_chan + iface->conf->secondary_channel * 4;
- /* Check for overlapping 20 MHz BSS */
- if (ieee80211n_check_20mhz_bss(bss, pri_freq, affected_start,
- affected_end)) {
- wpa_printf(MSG_DEBUG,
- "Overlapping 20 MHz BSS is found");
- return 0;
- }
-
- 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;
- }
- }
-
- ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
- 0);
- if (elems.ht_capabilities &&
- elems.ht_capabilities_len >=
- sizeof(struct ieee80211_ht_capabilities)) {
- struct ieee80211_ht_capabilities *ht_cap =
- (struct ieee80211_ht_capabilities *)
- elems.ht_capabilities;
-
- if (le_to_host16(ht_cap->ht_capabilities_info) &
- HT_CAP_INFO_40MHZ_INTOLERANT) {
- wpa_printf(MSG_DEBUG,
- "40 MHz Intolerant is set on channel %d in BSS "
- MACSTR, pri, MAC2STR(bss->bssid));
- return 0;
- }
- }
- }
-
- return 1;
+ return check_40mhz_2g4(iface->current_mode, scan_res, pri_chan,
+ sec_chan);
}
@@ -762,7 +523,11 @@
return 0;
}
- if ((conf & HT_CAP_INFO_SUPP_CHANNEL_WIDTH_SET) &&
+ /*
+ * Driver ACS chosen channel may not be HT40 due to internal driver
+ * restrictions.
+ */
+ if (!iface->conf->acs && (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*]");
@@ -893,12 +658,31 @@
static int ieee80211ac_supported_vht_capab(struct hostapd_iface *iface)
{
- u32 hw = iface->current_mode->vht_capab;
+ struct hostapd_hw_modes *mode = iface->current_mode;
+ u32 hw = mode->vht_capab;
u32 conf = iface->conf->vht_capab;
wpa_printf(MSG_DEBUG, "hw vht capab: 0x%x, conf vht capab: 0x%x",
hw, conf);
+ if (mode->mode == HOSTAPD_MODE_IEEE80211G &&
+ iface->conf->bss[0]->vendor_vht &&
+ mode->vht_capab == 0 && iface->hw_features) {
+ int i;
+
+ for (i = 0; i < iface->num_hw_features; i++) {
+ if (iface->hw_features[i].mode ==
+ HOSTAPD_MODE_IEEE80211A) {
+ mode = &iface->hw_features[i];
+ hw = mode->vht_capab;
+ wpa_printf(MSG_DEBUG,
+ "update hw vht capab based on 5 GHz band: 0x%x",
+ hw);
+ break;
+ }
+ }
+ }
+
#define VHT_CAP_CHECK(cap) \
do { \
if (!ieee80211ac_cap_check(hw, conf, cap, #cap)) \
@@ -1166,35 +950,11 @@
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;
+ return hw_get_freq(hapd->iface->current_mode, chan);
}
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;
+ return hw_get_chan(hapd->iface->current_mode, freq);
}
diff --git a/src/ap/hw_features.h b/src/ap/hw_features.h
index 0f67ab8..ca7f22b 100644
--- a/src/ap/hw_features.h
+++ b/src/ap/hw_features.h
@@ -36,6 +36,11 @@
return -1;
}
+static inline int hostapd_acs_completed(struct hostapd_iface *iface, int err)
+{
+ return -1;
+}
+
static inline int hostapd_select_hw_mode(struct hostapd_iface *iface)
{
return -100;
diff --git a/src/ap/ieee802_11.c b/src/ap/ieee802_11.c
index 9140f3e..62b40d2 100644
--- a/src/ap/ieee802_11.c
+++ b/src/ap/ieee802_11.c
@@ -137,8 +137,7 @@
}
-u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
- int probe)
+u16 hostapd_own_capab_info(struct hostapd_data *hapd)
{
int capab = WLAN_CAPABILITY_ESS;
int privacy;
@@ -171,20 +170,6 @@
privacy = 1;
#endif /* CONFIG_HS20 */
- 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;
@@ -333,6 +318,10 @@
#ifdef CONFIG_SAE
+#define dot11RSNASAERetransPeriod 40 /* msec */
+#define dot11RSNASAESync 5 /* attempts */
+
+
static struct wpabuf * auth_build_sae_commit(struct hostapd_data *hapd,
struct sta_info *sta, int update)
{
@@ -488,6 +477,66 @@
}
+static int sae_check_big_sync(struct sta_info *sta)
+{
+ if (sta->sae->sync > dot11RSNASAESync) {
+ sta->sae->state = SAE_NOTHING;
+ sta->sae->sync = 0;
+ return -1;
+ }
+ return 0;
+}
+
+
+static void auth_sae_retransmit_timer(void *eloop_ctx, void *eloop_data)
+{
+ struct hostapd_data *hapd = eloop_ctx;
+ struct sta_info *sta = eloop_data;
+ int ret;
+
+ if (sae_check_big_sync(sta))
+ return;
+ sta->sae->sync++;
+
+ switch (sta->sae->state) {
+ case SAE_COMMITTED:
+ ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+ eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+ auth_sae_retransmit_timer, hapd, sta);
+ break;
+ case SAE_CONFIRMED:
+ ret = auth_sae_send_confirm(hapd, sta, hapd->own_addr);
+ eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+ auth_sae_retransmit_timer, hapd, sta);
+ break;
+ default:
+ ret = -1;
+ break;
+ }
+
+ if (ret != WLAN_STATUS_SUCCESS)
+ wpa_printf(MSG_INFO, "SAE: Failed to retransmit: ret=%d", ret);
+}
+
+
+void sae_clear_retransmit_timer(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
+}
+
+
+static void sae_set_retransmit_timer(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+ if (!(hapd->conf->mesh & MESH_ENABLED))
+ return;
+
+ eloop_cancel_timeout(auth_sae_retransmit_timer, hapd, sta);
+ eloop_register_timeout(0, dot11RSNASAERetransPeriod * 1000,
+ auth_sae_retransmit_timer, hapd, sta);
+}
+
+
static int sae_sm_step(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *bssid, u8 auth_transaction)
{
@@ -535,6 +584,8 @@
* when receiving Confirm from STA.
*/
}
+ sta->sae->sync = 0;
+ sae_set_retransmit_timer(hapd, sta);
} else {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
@@ -543,6 +594,7 @@
}
break;
case SAE_COMMITTED:
+ sae_clear_retransmit_timer(hapd, sta);
if (auth_transaction == 1) {
if (sae_process_commit(sta->sae) < 0)
return WLAN_STATUS_UNSPECIFIED_FAILURE;
@@ -551,14 +603,22 @@
if (ret)
return ret;
sta->sae->state = SAE_CONFIRMED;
+ sta->sae->sync = 0;
+ sae_set_retransmit_timer(hapd, sta);
} else if (hapd->conf->mesh & MESH_ENABLED) {
/*
* In mesh case, follow SAE finite state machine and
- * send Commit now.
+ * send Commit now, if sync count allows.
*/
+ if (sae_check_big_sync(sta))
+ return WLAN_STATUS_SUCCESS;
+ sta->sae->sync++;
+
ret = auth_sae_send_commit(hapd, sta, bssid, 1);
if (ret)
return ret;
+
+ sae_set_retransmit_timer(hapd, sta);
} else {
/*
* For instructure BSS, send the postponed Confirm from
@@ -580,7 +640,12 @@
}
break;
case SAE_CONFIRMED:
+ sae_clear_retransmit_timer(hapd, sta);
if (auth_transaction == 1) {
+ if (sae_check_big_sync(sta))
+ return WLAN_STATUS_SUCCESS;
+ sta->sae->sync++;
+
ret = auth_sae_send_commit(hapd, sta, bssid, 1);
if (ret)
return ret;
@@ -591,6 +656,8 @@
ret = auth_sae_send_confirm(hapd, sta, bssid);
if (ret)
return ret;
+
+ sae_set_retransmit_timer(hapd, sta);
} else {
sta->flags |= WLAN_STA_AUTH;
sta->auth_alg = WLAN_AUTH_SAE;
@@ -608,6 +675,10 @@
MAC2STR(sta->addr));
ap_free_sta(hapd, sta);
} else {
+ if (sae_check_big_sync(sta))
+ return WLAN_STATUS_SUCCESS;
+ sta->sae->sync++;
+
ret = auth_sae_send_confirm(hapd, sta, bssid);
sae_clear_temp_data(sta->sae);
if (ret)
@@ -637,6 +708,7 @@
if (sta->sae == NULL)
return;
sta->sae->state = SAE_NOTHING;
+ sta->sae->sync = 0;
}
if (auth_transaction == 1) {
@@ -690,6 +762,8 @@
return;
}
sta->sae->state = SAE_COMMITTED;
+ sta->sae->sync = 0;
+ sae_set_retransmit_timer(hapd, sta);
return;
}
@@ -760,6 +834,39 @@
}
wpabuf_free(data);
}
+
+
+/**
+ * auth_sae_init_committed - Send COMMIT and start SAE in committed state
+ * @hapd: BSS data for the device initiating the authentication
+ * @sta: the peer to which commit authentication frame is sent
+ *
+ * This function implements Init event handling (IEEE Std 802.11-2012,
+ * 11.3.8.6.3) in which initial COMMIT message is sent. Prior to calling, the
+ * sta->sae structure should be initialized appropriately via a call to
+ * sae_prepare_commit().
+ */
+int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta)
+{
+ int ret;
+
+ if (!sta->sae || !sta->sae->tmp)
+ return -1;
+
+ if (sta->sae->state != SAE_NOTHING)
+ return -1;
+
+ ret = auth_sae_send_commit(hapd, sta, hapd->own_addr, 0);
+ if (ret)
+ return -1;
+
+ sta->sae->state = SAE_COMMITTED;
+ sta->sae->sync = 0;
+ sae_set_retransmit_timer(hapd, sta);
+
+ return 0;
+}
+
#endif /* CONFIG_SAE */
@@ -1186,8 +1293,7 @@
if (resp != WLAN_STATUS_SUCCESS)
return resp;
#ifdef CONFIG_IEEE80211N
- resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities,
- elems.ht_capabilities_len);
+ resp = copy_sta_ht_capab(hapd, sta, elems.ht_capabilities);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
if (hapd->iconf->ieee80211n && hapd->iconf->require_ht &&
@@ -1200,8 +1306,7 @@
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
- resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities,
- elems.vht_capabilities_len);
+ resp = copy_sta_vht_capab(hapd, sta, elems.vht_capabilities);
if (resp != WLAN_STATUS_SUCCESS)
return resp;
@@ -1216,6 +1321,13 @@
"mandatory VHT PHY - reject association");
return WLAN_STATUS_ASSOC_DENIED_NO_VHT;
}
+
+ if (hapd->conf->vendor_vht && !elems.vht_capabilities) {
+ resp = copy_sta_vendor_vht(hapd, sta, elems.vendor_vht,
+ elems.vendor_vht_len);
+ if (resp != WLAN_STATUS_SUCCESS)
+ return resp;
+ }
#endif /* CONFIG_IEEE80211AC */
#ifdef CONFIG_P2P
@@ -1476,7 +1588,7 @@
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));
+ host_to_le16(hostapd_own_capab_info(hapd));
reply->u.assoc_resp.status_code = host_to_le16(status_code);
reply->u.assoc_resp.aid = host_to_le16(sta->aid | BIT(14) | BIT(15));
/* Supported rates */
@@ -1505,8 +1617,10 @@
#endif /* CONFIG_IEEE80211N */
#ifdef CONFIG_IEEE80211AC
- p = hostapd_eid_vht_capabilities(hapd, p);
- p = hostapd_eid_vht_operation(hapd, p);
+ if (hapd->iconf->ieee80211ac && !hapd->conf->disable_11ac) {
+ p = hostapd_eid_vht_capabilities(hapd, p);
+ p = hostapd_eid_vht_operation(hapd, p);
+ }
#endif /* CONFIG_IEEE80211AC */
p = hostapd_eid_ext_capab(hapd, p);
@@ -1514,6 +1628,11 @@
if (sta->qos_map_enabled)
p = hostapd_eid_qos_map_set(hapd, p);
+#ifdef CONFIG_IEEE80211AC
+ if (hapd->conf->vendor_vht && (sta->flags & WLAN_STA_VENDOR_VHT))
+ p = hostapd_eid_vendor_vht(hapd, p);
+#endif /* CONFIG_IEEE80211AC */
+
if (sta->flags & WLAN_STA_WMM)
p = hostapd_eid_wmm(hapd, p);
@@ -2252,7 +2371,7 @@
char *ifname_wds)
{
int i;
- struct hostapd_ssid *ssid = sta->ssid;
+ struct hostapd_ssid *ssid = &hapd->conf->ssid;
if (hapd->conf->ieee802_1x || hapd->conf->wpa)
return;
@@ -2397,11 +2516,11 @@
* 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)
+ if (ap_sta_bind_vlan(hapd, sta) < 0)
return;
} 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)
+ if (ap_sta_bind_vlan(hapd, sta) < 0)
return;
}
diff --git a/src/ap/ieee802_11.h b/src/ap/ieee802_11.h
index cf0d3f2..44c1bff 100644
--- a/src/ap/ieee802_11.h
+++ b/src/ap/ieee802_11.h
@@ -14,6 +14,7 @@
struct sta_info;
struct hostapd_frame_info;
struct ieee80211_ht_capabilities;
+struct ieee80211_vht_capabilities;
struct ieee80211_mgmt;
int ieee802_11_mgmt(struct hostapd_data *hapd, const u8 *buf, size_t len,
@@ -40,8 +41,7 @@
return 0;
}
#endif /* NEED_AP_MLME */
-u16 hostapd_own_capab_info(struct hostapd_data *hapd, struct sta_info *sta,
- int probe);
+u16 hostapd_own_capab_info(struct hostapd_data *hapd);
void ap_ht2040_timeout(void *eloop_data, void *user_data);
u8 * hostapd_eid_ext_capab(struct hostapd_data *hapd, u8 *eid);
u8 * hostapd_eid_qos_map_set(struct hostapd_data *hapd, u8 *eid);
@@ -51,6 +51,7 @@
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);
+u8 * hostapd_eid_vendor_vht(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);
@@ -61,12 +62,15 @@
struct ieee80211_vht_capabilities *vht_cap,
struct ieee80211_vht_capabilities *neg_vht_cap);
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *ht_capab, size_t ht_capab_len);
+ const u8 *ht_capab);
+u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ie, size_t len);
+
void update_ht_state(struct hostapd_data *hapd, struct sta_info *sta);
void ht40_intolerant_add(struct hostapd_iface *iface, struct sta_info *sta);
void ht40_intolerant_remove(struct hostapd_iface *iface, 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);
+ const u8 *vht_capab);
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_opmode);
void hostapd_tx_status(struct hostapd_data *hapd, const u8 *addr,
@@ -89,4 +93,15 @@
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);
+int auth_sae_init_committed(struct hostapd_data *hapd, struct sta_info *sta);
+#ifdef CONFIG_SAE
+void sae_clear_retransmit_timer(struct hostapd_data *hapd,
+ struct sta_info *sta);
+#else /* CONFIG_SAE */
+static inline void sae_clear_retransmit_timer(struct hostapd_data *hapd,
+ struct sta_info *sta)
+{
+}
+#endif /* CONFIG_SAE */
+
#endif /* IEEE802_11_H */
diff --git a/src/ap/ieee802_11_ht.c b/src/ap/ieee802_11_ht.c
index 3f299f3..11fde2a 100644
--- a/src/ap/ieee802_11_ht.c
+++ b/src/ap/ieee802_11_ht.c
@@ -209,7 +209,7 @@
struct hostapd_iface *iface = hapd->iface;
struct ieee80211_2040_bss_coex_ie *bc_ie;
struct ieee80211_2040_intol_chan_report *ic_report;
- int is_ht_allowed = 1;
+ int is_ht40_allowed = 1;
int i;
const u8 *start = (const u8 *) mgmt;
const u8 *data = start + IEEE80211_HDRLEN + 2;
@@ -242,7 +242,7 @@
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"20 MHz BSS width request bit is set in BSS coexistence information field");
- is_ht_allowed = 0;
+ is_ht40_allowed = 0;
}
if (bc_ie->coex_param & WLAN_20_40_BSS_COEX_40MHZ_INTOL) {
@@ -250,7 +250,7 @@
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG,
"40 MHz intolerant bit is set in BSS coexistence information field");
- is_ht_allowed = 0;
+ is_ht40_allowed = 0;
}
if (start + len - data >= 3 &&
@@ -276,13 +276,13 @@
HOSTAPD_LEVEL_DEBUG,
"20_40_INTOLERANT channel %d reported",
chan);
- is_ht_allowed = 0;
+ is_ht40_allowed = 0;
}
}
- wpa_printf(MSG_DEBUG, "is_ht_allowed=%d num_sta_ht40_intolerant=%d",
- is_ht_allowed, iface->num_sta_ht40_intolerant);
+ wpa_printf(MSG_DEBUG, "is_ht40_allowed=%d num_sta_ht40_intolerant=%d",
+ is_ht40_allowed, iface->num_sta_ht40_intolerant);
- if (!is_ht_allowed &&
+ if (!is_ht40_allowed &&
(iface->drv_flags & WPA_DRIVER_FLAGS_HT_2040_COEX)) {
if (iface->conf->secondary_channel) {
hostapd_logger(hapd, mgmt->sa,
@@ -292,7 +292,8 @@
iface->conf->secondary_channel = 0;
ieee802_11_set_beacons(iface);
}
- if (!iface->num_sta_ht40_intolerant) {
+ if (!iface->num_sta_ht40_intolerant &&
+ iface->conf->obss_interval) {
unsigned int delay_time;
delay_time = OVERLAPPING_BSS_TRANS_DELAY_FACTOR *
iface->conf->obss_interval;
@@ -309,12 +310,15 @@
u16 copy_sta_ht_capab(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *ht_capab, size_t ht_capab_len)
+ const u8 *ht_capab)
{
- /* Disable HT caps for STAs associated to no-HT BSSes. */
+ /*
+ * Disable HT caps for STAs associated to no-HT BSSes, or for stations
+ * that did not specify a valid WMM IE in the (Re)Association Request
+ * frame.
+ */
if (!ht_capab ||
- ht_capab_len < sizeof(struct ieee80211_ht_capabilities) ||
- hapd->conf->disable_11n) {
+ !(sta->flags & WLAN_STA_WMM) || hapd->conf->disable_11n) {
sta->flags &= ~WLAN_STA_HT;
os_free(sta->ht_capabilities);
sta->ht_capabilities = NULL;
diff --git a/src/ap/ieee802_11_vht.c b/src/ap/ieee802_11_vht.c
index 437cf50..5bf1b5d 100644
--- a/src/ap/ieee802_11_vht.c
+++ b/src/ap/ieee802_11_vht.c
@@ -22,12 +22,25 @@
u8 * hostapd_eid_vht_capabilities(struct hostapd_data *hapd, u8 *eid)
{
struct ieee80211_vht_capabilities *cap;
+ struct hostapd_hw_modes *mode = hapd->iface->current_mode;
u8 *pos = eid;
- if (!hapd->iconf->ieee80211ac || !hapd->iface->current_mode ||
- hapd->conf->disable_11ac)
+ if (!mode)
return eid;
+ if (mode->mode == HOSTAPD_MODE_IEEE80211G && hapd->conf->vendor_vht &&
+ mode->vht_capab == 0 && hapd->iface->hw_features) {
+ int i;
+
+ for (i = 0; i < hapd->iface->num_hw_features; i++) {
+ if (hapd->iface->hw_features[i].mode ==
+ HOSTAPD_MODE_IEEE80211A) {
+ mode = &hapd->iface->hw_features[i];
+ break;
+ }
+ }
+ }
+
*pos++ = WLAN_EID_VHT_CAP;
*pos++ = sizeof(*cap);
@@ -37,8 +50,7 @@
hapd->iface->conf->vht_capab);
/* Supported MCS set comes from hw */
- os_memcpy(&cap->vht_supported_mcs_set,
- hapd->iface->current_mode->vht_mcs_set, 8);
+ os_memcpy(&cap->vht_supported_mcs_set, mode->vht_mcs_set, 8);
pos += sizeof(*cap);
@@ -51,9 +63,6 @@
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);
@@ -81,13 +90,54 @@
}
+static int check_valid_vht_mcs(struct hostapd_hw_modes *mode,
+ const u8 *sta_vht_capab)
+{
+ const struct ieee80211_vht_capabilities *vht_cap;
+ struct ieee80211_vht_capabilities ap_vht_cap;
+ u16 sta_rx_mcs_set, ap_tx_mcs_set;
+ int i;
+
+ if (!mode)
+ return 1;
+
+ /*
+ * Disable VHT caps for STAs for which there is not even a single
+ * allowed MCS in any supported number of streams, i.e., STA is
+ * advertising 3 (not supported) as VHT MCS rates for all supported
+ * stream cases.
+ */
+ os_memcpy(&ap_vht_cap.vht_supported_mcs_set, mode->vht_mcs_set,
+ sizeof(ap_vht_cap.vht_supported_mcs_set));
+ vht_cap = (const struct ieee80211_vht_capabilities *) sta_vht_capab;
+
+ /* AP Tx MCS map vs. STA Rx MCS map */
+ sta_rx_mcs_set = le_to_host16(vht_cap->vht_supported_mcs_set.rx_map);
+ ap_tx_mcs_set = le_to_host16(ap_vht_cap.vht_supported_mcs_set.tx_map);
+
+ for (i = 0; i < VHT_RX_NSS_MAX_STREAMS; i++) {
+ if ((ap_tx_mcs_set & (0x3 << (i * 2))) == 3)
+ continue;
+
+ if ((sta_rx_mcs_set & (0x3 << (i * 2))) == 3)
+ continue;
+
+ return 1;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "No matching VHT MCS found between AP TX and STA RX");
+ return 0;
+}
+
+
u16 copy_sta_vht_capab(struct hostapd_data *hapd, struct sta_info *sta,
- const u8 *vht_capab, size_t vht_capab_len)
+ const u8 *vht_capab)
{
/* 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) {
+ hapd->conf->disable_11ac ||
+ !check_valid_vht_mcs(hapd->iface->current_mode, vht_capab)) {
sta->flags &= ~WLAN_STA_VHT;
os_free(sta->vht_capabilities);
sta->vht_capabilities = NULL;
@@ -109,6 +159,66 @@
}
+u16 copy_sta_vendor_vht(struct hostapd_data *hapd, struct sta_info *sta,
+ const u8 *ie, size_t len)
+{
+ const u8 *vht_capab;
+ unsigned int vht_capab_len;
+
+ if (!ie || len < 5 + 2 + sizeof(struct ieee80211_vht_capabilities) ||
+ hapd->conf->disable_11ac)
+ goto no_capab;
+
+ /* The VHT Capabilities element embedded in vendor VHT */
+ vht_capab = ie + 5;
+ if (vht_capab[0] != WLAN_EID_VHT_CAP)
+ goto no_capab;
+ vht_capab_len = vht_capab[1];
+ if (vht_capab_len < sizeof(struct ieee80211_vht_capabilities) ||
+ (int) vht_capab_len > ie + len - vht_capab - 2)
+ goto no_capab;
+ vht_capab += 2;
+
+ 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 | WLAN_STA_VENDOR_VHT;
+ os_memcpy(sta->vht_capabilities, vht_capab,
+ sizeof(struct ieee80211_vht_capabilities));
+ return WLAN_STATUS_SUCCESS;
+
+no_capab:
+ sta->flags &= ~WLAN_STA_VENDOR_VHT;
+ return WLAN_STATUS_SUCCESS;
+}
+
+
+u8 * hostapd_eid_vendor_vht(struct hostapd_data *hapd, u8 *eid)
+{
+ u8 *pos = eid;
+
+ if (!hapd->iface->current_mode)
+ return eid;
+
+ *pos++ = WLAN_EID_VENDOR_SPECIFIC;
+ *pos++ = (5 + /* The Vendor OUI, type and subtype */
+ 2 + sizeof(struct ieee80211_vht_capabilities) +
+ 2 + sizeof(struct ieee80211_vht_operation));
+
+ WPA_PUT_BE32(pos, (OUI_BROADCOM << 8) | VENDOR_VHT_TYPE);
+ pos += 4;
+ *pos++ = VENDOR_VHT_SUBTYPE;
+ pos = hostapd_eid_vht_capabilities(hapd, pos);
+ pos = hostapd_eid_vht_operation(hapd, pos);
+
+ return pos;
+}
+
+
u16 set_sta_vht_opmode(struct hostapd_data *hapd, struct sta_info *sta,
const u8 *vht_oper_notif)
{
diff --git a/src/ap/ieee802_1x.c b/src/ap/ieee802_1x.c
index f5220b9..5a66291 100644
--- a/src/ap/ieee802_1x.c
+++ b/src/ap/ieee802_1x.c
@@ -1108,8 +1108,6 @@
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");
@@ -1123,11 +1121,8 @@
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);
+ ap_sta_bind_vlan(hapd, sta);
} else {
if (reassoc) {
/*
@@ -1211,15 +1206,11 @@
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);
+ 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);
+ eap_server_get_name(0, eap_type), eap_type);
break;
case EAP_CODE_SUCCESS:
os_strlcpy(buf, "EAP Success", sizeof(buf));
@@ -1275,6 +1266,11 @@
sm->eap_if->aaaEapKeyDataLen = len;
sm->eap_if->aaaEapKeyAvailable = TRUE;
}
+ } else {
+ wpa_printf(MSG_DEBUG,
+ "MS-MPPE: 1x_get_keys, could not get keys: %p send: %p recv: %p",
+ keys, keys ? keys->send : NULL,
+ keys ? keys->recv : NULL);
}
if (keys) {
@@ -1589,7 +1585,7 @@
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;
+ int session_timeout_set, vlan_id = 0;
struct eapol_state_machine *sm;
int override_eapReq = 0;
struct radius_hdr *hdr = radius_msg_get_hdr(msg);
@@ -1656,20 +1652,27 @@
switch (hdr->code) {
case RADIUS_CODE_ACCESS_ACCEPT:
- if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
- sta->vlan_id = 0;
+ if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+ 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_vlan_id_valid(hapd->conf->vlan, sta->vlan_id)) {
+ else
+ vlan_id = radius_msg_get_vlanid(msg);
+ if (vlan_id > 0 &&
+ hostapd_vlan_id_valid(hapd->conf->vlan, 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) {
+ "VLAN ID %d", vlan_id);
+ } else if (vlan_id > 0) {
+ sta->eapol_sm->authFail = TRUE;
+ hostapd_logger(hapd, sta->addr,
+ HOSTAPD_MODULE_RADIUS,
+ HOSTAPD_LEVEL_INFO,
+ "Invalid VLAN ID %d received from RADIUS server",
+ vlan_id);
+ break;
+ } else if (hapd->conf->ssid.dynamic_vlan ==
+ DYNAMIC_VLAN_REQUIRED) {
sta->eapol_sm->authFail = TRUE;
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE8021X,
@@ -1680,7 +1683,9 @@
}
#endif /* CONFIG_NO_VLAN */
- if (ap_sta_bind_vlan(hapd, sta, old_vlanid) < 0)
+ sta->vlan_id = vlan_id;
+ if ((sta->flags & WLAN_STA_ASSOC) &&
+ ap_sta_bind_vlan(hapd, sta) < 0)
break;
sta->session_timeout_set = !!session_timeout_set;
@@ -1925,10 +1930,11 @@
struct hostapd_data *hapd = ctx;
const struct hostapd_eap_user *eap_user;
int i;
+ int rv = -1;
eap_user = hostapd_get_eap_user(hapd, identity, identity_len, phase2);
if (eap_user == NULL)
- return -1;
+ goto out;
os_memset(user, 0, sizeof(*user));
user->phase2 = phase2;
@@ -1940,7 +1946,7 @@
if (eap_user->password) {
user->password = os_malloc(eap_user->password_len);
if (user->password == NULL)
- return -1;
+ goto out;
os_memcpy(user->password, eap_user->password,
eap_user->password_len);
user->password_len = eap_user->password_len;
@@ -1950,8 +1956,13 @@
user->macacl = eap_user->macacl;
user->ttls_auth = eap_user->ttls_auth;
user->remediation = eap_user->remediation;
+ rv = 0;
- return 0;
+out:
+ if (rv)
+ wpa_printf(MSG_DEBUG, "%s: Failed to find user", __func__);
+
+ return rv;
}
@@ -2487,15 +2498,23 @@
return len;
len += ret;
+ if (sm->acct_multi_session_id_hi) {
+ ret = os_snprintf(buf + len, buflen - len,
+ "authMultiSessionId=%08X+%08X\n",
+ sm->acct_multi_session_id_hi,
+ sm->acct_multi_session_id_lo);
+ if (os_snprintf_error(buflen - len, ret))
+ return len;
+ len += ret;
+ }
+
name1 = eap_server_get_name(0, sm->eap_type_authsrv);
name2 = eap_server_get_name(0, sm->eap_type_supp);
ret = os_snprintf(buf + len, buflen - len,
"last_eap_type_as=%d (%s)\n"
"last_eap_type_sta=%d (%s)\n",
- sm->eap_type_authsrv,
- name1 ? name1 : "",
- sm->eap_type_supp,
- name2 ? name2 : "");
+ sm->eap_type_authsrv, name1,
+ sm->eap_type_supp, name2);
if (os_snprintf_error(buflen - len, ret))
return len;
len += ret;
diff --git a/src/ap/pmksa_cache_auth.c b/src/ap/pmksa_cache_auth.c
index 4270382..877affe 100644
--- a/src/ap/pmksa_cache_auth.c
+++ b/src/ap/pmksa_cache_auth.c
@@ -1,6 +1,6 @@
/*
* hostapd - PMKSA cache for IEEE 802.11i RSN
- * Copyright (c) 2004-2008, 2012, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2008, 2012-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,6 +12,7 @@
#include "utils/eloop.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
+#include "radius/radius_das.h"
#include "sta_info.h"
#include "ap_config.h"
#include "pmksa_cache_auth.h"
@@ -268,7 +269,9 @@
return NULL;
os_memcpy(entry->pmk, pmk, pmk_len);
entry->pmk_len = pmk_len;
- if (wpa_key_mgmt_suite_b(akmp))
+ if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ rsn_pmkid_suite_b_192(kck, kck_len, aa, spa, entry->pmkid);
+ else if (wpa_key_mgmt_suite_b(akmp))
rsn_pmkid_suite_b(kck, kck_len, aa, spa, entry->pmkid);
else
rsn_pmkid(pmk, pmk_len, aa, spa, entry->pmkid,
@@ -452,3 +455,74 @@
return pmksa;
}
+
+
+static int das_attr_match(struct rsn_pmksa_cache_entry *entry,
+ struct radius_das_attrs *attr)
+{
+ int match = 0;
+
+ if (attr->sta_addr) {
+ if (os_memcmp(attr->sta_addr, entry->spa, ETH_ALEN) != 0)
+ return 0;
+ match++;
+ }
+
+ if (attr->acct_multi_session_id) {
+ char buf[20];
+
+ if (attr->acct_multi_session_id_len != 17)
+ return 0;
+ os_snprintf(buf, sizeof(buf), "%08X+%08X",
+ entry->acct_multi_session_id_hi,
+ entry->acct_multi_session_id_lo);
+ if (os_memcmp(attr->acct_multi_session_id, buf, 17) != 0)
+ return 0;
+ match++;
+ }
+
+ if (attr->cui) {
+ if (!entry->cui ||
+ attr->cui_len != wpabuf_len(entry->cui) ||
+ os_memcmp(attr->cui, wpabuf_head(entry->cui),
+ attr->cui_len) != 0)
+ return 0;
+ match++;
+ }
+
+ if (attr->user_name) {
+ if (!entry->identity ||
+ attr->user_name_len != entry->identity_len ||
+ os_memcmp(attr->user_name, entry->identity,
+ attr->user_name_len) != 0)
+ return 0;
+ match++;
+ }
+
+ return match;
+}
+
+
+int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
+ struct radius_das_attrs *attr)
+{
+ int found = 0;
+ struct rsn_pmksa_cache_entry *entry, *prev;
+
+ if (attr->acct_session_id)
+ return -1;
+
+ entry = pmksa->pmksa;
+ while (entry) {
+ if (das_attr_match(entry, attr)) {
+ found++;
+ prev = entry;
+ entry = entry->next;
+ pmksa_cache_free_entry(pmksa, prev);
+ continue;
+ }
+ entry = entry->next;
+ }
+
+ return found ? 0 : -1;
+}
diff --git a/src/ap/pmksa_cache_auth.h b/src/ap/pmksa_cache_auth.h
index 519555f..8b7be12 100644
--- a/src/ap/pmksa_cache_auth.h
+++ b/src/ap/pmksa_cache_auth.h
@@ -61,5 +61,7 @@
struct eapol_state_machine *eapol);
void pmksa_cache_free_entry(struct rsn_pmksa_cache *pmksa,
struct rsn_pmksa_cache_entry *entry);
+int pmksa_cache_auth_radius_das_disconnect(struct rsn_pmksa_cache *pmksa,
+ struct radius_das_attrs *attr);
#endif /* PMKSA_CACHE_H */
diff --git a/src/ap/sta_info.c b/src/ap/sta_info.c
index 9f16b88..17ecad5 100644
--- a/src/ap/sta_info.c
+++ b/src/ap/sta_info.c
@@ -171,6 +171,19 @@
!(sta->flags & WLAN_STA_PREAUTH))
hostapd_drv_sta_remove(hapd, sta->addr);
+#ifndef CONFIG_NO_VLAN
+ if (sta->vlan_id_bound) {
+ /*
+ * Need to remove the STA entry before potentially removing the
+ * VLAN.
+ */
+ if (hapd->iface->driver_ap_teardown &&
+ !(sta->flags & WLAN_STA_PREAUTH))
+ hostapd_drv_sta_remove(hapd, sta->addr);
+ vlan_remove_dynamic(hapd, sta->vlan_id_bound);
+ }
+#endif /* CONFIG_NO_VLAN */
+
ap_sta_hash_del(hapd, sta);
ap_sta_list_del(hapd, sta);
@@ -250,6 +263,7 @@
eloop_cancel_timeout(ap_handle_session_warning_timer, hapd, sta);
eloop_cancel_timeout(ap_sta_deauth_cb_timeout, hapd, sta);
eloop_cancel_timeout(ap_sta_disassoc_cb_timeout, hapd, sta);
+ sae_clear_retransmit_timer(hapd, sta);
ieee802_1x_free_station(sta);
wpa_auth_sta_deinit(sta->wpa_sm);
@@ -414,8 +428,15 @@
* 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) {
+ } else if (inactive_sec == -ENOENT) {
+ wpa_msg(hapd->msg_ctx, MSG_DEBUG,
+ "Station " MACSTR " has lost its driver entry",
+ MAC2STR(sta->addr));
+
+ /* Avoid sending client probe on removed client */
+ sta->timeout_next = STA_DISASSOC;
+ goto skip_poll;
+ } else if (inactive_sec < hapd->conf->ap_max_inactivity) {
/* station activity detected; reset timeout state */
wpa_msg(hapd->msg_ctx, MSG_INFO,
"Station " MACSTR " has been active %is ago",
@@ -451,6 +472,7 @@
hostapd_write_sta_taxonomy(sta);
#endif /* CONFIG_CLIENT_TAXONOMY */
+skip_poll:
if (next_time) {
wpa_printf(MSG_DEBUG, "%s: register ap_handle_timer timeout "
"for " MACSTR " (%lu seconds)",
@@ -659,7 +681,6 @@
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);
sta->last_seq_ctrl = WLAN_INVALID_MGMT_SEQ;
dl_list_init(&sta->ip6addr);
@@ -808,33 +829,19 @@
#endif /* CONFIG_WPS */
-int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta,
- int old_vlanid)
+int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta)
{
#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);
+ int old_vlanid = sta->vlan_id_bound;
iface = hapd->conf->iface;
- if (sta->ssid->vlan[0])
- iface = sta->ssid->vlan;
+ if (hapd->conf->ssid.vlan[0])
+ iface = hapd->conf->ssid.vlan;
- if (sta->ssid->dynamic_vlan == DYNAMIC_VLAN_DISABLED)
+ if (hapd->conf->ssid.dynamic_vlan == DYNAMIC_VLAN_DISABLED)
sta->vlan_id = 0;
else if (sta->vlan_id > 0) {
struct hostapd_vlan *wildcard_vlan = NULL;
@@ -852,12 +859,21 @@
iface = vlan->ifname;
}
+ /*
+ * Do not increment ref counters if the VLAN ID remains same, but do
+ * not skip hostapd_drv_set_sta_vlan() as hostapd_drv_sta_remove() might
+ * have been called before.
+ */
+ if (sta->vlan_id == old_vlanid)
+ goto skip_counting;
+
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;
+ ret = -1;
+ goto done;
} else if (sta->vlan_id > 0 && vlan->vlan_id == VLAN_ID_WILDCARD) {
vlan = vlan_add_dynamic(hapd, vlan, sta->vlan_id);
if (vlan == NULL) {
@@ -866,11 +882,12 @@
HOSTAPD_LEVEL_DEBUG, "could not add "
"dynamic VLAN interface for vlan_id=%d",
sta->vlan_id);
- return -1;
+ ret = -1;
+ goto done;
}
iface = vlan->ifname;
- if (vlan_setup_encryption_dyn(hapd, sta->ssid, iface) != 0) {
+ if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not "
@@ -883,7 +900,7 @@
HOSTAPD_LEVEL_DEBUG, "added new dynamic VLAN "
"interface '%s'", iface);
} else if (vlan && vlan->vlan_id == sta->vlan_id) {
- if (sta->vlan_id > 0) {
+ if (vlan->dynamic_vlan > 0) {
vlan->dynamic_vlan++;
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
@@ -897,7 +914,7 @@
* 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) {
+ if (vlan_setup_encryption_dyn(hapd, iface) != 0) {
hostapd_logger(hapd, sta->addr,
HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "could not "
@@ -907,6 +924,10 @@
}
}
+ /* ref counters have been increased, so mark the station */
+ sta->vlan_id_bound = sta->vlan_id;
+
+skip_counting:
hostapd_logger(hapd, sta->addr, HOSTAPD_MODULE_IEEE80211,
HOSTAPD_LEVEL_DEBUG, "binding station to interface "
"'%s'", iface);
@@ -920,6 +941,12 @@
HOSTAPD_LEVEL_DEBUG, "could not bind the STA "
"entry to vlan_id=%d", sta->vlan_id);
}
+
+ /* During 1x reauth, if the vlan id changes, then remove the old id. */
+ if (old_vlanid > 0 && old_vlanid != sta->vlan_id)
+ vlan_remove_dynamic(hapd, old_vlanid);
+done:
+
return ret;
#else /* CONFIG_NO_VLAN */
return 0;
@@ -1149,7 +1176,7 @@
int res;
buf[0] = '\0';
- res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ res = os_snprintf(buf, buflen, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
(flags & WLAN_STA_AUTH ? "[AUTH]" : ""),
(flags & WLAN_STA_ASSOC ? "[ASSOC]" : ""),
(flags & WLAN_STA_AUTHORIZED ? "[AUTHORIZED]" : ""),
@@ -1167,6 +1194,7 @@
(flags & WLAN_STA_WPS2 ? "[WPS2]" : ""),
(flags & WLAN_STA_GAS ? "[GAS]" : ""),
(flags & WLAN_STA_VHT ? "[VHT]" : ""),
+ (flags & WLAN_STA_VENDOR_VHT ? "[VENDOR_VHT]" : ""),
(flags & WLAN_STA_WNM_SLEEP_MODE ?
"[WNM_SLEEP_MODE]" : ""));
if (os_snprintf_error(buflen, res))
diff --git a/src/ap/sta_info.h b/src/ap/sta_info.h
index 65e71f8..ce8d9fb 100644
--- a/src/ap/sta_info.h
+++ b/src/ap/sta_info.h
@@ -35,6 +35,7 @@
#define WLAN_STA_VHT BIT(18)
#define WLAN_STA_WNM_SLEEP_MODE BIT(19)
#define WLAN_STA_VHT_OPMODE_ENABLED BIT(20)
+#define WLAN_STA_VENDOR_VHT BIT(21)
#define WLAN_STA_PENDING_DISASSOC_CB BIT(29)
#define WLAN_STA_PENDING_DEAUTH_CB BIT(30)
#define WLAN_STA_NONERP BIT(31)
@@ -84,6 +85,7 @@
unsigned int remediation:1;
unsigned int hs20_deauth_requested:1;
unsigned int session_timeout_set:1;
+ unsigned int radius_das_match:1;
u16 auth_alg;
@@ -115,10 +117,8 @@
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;
+ int vlan_id; /* 0: none, >0: VID */
+ int vlan_id_bound; /* updated by ap_sta_bind_vlan() */
/* PSKs from RADIUS authentication server */
struct hostapd_sta_wpa_psk_short *psk;
@@ -225,8 +225,7 @@
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);
+int ap_sta_bind_vlan(struct hostapd_data *hapd, struct sta_info *sta);
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);
diff --git a/src/ap/utils.c b/src/ap/utils.c
index 931968c..d60555a 100644
--- a/src/ap/utils.c
+++ b/src/ap/utils.c
@@ -59,6 +59,8 @@
if (!osta)
continue;
+ wpa_printf(MSG_INFO, "%s: Prune association for " MACSTR,
+ ohapd->conf->iface, MAC2STR(osta->addr));
ap_sta_disassociate(ohapd, osta, WLAN_REASON_UNSPECIFIED);
}
diff --git a/src/ap/vlan_init.c b/src/ap/vlan_init.c
index 4e4a352..baabbe3 100644
--- a/src/ap/vlan_init.c
+++ b/src/ap/vlan_init.c
@@ -485,7 +485,8 @@
wpa_printf(MSG_DEBUG, "VLAN: vlan_newlink(%s)", ifname);
while (vlan) {
- if (os_strcmp(ifname, vlan->ifname) == 0) {
+ if (os_strcmp(ifname, vlan->ifname) == 0 && !vlan->configured) {
+ vlan->configured = 1;
if (hapd->conf->vlan_bridge[0]) {
os_snprintf(br_name, sizeof(br_name), "%s%d",
@@ -617,6 +618,7 @@
struct ifinfomsg *ifi;
int attrlen, nlmsg_len, rta_len;
struct rtattr *attr;
+ char ifname[IFNAMSIZ + 1];
if (len < sizeof(*ifi))
return;
@@ -631,29 +633,44 @@
attr = (struct rtattr *) (((char *) ifi) + nlmsg_len);
+ os_memset(ifname, 0, sizeof(ifname));
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);
+ if ((size_t) n >= sizeof(ifname))
+ n = sizeof(ifname) - 1;
os_memcpy(ifname, ((char *) attr) + rta_len, n);
- if (del)
- vlan_dellink(ifname, hapd);
- else
- vlan_newlink(ifname, hapd);
}
attr = RTA_NEXT(attr, attrlen);
}
+
+ if (!ifname[0])
+ return;
+ if (del && if_nametoindex(ifname)) {
+ /* interface still exists, race condition ->
+ * iface has just been recreated */
+ return;
+ }
+
+ wpa_printf(MSG_DEBUG,
+ "VLAN: RTM_%sLINK: ifi_index=%d ifname=%s ifi_family=%d ifi_flags=0x%x (%s%s%s%s)",
+ del ? "DEL" : "NEW",
+ ifi->ifi_index, ifname, ifi->ifi_family, ifi->ifi_flags,
+ (ifi->ifi_flags & IFF_UP) ? "[UP]" : "",
+ (ifi->ifi_flags & IFF_RUNNING) ? "[RUNNING]" : "",
+ (ifi->ifi_flags & IFF_LOWER_UP) ? "[LOWER_UP]" : "",
+ (ifi->ifi_flags & IFF_DORMANT) ? "[DORMANT]" : "");
+
+ if (del)
+ vlan_dellink(ifname, hapd);
+ else
+ vlan_newlink(ifname, hapd);
}
@@ -677,7 +694,7 @@
}
h = (struct nlmsghdr *) buf;
- while (left >= (int) sizeof(*h)) {
+ while (NLMSG_OK(h, left)) {
int len, plen;
len = h->nlmsg_len;
@@ -698,9 +715,7 @@
break;
}
- len = NLMSG_ALIGN(len);
- left -= len;
- h = (struct nlmsghdr *) ((char *) h + len);
+ h = NLMSG_NEXT(h, left);
}
if (left > 0) {
@@ -769,8 +784,7 @@
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
-int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
- struct hostapd_ssid *mssid, const char *dyn_vlan)
+int vlan_setup_encryption_dyn(struct hostapd_data *hapd, const char *dyn_vlan)
{
int i;
@@ -780,10 +794,11 @@
/* 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] &&
+ if (hapd->conf->ssid.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]))
+ i == hapd->conf->ssid.wep.idx, NULL, 0,
+ hapd->conf->ssid.wep.key[i],
+ hapd->conf->ssid.wep.len[i]))
{
wpa_printf(MSG_ERROR, "VLAN: Could not set WEP "
"encryption for dynamic VLAN");
@@ -891,7 +906,7 @@
struct hostapd_vlan *vlan,
int vlan_id)
{
- struct hostapd_vlan *n;
+ struct hostapd_vlan *n = NULL;
char *ifname, *pos;
if (vlan == NULL || vlan_id <= 0 || vlan_id > MAX_VLAN_ID ||
@@ -904,28 +919,24 @@
if (ifname == NULL)
return NULL;
pos = os_strchr(ifname, '#');
- if (pos == NULL) {
- os_free(ifname);
- return NULL;
- }
+ if (pos == NULL)
+ goto free_ifname;
*pos++ = '\0';
n = os_zalloc(sizeof(*n));
- if (n == NULL) {
- os_free(ifname);
- return NULL;
- }
+ if (n == NULL)
+ goto free_ifname;
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 = NULL;
+ goto free_ifname;
}
n->next = hapd->conf->vlan;
@@ -935,6 +946,8 @@
ifconfig_up(n->ifname);
#endif /* CONFIG_FULL_DYNAMIC_VLAN */
+free_ifname:
+ os_free(ifname);
return n;
}
@@ -946,7 +959,8 @@
if (vlan_id <= 0 || vlan_id > MAX_VLAN_ID)
return 1;
- wpa_printf(MSG_DEBUG, "VLAN: %s(vlan_id=%d)", __func__, vlan_id);
+ wpa_printf(MSG_DEBUG, "VLAN: %s(ifname=%s vlan_id=%d)",
+ __func__, hapd->conf->iface, vlan_id);
vlan = hapd->conf->vlan;
while (vlan) {
diff --git a/src/ap/vlan_init.h b/src/ap/vlan_init.h
index 781eaac..fc39443 100644
--- a/src/ap/vlan_init.h
+++ b/src/ap/vlan_init.h
@@ -18,7 +18,6 @@
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)
@@ -43,7 +42,6 @@
}
static inline int vlan_setup_encryption_dyn(struct hostapd_data *hapd,
- struct hostapd_ssid *mssid,
const char *dyn_vlan)
{
return -1;
diff --git a/src/ap/wnm_ap.c b/src/ap/wnm_ap.c
index 7e8fb5c..4c8bc10 100644
--- a/src/ap/wnm_ap.c
+++ b/src/ap/wnm_ap.c
@@ -564,8 +564,11 @@
if (url) {
/* Session Information URL */
url_len = os_strlen(url);
- if (url_len > 255)
+ if (url_len > 255) {
+ os_free(buf);
return -1;
+ }
+
*pos++ = url_len;
os_memcpy(pos, url, url_len);
pos += url_len;
diff --git a/src/ap/wpa_auth.c b/src/ap/wpa_auth.c
index 7a7fd54..af24cf0 100644
--- a/src/ap/wpa_auth.c
+++ b/src/ap/wpa_auth.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 RSN / WPA Authenticator
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -67,6 +67,14 @@
}
+static inline void wpa_auth_psk_failure_report(
+ struct wpa_authenticator *wpa_auth, const u8 *addr)
+{
+ if (wpa_auth->cb.psk_failure_report)
+ wpa_auth->cb.psk_failure_report(wpa_auth->cb.ctx, addr);
+}
+
+
static inline void wpa_auth_set_eapol(struct wpa_authenticator *wpa_auth,
const u8 *addr, wpa_eapol_variable var,
int value)
@@ -415,6 +423,7 @@
wpa_auth);
if (wpa_auth->pmksa == NULL) {
wpa_printf(MSG_ERROR, "PMKSA cache initialization failed.");
+ os_free(wpa_auth->group);
os_free(wpa_auth->wpa_ie);
os_free(wpa_auth);
return NULL;
@@ -424,6 +433,7 @@
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->group);
os_free(wpa_auth->wpa_ie);
pmksa_cache_auth_deinit(wpa_auth->pmksa);
os_free(wpa_auth);
@@ -847,34 +857,45 @@
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
+ struct wpa_eapol_key_192 *key192;
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;
+ const u8 *eapol_key_ie, *key_data;
+ size_t eapol_key_ie_len, keyhdrlen, mic_len;
if (wpa_auth == NULL || !wpa_auth->conf.wpa || sm == NULL)
return;
- if (data_len < sizeof(*hdr) + sizeof(*key))
+ mic_len = wpa_mic_len(sm->wpa_key_mgmt);
+ keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+
+ if (data_len < sizeof(*hdr) + keyhdrlen)
return;
hdr = (struct ieee802_1x_hdr *) data;
key = (struct wpa_eapol_key *) (hdr + 1);
+ key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
key_info = WPA_GET_BE16(key->key_info);
- key_data_length = WPA_GET_BE16(key->key_data_length);
+ if (mic_len == 24) {
+ key_data = (const u8 *) (key192 + 1);
+ key_data_length = WPA_GET_BE16(key192->key_data_length);
+ } else {
+ key_data = (const u8 *) (key + 1);
+ 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)) {
+ if (key_data_length > data_len - sizeof(*hdr) - keyhdrlen) {
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)));
+ keyhdrlen));
return;
}
@@ -1081,8 +1102,7 @@
wpa_sta_disconnect(wpa_auth, sm->addr);
return;
}
- if (wpa_parse_kde_ies((u8 *) (key + 1), key_data_length,
- &kde) < 0) {
+ if (wpa_parse_kde_ies(key_data, 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");
@@ -1241,8 +1261,7 @@
*/
if (msg == SMK_ERROR) {
#ifdef CONFIG_PEERKEY
- wpa_smk_error(wpa_auth, sm, (const u8 *) (key + 1),
- key_data_length);
+ wpa_smk_error(wpa_auth, sm, key_data, key_data_length);
#endif /* CONFIG_PEERKEY */
return;
} else if (key_info & WPA_KEY_INFO_ERROR) {
@@ -1257,12 +1276,12 @@
wpa_request_new_ptk(sm);
#ifdef CONFIG_PEERKEY
} else if (msg == SMK_M1) {
- wpa_smk_m1(wpa_auth, sm, key, (const u8 *) (key + 1),
+ wpa_smk_m1(wpa_auth, sm, key, key_data,
key_data_length);
#endif /* CONFIG_PEERKEY */
} else if (key_data_length > 0 &&
- wpa_parse_kde_ies((const u8 *) (key + 1),
- key_data_length, &kde) == 0 &&
+ wpa_parse_kde_ies(key_data, key_data_length,
+ &kde) == 0 &&
kde.mac_addr) {
} else {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
@@ -1300,8 +1319,7 @@
#ifdef CONFIG_PEERKEY
if (msg == SMK_M3) {
- wpa_smk_m3(wpa_auth, sm, key, (const u8 *) (key + 1),
- key_data_length);
+ wpa_smk_m3(wpa_auth, sm, key, key_data, key_data_length);
return;
}
#endif /* CONFIG_PEERKEY */
@@ -1376,14 +1394,19 @@
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
- size_t len;
+ struct wpa_eapol_key_192 *key192;
+ size_t len, mic_len, keyhdrlen;
int alg;
int key_data_len, pad_len = 0;
u8 *buf, *pos;
int version, pairwise;
int i;
+ u8 *key_data;
- len = sizeof(struct ieee802_1x_hdr) + sizeof(struct wpa_eapol_key);
+ mic_len = wpa_mic_len(sm->wpa_key_mgmt);
+ keyhdrlen = mic_len == 24 ? sizeof(*key192) : sizeof(*key);
+
+ len = sizeof(struct ieee802_1x_hdr) + keyhdrlen;
if (force_version)
version = force_version;
@@ -1430,6 +1453,8 @@
hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
hdr->length = host_to_be16(len - sizeof(*hdr));
key = (struct wpa_eapol_key *) (hdr + 1);
+ key192 = (struct wpa_eapol_key_192 *) (hdr + 1);
+ key_data = ((u8 *) (hdr + 1)) + keyhdrlen;
key->type = sm->wpa == WPA_VERSION_WPA2 ?
EAPOL_KEY_TYPE_RSN : EAPOL_KEY_TYPE_WPA;
@@ -1466,8 +1491,11 @@
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);
+ os_memcpy(key_data, kde, kde_len);
+ if (mic_len == 24)
+ WPA_PUT_BE16(key192->key_data_length, kde_len);
+ else
+ WPA_PUT_BE16(key->key_data_length, kde_len);
} else if (encr && kde) {
buf = os_zalloc(key_data_len);
if (buf == NULL) {
@@ -1487,29 +1515,44 @@
sm->wpa_key_mgmt == WPA_KEY_MGMT_OSEN ||
wpa_key_mgmt_suite_b(sm->wpa_key_mgmt) ||
version == WPA_KEY_INFO_TYPE_AES_128_CMAC) {
- if (aes_wrap(sm->PTK.kek, 16,
- (key_data_len - 8) / 8, buf,
- (u8 *) (key + 1))) {
+ if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len,
+ (key_data_len - 8) / 8, buf, key_data)) {
os_free(hdr);
os_free(buf);
return;
}
- WPA_PUT_BE16(key->key_data_length, key_data_len);
- } else {
+ if (mic_len == 24)
+ WPA_PUT_BE16(key192->key_data_length,
+ key_data_len);
+ else
+ WPA_PUT_BE16(key->key_data_length,
+ key_data_len);
+ } else if (sm->PTK.kek_len == 16) {
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_memcpy(ek + 16, sm->PTK.kek, sm->PTK.kek_len);
+ os_memcpy(key_data, buf, key_data_len);
+ rc4_skip(ek, 32, 256, key_data, key_data_len);
+ if (mic_len == 24)
+ WPA_PUT_BE16(key192->key_data_length,
+ key_data_len);
+ else
+ WPA_PUT_BE16(key->key_data_length,
+ key_data_len);
+ } else {
+ os_free(hdr);
+ os_free(buf);
+ return;
}
os_free(buf);
}
if (key_info & WPA_KEY_INFO_MIC) {
+ u8 *key_mic;
+
if (!sm->PTK_valid) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_DEBUG,
"PTK not valid when sending EAPOL-Key "
@@ -1517,8 +1560,11 @@
os_free(hdr);
return;
}
- wpa_eapol_key_mic(sm->PTK.kck, sm->wpa_key_mgmt, version,
- (u8 *) hdr, len, key->key_mic);
+
+ key_mic = key192->key_mic; /* same offset for key and key192 */
+ wpa_eapol_key_mic(sm->PTK.kck, sm->PTK.kck_len,
+ sm->wpa_key_mgmt, version,
+ (u8 *) hdr, len, key_mic);
#ifdef CONFIG_TESTING_OPTIONS
if (!pairwise &&
wpa_auth->conf.corrupt_gtk_rekey_mic_probability > 0.0 &&
@@ -1526,7 +1572,7 @@
wpa_auth->conf.corrupt_gtk_rekey_mic_probability) {
wpa_auth_logger(wpa_auth, sm->addr, LOGGER_INFO,
"Corrupting group EAPOL-Key Key MIC");
- key->key_mic[0]++;
+ key_mic[0]++;
}
#endif /* CONFIG_TESTING_OPTIONS */
}
@@ -1575,23 +1621,27 @@
{
struct ieee802_1x_hdr *hdr;
struct wpa_eapol_key *key;
+ struct wpa_eapol_key_192 *key192;
u16 key_info;
int ret = 0;
- u8 mic[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+ size_t mic_len = wpa_mic_len(akmp);
if (data_len < sizeof(*hdr) + sizeof(*key))
return -1;
hdr = (struct ieee802_1x_hdr *) data;
key = (struct wpa_eapol_key *) (hdr + 1);
+ key192 = (struct wpa_eapol_key_192 *) (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, akmp, key_info & WPA_KEY_INFO_TYPE_MASK,
- data, data_len, key->key_mic) ||
- os_memcmp_const(mic, key->key_mic, 16) != 0)
+ os_memcpy(mic, key192->key_mic, mic_len);
+ os_memset(key192->key_mic, 0, mic_len);
+ if (wpa_eapol_key_mic(PTK->kck, PTK->kck_len, akmp,
+ key_info & WPA_KEY_INFO_TYPE_MASK,
+ data, data_len, key192->key_mic) ||
+ os_memcmp_const(mic, key192->key_mic, mic_len) != 0)
ret = -1;
- os_memcpy(key->key_mic, mic, 16);
+ os_memcpy(key192->key_mic, mic, mic_len);
return ret;
}
@@ -1840,8 +1890,12 @@
}
#endif /* CONFIG_IEEE80211R */
} else {
- wpa_printf(MSG_DEBUG, "WPA: Could not get PMK");
+ wpa_printf(MSG_DEBUG, "WPA: Could not get PMK, get_msk: %p",
+ sm->wpa_auth->cb.get_msk);
+ sm->Disconnect = TRUE;
+ return;
}
+ os_memset(msk, 0, sizeof(msk));
sm->req_replay_counter_used = 0;
/* IEEE 802.11i does not set keyRun to FALSE, but not doing this
@@ -1928,25 +1982,21 @@
static int wpa_derive_ptk(struct wpa_state_machine *sm, const u8 *snonce,
const u8 *pmk, struct wpa_ptk *ptk)
{
- size_t ptk_len = wpa_cipher_key_len(sm->pairwise) + 32;
#ifdef CONFIG_IEEE80211R
if (wpa_key_mgmt_ft(sm->wpa_key_mgmt))
- return wpa_auth_derive_ptk_ft(sm, pmk, ptk, ptk_len);
+ return wpa_auth_derive_ptk_ft(sm, pmk, ptk);
#endif /* CONFIG_IEEE80211R */
- wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
- sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
- (u8 *) ptk, ptk_len,
- wpa_key_mgmt_sha256(sm->wpa_key_mgmt));
-
- return 0;
+ return wpa_pmk_to_ptk(pmk, PMK_LEN, "Pairwise key expansion",
+ sm->wpa_auth->addr, sm->addr, sm->ANonce, snonce,
+ ptk, sm->wpa_key_mgmt, sm->pairwise);
}
SM_STATE(WPA_PTK, PTKCALCNEGOTIATING)
{
struct wpa_ptk PTK;
- int ok = 0;
+ int ok = 0, psk_found = 0;
const u8 *pmk = NULL;
SM_ENTRY_MA(WPA_PTK, PTKCALCNEGOTIATING, wpa_ptk);
@@ -1962,6 +2012,7 @@
sm->p2p_dev_addr, pmk);
if (pmk == NULL)
break;
+ psk_found = 1;
} else
pmk = sm->PMK;
@@ -1981,6 +2032,8 @@
if (!ok) {
wpa_auth_logger(sm->wpa_auth, sm->addr, LOGGER_DEBUG,
"invalid MIC in msg 2/4 of 4-Way Handshake");
+ if (psk_found)
+ wpa_auth_psk_failure_report(sm->wpa_auth, sm->addr);
return;
}
@@ -2271,7 +2324,7 @@
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)) {
+ sm->PTK.tk, klen)) {
wpa_printf(MSG_ERROR, "wpa_auth_set_key error");
wpa_sta_disconnect(sm->wpa_auth, sm->addr);
return;
@@ -3172,7 +3225,7 @@
return -1;
if (pmksa_cache_auth_add(sm->wpa_auth->pmksa, pmk, PMK_LEN,
- sm->PTK.kck, sizeof(sm->PTK.kck),
+ sm->PTK.kck, sm->PTK.kck_len,
sm->wpa_auth->addr, sm->addr, session_timeout,
eapol, sm->wpa_key_mgmt))
return 0;
@@ -3342,3 +3395,21 @@
return 0;
}
#endif /* CONFIG_P2P */
+
+
+int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
+ struct radius_das_attrs *attr)
+{
+ return pmksa_cache_auth_radius_das_disconnect(wpa_auth->pmksa, attr);
+}
+
+
+void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth)
+{
+ struct wpa_group *group;
+
+ if (!wpa_auth)
+ return;
+ for (group = wpa_auth->group; group; group = group->next)
+ wpa_group_config_group_keys(wpa_auth, group);
+}
diff --git a/src/ap/wpa_auth.h b/src/ap/wpa_auth.h
index 757e49e..e747806 100644
--- a/src/ap/wpa_auth.h
+++ b/src/ap/wpa_auth.h
@@ -12,6 +12,7 @@
#include "common/defs.h"
#include "common/eapol_common.h"
#include "common/wpa_common.h"
+#include "common/ieee802_11_defs.h"
#ifdef _MSC_VER
#pragma pack(push, 1)
@@ -146,8 +147,7 @@
int group_mgmt_cipher;
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
-#define SSID_LEN 32
- u8 ssid[SSID_LEN];
+ u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 r0_key_holder[FT_R0KH_ID_MAX_LEN];
@@ -189,6 +189,7 @@
const char *txt);
void (*disconnect)(void *ctx, const u8 *addr, u16 reason);
int (*mic_failure_report)(void *ctx, const u8 *addr);
+ void (*psk_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);
@@ -315,4 +316,9 @@
int wpa_auth_get_ip_addr(struct wpa_state_machine *sm, u8 *addr);
+struct radius_das_attrs;
+int wpa_auth_radius_das_disconnect_pmksa(struct wpa_authenticator *wpa_auth,
+ struct radius_das_attrs *attr);
+void wpa_auth_reconfig_group_keys(struct wpa_authenticator *wpa_auth);
+
#endif /* WPA_AUTH_H */
diff --git a/src/ap/wpa_auth_ft.c b/src/ap/wpa_auth_ft.c
index e061b5e..eeaffbf 100644
--- a/src/ap/wpa_auth_ft.c
+++ b/src/ap/wpa_auth_ft.c
@@ -1,6 +1,6 @@
/*
* hostapd - IEEE 802.11r - Fast BSS Transition
- * Copyright (c) 2004-2014, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -362,7 +362,7 @@
int wpa_auth_derive_ptk_ft(struct wpa_state_machine *sm, const u8 *pmk,
- struct wpa_ptk *ptk, size_t ptk_len)
+ struct wpa_ptk *ptk)
{
u8 pmk_r0[PMK_LEN], pmk_r0_name[WPA_PMK_NAME_LEN];
u8 pmk_r1[PMK_LEN];
@@ -374,7 +374,6 @@
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");
@@ -396,13 +395,9 @@
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;
+ return wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
+ sm->wpa_auth->addr, sm->pmk_r1_name,
+ ptk, ptk_name, sm->wpa_key_mgmt, sm->pairwise);
}
@@ -461,7 +456,8 @@
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, 16, key_len / 8, key, subelem + 13)) {
+ if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, key_len / 8, key,
+ subelem + 13)) {
os_free(subelem);
return NULL;
}
@@ -493,7 +489,7 @@
wpa_auth_get_seqnum(sm->wpa_auth, NULL, gsm->GN_igtk, pos);
pos += 6;
*pos++ = WPA_IGTK_LEN;
- if (aes_wrap(sm->PTK.kek, 16, WPA_IGTK_LEN / 8,
+ if (aes_wrap(sm->PTK.kek, sm->PTK.kek_len, WPA_IGTK_LEN / 8,
gsm->IGTK[gsm->GN_igtk - 4], pos)) {
os_free(subelem);
return NULL;
@@ -538,10 +534,8 @@
return pos;
}
-#ifdef NEED_AP_MLME
- if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
+ if (parse.wmm_tspec) {
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 "
@@ -559,7 +553,13 @@
}
tspec = (struct wmm_tspec_element *) pos;
os_memcpy(tspec, parse.wmm_tspec - 2, sizeof(*tspec));
- res = wmm_process_tspec(tspec);
+ }
+
+#ifdef NEED_AP_MLME
+ if (parse.wmm_tspec && sm->wpa_auth->conf.ap_mlme) {
+ int res;
+
+ res = wmm_process_tspec((struct wmm_tspec_element *) pos);
wpa_printf(MSG_DEBUG, "FT: ADDTS processing result: %d", res);
if (res == WMM_ADDTS_STATUS_INVALID_PARAMETERS)
rdie->status_code =
@@ -570,20 +570,17 @@
else {
/* TSPEC accepted; include updated TSPEC in response */
rdie->descr_count = 1;
- pos += sizeof(*tspec);
+ pos += sizeof(struct wmm_tspec_element);
}
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));
+ sizeof(struct wmm_tspec_element));
if (res >= 0) {
if (res)
rdie->status_code = host_to_le16(res);
@@ -591,7 +588,7 @@
/* TSPEC accepted; include updated TSPEC in
* response */
rdie->descr_count = 1;
- pos += sizeof(*tspec);
+ pos += sizeof(struct wmm_tspec_element);
}
return pos;
}
@@ -745,7 +742,8 @@
ric_start = NULL;
if (auth_alg == WLAN_AUTH_FT &&
- wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 6,
+ wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, sm->addr,
+ sm->wpa_auth->addr, 6,
mdie, mdie_len, ftie, ftie_len,
rsnie, rsnie_len,
ric_start, ric_start ? pos - ric_start : 0,
@@ -789,7 +787,7 @@
* optimized by adding the STA entry earlier.
*/
if (wpa_auth_set_key(sm->wpa_auth, 0, alg, sm->addr, 0,
- sm->PTK.tk1, klen))
+ sm->PTK.tk, klen))
return;
/* FIX: MLME-SetProtection.Request(TA, Tx_Rx) */
@@ -807,7 +805,7 @@
u8 ptk_name[WPA_PMK_NAME_LEN];
struct wpa_auth_config *conf;
struct wpa_ft_ies parse;
- size_t buflen, ptk_len;
+ size_t buflen;
int ret;
u8 *pos, *end;
int pairwise;
@@ -892,13 +890,11 @@
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);
+ if (wpa_pmk_r1_to_ptk(pmk_r1, sm->SNonce, sm->ANonce, sm->addr,
+ sm->wpa_auth->addr, pmk_r1_name,
+ &sm->PTK, ptk_name, sm->wpa_key_mgmt,
+ pairwise) < 0)
+ return WLAN_STATUS_UNSPECIFIED_FAILURE;
sm->pairwise = pairwise;
sm->PTK_valid = TRUE;
@@ -993,7 +989,8 @@
struct wpa_ft_ies parse;
struct rsn_mdie *mdie;
struct rsn_ftie *ftie;
- u8 mic[16];
+ u8 mic[WPA_EAPOL_KEY_MIC_MAX_LEN];
+ size_t mic_len = 16;
unsigned int count;
if (sm == NULL)
@@ -1108,7 +1105,8 @@
return -1;
}
- if (wpa_ft_mic(sm->PTK.kck, sm->addr, sm->wpa_auth->addr, 5,
+ if (wpa_ft_mic(sm->PTK.kck, sm->PTK.kck_len, 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,
@@ -1118,12 +1116,13 @@
return WLAN_STATUS_UNSPECIFIED_FAILURE;
}
- if (os_memcmp_const(mic, ftie->mic, 16) != 0) {
+ if (os_memcmp_const(mic, ftie->mic, mic_len) != 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: Received MIC",
+ ftie->mic, mic_len);
+ wpa_hexdump(MSG_MSGDUMP, "FT: Calculated MIC", mic, mic_len);
wpa_hexdump(MSG_MSGDUMP, "FT: MDIE",
parse.mdie - 2, parse.mdie_len + 2);
wpa_hexdump(MSG_MSGDUMP, "FT: FTIE",
diff --git a/src/ap/wpa_auth_glue.c b/src/ap/wpa_auth_glue.c
index 5433d70..59a56e8 100644
--- a/src/ap/wpa_auth_glue.c
+++ b/src/ap/wpa_auth_glue.c
@@ -11,6 +11,7 @@
#include "utils/common.h"
#include "common/ieee802_11_defs.h"
#include "common/sae.h"
+#include "common/wpa_ctrl.h"
#include "eapol_auth/eapol_auth_sm.h"
#include "eapol_auth/eapol_auth_sm_i.h"
#include "eap_server/eap.h"
@@ -53,8 +54,8 @@
#endif /* CONFIG_IEEE80211W */
#ifdef CONFIG_IEEE80211R
wconf->ssid_len = conf->ssid.ssid_len;
- if (wconf->ssid_len > SSID_LEN)
- wconf->ssid_len = SSID_LEN;
+ if (wconf->ssid_len > SSID_MAX_LEN)
+ wconf->ssid_len = SSID_MAX_LEN;
os_memcpy(wconf->ssid, conf->ssid.ssid, wconf->ssid_len);
os_memcpy(wconf->mobility_domain, conf->mobility_domain,
MOBILITY_DOMAIN_ID_LEN);
@@ -144,6 +145,14 @@
}
+static void hostapd_wpa_auth_psk_failure_report(void *ctx, const u8 *addr)
+{
+ struct hostapd_data *hapd = ctx;
+ wpa_msg(hapd->msg_ctx, MSG_INFO, AP_STA_POSSIBLE_PSK_MISMATCH MACSTR,
+ MAC2STR(addr));
+}
+
+
static void hostapd_wpa_auth_set_eapol(void *ctx, const u8 *addr,
wpa_eapol_variable var, int value)
{
@@ -249,12 +258,17 @@
struct sta_info *sta;
sta = ap_get_sta(hapd, addr);
- if (sta == NULL)
+ if (sta == NULL) {
+ wpa_printf(MSG_DEBUG, "AUTH_GET_MSK: Cannot find STA");
return -1;
+ }
key = ieee802_1x_get_key(sta->eapol_sm, &keylen);
- if (key == NULL)
+ if (key == NULL) {
+ wpa_printf(MSG_DEBUG, "AUTH_GET_MSK: Key is null, eapol_sm: %p",
+ sta->eapol_sm);
return -1;
+ }
if (keylen > *len)
keylen = *len;
@@ -574,6 +588,7 @@
cb.logger = hostapd_wpa_auth_logger;
cb.disconnect = hostapd_wpa_auth_disconnect;
cb.mic_failure_report = hostapd_wpa_auth_mic_failure_report;
+ cb.psk_failure_report = hostapd_wpa_auth_psk_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;
diff --git a/src/ap/wpa_auth_i.h b/src/ap/wpa_auth_i.h
index 478bc95..7b2cd3e 100644
--- a/src/ap/wpa_auth_i.h
+++ b/src/ap/wpa_auth_i.h
@@ -1,6 +1,6 @@
/*
* hostapd - IEEE 802.11i-2004 / WPA Authenticator: Internal definitions
- * Copyright (c) 2004-2007, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -248,7 +248,7 @@
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_ptk *ptk);
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);
diff --git a/src/ap/wpa_auth_ie.c b/src/ap/wpa_auth_ie.c
index c926765..f287297 100644
--- a/src/ap/wpa_auth_ie.c
+++ b/src/ap/wpa_auth_ie.c
@@ -1,6 +1,6 @@
/*
* hostapd - WPA/RSN IE and KDE definitions
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -205,6 +205,11 @@
pos += RSN_SELECTOR_LEN;
num_suites++;
}
+ if (conf->wpa_key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192) {
+ RSN_SELECTOR_PUT(pos, RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192);
+ pos += RSN_SELECTOR_LEN;
+ num_suites++;
+ }
#ifdef CONFIG_RSN_TESTING
if (rsn_testing) {
@@ -482,6 +487,8 @@
selector = RSN_AUTH_KEY_MGMT_UNSPEC_802_1X;
if (0) {
}
+ else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192;
else if (data.key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
selector = RSN_AUTH_KEY_MGMT_802_1X_SUITE_B;
#ifdef CONFIG_IEEE80211R
@@ -562,6 +569,8 @@
}
if (0) {
}
+ else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
else if (key_mgmt & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
sm->wpa_key_mgmt = WPA_KEY_MGMT_IEEE8021X_SUITE_B;
#ifdef CONFIG_IEEE80211R
diff --git a/src/ap/wps_hostapd.c b/src/ap/wps_hostapd.c
index 9ba7aba..68eaeca 100644
--- a/src/ap/wps_hostapd.c
+++ b/src/ap/wps_hostapd.c
@@ -324,7 +324,7 @@
wpa_printf(MSG_DEBUG, "WPS: Updating in-memory configuration");
bss->wps_state = 2;
- if (cred->ssid_len <= HOSTAPD_MAX_SSID_LEN) {
+ if (cred->ssid_len <= SSID_MAX_LEN) {
os_memcpy(bss->ssid.ssid, cred->ssid, cred->ssid_len);
bss->ssid.ssid_len = cred->ssid_len;
bss->ssid.ssid_set = 1;
@@ -362,10 +362,9 @@
if (bss->ssid.wpa_passphrase)
os_memcpy(bss->ssid.wpa_passphrase, cred->key,
cred->key_len);
- os_free(bss->ssid.wpa_psk);
- bss->ssid.wpa_psk = NULL;
+ hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
} else if (cred->key_len == 64) {
- os_free(bss->ssid.wpa_psk);
+ hostapd_config_clear_wpa_psk(&bss->ssid.wpa_psk);
bss->ssid.wpa_psk =
os_zalloc(sizeof(struct hostapd_wpa_psk));
if (bss->ssid.wpa_psk &&
@@ -857,8 +856,10 @@
wpabuf_free(hapd->wps_probe_resp_ie);
hapd->wps_probe_resp_ie = NULL;
- if (deinit_only)
+ if (deinit_only) {
+ hostapd_reset_ap_wps_ie(hapd);
return;
+ }
hostapd_set_ap_wps_ie(hapd);
}
diff --git a/src/ap/x_snoop.c b/src/ap/x_snoop.c
index 8f77015..aef9a53 100644
--- a/src/ap/x_snoop.c
+++ b/src/ap/x_snoop.c
@@ -51,6 +51,14 @@
return -1;
}
+#ifdef CONFIG_IPV6
+ if (hostapd_drv_br_set_net_param(hapd, DRV_BR_MULTICAST_SNOOPING, 1)) {
+ wpa_printf(MSG_DEBUG,
+ "x_snoop: Failed to enable multicast snooping on the bridge");
+ return -1;
+ }
+#endif /* CONFIG_IPV6 */
+
return 0;
}
diff --git a/src/common/Makefile b/src/common/Makefile
index adfd3df..e703630 100644
--- a/src/common/Makefile
+++ b/src/common/Makefile
@@ -1,8 +1,28 @@
-all:
- @echo Nothing to be made.
+all: libcommon.a
clean:
- rm -f *~ *.o *.d *.gcno *.gcda *.gcov
+ rm -f *~ *.o *.d *.gcno *.gcda *.gcov libcommon.a
install:
@echo Nothing to be made.
+
+include ../lib.rules
+
+CFLAGS += -DCONFIG_IEEE80211R
+CFLAGS += -DCONFIG_IEEE80211W
+CFLAGS += -DCONFIG_HS20
+CFLAGS += -DCONFIG_SAE
+CFLAGS += -DCONFIG_SUITE
+CFLAGS += -DCONFIG_SUITEB
+
+LIB_OBJS= \
+ gas.o \
+ hw_features_common.o \
+ ieee802_11_common.o \
+ sae.o \
+ wpa_common.o
+
+libcommon.a: $(LIB_OBJS)
+ $(AR) crT $@ $?
+
+-include $(OBJS:%.o=%.d)
diff --git a/src/common/defs.h b/src/common/defs.h
index e1bbd50..24f80ad 100644
--- a/src/common/defs.h
+++ b/src/common/defs.h
@@ -1,6 +1,6 @@
/*
* WPA Supplicant - Common definitions
- * Copyright (c) 2004-2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -50,6 +50,7 @@
#define WPA_KEY_MGMT_CCKM BIT(14)
#define WPA_KEY_MGMT_OSEN BIT(15)
#define WPA_KEY_MGMT_IEEE8021X_SUITE_B BIT(16)
+#define WPA_KEY_MGMT_IEEE8021X_SUITE_B_192 BIT(17)
static inline int wpa_key_mgmt_wpa_ieee8021x(int akm)
{
@@ -58,7 +59,8 @@
WPA_KEY_MGMT_CCKM |
WPA_KEY_MGMT_OSEN |
WPA_KEY_MGMT_IEEE8021X_SHA256 |
- WPA_KEY_MGMT_IEEE8021X_SUITE_B));
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
}
static inline int wpa_key_mgmt_wpa_psk(int akm)
@@ -91,9 +93,15 @@
WPA_KEY_MGMT_IEEE8021X_SUITE_B));
}
+static inline int wpa_key_mgmt_sha384(int akm)
+{
+ return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192);
+}
+
static inline int wpa_key_mgmt_suite_b(int akm)
{
- return !!(akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B);
+ return !!(akm & (WPA_KEY_MGMT_IEEE8021X_SUITE_B |
+ WPA_KEY_MGMT_IEEE8021X_SUITE_B_192));
}
static inline int wpa_key_mgmt_wpa(int akm)
@@ -302,23 +310,13 @@
WPA_CTRL_REQ_EAP_OTP,
WPA_CTRL_REQ_EAP_PASSPHRASE,
WPA_CTRL_REQ_SIM,
+ WPA_CTRL_REQ_PSK_PASSPHRASE,
NUM_WPA_CTRL_REQS
};
/* Maximum number of EAP methods to store for EAP server user information */
#define EAP_MAX_METHODS 8
-/**
- * enum ht_mode - channel width and offset
- */
-enum ht_mode {
- CHAN_UNDEFINED = 0,
- CHAN_NO_HT,
- CHAN_HT20,
- CHAN_HT40PLUS,
- CHAN_HT40MINUS,
-};
-
enum mesh_plink_state {
PLINK_LISTEN = 1,
PLINK_OPEN_SENT,
diff --git a/src/common/hw_features_common.c b/src/common/hw_features_common.c
new file mode 100644
index 0000000..e61f824
--- /dev/null
+++ b/src/common/hw_features_common.c
@@ -0,0 +1,461 @@
+/*
+ * Common hostapd/wpa_supplicant HW features
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2015, 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 "defs.h"
+#include "ieee802_11_defs.h"
+#include "ieee802_11_common.h"
+#include "hw_features_common.h"
+
+
+struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
+ int chan, int *freq)
+{
+ int i;
+
+ if (freq)
+ *freq = 0;
+
+ if (!mode)
+ return NULL;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *ch = &mode->channels[i];
+ if (ch->chan == chan) {
+ if (freq)
+ *freq = ch->freq;
+ return ch;
+ }
+ }
+
+ return NULL;
+}
+
+
+struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode,
+ int freq, int *chan)
+{
+ int i;
+
+ if (chan)
+ *chan = 0;
+
+ if (!mode)
+ return NULL;
+
+ for (i = 0; i < mode->num_channels; i++) {
+ struct hostapd_channel_data *ch = &mode->channels[i];
+ if (ch->freq == freq) {
+ if (chan)
+ *chan = ch->chan;
+ return ch;
+ }
+ }
+
+ return NULL;
+}
+
+
+int hw_get_freq(struct hostapd_hw_modes *mode, int chan)
+{
+ int freq;
+
+ hw_get_channel_chan(mode, chan, &freq);
+
+ return freq;
+}
+
+
+int hw_get_chan(struct hostapd_hw_modes *mode, int freq)
+{
+ int chan;
+
+ hw_get_channel_freq(mode, freq, &chan);
+
+ return chan;
+}
+
+
+int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
+ int sec_chan)
+{
+ int ok, j, first;
+ int allowed[] = { 36, 44, 52, 60, 100, 108, 116, 124, 132, 140,
+ 149, 157, 184, 192 };
+ size_t k;
+
+ if (pri_chan == sec_chan || !sec_chan)
+ return 1; /* HT40 not used */
+
+ wpa_printf(MSG_DEBUG,
+ "HT40: control channel: %d secondary channel: %d",
+ pri_chan, sec_chan);
+
+ /* Verify that HT40 secondary channel is an allowed 20 MHz
+ * channel */
+ ok = 0;
+ for (j = 0; j < mode->num_channels; j++) {
+ struct hostapd_channel_data *chan = &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 (mode->mode != HOSTAPD_MODE_IEEE80211A)
+ return 1;
+
+ first = pri_chan < sec_chan ? pri_chan : sec_chan;
+
+ ok = 0;
+ for (k = 0; k < ARRAY_SIZE(allowed); k++) {
+ if (first == allowed[k]) {
+ ok = 1;
+ break;
+ }
+ }
+ if (!ok) {
+ wpa_printf(MSG_ERROR, "HT40 channel pair (%d, %d) not allowed",
+ pri_chan, sec_chan);
+ return 0;
+ }
+
+ return 1;
+}
+
+
+void 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) {
+ oper = (struct ieee80211_ht_operation *) elems.ht_operation;
+ *pri_chan = oper->primary_chan;
+ if (oper->ht_param & HT_INFO_HT_PARAM_STA_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;
+ }
+ }
+}
+
+
+int check_40mhz_5g(struct hostapd_hw_modes *mode,
+ struct wpa_scan_results *scan_res, int pri_chan,
+ int sec_chan)
+{
+ int pri_freq, sec_freq, pri_bss, sec_bss;
+ int bss_pri_chan, bss_sec_chan;
+ size_t i;
+ int match;
+
+ if (!mode || !scan_res || !pri_chan || !sec_chan)
+ return 0;
+
+ if (pri_chan == sec_chan)
+ return 0;
+
+ pri_freq = hw_get_freq(mode, pri_chan);
+ sec_freq = hw_get_freq(mode, sec_chan);
+
+ /*
+ * 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");
+ return 2;
+ }
+
+ /*
+ * 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];
+ 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];
+ 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));
+ return 2;
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end)
+{
+ struct ieee802_11_elems elems;
+ struct ieee80211_ht_operation *oper;
+
+ if (bss->freq < start || bss->freq > end || bss->freq == pri_freq)
+ return 0;
+
+ ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems, 0);
+ if (!elems.ht_capabilities) {
+ wpa_printf(MSG_DEBUG, "Found overlapping legacy BSS: "
+ MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
+ return 1;
+ }
+
+ if (elems.ht_operation) {
+ oper = (struct ieee80211_ht_operation *) elems.ht_operation;
+ if (oper->ht_param & HT_INFO_HT_PARAM_SECONDARY_CHNL_OFF_MASK)
+ return 0;
+
+ wpa_printf(MSG_DEBUG, "Found overlapping 20 MHz HT BSS: "
+ MACSTR " freq=%d", MAC2STR(bss->bssid), bss->freq);
+ return 1;
+ }
+ return 0;
+}
+
+
+int check_40mhz_2g4(struct hostapd_hw_modes *mode,
+ struct wpa_scan_results *scan_res, int pri_chan,
+ int sec_chan)
+{
+ int pri_freq, sec_freq;
+ int affected_start, affected_end;
+ size_t i;
+
+ if (!mode || !scan_res || !pri_chan || !sec_chan)
+ return 0;
+
+ if (pri_chan == sec_chan)
+ return 0;
+
+ pri_freq = hw_get_freq(mode, pri_chan);
+ sec_freq = hw_get_freq(mode, sec_chan);
+
+ 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;
+ struct ieee802_11_elems elems;
+
+ /* Check for overlapping 20 MHz BSS */
+ if (check_20mhz_bss(bss, pri_freq, affected_start,
+ affected_end)) {
+ wpa_printf(MSG_DEBUG,
+ "Overlapping 20 MHz BSS is found");
+ return 0;
+ }
+
+ 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;
+ }
+ }
+
+ ieee802_11_parse_elems((u8 *) (bss + 1), bss->ie_len, &elems,
+ 0);
+ if (elems.ht_capabilities) {
+ struct ieee80211_ht_capabilities *ht_cap =
+ (struct ieee80211_ht_capabilities *)
+ elems.ht_capabilities;
+
+ if (le_to_host16(ht_cap->ht_capabilities_info) &
+ HT_CAP_INFO_40MHZ_INTOLERANT) {
+ wpa_printf(MSG_DEBUG,
+ "40 MHz Intolerant is set on channel %d in BSS "
+ MACSTR, pri, MAC2STR(bss->bssid));
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+
+int hostapd_set_freq_params(struct hostapd_freq_params *data,
+ enum hostapd_hw_mode mode,
+ int freq, int channel, int ht_enabled,
+ int vht_enabled, int sec_channel_offset,
+ int vht_oper_chwidth, int center_segment0,
+ int center_segment1, u32 vht_caps)
+{
+ os_memset(data, 0, sizeof(*data));
+ data->mode = mode;
+ data->freq = freq;
+ data->channel = channel;
+ data->ht_enabled = ht_enabled;
+ data->vht_enabled = vht_enabled;
+ data->sec_channel_offset = sec_channel_offset;
+ data->center_freq1 = freq + sec_channel_offset * 10;
+ data->center_freq2 = 0;
+ data->bandwidth = sec_channel_offset ? 40 : 20;
+
+ if (data->vht_enabled) switch (vht_oper_chwidth) {
+ case VHT_CHANWIDTH_USE_HT:
+ if (center_segment1)
+ return -1;
+ if (center_segment0 != 0 &&
+ 5000 + center_segment0 * 5 != data->center_freq1 &&
+ 2407 + center_segment0 * 5 != data->center_freq1)
+ return -1;
+ break;
+ case VHT_CHANWIDTH_80P80MHZ:
+ if (!(vht_caps & VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ)) {
+ wpa_printf(MSG_ERROR,
+ "80+80 channel width is not supported!");
+ return -1;
+ }
+ if (center_segment1 == center_segment0 + 4 ||
+ center_segment1 == center_segment0 - 4)
+ return -1;
+ data->center_freq2 = 5000 + center_segment1 * 5;
+ /* fall through */
+ case VHT_CHANWIDTH_80MHZ:
+ data->bandwidth = 80;
+ if (vht_oper_chwidth == 1 && center_segment1)
+ return -1;
+ if (vht_oper_chwidth == 3 && !center_segment1)
+ return -1;
+ if (!sec_channel_offset)
+ return -1;
+ if (!center_segment0) {
+ if (channel <= 48)
+ center_segment0 = 42;
+ else if (channel <= 64)
+ center_segment0 = 58;
+ else if (channel <= 112)
+ center_segment0 = 106;
+ else if (channel <= 128)
+ center_segment0 = 122;
+ else if (channel <= 144)
+ center_segment0 = 138;
+ else if (channel <= 161)
+ center_segment0 = 155;
+ data->center_freq1 = 5000 + center_segment0 * 5;
+ } else {
+ /*
+ * Note: HT/VHT config and params are coupled. Check if
+ * HT40 channel band is in VHT80 Pri channel band
+ * configuration.
+ */
+ if (center_segment0 == channel + 6 ||
+ center_segment0 == channel + 2 ||
+ center_segment0 == channel - 2 ||
+ center_segment0 == channel - 6)
+ data->center_freq1 = 5000 + center_segment0 * 5;
+ else
+ return -1;
+ }
+ break;
+ case VHT_CHANWIDTH_160MHZ:
+ data->bandwidth = 160;
+ if (!(vht_caps & (VHT_CAP_SUPP_CHAN_WIDTH_160MHZ |
+ VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))) {
+ wpa_printf(MSG_ERROR,
+ "160MHZ channel width is not supported!");
+ return -1;
+ }
+ if (center_segment1)
+ return -1;
+ if (!sec_channel_offset)
+ return -1;
+ /*
+ * Note: HT/VHT config and params are coupled. Check if
+ * HT40 channel band is in VHT160 channel band configuration.
+ */
+ if (center_segment0 == channel + 14 ||
+ center_segment0 == channel + 10 ||
+ center_segment0 == channel + 6 ||
+ center_segment0 == channel + 2 ||
+ center_segment0 == channel - 2 ||
+ center_segment0 == channel - 6 ||
+ center_segment0 == channel - 10 ||
+ center_segment0 == channel - 14)
+ data->center_freq1 = 5000 + center_segment0 * 5;
+ else
+ return -1;
+ break;
+ }
+
+ return 0;
+}
diff --git a/src/common/hw_features_common.h b/src/common/hw_features_common.h
new file mode 100644
index 0000000..7f43d00
--- /dev/null
+++ b/src/common/hw_features_common.h
@@ -0,0 +1,40 @@
+/*
+ * Common hostapd/wpa_supplicant HW features
+ * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2015, Qualcomm Atheros, Inc.
+ *
+ * This software may be distributed under the terms of the BSD license.
+ * See README for more details.
+ */
+
+#ifndef HW_FEATURES_COMMON_H
+#define HW_FEATURES_COMMON_H
+
+#include "drivers/driver.h"
+
+struct hostapd_channel_data * hw_get_channel_chan(struct hostapd_hw_modes *mode,
+ int chan, int *freq);
+struct hostapd_channel_data * hw_get_channel_freq(struct hostapd_hw_modes *mode,
+ int freq, int *chan);
+
+int hw_get_freq(struct hostapd_hw_modes *mode, int chan);
+int hw_get_chan(struct hostapd_hw_modes *mode, int freq);
+
+int allowed_ht40_channel_pair(struct hostapd_hw_modes *mode, int pri_chan,
+ int sec_chan);
+void get_pri_sec_chan(struct wpa_scan_res *bss, int *pri_chan, int *sec_chan);
+int check_40mhz_5g(struct hostapd_hw_modes *mode,
+ struct wpa_scan_results *scan_res, int pri_chan,
+ int sec_chan);
+int check_20mhz_bss(struct wpa_scan_res *bss, int pri_freq, int start, int end);
+int check_40mhz_2g4(struct hostapd_hw_modes *mode,
+ struct wpa_scan_results *scan_res, int pri_chan,
+ int sec_chan);
+int hostapd_set_freq_params(struct hostapd_freq_params *data,
+ enum hostapd_hw_mode mode,
+ int freq, int channel, int ht_enabled,
+ int vht_enabled, int sec_channel_offset,
+ int vht_oper_chwidth, int center_segment0,
+ int center_segment1, u32 vht_caps);
+
+#endif /* HW_FEATURES_COMMON_H */
diff --git a/src/common/ieee802_11_common.c b/src/common/ieee802_11_common.c
index e1d45cf..7843e6f 100644
--- a/src/common/ieee802_11_common.c
+++ b/src/common/ieee802_11_common.c
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Common routines
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -10,6 +10,7 @@
#include "common.h"
#include "defs.h"
+#include "wpa_common.h"
#include "ieee802_11_defs.h"
#include "ieee802_11_common.h"
@@ -128,6 +129,15 @@
elems->vendor_ht_cap = pos;
elems->vendor_ht_cap_len = elen;
break;
+ case VENDOR_VHT_TYPE:
+ if (elen > 4 &&
+ (pos[4] == VENDOR_VHT_SUBTYPE ||
+ pos[4] == VENDOR_VHT_SUBTYPE2)) {
+ elems->vendor_vht = pos;
+ elems->vendor_vht_len = elen;
+ } else
+ return -1;
+ break;
default:
wpa_printf(MSG_EXCESSIVE, "Unknown Broadcom "
"information element ignored "
@@ -187,6 +197,12 @@
switch (id) {
case WLAN_EID_SSID:
+ if (elen > SSID_MAX_LEN) {
+ wpa_printf(MSG_DEBUG,
+ "Ignored too long SSID element (elen=%u)",
+ elen);
+ break;
+ }
elems->ssid = pos;
elems->ssid_len = elen;
break;
@@ -195,8 +211,9 @@
elems->supp_rates_len = elen;
break;
case WLAN_EID_DS_PARAMS:
+ if (elen < 1)
+ break;
elems->ds_params = pos;
- elems->ds_params_len = elen;
break;
case WLAN_EID_CF_PARAMS:
case WLAN_EID_TIM:
@@ -206,8 +223,9 @@
elems->challenge_len = elen;
break;
case WLAN_EID_ERP_INFO:
+ if (elen < 1)
+ break;
elems->erp_info = pos;
- elems->erp_info_len = elen;
break;
case WLAN_EID_EXT_SUPP_RATES:
elems->ext_supp_rates = pos;
@@ -230,24 +248,31 @@
elems->supp_channels_len = elen;
break;
case WLAN_EID_MOBILITY_DOMAIN:
+ if (elen < sizeof(struct rsn_mdie))
+ break;
elems->mdie = pos;
elems->mdie_len = elen;
break;
case WLAN_EID_FAST_BSS_TRANSITION:
+ if (elen < sizeof(struct rsn_ftie))
+ break;
elems->ftie = pos;
elems->ftie_len = elen;
break;
case WLAN_EID_TIMEOUT_INTERVAL:
+ if (elen != 5)
+ break;
elems->timeout_int = pos;
- elems->timeout_int_len = elen;
break;
case WLAN_EID_HT_CAP:
+ if (elen < sizeof(struct ieee80211_ht_capabilities))
+ break;
elems->ht_capabilities = pos;
- elems->ht_capabilities_len = elen;
break;
case WLAN_EID_HT_OPERATION:
+ if (elen < sizeof(struct ieee80211_ht_operation))
+ break;
elems->ht_operation = pos;
- elems->ht_operation_len = elen;
break;
case WLAN_EID_MESH_CONFIG:
elems->mesh_config = pos;
@@ -262,12 +287,14 @@
elems->peer_mgmt_len = elen;
break;
case WLAN_EID_VHT_CAP:
+ if (elen < sizeof(struct ieee80211_vht_capabilities))
+ break;
elems->vht_capabilities = pos;
- elems->vht_capabilities_len = elen;
break;
case WLAN_EID_VHT_OPERATION:
+ if (elen < sizeof(struct ieee80211_vht_operation))
+ break;
elems->vht_operation = pos;
- elems->vht_operation_len = elen;
break;
case WLAN_EID_VHT_OPERATING_MODE_NOTIFICATION:
if (elen != 1)
@@ -817,6 +844,13 @@
}
+int ieee80211_is_dfs(int freq)
+{
+ /* TODO: this could be more accurate to better cover all domains */
+ return (freq >= 5260 && freq <= 5320) || (freq >= 5500 && freq <= 5700);
+}
+
+
static int is_11b(u8 rate)
{
return rate == 0x02 || rate == 0x04 || rate == 0x0b || rate == 0x16;
diff --git a/src/common/ieee802_11_common.h b/src/common/ieee802_11_common.h
index 2357afc..c84d8a7 100644
--- a/src/common/ieee802_11_common.h
+++ b/src/common/ieee802_11_common.h
@@ -35,6 +35,7 @@
const u8 *vht_operation;
const u8 *vht_opmode_notif;
const u8 *vendor_ht_cap;
+ const u8 *vendor_vht;
const u8 *p2p;
const u8 *wfd;
const u8 *link_id;
@@ -50,9 +51,7 @@
u8 ssid_len;
u8 supp_rates_len;
- u8 ds_params_len;
u8 challenge_len;
- u8 erp_info_len;
u8 ext_supp_rates_len;
u8 wpa_ie_len;
u8 rsn_ie_len;
@@ -62,15 +61,11 @@
u8 supp_channels_len;
u8 mdie_len;
u8 ftie_len;
- u8 timeout_int_len;
- u8 ht_capabilities_len;
- u8 ht_operation_len;
u8 mesh_config_len;
u8 mesh_id_len;
u8 peer_mgmt_len;
- u8 vht_capabilities_len;
- u8 vht_operation_len;
u8 vendor_ht_cap_len;
+ u8 vendor_vht_len;
u8 p2p_len;
u8 wfd_len;
u8 interworking_len;
@@ -106,6 +101,7 @@
const char *name, const char *val);
enum hostapd_hw_mode ieee80211_freq_to_chan(int freq, u8 *channel);
int ieee80211_chan_to_freq(const char *country, u8 op_class, u8 chan);
+int ieee80211_is_dfs(int freq);
int supp_rates_11b_only(struct ieee802_11_elems *elems);
diff --git a/src/common/ieee802_11_defs.h b/src/common/ieee802_11_defs.h
index 0ce5daf..feab921 100644
--- a/src/common/ieee802_11_defs.h
+++ b/src/common/ieee802_11_defs.h
@@ -1,6 +1,6 @@
/*
* IEEE 802.11 Frame type definitions
- * Copyright (c) 2002-2009, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
* Copyright (c) 2007-2008 Intel Corporation
*
* This software may be distributed under the terms of the BSD license.
@@ -10,6 +10,8 @@
#ifndef IEEE802_11_DEFS_H
#define IEEE802_11_DEFS_H
+#include <utils/common.h>
+
/* IEEE 802.11 defines */
#define WLAN_FC_PVER 0x0003
@@ -470,35 +472,35 @@
le16 auth_transaction;
le16 status_code;
/* possibly followed by Challenge text */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED auth;
struct {
le16 reason_code;
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED deauth;
struct {
le16 capab_info;
le16 listen_interval;
/* followed by SSID and Supported rates */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED assoc_req;
struct {
le16 capab_info;
le16 status_code;
le16 aid;
/* followed by Supported rates */
- u8 variable[0];
+ u8 variable[];
} 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];
+ u8 variable[];
} STRUCT_PACKED reassoc_req;
struct {
le16 reason_code;
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED disassoc;
struct {
u8 timestamp[8];
@@ -506,7 +508,7 @@
le16 capab_info;
/* followed by some of SSID, Supported rates,
* FH Params, DS Params, CF Params, IBSS Params, TIM */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED beacon;
struct {
/* only variable items: SSID, Supported rates */
@@ -518,7 +520,7 @@
le16 capab_info;
/* followed by some of SSID, Supported rates,
* FH Params, DS Params, CF Params, IBSS Params */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED probe_resp;
struct {
u8 category;
@@ -527,7 +529,7 @@
u8 action_code;
u8 dialog_token;
u8 status_code;
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED wmm_action;
struct{
u8 action_code;
@@ -541,14 +543,14 @@
u8 action;
u8 sta_addr[ETH_ALEN];
u8 target_ap_addr[ETH_ALEN];
- u8 variable[0]; /* FT Request */
+ u8 variable[]; /* 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 */
+ u8 variable[]; /* FT Request */
} STRUCT_PACKED ft_action_resp;
struct {
u8 action;
@@ -561,23 +563,23 @@
struct {
u8 action;
u8 dialogtoken;
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED wnm_sleep_req;
struct {
u8 action;
u8 dialogtoken;
le16 keydata_len;
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED wnm_sleep_resp;
struct {
u8 action;
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED public_action;
struct {
u8 action; /* 9 */
u8 oui[3];
/* Vendor-specific content */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED vs_public_action;
struct {
u8 action; /* 7 */
@@ -589,7 +591,7 @@
* Session Information URL (optional),
* BSS Transition Candidate List
* Entries */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED bss_tm_req;
struct {
u8 action; /* 8 */
@@ -599,7 +601,7 @@
/* Target BSSID (optional),
* BSS Transition Candidate List
* Entries (optional) */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED bss_tm_resp;
struct {
u8 action; /* 6 */
@@ -607,11 +609,11 @@
u8 query_reason;
/* BSS Transition Candidate List
* Entries (optional) */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED bss_tm_query;
struct {
u8 action; /* 15 */
- u8 variable[0];
+ u8 variable[];
} STRUCT_PACKED slf_prot_action;
struct {
u8 action; /* 5 */
@@ -1039,6 +1041,14 @@
P2P_ATTR_OPERATING_CHANNEL = 17,
P2P_ATTR_INVITATION_FLAGS = 18,
P2P_ATTR_OOB_GO_NEG_CHANNEL = 19,
+ P2P_ATTR_SERVICE_HASH = 21,
+ P2P_ATTR_SESSION_INFORMATION_DATA = 22,
+ P2P_ATTR_CONNECTION_CAPABILITY = 23,
+ P2P_ATTR_ADVERTISEMENT_ID = 24,
+ P2P_ATTR_ADVERTISED_SERVICE = 25,
+ P2P_ATTR_SESSION_ID = 26,
+ P2P_ATTR_FEATURE_CAPABILITY = 27,
+ P2P_ATTR_PERSISTENT_GROUP = 28,
P2P_ATTR_VENDOR_SPECIFIC = 221
};
@@ -1083,6 +1093,7 @@
P2P_SC_FAIL_BOTH_GO_INTENT_15 = 9,
P2P_SC_FAIL_INCOMPATIBLE_PROV_METHOD = 10,
P2P_SC_FAIL_REJECTED_BY_USER = 11,
+ P2P_SC_SUCCESS_DEFERRED = 12,
};
enum p2p_role_indication {
@@ -1121,6 +1132,7 @@
P2P_SERV_UPNP = 2,
P2P_SERV_WS_DISCOVERY = 3,
P2P_SERV_WIFI_DISPLAY = 4,
+ P2P_SERV_P2PS = 11,
P2P_SERV_VENDOR_SPECIFIC = 255
};
@@ -1160,6 +1172,9 @@
};
#define OUI_BROADCOM 0x00904c /* Broadcom (Epigram) */
+#define VENDOR_VHT_TYPE 0x04
+#define VENDOR_VHT_SUBTYPE 0x08
+#define VENDOR_VHT_SUBTYPE2 0x00
#define VENDOR_HT_CAPAB_OUI_TYPE 0x33 /* 00-90-4c:0x33 */
@@ -1194,6 +1209,7 @@
#define WLAN_AKM_SUITE_8021X_SHA256 0x000FAC05
#define WLAN_AKM_SUITE_PSK_SHA256 0x000FAC06
#define WLAN_AKM_SUITE_8021X_SUITE_B 0x000FAC11
+#define WLAN_AKM_SUITE_8021X_SUITE_B_192 0x000FAC12
#define WLAN_AKM_SUITE_CCKM 0x00409600
#define WLAN_AKM_SUITE_OSEN 0x506f9a01
@@ -1357,4 +1373,6 @@
u8 variable[0];
} STRUCT_PACKED;
+#define SSID_MAX_LEN 32
+
#endif /* IEEE802_11_DEFS_H */
diff --git a/src/common/privsep_commands.h b/src/common/privsep_commands.h
index 4dc34c4..c6a472d 100644
--- a/src/common/privsep_commands.h
+++ b/src/common/privsep_commands.h
@@ -9,6 +9,8 @@
#ifndef PRIVSEP_COMMANDS_H
#define PRIVSEP_COMMANDS_H
+#include "common/ieee802_11_defs.h"
+
enum privsep_cmd {
PRIVSEP_CMD_REGISTER,
PRIVSEP_CMD_UNREGISTER,
@@ -29,7 +31,7 @@
struct privsep_cmd_associate
{
u8 bssid[ETH_ALEN];
- u8 ssid[32];
+ u8 ssid[SSID_MAX_LEN];
size_t ssid_len;
int hwmode;
int freq;
diff --git a/src/common/qca-vendor.h b/src/common/qca-vendor.h
index ec1be86..e51f85f 100644
--- a/src/common/qca-vendor.h
+++ b/src/common/qca-vendor.h
@@ -1,6 +1,6 @@
/*
* Qualcomm Atheros OUI and vendor specific assignments
- * Copyright (c) 2014, Qualcomm Atheros, Inc.
+ * Copyright (c) 2014-2015, Qualcomm Atheros, Inc.
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -69,6 +69,26 @@
* @QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES: Command to get the features
* supported by the driver. enum qca_wlan_vendor_features defines
* the possible features.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED: Event used by driver,
+ * which supports DFS offloading, to indicate a channel availability check
+ * start.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED: Event used by driver,
+ * which supports DFS offloading, to indicate a channel availability check
+ * completion.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED: Event used by driver,
+ * which supports DFS offloading, to indicate that the channel availability
+ * check aborted, no change to the channel status.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED: Event used by
+ * driver, which supports DFS offloading, to indicate that the
+ * Non-Occupancy Period for this channel is over, channel becomes usable.
+ *
+ * @QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED: Event used by driver,
+ * which supports DFS offloading, to indicate a radar pattern has been
+ * detected. The channel is now unusable.
*/
enum qca_nl80211_vendor_subcmds {
QCA_NL80211_VENDOR_SUBCMD_UNSPEC = 0,
@@ -112,9 +132,25 @@
QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_SET_KEY = 50,
QCA_NL80211_VENDOR_SUBCMD_KEY_MGMT_ROAM_AUTH = 51,
QCA_NL80211_VENDOR_SUBCMD_APFIND = 52,
- /* 53 - reserved for QCA */
+ /* 53 - reserved - was used by QCA, but not in use anymore */
QCA_NL80211_VENDOR_SUBCMD_DO_ACS = 54,
QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES = 55,
+ QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_STARTED = 56,
+ QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_FINISHED = 57,
+ QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_ABORTED = 58,
+ QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_CAC_NOP_FINISHED = 59,
+ QCA_NL80211_VENDOR_SUBCMD_DFS_OFFLOAD_RADAR_DETECTED = 60,
+ /* 61-90 - reserved for QCA */
+ QCA_NL80211_VENDOR_SUBCMD_DATA_OFFLOAD = 91,
+ QCA_NL80211_VENDOR_SUBCMD_OCB_SET_CONFIG = 92,
+ QCA_NL80211_VENDOR_SUBCMD_OCB_SET_UTC_TIME = 93,
+ QCA_NL80211_VENDOR_SUBCMD_OCB_START_TIMING_ADVERT = 94,
+ QCA_NL80211_VENDOR_SUBCMD_OCB_STOP_TIMING_ADVERT = 95,
+ QCA_NL80211_VENDOR_SUBCMD_OCB_GET_TSF_TIMER = 96,
+ QCA_NL80211_VENDOR_SUBCMD_DCC_GET_STATS = 97,
+ QCA_NL80211_VENDOR_SUBCMD_DCC_CLEAR_STATS = 98,
+ QCA_NL80211_VENDOR_SUBCMD_DCC_UPDATE_NDL = 99,
+ QCA_NL80211_VENDOR_SUBCMD_DCC_STATS_EVENT = 100,
};
@@ -134,6 +170,7 @@
QCA_WLAN_VENDOR_ATTR_MAC_ADDR = 6,
/* used by QCA_NL80211_VENDOR_SUBCMD_GET_FEATURES */
QCA_WLAN_VENDOR_ATTR_FEATURE_FLAGS = 7,
+ QCA_WLAN_VENDOR_ATTR_TEST = 8,
/* keep last */
QCA_WLAN_VENDOR_ATTR_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_MAX = QCA_WLAN_VENDOR_ATTR_AFTER_LAST - 1,
@@ -167,6 +204,11 @@
QCA_WLAN_VENDOR_ATTR_ACS_HW_MODE,
QCA_WLAN_VENDOR_ATTR_ACS_HT_ENABLED,
QCA_WLAN_VENDOR_ATTR_ACS_HT40_ENABLED,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_ENABLED,
+ QCA_WLAN_VENDOR_ATTR_ACS_CHWIDTH,
+ QCA_WLAN_VENDOR_ATTR_ACS_CH_LIST,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG0_CENTER_CHANNEL,
+ QCA_WLAN_VENDOR_ATTR_ACS_VHT_SEG1_CENTER_CHANNEL,
/* keep last */
QCA_WLAN_VENDOR_ATTR_ACS_AFTER_LAST,
QCA_WLAN_VENDOR_ATTR_ACS_MAX =
@@ -194,4 +236,25 @@
NUM_QCA_WLAN_VENDOR_FEATURES /* keep last */
};
+/**
+ * enum qca_wlan_vendor_attr_data_offload_ind - Vendor Data Offload Indication
+ *
+ * @QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_SESSION: Session corresponding to
+ * the offloaded data.
+ * @QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_PROTOCOL: Protocol of the offloaded
+ * data.
+ * @QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_EVENT: Event type for the data offload
+ * indication.
+ */
+enum qca_wlan_vendor_attr_data_offload_ind {
+ QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_INVALID = 0,
+ QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_SESSION,
+ QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_PROTOCOL,
+ QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_EVENT,
+
+ /* keep last */
+ QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_AFTER_LAST,
+ QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_MAX =
+ QCA_WLAN_VENDOR_ATTR_DATA_OFFLOAD_IND_AFTER_LAST - 1
+};
#endif /* QCA_VENDOR_H */
diff --git a/src/common/sae.h b/src/common/sae.h
index 89d74ab..3ebf40c 100644
--- a/src/common/sae.h
+++ b/src/common/sae.h
@@ -44,6 +44,7 @@
u8 pmk[SAE_PMK_LEN];
struct crypto_bignum *peer_commit_scalar;
int group;
+ int sync;
struct sae_temporary_data *tmp;
};
diff --git a/src/common/version.h b/src/common/version.h
index c662270..5ddf617 100644
--- a/src/common/version.h
+++ b/src/common/version.h
@@ -5,6 +5,6 @@
#define VERSION_STR_POSTFIX ""
#endif /* VERSION_STR_POSTFIX */
-#define VERSION_STR "2.4-devel" VERSION_STR_POSTFIX
+#define VERSION_STR "2.5-devel" VERSION_STR_POSTFIX
#endif /* VERSION_H */
diff --git a/src/common/wpa_common.c b/src/common/wpa_common.c
index a573e11..a0747b4 100644
--- a/src/common/wpa_common.c
+++ b/src/common/wpa_common.c
@@ -1,6 +1,6 @@
/*
* WPA/RSN - Shared functions for supplicant and authenticator
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -12,6 +12,7 @@
#include "crypto/md5.h"
#include "crypto/sha1.h"
#include "crypto/sha256.h"
+#include "crypto/sha384.h"
#include "crypto/aes_wrap.h"
#include "crypto/crypto.h"
#include "ieee802_11_defs.h"
@@ -19,9 +20,34 @@
#include "wpa_common.h"
+static unsigned int wpa_kck_len(int akmp)
+{
+ if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ return 24;
+ return 16;
+}
+
+
+static unsigned int wpa_kek_len(int akmp)
+{
+ if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ return 32;
+ return 16;
+}
+
+
+unsigned int wpa_mic_len(int akmp)
+{
+ if (akmp == WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ return 24;
+ return 16;
+}
+
+
/**
* wpa_eapol_key_mic - Calculate EAPOL-Key MIC
* @key: EAPOL-Key Key Confirmation Key (KCK)
+ * @key_len: KCK length in octets
* @akmp: WPA_KEY_MGMT_* used in key derivation
* @ver: Key descriptor version (WPA_KEY_INFO_TYPE_*)
* @buf: Pointer to the beginning of the EAPOL header (version field)
@@ -38,18 +64,18 @@
* 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 akmp, int ver, const u8 *buf,
- size_t len, u8 *mic)
+int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
+ const u8 *buf, size_t len, u8 *mic)
{
- u8 hash[SHA256_MAC_LEN];
+ u8 hash[SHA384_MAC_LEN];
switch (ver) {
#ifndef CONFIG_FIPS
case WPA_KEY_INFO_TYPE_HMAC_MD5_RC4:
- return hmac_md5(key, 16, buf, len, mic);
+ return hmac_md5(key, key_len, buf, len, mic);
#endif /* CONFIG_FIPS */
case WPA_KEY_INFO_TYPE_HMAC_SHA1_AES:
- if (hmac_sha1(key, 16, buf, len, hash))
+ if (hmac_sha1(key, key_len, buf, len, hash))
return -1;
os_memcpy(mic, hash, MD5_MAC_LEN);
break;
@@ -65,11 +91,18 @@
#endif /* CONFIG_HS20 */
#ifdef CONFIG_SUITEB
case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
- if (hmac_sha256(key, 16, buf, len, hash))
+ if (hmac_sha256(key, key_len, buf, len, hash))
return -1;
os_memcpy(mic, hash, MD5_MAC_LEN);
break;
#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ if (hmac_sha384(key, key_len, buf, len, hash))
+ return -1;
+ os_memcpy(mic, hash, 24);
+ break;
+#endif /* CONFIG_SUITEB192 */
default:
return -1;
}
@@ -92,8 +125,9 @@
* @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
+ * @akmp: Negotiated AKM
+ * @cipher: Negotiated pairwise cipher
+ * Returns: 0 on success, -1 on failure
*
* IEEE Std 802.11i-2004 - 8.5.1.2 Pairwise key hierarchy
* PTK = PRF-X(PMK, "Pairwise key expansion",
@@ -104,12 +138,14 @@
* 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)
+int 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,
+ struct wpa_ptk *ptk, int akmp, int cipher)
{
u8 data[2 * ETH_ALEN + 2 * WPA_NONCE_LEN];
+ u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+ size_t ptk_len;
if (os_memcmp(addr1, addr2, ETH_ALEN) < 0) {
os_memcpy(data, addr1, ETH_ALEN);
@@ -129,76 +165,111 @@
WPA_NONCE_LEN);
}
+ ptk->kck_len = wpa_kck_len(akmp);
+ ptk->kek_len = wpa_kek_len(akmp);
+ ptk->tk_len = wpa_cipher_key_len(cipher);
+ ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+
#ifdef CONFIG_IEEE80211W
- if (use_sha256)
+ if (wpa_key_mgmt_sha256(akmp))
sha256_prf(pmk, pmk_len, label, data, sizeof(data),
- ptk, ptk_len);
+ tmp, ptk_len);
else
#endif /* CONFIG_IEEE80211W */
- sha1_prf(pmk, pmk_len, label, data, sizeof(data), ptk,
- ptk_len);
+ sha1_prf(pmk, pmk_len, label, data, sizeof(data), tmp, 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);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: PTK", tmp, ptk_len);
+
+ os_memcpy(ptk->kck, tmp, ptk->kck_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KCK", ptk->kck, ptk->kck_len);
+
+ os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: KEK", ptk->kek, ptk->kek_len);
+
+ os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
+ wpa_hexdump_key(MSG_DEBUG, "WPA: TK", ptk->tk, ptk->tk_len);
+
+ os_memset(tmp, 0, sizeof(tmp));
+ return 0;
}
#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,
+int wpa_ft_mic(const u8 *kck, size_t kck_len, 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;
+ const u8 *addr[9];
+ size_t len[9];
+ size_t i, num_elem = 0;
+ u8 zero_mic[16];
- buf_len = 2 * ETH_ALEN + 1 + mdie_len + ftie_len + rsnie_len + ric_len;
- buf = os_malloc(buf_len);
- if (buf == NULL)
+ if (kck_len != 16) {
+ wpa_printf(MSG_WARNING, "FT: Unsupported KCK length %u",
+ (unsigned int) kck_len);
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;
+ addr[num_elem] = sta_addr;
+ len[num_elem] = ETH_ALEN;
+ num_elem++;
+
+ addr[num_elem] = ap_addr;
+ len[num_elem] = ETH_ALEN;
+ num_elem++;
+
+ addr[num_elem] = &transaction_seqnum;
+ len[num_elem] = 1;
+ num_elem++;
+
if (rsnie) {
- os_memcpy(pos, rsnie, rsnie_len);
- pos += rsnie_len;
+ addr[num_elem] = rsnie;
+ len[num_elem] = rsnie_len;
+ num_elem++;
}
if (mdie) {
- os_memcpy(pos, mdie, mdie_len);
- pos += mdie_len;
+ addr[num_elem] = mdie;
+ len[num_elem] = mdie_len;
+ num_elem++;
}
if (ftie) {
- struct rsn_ftie *_ftie;
- os_memcpy(pos, ftie, ftie_len);
- if (ftie_len < 2 + sizeof(*_ftie)) {
- os_free(buf);
+ if (ftie_len < 2 + sizeof(struct rsn_ftie))
return -1;
- }
- _ftie = (struct rsn_ftie *) (pos + 2);
- os_memset(_ftie->mic, 0, sizeof(_ftie->mic));
- pos += ftie_len;
+
+ /* IE hdr and mic_control */
+ addr[num_elem] = ftie;
+ len[num_elem] = 2 + 2;
+ num_elem++;
+
+ /* MIC field with all zeros */
+ os_memset(zero_mic, 0, sizeof(zero_mic));
+ addr[num_elem] = zero_mic;
+ len[num_elem] = sizeof(zero_mic);
+ num_elem++;
+
+ /* Rest of FTIE */
+ addr[num_elem] = ftie + 2 + 2 + 16;
+ len[num_elem] = ftie_len - (2 + 2 + 16);
+ num_elem++;
}
if (ric) {
- os_memcpy(pos, ric, ric_len);
- pos += ric_len;
+ addr[num_elem] = ric;
+ len[num_elem] = ric_len;
+ num_elem++;
}
- wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", buf, pos - buf);
- if (omac1_aes_128(kck, buf, pos - buf, mic)) {
- os_free(buf);
+ for (i = 0; i < num_elem; i++)
+ wpa_hexdump(MSG_MSGDUMP, "FT: MIC data", addr[i], len[i]);
+ if (omac1_aes_128_vector(kck, num_elem, addr, len, mic))
return -1;
- }
-
- os_free(buf);
return 0;
}
@@ -285,6 +356,8 @@
parse->rsn_pmkid = data.pmkid;
break;
case WLAN_EID_MOBILITY_DOMAIN:
+ if (pos[1] < sizeof(struct rsn_mdie))
+ return -1;
parse->mdie = pos + 2;
parse->mdie_len = pos[1];
break;
@@ -297,6 +370,8 @@
return -1;
break;
case WLAN_EID_TIMEOUT_INTERVAL:
+ if (pos[1] != 5)
+ break;
parse->tie = pos + 2;
parse->tie_len = pos[1];
break;
@@ -413,6 +488,10 @@
#endif /* CONFIG_SAE */
if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B)
return WPA_KEY_MGMT_IEEE8021X_SUITE_B;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192)
+ return WPA_KEY_MGMT_IEEE8021X_SUITE_B_192;
+ if (RSN_SELECTOR_GET(s) == RSN_AUTH_KEY_MGMT_OSEN)
+ return WPA_KEY_MGMT_OSEN;
return 0;
}
@@ -447,7 +526,6 @@
int wpa_parse_wpa_ie_rsn(const u8 *rsn_ie, size_t rsn_ie_len,
struct wpa_ie_data *data)
{
- const struct rsn_ie_hdr *hdr;
const u8 *pos;
int left;
int i, count;
@@ -477,19 +555,30 @@
return -1;
}
- hdr = (const struct rsn_ie_hdr *) rsn_ie;
+ if (rsn_ie_len >= 6 && rsn_ie[1] >= 4 &&
+ rsn_ie[1] == rsn_ie_len - 2 &&
+ WPA_GET_BE32(&rsn_ie[2]) == OSEN_IE_VENDOR_TYPE) {
+ pos = rsn_ie + 6;
+ left = rsn_ie_len - 6;
- 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;
+ data->proto = WPA_PROTO_OSEN;
+ } else {
+ const struct rsn_ie_hdr *hdr;
+
+ 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);
}
- pos = (const u8 *) (hdr + 1);
- left = rsn_ie_len - sizeof(*hdr);
-
if (left >= RSN_SELECTOR_LEN) {
data->group_cipher = rsn_selector_to_bitfield(pos);
if (!wpa_cipher_valid_group(data->group_cipher)) {
@@ -753,7 +842,7 @@
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 +
+ u8 buf[1 + SSID_MAX_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];
@@ -767,7 +856,7 @@
* 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)
+ if (ssid_len > SSID_MAX_LEN || r0kh_id_len > FT_R0KH_ID_MAX_LEN)
return;
pos = buf;
*pos++ = ssid_len;
@@ -858,15 +947,17 @@
*
* 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)
+int 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,
+ struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher)
{
u8 buf[2 * WPA_NONCE_LEN + 2 * ETH_ALEN];
u8 *pos, hash[32];
const u8 *addr[6];
size_t len[6];
+ u8 tmp[WPA_KCK_MAX_LEN + WPA_KEK_MAX_LEN + WPA_TK_MAX_LEN];
+ size_t ptk_len;
/*
* PTK = KDF-PTKLen(PMK-R1, "FT-PTK", SNonce || ANonce ||
@@ -882,7 +973,12 @@
os_memcpy(pos, sta_addr, ETH_ALEN);
pos += ETH_ALEN;
- sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, ptk, ptk_len);
+ ptk->kck_len = wpa_kck_len(akmp);
+ ptk->kek_len = wpa_kek_len(akmp);
+ ptk->tk_len = wpa_cipher_key_len(cipher);
+ ptk_len = ptk->kck_len + ptk->kek_len + ptk->tk_len;
+
+ sha256_prf(pmk_r1, PMK_LEN, "FT-PTK", buf, pos - buf, tmp, ptk_len);
/*
* PTKName = Truncate-128(SHA-256(PMKR1Name || "FT-PTKN" || SNonce ||
@@ -903,6 +999,19 @@
sha256_vector(6, addr, len, hash);
os_memcpy(ptk_name, hash, WPA_PMK_NAME_LEN);
+
+ os_memcpy(ptk->kck, tmp, ptk->kck_len);
+ os_memcpy(ptk->kek, tmp + ptk->kck_len, ptk->kek_len);
+ os_memcpy(ptk->tk, tmp + ptk->kck_len + ptk->kek_len, ptk->tk_len);
+
+ wpa_hexdump_key(MSG_DEBUG, "FT: KCK", ptk->kck, ptk->kck_len);
+ wpa_hexdump_key(MSG_DEBUG, "FT: KEK", ptk->kek, ptk->kek_len);
+ wpa_hexdump_key(MSG_DEBUG, "FT: TK", ptk->tk, ptk->tk_len);
+ wpa_hexdump(MSG_DEBUG, "FT: PTKName", ptk_name, WPA_PMK_NAME_LEN);
+
+ os_memset(tmp, 0, sizeof(tmp));
+
+ return 0;
}
#endif /* CONFIG_IEEE80211R */
@@ -975,6 +1084,39 @@
#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+/**
+ * rsn_pmkid_suite_b_192 - Calculate PMK identifier for Suite B AKM
+ * @kck: Key confirmation key
+ * @kck_len: Length of kck in bytes
+ * @aa: Authenticator address
+ * @spa: Supplicant address
+ * @pmkid: Buffer for PMKID
+ * Returns: 0 on success, -1 on failure
+ *
+ * IEEE Std 802.11ac-2013 - 11.6.1.3 Pairwise key hierarchy
+ * PMKID = Truncate(HMAC-SHA-384(KCK, "PMK Name" || AA || SPA))
+ */
+int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, u8 *pmkid)
+{
+ char *title = "PMK Name";
+ const u8 *addr[3];
+ const size_t len[3] = { 8, ETH_ALEN, ETH_ALEN };
+ unsigned char hash[SHA384_MAC_LEN];
+
+ addr[0] = (u8 *) title;
+ addr[1] = aa;
+ addr[2] = spa;
+
+ if (hmac_sha384_vector(kck, kck_len, 3, addr, len, hash) < 0)
+ return -1;
+ os_memcpy(pmkid, hash, PMKID_LEN);
+ return 0;
+}
+#endif /* CONFIG_SUITEB192 */
+
+
/**
* wpa_cipher_txt - Convert cipher suite to a text string
* @cipher: Cipher suite (WPA_CIPHER_* enum)
@@ -1054,6 +1196,8 @@
return "OSEN";
case WPA_KEY_MGMT_IEEE8021X_SUITE_B:
return "WPA2-EAP-SUITE-B";
+ case WPA_KEY_MGMT_IEEE8021X_SUITE_B_192:
+ return "WPA2-EAP-SUITE-B-192";
default:
return "UNKNOWN";
}
@@ -1082,6 +1226,8 @@
return WLAN_AKM_SUITE_OSEN;
if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B)
return WLAN_AKM_SUITE_8021X_SUITE_B;
+ if (akm & WPA_KEY_MGMT_IEEE8021X_SUITE_B_192)
+ return WLAN_AKM_SUITE_8021X_SUITE_B_192;
return 0;
}
diff --git a/src/common/wpa_common.h b/src/common/wpa_common.h
index 17bed34..29c3503 100644
--- a/src/common/wpa_common.h
+++ b/src/common/wpa_common.h
@@ -1,6 +1,6 @@
/*
* WPA definitions shared between hostapd and wpa_supplicant
- * Copyright (c) 2002-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2002-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -9,8 +9,6 @@
#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
@@ -63,8 +61,8 @@
#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_802_1X_SUITE_B RSN_SELECTOR(0x00, 0x0f, 0xac, 11)
-#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_384 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
-#define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_384 \
+#define RSN_AUTH_KEY_MGMT_802_1X_SUITE_B_192 RSN_SELECTOR(0x00, 0x0f, 0xac, 12)
+#define RSN_AUTH_KEY_MGMT_FT_802_1X_SUITE_B_192 \
RSN_SELECTOR(0x00, 0x0f, 0xac, 13)
#define RSN_AUTH_KEY_MGMT_CCKM RSN_SELECTOR(0x00, 0x40, 0x96, 0x00)
#define RSN_AUTH_KEY_MGMT_OSEN RSN_SELECTOR(0x50, 0x6f, 0x9a, 0x01)
@@ -191,22 +189,38 @@
/* followed by key_data_length bytes of key_data */
} STRUCT_PACKED;
+struct wpa_eapol_key_192 {
+ 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[24];
+ u8 key_data_length[2]; /* big endian */
+ /* followed by key_data_length bytes of key_data */
+} STRUCT_PACKED;
+
+#define WPA_EAPOL_KEY_MIC_MAX_LEN 24
+#define WPA_KCK_MAX_LEN 24
+#define WPA_KEK_MAX_LEN 32
+#define WPA_TK_MAX_LEN 32
+
/**
* 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;
+ u8 kck[WPA_KCK_MAX_LEN]; /* EAPOL-Key Key Confirmation Key (KCK) */
+ u8 kek[WPA_KEK_MAX_LEN]; /* EAPOL-Key Key Encryption Key (KEK) */
+ u8 tk[WPA_TK_MAX_LEN]; /* Temporal Key (TK) */
+ size_t kck_len;
+ size_t kek_len;
+ size_t tk_len;
+};
/* WPA IE version 1
@@ -292,7 +306,6 @@
} STRUCT_PACKED;
#endif /* CONFIG_IEEE80211W */
-#ifdef CONFIG_IEEE80211R
struct rsn_mdie {
u8 mobility_domain[MOBILITY_DOMAIN_ID_LEN];
u8 ft_capab;
@@ -320,23 +333,23 @@
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 akmp, 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);
+int wpa_eapol_key_mic(const u8 *key, size_t key_len, int akmp, int ver,
+ const u8 *buf, size_t len, u8 *mic);
+int 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,
+ struct wpa_ptk *ptk, int akmp, int cipher);
#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,
+int wpa_ft_mic(const u8 *kck, size_t kck_len, 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);
@@ -349,10 +362,10 @@
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);
+int 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,
+ struct wpa_ptk *ptk, u8 *ptk_name, int akmp, int cipher);
#endif /* CONFIG_IEEE80211R */
struct wpa_ie_data {
@@ -384,6 +397,16 @@
return -1;
}
#endif /* CONFIG_SUITEB */
+#ifdef CONFIG_SUITEB192
+int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len, const u8 *aa,
+ const u8 *spa, u8 *pmkid);
+#else /* CONFIG_SUITEB192 */
+static inline int rsn_pmkid_suite_b_192(const u8 *kck, size_t kck_len,
+ const u8 *aa, const u8 *spa, u8 *pmkid)
+{
+ return -1;
+}
+#endif /* CONFIG_SUITEB192 */
const char * wpa_cipher_txt(int cipher);
const char * wpa_key_mgmt_txt(int key_mgmt, int proto);
@@ -429,5 +452,6 @@
int wpa_parse_cipher(const char *value);
int wpa_write_ciphers(char *start, char *end, int ciphers, const char *delim);
int wpa_select_ap_group_cipher(int wpa, int wpa_pairwise, int rsn_pairwise);
+unsigned int wpa_mic_len(int akmp);
#endif /* WPA_COMMON_H */
diff --git a/src/common/wpa_ctrl.c b/src/common/wpa_ctrl.c
index ccaaf1b..82d4655 100644
--- a/src/common/wpa_ctrl.c
+++ b/src/common/wpa_ctrl.c
@@ -21,6 +21,7 @@
#ifdef ANDROID
#include <dirent.h>
+#include <sys/stat.h>
#include <cutils/sockets.h>
#include "private/android_filesystem_config.h"
#endif /* ANDROID */
diff --git a/src/common/wpa_ctrl.h b/src/common/wpa_ctrl.h
index 1f747eb..e3a816f 100644
--- a/src/common/wpa_ctrl.h
+++ b/src/common/wpa_ctrl.h
@@ -42,6 +42,8 @@
#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 peer certificate alternative subject name component from TLS */
+#define WPA_EVENT_EAP_PEER_ALT "CTRL-EVENT-EAP-PEER-ALT "
/** EAP TLS certificate chain validation error */
#define WPA_EVENT_EAP_TLS_CERT_ERROR "CTRL-EVENT-EAP-TLS-CERT-ERROR "
/** EAP status */
@@ -125,6 +127,9 @@
#define MESH_GROUP_REMOVED "MESH-GROUP-REMOVED "
#define MESH_PEER_CONNECTED "MESH-PEER-CONNECTED "
#define MESH_PEER_DISCONNECTED "MESH-PEER-DISCONNECTED "
+/** Mesh SAE authentication failure. Wrong password suspected. */
+#define MESH_SAE_AUTH_FAILURE "MESH-SAE-AUTH-FAILURE "
+#define MESH_SAE_AUTH_BLOCKED "MESH-SAE-AUTH-BLOCKED "
/* WMM AC events */
#define WMM_AC_EVENT_TSPEC_ADDED "TSPEC-ADDED "
@@ -162,6 +167,7 @@
#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_SERV_ASP_RESP "P2P-SERV-ASP-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 "
@@ -170,11 +176,16 @@
#define P2P_EVENT_NFC_BOTH_GO "P2P-NFC-BOTH-GO "
#define P2P_EVENT_NFC_PEER_CLIENT "P2P-NFC-PEER-CLIENT "
#define P2P_EVENT_NFC_WHILE_CLIENT "P2P-NFC-WHILE-CLIENT "
+#define P2P_EVENT_FALLBACK_TO_GO_NEG "P2P-FALLBACK-TO-GO-NEG "
+#define P2P_EVENT_FALLBACK_TO_GO_NEG_ENABLED "P2P-FALLBACK-TO-GO-NEG-ENABLED "
/* parameters: <PMF enabled> <timeout in ms> <Session Information URL> */
#define ESS_DISASSOC_IMMINENT "ESS-DISASSOC-IMMINENT "
#define P2P_EVENT_REMOVE_AND_REFORM_GROUP "P2P-REMOVE-AND-REFORM-GROUP "
+#define P2P_EVENT_P2PS_PROVISION_START "P2PS-PROV-START "
+#define P2P_EVENT_P2PS_PROVISION_DONE "P2PS-PROV-DONE "
+
#define INTERWORKING_AP "INTERWORKING-AP "
#define INTERWORKING_BLACKLISTED "INTERWORKING-BLACKLISTED "
#define INTERWORKING_NO_MATCH "INTERWORKING-NO-MATCH "
@@ -194,6 +205,9 @@
/* parameters: <addr> <dialog_token> <freq> <status_code> <result> */
#define GAS_QUERY_DONE "GAS-QUERY-DONE "
+/* parameters: <addr> <result> */
+#define ANQP_QUERY_DONE "ANQP-QUERY-DONE "
+
#define HS20_SUBSCRIPTION_REMEDIATION "HS20-SUBSCRIPTION-REMEDIATION "
#define HS20_DEAUTH_IMMINENT_NOTICE "HS20-DEAUTH-IMMINENT-NOTICE "
@@ -213,6 +227,7 @@
#define WPS_EVENT_AP_PIN_DISABLED "WPS-AP-PIN-DISABLED "
#define AP_STA_CONNECTED "AP-STA-CONNECTED "
#define AP_STA_DISCONNECTED "AP-STA-DISCONNECTED "
+#define AP_STA_POSSIBLE_PSK_MISMATCH "AP-STA-POSSIBLE-PSK-MISMATCH "
#define AP_REJECTED_MAX_STA "AP-REJECTED-MAX-STA "
#define AP_REJECTED_BLOCKED_STA "AP-REJECTED-BLOCKED-STA "
@@ -260,6 +275,8 @@
#define WPA_BSS_MASK_WIFI_DISPLAY BIT(16)
#define WPA_BSS_MASK_DELIM BIT(17)
#define WPA_BSS_MASK_MESH_SCAN BIT(18)
+#define WPA_BSS_MASK_SNR BIT(19)
+#define WPA_BSS_MASK_EST_THROUGHPUT BIT(20)
/* VENDOR_ELEM_* frame id values */
@@ -277,6 +294,7 @@
VENDOR_ELEM_P2P_INV_RESP = 10,
VENDOR_ELEM_P2P_ASSOC_REQ = 11,
VENDOR_ELEM_P2P_ASSOC_RESP = 12,
+ VENDOR_ELEM_ASSOC_REQ = 13,
NUM_VENDOR_ELEM_FRAMES
};
diff --git a/src/crypto/aes-eax.c b/src/crypto/aes-eax.c
index 21941c6..15a09f8 100644
--- a/src/crypto/aes-eax.c
+++ b/src/crypto/aes-eax.c
@@ -71,7 +71,7 @@
ret = 0;
fail:
- os_free(buf);
+ bin_clear_free(buf, buf_len);
return ret;
}
diff --git a/src/crypto/aes-omac1.c b/src/crypto/aes-omac1.c
index c2b0686..375db57 100644
--- a/src/crypto/aes-omac1.c
+++ b/src/crypto/aes-omac1.c
@@ -1,5 +1,5 @@
/*
- * One-key CBC MAC (OMAC1) hash with AES-128
+ * One-key CBC MAC (OMAC1) hash with AES
*
* Copyright (c) 2003-2007, Jouni Malinen <j@w1.fi>
*
@@ -27,8 +27,9 @@
/**
- * omac1_aes_128_vector - One-Key CBC MAC (OMAC1) hash with AES-128
- * @key: 128-bit key for the hash operation
+ * omac1_aes_vector - One-Key CBC MAC (OMAC1) hash with AES
+ * @key: Key for the hash operation
+ * @key_len: Key length in octets
* @num_elem: Number of elements in the data vector
* @addr: Pointers to the data areas
* @len: Lengths of the data blocks
@@ -39,15 +40,15 @@
* 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)
+int omac1_aes_vector(const u8 *key, size_t key_len, 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);
+ ctx = aes_encrypt_init(key, key_len);
if (ctx == NULL)
return -1;
os_memset(cbc, 0, AES_BLOCK_SIZE);
@@ -114,6 +115,26 @@
/**
+ * 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)
+{
+ return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
+/**
* 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
@@ -129,3 +150,21 @@
{
return omac1_aes_128_vector(key, 1, &data, &data_len, mac);
}
+
+
+/**
+ * omac1_aes_256 - One-Key CBC MAC (OMAC1) hash with AES-256 (aka AES-CMAC)
+ * @key: 256-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_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}
diff --git a/src/crypto/aes-siv.c b/src/crypto/aes-siv.c
index ff4b823..5ac82c2 100644
--- a/src/crypto/aes-siv.c
+++ b/src/crypto/aes-siv.c
@@ -11,6 +11,7 @@
#include "common.h"
#include "aes.h"
#include "aes_wrap.h"
+#include "aes_siv.h"
static const u8 zero[AES_BLOCK_SIZE];
@@ -60,8 +61,8 @@
}
-int aes_s2v(const u8 *key, size_t num_elem, const u8 *addr[],
- size_t *len, u8 *mac)
+static int aes_s2v(const u8 *key, size_t num_elem, const u8 *addr[],
+ size_t *len, u8 *mac)
{
u8 tmp[AES_BLOCK_SIZE], tmp2[AES_BLOCK_SIZE];
u8 *buf = NULL;
@@ -94,7 +95,7 @@
os_memcpy(buf, addr[i], len[i]);
xorend(buf, len[i], tmp, AES_BLOCK_SIZE);
ret = omac1_aes_128(key, buf, len[i], mac);
- os_free(buf);
+ bin_clear_free(buf, len[i]);
return ret;
}
diff --git a/src/crypto/aes_wrap.h b/src/crypto/aes_wrap.h
index 6b3727c..4a14209 100644
--- a/src/crypto/aes_wrap.h
+++ b/src/crypto/aes_wrap.h
@@ -2,7 +2,7 @@
* AES-based functions
*
* - AES Key Wrap Algorithm (RFC3394)
- * - One-Key CBC MAC (OMAC1) hash with AES-128
+ * - One-Key CBC MAC (OMAC1) hash with AES-128 and AES-256
* - AES-128 CTR mode encryption
* - AES-128 EAX mode encryption/decryption
* - AES-128 CBC
@@ -22,11 +22,16 @@
u8 *cipher);
int __must_check aes_unwrap(const u8 *kek, size_t kek_len, int n,
const u8 *cipher, u8 *plain);
+int __must_check omac1_aes_vector(const u8 *key, size_t key_len,
+ size_t num_elem, const u8 *addr[],
+ const size_t *len, u8 *mac);
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 omac1_aes_256(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);
diff --git a/src/crypto/crypto_cryptoapi.c b/src/crypto/crypto_cryptoapi.c
deleted file mode 100644
index 55a069b..0000000
--- a/src/crypto/crypto_cryptoapi.c
+++ /dev/null
@@ -1,783 +0,0 @@
-/*
- * 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/src/crypto/crypto_module_tests.c b/src/crypto/crypto_module_tests.c
new file mode 100644
index 0000000..7137c27
--- /dev/null
+++ b/src/crypto/crypto_module_tests.c
@@ -0,0 +1,1679 @@
+/*
+ * crypto module tests
+ * Copyright (c) 2014-2015, 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/aes_siv.h"
+#include "crypto/aes_wrap.h"
+#include "crypto/aes.h"
+#include "crypto/ms_funcs.h"
+#include "crypto/crypto.h"
+#include "crypto/sha1.h"
+#include "crypto/sha256.h"
+
+
+static int test_siv(void)
+{
+#ifdef CONFIG_MESH
+ /* RFC 5297, A.1. Deterministic Authenticated Encryption Example */
+ u8 key[] = {
+ 0xff, 0xfe, 0xfd, 0xfc, 0xfb, 0xfa, 0xf9, 0xf8,
+ 0xf7, 0xf6, 0xf5, 0xf4, 0xf3, 0xf2, 0xf1, 0xf0,
+ 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
+ 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
+ };
+ u8 ad[] = {
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27
+ };
+ u8 plaintext[] = {
+ 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+ 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee
+ };
+ u8 iv_c[] = {
+ 0x85, 0x63, 0x2d, 0x07, 0xc6, 0xe8, 0xf3, 0x7f,
+ 0x95, 0x0a, 0xcd, 0x32, 0x0a, 0x2e, 0xcc, 0x93,
+ 0x40, 0xc0, 0x2b, 0x96, 0x90, 0xc4, 0xdc, 0x04,
+ 0xda, 0xef, 0x7f, 0x6a, 0xfe, 0x5c
+ };
+ /* RFC 5297, A.2. Nonce-Based Authenticated Encryption Example */
+ u8 key_2[] = {
+ 0x7f, 0x7e, 0x7d, 0x7c, 0x7b, 0x7a, 0x79, 0x78,
+ 0x77, 0x76, 0x75, 0x74, 0x73, 0x72, 0x71, 0x70,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f
+ };
+ u8 ad1_2[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ 0xde, 0xad, 0xda, 0xda, 0xde, 0xad, 0xda, 0xda,
+ 0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
+ 0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00
+ };
+ u8 ad2_2[] = {
+ 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80,
+ 0x90, 0xa0
+ };
+ u8 nonce_2[] = {
+ 0x09, 0xf9, 0x11, 0x02, 0x9d, 0x74, 0xe3, 0x5b,
+ 0xd8, 0x41, 0x56, 0xc5, 0x63, 0x56, 0x88, 0xc0
+ };
+ u8 plaintext_2[] = {
+ 0x74, 0x68, 0x69, 0x73, 0x20, 0x69, 0x73, 0x20,
+ 0x73, 0x6f, 0x6d, 0x65, 0x20, 0x70, 0x6c, 0x61,
+ 0x69, 0x6e, 0x74, 0x65, 0x78, 0x74, 0x20, 0x74,
+ 0x6f, 0x20, 0x65, 0x6e, 0x63, 0x72, 0x79, 0x70,
+ 0x74, 0x20, 0x75, 0x73, 0x69, 0x6e, 0x67, 0x20,
+ 0x53, 0x49, 0x56, 0x2d, 0x41, 0x45, 0x53
+ };
+ u8 iv_c_2[] = {
+ 0x7b, 0xdb, 0x6e, 0x3b, 0x43, 0x26, 0x67, 0xeb,
+ 0x06, 0xf4, 0xd1, 0x4b, 0xff, 0x2f, 0xbd, 0x0f,
+ 0xcb, 0x90, 0x0f, 0x2f, 0xdd, 0xbe, 0x40, 0x43,
+ 0x26, 0x60, 0x19, 0x65, 0xc8, 0x89, 0xbf, 0x17,
+ 0xdb, 0xa7, 0x7c, 0xeb, 0x09, 0x4f, 0xa6, 0x63,
+ 0xb7, 0xa3, 0xf7, 0x48, 0xba, 0x8a, 0xf8, 0x29,
+ 0xea, 0x64, 0xad, 0x54, 0x4a, 0x27, 0x2e, 0x9c,
+ 0x48, 0x5b, 0x62, 0xa3, 0xfd, 0x5c, 0x0d
+ };
+ u8 out[2 * AES_BLOCK_SIZE + sizeof(plaintext_2)];
+ const u8 *addr[3];
+ size_t len[3];
+
+ /* RFC 5297, A.1. Deterministic Authenticated Encryption Example */
+ addr[0] = ad;
+ len[0] = sizeof(ad);
+
+ if (aes_siv_encrypt(key, plaintext, sizeof(plaintext),
+ 1, addr, len, out)) {
+ wpa_printf(MSG_ERROR, "AES-SIV mode encryption failed");
+ return 1;
+ }
+ if (os_memcmp(out, iv_c, sizeof(iv_c)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-SIV mode encryption returned invalid cipher text");
+ return 1;
+ }
+
+ if (aes_siv_decrypt(key, iv_c, sizeof(iv_c), 1, addr, len, out)) {
+ wpa_printf(MSG_ERROR, "AES-SIV mode decryption failed");
+ return 1;
+ }
+ if (os_memcmp(out, plaintext, sizeof(plaintext)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-SIV mode decryption returned invalid plain text");
+ return 1;
+ }
+
+ /* RFC 5297, A.2. Nonce-Based Authenticated Encryption Example */
+ addr[0] = ad1_2;
+ len[0] = sizeof(ad1_2);
+ addr[1] = ad2_2;
+ len[1] = sizeof(ad2_2);
+ addr[2] = nonce_2;
+ len[2] = sizeof(nonce_2);
+
+ if (aes_siv_encrypt(key_2, plaintext_2, sizeof(plaintext_2),
+ 3, addr, len, out)) {
+ wpa_printf(MSG_ERROR, "AES-SIV mode encryption failed");
+ return 1;
+ }
+ if (os_memcmp(out, iv_c_2, sizeof(iv_c_2)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-SIV mode encryption returned invalid cipher text");
+ return 1;
+ }
+
+ if (aes_siv_decrypt(key_2, iv_c_2, sizeof(iv_c_2), 3, addr, len, out)) {
+ wpa_printf(MSG_ERROR, "AES-SIV mode decryption failed");
+ return 1;
+ }
+ if (os_memcmp(out, plaintext_2, sizeof(plaintext_2)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-SIV mode decryption returned invalid plain text");
+ return 1;
+ }
+
+ wpa_printf(MSG_INFO, "AES-SIV test cases passed");
+#endif /* CONFIG_MESH */
+
+ return 0;
+}
+
+
+/* OMAC1 AES-128 test vectors from
+ * http://csrc.nist.gov/CryptoToolkit/modes/proposedmodes/omac/omac-ad.pdf
+ * which are same as the examples from NIST SP800-38B
+ * http://csrc.nist.gov/CryptoToolkit/modes/800-38_Series_Publications/SP800-38B.pdf
+ */
+
+struct omac1_test_vector {
+ u8 k[16];
+ u8 msg[64];
+ int msg_len;
+ u8 tag[16];
+};
+
+static struct omac1_test_vector omac1_test_vectors[] =
+{
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { },
+ 0,
+ { 0xbb, 0x1d, 0x69, 0x29, 0xe9, 0x59, 0x37, 0x28,
+ 0x7f, 0xa3, 0x7d, 0x12, 0x9b, 0x75, 0x67, 0x46 }
+ },
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a},
+ 16,
+ { 0x07, 0x0a, 0x16, 0xb4, 0x6b, 0x4d, 0x41, 0x44,
+ 0xf7, 0x9b, 0xdd, 0x9d, 0xd0, 0x4a, 0x28, 0x7c }
+ },
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11 },
+ 40,
+ { 0xdf, 0xa6, 0x67, 0x47, 0xde, 0x9a, 0xe6, 0x30,
+ 0x30, 0xca, 0x32, 0x61, 0x14, 0x97, 0xc8, 0x27 }
+ },
+ {
+ { 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c },
+ { 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96,
+ 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c,
+ 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11,
+ 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17,
+ 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10 },
+ 64,
+ { 0x51, 0xf0, 0xbe, 0xbf, 0x7e, 0x3b, 0x9d, 0x92,
+ 0xfc, 0x49, 0x74, 0x17, 0x79, 0x36, 0x3c, 0xfe }
+ },
+};
+
+
+static int test_omac1_vector(struct omac1_test_vector *tv, unsigned int i)
+{
+ u8 key[] = {
+ 0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6,
+ 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c
+ };
+ u8 msg[] = { 0x12, 0x34, 0x56 };
+ u8 result[24], result2[24];
+ const u8 *addr[3];
+ size_t len[3];
+
+ if (omac1_aes_128(tv->k, tv->msg, tv->msg_len, result) ||
+ os_memcmp(result, tv->tag, 16) != 0) {
+ wpa_printf(MSG_ERROR, "OMAC1-AES-128 test vector %u failed", i);
+ return 1;
+ }
+
+ if (tv->msg_len > 1) {
+
+ addr[0] = tv->msg;
+ len[0] = 1;
+ addr[1] = tv->msg + 1;
+ len[1] = tv->msg_len - 1;
+
+ if (omac1_aes_128_vector(tv->k, 2, addr, len, result) ||
+ os_memcmp(result, tv->tag, 16) != 0) {
+ wpa_printf(MSG_ERROR,
+ "OMAC1-AES-128(vector) test vector %u failed",
+ i);
+ return 1;
+ }
+
+ addr[0] = tv->msg;
+ len[0] = tv->msg_len - 2;
+ addr[1] = tv->msg + tv->msg_len - 2;
+ len[1] = 1;
+ addr[2] = tv->msg + tv->msg_len - 1;
+ len[2] = 1;
+
+ if (omac1_aes_128_vector(tv->k, 3, addr, len, result) ||
+ os_memcmp(result, tv->tag, 16) != 0) {
+ wpa_printf(MSG_ERROR,
+ "OMAC1-AES-128(vector2) test vector %u failed",
+ i);
+ return 1;
+ }
+ }
+
+ addr[0] = &msg[0];
+ len[0] = 1;
+ addr[1] = &msg[1];
+ len[1] = 1;
+ addr[2] = &msg[2];
+ len[2] = 1;
+ if (omac1_aes_128(key, msg, sizeof(msg), result) ||
+ omac1_aes_128_vector(key, 3, addr, len, result2) ||
+ os_memcmp(result, result2, 16) != 0) {
+ wpa_printf(MSG_ERROR, "OMAC1-AES-128 short test mismatch");
+ return 1;
+ }
+
+ return 0;
+}
+
+
+static int test_omac1(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(omac1_test_vectors); i++) {
+ if (test_omac1_vector(&omac1_test_vectors[i], i))
+ return 1;
+ }
+
+ wpa_printf(MSG_INFO, "OMAC1-AES-128 test cases passed");
+
+ return 0;
+}
+
+
+static int test_eax(void)
+{
+#ifdef EAP_PSK
+ u8 msg[] = { 0xF7, 0xFB };
+ u8 key[] = { 0x91, 0x94, 0x5D, 0x3F, 0x4D, 0xCB, 0xEE, 0x0B,
+ 0xF4, 0x5E, 0xF5, 0x22, 0x55, 0xF0, 0x95, 0xA4 };
+ u8 nonce[] = { 0xBE, 0xCA, 0xF0, 0x43, 0xB0, 0xA2, 0x3D, 0x84,
+ 0x31, 0x94, 0xBA, 0x97, 0x2C, 0x66, 0xDE, 0xBD };
+ u8 hdr[] = { 0xFA, 0x3B, 0xFD, 0x48, 0x06, 0xEB, 0x53, 0xFA };
+ u8 cipher[] = { 0x19, 0xDD, 0x5C, 0x4C, 0x93, 0x31, 0x04, 0x9D,
+ 0x0B, 0xDA, 0xB0, 0x27, 0x74, 0x08, 0xF6, 0x79,
+ 0x67, 0xE5 };
+ u8 data[sizeof(msg)], tag[AES_BLOCK_SIZE];
+
+ os_memcpy(data, msg, sizeof(msg));
+ if (aes_128_eax_encrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
+ data, sizeof(data), tag)) {
+ wpa_printf(MSG_ERROR, "AES-128 EAX mode encryption failed");
+ return 1;
+ }
+ if (os_memcmp(data, cipher, sizeof(data)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-128 EAX mode encryption returned invalid cipher text");
+ return 1;
+ }
+ if (os_memcmp(tag, cipher + sizeof(data), AES_BLOCK_SIZE) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-128 EAX mode encryption returned invalid tag");
+ return 1;
+ }
+
+ if (aes_128_eax_decrypt(key, nonce, sizeof(nonce), hdr, sizeof(hdr),
+ data, sizeof(data), tag)) {
+ wpa_printf(MSG_ERROR, "AES-128 EAX mode decryption failed");
+ return 1;
+ }
+ if (os_memcmp(data, msg, sizeof(data)) != 0) {
+ wpa_printf(MSG_ERROR,
+ "AES-128 EAX mode decryption returned invalid plain text");
+ return 1;
+ }
+
+ wpa_printf(MSG_INFO, "AES-128 EAX mode test cases passed");
+#endif /* EAP_PSK */
+
+ return 0;
+}
+
+
+static int test_cbc(void)
+{
+ struct cbc_test_vector {
+ u8 key[16];
+ u8 iv[16];
+ u8 plain[32];
+ u8 cipher[32];
+ size_t len;
+ } vectors[] = {
+ {
+ { 0x06, 0xa9, 0x21, 0x40, 0x36, 0xb8, 0xa1, 0x5b,
+ 0x51, 0x2e, 0x03, 0xd5, 0x34, 0x12, 0x00, 0x06 },
+ { 0x3d, 0xaf, 0xba, 0x42, 0x9d, 0x9e, 0xb4, 0x30,
+ 0xb4, 0x22, 0xda, 0x80, 0x2c, 0x9f, 0xac, 0x41 },
+ "Single block msg",
+ { 0xe3, 0x53, 0x77, 0x9c, 0x10, 0x79, 0xae, 0xb8,
+ 0x27, 0x08, 0x94, 0x2d, 0xbe, 0x77, 0x18, 0x1a },
+ 16
+ },
+ {
+ { 0xc2, 0x86, 0x69, 0x6d, 0x88, 0x7c, 0x9a, 0xa0,
+ 0x61, 0x1b, 0xbb, 0x3e, 0x20, 0x25, 0xa4, 0x5a },
+ { 0x56, 0x2e, 0x17, 0x99, 0x6d, 0x09, 0x3d, 0x28,
+ 0xdd, 0xb3, 0xba, 0x69, 0x5a, 0x2e, 0x6f, 0x58 },
+ { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f },
+ { 0xd2, 0x96, 0xcd, 0x94, 0xc2, 0xcc, 0xcf, 0x8a,
+ 0x3a, 0x86, 0x30, 0x28, 0xb5, 0xe1, 0xdc, 0x0a,
+ 0x75, 0x86, 0x60, 0x2d, 0x25, 0x3c, 0xff, 0xf9,
+ 0x1b, 0x82, 0x66, 0xbe, 0xa6, 0xd6, 0x1a, 0xb1 },
+ 32
+ }
+ };
+ int ret = 0;
+ u8 *buf;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(vectors); i++) {
+ struct cbc_test_vector *tv = &vectors[i];
+
+ buf = os_malloc(tv->len);
+ if (buf == NULL) {
+ ret++;
+ break;
+ }
+
+ os_memcpy(buf, tv->plain, tv->len);
+ if (aes_128_cbc_encrypt(tv->key, tv->iv, buf, tv->len) ||
+ os_memcmp(buf, tv->cipher, tv->len) != 0) {
+ wpa_printf(MSG_ERROR, "AES-CBC encrypt %d failed", i);
+ ret++;
+ }
+
+ os_memcpy(buf, tv->cipher, tv->len);
+ if (aes_128_cbc_decrypt(tv->key, tv->iv, buf, tv->len) ||
+ os_memcmp(buf, tv->plain, tv->len) != 0) {
+ wpa_printf(MSG_ERROR, "AES-CBC decrypt %d failed", i);
+ ret++;
+ }
+
+ os_free(buf);
+ }
+
+ return ret;
+}
+
+
+static int test_ecb(void)
+{
+#ifdef EAP_PSK
+ struct ecb_test_vector {
+ char *key;
+ char *plaintext;
+ char *ciphertext;
+ } vectors[] = {
+ /* CAVS 11.1 - ECBGFSbox128.rsp */
+ {
+ "00000000000000000000000000000000",
+ "f34481ec3cc627bacd5dc3fb08f273e6",
+ "0336763e966d92595a567cc9ce537f5e"
+ },
+ {
+ "00000000000000000000000000000000",
+ "9798c4640bad75c7c3227db910174e72",
+ "a9a1631bf4996954ebc093957b234589"
+ },
+ {
+ "00000000000000000000000000000000",
+ "96ab5c2ff612d9dfaae8c31f30c42168",
+ "ff4f8391a6a40ca5b25d23bedd44a597"
+ },
+ {
+ "00000000000000000000000000000000",
+ "6a118a874519e64e9963798a503f1d35",
+ "dc43be40be0e53712f7e2bf5ca707209"
+ },
+ {
+ "00000000000000000000000000000000",
+ "cb9fceec81286ca3e989bd979b0cb284",
+ "92beedab1895a94faa69b632e5cc47ce"
+ },
+ {
+ "00000000000000000000000000000000",
+ "b26aeb1874e47ca8358ff22378f09144",
+ "459264f4798f6a78bacb89c15ed3d601"
+ },
+ {
+ "00000000000000000000000000000000",
+ "58c8e00b2631686d54eab84b91f0aca1",
+ "08a4e2efec8a8e3312ca7460b9040bbf"
+ },
+ /* CAVS 11.1 - ECBKeySbox128.rsp */
+ {
+ "10a58869d74be5a374cf867cfb473859",
+ "00000000000000000000000000000000",
+ "6d251e6944b051e04eaa6fb4dbf78465"
+ },
+ {
+ "caea65cdbb75e9169ecd22ebe6e54675",
+ "00000000000000000000000000000000",
+ "6e29201190152df4ee058139def610bb",
+ }
+ };
+ int ret = 0;
+ unsigned int i;
+ u8 key[16], plain[16], cipher[16], out[16];
+
+ for (i = 0; i < ARRAY_SIZE(vectors); i++) {
+ struct ecb_test_vector *tv = &vectors[i];
+
+ if (hexstr2bin(tv->key, key, sizeof(key)) ||
+ hexstr2bin(tv->plaintext, plain, sizeof(plain)) ||
+ hexstr2bin(tv->ciphertext, cipher, sizeof(cipher))) {
+ wpa_printf(MSG_ERROR, "Invalid AES-ECB test vector %u",
+ i);
+ ret++;
+ continue;
+ }
+
+ if (aes_128_encrypt_block(key, plain, out) < 0 ||
+ os_memcmp(out, cipher, 16) != 0) {
+ wpa_printf(MSG_ERROR, "AES-ECB encrypt %u failed", i);
+ ret++;
+ }
+ }
+
+ if (!ret)
+ wpa_printf(MSG_INFO, "AES ECB mode test cases passed");
+
+ return ret;
+#endif /* EAP_PSK */
+
+ return 0;
+}
+
+
+static int test_key_wrap(void)
+{
+ int ret = 0;
+
+ /* RFC 3394 - Test vector 4.1 */
+ u8 kek41[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
+ };
+ u8 plain41[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+ };
+ u8 crypt41[] = {
+ 0x1F, 0xA6, 0x8B, 0x0A, 0x81, 0x12, 0xB4, 0x47,
+ 0xAE, 0xF3, 0x4B, 0xD8, 0xFB, 0x5A, 0x7B, 0x82,
+ 0x9D, 0x3E, 0x86, 0x23, 0x71, 0xD2, 0xCF, 0xE5
+ };
+ /* RFC 3394 - Test vector 4.2 */
+ u8 kek42[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
+ };
+ u8 plain42[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+ };
+ u8 crypt42[] = {
+ 0x96, 0x77, 0x8B, 0x25, 0xAE, 0x6C, 0xA4, 0x35,
+ 0xF9, 0x2B, 0x5B, 0x97, 0xC0, 0x50, 0xAE, 0xD2,
+ 0x46, 0x8A, 0xB8, 0xA1, 0x7A, 0xD8, 0x4E, 0x5D
+ };
+ /* RFC 3394 - Test vector 4.3 */
+ u8 kek43[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+ };
+ u8 plain43[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff
+ };
+ u8 crypt43[] = {
+ 0x64, 0xE8, 0xC3, 0xF9, 0xCE, 0x0F, 0x5B, 0xA2,
+ 0x63, 0xE9, 0x77, 0x79, 0x05, 0x81, 0x8A, 0x2A,
+ 0x93, 0xC8, 0x19, 0x1E, 0x7D, 0x6E, 0x8A, 0xE7,
+ };
+ /* RFC 3394 - Test vector 4.4 */
+ u8 kek44[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
+ };
+ u8 plain44[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
+ };
+ u8 crypt44[] = {
+ 0x03, 0x1D, 0x33, 0x26, 0x4E, 0x15, 0xD3, 0x32,
+ 0x68, 0xF2, 0x4E, 0xC2, 0x60, 0x74, 0x3E, 0xDC,
+ 0xE1, 0xC6, 0xC7, 0xDD, 0xEE, 0x72, 0x5A, 0x93,
+ 0x6B, 0xA8, 0x14, 0x91, 0x5C, 0x67, 0x62, 0xD2
+ };
+ /* RFC 3394 - Test vector 4.5 */
+ u8 kek45[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+ };
+ u8 plain45[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07
+ };
+ u8 crypt45[] = {
+ 0xA8, 0xF9, 0xBC, 0x16, 0x12, 0xC6, 0x8B, 0x3F,
+ 0xF6, 0xE6, 0xF4, 0xFB, 0xE3, 0x0E, 0x71, 0xE4,
+ 0x76, 0x9C, 0x8B, 0x80, 0xA3, 0x2C, 0xB8, 0x95,
+ 0x8C, 0xD5, 0xD1, 0x7D, 0x6B, 0x25, 0x4D, 0xA1,
+ };
+ /* RFC 3394 - Test vector 4.6 */
+ u8 kek46[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+ };
+ u8 plain46[] = {
+ 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+ 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F
+ };
+ u8 crypt46[] = {
+ 0x28, 0xC9, 0xF4, 0x04, 0xC4, 0xB8, 0x10, 0xF4,
+ 0xCB, 0xCC, 0xB3, 0x5C, 0xFB, 0x87, 0xF8, 0x26,
+ 0x3F, 0x57, 0x86, 0xE2, 0xD8, 0x0E, 0xD3, 0x26,
+ 0xCB, 0xC7, 0xF0, 0xE7, 0x1A, 0x99, 0xF4, 0x3B,
+ 0xFB, 0x98, 0x8B, 0x9B, 0x7A, 0x02, 0xDD, 0x21
+ };
+ u8 result[40];
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.1");
+ if (aes_wrap(kek41, sizeof(kek41), sizeof(plain41) / 8, plain41,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-128 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt41, sizeof(crypt41)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-128 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek41, sizeof(kek41), sizeof(plain41) / 8, crypt41,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-128 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain41, sizeof(plain41)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-128 failed");
+ ret++;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.2");
+ if (aes_wrap(kek42, sizeof(kek42), sizeof(plain42) / 8, plain42,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-192 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt42, sizeof(crypt42)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-192 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek42, sizeof(kek42), sizeof(plain42) / 8, crypt42,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-192 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain42, sizeof(plain42)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-192 failed");
+ ret++;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.3");
+ if (aes_wrap(kek43, sizeof(kek43), sizeof(plain43) / 8, plain43,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt43, sizeof(crypt43)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek43, sizeof(kek43), sizeof(plain43) / 8, crypt43,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain43, sizeof(plain43)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 failed");
+ ret++;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.4");
+ if (aes_wrap(kek44, sizeof(kek44), sizeof(plain44) / 8, plain44,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-192 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt44, sizeof(crypt44)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-192 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek44, sizeof(kek44), sizeof(plain44) / 8, crypt44,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-192 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain44, sizeof(plain44)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-192 failed");
+ ret++;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.5");
+ if (aes_wrap(kek45, sizeof(kek45), sizeof(plain45) / 8, plain45,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt45, sizeof(crypt45)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek45, sizeof(kek45), sizeof(plain45) / 8, crypt45,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain45, sizeof(plain45)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 failed");
+ ret++;
+ }
+
+ wpa_printf(MSG_INFO, "RFC 3394 - Test vector 4.6");
+ if (aes_wrap(kek46, sizeof(kek46), sizeof(plain46) / 8, plain46,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, crypt46, sizeof(crypt46)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-WRAP-256 failed");
+ ret++;
+ }
+ if (aes_unwrap(kek46, sizeof(kek46), sizeof(plain46) / 8, crypt46,
+ result)) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 reported failure");
+ ret++;
+ }
+ if (os_memcmp(result, plain46, sizeof(plain46)) != 0) {
+ wpa_printf(MSG_ERROR, "AES-UNWRAP-256 failed");
+ ret++;
+ }
+
+ if (!ret)
+ wpa_printf(MSG_INFO, "AES key wrap/unwrap test cases passed");
+
+ return ret;
+}
+
+
+static int test_md5(void)
+{
+ struct {
+ char *data;
+ char *hash;
+ } tests[] = {
+ {
+ "",
+ "\xd4\x1d\x8c\xd9\x8f\x00\xb2\x04"
+ "\xe9\x80\x09\x98\xec\xf8\x42\x7e"
+ },
+ {
+ "a",
+ "\x0c\xc1\x75\xb9\xc0\xf1\xb6\xa8"
+ "\x31\xc3\x99\xe2\x69\x77\x26\x61"
+ },
+ {
+ "abc",
+ "\x90\x01\x50\x98\x3c\xd2\x4f\xb0"
+ "\xd6\x96\x3f\x7d\x28\xe1\x7f\x72"
+ },
+ {
+ "message digest",
+ "\xf9\x6b\x69\x7d\x7c\xb7\x93\x8d"
+ "\x52\x5a\x2f\x31\xaa\xf1\x61\xd0"
+ },
+ {
+ "abcdefghijklmnopqrstuvwxyz",
+ "\xc3\xfc\xd3\xd7\x61\x92\xe4\x00"
+ "\x7d\xfb\x49\x6c\xca\x67\xe1\x3b"
+ },
+ {
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
+ "0123456789",
+ "\xd1\x74\xab\x98\xd2\x77\xd9\xf5"
+ "\xa5\x61\x1c\x2c\x9f\x41\x9d\x9f"
+ },
+ {
+ "12345678901234567890123456789012345678901234567890"
+ "123456789012345678901234567890",
+ "\x57\xed\xf4\xa2\x2b\xe3\xc9\x55"
+ "\xac\x49\xda\x2e\x21\x07\xb6\x7a"
+ }
+ };
+ unsigned int i;
+ u8 hash[16];
+ const u8 *addr[2];
+ size_t len[2];
+ int errors = 0;
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ wpa_printf(MSG_INFO, "MD5 test case %d", i);
+
+ addr[0] = (u8 *) tests[i].data;
+ len[0] = strlen(tests[i].data);
+ if (md5_vector(1, addr, len, hash) < 0 ||
+ os_memcmp(hash, tests[i].hash, 16) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ if (len[0]) {
+ addr[0] = (u8 *) tests[i].data;
+ len[0] = strlen(tests[i].data);
+ addr[1] = (u8 *) tests[i].data + 1;
+ len[1] = strlen(tests[i].data) - 1;
+ if (md5_vector(1, addr, len, hash) < 0 ||
+ os_memcmp(hash, tests[i].hash, 16) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+ }
+ }
+
+ if (!errors)
+ wpa_printf(MSG_INFO, "MD5 test cases passed");
+
+ return errors;
+}
+
+
+static int test_eap_fast(void)
+{
+#ifdef EAP_FAST
+ /* RFC 4851, Appendix B.1 */
+ const u8 pac_key[] = {
+ 0x0B, 0x97, 0x39, 0x0F, 0x37, 0x51, 0x78, 0x09,
+ 0x81, 0x1E, 0xFD, 0x9C, 0x6E, 0x65, 0x94, 0x2B,
+ 0x63, 0x2C, 0xE9, 0x53, 0x89, 0x38, 0x08, 0xBA,
+ 0x36, 0x0B, 0x03, 0x7C, 0xD1, 0x85, 0xE4, 0x14
+ };
+ const u8 seed[] = {
+ 0x3F, 0xFB, 0x11, 0xC4, 0x6C, 0xBF, 0xA5, 0x7A,
+ 0x54, 0x40, 0xDA, 0xE8, 0x22, 0xD3, 0x11, 0xD3,
+ 0xF7, 0x6D, 0xE4, 0x1D, 0xD9, 0x33, 0xE5, 0x93,
+ 0x70, 0x97, 0xEB, 0xA9, 0xB3, 0x66, 0xF4, 0x2A,
+ 0x00, 0x00, 0x00, 0x02, 0x6A, 0x66, 0x43, 0x2A,
+ 0x8D, 0x14, 0x43, 0x2C, 0xEC, 0x58, 0x2D, 0x2F,
+ 0xC7, 0x9C, 0x33, 0x64, 0xBA, 0x04, 0xAD, 0x3A,
+ 0x52, 0x54, 0xD6, 0xA5, 0x79, 0xAD, 0x1E, 0x00
+ };
+ const u8 master_secret[] = {
+ 0x4A, 0x1A, 0x51, 0x2C, 0x01, 0x60, 0xBC, 0x02,
+ 0x3C, 0xCF, 0xBC, 0x83, 0x3F, 0x03, 0xBC, 0x64,
+ 0x88, 0xC1, 0x31, 0x2F, 0x0B, 0xA9, 0xA2, 0x77,
+ 0x16, 0xA8, 0xD8, 0xE8, 0xBD, 0xC9, 0xD2, 0x29,
+ 0x38, 0x4B, 0x7A, 0x85, 0xBE, 0x16, 0x4D, 0x27,
+ 0x33, 0xD5, 0x24, 0x79, 0x87, 0xB1, 0xC5, 0xA2
+ };
+ const u8 key_block[] = {
+ 0x59, 0x59, 0xBE, 0x8E, 0x41, 0x3A, 0x77, 0x74,
+ 0x8B, 0xB2, 0xE5, 0xD3, 0x60, 0xAC, 0x4D, 0x35,
+ 0xDF, 0xFB, 0xC8, 0x1E, 0x9C, 0x24, 0x9C, 0x8B,
+ 0x0E, 0xC3, 0x1D, 0x72, 0xC8, 0x84, 0x9D, 0x57,
+ 0x48, 0x51, 0x2E, 0x45, 0x97, 0x6C, 0x88, 0x70,
+ 0xBE, 0x5F, 0x01, 0xD3, 0x64, 0xE7, 0x4C, 0xBB,
+ 0x11, 0x24, 0xE3, 0x49, 0xE2, 0x3B, 0xCD, 0xEF,
+ 0x7A, 0xB3, 0x05, 0x39, 0x5D, 0x64, 0x8A, 0x44,
+ 0x11, 0xB6, 0x69, 0x88, 0x34, 0x2E, 0x8E, 0x29,
+ 0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
+ 0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
+ 0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84,
+ 0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
+ 0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
+ };
+ const u8 sks[] = {
+ 0xD6, 0x4B, 0x7D, 0x72, 0x17, 0x59, 0x28, 0x05,
+ 0xAF, 0xF9, 0xB7, 0xFF, 0x66, 0x6D, 0xA1, 0x96,
+ 0x8F, 0x0B, 0x5E, 0x06, 0x46, 0x7A, 0x44, 0x84,
+ 0x64, 0xC1, 0xC8, 0x0C, 0x96, 0x44, 0x09, 0x98,
+ 0xFF, 0x92, 0xA8, 0xB4, 0xC6, 0x42, 0x28, 0x71
+ };
+ const u8 isk[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ const u8 imck[] = {
+ 0x16, 0x15, 0x3C, 0x3F, 0x21, 0x55, 0xEF, 0xD9,
+ 0x7F, 0x34, 0xAE, 0xC8, 0x1A, 0x4E, 0x66, 0x80,
+ 0x4C, 0xC3, 0x76, 0xF2, 0x8A, 0xA9, 0x6F, 0x96,
+ 0xC2, 0x54, 0x5F, 0x8C, 0xAB, 0x65, 0x02, 0xE1,
+ 0x18, 0x40, 0x7B, 0x56, 0xBE, 0xEA, 0xA7, 0xC5,
+ 0x76, 0x5D, 0x8F, 0x0B, 0xC5, 0x07, 0xC6, 0xB9,
+ 0x04, 0xD0, 0x69, 0x56, 0x72, 0x8B, 0x6B, 0xB8,
+ 0x15, 0xEC, 0x57, 0x7B
+ };
+ const u8 msk[] = {
+ 0x4D, 0x83, 0xA9, 0xBE, 0x6F, 0x8A, 0x74, 0xED,
+ 0x6A, 0x02, 0x66, 0x0A, 0x63, 0x4D, 0x2C, 0x33,
+ 0xC2, 0xDA, 0x60, 0x15, 0xC6, 0x37, 0x04, 0x51,
+ 0x90, 0x38, 0x63, 0xDA, 0x54, 0x3E, 0x14, 0xB9,
+ 0x27, 0x99, 0x18, 0x1E, 0x07, 0xBF, 0x0F, 0x5A,
+ 0x5E, 0x3C, 0x32, 0x93, 0x80, 0x8C, 0x6C, 0x49,
+ 0x67, 0xED, 0x24, 0xFE, 0x45, 0x40, 0xA0, 0x59,
+ 0x5E, 0x37, 0xC2, 0xE9, 0xD0, 0x5D, 0x0A, 0xE3
+ };
+ const u8 emsk[] = {
+ 0x3A, 0xD4, 0xAB, 0xDB, 0x76, 0xB2, 0x7F, 0x3B,
+ 0xEA, 0x32, 0x2C, 0x2B, 0x74, 0xF4, 0x28, 0x55,
+ 0xEF, 0x2D, 0xBA, 0x78, 0xC9, 0x57, 0x2F, 0x0D,
+ 0x06, 0xCD, 0x51, 0x7C, 0x20, 0x93, 0x98, 0xA9,
+ 0x76, 0xEA, 0x70, 0x21, 0xD7, 0x0E, 0x25, 0x54,
+ 0x97, 0xED, 0xB2, 0x8A, 0xF6, 0xED, 0xFD, 0x0A,
+ 0x2A, 0xE7, 0xA1, 0x58, 0x90, 0x10, 0x50, 0x44,
+ 0xB3, 0x82, 0x85, 0xDB, 0x06, 0x14, 0xD2, 0xF9
+ };
+ /* RFC 4851, Appendix B.2 */
+ u8 tlv[] = {
+ 0x80, 0x0C, 0x00, 0x38, 0x00, 0x01, 0x01, 0x00,
+ 0xD8, 0x6A, 0x8C, 0x68, 0x3C, 0x32, 0x31, 0xA8,
+ 0x56, 0x63, 0xB6, 0x40, 0x21, 0xFE, 0x21, 0x14,
+ 0x4E, 0xE7, 0x54, 0x20, 0x79, 0x2D, 0x42, 0x62,
+ 0xC9, 0xBF, 0x53, 0x7F, 0x54, 0xFD, 0xAC, 0x58,
+ 0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF,
+ 0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC,
+ 0x05, 0xC5, 0x5B, 0xB7
+ };
+ const u8 compound_mac[] = {
+ 0x43, 0x24, 0x6E, 0x30, 0x92, 0x17, 0x6D, 0xCF,
+ 0xE6, 0xE0, 0x69, 0xEB, 0x33, 0x61, 0x6A, 0xCC,
+ 0x05, 0xC5, 0x5B, 0xB7
+ };
+ u8 buf[512];
+ const u8 *simck, *cmk;
+ int errors = 0;
+
+ wpa_printf(MSG_INFO, "EAP-FAST test cases");
+
+ wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / master_secret");
+ if (sha1_t_prf(pac_key, sizeof(pac_key),
+ "PAC to master secret label hash",
+ seed, sizeof(seed), buf, sizeof(master_secret)) < 0 ||
+ os_memcmp(master_secret, buf, sizeof(master_secret)) != 0) {
+ wpa_printf(MSG_INFO, "T-PRF test - FAILED!");
+ errors++;
+ }
+
+ wpa_printf(MSG_INFO, "- PRF (TLS, SHA1/MD5) test case / key_block");
+ if (tls_prf_sha1_md5(master_secret, sizeof(master_secret),
+ "key expansion", seed, sizeof(seed),
+ buf, sizeof(key_block)) ||
+ os_memcmp(key_block, buf, sizeof(key_block)) != 0) {
+ wpa_printf(MSG_INFO, "PRF test - FAILED!");
+ errors++;
+ }
+
+ wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / IMCK");
+ if (sha1_t_prf(sks, sizeof(sks), "Inner Methods Compound Keys",
+ isk, sizeof(isk), buf, sizeof(imck)) < 0 ||
+ os_memcmp(imck, buf, sizeof(imck)) != 0) {
+ wpa_printf(MSG_INFO, "T-PRF test - FAILED!");
+ errors++;
+ }
+
+ simck = imck;
+ cmk = imck + 40;
+
+ wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / MSK");
+ if (sha1_t_prf(simck, 40, "Session Key Generating Function",
+ (u8 *) "", 0, buf, sizeof(msk)) < 0 ||
+ os_memcmp(msk, buf, sizeof(msk)) != 0) {
+ wpa_printf(MSG_INFO, "T-PRF test - FAILED!");
+ errors++;
+ }
+
+ wpa_printf(MSG_INFO, "- T-PRF (SHA1) test case / EMSK");
+ if (sha1_t_prf(simck, 40, "Extended Session Key Generating Function",
+ (u8 *) "", 0, buf, sizeof(msk)) < 0 ||
+ os_memcmp(emsk, buf, sizeof(emsk)) != 0) {
+ wpa_printf(MSG_INFO, "T-PRF test - FAILED!");
+ errors++;
+ }
+
+ wpa_printf(MSG_INFO, "- Compound MAC test case");
+ os_memset(tlv + sizeof(tlv) - 20, 0, 20);
+ if (hmac_sha1(cmk, 20, tlv, sizeof(tlv), tlv + sizeof(tlv) - 20) < 0 ||
+ os_memcmp(tlv + sizeof(tlv) - 20, compound_mac,
+ sizeof(compound_mac)) != 0) {
+ wpa_printf(MSG_INFO, "Compound MAC test - FAILED!");
+ errors++;
+ }
+
+ return errors;
+#else /* EAP_FAST */
+ return 0;
+#endif /* EAP_FAST */
+}
+
+
+static u8 key0[] =
+{
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b
+};
+static u8 data0[] = "Hi There";
+static u8 prf0[] =
+{
+ 0xbc, 0xd4, 0xc6, 0x50, 0xb3, 0x0b, 0x96, 0x84,
+ 0x95, 0x18, 0x29, 0xe0, 0xd7, 0x5f, 0x9d, 0x54,
+ 0xb8, 0x62, 0x17, 0x5e, 0xd9, 0xf0, 0x06, 0x06,
+ 0xe1, 0x7d, 0x8d, 0xa3, 0x54, 0x02, 0xff, 0xee,
+ 0x75, 0xdf, 0x78, 0xc3, 0xd3, 0x1e, 0x0f, 0x88,
+ 0x9f, 0x01, 0x21, 0x20, 0xc0, 0x86, 0x2b, 0xeb,
+ 0x67, 0x75, 0x3e, 0x74, 0x39, 0xae, 0x24, 0x2e,
+ 0xdb, 0x83, 0x73, 0x69, 0x83, 0x56, 0xcf, 0x5a
+};
+
+static u8 key1[] = "Jefe";
+static u8 data1[] = "what do ya want for nothing?";
+static u8 prf1[] =
+{
+ 0x51, 0xf4, 0xde, 0x5b, 0x33, 0xf2, 0x49, 0xad,
+ 0xf8, 0x1a, 0xeb, 0x71, 0x3a, 0x3c, 0x20, 0xf4,
+ 0xfe, 0x63, 0x14, 0x46, 0xfa, 0xbd, 0xfa, 0x58,
+ 0x24, 0x47, 0x59, 0xae, 0x58, 0xef, 0x90, 0x09,
+ 0xa9, 0x9a, 0xbf, 0x4e, 0xac, 0x2c, 0xa5, 0xfa,
+ 0x87, 0xe6, 0x92, 0xc4, 0x40, 0xeb, 0x40, 0x02,
+ 0x3e, 0x7b, 0xab, 0xb2, 0x06, 0xd6, 0x1d, 0xe7,
+ 0xb9, 0x2f, 0x41, 0x52, 0x90, 0x92, 0xb8, 0xfc
+};
+
+
+static u8 key2[] =
+{
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa
+};
+static u8 data2[] =
+{
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd
+};
+static u8 prf2[] =
+{
+ 0xe1, 0xac, 0x54, 0x6e, 0xc4, 0xcb, 0x63, 0x6f,
+ 0x99, 0x76, 0x48, 0x7b, 0xe5, 0xc8, 0x6b, 0xe1,
+ 0x7a, 0x02, 0x52, 0xca, 0x5d, 0x8d, 0x8d, 0xf1,
+ 0x2c, 0xfb, 0x04, 0x73, 0x52, 0x52, 0x49, 0xce,
+ 0x9d, 0xd8, 0xd1, 0x77, 0xea, 0xd7, 0x10, 0xbc,
+ 0x9b, 0x59, 0x05, 0x47, 0x23, 0x91, 0x07, 0xae,
+ 0xf7, 0xb4, 0xab, 0xd4, 0x3d, 0x87, 0xf0, 0xa6,
+ 0x8f, 0x1c, 0xbd, 0x9e, 0x2b, 0x6f, 0x76, 0x07
+};
+
+
+struct passphrase_test {
+ char *passphrase;
+ char *ssid;
+ char psk[32];
+};
+
+static struct passphrase_test passphrase_tests[] =
+{
+ {
+ "password",
+ "IEEE",
+ {
+ 0xf4, 0x2c, 0x6f, 0xc5, 0x2d, 0xf0, 0xeb, 0xef,
+ 0x9e, 0xbb, 0x4b, 0x90, 0xb3, 0x8a, 0x5f, 0x90,
+ 0x2e, 0x83, 0xfe, 0x1b, 0x13, 0x5a, 0x70, 0xe2,
+ 0x3a, 0xed, 0x76, 0x2e, 0x97, 0x10, 0xa1, 0x2e
+ }
+ },
+ {
+ "ThisIsAPassword",
+ "ThisIsASSID",
+ {
+ 0x0d, 0xc0, 0xd6, 0xeb, 0x90, 0x55, 0x5e, 0xd6,
+ 0x41, 0x97, 0x56, 0xb9, 0xa1, 0x5e, 0xc3, 0xe3,
+ 0x20, 0x9b, 0x63, 0xdf, 0x70, 0x7d, 0xd5, 0x08,
+ 0xd1, 0x45, 0x81, 0xf8, 0x98, 0x27, 0x21, 0xaf
+ }
+ },
+ {
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
+ "ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ",
+ {
+ 0xbe, 0xcb, 0x93, 0x86, 0x6b, 0xb8, 0xc3, 0x83,
+ 0x2c, 0xb7, 0x77, 0xc2, 0xf5, 0x59, 0x80, 0x7c,
+ 0x8c, 0x59, 0xaf, 0xcb, 0x6e, 0xae, 0x73, 0x48,
+ 0x85, 0x00, 0x13, 0x00, 0xa9, 0x81, 0xcc, 0x62
+ }
+ },
+};
+
+#define NUM_PASSPHRASE_TESTS ARRAY_SIZE(passphrase_tests)
+
+
+struct rfc6070_test {
+ char *p;
+ char *s;
+ int c;
+ char dk[32];
+ size_t dk_len;
+};
+
+static struct rfc6070_test rfc6070_tests[] =
+{
+ {
+ "password",
+ "salt",
+ 1,
+ {
+ 0x0c, 0x60, 0xc8, 0x0f, 0x96, 0x1f, 0x0e, 0x71,
+ 0xf3, 0xa9, 0xb5, 0x24, 0xaf, 0x60, 0x12, 0x06,
+ 0x2f, 0xe0, 0x37, 0xa6
+ },
+ 20
+ },
+ {
+ "password",
+ "salt",
+ 2,
+ {
+ 0xea, 0x6c, 0x01, 0x4d, 0xc7, 0x2d, 0x6f, 0x8c,
+ 0xcd, 0x1e, 0xd9, 0x2a, 0xce, 0x1d, 0x41, 0xf0,
+ 0xd8, 0xde, 0x89, 0x57
+ },
+ 20
+ },
+ {
+ "password",
+ "salt",
+ 4096,
+ {
+ 0x4b, 0x00, 0x79, 0x01, 0xb7, 0x65, 0x48, 0x9a,
+ 0xbe, 0xad, 0x49, 0xd9, 0x26, 0xf7, 0x21, 0xd0,
+ 0x65, 0xa4, 0x29, 0xc1
+ },
+ 20
+ },
+#if 0 /* This takes quite long to derive.. */
+ {
+ "password",
+ "salt",
+ 16777216,
+ {
+ 0xee, 0xfe, 0x3d, 0x61, 0xcd, 0x4d, 0xa4, 0xe4,
+ 0xe9, 0x94, 0x5b, 0x3d, 0x6b, 0xa2, 0x15, 0x8c,
+ 0x26, 0x34, 0xe9, 0x84
+ },
+ 20
+ },
+#endif
+ {
+ "passwordPASSWORDpassword",
+ "saltSALTsaltSALTsaltSALTsaltSALTsalt",
+ 4096,
+ {
+ 0x3d, 0x2e, 0xec, 0x4f, 0xe4, 0x1c, 0x84, 0x9b,
+ 0x80, 0xc8, 0xd8, 0x36, 0x62, 0xc0, 0xe4, 0x4a,
+ 0x8b, 0x29, 0x1a, 0x96, 0x4c, 0xf2, 0xf0, 0x70,
+ 0x38
+ },
+ 25
+ },
+#if 0 /* \0 not currently supported in passphrase parameters.. */
+ {
+ "pass\0word",
+ "sa\0lt",
+ 4096,
+ {
+ 0x56, 0xfa, 0x6a, 0xa7, 0x55, 0x48, 0x09, 0x9d,
+ 0xcc, 0x37, 0xd7, 0xf0, 0x34, 0x25, 0xe0, 0xc3
+ },
+ 16
+ },
+#endif
+};
+
+#define NUM_RFC6070_TESTS ARRAY_SIZE(rfc6070_tests)
+
+
+static int test_sha1(void)
+{
+ u8 res[512];
+ int ret = 0;
+ unsigned int i;
+
+ wpa_printf(MSG_INFO, "PRF-SHA1 test cases:");
+
+ if (sha1_prf(key0, sizeof(key0), "prefix", data0, sizeof(data0) - 1,
+ res, sizeof(prf0)) == 0 &&
+ os_memcmp(res, prf0, sizeof(prf0)) == 0)
+ wpa_printf(MSG_INFO, "Test case 0 - OK");
+ else {
+ wpa_printf(MSG_INFO, "Test case 0 - FAILED!");
+ ret++;
+ }
+
+ if (sha1_prf(key1, sizeof(key1) - 1, "prefix", data1, sizeof(data1) - 1,
+ res, sizeof(prf1)) == 0 &&
+ os_memcmp(res, prf1, sizeof(prf1)) == 0)
+ wpa_printf(MSG_INFO, "Test case 1 - OK");
+ else {
+ wpa_printf(MSG_INFO, "Test case 1 - FAILED!");
+ ret++;
+ }
+
+ if (sha1_prf(key2, sizeof(key2), "prefix", data2, sizeof(data2),
+ res, sizeof(prf2)) == 0 &&
+ os_memcmp(res, prf2, sizeof(prf2)) == 0)
+ wpa_printf(MSG_INFO, "Test case 2 - OK");
+ else {
+ wpa_printf(MSG_INFO, "Test case 2 - FAILED!");
+ ret++;
+ }
+
+ ret += test_eap_fast();
+
+ wpa_printf(MSG_INFO, "PBKDF2-SHA1 Passphrase test cases:");
+ for (i = 0; i < NUM_PASSPHRASE_TESTS; i++) {
+ u8 psk[32];
+ struct passphrase_test *test = &passphrase_tests[i];
+
+ if (pbkdf2_sha1(test->passphrase,
+ (const u8 *) test->ssid, strlen(test->ssid),
+ 4096, psk, 32) == 0 &&
+ os_memcmp(psk, test->psk, 32) == 0)
+ wpa_printf(MSG_INFO, "Test case %d - OK", i);
+ else {
+ wpa_printf(MSG_INFO, "Test case %d - FAILED!", i);
+ ret++;
+ }
+ }
+
+ wpa_printf(MSG_INFO, "PBKDF2-SHA1 test cases (RFC 6070):");
+ for (i = 0; i < NUM_RFC6070_TESTS; i++) {
+ u8 dk[25];
+ struct rfc6070_test *test = &rfc6070_tests[i];
+
+ if (pbkdf2_sha1(test->p, (const u8 *) test->s, strlen(test->s),
+ test->c, dk, test->dk_len) == 0 &&
+ os_memcmp(dk, test->dk, test->dk_len) == 0)
+ wpa_printf(MSG_INFO, "Test case %d - OK", i);
+ else {
+ wpa_printf(MSG_INFO, "Test case %d - FAILED!", i);
+ ret++;
+ }
+ }
+
+ if (!ret)
+ wpa_printf(MSG_INFO, "SHA1 test cases passed");
+ return ret;
+}
+
+
+struct {
+ char *data;
+ u8 hash[32];
+} tests[] = {
+ {
+ "abc",
+ {
+ 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea,
+ 0x41, 0x41, 0x40, 0xde, 0x5d, 0xae, 0x22, 0x23,
+ 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+ 0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad
+ }
+ },
+ {
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ {
+ 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8,
+ 0xe5, 0xc0, 0x26, 0x93, 0x0c, 0x3e, 0x60, 0x39,
+ 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
+ 0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1
+ }
+ }
+};
+
+struct hmac_test {
+ u8 key[80];
+ size_t key_len;
+ u8 data[128];
+ size_t data_len;
+ u8 hash[32];
+} hmac_tests[] = {
+ /* draft-ietf-ipsec-ciph-sha-256-01.txt */
+ {
+ {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
+ },
+ 32,
+ "abc", 3,
+ {
+ 0xa2, 0x1b, 0x1f, 0x5d, 0x4c, 0xf4, 0xf7, 0x3a,
+ 0x4d, 0xd9, 0x39, 0x75, 0x0f, 0x7a, 0x06, 0x6a,
+ 0x7f, 0x98, 0xcc, 0x13, 0x1c, 0xb1, 0x6a, 0x66,
+ 0x92, 0x75, 0x90, 0x21, 0xcf, 0xab, 0x81, 0x81
+ }
+ },
+ {
+ {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
+ },
+ 32,
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ 56,
+ {
+ 0x10, 0x4f, 0xdc, 0x12, 0x57, 0x32, 0x8f, 0x08,
+ 0x18, 0x4b, 0xa7, 0x31, 0x31, 0xc5, 0x3c, 0xae,
+ 0xe6, 0x98, 0xe3, 0x61, 0x19, 0x42, 0x11, 0x49,
+ 0xea, 0x8c, 0x71, 0x24, 0x56, 0x69, 0x7d, 0x30
+ }
+ },
+ {
+ {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20
+ },
+ 32,
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq"
+ "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
+ 112,
+ {
+ 0x47, 0x03, 0x05, 0xfc, 0x7e, 0x40, 0xfe, 0x34,
+ 0xd3, 0xee, 0xb3, 0xe7, 0x73, 0xd9, 0x5a, 0xab,
+ 0x73, 0xac, 0xf0, 0xfd, 0x06, 0x04, 0x47, 0xa5,
+ 0xeb, 0x45, 0x95, 0xbf, 0x33, 0xa9, 0xd1, 0xa3
+ }
+ },
+ {
+ {
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b
+ },
+ 32,
+ "Hi There",
+ 8,
+ {
+ 0x19, 0x8a, 0x60, 0x7e, 0xb4, 0x4b, 0xfb, 0xc6,
+ 0x99, 0x03, 0xa0, 0xf1, 0xcf, 0x2b, 0xbd, 0xc5,
+ 0xba, 0x0a, 0xa3, 0xf3, 0xd9, 0xae, 0x3c, 0x1c,
+ 0x7a, 0x3b, 0x16, 0x96, 0xa0, 0xb6, 0x8c, 0xf7
+ }
+ },
+ {
+ "Jefe",
+ 4,
+ "what do ya want for nothing?",
+ 28,
+ {
+ 0x5b, 0xdc, 0xc1, 0x46, 0xbf, 0x60, 0x75, 0x4e,
+ 0x6a, 0x04, 0x24, 0x26, 0x08, 0x95, 0x75, 0xc7,
+ 0x5a, 0x00, 0x3f, 0x08, 0x9d, 0x27, 0x39, 0x83,
+ 0x9d, 0xec, 0x58, 0xb9, 0x64, 0xec, 0x38, 0x43
+ }
+ },
+ {
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+ },
+ 32,
+ {
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd
+ },
+ 50,
+ {
+ 0xcd, 0xcb, 0x12, 0x20, 0xd1, 0xec, 0xcc, 0xea,
+ 0x91, 0xe5, 0x3a, 0xba, 0x30, 0x92, 0xf9, 0x62,
+ 0xe5, 0x49, 0xfe, 0x6c, 0xe9, 0xed, 0x7f, 0xdc,
+ 0x43, 0x19, 0x1f, 0xbd, 0xe4, 0x5c, 0x30, 0xb0
+ }
+ },
+ {
+ {
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
+ 0x21, 0x22, 0x23, 0x24, 0x25
+ },
+ 37,
+ {
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd
+ },
+ 50,
+ {
+ 0xd4, 0x63, 0x3c, 0x17, 0xf6, 0xfb, 0x8d, 0x74,
+ 0x4c, 0x66, 0xde, 0xe0, 0xf8, 0xf0, 0x74, 0x55,
+ 0x6e, 0xc4, 0xaf, 0x55, 0xef, 0x07, 0x99, 0x85,
+ 0x41, 0x46, 0x8e, 0xb4, 0x9b, 0xd2, 0xe9, 0x17
+ }
+ },
+ {
+ {
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c
+ },
+ 32,
+ "Test With Truncation",
+ 20,
+ {
+ 0x75, 0x46, 0xaf, 0x01, 0x84, 0x1f, 0xc0, 0x9b,
+ 0x1a, 0xb9, 0xc3, 0x74, 0x9a, 0x5f, 0x1c, 0x17,
+ 0xd4, 0xf5, 0x89, 0x66, 0x8a, 0x58, 0x7b, 0x27,
+ 0x00, 0xa9, 0xc9, 0x7c, 0x11, 0x93, 0xcf, 0x42
+ }
+ },
+ {
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+ },
+ 80,
+ "Test Using Larger Than Block-Size Key - Hash Key First",
+ 54,
+ {
+ 0x69, 0x53, 0x02, 0x5e, 0xd9, 0x6f, 0x0c, 0x09,
+ 0xf8, 0x0a, 0x96, 0xf7, 0x8e, 0x65, 0x38, 0xdb,
+ 0xe2, 0xe7, 0xb8, 0x20, 0xe3, 0xdd, 0x97, 0x0e,
+ 0x7d, 0xdd, 0x39, 0x09, 0x1b, 0x32, 0x35, 0x2f
+ }
+ },
+ {
+ {
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa
+ },
+ 80,
+ "Test Using Larger Than Block-Size Key and Larger Than One "
+ "Block-Size Data",
+ 73,
+ {
+ 0x63, 0x55, 0xac, 0x22, 0xe8, 0x90, 0xd0, 0xa3,
+ 0xc8, 0x48, 0x1a, 0x5c, 0xa4, 0x82, 0x5b, 0xc8,
+ 0x84, 0xd3, 0xe7, 0xa1, 0xff, 0x98, 0xa2, 0xfc,
+ 0x2a, 0xc7, 0xd8, 0xe0, 0x64, 0xc3, 0xb2, 0xe6
+ }
+ }
+};
+
+
+static int test_sha256(void)
+{
+ unsigned int i;
+ u8 hash[32];
+ const u8 *addr[2];
+ size_t len[2];
+ int errors = 0;
+
+ for (i = 0; i < ARRAY_SIZE(tests); i++) {
+ wpa_printf(MSG_INFO, "SHA256 test case %d:", i + 1);
+
+ addr[0] = (u8 *) tests[i].data;
+ len[0] = strlen(tests[i].data);
+ sha256_vector(1, addr, len, hash);
+ if (memcmp(hash, tests[i].hash, 32) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ if (len[0]) {
+ addr[0] = (u8 *) tests[i].data;
+ len[0] = 1;
+ addr[1] = (u8 *) tests[i].data + 1;
+ len[1] = strlen(tests[i].data) - 1;
+ sha256_vector(2, addr, len, hash);
+ if (memcmp(hash, tests[i].hash, 32) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(hmac_tests); i++) {
+ struct hmac_test *t = &hmac_tests[i];
+
+ wpa_printf(MSG_INFO, "HMAC-SHA256 test case %d:", i + 1);
+
+ if (hmac_sha256(t->key, t->key_len, t->data, t->data_len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash, 32) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ addr[0] = t->data;
+ len[0] = t->data_len;
+ if (hmac_sha256_vector(t->key, t->key_len, 1, addr, len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash, 32) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+
+ if (len[0]) {
+ addr[0] = t->data;
+ len[0] = 1;
+ addr[1] = t->data + 1;
+ len[1] = t->data_len - 1;
+ if (hmac_sha256_vector(t->key, t->key_len, 2, addr, len,
+ hash) < 0 ||
+ os_memcmp(hash, t->hash, 32) != 0) {
+ wpa_printf(MSG_INFO, " FAIL");
+ errors++;
+ } else
+ wpa_printf(MSG_INFO, " OK");
+ }
+ }
+
+ wpa_printf(MSG_INFO, "Test IEEE 802.11r KDF");
+ sha256_prf((u8 *) "abc", 3, "KDF test", (u8 *) "data", 4,
+ hash, sizeof(hash));
+ /* TODO: add proper test case for this */
+
+ if (!errors)
+ wpa_printf(MSG_INFO, "SHA256 test cases passed");
+ return errors;
+}
+
+
+static int test_ms_funcs(void)
+{
+ /* Test vector from RFC2759 example */
+ char *username = "User";
+ char *password = "clientPass";
+ u8 auth_challenge[] = {
+ 0x5B, 0x5D, 0x7C, 0x7D, 0x7B, 0x3F, 0x2F, 0x3E,
+ 0x3C, 0x2C, 0x60, 0x21, 0x32, 0x26, 0x26, 0x28
+ };
+ u8 peer_challenge[] = {
+ 0x21, 0x40, 0x23, 0x24, 0x25, 0x5E, 0x26, 0x2A,
+ 0x28, 0x29, 0x5F, 0x2B, 0x3A, 0x33, 0x7C, 0x7E
+ };
+ u8 password_hash[] = {
+ 0x44, 0xEB, 0xBA, 0x8D, 0x53, 0x12, 0xB8, 0xD6,
+ 0x11, 0x47, 0x44, 0x11, 0xF5, 0x69, 0x89, 0xAE
+ };
+ u8 nt_response[] = {
+ 0x82, 0x30, 0x9E, 0xCD, 0x8D, 0x70, 0x8B, 0x5E,
+ 0xA0, 0x8F, 0xAA, 0x39, 0x81, 0xCD, 0x83, 0x54,
+ 0x42, 0x33, 0x11, 0x4A, 0x3D, 0x85, 0xD6, 0xDF
+ };
+ u8 password_hash_hash[] = {
+ 0x41, 0xC0, 0x0C, 0x58, 0x4B, 0xD2, 0xD9, 0x1C,
+ 0x40, 0x17, 0xA2, 0xA1, 0x2F, 0xA5, 0x9F, 0x3F
+ };
+ u8 authenticator_response[] = {
+ 0x40, 0x7A, 0x55, 0x89, 0x11, 0x5F, 0xD0, 0xD6,
+ 0x20, 0x9F, 0x51, 0x0F, 0xE9, 0xC0, 0x45, 0x66,
+ 0x93, 0x2C, 0xDA, 0x56
+ };
+ u8 master_key[] = {
+ 0xFD, 0xEC, 0xE3, 0x71, 0x7A, 0x8C, 0x83, 0x8C,
+ 0xB3, 0x88, 0xE5, 0x27, 0xAE, 0x3C, 0xDD, 0x31
+ };
+ u8 send_start_key[] = {
+ 0x8B, 0x7C, 0xDC, 0x14, 0x9B, 0x99, 0x3A, 0x1B,
+ 0xA1, 0x18, 0xCB, 0x15, 0x3F, 0x56, 0xDC, 0xCB
+ };
+ u8 buf[32];
+ int errors = 0;
+
+ if (nt_password_hash((u8 *) password, os_strlen(password), buf) ||
+ os_memcmp(password_hash, buf, sizeof(password_hash)) != 0) {
+ wpa_printf(MSG_ERROR, "nt_password_hash failed");
+ errors++;
+ }
+
+ if (generate_nt_response(auth_challenge, peer_challenge,
+ (u8 *) username, os_strlen(username),
+ (u8 *) password, os_strlen(password), buf) ||
+ os_memcmp(nt_response, buf, sizeof(nt_response)) != 0) {
+ wpa_printf(MSG_ERROR, "generate_nt_response failed");
+ errors++;
+ }
+
+ if (hash_nt_password_hash(password_hash, buf) ||
+ os_memcmp(password_hash_hash, buf,
+ sizeof(password_hash_hash)) != 0) {
+ wpa_printf(MSG_ERROR, "hash_nt_password_hash failed");
+ errors++;
+ }
+
+ if (generate_authenticator_response((u8 *) password,
+ os_strlen(password),
+ peer_challenge, auth_challenge,
+ (u8 *) username,
+ os_strlen(username),
+ nt_response, buf) ||
+ os_memcmp(authenticator_response, buf,
+ sizeof(authenticator_response)) != 0) {
+ wpa_printf(MSG_ERROR, "generate_authenticator_response failed");
+ errors++;
+ }
+
+ if (get_master_key(password_hash_hash, nt_response, buf) ||
+ os_memcmp(master_key, buf, sizeof(master_key)) != 0) {
+ wpa_printf(MSG_ERROR, "get_master_key failed");
+ errors++;
+ }
+
+ if (get_asymetric_start_key(master_key, buf, sizeof(send_start_key),
+ 1, 1) ||
+ os_memcmp(send_start_key, buf, sizeof(send_start_key)) != 0) {
+ wpa_printf(MSG_ERROR, "get_asymetric_start_key failed");
+ errors++;
+ }
+
+ if (errors)
+ wpa_printf(MSG_ERROR, "ms_funcs: %d errors", errors);
+ else
+ wpa_printf(MSG_INFO, "ms_funcs test cases passed");
+
+ return errors;
+}
+
+
+int crypto_module_tests(void)
+{
+ int ret = 0;
+
+ wpa_printf(MSG_INFO, "crypto module tests");
+ if (test_siv() ||
+ test_omac1() ||
+ test_eax() ||
+ test_cbc() ||
+ test_ecb() ||
+ test_key_wrap() ||
+ test_md5() ||
+ test_sha1() ||
+ test_sha256() ||
+ test_ms_funcs())
+ ret = -1;
+
+ return ret;
+}
diff --git a/src/crypto/crypto_nss.c b/src/crypto/crypto_nss.c
deleted file mode 100644
index acd0a55..0000000
--- a/src/crypto/crypto_nss.c
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * 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/src/crypto/crypto_openssl.c b/src/crypto/crypto_openssl.c
index b4c59d1..9834b25 100644
--- a/src/crypto/crypto_openssl.c
+++ b/src/crypto/crypto_openssl.c
@@ -1,6 +1,6 @@
/*
* Wrapper functions for OpenSSL libcrypto
- * Copyright (c) 2004-2013, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2004-2015, Jouni Malinen <j@w1.fi>
*
* This software may be distributed under the terms of the BSD license.
* See README for more details.
@@ -28,19 +28,12 @@
#include "dh_group5.h"
#include "sha1.h"
#include "sha256.h"
+#include "sha384.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 || defined(OPENSSL_IS_BORINGSSL)
+#ifdef OPENSSL_IS_BORINGSSL
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,
@@ -60,20 +53,11 @@
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 */
+#else /* OPENSSL_IS_BORINGSSL */
return get_rfc3526_prime_1536(NULL);
-#endif /* openssl < 0.9.8 */
+#endif /* OPENSSL_IS_BORINGSSL */
}
-#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
@@ -258,7 +242,7 @@
"in AES encrypt", len);
}
EVP_CIPHER_CTX_cleanup(c);
- os_free(c);
+ bin_clear_free(c, sizeof(*c));
}
@@ -309,7 +293,84 @@
"in AES decrypt", len);
}
EVP_CIPHER_CTX_cleanup(c);
- os_free(ctx);
+ bin_clear_free(c, sizeof(*c));
+}
+
+
+int aes_wrap(const u8 *kek, size_t kek_len, int n, const u8 *plain, u8 *cipher)
+{
+ AES_KEY actx;
+ int res;
+
+ if (AES_set_encrypt_key(kek, kek_len << 3, &actx))
+ return -1;
+ res = AES_wrap_key(&actx, NULL, cipher, plain, n * 8);
+ OPENSSL_cleanse(&actx, sizeof(actx));
+ return res <= 0 ? -1 : 0;
+}
+
+
+int aes_unwrap(const u8 *kek, size_t kek_len, int n, const u8 *cipher,
+ u8 *plain)
+{
+ AES_KEY actx;
+ int res;
+
+ if (AES_set_decrypt_key(kek, kek_len << 3, &actx))
+ return -1;
+ res = AES_unwrap_key(&actx, NULL, plain, cipher, (n + 1) * 8);
+ OPENSSL_cleanse(&actx, sizeof(actx));
+ return res <= 0 ? -1 : 0;
+}
+
+
+int aes_128_cbc_encrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+ EVP_CIPHER_CTX ctx;
+ int clen, len;
+ u8 buf[16];
+
+ EVP_CIPHER_CTX_init(&ctx);
+ if (EVP_EncryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
+ return -1;
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ clen = data_len;
+ if (EVP_EncryptUpdate(&ctx, data, &clen, data, data_len) != 1 ||
+ clen != (int) data_len)
+ return -1;
+
+ len = sizeof(buf);
+ if (EVP_EncryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
+ return -1;
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ return 0;
+}
+
+
+int aes_128_cbc_decrypt(const u8 *key, const u8 *iv, u8 *data, size_t data_len)
+{
+ EVP_CIPHER_CTX ctx;
+ int plen, len;
+ u8 buf[16];
+
+ EVP_CIPHER_CTX_init(&ctx);
+ if (EVP_DecryptInit_ex(&ctx, EVP_aes_128_cbc(), NULL, key, iv) != 1)
+ return -1;
+ EVP_CIPHER_CTX_set_padding(&ctx, 0);
+
+ plen = data_len;
+ if (EVP_DecryptUpdate(&ctx, data, &plen, data, data_len) != 1 ||
+ plen != (int) data_len)
+ return -1;
+
+ len = sizeof(buf);
+ if (EVP_DecryptFinal_ex(&ctx, buf, &len) != 1 || len != 0)
+ return -1;
+ EVP_CIPHER_CTX_cleanup(&ctx);
+
+ return 0;
}
@@ -507,8 +568,8 @@
return dh;
err:
- wpabuf_free(pubkey);
- wpabuf_free(privkey);
+ wpabuf_clear_free(pubkey);
+ wpabuf_clear_free(privkey);
DH_free(dh);
return NULL;
}
@@ -581,7 +642,7 @@
err:
BN_clear_free(pub_key);
- wpabuf_free(res);
+ wpabuf_clear_free(res);
return NULL;
}
@@ -638,7 +699,7 @@
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);
+ bin_clear_free(ctx, sizeof(*ctx));
return NULL;
}
#endif /* openssl < 0.9.9 */
@@ -664,7 +725,7 @@
return -2;
if (mac == NULL || len == NULL) {
- os_free(ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
return 0;
}
@@ -676,7 +737,7 @@
res = HMAC_Final(&ctx->ctx, mac, &mdlen);
#endif /* openssl < 0.9.9 */
HMAC_CTX_cleanup(&ctx->ctx);
- os_free(ctx);
+ bin_clear_free(ctx, sizeof(*ctx));
if (res == 1) {
*len = mdlen;
@@ -687,43 +748,26 @@
}
-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)
+static int openssl_hmac_vector(const EVP_MD *type, const u8 *key,
+ size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac,
+ unsigned int mdlen)
{
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);
+ HMAC_Init_ex(&ctx, key, key_len, type, NULL);
#else /* openssl < 0.9.9 */
- if (HMAC_Init_ex(&ctx, key, key_len, EVP_sha1(), NULL) != 1)
+ if (HMAC_Init_ex(&ctx, key, key_len, type, 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;
@@ -736,6 +780,43 @@
}
+#ifndef CONFIG_FIPS
+
+int hmac_md5_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return openssl_hmac_vector(EVP_md5(), key ,key_len, num_elem, addr, len,
+ mac, 16);
+}
+
+
+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);
+}
+
+#endif /* CONFIG_FIPS */
+
+
+int pbkdf2_sha1(const char *passphrase, const u8 *ssid, size_t ssid_len,
+ int iterations, u8 *buf, size_t buflen)
+{
+ if (PKCS5_PBKDF2_HMAC_SHA1(passphrase, os_strlen(passphrase), ssid,
+ ssid_len, iterations, buflen, buf) != 1)
+ return -1;
+ 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)
+{
+ return openssl_hmac_vector(EVP_sha1(), key, key_len, num_elem, addr,
+ len, mac, 20);
+}
+
+
int hmac_sha1(const u8 *key, size_t key_len, const u8 *data, size_t data_len,
u8 *mac)
{
@@ -748,32 +829,8 @@
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;
+ return openssl_hmac_vector(EVP_sha256(), key, key_len, num_elem, addr,
+ len, mac, 32);
}
@@ -786,6 +843,25 @@
#endif /* CONFIG_SHA256 */
+#ifdef CONFIG_SHA384
+
+int hmac_sha384_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return openssl_hmac_vector(EVP_sha384(), key, key_len, num_elem, addr,
+ len, mac, 32);
+}
+
+
+int hmac_sha384(const u8 *key, size_t key_len, const u8 *data,
+ size_t data_len, u8 *mac)
+{
+ return hmac_sha384_vector(key, key_len, 1, &data, &data_len, mac);
+}
+
+#endif /* CONFIG_SHA384 */
+
+
int crypto_get_random(void *buf, size_t len)
{
if (RAND_bytes(buf, len) != 1)
@@ -795,8 +871,8 @@
#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)
+int omac1_aes_vector(const u8 *key, size_t key_len, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
{
CMAC_CTX *ctx;
int ret = -1;
@@ -806,8 +882,15 @@
if (ctx == NULL)
return -1;
- if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
+ if (key_len == 32) {
+ if (!CMAC_Init(ctx, key, 32, EVP_aes_256_cbc(), NULL))
+ goto fail;
+ } else if (key_len == 16) {
+ if (!CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL))
+ goto fail;
+ } else {
goto fail;
+ }
for (i = 0; i < num_elem; i++) {
if (!CMAC_Update(ctx, addr[i], len[i]))
goto fail;
@@ -822,10 +905,23 @@
}
+int omac1_aes_128_vector(const u8 *key, size_t num_elem,
+ const u8 *addr[], const size_t *len, u8 *mac)
+{
+ return omac1_aes_vector(key, 16, num_elem, addr, len, mac);
+}
+
+
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);
}
+
+
+int omac1_aes_256(const u8 *key, const u8 *data, size_t data_len, u8 *mac)
+{
+ return omac1_aes_vector(key, 32, 1, &data, &data_len, mac);
+}
#endif /* CONFIG_OPENSSL_CMAC */
diff --git a/src/crypto/dh_groups.c b/src/crypto/dh_groups.c
index 58e94c3..d3b2631 100644
--- a/src/crypto/dh_groups.c
+++ b/src/crypto/dh_groups.c
@@ -1198,14 +1198,14 @@
if (dh == NULL)
return NULL;
- wpabuf_free(*priv);
+ wpabuf_clear_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);
+ wpabuf_clear_free(*priv);
*priv = NULL;
return NULL;
}
@@ -1224,7 +1224,7 @@
wpabuf_head(*priv), wpabuf_len(*priv),
dh->prime, dh->prime_len, wpabuf_mhead(pv),
&pv_len) < 0) {
- wpabuf_free(pv);
+ wpabuf_clear_free(pv);
wpa_printf(MSG_INFO, "